comparison arogue7/effects.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 * effects.c - functions for dealing with appllying effects to monsters
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 #include "curses.h"
16 #include "rogue.h"
17
18 /*
19 * effect:
20 * Check for effects of one thing hitting another thing. Return
21 * the reason code if the defender is killed. Otherwise return 0.
22 */
23 effect(att, def, weap, thrown, see_att, see_def)
24 register struct thing *att, *def;
25 struct object *weap;
26 bool thrown;
27 register bool see_att, see_def;
28 {
29 register bool att_player, def_player;
30 char attname[LINELEN+1], defname[LINELEN+1];
31
32 /* See if the attacker or defender is the player */
33 att_player = (att == &player);
34 def_player = (def == &player);
35
36 /*
37 * If the player could see the attacker or defender, they can't
38 * surprise anymore (don't bother checking if they could).
39 */
40 if (see_att) turn_off(*att, CANSURPRISE);
41 if (see_def) turn_off(*def, CANSURPRISE);
42
43 /* What are the attacker and defender names? */
44 if (att_player) strcpy(attname, "you");
45 else {
46 if (see_att) strcpy(attname, monster_name(att));
47 else strcpy(attname, "something");
48 }
49
50 if (def_player) strcpy(defname, "you");
51 else {
52 if (see_def) strcpy(defname, monster_name(def));
53 else strcpy(defname, "something");
54 }
55
56 /*
57 * See what happens to the attacker first. We can skip this
58 * whole section, however, if the defender is the player.
59 * Nothing happens (yet) to anyone just for hitting the player.
60 */
61 if (!def_player) {
62 if (!thrown) { /* Some things require a direct hit. */
63 /*
64 * If the attacker hits a rusting monster, The weapon
65 * may be damaged
66 */
67 if (on(*def, CANRUST) && weap &&
68 weap->o_type != RELIC && (weap->o_flags & ISMETAL) &&
69 !(weap->o_flags & ISPROT)) {
70 if ((weap->o_hplus < 1 && weap->o_dplus < 1) ||
71 roll(1,20) < weap->o_hplus+weap->o_dplus+10) {
72 if (rnd(100) < 50) weap->o_hplus--;
73 else weap->o_dplus--;
74 if (att_player)
75 msg(terse ? "Your %s weakens!"
76 : "Your %s appears to be weaker now!",
77 weaps[weap->o_which].w_name);
78 }
79 }
80 }
81
82 /* If the attacker hit something that shrieks, wake the dungeon */
83 if (on(*def, CANSHRIEK)) {
84 turn_off(*def, CANSHRIEK);
85 if (see_def)
86 msg("%s emits a piercing shriek.", prname(defname, TRUE));
87 else msg("You hear a piercing shriek.");
88 aggravate(TRUE, TRUE);
89 }
90
91 /*
92 * does the creature explode when hit?
93 */
94 if (on(*def, CANEXPLODE)) {
95 if (see_def) msg("%s explodes!", prname(defname, TRUE));
96 else msg("You hear a tremendous explosion!");
97 explode(def);
98 if (pstats.s_hpt <= 0)
99 death(def->t_index);
100 }
101 }
102
103 /*
104 * Now let's see what happens to the defender. Start out with
105 * the things that everyone can do. Then exit if the attacker
106 * is the player.
107 */
108 if (!thrown) {
109 /*
110 * Can the player confuse?
111 */
112 if (on(*att, CANHUH) && att_player) {
113 msg("Your hands stop glowing red.");
114 if (off(*def, ISCLEAR) &&
115 (off(*def, ISUNIQUE) || !save(VS_MAGIC, def, 0))) {
116 if (see_def) msg("%s appears confused.", prname(defname, TRUE));
117 turn_on(*def, ISHUH);
118 }
119 turn_off(*att, CANHUH);
120 }
121
122 /* Return now if the attacker is the player. */
123 if (att_player) return(0);
124
125 /*
126 * Some monsters may take half your hit points
127 */
128 if (on(*att, CANSUCK) && !save(VS_MAGIC, def, 0)) {
129 if (def->t_stats.s_hpt == 1) return(att->t_index); /* Killed! */
130 else {
131 def->t_stats.s_hpt /= 2;
132 if (def_player)
133 msg("You feel your life force being drawn from you.");
134 }
135 }
136
137 /*
138 * If a hugging monster hits, it may SQUEEEEEEEZE.
139 */
140 if (on(*att, CANHUG)) {
141 if (roll(1,20) >= 18 || roll(1,20) >= 18) {
142 if (def_player)
143 msg("%s squeezes you against itself.",
144 prname(attname, TRUE));
145 else if (see_att)
146 msg("%s squeezes hard.", prname(attname, TRUE));
147
148 if ((def->t_stats.s_hpt -= roll(2,8)) <= 0)
149 return(att->t_index);
150 }
151 }
152
153 /*
154 * Some monsters have poisonous bites.
155 */
156 if (on(*att, CANPOISON) && !save(VS_POISON, def, 0)) {
157 if (def_player) {
158 if (ISWEARING(R_SUSABILITY))
159 msg(terse ? "Sting has no effect"
160 : "A sting momentarily weakens you");
161 else {
162 chg_str(-1);
163 msg(terse ? "A sting has weakened you" :
164 "You feel a sting in your arm and now feel weaker");
165 }
166 }
167 else {
168 /* Subtract a strength point and see if it kills it */
169 if (--def->t_stats.s_str <= 0) return(D_STRENGTH);
170 }
171 }
172
173 /*
174 * Turning to stone:
175 */
176 if (on(*att, TOUCHSTONE)) {
177 if (def_player) turn_off(*att, TOUCHSTONE);
178 if (on(*def, CANINWALL)) {
179 if (def_player)
180 msg("%s's touch has no effect.", prname(attname, TRUE));
181 }
182 else {
183 if (!save(VS_PETRIFICATION, def, 0) && rnd(100) < 10) {
184 if (def_player) {
185 msg("Your body begins to solidify.");
186 msg("You are turned to stone !!! --More--");
187 wait_for(' ');
188 return(D_PETRIFY);
189 }
190 else {
191 /* The monster got stoned! */
192 turn_on(*def, ISSTONE);
193 turn_off(*def, ISRUN);
194 turn_off(*def, ISINVIS);
195 turn_off(*def, ISDISGUISE);
196 if (see_def)
197 msg("%s turns to stone.", prname(defname, TRUE));
198 else if (cansee(unc(def->t_pos)))
199 msg("A new statue appears!");
200 }
201 }
202 else if (def->t_action != A_FREEZE) {
203 if (def_player)
204 msg("%s's touch stiffens your limbs.",
205 prname(attname, TRUE));
206 else if (see_def)
207 msg("%s appears to freeze.", prname(defname, TRUE));
208
209 def->t_no_move += movement(def) * STONETIME;
210 def->t_action = A_FREEZE;
211 }
212 }
213 }
214
215 /*
216 * Wraiths might drain energy levels
217 */
218 if ((on(*att, CANDRAIN) || on(*att, DOUBLEDRAIN)) &&
219 !save(VS_POISON, def, 3-(att->t_stats.s_lvl/5))) {
220 if (def_player) {
221 lower_level(att->t_index);
222 if (on(*att, DOUBLEDRAIN)) lower_level(att->t_index);
223 turn_on(*att, DIDDRAIN);
224 }
225 else {
226 def->t_stats.s_hpt -= roll(1, 8);
227 def->t_stats.s_lvl--;
228 if (on(*att, DOUBLEDRAIN)) {
229 def->t_stats.s_hpt -= roll(1, 8);
230 def->t_stats.s_lvl--;
231 }
232 if (see_def)
233 msg("%s appears less skillfull.", prname(defname, TRUE));
234
235 /* Did it kill it? */
236 if (def->t_stats.s_hpt <= 0 ||
237 def->t_stats.s_lvl <= 0)
238 return(att->t_index);
239 }
240 }
241
242 /*
243 * Paralyzation:
244 */
245 if (on(*att, CANPARALYZE) && def->t_action != A_FREEZE) {
246 if (def_player) turn_off(*att, CANPARALYZE);
247 if (!save(VS_PARALYZATION, def, 0)) {
248 if (on(*def, CANINWALL)) {
249 if (def_player)
250 msg("%s's touch has no effect.", prname(attname, TRUE));
251 }
252 else {
253 if (def_player)
254 msg("%s's touch paralyzes you.", prname(attname, TRUE));
255 else if (see_def)
256 msg("%s appears to freeze.", prname(defname, TRUE));
257
258 def->t_no_move += movement(def) * FREEZETIME;
259 def->t_action = A_FREEZE;
260 }
261 }
262 }
263
264 /*
265 * Painful wounds make the defendant faint
266 */
267 if (on(*att, CANPAIN) && def->t_action != A_FREEZE) {
268 if (def_player) turn_off(*att, CANPAIN);
269 if (!ISWEARING(R_ALERT) && !save(VS_POISON, def, 0)) {
270 if (def_player)
271 msg("You faint from the painful wound");
272 else if (see_def)
273 msg("%s appears to faint.", prname(defname, TRUE));
274
275 def->t_no_move += movement(def) * PAINTIME;
276 def->t_action = A_FREEZE;
277 }
278 }
279
280 /*
281 * Some things currently affect only the player. Let's make
282 * a check here so we don't have to check for each thing.
283 */
284 if (def_player) {
285 /*
286 * Stinking monsters make the defender weaker (to hit). For now
287 * this will only affect the player. We may later add the HASSTINK
288 * effect to monsters, too.
289 */
290 if (on(*att, CANSTINK)) {
291 turn_off(*att, CANSTINK);
292 if (!save(VS_POISON, def, 0)) {
293 msg("The stench of %s sickens you.",
294 prname(attname, FALSE));
295 if (on(player, HASSTINK)) lengthen(unstink, STINKTIME);
296 else {
297 turn_on(player, HASSTINK);
298 fuse(unstink, 0, STINKTIME, AFTER);
299 }
300 }
301 }
302
303 /*
304 * Chilling monster reduces strength each time. This only
305 * affects the player for now because of its temporary nature.
306 */
307 if (on(*att, CANCHILL)) {
308 if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, def, 0)) {
309 msg("You cringe at %s's chilling touch.",
310 prname(attname, FALSE));
311 chg_str(-1);
312 if (lost_str++ == 0)
313 fuse(res_strength, 0, CHILLTIME, AFTER);
314 else lengthen(res_strength, CHILLTIME);
315 }
316 }
317
318 /*
319 * Itching monsters reduce dexterity (temporarily). This only
320 * affects the player for now because of its temporary nature.
321 */
322 if (on(*att, CANITCH) && !save(VS_POISON, def, 0)) {
323 msg("The claws of %s scratch you.", prname(attname, FALSE));
324 if (ISWEARING(R_SUSABILITY)) {
325 msg("The scratch has no effect");
326 }
327 else {
328 add_abil[A_DEXTERITY](-1);
329 }
330 }
331
332
333 /*
334 * If a disease-carrying monster hits, there is a chance the
335 * defender will catch the disease. This only applies to the
336 * player for now because of the temporary nature.
337 */
338 if (on(*att, CANDISEASE) &&
339 (rnd(def->t_stats.s_const) < att->t_stats.s_lvl) &&
340 off(*def, HASDISEASE)) {
341 if (ISWEARING(R_HEALTH) ||
342 player.t_ctype == C_PALADIN ||
343 player.t_ctype == C_MONK) {
344 msg("The wound heals quickly.");
345 }
346 else {
347 turn_on(*def, HASDISEASE);
348 fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER);
349 msg(terse ? "You have been diseased."
350 : "You have contracted a disease!");
351 }
352 }
353
354 /*
355 * If a rusting monster hits, you lose armor. This only applies to
356 * the player because monsters don't wear armor (for now).
357 */
358 if (on(*att, CANRUST)) {
359 if (cur_armor != NULL &&
360 cur_armor->o_which != LEATHER &&
361 cur_armor->o_which != STUDDED_LEATHER &&
362 cur_armor->o_which != PADDED_ARMOR &&
363 !(cur_armor->o_flags & ISPROT) &&
364 cur_armor->o_ac < def->t_stats.s_arm+1) {
365 msg(terse ? "Your armor weakens"
366 : "Your armor appears to be weaker now. Oh my!");
367 cur_armor->o_ac++;
368 }
369 if (cur_misc[WEAR_BRACERS] != NULL &&
370 cur_misc[WEAR_BRACERS]->o_ac > 0 &&
371 !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) {
372 cur_misc[WEAR_BRACERS]->o_ac--;
373 if (cur_misc[WEAR_BRACERS]->o_ac == 0) {
374 register struct linked_list *item;
375
376 for (item=pack; item!=NULL; item=next(item)) {
377 if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) {
378 detach(pack, item);
379 o_discard(item);
380 break;
381 }
382 }
383 msg ("Your bracers crumble and fall off!");
384 cur_misc[WEAR_BRACERS] = NULL;
385 inpack--;
386 }
387 else {
388 msg("Your bracers weaken!");
389 }
390 }
391 }
392
393 /*
394 * If can dissolve and hero has leather type armor. This
395 * also only applies to the player for now because of the
396 * armor.
397 */
398 if (on(*att, CANDISSOLVE) && cur_armor != NULL &&
399 (cur_armor->o_which == LEATHER ||
400 cur_armor->o_which == STUDDED_LEATHER ||
401 cur_armor->o_which == PADDED_ARMOR) &&
402 !(cur_armor->o_flags & ISPROT) &&
403 cur_armor->o_ac < def->t_stats.s_arm+1) {
404 msg(terse ? "Your armor dissolves"
405 : "Your armor appears to dissolve. Oh my!");
406 cur_armor->o_ac++;
407 }
408
409 /*
410 * If an infesting monster hits you, you get a parasite or rot.
411 * This will only affect the player until we figure out how to
412 * make it affect monsters.
413 */
414 if (on(*att, CANINFEST) &&
415 rnd(def->t_stats.s_const) < att->t_stats.s_lvl) {
416 if (ISWEARING(R_HEALTH) ||
417 player.t_ctype == C_PALADIN ||
418 player.t_ctype == C_MONK) {
419 msg("The wound heals quickly.");
420 }
421 else {
422 turn_off(*att, CANINFEST);
423 msg(terse ? "You have been infested."
424 : "You have contracted a parasitic infestation!");
425 infest_dam++;
426 turn_on(*def, HASINFEST);
427 }
428 }
429
430 /*
431 * Does it take wisdom away? This currently affects only
432 * the player because of its temporary nature.
433 */
434 if (on(*att, TAKEWISDOM) &&
435 !save(VS_MAGIC, def, 0) &&
436 !ISWEARING(R_SUSABILITY)) {
437 add_abil[A_WISDOM](-1);
438 }
439
440 /*
441 * Does it take intelligence away? This currently affects
442 * only the player because of its temporary nature.
443 */
444 if (on(*att, TAKEINTEL) &&
445 !save(VS_MAGIC, &player, 0) &&
446 !ISWEARING(R_SUSABILITY)) {
447 add_abil[A_INTELLIGENCE](-1);
448 }
449
450 /*
451 * Cause fear by touching. This currently affects only
452 * the player until we figure out how we want it to
453 * affect monsters.
454 */
455 if (on(*att, TOUCHFEAR)) {
456 turn_off(*att, TOUCHFEAR);
457 if (!ISWEARING(R_HEROISM) &&
458 !save(VS_WAND, def, 0) &&
459 !(on(*def, ISFLEE) && (def->t_dest == &att->t_pos))) {
460 turn_on(*def, ISFLEE);
461 def->t_dest = &att->t_pos;
462 msg("%s's touch terrifies you.", prname(attname, TRUE));
463
464 /* It is okay to turn tail */
465 if (!def_player) def->t_oldpos = def->t_pos;
466 }
467 }
468
469 /*
470 * Make the hero dance (as in otto's irresistable dance)
471 * This should be fairly easy to do to monsters, but
472 * we'll restrict it to players until we decide what to
473 * do about the temporary nature.
474 */
475 if (on(*att, CANDANCE) &&
476 !on(*def, ISDANCE) &&
477 def->t_action != A_FREEZE &&
478 !save(VS_MAGIC, def, -4)) {
479 turn_off(*att, CANDANCE);
480 turn_on(*def, ISDANCE);
481 msg("You begin to dance uncontrollably!");
482 fuse(undance, 0, roll(2,4), AFTER);
483 }
484
485 /*
486 * Suffocating our hero. Monsters don't get suffocated.
487 * That's too hard for now.
488 */
489 if (on(*att, CANSUFFOCATE) &&
490 !ISWEARING(R_FREEDOM) &&
491 rnd(100) < 25 &&
492 (find_slot(suffocate) == 0)) {
493 turn_on(*att, DIDSUFFOCATE);
494 msg("%s is beginning to suffocate you.", prname(attname, TRUE));
495 fuse(suffocate, 0, roll(9,3), AFTER);
496 }
497
498 /*
499 * some creatures stops the poor guy from moving.
500 * How can we do this to a monster?
501 */
502 if (on(*att,CANHOLD) && off(*att,DIDHOLD) && !ISWEARING(R_FREEDOM)){
503 turn_on(*def, ISHELD);
504 turn_on(*att, DIDHOLD);
505 hold_count++;
506 }
507
508 /*
509 * Sucker will suck blood and run. This
510 * should be easy to have happen to a monster,
511 * but we have to decide how to handle the fleeing.
512 */
513 if (on(*att, CANDRAW)) {
514 turn_off(*att, CANDRAW);
515 turn_on(*att, ISFLEE);
516 msg("%s sates itself with your blood.", prname(attname, TRUE));
517 if ((def->t_stats.s_hpt -= 12) <= 0) return(att->t_index);
518
519 /* It is okay to turn tail */
520 att->t_oldpos = att->t_pos;
521 }
522
523 /*
524 * Bad smell will force a reduction in strength.
525 * This will happen only to the player because of
526 * the temporary nature.
527 */
528 if (on(*att, CANSMELL)) {
529 turn_off(*att, CANSMELL);
530 if (save(VS_MAGIC, def, 0) || ISWEARING(R_SUSABILITY))
531 msg("You smell an unpleasant odor.");
532 else {
533 int odor_str = -(rnd(6)+1);
534
535 msg("You are overcome by a foul odor.");
536 if (lost_str == 0) {
537 chg_str(odor_str);
538 fuse(res_strength, 0, SMELLTIME, AFTER);
539 lost_str -= odor_str;
540 }
541 else lengthen(res_strength, SMELLTIME);
542 }
543 }
544
545 /*
546 * The monsters touch slows the defendant down.
547 */
548 if (on(*att, TOUCHSLOW)) {
549 turn_off(*att, TOUCHSLOW);
550 if (!save(VS_PARALYZATION, def, 0))
551 add_slow();
552 }
553
554 /*
555 * Rotting only affects the player.
556 */
557 if (on(*att, CANROT)) {
558 if (!ISWEARING(R_HEALTH) &&
559 player.t_ctype != C_PALADIN &&
560 player.t_ctype != C_MONK &&
561 !save(VS_POISON, def, 0) &&
562 off(*def, DOROT)) {
563 turn_on(*def, DOROT);
564 msg("You feel your skin starting to rot away!");
565 }
566 }
567
568 /*
569 * Monsters should be able to steal gold from anyone,
570 * but until this is rewritten, they will only steal
571 * from the player (tough break).
572 */
573 if (on(*att, STEALGOLD)) {
574 /*
575 * steal some gold
576 */
577 register long lastpurse;
578 register struct linked_list *item;
579 register struct object *obj;
580
581 lastpurse = purse;
582 purse -= GOLDCALC + GOLDCALC;
583 if (!save(VS_MAGIC, def, att->t_stats.s_lvl/10)) {
584 if (on(*att, ISUNIQUE))
585 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
586 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
587 }
588 if (purse < 0)
589 purse = 0;
590 if (purse != lastpurse) {
591 msg("Your purse feels lighter");
592
593 /* Give the gold to the thief */
594 for (item=att->t_pack; item != NULL; item=next(item)) {
595 obj = OBJPTR(item);
596 if (obj->o_type == GOLD) {
597 obj->o_count += lastpurse - purse;
598 break;
599 }
600 }
601
602 /* Did we do it? */
603 if (item == NULL) { /* Then make some */
604 item = new_item(sizeof *obj);
605 obj = OBJPTR(item);
606 obj->o_type = GOLD;
607 obj->o_count = lastpurse - purse;
608 obj->o_hplus = obj->o_dplus = 0;
609 strncpy(obj->o_damage, "0d0", sizeof(obj->o_damage));
610 strncpy(obj->o_hurldmg, "0d0", sizeof(obj->o_hurldmg));
611 obj->o_ac = 11;
612 obj->contents = NULL;
613 obj->o_group = 0;
614 obj->o_flags = 0;
615 obj->o_mark[0] = '\0';
616 obj->o_pos = att->t_pos;
617
618 attach(att->t_pack, item);
619 }
620 }
621
622 turn_on(*att, ISFLEE);
623 turn_on(*att, ISINVIS);
624
625 /* It is okay to turn tail */
626 att->t_oldpos = att->t_pos;
627 }
628 }
629
630 /*
631 * Stealing happens last since the monster disappears
632 * after the act.
633 */
634 if (on(*att, STEALMAGIC)) {
635 register struct linked_list *list, *steal;
636 register struct object *obj;
637 register int nobj;
638
639 /*
640 * steal a magic item, look through the pack
641 * and pick out one we like.
642 */
643 steal = NULL;
644 for (nobj = 0, list = def->t_pack; list != NULL; list = next(list))
645 {
646 obj = OBJPTR(list);
647 if (!is_current(obj) &&
648 list != def->t_using &&
649 obj->o_type != RELIC &&
650 is_magic(obj) &&
651 rnd(++nobj) == 0)
652 steal = list;
653 }
654 if (steal != NULL)
655 {
656 register struct object *obj;
657 struct linked_list *item;
658
659 obj = OBJPTR(steal);
660 if (on(*att, ISUNIQUE))
661 monsters[att->t_index].m_normal = TRUE;
662 item = find_mons(att->t_pos.y, att->t_pos.x);
663
664 killed(item, FALSE, FALSE, FALSE); /* Remove the attacker */
665
666 if (obj->o_count > 1 && obj->o_group == 0) {
667 register int oc;
668
669 oc = --(obj->o_count);
670 obj->o_count = 1;
671 if (def_player)
672 msg("%s stole %s!", prname(attname, TRUE),
673 inv_name(obj, TRUE));
674 obj->o_count = oc;
675 }
676 else {
677 if (def_player) {
678 msg("%s stole %s!", prname(attname, TRUE),
679 inv_name(obj, TRUE));
680
681 /* If this is a relic, clear its holding field */
682 if (obj->o_type == RELIC)
683 cur_relic[obj->o_which] = 0;
684
685 inpack--;
686 }
687
688 detach(def->t_pack, steal);
689 o_discard(steal);
690 }
691
692 updpack(FALSE, def);
693 }
694 }
695 }
696
697 /* Didn't kill the defender */
698 return(0);
699 }