Mercurial > hg > early-roguelike
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arogue7/effects.c Fri May 08 15:24:40 2015 -0400 @@ -0,0 +1,699 @@ +/* + * effects.c - functions for dealing with appllying effects to monsters + * + * Advanced Rogue + * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "curses.h" +#include "rogue.h" + +/* + * effect: + * Check for effects of one thing hitting another thing. Return + * the reason code if the defender is killed. Otherwise return 0. + */ +effect(att, def, weap, thrown, see_att, see_def) +register struct thing *att, *def; +struct object *weap; +bool thrown; +register bool see_att, see_def; +{ + register bool att_player, def_player; + char attname[LINELEN+1], defname[LINELEN+1]; + + /* See if the attacker or defender is the player */ + att_player = (att == &player); + def_player = (def == &player); + + /* + * If the player could see the attacker or defender, they can't + * surprise anymore (don't bother checking if they could). + */ + if (see_att) turn_off(*att, CANSURPRISE); + if (see_def) turn_off(*def, CANSURPRISE); + + /* What are the attacker and defender names? */ + if (att_player) strcpy(attname, "you"); + else { + if (see_att) strcpy(attname, monster_name(att)); + else strcpy(attname, "something"); + } + + if (def_player) strcpy(defname, "you"); + else { + if (see_def) strcpy(defname, monster_name(def)); + else strcpy(defname, "something"); + } + + /* + * See what happens to the attacker first. We can skip this + * whole section, however, if the defender is the player. + * Nothing happens (yet) to anyone just for hitting the player. + */ + if (!def_player) { + if (!thrown) { /* Some things require a direct hit. */ + /* + * If the attacker hits a rusting monster, The weapon + * may be damaged + */ + if (on(*def, CANRUST) && weap && + weap->o_type != RELIC && (weap->o_flags & ISMETAL) && + !(weap->o_flags & ISPROT)) { + if ((weap->o_hplus < 1 && weap->o_dplus < 1) || + roll(1,20) < weap->o_hplus+weap->o_dplus+10) { + if (rnd(100) < 50) weap->o_hplus--; + else weap->o_dplus--; + if (att_player) + msg(terse ? "Your %s weakens!" + : "Your %s appears to be weaker now!", + weaps[weap->o_which].w_name); + } + } + } + + /* If the attacker hit something that shrieks, wake the dungeon */ + if (on(*def, CANSHRIEK)) { + turn_off(*def, CANSHRIEK); + if (see_def) + msg("%s emits a piercing shriek.", prname(defname, TRUE)); + else msg("You hear a piercing shriek."); + aggravate(TRUE, TRUE); + } + + /* + * does the creature explode when hit? + */ + if (on(*def, CANEXPLODE)) { + if (see_def) msg("%s explodes!", prname(defname, TRUE)); + else msg("You hear a tremendous explosion!"); + explode(def); + if (pstats.s_hpt <= 0) + death(def->t_index); + } + } + + /* + * Now let's see what happens to the defender. Start out with + * the things that everyone can do. Then exit if the attacker + * is the player. + */ + if (!thrown) { + /* + * Can the player confuse? + */ + if (on(*att, CANHUH) && att_player) { + msg("Your hands stop glowing red."); + if (off(*def, ISCLEAR) && + (off(*def, ISUNIQUE) || !save(VS_MAGIC, def, 0))) { + if (see_def) msg("%s appears confused.", prname(defname, TRUE)); + turn_on(*def, ISHUH); + } + turn_off(*att, CANHUH); + } + + /* Return now if the attacker is the player. */ + if (att_player) return(0); + + /* + * Some monsters may take half your hit points + */ + if (on(*att, CANSUCK) && !save(VS_MAGIC, def, 0)) { + if (def->t_stats.s_hpt == 1) return(att->t_index); /* Killed! */ + else { + def->t_stats.s_hpt /= 2; + if (def_player) + msg("You feel your life force being drawn from you."); + } + } + + /* + * If a hugging monster hits, it may SQUEEEEEEEZE. + */ + if (on(*att, CANHUG)) { + if (roll(1,20) >= 18 || roll(1,20) >= 18) { + if (def_player) + msg("%s squeezes you against itself.", + prname(attname, TRUE)); + else if (see_att) + msg("%s squeezes hard.", prname(attname, TRUE)); + + if ((def->t_stats.s_hpt -= roll(2,8)) <= 0) + return(att->t_index); + } + } + + /* + * Some monsters have poisonous bites. + */ + if (on(*att, CANPOISON) && !save(VS_POISON, def, 0)) { + if (def_player) { + if (ISWEARING(R_SUSABILITY)) + msg(terse ? "Sting has no effect" + : "A sting momentarily weakens you"); + else { + chg_str(-1); + msg(terse ? "A sting has weakened you" : + "You feel a sting in your arm and now feel weaker"); + } + } + else { + /* Subtract a strength point and see if it kills it */ + if (--def->t_stats.s_str <= 0) return(D_STRENGTH); + } + } + + /* + * Turning to stone: + */ + if (on(*att, TOUCHSTONE)) { + if (def_player) turn_off(*att, TOUCHSTONE); + if (on(*def, CANINWALL)) { + if (def_player) + msg("%s's touch has no effect.", prname(attname, TRUE)); + } + else { + if (!save(VS_PETRIFICATION, def, 0) && rnd(100) < 10) { + if (def_player) { + msg("Your body begins to solidify."); + msg("You are turned to stone !!! --More--"); + wait_for(' '); + return(D_PETRIFY); + } + else { + /* The monster got stoned! */ + turn_on(*def, ISSTONE); + turn_off(*def, ISRUN); + turn_off(*def, ISINVIS); + turn_off(*def, ISDISGUISE); + if (see_def) + msg("%s turns to stone.", prname(defname, TRUE)); + else if (cansee(unc(def->t_pos))) + msg("A new statue appears!"); + } + } + else if (def->t_action != A_FREEZE) { + if (def_player) + msg("%s's touch stiffens your limbs.", + prname(attname, TRUE)); + else if (see_def) + msg("%s appears to freeze.", prname(defname, TRUE)); + + def->t_no_move += movement(def) * STONETIME; + def->t_action = A_FREEZE; + } + } + } + + /* + * Wraiths might drain energy levels + */ + if ((on(*att, CANDRAIN) || on(*att, DOUBLEDRAIN)) && + !save(VS_POISON, def, 3-(att->t_stats.s_lvl/5))) { + if (def_player) { + lower_level(att->t_index); + if (on(*att, DOUBLEDRAIN)) lower_level(att->t_index); + turn_on(*att, DIDDRAIN); + } + else { + def->t_stats.s_hpt -= roll(1, 8); + def->t_stats.s_lvl--; + if (on(*att, DOUBLEDRAIN)) { + def->t_stats.s_hpt -= roll(1, 8); + def->t_stats.s_lvl--; + } + if (see_def) + msg("%s appears less skillfull.", prname(defname, TRUE)); + + /* Did it kill it? */ + if (def->t_stats.s_hpt <= 0 || + def->t_stats.s_lvl <= 0) + return(att->t_index); + } + } + + /* + * Paralyzation: + */ + if (on(*att, CANPARALYZE) && def->t_action != A_FREEZE) { + if (def_player) turn_off(*att, CANPARALYZE); + if (!save(VS_PARALYZATION, def, 0)) { + if (on(*def, CANINWALL)) { + if (def_player) + msg("%s's touch has no effect.", prname(attname, TRUE)); + } + else { + if (def_player) + msg("%s's touch paralyzes you.", prname(attname, TRUE)); + else if (see_def) + msg("%s appears to freeze.", prname(defname, TRUE)); + + def->t_no_move += movement(def) * FREEZETIME; + def->t_action = A_FREEZE; + } + } + } + + /* + * Painful wounds make the defendant faint + */ + if (on(*att, CANPAIN) && def->t_action != A_FREEZE) { + if (def_player) turn_off(*att, CANPAIN); + if (!ISWEARING(R_ALERT) && !save(VS_POISON, def, 0)) { + if (def_player) + msg("You faint from the painful wound"); + else if (see_def) + msg("%s appears to faint.", prname(defname, TRUE)); + + def->t_no_move += movement(def) * PAINTIME; + def->t_action = A_FREEZE; + } + } + + /* + * Some things currently affect only the player. Let's make + * a check here so we don't have to check for each thing. + */ + if (def_player) { + /* + * Stinking monsters make the defender weaker (to hit). For now + * this will only affect the player. We may later add the HASSTINK + * effect to monsters, too. + */ + if (on(*att, CANSTINK)) { + turn_off(*att, CANSTINK); + if (!save(VS_POISON, def, 0)) { + msg("The stench of %s sickens you.", + prname(attname, FALSE)); + if (on(player, HASSTINK)) lengthen(unstink, STINKTIME); + else { + turn_on(player, HASSTINK); + fuse(unstink, 0, STINKTIME, AFTER); + } + } + } + + /* + * Chilling monster reduces strength each time. This only + * affects the player for now because of its temporary nature. + */ + if (on(*att, CANCHILL)) { + if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, def, 0)) { + msg("You cringe at %s's chilling touch.", + prname(attname, FALSE)); + chg_str(-1); + if (lost_str++ == 0) + fuse(res_strength, 0, CHILLTIME, AFTER); + else lengthen(res_strength, CHILLTIME); + } + } + + /* + * Itching monsters reduce dexterity (temporarily). This only + * affects the player for now because of its temporary nature. + */ + if (on(*att, CANITCH) && !save(VS_POISON, def, 0)) { + msg("The claws of %s scratch you.", prname(attname, FALSE)); + if (ISWEARING(R_SUSABILITY)) { + msg("The scratch has no effect"); + } + else { + add_abil[A_DEXTERITY](-1); + } + } + + + /* + * If a disease-carrying monster hits, there is a chance the + * defender will catch the disease. This only applies to the + * player for now because of the temporary nature. + */ + if (on(*att, CANDISEASE) && + (rnd(def->t_stats.s_const) < att->t_stats.s_lvl) && + off(*def, HASDISEASE)) { + if (ISWEARING(R_HEALTH) || + player.t_ctype == C_PALADIN || + player.t_ctype == C_MONK) { + msg("The wound heals quickly."); + } + else { + turn_on(*def, HASDISEASE); + fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER); + msg(terse ? "You have been diseased." + : "You have contracted a disease!"); + } + } + + /* + * If a rusting monster hits, you lose armor. This only applies to + * the player because monsters don't wear armor (for now). + */ + if (on(*att, CANRUST)) { + if (cur_armor != NULL && + cur_armor->o_which != LEATHER && + cur_armor->o_which != STUDDED_LEATHER && + cur_armor->o_which != PADDED_ARMOR && + !(cur_armor->o_flags & ISPROT) && + cur_armor->o_ac < def->t_stats.s_arm+1) { + msg(terse ? "Your armor weakens" + : "Your armor appears to be weaker now. Oh my!"); + cur_armor->o_ac++; + } + if (cur_misc[WEAR_BRACERS] != NULL && + cur_misc[WEAR_BRACERS]->o_ac > 0 && + !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) { + cur_misc[WEAR_BRACERS]->o_ac--; + if (cur_misc[WEAR_BRACERS]->o_ac == 0) { + register struct linked_list *item; + + for (item=pack; item!=NULL; item=next(item)) { + if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) { + detach(pack, item); + o_discard(item); + break; + } + } + msg ("Your bracers crumble and fall off!"); + cur_misc[WEAR_BRACERS] = NULL; + inpack--; + } + else { + msg("Your bracers weaken!"); + } + } + } + + /* + * If can dissolve and hero has leather type armor. This + * also only applies to the player for now because of the + * armor. + */ + if (on(*att, CANDISSOLVE) && cur_armor != NULL && + (cur_armor->o_which == LEATHER || + cur_armor->o_which == STUDDED_LEATHER || + cur_armor->o_which == PADDED_ARMOR) && + !(cur_armor->o_flags & ISPROT) && + cur_armor->o_ac < def->t_stats.s_arm+1) { + msg(terse ? "Your armor dissolves" + : "Your armor appears to dissolve. Oh my!"); + cur_armor->o_ac++; + } + + /* + * If an infesting monster hits you, you get a parasite or rot. + * This will only affect the player until we figure out how to + * make it affect monsters. + */ + if (on(*att, CANINFEST) && + rnd(def->t_stats.s_const) < att->t_stats.s_lvl) { + if (ISWEARING(R_HEALTH) || + player.t_ctype == C_PALADIN || + player.t_ctype == C_MONK) { + msg("The wound heals quickly."); + } + else { + turn_off(*att, CANINFEST); + msg(terse ? "You have been infested." + : "You have contracted a parasitic infestation!"); + infest_dam++; + turn_on(*def, HASINFEST); + } + } + + /* + * Does it take wisdom away? This currently affects only + * the player because of its temporary nature. + */ + if (on(*att, TAKEWISDOM) && + !save(VS_MAGIC, def, 0) && + !ISWEARING(R_SUSABILITY)) { + add_abil[A_WISDOM](-1); + } + + /* + * Does it take intelligence away? This currently affects + * only the player because of its temporary nature. + */ + if (on(*att, TAKEINTEL) && + !save(VS_MAGIC, &player, 0) && + !ISWEARING(R_SUSABILITY)) { + add_abil[A_INTELLIGENCE](-1); + } + + /* + * Cause fear by touching. This currently affects only + * the player until we figure out how we want it to + * affect monsters. + */ + if (on(*att, TOUCHFEAR)) { + turn_off(*att, TOUCHFEAR); + if (!ISWEARING(R_HEROISM) && + !save(VS_WAND, def, 0) && + !(on(*def, ISFLEE) && (def->t_dest == &att->t_pos))) { + turn_on(*def, ISFLEE); + def->t_dest = &att->t_pos; + msg("%s's touch terrifies you.", prname(attname, TRUE)); + + /* It is okay to turn tail */ + if (!def_player) def->t_oldpos = def->t_pos; + } + } + + /* + * Make the hero dance (as in otto's irresistable dance) + * This should be fairly easy to do to monsters, but + * we'll restrict it to players until we decide what to + * do about the temporary nature. + */ + if (on(*att, CANDANCE) && + !on(*def, ISDANCE) && + def->t_action != A_FREEZE && + !save(VS_MAGIC, def, -4)) { + turn_off(*att, CANDANCE); + turn_on(*def, ISDANCE); + msg("You begin to dance uncontrollably!"); + fuse(undance, 0, roll(2,4), AFTER); + } + + /* + * Suffocating our hero. Monsters don't get suffocated. + * That's too hard for now. + */ + if (on(*att, CANSUFFOCATE) && + !ISWEARING(R_FREEDOM) && + rnd(100) < 25 && + (find_slot(suffocate) == 0)) { + turn_on(*att, DIDSUFFOCATE); + msg("%s is beginning to suffocate you.", prname(attname, TRUE)); + fuse(suffocate, 0, roll(9,3), AFTER); + } + + /* + * some creatures stops the poor guy from moving. + * How can we do this to a monster? + */ + if (on(*att,CANHOLD) && off(*att,DIDHOLD) && !ISWEARING(R_FREEDOM)){ + turn_on(*def, ISHELD); + turn_on(*att, DIDHOLD); + hold_count++; + } + + /* + * Sucker will suck blood and run. This + * should be easy to have happen to a monster, + * but we have to decide how to handle the fleeing. + */ + if (on(*att, CANDRAW)) { + turn_off(*att, CANDRAW); + turn_on(*att, ISFLEE); + msg("%s sates itself with your blood.", prname(attname, TRUE)); + if ((def->t_stats.s_hpt -= 12) <= 0) return(att->t_index); + + /* It is okay to turn tail */ + att->t_oldpos = att->t_pos; + } + + /* + * Bad smell will force a reduction in strength. + * This will happen only to the player because of + * the temporary nature. + */ + if (on(*att, CANSMELL)) { + turn_off(*att, CANSMELL); + if (save(VS_MAGIC, def, 0) || ISWEARING(R_SUSABILITY)) + msg("You smell an unpleasant odor."); + else { + int odor_str = -(rnd(6)+1); + + msg("You are overcome by a foul odor."); + if (lost_str == 0) { + chg_str(odor_str); + fuse(res_strength, 0, SMELLTIME, AFTER); + lost_str -= odor_str; + } + else lengthen(res_strength, SMELLTIME); + } + } + + /* + * The monsters touch slows the defendant down. + */ + if (on(*att, TOUCHSLOW)) { + turn_off(*att, TOUCHSLOW); + if (!save(VS_PARALYZATION, def, 0)) + add_slow(); + } + + /* + * Rotting only affects the player. + */ + if (on(*att, CANROT)) { + if (!ISWEARING(R_HEALTH) && + player.t_ctype != C_PALADIN && + player.t_ctype != C_MONK && + !save(VS_POISON, def, 0) && + off(*def, DOROT)) { + turn_on(*def, DOROT); + msg("You feel your skin starting to rot away!"); + } + } + + /* + * Monsters should be able to steal gold from anyone, + * but until this is rewritten, they will only steal + * from the player (tough break). + */ + if (on(*att, STEALGOLD)) { + /* + * steal some gold + */ + register long lastpurse; + register struct linked_list *item; + register struct object *obj; + + lastpurse = purse; + purse -= GOLDCALC + GOLDCALC; + if (!save(VS_MAGIC, def, att->t_stats.s_lvl/10)) { + if (on(*att, ISUNIQUE)) + purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; + purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; + } + if (purse < 0) + purse = 0; + if (purse != lastpurse) { + msg("Your purse feels lighter"); + + /* Give the gold to the thief */ + for (item=att->t_pack; item != NULL; item=next(item)) { + obj = OBJPTR(item); + if (obj->o_type == GOLD) { + obj->o_count += lastpurse - purse; + break; + } + } + + /* Did we do it? */ + if (item == NULL) { /* Then make some */ + item = new_item(sizeof *obj); + obj = OBJPTR(item); + obj->o_type = GOLD; + obj->o_count = lastpurse - purse; + obj->o_hplus = obj->o_dplus = 0; + strncpy(obj->o_damage, "0d0", sizeof(obj->o_damage)); + strncpy(obj->o_hurldmg, "0d0", sizeof(obj->o_hurldmg)); + obj->o_ac = 11; + obj->contents = NULL; + obj->o_group = 0; + obj->o_flags = 0; + obj->o_mark[0] = '\0'; + obj->o_pos = att->t_pos; + + attach(att->t_pack, item); + } + } + + turn_on(*att, ISFLEE); + turn_on(*att, ISINVIS); + + /* It is okay to turn tail */ + att->t_oldpos = att->t_pos; + } + } + + /* + * Stealing happens last since the monster disappears + * after the act. + */ + if (on(*att, STEALMAGIC)) { + register struct linked_list *list, *steal; + register struct object *obj; + register int nobj; + + /* + * steal a magic item, look through the pack + * and pick out one we like. + */ + steal = NULL; + for (nobj = 0, list = def->t_pack; list != NULL; list = next(list)) + {