/* * creature.c: handle monster movement and attacks * * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke * * This software may be copied and distributed for educational, research, and * not for profit purposes provided that this copyright and statement are * included in all such copies. */ #include "constant.h" #include "monster.h" #include "config.h" #include "types.h" #include "externs.h" #ifdef USG #ifndef ATARIST_MWC #include #else char *strcat(); char *strcpy(); #endif #else #include #endif /* Lets do all prototypes correctly.... -CWS */ #ifndef NO_LINT_ARGS #ifdef __STDC__ static int check_mon_lite(int, int); static void get_moves(int, int *); static int monster_critical(int, int, int); static void make_attack(int); static void make_move(int, int *, int32u *); static void mon_cast_spell(int, int *); static void mon_move(int, int32u *); static void shatter_quake(int, int); static void br_wall(int, int); #else static int check_mon_lite(); static void get_moves(); static int monster_critical(); static void make_attack(); static void make_move(); static void mon_cast_spell(); static void mon_move(); static void shatter_quake(); static void br_wall(); #endif #endif /* Updates screen when monsters move about -RAK- */ void update_mon(monptr) int monptr; { register int flag; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; #ifdef ATARIST_MWC int32u holder; #endif m_ptr = &m_list[monptr]; flag = FALSE; if ((m_ptr->cdis <= MAX_SIGHT) && (!(py.flags.status & PY_BLIND) || py.flags.telepathy) && (panel_contains((int)m_ptr->fy, (int)m_ptr->fx))) { /* Wizard sight. */ if (wizard) flag = TRUE; /* if not mindless, telepathy sees -CWS */ if (py.flags.telepathy) { char c = c_list[m_ptr->mptr].cchar; const char *n = c_list[m_ptr->mptr].name; if (strchr("EMXgjvz.",c)); /* don't show these ever (elementals & golems & vorticies & xorns * "minds" are too different) -CFT */ else if (strchr("FKaclt",c)) { if (randint(5)==1) flag = TRUE; /* once in a while we see these almost mindless insects... -CFT */ } else if (c=='S' && strncmp(n, "Drider", 6) && !(c_list[m_ptr->mptr].cdefense & UNIQUE)) { if (randint(5)==1) flag = TRUE; /* once in a while show spiders, scops. But DO show drider, * Shelob, and Ungol. -CFT */ } else if (c=='m' && strncmp(n, "Death", 5)); /* don't show any molds, except the Death mold -CFT */ else if (c=='s' && !strstr(n, "ruj") && strncmp(n, "Cantor", 6)); /* don't show skeletons, but DO show druj and Cantoras -CFT */ else if (c=='i' && strncmp(n, "Blue", 4)); /* don't show icky things, except Blue icky things.. -CFT */ else if (c=='w' && strncmp(n, "Were", 4) && strncmp(n, "Gian", 4)) { if (randint(5)==1) flag = TRUE; /* occas. show worms, except Purple worms and Wereworms -CFT */ } else if (c==',' && strncmp(n, "Magic", 5)); /* don't show mushrooms, except magic 'shrooms -CFT */ else if (!(c_list[m_ptr->mptr].cdefense & MINDLESS)) flag = TRUE; /* if not mindless, they show up -CWS */ } /* Normal sight. */ if (los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) { c_ptr = &cave[m_ptr->fy][m_ptr->fx]; #ifdef GROSS_HACK /* Try to debug invis monsters...this is not 'fixed', per se * but it will correct the observed problem and also give me * a chance to trap the thing with a debugger. -CWS ******* * This should no longer be necessary, but it's harmless -CWS */ if (c_ptr->cptr != monptr) { char BUF[100]; sprintf(BUF, "Help! cptr = %d / monptr = %d, x = %d, y = %d", c_ptr->cptr, monptr, m_ptr->fx, m_ptr->fy); if (wizard) msg_print(BUF); c_ptr->cptr = monptr; } #endif /* GROSS_HACK */ r_ptr = &c_list[m_ptr->mptr]; /* moved here to allow infra to see invis -CFT */ if ((py.flags.see_infra > 0) && (m_ptr->cdis <= py.flags.see_infra)) { if (NO_INFRA & r_ptr->cdefense) /* changed to act sensibly -CFT */ c_recall[m_ptr->mptr].r_cdefense |= NO_INFRA; else flag = TRUE; /* only can see if not NO_INFRA... */ } if (c_ptr->pl || c_ptr->tl || (find_flag && m_ptr->cdis <= light_rad && player_light)) { #ifdef ATARIST_MWC holder = CM_INVISIBLE; if ((holder & r_ptr->cmove) == 0) #else if ((CM_INVISIBLE & r_ptr->cmove) == 0) #endif flag = TRUE; else if (py.flags.see_inv) { flag = TRUE; #ifdef ATARIST_MWC c_recall[m_ptr->mptr].r_cmove |= holder; #else c_recall[m_ptr->mptr].r_cmove |= CM_INVISIBLE; #endif } } } } /* Light it up. */ if (flag) { #ifdef TC_COLOR if (!no_color_flag) /* don't waste time if no color -CFT */ lite_spot((int)m_ptr->fy, (int)m_ptr->fx); /* redraw, even if lit, so MHD's change color -CFT */ #endif if (!m_ptr->ml) { disturb(1, 0); m_ptr->ml = TRUE; lite_spot((int)m_ptr->fy, (int)m_ptr->fx); screen_change = TRUE; /* notify inven_command */ } } /* Turn it off. */ else if (m_ptr->ml) { m_ptr->ml = FALSE; lite_spot((int)m_ptr->fy, (int)m_ptr->fx); screen_change = TRUE; /* notify inven_command */ } } /* Given speed, returns number of moves this turn. -RAK- */ /* NOTE: Player must always move at least once per iteration, * a slowed player is handled by moving monsters faster * * monnum = index in m_list[] now passed in, so (turn+monnum) can * be used to vary when monsters move. -CFT */ int movement_rate(monnum) int monnum; { register int ps, ms, tm, i; ps = 1 - py.flags.speed; /* this makes normal = 1, fast = 2, * v.fast = 3, slow = 0, v.slow = -1 -CFT */ ms = m_list[monnum].cspeed; i = (int)(turn & 0xFF) + (int)monnum; /* 0xFF to prevent negative values -CFT */ if (ps == ms) return 1; /* same spd as player -CFT */ if (ps<1 && ms<1) { /* both slow, swap "reciprocals" -CFT */ tm = 2 - ps; ps = 2 - ms; ms = tm; } if (ps < 1) /* then mon must be fast, or above would */ return ms * (2 - ps); /* have happened -CFT */ if (ms<1) /* then player fast... move once in a while -CFT */ return !(i % (ps * (2 - ms))); /* player faster. * This formula is not intuitive, but it effectively uses the turn counter * (offset by the monster index, so not every monster moves at same time) * to compute factional parts of movement ratios.. so that a monster 2/3 the * player's spd will move twice every 3 turns. An earlier version of this * equation performed the same result on average, but it was prone to "clumps" * of speed... if the player was spd 4, and the monster spd 2, then for each * 4 turn cycle, the monster would move 0,0,1,1. This equation will result * in 0,1,0,1, which is better. -CFT */ if (ps>ms) return (((i*ms) % ps) < ms); if (!(tm = (ms % ps))) /* divides evenly, simple case -CFT */ return (ms / ps); /* Like the player-faster formula, this is NOT intuitive. However, it * effectively uses the turn counter & monster index to decide when a * monster should get an "extra" move. It also prevents "clumps". -CFT */ return ((ms / ps) + (((i*tm) % ps) < tm)); } /* Makes sure a new creature gets lit up. -CJS- */ static int check_mon_lite(y, x) int y, x; { register int monptr; monptr = cave[y][x].cptr; if (monptr <= 1) return FALSE; else { update_mon(monptr); return m_list[monptr].ml; } } /* Choose correct directions for monster movement -RAK- */ static void get_moves(monptr, mm) int monptr; register int *mm; { int y, ay, x, ax, move_val; y = m_list[monptr].fy - char_row; x = m_list[monptr].fx - char_col; /* lvl 1..15 always afraid, 16..22 some, based on maxhp %8 : * lvl 16 7 of 8 monsters afraid [ this is for a 50th ] * lvl 22 1 of 8 monsters afraid [ level player, lower ] * lvl 23++ no afraid monsters [ level=less afraid m. ] */ if (((int16)(py.misc.lev - 34 - c_list[(m_list[monptr]).mptr].level + ((m_list[monptr].maxhp) % 8)) > 0) || m_list[monptr].monfear) { /* Run away! Run away! -DGK */ y = (-y); /* FIXME: make monsters running away more intelligent */ x = (-x); } if (y < 0) { move_val = 8; ay = (-y); } else { move_val = 0; ay = y; } if (x > 0) { move_val += 4; ax = x; } else ax = (-x); /* this has the advantage of preventing the diamond maneuvre, also faster */ if (ay > (ax << 1)) move_val += 2; else if (ax > (ay << 1)) move_val++; switch (move_val) { case 0: mm[0] = 9; if (ay > ax) { mm[1] = 8; mm[2] = 6; mm[3] = 7; mm[4] = 3; } else { mm[1] = 6; mm[2] = 8; mm[3] = 3; mm[4] = 7; } break; case 1: case 9: mm[0] = 6; if (y < 0) { mm[1] = 3; mm[2] = 9; mm[3] = 2; mm[4] = 8; } else { mm[1] = 9; mm[2] = 3; mm[3] = 8; mm[4] = 2; } break; case 2: case 6: mm[0] = 8; if (x < 0) { mm[1] = 9; mm[2] = 7; mm[3] = 6; mm[4] = 4; } else { mm[1] = 7; mm[2] = 9; mm[3] = 4; mm[4] = 6; } break; case 4: mm[0] = 7; if (ay > ax) { mm[1] = 8; mm[2] = 4; mm[3] = 9; mm[4] = 1; } else { mm[1] = 4; mm[2] = 8; mm[3] = 1; mm[4] = 9; } break; case 5: case 13: mm[0] = 4; if (y < 0) { mm[1] = 1; mm[2] = 7; mm[3] = 2; mm[4] = 8; } else { mm[1] = 7; mm[2] = 1; mm[3] = 8; mm[4] = 2; } break; case 8: mm[0] = 3; if (ay > ax) { mm[1] = 2; mm[2] = 6; mm[3] = 1; mm[4] = 9; } else { mm[1] = 6; mm[2] = 2; mm[3] = 9; mm[4] = 1; } break; case 10: case 14: mm[0] = 2; if (x < 0) { mm[1] = 3; mm[2] = 1; mm[3] = 6; mm[4] = 4; } else { mm[1] = 1; mm[2] = 3; mm[3] = 4; mm[4] = 6; } break; case 12: mm[0] = 1; if (ay > ax) { mm[1] = 2; mm[2] = 4; mm[3] = 3; mm[4] = 7; } else { mm[1] = 4; mm[2] = 2; mm[3] = 7; mm[4] = 3; } break; } } static int monster_critical(dice, sides, dam) int dice, sides, dam; { int total = dice * sides; int max = 0; if (dam == total && dam > 20) max = 1; if ((dam > (19 * total) / 20) && ((dam < 20) ? randint(20) == 1 : TRUE)) { if (dam > 20) while (randint(50) == 1) max++; if (dam > 45) return 6 + max; if (dam > 33) return 5 + max; if (dam > 25) return 4 + max; if (dam > 18) return 3 + max; if (dam > 11) return 2 + max; return 1 + max; } return 0; } /* Make an attack on the player (chuckle.) -RAK- */ static void make_attack(monptr) int monptr; { int attype, adesc, adice, asides; int i, j, damage, flag, attackn, notice, visible; int shatter = FALSE; int CUT = FALSE, STUN = FALSE; int32 gold; attid *attstr, *attstr_orig; vtype cdesc, tmp_str, ddesc; register creature_type *r_ptr; monster_type *m_ptr; register struct misc *p_ptr; register struct flags *f_ptr; register inven_type *i_ptr; int8u blinked = 0; /* flag to see if blinked away (after * steal) -CFT */ if (death) /* don't beat a dead body! */ return; m_ptr = &m_list[monptr]; r_ptr = &c_list[m_ptr->mptr]; if (r_ptr->cdefense & DESTRUCT) shatter = TRUE; if (!m_ptr->ml) (void)strcpy(cdesc, "It "); else { if (c_list[m_ptr->mptr].cdefense & UNIQUE) (void)sprintf(cdesc, "%s ", r_ptr->name); else (void)sprintf(cdesc, "The %s ", r_ptr->name); } /* For "DIED_FROM" string */ if (r_ptr->cdefense & UNIQUE) (void)sprintf(ddesc, "%s", r_ptr->name); else if (is_a_vowel(r_ptr->name[0])) (void)sprintf(ddesc, "an %s", r_ptr->name); else (void)sprintf(ddesc, "a %s", r_ptr->name); /* End DIED_FROM */ attackn = 0; attstr = r_ptr->damage; attstr_orig = attstr; /* if has no attacks (*attstr starts off 0), still loop once to accumulate * notices that it has no attacks - dbd */ while ((*attstr != 0 || attstr == attstr_orig) && !death && !blinked) { attype = monster_attacks[*attstr].attack_type; adesc = monster_attacks[*attstr].attack_desc; adice = monster_attacks[*attstr].attack_dice; asides = monster_attacks[*attstr].attack_sides; attstr++; flag = FALSE; if (((py.flags.protevil > 0) && (r_ptr->cdefense & EVIL) && ((py.misc.lev + 1) > r_ptr->level)) && (randint(100) + (py.misc.lev) > 50)) /* Random (100) + level > 50 chance for stop any attack added */ { if (m_ptr->ml) c_recall[m_ptr->mptr].r_cdefense |= EVIL; attype = 99; adesc = 99; } p_ptr = &py.misc; switch (attype) { case 1: /* Normal attack */ if (test_hit(60, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 2: /* Lose Strength */ if (test_hit(-3, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 3: /* Confusion attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 4: /* Fear attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 5: /* Fire attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 6: /* Acid attack */ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 7: /* Cold attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 8: /* Lightning attack */ if (test_hit(10, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 9: /* Corrosion attack */ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 10: /* Blindness attack */ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 11: /* Paralysis attack */ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 12: /* Steal Money */ if ((test_hit(5, (int)r_ptr->level, 0, (int)py.misc.lev, CLA_MISC_HIT)) && (py.misc.au > 0)) flag = TRUE; break; case 13: /* Steal Object */ if ((test_hit(2, (int)r_ptr->level, 0, (int)py.misc.lev, CLA_MISC_HIT)) && (inven_ctr > 0)) flag = TRUE; break; case 14: /* Poison */ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 15: /* Lose dexterity */ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 16: /* Lose constitution */ if (test_hit(0, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 17: /* Lose intelligence */ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 18: /* Lose wisdom */ if (test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 19: /* Lose experience */ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 20: /* Aggravate monsters */ flag = TRUE; break; case 21: /* Disenchant */ if (test_hit(20, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 22: /* Eat food */ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 23: /* Eat light */ if (test_hit(5, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) flag = TRUE; break; case 24: /* Eat charges */ if ((test_hit(15, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT)) && (inven_ctr > 0)) /* check to make sure an object exists */ flag = TRUE; break; case 25: /* Drain all stats */ if ((test_hit(2, (int)r_ptr->level, 0, p_ptr->pac + p_ptr->ptoac, CLA_MISC_HIT))) flag = TRUE; break; case 99: flag = TRUE; break; case 0: /* Monster has no physical attacks - dbd */ flag = TRUE; break; default: break; } /* can not strcat to cdesc because the creature may have multiple attacks */ if (flag) { disturb(1, 0); (void)strcpy(tmp_str, cdesc); CUT = STUN = FALSE; switch (adesc) { case 1: msg_print(strcat(tmp_str, "hits you.")); CUT = TRUE; STUN = TRUE; break; case 2: msg_print(strcat(tmp_str, "bites you.")); CUT = TRUE; break; case 3: msg_print(strcat(tmp_str, "claws you.")); CUT = TRUE; break; case 4: msg_print(strcat(tmp_str, "stings you.")); break; case 5: msg_print(strcat(tmp_str, "touches you.")); break; case 6: msg_print(strcat(tmp_str, "kicks you.")); break; case 7: msg_print(strcat(tmp_str, "gazes at you.")); break; case 8: msg_print(strcat(tmp_str, "breathes on you.")); break; case 9: msg_print(strcat(tmp_str, "spits on you.")); break; case 10: msg_print(strcat(tmp_str, "makes a horrible wail.")); break; case 11: msg_print(strcat(tmp_str, "embraces you.")); break; case 12: msg_print(strcat(tmp_str, "crawls on you.")); break; case 13: msg_print(strcat(tmp_str, "releases a cloud of spores.")); break; case 14: msg_print(strcat(tmp_str, "begs you for money.")); break; case 15: msg_print("You've been slimed!"); break; case 16: msg_print(strcat(tmp_str, "crushes you.")); break; case 17: msg_print(strcat(tmp_str, "tramples you.")); STUN = TRUE; break; case 18: msg_print(strcat(tmp_str, "drools on you.")); break; case 19: switch (randint(9)) { case 1: msg_print(strcat(tmp_str, "insults you!")); break; case 2: msg_print(strcat(tmp_str, "insults your mother!")); break; case 3: msg_print(strcat(tmp_str, "gives you the finger!")); break; case 4: msg_print(strcat(tmp_str, "humiliates you!")); break; case 5: msg_print(strcat(tmp_str, "wets on your leg!")); break; case 6: msg_print(strcat(tmp_str, "defiles you!")); break; case 7: msg_print(strcat(tmp_str, "dances around you!")); break; case 8: msg_print(strcat(tmp_str, "makes obscene gestures!")); break; case 9: msg_print(strcat(tmp_str, "moons you!!!")); break; } break; case 20: msg_print(strcat(tmp_str, "butts you.")); STUN = TRUE; break; case 21: msg_print(strcat(tmp_str, "charges you.")); STUN = TRUE; break; case 22: msg_print(strcat(tmp_str, "engulfs you.")); break; case 23: switch (randint(5)) { case 1: msg_print(strcat(tmp_str, "wants his mushrooms back. ")); break; case 2: msg_print(strcat(tmp_str, "tells you to get off his land. ")); break; case 3: msg_print(strcat(tmp_str, "looks for his dogs. ")); break; case 4: msg_print(strcat(tmp_str, "says 'Did you kill my Fang?' ")); break; case 5: msg_print(strcat(tmp_str, "asks 'Do you want to buy any mushrooms?' ")); break; } break; case 99: msg_print(strcat(tmp_str, "is repelled.")); break; default: /* no message for case 0 because no attacks - dbd */ break; } notice = TRUE; /* * always fail to notice attack if creature invisible, set notice and * visible here since creature may be visible when attacking and then * teleport afterwards (becoming effectively invisible) */ if (!m_ptr->ml) { visible = FALSE; notice = FALSE; } else visible = TRUE; damage = damroll(adice, asides); switch (attype) { case 0: /* No physical attacks */ /* put something here to notice if monster *has* no physical attacks -CWS */ if (!randint(10)) notice = TRUE; break; case 1: /* Normal attack */ /* round half-way case down */ damage -= ((((((p_ptr->pac + p_ptr->ptoac) > 150) ? 150 : (p_ptr->pac + p_ptr->ptoac)) * 3) / 4) * damage) / 200; take_hit(damage, ddesc); if ((damage > 23) && shatter) shatter_quake(m_ptr->fy, m_ptr->fx); break; case 2: /* Lose Strength */ take_hit(damage, ddesc); if (py.flags.sustain_str) msg_print("You feel weaker for a moment, but it passes."); else if (randint(2) == 1) { msg_print("You feel weaker."); (void)dec_stat(A_STR); } else notice = FALSE; break; case 3: /* Confusion attack */ f_ptr = &py.flags; take_hit(damage, ddesc); if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) { if (randint(2) == 1) { if (f_ptr->confused < 1) { msg_print("You feel confused."); f_ptr->confused += randint((int)r_ptr->level); } else notice = FALSE; f_ptr->confused += 3; } else notice = FALSE; } break; case 4: /* Fear attack */ f_ptr = &py.flags; take_hit(damage, ddesc); if (player_saves() || (py.misc.pclass == 1 && randint(3) == 1) || py.flags.fear_resist) msg_print("You stand your ground!"); else if (f_ptr->afraid < 1) { msg_print("You are suddenly afraid!"); f_ptr->afraid += 3 + randint((int)r_ptr->level); } else { f_ptr->afraid += 3; notice = FALSE; } break; case 5: /* Fire attack */ msg_print("You are enveloped in flames!"); fire_dam(damage, ddesc); break; case 6: /* Acid attack */ msg_print("You are covered in acid!"); acid_dam(damage, ddesc); break; case 7: /* Cold attack */ msg_print("You are covered with frost!"); cold_dam(damage, ddesc); break; case 8: /* Lightning attack */ msg_print("Lightning strikes you!"); light_dam(damage, ddesc); break; case 9: /* Corrosion attack */ msg_print("A stinging red gas swirls about you."); corrode_gas(ddesc); take_hit(damage, ddesc); break; case 10: /* Blindness attack */ f_ptr = &py.flags; take_hit(damage, ddesc); if (!py.flags.blindness_resist) { if (f_ptr->blind < 1) { f_ptr->blind += 10 + randint((int)r_ptr->level); msg_print("Your eyes begin to sting."); } else { f_ptr->blind += 5; notice = FALSE; } } break; case 11: /* Paralysis attack */ f_ptr = &py.flags; take_hit(damage, ddesc); if (player_saves()) msg_print("You resist the effects!"); else if (f_ptr->paralysis < 1) { if (f_ptr->free_act) msg_print("You are unaffected."); else { f_ptr->paralysis = randint((int)r_ptr->level) + 3; msg_print("You are paralysed."); } } else notice = FALSE; break; case 12: /* Steal Money */ if ((py.flags.paralysis < 1) && (randint(168) < py.stats.use_stat[A_DEX])) /* immune to steal at 18/150 */ msg_print("You quickly protect your money pouch!"); else { /* make this more sane.... -CWS */ vtype t1; gold = (p_ptr->au / 10) + randint(25); if (gold > 5000) gold = 2000 + randint(1000) + (p_ptr->au / 20); if (gold > p_ptr->au) gold = p_ptr->au; p_ptr->au -= gold; msg_print("Your purse feels lighter."); sprintf(t1, "%ld coin%s stolen!", (long)gold, (gold > 1L) ? "s were" : " was"); msg_print(t1); prt_gold(); } if (randint(2) == 1) { msg_print("There is a puff of smoke!"); blinked = 1; /* added -CFT */ teleport_away(monptr, MAX_SIGHT); } break; case 13: /* Steal Object */ if ((py.flags.paralysis < 1) && (randint(168) < py.stats.use_stat[A_DEX])) /* immune to steal at 18/150 change */ msg_print("You grab hold of your backpack!"); else { vtype t1, t2; i = randint(inven_ctr) - 1; if ((inventory[i].tval >= TV_MIN_WEAR) && (inventory[i].tval <= TV_MAX_WEAR) && (inventory[i].flags2 & TR_ARTIFACT)) break; /* don't destroy artifacts -CFT */ objdes(t1, &inventory[i], FALSE); /* stacked single items */ sprintf(t2, "%sour %s (%c) %s stolen!", ((inventory[i].subval <= ITEM_SINGLE_STACK_MAX) && (inventory[i].number > 1)) ? "One of y" : "Y", t1, i + 'a', /* stacked group items */ ((inventory[i].subval > ITEM_SINGLE_STACK_MAX) && (inventory[i].number > 1)) ? "were" : "was"); msg_print(t2); inven_destroy(i); } if (randint(3) == 1) { msg_print("There is a puff of smoke!"); blinked = 1; /* added -CFT */ teleport_away(monptr, MAX_SIGHT); } break; case 14: /* Poison */ f_ptr = &py.flags; take_hit(damage, ddesc); if (!(f_ptr->poison_im || f_ptr->poison_resist || f_ptr->resist_poison)) { msg_print("You feel very sick."); f_ptr->poisoned += randint((int)r_ptr->level) + 5; } else { msg_print("The poison has no effect."); } break; case 15: /* Lose dexterity */ f_ptr = &py.flags; take_hit(damage, ddesc); if (f_ptr->sustain_dex) msg_print("You feel clumsy for a moment, but it passes."); else { msg_print("You feel more clumsy."); (void)dec_stat(A_DEX); } break; case 16: /* Lose constitution */ f_ptr = &py.flags; take_hit(damage, ddesc); if (f_ptr->sustain_con) msg_print("Your body resists the effects of the disease."); else { msg_print("Your health is damaged!"); (void)dec_stat(A_CON); } break; case 17: /* Lose intelligence */ f_ptr = &py.flags; take_hit(damage, ddesc); msg_print("You have trouble thinking clearly."); if (f_ptr->sustain_int) msg_print("But your mind quickly clears."); else (void)dec_stat(A_INT); break; case 18: /* Lose wisdom */ f_ptr = &py.flags; take_hit(damage, ddesc); if (f_ptr->sustain_wis) msg_print("Your wisdom is sustained."); else { msg_print("Your wisdom is drained."); (void)dec_stat(A_WIS); } break; case 19: /* Lose experience */ f_ptr = &py.flags; if (f_ptr->hold_life && randint(5) > 1) msg_print("You keep hold of your life force!"); else { if (f_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(damage + (py.misc.exp/1000) * MON_DRAIN_LIFE); } else { msg_print("You feel your life draining away!"); lose_exp(damage + (py.misc.exp/100) * MON_DRAIN_LIFE); } } break; case 20: /* Aggravate monster */ (void)aggravate_monster(20); break; case 21: /* Disenchant */ if (!py.flags.disenchant_resist) { int8u chance = 0; take_hit(damage, ddesc); flag = FALSE; switch (randint(7)) { case 1: i = INVEN_WIELD; break; case 2: i = INVEN_BODY; break; case 3: i = INVEN_ARM; break; case 4: i = INVEN_OUTER; break; case 5: i = INVEN_HANDS; break; case 6: i = INVEN_HEAD; break; case 7: i = INVEN_FEET; break; } i_ptr = &inventory[i]; if (i_ptr->tval != TV_NOTHING) { if (i_ptr->flags2 & TR_ARTIFACT) chance = randint(5); if ((i_ptr->tohit > 0) && (chance < 3)){ i_ptr->tohit -= randint(2); /* don't send it below zero */ if (i_ptr->tohit < 0) i_ptr->tohit = 0; flag = TRUE; } if ((i_ptr->todam > 0) && (chance < 3)) { i_ptr->todam -= randint(2); /* don't send it below zero */ if (i_ptr->todam < 0) i_ptr->todam = 0; flag = TRUE; } if ((i_ptr->toac > 0) && (chance < 3)) { i_ptr->toac -= randint(2); /* don't send it below zero */ if (i_ptr->toac < 0) i_ptr->toac = 0; flag = TRUE; } if (flag || (chance > 2)) { vtype t1, t2; objdes(t1, &inventory[i], FALSE); if (chance < 3) sprintf(t2, "Your %s (%c) %s disenchanted!", t1, i+'a'-INVEN_WIELD, (inventory[i].number != 1) ? "were":"was"); else sprintf(t2, "Your %s (%c) %s disenchantment!", t1, i+'a'-INVEN_WIELD, (inventory[i].number != 1) ? "resist":"resists"); msg_print (t2); calc_bonuses (); } else notice = FALSE; } } break; case 22: /* Eat food */ if (find_range(TV_FOOD, TV_NEVER, &i, &j)) { inven_destroy(i); msg_print("It got at your rations!"); } else notice = FALSE; break; case 23: /* Eat light */ i_ptr = &inventory[INVEN_LIGHT]; if ((i_ptr->p1 > 0) && ((i_ptr->flags2 & TR_ARTIFACT) == 0)) { i_ptr->p1 -= (250 + randint(250)); if (i_ptr->p1 < 1) i_ptr->p1 = 1; if (py.flags.blind < 1) msg_print("Your light dims."); else notice = FALSE; } else notice = FALSE; break; case 24: /* Eat charges */ i = randint(inven_ctr) - 1; j = r_ptr->level; i_ptr = &inventory[i]; if (((i_ptr->tval == TV_STAFF) || (i_ptr->tval == TV_WAND)) && (i_ptr->p1 > 0)) { m_ptr->hp += j * i_ptr->p1; i_ptr->p1 = 0; if (!known2_p(i_ptr)) add_inscribe(i_ptr, ID_EMPTY); msg_print("Energy drains from your pack!"); } else notice = FALSE; break; case 25: /* Drain all stats. Haha! SM */ f_ptr = &py.flags; take_hit(damage, ddesc); if (py.flags.sustain_str) msg_print("You feel weaker for a moment, but it passes."); else { msg_print("You feel weaker."); (void)dec_stat(A_STR); } if (f_ptr->sustain_dex) msg_print("You feel clumsy for a moment, but it passes."); else { msg_print("You feel more clumsy."); (void)dec_stat(A_DEX); } if (f_ptr->sustain_con) msg_print("Your body resists the effects of the disease."); else { msg_print("Your health is damaged!"); (void)dec_stat(A_CON); } msg_print("You have trouble thinking clearly."); if (f_ptr->sustain_int) msg_print("But your mind quickly clears."); else (void)dec_stat(A_INT); if (f_ptr->sustain_wis) msg_print("Your wisdom is sustained."); else { msg_print("Your wisdom is drained."); (void)dec_stat(A_WIS); } if (f_ptr->sustain_chr) msg_print("You keep your good looks."); else { msg_print("Your features are twisted."); (void)dec_stat(A_CHR); } break; case 99: notice = FALSE; break; default: notice = FALSE; break; } if (CUT && STUN) { switch (randint(2)) { case 1: CUT = FALSE; break; case 2: STUN = FALSE; break; } } switch (monster_critical(adice, asides, damage)) { case 0: break; case 1: if (CUT) cut_player(randint(5)); else if (STUN) stun_player(randint(5)); break; case 2: if (CUT) cut_player(randint(5) + 5); else if (STUN) stun_player(randint(5) + 5); break; case 3: if (CUT) cut_player(randint(30) + 20); else if (STUN) stun_player(randint(20) + 10); break; case 4: if (CUT) cut_player(randint(70) + 30); else if (STUN) stun_player(randint(40) + 30); break; case 5: if (CUT) cut_player(randint(250) + 50); else if (STUN) stun_player(randint(50) + 40); break; case 6: if (CUT) cut_player(300); else if (STUN) stun_player(randint(60) + 57); break; default: if (CUT) cut_player(5000); else if (STUN) stun_player(100 + randint(10)); break; } /* moved here from mon_move, so that monster only confused if it actually hits */ if (!attype) { /* if no attacks, monster can't get confused -dbd */ if (py.flags.confuse_monster && py.flags.protevil <= 0) { msg_print("Your hands stop glowing."); py.flags.confuse_monster = FALSE; if ((randint(MAX_MONS_LEVEL) < r_ptr->level) || (CHARM_SLEEP & r_ptr->cdefense)) (void)sprintf(tmp_str, "%sis unaffected.", cdesc); else { (void)sprintf(tmp_str, "%sappears confused.", cdesc); m_ptr->confused = TRUE; } msg_print(tmp_str); if (visible && !death && randint(4) == 1) c_recall[m_ptr->mptr].r_cdefense |= r_ptr->cdefense & CHARM_SLEEP; } } /* * increase number of attacks if notice true, or if had previously * noticed the attack (in which case all this does is help player * learn damage), note that in the second case do not increase * attacks if creature repelled (no damage done) */ if ((notice || (c_recall[m_ptr->mptr].r_attacks[attackn] != 0 && attype != 99)) && c_recall[m_ptr->mptr].r_attacks[attackn] < MAX_UCHAR) c_recall[m_ptr->mptr].r_attacks[attackn]++; if (visible && death && c_recall[m_ptr->mptr].r_deaths < MAX_SHORT) c_recall[m_ptr->mptr].r_deaths++; } else { if ((adesc >= 1 && adesc <= 3) || (adesc == 6)) { disturb(1, 0); (void)strcpy(tmp_str, cdesc); msg_print(strcat(tmp_str, "misses you.")); } } if (attackn < MAX_MON_NATTACK - 1) attackn++; else break; } } /* Make the move if possible, five choices -RAK- */ static void make_move(monptr, mm, rcmove) int monptr, *mm; int32u *rcmove; { int i, newy, newx, do_turn, do_move, stuck_door; int32u movebits; register cave_type *c_ptr; register monster_type *m_ptr; register inven_type *t_ptr; #ifdef ATARIST_MWC int32u holder; #endif i = 0; do_turn = FALSE; do_move = FALSE; m_ptr = &m_list[monptr]; movebits = c_list[m_ptr->mptr].cmove; do { /* Get new position */ newy = m_ptr->fy; newx = m_ptr->fx; (void)mmove(mm[i], &newy, &newx); c_ptr = &cave[newy][newx]; if ((i == 4) && (m_ptr->monfear) && /* cornered (or things in the way!) -CWS */ ((c_ptr->fval > MAX_OPEN_SPACE) || (c_ptr->cptr > 1))) { creature_type *r_ptr = &c_list[m_ptr->mptr]; vtype m_name, out_val; m_ptr->monfear = 0; if (m_ptr->ml && los(char_row, char_col, m_ptr->fy, m_ptr->fx)) { monster_name(m_name, m_ptr, r_ptr); sprintf(out_val, "%s turns to fight!", m_name); msg_print(out_val); } break; /* don't try to actually do anything -CWS */ } if (c_ptr->fval != BOUNDARY_WALL) { /* Floor is open? */ if (c_ptr->fval <= MAX_OPEN_SPACE) do_move = TRUE; /* Creature moves through walls? */ else if (movebits & CM_PHASE) { do_move = TRUE; *rcmove |= CM_PHASE; } else if (c_list[m_ptr->mptr].cdefense & BREAK_WALL) { /* Crunch up those Walls Morgoth and Umber Hulks!!!! */ t_ptr = &t_list[c_ptr->tptr]; do_move = TRUE; c_recall[m_ptr->mptr].r_cdefense |= BREAK_WALL; if ((t_ptr->tval == TV_CLOSED_DOOR) || (t_ptr->tval == TV_SECRET_DOOR)) { /* break the door -CFT */ invcopy(t_ptr, OBJ_OPEN_DOOR); t_ptr->p1 = (-1); /* make it broken, not just open */ c_ptr->fval = CORR_FLOOR; /* change floor setting */ lite_spot(newy, newx); /* show broken door */ msg_print("You hear a door burst open!"); disturb(1, 0); } else /* otherwise, break those walls! -CFT */ (void)twall(newy, newx, 1, 0); } /* Creature can open doors? */ else if (c_ptr->tptr != 0) { t_ptr = &t_list[c_ptr->tptr]; if (movebits & CM_OPEN_DOOR) { /* Creature can open doors. */ stuck_door = FALSE; if (t_ptr->tval == TV_CLOSED_DOOR) { do_turn = TRUE; if ((m_ptr->monfear) && randint(2) == 1) /* afraid */ t_ptr->p1 = 0; if (t_ptr->p1 == 0) /* Closed door */ do_move = TRUE; else if (t_ptr->p1 > 0) { /* Locked doors */ if (randint((m_ptr->hp + 1) * (50 + t_ptr->p1)) < 40 * (m_ptr->hp - 10 - t_ptr->p1)) t_ptr->p1 = 0; } else if (t_ptr->p1 < 0) { /* Stuck doors */ if (randint((m_ptr->hp + 1) * (50 - t_ptr->p1)) < 40 * (m_ptr->hp - 10 + t_ptr->p1)) { msg_print("You hear a door burst open!"); disturb(1, 0); stuck_door = TRUE; do_move = TRUE; } } } else if (t_ptr->tval == TV_SECRET_DOOR) { do_turn = TRUE; do_move = TRUE; } if (do_move) { invcopy(t_ptr, OBJ_OPEN_DOOR); if (stuck_door) /* 50% chance of breaking door */ t_ptr->p1 = 1 - randint(2); c_ptr->fval = CORR_FLOOR; lite_spot(newy, newx); *rcmove |= CM_OPEN_DOOR; do_move = FALSE; } } else { /* Creature can not open doors, must bash them */ if (t_ptr->tval == TV_CLOSED_DOOR) { do_turn = TRUE; if (randint((m_ptr->hp + 1) * (80 + MY_ABS(t_ptr->p1))) < 40 * (m_ptr->hp - 20 - MY_ABS(t_ptr->p1))) { invcopy(t_ptr, OBJ_OPEN_DOOR); /* 50% chance of breaking door */ t_ptr->p1 = 1 - randint(2); c_ptr->fval = CORR_FLOOR; lite_spot(newy, newx); msg_print("You hear a door burst open!"); disturb(1, 0); } } } } /* Glyph of warding present? */ if (do_move && (c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval == TV_VIS_TRAP) && (t_list[c_ptr->tptr].subval == 99)) { if (randint(OBJ_RUNE_PROT) < c_list[m_ptr->mptr].level) { if ((newy == char_row) && (newx == char_col)) msg_print("The rune of protection is broken!"); (void)delete_object(newy, newx); } else { do_move = FALSE; /* If the creature moves only to attack, don't let it move if the glyph * prevents it from attacking */ if (movebits & CM_ATTACK_ONLY) do_turn = TRUE; } } /* Creature has attempted to move on player? */ if (do_move) if (c_ptr->cptr == 1) { /* * if the monster is not lit, must call update_mon, it may be * faster than character, and hence could have just moved * next to character this same turn */ if (!m_ptr->ml) update_mon(monptr); make_attack(monptr); do_move = FALSE; do_turn = TRUE; } /* Creature is attempting to move on other creature? */ else if ((c_ptr->cptr > 1) && ((newy != m_ptr->fy) || (newx != m_ptr->fx))) { /* Creature eats other creatures? */ #ifdef ATARIST_MWC if ((movebits & (holder = CM_EATS_OTHER)) && #else if ((movebits & CM_EATS_OTHER) && #endif (c_list[m_ptr->mptr].mexp > c_list[m_list[c_ptr->cptr].mptr].mexp)) { if (m_list[c_ptr->cptr].ml) #ifdef ATARIST_MWC *rcmove |= holder; #else *rcmove |= CM_EATS_OTHER; #endif /* It ate an already processed monster. Handle normally. */ if (monptr < c_ptr->cptr) delete_monster((int)c_ptr->cptr); /* * If it eats this monster, an already processed monster * will take its place, causing all kinds of havoc. * Delay the kill a bit. */ else fix1_delete_monster((int)c_ptr->cptr); } else do_move = FALSE; } /* Creature has been allowed move. */ if (do_move) { /* Move creature record */ move_rec((int)m_ptr->fy, (int)m_ptr->fx, newy, newx); if (m_ptr->ml) { m_ptr->ml = FALSE; lite_spot((int)m_ptr->fy, (int)m_ptr->fx); } m_ptr->fy = newy; m_ptr->fx = newx; m_ptr->cdis = distance(char_row, char_col, newy, newx); do_turn = TRUE; /* Pick up or eat an object */ #ifdef ATARIST_MWC if (movebits & (holder = CM_PICKS_UP)) #else if (movebits & CM_PICKS_UP) #endif { /* used in code to prevent orcs from picking up Slay Orc weapons, etc -CFT */ int32u t; c_ptr = &cave[newy][newx]; if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval <= TV_MAX_OBJECT)) { #ifdef ATARIST_MWC *rcmove |= holder; #else *rcmove |= CM_PICKS_UP; #endif t = 0L; if ((t_list[c_ptr->tptr].flags & TR_SLAY_DRAGON) || (t_list[c_ptr->tptr].flags & TR_SLAY_X_DRAGON)) t |= DRAGON; if (t_list[c_ptr->tptr].flags & TR_SLAY_UNDEAD) t |= UNDEAD; if (t_list[c_ptr->tptr].flags2 & TR_SLAY_DEMON) t |= DEMON; if (t_list[c_ptr->tptr].flags2 & TR_SLAY_TROLL) t |= TROLL; if (t_list[c_ptr->tptr].flags2 & TR_SLAY_GIANT) t |= GIANT; if (t_list[c_ptr->tptr].flags2 & TR_SLAY_ORC) t |= ORC; /* if artifact, or wearable & hurts this monster -CWS */ if ((t_list[c_ptr->tptr].flags2 & TR_ARTIFACT) || ( (t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) && (t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) && (c_list[m_ptr->mptr].cdefense & t) )) { /* FIXME: should use new line-splitting code */ vtype m_name, out_val, i_name; int ii, split = (-1); update_mon(monptr); /* make sure ml see right -CFT */ if ((m_ptr->ml) && los(char_row, char_col, m_ptr->fy, m_ptr->fx)) { /* if we can see it, tell us what happened -CFT */ monster_name(m_name, m_ptr, &(c_list[m_ptr->mptr])); objdes(i_name, &(t_list[c_ptr->tptr]), TRUE); sprintf(out_val, "%s tries to pick up %s, but stops suddenly!", m_name, i_name); for (ii = 0; ii < 72 && out_val[ii]; ii++) if (out_val[ii] == ' ') split = ii; if ((ii > 71) && (split != (-1))) { /* then we should probably split it -CFT */ out_val[split] = 0; msg_print(out_val); msg_print(&out_val[split + 1]); } else /* if ii <= 71, then it'll fit nicely in 1 line. * Or, we found no space to split at... -CFT */ msg_print(out_val); } /* if can see */ } /* if shouldn't pick up */ else (void)delete_object(newy, newx); } } } } i++; /* Up to 5 attempts at moving, give up. */ } while ((!do_turn) && (i < 5)); } /* Creatures can cast spells too. (Dragon Breath) -RAK- */ /* cast_spell = true if creature changes position */ /* took_turn = true if creature casts a spell */ static void mon_cast_spell(monptr, took_turn) int monptr, *took_turn; { int32u i; int y, x, chance, thrown_spell, r1; register int k; int spell_choice[64], desperate = FALSE; vtype cdesc, outval, ddesc; register struct flags *f_ptr; register monster_type *m_ptr; register creature_type *r_ptr; char sex; int blind = (py.flags.blind > 0); /* alter msgs if player can't see -CFT */ if (death) return; m_ptr = &m_list[monptr]; r_ptr = &c_list[m_ptr->mptr]; sex = r_ptr->gender; /* 1 in x chance of casting spell */ chance = (int)(r_ptr->spells & CS_FREQ); if (chance == 0) { msg_print("CHANCE == 0"); msg_print("caused by ...."); msg_print(r_ptr->name); *took_turn = FALSE; } else if (randint(chance) != 1) *took_turn = FALSE; /* Must be within certain range */ else if (m_ptr->cdis > MAX_SPELL_DIS) *took_turn = FALSE; /* Must have unobstructed Line-Of-Sight (reversed direction -CWS) */ else if (!los((int)m_ptr->fy, (int)m_ptr->fx, char_row, char_col)) *took_turn = FALSE; else { /* Creature is going to cast a spell */ *took_turn = TRUE; /* Check to see if monster should be lit. */ update_mon(monptr); /* Describe the attack */ if (m_ptr->ml) { if (r_ptr->cdefense & UNIQUE) (void)sprintf(cdesc, "%s ", r_ptr->name); else (void)sprintf(cdesc, "The %s ", r_ptr->name); } else (void)strcpy(cdesc, "It "); /* For "DIED_FROM" string */ if (UNIQUE & r_ptr->cdefense) (void)sprintf(ddesc, "%s", r_ptr->name); else if (is_a_vowel(r_ptr->name[0])) (void)sprintf(ddesc, "an %s", r_ptr->name); else (void)sprintf(ddesc, "a %s", r_ptr->name); /* End DIED_FROM */ /* Extract all possible spells into spell_choice */ if ((r_ptr->cdefense & INTELLIGENT) && (m_ptr->hp < ((r_ptr->hd[0] * r_ptr->hd[1]) / 10)) && (r_ptr->spells & CS_INT1 || r_ptr->spells2 & CS_INT2 || r_ptr->spells3 & CS_INT3) && randint(2) == 1) { desperate = TRUE; c_recall[m_ptr->mptr].r_cdefense |= INTELLIGENT; } i = (r_ptr->spells & ~CS_FREQ); if (desperate) i &= CS_INT1; k = 0; while (i != 0) { spell_choice[k] = bit_pos(&i); k++; } i = r_ptr->spells2; if (desperate) i &= CS_INT2; while (i != 0) { spell_choice[k] = bit_pos(&i) + 32; k++; } i = r_ptr->spells3; if (desperate) i &= CS_INT3; while (i != 0) { spell_choice[k] = bit_pos(&i) + 64; k++; } /* Choose a spell to cast */ if (!k) thrown_spell = 200; else thrown_spell = spell_choice[randint(k) - 1]; thrown_spell++; /* all except teleport_away() and drain mana spells always disturb */ if (thrown_spell > 6 && thrown_spell != 7) disturb(1, 0); /* Cast the spell. */ switch (thrown_spell) { case 5: /* Teleport Short */ (void)strcat(cdesc, "blinks away."); msg_print(cdesc); teleport_away(monptr, 5); break; case 6: /* Teleport Long */ (void)strcat(cdesc, "teleports away."); msg_print(cdesc); teleport_away(monptr, MAX_SIGHT); break; case 7: /* Teleport To */ (void)strcat(cdesc, "commands you to return!"); msg_print(cdesc); teleport_to((int)m_ptr->fy, (int)m_ptr->fx); break; case 8: /* Light Wound */ if (!blind) (void)strcat(cdesc, "points at you and curses."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); if (player_saves()) msg_print("You resist the effects of the spell."); else take_hit(damroll(3, 8), ddesc); break; case 9: /* Serious Wound */ if (!blind) (void)strcat(cdesc, "points at you and curses horribly."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); if (player_saves()) msg_print("You resist the effects of the spell."); else take_hit(damroll(8, 8), ddesc); break; case 10: /* Hold Person */ if (!blind) (void)strcat(cdesc, "gazes deep into your eyes!"); else (void)strcat(cdesc, "mumbles, and you feel something holding you!"); msg_print(cdesc); if (py.flags.free_act) msg_print("You are unaffected."); else if (player_saves()) if (!blind) msg_print("You stare back unafraid!"); else msg_print("You resist!"); else if (py.flags.paralysis > 0) py.flags.paralysis += 2; else py.flags.paralysis = randint(5) + 4; break; case 11: /* Cause Blindness */ if (!blind) (void)strcat(cdesc, "casts a spell, burning your eyes!"); else (void)strcat(cdesc, "mumbles, and your eyes burn even more."); msg_print(cdesc); if ((player_saves()) || (py.flags.blindness_resist)) if (!blind) msg_print("You blink and your vision clears."); else msg_print("But the extra burning quickly fades away."); else if (py.flags.blind > 0) py.flags.blind += 6; else py.flags.blind += 12 + randint(3); break; case 12: /* Cause Confuse */ if (!blind) (void)strcat(cdesc, "creates a mesmerising illusion."); else (void)strcat(cdesc, "mumbles, and you hear puzzling noises."); msg_print(cdesc); if ((player_saves()) || (py.flags.confusion_resist) || (py.flags.chaos_resist)) msg_print("You disbelieve the feeble spell."); else if (py.flags.confused > 0) py.flags.confused += 2; else py.flags.confused = randint(5) + 3; break; case 13: /* Cause Fear */ if (!blind) (void)strcat(cdesc, "casts a fearful illusion."); else (void)strcat(cdesc, "mumbles, and you hear scary noises."); msg_print(cdesc); if (player_saves() || py.flags.fear_resist) msg_print("You refuse to be frightened."); else if (py.flags.afraid > 0) py.flags.afraid += 2; else py.flags.afraid = randint(5) + 3; break; case 14: /* Summon Monster */ if (!blind) (void)strcat(cdesc, "magically summons help!"); else (void)strcat(cdesc, "mumbles, and you hear something appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; (void)summon_monster(&y, &x, FALSE); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); break; case 15: /* Summon Undead */ if (!blind) (void)strcat(cdesc, "magically summons help from beyond the grave!"); else (void)strcat(cdesc, "mumbles, and you hear something creepy appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; (void)summon_undead(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); break; case 16: /* Slow Person */ (void)strcat(cdesc, "drains power from your muscles!"); msg_print(cdesc); if (py.flags.free_act) msg_print("You are unaffected."); else if (player_saves()) msg_print("Your body resists the spell."); else if (py.flags.slow > 0) py.flags.slow += 2; else py.flags.slow = randint(5) + 3; break; case 17: /* Drain Mana */ if (py.misc.cmana > 0) { disturb(1, 0); (void)sprintf(outval, "%sdraws psychic energy from you!", cdesc); msg_print(outval); if (m_ptr->ml) { (void)sprintf(outval, "%sappears healthier.", cdesc); msg_print(outval); } r1 = (randint((int)r_ptr->level) >> 1) + 1; if (r1 > py.misc.cmana) { r1 = py.misc.cmana; py.misc.cmana = 0; py.misc.cmana_frac = 0; } else py.misc.cmana -= r1; prt_cmana(); m_ptr->hp += 6 * (r1); } break; case 18: /* Summon Demon */ if (!blind) (void)strcat(cdesc, "summons a hellish adversary!"); else (void)strcat(cdesc, "mumbles, and you smell fire and brimstone nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; (void)summon_demon(c_list[m_ptr->mptr].level, &y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); break; case 19: /* Summon Dragon */ if (!blind) (void)strcat(cdesc, "magically summons a Dragon!"); else (void)strcat(cdesc, "mumbles, and you hear something large appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; (void)summon_dragon(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); break; case 20: /* Breath Light */ if (!blind) (void)strcat(cdesc, "breathes lightning."); else (void)strcat(cdesc, "breathes, and you get zapped."); msg_print(cdesc); breath(GF_LIGHTNING, char_row, char_col, ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), ddesc, monptr); break; case 21: /* Breath Gas */ if (!blind) (void)strcat(cdesc, "breathes gas."); else (void)strcat(cdesc, "breathes, and you inhale noxious gases."); msg_print(cdesc); breath(GF_POISON_GAS, char_row, char_col, ((m_ptr->hp / 3) > 800 ? 800 : (m_ptr->hp / 3)), ddesc, monptr); break; case 22: /* Breath Acid */ if (!blind) (void)strcat(cdesc, "breathes acid."); else (void)strcat(cdesc, "breathes, and your skin is burning."); msg_print(cdesc); breath(GF_ACID, char_row, char_col, ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), ddesc, monptr); break; case 23: /* Breath Frost */ if (!blind) (void)strcat(cdesc, "breathes frost."); else (void)strcat(cdesc, "breathes, and feel a frigid blast."); msg_print(cdesc); breath(GF_FROST, char_row, char_col, ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), ddesc, monptr); break; case 24: /* Breath Fire */ if (!blind) (void)strcat(cdesc, "breathes fire."); else (void)strcat(cdesc, "breathes, and you're on fire."); msg_print(cdesc); breath(GF_FIRE, char_row, char_col, ((m_ptr->hp / 3) > 1600 ? 1600 : (m_ptr->hp / 3)), ddesc, monptr); break; case 25: /* Fire Bolt */ if (!blind) (void)strcat(cdesc, "casts a Fire bolt."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); bolt(GF_FIRE, char_row, char_col, damroll(9, 8) + (c_list[m_ptr->mptr].level / 3) ,ddesc, m_ptr, monptr); break; case 26: /* Frost Bolt */ if (!blind) (void)strcat(cdesc, "casts a Frost bolt."); else (void)strcat(cdesc, "mumbles, and you feel a frigid blast ."); msg_print(cdesc); bolt(GF_FROST, char_row, char_col, damroll(6, 8) + (c_list[m_ptr->mptr].level / 3) ,ddesc, m_ptr, monptr); break; case 27: /* Acid Bolt */ if (!blind) (void)strcat(cdesc, "casts a Acid bolt."); else (void)strcat(cdesc, "mumbles, and your skin burns."); msg_print(cdesc); bolt(GF_ACID, char_row, char_col, damroll(7, 8) + (c_list[m_ptr->mptr].level / 3) ,ddesc, m_ptr, monptr); break; case 28: /* Magic Missiles */ if (!blind) (void)strcat(cdesc, "casts a Magic missile."); else (void)strcat(cdesc, "mumbles, and you feel an arrow hit you."); msg_print(cdesc); bolt(GF_MAGIC_MISSILE, char_row, char_col, damroll(2, 6) + (c_list[m_ptr->mptr].level / 3) ,ddesc, m_ptr, monptr); break; case 29: /* Critical Wound */ if (!blind) (void)strcat(cdesc, "points at you, incanting terribly!"); else (void)strcat(cdesc, "mumbles loudly."); msg_print(cdesc); if (player_saves()) msg_print("You resist the effects of the spell."); else take_hit(damroll(10, 15), ddesc); break; case 30: /* Fire Ball */ if (!blind) (void)strcat(cdesc, "casts a Fire ball."); else (void)strcat(cdesc, "mumbles, and you're on fire."); msg_print(cdesc); breath(GF_FIRE, char_row, char_col, randint((c_list[m_ptr->mptr].level * 7) / 2) + 10, ddesc, monptr); break; case 31: /* Frost Ball */ if (!blind) (void)strcat(cdesc, "casts a Frost ball."); else (void)strcat(cdesc, "mumbles, and you feel a frigid blast."); msg_print(cdesc); breath(GF_FROST, char_row, char_col, randint((c_list[m_ptr->mptr].level * 3) / 2) + 10, ddesc, monptr); break; case 32: /* Mana Bolt */ if (!blind) (void)strcat(cdesc, "casts a Mana bolt."); else (void)strcat(cdesc, "mumbles, and you feel a magical blast."); msg_print(cdesc); bolt(GF_MAGIC_MISSILE, char_row, char_col, randint((c_list[m_ptr->mptr].level * 7) / 2) + 50, ddesc, m_ptr, monptr); break; case 33: if (!blind) (void)strcat(cdesc, "breathes chaos."); else (void)strcat(cdesc, "breathes, and you feel a strange flux."); msg_print(cdesc); breath(GF_CHAOS, char_row, char_col, ((m_ptr->hp / 6) > 600 ? 600 : (m_ptr->hp / 6)), ddesc, monptr); break; case 34: if (!blind) (void)strcat(cdesc, "breathes shards."); else (void)strcat(cdesc, "breathes, and sharp fragments cut you."); msg_print(cdesc); breath(GF_SHARDS, char_row, char_col, ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr); break; case 35: if (!blind) (void)strcat(cdesc, "breathes sound."); else (void)strcat(cdesc, "breathes, and you are deafened."); msg_print(cdesc); breath(GF_SOUND, char_row, char_col, ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr); break; case 36: if (!blind) (void)strcat(cdesc, "breathes confusion."); else (void)strcat(cdesc, "breathes, and you feel dizzy."); msg_print(cdesc); breath(GF_CONFUSION, char_row, char_col, ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr); break; case 37: if (!blind) (void)strcat(cdesc, "breathes disenchantment."); else (void)strcat(cdesc, "breathes, and your equipment seems less powerful."); msg_print(cdesc); breath(GF_DISENCHANT, char_row, char_col, ((m_ptr->hp / 6) > 500 ? 500 : (m_ptr->hp / 6)), ddesc, monptr); break; case 38: if (!blind) (void)strcat(cdesc, "breathes nether."); else (void)strcat(cdesc, "breathes, and you feel an unholy aura."); msg_print(cdesc); breath(GF_NETHER, char_row, char_col, ((m_ptr->hp / 6) > 550 ? 550 : (m_ptr->hp / 6)), ddesc, monptr); break; case 39: if (!blind) (void)strcat(cdesc, "casts a Lightning bolt."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); bolt(GF_LIGHTNING, char_row, char_col, damroll(4, 8) + (c_list[m_ptr->mptr].level / 3) ,ddesc, m_ptr, monptr); break; case 40: if (!blind) (void)strcat(cdesc, "casts a Lightning Ball."); else (void)strcat(cdesc, "mumbles, and you get zapped."); msg_print(cdesc); breath(GF_LIGHTNING, char_row, char_col, randint((c_list[m_ptr->mptr].level * 3) / 2) + 8, ddesc, monptr); break; case 41: if (!blind) (void)strcat(cdesc, "casts an Acid Ball."); else (void)strcat(cdesc, "mumbles, and your skin is burning."); msg_print(cdesc); breath(GF_ACID, char_row, char_col, randint(c_list[m_ptr->mptr].level * 3) + 15, ddesc, monptr); break; case 42: if (!blind) (void)strcat(cdesc, "casts a spell and cackles evilly."); else (void)strcat(cdesc, "mumbles, and then cackles evilly."); msg_print(cdesc); (void)trap_creation(); break; case 43: if (!blind) (void)strcat(cdesc, "points at you, screaming the word DIE!"); else (void)strcat(cdesc, "mumbles, and then screams 'DIE!'."); msg_print(cdesc); if (player_saves()) msg_print("You laugh at the feeble spell."); else { msg_print("You start to bleed!"); take_hit(damroll(15, 15), ddesc); cut_player(m_ptr->hp); } break; case 44: if (!blind) { (void)strcat(cdesc, "stares at you."); msg_print(cdesc); } else msg_print("You feel something focusing on your mind."); if (player_saves()) msg_print("You resist the effects."); else { msg_print("Your mind is blasted by psionic energy."); if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) { if (py.flags.confused > 0) py.flags.confused += 2; else py.flags.confused = randint(5) + 3; } take_hit(damroll(8, 8), ddesc); } break; case 45: (void)strcat(cdesc, "teleports you away."); msg_print(cdesc); (void)teleport(100); break; case 46: /* healing, added monster fear code -CWS */ if (!blind) (void)sprintf(outval, "%sconcentrates on %s wounds.", cdesc, (sex == 'm' ? "his" : sex == 'f' ? "her" : sex == 'p' ? "their" : "its")); else (void)sprintf(outval, "%smumbles to itself.", cdesc); msg_print(outval); monster_is_afraid = 0; if (m_ptr->maxhp == 0) { /* then we're just going to fix it! * -CFT */ if ((c_list[m_ptr->mptr].cdefense & MAX_HP) || be_nasty) m_ptr->maxhp = max_hp(c_list[m_ptr->mptr].hd); else m_ptr->maxhp = pdamroll(c_list[m_ptr->mptr].hd); } if (!blind) /* if we bother to say "mumbles" above, then shouldn't * see it heal itself -CFT */ strcat(cdesc, "looks "); else strcat(cdesc, "sounds "); if (m_ptr->hp >= m_ptr->maxhp) { /* need >= because, if we recalc-ed maxhp, we might have gotten a low roll, * which could be below hp -CFT */ (void)strcat(cdesc, "looks as healthy as can be."); msg_print(cdesc); if (m_ptr->monfear > 0) { /* can't be afraid at max hp's */ m_ptr->monfear = 0; monster_is_afraid = (-1); } } else { m_ptr->hp += (c_list[m_ptr->mptr].level) * 6; if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp; if (m_ptr->hp == m_ptr->maxhp) { (void)strcat(cdesc, "looks REALLY healthy!"); if (m_ptr->monfear > 0) { /* can't be afraid at max * hp's */ m_ptr->monfear = 0; monster_is_afraid = (-1); } } else { (void)strcat(cdesc, "looks healthier."); if ((m_ptr->monfear > 0) && (m_ptr->maxhp / (m_ptr->hp + 1) < 3)) { m_ptr->monfear = 0; /* has recovered 33% of it's * hit points */ monster_is_afraid = (-1); } } msg_print(cdesc); if (monster_is_afraid == -1) { /* no longer afraid -CWS */ vtype m_name, out_val; monster_name(m_name, m_ptr, &c_list[m_ptr->mptr]); sprintf(out_val, "%s recovers %s courage.", m_name, (sex == 'm' ? "his" : sex == 'f' ? "her" : sex == 'p' ? "their" : "its")); msg_print(out_val); } } break; case 47: if (!blind) (void)sprintf(outval, "%scasts a spell.", cdesc); else (void)sprintf(outval, "%smumbles to %sself.", cdesc, (sex == 'm' ? "him" : sex == 'f' ? "her" : sex == 'p' ? "them" : "it")); msg_print(outval); if ((m_ptr->cspeed) <= ((int)(c_list[m_ptr->mptr].speed) - 10)) { if ((c_list[m_ptr->mptr].speed) <= 15) { (void)strcat(cdesc, "starts moving faster."); msg_print(cdesc); m_ptr->cspeed += 1; } } break; case 48: if (!blind) (void)strcat(cdesc, "fires missiles at you."); else (void)strcat(cdesc, "sounds like it threw something."); msg_print(cdesc); bolt(GF_ARROW, char_row, char_col, damroll(6, 7), ddesc, m_ptr, monptr); break; case 49: if (!blind) (void)strcat(cdesc, "casts a Plasma Bolt."); else (void)strcat(cdesc, "mumbles, and you are hit with a hellish blast."); msg_print(cdesc); bolt(GF_PLASMA, char_row, char_col, 10 + damroll(8, 7) + (c_list[m_ptr->mptr].level), ddesc, m_ptr, monptr); break; case 50: if (!blind) (void)strcat(cdesc, "magically summons monsters!"); else (void)strcat(cdesc, "mumbles, and you hear many things appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ for (k = 0; k < 8; k++) { hack_monptr = monptr; (void)summon_monster(&y, &x, FALSE); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 51: if (!blind) (void)strcat(cdesc, "casts a Nether Bolt."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); bolt(GF_NETHER, char_row, char_col, 30 + damroll(5, 5) + (c_list[m_ptr->mptr].level * 3) / 2, ddesc, m_ptr, monptr); break; case 52: if (!blind) (void)strcat(cdesc, "casts an Ice Bolt."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); bolt(GF_FROST, char_row, char_col, damroll(6, 6) + (c_list[m_ptr->mptr].level) ,ddesc, m_ptr, monptr); break; case 53: if (!blind) (void)strcat(cdesc, "gestures in shadow."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); (void)unlight_area(char_row, char_col); break; case 54: (void)strcat(cdesc, "tries to blank your mind."); msg_print(cdesc); if (player_saves() || randint(2) == 1) msg_print("You resist the spell."); else if (lose_all_info()) msg_print("Your memories fade away."); break; case 55: if (!blind) { (void)sprintf(outval, "%sconcentrates and %s eyes glow red.", cdesc, (sex == 'm' ? "his" : sex == 'f' ? "her" : sex == 'p' ? "their" : "its")); msg_print(outval); } else msg_print("You feel something focusing on your mind."); if (player_saves()) if (!blind) msg_print("You avert your gaze!"); else msg_print("You resist the effects."); else { msg_print("Your mind is blasted by psionic energy."); take_hit(damroll(12, 15), ddesc); if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) { if (py.flags.confused > 0) py.flags.confused += 2; else py.flags.confused = randint(5) + 3; } if (!py.flags.free_act) { if (py.flags.paralysis > 0) py.flags.paralysis += 2; else py.flags.paralysis = randint(5) + 4; if (py.flags.slow > 0) py.flags.slow += 2; else py.flags.slow = randint(5) + 3; } if (!py.flags.blindness_resist) { if (py.flags.blind > 0) py.flags.blind += 6; else py.flags.blind += 12 + randint(3); } } break; case 56: if (!blind) (void)strcat(cdesc, "casts a Stinking Cloud."); else (void)strcat(cdesc, "mumbles, and you smell a foul odor."); msg_print(cdesc); breath(GF_POISON_GAS, char_row, char_col, damroll(12, 2), ddesc, monptr); break; case 57: if (!blind) (void)strcat(cdesc, "gestures at you."); else (void)strcat(cdesc, "mumbles strangely."); msg_print(cdesc); if ((player_saves()) || (randint(3) != 1) || (py.flags.nexus_resist)) msg_print("You keep your feet firmly on the ground."); else { k = dun_level; if (dun_level == Q_PLANE) dun_level = 0; else if (is_quest(dun_level)) dun_level -= 1; else dun_level += (-3) + 2 * randint(2); if (dun_level < 0) dun_level = 0; if (k == Q_PLANE) msg_print("You warp through a cross-dimension gate."); else if (k < dun_level) msg_print("You sink through the floor."); else msg_print("You rise up through the ceiling."); new_level_flag = TRUE; } break; case 58: f_ptr = (&py.flags); if (!blind) (void)strcat(cdesc, "casts a Water Bolt."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); bolt(GF_WATER, char_row, char_col, damroll(10, 10) + (c_list[m_ptr->mptr].level) ,ddesc, m_ptr, monptr); break; case 59: f_ptr = &py.flags; if (!blind) (void)strcat(cdesc, "gestures fluidly."); else (void)strcat(cdesc, "mumbles."); msg_print(cdesc); msg_print("You are engulfed in a whirlpool."); breath(GF_WATER, char_row, char_col, randint((c_list[m_ptr->mptr].level * 5) / 2) + 50, ddesc, monptr); break; case 60: if (!blind) (void)strcat(cdesc, "casts a Nether Ball."); else (void)strcat(cdesc, "mumbles, and you feel an unholy aura."); msg_print(cdesc); breath(GF_NETHER, char_row, char_col, (50 + damroll(10, 10) + (c_list[m_ptr->mptr].level)), ddesc, monptr); break; case 61: if (!blind) (void)strcat(cdesc, "summons an Angel."); else (void)strcat(cdesc, "mumbles, and you hear something appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; (void)summon_angel(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); break; case 62: if (!blind) (void)strcat(cdesc, "magically summons Spiders."); else (void)strcat(cdesc, "mumbles, and you hear many things appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ for (k = 0; k < 6; k++) { hack_monptr = monptr; (void)summon_spider(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 63: if (!blind) (void)strcat(cdesc, "magically summons Hounds."); else (void)strcat(cdesc, "mumbles, and you hear many things appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called,it needs monptr */ for (k = 0; k < 8; k++) { hack_monptr = monptr; (void)summon_hound(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 64: if (!blind) (void)strcat(cdesc, "breathes Nexus."); else (void)strcat(cdesc, "breathes, and you feel strange."); msg_print(cdesc); breath(GF_NEXUS, char_row, char_col, ((m_ptr->hp / 3) > 250 ? 250 : (m_ptr->hp / 3)), ddesc, monptr); break; case 65: if (!blind) (void)strcat(cdesc, "breathes elemental force."); else (void)strcat(cdesc, "breathes, and you are hit hard."); msg_print(cdesc); if (randint(10) == 1) br_wall(m_ptr->fy, m_ptr->fx); else breath(GF_FORCE, char_row, char_col, ((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)), ddesc, monptr); break; case 66: if (!blind) (void)strcat(cdesc, "breathes inertia."); else (void)strcat(cdesc, "breathes."); msg_print(cdesc); breath(GF_INERTIA, char_row, char_col, ((m_ptr->hp / 6) > 200 ? 200 : (m_ptr->hp / 6)), ddesc, monptr); break; case 67: if (!blind) (void)strcat(cdesc, "breathes light."); else (void)strcat(cdesc, "breathes."); msg_print(cdesc); breath(GF_LIGHT, char_row, char_col, ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr); break; case 68: if (!blind) (void)strcat(cdesc, "breathes time."); else (void)strcat(cdesc, "breathes."); msg_print(cdesc); breath(GF_TIME, char_row, char_col, ((m_ptr->hp / 3) > 150 ? 150 : (m_ptr->hp / 3)), ddesc, monptr); break; case 69: /* gravity */ if (!blind) (void)strcat(cdesc, "breathes gravity."); else (void)strcat(cdesc, "breathes, and you feel heavy."); msg_print(cdesc); breath(GF_GRAVITY, char_row, char_col, ((m_ptr->hp / 3) > 200 ? 200 : (m_ptr->hp / 3)), ddesc, monptr); break; case 70: /* darkness */ if (!blind) (void)strcat(cdesc, "breathes darkness."); else (void)strcat(cdesc, "breathes."); msg_print(cdesc); breath(GF_DARK, char_row, char_col, ((m_ptr->hp / 6) > 400 ? 400 : (m_ptr->hp / 6)), ddesc, monptr); break; case 71: /* plasma */ if (!blind) (void)strcat(cdesc, "breathes plasma."); else (void)strcat(cdesc, "breathes."); msg_print(cdesc); breath(GF_PLASMA, char_row, char_col, ((m_ptr->hp / 6) > 150 ? 150 : (m_ptr->hp / 6)), ddesc, monptr); break; case 72: if (!blind) { (void)strcat(cdesc, "fires an arrow at you."); msg_print(cdesc); } else msg_print("You hear the 'twang' of a bowstring."); bolt(GF_ARROW, char_row, char_col, damroll(1, 6), ddesc, m_ptr, monptr); break; case 73: if (!blind) (void)strcat(cdesc, "magically summons mighty undead opponents."); else (void)strcat(cdesc, "mumbles, and you hear many creepy things appear."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called, it needs monptr */ for (k = 0; k < 10; k++) { hack_monptr = monptr; (void)summon_wraith(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } for (k = 0; k < 7; k++) { hack_monptr = monptr; (void)summon_gundead(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 74: /* Big darkness storm */ if (!blind) (void)strcat(cdesc, "casts a Darkness Storm."); else (void)strcat(cdesc, "mumbles powerfully."); msg_print(cdesc); breath(GF_DARK, char_row, char_col, ((m_ptr->hp / 6) > 500 ? 500 : (m_ptr->hp / 6)), ddesc, monptr); break; case 75: /* Mana storm */ if (!blind) (void)strcat(cdesc, "invokes a Mana Storm."); else (void)strcat(cdesc, "mumbles, and you are hit by a storm of power."); msg_print(cdesc); breath(GF_MANA, char_row, char_col, (c_list[m_ptr->mptr].level * 5) + damroll(10, 10), ddesc, monptr); break; case 76: /* Summon reptiles */ if (!blind) (void)strcat(cdesc, "magically summons reptiles."); else (void)strcat(cdesc, "mumbles, and you hear many things appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called, it needs monptr */ for (k = 0; k < 8; k++) { hack_monptr = monptr; (void)summon_reptile(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 77: /* Summon ants */ if (!blind) (void)strcat(cdesc, "magically summons ants."); else (void)strcat(cdesc, "mumbles, and you hear many things appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called, it needs monptr */ for (k = 0; k < 7; k++) { hack_monptr = monptr; (void)summon_ant(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 78: /* Summon unique monsters */ if (!blind) (void)strcat(cdesc, "summons special opponents!"); else (void)strcat(cdesc, "mumbles, and you're worried by the things you hear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called, it needs monptr */ for (k = 0; k < 5; k++) { hack_monptr = monptr; (void)summon_unique(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } for (k = 0; k < 4; k++) { hack_monptr = monptr; (void)summon_jabberwock(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 79: /* Summon greater undead */ if (!blind) (void)strcat(cdesc, "summons the DEAD!"); else (void)strcat(cdesc, "mumbles, and a chill runs down your spine."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called, it needs monptr */ for (k = 0; k < 8; k++) { hack_monptr = monptr; (void)summon_gundead(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; case 80: /* Summon ancient dragons */ if (!blind) (void)strcat(cdesc, "summons ancient dragons."); else (void)strcat(cdesc, "mumbles, and you hear many huge things appear nearby."); msg_print(cdesc); y = char_row; x = char_col; /* in case compact_monster() is called, it needs monptr */ for (k = 0; k < 5; k++) { hack_monptr = monptr; (void)summon_ancientd(&y, &x); hack_monptr = (-1); update_mon((int)cave[y][x].cptr); } break; default: if (k != 200) (void)strcat(cdesc, "casts a bugged spell."); else (void)strcat(cdesc, "had no spell to cast, tell someone NOW!"); msg_print(cdesc); } /* End of spells */ if ((m_ptr->ml) /* this won't work if we've been moved, so... */ ||(thrown_spell == 45) /* add teleport away, */ ||(thrown_spell == 57) /* and teleport lv -CFT */ ) { if (thrown_spell < 33) c_recall[m_ptr->mptr].r_spells |= 1L << (thrown_spell - 1); else if (thrown_spell < 65) c_recall[m_ptr->mptr].r_spells2 |= 1L << (thrown_spell - 33); else if (thrown_spell < 97) /* in case of 200 for bugs... -CFT */ c_recall[m_ptr->mptr].r_spells3 |= 1L << (thrown_spell - 65); if ((c_recall[m_ptr->mptr].r_spells & CS_FREQ) != CS_FREQ) c_recall[m_ptr->mptr].r_spells++; if (death && c_recall[m_ptr->mptr].r_deaths < MAX_SHORT) c_recall[m_ptr->mptr].r_deaths++; } } } /* Places creature adjacent to given location -RAK- */ /* Rats and Flys are fun! */ int multiply_monster(y, x, cr_index, monptr) int y, x, cr_index, monptr; { register int i, j, k; register cave_type *c_ptr; int result; #ifdef ATARIST_MWC int32u holder; #endif i = 0; do { j = y - 2 + randint(3); k = x - 2 + randint(3); /* * don't create a new creature on top of the old one, that causes * invincible/invisible creatures to appear */ if (in_bounds(j, k) && (j != y || k != x)) { c_ptr = &cave[j][k]; if ((c_ptr->fval <= MAX_OPEN_SPACE) && (c_ptr->tptr == 0) && (c_ptr->cptr != 1)) { if (c_ptr->cptr > 1) { /* Creature there already? */ /* Some critters are cannibalistic! */ if ((c_list[cr_index].cmove & CM_EATS_OTHER) /* Check the experience level -CJS- */ && c_list[cr_index].mexp >= c_list[m_list[c_ptr->cptr].mptr].mexp) { /* It ate an already processed monster.Handle normally. */ if (monptr < c_ptr->cptr) delete_monster((int)c_ptr->cptr); /* * If it eats this monster, an already processed mosnter * will take its place, causing all kinds of havoc. Delay * the kill a bit. */ else fix1_delete_monster((int)c_ptr->cptr); /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; result = place_monster(j, k, cr_index, FALSE); hack_monptr = (-1); if (!result) return FALSE; mon_tot_mult++; return check_mon_lite(j, k); } } else /* All clear, place a monster */ { /* in case compact_monster() is called,it needs monptr */ hack_monptr = monptr; result = place_monster(j, k, cr_index, FALSE); hack_monptr = (-1); if (!result) return FALSE; mon_tot_mult++; return check_mon_lite(j, k); } } } i++; } while (i <= 18); return FALSE; } /* Move the critters about the dungeon -RAK- */ static void mon_move(monptr, rcmove) int monptr; int32u *rcmove; { register int i, j; int k, move_test, dir; register creature_type *r_ptr; register monster_type *m_ptr; int mm[9]; bigvtype out_val, m_name; m_ptr = &m_list[monptr]; r_ptr = &c_list[m_ptr->mptr]; /* reduce fear, tough monsters can unfear faster -CFT, hacked by DGK */ if (m_ptr->monfear) { int t = (int)m_ptr->monfear; /* use int so avoid unsigned wraparound -CFT */ t -= randint(c_list[m_ptr->mptr].level / 10); if (t <= 0) { t = 0; if (m_ptr->ml && los(char_row, char_col, m_ptr->fy, m_ptr->fx)) { monster_name(m_name, m_ptr, r_ptr); sprintf(out_val, "%s recovers its courage.", m_name); msg_print(out_val); } } m_ptr->monfear = (int8u) t; } /* Does the critter multiply? */ if ((r_ptr->cmove & CM_MULTIPLY) && (MAX_MON_MULT >= mon_tot_mult) && (((py.flags.rest != -1) && ((py.flags.rest % MON_MULT_ADJ) == 0)) || ((py.flags.rest == -1) && (randint(MON_MULT_ADJ) == 1)))) { k = 0; for (i = (int)m_ptr->fy - 1; i <= (int)m_ptr->fy + 1; i++) for (j = (int)m_ptr->fx - 1; j <= (int)m_ptr->fx + 1; j++) if (in_bounds(i, j) && (cave[i][j].cptr > 1)) k++; /* can't call randint with a value of zero, increment counter to allow * creature multiplication */ if (k == 0) k++; if ((k < 4) && (randint(k * MON_MULT_ADJ) == 1)) if (multiply_monster((int)m_ptr->fy, (int)m_ptr->fx, (int)m_ptr->mptr, monptr)) *rcmove |= CM_MULTIPLY; } move_test = FALSE; /* if in wall, must immediately escape to a clear area */ if (!(r_ptr->cmove & CM_PHASE) && (cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL)) { /* If the monster is already dead, don't kill it again! This can happen * for monsters moving faster than the player. They will get multiple * moves, but should not if they die on the first move. This is only a * problem for monsters stuck in rock. */ if (m_ptr->hp < 0) return; k = 0; dir = 1; /* note direction of for loops matches direction of keypad from 1 to 9 */ /* do not allow attack against the player */ for (i = m_ptr->fy + 1; i >= (int)(m_ptr->fy - 1); i--) for (j = m_ptr->fx - 1; j <= (int)(m_ptr->fx + 1); j++) { if ((dir != 5) && (cave[i][j].fval <= MAX_OPEN_SPACE) && (cave[i][j].cptr != 1)) mm[k++] = dir; dir++; } if (k != 0) { /* put a random direction first */ dir = randint(k) - 1; i = mm[0]; mm[0] = mm[dir]; mm[dir] = i; make_move(monptr, mm, rcmove); /* this can only fail if mm[0] has a rune of protection */ } /* if still in a wall, let it dig itself out, but also apply some more damage */ if (cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL) { /* in case the monster dies, may need to call fix1_delete_monster() * instead of delete_monsters() */ hack_monptr = monptr; i = mon_take_hit(monptr, damroll(8, 8), FALSE); hack_monptr = (-1); if (i >= 0) msg_print("You hear a scream muffled by rock!"); else (void)twall((int)m_ptr->fy, (int)m_ptr->fx, 1, 0); } return; /* monster movement finished */ } /* Creature is confused? Chance it becomes un-confused */ else if (m_ptr->confused) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); /* don't move him if he is not supposed to move! */ if (!(r_ptr->cmove & CM_ATTACK_ONLY)) { *rcmove |= CM_ATTACK_ONLY; make_move(monptr, mm, rcmove); } /* reduce conf, tough monsters can unconf faster -CFT */ { /* use int so avoid unsigned wraparound -CFT */ int t = (int)m_ptr->confused; t -= randint(c_list[m_ptr->mptr].level / 10); if (t < 0) t = 0; m_ptr->confused = (int8u) t; } move_test = TRUE; } /* Creature may cast a spell */ else if (r_ptr->spells != 0) { mon_cast_spell(monptr, &move_test); } if (!move_test) { /* 75% random movement */ if ((r_ptr->cmove & CM_75_RANDOM) && (randint(100) < 75)) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); *rcmove |= CM_75_RANDOM; make_move(monptr, mm, rcmove); } /* 40% random movement */ else if ((r_ptr->cmove & CM_40_RANDOM) && (randint(100) < 40)) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); *rcmove |= CM_40_RANDOM; make_move(monptr, mm, rcmove); } /* 20% random movement */ else if ((r_ptr->cmove & CM_20_RANDOM) && (randint(100) < 20)) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); *rcmove |= CM_20_RANDOM; make_move(monptr, mm, rcmove); } /* Normal movement */ else if (r_ptr->cmove & CM_MOVE_NORMAL) { if (randint(200) == 1) { mm[0] = randint(9); mm[1] = randint(9); mm[2] = randint(9); mm[3] = randint(9); mm[4] = randint(9); } else get_moves(monptr, mm); *rcmove |= CM_MOVE_NORMAL; make_move(monptr, mm, rcmove); } /* Attack, but don't move */ else if ((r_ptr->cmove & CM_ATTACK_ONLY) && (m_ptr->cdis < 2)) { *rcmove |= CM_ATTACK_ONLY; get_moves(monptr, mm); make_move(monptr, mm, rcmove); } else if ((r_ptr->cmove & CM_ALL_MV_FLAGS) == 0 && (m_ptr->cdis < 2)) { /* little hack for Quylthulgs, so that will eventually notice * that they have no physical attacks */ if (c_recall[m_ptr->mptr].r_attacks[0] < MAX_UCHAR) c_recall[m_ptr->mptr].r_attacks[0]++; } } } /* Creatures movement and attacking are done from here -RAK- */ void creatures(attack) int attack; { register int i, k; register monster_type *m_ptr; recall_type *r_ptr; int32u notice, rcmove; int wake, ignore; vtype cdesc; /* Process the monsters */ for (i = mfptr - 1; i >= MIN_MONIX && !death; i--) { m_ptr = &m_list[i]; /* Get rid of an eaten/breathed on monster. Note: Be sure not to process * this monster. This is necessary because we can't delete monsters while * scanning the m_list here. */ if (m_ptr->hp < 0) { check_unique(m_ptr); fix2_delete_monster(i); continue; } m_ptr->cdis = distance(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx); if (attack) { /* Attack is argument passed to CREATURE */ k = movement_rate(i); if (k <= 0) update_mon(i); else while (k > 0) { k--; wake = FALSE; ignore = FALSE; rcmove = 0; if ((m_ptr->ml && /* check los so telepathy won't wake lice -CFT */ los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) || (m_ptr->cdis <= c_list[m_ptr->mptr].aaf) /* Monsters trapped in rock must be given a turn also, * so that they will die/dig out immediately. */ #ifdef ATARIST_MWC || ((!(c_list[m_ptr->mptr].cmove & (holder = CM_PHASE))) #else || ((!(c_list[m_ptr->mptr].cmove & CM_PHASE)) #endif && cave[m_ptr->fy][m_ptr->fx].fval >= MIN_CAVE_WALL)) { if (m_ptr->csleep > 0) if (py.flags.aggravate) m_ptr->csleep = 0; else if ((py.flags.rest == 0 && py.flags.paralysis < 1) || (randint(50) == 1)) { notice = randint(1024); if ((notice * notice * notice) <= (1L << (29 - py.misc.stl))) { m_ptr->csleep -= (100 / m_ptr->cdis); if (m_ptr->csleep > 0) ignore = TRUE; else { wake = TRUE; /* force it to be exactly zero */ m_ptr->csleep = 0; } } } if (m_ptr->stunned != 0) { /* NOTE: Balrog = 100*100 = 10000, it always recovers instantly */ if (randint(5000) < c_list[m_ptr->mptr].level * c_list[m_ptr->mptr].level) m_ptr->stunned = 0; else m_ptr->stunned--; if (m_ptr->stunned == 0) { if (!m_ptr->ml) (void)strcpy(cdesc, "It "); else if (c_list[m_ptr->mptr].cdefense & UNIQUE) (void)sprintf(cdesc, "%s ", c_list[m_ptr->mptr].name); else (void)sprintf(cdesc, "The %s ", c_list[m_ptr->mptr].name); msg_print(strcat(cdesc, "recovers and glares at you.")); } } if ((m_ptr->csleep == 0) && (m_ptr->stunned == 0)) mon_move(i, &rcmove); } update_mon(i); if (m_ptr->ml) { r_ptr = &c_recall[m_ptr->mptr]; if (wake) { if (r_ptr->r_wake < MAX_UCHAR) r_ptr->r_wake++; } else if (ignore) { if (r_ptr->r_ignore < MAX_UCHAR) r_ptr->r_ignore++; } r_ptr->r_cmove |= rcmove; } } } else update_mon(i); /* Get rid of an eaten/breathed on monster. This is necessary because we * can't delete monsters while scanning the m_list here. This monster * may have been killed during mon_move(). */ if (m_ptr->hp < 0) { check_unique(m_ptr); fix2_delete_monster(i); continue; } } /* End processing monsters */ } /* This is a fun one. In a given block, pick some walls and */ /* turn them into open spots. Pick some open spots and turn */ /* them into walls. An "Earthquake" effect. -LVB- */ static void shatter_quake(mon_y, mon_x) int mon_y, mon_x; { register int i, j, k, l; register cave_type *c_ptr; register monster_type *m_ptr; register creature_type *r_ptr; int kill, damage = 0, tmp, y, x = 0; vtype out_val, m_name; int monptr = cave[mon_y][mon_x].cptr; /* needed when we kill another monster */ for (i = mon_y - 8; i <= mon_y + 8; i++) for (j = mon_x - 8; j <= mon_x + 8; j++) if (in_bounds(i, j) && (randint(8) == 1)) { if ((i == mon_y) && (j == mon_x)) continue; c_ptr = &cave[i][j]; if (c_ptr->cptr > 1) { m_ptr = &m_list[c_ptr->cptr]; r_ptr = &c_list[m_ptr->mptr]; if (!(r_ptr->cmove & CM_PHASE) && !(r_ptr->cdefense & BREAK_WALL)) { if ((movement_rate(c_ptr->cptr) == 0) || (r_ptr->cmove & CM_ATTACK_ONLY)) /* monster can not move to escape the wall */ kill = TRUE; else { /* only kill if there is nowhere for the monster to escape to */ kill = TRUE; for (y = i - 1; y <= i + 1; y++) { for (x = j - 1; x <= j + 1; x++) { if ((cave[y][x].fval <= MAX_OPEN_SPACE) && !(y == i && x == j)) { kill = FALSE; break; } } if (!kill) break; } } if (kill) damage = 0x7fff; /* this will kill everything */ else damage = damroll(4, 8); monster_name(m_name, m_ptr, r_ptr); (void)sprintf(out_val, "%s wails out in pain!", m_name); msg_print(out_val); /* kill monster "by hand", so player doesn't get exp -CFT */ m_ptr->hp = m_ptr->hp - damage; m_ptr->csleep = 0; /* prevent unique monster from death by other monsters. It causes trouble * (monster not marked as dead, quest monsters don't satisfy quest, etc). * So, we let then live, but extremely wimpy. This isn't great, because * monster might heal itself before player's next swing... -CFT */ if ((r_ptr->cdefense & UNIQUE) && (m_ptr->hp < 0)) m_ptr->hp = 0; if (m_ptr->hp < 0) { int32u temp, treas; (void)sprintf(out_val, "%s is embedded in the rock.", m_name); msg_print(out_val); object_level = (dun_level + r_ptr->level) >> 1; treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx, r_ptr->cmove, 0, 0); if (m_ptr->ml) { temp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE) >> CM_TR_SHIFT; if (temp > ((treas & CM_TREASURE) >> CM_TR_SHIFT)) treas = (treas & ~CM_TREASURE) | (temp << CM_TR_SHIFT); c_recall[m_ptr->mptr].r_cmove = treas | (c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE); } if (monptr < c_ptr->cptr) delete_monster((int)c_ptr->cptr); else fix1_delete_monster((int)c_ptr->cptr); } /* if monster's hp < 0 */ } } else if (c_ptr->cptr == 1) { /* Kill the dumb player! */ kill = TRUE; for (y = i - 1; y <= i + 1; y++) { for (x = j - 1; x <= j + 1; x++) { if ((cave[y][x].fval <= MAX_OPEN_SPACE) && (cave[y][x].cptr == 0) && !(y == i && x == j)) { kill = FALSE; break; } } if (!kill) break; } switch (randint(3)) { case 1: msg_print("The cave ceiling collapses!"); break; case 2: msg_print("The floor turns and crushes you!"); break; case 3: msg_print("You are pummeled with debris!"); break; } if (kill) { msg_print("You are trapped and cannot move! You are crushed beneath rock!"); msg_print(NULL); damage = 320; } else { switch (randint(3)) { case 1: msg_print("The rubble bashes you!"); damage = damroll(10, 4); stun_player(randint(50)); break; case 2: msg_print("But you nimbly dodge the blast!"); damage = 0; break; case 3: msg_print("The floor crushes you against the ceiling!"); damage = damroll(10, 4); stun_player(randint(50)); break; } move_rec(char_row, char_col, y, x); for (k = char_row - 1; k <= char_row + 1; k++) for (l = char_col - 1; l <= char_col + 1; l++) { c_ptr = &cave[k][l]; c_ptr->tl = FALSE; lite_spot(k, l); } lite_spot(char_row, char_col); char_row = y; char_col = x; check_view(); /* light creatures */ creatures(FALSE); } take_hit(damage, "an Earthquake"); } if (c_ptr->tptr != 0) if (((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) && (t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) && (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) || (t_list[c_ptr->tptr].tval == TV_UP_STAIR) || (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR) || (t_list[c_ptr->tptr].tval == TV_STORE_DOOR)) continue; /* don't kill artifacts... */ else (void)delete_object(i, j); if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL)) { c_ptr->fval = CORR_FLOOR; c_ptr->pl = FALSE; c_ptr->fm = FALSE; } else if ((c_ptr->fval <= MAX_CAVE_FLOOR) && (c_ptr->tptr == 0) && (c_ptr->cptr != 1)) { /* don't bury player, it made him unattackable -CFT */ tmp = randint(10); if (tmp < 6) c_ptr->fval = QUARTZ_WALL; else if (tmp < 9) c_ptr->fval = MAGMA_WALL; else c_ptr->fval = GRANITE_WALL; c_ptr->fm = FALSE; } lite_spot(i, j); } } /* This is a fun one. In a given block, pick some walls and */ /* turn them into open spots. Pick some open spots and turn */ /* them into walls. An "Earthquake" effect. -LVB- */ static void br_wall(mon_y, mon_x) int mon_y, mon_x; { register int k, l; register cave_type *c_ptr; int kill, damage = 0, tmp, y, x = 0; kill = TRUE; for (y = char_row - 1; y <= char_row + 1; y++) { for (x = char_col - 1; x <= char_col + 1; x++) { if ((cave[y][x].fval <= MAX_OPEN_SPACE) && (cave[y][x].cptr == 0) && !(y == char_row && x == char_col)) { kill = FALSE; break; } } if (!kill) break; } switch (randint(3)) { case 1: msg_print("The cave ceiling collapses!"); break; case 2: msg_print("The floor turns and crushes you!"); break; case 3: msg_print("You are pummeled with debris!"); break; } if (kill) { msg_print("You are trapped, crushed and cannot move!"); damage = 250; } else { switch (randint(3)) { case 1: msg_print("The rubble bashes you!"); damage = damroll(10, 4); stun_player(randint(50)); break; case 2: msg_print("But you nimbly dodge the blast!"); damage = 0; break; case 3: msg_print("The floor crushes you against the ceiling!"); damage = damroll(10, 4); stun_player(randint(50)); break; } c_ptr = &cave[char_row][char_col]; move_rec(char_row, char_col, y, x); /* don't destroy floor if stairs, shop, or artifact... */ if ((c_ptr->fval <= MAX_CAVE_FLOOR) && ((c_ptr->tptr == 0) || ((t_list[c_ptr->tptr].tval != TV_UP_STAIR) && (t_list[c_ptr->tptr].tval != TV_DOWN_STAIR) && (t_list[c_ptr->tptr].tval != TV_STORE_DOOR) && !((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) && (t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) && (t_list[c_ptr->tptr].flags2 & TR_ARTIFACT))))) { if (c_ptr->tptr) delete_object(char_row, char_col); tmp = randint(10); if (tmp < 6) c_ptr->fval = QUARTZ_WALL; else if (tmp < 9) c_ptr->fval = MAGMA_WALL; else c_ptr->fval = GRANITE_WALL; c_ptr->fm = FALSE; } for (k = char_row - 1; k <= char_row + 1; k++) for (l = char_col - 1; l <= char_col + 1; l++) { c_ptr = &cave[k][l]; c_ptr->tl = FALSE; lite_spot(k, l); } lite_spot(char_row, char_col); char_row = y; char_col = x; } /* !kill */ check_view(); /* light creatures */ creatures(FALSE); lite_spot(char_row, char_col); take_hit(damage, "an Earthquake"); }