/* * Close the drawbridge located at x,y. * Returns TRUE if the drawbridge was closed, FALSE otherwise. */ boolean close_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct monst *m; struct trap *t; int x2, y2; loc1 = &level->locations[x][y]; if (loc1->typ != DRAWBRIDGE_DOWN) return FALSE; /* A huge monster will block the drawbridge. */ if ((m = m_at(level, x, y)) && hugemonst(m->data)) { pline("%s blocks the drawbridge with %s weight!", canseemon(level, m) ? Amonnam(m) : "Something", canseemon(level, m) ? mhis(level, m) : "its"); return FALSE; } if (rn2(5) == 0) { pline("The mechanism seems to have something stuck in it and won't close."); return FALSE; } x2 = x; y2 = y; get_wall_for_db(&x2,&y2); if (cansee(x,y) || cansee(x2,y2)) pline("You see a drawbridge %s up!", (((u.ux == x || u.uy == y) && !Underwater) || distu(x2,y2) < distu(x,y)) ? "coming" : "going"); loc1->typ = DRAWBRIDGE_UP; loc2 = &level->locations[x2][y2]; loc2->typ = DBWALL; switch (loc1->drawbridgemask & DB_DIR) { case DB_NORTH: case DB_SOUTH: loc2->horizontal = TRUE; break; case DB_WEST: case DB_EAST: loc2->horizontal = FALSE; break; } loc2->wall_info = W_NONDIGGABLE; set_entity(x, y, &(occupants[0])); set_entity(x2, y2, &(occupants[1])); do_entity(&(occupants[0])); /* Do set_entity after first */ set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tail */ do_entity(&(occupants[1])); if (OBJ_AT(x, y) && flags.soundok) You_hear("smashing and crushing."); revive_nasty(x,y,NULL); revive_nasty(x2,y2,NULL); delallobj(x, y); delallobj(x2, y2); if ((t = t_at(level, x, y)) != 0) deltrap(level, t); if ((t = t_at(level, x2, y2)) != 0) deltrap(level, t); newsym(x, y); newsym(x2, y2); block_point(x2,y2); /* vision */ return TRUE; }
/* returns 1 if it won't attack. */ int demon_talk(struct monst *mtmp) { long cash, demand, offer; if (uwep && uwep->oartifact == ART_EXCALIBUR) { pline("%s looks very angry.", Amonnam(mtmp)); msethostility(mtmp, TRUE, TRUE); return 0; } /* Slight advantage given. */ if (is_dprince(mtmp->data) && mtmp->minvis) { mtmp->minvis = mtmp->perminvis = 0; if (!Blind) pline("%s appears before you.", Amonnam(mtmp)); newsym(mtmp->mx, mtmp->my); } if (youmonst.data->mlet == S_DEMON) { /* Won't blackmail their own. */ pline("%s says, \"Good hunting, %s.\"", Amonnam(mtmp), u.ufemale ? "Sister" : "Brother"); if (!tele_restrict(mtmp)) rloc(mtmp, TRUE); return 1; } cash = money_cnt(invent); /* don't bother with a custom RNG here, too much unpredictability is involved */ demand = (cash * (rnd(80) + 20 * Athome)) / (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp)))); if (!demand) { /* you have no gold */ msethostility(mtmp, TRUE, TRUE); return 0; } else { /* make sure that the demand is unmeetable if the monster has the Amulet, preventing monster from being satisified and removed from the game (along with said Amulet...) */ if (mon_has_amulet(mtmp)) demand = cash + (long)rn1(1000, 40); pline("%s demands %ld %s for safe passage.", Amonnam(mtmp), demand, currency(demand)); if ((offer = bribe(mtmp)) >= demand) { pline("%s vanishes, laughing about cowardly %s.", Amonnam(mtmp), makeplural(mortal_or_creature(youmonst.data, FALSE))); } else if (offer > 0L && (long)rnd(40) > (demand - offer)) { pline("%s scowls at you menacingly, then vanishes.", Amonnam(mtmp)); } else { pline("%s gets angry...", Amonnam(mtmp)); msethostility(mtmp, TRUE, TRUE); return 0; } } mongone(mtmp); return 1; }
void summon_minion(aligntyp alignment, boolean talk) { struct monst *mon; int mnum; switch ((int)alignment) { case A_LAWFUL: mnum = lminion(); break; case A_NEUTRAL: mnum = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: mnum = ndemon(&u.uz, alignment); break; default: impossible("unaligned player?"); mnum = ndemon(&u.uz, A_NONE); break; } if (mnum == NON_PM) { mon = 0; } else if (mons[mnum].pxtyp == MX_NONE) { const struct permonst *pm = &mons[mnum]; mon = makemon(pm, level, u.ux, u.uy, MM_EMIN); if (mon) { mon->isminion = TRUE; EMIN(mon)->min_align = alignment; } } else if (roamer_type(&mons[mnum])) { mon = makemon(&mons[mnum], level, u.ux, u.uy, NO_MM_FLAGS); if (mon) { mon->isminion = TRUE; EPRI(mon)->shralign = alignment; } } else mon = makemon(&mons[mnum], level, u.ux, u.uy, NO_MM_FLAGS); if (mon) { if (talk) { pline("The voice of %s booms:", align_gname(alignment)); verbalize("Thou shalt pay for thy indiscretion!"); if (!Blind) pline("%s appears before you.", Amonnam(mon)); } mon->mpeaceful = FALSE; /* don't call set_malign(); player was naughty */ } }
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(level, 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 = maybe_polyd(u.umonnum == PM_VAMPIRE || u.umonnum == PM_VAMPIRE_LORD, Race_if(PM_VAMPIRE)); 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_mname(&mons[u.umonnum])) : 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(level, 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: if (mtmp->mtame && (mtmp->data == &mons[PM_MONKEY] || mtmp->data == &mons[PM_APE] || mtmp->data == &mons[PM_CARNIVOROUS_APE])) { if (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5) { pline_msg = "shrieks."; wake_nearto(mtmp->mx, mtmp->my, 8*8); } else if (EDOG(mtmp)->hungrytime > moves + 1000) { pline_msg = "chatters."; } else { pline_msg = "hoots."; } } else { 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"); 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(level, 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 (monsndx(ptr) == PM_PRISON_GUARD) { long gdemand = 500 * u.ulevel; long goffer = 0; if (!mtmp->mpeaceful && !mtmp->mtame) { pline("%s demands %ld %s to avoid re-arrest.", Amonnam(mtmp), gdemand, currency(gdemand)); if ((goffer = bribe(mtmp)) >= gdemand) { verbl_msg = "Good. Now beat it, scum!"; mtmp->mpeaceful = 1; set_malign(mtmp); } else { verbalize("I said %ld!", gdemand); mtmp->mspec_used = 1000; } } else { verbl_msg = "Out of my way, scum!"; /* still a jerk */ } break; } else 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 = (ptr == &mons[PM_DEATH]) ? "WHO DO YOU THINK YOU ARE, WAR?" : "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; }
// returns 1 when something was stolen // (or at least, when N should flee now) // avoid stealing the object stealoid int steal(struct monst *mtmp) { struct obj *otmp; int tmp; int named = 0; if (!invent) { if (Blind) pline("Somebody tries to rob you, but finds nothing to steal."); else pline("%s tries to rob you, but she finds nothing to steal!", Monnam(mtmp)); return 1; // let her flee } tmp = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp != uarm2) tmp += ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1); tmp = rn2(tmp); for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp != uarm2) if ((tmp -= ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1)) < 0) break; if (!otmp) { impossible("Steal fails!"); return 0; } if (otmp->o_id == stealoid) return 0; if ((otmp->owornmask & (W_ARMOR | W_RING))) { switch (otmp->olet) { case RING_SYM: ringoff(otmp); break; case ARMOR_SYM: if (multi < 0 || otmp == uarms) { setworn((struct obj *) 0, otmp->owornmask & W_ARMOR); break; } { int curssv = otmp->cursed; otmp->cursed = 0; stop_occupation(); pline("%s seduces you and %s off your %s.", Amonnam(mtmp, Blind ? "gentle" : "beautiful"), otmp->cursed ? "helps you to take" : "you start taking", (otmp == uarmg) ? "gloves" : (otmp == uarmh) ? "helmet" : "armor"); named++; (void) armoroff(otmp); 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."); } } else if (otmp == uwep) setuwep((struct obj *) 0); if (otmp->olet == CHAIN_SYM) { impossible("How come you are carrying that chain?"); } if (Punished && otmp == uball) { Punished = 0; freeobj(uchain); free((char *) uchain); uchain = (struct obj *) 0; uball->spe = 0; uball = (struct obj *) 0; // superfluous } freeinv(otmp); pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp)); mpickobj(mtmp, otmp); return multi < 0 ? 0 : 1; }
/* Generate earthquake :-) of desired force. That is: create random chasms (pits). Currently assumes that the player created it (you'll need to change at least messages, angering, and kill credit if you generalize it). */ static void do_earthquake(int force) { int x, y; struct monst *mtmp; struct obj *otmp; struct trap *chasm, *oldtrap; int start_x, start_y, end_x, end_y; start_x = youmonst.mx - (force * 2); start_y = youmonst.my - (force * 2); end_x = youmonst.mx + (force * 2); end_y = youmonst.my + (force * 2); if (start_x < 0) start_x = 0; if (start_y < 0) start_y = 0; if (end_x >= COLNO) end_x = COLNO - 1; if (end_y >= ROWNO) end_y = ROWNO - 1; for (x = start_x; x <= end_x; x++) for (y = start_y; y <= end_y; y++) { if ((mtmp = m_at(level, x, y)) != 0) { wakeup(mtmp, FALSE); /* peaceful monster will become hostile */ if (mtmp->mundetected && is_hider(mtmp->data)) { mtmp->mundetected = 0; if (cansee(x, y)) pline(msgc_youdiscover, "%s is shaken loose from %s!", Amonnam(mtmp), mtmp->data == &mons[PM_TRAPPER] ? "its hiding place" : the(ceiling(youmonst.mx, youmonst.my))); else You_hear(msgc_levelsound, "a thumping sound."); if (x == youmonst.mx && y == youmonst.my && mtmp->data != &mons[PM_TRAPPER]) pline(msgc_moncombatgood, "You easily dodge the falling %s.", mon_nam(mtmp)); newsym(x, y); } } if (!rn2(14 - force)) switch (level->locations[x][y].typ) { case FOUNTAIN: /* Make the fountain disappear */ if (cansee(x, y)) pline(msgc_consequence, "The fountain falls into a chasm."); goto do_pit; case SINK: if (cansee(x, y)) pline(msgc_consequence, "The kitchen sink falls into a chasm."); goto do_pit; case ALTAR: if (level->locations[x][y].altarmask & AM_SANCTUM) break; if (cansee(x, y)) pline(msgc_consequence, "The altar falls into a chasm."); goto do_pit; case GRAVE: if (cansee(x, y)) pline(msgc_consequence, "The headstone topples into a chasm."); goto do_pit; case THRONE: if (cansee(x, y)) pline(msgc_consequence, "The throne falls into a chasm."); /* Falls into next case */ case ROOM: case CORR: /* Try to make a pit */ /* Pits, spiked pits, holes, trapdoors, vibrating squares, magic portals are immune. A bear trap will leave the trap in the pit. It would be kind of cool to make landmines detonate, but that's more trouble than it's worth. */ if ((oldtrap = t_at(level, x, y))) { if (oldtrap->ttyp == PIT || oldtrap->ttyp == SPIKED_PIT || oldtrap->ttyp == HOLE || oldtrap->ttyp == TRAPDOOR || oldtrap->ttyp == VIBRATING_SQUARE || oldtrap->ttyp == MAGIC_PORTAL) break; if (oldtrap->ttyp == BEAR_TRAP) { if (mtmp) mtmp->mtrapped = 0; cnv_trap_obj(level, BEARTRAP, 1, oldtrap); } } do_pit: chasm = maketrap(level, x, y, PIT, rng_main); if (!chasm) break; /* no pit if portal at that location */ chasm->tseen = 1; level->locations[x][y].doormask = 0; mtmp = m_at(level, x, y); if ((otmp = sobj_at(BOULDER, level, x, y)) != 0) { if (cansee(x, y)) pline(msgc_consequence, "KADOOM! The boulder falls into a chasm%s!", ((x == youmonst.mx) && (y == youmonst.my)) ? " below you" : ""); if (mtmp) mtmp->mtrapped = 0; obj_extract_self(otmp); flooreffects(otmp, x, y, ""); break; } /* We have to check whether monsters or player falls in a chasm... */ if (mtmp) { if (!flying(mtmp) && !levitates(mtmp) && !is_clinger(mtmp->data)) { mtmp->mtrapped = 1; if (cansee(x, y)) pline(combat_msgc(&youmonst, mtmp, cr_hit), "%s falls into a chasm!", Monnam(mtmp)); else if (humanoid(mtmp->data)) You_hear(msgc_levelsound, "a scream!"); mselftouch(mtmp, "Falling, ", &youmonst); if (!DEADMONSTER(mtmp)) if ((mtmp->mhp -= rnd(6)) <= 0) { if (!cansee(x, y)) pline(msgc_kill, "It is destroyed!"); else { pline(msgc_petfatal, "You destroy %s!", mtmp->mtame ? x_monnam(mtmp, ARTICLE_THE, "poor", mx_name(mtmp) ? SUPPRESS_SADDLE : 0, FALSE) : mon_nam(mtmp)); } xkilled(mtmp, 0); } } } else if (!u.utrap && x == youmonst.mx && y == youmonst.my) { if (Levitation || Flying || is_clinger(youmonst.data)) { pline(msgc_noconsequence, "A chasm opens up under you!"); pline(msgc_noconsequence, "You don't fall in!"); } else { pline(msgc_badidea, "You fall into a chasm!"); u.utrap = rn1(6, 2); u.utraptype = TT_PIT; turnstate.vision_full_recalc = TRUE; losehp(rnd(6), "fell into a chasm"); selftouch("Falling, you", "falling into a chasm while wielding"); } } else newsym(x, y); break; case DOOR: /* Make the door collapse */ if (level->locations[x][y].doormask == D_NODOOR) goto do_pit; if (cansee(x, y)) pline(msgc_consequence, "The door collapses."); if (*in_rooms(level, x, y, SHOPBASE)) add_damage(x, y, 0L); level->locations[x][y].doormask = D_NODOOR; unblock_point(x, y); newsym(x, y); break; } } }
/* * 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); }