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 } |