Mercurial > hg > early-roguelike
comparison arogue5/sticks.c @ 63:0ed67132cf10
Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
| author | elwin |
|---|---|
| date | Thu, 09 Aug 2012 22:58:48 +0000 |
| parents | |
| children | c49f7927b0fa |
comparison
equal
deleted
inserted
replaced
| 62:0ef99244acb8 | 63:0ed67132cf10 |
|---|---|
| 1 /* | |
| 2 * Functions to implement the various sticks one might find | |
| 3 * while wandering around the dungeon. | |
| 4 * | |
| 5 * Advanced Rogue | |
| 6 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T | |
| 7 * All rights reserved. | |
| 8 * | |
| 9 * Based on "Rogue: Exploring the Dungeons of Doom" | |
| 10 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
| 11 * All rights reserved. | |
| 12 * | |
| 13 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 14 */ | |
| 15 | |
| 16 #include "curses.h" | |
| 17 #include <ctype.h> | |
| 18 #include "rogue.h" | |
| 19 | |
| 20 | |
| 21 /* | |
| 22 * zap a stick and see what happens | |
| 23 */ | |
| 24 do_zap(gotdir, which, flag) | |
| 25 bool gotdir; | |
| 26 int which; | |
| 27 int flag; | |
| 28 { | |
| 29 register struct linked_list *item; | |
| 30 register struct object *obj = NULL; | |
| 31 register struct thing *tp; | |
| 32 register int y, x; | |
| 33 struct linked_list *nitem; | |
| 34 struct object *nobj; | |
| 35 bool cursed, blessed, is_stick; | |
| 36 | |
| 37 blessed = FALSE; | |
| 38 cursed = FALSE; | |
| 39 is_stick = FALSE; | |
| 40 | |
| 41 if (which == 0) { | |
| 42 if ((item = get_item(pack, "zap with", ZAPPABLE)) == NULL) | |
| 43 return(FALSE); | |
| 44 obj = OBJPTR(item); | |
| 45 | |
| 46 /* Handle relics specially here */ | |
| 47 if (obj->o_type == RELIC) { | |
| 48 switch (obj->o_which) { | |
| 49 case ORCUS_WAND: | |
| 50 msg(nothing); | |
| 51 return(TRUE); | |
| 52 when MING_STAFF: | |
| 53 which = WS_MISSILE; | |
| 54 when ASMO_ROD: | |
| 55 switch (rnd(3)) { | |
| 56 case 0: | |
| 57 which = WS_ELECT; | |
| 58 when 1: | |
| 59 which = WS_COLD; | |
| 60 otherwise: | |
| 61 which = WS_FIRE; | |
| 62 } | |
| 63 } | |
| 64 cursed = FALSE; | |
| 65 blessed = FALSE; | |
| 66 } | |
| 67 else { | |
| 68 which = obj->o_which; | |
| 69 ws_know[which] = TRUE; | |
| 70 cursed = (obj->o_flags & ISCURSED) != 0; | |
| 71 blessed = (obj->o_flags & ISBLESSED) != 0; | |
| 72 is_stick = TRUE; | |
| 73 } | |
| 74 } | |
| 75 else { | |
| 76 cursed = flag & ISCURSED; | |
| 77 blessed = flag & ISBLESSED; | |
| 78 } | |
| 79 switch (which) { /* no direction for these */ | |
| 80 case WS_LIGHT: | |
| 81 case WS_DRAIN: | |
| 82 case WS_CHARGE: | |
| 83 case WS_CURING: | |
| 84 break; | |
| 85 | |
| 86 default: | |
| 87 if (!get_dir()) | |
| 88 return(FALSE); | |
| 89 if (!gotdir) { | |
| 90 do { | |
| 91 delta.y = rnd(3) - 1; | |
| 92 delta.x = rnd(3) - 1; | |
| 93 } while (delta.y == 0 && delta.x == 0); | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 if (is_stick) { | |
| 98 if (obj->o_charges < 1) { | |
| 99 msg(nothing); | |
| 100 return(TRUE); | |
| 101 } | |
| 102 obj->o_charges--; | |
| 103 } | |
| 104 if (which == WS_WONDER) { | |
| 105 switch (rnd(14)) { | |
| 106 case 0: which = WS_ELECT; | |
| 107 when 1: which = WS_FIRE; | |
| 108 when 2: which = WS_COLD; | |
| 109 when 3: which = WS_POLYMORPH; | |
| 110 when 4: which = WS_MISSILE; | |
| 111 when 5: which = WS_SLOW_M; | |
| 112 when 6: which = WS_TELMON; | |
| 113 when 7: which = WS_CANCEL; | |
| 114 when 8: which = WS_CONFMON; | |
| 115 when 9: which = WS_DISINTEGRATE; | |
| 116 when 10: which = WS_PETRIFY; | |
| 117 when 11: which = WS_PARALYZE; | |
| 118 when 12: which = WS_MDEG; | |
| 119 when 13: which = WS_FEAR; | |
| 120 } | |
| 121 if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){ | |
| 122 cursed = TRUE; | |
| 123 blessed = FALSE; | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 switch (which) { | |
| 128 case WS_LIGHT: | |
| 129 /* | |
| 130 * Reddy Kilowat wand. Light up the room | |
| 131 */ | |
| 132 blue_light(blessed, cursed); | |
| 133 when WS_DRAIN: | |
| 134 /* | |
| 135 * Take away 1/2 of hero's hit points, then take it away | |
| 136 * evenly from the monsters in the room or next to hero | |
| 137 * if he is in a passage (but leave the monsters alone | |
| 138 * if the stick is cursed) | |
| 139 */ | |
| 140 if (pstats.s_hpt < 2) { | |
| 141 msg("You are too weak to use it."); | |
| 142 return(TRUE); | |
| 143 } | |
| 144 if (cursed) | |
| 145 pstats.s_hpt /= 2; | |
| 146 else | |
| 147 drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1); | |
| 148 when WS_POLYMORPH: | |
| 149 case WS_TELMON: | |
| 150 case WS_CANCEL: | |
| 151 { | |
| 152 register char monster, oldch; | |
| 153 register int rm; | |
| 154 | |
| 155 y = hero.y; | |
| 156 x = hero.x; | |
| 157 while (shoot_ok(winat(y, x))) { | |
| 158 y += delta.y; | |
| 159 x += delta.x; | |
| 160 } | |
| 161 if (isalpha(monster = CCHAR( mvwinch(mw, y, x) ))) { | |
| 162 register struct room *rp; | |
| 163 | |
| 164 item = find_mons(y, x); | |
| 165 tp = THINGPTR(item); | |
| 166 /* if the monster gets the saving throw, leave the case */ | |
| 167 if (save(VS_MAGIC, tp, 0)) { | |
| 168 msg(nothing); | |
| 169 break; | |
| 170 } | |
| 171 | |
| 172 /* Unhold player */ | |
| 173 if (on(*tp, DIDHOLD)) { | |
| 174 turn_off(*tp, DIDHOLD); | |
| 175 if (--hold_count == 0) turn_off(player, ISHELD); | |
| 176 } | |
| 177 /* unsuffocate player */ | |
| 178 if (on(*tp, DIDSUFFOCATE)) { | |
| 179 turn_off(*tp, DIDSUFFOCATE); | |
| 180 extinguish(suffocate); | |
| 181 } | |
| 182 rp = roomin(&tp->t_pos); | |
| 183 /* | |
| 184 * check to see if room should go dark | |
| 185 */ | |
| 186 if (on(*tp, HASFIRE)) { | |
| 187 if (rp != NULL) { | |
| 188 register struct linked_list *fire_item; | |
| 189 | |
| 190 for (fire_item = rp->r_fires; fire_item != NULL; | |
| 191 fire_item = next(fire_item)) { | |
| 192 if (THINGPTR(fire_item) == tp) { | |
| 193 detach(rp->r_fires, fire_item); | |
| 194 destroy_item(fire_item); | |
| 195 if (rp->r_fires == NULL) { | |
| 196 rp->r_flags &= ~HASFIRE; | |
| 197 if(cansee(tp->t_pos.y,tp->t_pos.x)) | |
| 198 light(&hero); | |
| 199 } | |
| 200 break; | |
| 201 } | |
| 202 } | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 if (which == WS_POLYMORPH) { | |
| 207 register struct linked_list *pitem; | |
| 208 | |
| 209 delta.x = x; | |
| 210 delta.y = y; | |
| 211 detach(mlist, item); | |
| 212 oldch = tp->t_oldch; | |
| 213 pitem = tp->t_pack; /* save his pack */ | |
| 214 tp->t_pack = NULL; | |
| 215 new_monster(item,rnd(NUMMONST-NUMUNIQUE-1)+1,&delta,FALSE); | |
| 216 if (tp->t_pack != NULL) | |
| 217 o_free_list (tp->t_pack); | |
| 218 tp->t_pack = pitem; | |
| 219 monster = tp->t_type; | |
| 220 if (isalpha(mvwinch(cw, y, x))) | |
| 221 mvwaddch(cw, y, x, monster); | |
| 222 tp->t_oldch = oldch; | |
| 223 /* | |
| 224 * should the room light up? | |
| 225 */ | |
| 226 if (on(*tp, HASFIRE)) { | |
| 227 if (rp) { | |
| 228 register struct linked_list *fire_item; | |
| 229 | |
| 230 fire_item = creat_item(); | |
| 231 ldata(fire_item) = (char *) tp; | |
| 232 attach(rp->r_fires, fire_item); | |
| 233 rp->r_flags |= HASFIRE; | |
| 234 if (cansee(tp->t_pos.y,tp->t_pos.x) && | |
| 235 next(rp->r_fires) == NULL) light(&hero); | |
| 236 } | |
| 237 } | |
| 238 msg(terse ? "A new %s!" : "You have created a new %s!", | |
| 239 monsters[tp->t_index].m_name); | |
| 240 } | |
| 241 else if (which == WS_CANCEL) { | |
| 242 tp->t_flags[0] &= CANC0MASK; | |
| 243 tp->t_flags[1] &= CANC1MASK; | |
| 244 tp->t_flags[2] &= CANC2MASK; | |
| 245 tp->t_flags[3] &= CANC3MASK; | |
| 246 tp->t_flags[4] &= CANC4MASK; | |
| 247 tp->t_flags[4] &= CANC5MASK; | |
| 248 } | |
| 249 else { /* A teleport stick */ | |
| 250 if (cursed) { /* Teleport monster to player */ | |
| 251 if ((y == (hero.y + delta.y)) && | |
| 252 (x == (hero.x + delta.x))) | |
| 253 msg(nothing); | |
| 254 else { | |
| 255 tp->t_pos.y = hero.y + delta.y; | |
| 256 tp->t_pos.x = hero.x + delta.x; | |
| 257 } | |
| 258 } | |
| 259 else if (blessed) { /* Get rid of monster */ | |
| 260 killed(item, FALSE, TRUE); | |
| 261 return(TRUE); | |
| 262 } | |
| 263 else { | |
| 264 register int i=0; | |
| 265 | |
| 266 do { /* Move monster to another room */ | |
| 267 rm = rnd_room(); | |
| 268 rnd_pos(&rooms[rm], &tp->t_pos); | |
| 269 }until(winat(tp->t_pos.y,tp->t_pos.x)==FLOOR ||i++>500); | |
| 270 rp = &rooms[rm]; | |
| 271 } | |
| 272 | |
| 273 /* Now move the monster */ | |
| 274 if (isalpha(mvwinch(cw, y, x))) | |
| 275 mvwaddch(cw, y, x, tp->t_oldch); | |
| 276 turn_off(*tp, ISDISGUISE); | |
| 277 mvwaddch(mw, y, x, ' '); | |
| 278 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, monster); | |
| 279 if (tp->t_pos.y != y || tp->t_pos.x != x) | |
| 280 tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) ); | |
| 281 /* | |
| 282 * check to see if room that creature appears in should | |
| 283 * light up | |
| 284 */ | |
| 285 if (on(*tp, HASFIRE)) { | |
| 286 register struct linked_list *fire_item; | |
| 287 | |
| 288 fire_item = creat_item(); | |
| 289 ldata(fire_item) = (char *) tp; | |
| 290 attach(rp->r_fires, fire_item); | |
| 291 rp->r_flags |= HASFIRE; | |
| 292 if(cansee(tp->t_pos.y, tp->t_pos.x) && | |
| 293 next(rp->r_fires) == NULL) | |
| 294 light(&hero); | |
| 295 } | |
| 296 } | |
| 297 runto(tp, &hero); | |
| 298 } | |
| 299 } | |
| 300 when WS_MISSILE: | |
| 301 { | |
| 302 static struct object bolt = | |
| 303 { | |
| 304 MISSILE , {0, 0}, "", 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1 | |
| 305 }; | |
| 306 | |
| 307 sprintf(bolt.o_hurldmg, "%dd4", pstats.s_lvl); | |
| 308 do_motion(&bolt, delta.y, delta.x, &player); | |
| 309 if (!hit_monster(unc(bolt.o_pos), &bolt, &player)) | |
| 310 msg("The missile vanishes with a puff of smoke"); | |
| 311 } | |
| 312 when WS_HIT: | |
| 313 { | |
| 314 register char ch; | |
| 315 struct object strike; /* don't want to change sticks attributes */ | |
| 316 | |
| 317 delta.y += hero.y; | |
| 318 delta.x += hero.x; | |
| 319 ch = CCHAR( winat(delta.y, delta.x) ); | |
| 320 if (isalpha(ch)) | |
| 321 { | |
| 322 strike = *obj; | |
| 323 strike.o_hplus = 6; | |
| 324 if (EQUAL(ws_type[which], "staff")) | |
| 325 strcpy(strike.o_damage,"3d8"); | |
| 326 else | |
| 327 strcpy(strike.o_damage,"2d8"); | |
| 328 fight(&delta, &strike, FALSE); | |
| 329 } | |
| 330 } | |
| 331 case WS_SLOW_M: | |
| 332 y = hero.y; | |
| 333 x = hero.x; | |
| 334 while (shoot_ok(winat(y, x))) { | |
| 335 y += delta.y; | |
| 336 x += delta.x; | |
| 337 } | |
| 338 if (isalpha(mvwinch(mw, y, x))) { | |
| 339 item = find_mons(y, x); | |
| 340 tp = THINGPTR(item); | |
| 341 runto(tp, &hero); | |
| 342 if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) | |
| 343 msg(nothing); | |
| 344 else if (on(*tp, NOSLOW)) | |
| 345 msg(nothing); | |
| 346 else if (cursed) { | |
| 347 if (on(*tp, ISSLOW)) | |
| 348 turn_off(*tp, ISSLOW); | |
| 349 else | |
| 350 turn_on(*tp, ISHASTE); | |
| 351 } | |
| 352 else if (blessed) { | |
| 353 turn_off(*tp, ISRUN); | |
| 354 turn_on(*tp, ISHELD); | |
| 355 return(TRUE); | |
| 356 } | |
| 357 else { | |
| 358 if (on(*tp, ISHASTE)) | |
| 359 turn_off(*tp, ISHASTE); | |
| 360 else | |
| 361 turn_on(*tp, ISSLOW); | |
| 362 tp->t_turn = TRUE; | |
| 363 } | |
| 364 } | |
| 365 when WS_CHARGE: | |
| 366 if (ws_know[WS_CHARGE] != TRUE && is_stick) | |
| 367 msg("This is a wand of charging."); | |
| 368 if ((nitem = get_item(pack, "charge", STICK)) != NULL) { | |
| 369 nobj = OBJPTR(nitem); | |
| 370 if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT)) | |
| 371 fix_stick(nobj); | |
| 372 if (EQUAL(ws_type[nobj->o_which], "staff")) { | |
| 373 if (nobj->o_charges > 100) | |
| 374 nobj->o_charges = 100; | |
| 375 } | |
| 376 else { | |
| 377 if (nobj->o_charges > 50) | |
| 378 nobj->o_charges = 50; | |
| 379 } | |
| 380 } | |
| 381 when WS_ELECT: | |
| 382 case WS_FIRE: | |
| 383 case WS_COLD: | |
| 384 { | |
| 385 char *name; | |
| 386 | |
| 387 if (which == WS_ELECT) | |
| 388 name = "lightning bolt"; | |
| 389 else if (which == WS_FIRE) | |
| 390 name = "flame"; | |
| 391 else | |
| 392 name = "ice"; | |
| 393 | |
| 394 shoot_bolt( &player, hero, | |
| 395 delta, TRUE, D_BOLT, | |
| 396 name, roll(pstats.s_lvl,6)); | |
| 397 } | |
| 398 when WS_PETRIFY: { | |
| 399 reg int m1, m2, x1, y1; | |
| 400 reg char ch; | |
| 401 reg struct linked_list *ll; | |
| 402 reg struct thing *lt; | |
| 403 | |
| 404 y1 = hero.y; | |
| 405 x1 = hero.x; | |
| 406 do { | |
| 407 y1 += delta.y; | |
| 408 x1 += delta.x; | |
| 409 ch = CCHAR( winat(y1,x1) ); | |
| 410 } while (ch == PASSAGE || ch == FLOOR); | |
| 411 for (m1 = x1 - 1 ; m1 <= x1 + 1 ; m1++) { | |
| 412 for(m2 = y1 - 1 ; m2 <= y1 + 1 ; m2++) { | |
| 413 ch = CCHAR( winat(m2,m1) ); | |
| 414 if (m1 == hero.x && m2 == hero.y) | |
| 415 continue; | |
| 416 if (ch != ' ') { | |
| 417 ll = find_obj(m2,m1); | |
| 418 if (ll != NULL) { | |
| 419 detach(lvl_obj,ll); | |
| 420 o_discard(ll); | |
| 421 } | |
| 422 ll = find_mons(m2,m1); | |
| 423 if (ll != NULL) { | |
| 424 lt = THINGPTR(ll); | |
| 425 if (on(*lt, ISUNIQUE)) | |
| 426 monsters[lt->t_index].m_normal = TRUE; | |
| 427 check_residue(lt); | |
| 428 detach(mlist,ll); | |
| 429 t_discard(ll); | |
| 430 mvwaddch(mw,m2,m1,' '); | |
| 431 } | |
| 432 mvaddch(m2,m1,' '); | |
| 433 mvwaddch(cw,m2,m1,' '); | |
| 434 } | |
| 435 } | |
| 436 } | |
| 437 touchwin(cw); | |
| 438 touchwin(mw); | |
| 439 } | |
| 440 when WS_CONFMON: | |
| 441 if (cursed) { | |
| 442 if (off(player, ISCLEAR)) { | |
| 443 if (on(player, ISHUH)) | |
| 444 lengthen(unconfuse, rnd(20)+HUHDURATION); | |
| 445 else { | |
| 446 turn_on(player, ISHUH); | |
| 447 fuse(unconfuse,0,rnd(20)+HUHDURATION,AFTER); | |
| 448 msg("Wait, what's going on here. Huh? What? Who?"); | |
| 449 } | |
| 450 } | |
| 451 else msg("You feel dizzy for a moment, but it quickly passes."); | |
| 452 } | |
| 453 else { | |
| 454 y = hero.y; | |
| 455 x = hero.x; | |
| 456 while (shoot_ok(winat(y, x))) | |
| 457 { | |
| 458 y += delta.y; | |
| 459 x += delta.x; | |
| 460 } | |
| 461 if (isalpha(mvwinch(mw, y, x))) | |
| 462 { | |
| 463 item = find_mons(y, x); | |
| 464 tp = THINGPTR(item); | |
| 465 if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR)) | |
| 466 msg(nothing); | |
| 467 else | |
| 468 turn_on (*tp, ISHUH); | |
| 469 runto(tp, &hero); | |
| 470 } | |
| 471 } | |
| 472 when WS_PARALYZE: | |
| 473 if (cursed) { | |
| 474 no_command += FREEZETIME; | |
| 475 msg("You can't move."); | |
| 476 } | |
| 477 else { | |
| 478 y = hero.y; | |
| 479 x = hero.x; | |
| 480 while (shoot_ok(winat(y, x))) | |
| 481 { | |
| 482 y += delta.y; | |
| 483 x += delta.x; | |
| 484 } | |
| 485 if (isalpha(mvwinch(mw, y, x))) | |
| 486 { | |
| 487 item = find_mons(y, x); | |
| 488 tp = THINGPTR(item); | |
| 489 if (save(VS_WAND, tp, 0) || on(*tp, NOPARALYZE)) | |
| 490 msg(nothing); | |
| 491 else { | |
| 492 tp->t_no_move = FREEZETIME; | |
| 493 } | |
| 494 runto(tp, &hero); | |
| 495 } | |
| 496 } | |
| 497 when WS_FEAR: | |
| 498 y = hero.y; | |
| 499 x = hero.x; | |
| 500 while (shoot_ok(winat(y, x))) | |
| 501 { | |
| 502 y += delta.y; | |
| 503 x += delta.x; | |
| 504 } | |
| 505 if (isalpha(mvwinch(mw, y, x))) | |
| 506 { | |
| 507 item = find_mons(y, x); | |
| 508 tp = THINGPTR(item); | |
| 509 runto(tp, &hero); | |
| 510 if (save(VS_WAND, tp, 0) || | |
| 511 on(*tp, ISUNDEAD) || | |
| 512 on(*tp, NOFEAR)) | |
| 513 msg(nothing); | |
| 514 else { | |
| 515 turn_on(*tp, ISFLEE); | |
| 516 turn_on(*tp, WASTURNED); | |
| 517 | |
| 518 /* If monster was suffocating, stop it */ | |
| 519 if (on(*tp, DIDSUFFOCATE)) { | |
| 520 turn_off(*tp, DIDSUFFOCATE); | |
| 521 extinguish(suffocate); | |
| 522 } | |
| 523 | |
| 524 /* If monster held us, stop it */ | |
| 525 if (on(*tp, DIDHOLD) && (--hold_count == 0)) | |
| 526 turn_off(player, ISHELD); | |
| 527 turn_off(*tp, DIDHOLD); | |
| 528 } | |
| 529 } | |
| 530 when WS_MDEG: | |
| 531 y = hero.y; | |
| 532 x = hero.x; | |
| 533 while (shoot_ok(winat(y, x))) | |
| 534 { | |
| 535 y += delta.y; | |
| 536 x += delta.x; | |
| 537 } | |
| 538 if (isalpha(mvwinch(mw, y, x))) | |
| 539 { | |
| 540 item = find_mons(y, x); | |
| 541 tp = THINGPTR(item); | |
| 542 if (cursed) { | |
| 543 tp->t_stats.s_hpt *= 2; | |
| 544 msg("The %s appears to be stronger now!", | |
| 545 monsters[tp->t_index].m_name); | |
| 546 } | |
| 547 else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0)) | |
| 548 msg (nothing); | |
| 549 else { | |
| 550 tp->t_stats.s_hpt /= 2; | |
| 551 msg("The %s appears to be weaker now", | |
| 552 monsters[tp->t_index].m_name); | |
| 553 } | |
| 554 runto(tp, &hero); | |
| 555 if (tp->t_stats.s_hpt < 1) | |
| 556 killed(item, TRUE, TRUE); | |
| 557 } | |
| 558 when WS_DISINTEGRATE: | |
| 559 y = hero.y; | |
| 560 x = hero.x; | |
| 561 while (shoot_ok(winat(y, x))) { | |
| 562 y += delta.y; | |
| 563 x += delta.x; | |
| 564 } | |
| 565 if (isalpha(mvwinch(mw, y, x))) { | |
| 566 item = find_mons(y, x); | |
| 567 tp = THINGPTR(item); | |
| 568 turn_on (*tp, ISMEAN); | |
| 569 runto(tp, &hero); | |
| 570 if (cursed) { | |
| 571 register int m1, m2; | |
| 572 coord mp; | |
| 573 struct linked_list *titem; | |
| 574 char ch; | |
| 575 struct thing *th; | |
| 576 | |
| 577 if (on(*tp, ISUNIQUE)) { | |
| 578 msg (nothing); | |
| 579 break; | |
| 580 } | |
| 581 for (m1=tp->t_pos.x-1 ; m1 <= tp->t_pos.x+1 ; m1++) { | |
| 582 for(m2=tp->t_pos.y-1 ; m2<=tp->t_pos.y+1 ; m2++) { | |
| 583 ch = CCHAR( winat(m2,m1) ); | |
| 584 if (shoot_ok(ch) && ch != PLAYER) { | |
| 585 mp.x = m1; /* create it */ | |
| 586 mp.y = m2; | |
| 587 titem = new_item(sizeof(struct thing)); | |
| 588 new_monster(titem,(short)tp->t_index,&mp,FALSE); | |
| 589 th = THINGPTR(titem); | |
| 590 turn_on (*th, ISMEAN); | |
| 591 runto(th,&hero); | |
| 592 if (on(*th, HASFIRE)) { | |
| 593 register struct room *rp; | |
| 594 | |
| 595 rp = roomin(&th->t_pos); | |
| 596 if (rp) { | |
| 597 register struct linked_list *fire_item; | |
| 598 | |
| 599 fire_item = creat_item(); | |
| 600 ldata(fire_item) = (char *) th; | |
| 601 attach(rp->r_fires, fire_item); | |
| 602 rp->r_flags |= HASFIRE; | |
| 603 if (cansee(th->t_pos.y, th->t_pos.x) && | |
| 604 next(rp->r_fires) == NULL) | |
| 605 light(&hero); | |
| 606 } | |
| 607 } | |
| 608 } | |
| 609 } | |
| 610 } | |
| 611 } | |
| 612 else { /* if its a UNIQUE it might still live */ | |
| 613 tp = THINGPTR(item); | |
| 614 if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) { | |
| 615 tp->t_stats.s_hpt /= 2; | |
| 616 if (tp->t_stats.s_hpt < 1) { | |
| 617 killed(item, FALSE, TRUE); | |
| 618 msg("You have disintegrated the %s", | |
| 619 monsters[tp->t_index].m_name); | |
| 620 } | |
| 621 else { | |
| 622 msg("The %s appears wounded", | |
| 623 monsters[tp->t_index].m_name); | |
| 624 } | |
| 625 } | |
| 626 else { | |
| 627 msg("You have disintegrated the %s", | |
| 628 monsters[tp->t_index].m_name); | |
| 629 killed (item, FALSE, TRUE); | |
| 630 } | |
| 631 } | |
| 632 } | |
| 633 when WS_CURING: | |
| 634 ws_know[WS_CURING] = TRUE; | |
| 635 if (cursed) { | |
| 636 if (!save(VS_POISON, &player, 0)) { | |
| 637 msg("You feel extremely sick now"); | |
| 638 pstats.s_hpt /=2; | |
| 639 if (pstats.s_hpt == 0) death (D_POISON); | |
| 640 } | |
| 641 if (!save(VS_WAND, &player, 0) && !ISWEARING(R_HEALTH)) { | |
| 642 turn_on(player, HASDISEASE); | |
| 643 turn_on(player, HASINFEST); | |
| 644 turn_on(player, DOROT); | |
| 645 fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER); | |
| 646 infest_dam++; | |
| 647 } | |
| 648 else msg("You fell momentarily sick"); | |
| 649 } | |
| 650 else { | |
| 651 if (on(player, HASDISEASE)) { | |
| 652 extinguish(cure_disease); | |
| 653 cure_disease(); | |
| 654 msg(terse ? "You feel yourself improving." | |
| 655 : "You begin to feel yourself improving again."); | |
| 656 } | |
| 657 if (on(player, HASINFEST)) { | |
| 658 turn_off(player, HASINFEST); | |
| 659 infest_dam = 0; | |
| 660 msg(terse ? "You feel yourself improving." | |
| 661 : "You begin to feel yourself improving again."); | |
| 662 } | |
| 663 if (on(player, DOROT)) { | |
| 664 msg("You feel your skin returning to normal."); | |
| 665 turn_off(player, DOROT); | |
| 666 } | |
| 667 pstats.s_hpt += roll(pstats.s_lvl, blessed ? 6 : 4); | |
| 668 if (pstats.s_hpt > max_stats.s_hpt) | |
| 669 pstats.s_hpt = max_stats.s_hpt; | |
| 670 msg("You begin to feel %sbetter.", blessed ? "much " : ""); | |
| 671 | |
| 672 } | |
| 673 otherwise: | |
| 674 msg("What a bizarre schtick!"); | |
| 675 } | |
| 676 return(TRUE); | |
| 677 } | |
| 678 | |
| 679 | |
| 680 /* | |
| 681 * drain: | |
| 682 * Do drain hit points from player shtick | |
| 683 */ | |
| 684 | |
| 685 drain(ymin, ymax, xmin, xmax) | |
| 686 int ymin, ymax, xmin, xmax; | |
| 687 { | |
| 688 register int i, j, count; | |
| 689 register struct thing *ick; | |
| 690 register struct linked_list *item; | |
| 691 | |
| 692 /* | |
| 693 * First count how many things we need to spread the hit points among | |
| 694 */ | |
| 695 count = 0; | |
| 696 for (i = ymin; i <= ymax; i++) { | |
| 697 if (i < 1 || i > LINES - 3) | |
| 698 continue; | |
| 699 for (j = xmin; j <= xmax; j++) { | |
| 700 if (j < 0 || j > COLS - 1) | |
| 701 continue; | |
| 702 if (isalpha(mvwinch(mw, i, j))) | |
| 703 count++; | |
| 704 } | |
| 705 } | |
| 706 if (count == 0) | |
| 707 { | |
| 708 msg("You have a tingling feeling"); | |
| 709 return; | |
| 710 } | |
| 711 count = pstats.s_hpt / count; | |
| 712 pstats.s_hpt /= 2; | |
| 713 /* | |
| 714 * Now zot all of the monsters | |
| 715 */ | |
| 716 for (i = ymin; i <= ymax; i++) { | |
| 717 if (i < 1 || i > LINES - 3) | |
| 718 continue; | |
| 719 for (j = xmin; j <= xmax; j++) { | |
| 720 if (j < 0 || j > COLS - 1) | |
| 721 continue; | |
| 722 if (isalpha(mvwinch(mw, i, j)) && | |
| 723 ((item = find_mons(i, j)) != NULL)) { | |
| 724 ick = THINGPTR(item); | |
| 725 if (on(*ick, ISUNIQUE) && save(VS_MAGIC, ick, 0)) | |
| 726 ick->t_stats.s_hpt -= count / 2; | |
| 727 else | |
| 728 ick->t_stats.s_hpt -= count; | |
| 729 if (ick->t_stats.s_hpt < 1) | |
| 730 killed(item, | |
| 731 cansee(i,j)&&(!on(*ick,ISINVIS)||on(player,CANSEE)), | |
| 732 TRUE); | |
| 733 else { | |
| 734 runto(ick, &hero); | |
| 735 if (cansee(i,j) && (!on(*ick,ISINVIS)||on(player,CANSEE))) | |
| 736 msg("The %s appears wounded", | |
| 737 monsters[ick->t_index].m_name); | |
| 738 } | |
| 739 } | |
| 740 } | |
| 741 } | |
| 742 } | |
| 743 | |
| 744 /* | |
| 745 * initialize a stick | |
| 746 */ | |
| 747 fix_stick(cur) | |
| 748 register struct object *cur; | |
| 749 { | |
| 750 if (EQUAL(ws_type[cur->o_which], "staff")) { | |
| 751 cur->o_weight = 100; | |
| 752 cur->o_charges = 5 + rnd(10); | |
| 753 strcpy(cur->o_damage,"2d3"); | |
| 754 cur->o_hplus = 1; | |
| 755 cur->o_dplus = 0; | |
| 756 switch (cur->o_which) { | |
| 757 case WS_HIT: | |
| 758 cur->o_hplus = 3; | |
| 759 cur->o_dplus = 3; | |
| 760 strcpy(cur->o_damage,"2d8"); | |
| 761 when WS_LIGHT: | |
| 762 cur->o_charges = 20 + rnd(10); | |
| 763 } | |
| 764 } | |
| 765 else { | |
| 766 strcpy(cur->o_damage,"1d3"); | |
| 767 cur->o_weight = 60; | |
| 768 cur->o_hplus = 1; | |
| 769 cur->o_dplus = 0; | |
| 770 cur->o_charges = 3 + rnd(5); | |
| 771 switch (cur->o_which) { | |
| 772 case WS_HIT: | |
| 773 cur->o_hplus = 3; | |
| 774 cur->o_dplus = 3; | |
| 775 strcpy(cur->o_damage,"1d8"); | |
| 776 when WS_LIGHT: | |
| 777 cur->o_charges = 10 + rnd(10); | |
| 778 } | |
| 779 } | |
| 780 strcpy(cur->o_hurldmg,"1d1"); | |
| 781 | |
| 782 } | |
| 783 | |
| 784 /* | |
| 785 * shoot_bolt fires a bolt from the given starting point in the | |
| 786 * given direction | |
| 787 */ | |
| 788 | |
| 789 shoot_bolt(shooter, start, dir, get_points, reason, name, damage) | |
| 790 struct thing *shooter; | |
| 791 coord start, dir; | |
| 792 bool get_points; | |
| 793 short reason; | |
| 794 char *name; | |
| 795 int damage; | |
| 796 { | |
| 797 register char dirch = 0, ch; | |
| 798 register bool used, change; | |
| 799 register short y, x, bounces; | |
| 800 bool mdead = FALSE; | |
| 801 coord pos; | |
| 802 struct { | |
| 803 coord place; | |
| 804 char oldch; | |
| 805 } spotpos[BOLT_LENGTH]; | |
| 806 | |
| 807 switch (dir.y + dir.x) { | |
| 808 case 0: dirch = '/'; | |
| 809 when 1: case -1: dirch = (dir.y == 0 ? '-' : '|'); | |
| 810 when 2: case -2: dirch = '\\'; | |
| 811 } | |
| 812 pos.y = start.y + dir.y; | |
| 813 pos.x = start.x + dir.x; | |
| 814 used = FALSE; | |
| 815 change = FALSE; | |
| 816 | |
| 817 bounces = 0; /* No bounces yet */ | |
| 818 for (y = 0; y < BOLT_LENGTH && !used; y++) | |
| 819 { | |
| 820 ch = CCHAR( winat(pos.y, pos.x) ); | |
| 821 spotpos[y].place = pos; | |
| 822 spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) ); | |
| 823 | |
| 824 /* Are we at hero? */ | |
| 825 if (ce(pos, hero)) goto at_hero; | |
| 826 | |
| 827 switch (ch) | |
| 828 { | |
| 829 case SECRETDOOR: | |
| 830 case '|': | |
| 831 case '-': | |
| 832 case ' ': | |
| 833 if (dirch == '-' || dirch == '|') { | |
| 834 dir.y = -dir.y; | |
| 835 dir.x = -dir.x; | |
| 836 } | |
| 837 else { | |
| 838 char chx = CCHAR( mvinch(pos.y-dir.y, pos.x) ), | |
| 839 chy = CCHAR( mvinch(pos.y, pos.x-dir.x) ); | |
| 840 bool anychange = FALSE; /* Did we change anthing */ | |
| 841 | |
| 842 if (chy == WALL || chy == SECRETDOOR || | |
| 843 chy == '-' || chy == '|') { | |
| 844 dir.y = -dir.y; | |
| 845 change ^= TRUE; /* Change at least one direction */ | |
| 846 anychange = TRUE; | |
| 847 } | |
| 848 if (chx == WALL || chx == SECRETDOOR || | |
| 849 chx == '-' || chx == '|') { | |
| 850 dir.x = -dir.x; | |
| 851 change ^= TRUE; /* Change at least one direction */ | |
| 852 anychange = TRUE; | |
| 853 } | |
| 854 | |
| 855 /* If we didn't make any change, make both changes */ | |
| 856 if (!anychange) { | |
| 857 dir.x = -dir.x; | |
| 858 dir.y = -dir.y; | |
| 859 } | |
| 860 } | |
| 861 | |
| 862 /* Do we change how the bolt looks? */ | |
| 863 if (change) { | |
| 864 change = FALSE; | |
| 865 if (dirch == '\\') dirch = '/'; | |
| 866 else if (dirch == '/') dirch = '\\'; | |
| 867 } | |
| 868 | |
| 869 y--; /* The bounce doesn't count as using up the bolt */ | |
| 870 | |
| 871 /* Make sure we aren't in an infinite bounce */ | |
| 872 if (++bounces > BOLT_LENGTH) used = TRUE; | |
| 873 msg("The %s bounces", name); | |
| 874 break; | |
| 875 default: | |
| 876 if (isalpha(ch)) { | |
| 877 register struct linked_list *item; | |
| 878 register struct thing *tp; | |
| 879 register const char *mname; | |
| 880 bool see_monster = cansee(pos.y, pos.x); | |
| 881 | |
| 882 item = find_mons(unc(pos)); | |
| 883 tp = THINGPTR(item); | |
| 884 mname = monsters[tp->t_index].m_name; | |
| 885 | |
| 886 if (!save(VS_BREATH, tp, -(shooter->t_stats.s_lvl/10))) { | |
| 887 if (see_monster) { | |
| 888 if (on(*tp, ISDISGUISE) && | |
| 889 (tp->t_type != tp->t_disguise)) { | |
| 890 msg("Wait! That's a %s!", mname); | |
| 891 turn_off(*tp, ISDISGUISE); | |
| 892 } | |
| 893 | |
| 894 sprintf(outstring,"The %s hits the %s", name, mname); | |
| 895 msg(outstring); | |
| 896 } | |
| 897 | |
| 898 tp->t_wasshot = TRUE; | |
| 899 runto(tp, &hero); | |
| 900 used = TRUE; | |
| 901 | |
| 902 /* Hit the monster -- does it do anything? */ | |
| 903 if ((EQUAL(name,"ice") && | |
| 904 (on(*tp, NOCOLD) || on(*tp, ISUNDEAD))) || | |
| 905 (EQUAL(name,"flame") && on(*tp, NOFIRE)) || | |
| 906 (EQUAL(name,"acid") && on(*tp, NOACID)) || | |
| 907 (EQUAL(name,"lightning bolt")&& on(*tp,NOBOLT)) || | |
| 908 (EQUAL(name,"nerve gas") &&on(*tp,NOPARALYZE))|| | |
| 909 (EQUAL(name,"sleeping gas") && | |
| 910 (on(*tp, NOSLEEP) || on(*tp, ISUNDEAD))) || | |
| 911 (EQUAL(name,"slow gas") && on(*tp,NOSLOW)) || | |
| 912 (EQUAL(name,"fear gas") && on(*tp,NOFEAR)) || | |
| 913 (EQUAL(name,"confusion gas") && on(*tp,ISCLEAR)) || | |
| 914 (EQUAL(name,"chlorine gas") && on(*tp,NOGAS))) { | |
| 915 if (see_monster){ | |
| 916 sprintf(outstring,"The %s has no effect on the %s.", | |
| 917 name, mname); | |
| 918 msg(outstring); | |
| 919 } | |
| 920 } | |
| 921 | |
| 922 /* | |
| 923 * Check for gas with special effects | |
| 924 */ | |
| 925 else if (EQUAL(name, "nerve gas")) { | |
| 926 tp->t_no_move = FREEZETIME; | |
| 927 } | |
| 928 else if (EQUAL(name, "sleeping gas")) { | |
| 929 tp->t_no_move = SLEEPTIME; | |
| 930 } | |
| 931 else if (EQUAL(name, "slow gas")) { | |
| 932 if (on(*tp, ISHASTE)) | |
| 933 turn_off(*tp, ISHASTE); | |
| 934 else | |
| 935 turn_on(*tp, ISSLOW); | |
| 936 tp->t_turn = TRUE; | |
| 937 } | |
| 938 else if (EQUAL(name, "fear gas")) { | |
| 939 turn_on(*tp, ISFLEE); | |
| 940 tp->t_dest = &hero; | |
| 941 } | |
| 942 else if (EQUAL(name, "confusion gas")) { | |
| 943 turn_on(*tp, ISHUH); | |
| 944 tp->t_dest = &hero; | |
| 945 } | |
| 946 else if ((EQUAL(name, "lightning bolt")) && | |
| 947 on(*tp, BOLTDIVIDE)) { | |
| 948 if (creat_mons(tp, tp->t_index, FALSE)) { | |
| 949 if (see_monster){ | |
| 950 sprintf(outstring,"The %s divides the %s.",name,mname); | |
| 951 msg(outstring); | |
| 952 } | |
| 953 light(&hero); | |
| 954 } | |
| 955 else if (see_monster){ | |
| 956 sprintf(outstring,"The %s has no effect on the %s.", | |
| 957 name, mname); | |
| 958 msg(outstring); | |
| 959 } | |
| 960 } | |
| 961 else { | |
| 962 if(save(VS_BREATH,tp, -(shooter->t_stats.s_lvl/10))) | |
| 963 damage /= 2; | |
| 964 | |
| 965 /* The poor fellow got killed! */ | |
| 966 if ((tp->t_stats.s_hpt -= damage) <= 0) { | |
| 967 if (see_monster){ | |
| 968 sprintf(outstring,"The %s kills the %s", name, mname); | |
| 969 msg(outstring); | |
| 970 } | |
| 971 else | |
| 972 msg("You hear a faint groan in the distance"); | |
| 973 killed(item, FALSE, get_points); | |
| 974 | |
| 975 /* Replace the screen character */ | |
| 976 spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) ); | |
| 977 | |
| 978 mdead = TRUE; | |
| 979 } | |
| 980 else { /* Not dead, so just scream */ | |
| 981 if (!see_monster) | |
| 982 msg("You hear a scream in the distance"); | |
| 983 } | |
| 984 } | |
| 985 } | |
| 986 else if (isalpha(show(pos.y, pos.x))) { | |
| 987 if (see_monster) { | |
| 988 if (terse) | |
| 989 msg("%s misses", name); | |
| 990 else { | |
| 991 sprintf(outstring,"The %s whizzes past the %s", name, mname); | |
| 992 msg(outstring); | |
| 993 } | |
| 994 } | |
| 995 if (get_points) runto(tp, &hero); | |
| 996 } | |
| 997 } | |
| 998 else if (pos.y == hero.y && pos.x == hero.x) { | |
| 999 at_hero: if (!save(VS_BREATH, &player, | |
| 1000 -(shooter->t_stats.s_lvl/10))){ | |
| 1001 if (terse) | |
| 1002 msg("The %s hits you", name); | |
| 1003 else | |
| 1004 msg("You are hit by the %s", name); | |
| 1005 used = TRUE; | |
| 1006 | |
| 1007 /* | |
| 1008 * The Amulet of Yendor protects against all "breath" | |
| 1009 * | |
| 1010 * The following two if statements could be combined | |
| 1011 * into one, but it makes the compiler barf, so split | |
| 1012 * it up | |
| 1013 */ | |
| 1014 if (cur_relic[YENDOR_AMULET] || | |
| 1015 (EQUAL(name,"chlorine gas")&&on(player, NOGAS)) || | |
| 1016 (EQUAL(name,"sleeping gas")&&ISWEARING(R_ALERT))){ | |
| 1017 msg("The %s has no affect", name); | |
| 1018 } | |
| 1019 else if((EQUAL(name, "flame") && on(player, NOFIRE)) || | |
| 1020 (EQUAL(name, "ice") && on(player, NOCOLD)) || | |
| 1021 (EQUAL(name,"fear gas")&&ISWEARING(R_HEROISM))){ | |
| 1022 msg("The %s has no affect", name); | |
| 1023 } | |
| 1024 /* | |
| 1025 * Check for gas with special effects | |
| 1026 */ | |
| 1027 else if (EQUAL(name, "nerve gas")) { | |
| 1028 msg("The nerve gas paralyzes you."); | |
| 1029 no_command += FREEZETIME; | |
| 1030 } | |
| 1031 else if (EQUAL(name, "sleeping gas")) { | |
| 1032 msg("The sleeping gas puts you to sleep."); | |
| 1033 no_command += SLEEPTIME; | |
| 1034 } | |
| 1035 else if (EQUAL(name, "confusion gas")) { | |
| 1036 if (off(player, ISCLEAR)) { | |
| 1037 if (on(player, ISHUH)) | |
| 1038 lengthen(unconfuse, rnd(20)+HUHDURATION); | |
| 1039 else { | |
| 1040 turn_on(player, ISHUH); | |
| 1041 fuse(unconfuse,0,rnd(20)+HUHDURATION,AFTER); | |
| 1042 msg("The confusion gas has confused you."); | |
| 1043 } | |
| 1044 } | |
| 1045 else msg("You feel dizzy for a moment, but it quickly passes."); | |
| 1046 } | |
| 1047 else if (EQUAL(name, "slow gas")) { | |
| 1048 add_slow(); | |
| 1049 } | |
| 1050 else if (EQUAL(name, "fear gas")) { | |
| 1051 turn_on(player, ISFLEE); | |
| 1052 player.t_dest = &shooter->t_pos; | |
| 1053 msg("The fear gas terrifies you."); | |
| 1054 } | |
| 1055 else { | |
| 1056 if(save(VS_BREATH,&player, -(shooter->t_stats.s_lvl/10))) | |
| 1057 damage /= 2; | |
| 1058 if ((pstats.s_hpt -= damage) <= 0) | |
| 1059 death(reason); | |
| 1060 } | |
| 1061 } | |
| 1062 else | |
| 1063 msg("The %s whizzes by you", name); | |
| 1064 } | |
| 1065 | |
| 1066 mvwaddch(cw, pos.y, pos.x, dirch); | |
| 1067 draw(cw); | |
| 1068 } | |
| 1069 | |
| 1070 pos.y += dir.y; | |
| 1071 pos.x += dir.x; | |
| 1072 } | |
| 1073 for (x = y - 1; x >= 0; x--) | |
| 1074 mvwaddch(cw, spotpos[x].place.y, spotpos[x].place.x, spotpos[x].oldch); | |
| 1075 return(mdead); | |
| 1076 } |
