OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / pline.c
1 /* NetHack 3.6  pline.c $NHDT-Date: 1432512770 2015/05/25 00:12:50 $  $NHDT-Branch: master $:$NHDT-Revision: 1.42 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers \
6                                        */
7 #include "hack.h"
8
9 static boolean no_repeat = FALSE;
10 static char prevmsg[BUFSZ];
11
12 static char *FDECL(You_buf, (int));
13
14 /*VARARGS1*/
15 /* Note that these declarations rely on knowledge of the internals
16  * of the variable argument handling stuff in "tradstdc.h"
17  */
18
19 #if defined(USE_STDARG) || defined(USE_VARARGS)
20 static void FDECL(vpline, (const char *, va_list));
21
22 void pline
23 VA_DECL(const char *, line)
24 {
25     VA_START(line);
26     VA_INIT(line, char *);
27     vpline(line, VA_ARGS);
28     VA_END();
29 }
30
31 # ifdef USE_STDARG
32 static void
33 vpline(const char *line, va_list the_args)
34 # else
35 static void
36 vpline(line, the_args)
37 const char *line;
38 va_list the_args;
39 # endif
40
41 #else /* USE_STDARG | USE_VARARG */
42
43 # define vpline pline
44
45 void pline
46 VA_DECL(const char *, line)
47 #endif /* USE_STDARG | USE_VARARG */
48 {       /* start of vpline() or of nested block in USE_OLDARG's pline() */
49     char pbuf[3 * BUFSZ];
50     int ln;
51     xchar msgtyp;
52     /* Do NOT use VA_START and VA_END in here... see above */
53
54     if (!line || !*line)
55         return;
56 #ifdef HANGUPHANDLING
57     if (program_state.done_hup)
58         return;
59 #endif
60     if (program_state.wizkit_wishing)
61         return;
62
63     if (index(line, '%')) {
64         Vsprintf(pbuf, line, VA_ARGS);
65         line = pbuf;
66     }
67     if ((ln = (int) strlen(line)) > BUFSZ - 1) {
68         if (line != pbuf)                          /* no '%' was present */
69             (void) strncpy(pbuf, line, BUFSZ - 1); /* caveat: unterminated */
70         /* truncate, preserving the final 3 characters:
71            "___ extremely long text" -> "___ extremely l...ext"
72            (this may be suboptimal if overflow is less than 3) */
73         (void) strncpy(pbuf + BUFSZ - 1 - 6, "...", 3);
74         /* avoid strncpy; buffers could overlap if excess is small */
75         pbuf[BUFSZ - 1 - 3] = line[ln - 3];
76         pbuf[BUFSZ - 1 - 2] = line[ln - 2];
77         pbuf[BUFSZ - 1 - 1] = line[ln - 1];
78         pbuf[BUFSZ - 1] = '\0';
79         line = pbuf;
80     }
81     if (!iflags.window_inited) {
82         raw_print(line);
83         iflags.last_msg = PLNMSG_UNKNOWN;
84         return;
85     }
86 #ifndef MAC
87     if (no_repeat && !strcmp(line, toplines))
88         return;
89 #endif /* MAC */
90     if (vision_full_recalc)
91         vision_recalc(0);
92     if (u.ux)
93         flush_screen(1); /* %% */
94     msgtyp = msgtype_type(line);
95     if (msgtyp == MSGTYP_NOSHOW) return;
96     if (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg)) return;
97     putstr(WIN_MESSAGE, 0, line);
98     /* this gets cleared after every pline message */
99     iflags.last_msg = PLNMSG_UNKNOWN;
100     strncpy(prevmsg, line, BUFSZ);
101     if (msgtyp == MSGTYP_STOP) display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */
102
103 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
104     /* provide closing brace for the nested block
105        which immediately follows USE_OLDARGS's VA_DECL() */
106     VA_END();
107 #endif
108 }
109
110 /*VARARGS1*/
111 void Norep
112 VA_DECL(const char *, line)
113 {
114     VA_START(line);
115     VA_INIT(line, const char *);
116     no_repeat = TRUE;
117     vpline(line, VA_ARGS);
118     no_repeat = FALSE;
119     VA_END();
120     return;
121 }
122
123 /* work buffer for You(), &c and verbalize() */
124 static char *you_buf = 0;
125 static int you_buf_siz = 0;
126
127 static char *
128 You_buf(siz)
129 int siz;
130 {
131     if (siz > you_buf_siz) {
132         if (you_buf)
133             free((genericptr_t) you_buf);
134         you_buf_siz = siz + 10;
135         you_buf = (char *) alloc((unsigned) you_buf_siz);
136     }
137     return you_buf;
138 }
139
140 void
141 free_youbuf()
142 {
143     if (you_buf)
144         free((genericptr_t) you_buf), you_buf = (char *) 0;
145     you_buf_siz = 0;
146 }
147
148 /* `prefix' must be a string literal, not a pointer */
149 #define YouPrefix(pointer, prefix, text) \
150     Strcpy((pointer = You_buf((int) (strlen(text) + sizeof prefix))), prefix)
151
152 #define YouMessage(pointer, prefix, text) \
153     strcat((YouPrefix(pointer, prefix, text), pointer), text)
154
155 /*VARARGS1*/
156 void You
157 VA_DECL(const char *, line)
158 {
159     char *tmp;
160     VA_START(line);
161     VA_INIT(line, const char *);
162     vpline(YouMessage(tmp, "You ", line), VA_ARGS);
163     VA_END();
164 }
165
166 /*VARARGS1*/
167 void Your
168 VA_DECL(const char *, line)
169 {
170     char *tmp;
171     VA_START(line);
172     VA_INIT(line, const char *);
173     vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
174     VA_END();
175 }
176
177 /*VARARGS1*/
178 void You_feel
179 VA_DECL(const char *, line)
180 {
181     char *tmp;
182     VA_START(line);
183     VA_INIT(line, const char *);
184     if (Unaware)
185         YouPrefix(tmp, "You dream that you feel ", line);
186     else
187         YouPrefix(tmp, "You feel ", line);
188     vpline(strcat(tmp, line), VA_ARGS);
189     VA_END();
190 }
191
192 /*VARARGS1*/
193 void You_cant
194 VA_DECL(const char *, line)
195 {
196     char *tmp;
197     VA_START(line);
198     VA_INIT(line, const char *);
199     vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
200     VA_END();
201 }
202
203 /*VARARGS1*/
204 void pline_The
205 VA_DECL(const char *, line)
206 {
207     char *tmp;
208     VA_START(line);
209     VA_INIT(line, const char *);
210     vpline(YouMessage(tmp, "The ", line), VA_ARGS);
211     VA_END();
212 }
213
214 /*VARARGS1*/
215 void There
216 VA_DECL(const char *, line)
217 {
218     char *tmp;
219     VA_START(line);
220     VA_INIT(line, const char *);
221     vpline(YouMessage(tmp, "There ", line), VA_ARGS);
222     VA_END();
223 }
224
225 /*VARARGS1*/
226 void You_hear
227 VA_DECL(const char *, line)
228 {
229     char *tmp;
230
231     if (Deaf || !flags.acoustics)
232         return;
233     VA_START(line);
234     VA_INIT(line, const char *);
235     if (Underwater)
236         YouPrefix(tmp, "You barely hear ", line);
237     else if (Unaware)
238         YouPrefix(tmp, "You dream that you hear ", line);
239     else
240         YouPrefix(tmp, "You hear ", line);
241     vpline(strcat(tmp, line), VA_ARGS);
242     VA_END();
243 }
244
245 /*VARARGS1*/
246 void You_see
247 VA_DECL(const char *, line)
248 {
249     char *tmp;
250
251     VA_START(line);
252     VA_INIT(line, const char *);
253     if (Unaware)
254         YouPrefix(tmp, "You dream that you see ", line);
255     else if (Blind) /* caller should have caught this... */
256         YouPrefix(tmp, "You sense ", line);
257     else
258         YouPrefix(tmp, "You see ", line);
259     vpline(strcat(tmp, line), VA_ARGS);
260     VA_END();
261 }
262
263 /* Print a message inside double-quotes.
264  * The caller is responsible for checking deafness.
265  * Gods can speak directly to you in spite of deafness.
266  */
267 /*VARARGS1*/
268 void verbalize
269 VA_DECL(const char *, line)
270 {
271     char *tmp;
272
273     VA_START(line);
274     VA_INIT(line, const char *);
275     tmp = You_buf((int) strlen(line) + sizeof "\"\"");
276     Strcpy(tmp, "\"");
277     Strcat(tmp, line);
278     Strcat(tmp, "\"");
279     vpline(tmp, VA_ARGS);
280     VA_END();
281 }
282
283 /*VARARGS1*/
284 /* Note that these declarations rely on knowledge of the internals
285  * of the variable argument handling stuff in "tradstdc.h"
286  */
287
288 #if defined(USE_STDARG) || defined(USE_VARARGS)
289 static void FDECL(vraw_printf, (const char *, va_list));
290
291 void raw_printf
292 VA_DECL(const char *, line)
293 {
294     VA_START(line);
295     VA_INIT(line, char *);
296     vraw_printf(line, VA_ARGS);
297     VA_END();
298 }
299
300 # ifdef USE_STDARG
301 static void
302 vraw_printf(const char *line, va_list the_args)
303 # else
304 static void
305 vraw_printf(line, the_args)
306 const char *line;
307 va_list the_args;
308 # endif
309
310 #else /* USE_STDARG | USE_VARARG */
311
312 void raw_printf
313 VA_DECL(const char *, line)
314 #endif
315 {
316     char pbuf[3 * BUFSZ];
317     int ln;
318     /* Do NOT use VA_START and VA_END in here... see above */
319
320     if (index(line, '%')) {
321         Vsprintf(pbuf, line, VA_ARGS);
322         line = pbuf;
323     }
324     if ((ln = (int) strlen(line)) > BUFSZ - 1) {
325         if (line != pbuf)
326             line = strncpy(pbuf, line, BUFSZ - 1);
327         /* unlike pline, we don't futz around to keep last few chars */
328         pbuf[BUFSZ - 1] = '\0'; /* terminate strncpy or truncate vsprintf */
329     }
330     raw_print(line);
331 #if !(defined(USE_STDARG) || defined(USE_VARARGS))
332     VA_END(); /* (see vpline) */
333 #endif
334 }
335
336 /*VARARGS1*/
337 void impossible
338 VA_DECL(const char *, s)
339 {
340     char pbuf[2 * BUFSZ];
341     VA_START(s);
342     VA_INIT(s, const char *);
343     if (program_state.in_impossible)
344         panic("impossible called impossible");
345
346     program_state.in_impossible = 1;
347     Vsprintf(pbuf, s, VA_ARGS);
348     pbuf[BUFSZ - 1] = '\0'; /* sanity */
349     paniclog("impossible", pbuf);
350     pline("%s", pbuf);
351     pline("Program in disorder - perhaps you'd better #quit.");
352     program_state.in_impossible = 0;
353     VA_END();
354 }
355
356 const char *
357 align_str(alignment)
358 aligntyp alignment;
359 {
360     switch ((int) alignment) {
361     case A_CHAOTIC:
362         return "chaotic";
363     case A_NEUTRAL:
364         return "neutral";
365     case A_LAWFUL:
366         return "lawful";
367     case A_NONE:
368         return "unaligned";
369     }
370     return "unknown";
371 }
372
373 void
374 mstatusline(mtmp)
375 register struct monst *mtmp;
376 {
377     aligntyp alignment = mon_aligntyp(mtmp);
378     char info[BUFSZ], monnambuf[BUFSZ];
379
380     info[0] = 0;
381     if (mtmp->mtame) {
382         Strcat(info, ", tame");
383         if (wizard) {
384             Sprintf(eos(info), " (%d", mtmp->mtame);
385             if (!mtmp->isminion)
386                 Sprintf(eos(info), "; hungry %ld; apport %d",
387                         EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
388             Strcat(info, ")");
389         }
390     } else if (mtmp->mpeaceful)
391         Strcat(info, ", peaceful");
392     if (mtmp->cham >= LOW_PM && mtmp->data != &mons[mtmp->cham])
393         /* don't reveal the innate form (chameleon, vampire, &c),
394            just expose the fact that this current form isn't it */
395         Strcat(info, ", shapechanger");
396     /* pets eating mimic corpses mimic while eating, so this comes first */
397     if (mtmp->meating)
398         Strcat(info, ", eating");
399     /* a stethoscope exposes mimic before getting here so this
400        won't be relevant for it, but wand of probing doesn't */
401     if (mtmp->m_ap_type)
402         Sprintf(eos(info), ", mimicking %s",
403                 (mtmp->m_ap_type == M_AP_FURNITURE)
404                     ? an(defsyms[mtmp->mappearance].explanation)
405                     : (mtmp->m_ap_type == M_AP_OBJECT)
406                           ? ((mtmp->mappearance == GOLD_PIECE)
407                                  ? "gold"
408                                  : an(simple_typename(mtmp->mappearance)))
409                           : (mtmp->m_ap_type == M_AP_MONSTER)
410                                 ? an(mons[mtmp->mappearance].mname)
411                                 : something); /* impossible... */
412     if (mtmp->mcan)
413         Strcat(info, ", cancelled");
414     if (mtmp->mconf)
415         Strcat(info, ", confused");
416     if (mtmp->mblinded || !mtmp->mcansee)
417         Strcat(info, ", blind");
418     if (mtmp->mstun)
419         Strcat(info, ", stunned");
420     if (mtmp->msleeping)
421         Strcat(info, ", asleep");
422 #if 0 /* unfortunately mfrozen covers temporary sleep and being busy \
423          (donning armor, for instance) as well as paralysis */
424         else if (mtmp->mfrozen)   Strcat(info, ", paralyzed");
425 #else
426     else if (mtmp->mfrozen || !mtmp->mcanmove)
427         Strcat(info, ", can't move");
428 #endif
429     /* [arbitrary reason why it isn't moving] */
430     else if (mtmp->mstrategy & STRAT_WAITMASK)
431         Strcat(info, ", meditating");
432     if (mtmp->mflee)
433         Strcat(info, ", scared");
434     if (mtmp->mtrapped)
435         Strcat(info, ", trapped");
436     if (mtmp->mspeed)
437         Strcat(info, mtmp->mspeed == MFAST ? ", fast" : mtmp->mspeed == MSLOW
438                                                             ? ", slow"
439                                                             : ", ???? speed");
440     if (mtmp->mundetected)
441         Strcat(info, ", concealed");
442     if (mtmp->minvis)
443         Strcat(info, ", invisible");
444     if (mtmp == u.ustuck)
445         Strcat(info, sticks(youmonst.data)
446                          ? ", held by you"
447                          : !u.uswallow ? ", holding you"
448                                        : attacktype_fordmg(u.ustuck->data,
449                                                            AT_ENGL, AD_DGST)
450                                              ? ", digesting you"
451                                              : is_animal(u.ustuck->data)
452                                                    ? ", swallowing you"
453                                                    : ", engulfing you");
454     if (mtmp == u.usteed)
455         Strcat(info, ", carrying you");
456
457     /* avoid "Status of the invisible newt ..., invisible" */
458     /* and unlike a normal mon_nam, use "saddled" even if it has a name */
459     Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *) 0,
460                                (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE));
461
462     pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", monnambuf,
463           align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax,
464           find_mac(mtmp), info);
465 }
466
467 void
468 ustatusline()
469 {
470     char info[BUFSZ];
471
472     info[0] = '\0';
473     if (Sick) {
474         Strcat(info, ", dying from");
475         if (u.usick_type & SICK_VOMITABLE)
476             Strcat(info, " food poisoning");
477         if (u.usick_type & SICK_NONVOMITABLE) {
478             if (u.usick_type & SICK_VOMITABLE)
479                 Strcat(info, " and");
480             Strcat(info, " illness");
481         }
482     }
483     if (Stoned)
484         Strcat(info, ", solidifying");
485     if (Slimed)
486         Strcat(info, ", becoming slimy");
487     if (Strangled)
488         Strcat(info, ", being strangled");
489     if (Vomiting)
490         Strcat(info, ", nauseated"); /* !"nauseous" */
491     if (Confusion)
492         Strcat(info, ", confused");
493     if (Blind) {
494         Strcat(info, ", blind");
495         if (u.ucreamed) {
496             if ((long) u.ucreamed < Blinded || Blindfolded
497                 || !haseyes(youmonst.data))
498                 Strcat(info, ", cover");
499             Strcat(info, "ed by sticky goop");
500         } /* note: "goop" == "glop"; variation is intentional */
501     }
502     if (Stunned)
503         Strcat(info, ", stunned");
504     if (!u.usteed && Wounded_legs) {
505         const char *what = body_part(LEG);
506         if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
507             what = makeplural(what);
508         Sprintf(eos(info), ", injured %s", what);
509     }
510     if (Glib)
511         Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND)));
512     if (u.utrap)
513         Strcat(info, ", trapped");
514     if (Fast)
515         Strcat(info, Very_fast ? ", very fast" : ", fast");
516     if (u.uundetected)
517         Strcat(info, ", concealed");
518     if (Invis)
519         Strcat(info, ", invisible");
520     if (u.ustuck) {
521         if (sticks(youmonst.data))
522             Strcat(info, ", holding ");
523         else
524             Strcat(info, ", held by ");
525         Strcat(info, mon_nam(u.ustuck));
526     }
527
528     pline("Status of %s (%s%s):  Level %d  HP %d(%d)  AC %d%s.", plname,
529           (u.ualign.record >= 20)
530               ? "piously "
531               : (u.ualign.record > 13)
532                     ? "devoutly "
533                     : (u.ualign.record > 8)
534                           ? "fervently "
535                           : (u.ualign.record > 3)
536                                 ? "stridently "
537                                 : (u.ualign.record == 3)
538                                       ? ""
539                                       : (u.ualign.record >= 1)
540                                             ? "haltingly "
541                                             : (u.ualign.record == 0)
542                                                   ? "nominally "
543                                                   : "insufficiently ",
544           align_str(u.ualign.type),
545           Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp,
546           Upolyd ? u.mhmax : u.uhpmax, u.uac, info);
547 }
548
549 void
550 self_invis_message()
551 {
552     pline("%s %s.",
553           Hallucination ? "Far out, man!  You" : "Gee!  All of a sudden, you",
554           See_invisible ? "can see right through yourself"
555                         : "can't see yourself");
556 }
557
558 void
559 pudding_merge_message(otmp, otmp2)
560 struct obj *otmp;
561 struct obj *otmp2;
562 {
563     boolean visible =
564         cansee(otmp->ox, otmp->oy) || cansee(otmp2->ox, otmp2->oy);
565     boolean onfloor = otmp->where == OBJ_FLOOR || otmp2->where == OBJ_FLOOR;
566     boolean inpack = carried(otmp) || carried(otmp2);
567
568     /* the player will know something happened inside his own inventory */
569     if ((!Blind && visible) || inpack) {
570         if (Hallucination) {
571             if (onfloor) {
572                 You_see("parts of the floor melting!");
573             } else if (inpack) {
574                 Your("pack reaches out and grabs something!");
575             }
576             /* even though we can see where they should be,
577              * they'll be out of our view (minvent or container)
578              * so don't actually show anything */
579         } else if (onfloor || inpack) {
580             pline("The %s coalesce%s.", makeplural(obj_typename(otmp->otyp)),
581                   inpack ? " inside your pack" : "");
582         }
583     } else {
584         You_hear("a faint sloshing sound.");
585     }
586 }
587
588 /*pline.c*/