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