/* * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good * for an object? * * This function will only look at mtmp->mdat, so makemon, mplayer, etc can * call it to generate new monster positions with fake monster structures. */ boolean goodpos(struct level *lev, int x, int y, struct monst *mtmp, unsigned gpflags) { const struct permonst *mdat = NULL; boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0); if (!isok(x, y)) return FALSE; /* in many cases, we're trying to create a new monster, which * can't go on top of the player or any existing monster. * however, occasionally we are relocating engravings or objects, * which could be co-located and thus get restricted a bit too much. * oh well. */ if (mtmp != &youmonst && x == u.ux && y == u.uy && (!u.usteed || mtmp != u.usteed)) return FALSE; if (mtmp) { struct monst *mtmp2 = m_at(lev, x,y); /* Be careful with long worms. A monster may be placed back in * its own location. Normally, if m_at() returns the same monster * that we're trying to place, the monster is being placed in its * own location. However, that is not correct for worm segments, * because all the segments of the worm return the same m_at(). * Actually we overdo the check a little bit--a worm can't be placed * in its own location, period. If we just checked for mtmp->mx * != x || mtmp->my != y, we'd miss the case where we're called * to place the worm segment and the worm's head is at x,y. */ if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno)) return FALSE; mdat = mtmp->data; if (is_pool(lev, x,y) && !ignorewater) { if (mtmp == &youmonst) return !!(HLevitation || Flying || Wwalking || Swimming || Amphibious); else return (is_flyer(mdat) || is_swimmer(mdat) || is_clinger(mdat)); } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) { return FALSE; } else if (is_lava(lev, x,y)) { if (mtmp == &youmonst) return !!HLevitation; else return is_flyer(mdat) || likes_lava(mdat); } if (passes_walls(mdat) && may_passwall(lev, x,y)) return TRUE; } if (!ACCESSIBLE(lev->locations[x][y].typ)) { if (!(is_pool(lev, x,y) && ignorewater)) return FALSE; } if (closed_door(lev, x, y) && (!mdat || !amorphous(mdat))) return FALSE; if (sobj_at(BOULDER, lev, x, y) && (!mdat || !throws_rocks(mdat))) return FALSE; return TRUE; }
const char *surface(int x, int y) { struct rm *loc = &level->locations[x][y]; if ((x == u.ux) && (y == u.uy) && u.uswallow && is_animal(u.ustuck->data)) return "maw"; else if (IS_AIR(loc->typ) && Is_airlevel(&u.uz)) return "air"; else if (is_pool(level, x, y)) return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water"; else if (is_ice(level, x, y)) return "ice"; else if (is_lava(level, x, y)) return "lava"; else if (loc->typ == DRAWBRIDGE_DOWN) return "bridge"; else if (IS_ALTAR(level->locations[x][y].typ)) return "altar"; else if (IS_GRAVE(level->locations[x][y].typ)) return "headstone"; else if (IS_FOUNTAIN(level->locations[x][y].typ)) return "fountain"; else if ((IS_ROOM(loc->typ) && !Is_earthlevel(&u.uz)) || IS_WALL(loc->typ) || IS_DOOR(loc->typ) || loc->typ == SDOOR) return "floor"; else return "ground"; }
/* * Does falling drawbridge or portcullis miss etmp? */ static boolean e_missed(struct entity *etmp, boolean chunks) { int misses; if (automiss(etmp)) return TRUE; if (flying(etmp->emon) && (is_u(etmp) ? !u_helpless(hm_all) : (etmp->emon->mcanmove && !etmp->emon->msleeping))) /* flying requires mobility */ misses = 5; /* out of 8 */ else if (levitates(etmp->emon) || (is_u(etmp) && Levitation)) /* doesn't require mobility */ misses = 3; else if (chunks && is_pool(level, etmp->ex, etmp->ey)) misses = 2; /* sitting ducks */ else misses = 0; if (is_db_wall(etmp->ex, etmp->ey)) misses -= 3; /* less airspace */ enum rng rng = is_u(etmp) ? rng_survive_dbridge : rng_main; return (boolean) ((misses > rn2_on_rng(8, rng)) ? TRUE : FALSE); }
/* * Does falling drawbridge or portcullis miss etmp? */ static boolean e_missed(struct entity *etmp, boolean chunks) { int misses; if (automiss(etmp)) return TRUE; if (is_flyer(etmp->edata) && (is_u(etmp)? !Sleeping : (etmp->emon->mcanmove && !etmp->emon->msleeping))) /* flying requires mobility */ misses = 5; /* out of 8 */ else if (is_floater(etmp->edata) || (is_u(etmp) && Levitation)) /* doesn't require mobility */ misses = 3; else if (chunks && is_pool(level, etmp->ex, etmp->ey)) misses = 2; /* sitting ducks */ else misses = 0; if (is_db_wall(etmp->ex, etmp->ey)) misses -= 3; /* less airspace */ return (boolean)((misses >= rnd(8))? TRUE : FALSE); }
static int describe_object(int x, int y, int votyp, char *buf) { int num_objs = 0; struct obj *otmp; if (votyp == -1) return -1; otmp = vobj_at(x,y); if (!otmp || otmp->otyp != votyp) { if (votyp != STRANGE_OBJECT) { otmp = mksobj(level, votyp, FALSE, FALSE); if (otmp->oclass == COIN_CLASS) otmp->quan = 1L; /* to force pluralization off */ else if (otmp->otyp == SLIME_MOLD) otmp->spe = current_fruit; /* give the fruit a type */ strcpy(buf, distant_name(otmp, xname)); dealloc_obj(otmp); otmp = vobj_at(x,y); /* make sure we don't point to the temp obj any more */ } } else strcpy(buf, distant_name(otmp, xname)); if (level->locations[x][y].typ == STONE || level->locations[x][y].typ == SCORR) strcat(buf, " embedded in stone"); else if (IS_WALL(level->locations[x][y].typ) || level->locations[x][y].typ == SDOOR) strcat(buf, " embedded in a wall"); else if (closed_door(level, x,y)) strcat(buf, " embedded in a door"); else if (is_pool(level, x,y)) strcat(buf, " in water"); else if (is_lava(level, x,y)) strcat(buf, " in molten lava"); /* [can this ever happen?] */ if (!cansee(x, y)) return -1; /* don't disclose the number of objects for location out of LOS */ if (!otmp) /* There is no object here. Since the player sees one it must be a mimic */ return 1; if (otmp->otyp != votyp) /* Hero sees something other than the actual top object. Probably a mimic */ num_objs++; for ( ; otmp; otmp = otmp->nexthere) num_objs++; return num_objs; }
/* * Simple-minded "can it be here?" routine */ static boolean e_survives_at(struct entity *etmp, int x, int y) { if (noncorporeal(etmp->edata)) return TRUE; if (is_pool(level, x, y)) return (boolean) (waterwalks(etmp->emon) || unbreathing(etmp->emon) || swims(etmp->emon) || flying(etmp->emon) || levitates(etmp->emon)); /* must force call to lava_effects in e_died if is_u */ if (is_lava(level, x, y)) return (boolean) (likes_lava(etmp->edata) || flying(etmp->emon) || levitates(etmp->emon)); if (is_db_wall(x, y)) return !!phasing(etmp->emon); return TRUE; }
/* * Simple-minded "can it be here?" routine */ static boolean e_survives_at(struct entity *etmp, int x, int y) { if (noncorporeal(etmp->edata)) return TRUE; if (is_pool(level, x, y)) return (boolean)((is_u(etmp) && (Wwalking || Amphibious || Swimming || Flying || Levitation)) || is_swimmer(etmp->edata) || is_flyer(etmp->edata) || is_floater(etmp->edata)); /* must force call to lava_effects in e_died if is_u */ if (is_lava(level, x, y)) return (boolean)((is_u(etmp) && (Levitation || Flying)) || likes_lava(etmp->edata) || is_flyer(etmp->edata)); if (is_db_wall(x, y)) return((boolean)(is_u(etmp) ? Passes_walls : passes_walls(etmp->edata))); return TRUE; }
/* pick a lock on a chest or door with a given object */ int pick_lock(struct obj *pick, const struct nh_cmd_arg *arg) { int picktyp, c; coord cc; schar dx, dy, dz; struct rm *door; struct obj *otmp; const char *qbuf; if (!getargdir(arg, NULL, &dx, &dy, &dz)) return 0; cc.x = youmonst.mx + dx; cc.y = youmonst.my + dy; if (!isok(cc.x, cc.y)) return 0; picktyp = pick->otyp; pick->lastused = moves; /* Check whether we're resuming an interrupted previous attempt. For a floor pick, we have u.utracked[tos_lock] as a non-zeroobj and dx and dy as 0. For a door, we have u.utracked_location[tl_lock] specifying the location and u.utracked[tos_lock] as &zeroobj. */ if (u.uoccupation_progress[tos_lock] && ((u.utracked_location[tl_lock].x == cc.x && u.utracked_location[tl_lock].y == cc.y && u.utracked[tos_lock] == &zeroobj) || (dx == 0 && dy == 0 && u.utracked[tos_lock] != &zeroobj))) { static const char no_longer[] = "Unfortunately, you can no longer %s %s."; if (nohands(youmonst.data)) { const char *what = (picktyp == LOCK_PICK) ? "pick" : "key"; if (picktyp == CREDIT_CARD) what = "card"; pline(msgc_interrupted, no_longer, "hold the", what); return reset_pick(); } else if (u.utracked[tos_lock] != &zeroobj && !can_reach_floor()) { pline(msgc_interrupted, no_longer, "reach the", "lock"); return reset_pick(); } else { const char *action = lock_action(); if (turnstate.continue_message) pline(msgc_occstart, "You resume your attempt at %s.", action); one_occupation_turn(picklock, "picking the lock", occ_lock); return 1; } } if (nohands(youmonst.data)) { pline(msgc_cancelled, "You can't hold %s -- you have no hands!", doname(pick)); return 0; } if ((picktyp != LOCK_PICK && picktyp != CREDIT_CARD && picktyp != SKELETON_KEY)) { impossible("picking lock with object %d?", picktyp); return 0; } if (!dx && !dy) { /* pick lock on a container */ const char *verb; boolean it; int count; if (dz < 0) { pline(msgc_cancelled, "There isn't any sort of lock up %s.", Levitation ? "here" : "there"); return 0; } else if (is_lava(level, youmonst.mx, youmonst.my)) { pline(msgc_cancelled, "Doing that would probably melt your %s.", xname(pick)); return 0; } else if (is_pool(level, youmonst.mx, youmonst.my) && !Underwater) { /* better YAFM - AIS */ pline(msgc_cancelled, "Canals might have locks, but this water doesn't."); return 0; } count = 0; c = 'n'; /* in case there are no boxes here */ for (otmp = level->objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { ++count; if (!can_reach_floor()) { pline(msgc_cancelled, "You can't reach %s from up here.", the(xname(otmp))); return 0; } it = 0; if (otmp->obroken) verb = "fix"; else if (!otmp->olocked) verb = "lock", it = 1; else if (picktyp != LOCK_PICK) verb = "unlock", it = 1; else verb = "pick"; qbuf = msgprintf( "There is %s here, %s %s?", safe_qbuf("", sizeof ("There is here, unlock its lock?"), doname(otmp), an(simple_typename(otmp->otyp)), "a box"), verb, it ? "it" : "its lock"); c = ynq(qbuf); if (c == 'q') return 0; if (c == 'n') continue; if (otmp->obroken) { pline(msgc_cancelled, "You can't fix its broken lock with %s.", doname(pick)); return 0; } else if (picktyp == CREDIT_CARD && !otmp->olocked) { /* credit cards are only good for unlocking */ pline(msgc_cancelled, "You can't do that with %s.", doname(pick)); return 0; } u.utracked[tos_lock] = otmp; u.uoccupation_progress[tos_lock] = 0; break; } if (c != 'y') { if (!count) pline(msgc_cancelled, "There doesn't seem to be any sort of lock here."); return 0; /* decided against all boxes */ } } else { /* pick the lock in a door */ struct monst *mtmp; if (u.utrap && u.utraptype == TT_PIT) { pline(msgc_cancelled, "You can't reach over the edge of the pit."); return 0; } door = &level->locations[cc.x][cc.y]; if ((mtmp = m_at(level, cc.x, cc.y)) && canseemon(mtmp)) { if (picktyp == CREDIT_CARD && (mx_eshk(mtmp) || mtmp->data == &mons[PM_ORACLE])) verbalize(msgc_npcvoice, "No checks, no credit, no problem."); else pline(msgc_mispaste, "I don't think %s would appreciate that.", mon_nam(mtmp)); return 0; } if (mtmp && (mtmp->m_ap_type == M_AP_FURNITURE) && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp, dx, dy); return 1; } if (!IS_DOOR(door->typ)) { if (is_drawbridge_wall(cc.x, cc.y) >= 0) pline(msgc_cancelled, "You %s no lock on the drawbridge.", Blind ? "feel" : "see"); else pline(msgc_mispaste, "You %s no door there.", Blind ? "feel" : "see"); return 0; } switch (door->doormask) { case D_NODOOR: pline(msgc_cancelled, "This doorway has no door."); return 0; case D_ISOPEN: pline(msgc_cancelled, "You cannot lock an open door."); return 0; case D_BROKEN: pline(msgc_cancelled, "This door is broken."); return 0; default: /* credit cards are only good for unlocking */ if (picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) { pline(msgc_cancelled, "You can't lock a door with a credit card."); return 0; } /* At this point, the player knows that the door is a door, and whether it's locked, but not whether it's trapped; to do this, we set the mem_door_l flag and call map_background, which will clear it if necessary (i.e. not a door after all). */ level->locations[cc.x][cc.y].mem_door_l = 1; map_background(cc.x, cc.y, TRUE); u.utracked[tos_lock] = &zeroobj; u.utracked_location[tl_lock] = cc; u.uoccupation_progress[tos_lock] = 0; } } one_occupation_turn(picklock, "picking the lock", occ_lock); return 1; }
/* Stop riding the current steed */ void dismount_steed(int reason) { struct monst *mtmp; struct obj *otmp; coord cc; const char *verb = "fall"; boolean repair_leg_damage = TRUE; unsigned save_utrap = u.utrap; boolean have_spot = landing_spot(&cc, reason, 0); mtmp = u.usteed; /* make a copy of steed pointer */ /* Sanity check */ if (!mtmp) /* Just return silently */ return; /* Check the reason for dismounting */ otmp = which_armor(mtmp, os_saddle); switch (reason) { case DISMOUNT_THROWN: verb = "are thrown"; case DISMOUNT_FELL: pline("You %s off of %s!", verb, mon_nam(mtmp)); if (!have_spot) have_spot = landing_spot(&cc, reason, 1); losehp(rn1(10, 10), "killed in a riding accident"); set_wounded_legs(LEFT_SIDE, (int)LWounded_legs + rn1(5, 5)); set_wounded_legs(RIGHT_SIDE, (int)RWounded_legs + rn1(5, 5)); repair_leg_damage = FALSE; break; case DISMOUNT_POLY: pline("You can no longer ride %s.", mon_nam(u.usteed)); if (!have_spot) have_spot = landing_spot(&cc, reason, 1); break; case DISMOUNT_ENGULFED: /* caller displays message */ break; case DISMOUNT_BONES: /* hero has just died... */ break; case DISMOUNT_GENERIC: /* no messages, just make it so */ break; case DISMOUNT_BYCHOICE: default: if (otmp && otmp->cursed) { pline("You can't. The saddle %s cursed.", otmp->bknown ? "is" : "seems to be"); otmp->bknown = TRUE; return; } if (!have_spot) { pline("You can't. There isn't anywhere for you to stand."); return; } if (!mtmp->mnamelth) { pline("You've been through the dungeon on %s with no name.", an(mtmp->data->mname)); if (Hallucination) pline("It felt good to get out of the rain."); } else pline("You dismount %s.", mon_nam(mtmp)); } /* While riding these refer to the steed's legs so after dismounting they refer to the player's legs once again. */ if (repair_leg_damage) LWounded_legs = RWounded_legs = 0; /* Release the steed and saddle */ u.usteed = 0; u.ugallop = 0L; /* Set player and steed's position. Try moving the player first unless we're in the midst of creating a bones file. */ if (reason == DISMOUNT_BONES) { /* move the steed to an adjacent square */ if (enexto(&cc, level, u.ux, u.uy, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); else /* evidently no room nearby; move steed elsewhere */ rloc(mtmp, FALSE); return; } if (!DEADMONSTER(mtmp)) { place_monster(mtmp, u.ux, u.uy); if (!Engulfed && !u.ustuck && have_spot) { const struct permonst *mdat = mtmp->data; /* The steed may drop into water/lava */ if (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) { if (is_pool(level, u.ux, u.uy)) { if (!Underwater) pline("%s falls into the %s!", Monnam(mtmp), surface(u.ux, u.uy)); if (!is_swimmer(mdat) && !amphibious(mdat)) { killed(mtmp); adjalign(-1); } } else if (is_lava(level, u.ux, u.uy)) { pline("%s is pulled into the lava!", Monnam(mtmp)); if (!likes_lava(mdat)) { killed(mtmp); adjalign(-1); } } } /* Steed dismounting consists of two steps: being moved to another square, and descending to the floor. We have functions to do each of these activities, but they're normally called individually and include an attempt to look at or pick up the objects on the floor: teleds() --> spoteffects() --> pickup() float_down() --> pickup() We use this kludge to make sure there is only one such attempt. Clearly this is not the best way to do it. A full fix would involve having these functions not call pickup() at all, instead calling them first and calling pickup() afterwards. But it would take a lot of work to keep this change from having any unforseen side effects (for instance, you would no longer be able to walk onto a square with a hole, and autopickup before falling into the hole). */ /* [ALI] No need to move the player if the steed died. */ if (!DEADMONSTER(mtmp)) { /* Keep steed here, move the player to cc; teleds() clears u.utrap */ in_steed_dismounting = TRUE; teleds(cc.x, cc.y, TRUE); in_steed_dismounting = FALSE; /* Put your steed in your trap */ if (save_utrap) mintrap(mtmp); } /* Couldn't... try placing the steed */ } else if (enexto(&cc, level, u.ux, u.uy, mtmp->data)) { /* Keep player here, move the steed to cc */ rloc_to(mtmp, cc.x, cc.y); /* Player stays put */ /* Otherwise, kill the steed */ } else { killed(mtmp); adjalign(-1); } } /* Return the player to the floor */ if (reason != DISMOUNT_ENGULFED) { in_steed_dismounting = TRUE; float_down(0L); in_steed_dismounting = FALSE; encumber_msg(); turnstate.vision_full_recalc = TRUE; } else /* polearms behave differently when not mounted */ if (uwep && is_pole(uwep)) u.bashmsg = FALSE; return; }
int dosit() { static const char sit_message[] = "VERB_SITZEN auf OBJECT KASUS_DATIV ARTIKEL_BESTIMMTER %s."; /* EN static const char sit_message[] = "sit on the %s."; */ register struct trap *trap; register int typ = levl[u.ux][u.uy].typ; #ifdef STEED if (u.usteed) { You("VERB_SITZEN bereits auf KASUS_DATIV %s.", mon_nam(u.usteed)); /* EN You("are already sitting on %s.", mon_nam(u.usteed)); */ return (0); } #endif if(!can_reach_floor()) { if (Levitation) You("VERB_SCHLAGEN Purzelbäume."); /* EN You("tumble in place."); */ else You("VERB_SITZEN auf Luft."); /* EN You("are sitting on air."); */ return 0; } else if (is_pool(u.ux, u.uy) && !Underwater) { /* water walking */ goto in_water; } if(OBJ_AT(u.ux, u.uy)) { register struct obj *obj; obj = level.objects[u.ux][u.uy]; You("VERB_SITZEN auf OBJECT KASUS_DATIV %s.", the(xname(obj))); /* EN You("sit on %s.", the(xname(obj))); */ if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH)) pline("Das ist nicht sehr bequem ..."); /* EN pline("It's not very comfortable..."); */ } else if ((trap = t_at(u.ux, u.uy)) != 0 || (u.utrap && (u.utraptype >= TT_LAVA))) { if (u.utrap) { exercise(A_WIS, FALSE); /* you're getting stuck longer */ if(u.utraptype == TT_BEARTRAP) { pline("Mit KASUS_DATIV PRONOMEN_POSSESSIV %s in KASUS_DATIV ARTIKEL_BESTIMMTER NOUN_BEARTRAP SUBJECT_IM_SATZ VERB_KOENNEN PRONOMEN_PERSONAL OBJECT PRONOMEN_PERSONAL nicht hinsetzen.", body_part(FOOT)); /* EN You_cant("sit down with your %s in the bear trap.", body_part(FOOT)); */ u.utrap++; } else if(u.utraptype == TT_PIT) { if(trap->ttyp == SPIKED_PIT) { You("VERB_SETZEN OBJECT PRONOMEN_PERSONAL auf einen Stachel. Aua!"); /* EN You("sit down on a spike. Ouch!"); */ losehp(1, "durch Sitzen auf einen Eisenstachel", KILLED_WITHOUT_PREPOSITION); /* EN losehp(1, "sitting on an iron spike", KILLED_BY); */ exercise(A_STR, FALSE); } else You("VERB_SETZEN OBJECT PRONOMEN_PERSONAL in die Grube."); /* EN You("sit down in the pit."); */ u.utrap += rn2(5); } else if(u.utraptype == TT_WEB) { You("VERB_SETZEN OBJECT PRONOMEN_PERSONAL ins Spinnenetz und VERB_VERHEDDERN OBJECT PRONOMEN_PERSONAL noch mehr!"); /* EN You("sit in the spider web and get entangled further!"); */ u.utrap += rn1(10, 5); } else if(u.utraptype == TT_LAVA) { /* Must have fire resistance or they'd be dead already */ You("VERB_SETZEN OBJECT PRONOMEN_PERSONAL in die Lava!"); /* EN You("sit in the lava!"); */ u.utrap += rnd(4); losehp(d(2,10), "durch Sitzen in Lava", KILLED_WITHOUT_PREPOSITION); /* EN losehp(d(2,10), "sitting in lava", KILLED_BY); */ } else if(u.utraptype == TT_INFLOOR) { You("VERB_CAN OBJECT PRONOMEN_PERSONAL nicht richtig hinsetzen!"); /* EN You_cant("maneuver to sit!"); */ u.utrap++; } } else { You("VERB_SETZEN OBJECT PRONOMEN_PERSONAL hin."); /* EN You("sit down."); */ dotrap(trap, 0); } } else if(Underwater || Is_waterlevel(&u.uz)) { if (Is_waterlevel(&u.uz)) pline("Hier gibt es keine Sitzkissen."); /* EN There("are no cushions floating nearby."); */ else You("VERB_SETZEN OBJECT PRONOMEN_PERSONAL auf den schlammigen Untergrund."); /* EN You("sit down on the muddy bottom."); */ } else if(is_pool(u.ux, u.uy)) { in_water: You("VERB_SITZEN im Wasser."); /* EN You("sit in the water."); */ if (!rn2(10) && uarm) (void) rust_dmg(uarm, "NOUN_ARMOR", 1, TRUE, &youmonst); /* EN (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); */ if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS) (void) rust_dmg(uarm, "NOUN_ARMOR", 1, TRUE, &youmonst); /* EN (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); */ #ifdef SINKS } else if(IS_SINK(typ)) { You(sit_message, defsyms[S_sink].explanation); Your("%s VERB_WERDEN nass.", humanoid(youmonst.data) ? "NOUN_HINTERTEIL" : "NOUN_UNTERSEITE"); /* EN Your("%s gets wet.", humanoid(youmonst.data) ? "rump" : "underside"); */ #endif } else if(IS_ALTAR(typ)) { You(sit_message, defsyms[S_altar].explanation); altar_wrath(u.ux, u.uy); } else if(IS_GRAVE(typ)) { You(sit_message, defsyms[S_grave].explanation); } else if(typ == STAIRS) { You(sit_message, "NOUN_STUFEs"); /* EN You(sit_message, "stairs"); */ } else if(typ == LADDER) { You(sit_message, "NOUN_LADDER"); /* EN You(sit_message, "ladder"); */ } else if (is_lava(u.ux, u.uy)) { /* must be WWalking */ You(sit_message, "NOUN_LAVA"); /* EN You(sit_message, "lava"); */ burn_away_slime(); if (likes_lava(youmonst.data)) { pline_The("NOUN_LAVA fühlt sich warm an."); /* EN pline_The("lava feels warm."); */ return 1; } pline_The("NOUN_LAVA VERB_VERBRENNEN OBJECT PRONOMEN_PERSONAL!"); /* EN pline_The("lava burns you!"); */ losehp(d((Fire_resistance ? 2 : 10), 10), "durch Sitzen auf Lava", KILLED_WITHOUT_PREPOSITION); /* EN "sitting on lava", KILLED_BY); */ } else if (is_ice(u.ux, u.uy)) { You(sit_message, defsyms[S_ice].explanation); if (!Cold_resistance) pline_The("NOUN_ICE fühlt sich kalt an."); /* EN if (!Cold_resistance) pline_The("ice feels cold."); */ } else if (typ == DRAWBRIDGE_DOWN) { You(sit_message, "NOUN_DRAWBRIDGE"); /* EN You(sit_message, "drawbridge"); */ } else if(IS_THRONE(typ)) { You(sit_message, defsyms[S_throne].explanation); if (rnd(6) > 4) { switch (rnd(13)) { case 1: (void) adjattrib(rn2(A_MAX), -rn1(4,3), FALSE); losehp(rnd(10), "ADJEKTIV_CURSED NOUN_THRON", KILLED_BY_AN); /* EN losehp(rnd(10), "cursed throne", KILLED_BY_AN); */ break; case 2: (void) adjattrib(rn2(A_MAX), 1, FALSE); break; case 3: pline("SUBJECT ARTIKEL_UNBESTIMMTER%s elektrischer NOUN_SCHLAG VERB_SCHIESSEN OBJECT durch PRONOMEN_POSSESSIV NOUN_BODY!", /* EN pline("A%s electric shock shoots through your body!", */ (Shock_resistance) ? "" : " massiver"); /* EN (Shock_resistance) ? "n" : " massive"); */ losehp(Shock_resistance ? rnd(6) : rnd(30), "ADJEKTIV_ELEKTRISCH NOUN_STUHL", KILLED_BY_AN); /* EN "electric chair", KILLED_BY_AN); */ exercise(A_CON, FALSE); break; case 4: Du_fuehlst_dich("viel, viel besser!"); /* EN You_feel("much, much better!"); */ if (Upolyd) { if (u.mh >= (u.mhmax - 5)) u.mhmax += 4; u.mh = u.mhmax; } if(u.uhp >= (u.uhpmax - 5)) u.uhpmax += 4; u.uhp = u.uhpmax; make_blinded(0L,TRUE); make_sick(0L, (char *) 0, FALSE, SICK_ALL); heal_legs(); flags.botl = 1; break; case 5: take_gold(); break; case 6: if(u.uluck + rn2(5) < 0) { You("VERB_FUEHLEN, NEUER_SATZ SUBJECT_IM_SATZ wie PRONOMEN_POSSESSIV NOUN_LUCK sich ändert."); /* EN You_feel("your luck is changing."); */ change_luck(1); } else makewish(); break; case 7: { register int cnt = rnd(10); pline("Eine Stimme ertönt:"); /* EN pline("A voice echoes:"); */ verbalize("Euer Auditorium erwartet Euch bereits, %s!", /* EN verbalize("Thy audience hath been summoned, %s!", */ flags.female ? "Gebieterin" : "Gebieter"); /* EN flags.female ? "Dame" : "Sire"); */ while(cnt--) (void) makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS); break; } case 8: pline("Eine Stimme ertönt:"); /* EN pline("A voice echoes:"); */ verbalize("Wie es Euch beliebt, %s...", /* EN verbalize("By thy Imperious order, %s...", */ flags.female ? "Gebieterin" : "Gebieter"); /* EN flags.female ? "Dame" : "Sire"); */ do_genocide(5); /* REALLY|ONTHRONE, see do_genocide() */ break; case 9: pline("Eine Stimme ertönt:"); /* EN pline("A voice echoes:"); */ verbalize("SATZBEGINN MODIFIER_VERB_IMPERATIV VERB_SEIN verflucht dafür, NEUER_SATZ dass SUBJECT_IM_SATZ PRONOMEN_PERSONAL OBJECT PRONOMEN_PERSONAL auf diesem allerheiligsten Thron niedergelassen VERB_HABEN!"); /* EN verbalize("A curse upon thee for sitting upon this most holy throne!"); */ if (Luck > 0) { make_blinded(Blinded + rn1(100,250),TRUE); } else rndcurse(); break; case 10: if (Luck < 0 || (HSee_invisible & INTRINSIC)) { if (level.flags.nommap) { pline( "Ein schreckliches Dröhnen erfüllt KASUS_AKKUSATIV PRONOMEN_POSSESSIV NOUN_KOPF!"); /* EN "A terrible drone fills your head!"); */ make_confused(HConfusion + rnd(30), FALSE); } else { pline("Ein Bild formt sich in KASUS_DATIV PRONOMEN_POSSESSIV NOUN_GEDANKEs."); /* EN pline("An image forms in your mind."); */ do_mapping(); } } else { Your("NOUN_BLICK klärt sich."); /* EN Your("vision becomes clear."); */ HSee_invisible |= FROMOUTSIDE; newsym(u.ux, u.uy); } break; case 11: if (Luck < 0) { Du_fuehlst_dich("bedroht."); /* EN You_feel("threatened."); */ aggravate(); } else { Du_spuerst("einen reißenden Schmerz."); /* EN You_feel("a wrenching sensation."); */ tele(); /* teleport him */ } break; case 12: Dir_wird("eine Einsicht gewährt!"); /* EN You("are granted an insight!"); */ if (invent) { /* rn2(5) agrees w/seffects() */ identify_pack(rn2(5)); } break; case 13: Your("NOUN_VERSTAND verknotet sich zu einer Bretzel!"); /* EN Your("mind turns into a pretzel!"); */ make_confused(HConfusion + rn1(7,16),FALSE); break; default: impossible("throne effect"); break; } } else { if (is_prince(youmonst.data)) Du_fuehlst_dich("hier sehr wohl."); /* EN You_feel("very comfortable here."); */ else Du_fuehlst_dich("irgendwie fehl am Platz ..."); /* EN You_feel("somehow out of place..."); */ } if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ levl[u.ux][u.uy].typ = ROOM; pline_The("NOUN_THRON VERB_AUFLOESEN sich in ein Logikwölkchen SATZKLAMMER."); /* EN pline_The("throne vanishes in a puff of logic."); */ newsym(u.ux,u.uy); } } else if (lays_eggs(youmonst.data)) { struct obj *uegg; if (!flags.female) { pline("Männchen können keine Eier legen!"); /* EN pline("Males can't lay eggs!"); */ return 0; } if (u.uhunger < (int)objects[EGG].oc_nutrition) { You("VERB_HAVE nicht genug Energie um ein Ei zu legen."); /* EN You("don't have enough energy to lay an egg."); */ return 0; } uegg = mksobj(EGG, FALSE, FALSE); uegg->spe = 1; uegg->quan = 1; uegg->owt = weight(uegg); uegg->corpsenm = egg_type_from_parent(u.umonnum, FALSE); uegg->known = uegg->dknown = 1; attach_egg_hatch_timeout(uegg); You("VERB_LEGEN ein Ei."); /* EN You("lay an egg."); */ dropy(uegg); stackobj(uegg); morehungry((int)objects[EGG].oc_nutrition); } else if (u.uswallow) pline("Hier gibt es keine Sitzmöglichkeiten!"); /* EN There("are no seats in here!"); */ else pline("Spaß daran, %s zu sitzen?", auf_dem_Boden(u.ux,u.uy)); /* EN pline("Having fun sitting on the %s?", surface(u.ux,u.uy)); */ return(1); }
/* make a (new) human out of the player */ static void polyman(const char *fmt, const char *arg) { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT); boolean could_pass_walls = Passes_walls; boolean was_blind = !!Blind; if (Upolyd) { u.acurr = u.macurr; /* restore old attribs */ u.amax = u.mamax; u.umonnum = u.umonster; flags.female = u.mfemale; } set_uasmon(); u.mh = u.mhmax = 0; u.mtimedone = 0; skinback(FALSE); u.uundetected = 0; if (sticky) uunstick(); find_ac(); if (was_mimicking) { if (multi < 0) unmul(""); youmonst.m_ap_type = M_AP_NOTHING; } newsym(u.ux,u.uy); pline(fmt, arg); /* check whether player foolishly genocided self while poly'd */ if ((mvitals[urole.malenum].mvflags & G_GENOD) || (urole.femalenum != NON_PM && (mvitals[urole.femalenum].mvflags & G_GENOD)) || (mvitals[urace.malenum].mvflags & G_GENOD) || (urace.femalenum != NON_PM && (mvitals[urace.femalenum].mvflags & G_GENOD))) { /* intervening activity might have clobbered genocide info */ killer = delayed_killer; if (!killer || !strstri(killer, "genocid")) { killer_format = KILLED_BY; killer = "self-genocide"; } done(GENOCIDED); } if (u.twoweap && !could_twoweap(youmonst.data)) untwoweapon(); if (u.utraptype == TT_PIT) { if (could_pass_walls) { /* player forms cannot pass walls */ u.utrap = rn1(6,2); } } if (was_blind && !Blind) { /* reverting from eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } if (!Levitation && !u.ustuck && (is_pool(level, u.ux,u.uy) || is_lava(level, u.ux,u.uy))) spoteffects(TRUE); see_monsters(); }
/* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; int x2, y2; int db_u; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); loc1 = &level->locations[x][y]; if (!IS_DRAWBRIDGE(loc1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2,&y2); loc2 = &level->locations[x2][y2]; db_u = (loc1->drawbridgemask & DB_UNDER); if (db_u == DB_MOAT || db_u == DB_LAVA || db_u == DB_BOG) { struct obj *otmp; int where = (db_u == DB_LAVA) ? 0 : (db_u == DB_MOAT) ? 1 : 2; static char *wstr[3] = { "lava", "moat", "swamp" }; if (loc1->typ == DRAWBRIDGE_UP) { if (cansee(x2,y2)) pline("The portcullis of the drawbridge falls into the %s!", wstr[where]); else if (flags.soundok) You_hear("a loud *SPLASH*!"); } else { if (cansee(x,y)) pline("The drawbridge collapses into the %s!", wstr[where]); else if (flags.soundok) You_hear("a loud *SPLASH*!"); } loc1->typ = (where == 0) ? LAVAPOOL : (where == 1) ? MOAT : BOG; loc1->drawbridgemask = 0; if ((otmp = sobj_at(BOULDER, level, x,y)) != 0) { obj_extract_self(otmp); flooreffects(otmp,x,y,"fall"); } } else { if (cansee(x,y)) pline("The drawbridge disintegrates!"); else You_hear("a loud *CRASH*!"); loc1->typ = ((loc1->drawbridgemask & DB_ICE) ? ICE : ROOM); loc1->icedpool = ((loc1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); loc2->typ = DOOR; loc2->doormask = D_NODOOR; 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); if (!does_block(level, x2, y2, NULL)) unblock_point(x2,y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { e_inview = e_canseemon(level, etmp2); if (!automiss(etmp2)) { if (e_inview) pline("%s blown apart by flying debris.", E_phrase(etmp2, "are")); killer_format = KILLED_BY_AN; killer = "exploding drawbridge"; e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/ } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { e_inview = e_canseemon(level, etmp1); if (!e_missed(etmp1, TRUE)) { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline("%s into some heavy metal!", E_phrase(etmp1, "get")); else pline("%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (flags.soundok && !is_u(etmp1) && !is_pool(level, x,y)) You_hear("a crushing sound."); } killer_format = KILLED_BY_AN; killer = "collapsing drawbridge"; e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/ if (loc1->typ == MOAT) do_entity(etmp1); } } }
/* return TRUE if the caller needs to place the ball and chain down again * * Should not be called while swallowed. Should be called before movement, * because we might want to move the ball or chain to the hero's old position. * * It is called if we are moving. It is also called if we are teleporting * *if* the ball doesn't move and we thus must drag the chain. It is not * called for ordinary teleportation. * * allow_drag is only used in the ugly special case where teleporting must * drag the chain, while an identical-looking movement must drag both the ball * and chain. */ boolean drag_ball(xchar x, xchar y, int *bc_control, xchar * ballx, xchar * bally, xchar * chainx, xchar * chainy, boolean * cause_delay, boolean allow_drag) { struct trap *t = NULL; boolean already_in_rock; *ballx = uball->ox; *bally = uball->oy; *chainx = uchain->ox; *chainy = uchain->oy; *bc_control = 0; *cause_delay = FALSE; if (dist2(x, y, uchain->ox, uchain->oy) <= 2) { /* nothing moved */ move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); return TRUE; } /* only need to move the chain? */ if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) { xchar oldchainx = uchain->ox, oldchainy = uchain->oy; *bc_control = BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); if (carried(uball)) { /* move chain only if necessary */ if (distmin(x, y, uchain->ox, uchain->oy) > 1) { *chainx = u.ux; *chainy = u.uy; } return TRUE; } #define CHAIN_IN_MIDDLE(chx, chy) \ (distmin(x, y, chx, chy) <= 1 && \ distmin(chx, chy, uball->ox, uball->oy) <= 1) #define IS_CHAIN_ROCK(x,y) \ (IS_ROCK(level->locations[x][y].typ) || \ (IS_DOOR(level->locations[x][y].typ) && \ (level->locations[x][y].doormask & (D_CLOSED|D_LOCKED)))) /* Don't ever move the chain into solid rock. If we have to, then instead * undo the move_bc() and jump to the drag ball code. Note that this also * means the "cannot carry and drag" message will not appear, since unless we * moved at least two squares there is no possibility of the chain position * being in solid rock. */ #define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \ move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \ goto drag; } if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy) || IS_CHAIN_ROCK(uball->ox, uball->oy)) already_in_rock = TRUE; else already_in_rock = FALSE; switch (dist2(x, y, uball->ox, uball->oy)) { /* two spaces diagonal from ball, move chain inbetween */ case 8: *chainx = (uball->ox + x) / 2; *chainy = (uball->oy + y) / 2; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; /* player is distance 2/1 from ball; move chain to one of the two spaces between @ __ 0 */ case 5:{ xchar tempx, tempy, tempx2, tempy2; /* find position closest to current position of chain */ /* no effect if current position is already OK */ if (abs(x - uball->ox) == 1) { tempx = x; tempx2 = uball->ox; tempy = tempy2 = (uball->oy + y) / 2; } else { tempx = tempx2 = (uball->ox + x) / 2; tempy = y; tempy2 = uball->oy; } if (IS_CHAIN_ROCK(tempx, tempy) && !IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { if (allow_drag) { /* Avoid pathological case *if* not teleporting: 0 0_ _X move northeast -----> X@ @ */ if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && dist2(x, y, tempx, tempy) == 1) SKIP_TO_DRAG; /* Avoid pathological case *if* not teleporting: 0 0 _X move east -----> X_ @ @ */ if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && dist2(x, y, tempx, tempy) == 2) SKIP_TO_DRAG; } *chainx = tempx2; *chainy = tempy2; } else if (!IS_CHAIN_ROCK(tempx, tempy) && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { if (allow_drag) { if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && dist2(x, y, tempx2, tempy2) == 1) SKIP_TO_DRAG; if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && dist2(x, y, tempx2, tempy2) == 2) SKIP_TO_DRAG; } *chainx = tempx; *chainy = tempy; } else if (IS_CHAIN_ROCK(tempx, tempy) && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { SKIP_TO_DRAG; } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) < dist2(tempx2, tempy2, uchain->ox, uchain->oy) || ((dist2(tempx, tempy, uchain->ox, uchain->oy) == dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) { *chainx = tempx; *chainy = tempy; } else { *chainx = tempx2; *chainy = tempy2; } break; } /* ball is two spaces horizontal or vertical from player; move */ /* chain inbetween *unless* current chain position is OK */ case 4: if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) break; *chainx = (x + uball->ox) / 2; *chainy = (y + uball->oy) / 2; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; /* ball is one space diagonal from player. Check for the following special case: @ _ moving southwest becomes @_ 0 0 (This will also catch teleporting that happens to resemble this case, but oh well.) Otherwise fall through. */ case 2: if (dist2(x, y, uball->ox, uball->oy) == 2 && dist2(x, y, uchain->ox, uchain->oy) == 4) { if (uchain->oy == y) *chainx = uball->ox; else *chainy = uball->oy; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; } /* fall through */ case 1: case 0: /* do nothing if possible */ if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) break; /* otherwise try to drag chain to player's old position */ if (CHAIN_IN_MIDDLE(u.ux, u.uy)) { *chainx = u.ux; *chainy = u.uy; break; } /* otherwise use player's new position (they must have teleported, for this to happen) */ *chainx = x; *chainy = y; break; default: impossible("bad chain movement"); break; } #undef SKIP_TO_DRAG #undef IS_CHAIN_ROCK #undef CHAIN_IN_MIDDLE return TRUE; } drag: if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) { pline("You cannot %sdrag the heavy iron ball.", invent ? "carry all that and also " : ""); action_completed(); return FALSE; } if ((is_pool(level, uchain->ox, uchain->oy) && /* water not mere continuation of previous water */ (level->locations[uchain->ox][uchain->oy].typ == POOL || !is_pool(level, uball->ox, uball->oy) || level->locations[uball->ox][uball->oy].typ == POOL)) || ((t = t_at(level, uchain->ox, uchain->oy)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == HOLE || t->ttyp == TRAPDOOR))) { if (Levitation) { pline("You feel a tug from the iron ball."); if (t) t->tseen = 1; } else { struct monst *victim; pline("You are jerked back by the iron ball!"); if ((victim = m_at(level, uchain->ox, uchain->oy)) != 0) { int tmp; tmp = -2 + Luck + find_mac(victim); tmp += omon_adj(victim, uball, TRUE); if (tmp >= rnd(20)) hmon(victim, uball, 1); else miss(xname(uball), victim); } /* now check again in case mon died */ if (!m_at(level, uchain->ox, uchain->oy)) { u.ux = uchain->ox; u.uy = uchain->oy; newsym(u.ux0, u.uy0); } action_interrupted(); *bc_control = BC_BALL; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); *ballx = uchain->ox; *bally = uchain->oy; move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); spoteffects(TRUE); return FALSE; } } *bc_control = BC_BALL | BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); if (dist2(x, y, u.ux, u.uy) > 2) { /* Awful case: we're still in range of the ball, so we thought we could only move the chain, but it turned out that the target square for the chain was rock, so we had to drag it instead. But we can't drag it either, because we teleported and are more than one square from our old position. Revert to the teleport behavior. */ *ballx = *chainx = x; *bally = *chainy = y; } else { *ballx = uchain->ox; *bally = uchain->oy; *chainx = u.ux; *chainy = u.uy; } *cause_delay = TRUE; return TRUE; }
/* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; struct obj *chain; int x2, y2, i; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); loc1 = &level->locations[x][y]; if (!IS_DRAWBRIDGE(loc1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); loc2 = &level->locations[x2][y2]; if ((loc1->drawbridgemask & DB_UNDER) == DB_MOAT || (loc1->drawbridgemask & DB_UNDER) == DB_LAVA) { struct obj *otmp; boolean lava = (loc1->drawbridgemask & DB_UNDER) == DB_LAVA; if (loc1->typ == DRAWBRIDGE_UP) { if (cansee(x2, y2)) pline("The portcullis of the drawbridge falls into the %s!", lava ? "lava" : waterbody_name(x2, y2)); else You_hear("a loud *SPLASH*!"); } else { if (cansee(x, y)) pline("The drawbridge collapses into the %s!", lava ? "lava" : waterbody_name(x, y)); else You_hear("a loud *SPLASH*!"); } loc1->typ = lava ? LAVAPOOL : MOAT; loc1->drawbridgemask = 0; if ((otmp = sobj_at(BOULDER, level, x, y)) != 0) { obj_extract_self(otmp); flooreffects(otmp, x, y, "fall"); } } else { if (cansee(x, y)) pline("The drawbridge disintegrates!"); else You_hear("a loud *CRASH*!"); loc1->typ = ((loc1->drawbridgemask & DB_ICE) ? ICE : ROOM); loc1->icedpool = ((loc1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); loc2->typ = DOOR; loc2->doormask = D_NODOOR; if ((t = t_at(level, x, y)) != 0) deltrap(level, t); if ((t = t_at(level, x2, y2)) != 0) deltrap(level, t); del_engr_at(level, x, y); del_engr_at(level, x2, y2); for (i = rn2(6); i > 0; --i) { /* scatter some debris */ /* doesn't matter if we happen to pick <x,y2> or <x2,y>; since drawbridges are never placed diagonally, those pairings will always match one of <x,y> or <x2,y2> */ chain = mksobj_at(IRON_CHAIN, level, rn2(2) ? x : x2, rn2(2) ? y : y2, TRUE, FALSE, rng_main); /* a force of 5 here would yield a radius of 2 for iron chain; anything less produces a radius of 1 */ (void) scatter(chain->ox, chain->oy, 1, MAY_HIT, chain); } newsym(x, y); newsym(x2, y2); if (!does_block(level, x2, y2)) unblock_point(x2, y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { e_inview = e_canseemon(etmp2); if (!automiss(etmp2)) { if (e_inview) pline("%s blown apart by flying debris.", E_phrase(etmp2, "are")); e_died(etmp2, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "an exploding drawbridge")); } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { e_inview = e_canseemon(etmp1); if (!e_missed(etmp1, TRUE)) { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline("%s into some heavy metal!", E_phrase(etmp1, "get")); else pline("%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (!is_u(etmp1) && !is_pool(level, x, y)) You_hear("a crushing sound."); } e_died(etmp1, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "a collapsing drawbridge")); /* if (loc1->typ == MOAT) do_entity(etmp1); */ } if (is_u(etmp1)) spoteffects(FALSE); else if (!DEADMONSTER(etmp1->emon)) minliquid(etmp1->emon); } }
struct monst * make_familiar(struct obj *otmp, xchar x, xchar y, boolean quietly) { const struct permonst *pm; struct monst *mtmp = 0; int chance, trycnt = 100; do { if (otmp) { /* figurine; otherwise spell */ int mndx = otmp->corpsenm; pm = &mons[mndx]; /* activating a figurine provides one way to exceed the maximum number of the target critter created--unless it has a special limit (erinys, Nazgul) */ if ((mvitals[mndx].mvflags & G_EXTINCT) && mbirth_limit(mndx) != MAXMONNO) { if (!quietly) /* have just been given "You <do something with> the figurine and it transforms." message */ pline("... into a pile of dust."); break; /* mtmp is null */ } } else if (!rn2(3)) { pm = &mons[pet_type(NULL)]; } else { pm = rndmonst(&u.uz, rng_t_create_monster); if (!pm) { if (!quietly) pline ("There seems to be nothing available for a familiar."); break; } } mtmp = makemon(pm, level, x, y, MM_EDOG | MM_IGNOREWATER | (otmp ? 0 : (MM_CREATEMONSTER | MM_CMONSTER_T))); if (otmp && !mtmp) { /* monster was genocided or square occupied */ if (!quietly) pline("The figurine writhes and then shatters into pieces!"); break; } } while (!mtmp && --trycnt > 0); if (!mtmp) return NULL; if (is_pool(level, mtmp->mx, mtmp->my) && minliquid(mtmp)) return NULL; initedog(mtmp); mtmp->msleeping = 0; if (otmp) { /* figurine; resulting monster might not become a pet */ chance = rn2_on_rng(10, rng_figurine_effect); /* 0: tame, 1: peaceful, 2: hostile, 3+: matching BCU; this gives an 80% chance of the desired effect, 10% of each other effect */ if (chance > 2) chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2; if (chance > 0) { mtmp->mtame = 0; /* not tame after all */ if (chance == 2) { /* hostile (cursed figurine) */ if (!quietly) pline("You get a bad feeling about this."); msethostility(mtmp, TRUE, TRUE); } } /* if figurine has been named, give same name to the monster */ if (otmp->onamelth) mtmp = christen_monst(mtmp, ONAME(otmp)); } set_malign(mtmp); /* more alignment changes */ newsym(mtmp->mx, mtmp->my); /* must wield weapon immediately since pets will otherwise drop it */ if (mtmp->mtame && attacktype(mtmp->data, AT_WEAP)) { mtmp->weapon_check = NEED_HTH_WEAPON; mon_wield_item(mtmp); } return mtmp; }
/* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; int x2, y2; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); loc1 = &level->locations[x][y]; if (!IS_DRAWBRIDGE(loc1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); loc2 = &level->locations[x2][y2]; if ((loc1->drawbridgemask & DB_UNDER) == DB_MOAT || (loc1->drawbridgemask & DB_UNDER) == DB_LAVA) { struct obj *otmp; boolean lava = (loc1->drawbridgemask & DB_UNDER) == DB_LAVA; if (loc1->typ == DRAWBRIDGE_UP) { if (cansee(x2, y2)) pline(msgc_consequence, "The portcullis of the drawbridge falls into the %s!", lava ? "lava" : waterbody_name(x2, y2)); else You_hear(msgc_levelsound, "a loud *SPLASH*!"); } else { if (cansee(x, y)) pline(msgc_consequence, "The drawbridge collapses into the %s!", lava ? "lava" : waterbody_name(x, y)); else You_hear(msgc_levelsound, "a loud *SPLASH*!"); } loc1->typ = lava ? LAVAPOOL : MOAT; loc1->drawbridgemask = 0; if ((otmp = sobj_at(BOULDER, level, x, y)) != 0) { obj_extract_self(otmp); flooreffects(otmp, x, y, "fall"); } } else { if (cansee(x, y)) pline(msgc_consequence, "The drawbridge disintegrates!"); else You_hear(msgc_levelsound, "a loud *CRASH*!"); loc1->typ = ((loc1->drawbridgemask & DB_ICE) ? ICE : ROOM); loc1->icedpool = ((loc1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); loc2->typ = DOOR; loc2->doormask = D_NODOOR; 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); if (!does_block(level, x2, y2)) unblock_point(x2, y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { enum msg_channel hit_msgc; if (is_u(etmp2)) hit_msgc = msgc_fatal_predone; else if (etmp2->emon->mtame && canspotmon(etmp2->emon)) hit_msgc = msgc_petfatal; else hit_msgc = msgc_monneutral; e_inview = e_canseemon(etmp2); if (!automiss(etmp2)) { if (e_inview) pline(hit_msgc, "%s blown apart by flying debris.", E_phrase(etmp2, "are")); e_died(etmp2, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "an exploding drawbridge")); } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { enum msg_channel hit_msgc; if (is_u(etmp1)) hit_msgc = msgc_fatal_predone; else if (etmp1->emon->mtame && canspotmon(etmp1->emon)) hit_msgc = msgc_petfatal; else hit_msgc = msgc_monneutral; e_inview = e_canseemon(etmp1); if (!e_missed(etmp1, TRUE)) { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline(hit_msgc, "%s into some heavy metal!", E_phrase(etmp1, "get")); else pline(hit_msgc, "%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (!is_u(etmp1) && !is_pool(level, x, y)) You_hear(msgc_levelsound, "a crushing sound."); } e_died(etmp1, e_inview ? 3 : 2, CRUSHING, killer_msg(CRUSHING, "a collapsing drawbridge")); /* if (loc1->typ == MOAT) do_entity(etmp1); */ } if (is_u(etmp1)) spoteffects(FALSE); else if (!DEADMONSTER(etmp1->emon)) minliquid(etmp1->emon); } }
/* * drop_ball() * * The punished hero drops or throws her iron ball. If the hero is * blind, we must reset the order and glyph. Check for side effects. * This routine expects the ball to be already placed. * * Should not be called while swallowed. */ void drop_ball(xchar x, xchar y, schar dx, schar dy) { if (Blind) { u.bc_order = bc_order(); /* get the order */ /* pick up mem_obj */ u.bglyph = (u.bc_order) ? u.cglyph : level->locations[x][y].mem_obj; } if (x != u.ux || y != u.uy) { struct trap *t; const char *pullmsg = "The ball pulls you out of the %s!"; if (u.utrap && u.utraptype != TT_INFLOOR) { switch (u.utraptype) { case TT_PIT: pline(pullmsg, "pit"); break; case TT_WEB: pline(pullmsg, "web"); pline("The web is destroyed!"); deltrap(level, t_at(level, u.ux, u.uy)); break; case TT_LAVA: pline(pullmsg, "lava"); break; case TT_BEARTRAP:{ long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; pline(pullmsg, "bear trap"); set_wounded_legs(side, rn1(1000, 500)); if (!u.usteed) { pline("Your %s %s is severely damaged.", (side == LEFT_SIDE) ? "left" : "right", body_part(LEG)); losehp(2, killer_msg(DIED, "leg damage from being " "pulled out of a bear trap")); } break; } } u.utrap = 0; fill_pit(level, u.ux, u.uy); } u.ux0 = u.ux; u.uy0 = u.uy; if (!Levitation && !MON_AT(level, x, y) && !u.utrap && (is_pool(level, x, y) || ((t = t_at(level, x, y)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) { u.ux = x; u.uy = y; } else { u.ux = x - dx; u.uy = y - dy; } /* hero has moved, recalculate vision later */ turnstate.vision_full_recalc = TRUE; if (Blind) { /* drop glyph under the chain */ if (u.bc_felt & BC_CHAIN) level->locations[uchain->ox][uchain->oy].mem_obj = u.cglyph; u.bc_felt = 0; /* feel nothing */ /* pick up new glyph */ u.cglyph = (u.bc_order) ? u.bglyph : level->locations[u.ux][u.uy].mem_obj; } movobj(uchain, u.ux, u.uy); /* has a newsym */ if (Blind) { u.bc_order = bc_order(); } newsym(u.ux0, u.uy0); /* clean up old position */ if (u.ux0 != u.ux || u.uy0 != u.uy) { spoteffects(TRUE); if (In_sokoban(&u.uz)) change_luck(-1); /* Sokoban guilt */ } } }
static void do_entity(struct entity *etmp) { int newx, newy, at_portcullis, oldx, oldy; boolean must_jump = FALSE, relocates = FALSE, e_inview; struct rm *crm; if (!etmp->edata) return; e_inview = e_canseemon(level, etmp); oldx = etmp->ex; oldy = etmp->ey; at_portcullis = is_db_wall(oldx, oldy); crm = &level->locations[oldx][oldy]; if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) { if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ))) pline("The %s passes through %s!", at_portcullis ? "portcullis" : "drawbridge", e_nam(etmp)); if (is_u(etmp)) spoteffects(FALSE); return; } if (e_missed(etmp, FALSE)) { if (at_portcullis) pline("The portcullis misses %s!", e_nam(etmp)); if (e_survives_at(etmp, oldx, oldy)) return; else { if (at_portcullis) must_jump = TRUE; else relocates = TRUE; /* just ride drawbridge in */ } } else { if (crm->typ == DRAWBRIDGE_DOWN) { pline("%s crushed underneath the drawbridge.", E_phrase(etmp, "are")); /* no jump */ e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */ return; /* Note: Beyond this point, we know we're */ } /* not at an opened drawbridge, since all */ must_jump = TRUE; /* *missable* creatures survive on the */ } /* square, and all the unmissed ones die. */ if (must_jump) { if (at_portcullis) { if (e_jumps(etmp)) { relocates = TRUE; } else { if (e_inview) pline("%s crushed by the falling portcullis!", E_phrase(etmp, "are")); else if (flags.soundok) You_hear("a crushing sound."); e_died(etmp, e_inview? 3 : 2, CRUSHING); /* no corpse */ return; } } else { /* tries to jump off bridge to original square */ relocates = !e_jumps(etmp); } } /* * Here's where we try to do relocation. Assumes that etmp is not arriving * at the portcullis square while the drawbridge is falling, since this square * would be inaccessible (i.e. etmp started on drawbridge square) or * unnecessary (i.e. etmp started here) in such a situation. */ newx = oldx; newy = oldy; find_drawbridge(&newx, &newy); if ((newx == oldx) && (newy == oldy)) get_wall_for_db(&newx, &newy); if (relocates && (e_at(newx, newy))) { /* * Standoff problem: one or both entities must die, and/or both switch * places. Avoid infinite recursion by checking first whether the other * entity is staying put. Clean up if we happen to move/die in recursion. */ struct entity *other; other = e_at(newx, newy); if (e_survives_at(other, newx, newy) && automiss(other)) { relocates = FALSE; /* "other" won't budge */ } else { while ((e_at(newx, newy) != 0) && (e_at(newx, newy) != etmp)) do_entity(other); if (e_at(oldx, oldy) != etmp) { return; } } } if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */ if (!is_u(etmp)) { remove_monster(level, etmp->ex, etmp->ey); place_monster(etmp->emon, newx, newy); update_monster_region(etmp->emon); } else { u.ux = newx; u.uy = newy; } etmp->ex = newx; etmp->ey = newy; e_inview = e_canseemon(level, etmp); } if (is_db_wall(etmp->ex, etmp->ey)) { if (e_inview) { if (is_u(etmp)) { pline("You tumble towards the closed portcullis!"); if (automiss(etmp)) pline("You pass through it!"); else pline("The drawbridge closes in..."); } else pline("%s behind the drawbridge.", E_phrase(etmp, "disappear")); } if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { killer_format = KILLED_BY_AN; killer = "closing drawbridge"; e_died(etmp, 0, CRUSHING); /* no message */ return; } } else { if (is_pool(level, etmp->ex, etmp->ey) && !e_inview) if (flags.soundok) You_hear("a splash."); if (e_survives_at(etmp, etmp->ex, etmp->ey)) { if (e_inview && !is_flyer(etmp->edata) && !is_floater(etmp->edata)) pline("%s from the bridge.", E_phrase(etmp, "fall")); return; } if (is_pool(level, etmp->ex, etmp->ey) || is_lava(level, etmp->ex, etmp->ey)) if (e_inview && !is_u(etmp)) { /* drown() will supply msgs if nec. */ boolean lava = is_lava(level, etmp->ex, etmp->ey); if (Hallucination) pline("%s the %s and disappears.", E_phrase(etmp, "drink"), lava ? "lava" : "moat"); else pline("%s into the %s.", E_phrase(etmp, "fall"), lava ? "lava" : "moat"); } killer_format = NO_KILLER_PREFIX; killer = "fell from a drawbridge"; e_died(etmp, e_inview ? 3 : 2, /* CRUSHING is arbitrary */ (is_pool(level, etmp->ex, etmp->ey)) ? DROWNING : (is_lava(level, etmp->ex, etmp->ey)) ? BURNING : CRUSHING); /*no corpse*/ return; } }
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); } 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(); commands_init(); (void) encumber_msg(); /* in case they auto-picked up something */ 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) { curmonst = &youmonst; 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; } } 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(); 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) && !(u.uswallow && u.ustuck->data == &mons[PM_WATER_ELEMENTAL])) { if (u.mh > 1) { u.mh--; flags.botl = 1; } else if (u.mh < 1) killer_format = KILLED_BY_AN, rehumanize("inability to breathe air"); } else if (Upolyd && u.mh < u.mhmax) { if (u.mh < 1) rehumanize(0); 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)) { 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; } flags.botl = 1; u.uhp += heal; if(u.uhp > u.uhpmax) u.uhp = u.uhpmax; } else if (Regeneration || (u.ulevel <= 9 && !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) { flags.botl = 1; u.uhp++; } } /* 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); } } } 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; 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(old_ux, old_uy); } #ifdef REDO /* clear doagain keystrokes */ pushch(0); savech(0); #endif } } /* 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); if (change == 1) polyself(FALSE); else you_were(); change = 0; } } 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); } } } } if(Searching && multi >= 0) (void) dosearch0(1); dosounds(); /* hack - make sure damage from storms is not blamed on the player */ flags.mon_moving = TRUE; do_storms(); flags.mon_moving = FALSE; 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 */ /******************************************/ curmonst = &youmonst; } /* 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 (HHallucination && !Halluc_resistance) { /* update screen randomly */ /* see_monsters(); see_objects(); see_traps(); if (u.uswallow) swallowed(0); */ if (u.uswallow) { swallowed(1); } else if (Underwater && !Is_waterlevel(&u.uz)) { under_water(1); } else if (u.uburied) { under_ground(1); } else { register int x, y; register struct rm *lev; vision_recalc(2); /*clear_nhwindow(WIN_MAP);*/ clear_glyph_buffer(); for (x = 1; x < COLNO; x++) { lev = &levl[x][0]; for (y = 0; y < ROWNO; y++, lev++) if (lev->glyph != cmap_to_glyph(S_stone)) show_glyph(x,y,lev->glyph); } vision_recalc(0); see_monsters(); } } else if (Unblind_telepat) { see_monsters(); } else if (Warning || Warn_of_mon) see_monsters(); if (vision_full_recalc) vision_recalc(0); /* vision! */ } #ifdef REALTIME_ON_BOTL if(iflags.showrealtime) { /* Update the bottom line if the number of minutes has * changed */ if(get_realtime() / 60 != realtime_data.last_displayed_time / 60) flags.botl = 1; } #endif 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(); #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); } } }
void polyself(boolean forcecontrol) { char buf[BUFSZ]; int old_light, new_light; int mntmp = NON_PM; int tries=0; boolean draconian = (uarm && uarm->otyp >= GRAY_DRAGON_SCALE_MAIL && uarm->otyp <= YELLOW_DRAGON_SCALES); boolean iswere = (u.ulycn >= LOW_PM || is_were(youmonst.data)); boolean isvamp = (youmonst.data->mlet == S_VAMPIRE || u.umonnum == PM_VAMPIRE_BAT); boolean was_floating = (Levitation || Flying); if (!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) { if (rn2(20) > ACURR(A_CON)) { pline("You shudder for a moment."); losehp(rnd(30), "system shock", KILLED_BY_AN); exercise(A_CON, FALSE); return; } } old_light = Upolyd ? emits_light(youmonst.data) : 0; if (Polymorph_control || forcecontrol) { do { getlin("Become what kind of monster? [type the name]", buf); mntmp = name_to_mon(buf); if (mntmp < LOW_PM) pline("I've never heard of such monsters."); /* Note: humans are illegal as monsters, but an * illegal monster forces newman(), which is what we * want if they specified a human.... */ else if (!polyok(&mons[mntmp]) && !your_race(&mons[mntmp])) pline("You cannot polymorph into that."); else break; } while (++tries < 5); if (tries==5) pline("That's enough tries!"); /* allow skin merging, even when polymorph is controlled */ if (draconian && (mntmp == armor_to_dragon(uarm->otyp) || tries == 5)) goto do_merge; } else if (draconian || iswere || isvamp) { /* special changes that don't require polyok() */ if (draconian) { do_merge: mntmp = armor_to_dragon(uarm->otyp); if (!(mvitals[mntmp].mvflags & G_GENOD)) { /* allow G_EXTINCT */ pline("You merge with your scaly armor."); uskin = uarm; uarm = NULL; /* save/restore hack */ uskin->owornmask |= I_SPECIAL; } } else if (iswere) { if (is_were(youmonst.data)) mntmp = PM_HUMAN; /* Illegal; force newman() */ else mntmp = u.ulycn; } else { if (youmonst.data->mlet == S_VAMPIRE) mntmp = PM_VAMPIRE_BAT; else mntmp = PM_VAMPIRE; } /* if polymon fails, "you feel" message has been given so don't follow up with another polymon or newman */ if (mntmp == PM_HUMAN) newman(); /* werecritter */ else polymon(mntmp); goto made_change; /* maybe not, but this is right anyway */ } if (mntmp < LOW_PM) { tries = 0; do { /* randomly pick an "ordinary" monster */ mntmp = rn1(SPECIAL_PM - LOW_PM, LOW_PM); } while ((!polyok(&mons[mntmp]) || is_placeholder(&mons[mntmp])) && tries++ < 200); } /* The below polyok() fails either if everything is genocided, or if * we deliberately chose something illegal to force newman(). */ if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp])) newman(); else if (!polymon(mntmp)) return; if (!uarmg) selftouch("No longer petrify-resistant, you"); made_change: new_light = Upolyd ? emits_light(youmonst.data) : 0; if (old_light != new_light) { if (old_light) del_light_source(level, LS_MONSTER, &youmonst); if (new_light == 1) ++new_light; /* otherwise it's undetectable */ if (new_light) new_light_source(level, u.ux, u.uy, new_light, LS_MONSTER, &youmonst); } if (is_pool(level, u.ux,u.uy) && was_floating && !(Levitation || Flying) && !breathless(youmonst.data) && !amphibious(youmonst.data) && !Swimming) drown(); }
int dosit() { static const char sit_message[] = "sit on the %s."; register struct trap *trap; register int typ = levl[u.ux][u.uy].typ; #ifdef STEED if (u.usteed) { You("are already sitting on %s.", mon_nam(u.usteed)); return (0); } #endif if(!can_reach_floor()) { if (Levitation) You("tumble in place."); else You("are sitting on air."); return 0; } else if (is_pool(u.ux, u.uy) && !Underwater) { /* water walking */ goto in_water; } if(OBJ_AT(u.ux, u.uy)) { register struct obj *obj; obj = level.objects[u.ux][u.uy]; You("sit on %s.", the(xname(obj))); if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH)) pline("It's not very comfortable..."); } else if ((trap = t_at(u.ux, u.uy)) != 0 || (u.utrap && (u.utraptype >= TT_LAVA))) { if (u.utrap) { exercise(A_WIS, FALSE); /* you're getting stuck longer */ if(u.utraptype == TT_BEARTRAP) { You_cant("sit down with your %s in the bear trap.", body_part(FOOT)); u.utrap++; } else if(u.utraptype == TT_PIT) { if(trap->ttyp == SPIKED_PIT) { You("sit down on a spike. Ouch!"); losehp(1, "sitting on an iron spike", KILLED_BY); exercise(A_STR, FALSE); } else You("sit down in the pit."); u.utrap += rn2(5); } else if(u.utraptype == TT_WEB) { You("sit in the spider web and get entangled further!"); u.utrap += rn1(10, 5); } else if(u.utraptype == TT_LAVA) { /* Must have fire resistance or they'd be dead already */ You("sit in the lava!"); u.utrap += rnd(4); losehp(d(2,10), "sitting in lava", KILLED_BY); } else if(u.utraptype == TT_INFLOOR) { You_cant("maneuver to sit!"); u.utrap++; } } else { You("sit down."); dotrap(trap, 0); } } else if(Underwater || Is_waterlevel(&u.uz)) { if (Is_waterlevel(&u.uz)) There("are no cushions floating nearby."); else You("sit down on the muddy bottom."); } else if(is_pool(u.ux, u.uy)) { in_water: You("sit in the water."); if (!rn2(10) && uarm) (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS) (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); #ifdef SINKS } else if(IS_SINK(typ)) { You(sit_message, defsyms[S_sink].explanation); Your("%s gets wet.", humanoid(youmonst.data) ? "rump" : "underside"); #endif } else if(IS_ALTAR(typ)) { You(sit_message, defsyms[S_altar].explanation); altar_wrath(u.ux, u.uy); } else if(IS_GRAVE(typ)) { You(sit_message, defsyms[S_grave].explanation); } else if(typ == STAIRS) { You(sit_message, "stairs"); } else if(typ == LADDER) { You(sit_message, "ladder"); } else if (is_lava(u.ux, u.uy)) { /* must be WWalking */ You(sit_message, "lava"); burn_away_slime(); if (likes_lava(youmonst.data)) { pline_The("lava feels warm."); return 1; } pline_The("lava burns you!"); losehp(d((Fire_resistance ? 2 : 10), 10), "sitting on lava", KILLED_BY); } else if (is_ice(u.ux, u.uy)) { You(sit_message, defsyms[S_ice].explanation); if (!Cold_resistance) pline_The("ice feels cold."); } else if (typ == DRAWBRIDGE_DOWN) { You(sit_message, "drawbridge"); } else if(IS_THRONE(typ)) { You(sit_message, defsyms[S_throne].explanation); if (rnd(6) > 4) { switch (rnd(13)) { case 1: (void) adjattrib(rn2(A_MAX), -rn1(4,3), FALSE); losehp(rnd(10), "cursed throne", KILLED_BY_AN); break; case 2: (void) adjattrib(rn2(A_MAX), 1, FALSE); break; case 3: pline("A%s electric shock shoots through your body!", (Shock_resistance) ? "n" : " massive"); losehp(Shock_resistance ? rnd(6) : rnd(30), "electric chair", KILLED_BY_AN); exercise(A_CON, FALSE); break; case 4: You_feel("much, much better!"); if (Upolyd) { if (u.mh >= (u.mhmax - 5)) u.mhmax += 4; u.mh = u.mhmax; } if(u.uhp >= (u.uhpmax - 5)) u.uhpmax += 4; u.uhp = u.uhpmax; make_blinded(0L,TRUE); make_sick(0L, (char *) 0, FALSE, SICK_ALL); heal_legs(); flags.botl = 1; break; case 5: take_gold(); break; case 6: if(u.uluck + rn2(5) < 0) { You_feel("your luck is changing."); change_luck(1); } else makewish(); break; case 7: { register int cnt = rnd(10); pline("A voice echoes:"); verbalize("Thy audience hath been summoned, %s!", flags.female ? "Dame" : "Sire"); while(cnt--) (void) makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS); break; } case 8: pline("A voice echoes:"); verbalize("By thy Imperious order, %s...", flags.female ? "Dame" : "Sire"); do_genocide(5); /* REALLY|ONTHRONE, see do_genocide() */ break; case 9: pline("A voice echoes:"); verbalize("A curse upon thee for sitting upon this most holy throne!"); if (Luck > 0) { make_blinded(Blinded + rn1(100,250),TRUE); } else rndcurse(); break; case 10: if (Luck < 0 || (HSee_invisible & INTRINSIC)) { if (level.flags.nommap) { pline( "A terrible drone fills your head!"); make_confused(HConfusion + rnd(30), FALSE); } else { pline("An image forms in your mind."); do_mapping(); } } else { Your("vision becomes clear."); HSee_invisible |= FROMOUTSIDE; newsym(u.ux, u.uy); } break; case 11: if (Luck < 0) { You_feel("threatened."); aggravate(); } else { You_feel("a wrenching sensation."); tele(); /* teleport him */ } break; case 12: You("are granted an insight!"); if (invent) { /* rn2(5) agrees w/seffects() */ identify_pack(rn2(5)); } break; case 13: Your("mind turns into a pretzel!"); make_confused(HConfusion + rn1(7,16),FALSE); break; default: impossible("throne effect"); break; } } else { if (is_prince(youmonst.data)) You_feel("very comfortable here."); else You_feel("somehow out of place..."); } if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ levl[u.ux][u.uy].typ = ROOM; pline_The("throne vanishes in a puff of logic."); newsym(u.ux,u.uy); } } else if (lays_eggs(youmonst.data)) { struct obj *uegg; if (!flags.female) { pline("Males can't lay eggs!"); return 0; } if (u.uhunger < (int)objects[EGG].oc_nutrition) { You("don't have enough energy to lay an egg."); return 0; } uegg = mksobj(EGG, FALSE, FALSE); uegg->spe = 1; uegg->quan = 1; uegg->owt = weight(uegg); uegg->corpsenm = egg_type_from_parent(u.umonnum, FALSE); uegg->known = uegg->dknown = 1; attach_egg_hatch_timeout(uegg); You("lay an egg."); dropy(uegg); stackobj(uegg); morehungry((int)objects[EGG].oc_nutrition); } else if (u.uswallow) There("are no seats in here!"); else pline("Having fun sitting on the %s?", surface(u.ux,u.uy)); return(1); }
/* returns 1 if polymorph successful */ int polymon(int mntmp) { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_blind = !!Blind, dochange = FALSE; boolean could_pass_walls = Passes_walls; int mlvl; if (mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ pline("You feel rather %s-ish.",mons[mntmp].mname); exercise(A_WIS, TRUE); return 0; } /* KMH, conduct */ u.uconduct.polyselfs++; if (!Upolyd) { /* Human to monster; save human stats */ u.macurr = u.acurr; u.mamax = u.amax; u.mfemale = flags.female; } else { /* Monster to monster; restore human stats, to be * immediately changed to provide stats for the new monster */ u.acurr = u.macurr; u.amax = u.mamax; flags.female = u.mfemale; } if (youmonst.m_ap_type) { /* stop mimicking immediately */ if (multi < 0) unmul(""); } else if (mons[mntmp].mlet != S_MIMIC) { /* as in polyman() */ youmonst.m_ap_type = M_AP_NOTHING; } if (is_male(&mons[mntmp])) { if (flags.female) dochange = TRUE; } else if (is_female(&mons[mntmp])) { if (!flags.female) dochange = TRUE; } else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) { if (!rn2(10)) dochange = TRUE; } if (dochange) { flags.female = !flags.female; pline("You %s %s%s!", (u.umonnum != mntmp) ? "turn into a" : "feel like a new", (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" : flags.female ? "female " : "male ", mons[mntmp].mname); } else { if (u.umonnum != mntmp) pline("You turn into %s!", an(mons[mntmp].mname)); else pline("You feel like a new %s!", mons[mntmp].mname); } if (Stoned && poly_when_stoned(&mons[mntmp])) { /* poly_when_stoned already checked stone golem genocide */ pline("You turn to stone!"); mntmp = PM_STONE_GOLEM; Stoned = 0; delayed_killer = 0; } u.mtimedone = rn1(500, 500); u.umonnum = mntmp; set_uasmon(); /* New stats for monster, to last only as long as polymorphed. * Currently only strength gets changed. */ if (strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100); if (Stone_resistance && Stoned) { /* [email protected] */ Stoned = 0; delayed_killer = 0; pline("You no longer seem to be petrifying."); } if (Sick_resistance && Sick) { make_sick(0L, NULL, FALSE, SICK_ALL); pline("You no longer feel sick."); } if (Slimed) { if (flaming(youmonst.data)) { pline("The slime burns away!"); Slimed = 0L; iflags.botl = 1; } else if (mntmp == PM_GREEN_SLIME) { /* do it silently */ Slimed = 0L; iflags.botl = 1; } } if (nohands(youmonst.data)) Glib = 0; /* mlvl = adj_lev(&mons[mntmp]); * We can't do the above, since there's no such thing as an * "experience level of you as a monster" for a polymorphed character. */ mlvl = (int)mons[mntmp].mlevel; if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) { u.mhmax = In_endgame(&u.uz) ? (8*mlvl) : (4*mlvl + dice(mlvl,4)); } else if (is_golem(youmonst.data)) { u.mhmax = golemhp(mntmp); } else { if (!mlvl) u.mhmax = rnd(4); else u.mhmax = dice(mlvl, 8); if (is_home_elemental(&u.uz, &mons[mntmp])) u.mhmax *= 3; } u.mh = u.mhmax; if (u.ulevel < mlvl) { /* Low level characters can't become high level monsters for long */ u.mtimedone = u.mtimedone * u.ulevel / mlvl; } if (uskin && mntmp != armor_to_dragon(uskin->otyp)) skinback(FALSE); break_armor(); drop_weapon(1); if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(u.ux, u.uy); else if (youmonst.data->mlet == S_EEL) u.uundetected = is_pool(level, u.ux, u.uy); else u.uundetected = 0; if (u.utraptype == TT_PIT) { if (could_pass_walls && !Passes_walls) { u.utrap = rn1(6,2); } else if (!could_pass_walls && Passes_walls) { u.utrap = 0; } } if (was_blind && !Blind) { /* previous form was eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } newsym(u.ux,u.uy); /* Change symbol */ if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0; else if (sticky && !sticks(youmonst.data)) uunstick(); if (u.usteed) { if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { char buf[BUFSZ]; pline("No longer petrifying-resistant, you touch %s.", mon_nam(u.usteed)); sprintf(buf, "riding %s", an(u.usteed->data->mname)); instapetrify(buf); } if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY); } if (flags.verbose) { static const char use_thec[] = "Use the command #%s to %s."; static const char monsterc[] = "monster"; if (can_breathe(youmonst.data)) pline(use_thec,monsterc,"use your breath weapon"); if (attacktype(youmonst.data, AT_SPIT)) pline(use_thec,monsterc,"spit venom"); if (youmonst.data->mlet == S_NYMPH) pline(use_thec,monsterc,"remove an iron ball"); if (attacktype(youmonst.data, AT_GAZE)) pline(use_thec,monsterc,"gaze at monsters"); if (is_hider(youmonst.data)) pline(use_thec,monsterc,"hide"); if (is_were(youmonst.data)) pline(use_thec,monsterc,"summon help"); if (webmaker(youmonst.data)) pline(use_thec,monsterc,"spin a web"); if (u.umonnum == PM_GREMLIN) pline(use_thec,monsterc,"multiply in a fountain"); if (is_unicorn(youmonst.data)) pline(use_thec,monsterc,"use your horn"); if (is_mind_flayer(youmonst.data)) pline(use_thec,monsterc,"emit a mental blast"); if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */ pline(use_thec,monsterc,"shriek"); if (lays_eggs(youmonst.data) && flags.female) pline(use_thec,"sit","lay an egg"); } /* you now know what an egg of your type looks like */ if (lays_eggs(youmonst.data)) { learn_egg_type(u.umonnum); /* make queen bees recognize killer bee eggs */ learn_egg_type(egg_type_from_parent(u.umonnum, TRUE)); } find_ac(); if ((!Levitation && !u.ustuck && !Flying && (is_pool(level, u.ux,u.uy) || is_lava(level, u.ux,u.uy))) || (Underwater && !Swimming)) spoteffects(TRUE); if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) { u.utrap = 0; pline("The rock seems to no longer trap you."); } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) { u.utrap = 0; pline("The lava now feels soothing."); } if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { if (Punished) { pline("You slip out of the iron chain."); unpunish(); } } if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) && (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) || (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) { pline("You are no longer stuck in the %s.", u.utraptype == TT_WEB ? "web" : "bear trap"); /* probably should burn webs too if PM_FIRE_ELEMENTAL */ u.utrap = 0; } if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) { pline("You orient yourself on the web."); u.utrap = 0; } iflags.botl = 1; vision_full_recalc = 1; see_monsters(); exercise(A_CON, FALSE); exercise(A_WIS, TRUE); encumber_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); } } }
static int describe_object(int x, int y, int votyp, char *buf, int known_embed, boolean *feature_described) { int num_objs = 0; struct obj *otmp; int typ; *feature_described = FALSE; if (votyp == -1) return -1; otmp = vobj_at(x, y); if (!otmp || otmp->otyp != votyp) { /* We have a mimic. */ if (votyp == STRANGE_OBJECT) { strcpy(buf, "strange object"); } else { otmp = mktemp_sobj(level, votyp); otmp->corpsenm = PM_TENGU; /* (basic object only, no random features) */ if (otmp->oclass == COIN_CLASS) otmp->quan = 1L; /* to force pluralization off */ else if (otmp->otyp == SLIME_MOLD) otmp->spe = gamestate.fruits.current;/* give the fruit a type */ strcpy(buf, distant_name(otmp, xname)); dealloc_obj(otmp); otmp = vobj_at(x, y); /* make sure we don't point to the temp obj any more */ } } else strcpy(buf, distant_name(otmp, xname)); typ = level->locations[x][y].typ; if (known_embed && IS_TREE(typ)) strcat(buf, " stuck"); else if (known_embed && (IS_ROCK(typ) || closed_door(level, x, y))) strcat(buf, " embedded"); else if (IS_TREE(typ)) { strcat(buf, " stuck in a tree"); *feature_described = TRUE; } else if (typ == STONE || typ == SCORR) { strcat(buf, " embedded in stone"); *feature_described = TRUE; } else if (IS_WALL(typ) || typ == SDOOR) { strcat(buf, " embedded in a wall"); *feature_described = TRUE; } else if (closed_door(level, x, y)) { strcat(buf, " embedded in a door"); *feature_described = TRUE; } else if (is_pool(level, x, y)) { strcat(buf, " in water"); *feature_described = TRUE; } else if (is_lava(level, x, y)) { strcat(buf, " in molten lava"); /* [can this ever happen?] */ *feature_described = TRUE; } if (!cansee(x, y)) return -1; /* don't disclose the number of objects for location out of LOS */ if (!otmp) /* There is no object here. Since the player sees one it must be a mimic */ return 1; if (otmp->otyp != votyp) /* Hero sees something other than the actual top object. Probably a mimic */ num_objs++; for (; otmp; otmp = otmp->nexthere) num_objs++; return num_objs; }
/* #sit command */ int dosit() { /*JP static const char sit_message[] = "sit on the %s."; */ static const char sit_message[] = "%sに座った."; register struct trap *trap = t_at(u.ux, u.uy); register int typ = levl[u.ux][u.uy].typ; if (u.usteed) { /*JP You("are already sitting on %s.", mon_nam(u.usteed)); */ You("もう%sに座っている.", mon_nam(u.usteed)); return 0; } if (u.uundetected && is_hider(youmonst.data) && u.umonnum != PM_TRAPPER) u.uundetected = 0; /* no longer on the ceiling */ if (!can_reach_floor(FALSE)) { if (u.uswallow) /*JP There("are no seats in here!"); */ pline("ここには椅子がない!"); else if (Levitation) /*JP You("tumble in place."); */ You("その場で宙返りした."); else /*JP You("are sitting on air."); */ You("空中に座った."); return 0; } else if (u.ustuck && !sticks(youmonst.data)) { /* holding monster is next to hero rather than beneath, but hero is in no condition to actually sit at has/her own spot */ if (humanoid(u.ustuck->data)) /*JP pline("%s won't offer %s lap.", Monnam(u.ustuck), mhis(u.ustuck)); */ pline("%sはひざを出さなかった.", Monnam(u.ustuck)); else /*JP pline("%s has no lap.", Monnam(u.ustuck)); */ pline("%sにはひざがない.", Monnam(u.ustuck)); return 0; } else if (is_pool(u.ux, u.uy) && !Underwater) { /* water walking */ goto in_water; } if (OBJ_AT(u.ux, u.uy) /* ensure we're not standing on the precipice */ && !uteetering_at_seen_pit(trap)) { register struct obj *obj; obj = level.objects[u.ux][u.uy]; if (youmonst.data->mlet == S_DRAGON && obj->oclass == COIN_CLASS) { #if 0 /*JP*/ You("coil up around your %shoard.", (obj->quan + money_cnt(invent) < u.ulevel * 1000) ? "meager " : ""); #else You("%sお宝のまわりでとぐろを巻いた.", (obj->quan + money_cnt(invent) < u.ulevel * 1000) ? "わずかな" : ""); #endif } else { /*JP You("sit on %s.", the(xname(obj))); */ You("%sに座った.", the(xname(obj))); if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH)) /*JP pline("It's not very comfortable..."); */ pline("あまり座りごこちがよくない..."); } } else if (trap != 0 || (u.utrap && (u.utraptype >= TT_LAVA))) { if (u.utrap) { exercise(A_WIS, FALSE); /* you're getting stuck longer */ if (u.utraptype == TT_BEARTRAP) { /*JP You_cant("sit down with your %s in the bear trap.", */ pline("%sが熊の罠にはさまっているので座れない.", body_part(FOOT)); u.utrap++; } else if (u.utraptype == TT_PIT) { if (trap && trap->ttyp == SPIKED_PIT) { /*JP You("sit down on a spike. Ouch!"); */ You("トゲの上に座った.いてっ!"); losehp(Half_physical_damage ? rn2(2) : 1, /*JP "sitting on an iron spike", KILLED_BY); */ "鉄のトゲの上に座って", KILLED_BY); exercise(A_STR, FALSE); } else /*JP You("sit down in the pit."); */ You("落し穴の中で座った."); u.utrap += rn2(5); } else if (u.utraptype == TT_WEB) { /*JP You("sit in the spider web and get entangled further!"); */ You("くもの巣の中で座ったら,ますます絡まった!"); u.utrap += rn1(10, 5); } else if (u.utraptype == TT_LAVA) { /* Must have fire resistance or they'd be dead already */ /*JP You("sit in the lava!"); */ You("溶岩の中に座った!"); if (Slimed) burn_away_slime(); u.utrap += rnd(4); /*JP losehp(d(2, 10), "sitting in lava", */ losehp(d(2, 10), "溶岩の中に座って", KILLED_BY); /* lava damage */ } else if (u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL) { /*JP You_cant("maneuver to sit!"); */ You("座るような動作ができない!"); u.utrap++; } } else { /*JP You("sit down."); */ You("座った."); dotrap(trap, 0); } } else if (Underwater || Is_waterlevel(&u.uz)) { if (Is_waterlevel(&u.uz)) /*JP There("are no cushions floating nearby."); */ pline("近くに浮いているクッションはない."); else /*JP You("sit down on the muddy bottom."); */ You("どろどろした底に座った."); } else if (is_pool(u.ux, u.uy)) { in_water: /*JP You("sit in the water."); */ You("水の中で座った."); if (!rn2(10) && uarm) /*JP (void) water_damage(uarm, "armor", TRUE); */ (void) water_damage(uarm, "鎧", TRUE); if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS) /*JP (void) water_damage(uarm, "armor", TRUE); */ (void) water_damage(uarm, "鎧", TRUE); } else if (IS_SINK(typ)) { You(sit_message, defsyms[S_sink].explanation); /*JP Your("%s gets wet.", humanoid(youmonst.data) ? "rump" : "underside"); */ Your("%sは濡れた.", humanoid(youmonst.data) ? "尻" : "下部"); } else if (IS_ALTAR(typ)) { You(sit_message, defsyms[S_altar].explanation); altar_wrath(u.ux, u.uy); } else if (IS_GRAVE(typ)) { You(sit_message, defsyms[S_grave].explanation); } else if (typ == STAIRS) { /*JP You(sit_message, "stairs"); */ You(sit_message, "階段"); } else if (typ == LADDER) { /*JP You(sit_message, "ladder"); */ You(sit_message, "はしご"); } else if (is_lava(u.ux, u.uy)) { /* must be WWalking */ /*JP You(sit_message, "lava"); */ You(sit_message, "溶岩"); burn_away_slime(); if (likes_lava(youmonst.data)) { /*JP pline_The("lava feels warm."); */ pline("溶岩は暖かい."); return 1; } /*JP pline_The("lava burns you!"); */ You("溶岩で燃えた!"); losehp(d((Fire_resistance ? 2 : 10), 10), /* lava damage */ /*JP "sitting on lava", KILLED_BY); */ "溶岩に座って", KILLED_BY); } else if (is_ice(u.ux, u.uy)) { You(sit_message, defsyms[S_ice].explanation); if (!Cold_resistance) /*JP pline_The("ice feels cold."); */ pline("氷は冷たく感じた."); } else if (typ == DRAWBRIDGE_DOWN) { /*JP You(sit_message, "drawbridge"); */ You(sit_message, "跳ね橋"); } else if (IS_THRONE(typ)) { You(sit_message, defsyms[S_throne].explanation); if (rnd(6) > 4) { switch (rnd(13)) { case 1: (void) adjattrib(rn2(A_MAX), -rn1(4, 3), FALSE); /*JP losehp(rnd(10), "cursed throne", KILLED_BY_AN); */ losehp(rnd(10), "呪われた玉座で", KILLED_BY_AN); break; case 2: (void) adjattrib(rn2(A_MAX), 1, FALSE); break; case 3: #if 0 /*JP*/ pline("A%s electric shock shoots through your body!", (Shock_resistance) ? "n" : " massive"); #else pline("%s電気があなたの体を走り抜けた!", (Shock_resistance) ? "" : "激しい"); #endif /*JP losehp(Shock_resistance ? rnd(6) : rnd(30), "electric chair", */ losehp(Shock_resistance ? rnd(6) : rnd(30), "電気椅子で", KILLED_BY_AN); exercise(A_CON, FALSE); break; case 4: /*JP You_feel("much, much better!"); */ You_feel("とても,とても元気になったような気がした!"); if (Upolyd) { if (u.mh >= (u.mhmax - 5)) u.mhmax += 4; u.mh = u.mhmax; } if (u.uhp >= (u.uhpmax - 5)) u.uhpmax += 4; u.uhp = u.uhpmax; make_blinded(0L, TRUE); make_sick(0L, (char *) 0, FALSE, SICK_ALL); heal_legs(); context.botl = 1; break; case 5: take_gold(); break; case 6: if (u.uluck + rn2(5) < 0) { /*JP You_feel("your luck is changing."); */ pline("運が向いてきた気がする."); change_luck(1); } else makewish(); break; case 7: { int cnt = rnd(10); /* Magical voice not affected by deafness */ /*JP pline("A voice echoes:"); */ pline("声が響いた:"); #if 0 /*JP*/ verbalize("Thy audience hath been summoned, %s!", flags.female ? "Dame" : "Sire"); #else verbalize("%sよ!汝の聴衆召喚されし.", flags.female ? "女" : "男"); #endif while (cnt--) (void) makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS); break; } case 8: /* Magical voice not affected by deafness */ /*JP pline("A voice echoes:"); */ pline("声が響いた:"); #if 0 /*JP*/ verbalize("By thine Imperious order, %s...", flags.female ? "Dame" : "Sire"); #else verbalize("%sよ!汝の傲慢聞きいれようぞ.", flags.female ? "女" : "男"); #endif do_genocide(5); /* REALLY|ONTHRONE, see do_genocide() */ break; case 9: /* Magical voice not affected by deafness */ /*JP pline("A voice echoes:"); */ pline("声が響いた:"); verbalize( /*JP "A curse upon thee for sitting upon this most holy throne!"); */ "聖なる玉座に座りし汝に呪いあれ!"); if (Luck > 0) { make_blinded(Blinded + rn1(100, 250), TRUE); } else rndcurse(); break; case 10: if (Luck < 0 || (HSee_invisible & INTRINSIC)) { if (level.flags.nommap) { /*JP pline("A terrible drone fills your head!"); */ pline("恐しいブンブンという音が頭に響いた!"); make_confused((HConfusion & TIMEOUT) + (long) rnd(30), FALSE); } else { /*JP pline("An image forms in your mind."); */ pline("あるイメージが頭に浮んだ."); do_mapping(); } } else { /*JP Your("vision becomes clear."); */ Your("視界は冴え渡った."); HSee_invisible |= FROMOUTSIDE; newsym(u.ux, u.uy); } break; case 11: if (Luck < 0) { /*JP You_feel("threatened."); */ You("脅迫されているような気がした."); aggravate(); } else { /*JP You_feel("a wrenching sensation."); */ You("ねじられたような感覚を感じた."); tele(); /* teleport him */ } break; case 12: /*JP You("are granted an insight!"); */ You("洞察力を得た!"); if (invent) { /* rn2(5) agrees w/seffects() */ identify_pack(rn2(5), FALSE); } break; case 13: /*JP Your("mind turns into a pretzel!"); */ Your("心はクネクネになった!"); make_confused((HConfusion & TIMEOUT) + (long) rn1(7, 16), FALSE); break; default: impossible("throne effect"); break; } } else { if (is_prince(youmonst.data)) /*JP You_feel("very comfortable here."); */ You("ここはとても落ち着く."); else /*JP You_feel("somehow out of place..."); */ You("何か場違いの気がした..."); } if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ levl[u.ux][u.uy].typ = ROOM; /*JP pline_The("throne vanishes in a puff of logic."); */ pline("玉座はふっと消えた."); newsym(u.ux, u.uy); } } else if (lays_eggs(youmonst.data)) { struct obj *uegg; if (!flags.female) { #if 0 /*JP*/ pline("%s can't lay eggs!", Hallucination ? "You may think you are a platypus, but a male still" : "Males"); #else pline("%s雄は卵を産めない!", Hallucination ? "あなたは自分がカモノハシだと思っているかもしれないが,やっぱり" : ""); #endif return 0; } else if (u.uhunger < (int) objects[EGG].oc_nutrition) { /*JP You("don't have enough energy to lay an egg."); */ You("卵を産むだけのエネルギーがない."); return 0; } uegg = mksobj(EGG, FALSE, FALSE); uegg->spe = 1; uegg->quan = 1L; uegg->owt = weight(uegg); /* this sets hatch timers if appropriate */ set_corpsenm(uegg, egg_type_from_parent(u.umonnum, FALSE)); uegg->known = uegg->dknown = 1; /*JP You("lay an egg."); */ You("卵を産んだ."); dropy(uegg); stackobj(uegg); morehungry((int) objects[EGG].oc_nutrition); } else { /*JP pline("Having fun sitting on the %s?", surface(u.ux, u.uy)); */ pline("%sに座って楽しいかい?", surface(u.ux,u.uy)); } return 1; }
void teleds(int nux, int nuy, boolean allow_drag) { boolean ball_active = (Punished && uball->where != OBJ_FREE), ball_still_in_range = FALSE; /* If they have to move the ball, then drag if allow_drag is true; otherwise they are teleporting, so unplacebc(). If they don't have to move the ball, then always "drag" whether or not allow_drag is true, because we are calling that function, not to drag, but to move the chain. *However* there are some dumb special cases: 0 0 _X move east -----> X_ @ @ These are permissible if teleporting, but not if dragging. As a result, drag_ball() needs to know about allow_drag and might end up dragging the ball anyway. Also, drag_ball() might find that dragging the ball is completely impossible (ball in range but there's rock in the way), in which case it teleports the ball on its own. */ if (ball_active) { if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2) ball_still_in_range = TRUE; /* don't have to move the ball */ else { /* have to move the ball */ if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) { /* we should not have dist > 1 and allow_drag at the same time, but just in case, we must then revert to teleport. */ allow_drag = FALSE; unplacebc(); } } } u.utrap = 0; u.ustuck = 0; u.ux0 = u.ux; u.uy0 = u.uy; if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(nux, nuy); else if (youmonst.data->mlet == S_EEL) u.uundetected = is_pool(level, nux, nuy); else { u.uundetected = 0; /* mimics stop being unnoticed */ if (youmonst.data->mlet == S_MIMIC) youmonst.m_ap_type = M_AP_NOTHING; } if (Engulfed) { u.uswldtim = Engulfed = 0; if (Punished && !ball_active) { /* ensure ball placement, like unstuck */ ball_active = TRUE; allow_drag = FALSE; } doredraw(); } if (ball_active) { if (ball_still_in_range || allow_drag) { int bc_control; xchar ballx, bally, chainx, chainy; boolean cause_delay; if (drag_ball (nux, nuy, &bc_control, &ballx, &bally, &chainx, &chainy, &cause_delay, allow_drag)) move_bc(0, bc_control, ballx, bally, chainx, chainy); } } /* must set u.ux, u.uy after drag_ball(), which may need to know the old position if allow_drag is true... */ u.ux = nux; u.uy = nuy; fill_pit(level, u.ux0, u.uy0); if (ball_active) { if (!ball_still_in_range && !allow_drag) placebc(); } initrack(); /* teleports mess up tracking monsters without this */ update_player_regions(level); /* Move your steed, too */ if (u.usteed) { u.usteed->mx = nux; u.usteed->my = nuy; } /* * Make sure the hero disappears from the old location. This will * not happen if she is teleported within sight of her previous * location. Force a full vision recalculation because the hero * is now in a new location. */ newsym(u.ux0, u.uy0); see_monsters(FALSE); turnstate.vision_full_recalc = TRUE; action_interrupted(); vision_recalc(0); /* vision before effects */ spoteffects(TRUE); invocation_message(); }
/* return 1 if action took 1 (or more) moves, 0 if error or aborted */ int doengrave(struct obj *otmp) { boolean dengr = FALSE; /* TRUE if we wipe out the current engraving */ boolean doblind = FALSE;/* TRUE if engraving blinds the player */ boolean doknown = FALSE;/* TRUE if we identify the stylus */ boolean eow = FALSE; /* TRUE if we are overwriting oep */ boolean jello = FALSE; /* TRUE if we are engraving in slime */ boolean ptext = TRUE; /* TRUE if we must prompt for engrave text */ boolean teleengr =FALSE;/* TRUE if we move the old engraving */ boolean zapwand = FALSE;/* TRUE if we remove a wand charge */ xchar type = DUST; /* Type of engraving made */ char buf[BUFSZ]; /* Buffer for final/poly engraving text */ char ebuf[BUFSZ]; /* Buffer for initial engraving text */ char qbuf[QBUFSZ]; /* Buffer for query text */ char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */ const char *everb; /* Present tense of engraving type */ const char *eloc; /* Where the engraving is (ie dust/floor/...) */ char *sp; /* Place holder for space count of engr text */ int len; /* # of nonspace chars of new engraving text */ int maxelen; /* Max allowable length of engraving text */ struct engr *oep = engr_at(level, u.ux,u.uy); /* The current engraving */ char *writer; multi = 0; /* moves consumed */ nomovemsg = NULL; /* occupation end message */ buf[0] = (char)0; ebuf[0] = (char)0; post_engr_text[0] = (char)0; maxelen = BUFSZ - 1; if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE) type = ENGR_BLOOD; /* Can the adventurer engrave at all? */ if (u.uswallow) { if (is_animal(u.ustuck->data)) { pline("What would you write? \"Jonah was here\"?"); return 0; } else if (is_whirly(u.ustuck->data)) { pline("You can't reach the %s.", surface(u.ux,u.uy)); return 0; } else jello = TRUE; } else if (is_lava(level, u.ux, u.uy)) { pline("You can't write on the lava!"); return 0; } else if (Underwater) { pline("You can't write underwater!"); return 0; } else if (is_pool(level, u.ux,u.uy) || IS_FOUNTAIN(level->locations[u.ux][u.uy].typ)) { pline("You can't write on the water!"); return 0; } if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) { pline("You can't write in thin air!"); return 0; } if (cantwield(youmonst.data)) { pline("You can't even hold anything!"); return 0; } if (check_capacity(NULL)) return 0; /* One may write with finger, or weapon, or wand, or..., or... * Edited by GAN 10/20/86 so as not to change weapon wielded. */ if (otmp && !validate_object(otmp, styluses, "write with")) return 0; else if (!otmp) otmp = getobj(styluses, "write with"); if (!otmp) return 0; /* otmp == zeroobj if fingers */ if (otmp == &zeroobj) writer = makeplural(body_part(FINGER)); else writer = xname(otmp); /* There's no reason you should be able to write with a wand * while both your hands are tied up. */ if (!freehand() && otmp != uwep && !otmp->owornmask) { pline("You have no free %s to write with!", body_part(HAND)); return 0; } if (jello) { pline("You tickle %s with your %s.", mon_nam(u.ustuck), writer); pline("Your message dissolves..."); return 0; } if (otmp->oclass != WAND_CLASS && !can_reach_floor()) { pline("You can't reach the %s!", surface(u.ux,u.uy)); return 0; } if (IS_ALTAR(level->locations[u.ux][u.uy].typ)) { pline("You make a motion towards the altar with your %s.", writer); altar_wrath(u.ux, u.uy); return 0; } if (IS_GRAVE(level->locations[u.ux][u.uy].typ)) { if (otmp == &zeroobj) { /* using only finger */ pline("You would only make a small smudge on the %s.", surface(u.ux, u.uy)); return 0; } else if (!level->locations[u.ux][u.uy].disturbed) { pline("You disturb the undead!"); level->locations[u.ux][u.uy].disturbed = 1; makemon(&mons[PM_GHOUL], level, u.ux, u.uy, NO_MM_FLAGS); exercise(A_WIS, FALSE); return 1; } } /* SPFX for items */ switch (otmp->oclass) { default: case AMULET_CLASS: case CHAIN_CLASS: case POTION_CLASS: case COIN_CLASS: break; case RING_CLASS: /* "diamond" rings and others should work */ case GEM_CLASS: /* diamonds & other hard gems should work */ if (objects[otmp->otyp].oc_tough) { type = ENGRAVE; break; } break; case ARMOR_CLASS: if (is_boots(otmp)) { type = DUST; break; } /* fall through */ /* Objects too large to engrave with */ case BALL_CLASS: case ROCK_CLASS: pline("You can't engrave with such a large object!"); ptext = FALSE; break; /* Objects too silly to engrave with */ case FOOD_CLASS: case SCROLL_CLASS: case SPBOOK_CLASS: pline("Your %s would get %s.", xname(otmp), is_ice(level, u.ux, u.uy) ? "all frosty" : "too dirty"); ptext = FALSE; break; case RANDOM_CLASS: /* This should mean fingers */ break; /* The charge is removed from the wand before prompting for * the engraving text, because all kinds of setup decisions * and pre-engraving messages are based upon knowing what type * of engraving the wand is going to do. Also, the player * will have potentially seen "You wrest .." message, and * therefore will know they are using a charge. */ case WAND_CLASS: if (zappable(otmp)) { check_unpaid(otmp); zapwand = TRUE; if (Levitation) ptext = FALSE; switch (otmp->otyp) { /* DUST wands */ default: break; /* NODIR wands */ case WAN_LIGHT: case WAN_SECRET_DOOR_DETECTION: case WAN_CREATE_MONSTER: case WAN_WISHING: case WAN_ENLIGHTENMENT: zapnodir(otmp); break; /* IMMEDIATE wands */ /* If wand is "IMMEDIATE", remember to affect the * previous engraving even if turning to dust. */ case WAN_STRIKING: strcpy(post_engr_text, "The wand unsuccessfully fights your attempt to write!" ); break; case WAN_SLOW_MONSTER: if (!Blind) { sprintf(post_engr_text, "The bugs on the %s slow down!", surface(u.ux, u.uy)); } break; case WAN_SPEED_MONSTER: if (!Blind) { sprintf(post_engr_text, "The bugs on the %s speed up!", surface(u.ux, u.uy)); } break; case WAN_POLYMORPH: if (oep) { if (!Blind) { type = (xchar)0; /* random */ random_engraving(buf); } dengr = TRUE; } break; case WAN_NOTHING: case WAN_UNDEAD_TURNING: case WAN_OPENING: case WAN_LOCKING: case WAN_PROBING: break; /* RAY wands */ case WAN_MAGIC_MISSILE: ptext = TRUE; if (!Blind) { sprintf(post_engr_text, "The %s is riddled by bullet holes!", surface(u.ux, u.uy)); } break; /* can't tell sleep from death - Eric Backus */ case WAN_SLEEP: case WAN_DEATH: if (!Blind) { sprintf(post_engr_text, "The bugs on the %s stop moving!", surface(u.ux, u.uy)); } break; case WAN_COLD: if (!Blind) strcpy(post_engr_text, "A few ice cubes drop from the wand."); if (!oep || (oep->engr_type != BURN)) break; case WAN_CANCELLATION: case WAN_MAKE_INVISIBLE: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline("The engraving on the %s vanishes!", surface(u.ux,u.uy)); dengr = TRUE; } break; case WAN_TELEPORTATION: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline("The engraving on the %s vanishes!", surface(u.ux,u.uy)); teleengr = TRUE; } break; /* type = ENGRAVE wands */ case WAN_DIGGING: ptext = TRUE; type = ENGRAVE; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of digging!", xname(otmp)); doknown = TRUE; } if (!Blind) strcpy(post_engr_text, IS_GRAVE(level->locations[u.ux][u.uy].typ) ? "Chips fly out from the headstone." : is_ice(level, u.ux, u.uy) ? "Ice chips fly up from the ice surface!" : "Gravel flies up from the floor."); else strcpy(post_engr_text, "You hear drilling!"); break; /* type = BURN wands */ case WAN_FIRE: ptext = TRUE; type = BURN; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of fire!", xname(otmp)); doknown = TRUE; } strcpy(post_engr_text, Blind ? "You feel the wand heat up." : "Flames fly from the wand."); break; case WAN_LIGHTNING: ptext = TRUE; type = BURN; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of lightning!", xname(otmp)); doknown = TRUE; } if (!Blind) { strcpy(post_engr_text, "Lightning arcs from the wand."); doblind = TRUE; } else strcpy(post_engr_text, "You hear crackling!"); break; /* type = MARK wands */ /* type = ENGR_BLOOD wands */ } } else /* end if zappable */ if (!can_reach_floor()) { pline("You can't reach the %s!", surface(u.ux,u.uy)); /* If it's a wrestable wand, the player wasted a turn trying. */ if (wrestable(otmp)) return 1; else return 0; } break; case WEAPON_CLASS: if (is_blade(otmp)) { if ((int)otmp->spe > -3) type = ENGRAVE; else pline("Your %s too dull for engraving.", aobjnam(otmp,"are")); } break; case TOOL_CLASS: if (otmp == ublindf) { pline( "That is a bit difficult to engrave with, don't you think?"); return 0; } switch (otmp->otyp) { case MAGIC_MARKER: if (otmp->spe <= 0) pline("Your marker has dried out."); else type = MARK; break; case TOWEL: /* Can't really engrave with a towel */ ptext = FALSE; if (oep) if ((oep->engr_type == DUST ) || (oep->engr_type == ENGR_BLOOD) || (oep->engr_type == MARK )) { if (!Blind) pline("You wipe out the message here."); else pline("Your %s %s %s.", xname(otmp), otense(otmp, "get"), is_ice(level, u.ux, u.uy) ? "frosty" : "dusty"); dengr = TRUE; } else pline("Your %s can't wipe out this engraving.", xname(otmp)); else pline("Your %s %s %s.", xname(otmp), otense(otmp, "get"), is_ice(level, u.ux, u.uy) ? "frosty" : "dusty"); break; default: break; } break; case VENOM_CLASS: if (wizard) { pline("Writing a poison pen letter??"); break; } case ILLOBJ_CLASS: impossible("You're engraving with an illegal object!"); break; } if (IS_GRAVE(level->locations[u.ux][u.uy].typ)) { if (type == ENGRAVE || type == 0) type = HEADSTONE; else { /* ensures the "cannot wipe out" case */ type = DUST; dengr = FALSE; teleengr = FALSE; buf[0] = (char)0; } } /* End of implement setup */ /* Identify stylus */ if (doknown) { makeknown(otmp->otyp); more_experienced(0,10); } if (teleengr) { rloc_engr(oep); oep = NULL; } if (dengr) { del_engr(oep, level); oep = NULL; } /* Something has changed the engraving here */ if (*buf) { make_engr_at(level, u.ux, u.uy, buf, moves, type); pline("The engraving now reads: \"%s\".", buf); ptext = FALSE; } if (zapwand && (otmp->spe < 0)) { pline("%s %sturns to dust.", The(xname(otmp)), Blind ? "" : "glows violently, then "); if (!IS_GRAVE(level->locations[u.ux][u.uy].typ)) pline("You are not going to get anywhere trying to write in the %s with your dust.", is_ice(level, u.ux, u.uy) ? "frost" : "dust"); useup(otmp); ptext = FALSE; } if (!ptext) { /* Early exit for some implements. */ if (otmp->oclass == WAND_CLASS && !can_reach_floor()) pline("You can't reach the %s!", surface(u.ux,u.uy)); return 1; } /* Special effects should have deleted the current engraving (if * possible) by now. */ if (oep) { char c = 'n'; /* Give player the choice to add to engraving. */ if (type == HEADSTONE) { /* no choice, only append */ c = 'y'; } else if ( (type == oep->engr_type) && (!Blind || (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) { c = yn_function("Do you want to add to the current engraving?", ynqchars, 'y'); if (c == 'q') { pline("Never mind."); return 0; } } if (c == 'n' || Blind) { if ( (oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) || (oep->engr_type == MARK) ) { if (!Blind) { pline("You wipe out the message that was %s here.", ((oep->engr_type == DUST) ? "written in the dust" : ((oep->engr_type == ENGR_BLOOD) ? "scrawled in blood" : "written"))); del_engr(oep, level); oep = NULL; } else /* Don't delete engr until after we *know* we're engraving */ eow = TRUE; } else if ( (type == DUST) || (type == MARK) || (type == ENGR_BLOOD) ) { pline( "You cannot wipe out the message that is %s the %s here.", oep->engr_type == BURN ? (is_ice(level, u.ux, u.uy) ? "melted into" : "burned into") : "engraved in", surface(u.ux,u.uy)); return 1; } else if ( (type != oep->engr_type) || (c == 'n') ) { if (!Blind || can_reach_floor()) pline("You will overwrite the current message."); eow = TRUE; } } } eloc = surface(u.ux,u.uy); switch(type){ default: everb = (oep && !eow ? "add to the weird writing on" : "write strangely on"); break; case DUST: everb = (oep && !eow ? "add to the writing in" : "write in"); eloc = is_ice(level, u.ux, u.uy) ? "frost" : "dust"; break; case HEADSTONE: everb = (oep && !eow ? "add to the epitaph on" : "engrave on"); break; case ENGRAVE: everb = (oep && !eow ? "add to the engraving in" : "engrave in"); break; case BURN: everb = (oep && !eow ? ( is_ice(level, u.ux,u.uy) ? "add to the text melted into" : "add to the text burned into") : ( is_ice(level, u.ux,u.uy) ? "melt into" : "burn into")); break; case MARK: everb = (oep && !eow ? "add to the graffiti on" : "scribble on"); break; case ENGR_BLOOD: everb = (oep && !eow ? "add to the scrawl on" : "scrawl on"); break; } /* Tell adventurer what is going on */ if (otmp != &zeroobj) pline("You %s the %s with %s.", everb, eloc, doname(otmp)); else pline("You %s the %s with your %s.", everb, eloc, makeplural(body_part(FINGER))); /* Prompt for engraving! */ sprintf(qbuf,"What do you want to %s the %s here?", everb, eloc); getlin(qbuf, ebuf); /* Count the actual # of chars engraved not including spaces */ len = strlen(ebuf); for (sp = ebuf; *sp; sp++) if (isspace(*sp)) len -= 1; if (len == 0 || strchr(ebuf, '\033')) { if (zapwand) { if (!Blind) pline("%s, then %s.", Tobjnam(otmp, "glow"), otense(otmp, "fade")); return 1; } else { pline("Never mind."); if (otmp && otmp->oclass == WAND_CLASS && wrestable(otmp)) return 1; /* disallow zero turn wrest */ else return 0; } } /* A single `x' is the traditional signature of an illiterate person */ if (len != 1 || (!strchr(ebuf, 'x') && !strchr(ebuf, 'X'))) u.uconduct.literate++; /* Mix up engraving if surface or state of mind is unsound. Note: this won't add or remove any spaces. */ for (sp = ebuf; *sp; sp++) { if (isspace(*sp)) continue; if (((type == DUST || type == ENGR_BLOOD) && !rn2(25)) || (Blind && !rn2(11)) || (Confusion && !rn2(7)) || (Stunned && !rn2(4)) || (Hallucination && !rn2(2))) *sp = ' ' + rnd(96 - 2); /* ASCII '!' thru '~' (excludes ' ' and DEL) */ } /* Previous engraving is overwritten */ if (eow) { del_engr(oep, level); oep = NULL; } /* Figure out how long it took to engrave, and if player has * engraved too much. */ switch(type){ default: multi = -(len/10); if (multi) nomovemsg = "You finish your weird engraving."; break; case DUST: multi = -(len/10); if (multi) nomovemsg = "You finish writing in the dust."; break; case HEADSTONE: case ENGRAVE: multi = -(len/10); if ((otmp->oclass == WEAPON_CLASS) && ((otmp->otyp != ATHAME) || otmp->cursed)) { multi = -len; maxelen = ((otmp->spe + 3) * 2) + 1; /* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11 * Note: this does not allow a +0 anything (except * an athame) to engrave "Elbereth" all at once. * However, you could now engrave "Elb", then * "ere", then "th". */ pline("Your %s dull.", aobjnam(otmp, "get")); if (otmp->unpaid) { struct monst *shkp = shop_keeper(level, *u.ushops); if (shkp) { pline("You damage it, you pay for it!"); bill_dummy_object(otmp); } } if (len > maxelen) { multi = -maxelen; otmp->spe = -3; } else if (len > 1) otmp->spe -= len >> 1; else otmp->spe -= 1; /* Prevent infinite engraving */ } else
int dosit() { static const char *sit_message = "sit on the %s."; register struct trap *trap; register int typ = levl[u.ux][u.uy].typ; if(Levitation) { pline("You're sitting on air."); return 0; } if(OBJ_AT(u.ux, u.uy)) { register struct obj *obj; obj = level.objects[u.ux][u.uy]; You("sit on %s.", the(xname(obj))); if(!Is_box(obj)) pline("It's not very comfortable..."); } else if ((trap = t_at(u.ux, u.uy)) != 0) { if (u.utrap) { exercise(A_WIS, FALSE); /* you're getting stuck longer */ if(u.utraptype == TT_BEARTRAP) { You("can't sit down with your %s in the bear trap.", body_part(FOOT)); u.utrap++; } else if(u.utraptype == TT_PIT) { if(trap->ttyp == SPIKED_PIT) { You("sit down on a spike. Ouch!"); losehp(1, "sitting on an iron spike", KILLED_BY); exercise(A_STR, FALSE); } else You("sit down in the pit."); u.utrap += rn2(5); } else if(u.utraptype == TT_WEB) { You("sit in the spider web and get entangled further!"); u.utrap += rn1(10, 5); } else if(u.utraptype == TT_LAVA) { /* Must have fire resistance or they'd be dead already */ You("sit in the lava!"); u.utrap += rnd(4); losehp(d(2,10), "sitting in lava", KILLED_BY); } else if(u.utraptype == TT_INFLOOR) { You("can't maneuver to sit!"); u.utrap++; } } else { You("sit down."); dotrap(trap); } } else if(Underwater || Is_waterlevel(&u.uz)) { if (Is_waterlevel(&u.uz)) pline("There are no cushions floating nearby."); else You("sit down in the muddy bottom."); } else if(is_pool(u.ux, u.uy)) { You("sit in the water."); if (!rn2(10) && uarm) (void) rust_dmg(uarm, "armor", 1, TRUE); #ifdef POLYSELF /* Note: without POLYSELF, this can't _happen_ without */ /* water walking boots.... */ if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS) (void) rust_dmg(uarm, "armor", 1, TRUE); #endif #ifdef SINKS } else if(IS_SINK(typ)) { You(sit_message, defsyms[S_sink].explanation); Your("%s gets wet.", humanoid(uasmon) ? "rump" : "underside"); #endif } else if(IS_ALTAR(typ)) { You(sit_message, defsyms[S_altar].explanation); altar_wrath(u.ux, u.uy); } else if(typ == STAIRS) { You(sit_message, "stairs"); } else if(typ == LADDER) { You(sit_message, "ladder"); } else if (is_lava(u.ux, u.uy)) { /* must be WWalking */ You(sit_message, "lava"); pline("The lava burns you!"); losehp(d((Fire_resistance ? 2 : 10), 10), "sitting on lava", KILLED_BY); } else if (is_ice(u.ux, u.uy)) { You(sit_message, defsyms[S_ice].explanation); if (!Cold_resistance) pline("The ice feels cold."); } else if (typ == DRAWBRIDGE_DOWN) { You(sit_message, "drawbridge"); } else if(IS_THRONE(typ)) { You(sit_message, defsyms[S_throne].explanation); if (rnd(6) > 4) { switch (rnd(13)) { case 1: (void) adjattrib(rn2(A_MAX), -rn1(4,3), FALSE); losehp(rnd(10), "cursed throne", KILLED_BY_AN); break; case 2: (void) adjattrib(rn2(A_MAX), 1, FALSE); break; case 3: pline("A%s electric shock shoots through your body!", (Shock_resistance) ? "" : " massive"); losehp(Shock_resistance ? rnd(6) : rnd(30), "electric chair", KILLED_BY_AN); exercise(A_CON, FALSE); break; case 4: You("feel much, much better!"); if(u.uhp >= (u.uhpmax - 5)) u.uhpmax += 4; u.uhp = u.uhpmax; make_blinded(0L,TRUE); make_sick(0L,FALSE); heal_legs(); flags.botl = 1; break; case 5: take_gold(); break; case 6: if(u.uluck + rn2(5) < 0) { You("feel your luck is changing."); change_luck(1); } else makewish(); break; case 7: { register int cnt = rnd(10); pline("A voice echoes:"); verbalize("Thy audience hath been summoned, %s!", flags.female ? "Dame" : "Sire"); while(cnt--) (void) makemon(courtmon(), u.ux, u.uy); break; } case 8: pline("A voice echoes:"); verbalize("By thy Imperious order, %s...", flags.female ? "Dame" : "Sire"); do_genocide(1); break; case 9: pline("A voice echoes:"); verbalize("A curse upon thee for sitting upon this most holy throne!"); if (Luck > 0) { make_blinded(Blinded + rn1(100,250),TRUE); } else rndcurse(); break; case 10: if (Luck < 0 || (HSee_invisible & INTRINSIC)) { if (level.flags.nommap) { pline( "A terrible drone fills your head!"); make_confused(HConfusion + rnd(30), FALSE); } else { pline("An image forms in your mind."); do_mapping(); } } else { Your("vision becomes clear."); HSee_invisible |= FROMOUTSIDE; newsym(u.ux, u.uy); } break; case 11: if (Luck < 0) { You("feel threatened."); aggravate(); } else { You("feel a wrenching sensation."); tele(); /* teleport him */ } break; case 12: You("are granted an insight!"); if (invent) { int ret, cval = rn2(5); /* agrees w/seffects() */ /* use up `cval' "charges"; 0 is special case */ do { ret = ggetobj("identify", identify, cval); if (ret < 0) break; /* quit */ } while (ret == 0 || (cval -= ret) > 0); } break; case 13: Your("mind turns into a pretzel!"); make_confused(HConfusion + rn1(7,16),FALSE); break; default: impossible("throne effect"); break; } } else You("feel somehow out of place..."); if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ pline("The throne vanishes in a puff of logic."); levl[u.ux][u.uy].typ = ROOM; if(Invisible) newsym(u.ux,u.uy); } #ifdef POLYSELF } else if (lays_eggs(uasmon) || u.umonnum == PM_QUEEN_BEE) { struct obj *uegg; if (!flags.female) { pline("Males can't lay eggs!"); return 0; } if (u.uhunger < (int)objects[EGG].oc_nutrition) { You("don't have enough energy to lay an egg."); return 0; } uegg = mksobj(EGG, FALSE, FALSE); uegg->spe = 1; uegg->quan = 1; uegg->owt = weight(uegg); uegg->corpsenm = (u.umonnum==PM_QUEEN_BEE ? PM_KILLER_BEE : monsndx(uasmon)); uegg->known = uegg->dknown = 1; You("lay an egg."); dropy(uegg); stackobj(uegg); morehungry((int)objects[EGG].oc_nutrition); #endif } else if (u.uswallow) pline("There are no seats in here!"); else pline("Having fun sitting on the %s?", surface(u.ux,u.uy)); return(1); }
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(); } }