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