From: Derek S. Ray Date: Sun, 29 Mar 2015 21:32:12 +0000 (-0400) Subject: Merge branch 'master' into derek-farming X-Git-Tag: NetHack-3.6.0_RC01~414^2~41^2~14 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ca60cac1053512fe56b25c4b699a5ea4bc9ed8bc;p=nethack Merge branch 'master' into derek-farming * master: (41 commits) Add more explicit helpless reasons add data.base suggestion for whistle Use existing function to count containers ... Conflicts: src/do.c src/hack.c src/invent.c src/mon.c src/objnam.c --- ca60cac1053512fe56b25c4b699a5ea4bc9ed8bc diff --cc src/do.c index 1fe18d7c5,c690ad4fa..d253af133 --- a/src/do.c +++ b/src/do.c @@@ -1034,382 -1026,383 +1034,383 @@@ boolean at_stairs, falling, portal * -1 11.46 12.50 12.5 * -2 5.21 4.17 0.0 * -3 2.08 0.0 0.0 - */ - if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && - (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) { - if (!rn2(4)) { - int odds = 3 + (int)u.ualign.type, /* 2..4 */ - diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */ - - if (diff != 0) { - assign_rnd_level(newlevel, &u.uz, diff); - /* if inside the tower, stay inside */ - if (was_in_W_tower && - !On_W_tower_level(newlevel)) diff = 0; - } - if (diff == 0) - assign_level(newlevel, &u.uz); - - new_ledger = ledger_no(newlevel); - - pline("A mysterious force momentarily surrounds you..."); - if (on_level(newlevel, &u.uz)) { - (void) safe_teleds(FALSE); - (void) next_to_u(); - return; - } else - at_stairs = at_ladder = FALSE; - } - } + */ + if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && + (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) { + if (!rn2(4)) { + int odds = 3 + (int)u.ualign.type, /* 2..4 */ + diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */ + + if (diff != 0) { + assign_rnd_level(newlevel, &u.uz, diff); + /* if inside the tower, stay inside */ + if (was_in_W_tower && + !On_W_tower_level(newlevel)) diff = 0; + } + if (diff == 0) + assign_level(newlevel, &u.uz); + + new_ledger = ledger_no(newlevel); + + pline("A mysterious force momentarily surrounds you..."); + if (on_level(newlevel, &u.uz)) { + (void) safe_teleds(FALSE); + (void) next_to_u(); + return; + } else + at_stairs = at_ladder = FALSE; + } + } - /* Prevent the player from going past the first quest level unless - * (s)he has been given the go-ahead by the leader. - */ - if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) { - pline("A mysterious force prevents you from descending."); - return; - } + /* Prevent the player from going past the first quest level unless + * (s)he has been given the go-ahead by the leader. + */ + if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) { + pline("A mysterious force prevents you from descending."); + return; + } - if (on_level(newlevel, &u.uz)) return; /* this can happen */ - - /* tethered movement makes level change while trapped feasible */ - if (u.utrap && u.utraptype == TT_BURIEDBALL) - buried_ball_to_punishment(); /* (before we save/leave old level) */ - - fd = currentlevel_rewrite(); - if (fd < 0) return; - - if (falling) /* assuming this is only trap door or hole */ - impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel); - - check_special_room(TRUE); /* probably was a trap door */ - if (Punished) unplacebc(); - u.utrap = 0; /* needed in level_tele */ - fill_pit(u.ux, u.uy); - u.ustuck = 0; /* idem */ - u.uinwater = 0; - u.uundetected = 0; /* not hidden, even if means are available */ - keepdogs(FALSE); - if (u.uswallow) /* idem */ - u.uswldtim = u.uswallow = 0; - recalc_mapseen(); /* recalculate map overview before we leave the level */ - /* - * We no longer see anything on the level. Make sure that this - * follows u.uswallow set to null since uswallow overrides all - * normal vision. - */ - vision_recalc(2); - - /* - * Save the level we're leaving. If we're entering the endgame, - * we can get rid of all existing levels because they cannot be - * reached any more. We still need to use savelev()'s cleanup - * for the level being left, to recover dynamic memory in use and - * to avoid dangling timers and light sources. - */ - cant_go_back = (newdungeon && In_endgame(newlevel)); - if (!cant_go_back) { - update_mlstmv(); /* current monsters are becoming inactive */ - bufon(fd); /* use buffered output */ - } - savelev(fd, ledger_no(&u.uz), - cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE)); - bclose(fd); - if (cant_go_back) { - /* discard unreachable levels; keep #0 */ - for (l_idx = maxledgerno(); l_idx > 0; --l_idx) - delete_levelfile(l_idx); - /* mark #overview data for all dungeon branches as uninteresting */ - for (l_idx = 0; l_idx < n_dgns; ++l_idx) - remdun_mapseen(l_idx); - } + if (on_level(newlevel, &u.uz)) return; /* this can happen */ + + /* tethered movement makes level change while trapped feasible */ + if (u.utrap && u.utraptype == TT_BURIEDBALL) + buried_ball_to_punishment(); /* (before we save/leave old level) */ + + fd = currentlevel_rewrite(); + if (fd < 0) return; + + if (falling) /* assuming this is only trap door or hole */ + impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel); + + check_special_room(TRUE); /* probably was a trap door */ + if (Punished) unplacebc(); + u.utrap = 0; /* needed in level_tele */ + fill_pit(u.ux, u.uy); + u.ustuck = 0; /* idem */ + u.uinwater = 0; + u.uundetected = 0; /* not hidden, even if means are available */ + keepdogs(FALSE); + if (u.uswallow) /* idem */ + u.uswldtim = u.uswallow = 0; + recalc_mapseen(); /* recalculate map overview before we leave the level */ + /* + * We no longer see anything on the level. Make sure that this + * follows u.uswallow set to null since uswallow overrides all + * normal vision. + */ + vision_recalc(2); + + /* + * Save the level we're leaving. If we're entering the endgame, + * we can get rid of all existing levels because they cannot be + * reached any more. We still need to use savelev()'s cleanup + * for the level being left, to recover dynamic memory in use and + * to avoid dangling timers and light sources. + */ + cant_go_back = (newdungeon && In_endgame(newlevel)); + if (!cant_go_back) { + update_mlstmv(); /* current monsters are becoming inactive */ + bufon(fd); /* use buffered output */ + } + savelev(fd, ledger_no(&u.uz), + cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE)); + bclose(fd); + if (cant_go_back) { + /* discard unreachable levels; keep #0 */ + for (l_idx = maxledgerno(); l_idx > 0; --l_idx) + delete_levelfile(l_idx); + /* mark #overview data for all dungeon branches as uninteresting */ + for (l_idx = 0; l_idx < n_dgns; ++l_idx) + remdun_mapseen(l_idx); + } - if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz)) - assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY); + if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz)) + assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY); #ifdef USE_TILES - substitute_tiles(newlevel); + substitute_tiles(newlevel); #endif - /* record this level transition as a potential seen branch unless using - * some non-standard means of transportation (level teleport). - */ - if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum)) - recbranch_mapseen(&u.uz, newlevel); - assign_level(&u.uz0, &u.uz); - assign_level(&u.uz, newlevel); - assign_level(&u.utolev, newlevel); - u.utotype = 0; - if (dunlev_reached(&u.uz) < dunlev(&u.uz)) - dunlev_reached(&u.uz) = dunlev(&u.uz); - reset_rndmonst(NON_PM); /* u.uz change affects monster generation */ - - /* set default level change destination areas */ - /* the special level code may override these */ - (void) memset((genericptr_t) &updest, 0, sizeof updest); - (void) memset((genericptr_t) &dndest, 0, sizeof dndest); - - if (!(level_info[new_ledger].flags & LFILE_EXISTS)) { - /* entering this level for first time; make it now */ - if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) { - impossible("goto_level: returning to discarded level?"); - level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED); - } - mklev(); - new = TRUE; /* made the level */ - } else { - /* returning to previously visited level; reload it */ - fd = open_levelfile(new_ledger, whynot); - if (fd < 0) { - pline1(whynot); - pline("Probably someone removed it."); - Strcpy(killer.name, whynot); - done(TRICKED); - /* we'll reach here if running in wizard mode */ - error("Cannot continue this game."); - } - minit(); /* ZEROCOMP */ - getlev(fd, hackpid, new_ledger, FALSE); - (void) close(fd); - oinit(); /* reassign level dependent obj probabilities */ - } - /* do this prior to level-change pline messages */ - vision_reset(); /* clear old level's line-of-sight */ - vision_full_recalc = 0; /* don't let that reenable vision yet */ - flush_screen(-1); /* ensure all map flushes are postponed */ - - if (portal && !In_endgame(&u.uz)) { - /* find the portal on the new level */ - register struct trap *ttrap; - - for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap) - if (ttrap->ttyp == MAGIC_PORTAL) break; - - if (!ttrap) panic("goto_level: no corresponding portal!"); - seetrap(ttrap); - u_on_newpos(ttrap->tx, ttrap->ty); - } else if (at_stairs && !In_endgame(&u.uz)) { - if (up) { - if (at_ladder) - u_on_newpos(xdnladder, ydnladder); - else if (newdungeon) - u_on_sstairs(1); - else - u_on_dnstairs(); - /* you climb up the {stairs|ladder}; - fly up the stairs; fly up along the ladder */ - pline("%s %s up%s the %s.", - (Punished && !Levitation) ? "With great effort you" : - "You", - Flying ? "fly" : "climb", - (Flying && at_ladder) ? " along" : "", - at_ladder ? "ladder" : "stairs"); - } else { /* down */ - if (at_ladder) - u_on_newpos(xupladder, yupladder); - else if (newdungeon) - u_on_sstairs(0); - else - u_on_upstairs(); - if (!u.dz) { - ; /* stayed on same level? (no transit effects) */ - } else if (Flying) { - if (flags.verbose) - You("fly down %s.", - at_ladder ? "along the ladder" : "the stairs"); - } else if (near_capacity() > UNENCUMBERED || - Punished || Fumbling) { - You("fall down the %s.", at_ladder ? "ladder" : "stairs"); - if (Punished) { - drag_down(); - if (carried(uball)) { - if (uwep == uball) - setuwep((struct obj *)0); - if (uswapwep == uball) - setuswapwep((struct obj *)0); - if (uquiver == uball) - setuqwep((struct obj *)0); - freeinv(uball); - } - } - /* falling off steed has its own losehp() call */ - if (u.usteed) - dismount_steed(DISMOUNT_FELL); - else - losehp(Maybe_Half_Phys(rnd(3)), - at_ladder ? "falling off a ladder" : - "tumbling down a flight of stairs", - KILLED_BY); - selftouch("Falling, you"); - } else { /* ordinary descent */ - if (flags.verbose) - You("%s.", at_ladder ? "climb down the ladder" : - "descend the stairs"); - } - } - } else { /* trap door or level_tele or In_endgame */ - u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0)); - if (falling) { - if (Punished) ballfall(); - selftouch("Falling, you"); - } - } + /* record this level transition as a potential seen branch unless using + * some non-standard means of transportation (level teleport). + */ + if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum)) + recbranch_mapseen(&u.uz, newlevel); + assign_level(&u.uz0, &u.uz); + assign_level(&u.uz, newlevel); + assign_level(&u.utolev, newlevel); + u.utotype = 0; + if (dunlev_reached(&u.uz) < dunlev(&u.uz)) + dunlev_reached(&u.uz) = dunlev(&u.uz); + reset_rndmonst(NON_PM); /* u.uz change affects monster generation */ + + /* set default level change destination areas */ + /* the special level code may override these */ + (void) memset((genericptr_t) &updest, 0, sizeof updest); + (void) memset((genericptr_t) &dndest, 0, sizeof dndest); + + if (!(level_info[new_ledger].flags & LFILE_EXISTS)) { + /* entering this level for first time; make it now */ + if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) { + impossible("goto_level: returning to discarded level?"); + level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED); + } + mklev(); + new = TRUE; /* made the level */ + } else { + /* returning to previously visited level; reload it */ + fd = open_levelfile(new_ledger, whynot); + if (fd < 0) { + pline1(whynot); + pline("Probably someone removed it."); + Strcpy(killer.name, whynot); + done(TRICKED); + /* we'll reach here if running in wizard mode */ + error("Cannot continue this game."); + } + minit(); /* ZEROCOMP */ + getlev(fd, hackpid, new_ledger, FALSE); + (void) close(fd); + oinit(); /* reassign level dependent obj probabilities */ + } + /* do this prior to level-change pline messages */ + vision_reset(); /* clear old level's line-of-sight */ + vision_full_recalc = 0; /* don't let that reenable vision yet */ + flush_screen(-1); /* ensure all map flushes are postponed */ + + if (portal && !In_endgame(&u.uz)) { + /* find the portal on the new level */ + register struct trap *ttrap; + + for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap) + if (ttrap->ttyp == MAGIC_PORTAL) break; + + if (!ttrap) panic("goto_level: no corresponding portal!"); + seetrap(ttrap); + u_on_newpos(ttrap->tx, ttrap->ty); + } else if (at_stairs && !In_endgame(&u.uz)) { + if (up) { + if (at_ladder) + u_on_newpos(xdnladder, ydnladder); + else if (newdungeon) + u_on_sstairs(1); + else + u_on_dnstairs(); + /* you climb up the {stairs|ladder}; + fly up the stairs; fly up along the ladder */ + pline("%s %s up%s the %s.", + (Punished && !Levitation) ? "With great effort you" : + "You", + Flying ? "fly" : "climb", + (Flying && at_ladder) ? " along" : "", + at_ladder ? "ladder" : "stairs"); + } else { /* down */ + if (at_ladder) + u_on_newpos(xupladder, yupladder); + else if (newdungeon) + u_on_sstairs(0); + else + u_on_upstairs(); + if (!u.dz) { + ; /* stayed on same level? (no transit effects) */ + } else if (Flying) { + if (flags.verbose) + You("fly down %s.", + at_ladder ? "along the ladder" : "the stairs"); + } else if (near_capacity() > UNENCUMBERED || + Punished || Fumbling) { + You("fall down the %s.", at_ladder ? "ladder" : "stairs"); + if (Punished) { + drag_down(); + if (carried(uball)) { + if (uwep == uball) + setuwep((struct obj *)0); + if (uswapwep == uball) + setuswapwep((struct obj *)0); + if (uquiver == uball) + setuqwep((struct obj *)0); + freeinv(uball); + } + } + /* falling off steed has its own losehp() call */ + if (u.usteed) + dismount_steed(DISMOUNT_FELL); + else + losehp(Maybe_Half_Phys(rnd(3)), + at_ladder ? "falling off a ladder" : + "tumbling down a flight of stairs", + KILLED_BY); + selftouch("Falling, you"); + } else { /* ordinary descent */ + if (flags.verbose) + You("%s.", at_ladder ? "climb down the ladder" : + "descend the stairs"); + } + } + } else { /* trap door or level_tele or In_endgame */ + u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0)); + if (falling) { + if (Punished) ballfall(); + selftouch("Falling, you"); + } + } - if (Punished) placebc(); - obj_delivery(FALSE); - losedogs(); - kill_genocided_monsters(); /* for those wiped out while in limbo */ - /* - * Expire all timers that have gone off while away. Must be - * after migrating monsters and objects are delivered - * (losedogs and obj_delivery). - */ - run_timers(); - - initrack(); - - if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) { - /* There's a monster at your target destination; it might be one - which accompanied you--see mon_arrive(dogmove.c)--or perhaps - it was already here. Randomly move you to an adjacent spot - or else the monster to any nearby location. Prior to 3.3.0 - the latter was done unconditionally. */ - coord cc; - - if (!rn2(2) && - enexto(&cc, u.ux, u.uy, youmonst.data) && - distu(cc.x, cc.y) <= 2) - u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/ - else - mnexto(mtmp); - - if ((mtmp = m_at(u.ux, u.uy)) != 0) { - /* there was an unconditional impossible("mnearto failed") - here, but it's not impossible and we're prepared to cope - with the situation, so only say something when debugging */ - if (wizard) pline("(monster in hero's way)"); - if (!rloc(mtmp, TRUE)) - /* no room to move it; send it away, to return later */ - migrate_to_level(mtmp, ledger_no(&u.uz), - MIGR_RANDOM, (coord *)0); - } - } + if (Punished) placebc(); + obj_delivery(FALSE); + losedogs(); + kill_genocided_monsters(); /* for those wiped out while in limbo */ + /* + * Expire all timers that have gone off while away. Must be + * after migrating monsters and objects are delivered + * (losedogs and obj_delivery). + */ + run_timers(); + + initrack(); + + if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) { + /* There's a monster at your target destination; it might be one + which accompanied you--see mon_arrive(dogmove.c)--or perhaps + it was already here. Randomly move you to an adjacent spot + or else the monster to any nearby location. Prior to 3.3.0 + the latter was done unconditionally. */ + coord cc; + + if (!rn2(2) && + enexto(&cc, u.ux, u.uy, youmonst.data) && + distu(cc.x, cc.y) <= 2) + u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/ + else + mnexto(mtmp); + + if ((mtmp = m_at(u.ux, u.uy)) != 0) { + /* there was an unconditional impossible("mnearto failed") + here, but it's not impossible and we're prepared to cope + with the situation, so only say something when debugging */ + if (wizard) pline("(monster in hero's way)"); + if (!rloc(mtmp, TRUE)) + /* no room to move it; send it away, to return later */ + migrate_to_level(mtmp, ledger_no(&u.uz), + MIGR_RANDOM, (coord *)0); + } + } - /* initial movement of bubbles just before vision_recalc */ - if (Is_waterlevel(&u.uz)) - movebubbles(); + /* initial movement of bubbles just before vision_recalc */ + if (Is_waterlevel(&u.uz)) + movebubbles(); - if (level_info[new_ledger].flags & FORGOTTEN) { - forget_map(ALL_MAP); /* forget the map */ - forget_traps(); /* forget all traps too */ - familiar = TRUE; - level_info[new_ledger].flags &= ~FORGOTTEN; - } + if (level_info[new_ledger].flags & FORGOTTEN) { + forget_map(ALL_MAP); /* forget the map */ + forget_traps(); /* forget all traps too */ + familiar = TRUE; + level_info[new_ledger].flags &= ~FORGOTTEN; + } - /* Reset the screen. */ - vision_reset(); /* reset the blockages */ - docrt(); /* does a full vision recalc */ - flush_screen(-1); + /* Reset the screen. */ + vision_reset(); /* reset the blockages */ + docrt(); /* does a full vision recalc */ + flush_screen(-1); - /* - * Move all plines beyond the screen reset. - */ + /* + * Move all plines beyond the screen reset. + */ - /* special levels can have a custom arrival message */ - deliver_splev_message(); + /* special levels can have a custom arrival message */ + deliver_splev_message(); - /* give room entrance message, if any */ - check_special_room(FALSE); + /* give room entrance message, if any */ + check_special_room(FALSE); - /* deliver objects traveling with player */ - obj_delivery(TRUE); + /* deliver objects traveling with player */ + obj_delivery(TRUE); - /* Check whether we just entered Gehennom. */ - if (!In_hell(&u.uz0) && Inhell) { - if (Is_valley(&u.uz)) { - You("arrive at the Valley of the Dead..."); - pline_The("odor of burnt flesh and decay pervades the air."); + /* Check whether we just entered Gehennom. */ + if (!In_hell(&u.uz0) && Inhell) { + if (Is_valley(&u.uz)) { + You("arrive at the Valley of the Dead..."); + pline_The("odor of burnt flesh and decay pervades the air."); #ifdef MICRO - display_nhwindow(WIN_MESSAGE, FALSE); + display_nhwindow(WIN_MESSAGE, FALSE); #endif - You_hear("groans and moans everywhere."); - } else pline("It is hot here. You smell smoke..."); + You_hear("groans and moans everywhere."); + } else pline("It is hot here. You smell smoke..."); u.uachieve.enter_gehennom = 1; - } - /* in case we've managed to bypass the Valley's stairway down */ - if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1; - - if (familiar) { - static const char * const fam_msgs[4] = { - "You have a sense of deja vu.", - "You feel like you've been here before.", - "This place %s familiar...", - 0 /* no message */ - }; - static const char * const halu_fam_msgs[4] = { - "Whoa! Everything %s different.", - "You are surrounded by twisty little passages, all alike.", - "Gee, this %s like uncle Conan's place...", - 0 /* no message */ - }; - const char *mesg; - char buf[BUFSZ]; - int which = rn2(4); - - if (Hallucination) - mesg = halu_fam_msgs[which]; - else - mesg = fam_msgs[which]; - if (mesg && index(mesg, '%')) { - Sprintf(buf, mesg, !Blind ? "looks" : "seems"); - mesg = buf; - } - if (mesg) pline1(mesg); - } + } + /* in case we've managed to bypass the Valley's stairway down */ + if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1; + + if (familiar) { + static const char * const fam_msgs[4] = { + "You have a sense of deja vu.", + "You feel like you've been here before.", + "This place %s familiar...", + 0 /* no message */ + }; + static const char * const halu_fam_msgs[4] = { + "Whoa! Everything %s different.", + "You are surrounded by twisty little passages, all alike.", + "Gee, this %s like uncle Conan's place...", + 0 /* no message */ + }; + const char *mesg; + char buf[BUFSZ]; + int which = rn2(4); + + if (Hallucination) + mesg = halu_fam_msgs[which]; + else + mesg = fam_msgs[which]; + if (mesg && index(mesg, '%')) { + Sprintf(buf, mesg, !Blind ? "looks" : "seems"); + mesg = buf; + } + if (mesg) pline1(mesg); + } - /* special location arrival messages/events */ - if (In_endgame(&u.uz)) { - if (new && on_level(&u.uz, &astral_level)) - final_level(); /* guardian angel,&c */ - else if (newdungeon && u.uhave.amulet) - resurrect(); /* force confrontation with Wizard */ - } else if (In_quest(&u.uz)) { - onquest(); /* might be reaching locate|goal level */ - } else if (In_V_tower(&u.uz)) { - if (newdungeon && In_hell(&u.uz0)) - pline_The("heat and smoke are gone."); - } else if (Is_knox(&u.uz)) { - /* alarm stops working once Croesus has died */ - if (new || !mvitals[PM_CROESUS].died) { - You("have penetrated a high security area!"); - pline("An alarm sounds!"); - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) continue; - mtmp->msleeping = 0; - } - } - } else { - if (new && Is_rogue_level(&u.uz)) - You("enter what seems to be an older, more primitive world."); - /* main dungeon message from your quest leader */ - if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && - !(u.uevent.qcompleted || u.uevent.qexpelled || - quest_status.leader_is_dead)) { - if (!u.uevent.qcalled) { - u.uevent.qcalled = 1; - com_pager(2); /* main "leader needs help" message */ - } else { /* reminder message */ - com_pager(Role_if(PM_ROGUE) ? 4 : 3); - } - } - } + /* special location arrival messages/events */ + if (In_endgame(&u.uz)) { + if (new && on_level(&u.uz, &astral_level)) + final_level(); /* guardian angel,&c */ + else if (newdungeon && u.uhave.amulet) + resurrect(); /* force confrontation with Wizard */ + } else if (In_quest(&u.uz)) { + onquest(); /* might be reaching locate|goal level */ + } else if (In_V_tower(&u.uz)) { + if (newdungeon && In_hell(&u.uz0)) + pline_The("heat and smoke are gone."); + } else if (Is_knox(&u.uz)) { + /* alarm stops working once Croesus has died */ + if (new || !mvitals[PM_CROESUS].died) { + You("have penetrated a high security area!"); + pline("An alarm sounds!"); + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + mtmp->msleeping = 0; + } + } + } else { + if (new && Is_rogue_level(&u.uz)) + You("enter what seems to be an older, more primitive world."); + /* main dungeon message from your quest leader */ + if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && + !(u.uevent.qcompleted || u.uevent.qexpelled || + quest_status.leader_is_dead)) { + if (!u.uevent.qcalled) { + u.uevent.qcalled = 1; + com_pager(2); /* main "leader needs help" message */ + } else { /* reminder message */ + com_pager(Role_if(PM_ROGUE) ? 4 : 3); + } + } + } - assign_level(&u.uz0, &u.uz); /* reset u.uz0 */ + assign_level(&u.uz0, &u.uz); /* reset u.uz0 */ #ifdef INSURANCE - save_currentstate(); + save_currentstate(); #endif - /* assume this will always return TRUE when changing level */ - (void) in_out_region(u.ux, u.uy); - (void) pickup(1); + /* assume this will always return TRUE when changing level */ + (void) in_out_region(u.ux, u.uy); + (void) pickup(1); + context.polearm.hitmon = NULL; } STATIC_OVL void diff --cc src/hack.c index 1eb9eac97,32ceb8e69..ef8c90a52 --- a/src/hack.c +++ b/src/hack.c @@@ -1101,490 -1101,491 +1101,491 @@@ struct trap *desttrap; /* nonnull if an void domove() { - register struct monst *mtmp; - register struct rm *tmpr; - register xchar x,y; - struct trap *trap; - int wtcap; - boolean on_ice; - xchar chainx, chainy, ballx, bally; /* ball&chain new positions */ - int bc_control; /* control for ball&chain */ - boolean cause_delay = FALSE; /* dragging ball will skip a move */ - - u_wipe_engr(rnd(5)); - - if (context.travel) { - if (!findtravelpath(FALSE)) - (void) findtravelpath(TRUE); - context.travel1 = 0; - } - - if(((wtcap = near_capacity()) >= OVERLOADED - || (wtcap > SLT_ENCUMBER && - (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) - : (u.uhp < 10 && u.uhp != u.uhpmax)))) - && !Is_airlevel(&u.uz)) { - if(wtcap < OVERLOADED) { - You("don't have enough stamina to move."); - exercise(A_CON, FALSE); - } else - You("collapse under your load."); - nomul(0); - return; - } - if(u.uswallow) { - u.dx = u.dy = 0; - u.ux = x = u.ustuck->mx; - u.uy = y = u.ustuck->my; - mtmp = u.ustuck; - } else { - if (Is_airlevel(&u.uz) && rn2(4) && - !Levitation && !Flying) { - switch(rn2(3)) { - case 0: - You("tumble in place."); - exercise(A_DEX, FALSE); - break; - case 1: - You_cant("control your movements very well."); break; - case 2: - pline("It's hard to walk in thin air."); - exercise(A_DEX, TRUE); - break; - } - return; - } - - /* check slippery ice */ - on_ice = !Levitation && is_ice(u.ux, u.uy); - if (on_ice) { - static int skates = 0; - if (!skates) skates = find_skates(); - if ((uarmf && uarmf->otyp == skates) - || resists_cold(&youmonst) || Flying - || is_floater(youmonst.data) || is_clinger(youmonst.data) - || is_whirly(youmonst.data)) - on_ice = FALSE; - else if (!rn2(Cold_resistance ? 3 : 2)) { - HFumbling |= FROMOUTSIDE; - HFumbling &= ~TIMEOUT; - HFumbling += 1; /* slip on next move */ - } - } - if (!on_ice && (HFumbling & FROMOUTSIDE)) - HFumbling &= ~FROMOUTSIDE; - - x = u.ux + u.dx; - y = u.uy + u.dy; - if(Stunned || (Confusion && !rn2(5))) { - register int tries = 0; - - do { - if(tries++ > 50) { - nomul(0); - return; - } - confdir(); - x = u.ux + u.dx; - y = u.uy + u.dy; - } while(!isok(x, y) || bad_rock(youmonst.data, x, y)); - } - /* turbulence might alter your actual destination */ - if (u.uinwater) { - water_friction(); - if (!u.dx && !u.dy) { - nomul(0); - return; - } - x = u.ux + u.dx; - y = u.uy + u.dy; - } - if(!isok(x, y)) { - nomul(0); - return; - } - if (((trap = t_at(x, y)) && trap->tseen) || - (Blind && !Levitation && !Flying && - !is_clinger(youmonst.data) && - is_pool_or_lava(x, y) && levl[x][y].seenv)) { - if(context.run >= 2) { - nomul(0); - context.move = 0; - return; - } else - nomul(0); - } - - if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) { - if (distu(u.ustuck->mx, u.ustuck->my) > 2) { - /* perhaps it fled (or was teleported or ... ) */ - u.ustuck = 0; - } else if (sticks(youmonst.data)) { - /* When polymorphed into a sticking monster, - * u.ustuck means it's stuck to you, not you to it. - */ - You("release %s.", mon_nam(u.ustuck)); - u.ustuck = 0; - } else { - /* If holder is asleep or paralyzed: - * 37.5% chance of getting away, - * 12.5% chance of waking/releasing it; - * otherwise: - * 7.5% chance of getting away. - * [strength ought to be a factor] - * If holder is tame and there is no conflict, - * guaranteed escape. - */ - switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) { - case 0: case 1: case 2: - pull_free: - You("pull free from %s.", mon_nam(u.ustuck)); - u.ustuck = 0; - break; - case 3: - if (!u.ustuck->mcanmove) { - /* it's free to move on next turn */ - u.ustuck->mfrozen = 1; - u.ustuck->msleeping = 0; - } - /*FALLTHRU*/ - default: - if (u.ustuck->mtame && - !Conflict && !u.ustuck->mconf) - goto pull_free; - You("cannot escape from %s!", mon_nam(u.ustuck)); - nomul(0); - return; - } - } - } - - mtmp = m_at(x,y); - if (mtmp) { - /* Don't attack if you're running, and can see it */ - /* We should never get here if forcefight */ - if (context.run && - ((!Blind && mon_visible(mtmp) && - ((mtmp->m_ap_type != M_AP_FURNITURE && - mtmp->m_ap_type != M_AP_OBJECT) || - Protection_from_shape_changers)) || - sensemon(mtmp))) { - nomul(0); - context.move = 0; - return; - } - } - } - - u.ux0 = u.ux; - u.uy0 = u.uy; - bhitpos.x = x; - bhitpos.y = y; - tmpr = &levl[x][y]; - - /* attack monster */ - if(mtmp) { - nomul(0); - /* only attack if we know it's there */ - /* or if we used the 'F' command to fight blindly */ - /* or if it hides_under, in which case we call attack() to print - * the Wait! message. - * This is different from ceiling hiders, who aren't handled in - * attack(). - */ - - /* If they used a 'm' command, trying to move onto a monster - * prints the below message and wastes a turn. The exception is - * if the monster is unseen and the player doesn't remember an - * invisible monster--then, we fall through to attack() and - * attack_check(), which still wastes a turn, but prints a - * different message and makes the player remember the monster. */ - if(context.nopick && - (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){ - if(mtmp->m_ap_type && !Protection_from_shape_changers - && !sensemon(mtmp)) - stumble_onto_mimic(mtmp); - else if (mtmp->mpeaceful && !Hallucination) - pline("Pardon me, %s.", m_monnam(mtmp)); - else - You("move right into %s.", mon_nam(mtmp)); - return; - } - if(context.forcefight || !mtmp->mundetected || sensemon(mtmp) || - ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) && - !is_safepet(mtmp))){ - /* try to attack; note that it might evade */ - /* also, we don't attack tame when _safepet_ */ - if(attack(mtmp)) return; - } - } - - /* specifying 'F' with no monster wastes a turn */ - if (context.forcefight || - /* remembered an 'I' && didn't use a move command */ - (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) { - struct obj *boulder = sobj_at(BOULDER, x, y); - boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)), - solid = !accessible(x, y); - int glyph = glyph_at(x, y); /* might be monster */ - char buf[BUFSZ]; - - /* if a statue is displayed at the target location, - player is attempting to attack it [and boulder - handlng below is suitable for handling that] */ - if (glyph_is_statue(glyph) || - (Hallucination && glyph_is_monster(glyph))) - boulder = sobj_at(STATUE, x, y); - - /* force fight at boulder/statue or wall/door while wielding - pick: start digging to break the boulder or wall */ - if (context.forcefight && - /* can we dig? */ - uwep && dig_typ(uwep, x, y) && - /* should we dig? */ - !glyph_is_invisible(glyph) && - !glyph_is_monster(glyph)) { - (void)use_pick_axe2(uwep); - return; - } - - if (boulder) - Strcpy(buf, ansimpleoname(boulder)); - else if (solid) - Strcpy(buf, the(defsyms[glyph_to_cmap(glyph)].explanation)); - else if (!Underwater) - Strcpy(buf, "thin air"); - else if (is_pool(x, y)) - Strcpy(buf, "empty water"); - else /* Underwater, targetting non-water */ - Sprintf(buf, "a vacant spot on the %s", surface(x,y)); - You("%s%s %s.", - !(boulder || solid) ? "" : - !explo ? "harmlessly " : "futilely ", - explo ? "explode at" : "attack", - buf); - unmap_object(x, y); /* known empty -- remove 'I' if present */ - if (boulder) map_object(boulder, TRUE); - newsym(x, y); - nomul(0); - if (explo) { - wake_nearby(); - u.mh = -1; /* dead in the current form */ - rehumanize(); - } - return; - } - if (glyph_is_invisible(levl[x][y].glyph)) { - unmap_object(x, y); - newsym(x, y); - } - /* not attacking an animal, so we try to move */ - if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) { - nomul(0); - return; - } - if(!youmonst.data->mmove) { - You("are rooted %s.", - Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? - "in place" : "to the ground"); - nomul(0); - return; - } - if(u.utrap) { - if (!trapmove(x, y, trap)) return; - } - - if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) { - context.move = 0; - nomul(0); - return; - } - - /* Move ball and chain. */ - if (Punished) - if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy, - &cause_delay, TRUE)) - return; - - /* Check regions entering/leaving */ - if (!in_out_region(x,y)) - return; - - /* now move the hero */ - mtmp = m_at(x, y); - u.ux += u.dx; - u.uy += u.dy; - /* Move your steed, too */ - if (u.usteed) { - u.usteed->mx = u.ux; - u.usteed->my = u.uy; - exercise_steed(); - } - - /* - * If safepet at destination then move the pet to the hero's - * previous location using the same conditions as in attack(). - * there are special extenuating circumstances: - * (1) if the pet dies then your god angers, - * (2) if the pet gets trapped then your god may disapprove, - * (3) if the pet was already trapped and you attempt to free it - * not only do you encounter the trap but you may frighten your - * pet causing it to go wild! moral: don't abuse this privilege. - * - * Ceiling-hiding pets are skipped by this section of code, to - * be caught by the normal falling-monster code. - */ - if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) { - /* if trapped, there's a chance the pet goes wild */ - if (mtmp->mtrapped) { - if (!rn2(mtmp->mtame)) { - mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0; - if (mtmp->mleashed) m_unleash(mtmp, TRUE); - growl(mtmp); - } else { - yelp(mtmp); - } - } - mtmp->mundetected = 0; - if (mtmp->m_ap_type) seemimic(mtmp); - else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); - - if (mtmp->mtrapped && - (trap = t_at(mtmp->mx, mtmp->my)) != 0 && - (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && - sobj_at(BOULDER, trap->tx, trap->ty)) { - /* can't swap places with pet pinned in a pit by a boulder */ - u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ - } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { - /* can't swap places when pet can't move to your spot */ - u.ux = u.ux0, u.uy = u.uy0; - You("stop. %s can't move diagonally.", - upstart(y_monnam(mtmp))); - } else if (u.ux0 != x && u.uy0 != y && - bad_rock(mtmp->data, x, u.uy0) && - bad_rock(mtmp->data, u.ux0, y) && - (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { - /* can't swap places when pet won't fit thru the opening */ - u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ - You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); - } else { - char pnambuf[BUFSZ]; - - /* save its current description in case of polymorph */ - Strcpy(pnambuf, y_monnam(mtmp)); - mtmp->mtrapped = 0; - remove_monster(x, y); - place_monster(mtmp, u.ux0, u.uy0); - newsym(x, y); - newsym(u.ux0, u.uy0); - - You("%s %s.", mtmp->mtame ? "swap places with" : "frighten", - pnambuf); - - /* check for displacing it into pools and traps */ - switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { - case 0: - break; - case 1: /* trapped */ - case 3: /* changed levels */ - /* there's already been a trap message, reinforce it */ - abuse_dog(mtmp); - adjalign(-3); - break; - case 2: - /* drowned or died... - * you killed your pet by direct action, so get experience - * and possibly penalties; - * we want the level gain message, if it happens, to occur - * before the guilt message below - */ - { - /* minliquid() and mintrap() call mondead() rather than - killed() so we duplicate some of the latter here */ - int tmp, mndx; - - u.uconduct.killer++; - mndx = monsndx(mtmp->data); - tmp = experience(mtmp, (int)mvitals[mndx].died); - more_experienced(tmp, 0); - newexplevel(); /* will decide if you go up */ - } - /* That's no way to treat a pet! Your god gets angry. - * - * [This has always been pretty iffy. Why does your - * patron deity care at all, let alone enough to get mad?] - */ - if (rn2(4)) { - You_feel("guilty about losing your pet like this."); - u.ugangr++; - adjalign(-15); - } - break; - default: - pline("that's strange, unknown mintrap result!"); - break; - } - } - } - - reset_occupations(); - if (context.run) { - if ( context.run < 8 ) - if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) || - IS_FURNITURE(tmpr->typ)) - nomul(0); - } - - if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) || - u.dx || u.dy) - (void) hideunder(&youmonst); - - /* - * Mimics (or whatever) become noticeable if they move and are - * imitating something that doesn't move. We could extend this - * to non-moving monsters... - */ - if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT - || youmonst.m_ap_type == M_AP_FURNITURE)) - youmonst.m_ap_type = M_AP_NOTHING; - - check_leash(u.ux0,u.uy0); - - if(u.ux0 != u.ux || u.uy0 != u.uy) { - u.umoved = TRUE; - /* Clean old position -- vision_recalc() will print our new one. */ - newsym(u.ux0,u.uy0); - /* Since the hero has moved, adjust what can be seen/unseen. */ - vision_recalc(1); /* Do the work now in the recover time. */ - invocation_message(); - } - - if (Punished) /* put back ball and chain */ - move_bc(0,bc_control,ballx,bally,chainx,chainy); - - spoteffects(TRUE); - - /* delay next move because of ball dragging */ - /* must come after we finished picking up, in spoteffects() */ - if (cause_delay) { - nomul(-2); + register struct monst *mtmp; + register struct rm *tmpr; + register xchar x,y; + struct trap *trap = NULL; + int wtcap; + boolean on_ice; + xchar chainx, chainy, ballx, bally; /* ball&chain new positions */ + int bc_control; /* control for ball&chain */ + boolean cause_delay = FALSE; /* dragging ball will skip a move */ + + u_wipe_engr(rnd(5)); + + if (context.travel) { + if (!findtravelpath(FALSE)) + (void) findtravelpath(TRUE); + context.travel1 = 0; + } + + if(((wtcap = near_capacity()) >= OVERLOADED + || (wtcap > SLT_ENCUMBER && + (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) + : (u.uhp < 10 && u.uhp != u.uhpmax)))) + && !Is_airlevel(&u.uz)) { + if(wtcap < OVERLOADED) { + You("don't have enough stamina to move."); + exercise(A_CON, FALSE); + } else + You("collapse under your load."); + nomul(0); + return; + } + if(u.uswallow) { + u.dx = u.dy = 0; + u.ux = x = u.ustuck->mx; + u.uy = y = u.ustuck->my; + mtmp = u.ustuck; + } else { + if (Is_airlevel(&u.uz) && rn2(4) && + !Levitation && !Flying) { + switch(rn2(3)) { + case 0: + You("tumble in place."); + exercise(A_DEX, FALSE); + break; + case 1: + You_cant("control your movements very well."); break; + case 2: + pline("It's hard to walk in thin air."); + exercise(A_DEX, TRUE); + break; + } + return; + } + + /* check slippery ice */ + on_ice = !Levitation && is_ice(u.ux, u.uy); + if (on_ice) { + static int skates = 0; + if (!skates) skates = find_skates(); + if ((uarmf && uarmf->otyp == skates) + || resists_cold(&youmonst) || Flying + || is_floater(youmonst.data) || is_clinger(youmonst.data) + || is_whirly(youmonst.data)) + on_ice = FALSE; + else if (!rn2(Cold_resistance ? 3 : 2)) { + HFumbling |= FROMOUTSIDE; + HFumbling &= ~TIMEOUT; + HFumbling += 1; /* slip on next move */ + } + } + if (!on_ice && (HFumbling & FROMOUTSIDE)) + HFumbling &= ~FROMOUTSIDE; + + x = u.ux + u.dx; + y = u.uy + u.dy; + if(Stunned || (Confusion && !rn2(5))) { + register int tries = 0; + + do { + if(tries++ > 50) { + nomul(0); + return; + } + confdir(); + x = u.ux + u.dx; + y = u.uy + u.dy; + } while(!isok(x, y) || bad_rock(youmonst.data, x, y)); + } + /* turbulence might alter your actual destination */ + if (u.uinwater) { + water_friction(); + if (!u.dx && !u.dy) { + nomul(0); + return; + } + x = u.ux + u.dx; + y = u.uy + u.dy; + } + if(!isok(x, y)) { + nomul(0); + return; + } + if (((trap = t_at(x, y)) && trap->tseen) || + (Blind && !Levitation && !Flying && + !is_clinger(youmonst.data) && + is_pool_or_lava(x, y) && levl[x][y].seenv)) { + if(context.run >= 2) { + nomul(0); + context.move = 0; + return; + } else + nomul(0); + } + + if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) { + if (distu(u.ustuck->mx, u.ustuck->my) > 2) { + /* perhaps it fled (or was teleported or ... ) */ + u.ustuck = 0; + } else if (sticks(youmonst.data)) { + /* When polymorphed into a sticking monster, + * u.ustuck means it's stuck to you, not you to it. + */ + You("release %s.", mon_nam(u.ustuck)); + u.ustuck = 0; + } else { + /* If holder is asleep or paralyzed: + * 37.5% chance of getting away, + * 12.5% chance of waking/releasing it; + * otherwise: + * 7.5% chance of getting away. + * [strength ought to be a factor] + * If holder is tame and there is no conflict, + * guaranteed escape. + */ + switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) { + case 0: case 1: case 2: + pull_free: + You("pull free from %s.", mon_nam(u.ustuck)); + u.ustuck = 0; + break; + case 3: + if (!u.ustuck->mcanmove) { + /* it's free to move on next turn */ + u.ustuck->mfrozen = 1; + u.ustuck->msleeping = 0; + } + /*FALLTHRU*/ + default: + if (u.ustuck->mtame && + !Conflict && !u.ustuck->mconf) + goto pull_free; + You("cannot escape from %s!", mon_nam(u.ustuck)); + nomul(0); + return; + } + } + } + + mtmp = m_at(x,y); + if (mtmp) { + /* Don't attack if you're running, and can see it */ + /* We should never get here if forcefight */ + if (context.run && + ((!Blind && mon_visible(mtmp) && + ((mtmp->m_ap_type != M_AP_FURNITURE && + mtmp->m_ap_type != M_AP_OBJECT) || + Protection_from_shape_changers)) || + sensemon(mtmp))) { + nomul(0); + context.move = 0; + return; + } + } + } + + u.ux0 = u.ux; + u.uy0 = u.uy; + bhitpos.x = x; + bhitpos.y = y; + tmpr = &levl[x][y]; + + /* attack monster */ + if(mtmp) { + nomul(0); + /* only attack if we know it's there */ + /* or if we used the 'F' command to fight blindly */ + /* or if it hides_under, in which case we call attack() to print + * the Wait! message. + * This is different from ceiling hiders, who aren't handled in + * attack(). + */ + + /* If they used a 'm' command, trying to move onto a monster + * prints the below message and wastes a turn. The exception is + * if the monster is unseen and the player doesn't remember an + * invisible monster--then, we fall through to attack() and + * attack_check(), which still wastes a turn, but prints a + * different message and makes the player remember the monster. */ + if(context.nopick && + (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){ + if(mtmp->m_ap_type && !Protection_from_shape_changers + && !sensemon(mtmp)) + stumble_onto_mimic(mtmp); + else if (mtmp->mpeaceful && !Hallucination) + pline("Pardon me, %s.", m_monnam(mtmp)); + else + You("move right into %s.", mon_nam(mtmp)); + return; + } + if(context.forcefight || !mtmp->mundetected || sensemon(mtmp) || + ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) && + !is_safepet(mtmp))){ + /* try to attack; note that it might evade */ + /* also, we don't attack tame when _safepet_ */ + if(attack(mtmp)) return; + } + } + + /* specifying 'F' with no monster wastes a turn */ + if (context.forcefight || + /* remembered an 'I' && didn't use a move command */ + (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) { + struct obj *boulder = sobj_at(BOULDER, x, y); + boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)), + solid = !accessible(x, y); + int glyph = glyph_at(x, y); /* might be monster */ + char buf[BUFSZ]; + + /* if a statue is displayed at the target location, + player is attempting to attack it [and boulder + handlng below is suitable for handling that] */ + if (glyph_is_statue(glyph) || + (Hallucination && glyph_is_monster(glyph))) + boulder = sobj_at(STATUE, x, y); + + /* force fight at boulder/statue or wall/door while wielding + pick: start digging to break the boulder or wall */ + if (context.forcefight && + /* can we dig? */ + uwep && dig_typ(uwep, x, y) && + /* should we dig? */ + !glyph_is_invisible(glyph) && + !glyph_is_monster(glyph)) { + (void)use_pick_axe2(uwep); + return; + } + + if (boulder) + Strcpy(buf, ansimpleoname(boulder)); + else if (solid) + Strcpy(buf, the(defsyms[glyph_to_cmap(glyph)].explanation)); + else if (!Underwater) + Strcpy(buf, "thin air"); + else if (is_pool(x, y)) + Strcpy(buf, "empty water"); + else /* Underwater, targetting non-water */ + Sprintf(buf, "a vacant spot on the %s", surface(x,y)); + You("%s%s %s.", + !(boulder || solid) ? "" : + !explo ? "harmlessly " : "futilely ", + explo ? "explode at" : "attack", + buf); + unmap_object(x, y); /* known empty -- remove 'I' if present */ + if (boulder) map_object(boulder, TRUE); + newsym(x, y); + nomul(0); + if (explo) { + wake_nearby(); + u.mh = -1; /* dead in the current form */ + rehumanize(); + } + return; + } + if (glyph_is_invisible(levl[x][y].glyph)) { + unmap_object(x, y); + newsym(x, y); + } + /* not attacking an animal, so we try to move */ + if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) { + nomul(0); + return; + } + if(!youmonst.data->mmove) { + You("are rooted %s.", + Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? + "in place" : "to the ground"); + nomul(0); + return; + } + if(u.utrap) { + if (!trapmove(x, y, trap)) return; + } + + if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) { + context.move = 0; + nomul(0); + return; + } + + /* Move ball and chain. */ + if (Punished) + if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy, + &cause_delay, TRUE)) + return; + + /* Check regions entering/leaving */ + if (!in_out_region(x,y)) + return; + + /* now move the hero */ + mtmp = m_at(x, y); + u.ux += u.dx; + u.uy += u.dy; + /* Move your steed, too */ + if (u.usteed) { + u.usteed->mx = u.ux; + u.usteed->my = u.uy; + exercise_steed(); + } + + /* + * If safepet at destination then move the pet to the hero's + * previous location using the same conditions as in attack(). + * there are special extenuating circumstances: + * (1) if the pet dies then your god angers, + * (2) if the pet gets trapped then your god may disapprove, + * (3) if the pet was already trapped and you attempt to free it + * not only do you encounter the trap but you may frighten your + * pet causing it to go wild! moral: don't abuse this privilege. + * + * Ceiling-hiding pets are skipped by this section of code, to + * be caught by the normal falling-monster code. + */ + if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) { + /* if trapped, there's a chance the pet goes wild */ + if (mtmp->mtrapped) { + if (!rn2(mtmp->mtame)) { + mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0; + if (mtmp->mleashed) m_unleash(mtmp, TRUE); + growl(mtmp); + } else { + yelp(mtmp); + } + } + mtmp->mundetected = 0; + if (mtmp->m_ap_type) seemimic(mtmp); + else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); + + if (mtmp->mtrapped && + (trap = t_at(mtmp->mx, mtmp->my)) != 0 && + (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && + sobj_at(BOULDER, trap->tx, trap->ty)) { + /* can't swap places with pet pinned in a pit by a boulder */ + u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ + } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { + /* can't swap places when pet can't move to your spot */ + u.ux = u.ux0, u.uy = u.uy0; + You("stop. %s can't move diagonally.", + upstart(y_monnam(mtmp))); + } else if (u.ux0 != x && u.uy0 != y && + bad_rock(mtmp->data, x, u.uy0) && + bad_rock(mtmp->data, u.ux0, y) && + (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { + /* can't swap places when pet won't fit thru the opening */ + u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ + You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); + } else { + char pnambuf[BUFSZ]; + + /* save its current description in case of polymorph */ + Strcpy(pnambuf, y_monnam(mtmp)); + mtmp->mtrapped = 0; + remove_monster(x, y); + place_monster(mtmp, u.ux0, u.uy0); + newsym(x, y); + newsym(u.ux0, u.uy0); + + You("%s %s.", mtmp->mtame ? "swap places with" : "frighten", + pnambuf); + + /* check for displacing it into pools and traps */ + switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { + case 0: + break; + case 1: /* trapped */ + case 3: /* changed levels */ + /* there's already been a trap message, reinforce it */ + abuse_dog(mtmp); + adjalign(-3); + break; + case 2: + /* drowned or died... + * you killed your pet by direct action, so get experience + * and possibly penalties; + * we want the level gain message, if it happens, to occur + * before the guilt message below + */ + { + /* minliquid() and mintrap() call mondead() rather than + killed() so we duplicate some of the latter here */ + int tmp, mndx; + + u.uconduct.killer++; + mndx = monsndx(mtmp->data); + tmp = experience(mtmp, (int)mvitals[mndx].died); + more_experienced(tmp, 0); + newexplevel(); /* will decide if you go up */ + } + /* That's no way to treat a pet! Your god gets angry. + * + * [This has always been pretty iffy. Why does your + * patron deity care at all, let alone enough to get mad?] + */ + if (rn2(4)) { + You_feel("guilty about losing your pet like this."); + u.ugangr++; + adjalign(-15); + } + break; + default: + pline("that's strange, unknown mintrap result!"); + break; + } + } + } + + reset_occupations(); + if (context.run) { + if ( context.run < 8 ) + if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) || + IS_FURNITURE(tmpr->typ)) + nomul(0); + } + + if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) || + u.dx || u.dy) + (void) hideunder(&youmonst); + + /* + * Mimics (or whatever) become noticeable if they move and are + * imitating something that doesn't move. We could extend this + * to non-moving monsters... + */ + if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT + || youmonst.m_ap_type == M_AP_FURNITURE)) + youmonst.m_ap_type = M_AP_NOTHING; + + check_leash(u.ux0,u.uy0); + + if(u.ux0 != u.ux || u.uy0 != u.uy) { + u.umoved = TRUE; + /* Clean old position -- vision_recalc() will print our new one. */ + newsym(u.ux0,u.uy0); + /* Since the hero has moved, adjust what can be seen/unseen. */ + vision_recalc(1); /* Do the work now in the recover time. */ + invocation_message(); + } + + if (Punished) /* put back ball and chain */ + move_bc(0,bc_control,ballx,bally,chainx,chainy); + + spoteffects(TRUE); + + /* delay next move because of ball dragging */ + /* must come after we finished picking up, in spoteffects() */ + if (cause_delay) { + nomul(-2); + multi_reason = "dragging an iron ball"; - nomovemsg = ""; - } - - if (context.run && flags.runmode != RUN_TPORT) { - /* display every step or every 7th step depending upon mode */ - if (flags.runmode != RUN_LEAP || !(moves % 7L)) { - if (flags.time) context.botl = 1; - curs_on_u(); - delay_output(); - if (flags.runmode == RUN_CRAWL) { - delay_output(); - delay_output(); - delay_output(); - delay_output(); - } - } - } + nomovemsg = ""; + } + + if (context.run && flags.runmode != RUN_TPORT) { + /* display every step or every 7th step depending upon mode */ + if (flags.runmode != RUN_LEAP || !(moves % 7L)) { + if (flags.time) context.botl = 1; + curs_on_u(); + delay_output(); + if (flags.runmode == RUN_CRAWL) { + delay_output(); + delay_output(); + delay_output(); + delay_output(); + } + } + } } /* combat increases metabolism */ @@@ -2165,64 -2166,76 +2166,76 @@@ register boolean newlev int dopickup() { - int count; - struct trap *traphere = t_at(u.ux, u.uy); - /* awful kludge to work around parse()'s pre-decrement */ - count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0; - multi = 0; /* always reset */ - /* uswallow case added by GAN 01/29/87 */ - if(u.uswallow) { - if (!u.ustuck->minvent) { - if (is_animal(u.ustuck->data)) { - You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck))); - pline("But it's kind of slimy, so you drop it."); - } else - You("don't %s anything in here to pick up.", - Blind ? "feel" : "see"); - return(1); - } else { - int tmpcount = -count; - return loot_mon(u.ustuck, &tmpcount, (boolean *)0); - } - } - if(is_pool(u.ux, u.uy)) { - if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) - || (Flying && !Breathless)) { - You("cannot dive into the water to pick things up."); - return(0); - } else if (!Underwater) { - You_cant("even see the bottom, let alone pick up %s.", - something); - return(0); - } - } - if (is_lava(u.ux, u.uy)) { - if (Wwalking || is_floater(youmonst.data) || - is_clinger(youmonst.data) || (Flying && !Breathless)) { - You_cant("reach the bottom to pick things up."); - return(0); - } else if (!likes_lava(youmonst.data)) { - You("would burn to a crisp trying to pick things up."); - return(0); - } - } - if (!OBJ_AT(u.ux, u.uy)) { + int count; + struct trap *traphere = t_at(u.ux, u.uy); + /* awful kludge to work around parse()'s pre-decrement */ + count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0; + multi = 0; /* always reset */ + /* uswallow case added by GAN 01/29/87 */ + if(u.uswallow) { + if (!u.ustuck->minvent) { + if (is_animal(u.ustuck->data)) { + You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck))); + pline("But it's kind of slimy, so you drop it."); + } else + You("don't %s anything in here to pick up.", + Blind ? "feel" : "see"); + return(1); + } else { + int tmpcount = -count; + return loot_mon(u.ustuck, &tmpcount, (boolean *)0); + } + } + if(is_pool(u.ux, u.uy)) { + if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) + || (Flying && !Breathless)) { + You("cannot dive into the water to pick things up."); + return(0); + } else if (!Underwater) { + You_cant("even see the bottom, let alone pick up %s.", + something); + return(0); + } + } + if (is_lava(u.ux, u.uy)) { + if (Wwalking || is_floater(youmonst.data) || + is_clinger(youmonst.data) || (Flying && !Breathless)) { + You_cant("reach the bottom to pick things up."); + return(0); + } else if (!likes_lava(youmonst.data)) { + You("would burn to a crisp trying to pick things up."); + return(0); + } + } + if (!OBJ_AT(u.ux, u.uy)) { - There("is nothing here to pick up."); + register struct rm *lev = &levl[u.ux][u.uy]; + if (IS_THRONE(lev->typ)) + pline("It must weigh%s a ton!", + lev->looted ? " almost" : ""); + else if (IS_SINK(lev->typ)) + pline_The("plumbing connects it to the floor."); + else if (IS_GRAVE(lev->typ)) + You("don't need a gravestone. Yet."); + else if (IS_FOUNTAIN(lev->typ)) + You("could drink the water..."); + else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN)) + pline("It won't come off the hinges."); + else There("is nothing here to pick up."); - return 0; - } - if (!can_reach_floor(TRUE)) { - if (traphere && uteetering_at_seen_pit(traphere)) - You("cannot reach the bottom of the pit."); - else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) - rider_cant_reach(); - else if (Blind && !can_reach_floor(TRUE)) - You("cannot reach anything here."); - else - You("cannot reach the %s.", surface(u.ux,u.uy)); - return 0; - } - - return (pickup(-count)); + return 0; + } + if (!can_reach_floor(TRUE)) { + if (traphere && uteetering_at_seen_pit(traphere)) + You("cannot reach the bottom of the pit."); + else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) + rider_cant_reach(); + else if (Blind && !can_reach_floor(TRUE)) + You("cannot reach anything here."); + else + You("cannot reach the %s.", surface(u.ux,u.uy)); + return 0; + } + + return (pickup(-count)); } /* stop running if we see something interesting */ @@@ -2416,13 -2429,14 +2429,14 @@@ monster_nearby( void nomul(nval) - register int nval; + register int nval; { - if(multi < nval) return; /* This is a bug fix by ab@unido */ - u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */ - u.usleep = 0; - multi = nval; + if(multi < nval) return; /* This is a bug fix by ab@unido */ + u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */ + u.usleep = 0; + multi = nval; + if (nval == 0) multi_reason = NULL; - context.travel = context.travel1 = context.mv = context.run = 0; + context.travel = context.travel1 = context.mv = context.run = 0; } /* called when a non-movement, multi-turn action has completed */ @@@ -2430,14 -2444,15 +2444,15 @@@ voi unmul(msg_override) const char *msg_override; { - multi = 0; /* caller will usually have done this already */ - if (msg_override) nomovemsg = msg_override; - else if (!nomovemsg) nomovemsg = You_can_move_again; - if (*nomovemsg) pline1(nomovemsg); - nomovemsg = 0; - u.usleep = 0; + multi = 0; /* caller will usually have done this already */ + if (msg_override) nomovemsg = msg_override; + else if (!nomovemsg) nomovemsg = You_can_move_again; + if (*nomovemsg) pline1(nomovemsg); + nomovemsg = 0; + u.usleep = 0; + multi_reason = NULL; - if (afternmv) (*afternmv)(); - afternmv = 0; + if (afternmv) (*afternmv)(); + afternmv = 0; } STATIC_OVL void diff --cc src/invent.c index 1a6e7673e,2cc9e9004..f1a38683a --- a/src/invent.c +++ b/src/invent.c @@@ -765,225 -753,225 +765,225 @@@ struct obj getobj(let,word) register const char *let,*word; { - register struct obj *otmp; - register char ilet; - char buf[BUFSZ], qbuf[QBUFSZ]; - char lets[BUFSZ], altlets[BUFSZ], *ap; - register int foo = 0; - register char *bp = buf; - xchar allowcnt = 0; /* 0, 1 or 2 */ - struct obj *firstobj = invent; - boolean usegold = FALSE; /* can't use gold because its illegal */ - boolean allowall = FALSE; - boolean allownone = FALSE; - boolean useboulder = FALSE; - xchar foox = 0; - long cnt, prevcnt; - boolean prezero; - long dummymask; - - if(*let == ALLOW_COUNT) let++, allowcnt = 1; - if(*let == COIN_CLASS) let++, usegold = TRUE; - - /* Equivalent of an "ugly check" for gold */ - if (usegold && !strcmp(word, "eat") && - (!metallivorous(youmonst.data) - || youmonst.data == &mons[PM_RUST_MONSTER])) - usegold = FALSE; - - if(*let == ALL_CLASSES) let++, allowall = TRUE; - if(*let == ALLOW_NONE) let++, allownone = TRUE; - /* "ugly check" for reading fortune cookies, part 1 */ - /* The normal 'ugly check' keeps the object on the inventory list. - * We don't want to do that for shirts/cookies, so the check for - * them is handled a bit differently (and also requires that we set - * allowall in the caller) - */ - if(allowall && !strcmp(word, "read")) allowall = FALSE; - - /* another ugly check: show boulders (not statues) */ - if(*let == WEAPON_CLASS && - !strcmp(word, "throw") && throws_rocks(youmonst.data)) - useboulder = TRUE; - - if(allownone) *bp++ = '-'; - if(bp > buf && bp[-1] == '-') *bp++ = ' '; - ap = altlets; - - if (!flags.invlet_constant) reassign(); - - for (otmp = firstobj; otmp; otmp = otmp->nobj) { - if (&bp[foo] == &buf[sizeof buf - 1] || - ap == &altlets[sizeof altlets - 1]) { - /* we must have a huge number of NOINVSYM items somehow */ - impossible("getobj: inventory overflow"); - break; - } + register struct obj *otmp; + register char ilet; + char buf[BUFSZ], qbuf[QBUFSZ]; + char lets[BUFSZ], altlets[BUFSZ], *ap; + register int foo = 0; + register char *bp = buf; + xchar allowcnt = 0; /* 0, 1 or 2 */ + struct obj *firstobj = invent; + boolean usegold = FALSE; /* can't use gold because its illegal */ + boolean allowall = FALSE; + boolean allownone = FALSE; + boolean useboulder = FALSE; + xchar foox = 0; + long cnt, prevcnt; + boolean prezero; + long dummymask; + + if(*let == ALLOW_COUNT) let++, allowcnt = 1; + if(*let == COIN_CLASS) let++, usegold = TRUE; + + /* Equivalent of an "ugly check" for gold */ + if (usegold && !strcmp(word, "eat") && + (!metallivorous(youmonst.data) + || youmonst.data == &mons[PM_RUST_MONSTER])) + usegold = FALSE; + + if(*let == ALL_CLASSES) let++, allowall = TRUE; + if(*let == ALLOW_NONE) let++, allownone = TRUE; + /* "ugly check" for reading fortune cookies, part 1 */ + /* The normal 'ugly check' keeps the object on the inventory list. + * We don't want to do that for shirts/cookies, so the check for + * them is handled a bit differently (and also requires that we set + * allowall in the caller) + */ + if(allowall && !strcmp(word, "read")) allowall = FALSE; + + /* another ugly check: show boulders (not statues) */ + if(*let == WEAPON_CLASS && + !strcmp(word, "throw") && throws_rocks(youmonst.data)) + useboulder = TRUE; + + if(allownone) *bp++ = '-'; + if(bp > buf && bp[-1] == '-') *bp++ = ' '; + ap = altlets; + + if (!flags.invlet_constant) reassign(); - if (!*let || index(let, otmp->oclass) - || (usegold && otmp->invlet == GOLD_SYM) - || (useboulder && otmp->otyp == BOULDER) - ) { - register int otyp = otmp->otyp; - bp[foo++] = otmp->invlet; - - /* ugly check: remove inappropriate things */ - if ((taking_off(word) && - !(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) - || (putting_on(word) && - (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) - /* already worn */ + for (otmp = firstobj; otmp; otmp = otmp->nobj) { + if (&bp[foo] == &buf[sizeof buf - 1] || + ap == &altlets[sizeof altlets - 1]) { + /* we must have a huge number of NOINVSYM items somehow */ + impossible("getobj: inventory overflow"); + break; + } + + if (!*let || index(let, otmp->oclass) + || (usegold && otmp->invlet == GOLD_SYM) + || (useboulder && otmp->otyp == BOULDER) + ) { + register int otyp = otmp->otyp; + bp[foo++] = otmp->invlet; + + /* ugly check: remove inappropriate things */ + if ((taking_off(word) && + !(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) + || (putting_on(word) && + (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) + /* already worn */ #if 0 /* 3.4.1 -- include currently wielded weapon among the choices */ - || (!strcmp(word, "wield") && - (otmp->owornmask & W_WEP)) + || (!strcmp(word, "wield") && + (otmp->owornmask & W_WEP)) #endif - || (!strcmp(word, "ready") && - (otmp == uwep || (otmp == uswapwep && u.twoweap))) - || ((!strcmp(word, "dip") || !strcmp(word, "grease")) && - inaccessible_equipment(otmp, (const char *)0 , FALSE)) - ) { - foo--; - foox++; - } - - /* Second ugly check; unlike the first it won't trigger an - * "else" in "you don't have anything else to ___". - */ - else if ((putting_on(word) && - ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) || - (otmp->oclass == TOOL_CLASS && - otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES))) - || (!strcmp(word, "wield") && - (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) - || (!strcmp(word, "eat") && !is_edible(otmp)) - || (!strcmp(word, "sacrifice") && - (otyp != CORPSE && - otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR)) - || (!strcmp(word, "write with") && - (otmp->oclass == TOOL_CLASS && - otyp != MAGIC_MARKER && otyp != TOWEL)) - || (!strcmp(word, "tin") && - (otyp != CORPSE || !tinnable(otmp))) - || (!strcmp(word, "rub") && - ((otmp->oclass == TOOL_CLASS && - otyp != OIL_LAMP && otyp != MAGIC_LAMP && - otyp != BRASS_LANTERN) || - (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) - || ((!strcmp(word, "use or apply") || - !strcmp(word, "untrap with")) && - /* Picks, axes, pole-weapons, bullwhips */ - ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) && - !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) || - (otmp->oclass == POTION_CLASS && - /* only applicable potion is oil, and it will only - be offered as a choice when already discovered */ - (otyp != POT_OIL || !otmp->dknown || - !objects[POT_OIL].oc_name_known)) || - (otmp->oclass == FOOD_CLASS && - otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) || - (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) - || (!strcmp(word, "invoke") && - (!otmp->oartifact && !objects[otyp].oc_unique && - (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) && - otyp != CRYSTAL_BALL && /* #invoke synonym for apply */ - /* note: presenting the possibility of invoking non-artifact - mirrors and/or lamps is a simply a cruel deception... */ - otyp != MIRROR && otyp != MAGIC_LAMP && - (otyp != OIL_LAMP || /* don't list known oil lamp */ - (otmp->dknown && objects[OIL_LAMP].oc_name_known)))) - || (!strcmp(word, "untrap with") && - (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)) - || (!strcmp(word, "tip") && !Is_container(otmp) && - /* include horn of plenty if sufficiently discovered */ - (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown || - !objects[HORN_OF_PLENTY].oc_name_known)) - || (!strcmp(word, "charge") && !is_chargeable(otmp)) - || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) - ) - foo--; - /* ugly check for unworn armor that can't be worn */ - else if ((putting_on(word) && *let == ARMOR_CLASS && - !canwearobj(otmp, &dummymask, FALSE)) - /* or unsuitable items rubbed on known touchstone */ - || (!strncmp(word, "rub on the stone", 16) && - *let == GEM_CLASS && - otmp->dknown && objects[otyp].oc_name_known) - /* suppress corpses on astral, amulets elsewhere */ - || (!strcmp(word, "sacrifice") && - /* (!astral && amulet) || (astral && !amulet) */ - (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) - /* suppress container being stashed into */ - || (!strcmp(word, "stash") && !ck_bag(otmp)) - /* worn armor or accessory covered by cursed worn armor */ - || (taking_off(word) && - inaccessible_equipment(otmp, (const char *)0, TRUE)) - ) { - /* acceptable but not listed as likely candidate */ - foo--; - allowall = TRUE; - *ap++ = otmp->invlet; - } - } else { - - /* "ugly check" for reading fortune cookies, part 2 */ - if ((!strcmp(word, "read") + || (!strcmp(word, "ready") && + (otmp == uwep || (otmp == uswapwep && u.twoweap))) + || ((!strcmp(word, "dip") || !strcmp(word, "grease")) && + inaccessible_equipment(otmp, (const char *)0 , FALSE)) + ) { + foo--; + foox++; + } + + /* Second ugly check; unlike the first it won't trigger an + * "else" in "you don't have anything else to ___". + */ + else if ((putting_on(word) && + ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) || + (otmp->oclass == TOOL_CLASS && + otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES))) + || (!strcmp(word, "wield") && + (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) + || (!strcmp(word, "eat") && !is_edible(otmp)) + || (!strcmp(word, "sacrifice") && + (otyp != CORPSE && + otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR)) + || (!strcmp(word, "write with") && + (otmp->oclass == TOOL_CLASS && + otyp != MAGIC_MARKER && otyp != TOWEL)) + || (!strcmp(word, "tin") && + (otyp != CORPSE || !tinnable(otmp))) + || (!strcmp(word, "rub") && + ((otmp->oclass == TOOL_CLASS && + otyp != OIL_LAMP && otyp != MAGIC_LAMP && + otyp != BRASS_LANTERN) || + (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) + || ((!strcmp(word, "use or apply") || + !strcmp(word, "untrap with")) && + /* Picks, axes, pole-weapons, bullwhips */ + ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) && + !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) || + (otmp->oclass == POTION_CLASS && + /* only applicable potion is oil, and it will only + be offered as a choice when already discovered */ + (otyp != POT_OIL || !otmp->dknown || + !objects[POT_OIL].oc_name_known)) || + (otmp->oclass == FOOD_CLASS && + otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) || + (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) + || (!strcmp(word, "invoke") && + (!otmp->oartifact && !objects[otyp].oc_unique && + (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) && + otyp != CRYSTAL_BALL && /* #invoke synonym for apply */ + /* note: presenting the possibility of invoking non-artifact + mirrors and/or lamps is a simply a cruel deception... */ + otyp != MIRROR && otyp != MAGIC_LAMP && + (otyp != OIL_LAMP || /* don't list known oil lamp */ + (otmp->dknown && objects[OIL_LAMP].oc_name_known)))) + || (!strcmp(word, "untrap with") && + (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)) + || (!strcmp(word, "tip") && !Is_container(otmp) && + /* include horn of plenty if sufficiently discovered */ + (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown || + !objects[HORN_OF_PLENTY].oc_name_known)) + || (!strcmp(word, "charge") && !is_chargeable(otmp)) + || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) + ) + foo--; + /* ugly check for unworn armor that can't be worn */ + else if ((putting_on(word) && *let == ARMOR_CLASS && + !canwearobj(otmp, &dummymask, FALSE)) + /* or unsuitable items rubbed on known touchstone */ + || (!strncmp(word, "rub on the stone", 16) && + *let == GEM_CLASS && + otmp->dknown && objects[otyp].oc_name_known) + /* suppress corpses on astral, amulets elsewhere */ + || (!strcmp(word, "sacrifice") && + /* (!astral && amulet) || (astral && !amulet) */ + (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) + /* suppress container being stashed into */ + || (!strcmp(word, "stash") && !ck_bag(otmp)) + /* worn armor or accessory covered by cursed worn armor */ + || (taking_off(word) && + inaccessible_equipment(otmp, (const char *)0, TRUE)) + ) { + /* acceptable but not listed as likely candidate */ + foo--; + allowall = TRUE; + *ap++ = otmp->invlet; + } + } else { + + /* "ugly check" for reading fortune cookies, part 2 */ + if ((!strcmp(word, "read") - && (otmp->otyp == FORTUNE_COOKIE || otmp->otyp == T_SHIRT))) - allowall = TRUE; + && is_readable(otmp))) + allowall = usegold = TRUE; - } - } - bp[foo] = 0; - if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0; - Strcpy(lets, bp); /* necessary since we destroy buf */ - if(foo > 5) /* compactify string */ - compactify(bp); - *ap = '\0'; - - if(!foo && !allowall && !allownone) { - You("don't have anything %sto %s.", - foox ? "else " : "", word); - return((struct obj *)0); - } - for(;;) { - cnt = 0; - if (allowcnt == 2) allowcnt = 1; /* abort previous count */ - prezero = FALSE; - if(!buf[0]) { - Sprintf(qbuf, "What do you want to %s? [*]", word); - } else { - Sprintf(qbuf, "What do you want to %s? [%s or ?*]", - word, buf); - } - if (in_doagain) - ilet = readchar(); - else - ilet = yn_function(qbuf, (char *)0, '\0'); - if (digit(ilet) && !allowcnt) { - pline("No count allowed with this command."); - continue; - } - if (ilet == '0') prezero = TRUE; - while (digit(ilet)) { - if (ilet != '?' && ilet != '*') savech(ilet); - /* accumulate unless cnt has overflowed */ - if (allowcnt < 3) { - prevcnt = cnt; - cnt = 10L * cnt + (long)(ilet - '0'); - /* signal presence of cnt */ - allowcnt = (cnt >= prevcnt) ? 2 : 3; - } - ilet = readchar(); - } - if (allowcnt == 3) { - /* overflow detected; force cnt to be invalid */ - cnt = -1L; - allowcnt = 2; - } - if(index(quitchars,ilet)) { - if(flags.verbose) - pline1(Never_mind); - return((struct obj *)0); - } - if(ilet == '-') { + } + } + bp[foo] = 0; + if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0; + Strcpy(lets, bp); /* necessary since we destroy buf */ + if(foo > 5) /* compactify string */ + compactify(bp); + *ap = '\0'; + + if(!foo && !allowall && !allownone) { + You("don't have anything %sto %s.", + foox ? "else " : "", word); + return((struct obj *)0); + } + for(;;) { + cnt = 0; + if (allowcnt == 2) allowcnt = 1; /* abort previous count */ + prezero = FALSE; + if(!buf[0]) { + Sprintf(qbuf, "What do you want to %s? [*]", word); + } else { + Sprintf(qbuf, "What do you want to %s? [%s or ?*]", + word, buf); + } + if (in_doagain) + ilet = readchar(); + else + ilet = yn_function(qbuf, (char *)0, '\0'); + if (digit(ilet) && !allowcnt) { + pline("No count allowed with this command."); + continue; + } + if (ilet == '0') prezero = TRUE; + while (digit(ilet)) { + if (ilet != '?' && ilet != '*') savech(ilet); + /* accumulate unless cnt has overflowed */ + if (allowcnt < 3) { + prevcnt = cnt; + cnt = 10L * cnt + (long)(ilet - '0'); + /* signal presence of cnt */ + allowcnt = (cnt >= prevcnt) ? 2 : 3; + } + ilet = readchar(); + } + if (allowcnt == 3) { + /* overflow detected; force cnt to be invalid */ + cnt = -1L; + allowcnt = 2; + } + if(index(quitchars,ilet)) { + if(flags.verbose) + pline1(Never_mind); + return((struct obj *)0); + } + if(ilet == '-') { if (!allownone) { char *suf = NULL; strcpy(buf, word); diff --cc src/mon.c index 2da55e37f,41d17e671..9e511670b --- a/src/mon.c +++ b/src/mon.c @@@ -622,91 -603,92 +622,92 @@@ movemon( */ int meatmetal(mtmp) - register struct monst *mtmp; + register struct monst *mtmp; { - register struct obj *otmp; - struct permonst *ptr; - int poly, grow, heal, mstone; + register struct obj *otmp; + struct permonst *ptr; + int poly, grow, heal, mstone; - /* If a pet, eating is handled separately, in dog.c */ - if (mtmp->mtame) return 0; + /* If a pet, eating is handled separately, in dog.c */ + if (mtmp->mtame) return 0; - /* Eats topmost metal object if it is there */ - for (otmp = level.objects[mtmp->mx][mtmp->my]; - otmp; otmp = otmp->nexthere) { + /* Eats topmost metal object if it is there */ + for (otmp = level.objects[mtmp->mx][mtmp->my]; + otmp; otmp = otmp->nexthere) { - if (mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) + /* Don't eat indigestible/choking/inappropriate objects */ + if ((mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) || + (otmp->otyp == AMULET_OF_STRANGULATION) || + (otmp->otyp == RIN_SLOW_DIGESTION)) - continue; - if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && - touch_artifact(otmp,mtmp)) { - if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) { - if (canseemon(mtmp) && flags.verbose) { - pline("%s eats %s!", - Monnam(mtmp), - distant_name(otmp,doname)); - } - /* The object's rustproofing is gone now */ - otmp->oerodeproof = 0; - mtmp->mstun = 1; - if (canseemon(mtmp) && flags.verbose) { - pline("%s spits %s out in disgust!", - Monnam(mtmp), distant_name(otmp,doname)); - } + continue; + if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && + touch_artifact(otmp,mtmp)) { + if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) { + if (canseemon(mtmp) && flags.verbose) { + pline("%s eats %s!", + Monnam(mtmp), + distant_name(otmp,doname)); + } + /* The object's rustproofing is gone now */ + otmp->oerodeproof = 0; + mtmp->mstun = 1; + if (canseemon(mtmp) && flags.verbose) { + pline("%s spits %s out in disgust!", + Monnam(mtmp), distant_name(otmp,doname)); + } - /* KMH -- Don't eat indigestible/choking objects */ - } else if (otmp->otyp != AMULET_OF_STRANGULATION && - otmp->otyp != RIN_SLOW_DIGESTION) { + } else { - if (cansee(mtmp->mx,mtmp->my) && flags.verbose) - pline("%s eats %s!", Monnam(mtmp), - distant_name(otmp,doname)); - else if (flags.verbose) - You_hear("a crunching sound."); - mtmp->meating = otmp->owt/2 + 1; - /* Heal up to the object's weight in hp */ - if (mtmp->mhp < mtmp->mhpmax) { - mtmp->mhp += objects[otmp->otyp].oc_weight; - if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; - } - if(otmp == uball) { - unpunish(); - delobj(otmp); - } else if (otmp == uchain) { - unpunish(); /* frees uchain */ - } else { - poly = polyfodder(otmp); - grow = mlevelgain(otmp); - heal = mhealup(otmp); - mstone = mstoning(otmp); - delobj(otmp); - ptr = mtmp->data; - if (poly) { - if (newcham(mtmp, (struct permonst *)0, - FALSE, FALSE)) - ptr = mtmp->data; - } else if (grow) { - ptr = grow_up(mtmp, (struct monst *)0); - } else if (mstone) { - if (poly_when_stoned(ptr)) { - mon_to_stone(mtmp); - ptr = mtmp->data; - } else if (!resists_ston(mtmp)) { - if (canseemon(mtmp)) - pline("%s turns to stone!", Monnam(mtmp)); - monstone(mtmp); - ptr = (struct permonst *)0; - } - } else if (heal) { - mtmp->mhp = mtmp->mhpmax; - } - if (!ptr) return 2; /* it died */ - } - /* Left behind a pile? */ - if (rnd(25) < 3) - (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); - newsym(mtmp->mx, mtmp->my); - return 1; - } - } - } - return 0; + if (cansee(mtmp->mx,mtmp->my) && flags.verbose) + pline("%s eats %s!", Monnam(mtmp), + distant_name(otmp,doname)); + else if (flags.verbose) + You_hear("a crunching sound."); + mtmp->meating = otmp->owt/2 + 1; + /* Heal up to the object's weight in hp */ + if (mtmp->mhp < mtmp->mhpmax) { + mtmp->mhp += objects[otmp->otyp].oc_weight; + if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; + } + if(otmp == uball) { + unpunish(); + delobj(otmp); + } else if (otmp == uchain) { + unpunish(); /* frees uchain */ + } else { + poly = polyfodder(otmp); + grow = mlevelgain(otmp); + heal = mhealup(otmp); + mstone = mstoning(otmp); + delobj(otmp); + ptr = mtmp->data; + if (poly) { + if (newcham(mtmp, (struct permonst *)0, + FALSE, FALSE)) + ptr = mtmp->data; + } else if (grow) { + ptr = grow_up(mtmp, (struct monst *)0); + } else if (mstone) { + if (poly_when_stoned(ptr)) { + mon_to_stone(mtmp); + ptr = mtmp->data; + } else if (!resists_ston(mtmp)) { + if (canseemon(mtmp)) + pline("%s turns to stone!", Monnam(mtmp)); + monstone(mtmp); + ptr = (struct permonst *)0; + } + } else if (heal) { + mtmp->mhp = mtmp->mhpmax; + } + if (!ptr) return 2; /* it died */ + } + /* Left behind a pile? */ + if (rnd(25) < 3) + (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); + newsym(mtmp->mx, mtmp->my); + return 1; + } + } + } + return 0; } /* monster eats a pile of objects */ @@@ -1254,13 -1236,15 +1255,15 @@@ dmonsfree( int count = 0; for (mtmp = &fmon; *mtmp;) { - freetmp = *mtmp; - if (freetmp->mhp <= 0 && !freetmp->isgd) { + freetmp = *mtmp; + if (freetmp->mhp <= 0 && !freetmp->isgd) { + if (freetmp == context.polearm.hitmon) + context.polearm.hitmon = NULL; - *mtmp = freetmp->nmon; - dealloc_monst(freetmp); - count++; - } else - mtmp = &(freetmp->nmon); + *mtmp = freetmp->nmon; + dealloc_monst(freetmp); + count++; + } else + mtmp = &(freetmp->nmon); } if (count != iflags.purge_monsters) diff --cc src/objnam.c index 13a145043,f40222c3b..a1115f5af --- a/src/objnam.c +++ b/src/objnam.c @@@ -239,272 -239,269 +239,277 @@@ char xname(obj) register struct obj *obj; { - register char *buf; - register int typ = obj->otyp; - register struct objclass *ocl = &objects[typ]; - int nn = ocl->oc_name_known, omndx = obj->corpsenm; - const char *actualn = OBJ_NAME(*ocl); - const char *dn = OBJ_DESCR(*ocl); - const char *un = ocl->oc_uname; - boolean pluralize = (obj->quan != 1L); - boolean known, dknown, bknown; - - buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ - if (Role_if(PM_SAMURAI) && Japanese_item_name(typ)) - actualn = Japanese_item_name(typ); - - buf[0] = '\0'; - /* - * clean up known when it's tied to oc_name_known, eg after AD_DRIN - * This is only required for unique objects since the article - * printed for the object is tied to the combination of the two - * and printing the wrong article gives away information. - */ - if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0; - if (!Blind) obj->dknown = TRUE; - if (Role_if(PM_PRIEST)) obj->bknown = TRUE; + register char *buf; + register int typ = obj->otyp; + register struct objclass *ocl = &objects[typ]; + int nn = ocl->oc_name_known, omndx = obj->corpsenm; + const char *actualn = OBJ_NAME(*ocl); + const char *dn = OBJ_DESCR(*ocl); + const char *un = ocl->oc_uname; + boolean pluralize = (obj->quan != 1L); + boolean known, dknown, bknown; + + buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ + if (Role_if(PM_SAMURAI) && Japanese_item_name(typ)) + actualn = Japanese_item_name(typ); + + buf[0] = '\0'; + /* + * clean up known when it's tied to oc_name_known, eg after AD_DRIN + * This is only required for unique objects since the article + * printed for the object is tied to the combination of the two + * and printing the wrong article gives away information. + */ + if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0; + if (!Blind) obj->dknown = TRUE; + if (Role_if(PM_PRIEST)) obj->bknown = TRUE; - if (iflags.override_ID) { - known = dknown = bknown = TRUE; - nn = 1; - } else { - known = obj->known; - dknown = obj->dknown; - bknown = obj->bknown; - } + if (iflags.override_ID) { + known = dknown = bknown = TRUE; + nn = 1; + } else { + known = obj->known; + dknown = obj->dknown; + bknown = obj->bknown; + } - if (obj_is_pname(obj)) - goto nameit; - switch (obj->oclass) { - case AMULET_CLASS: - if (!dknown) - Strcpy(buf, "amulet"); - else if (typ == AMULET_OF_YENDOR || - typ == FAKE_AMULET_OF_YENDOR) - /* each must be identified individually */ - Strcpy(buf, known ? actualn : dn); - else if (nn) - Strcpy(buf, actualn); - else if (un) - Sprintf(buf,"amulet called %s", un); - else - Sprintf(buf,"%s amulet", dn); - break; - case WEAPON_CLASS: - if (is_poisonable(obj) && obj->opoisoned) - Strcpy(buf, "poisoned "); - case VENOM_CLASS: - case TOOL_CLASS: - if (typ == LENSES) - Strcpy(buf, "pair of "); - - if (!dknown) - Strcat(buf, dn ? dn : actualn); - else if (nn) - Strcat(buf, actualn); - else if (un) { - Strcat(buf, dn ? dn : actualn); - Strcat(buf, " called "); - Strcat(buf, un); - } else - Strcat(buf, dn ? dn : actualn); - /* If we use an() here we'd have to remember never to use */ - /* it whenever calling doname() or xname(). */ - if (typ == FIGURINE && omndx != NON_PM) - Sprintf(eos(buf), " of a%s %s", - index(vowels, *mons[omndx].mname) ? "n" : "", - mons[omndx].mname); - break; - case ARMOR_CLASS: - /* depends on order of the dragon scales objects */ - if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) { - Sprintf(buf, "set of %s", actualn); - break; - } - if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of "); - - if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD - && !dknown) { - Strcpy(buf, "shield"); - break; - } - if(obj->otyp == SHIELD_OF_REFLECTION && !dknown) { - Strcpy(buf, "smooth shield"); - break; - } - - if(nn) Strcat(buf, actualn); - else if(un) { - if(is_boots(obj)) - Strcat(buf,"boots"); - else if(is_gloves(obj)) - Strcat(buf,"gloves"); - else if(is_cloak(obj)) - Strcpy(buf,"cloak"); - else if(is_helmet(obj)) - Strcpy(buf,"helmet"); - else if(is_shield(obj)) - Strcpy(buf,"shield"); - else - Strcpy(buf,"armor"); - Strcat(buf, " called "); - Strcat(buf, un); - } else Strcat(buf, dn); - break; - case FOOD_CLASS: - if (typ == SLIME_MOLD) { - register struct fruit *f; - - for(f=ffruit; f; f = f->nextf) { - if(f->fid == obj->spe) { - Strcpy(buf, f->fname); - break; - } - } - if (!f) { - impossible("Bad fruit #%d?", obj->spe); - Strcpy(buf, "fruit"); - } else if (pluralize) { - /* ick; already pluralized fruit names - are allowed--we want to try to avoid - adding a redundant plural suffix */ - Strcpy(buf, makeplural(makesingular(buf))); - pluralize = FALSE; - } - break; - } - - Strcpy(buf, actualn); - if (typ == TIN && known) - tin_details(obj, omndx, buf); - break; - case COIN_CLASS: - case CHAIN_CLASS: - Strcpy(buf, actualn); - break; - case ROCK_CLASS: - if (typ == STATUE && omndx != NON_PM) - Sprintf(buf, "%s%s of %s%s", - (Role_if(PM_ARCHEOLOGIST) && - (obj->spe & STATUE_HISTORIC)) ? "historic " : "", - actualn, - type_is_pname(&mons[omndx]) ? "" : - the_unique_pm(&mons[omndx]) ? "the " : - index(vowels, *mons[omndx].mname) ? "an " : "a ", - mons[omndx].mname); - else Strcpy(buf, actualn); - break; - case BALL_CLASS: - Sprintf(buf, "%sheavy iron ball", - (obj->owt > ocl->oc_weight) ? "very " : ""); - break; - case POTION_CLASS: - if (dknown && obj->odiluted) - Strcpy(buf, "diluted "); - if(nn || un || !dknown) { - Strcat(buf, "potion"); - if(!dknown) break; - if(nn) { - Strcat(buf, " of "); - if (typ == POT_WATER && - bknown && (obj->blessed || obj->cursed)) { - Strcat(buf, obj->blessed ? "holy " : "unholy "); - } - Strcat(buf, actualn); - } else { - Strcat(buf, " called "); - Strcat(buf, un); - } - } else { - Strcat(buf, dn); - Strcat(buf, " potion"); - } - break; - case SCROLL_CLASS: - Strcpy(buf, "scroll"); - if(!dknown) break; - if(nn) { - Strcat(buf, " of "); - Strcat(buf, actualn); - } else if(un) { - Strcat(buf, " called "); - Strcat(buf, un); - } else if (ocl->oc_magic) { - Strcat(buf, " labeled "); - Strcat(buf, dn); - } else { - Strcpy(buf, dn); - Strcat(buf, " scroll"); - } - break; - case WAND_CLASS: - if(!dknown) - Strcpy(buf, "wand"); - else if(nn) - Sprintf(buf, "wand of %s", actualn); - else if(un) - Sprintf(buf, "wand called %s", un); - else - Sprintf(buf, "%s wand", dn); - break; - case SPBOOK_CLASS: - if (!dknown) { - Strcpy(buf, "spellbook"); - } else if (nn) { - if (typ != SPE_BOOK_OF_THE_DEAD) - Strcpy(buf, "spellbook of "); - Strcat(buf, actualn); - } else if (un) { - Sprintf(buf, "spellbook called %s", un); - } else - Sprintf(buf, "%s spellbook", dn); - break; - case RING_CLASS: - if(!dknown) - Strcpy(buf, "ring"); - else if(nn) - Sprintf(buf, "ring of %s", actualn); - else if(un) - Sprintf(buf, "ring called %s", un); - else - Sprintf(buf, "%s ring", dn); - break; - case GEM_CLASS: - { - const char *rock = - (ocl->oc_material == MINERAL) ? "stone" : "gem"; - if (!dknown) { - Strcpy(buf, rock); - } else if (!nn) { - if (un) Sprintf(buf,"%s called %s", rock, un); - else Sprintf(buf, "%s %s", dn, rock); - } else { - Strcpy(buf, actualn); - if (GemStone(typ)) Strcat(buf, " stone"); - } - break; - } - default: - Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe); - } - if (pluralize) Strcpy(buf, makeplural(buf)); + if (obj_is_pname(obj)) + goto nameit; + switch (obj->oclass) { + case AMULET_CLASS: + if (!dknown) + Strcpy(buf, "amulet"); + else if (typ == AMULET_OF_YENDOR || + typ == FAKE_AMULET_OF_YENDOR) + /* each must be identified individually */ + Strcpy(buf, known ? actualn : dn); + else if (nn) + Strcpy(buf, actualn); + else if (un) + Sprintf(buf,"amulet called %s", un); + else + Sprintf(buf,"%s amulet", dn); + break; + case WEAPON_CLASS: + if (is_poisonable(obj) && obj->opoisoned) + Strcpy(buf, "poisoned "); + case VENOM_CLASS: + case TOOL_CLASS: + if (typ == LENSES) + Strcpy(buf, "pair of "); + + if (!dknown) + Strcat(buf, dn ? dn : actualn); + else if (nn) + Strcat(buf, actualn); + else if (un) { + Strcat(buf, dn ? dn : actualn); + Strcat(buf, " called "); + Strcat(buf, un); + } else + Strcat(buf, dn ? dn : actualn); + /* If we use an() here we'd have to remember never to use */ + /* it whenever calling doname() or xname(). */ + if (typ == FIGURINE && omndx != NON_PM) + Sprintf(eos(buf), " of a%s %s", + index(vowels, *mons[omndx].mname) ? "n" : "", + mons[omndx].mname); + break; + case ARMOR_CLASS: + /* depends on order of the dragon scales objects */ + if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) { + Sprintf(buf, "set of %s", actualn); + break; + } + if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of "); + + if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD + && !dknown) { + Strcpy(buf, "shield"); + break; + } + if(obj->otyp == SHIELD_OF_REFLECTION && !dknown) { + Strcpy(buf, "smooth shield"); + break; + } + + if(nn) Strcat(buf, actualn); + else if(un) { + if(is_boots(obj)) + Strcat(buf,"boots"); + else if(is_gloves(obj)) + Strcat(buf,"gloves"); + else if(is_cloak(obj)) + Strcpy(buf,"cloak"); + else if(is_helmet(obj)) + Strcpy(buf,"helmet"); + else if(is_shield(obj)) + Strcpy(buf,"shield"); + else + Strcpy(buf,"armor"); + Strcat(buf, " called "); + Strcat(buf, un); + } else Strcat(buf, dn); + break; + case FOOD_CLASS: + if (typ == SLIME_MOLD) { + register struct fruit *f; + + for(f=ffruit; f; f = f->nextf) { + if(f->fid == obj->spe) { + Strcpy(buf, f->fname); + break; + } + } + if (!f) { + impossible("Bad fruit #%d?", obj->spe); + Strcpy(buf, "fruit"); + } else if (pluralize) { + /* ick; already pluralized fruit names + are allowed--we want to try to avoid + adding a redundant plural suffix */ + Strcpy(buf, makeplural(makesingular(buf))); + pluralize = FALSE; + } + break; + } + if (Is_pudding(obj)) { + Sprintf(buf, "%s%s", + obj->owt < 100 ? "small " + : obj->owt > 500 ? "very large " + : obj->owt > 300 ? "large " + : "", actualn); + break; + } + + Strcpy(buf, actualn); + if (typ == TIN && known) + tin_details(obj, omndx, buf); + break; + case COIN_CLASS: + case CHAIN_CLASS: + Strcpy(buf, actualn); + break; + case ROCK_CLASS: + if (typ == STATUE && omndx != NON_PM) + Sprintf(buf, "%s%s of %s%s", + (Role_if(PM_ARCHEOLOGIST) && + (obj->spe & STATUE_HISTORIC)) ? "historic " : "", + actualn, + type_is_pname(&mons[omndx]) ? "" : + the_unique_pm(&mons[omndx]) ? "the " : + index(vowels, *mons[omndx].mname) ? "an " : "a ", + mons[omndx].mname); + else Strcpy(buf, actualn); + break; + case BALL_CLASS: + Sprintf(buf, "%sheavy iron ball", + (obj->owt > ocl->oc_weight) ? "very " : ""); + break; + case POTION_CLASS: + if (dknown && obj->odiluted) + Strcpy(buf, "diluted "); + if(nn || un || !dknown) { + Strcat(buf, "potion"); + if(!dknown) break; + if(nn) { + Strcat(buf, " of "); + if (typ == POT_WATER && + bknown && (obj->blessed || obj->cursed)) { + Strcat(buf, obj->blessed ? "holy " : "unholy "); + } + Strcat(buf, actualn); + } else { + Strcat(buf, " called "); + Strcat(buf, un); + } + } else { + Strcat(buf, dn); + Strcat(buf, " potion"); + } + break; + case SCROLL_CLASS: + Strcpy(buf, "scroll"); + if(!dknown) break; + if(nn) { + Strcat(buf, " of "); + Strcat(buf, actualn); + } else if(un) { + Strcat(buf, " called "); + Strcat(buf, un); + } else if (ocl->oc_magic) { + Strcat(buf, " labeled "); + Strcat(buf, dn); + } else { + Strcpy(buf, dn); + Strcat(buf, " scroll"); + } + break; + case WAND_CLASS: + if(!dknown) + Strcpy(buf, "wand"); + else if(nn) + Sprintf(buf, "wand of %s", actualn); + else if(un) + Sprintf(buf, "wand called %s", un); + else + Sprintf(buf, "%s wand", dn); + break; + case SPBOOK_CLASS: + if (!dknown) { + Strcpy(buf, "spellbook"); + } else if (nn) { + if (typ != SPE_BOOK_OF_THE_DEAD) + Strcpy(buf, "spellbook of "); + Strcat(buf, actualn); + } else if (un) { + Sprintf(buf, "spellbook called %s", un); + } else + Sprintf(buf, "%s spellbook", dn); + break; + case RING_CLASS: + if(!dknown) + Strcpy(buf, "ring"); + else if(nn) + Sprintf(buf, "ring of %s", actualn); + else if(un) + Sprintf(buf, "ring called %s", un); + else + Sprintf(buf, "%s ring", dn); + break; + case GEM_CLASS: + { + const char *rock = + (ocl->oc_material == MINERAL) ? "stone" : "gem"; + if (!dknown) { + Strcpy(buf, rock); + } else if (!nn) { + if (un) Sprintf(buf,"%s called %s", rock, un); + else Sprintf(buf, "%s %s", dn, rock); + } else { + Strcpy(buf, actualn); + if (GemStone(typ)) Strcat(buf, " stone"); + } + break; + } + default: + Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe); + } + if (pluralize) Strcpy(buf, makeplural(buf)); + if (obj->otyp == T_SHIRT && program_state.gameover) { + char tmpbuf[BUFSZ]; + Sprintf(eos(buf), " with text \"%s\"", tshirt_text(obj, tmpbuf)); + } + - if (has_oname(obj) && dknown) { - Strcat(buf, " named "); + if (has_oname(obj) && dknown) { + Strcat(buf, " named "); nameit: - Strcat(buf, ONAME(obj)); - } + Strcat(buf, ONAME(obj)); + } - if (!strncmpi(buf, "the ", 4)) buf += 4; - return(buf); + if (!strncmpi(buf, "the ", 4)) buf += 4; + return(buf); } /* similar to simple_typename but minimal_xname operates on a particular @@@ -649,287 -646,293 +654,296 @@@ char doname(obj) register struct obj *obj; { - boolean ispoisoned = FALSE; - boolean known, cknown, bknown, lknown; - int omndx = obj->corpsenm; - char prefix[PREFIX]; - char tmpbuf[PREFIX+1]; - /* when we have to add something at the start of prefix instead of the - * end (Strcat is used on the end) - */ - register char *bp = xname(obj); + boolean ispoisoned = FALSE; + boolean known, cknown, bknown, lknown; + int omndx = obj->corpsenm; + char prefix[PREFIX]; + char tmpbuf[PREFIX+1]; + /* when we have to add something at the start of prefix instead of the + * end (Strcat is used on the end) + */ + register char *bp = xname(obj); - if (iflags.override_ID) known = cknown = bknown = lknown = TRUE; - else { + if (iflags.override_ID) { + known = cknown = bknown = lknown = TRUE; + } else { - known = obj->known; - cknown = obj->cknown; - bknown = obj->bknown; - lknown = obj->lknown; - } + known = obj->known; + cknown = obj->cknown; + bknown = obj->bknown; + lknown = obj->lknown; + } - /* When using xname, we want "poisoned arrow", and when using - * doname, we want "poisoned +0 arrow". This kludge is about the only - * way to do it, at least until someone overhauls xname() and doname(), - * combining both into one function taking a parameter. - */ - /* must check opoisoned--someone can have a weirdly-named fruit */ - if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) { - bp += 9; - ispoisoned = TRUE; - } + /* When using xname, we want "poisoned arrow", and when using + * doname, we want "poisoned +0 arrow". This kludge is about the only + * way to do it, at least until someone overhauls xname() and doname(), + * combining both into one function taking a parameter. + */ + /* must check opoisoned--someone can have a weirdly-named fruit */ + if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) { + bp += 9; + ispoisoned = TRUE; + } - if(obj->quan != 1L) - Sprintf(prefix, "%ld ", obj->quan); - else if (obj->otyp == CORPSE) - /* skip article prefix for corpses [else corpse_xname() - would have to be taught how to strip it off again] */ - *prefix = '\0'; - else if (obj_is_pname(obj) || the_unique_obj(obj)) { - if (!strncmpi(bp, "the ", 4)) - bp += 4; - Strcpy(prefix, "the "); - } else - Strcpy(prefix, "a "); - - /* "empty" goes at the beginning, but item count goes at the end */ - if (cknown && + if(obj->quan != 1L) + Sprintf(prefix, "%ld ", obj->quan); + else if (obj->otyp == CORPSE) + /* skip article prefix for corpses [else corpse_xname() + would have to be taught how to strip it off again] */ + *prefix = '\0'; + else if (obj_is_pname(obj) || the_unique_obj(obj)) { + if (!strncmpi(bp, "the ", 4)) + bp += 4; + Strcpy(prefix, "the "); + } else + Strcpy(prefix, "a "); + + /* "empty" goes at the beginning, but item count goes at the end */ + if (cknown && - (Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj)) + /* bag of tricks: include "empty" prefix if it's known to + be empty but its precise number of charges isn't known + (when that is known, suffix of "(n:0)" will be appended, + making the prefix be redundant; note that 'known' flag + isn't set when emptiness gets discovered because then + charging magic would yield known number of new charges) */ + (obj->otyp == BAG_OF_TRICKS ? (obj->spe == 0 && !obj->known) : + /* not bag of tricks: empty if container which has no contents */ + (Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj))) - Strcat(prefix, "empty "); - - if (bknown && - obj->oclass != COIN_CLASS && - (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known - || (!obj->cursed && !obj->blessed))) { - /* allow 'blessed clear potion' if we don't know it's holy water; - * always allow "uncursed potion of water" - */ - if (obj->cursed) - Strcat(prefix, "cursed "); - else if (obj->blessed) - Strcat(prefix, "blessed "); - else if ((!known || !objects[obj->otyp].oc_charged || - (obj->oclass == ARMOR_CLASS || - obj->oclass == RING_CLASS)) - /* For most items with charges or +/-, if you know how many - * charges are left or what the +/- is, then you must have - * totally identified the item, so "uncursed" is unneccesary, - * because an identified object not described as "blessed" or - * "cursed" must be uncursed. - * - * If the charges or +/- is not known, "uncursed" must be - * printed to avoid ambiguity between an item whose curse - * status is unknown, and an item known to be uncursed. - */ + Strcat(prefix, "empty "); + + if (bknown && + obj->oclass != COIN_CLASS && + (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known + || (!obj->cursed && !obj->blessed))) { + /* allow 'blessed clear potion' if we don't know it's holy water; + * always allow "uncursed potion of water" + */ + if (obj->cursed) + Strcat(prefix, "cursed "); + else if (obj->blessed) + Strcat(prefix, "blessed "); + else if ((!known || !objects[obj->otyp].oc_charged || + (obj->oclass == ARMOR_CLASS || + obj->oclass == RING_CLASS)) + /* For most items with charges or +/-, if you know how many + * charges are left or what the +/- is, then you must have + * totally identified the item, so "uncursed" is unneccesary, + * because an identified object not described as "blessed" or + * "cursed" must be uncursed. + * + * If the charges or +/- is not known, "uncursed" must be + * printed to avoid ambiguity between an item whose curse + * status is unknown, and an item known to be uncursed. + */ #ifdef MAIL - && obj->otyp != SCR_MAIL + && obj->otyp != SCR_MAIL #endif - && obj->otyp != FAKE_AMULET_OF_YENDOR - && obj->otyp != AMULET_OF_YENDOR - && !Role_if(PM_PRIEST)) - Strcat(prefix, "uncursed "); - } + && obj->otyp != FAKE_AMULET_OF_YENDOR + && obj->otyp != AMULET_OF_YENDOR + && !Role_if(PM_PRIEST)) + Strcat(prefix, "uncursed "); + } - if (lknown && Is_box(obj)) { - if (obj->obroken) - Strcat(prefix, "unlockable "); - else if (obj->olocked) - Strcat(prefix, "locked "); - else - Strcat(prefix, "unlocked "); - } + if (lknown && Is_box(obj)) { + if (obj->obroken) + Strcat(prefix, "unlockable "); + else if (obj->olocked) + Strcat(prefix, "locked "); + else + Strcat(prefix, "unlocked "); + } - if (obj->greased) Strcat(prefix, "greased "); + if (obj->greased) Strcat(prefix, "greased "); - if (cknown && Has_contents(obj)) { - /* we count all objects (obj->quantity); perhaps we should - count seperate stacks instead (or even introduce a user - preference option to choose between the two alternatives) - since it's somewhat odd so see "containing 1002 items" - when there are 2 scrolls plus 1000 gold pieces */ - long itemcount = count_contents(obj, FALSE, TRUE, TRUE); + if (cknown && Has_contents(obj)) { + /* we count all objects (obj->quantity); perhaps we should + count seperate stacks instead (or even introduce a user + preference option to choose between the two alternatives) + since it's somewhat odd so see "containing 1002 items" + when there are 2 scrolls plus 1000 gold pieces */ + long itemcount = count_contents(obj, FALSE, TRUE, TRUE); - Sprintf(eos(bp), " containing %ld item%s", - itemcount, plur(itemcount)); - } + Sprintf(eos(bp), " containing %ld item%s", + itemcount, plur(itemcount)); + } - switch(obj->oclass) { - case AMULET_CLASS: - if(obj->owornmask & W_AMUL) - Strcat(bp, " (being worn)"); - break; - case WEAPON_CLASS: - if(ispoisoned) - Strcat(prefix, "poisoned "); + switch(obj->oclass) { + case AMULET_CLASS: + if(obj->owornmask & W_AMUL) + Strcat(bp, " (being worn)"); + break; + case WEAPON_CLASS: + if(ispoisoned) + Strcat(prefix, "poisoned "); plus: - add_erosion_words(obj, prefix); - if(known) { - Strcat(prefix, sitoa(obj->spe)); - Strcat(prefix, " "); - } - break; - case ARMOR_CLASS: - if(obj->owornmask & W_ARMOR) - Strcat(bp, (obj == uskin) ? " (embedded in your skin)" : - " (being worn)"); - goto plus; - case TOOL_CLASS: - /* weptools already get this done when we go to the +n code */ - if (!is_weptool(obj)) - add_erosion_words(obj, prefix); - if(obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) { - Strcat(bp, " (being worn)"); - break; - } - if (obj->otyp == LEASH && obj->leashmon != 0) { - Strcat(bp, " (in use)"); - break; - } - if (is_weptool(obj)) - goto plus; - if (obj->otyp == CANDELABRUM_OF_INVOCATION) { - if (!obj->spe) - Strcpy(tmpbuf, "no"); - else - Sprintf(tmpbuf, "%d", obj->spe); - Sprintf(eos(bp), " (%s candle%s%s)", - tmpbuf, plur(obj->spe), - !obj->lamplit ? " attached" : ", lit"); - break; - } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || - obj->otyp == BRASS_LANTERN || Is_candle(obj)) { - if (Is_candle(obj) && - obj->age < 20L * (long)objects[obj->otyp].oc_cost) - Strcat(prefix, "partly used "); - if(obj->lamplit) - Strcat(bp, " (lit)"); - break; - } - if(objects[obj->otyp].oc_charged) - goto charges; - break; - case WAND_CLASS: - add_erosion_words(obj, prefix); + add_erosion_words(obj, prefix); + if(known) { + Strcat(prefix, sitoa(obj->spe)); + Strcat(prefix, " "); + } + break; + case ARMOR_CLASS: + if(obj->owornmask & W_ARMOR) + Strcat(bp, (obj == uskin) ? " (embedded in your skin)" : + " (being worn)"); + goto plus; + case TOOL_CLASS: + /* weptools already get this done when we go to the +n code */ + if (!is_weptool(obj)) + add_erosion_words(obj, prefix); + if(obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) { + Strcat(bp, " (being worn)"); + break; + } + if (obj->otyp == LEASH && obj->leashmon != 0) { + Strcat(bp, " (in use)"); + break; + } + if (is_weptool(obj)) + goto plus; + if (obj->otyp == CANDELABRUM_OF_INVOCATION) { + if (!obj->spe) + Strcpy(tmpbuf, "no"); + else + Sprintf(tmpbuf, "%d", obj->spe); + Sprintf(eos(bp), " (%s candle%s%s)", + tmpbuf, plur(obj->spe), + !obj->lamplit ? " attached" : ", lit"); + break; + } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || + obj->otyp == BRASS_LANTERN || Is_candle(obj)) { + if (Is_candle(obj) && + obj->age < 20L * (long)objects[obj->otyp].oc_cost) + Strcat(prefix, "partly used "); + if(obj->lamplit) + Strcat(bp, " (lit)"); + break; + } + if(objects[obj->otyp].oc_charged) + goto charges; + break; + case WAND_CLASS: + add_erosion_words(obj, prefix); charges: - if(known) - Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe); - break; - case POTION_CLASS: - if (obj->otyp == POT_OIL && obj->lamplit) - Strcat(bp, " (lit)"); - break; - case RING_CLASS: - add_erosion_words(obj, prefix); + if(known) + Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe); + break; + case POTION_CLASS: + if (obj->otyp == POT_OIL && obj->lamplit) + Strcat(bp, " (lit)"); + break; + case RING_CLASS: + add_erosion_words(obj, prefix); ring: - if(obj->owornmask & W_RINGR) Strcat(bp, " (on right "); - if(obj->owornmask & W_RINGL) Strcat(bp, " (on left "); - if(obj->owornmask & W_RING) { - Strcat(bp, body_part(HAND)); - Strcat(bp, ")"); - } - if(known && objects[obj->otyp].oc_charged) { - Strcat(prefix, sitoa(obj->spe)); - Strcat(prefix, " "); - } - break; - case FOOD_CLASS: - if (obj->oeaten) - Strcat(prefix, "partly eaten "); - if (obj->otyp == CORPSE) { - Sprintf(prefix, "%s ", - corpse_xname(obj, prefix, - CXN_ARTICLE|CXN_NOCORPSE)); - } else if (obj->otyp == EGG) { + if(obj->owornmask & W_RINGR) Strcat(bp, " (on right "); + if(obj->owornmask & W_RINGL) Strcat(bp, " (on left "); + if(obj->owornmask & W_RING) { + Strcat(bp, body_part(HAND)); + Strcat(bp, ")"); + } + if(known && objects[obj->otyp].oc_charged) { + Strcat(prefix, sitoa(obj->spe)); + Strcat(prefix, " "); + } + break; + case FOOD_CLASS: + if (obj->oeaten) + Strcat(prefix, "partly eaten "); + if (obj->otyp == CORPSE) { + Sprintf(prefix, "%s ", + corpse_xname(obj, prefix, + CXN_ARTICLE|CXN_NOCORPSE)); + } else if (obj->otyp == EGG) { #if 0 /* corpses don't tell if they're stale either */ - if (known && stale_egg(obj)) - Strcat(prefix, "stale "); + if (known && stale_egg(obj)) + Strcat(prefix, "stale "); #endif - if (omndx >= LOW_PM && (known || - (mvitals[omndx].mvflags & MV_KNOWS_EGG))) { - Strcat(prefix, mons[omndx].mname); - Strcat(prefix, " "); - if (obj->spe) - Strcat(bp, " (laid by you)"); - } - } - if (obj->otyp == MEAT_RING) goto ring; - break; - case BALL_CLASS: - case CHAIN_CLASS: - add_erosion_words(obj, prefix); - if(obj->owornmask & W_BALL) - Strcat(bp, " (chained to you)"); - break; - } + if (omndx >= LOW_PM && (known || + (mvitals[omndx].mvflags & MV_KNOWS_EGG))) { + Strcat(prefix, mons[omndx].mname); + Strcat(prefix, " "); + if (obj->spe) + Strcat(bp, " (laid by you)"); + } + } + if (wizard) { + Sprintf(eos(bp), " (%d aum)", obj->owt); + } + if (obj->otyp == MEAT_RING) goto ring; + break; + case BALL_CLASS: + case CHAIN_CLASS: + add_erosion_words(obj, prefix); + if(obj->owornmask & W_BALL) + Strcat(bp, " (chained to you)"); + break; + } - if((obj->owornmask & W_WEP) && !mrg_to_wielded) { - if (obj->quan != 1L) { - Strcat(bp, " (wielded)"); - } else { - const char *hand_s = body_part(HAND); + if((obj->owornmask & W_WEP) && !mrg_to_wielded) { + if (obj->quan != 1L) { + Strcat(bp, " (wielded)"); + } else { + const char *hand_s = body_part(HAND); - if (bimanual(obj)) hand_s = makeplural(hand_s); - Sprintf(eos(bp), " (weapon in %s)", hand_s); - } - } - if(obj->owornmask & W_SWAPWEP) { - if (u.twoweap) - Sprintf(eos(bp), " (wielded in other %s)", - body_part(HAND)); - else - Strcat(bp, " (alternate weapon; not wielded)"); - } - if(obj->owornmask & W_QUIVER){ - switch(obj->oclass){ - case WEAPON_CLASS: - if(is_ammo(obj)){ - if(objects[obj->otyp].oc_skill == -P_BOW){ - /* Ammo for a bow */ - Strcat(bp, " (in quiver)"); - break; - } else { - /* Ammo not for a bow */ - Strcat(bp, " (in quiver pouch)"); - break; - } - } else { - /* Weapons not considered ammo */ - Strcat(bp, " (at the ready)"); - break; - } - - /* Small things and ammo not for a bow */ - case RING_CLASS: - case AMULET_CLASS: - case WAND_CLASS: - case COIN_CLASS: - case GEM_CLASS: - Strcat(bp, " (in quiver pouch)"); - break; - default: /* odd things */ - Strcat(bp, " (at the ready)"); - } - } - if (!iflags.suppress_price && is_unpaid(obj)) { - long quotedprice = unpaid_cost(obj, TRUE); + if (bimanual(obj)) hand_s = makeplural(hand_s); + Sprintf(eos(bp), " (weapon in %s)", hand_s); + } + } + if(obj->owornmask & W_SWAPWEP) { + if (u.twoweap) + Sprintf(eos(bp), " (wielded in other %s)", + body_part(HAND)); + else + Strcat(bp, " (alternate weapon; not wielded)"); + } + if(obj->owornmask & W_QUIVER){ + switch(obj->oclass){ + case WEAPON_CLASS: + if(is_ammo(obj)){ + if(objects[obj->otyp].oc_skill == -P_BOW){ + /* Ammo for a bow */ + Strcat(bp, " (in quiver)"); + break; + } else { + /* Ammo not for a bow */ + Strcat(bp, " (in quiver pouch)"); + break; + } + } else { + /* Weapons not considered ammo */ + Strcat(bp, " (at the ready)"); + break; + } + + /* Small things and ammo not for a bow */ + case RING_CLASS: + case AMULET_CLASS: + case WAND_CLASS: + case COIN_CLASS: + case GEM_CLASS: + Strcat(bp, " (in quiver pouch)"); + break; + default: /* odd things */ + Strcat(bp, " (at the ready)"); + } + } + if (!iflags.suppress_price && is_unpaid(obj)) { + long quotedprice = unpaid_cost(obj, TRUE); - Sprintf(eos(bp), " (%s, %ld %s)", - obj->unpaid ? "unpaid" : "contents", - quotedprice, currency(quotedprice)); - } - if (!strncmp(prefix, "a ", 2) && - index(vowels, *(prefix+2) ? *(prefix+2) : *bp) - && (*(prefix+2) || (strncmp(bp, "uranium", 7) - && strncmp(bp, "unicorn", 7) - && strncmp(bp, "eucalyptus", 10)))) { - Strcpy(tmpbuf, prefix); - Strcpy(prefix, "an "); - Strcpy(prefix+3, tmpbuf+2); - } - bp = strprepend(bp, prefix); - return(bp); + Sprintf(eos(bp), " (%s, %ld %s)", + obj->unpaid ? "unpaid" : "contents", + quotedprice, currency(quotedprice)); + } + if (!strncmp(prefix, "a ", 2) && + index(vowels, *(prefix+2) ? *(prefix+2) : *bp) + && (*(prefix+2) || (strncmp(bp, "uranium", 7) + && strncmp(bp, "unicorn", 7) + && strncmp(bp, "eucalyptus", 10)))) { + Strcpy(tmpbuf, prefix); + Strcpy(prefix, "an "); + Strcpy(prefix+3, tmpbuf+2); + } + bp = strprepend(bp, prefix); + return(bp); } /* used from invent.c */