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