void nh_timeout() { register struct prop *upp; int sleeptime; int m_idx; int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0; if (flags.friday13) baseluck -= 1; if (u.uluck != baseluck && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) { /* Cursed luckstones stop bad luck from timing out; blessed luckstones * stop good luck from timing out; normal luckstones stop both; * neither is stopped if you don't have a luckstone. * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th */ register int time_luck = stone_luck(FALSE); boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE); if(u.uluck > baseluck && (nostone || time_luck < 0)) u.uluck--; else if(u.uluck < baseluck && (nostone || time_luck > 0)) u.uluck++; } if(u.uinvulnerable) return; /* things past this point could kill you */ if(Stoned) stoned_dialogue(); if(Slimed) slime_dialogue(); if(Vomiting) vomiting_dialogue(); if(Strangled) choke_dialogue(); if(u.mtimedone && !--u.mtimedone) { if (Unchanging) u.mtimedone = rnd(100*youmonst.data->mlevel + 1); else rehumanize(); } if(u.ucreamed) u.ucreamed--; /* Dissipate spell-based protection. */ if (u.usptime) { if (--u.usptime == 0 && u.uspellprot) { u.usptime = u.uspmtime; u.uspellprot--; find_ac(); if (!Blind) Norep("The %s haze around you %s.", hcolor(NH_GOLDEN), u.uspellprot ? "becomes less dense" : "disappears"); } } #ifdef STEED if (u.ugallop) { if (--u.ugallop == 0L && u.usteed) pline("%s stops galloping.", Monnam(u.usteed)); } #endif for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++) if((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) { switch(upp - u.uprops){ case STONED: if (delayed_killer && !killer) { killer = delayed_killer; delayed_killer = 0; } if (!killer) { /* leaving killer_format would make it "petrified by petrification" */ killer_format = NO_KILLER_PREFIX; killer = "killed by petrification"; } done(STONING); break; case SLIMED: if (delayed_killer && !killer) { killer = delayed_killer; delayed_killer = 0; } if (!killer) { killer_format = NO_KILLER_PREFIX; killer = "turned into green slime"; } done(TURNED_SLIME); break; case VOMITING: make_vomiting(0L, TRUE); break; case SICK: You("die from your illness."); killer_format = KILLED_BY_AN; killer = u.usick_cause; if ((m_idx = name_to_mon(killer)) >= LOW_PM) { if (type_is_pname(&mons[m_idx])) { killer_format = KILLED_BY; } else if (mons[m_idx].geno & G_UNIQ) { killer = the(killer); Strcpy(u.usick_cause, killer); killer_format = KILLED_BY; } } u.usick_type = 0; done(POISONING); break; case FAST: if (!Very_fast) You_feel("yourself slowing down%s.", Fast ? " a bit" : ""); break; case CONFUSION: HConfusion = 1; /* So make_confused works properly */ make_confused(0L, TRUE); stop_occupation(); break; case STUNNED: HStun = 1; make_stunned(0L, TRUE); stop_occupation(); break; case BLINDED: Blinded = 1; make_blinded(0L, TRUE); stop_occupation(); break; case INVIS: newsym(u.ux,u.uy); if (!Invis && !BInvis && !Blind) { You(!See_invisible ? "are no longer invisible." : "can no longer see through yourself."); stop_occupation(); } break; case SEE_INVIS: set_mimic_blocking(); /* do special mimic handling */ see_monsters(); /* make invis mons appear */ newsym(u.ux,u.uy); /* make self appear */ stop_occupation(); break; case WOUNDED_LEGS: heal_legs(); stop_occupation(); break; case HALLUC: HHallucination = 1; (void) make_hallucinated(0L, TRUE, 0L); stop_occupation(); break; case SLEEPING: if (unconscious() || Sleep_resistance) HSleeping += rnd(100); else if (Sleeping) { You("fall asleep."); sleeptime = rnd(20); fall_asleep(-sleeptime, TRUE); HSleeping += sleeptime + rnd(100); } break; case LEVITATION: (void) float_down(I_SPECIAL|TIMEOUT, 0L); break; case STRANGLED: killer_format = KILLED_BY; killer = (u.uburied) ? "suffocation" : "strangulation"; done(DIED); break; case FUMBLING: /* call this only when a move took place. */ /* otherwise handle fumbling msgs locally. */ if (u.umoved && !Levitation) { slip_or_trip(); nomul(-2); nomovemsg = ""; /* The more you are carrying the more likely you * are to make noise when you fumble. Adjustments * to this number must be thoroughly play tested. */ if ((inv_weight() > -500)) { You("make a lot of noise!"); wake_nearby(); } } /* from outside means slippery ice; don't reset counter if that's the only fumble reason */ HFumbling &= ~FROMOUTSIDE; if (Fumbling) HFumbling += rnd(20); break; case DETECT_MONSTERS: see_monsters(); break; } } run_timers(); }
static void cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum) { if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) { impossible("cast directed cleric spell (%d) with dmg=0?", spellnum); return; } switch (spellnum) { case CLC_GEYSER: /* this is physical damage, not magical damage */ pline("A sudden geyser slams into you from nowhere!"); dmg = dice(8, 6); if (Half_physical_damage) dmg = (dmg + 1) / 2; break; case CLC_FIRE_PILLAR: pline("A pillar of fire strikes all around you!"); if (Fire_resistance) { shieldeff(u.ux, u.uy); dmg = 0; } else dmg = dice(8, 6); if (Half_spell_damage) dmg = (dmg + 1) / 2; burn_away_slime(); burnarmor(&youmonst); destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); burn_floor_paper(u.ux, u.uy, TRUE, FALSE); break; case CLC_LIGHTNING: { boolean reflects; pline("A bolt of lightning strikes down at you from above!"); reflects = ureflects("It bounces off your %s%s.", ""); if (reflects || Shock_resistance) { shieldeff(u.ux, u.uy); dmg = 0; if (reflects) break; } else dmg = dice(8, 6); if (Half_spell_damage) dmg = (dmg + 1) / 2; destroy_item(WAND_CLASS, AD_ELEC); destroy_item(RING_CLASS, AD_ELEC); break; } case CLC_CURSE_ITEMS: pline("You feel as if you need some help."); rndcurse(); dmg = 0; break; case CLC_INSECTS: { /* Try for insects, and if there are none left, go for (sticks to) snakes. -3. */ const struct permonst *pm = mkclass(&u.uz, S_ANT,0); struct monst *mtmp2 = NULL; char let = (pm ? S_ANT : S_SNAKE); boolean success; int i; coord bypos; int quan; quan = (mtmp->m_lev < 2) ? 1 : rnd((int)mtmp->m_lev / 2); if (quan < 3) quan = 3; success = pm ? TRUE : FALSE; for (i = 0; i <= quan; i++) { if (!enexto(&bypos, level, mtmp->mux, mtmp->muy, mtmp->data)) break; if ((pm = mkclass(&u.uz, let,0)) != 0 && (mtmp2 = makemon(pm, level, bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { success = TRUE; mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0; set_malign(mtmp2); } } /* Not quite right: * -- message doesn't always make sense for unseen caster (particularly * the first message) * -- message assumes plural monsters summoned (non-plural should be * very rare, unlike in nasty()) * -- message assumes plural monsters seen */ if (!success) pline("%s casts at a clump of sticks, but nothing happens.", Monnam(mtmp)); else if (let == S_SNAKE) pline("%s transforms a clump of sticks into snakes!", Monnam(mtmp)); else if (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s summons insects around a spot near you!", Monnam(mtmp)); else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s summons insects around your displaced image!", Monnam(mtmp)); else pline("%s summons insects!", Monnam(mtmp)); dmg = 0; break; } case CLC_BLIND_YOU: /* note: resists_blnd() doesn't apply here */ if (!Blinded) { int num_eyes = eyecount(youmonst.data); pline("Scales cover your %s!", (num_eyes == 1) ? body_part(EYE) : makeplural(body_part(EYE))); make_blinded(Half_spell_damage ? 100L : 200L, FALSE); if (!Blind) pline("Your vision quickly clears."); dmg = 0; } else impossible("no reason for monster to cast blindness spell?"); break; case CLC_PARALYZE: if (Antimagic || Free_action) { shieldeff(u.ux, u.uy); if (multi >= 0) pline("You stiffen briefly."); nomul(-1, "paralyzed by a monster"); } else { if (multi >= 0) pline("You are frozen in place!"); dmg = 4 + (int)mtmp->m_lev; if (Half_spell_damage) dmg = (dmg + 1) / 2; nomul(-dmg, "paralyzed by a monster"); } dmg = 0; break; case CLC_CONFUSE_YOU: if (Antimagic) { shieldeff(u.ux, u.uy); pline("You feel momentarily dizzy."); } else { boolean oldprop = !!Confusion; dmg = (int)mtmp->m_lev; if (Half_spell_damage) dmg = (dmg + 1) / 2; make_confused(HConfusion + dmg, TRUE); if (Hallucination) pline("You feel %s!", oldprop ? "trippier" : "trippy"); else pline("You feel %sconfused!", oldprop ? "more " : ""); } dmg = 0; break; case CLC_CURE_SELF: if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) pline("%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += dice(3,6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; dmg = 0; } break; case CLC_OPEN_WOUNDS: if (Antimagic) { shieldeff(u.ux, u.uy); dmg = (dmg + 1) / 2; } if (dmg <= 5) pline("Your skin itches badly for a moment."); else if (dmg <= 10) pline("Wounds appear on your body!"); else if (dmg <= 20) pline("Severe wounds appear on your body!"); else pline("Your body is covered with painful wounds!"); break; default: impossible("mcastu: invalid clerical spell (%d)", spellnum); dmg = 0; break; } if (dmg) mdamageu(mtmp, dmg); }
int doeat(void) { struct obj *otmp; struct objclass *ftmp; int tmp; // Is there some food (probably a heavy corpse) here on the ground? if (!Levitation) for (otmp = fobj; otmp; otmp = otmp->nobj) { if (otmp->ox == u.ux && otmp->oy == u.uy && otmp->olet == FOOD_SYM) { pline("There %s %s here; eat %s? [ny] ", (otmp->quan == 1) ? "is" : "are", doname(otmp), (otmp->quan == 1) ? "it" : "one"); if (readchar() == 'y') { if (otmp->quan != 1) (void) splitobj(otmp, 1); freeobj(otmp); otmp = addinv(otmp); addtobill(otmp); goto gotit; } } } otmp = getobj("%", "eat"); if (!otmp) return 0; gotit: if (otmp->otyp == TIN) { if (uwep) { switch (uwep->otyp) { case CAN_OPENER: tmp = 1; break; case DAGGER: case CRYSKNIFE: tmp = 3; break; case PICK_AXE: case AXE: tmp = 6; break; default: goto no_opener; } pline("Using your %s you try to open the tin.", aobjnam(uwep, (char *) 0)); } else { no_opener: pline("It is not so easy to open this tin."); if (Glib) { pline("The tin slips out of your hands."); if (otmp->quan > 1) { struct obj *obj; obj = splitobj(otmp, 1); if (otmp == uwep) setuwep(obj); } dropx(otmp); return 1; } tmp = 10 + rn2(1 + 500 / ((int) (u.ulevel + u.ustr))); } tin.reqtime = tmp; tin.usedtime = 0; tin.tin = otmp; occupation = opentin; occtxt = "opening the tin"; return 1; } ftmp = &objects[otmp->otyp]; multi = -ftmp->oc_delay; if (otmp->otyp >= CORPSE && eatcorpse(otmp)) goto eatx; if (!rn2(7) && otmp->otyp != FORTUNE_COOKIE) { pline("Blecch! Rotten food!"); if (!rn2(4)) { pline("You feel rather light headed."); Confusion += d(2, 4); } else if (!rn2(4) && !Blind) { pline("Everything suddenly goes dark."); Blind = d(2, 10); seeoff(0); } else if (!rn2(3)) { if (Blind) pline("The world spins and you slap against the floor."); else pline("The world spins and goes dark."); nomul(-rnd(10)); nomovemsg = "You are conscious again."; } lesshungry(ftmp->nutrition / 4); } else { if (u.uhunger >= 1500) { pline("You choke over your food."); pline("You die..."); killer = ftmp->oc_name; done("choked"); } switch (otmp->otyp) { case FOOD_RATION: if (u.uhunger <= 200) pline("That food really hit the spot!"); else if (u.uhunger <= 700) pline("That satiated your stomach!"); else { pline("You're having a hard time getting all that food down."); multi -= 2; } lesshungry(ftmp->nutrition); if (multi < 0) nomovemsg = "You finished your meal."; break; case TRIPE_RATION: pline("Yak - dog food!"); more_experienced(1, 0); flags.botl = 1; if (rn2(2)) { pline("You vomit."); morehungry(20); if (Sick) { Sick = 0; // David Neves pline("What a relief!"); } } else lesshungry(ftmp->nutrition); break; default: if (otmp->otyp >= CORPSE) pline("That %s tasted terrible!", ftmp->oc_name); else pline("That %s was delicious!", ftmp->oc_name); lesshungry(ftmp->nutrition); if (otmp->otyp == DEAD_LIZARD && (Confusion > 2)) Confusion = 2; else #ifdef QUEST if (otmp->otyp == CARROT && !Blind) { u.uhorizon++; setsee(); pline("Your vision improves."); } else #endif // QUEST if (otmp->otyp == FORTUNE_COOKIE) { if (Blind) { pline("This cookie has a scrap of paper inside!"); pline("What a pity, that you cannot read it!"); } else outrumor(); } else if (otmp->otyp == LUMP_OF_ROYAL_JELLY) { // This stuff seems to be VERY healthy! if (u.ustrmax < 118) u.ustrmax++; if (u.ustr < u.ustrmax) u.ustr++; u.uhp += rnd(20); if (u.uhp > u.uhpmax) { if (!rn2(17)) u.uhpmax++; u.uhp = u.uhpmax; } heal_legs(); } break; } } eatx: if (multi < 0 && !nomovemsg) { static char msgbuf[BUFSZ]; (void) sprintf(msgbuf, "You finished eating the %s.", ftmp->oc_name); nomovemsg = msgbuf; } useup(otmp); return 1; }
int dodrink() { struct obj *otmp, *objs; struct monst *mtmp; int unkn = 0, nothing = 0; otmp = getobj("!", "drink"); if (!otmp) return (0); if (!strcmp(objects[otmp->otyp].oc_descr, "smoky") && !rn2(13)) { ghost_from_bottle(); goto use_it; } switch (otmp->otyp) { case POT_RESTORE_STRENGTH: unkn++; pline("Wow! This makes you feel great!"); if (u.ustr < u.ustrmax) { u.ustr = u.ustrmax; flags.botl = 1; } break; case POT_BOOZE: unkn++; pline("Ooph! This tastes like liquid fire!"); Confusion += d(3, 8); /* the whiskey makes us feel better */ if (u.uhp < u.uhpmax) losehp(-1, "bottle of whiskey"); if (!rn2(4)) { pline("You pass out."); multi = -rnd(15); nomovemsg = "You awake with a headache."; } break; case POT_INVISIBILITY: if (Invis || See_invisible) nothing++; else { if (!Blind) pline("Gee! All of a sudden, you can't see yourself."); else pline("You feel rather airy."), unkn++; newsym(u.ux, u.uy); } Invis += rn1(15, 31); break; case POT_FRUIT_JUICE: pline("This tastes like fruit juice."); lesshungry(20); break; case POT_HEALING: pline("You begin to feel better."); flags.botl = 1; u.uhp += rnd(10); if (u.uhp > u.uhpmax) u.uhp = ++u.uhpmax; if (Blind) Blind = 1; /* see on next move */ if (Sick) Sick = 0; break; case POT_PARALYSIS: if (Levitation) pline("You are motionlessly suspended."); else pline("Your feet are frozen to the floor!"); nomul(-(rn1(10, 25))); break; case POT_MONSTER_DETECTION: if (!fmon) { strange_feeling(otmp, "You feel threatened."); return (1); } else { cls(); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp->mx > 0) at(mtmp->mx, mtmp->my, mtmp->data->mlet); prme(); pline("You sense the presence of monsters."); more(); docrt(); } break; case POT_OBJECT_DETECTION: if (!fobj) { strange_feeling(otmp, "You feel a pull downward."); return (1); } else { for (objs = fobj; objs; objs = objs->nobj) if (objs->ox != u.ux || objs->oy != u.uy) goto outobjmap; pline("You sense the presence of objects close nearby."); break; outobjmap: cls(); for (objs = fobj; objs; objs = objs->nobj) at(objs->ox, objs->oy, objs->olet); prme(); pline("You sense the presence of objects."); more(); docrt(); } break; case POT_SICKNESS: pline("Yech! This stuff tastes like poison."); if (Poison_resistance) pline("(But in fact it was biologically contaminated orange juice.)"); losestr(rn1(4, 3)); losehp(rnd(10), "contaminated potion"); break; case POT_CONFUSION: if (!Confusion) pline("Huh, What? Where am I?"); else nothing++; Confusion += rn1(7, 16); break; case POT_GAIN_STRENGTH: pline("Wow do you feel strong!"); if (u.ustr >= 118) break; /* > 118 is impossible */ if (u.ustr > 17) u.ustr += rnd(118 - u.ustr); else u.ustr++; if (u.ustr > u.ustrmax) u.ustrmax = u.ustr; flags.botl = 1; break; case POT_SPEED: if (Wounded_legs) { heal_legs(); unkn++; break; } if (!(Fast & ~INTRINSIC)) pline("You are suddenly moving much faster."); else pline("Your legs get new energy."), unkn++; Fast += rn1(10, 100); break; case POT_BLINDNESS: if (!Blind) pline("A cloud of darkness falls upon you."); else nothing++; Blind += rn1(100, 250); seeoff(0); break; case POT_GAIN_LEVEL: pluslvl(); break; case POT_EXTRA_HEALING: pline("You feel much better."); flags.botl = 1; u.uhp += d(2, 20) + 1; if (u.uhp > u.uhpmax) u.uhp = (u.uhpmax += 2); if (Blind) Blind = 1; if (Sick) Sick = 0; break; case POT_LEVITATION: if (!Levitation) float_up(); else nothing++; Levitation += rnd(100); u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down; break; default: impossible("What a funny potion! (%u)", otmp->otyp); return (0); } if (nothing) { unkn++; pline("You have a peculiar feeling for a moment, then it passes."); } if (otmp->dknown && !objects[otmp->otyp].oc_name_known) { if (!unkn) { objects[otmp->otyp].oc_name_known = 1; more_experienced(0, 10); } else if (!objects[otmp->otyp].oc_uname) docall(otmp); } use_it: useup(otmp); return (1); }
/* return values: * 1: successful spell * 0: unsuccessful spell */ int castmu(struct monst *mtmp, const struct attack *mattk, boolean thinks_it_foundyou, boolean foundyou) { int dmg, ml = mtmp->m_lev; int ret; int spellnum = 0; /* Three cases: * -- monster is attacking you. Search for a useful spell. * -- monster thinks it's attacking you. Search for a useful spell, * without checking for undirected. If the spell found is directed, * it fails with cursetxt() and loss of mspec_used. * -- monster isn't trying to attack. Select a spell once. Don't keep * searching; if that spell is not useful (or if it's directed), * return and do something else. * Since most spells are directed, this means that a monster that isn't * attacking casts spells only a small portion of the time that an * attacking monster does. */ if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) { int cnt = 40; do { spellnum = rn2(ml); if (mattk->adtyp == AD_SPEL) spellnum = choose_magic_spell(spellnum); else spellnum = choose_clerical_spell(spellnum); /* not trying to attack? don't allow directed spells */ if (!thinks_it_foundyou) { if (!is_undirected_spell(mattk->adtyp, spellnum) || spell_would_be_useless(mtmp, mattk->adtyp, spellnum)) { if (foundyou) impossible("spellcasting monster found you and doesn't know it?"); return 0; } break; } } while (--cnt > 0 && spell_would_be_useless(mtmp, mattk->adtyp, spellnum)); if (cnt == 0) return 0; } /* monster unable to cast spells? */ if (mtmp->mcan || mtmp->mspec_used || !ml) { cursetxt(mtmp, is_undirected_spell(mattk->adtyp, spellnum)); return 0; } if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) { mtmp->mspec_used = 10 - mtmp->m_lev; if (mtmp->mspec_used < 2) mtmp->mspec_used = 2; } /* monster can cast spells, but is casting a directed spell at the wrong place? If so, give a message, and return. Do this *after* penalizing mspec_used. */ if (!foundyou && thinks_it_foundyou && !is_undirected_spell(mattk->adtyp, spellnum)) { pline("%s casts a spell at %s!", canseemon(mtmp) ? Monnam(mtmp) : "Something", level->locations[mtmp->mux][mtmp->muy].typ == WATER ? "empty water" : "thin air"); return 0; } nomul(0, NULL); if (rn2(ml*10) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */ if (canseemon(mtmp) && flags.soundok) pline("The air crackles around %s.", mon_nam(mtmp)); return 0; } if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) { pline("%s casts a spell%s!", canspotmon(mtmp) ? Monnam(mtmp) : "Something", is_undirected_spell(mattk->adtyp, spellnum) ? "" : (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? " at a spot near you" : (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? " at your displaced image" : " at you"); } /* * As these are spells, the damage is related to the level * of the monster casting the spell. */ if (!foundyou) { dmg = 0; if (mattk->adtyp != AD_SPEL && mattk->adtyp != AD_CLRC) { impossible( "%s casting non-hand-to-hand version of hand-to-hand spell %d?", Monnam(mtmp), mattk->adtyp); return 0; } } else if (mattk->damd) dmg = dice((int)((ml/2) + mattk->damn), (int)mattk->damd); else dmg = dice((int)((ml/2) + 1), 6); if (Half_spell_damage) dmg = (dmg+1) / 2; ret = 1; switch (mattk->adtyp) { case AD_FIRE: pline("You're enveloped in flames."); if (Fire_resistance) { shieldeff(u.ux, u.uy); pline("But you resist the effects."); dmg = 0; } burn_away_slime(); break; case AD_COLD: pline("You're covered in frost."); if (Cold_resistance) { shieldeff(u.ux, u.uy); pline("But you resist the effects."); dmg = 0; } break; case AD_MAGM: pline("You are hit by a shower of missiles!"); if (Antimagic) { shieldeff(u.ux, u.uy); pline("The missiles bounce off!"); dmg = 0; } else dmg = dice((int)mtmp->m_lev/2 + 1,6); break; case AD_SPEL: /* wizard spell */ case AD_CLRC: /* clerical spell */ { if (mattk->adtyp == AD_SPEL) cast_wizard_spell(mtmp, dmg, spellnum); else cast_cleric_spell(mtmp, dmg, spellnum); dmg = 0; /* done by the spell casting functions */ break; } } if (dmg) mdamageu(mtmp, dmg); return ret; }
/* perform the command given by cmdidx (in index into cmdlist in cmd.c) * returns -1 if the command completes */ int command_input(int cmdidx, int rep, struct nh_cmd_arg *arg) { boolean didmove = FALSE; if (multi >= 0 && occupation) handle_occupation(); else if (multi == 0 || (multi > 0 && cmdidx != -1)) { saved_cmd = cmdidx; do_command(cmdidx, rep, TRUE, arg); } else if (multi > 0) { /* allow interruption of multi-turn commands */ if (rep == -1) { nomul(0, NULL); return READY_FOR_INPUT; } if (flags.mv) { if (multi < COLNO && !--multi) flags.travel = iflags.travel1 = flags.mv = flags.run = 0; if (!domove(u.dx, u.dy, 0)) { /* Don't use a move when travelling into an obstacle. */ flags.move = FALSE; nomul(0, NULL); } } else do_command(saved_cmd, multi, FALSE, arg); } /* no need to do anything here for multi < 0 */ if (u.utotype) /* change dungeon level */ deferred_goto(); /* after rhack() */ /* !flags.move here: multiple movement command stopped */ else if (!flags.move || !flags.mv) iflags.botl = 1; if (vision_full_recalc) vision_recalc(0); /* vision! */ /* when running in non-tport mode, this gets done through domove() */ if ((!flags.run || iflags.runmode == RUN_TPORT) && (multi && (!flags.travel ? !(multi % 7) : !(moves % 7L)))) { if (flags.run) iflags.botl = 1; flush_screen(); } didmove = flags.move; if (didmove) { you_moved(); } /* actual time passed */ /****************************************/ /* once-per-player-input things go here */ /****************************************/ xmalloc_cleanup(); iflags.next_msg_nonblocking = FALSE; /* prepare for the next move */ flags.move = 1; pre_move_tasks(didmove); do_delay_msg(); if (multi == 0 && !occupation) { flush_screen(); /* Flush screen buffer */ maybe_tutorial(); } return -1; }
static int domonnoise(struct monst *mtmp) { const char *pline_msg = 0, /* Monnam(mtmp) will be prepended */ *verbl_msg = 0; /* verbalize() */ const struct permonst *ptr = mtmp->data; char verbuf[BUFSZ]; /* presumably nearness and sleep checks have already been made */ if (!flags.soundok) return 0; if (is_silent(ptr)) return 0; /* Make sure its your role's quest quardian; adjust if not */ if (ptr->msound == MS_GUARDIAN && ptr != &pm_guardian) { int mndx = monsndx(ptr); ptr = &mons[genus(mndx, 1)]; } /* be sure to do this before talking; the monster might teleport away, in which case we want to check its pre-teleport position */ if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); switch (ptr->msound) { case MS_ORACLE: return doconsult(mtmp); case MS_PRIEST: priest_talk(mtmp); break; case MS_LEADER: case MS_NEMESIS: case MS_GUARDIAN: quest_chat(mtmp); break; case MS_SELL: /* pitch, pay, total */ shk_chat(mtmp); break; case MS_VAMPIRE: { /* vampire messages are varied by tameness, peacefulness, and time of night */ boolean isnight = night(); boolean kindred = (Upolyd && (u.umonnum == PM_VAMPIRE || u.umonnum == PM_VAMPIRE_LORD)); boolean nightchild = (Upolyd && (u.umonnum == PM_WOLF || u.umonnum == PM_WINTER_WOLF || u.umonnum == PM_WINTER_WOLF_CUB)); const char *racenoun = (flags.female && urace.individual.f) ? urace.individual. f : (urace.individual.m) ? urace.individual.m : urace.noun; if (mtmp->mtame) { if (kindred) { sprintf(verbuf, "Good %s to you Master%s", isnight ? "evening" : "day", isnight ? "!" : ". Why do we not rest?"); verbl_msg = verbuf; } else { sprintf(verbuf, "%s%s", nightchild ? "Child of the night, " : "", midnight()? "I can stand this craving no longer!" : isnight ? "I beg you, help me satisfy this growing craving!" : "I find myself growing a little weary."); verbl_msg = verbuf; } } else if (mtmp->mpeaceful) { if (kindred && isnight) { sprintf(verbuf, "Good feeding %s!", flags.female ? "sister" : "brother"); verbl_msg = verbuf; } else if (nightchild && isnight) { sprintf(verbuf, "How nice to hear you, child of the night!"); verbl_msg = verbuf; } else verbl_msg = "I only drink... potions."; } else { int vampindex; static const char *const vampmsg[] = { /* These first two (0 and 1) are specially handled below */ "I vant to suck your %s!", "I vill come after %s without regret!", /* other famous vampire quotes can follow here if desired */ }; if (kindred) verbl_msg = "This is my hunting ground that you dare to prowl!"; else if (youmonst.data == &mons[PM_SILVER_DRAGON] || youmonst.data == &mons[PM_BABY_SILVER_DRAGON]) { /* Silver dragons are silver in color, not made of silver */ sprintf(verbuf, "%s! Your silver sheen does not frighten me!", youmonst.data == &mons[PM_SILVER_DRAGON] ? "Fool" : "Young Fool"); verbl_msg = verbuf; } else { vampindex = rn2(SIZE(vampmsg)); if (vampindex == 0) { sprintf(verbuf, vampmsg[vampindex], body_part(BLOOD)); verbl_msg = verbuf; } else if (vampindex == 1) { sprintf(verbuf, vampmsg[vampindex], Upolyd ? an(mons[u.umonnum]. mname) : an(racenoun)); verbl_msg = verbuf; } else verbl_msg = vampmsg[vampindex]; } } } break; case MS_WERE: if (flags.moonphase == FULL_MOON && (night() ^ !rn2(13))) { pline("%s throws back %s head and lets out a blood curdling %s!", Monnam(mtmp), mhis(mtmp), ptr == &mons[PM_HUMAN_WERERAT] ? "shriek" : "howl"); wake_nearto(mtmp->mx, mtmp->my, 11 * 11); } else pline_msg = "whispers inaudibly. All you can make out is \"moon\"."; break; case MS_BARK: if (flags.moonphase == FULL_MOON && night()) { pline_msg = "howls."; } else if (mtmp->mpeaceful) { if (mtmp->mtame && (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5)) pline_msg = "whines."; else if (mtmp->mtame && EDOG(mtmp)->hungrytime > moves + 1000) pline_msg = "yips."; else { if (mtmp->data != &mons[PM_DINGO]) /* dingos do not actually bark */ pline_msg = "barks."; } } else { pline_msg = "growls."; } break; case MS_MEW: if (mtmp->mtame) { if (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || mtmp->mtame < 5) pline_msg = "yowls."; else if (moves > EDOG(mtmp)->hungrytime) pline_msg = "meows."; else if (EDOG(mtmp)->hungrytime > moves + 1000) pline_msg = "purrs."; else pline_msg = "mews."; break; } /* else FALLTHRU */ case MS_GROWL: pline_msg = mtmp->mpeaceful ? "snarls." : "growls!"; break; case MS_ROAR: pline_msg = mtmp->mpeaceful ? "snarls." : "roars!"; break; case MS_SQEEK: pline_msg = "squeaks."; break; case MS_SQAWK: if (ptr == &mons[PM_RAVEN] && !mtmp->mpeaceful) verbl_msg = "Nevermore!"; else pline_msg = "squawks."; break; case MS_HISS: if (!mtmp->mpeaceful) pline_msg = "hisses!"; else return 0; /* no sound */ break; case MS_BUZZ: pline_msg = mtmp->mpeaceful ? "drones." : "buzzes angrily."; break; case MS_GRUNT: pline_msg = "grunts."; break; case MS_NEIGH: if (mtmp->mtame < 5) pline_msg = "neighs."; else if (moves > EDOG(mtmp)->hungrytime) pline_msg = "whinnies."; else pline_msg = "whickers."; break; case MS_WAIL: pline_msg = "wails mournfully."; break; case MS_GURGLE: pline_msg = "gurgles."; break; case MS_BURBLE: pline_msg = "burbles."; break; case MS_SHRIEK: pline_msg = "shrieks."; aggravate(); break; case MS_IMITATE: pline_msg = "imitates you."; break; case MS_BONES: pline("%s rattles noisily.", Monnam(mtmp)); pline("You freeze for a moment."); nomul(-2, "scared by rattling"); nomovemsg = 0; /* default: "You can move again." */ break; case MS_LAUGH: { static const char *const laugh_msg[4] = { "giggles.", "chuckles.", "snickers.", "laughs.", }; pline_msg = laugh_msg[rn2(4)]; } break; case MS_MUMBLE: pline_msg = "mumbles incomprehensibly."; break; case MS_DJINNI: if (mtmp->mtame) { verbl_msg = "Sorry, I'm all out of wishes."; } else if (mtmp->mpeaceful) { if (ptr == &mons[PM_WATER_DEMON]) pline_msg = "gurgles."; else verbl_msg = "I'm free!"; } else verbl_msg = "This will teach you not to disturb me!"; break; case MS_BOAST: /* giants */ if (!mtmp->mpeaceful) { switch (rn2(4)) { case 0: pline("%s boasts about %s gem collection.", Monnam(mtmp), mhis(mtmp)); break; case 1: pline_msg = "complains about a diet of mutton."; break; default: pline_msg = "shouts \"Fee Fie Foe Foo!\" and guffaws."; wake_nearto(mtmp->mx, mtmp->my, 7 * 7); break; } break; } /* else FALLTHRU */ case MS_HUMANOID: if (!mtmp->mpeaceful) { if (In_endgame(&u.uz) && is_mplayer(ptr)) { mplayer_talk(mtmp); break; } else return 0; /* no sound */ } /* Generic peaceful humanoid behaviour. */ if (mtmp->mflee) pline_msg = "wants nothing to do with you."; else if (mtmp->mhp < mtmp->mhpmax / 4) pline_msg = "moans."; else if (mtmp->mconf || mtmp->mstun) verbl_msg = !rn2(3) ? "Huh?" : rn2(2) ? "What?" : "Eh?"; else if (!mtmp->mcansee) verbl_msg = "I can't see!"; else if (mtmp->mtrapped) { struct trap *t = t_at(level, mtmp->mx, mtmp->my); if (t) t->tseen = 1; verbl_msg = "I'm trapped!"; } else if (mtmp->mhp < mtmp->mhpmax / 2) pline_msg = "asks for a potion of healing."; else if (mtmp->mtame && !mtmp->isminion && moves > EDOG(mtmp)->hungrytime) verbl_msg = "I'm hungry."; /* Specific monsters' interests */ else if (is_elf(ptr)) pline_msg = "curses orcs."; else if (is_dwarf(ptr)) pline_msg = "talks about mining."; else if (likes_magic(ptr)) pline_msg = "talks about spellcraft."; else if (ptr->mlet == S_CENTAUR) pline_msg = "discusses hunting."; else switch (monsndx(ptr)) { case PM_HOBBIT: pline_msg = (mtmp->mhpmax - mtmp->mhp >= 10) ? "complains about unpleasant dungeon conditions." : "asks you about the One Ring."; break; case PM_ARCHEOLOGIST: pline_msg = "describes a recent article in \"Spelunker Today\" magazine."; break; case PM_TOURIST: verbl_msg = "Aloha."; break; default: pline_msg = "discusses dungeon exploration."; break; } break; case MS_SEDUCE: if (ptr->mlet != S_NYMPH && flags.seduce_enabled && could_seduce(mtmp, &youmonst, NULL) == 1) { doseduce(mtmp); break; } switch ((poly_gender() != (int)mtmp->female) ? rn2(3) : 0) { case 2: verbl_msg = "Hello, sailor."; break; case 1: pline_msg = "comes on to you."; break; default: pline_msg = "cajoles you."; } break; case MS_ARREST: if (mtmp->mpeaceful) verbalize("Just the facts, %s.", flags.female ? "Ma'am" : "Sir"); else { static const char *const arrest_msg[3] = { "Anything you say can be used against you.", "You're under arrest!", "Stop in the name of the Law!", }; verbl_msg = arrest_msg[rn2(3)]; } break; case MS_BRIBE: if (mtmp->mpeaceful && !mtmp->mtame) { demon_talk(mtmp); break; } /* fall through */ case MS_CUSS: if (!mtmp->mpeaceful) cuss(mtmp); break; case MS_SPELL: /* deliberately vague, since it's not actually casting any spell */ pline_msg = "seems to mutter a cantrip."; break; case MS_NURSE: if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) verbl_msg = "Put that weapon away before you hurt someone!"; else if (uarmc || uarm || uarmh || uarms || uarmg || uarmf) verbl_msg = Role_if(PM_HEALER) ? "Doc, I can't help you unless you cooperate." : "Please undress so I can examine you."; else if (uarmu) verbl_msg = "Take off your shirt, please."; else verbl_msg = "Relax, this won't hurt a bit."; break; case MS_GUARD: if (money_cnt(invent)) verbl_msg = "Please drop that gold and follow me."; else verbl_msg = "Please follow me."; break; case MS_SOLDIER: { static const char *const soldier_foe_msg[3] = { "Resistance is useless!", "You're dog meat!", "Surrender!", }, *const soldier_pax_msg[3] = { "What lousy pay we're getting here!", "The food's not fit for Orcs!", "My feet hurt, I've been on them all day!", }; verbl_msg = mtmp->mpeaceful ? soldier_pax_msg[rn2(3)] : soldier_foe_msg[rn2(3)]; } break; case MS_RIDER: if (ptr == &mons[PM_DEATH] && !rn2(10)) pline_msg = "is busy reading a copy of Sandman #8."; else verbl_msg = "Who do you think you are, War?"; break; } if (pline_msg) pline("%s %s", Monnam(mtmp), pline_msg); else if (verbl_msg) verbalize(verbl_msg); return 1; }
void moveloop() { #if defined(MICRO) || defined(WIN32) char ch; int abort_lev; #endif int moveamt = 0, wtcap = 0, change = 0; boolean didmove = FALSE, monscanmove = FALSE; flags.moonphase = phase_of_the_moon(); if(flags.moonphase == FULL_MOON) { You("are lucky! Full moon tonight."); change_luck(1); } else if(flags.moonphase == NEW_MOON) { pline("Be careful! New moon tonight."); } flags.friday13 = friday_13th(); if (flags.friday13) { pline("Watch out! Bad things can happen on Friday the 13th."); change_luck(-1); } /* KMH -- February 2 */ flags.groundhogday = groundhog_day(); if (flags.groundhogday) pline("Happy Groundhog Day!"); initrack(); /* Note: these initializers don't do anything except guarantee that we're linked properly. */ decl_init(); monst_init(); monstr_init(); /* monster strengths */ objects_init(); #ifdef WIZARD if (wizard) add_debug_extended_commands(); #endif (void) encumber_msg(); /* in case they auto-picked up something */ if (defer_see_monsters) { defer_see_monsters = FALSE; see_monsters(); } u.uz0.dlevel = u.uz.dlevel; youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */ for(;;) { get_nh_event(); #ifdef POSITIONBAR do_positionbar(); #endif didmove = flags.move; if(didmove) { /* actual time passed */ youmonst.movement -= NORMAL_SPEED; do { /* hero can't move this turn loop */ wtcap = encumber_msg(); flags.mon_moving = TRUE; do { monscanmove = movemon(); if (youmonst.movement > NORMAL_SPEED) break; /* it's now your turn */ } while (monscanmove); flags.mon_moving = FALSE; if (!monscanmove && youmonst.movement < NORMAL_SPEED) { /* both you and the monsters are out of steam this round */ /* set up for a new turn */ struct monst *mtmp; mcalcdistress(); /* adjust monsters' trap, blind, etc */ /* reallocate movement rations to monsters */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) mtmp->movement += mcalcmove(mtmp); if(!rn2(u.uevent.udemigod ? 25 : (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70)) (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS); /* calculate how much time passed. */ #ifdef STEED if (u.usteed && u.umoved) { /* your speed doesn't augment steed's speed */ moveamt = mcalcmove(u.usteed); } else #endif { moveamt = youmonst.data->mmove; if (Very_fast) { /* speed boots or potion */ /* average movement is 1.67 times normal */ moveamt += NORMAL_SPEED / 2; if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2; } else if (Fast) { /* average movement is 1.33 times normal */ if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2; } if (tech_inuse(T_BLINK)) { /* TECH: Blinking! */ /* Case Average Variance * ------------------------- * Normal 12 0 * Fast 16 12 * V fast 20 12 * Blinking 24 12 * F & B 28 18 * V F & B 30 18 */ moveamt += NORMAL_SPEED * 2 / 3; if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2; } } switch (wtcap) { case UNENCUMBERED: break; case SLT_ENCUMBER: moveamt -= (moveamt / 4); break; case MOD_ENCUMBER: moveamt -= (moveamt / 2); break; case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break; case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break; default: break; } youmonst.movement += moveamt; if (youmonst.movement < 0) youmonst.movement = 0; settrack(); monstermoves++; moves++; /********************************/ /* once-per-turn things go here */ /********************************/ if (flags.bypasses) clear_bypasses(); if(Glib) glibr(); nh_timeout(); run_regions(); #ifdef DUNGEON_GROWTH dgn_growths(TRUE, TRUE); #endif if (u.ublesscnt) u.ublesscnt--; if(flags.time && !flags.run) flags.botl = 1; /* One possible result of prayer is healing. Whether or * not you get healed depends on your current hit points. * If you are allowed to regenerate during the prayer, the * end-of-prayer calculation messes up on this. * Another possible result is rehumanization, which requires * that encumbrance and movement rate be recalculated. */ if (u.uinvulnerable) { /* for the moment at least, you're in tiptop shape */ wtcap = UNENCUMBERED; } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz)) { if (u.mh > 1) { u.mh--; flags.botl = 1; } else if (u.mh < 1) rehumanize(); } else if (Upolyd && u.mh < u.mhmax) { if (u.mh < 1) rehumanize(); else if (Regeneration || (wtcap < MOD_ENCUMBER && !(moves%20))) { flags.botl = 1; u.mh++; } } else if (u.uhp < u.uhpmax && (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) { /* * KMH, balance patch -- New regeneration code * Healthstones have been added, which alter your effective * experience level and constitution (-2 cursed, +1 uncursed, * +2 blessed) for the basis of regeneration calculations. */ int efflev = u.ulevel + u.uhealbonus; int effcon = ACURR(A_CON) + u.uhealbonus; int heal = 1; if (efflev > 9 && !(moves % 3)) { if (effcon <= 12) { heal = 1; } else { heal = rnd(effcon); if (heal > efflev-9) heal = efflev-9; } flags.botl = 1; u.uhp += heal; if(u.uhp > u.uhpmax) u.uhp = u.uhpmax; } else if (Regeneration || (efflev <= 9 && !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) { flags.botl = 1; u.uhp++; } } if (!u.uinvulnerable && u.uen > 0 && u.uhp < u.uhpmax && tech_inuse(T_CHI_HEALING)) { u.uen--; u.uhp++; flags.botl = 1; } /* moving around while encumbered is hard work */ if (wtcap > MOD_ENCUMBER && u.umoved) { if(!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) { if (Upolyd && u.mh > 1) { u.mh--; } else if (!Upolyd && u.uhp > 1) { u.uhp--; } else { You("pass out from exertion!"); exercise(A_CON, FALSE); fall_asleep(-10, FALSE); } } } /* KMH -- OK to regenerate if you don't move */ if ((u.uen < u.uenmax) && (Energy_regeneration || ((wtcap < MOD_ENCUMBER || !flags.mv) && (!(moves%((MAXULEV + 15 - u.ulevel) * (Role_if(PM_WIZARD) ? 3 : 4) / 6)))))) { u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1); #ifdef WIZ_PATCH_DEBUG pline("mana was = %d now = %d",temp,u.uen); #endif if (u.uen > u.uenmax) u.uen = u.uenmax; flags.botl = 1; } if(!u.uinvulnerable) { if(Teleportation && !rn2(85)) { xchar old_ux = u.ux, old_uy = u.uy; tele(); if (u.ux != old_ux || u.uy != old_uy) { if (!next_to_u()) { check_leash(&youmonst, old_ux, old_uy, TRUE); } #ifdef REDO /* clear doagain keystrokes */ pushch(0); savech(0); #endif } } long ch = (80 - (40 * night())) / 2 * (Race_if(PM_HUMAN_WEREWOLF) ? u.ulevel * u.ulevel : 2); ch = (ch > LARGEST_INT) ? LARGEST_INT : ch; /* delayed change may not be valid anymore */ if ((change == 1 && !Polymorph) || (change == 2 && u.ulycn == NON_PM)) change = 0; if(Polymorph && !rn2(100)) change = 1; else if (u.ulycn >= LOW_PM && !Upolyd && !rn2((int)ch)) change = 2; if (change && !Unchanging) { if (multi >= 0) { if (occupation) stop_occupation(); else nomul(0); if (change == 1) polyself(FALSE); else you_were(); change = 0; } } } /* !u.uinvulnerable */ if(Searching && multi >= 0) (void) dosearch0(1); dosounds(); do_storms(); gethungry(); age_spells(); exerchk(); invault(); if (u.uhave.amulet) amulet(); if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3)); if (u.uevent.udemigod && !u.uinvulnerable) { if (u.udg_cnt) u.udg_cnt--; if (!u.udg_cnt) { intervene(); u.udg_cnt = rn1(200, 50); } } restore_attrib(); /* underwater and waterlevel vision are done here */ if (Is_waterlevel(&u.uz)) movebubbles(); else if (Underwater) under_water(0); /* vision while buried done here */ else if (u.uburied) under_ground(0); /* when immobile, count is in turns */ if(multi < 0) { if (++multi == 0) { /* finished yet? */ unmul((char *)0); /* if unmul caused a level change, take it now */ if (u.utotype) deferred_goto(); } } } } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */ /******************************************/ /* once-per-hero-took-time things go here */ /******************************************/ } /* actual time passed */ /****************************************/ /* once-per-player-input things go here */ /****************************************/ find_ac(); if(!flags.mv || Blind) { /* redo monsters if hallu or wearing a helm of telepathy */ if (Hallucination) { /* update screen randomly */ see_monsters(); see_objects(); see_traps(); if (u.uswallow) swallowed(0); } else if (Unblind_telepat) { see_monsters(); } else if (Warning || Warn_of_mon) see_monsters(); if (vision_full_recalc) vision_recalc(0); /* vision! */ } if(flags.botl || flags.botlx) bot(); flags.move = 1; if(multi >= 0 && occupation) { #if defined(MICRO) || defined(WIN32) abort_lev = 0; if (kbhit()) { if ((ch = Getchar()) == ABORT) abort_lev++; # ifdef REDO else pushch(ch); # endif /* REDO */ } if (!abort_lev && (*occupation)() == 0) #else if ((*occupation)() == 0) #endif occupation = 0; if( #if defined(MICRO) || defined(WIN32) abort_lev || #endif monster_nearby()) { stop_occupation(); reset_eat(); } #if defined(MICRO) || defined(WIN32) if (!(++occtime % 7)) display_nhwindow(WIN_MAP, FALSE); #endif continue; } if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz) && !BClairvoyant && !(moves % 15) && !rn2(2)) do_vicinity_map(); if(u.utrap && u.utraptype == TT_LAVA) { if(!is_lava(u.ux,u.uy)) u.utrap = 0; else if (!u.uinvulnerable) { u.utrap -= 1<<8; if(u.utrap < 1<<8) { killer_format = KILLED_BY; killer = "molten lava"; You("sink below the surface and die."); done(DISSOLVED); } else if(didmove && !u.umoved) { Norep("You sink deeper into the lava."); u.utrap += rnd(4); } } } #ifdef WIZARD if (iflags.sanity_check) sanity_check(); #endif #ifdef CLIPPING /* just before rhack */ cliparound(u.ux, u.uy); #endif u.umoved = FALSE; if (multi > 0) { lookaround(); if (!multi) { /* lookaround may clear multi */ flags.move = 0; if (flags.time) flags.botl = 1; continue; } if (flags.mv) { if(multi < COLNO && !--multi) flags.travel = iflags.travel1 = flags.mv = flags.run = 0; domove(); } else { --multi; rhack(save_cm); } } else if (multi == 0) { #ifdef MAIL ckmailstatus(); #endif rhack((char *)0); } if (u.utotype) /* change dungeon level */ deferred_goto(); /* after rhack() */ /* !flags.move here: multiple movement command stopped */ else if (flags.time && (!flags.move || !flags.mv)) flags.botl = 1; if (vision_full_recalc) vision_recalc(0); /* vision! */ /* when running in non-tport mode, this gets done through domove() */ if ((!flags.run || iflags.runmode == RUN_TPORT) && (multi && (!flags.travel ? !(multi % 7) : !(moves % 7L)))) { if (flags.time && flags.run) flags.botl = 1; display_nhwindow(WIN_MAP, FALSE); } } }
/* * mhitu: monster hits you * returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise */ bool mhitu(struct monst *mtmp) { struct permonst *mdat = mtmp->data; int tmp, ctmp; nomul(0); /* If swallowed, can only be affected by hissers and by u.ustuck */ if (u.uswallow) { if (mtmp != u.ustuck) { if (mdat->mlet == 'c' && !rn2(13)) { pline("Outside, you hear %s's hissing!", monnam(mtmp)); pline("%s gets turned to stone!", Monnam(u.ustuck)); pline("And the same fate befalls you."); done_in_by(mtmp); /* "notreached": not return(1); */ } return (0); } switch (mdat->mlet) { /* now mtmp == u.ustuck */ case ',': youswld(mtmp, (u.uac > 0) ? u.uac + 4 : 4, 5, "The trapper"); break; case '\'': youswld(mtmp, rnd(6), 7, "The lurker above"); break; case 'P': youswld(mtmp, d(2, 4), 12, "The purple worm"); break; default: /* This is not impossible! */ pline("The mysterious monster totally digests you."); u.uhp = 0; } if (u.uhp < 1) done_in_by(mtmp); return (0); } if (mdat->mlet == 'c' && Stoned) return (0); /* make eels visible the moment they hit/miss us */ if (mdat->mlet == ';' && mtmp->minvis && cansee(mtmp->mx, mtmp->my)) { mtmp->minvis = 0; pmon(mtmp); } if (!strchr("1&DuxynNF", mdat->mlet)) tmp = hitu(mtmp, d(mdat->damn, mdat->damd)); else tmp = 0; if (strchr(UNDEAD, mdat->mlet) && midnight()) tmp += hitu(mtmp, d(mdat->damn, mdat->damd)); ctmp = tmp && !mtmp->mcan && (!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50)); switch (mdat->mlet) { case '1': if (wiz_hit(mtmp)) /* he disappeared */ return (1); break; case '&': if (!mtmp->cham && !mtmp->mcan && !rn2(13)) { makemon(PM_DEMON, u.ux, u.uy); } else { hitu(mtmp, d(2, 6)); hitu(mtmp, d(2, 6)); hitu(mtmp, rnd(3)); hitu(mtmp, rnd(3)); hitu(mtmp, rn1(4, 2)); } break; case ',': if (tmp) justswld(mtmp, "The trapper"); break; case '\'': if (tmp) justswld(mtmp, "The lurker above"); break; case ';': if (ctmp) { if (!u.ustuck && !rn2(10)) { pline("%s swings itself around you!", Monnam(mtmp)); u.ustuck = mtmp; } else if (u.ustuck == mtmp && levl[mtmp->mx][mtmp->my].typ == POOL) { pline("%s drowns you ...", Monnam(mtmp)); done("drowned"); } } break; case 'A': if (ctmp && rn2(2)) { if (Poison_resistance) pline("The sting doesn't seem to affect you."); else { pline("You feel weaker!"); losestr(1); } } break; case 'C': hitu(mtmp, rnd(6)); break; case 'c': if (!rn2(5)) { pline("You hear %s's hissing!", monnam(mtmp)); if (ctmp || !rn2(20) || (flags.moonphase == NEW_MOON && !carrying(DEAD_LIZARD))) Stoned = 5; } break; case 'D': if (rn2(6) || mtmp->mcan) { hitu(mtmp, d(3, 10)); hitu(mtmp, rnd(8)); hitu(mtmp, rnd(8)); break; } kludge("%s breathes fire!", "The dragon"); buzz(-1, mtmp->mx, mtmp->my, u.ux - mtmp->mx, u.uy - mtmp->my); break; case 'd': hitu(mtmp, d(2, (flags.moonphase == FULL_MOON) ? 3 : 4)); break; case 'e': hitu(mtmp, d(3, 6)); break; case 'F': if (mtmp->mcan) break; kludge("%s explodes!", "The freezing sphere"); if (Cold_resistance) pline("You don't seem affected by it."); else { xchar dn; if (17 - (u.ulevel / 2) > rnd(20)) { pline("You get blasted!"); dn = 6; } else { pline("You duck the blast..."); dn = 3; } losehp_m(d(dn, 6), mtmp); } mondead(mtmp); return (1); case 'g': if (ctmp && multi >= 0 && !rn2(3)) { kludge("You are frozen by %ss juices", "the cube'"); nomul(-rnd(10)); } break; case 'h': if (ctmp && multi >= 0 && !rn2(5)) { nomul(-rnd(10)); kludge("You are put to sleep by %ss bite!", "the homunculus'"); } break; case 'j': tmp = hitu(mtmp, rnd(3)); tmp &= hitu(mtmp, rnd(3)); if (tmp) { hitu(mtmp, rnd(4)); hitu(mtmp, rnd(4)); } break; case 'k': if ((hitu(mtmp, rnd(4)) || !rn2(3)) && ctmp) poisoned("bee's sting", mdat->mname); break; case 'L': if (tmp) stealgold(mtmp); break; case 'N': if (mtmp->mcan && !Blind) { pline("%s tries to seduce you, but you seem not interested.", Amonnam(mtmp, "plain")); if (rn2(3)) rloc(mtmp); } else if (steal(mtmp)) { rloc(mtmp); mtmp->mflee = 1; } break; case 'n': if (!uwep && !uarm && !uarmh && !uarms && !uarmg) { pline("%s hits! (I hope you don't mind)", Monnam(mtmp)); u.uhp += rnd(7); if (!rn2(7)) u.uhpmax++; if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; flags.botl = 1; if (!rn2(50)) rloc(mtmp); } else { hitu(mtmp, d(2, 6)); hitu(mtmp, d(2, 6)); } break; case 'o': tmp = hitu(mtmp, rnd(6)); if (hitu(mtmp, rnd(6)) && tmp && /* hits with both paws */ !u.ustuck && rn2(2)) { u.ustuck = mtmp; kludge("%s has grabbed you!", "The owlbear"); u.uhp -= d(2, 8); } else if (u.ustuck == mtmp) { u.uhp -= d(2, 8); pline("You are being crushed."); } break; case 'P': if (ctmp && !rn2(4)) justswld(mtmp, "The purple worm"); else hitu(mtmp, d(2, 4)); break; case 'Q': hitu(mtmp, rnd(2)); hitu(mtmp, rnd(2)); break; case 'R': if (tmp && uarmh && !uarmh->rustfree && (int)uarmh->spe >= -1) { pline("Your helmet rusts!"); uarmh->spe--; } else if (ctmp && uarm && !uarm->rustfree && /* Mike Newton */ uarm->otyp < STUDDED_LEATHER_ARMOR && (int)uarm->spe >= -1) { pline("Your armor rusts!"); uarm->spe--; } break; case 'S': if (ctmp && !rn2(8)) poisoned("snake's bite", mdat->mname); break; case 's': if (tmp && !rn2(8)) poisoned("scorpion's sting", mdat->mname); hitu(mtmp, rnd(8)); hitu(mtmp, rnd(8)); break; case 'T': hitu(mtmp, rnd(6)); hitu(mtmp, rnd(6)); break; case 't': if (!rn2(5)) rloc(mtmp); break; case 'u': mtmp->mflee = 1; break; case 'U': hitu(mtmp, d(3, 4)); hitu(mtmp, d(3, 4)); break; case 'v': if (ctmp && !u.ustuck) u.ustuck = mtmp; break; case 'V': if (tmp) u.uhp -= 4; if (ctmp) losexp(); break; case 'W': if (ctmp) losexp(); break; #ifndef NOWORM case 'w': if (tmp) wormhit(mtmp); #endif /* NOWORM */ break; case 'X': hitu(mtmp, rnd(5)); hitu(mtmp, rnd(5)); hitu(mtmp, rnd(5)); break; case 'x': { long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE; pline("%s pricks in your %s leg!", Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left"); set_wounded_legs(side, rnd(50)); losehp_m(2, mtmp); break; } case 'y': if (mtmp->mcan) break; mondead(mtmp); if (!Blind) { pline("You are blinded by a blast of light!"); Blind = d(4, 12); seeoff(0); } return (1); case 'Y': hitu(mtmp, rnd(6)); break; } if (u.uhp < 1) done_in_by(mtmp); return (0); }
void inrange(struct monst *mtmp) { schar tx, ty; /* do nothing if cancelled (but make '1' say something) */ if (mtmp->data->mlet != '1' && mtmp->mcan) return; /* spit fire only when both in a room or both in a corridor */ if (inroom(u.ux, u.uy) != inroom(mtmp->mx, mtmp->my)) return; tx = u.ux - mtmp->mx; ty = u.uy - mtmp->my; if ((!tx && abs(ty) < BOLT_LIM) || (!ty && abs(tx) < BOLT_LIM) || (abs(tx) == abs(ty) && abs(tx) < BOLT_LIM)) { switch (mtmp->data->mlet) { case 'D': /* spit fire in the direction of @ (not nec. hitting) */ buzz(-1, mtmp->mx, mtmp->my, sgn(tx), sgn(ty)); break; case '1': if (rn2(WIZSHOT)) break; /* * if you zapped wizard with wand of cancellation, he * has to shake off the effects before he can throw * spells successfully. 1/2 the time they fail anyway */ if (mtmp->mcan || rn2(2)) { if (canseemon(mtmp)) pline("%s makes a gesture, then curses.", Monnam(mtmp)); else pline("You hear mumbled cursing."); if (!rn2(3)) { mtmp->mspeed = 0; mtmp->minvis = 0; } if (!rn2(3)) mtmp->mcan = 0; } else { if (canseemon(mtmp)) { if (!rn2(6) && !Invis) { pline("%s hypnotizes you.", Monnam(mtmp)); nomul(rn2(3) + 3); break; } else pline("%s chants an incantation.", Monnam(mtmp)); } else pline("You hear a mumbled incantation."); switch (rn2(Invis ? 5 : 6)) { case 0: /* create a nasty monster from a deep level */ /* (for the moment, 'nasty' is not implemented) */ makemon(NULL, u.ux, u.uy); break; case 1: pline("\"Destroy the thief, my pets!\""); aggravate(); /* aggravate all the monsters */ /* fall into next case */ case 2: if (flags.no_of_wizards == 1 && rnd(5) == 0) /* if only 1 wizard, clone himself */ clonewiz(mtmp); break; case 3: if (mtmp->mspeed == MSLOW) mtmp->mspeed = 0; else mtmp->mspeed = MFAST; break; case 4: mtmp->minvis = 1; break; case 5: /* Only if not Invisible */ pline("You hear a clap of thunder!"); /* shoot a bolt of fire or cold, or a sleep ray */ buzz(-rnd(3), mtmp->mx, mtmp->my, sgn(tx), sgn(ty)); break; } } } if (u.uhp < 1) done_in_by(mtmp); } }
/* called with dx = dy = 0 with vertical bolts */ void buzz(int type, xchar sx, xchar sy, int dx, int dy) { int abstype = abs(type); const char *fltxt = (type == -1) ? "blaze of fire" : fl[abstype]; struct rm *lev; xchar range; struct monst *mon; if (u.uswallow) { int tmp; if (type < 0) return; tmp = zhit(u.ustuck, type); pline("The %s rips into %s%s", fltxt, monnam(u.ustuck), exclam(tmp)); return; } if (type < 0) pru(); range = rn1(7, 7); Tmp_at(-1, dirlet(dx, dy)); /* open call */ while (range-- > 0) { sx += dx; sy += dy; if ((lev = &levl[sx][sy])->typ) Tmp_at(sx, sy); else { int bounce = 0; if (cansee(sx - dx, sy - dy)) pline("The %s bounces!", fltxt); if (ZAP_POS(levl[sx][sy - dy].typ)) bounce = 1; if (ZAP_POS(levl[sx - dx][sy].typ)) { if (!bounce || rn2(2)) bounce = 2; } switch (bounce) { case 0: dx = -dx; dy = -dy; continue; case 1: dy = -dy; sx -= dx; break; case 2: dx = -dx; sy -= dy; break; } Tmp_at(-2, dirlet(dx, dy)); continue; } if (lev->typ == POOL && abstype == 1 /* fire */) { range -= 3; lev->typ = ROOM; if (cansee(sx, sy)) { mnewsym(sx, sy); pline("The water evaporates."); } else pline("You hear a hissing sound."); } if ((mon = m_at(sx, sy)) && (type != -1 || mon->data->mlet != 'D')) { wakeup(mon); if (rnd(20) < 18 + mon->data->ac) { int tmp = zhit(mon, abstype); if (mon->mhp < 1) { if (type < 0) { if (cansee(mon->mx, mon->my)) pline("%s is killed by the %s!", Monnam(mon), fltxt); mondied(mon); } else killed(mon); } else hit(fltxt, mon, exclam(tmp)); range -= 2; } else miss(fltxt, mon); } else if (sx == u.ux && sy == u.uy) { nomul(0); if (rnd(20) < 18 + u.uac) { int dam = 0; range -= 2; pline("The %s hits you!", fltxt); switch (abstype) { case 0: dam = d(2, 6); break; case 1: if (Fire_resistance) pline("You don't feel hot!"); else dam = d(6, 6); if (!rn2(3)) burn_scrolls(); break; case 2: nomul(-rnd(25)); /* sleep ray */ break; case 3: if (Cold_resistance) pline("You don't feel cold!"); else dam = d(6, 6); break; case 4: u.uhp = -1; } losehp(dam, fltxt); } else pline("The %s whizzes by you!", fltxt); stop_occupation(); } if (!ZAP_POS(lev->typ)) { int bounce = 0, rmn; if (cansee(sx, sy)) pline("The %s bounces!", fltxt); range--; if (!dx || !dy || !rn2(20)) { dx = -dx; dy = -dy; } else { if (ZAP_POS(rmn = levl[sx][sy - dy].typ) && (IS_ROOM(rmn) || ZAP_POS(levl[sx + dx][sy - dy].typ))) bounce = 1; if (ZAP_POS(rmn = levl[sx - dx][sy].typ) && (IS_ROOM(rmn) || ZAP_POS(levl[sx - dx][sy + dy].typ))) if (!bounce || rn2(2)) bounce = 2; switch (bounce) { case 0: dy = -dy; dx = -dx; break; case 1: dy = -dy; break; case 2: dx = -dx; break; } Tmp_at(-2, dirlet(dx, dy)); } } } Tmp_at(-1, -1); }
/* u.dx and u.dy must be set */ int attack(struct monst *mtmp) { schar tmp; boolean malive = TRUE; const struct permonst *mdat; mdat = mtmp->data; u_wipe_engr(3); /* andrew@orca: prevent unlimited pick-axe * attacks */ if (mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep && !mtmp->mconf && mtmp->mcansee && !rn2(7) && (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */ mtmp->mx != u.ux + u.dx || mtmp->my != u.uy + u.dy)) return (FALSE); if (mtmp->mimic) { if (!u.ustuck && !mtmp->mflee) u.ustuck = mtmp; switch (levl[u.ux + u.dx][u.uy + u.dy].scrsym) { case '+': pline("The door actually was a Mimic."); break; case '$': pline("The chest was a Mimic!"); break; default: pline("Wait! That's a Mimic!"); } wakeup(mtmp); /* clears mtmp->mimic */ return (TRUE); } wakeup(mtmp); if (mtmp->mhide && mtmp->mundetected) { struct obj *obj; mtmp->mundetected = 0; if ((obj = o_at(mtmp->mx, mtmp->my)) && !Blind) pline("Wait! There's a %s hiding under %s!", mdat->mname, doname(obj)); return (TRUE); } tmp = u.uluck + u.ulevel + mdat->ac + abon(); if (uwep) { if (uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE) tmp += uwep->spe; if (uwep->otyp == TWO_HANDED_SWORD) tmp -= 1; else if (uwep->otyp == DAGGER) tmp += 2; else if (uwep->otyp == CRYSKNIFE) tmp += 3; else if (uwep->otyp == SPEAR && strchr("XDne", mdat->mlet)) tmp += 2; } if (mtmp->msleep) { mtmp->msleep = 0; tmp += 2; } if (mtmp->mfroz) { tmp += 4; if (!rn2(10)) mtmp->mfroz = 0; } if (mtmp->mflee) tmp += 2; if (u.utrap) tmp -= 3; /* with a lot of luggage, your agility diminishes */ tmp -= (inv_weight() + 40) / 20; if (tmp <= rnd(20) && !u.uswallow) { if (Blind) pline("You miss it."); else pline("You miss %s.", monnam(mtmp)); } else { /* we hit the monster; be careful: it might die! */ if ((malive = hmon(mtmp, uwep, 0)) == TRUE) { /* monster still alive */ if (!rn2(25) && mtmp->mhp < mtmp->mhpmax / 2) { mtmp->mflee = 1; if (!rn2(3)) mtmp->mfleetim = rnd(100); if (u.ustuck == mtmp && !u.uswallow) u.ustuck = 0; } #ifndef NOWORM if (mtmp->wormno) cutworm(mtmp, u.ux + u.dx, u.uy + u.dy, uwep ? uwep->otyp : 0); #endif /* NOWORM */ } if (mdat->mlet == 'a') { if (rn2(2)) { pline("You are splashed by the blob's acid!"); losehp_m(rnd(6), mtmp); if (!rn2(30)) corrode_armor(); } if (!rn2(6)) corrode_weapon(); } } if (malive && mdat->mlet == 'E' && canseemon(mtmp) && !mtmp->mcan && rn2(3)) { if (mtmp->mcansee) { pline("You are frozen by the floating eye's gaze!"); nomul((u.ulevel > 6 || rn2(4)) ? rn1(20, -21) : -200); } else { pline("The blinded floating eye cannot defend itself."); if (!rn2(500)) if ((int) u.uluck > LUCKMIN) u.uluck--; } } return (TRUE); }
void do_trap(trap_t *trap) // was dotrap { Short ttype = get_trap_type(trap->trap_info); nomul(0); if (get_trap_seen(trap->trap_info) && !rund(5) && ttype != PIT) { StrPrintF(ScratchBuffer, "You escape a%s.", traps[ttype]); message(ScratchBuffer); } else { trap->trap_info |= SEEN_TRAP; switch(ttype) { case SLP_GAS_TRAP: message("A cloud of gas puts you to sleep!"); nomul(-rnd(25)); break; case BEAR_TRAP: if (Levitation) { message("You float over a bear trap."); break; } you.utrap = 4 + rund(4); you.utraptype = TT_BEARTRAP; message("A bear trap closes on your foot!"); break; case PIERC: deltrap(trap); if (makemon(PM_PIERCER, you.ux, you.uy)) { message("A piercer suddenly drops from the ceiling!"); if (uarmh) message("Its blow glances off your helmet."); else thing_hit_you(3, dice(4,6), "falling piercer"); } break; case ARROW_TRAP: message("An arrow shoots out at you!"); if (!thing_hit_you(8, rnd(6), "arrow")){ mksobj_at(ARROW, you.ux, you.uy); fobj->quantity = 1; } break; case TRAPDOOR: if (!xdnstair) { message("A trap door in the ceiling opens and a rock falls on your head!"); if (uarmh) message("Fortunately, you are wearing a helmet!"); losehp((uarmh ? 2 : dice(2,10)), "falling rock"); mksobj_at(ROCK, you.ux, you.uy); fobj->quantity = 1; stackobj(fobj); if (Invisible) newsym(you.ux, you.uy); } else { Short newlevel = dlevel + 1; while (!rund(4) && newlevel < 29) newlevel++; message("A trap door opens up under you!"); if (Levitation || you.ustuck) { message("For some reason you don't fall in."); break; } goto_level(newlevel, false); } break; case DART_TRAP: message("A little dart shoots out at you!"); if (thing_hit_you(7, rnd(3), "little dart")) { if (!rund(6)) poisoned("dart", "poison dart"); } else { mksobj_at(DART, you.ux, you.uy); fobj->quantity = 1; } break; case TELEP_TRAP: map_mode_teleport = TELE_TRAP; if (get_trap_once(trap->trap_info)) { deltrap(trap); newsym(you.ux,you.uy); vtele(); } else { newsym(you.ux,you.uy); tele(); } break; case PIT: if (Levitation) { message("A pit opens up under you!"); message("You don't fall in!"); break; } message("You fall into a pit!"); you.utrap = rund(6) + 2; you.utraptype = TT_PIT; losehp(rnd(6),"fall into a pit"); selftouch("Falling, you"); break; default: StrPrintF(ScratchBuffer, "BUG: You hit a trap with info=%u", trap->trap_info); message(ScratchBuffer); } } }
int dogaze(void) { struct monst *mtmp; int looked = 0; char qbuf[QBUFSZ]; int i; unsigned char adtyp = 0; for (i = 0; i < NATTK; i++) { if(youmonst.data->mattk[i].aatyp == AT_GAZE) { adtyp = youmonst.data->mattk[i].adtyp; break; } } if (adtyp != AD_CONF && adtyp != AD_FIRE) { impossible("gaze attack %d?", adtyp); return 0; } if (Blind()) { You_cant("see anything to gaze at."); return 0; } if (u.uen < 15) { You("lack the energy to use your special gaze!"); return(0); } u.uen -= 15; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) { looked++; if (Invis && !perceives(mtmp->data)) { message_monster(MSG_M_SEEMS_NOT_NOTICE_GAZE, mtmp); } else if (mtmp->minvis && !See_invisible()) { message_monster(MSG_YOU_CANT_SEE_WHERE_GAZE_M, mtmp); } else if (mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) { looked--; continue; } else if (flags.safe_dog && !Confusion() && !Hallucination() && mtmp->mtame) { message_monster(MSG_YOU_AVOID_GAZING_AT_M, mtmp); } else { if (flags.confirm && mtmp->mpeaceful && !Confusion() && !Hallucination()) { sprintf(qbuf, "Really %s %s?", (adtyp == AD_CONF) ? "confuse" : "attack", "TODO: mon_nam(mtmp)"); if (yn(qbuf) != 'y') continue; setmangry(mtmp); } if (!mtmp->mcanmove || mtmp->mstun || mtmp->msleeping || !mtmp->mcansee || !haseyes(mtmp->data)) { looked--; continue; } /* No reflection check for consistency with when a monster * gazes at *you*--only medusa gaze gets reflected then. */ if (adtyp == AD_CONF) { if (!mtmp->mconf) { message_monster(MSG_GAZE_CONFUSES_M, mtmp); } else { message_monster(MSG_M_GETTING_MORE_CONFUSED, mtmp); } mtmp->mconf = 1; } else if (adtyp == AD_FIRE) { int dmg = d(2,6); message_monster(MSG_ATTACK_M_WITH_FIERY_GAZE, mtmp); if (resists_fire(mtmp)) { message_monster(MSG_FIRE_DOES_NOT_BURN_M, mtmp); dmg = 0; } if((int) u.ulevel > rn2(20)) (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); if((int) u.ulevel > rn2(20)) (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); if((int) u.ulevel > rn2(25)) (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); if (dmg && !DEADMONSTER(mtmp)) mtmp->mhp -= dmg; if (mtmp->mhp <= 0) killed(mtmp); } /* For consistency with passive() in uhitm.c, this only * affects you if the monster is still alive. */ if (!DEADMONSTER(mtmp) && (mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) { if (!Free_action) { message_monster(MSG_YOU_ARE_FROZEN_BY_M_GAZE, mtmp); nomul((u.ulevel > 6 || rn2(4)) ? -d((int)mtmp->m_lev+1, (int)mtmp->data->mattk[0].damd) : -200); return 1; } else { message_monster(MSG_STIFFEN_MOMENTARILY_UNDER_M_GAZE, mtmp); } } /* Technically this one shouldn't affect you at all because * the Medusa gaze is an active monster attack that only * works on the monster's turn, but for it to *not* have an * effect would be too weird. */ if (!DEADMONSTER(mtmp) && (mtmp->data == &mons[PM_MEDUSA]) && !mtmp->mcan) { message_monster(MSG_GAZING_AT_AWAKE_MEDUSA_BAD_IDEA, mtmp); /* as if gazing at a sleeping anything is fruitful... */ You("turn to stone..."); killer = killed_by_const(KM_DELIBERATELY_MEETING_MEDUSA_GAZE); done(KM_STONING); } } } } if (!looked) You("gaze at no place in particular."); return 1; }
// Note: this is a litte different, it will return true // iff the action is COMPLETE, and false if there was no action OR // the action is needing to finish up (after leaving SenseForm). // So if (do_drink) the caller should exit invform _and_ tick, // otherwise the caller should just exit invform. // (exiting the invform occurs _before_ calling do_drink..) // .. Ok, I've modified this again so that it lets the caller distinguish // between "it worked" and "it worked and I popped up EngraveForm". tri_val_t do_drink(obj_t *otmp) { obj_t *objs; // monst_t *mtmp; Boolean unkn = false, nothing = false, b; Short tmp; if (!otmp) return NO_OP; tmp = oc_descr_offset[otmp->otype]; if (tmp >= 0 && (0 == StrNCompare("smoky", oc_descrs+tmp, 5)) && !rund(13)) { ghost_from_bottle(); useup(otmp); return DONE; } switch(otmp->otype) { case POT_RESTORE_STRENGTH: unkn = true; message("Wow! This makes you feel great!"); if (you.ustr < you.ustrmax) { you.ustr = you.ustrmax; flags.botl |= BOTL_STR; } break; case POT_BOOZE: unkn = true; message("Ooph! This tastes like liquid fire!"); Confusion += dice(3,8); /* the whiskey makes us feel better */ if (you.uhp < you.uhpmax) losehp(-1, "bottle of whiskey"); if (!rund(4)) { tri_val_t t; // Short coma; message("You pass out."); multi = -rnd(15); spin_multi("You awake with a headache."); // coma = rnd(15); // // do { tick(); } while (--coma > 0); // message("You awake with a headache."); // // nomovemsg = "You awake with a headache."; t = finish_do_drink(otmp, nothing, unkn); //.... I guess.... return (t==DONE ? NO_OP : t); // so that we don't take any _more_ turns } break; case POT_INVISIBILITY: if (Invis || See_invisible) nothing = true; else { if (!Blind) message("Gee! All of a sudden, you can't see yourself."); else { message("You feel rather airy."); unkn = true; } newsym(you.ux,you.uy); } Invis += rund(15)+31; break; case POT_FRUIT_JUICE: message("This tastes like fruit juice."); lesshungry(20); break; case POT_HEALING: message("You begin to feel better."); you.uhp += rnd(10); if (you.uhp > you.uhpmax) you.uhp = ++you.uhpmax; if (Blind) Blind = 1; /* you'll see again on the next move */ if (Sick) Sick = 0; flags.botl |= BOTL_HP; break; case POT_PARALYSIS: if (Levitation) message("You are motionlessly suspended."); else message("Your feet are frozen to the floor!"); nomul(-(rund(10)+25)); break; case POT_MONSTER_DETECTION: if (!fmon) { b = strange_feeling(otmp, "You feel threatened."); return ((b) ? GO_ON : DONE); } else { sense_what = SENSE_MONSTERS; sense_by_what = otmp; sense_init_screen(); FrmPopupForm(SenseForm); return GO_ON; // to postpone the tick! } break; case POT_OBJECT_DETECTION: if (!fobj) { b = strange_feeling(otmp, "You feel a pull downward."); return ((b) ? GO_ON : DONE); } else { for (objs = fobj; objs; objs = objs->nobj) if (objs->ox != you.ux || objs->oy != you.uy) { sense_what = SENSE_OBJECTS; sense_by_what = otmp; sense_init_screen(); FrmPopupForm(SenseForm); return GO_ON; // to postpone the tick! } message("You sense the presence of objects close nearby."); break; } break; case POT_SICKNESS: message("Yech! This stuff tastes like poison."); if (Poison_resistance) message("(But in fact it was biologically contaminated orange juice.)"); losestr(rund(4)+3); losehp(rnd(10), "contaminated potion"); flags.botl |= BOTL_STR; break; case POT_CONFUSION: if (!Confusion) message("Huh, What? Where am I?"); else nothing = true; Confusion += rund(7)+16; break; case POT_GAIN_STRENGTH: message("Wow do you feel strong!"); if (you.ustr >= 118) break; /* > 118 is impossible */ if (you.ustr > 17) you.ustr += rnd(118-you.ustr); else you.ustr++; if (you.ustr > you.ustrmax) you.ustrmax = you.ustr; flags.botl |= BOTL_STR; break; case POT_SPEED: if (Wounded_legs) { heal_legs(); unkn = true; break; } if (!(Fast & ~INTRINSIC)) message("You are suddenly moving much faster."); else { message("Your legs get new energy."); unkn = true; } Fast += rund(10)+100; break; case POT_BLINDNESS: if (!Blind) message("A cloud of darkness falls upon you."); else nothing = true; Blind += rund(100)+250; seeoff(false); break; case POT_GAIN_LEVEL: pluslvl(); break; case POT_EXTRA_HEALING: message("You feel much better."); you.uhp += dice(2,20)+1; if (you.uhp > you.uhpmax) you.uhp = (you.uhpmax += 2); if (Blind) Blind = 1; if (Sick) Sick = 0; flags.botl |= BOTL_HP; break; case POT_LEVITATION: if (!Levitation) float_up(); else nothing = true; Levitation += rnd(100); // you.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down; // UNNEEDED, // it has been replaced by tweaking timeout.c to call float_down directly! break; default: StrPrintF(ScratchBuffer, "What a funny potion! (%u)", otmp->otype); message(ScratchBuffer); return NO_OP; } return finish_do_drink(otmp, nothing, unkn); }
/* Returns 1 when something was stolen (or at least, when N should flee now) * Returns -1 if the monster died in the attempt * Avoid stealing the object stealoid */ int steal(struct monst *mtmp, char *objnambuf) { struct obj *otmp; int tmp, could_petrify, named = 0, armordelay; boolean monkey_business; /* true iff an animal is doing the thievery */ if (objnambuf) *objnambuf = '\0'; /* the following is true if successful on first of two attacks. */ if (!monnear(mtmp, u.ux, u.uy)) return 0; /* food being eaten might already be used up but will not have been removed from inventory yet; we don't want to steal that, so this will cause it to be removed now */ if (occupation) maybe_finished_meal(FALSE); if (!invent || (inv_cnt() == 1 && uskin)) { nothing_to_steal: /* Not even a thousand men in armor can strip a naked man. */ if (Blind) pline("Somebody tries to rob you, but finds nothing to steal."); else pline("%s tries to rob you, but there is nothing to steal!", Monnam(mtmp)); return 1; /* let her flee */ } monkey_business = is_animal(mtmp->data); if (monkey_business) { ; /* skip ring special cases */ } else if (Adornment & LEFT_RING) { otmp = uleft; goto gotobj; } else if (Adornment & RIGHT_RING) { otmp = uright; goto gotobj; } tmp = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin #ifdef INVISIBLE_OBJECTS && (!otmp->oinvis || perceives(mtmp->data)) #endif ) tmp += ((otmp-> owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1); if (!tmp) goto nothing_to_steal; tmp = rn2(tmp); for (otmp = invent; otmp; otmp = otmp->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin #ifdef INVISIBLE_OBJECTS && (!otmp->oinvis || perceives(mtmp->data)) #endif ) if ((tmp -= ((otmp-> owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1)) < 0) break; if (!otmp) { impossible("Steal fails!"); return 0; } /* can't steal gloves while wielding - so steal the wielded item. */ if (otmp == uarmg && uwep) otmp = uwep; /* can't steal armor while wearing cloak - so steal the cloak. */ else if (otmp == uarm && uarmc) otmp = uarmc; else if (otmp == uarmu && uarmc) otmp = uarmc; else if (otmp == uarmu && uarm) otmp = uarm; gotobj: if (otmp->o_id == stealoid) return 0; /* animals can't overcome curse stickiness nor unlock chains */ if (monkey_business) { boolean ostuck; /* is the player prevented from voluntarily giving up this item? (ignores loadstones; the !can_carry() check will catch those) */ if (otmp == uball) ostuck = TRUE; /* effectively worn; curse is implicit */ else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) ostuck = FALSE; /* not really worn; curse doesn't matter */ else ostuck = (otmp->cursed && otmp->owornmask); if (ostuck || !can_carry(mtmp, otmp)) { static const char *const how[] = { "steal", "snatch", "grab", "take" }; cant_take: pline("%s tries to %s your %s but gives up.", Monnam(mtmp), how[rn2(SIZE(how))], (otmp->owornmask & W_ARMOR) ? equipname(otmp) : cxname(otmp)); /* the fewer items you have, the less likely the thief is going to stick around to try again (0) instead of running away (1) */ return !rn2(inv_cnt() / 5 + 2); } } if (otmp->otyp == LEASH && otmp->leashmon) { if (monkey_business && otmp->cursed) goto cant_take; o_unleash(otmp); } /* you're going to notice the theft... */ stop_occupation(); if ((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) { switch (otmp->oclass) { case TOOL_CLASS: case AMULET_CLASS: case RING_CLASS: case FOOD_CLASS: /* meat ring */ remove_worn_item(otmp, TRUE); break; case ARMOR_CLASS: armordelay = objects[otmp->otyp].oc_delay; /* Stop putting on armor which has been stolen. */ if (donning(otmp)) { remove_worn_item(otmp, TRUE); break; } else if (monkey_business) { /* animals usually don't have enough patience to take off items which require extra time */ if (armordelay >= 1 && rn2(10)) goto cant_take; remove_worn_item(otmp, TRUE); break; } else { int curssv = otmp->cursed; int slowly; boolean seen = canspotmon(mtmp); otmp->cursed = 0; /* can't charm you without first waking you */ if (multi < 0 && is_fainted()) unmul(NULL); slowly = (armordelay >= 1 || multi < 0); if (multi < 0) { pline ("%s tries to %s you, but is dismayed by your lack of response.", !seen ? "She" : Monnam(mtmp), flags.female ? "charm" : "seduce"); return (0); } if (flags.female) pline("%s charms you. You gladly %s your %s.", !seen ? "She" : Monnam(mtmp), curssv ? "let her take" : slowly ? "start removing" : "hand over", equipname(otmp)); else pline("%s seduces you and %s off your %s.", !seen ? "She" : Adjmonnam(mtmp, "beautiful"), curssv ? "helps you to take" : slowly ? "you start taking" : "you take", equipname(otmp)); named++; /* the following is to set multi for later on */ nomul(-armordelay, "taking off clothes"); nomovemsg = "You finish disrobing."; remove_worn_item(otmp, TRUE); otmp->cursed = curssv; if (multi < 0) { /* multi = 0; nomovemsg = 0; afternmv = 0; */ stealoid = otmp->o_id; stealmid = mtmp->m_id; afternmv = stealarm; return 0; } } break; default: impossible("Tried to steal a strange worn thing. [%d]", otmp->oclass); } } else if (otmp->owornmask) remove_worn_item(otmp, TRUE); /* do this before removing it from inventory */ if (objnambuf) strcpy(objnambuf, yname(otmp)); /* set mavenge bit so knights won't suffer an alignment penalty during retaliation; */ mtmp->mavenge = 1; freeinv(otmp); pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp)); could_petrify = (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])); mpickobj(mtmp, otmp); /* may free otmp */ if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) { minstapetrify(mtmp, TRUE); return -1; } return (multi < 0) ? 0 : 1; }
/* returns 1 if some text was printed */ static int eatcorpse(struct obj *otmp) { char let = CORPSE_I_TO_C(otmp->otyp); int tp = 0; if (let != 'a' && moves > otmp->age + 50 + rn2(100)) { tp++; pline("Ulch -- that meat was tainted!"); pline("You get very sick."); Sick = 10 + rn2(10); u.usick_cause = objects[otmp->otyp].oc_name; } else if (strchr(POISONOUS, let) && rn2(5)) { tp++; pline("Ecch -- that must have been poisonous!"); if (!Poison_resistance) { losestr(rnd(4)); losehp(rnd(15), "poisonous corpse"); } else pline("You don't seem affected by the poison."); } else if (strchr("ELNOPQRUuxz", let) && rn2(5)) { tp++; pline("You feel sick."); losehp(rnd(8), "cadaver"); } switch (let) { case 'L': case 'N': case 't': Teleportation |= INTRINSIC; break; case 'W': pluslvl(); break; case 'n': u.uhp = u.uhpmax; flags.botl = 1; /* fall into next case */ case '@': pline("You cannibal! You will be sorry for this!"); /* not tp++; */ /* fall into next case */ case 'd': Aggravate_monster |= INTRINSIC; break; case 'I': if (!Invis) { Invis = 50 + rn2(100); if (!See_invisible) newsym(u.ux, u.uy); } else { Invis |= INTRINSIC; See_invisible |= INTRINSIC; } /* fall into next case */ case 'y': #ifdef QUEST u.uhorizon++; #endif /* QUEST */ /* fall into next case */ case 'B': Confusion = 50; break; case 'D': Fire_resistance |= INTRINSIC; break; case 'E': Telepat |= INTRINSIC; break; case 'F': case 'Y': Cold_resistance |= INTRINSIC; break; case 'k': case 's': Poison_resistance |= INTRINSIC; break; case 'c': pline("You turn to stone."); killer = "dead cockatrice"; done("died"); /* NOTREACHED */ case 'a': if (Stoned) { pline("What a pity - you just destroyed a future piece of art!"); tp++; Stoned = 0; } break; case 'M': pline("You cannot resist the temptation to mimic a treasure chest."); tp++; nomul(-30); afternmv = Meatdone; nomovemsg = "You now again prefer mimicking a human."; u.usym = '$'; prme(); break; } return (tp); }
static void you_moved(void) { int moveamt = 0, wtcap = 0, change = 0; boolean monscanmove = FALSE; /* Begin turn-tracking for delay_msg. */ if (delay_start == 0) delay_start = moves; /* actual time passed */ youmonst.movement -= NORMAL_SPEED; do { /* hero can't move this turn loop */ wtcap = encumber_msg(); calc_attr_bonus(); flags.mon_moving = TRUE; do { monscanmove = movemon(); if (youmonst.movement > NORMAL_SPEED) break; /* it's now your turn */ } while (monscanmove); flags.mon_moving = FALSE; if (!monscanmove && youmonst.movement < NORMAL_SPEED) { /* both you and the monsters are out of steam this round */ /* set up for a new turn */ struct monst *mtmp; mcalcdistress(); /* adjust monsters' trap, blind, etc */ /* reallocate movement rations to monsters */ for (mtmp = level->monlist; mtmp; mtmp = mtmp->nmon) mtmp->movement += mcalcmove(mtmp); if (!rn2(u.uevent.udemigod ? 25 : (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70)) makemon(NULL, level, 0, 0, NO_MM_FLAGS); /* calculate how much time passed. */ if (u.usteed && u.umoved) { /* your speed doesn't augment steed's speed */ moveamt = mcalcmove(u.usteed); } else { moveamt = youmonst.data->mmove; if (Very_fast) { /* speed boots or potion */ /* average movement is 1.67 times normal */ moveamt += NORMAL_SPEED / 2; if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2; } else if (Fast) { /* average movement is 1.33 times normal */ if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2; } } switch (wtcap) { case UNENCUMBERED: break; case SLT_ENCUMBER: moveamt -= (moveamt / 4); break; case MOD_ENCUMBER: moveamt -= (moveamt / 2); break; case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break; case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break; default: break; } youmonst.movement += moveamt; if (youmonst.movement < 0) youmonst.movement = 0; settrack(); moves++; level->lastmoves = moves; /********************************/ /* once-per-turn things go here */ /********************************/ if (flags.bypasses) clear_bypasses(); if (Glib) glibr(); nh_timeout(); run_regions(level); dgn_growths(level, TRUE, TRUE); if (u.ublesscnt) u.ublesscnt--; iflags.botl = 1; /* One possible result of prayer is healing. Whether or * not you get healed depends on your current hit points. * If you are allowed to regenerate during the prayer, the * end-of-prayer calculation messes up on this. * Another possible result is rehumanization, which requires * that encumbrance and movement rate be recalculated. */ if (u.uinvulnerable) { /* for the moment at least, you're in tiptop shape */ wtcap = UNENCUMBERED; } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(level, u.ux,u.uy) && !Is_waterlevel(&u.uz)) { if (u.mh > 1) { u.mh--; iflags.botl = 1; } else if (u.mh < 1) rehumanize(); } else if (Upolyd && u.mh < u.mhmax) { if (u.mh < 1) rehumanize(); else if (Regeneration || (wtcap < MOD_ENCUMBER && !(moves%20))) { iflags.botl = 1; u.mh++; interrupt_multi("Hit points", u.mh, u.mhmax); } } else if (u.uhp < u.uhpmax && (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) { if (u.ulevel > 9 && !(moves % 3)) { int heal, Con = (int) ACURR(A_CON); if (Con <= 12) { heal = 1; } else { heal = rnd(Con); if (heal > u.ulevel-9) heal = u.ulevel-9; } iflags.botl = 1; u.uhp += heal; if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; interrupt_multi("Hit points", u.uhp, u.uhpmax); } else if (Regeneration || (u.ulevel <= 9 && !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) { iflags.botl = 1; u.uhp++; interrupt_multi("Hit points", u.uhp, u.uhpmax); } } /* moving around while encumbered is hard work */ if (wtcap > MOD_ENCUMBER && u.umoved) { if (!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) { if (Upolyd && u.mh > 1) { u.mh--; } else if (!Upolyd && u.uhp > 1) { u.uhp--; } else { pline("你用力过度昏倒了!"); exercise(A_CON, FALSE); fall_asleep(-10, FALSE); } } } if ((u.uen < u.uenmax) && ((wtcap < MOD_ENCUMBER && (!(moves%((MAXULEV + 8 - u.ulevel) * (Role_if (PM_WIZARD) ? 3 : 4) / 6)))) || Energy_regeneration)) { u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1); if (u.uen > u.uenmax) u.uen = u.uenmax; iflags.botl = 1; interrupt_multi("Magic energy", u.uen, u.uenmax); } if (!u.uinvulnerable) { if (Teleportation && !rn2(85)) { xchar old_ux = u.ux, old_uy = u.uy; tele(); if (u.ux != old_ux || u.uy != old_uy) { if (!next_to_u()) { check_leash(old_ux, old_uy); } } } /* delayed change may not be valid anymore */ if ((change == 1 && !Polymorph) || (change == 2 && u.ulycn == NON_PM)) change = 0; if (Polymorph && !rn2(100)) change = 1; else if (u.ulycn >= LOW_PM && !Upolyd && !rn2(80 - (20 * night()))) change = 2; if (change && !Unchanging) { if (multi >= 0) { if (occupation) stop_occupation(); else nomul(0, NULL); if (change == 1) polyself(FALSE); else you_were(); change = 0; } } } if (Searching && multi >= 0) dosearch0(1); dosounds(); do_storms(); gethungry(); age_spells(); exerchk(); invault(); if (u.uhave.amulet) amulet(); if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3)); if (u.uevent.udemigod && !u.uinvulnerable) { if (u.udg_cnt) u.udg_cnt--; if (!u.udg_cnt) { intervene(); u.udg_cnt = rn1(200, 50); } } restore_attrib(); /* underwater and waterlevel vision are done here */ if (Is_waterlevel(&u.uz)) movebubbles(); else if (Underwater) under_water(0); /* vision while buried done here */ else if (u.uburied) under_ground(0); /* when immobile, count is in turns */ if (multi < 0) { if (++multi == 0) { /* finished yet? */ unmul(NULL); /* if unmul caused a level change, take it now */ if (u.utotype) deferred_goto(); } } } } while (youmonst.movement<NORMAL_SPEED); /* hero can't move loop */ /******************************************/ /* once-per-hero-took-time things go here */ /******************************************/ if (u.utrap && u.utraptype == TT_LAVA) handle_lava_trap(TRUE); if (iflags.hp_notify && prev_hp_notify != uhp()) { pline("%s", hp_notify_format_str(iflags.hp_notify_fmt ? iflags.hp_notify_fmt : "[HP%c%a=%h]")); prev_hp_notify = uhp(); } }