1 /* NetHack 3.6 pline.c $NHDT-Date: 1456528597 2016/02/26 23:16:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.49 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers \
9 static boolean no_repeat
= FALSE
;
10 static char prevmsg
[BUFSZ
];
12 static char *FDECL(You_buf
, (int));
13 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
14 static void FDECL(execplinehandler
, (const char *));
18 /* Note that these declarations rely on knowledge of the internals
19 * of the variable argument handling stuff in "tradstdc.h"
22 #if defined(USE_STDARG) || defined(USE_VARARGS)
23 static void FDECL(vpline
, (const char *, va_list));
26 VA_DECL(const char *, line
)
29 VA_INIT(line
, char *);
30 vpline(line
, VA_ARGS
);
36 vpline(const char *line
, va_list the_args
)
39 vpline(line
, the_args
)
44 #else /* USE_STDARG | USE_VARARG */
49 VA_DECL(const char *, line
)
50 #endif /* USE_STDARG | USE_VARARG */
51 { /* start of vpline() or of nested block in USE_OLDARG's pline() */
55 /* Do NOT use VA_START and VA_END in here... see above */
60 if (program_state
.done_hup
)
63 if (program_state
.wizkit_wishing
)
66 if (index(line
, '%')) {
67 Vsprintf(pbuf
, line
, VA_ARGS
);
70 if ((ln
= (int) strlen(line
)) > BUFSZ
- 1) {
71 if (line
!= pbuf
) /* no '%' was present */
72 (void) strncpy(pbuf
, line
, BUFSZ
- 1); /* caveat: unterminated */
73 /* truncate, preserving the final 3 characters:
74 "___ extremely long text" -> "___ extremely l...ext"
75 (this may be suboptimal if overflow is less than 3) */
76 (void) strncpy(pbuf
+ BUFSZ
- 1 - 6, "...", 3);
77 /* avoid strncpy; buffers could overlap if excess is small */
78 pbuf
[BUFSZ
- 1 - 3] = line
[ln
- 3];
79 pbuf
[BUFSZ
- 1 - 2] = line
[ln
- 2];
80 pbuf
[BUFSZ
- 1 - 1] = line
[ln
- 1];
81 pbuf
[BUFSZ
- 1] = '\0';
84 if (!iflags
.window_inited
) {
86 iflags
.last_msg
= PLNMSG_UNKNOWN
;
90 msgtyp
= msgtype_type(line
, no_repeat
);
91 if (msgtyp
== MSGTYP_NOSHOW
92 || (msgtyp
== MSGTYP_NOREP
&& !strcmp(line
, prevmsg
)))
94 if (vision_full_recalc
)
97 flush_screen(1); /* %% */
99 putstr(WIN_MESSAGE
, 0, line
);
101 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
102 execplinehandler(line
);
105 /* this gets cleared after every pline message */
106 iflags
.last_msg
= PLNMSG_UNKNOWN
;
107 strncpy(prevmsg
, line
, BUFSZ
), prevmsg
[BUFSZ
- 1] = '\0';
108 if (msgtyp
== MSGTYP_STOP
)
109 display_nhwindow(WIN_MESSAGE
, TRUE
); /* --more-- */
111 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
112 /* provide closing brace for the nested block
113 which immediately follows USE_OLDARGS's VA_DECL() */
120 VA_DECL(const char *, line
)
123 VA_INIT(line
, const char *);
125 vpline(line
, VA_ARGS
);
131 /* work buffer for You(), &c and verbalize() */
132 static char *you_buf
= 0;
133 static int you_buf_siz
= 0;
139 if (siz
> you_buf_siz
) {
141 free((genericptr_t
) you_buf
);
142 you_buf_siz
= siz
+ 10;
143 you_buf
= (char *) alloc((unsigned) you_buf_siz
);
152 free((genericptr_t
) you_buf
), you_buf
= (char *) 0;
156 /* `prefix' must be a string literal, not a pointer */
157 #define YouPrefix(pointer, prefix, text) \
158 Strcpy((pointer = You_buf((int) (strlen(text) + sizeof prefix))), prefix)
160 #define YouMessage(pointer, prefix, text) \
161 strcat((YouPrefix(pointer, prefix, text), pointer), text)
165 VA_DECL(const char *, line
)
169 VA_INIT(line
, const char *);
170 vpline(YouMessage(tmp
, "You ", line
), VA_ARGS
);
176 VA_DECL(const char *, line
)
180 VA_INIT(line
, const char *);
181 vpline(YouMessage(tmp
, "Your ", line
), VA_ARGS
);
187 VA_DECL(const char *, line
)
191 VA_INIT(line
, const char *);
193 YouPrefix(tmp
, "You dream that you feel ", line
);
195 YouPrefix(tmp
, "You feel ", line
);
196 vpline(strcat(tmp
, line
), VA_ARGS
);
202 VA_DECL(const char *, line
)
206 VA_INIT(line
, const char *);
207 vpline(YouMessage(tmp
, "You can't ", line
), VA_ARGS
);
213 VA_DECL(const char *, line
)
217 VA_INIT(line
, const char *);
218 vpline(YouMessage(tmp
, "The ", line
), VA_ARGS
);
224 VA_DECL(const char *, line
)
228 VA_INIT(line
, const char *);
229 vpline(YouMessage(tmp
, "There ", line
), VA_ARGS
);
235 VA_DECL(const char *, line
)
239 if (Deaf
|| !flags
.acoustics
)
242 VA_INIT(line
, const char *);
244 YouPrefix(tmp
, "You barely hear ", line
);
246 YouPrefix(tmp
, "You dream that you hear ", line
);
248 YouPrefix(tmp
, "You hear ", line
);
249 vpline(strcat(tmp
, line
), VA_ARGS
);
255 VA_DECL(const char *, line
)
260 VA_INIT(line
, const char *);
262 YouPrefix(tmp
, "You dream that you see ", line
);
263 else if (Blind
) /* caller should have caught this... */
264 YouPrefix(tmp
, "You sense ", line
);
266 YouPrefix(tmp
, "You see ", line
);
267 vpline(strcat(tmp
, line
), VA_ARGS
);
271 /* Print a message inside double-quotes.
272 * The caller is responsible for checking deafness.
273 * Gods can speak directly to you in spite of deafness.
277 VA_DECL(const char *, line
)
282 VA_INIT(line
, const char *);
283 tmp
= You_buf((int) strlen(line
) + sizeof "\"\"");
287 vpline(tmp
, VA_ARGS
);
292 /* Note that these declarations rely on knowledge of the internals
293 * of the variable argument handling stuff in "tradstdc.h"
296 #if defined(USE_STDARG) || defined(USE_VARARGS)
297 static void FDECL(vraw_printf
, (const char *, va_list));
300 VA_DECL(const char *, line
)
303 VA_INIT(line
, char *);
304 vraw_printf(line
, VA_ARGS
);
310 vraw_printf(const char *line
, va_list the_args
)
313 vraw_printf(line
, the_args
)
318 #else /* USE_STDARG | USE_VARARG */
321 VA_DECL(const char *, line
)
324 char pbuf
[3 * BUFSZ
];
326 /* Do NOT use VA_START and VA_END in here... see above */
328 if (index(line
, '%')) {
329 Vsprintf(pbuf
, line
, VA_ARGS
);
332 if ((ln
= (int) strlen(line
)) > BUFSZ
- 1) {
334 line
= strncpy(pbuf
, line
, BUFSZ
- 1);
335 /* unlike pline, we don't futz around to keep last few chars */
336 pbuf
[BUFSZ
- 1] = '\0'; /* terminate strncpy or truncate vsprintf */
339 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
340 VA_END(); /* (see vpline) */
346 VA_DECL(const char *, s
)
348 char pbuf
[2 * BUFSZ
];
350 VA_INIT(s
, const char *);
351 if (program_state
.in_impossible
)
352 panic("impossible called impossible");
354 program_state
.in_impossible
= 1;
355 Vsprintf(pbuf
, s
, VA_ARGS
);
356 pbuf
[BUFSZ
- 1] = '\0'; /* sanity */
357 paniclog("impossible", pbuf
);
359 pline("Program in disorder - perhaps you'd better #quit.");
360 program_state
.in_impossible
= 0;
368 switch ((int) alignment
) {
383 register struct monst
*mtmp
;
385 aligntyp alignment
= mon_aligntyp(mtmp
);
386 char info
[BUFSZ
], monnambuf
[BUFSZ
];
390 Strcat(info
, ", tame");
392 Sprintf(eos(info
), " (%d", mtmp
->mtame
);
394 Sprintf(eos(info
), "; hungry %ld; apport %d",
395 EDOG(mtmp
)->hungrytime
, EDOG(mtmp
)->apport
);
398 } else if (mtmp
->mpeaceful
)
399 Strcat(info
, ", peaceful");
401 if (mtmp
->data
== &mons
[PM_LONG_WORM
]) {
402 int segndx
, nsegs
= count_wsegs(mtmp
);
404 /* the worm code internals don't consider the head of be one of
405 the worm's segments, but we count it as such when presenting
406 worm feedback to the player */
408 Strcat(info
, ", single segment");
410 ++nsegs
; /* include head in the segment count */
411 segndx
= wseg_at(mtmp
, bhitpos
.x
, bhitpos
.y
);
412 Sprintf(eos(info
), ", %d%s of %d segments",
413 segndx
, ordin(segndx
), nsegs
);
416 if (mtmp
->cham
>= LOW_PM
&& mtmp
->data
!= &mons
[mtmp
->cham
])
417 /* don't reveal the innate form (chameleon, vampire, &c),
418 just expose the fact that this current form isn't it */
419 Strcat(info
, ", shapechanger");
420 /* pets eating mimic corpses mimic while eating, so this comes first */
422 Strcat(info
, ", eating");
423 /* a stethoscope exposes mimic before getting here so this
424 won't be relevant for it, but wand of probing doesn't */
425 if (mtmp
->mundetected
|| mtmp
->m_ap_type
)
426 mhidden_description(mtmp
, TRUE
, eos(info
));
428 Strcat(info
, ", cancelled");
430 Strcat(info
, ", confused");
431 if (mtmp
->mblinded
|| !mtmp
->mcansee
)
432 Strcat(info
, ", blind");
434 Strcat(info
, ", stunned");
436 Strcat(info
, ", asleep");
437 #if 0 /* unfortunately mfrozen covers temporary sleep and being busy \
438 (donning armor, for instance) as well as paralysis */
439 else if (mtmp
->mfrozen
) Strcat(info
, ", paralyzed");
441 else if (mtmp
->mfrozen
|| !mtmp
->mcanmove
)
442 Strcat(info
, ", can't move");
444 /* [arbitrary reason why it isn't moving] */
445 else if (mtmp
->mstrategy
& STRAT_WAITMASK
)
446 Strcat(info
, ", meditating");
448 Strcat(info
, ", scared");
450 Strcat(info
, ", trapped");
452 Strcat(info
, mtmp
->mspeed
== MFAST
? ", fast" : mtmp
->mspeed
== MSLOW
456 Strcat(info
, ", invisible");
457 if (mtmp
== u
.ustuck
)
458 Strcat(info
, sticks(youmonst
.data
)
460 : !u
.uswallow
? ", holding you"
461 : attacktype_fordmg(u
.ustuck
->data
,
464 : is_animal(u
.ustuck
->data
)
466 : ", engulfing you");
467 if (mtmp
== u
.usteed
)
468 Strcat(info
, ", carrying you");
470 /* avoid "Status of the invisible newt ..., invisible" */
471 /* and unlike a normal mon_nam, use "saddled" even if it has a name */
472 Strcpy(monnambuf
, x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
473 (SUPPRESS_IT
| SUPPRESS_INVISIBLE
), FALSE
));
475 pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", monnambuf
,
476 align_str(alignment
), mtmp
->m_lev
, mtmp
->mhp
, mtmp
->mhpmax
,
477 find_mac(mtmp
), info
);
487 Strcat(info
, ", dying from");
488 if (u
.usick_type
& SICK_VOMITABLE
)
489 Strcat(info
, " food poisoning");
490 if (u
.usick_type
& SICK_NONVOMITABLE
) {
491 if (u
.usick_type
& SICK_VOMITABLE
)
492 Strcat(info
, " and");
493 Strcat(info
, " illness");
497 Strcat(info
, ", solidifying");
499 Strcat(info
, ", becoming slimy");
501 Strcat(info
, ", being strangled");
503 Strcat(info
, ", nauseated"); /* !"nauseous" */
505 Strcat(info
, ", confused");
507 Strcat(info
, ", blind");
509 if ((long) u
.ucreamed
< Blinded
|| Blindfolded
510 || !haseyes(youmonst
.data
))
511 Strcat(info
, ", cover");
512 Strcat(info
, "ed by sticky goop");
513 } /* note: "goop" == "glop"; variation is intentional */
516 Strcat(info
, ", stunned");
517 if (!u
.usteed
&& Wounded_legs
) {
518 const char *what
= body_part(LEG
);
519 if ((Wounded_legs
& BOTH_SIDES
) == BOTH_SIDES
)
520 what
= makeplural(what
);
521 Sprintf(eos(info
), ", injured %s", what
);
524 Sprintf(eos(info
), ", slippery %s", makeplural(body_part(HAND
)));
526 Strcat(info
, ", trapped");
528 Strcat(info
, Very_fast
? ", very fast" : ", fast");
530 Strcat(info
, ", concealed");
532 Strcat(info
, ", invisible");
534 if (sticks(youmonst
.data
))
535 Strcat(info
, ", holding ");
537 Strcat(info
, ", held by ");
538 Strcat(info
, mon_nam(u
.ustuck
));
541 pline("Status of %s (%s%s): Level %d HP %d(%d) AC %d%s.", plname
,
542 (u
.ualign
.record
>= 20)
544 : (u
.ualign
.record
> 13)
546 : (u
.ualign
.record
> 8)
548 : (u
.ualign
.record
> 3)
550 : (u
.ualign
.record
== 3)
552 : (u
.ualign
.record
>= 1)
554 : (u
.ualign
.record
== 0)
557 align_str(u
.ualign
.type
),
558 Upolyd
? mons
[u
.umonnum
].mlevel
: u
.ulevel
, Upolyd
? u
.mh
: u
.uhp
,
559 Upolyd
? u
.mhmax
: u
.uhpmax
, u
.uac
, info
);
566 Hallucination
? "Far out, man! You" : "Gee! All of a sudden, you",
567 See_invisible
? "can see right through yourself"
568 : "can't see yourself");
572 pudding_merge_message(otmp
, otmp2
)
577 cansee(otmp
->ox
, otmp
->oy
) || cansee(otmp2
->ox
, otmp2
->oy
);
578 boolean onfloor
= otmp
->where
== OBJ_FLOOR
|| otmp2
->where
== OBJ_FLOOR
;
579 boolean inpack
= carried(otmp
) || carried(otmp2
);
581 /* the player will know something happened inside his own inventory */
582 if ((!Blind
&& visible
) || inpack
) {
585 You_see("parts of the floor melting!");
587 Your("pack reaches out and grabs something!");
589 /* even though we can see where they should be,
590 * they'll be out of our view (minvent or container)
591 * so don't actually show anything */
592 } else if (onfloor
|| inpack
) {
593 pline("The %s coalesce%s.", makeplural(obj_typename(otmp
->otyp
)),
594 inpack
? " inside your pack" : "");
597 You_hear("a faint sloshing sound.");
601 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
602 static boolean use_pline_handler
= TRUE
;
604 execplinehandler(line
)
611 if (!use_pline_handler
)
614 if (!(env
= nh_getenv("NETHACK_MSGHANDLER"))) {
615 use_pline_handler
= FALSE
;
620 if (f
== 0) { /* child */
624 (void) setgid(getgid());
625 (void) setuid(getuid());
626 (void) execv(args
[0], (char *const *) args
);
628 (void) fprintf(stderr
, "Exec to message handler %s failed.\n",
630 terminate(EXIT_FAILURE
);
631 } else if (f
== -1) {
633 use_pline_handler
= FALSE
;
634 pline("Fork to message handler failed.");
637 #endif /* defined(POSIX_TYPES) || defined(__GNUC__) */