static int modify_damage(int dmg, string type, object foe, string loc, int prot, int resist, int vuln, int ac, object wpn) { object env; if (!objectp(env = environment())) { return 0; } if (lower_case(type) == "fire") { tell_room(env, "The demon does not seem to be affected by the fire.\n"); heal_self(dmg / 2); return -dmg; } if (is_evil(wpn)) { return -dmg / 2; } if (dmg > 30) { command("scream ago"); } if (resist < -10) { command("cackle"); } if (prot < -20) { command("hydr ehv"); } if (dmg < 10 && random(100) > 25) { return 0; } if (is_good(wpn)) { tell_object(foe, "Your " + wpn->query_name() + " rips straight " + "through the demon's skin!\n"); return 2 * dmg; } if (is_good(foe)) { tell_object(foe, "You rip straight through the demon's skin.\n"); return dmg; } return 0; }
/* * quaff: * Let the hero drink a potion */ int quaff() { struct object *obj; struct linked_list *item, *titem; struct thing *th; int wh; char buf[LINLEN]; bool bless, curse; /* * Make certain that it is somethings that we want to drink */ if ((item = get_item("quaff", POTION)) == NULL) return 0; obj = OBJPTR(item); if (obj->o_type != POTION) { msg("That's undrinkable!"); after = FALSE; return 0; } wh = obj->o_which; bless = o_on(obj, ISBLESS); curse = o_on(obj, ISCURSED); del_pack(item); /* get rid of it */ /* * Calculate the effect it has on the poor guy. */ switch(wh) { case P_CONFUSE: if (!bless) { if (pl_on(ISINVINC)) msg("You remain level-headed."); else { chg_abil(WIS,-1,TRUE); /* confuse his mind */ if (pl_off(ISHUH)) { msg("Wait, what's going on here. Huh? What? Who?"); if (pl_on(ISHUH)) lengthen(unconfuse,rnd(8)+HUHDURATION); else fuse(unconfuse,TRUE,rnd(8)+HUHDURATION); player.t_flags |= ISHUH; } } p_know[P_CONFUSE] = TRUE; } when P_POISON: if (!bless) { if (pl_off(ISINVINC) && !iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) { chg_abil(CON,-1,TRUE); chg_abil(STR,-(rnd(3)+1),TRUE); msg("You feel very sick now."); } else msg("You feel momentarily sick."); p_know[P_POISON] = TRUE; } when P_HEALING: if (!curse) { heal_self(4, TRUE); msg("You begin to feel better."); if (!iswearing(R_SLOW)) notslow(FALSE); sight(FALSE); p_know[P_HEALING] = TRUE; } when P_STRENGTH: if (!curse) { msg("You feel stronger, now. What bulging muscles!"); chg_abil(STR,1,TRUE); p_know[P_STRENGTH] = TRUE; } when P_MFIND: /* * Potion of monster detection - find all monsters */ if (mlist != NULL && !curse) { dispmons(); mpos = 0; msg("You begin to sense the presence of monsters--More--"); p_know[P_MFIND] = TRUE; wait_for(cw,' '); msg(""); /* clear line */ } else msg("You have a strange feeling for a moment, then it passes."); when P_TFIND: /* * Potion of magic detection. Show the potions and scrolls */ if (lvl_obj != NULL && !curse) { struct linked_list *mobj; struct object *tp; bool show; show = FALSE; wclear(hw); for (mobj = lvl_obj; mobj != NULL; mobj = next(mobj)) { tp = OBJPTR(mobj); if (is_magic(tp)) { show = TRUE; mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, MAGIC); } } for(titem = mlist; titem != NULL; titem = next(titem)) { struct linked_list *pitem; th = THINGPTR(titem); for(pitem=th->t_pack;pitem!=NULL;pitem=next(pitem)) { if (is_magic(ldata(pitem))) { show = TRUE; mvwaddch(hw,th->t_pos.y, th->t_pos.x, MAGIC); } } } if (show) { msg("You begin to sense the presence of magic."); overlay(hw,cw); p_know[P_TFIND] = TRUE; break; } } msg("You have a strange feeling for a moment, then it passes."); when P_PARALYZE: if (!bless) { if (pl_on(ISINVINC)) msg("You feel numb for a moment."); else { msg("You can't move."); player.t_nocmd = HOLDTIME; } p_know[P_PARALYZE] = TRUE; } when P_SEEINVIS: if (!curse) { int invlen = roll(40,20); msg("This potion tastes like %s juice.", fruit); if (pl_off(CANSEE)) { player.t_flags |= CANSEE; fuse(unsee, TRUE, invlen); light(&hero); } else lengthen(unsee, invlen); sight(FALSE); } when P_RAISE: if (!curse) { msg("You suddenly feel much more skillful."); p_know[P_RAISE] = TRUE; chg_abil(DEX,1,TRUE); chg_abil(WIS,1,TRUE); chg_abil(CON,1,TRUE); raise_level(); } when P_XHEAL: if (!curse) { heal_self(8, TRUE); if (rnd(100) < 50) chg_abil(CON,1,TRUE); msg("You begin to feel much better."); p_know[P_XHEAL] = TRUE; if (!iswearing(R_SLOW)) notslow(FALSE); unconfuse(); extinguish(unconfuse); sight(FALSE); } when P_HASTE: if (!curse) { add_haste(TRUE); msg("You feel yourself moving much faster."); p_know[P_HASTE] = TRUE; } when P_INVINC: if (!curse) { int time = rnd(400) + 350; msg("You feel invincible."); if (player.t_flags & ISINVINC) lengthen(notinvinc,time); else fuse(notinvinc,TRUE,time); player.t_flags |= ISINVINC; p_know[P_INVINC] = TRUE; } when P_SMART: if (!curse) { msg("You feel more perceptive."); p_know[P_SMART] = TRUE; chg_abil(WIS,1,TRUE); } when P_RESTORE: if (!curse) { msg("Hey, this tastes great. You feel warm all over."); him->s_re = max_stats.s_re; him->s_ef = max_stats.s_re; ringabil(); /* add in rings */ updpack(); /* update weight */ p_know[P_RESTORE] = TRUE; extinguish(rchg_str); /* kill restore in from ulodyte */ } when P_BLIND: if (!bless) { if (pl_on(ISINVINC)) msg("The light dims for a moment."); else { chg_abil(WIS,-1,TRUE); msg("A cloak of darkness falls around you."); if (pl_off(ISBLIND)) { player.t_flags |= ISBLIND; fuse(sight, TRUE, rnd(400) + 450); light(&hero); } } p_know[P_BLIND] = TRUE; } when P_ETH: if (!curse) { int ethlen = roll(40,20); msg("You feel more vaporous."); if (pl_on(ISETHER)) lengthen(noteth,ethlen); else fuse(noteth,TRUE,ethlen); player.t_flags |= ISETHER; p_know[P_ETH] = TRUE; } when P_NOP: msg("This potion tastes extremely dull."); when P_DEX: if (!curse) { chg_abil(DEX,1,TRUE); /* increase dexterity */ p_know[P_DEX] = TRUE; msg("You feel much more agile."); } when P_REGEN: if (!curse) { int reglen = rnd(450) + 450; if (pl_on(ISREGEN)) lengthen(notregen, reglen); else fuse(notregen, TRUE, reglen); player.t_flags |= ISREGEN; msg("You feel yourself improved."); p_know[P_REGEN] = TRUE; } when P_DECREP: case P_SUPHERO: { int howmuch = rnd(3) + 1; if (wh == P_DECREP) { if (!bless) { if (iswearing(R_SUSAB) || pl_on(ISINVINC)) { msg("You feel momentarily woozy."); howmuch = 0; } else { msg("You feel crippled."); howmuch = -howmuch; if (!iswearing(R_SUSTSTR)) chg_abil(STR,howmuch,TRUE); } } else howmuch = 0; } else { /* potion of superhero */ if (curse) howmuch = 0; msg("You feel invigorated."); chg_abil(STR,howmuch,TRUE); } chg_abil(CON,howmuch,TRUE); chg_abil(DEX,howmuch,TRUE); chg_abil(WIS,howmuch,TRUE); /* change abilities */ p_know[wh] = TRUE; } otherwise: msg("What an odd tasting potion!"); return 0; } nochange = FALSE; if (p_know[wh] && p_guess[wh]) { free(p_guess[wh]); p_guess[wh] = NULL; } else if(!p_know[wh] && p_guess[wh] == NULL) { strcpy(buf, p_colors[wh]); msg(callit); if (get_str(buf, cw) == NORM) { p_guess[wh] = new(strlen(buf) + 1); strcpy(p_guess[wh], buf); }
/** * Apply side effects from a spell attack to the player * * \param spell is the attack type * \param dam is the amount of damage caused by the attack * \param m_idx is the attacking monster * \param rlev is its level * \param seen is whether @ can see it */ static void do_side_effects(int spell, int dam, int m_idx, bool seen) { monster_type *m_ptr = cave_monster(cave, m_idx); monster_race *r_ptr = &r_info[m_ptr->r_idx]; const struct spell_effect *re_ptr; const struct mon_spell *rs_ptr = &mon_spell_table[spell]; int i, choice[99], dur = 0, j = 0, count = 0; s32b d = 0; bool sustain = FALSE, perma = FALSE, chosen[RSE_MAX] = { 0 }; /* Extract the monster level */ int rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); /* First we note all the effects we'll be doing. */ for (re_ptr = spell_effect_table; re_ptr->index < RSE_MAX; re_ptr++) { if ((re_ptr->method && (re_ptr->method == rs_ptr->index)) || (re_ptr->gf && (re_ptr->gf == rs_ptr->gf))) { /* If we have a choice of effects, we create a cum freq table */ if (re_ptr->chance) { for (i = j; i < (j + re_ptr->chance); i++) choice[i] = re_ptr->index; j = i; } else chosen[re_ptr->index] = TRUE; } } /* If we have built a cum freq table, choose an effect from it */ if (j) chosen[choice[randint0(j)]] = TRUE; /* Now we cycle through again to activate the chosen effects */ for (re_ptr = spell_effect_table; re_ptr->index < RSE_MAX; re_ptr++) { if (chosen[re_ptr->index]) { /* * Check for resistance - there are three possibilities: * 1. Immunity to the attack type if side_immune is TRUE * 2. Resistance to the attack type if it affords no immunity * 3. Resistance to the specific side-effect * * TODO - add interesting messages to the RSE_ and GF_ tables * to replace the generic ones below. (See #1376) */ if (re_ptr->res_flag) update_smart_learn(m_ptr, p_ptr, re_ptr->res_flag); if ((rs_ptr->gf && check_side_immune(rs_ptr->gf)) || check_state(p_ptr, re_ptr->res_flag, p_ptr->state.flags)) { msg("You resist the effect!"); continue; } /* Allow saving throw if available */ if (re_ptr->save && randint0(100) < p_ptr->state.skills[SKILL_SAVE]) { msg("You avoid the effect!"); continue; } /* Implement the effect */ if (re_ptr->timed) { /* Calculate base duration (m_bonus is not used) */ dur = randcalc(re_ptr->base, 0, RANDOMISE); /* Calculate the damage-dependent duration (m_bonus is * used as a cap) */ dur += damcalc(re_ptr->dam.dice, re_ptr->dam.sides * dam / 100, RANDOMISE); if (re_ptr->dam.m_bonus && (dur > re_ptr->dam.m_bonus)) dur = re_ptr->dam.m_bonus; /* Apply the effect - we have already checked for resistance */ (void)player_inc_timed(p_ptr, re_ptr->flag, dur, TRUE, FALSE); } else { switch (re_ptr->flag) { case S_INV_DAM: if (dam > 0) inven_damage(p_ptr, re_ptr->gf, MIN(dam * randcalc(re_ptr->dam, 0, RANDOMISE), 300)); break; case S_TELEPORT: /* m_bonus is used as a clev filter */ if (!re_ptr->dam.m_bonus || randint1(re_ptr->dam.m_bonus) > p_ptr->lev) teleport_player(randcalc(re_ptr->base, 0, RANDOMISE)); break; case S_TELE_TO: teleport_player_to(m_ptr->fy, m_ptr->fx); break; case S_TELE_LEV: teleport_player_level(); break; case S_TELE_SELF: teleport_away(m_ptr, randcalc(re_ptr->base, 0, RANDOMISE)); break; case S_DRAIN_LIFE: d = re_ptr->base.base + (p_ptr->exp * re_ptr->base.sides / 100) * MON_DRAIN_LIFE; msg("You feel your life force draining away!"); player_exp_lose(p_ptr, d, FALSE); break; case S_DRAIN_STAT: /* m_bonus is used as a flag */ if (re_ptr->dam.m_bonus > 0) sustain = TRUE; if (abs(re_ptr->dam.m_bonus) > 1) perma = TRUE; drain_stats(randcalc(re_ptr->base, 0, RANDOMISE), sustain, perma); break; case S_SWAP_STAT: swap_stats(); break; case S_DRAIN_ALL: msg("You're not as powerful as you used to be..."); for (i = 0; i < A_MAX; i++) player_stat_dec(p_ptr, i, FALSE); break; case S_DISEN: (void)apply_disenchant(0); break; case S_DRAIN_MANA: drain_mana(m_idx, rlev, seen); break; case S_HEAL: heal_self(m_idx, rlev, seen); break; case S_DARKEN: (void)unlight_area(0, 3); break; case S_TRAPS: (void)trap_creation(); break; case S_AGGRAVATE: aggravate_monsters(m_idx); break; case S_KIN: summon_kin_type = r_ptr->d_char; case S_MONSTER: case S_MONSTERS: case S_SPIDER: case S_HOUND: case S_HYDRA: case S_AINU: case S_ANIMAL: case S_DEMON: case S_HI_DEMON: case S_UNDEAD: case S_HI_UNDEAD: case S_WRAITH: case S_DRAGON: case S_HI_DRAGON: case S_UNIQUE: count = summon_monster_aux(re_ptr->flag, m_idx, rlev, re_ptr->base.base); /* In the special case that uniques or wraiths were summoned but all were dead S_HI_UNDEAD is used instead */ if ((!count) && ((re_ptr->flag == S_WRAITH) || (re_ptr->flag == S_UNIQUE))) count = summon_monster_aux(S_HI_UNDEAD, m_idx, rlev, re_ptr->base.base); if (count && p_ptr->timed[TMD_BLIND]) msgt(rs_ptr->msgt, "You hear %s appear nearby.", (count > 1 ? "many things" : "something")); default: break; } } } } return; }