1 /*	SCCS Id: @(#)pline.c	3.4	1999/11/28	*/
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 #include "hack.h"
7 #include "epri.h"
8 #ifdef WIZARD
9 #include "edog.h"
10 #include "eshk.h"
11 #endif
12 
13 #ifdef OVLB
14 
15 static boolean no_repeat = FALSE;
16 
17 static char *FDECL(You_buf, (int));
18 
19 #if defined(DUMP_LOG) && defined(DUMPMSGS)
20 char msgs[DUMPMSGS][BUFSZ];
21 int lastmsg = -1;
22 #endif
23 
24 /*VARARGS1*/
25 /* Note that these declarations rely on knowledge of the internals
26  * of the variable argument handling stuff in "tradstdc.h"
27  */
28 
29 #if defined(USE_STDARG) || defined(USE_VARARGS)
30 static void FDECL(vpline, (const char *, va_list));
31 
32 void
33 pline VA_DECL(const char *, line)
34 	VA_START(line);
35 	VA_INIT(line, char *);
36 	vpline(line, VA_ARGS);
37 	VA_END();
38 }
39 
40 # ifdef USE_STDARG
41 static void
42 vpline(const char *line, va_list the_args) {
43 # else
44 static void
45 vpline(line, the_args) const char *line; va_list the_args; {
46 # endif
47 
48 #else	/* USE_STDARG | USE_VARARG */
49 
50 #define vpline pline
51 
52 void
53 pline VA_DECL(const char *, line)
54 #endif	/* USE_STDARG | USE_VARARG */
55 
56 	char pbuf[BUFSZ];
57 /* Do NOT use VA_START and VA_END in here... see above */
58 
59 	if (!line || !*line) return;
60 	if (index(line, '%')) {
61 	    Vsprintf(pbuf,line,VA_ARGS);
62 	    line = pbuf;
63 	}
64 #if defined(DUMP_LOG) && defined(DUMPMSGS)
65 	if (DUMPMSGS > 0 && !program_state.gameover) {
66 	  lastmsg = (lastmsg + 1) % DUMPMSGS;
67 	  strncpy(msgs[lastmsg], line, BUFSZ);
68 	}
69 #endif
70 	if (!iflags.window_inited) {
71 	    raw_print(line);
72 	    return;
73 	}
74 #ifndef MAC
75 	if (no_repeat && !strcmp(line, toplines))
76 	    return;
77 #endif /* MAC */
78 	if (vision_full_recalc) vision_recalc(0);
79 	if (u.ux) flush_screen(1);		/* %% */
80 	putstr(WIN_MESSAGE, 0, line);
81 }
82 
83 /*VARARGS1*/
84 void
85 Norep VA_DECL(const char *, line)
86 	VA_START(line);
87 	VA_INIT(line, const char *);
88 	no_repeat = TRUE;
89 	vpline(line, VA_ARGS);
90 	no_repeat = FALSE;
91 	VA_END();
92 	return;
93 }
94 
95 /* work buffer for You(), &c and verbalize() */
96 static char *you_buf = 0;
97 static int you_buf_siz = 0;
98 
99 static char *
100 You_buf(siz)
101 int siz;
102 {
103 	if (siz > you_buf_siz) {
104 		if (you_buf) free((genericptr_t) you_buf);
105 		you_buf_siz = siz + 10;
106 		you_buf = (char *) alloc((unsigned) you_buf_siz);
107 	}
108 	return you_buf;
109 }
110 
111 void
112 free_youbuf()
113 {
114 	if (you_buf) free((genericptr_t) you_buf),  you_buf = (char *)0;
115 	you_buf_siz = 0;
116 }
117 
118 /* `prefix' must be a string literal, not a pointer */
119 #define YouPrefix(pointer,prefix,text) \
120  Strcpy((pointer = You_buf((int)(strlen(text) + sizeof prefix))), prefix)
121 
122 #define YouMessage(pointer,prefix,text) \
123  strcat((YouPrefix(pointer, prefix, text), pointer), text)
124 
125 /*VARARGS1*/
126 void
127 You VA_DECL(const char *, line)
128 	char *tmp;
129 	VA_START(line);
130 	VA_INIT(line, const char *);
131 	vpline(YouMessage(tmp, "You ", line), VA_ARGS);
132 	VA_END();
133 }
134 
135 /*VARARGS1*/
136 void
137 Your VA_DECL(const char *,line)
138 	char *tmp;
139 	VA_START(line);
140 	VA_INIT(line, const char *);
141 	vpline(YouMessage(tmp, "Your ", line), VA_ARGS);
142 	VA_END();
143 }
144 
145 /*VARARGS1*/
146 void
147 You_feel VA_DECL(const char *,line)
148 	char *tmp;
149 	VA_START(line);
150 	VA_INIT(line, const char *);
151 	vpline(YouMessage(tmp, "You feel ", line), VA_ARGS);
152 	VA_END();
153 }
154 
155 
156 /*VARARGS1*/
157 void
158 You_cant VA_DECL(const char *,line)
159 	char *tmp;
160 	VA_START(line);
161 	VA_INIT(line, const char *);
162 	vpline(YouMessage(tmp, "You can't ", line), VA_ARGS);
163 	VA_END();
164 }
165 
166 /*VARARGS1*/
167 void
168 pline_The VA_DECL(const char *,line)
169 	char *tmp;
170 	VA_START(line);
171 	VA_INIT(line, const char *);
172 	vpline(YouMessage(tmp, "The ", line), VA_ARGS);
173 	VA_END();
174 }
175 
176 /*VARARGS1*/
177 void
178 There VA_DECL(const char *,line)
179 	char *tmp;
180 	VA_START(line);
181 	VA_INIT(line, const char *);
182 	vpline(YouMessage(tmp, "There ", line), VA_ARGS);
183 	VA_END();
184 }
185 
186 /*VARARGS1*/
187 void
188 You_hear VA_DECL(const char *,line)
189 	char *tmp;
190 	VA_START(line);
191 	VA_INIT(line, const char *);
192 	if (Underwater)
193 		YouPrefix(tmp, "You barely hear ", line);
194 	else if (u.usleep)
195 		YouPrefix(tmp, "You dream that you hear ", line);
196 	else
197 		YouPrefix(tmp, "You hear ", line);
198 	vpline(strcat(tmp, line), VA_ARGS);
199 	VA_END();
200 }
201 
202 /*VARARGS1*/
203 void
204 verbalize VA_DECL(const char *,line)
205 	char *tmp;
206 	if (!flags.soundok) return;
207 	VA_START(line);
208 	VA_INIT(line, const char *);
209 	tmp = You_buf((int)strlen(line) + sizeof "\"\"");
210 	Strcpy(tmp, "\"");
211 	Strcat(tmp, line);
212 	Strcat(tmp, "\"");
213 	vpline(tmp, VA_ARGS);
214 	VA_END();
215 }
216 
217 /*VARARGS1*/
218 /* Note that these declarations rely on knowledge of the internals
219  * of the variable argument handling stuff in "tradstdc.h"
220  */
221 
222 #if defined(USE_STDARG) || defined(USE_VARARGS)
223 static void FDECL(vraw_printf,(const char *,va_list));
224 
225 void
226 raw_printf VA_DECL(const char *, line)
227 	VA_START(line);
228 	VA_INIT(line, char *);
229 	vraw_printf(line, VA_ARGS);
230 	VA_END();
231 }
232 
233 # ifdef USE_STDARG
234 static void
235 vraw_printf(const char *line, va_list the_args) {
236 # else
237 static void
238 vraw_printf(line, the_args) const char *line; va_list the_args; {
239 # endif
240 
241 #else  /* USE_STDARG | USE_VARARG */
242 
243 void
244 raw_printf VA_DECL(const char *, line)
245 #endif
246 /* Do NOT use VA_START and VA_END in here... see above */
247 
248 	if(!index(line, '%'))
249 	    raw_print(line);
250 	else {
251 	    char pbuf[BUFSZ];
252 	    Vsprintf(pbuf,line,VA_ARGS);
253 	    raw_print(pbuf);
254 	}
255 }
256 
257 
258 /*VARARGS1*/
259 void
260 impossible VA_DECL(const char *, s)
261 	VA_START(s);
262 	VA_INIT(s, const char *);
263 	if (program_state.in_impossible)
264 		panic("impossible called impossible");
265 	program_state.in_impossible = 1;
266 	{
267 	    char pbuf[BUFSZ];
268 	    Vsprintf(pbuf,s,VA_ARGS);
269 	    paniclog("impossible", pbuf);
270 	}
271 	vpline(s,VA_ARGS);
272 	pline("Program in disorder; you probably should S)ave and restart the process.");
273 	program_state.in_impossible = 0;
274 	VA_END();
275 }
276 
277 void
278 warning VA_DECL(const char *, s)
279 	char str[BUFSZ];
280 	VA_START(s);
281 	VA_INIT(s, const char *);
282 	{
283 	    char pbuf[BUFSZ];
284 	    Vsprintf(pbuf,s,VA_ARGS);
285 	    paniclog("warning", pbuf);
286 	}
287 	Vsprintf(str,s,VA_ARGS);
288 	pline("Warning: %s\n", str);
289 	VA_END();
290 }
291 
292 const char *
293 align_str(alignment)
294     aligntyp alignment;
295 {
296     switch ((int)alignment) {
297 	case A_CHAOTIC: return "chaotic";
298 	case A_NEUTRAL: return "neutral";
299 	case A_LAWFUL:	return "lawful";
300 	case A_NONE:	return "unaligned";
301     }
302     return "unknown";
303 }
304 
305 void
306 mstatusline(mtmp)
307 register struct monst *mtmp;
308 {
309 	aligntyp alignment;
310 	char info[BUFSZ], monnambuf[BUFSZ];
311 
312 	if (mtmp->ispriest || mtmp->data == &mons[PM_ALIGNED_PRIEST]
313 				|| mtmp->data == &mons[PM_ANGEL])
314 		alignment = EPRI(mtmp)->shralign;
315 	else
316 		alignment = mtmp->data->maligntyp;
317 	alignment = (alignment > 0) ? A_LAWFUL :
318 		(alignment < 0) ? A_CHAOTIC :
319 		A_NEUTRAL;
320 
321 	info[0] = 0;
322 	if (mtmp->mtame) {	  Strcat(info, ", tame");
323 #ifdef WIZARD
324 	    if (wizard) {
325 		Sprintf(eos(info), " (%d", mtmp->mtame);
326 		if (!mtmp->isminion)
327 		    Sprintf(eos(info), "; hungry %ld; apport %d",
328 			EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
329 		Strcat(info, ")");
330 	    }
331 #endif
332 	}
333 	else if (mtmp->mpeaceful) Strcat(info, ", peaceful");
334 	if (mtmp->meating)	  Strcat(info, ", eating");
335 	if (mtmp->mcan)		  Strcat(info, ", cancelled");
336 	if (mtmp->mconf)	  Strcat(info, ", confused");
337 	if (mtmp->mblinded || !mtmp->mcansee)
338 				  Strcat(info, ", blind");
339 	if (mtmp->mstun)	  Strcat(info, ", stunned");
340 	if (mtmp->msleeping)	  Strcat(info, ", asleep");
341 #if 0	/* unfortunately mfrozen covers temporary sleep and being busy
342 	   (donning armor, for instance) as well as paralysis */
343 	else if (mtmp->mfrozen)	  Strcat(info, ", paralyzed");
344 #else
345 	else if (mtmp->mfrozen || !mtmp->mcanmove)
346 				  Strcat(info, ", can't move");
347 #endif
348 				  /* [arbitrary reason why it isn't moving] */
349 	else if (mtmp->mstrategy & STRAT_WAITMASK)
350 				  Strcat(info, ", meditating");
351 	else if (mtmp->mflee)	  Strcat(info, ", scared");
352 	if (mtmp->mtrapped)	  Strcat(info, ", trapped");
353 	if (mtmp->mspeed)	  Strcat(info,
354 					mtmp->mspeed == MFAST ? ", fast" :
355 					mtmp->mspeed == MSLOW ? ", slow" :
356 					", ???? speed");
357 	if (mtmp->mundetected)	  Strcat(info, ", concealed");
358 	if (mtmp->minvis)	  Strcat(info, ", invisible");
359 	if (mtmp == u.ustuck)	  Strcat(info,
360 			(sticks(youmonst.data)) ? ", held by you" :
361 				u.uswallow ? (is_animal(u.ustuck->data) ?
362 				", swallowed you" :
363 				", engulfed you") :
364 				", holding you");
365 #ifdef STEED
366 	if (mtmp == u.usteed)	  Strcat(info, ", carrying you");
367 #endif
368 #ifdef WIZARD
369 	if (wizard &&
370 	    mtmp->isshk && ESHK(mtmp)->cheapskate) {
371 		Strcat(info, ", cheapskate");
372 	}
373 #endif
374 
375 	/* avoid "Status of the invisible newt ..., invisible" */
376 	/* and unlike a normal mon_nam, use "saddled" even if it has a name */
377 	Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *)0,
378 	    (SUPPRESS_IT|SUPPRESS_INVISIBLE), FALSE));
379 
380 	pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.",
381 		monnambuf,
382 		align_str(alignment),
383 		mtmp->m_lev,
384 		mtmp->mhp,
385 		mtmp->mhpmax,
386 		find_mac(mtmp),
387 		info);
388 }
389 
390 void
391 ustatusline()
392 {
393 	char info[BUFSZ];
394 
395 	info[0] = '\0';
396 	if (Sick) {
397 		Strcat(info, ", dying from");
398 		if (u.usick_type & SICK_VOMITABLE)
399 			Strcat(info, " food poisoning");
400 		if (u.usick_type & SICK_NONVOMITABLE) {
401 			if (u.usick_type & SICK_VOMITABLE)
402 				Strcat(info, " and");
403 			Strcat(info, " illness");
404 		}
405 	}
406 	if (Stoned)		Strcat(info, ", solidifying");
407 	if (Slimed)		Strcat(info, ", becoming slimy");
408 	if (Strangled)		Strcat(info, ", being strangled");
409 	if (Vomiting)		Strcat(info, ", nauseated"); /* !"nauseous" */
410 	if (Confusion)		Strcat(info, ", confused");
411 	if (Blind) {
412 	    Strcat(info, ", blind");
413 	    if (u.ucreamed) {
414 		if ((long)u.ucreamed < Blinded || Blindfolded
415 						|| !haseyes(youmonst.data))
416 		    Strcat(info, ", cover");
417 		Strcat(info, "ed by sticky goop");
418 	    }	/* note: "goop" == "glop"; variation is intentional */
419 	}
420 	if (Stunned)		Strcat(info, ", stunned");
421 #ifdef STEED
422 	if (!u.usteed)
423 #endif
424 	if (Wounded_legs) {
425 	    const char *what = body_part(LEG);
426 	    if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
427 		what = makeplural(what);
428 				Sprintf(eos(info), ", injured %s", what);
429 	}
430 	if (Glib)		Sprintf(eos(info), ", slippery %s",
431 					makeplural(body_part(HAND)));
432 	if (u.utrap)		Strcat(info, ", trapped");
433 	if (Fast)		Strcat(info, Very_fast ?
434 						", very fast" : ", fast");
435 	if (u.uundetected)	Strcat(info, ", concealed");
436 	if (Invis)		Strcat(info, ", invisible");
437 	if (u.ustuck) {
438 	    if (sticks(youmonst.data))
439 		Strcat(info, ", holding ");
440 	    else
441 		Strcat(info, ", held by ");
442 	    Strcat(info, mon_nam(u.ustuck));
443 	}
444 
445 	pline("Status of %s (%s%s):  Level %d  HP %d(%d)  AC %d%s.",
446 		plname,
447 		    (u.ualign.record >= 20) ? "piously " :
448 		    (u.ualign.record > 13) ? "devoutly " :
449 		    (u.ualign.record > 8) ? "fervently " :
450 		    (u.ualign.record > 3) ? "stridently " :
451 		    (u.ualign.record == 3) ? "" :
452 		    (u.ualign.record >= 1) ? "haltingly " :
453 		    (u.ualign.record == 0) ? "nominally " :
454 					    "insufficiently ",
455 		align_str(u.ualign.type),
456 		Upolyd ? mons[u.umonnum].mlevel : u.ulevel,
457 		Upolyd ? u.mh : u.uhp,
458 		Upolyd ? u.mhmax : u.uhpmax,
459 		u.uac,
460 		info);
461 }
462 
463 void
464 self_invis_message()
465 {
466 	pline("%s %s.",
467 	    Hallucination ? "Far out, man!  You" : "Gee!  All of a sudden, you",
468 	    See_invisible ? "can see right through yourself" :
469 		"can't see yourself");
470 }
471 
472 #endif /* OVLB */
473 /*pline.c*/
474