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