display effect. on MSDOS without the termcap
lib, whether or not to pause for visual effect. [TRUE]
+Boolean option if TTY_GRAPHICS was set at compile time:
+msg_window show previous messages in a screen-size window [FALSE]
+
Boolean option if USE_TILES was set at compile time (MSDOS protected mode only):
preload_tiles control whether tiles get pre-loaded into RAM at the
start of the game. Doing so enhances performance
.lp msghistory
The number of top line messages to save (and recall with ^P) (default 20).
Cannot be set with the `O' command.
+.lp msg_window
+Use a screen-size window to show the previous messages with ^P instead of
+showing them one at a time. (Currently implemented for tty only.)
.lp "name "
Set your character's name (defaults to your user name). You can also
set your character's role by appending a dash and one or more letters of
The number of top line messages to save (and recall with `{\tt \^{}P}')
(default 20). Cannot be set with the `{\tt O}' command.
%.lp
+\item[\ib{msg\_window}]
+Use a screen-size window to show the previous messages with `{\tt \^{}P}'
+instead of showing them one at a time. (Currently implemented for tty only.)
+%.lp
\item[\ib{name}]
Set your character's name (defaults to your user name). You can also
set your character's role by appending a dash and one or more letters of
Orc monsters should be given poison res? [psmith@spod-central.org]
-Ninja monsters should get multishot bonuses with yumi-ya?
-[psmith@spod-central.org]
-
Chromatic Dragon should have reflection? [psmith@spod-central.org]
stone-to-flesh monsters' inventory? [psmith@spod-central.org]
Releasing your pet from a bear trap by displacing is silly.
[eino.keskitalo@purkki.mbnet.fi]
-When punished, being teleported always places the iron ball underneath you
-even when you land at a spot that's within range of the current ball&chain
-position. Since the teleport mechanism is used for crawling out of water,
-this can produce an even stranger effect: if you're carrying the attached
-ball when you step into water and it happens to be chosen as an item to
-drop in order to lighten your load, it will end up crawling out of the
-water with you. (Ie, it will end up underneath you on land rather than in
-the adjacent water where it was actually dropped.)
-
Monster spellcasting is in serious need of overhaul.
Clerical spell `case 1' has ``if (...) {} /* else fall into default */''
but the default case has been moved away so the comment is a lie.
all of the migrating objects that are being scattered onto a special obj
chain which scatter() could easily be changed to accomodate.
-Occasionally an eating attempt which gets interrupted will produce a
-food object that is not flagged as partially eaten, even though it did
-get split out of a merged group. (Observed in both 3.1.3 and 3.2.2),
-for ordinary food rations carried in the player's inventory.)
-
-Occasionally player will get messages about become encumbered while eating,
-when they didn't begin eating encumbered, but they return to proper encum-
-berance when finished eating. There is also a problem with partly eaten
-food rations carrying the wrong nutritional value (player can start out weak,
-get interrupted, finish the partly eaten ration, and end up satiated) which is
-likely the same bug.
-
For "traditional" menu style, pickup and #loot/apply can't accept an 'm'
response to bring up a menu upon request when all items involved are of
the same class, because the prompt where that response is allowed only
no apparent pattern. There is a proposal to do timing in a different manner.
Monsters do not get affected by special properties of many types of armor,
-like levitation boots. They do get affected by speed boots, but do not
-consider such items to be any better than other shoes which grant 1 point
-of AC when deciding whether to wear them.
+like levitation boots.
Corpses buried under ice ought to be handled as if they were inside an
ice box.
healing potions/spells shouldn't fix being creamed
make pie throwing and venom spitting by the player be consistent with the
effects of those attacks by monsters
+offering & tinning corpses on altars should work even while riding
+It was possible to faint after eating a fortune cookie and still read
+ the fortune's text despite being unconscious
+when filling a pit containing a vortex, a surviving vortex gets untrapped
+teleporting no longer moves the iron ball to under you if that's not necessary;
+ prevents odd ball movement when crawling out of water
+monsters now prefer to wear speed boots over other boots
+prevent crash when loading a special level specifying a mimic using m_object
+prevent crashes caused by dropping or shipping quivered or secondary weapons
+don't trigger spurious encumbrance messages on last turn of a multi-turn meal
+prevent food being restored to untouched status if interrupted while eating
+troll revival shouldn't increment the troll creation counter
+breaking mirrors and your eggs should be bad luck when kicking chests as well
+ as throwing
+vampires should be G_NOCORPSE so you can't wish for them
+glass objects should break when thrown, just like when kicked in chests
+rocks/gems shouldn't be hard to throw by hand because they are ammo
+avoid all cases where splitting an object would result in two objects being
+ quivered, wielded or otherwise having its owornflag set
Platform- and/or Interface-Specific Fixes
Gnome: workaround for GTK+ attempts to disallow setgid executables
X11: general solution to the problem that the meaning of font height varies
among different implementations of X11
+X11: make "slow" mode the default since it seems to be very prevalent
General New Features
new T-shirt messages from Scott Bigham
option to get rid of resistance 'sparkle' (shieldeffect) (Scott Bigham)
glowing Sunsword (inspired by Slashem)
+msg_window option for ^P in TTY mode (Jay Tilton)
+ninjas should get multishot bonus with yumi and ya (Dylan O'Donnell)
Platform- and/or Interface-Specific New Features
E NEARDATA int killer_format;
E const char *killer;
E const char *delayed_killer;
+#ifdef GOLDOBJ
+E long done_money;
+#endif
E char killer_buf[BUFSZ];
E const char *configfile;
E NEARDATA char plname[PL_NSIZ];
-/* SCCS Id: @(#)extern.h 3.3 2001/09/06 */
+/* SCCS Id: @(#)extern.h 3.3 2002/01/04 */
/* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */
E void FDECL(food_disappears, (struct obj *));
E void FDECL(food_substitution, (struct obj *,struct obj *));
E void NDECL(fix_petrification);
+E void FDECL(consume_oeaten, (struct obj *,int));
+E boolean FDECL(maybe_finished_meal, (BOOLEAN_P));
/* ### end.c ### */
E int FDECL(askchain, (struct obj **,const char *,int,int (*)(OBJ_P),
int (*)(OBJ_P),int,const char *));
E void FDECL(prinv, (const char *,struct obj *,long));
-E char *FDECL(xprname, (struct obj *,const char *,CHAR_P,BOOLEAN_P,long));
+E char *FDECL(xprname, (struct obj *,const char *,CHAR_P,BOOLEAN_P,long,long));
E int NDECL(ddoinv);
E char FDECL(display_inventory, (const char *,BOOLEAN_P));
E int FDECL(display_binventory, (int,int,BOOLEAN_P));
boolean lan_mail_fetched; /* mail is awaiting display */
#endif
uchar bouldersym; /* alternative boulder symbol */
+#ifdef TTY_GRAPHICS
+ boolean prevmsg_window; /* show more old messages at a time */
+#endif
};
extern NEARDATA struct flag flags;
#define MM_EMIN 0x08 /* add emin structure */
#define MM_ANGRY 0x10 /* monster is created angry */
#define MM_NONAME 0x20 /* monster is not christened */
+#define MM_NOCOUNTBIRTH 0x40 /* don't increment born counter (for revival) */
/* flags for special ggetobj status returns */
#define ALL_FINISHED 0x01 /* called routine already finished the job */
-/* SCCS Id: @(#)allmain.c 3.3 2000/05/05 */
+/* SCCS Id: @(#)allmain.c 3.3 2002/01/04 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
stop_occupation()
{
if(occupation) {
- You("stop %s.", occtxt);
+ if (!maybe_finished_meal(TRUE))
+ You("stop %s.", occtxt);
occupation = 0;
flags.botl = 1; /* in case u.uhs changed */
/* fainting stops your occupation, there's no reason to sync.
return;
} else {
if ((long)otmp->spe + obj->quan > 7L)
- (void)splitobj(obj, 7L - (long)otmp->spe);
+ obj = splitobj(obj, 7L - (long)otmp->spe);
You("attach %ld%s candle%s to %s.",
obj->quan, !otmp->spe ? "" : " more",
plur(obj->quan), the(xname(otmp)));
makeknown(obj->otyp);
if (obj->quan > 1L) {
- (void) splitobj(obj, 1L);
+ obj = splitobj(obj, 1L);
begin_burn(obj, FALSE); /* burn before free to get position */
obj_extract_self(obj); /* free from inv */
/* return TRUE if ball could be dragged
*
- * Should not be called while swallowed.
+ * Should not be called while swallowed. Should be called before movement,
+ * because we might want to move the ball or chain to the hero's old position.
*/
boolean
drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay)
return TRUE;
}
- if (carried(uball) || dist2(x, y, uball->ox, uball->oy) < 3 ||
- (uball->ox == uchain->ox && uball->oy == uchain->oy)) {
- /*
- * Case where the ball doesn't move but the chain can't just move
- * to the player's position:
- * @ _
- * _ moving southwest becomes @_ and not @
- * 0 0 0
- */
+ /* only need to move the chain? */
+ if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
*bc_control = BC_CHAIN;
move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
- if (dist2(x, y, uball->ox, uball->oy) == 2 &&
- dist2(x, y, uchain->ox, uchain->oy) == 4) {
- if (uchain->oy == y)
- *chainx = uball->ox;
- else
- *chainy = uball->oy;
- } else {
- *chainx = u.ux;
- *chainy = u.uy;
+ if (carried(uball)) {
+ /* move chain only if necessary; assume they didn't teleport */
+ if (distmin(x, y, uchain->ox, uchain->oy) > 1) {
+ *chainx = u.ux;
+ *chainy = u.uy;
+ }
+ return TRUE;
+ }
+#define CHAIN_IN_MIDDLE(chx, chy) \
+(distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
+ switch(dist2(x, y, uball->ox, uball->oy)) {
+ /* two spaces diagonal from ball, move chain inbetween */
+ case 8:
+ *chainx = (uball->ox + x)/2;
+ *chainy = (uball->oy + y)/2;
+ break;
+
+ /* player is distance 2/1 from ball; move chain to one of the
+ * two spaces between
+ * @
+ * __
+ * 0
+ */
+ case 5: {
+ xchar tempx, tempy, tempx2, tempy2;
+
+ /* find position closest to current position of chain */
+ /* no effect if current position is already OK */
+ if (abs(x - uball->ox) == 1) {
+ tempx = x;
+ tempx2 = uball->ox;
+ tempy = tempy2 = (uball->oy + y)/2;
+ } else {
+ tempx = tempx2 = (uball->ox + x)/2;
+ tempy = y;
+ tempy2 = uball->oy;
+ }
+ if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
+ dist2(tempx2, tempy2, uchain->ox, uchain->oy) ||
+ ((dist2(tempx, tempy, uchain->ox, uchain->oy) ==
+ dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) {
+ *chainx = tempx;
+ *chainy = tempy;
+ } else {
+ *chainx = tempx2;
+ *chainy = tempy2;
+ }
+ break;
+ }
+
+ /* ball is two spaces horizontal or vertical from player; move*/
+ /* chain inbetween *unless* current chain position is OK */
+ case 4:
+ if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
+ break;
+ *chainx = (x + uchain->ox)/2;
+ *chainy = (y + uchain->oy)/2;
+ break;
+
+ /* ball is one space diagonal from player. Check for the
+ * following special case:
+ * @
+ * _ moving southwest becomes @_
+ * 0 0
+ * (This will also catch teleporting that happens to resemble
+ * this case, but oh well.) Otherwise fall through.
+ */
+ case 2:
+ if (dist2(x, y, uball->ox, uball->oy) == 2 &&
+ dist2(x, y, uchain->ox, uchain->oy) == 4) {
+ if (uchain->oy == y)
+ *chainx = uball->ox;
+ else
+ *chainy = uball->oy;
+ break;
+ }
+ /* fall through */
+ case 1:
+ case 0:
+ /* do nothing if possible */
+ if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
+ break;
+ /* otherwise try to drag chain to player's old position */
+ if (CHAIN_IN_MIDDLE(u.ux, u.uy)) {
+ *chainx = u.ux;
+ *chainy = u.uy;
+ break;
+ }
+ /* otherwise use player's new position (they must have
+ teleported, for this to happen) */
+ *chainx = x;
+ *chainy = y;
+ break;
+
+ default: impossible("bad chain movement");
+ break;
}
+#undef CHAIN_IN_MIDDLE
return TRUE;
}
NEARDATA int killer_format = 0;
const char *killer = 0;
const char *delayed_killer = 0;
+#ifdef GOLDOBJ
+NEARDATA long done_money = 0;
+#endif
char killer_buf[BUFSZ] = DUMMY;
const char *nomovemsg = 0;
const char nul[40] = DUMMY; /* contains zeros */
if (mtmp) {
if (!passes_walls(mtmp->data) &&
!throws_rocks(mtmp->data)) {
- if (hmon(mtmp, obj, TRUE))
+ if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data))
return FALSE; /* still alive */
- } else mtmp->mtrapped = 0;
+ }
+ mtmp->mtrapped = 0;
} else {
if (!Passes_walls && !throws_rocks(youmonst.data)) {
losehp(rnd(15), "squished under a boulder",
dropy(obj)
register struct obj *obj;
{
+ if (obj == uwep) setuwep((struct obj *)0);
+ if (obj == uquiver) setuqwep((struct obj *)0);
+ if (obj == uswapwep) setuswapwep((struct obj *)0);
+
if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
/* uswallow check done by GAN 01/29/87 */
obj_no_longer_held(obj);
if(u.uswallow) {
- boolean could_petrify;
- if (obj != uball) { /* mon doesn't pick up ball */
- could_petrify = obj->otyp == CORPSE &&
- touch_petrifies(&mons[obj->corpsenm]);
- (void) mpickobj(u.ustuck,obj);
- if (could_petrify && is_animal(u.ustuck->data)) {
- minstapetrify(u.ustuck, TRUE);
- /* Don't leave a cockatrice corpse available in a statue */
- if (!u.uswallow) delobj(obj);
- }
+ boolean could_petrify;
+ if (obj != uball) { /* mon doesn't pick up ball */
+ could_petrify = obj->otyp == CORPSE &&
+ touch_petrifies(&mons[obj->corpsenm]);
+ (void) mpickobj(u.ustuck,obj);
+ if (could_petrify && is_animal(u.ustuck->data)) {
+ minstapetrify(u.ustuck, TRUE);
+ /* Don't leave a cockatrice corpse available in a statue */
+ if (!u.uswallow) delobj(obj);
}
+ }
} else {
- place_object(obj, u.ux, u.uy);
- if (obj == uball)
- drop_ball(u.ux,u.uy);
- else
- sellobj(obj, u.ux, u.uy);
- stackobj(obj);
- if(Blind && Levitation)
- map_object(obj, 0);
- newsym(u.ux,u.uy); /* remap location under self */
+ place_object(obj, u.ux, u.uy);
+ if (obj == uball)
+ drop_ball(u.ux,u.uy);
+ else
+ sellobj(obj, u.ux, u.uy);
+ stackobj(obj);
+ if(Blind && Levitation)
+ map_object(obj, 0);
+ newsym(u.ux,u.uy); /* remap location under self */
}
}
{
int n, i, n_dropped = 0;
long cnt;
- struct obj *otmp, *otmp2, *u_gold = 0;
+ struct obj *otmp, *otmp2;
+#ifndef GOLDOBJ
+ struct obj *u_gold = 0;
+#endif
menu_item *pick_list;
boolean all_categories = TRUE;
boolean drop_everything = FALSE;
cnt = pick_list[i].count;
if (cnt < otmp->quan && !welded(otmp) &&
(!otmp->cursed || otmp->otyp != LOADSTONE)) {
- otmp2 = splitobj(otmp, cnt);
- /* assume other worn items aren't mergable */
- if (otmp == uwep) setuwep(otmp2);
- if (otmp == uquiver) setuqwep(otmp2);
- if (otmp == uswapwep) setuswapwep(otmp2);
+ otmp = splitobj(otmp, cnt);
}
n_dropped += drop(otmp);
}
result = "cracking";
}
if (result) {
+ if (otmp->otyp == MIRROR)
+ change_luck(-2);
+ /* eggs laid by you */
+ if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
+ change_luck(-5);
You_hear("a muffled %s.",result);
if(costly) loss += stolen_value(otmp, x, y,
(boolean)shkp->mpeaceful, TRUE);
return(!rn2(3) || martial());
}
- if (kickobj->quan > 1L && !isgold) (void) splitobj(kickobj, 1L);
+ if (kickobj->quan > 1L && !isgold) kickobj = splitobj(kickobj, 1L);
if (slide && !Blind)
pline("Whee! %s slide%s across the %s.", Doname2(kickobj),
otmp->no_charge = 0;
}
+ if (otmp == uwep) setuwep((struct obj *)0);
+ if (otmp == uquiver) setuqwep((struct obj *)0);
+ if (otmp == uswapwep) setuswapwep((struct obj *)0);
+
add_to_migration(otmp);
otmp->ox = cc.x;
otmp->oy = cc.y;
if(obj->oclass == GOLD_CLASS) return(throw_gold(obj));
#else
- if (!getdir((char *)0)) return(0);
+ if (!getdir((char *)0)) {
+ /* obj might need to be merged back into the singular gold object */
+ freeinv(obj);
+ addinv(obj);
+ return(0);
+ }
/*
Throwing money is usually for getting rid of it when
twoweap = u.twoweap;
/* split this object off from its slot if necessary */
if (obj->quan > 1L) {
- otmp = splitobj(obj, obj->quan - 1L);
- otmp->owornmask = 0L;
+ otmp = splitobj(obj, 1L);
} else {
otmp = obj;
if (otmp->owornmask && otmp != uball)
if (is_ammo(obj)) {
if (ammo_and_launcher(obj, uwep))
range++;
- else
+ else if (obj->oclass != GEM_CLASS)
range /= 2;
}
struct obj *obj;
{
if (obj_resists(obj, 1, 99)) return 0;
+ if (objects[obj->otyp].oc_material == GLASS && !obj->oartifact &&
+ obj->oclass != GEM_CLASS)
+ return 1;
switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
- case MIRROR:
- case CRYSTAL_BALL:
#ifdef TOURIST
case EXPENSIVE_CAMERA:
#endif
to_pieces = "";
switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) {
+ default: /* glass or crystal wand */
+ if (obj->oclass != WAND_CLASS)
+ impossible("breaking odd object?");
+ case CRYSTAL_PLATE_MAIL:
+ case LENSES:
case MIRROR:
case CRYSTAL_BALL:
#ifdef TOURIST
-/* SCCS Id: @(#)eat.c 3.3 2001/11/28 */
+/* SCCS Id: @(#)eat.c 3.3 2002/01/02 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
STATIC_DCL int FDECL(rottenfood, (struct obj *));
STATIC_DCL void NDECL(eatspecial);
STATIC_DCL void FDECL(eataccessory, (struct obj *));
-STATIC_DCL const char * FDECL(foodword, (struct obj *));
+STATIC_DCL const char *FDECL(foodword, (struct obj *));
char msgbuf[BUFSZ];
{
if (otmp->quan > 1L) {
if(!carried(otmp))
- (void) splitobj(otmp, 1L);
+ (void) splitobj(otmp, otmp->quan - 1L);
else
- otmp = splitobj(otmp, otmp->quan - 1L);
+ otmp = splitobj(otmp, 1L);
#ifdef DEBUG
debugpline("split object,");
#endif
pline_The("tin slips from your %s.",
makeplural(body_part(FINGER)));
if(otmp->quan > 1L) {
- register struct obj *obj;
- obj = splitobj(otmp, 1L);
- if (otmp == uwep) setuwep(obj);
- if (otmp == uswapwep) setuswapwep(obj);
- if (otmp == uquiver) setuqwep(obj);
+ otmp = splitobj(otmp, 1L);
}
if (carried(otmp)) dropx(otmp);
else stackobj(otmp);
(void)touchfood(otmp);
retcode = 1;
} else
- otmp->oeaten >>= 2;
+ consume_oeaten(otmp, 2); /* oeaten >>= 2 */
} else {
pline("%s%s %s!",
!uniq ? "This " : !type_is_pname(&mons[mnum]) ? "The " : "",
u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) {
otmp->rknown = TRUE;
if (otmp->quan > 1L) {
- if(!carried(otmp))
- (void) splitobj(otmp, 1L);
- else
- otmp = splitobj(otmp, otmp->quan - 1L);
+ if(!carried(otmp))
+ (void) splitobj(otmp, otmp->quan - 1L);
+ else
+ otmp = splitobj(otmp, 1L);
}
pline("Ulch - That %s was rustproofed!", xname(otmp));
/* The regurgitated object's rustproofing is gone now */
otmp->orotten = TRUE;
dont_start = TRUE;
}
- otmp->oeaten >>= 1;
+ consume_oeaten(otmp, 1); /* oeaten >>= 1 */
} else fprefx(otmp);
}
force_save_hs = TRUE;
if(victual.nmod < 0) {
lesshungry(-victual.nmod);
- victual.piece->oeaten -= -victual.nmod;
+ consume_oeaten(victual.piece, victual.nmod); /* -= -nmod */
} else if(victual.nmod > 0 && (victual.usedtime % victual.nmod)) {
lesshungry(1);
- victual.piece->oeaten--;
+ consume_oeaten(victual.piece, -1); /* -= 1 */
}
force_save_hs = FALSE;
recalc_wt();
/* if we can't touch floor objects then use invent food only */
if (!can_reach_floor() ||
#ifdef STEED
- u.usteed || /* can't eat off floor while riding */
+ (feeding && u.usteed) || /* can't eat off floor while riding */
#endif
((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) &&
(Wwalking || is_clinger(youmonst.data) ||
return (base < 1) ? 1 : base;
}
+/* reduce obj's oeaten field, making sure it never hits or passes 0 */
+void
+consume_oeaten(obj, amt)
+struct obj *obj;
+int amt;
+{
+ /*
+ * This is a hack to try to squelch several long standing mystery
+ * food bugs. A better solution would be to rewrite the entire
+ * victual handling mechanism from scratch using a less complex
+ * model. Alternatively, this routine could call done_eating()
+ * or food_disappears() but its callers would need revisions to
+ * cope with victual.piece unexpectedly going away.
+ *
+ * Multi-turn eating operates by setting the food's oeaten field
+ * to its full nutritional value and then running a counter which
+ * independently keeps track of whether there is any food left.
+ * The oeaten field can reach exactly zero on the last turn, and
+ * the object isn't removed from inventory until the next turn
+ * when the "you finish eating" message gets delivered, so the
+ * food would be restored to the status of untouched during that
+ * interval. This resulted in unexpected encumbrance messages
+ * at the end of a meal (if near enough to a threshold) and would
+ * yield full food if there was an interruption on the critical
+ * turn. Also, there have been reports over the years of food
+ * becoming massively heavy or producing unlimited satiation;
+ * this would occur if reducing oeaten via subtraction attempted
+ * to drop it below 0 since its unsigned type would produce a
+ * huge positive value instead. So far, no one has figured out
+ * _why_ that inappropriate subtraction might sometimes happen.
+ */
+
+ if (amt > 0) {
+ /* bit shift to divide the remaining amount of food */
+ obj->oeaten >>= amt;
+ } else {
+ /* simple decrement; value is negative so we actually add it */
+ if ((int) obj->oeaten > -amt)
+ obj->oeaten += amt;
+ else
+ obj->oeaten = 0;
+ }
+
+ if (obj->oeaten == 0) {
+ if (obj == victual.piece) /* always true unless wishing... */
+ victual.reqtime = victual.usedtime; /* no bites left */
+ obj->oeaten = 1; /* smallest possible positive value */
+ }
+}
+
#endif /* OVLB */
+#ifdef OVL1
+
+/* called when eatfood occupation has been interrupted,
+ or in the case of theft, is about to be interrupted */
+boolean
+maybe_finished_meal(stopping)
+boolean stopping;
+{
+ /* in case consume_oeaten() has decided that the food is all gone */
+ if (occupation == eatfood && victual.usedtime >= victual.reqtime) {
+ if (stopping) occupation = 0; /* for do_reset_eat */
+ (void) eatfood(); /* calls done_eating() to use up victual.piece */
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#endif /* OVL1 */
/*eat.c*/
#ifndef GOLDOBJ
u.ugold = umoney;
#else
- /* FIXME */
+ done_money = umoney;
#endif
/* clean up unneeded windows */
qtmp = otmp->quan - 1;
if (qtmp > LARGEST_INT) qtmp = LARGEST_INT;
qtmp = (long)rnd((int)qtmp);
- (void) splitobj(otmp, qtmp);
- if (qtmp < otmp->quan)
- split_up = TRUE;
+ otmp = splitobj(otmp, qtmp);
+ if (rn2(qtmp))
+ split_up = TRUE;
else
- split_up = FALSE;
- }
+ split_up = FALSE;
+ } else
+ split_up = FALSE;
if (individual_object) {
- if (split_up) {
- if (otmp->where == OBJ_FLOOR)
- obj = otmp->nexthere;
- else
- obj = otmp->nobj;
+ if (split_up) {
+ obj = otmp;
} else
- obj = (struct obj *)0;
+ obj = (struct obj *)0;
}
obj_extract_self(otmp);
used_up = FALSE;
* end up being displayed after the error message.
*/
if (istty)
- fflush(stdout);
+ wait_synch();
# endif
if (f == 0) { /* child */
# ifdef TTY_GRAPHICS
* invisible if there are no error messages.
*/
if (istty)
- raw_printf("");
+ raw_print("");
# endif
/* run compressor without privileges, in case other programs
* have surprises along the line of gzip once taking filenames
continue;
case HOLE:
case TRAPDOOR:
- pline("%s %s and plugs a %s in the %s!",
+ if (Blind)
+ pline("Kerplunk! You no longer feel %s.",
+ the(xname(otmp)));
+ else
+ pline("%s %s and plugs a %s in the %s!",
The(xname(otmp)),
(ttmp->ttyp == TRAPDOOR) ? "triggers" : "falls into",
(ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
#ifdef GOLDOBJ
/* There is only one of these in inventory... */
- if (otmp->oclass == GOLD_CLASS) otmp->invlet = GOLD_SYM;
- return;
+ if (otmp->oclass == GOLD_CLASS) {
+ otmp->invlet = GOLD_SYM;
+ return;
+ }
#endif
for(i = 0; i < 52; i++) inuse[i] = FALSE;
if (drop_fmt) pline(drop_fmt, drop_arg);
/* undo any merge which took place */
if (obj->quan > oquan) {
- struct obj *otmp = splitobj(obj, oquan);
- /* might have merged with weapon */
- if (obj->owornmask)
- setworn(otmp, obj->owornmask);
+ obj = splitobj(obj, oquan);
}
dropx(obj);
} else {
pline_The("LRS would be very interested to know you have that much.");
return(struct obj *)0;
}
-#ifndef GOLDOBJ
+#ifndef GOLDOBJ
if(!(allowcnt == 2 && cnt < u.ugold))
cnt = u.ugold;
return(mkgoldobj(cnt));
#endif
}
if(allowcnt == 2 && !strcmp(word,"throw")) {
- /* permit counts for throwing gold, but don't accept
- * counts for other things since the throw code will
- * split off a single item anyway */
+ /* permit counts for throwing gold, but don't accept
+ * counts for other things since the throw code will
+ * split off a single item anyway */
+#ifdef GOLDOBJ
+ if (ilet != def_oc_syms[GOLD_CLASS])
+#endif
allowcnt = 1;
- if(cnt == 0 && prezero) return((struct obj *)0);
- if(cnt > 1) {
- You("can only throw one item at a time.");
- continue;
- }
+ if(cnt == 0 && prezero) return((struct obj *)0);
+ if(cnt > 1) {
+ You("can only throw one item at a time.");
+ continue;
+ }
}
#ifdef GOLDOBJ
flags.botl = 1; /* May have changed the amount of money */
return((struct obj *)0);
}
if(allowcnt == 2) { /* cnt given */
- if(cnt == 0) return (struct obj *)0;
- if(cnt != otmp->quan) {
- register struct obj *obj = splitobj(otmp, cnt);
+ if(cnt == 0) return (struct obj *)0;
+ if(cnt != otmp->quan) {
+ otmp = splitobj(otmp, cnt);
/* Very ugly kludge necessary to prevent someone from trying
* to drop one of several loadstones and having the loadstone
* now be separate.
*/
- if (!strcmp(word, "drop") &&
- obj->otyp == LOADSTONE && obj->cursed)
- otmp->corpsenm = obj->invlet;
- if(otmp == uwep) setuwep(obj);
- else if (otmp == uquiver) setuqwep(obj);
- if (otmp == uswapwep) setuswapwep(obj);
- }
+ if (!strcmp(word, "drop") &&
+ otmp->otyp == LOADSTONE && otmp->cursed)
+ otmp->corpsenm = otmp->invlet;
+ }
}
return(otmp);
}
if (ckfn && !(*ckfn)(otmp)) continue;
if (!allflag) {
Strcpy(qbuf, !ininv ? doname(otmp) :
- xprname(otmp, (char *)0, ilet, !nodot, 0L));
+ xprname(otmp, (char *)0, ilet, !nodot, 0L, 0L));
Strcat(qbuf, "?");
sym = (takeoff || ident || otmp->quan < 2L) ?
nyaq(qbuf) : nyNaq(qbuf);
sym = 'y';
if (yn_number < otmp->quan && !welded(otmp) &&
(!otmp->cursed || otmp->otyp != LOADSTONE)) {
- struct obj *otmpx = splitobj(otmp, yn_number);
- if (!otmpx || otmpx->nobj != otmp2)
- impossible("bad object split in askchain");
- /* assume other worn items aren't mergable */
- if (otmp == uwep) setuwep(otmpx);
- if (otmp == uquiver) setuqwep(otmpx);
- if (otmp == uswapwep) setuswapwep(otmpx);
+ otmp = splitobj(otmp, yn_number);
}
}
}
register struct obj *obj;
long quan;
{
- long savequan = obj->quan;
- if (quan) obj->quan = quan;
if (!prefix) prefix = "";
pline("%s%s%s",
prefix, *prefix ? " " : "",
- xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L));
- if (quan) obj->quan = savequan;
+ xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan));
}
#endif /* OVL2 */
#ifdef OVL1
char *
-xprname(obj, txt, let, dot, cost)
+xprname(obj, txt, let, dot, cost, quan)
struct obj *obj;
const char *txt; /* text to print instead of obj */
char let; /* inventory letter */
boolean dot; /* append period; (dot && cost => Iu) */
long cost; /* cost (for inventory of unpaid or expended items) */
+long quan; /* if non-0, print this quantity, not obj->quan */
{
#ifdef LINT /* handle static char li[BUFSZ]; */
- char li[BUFSZ];
+ char li[BUFSZ];
#else
- static char li[BUFSZ];
+ static char li[BUFSZ];
#endif
- boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
+ boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
+ long savequan = obj->quan;
+
+ if (quan) obj->quan = quan;
/*
* If let is:
* * Then obj == null and we are printing a total amount.
(use_invlet ? obj->invlet : let),
(txt ? txt : doname(obj)), (dot ? "." : ""));
}
+ if (quan) obj->quan = savequan;
+
return li;
}
for (otmp = invent; otmp; otmp = otmp->nobj) {
if (otmp->invlet == lets[0]) {
ret = message_menu(lets[0],
- want_reply ? PICK_ONE : PICK_NONE,
- xprname(otmp, (char *)0, lets[0], TRUE, 0L));
+ want_reply ? PICK_ONE : PICK_NONE,
+ xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
break;
}
}
pline("%s", xprname(otmp, distant_name(otmp, doname),
marker ? otmp->invlet : CONTAINED_SYM,
- TRUE, unpaid_cost(otmp)));
+ TRUE, unpaid_cost(otmp), 0L));
return;
}
save_unpaid = otmp->unpaid;
otmp->unpaid = 0;
putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
- ilet, TRUE, cost));
+ ilet, TRUE, cost, 0L));
otmp->unpaid = save_unpaid;
num_so_far++;
}
marker->unpaid = 0; /* suppress "(unpaid)" suffix */
putstr(win, 0,
xprname(marker, distant_name(marker, doname),
- CONTAINED_SYM, TRUE, cost));
+ CONTAINED_SYM, TRUE, cost, 0L));
marker->unpaid = save_unpaid;
}
}
}
putstr(win, 0, "");
- putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost));
+ putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost, 0L));
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
}
/* burn_floor_paper() keeps an object pointer that it tries to
* useupf() multiple times, so obj must survive if plural */
if (obj->quan > numused)
- otmp = splitobj(obj, obj->quan - numused);
+ otmp = splitobj(obj, numused);
else
otmp = obj;
if(costly_spot(otmp->ox, otmp->oy)) {
boolean anymon = (!ptr);
boolean byyou = (x == u.ux && y == u.uy);
boolean allow_minvent = ((mmflags & NO_MINVENT) == 0);
+ boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0);
uchar lim;
/* if caller wants random location, do it here */
* the caller manually decrement mvitals if the monster is created
* under circumstances where one would not logically expect the
* creation to reduce the supply of wild monsters. Monster cloning
- * might be one such case, but we go against logic there in order to
+ * might be one such case, but we go against logic there in order to
* reduce the possibility of abuse.
*/
- if (mvitals[mndx].born < 255) mvitals[mndx].born++;
+ if (mvitals[mndx].born < 255 && countbirth) mvitals[mndx].born++;
lim = mbirth_limit(mndx);
if ((int) mvitals[mndx].born >= lim && !(mons[mndx].geno & G_NOGEN) &&
!(mvitals[mndx].mvflags & G_EXTINCT)) {
}
/*
- * Split obj so that it gets size num. The remainder is put in the object
- * structure delivered by this call. The object is positioned just
- * following the original in the nobj chain (and nexthere chain when on
- * the floor).
+ * Split obj so that it gets size gets reduced by num. The quantity num is
+ * put in the object structure delivered by this call. The returned object
+ * has its wornmask cleared and is positioned just following the original
+ * in the nobj chain (and nexthere chain when on the floor).
*/
struct obj *
splitobj(obj, num)
{
struct obj *otmp;
- if (obj->cobj || num <= 0L || obj->quan < num)
+ if (obj->cobj || num <= 0L || obj->quan <= num)
panic("splitobj"); /* can't split containers */
otmp = newobj(obj->oxlth + obj->onamelth);
*otmp = *obj; /* copies whole structure */
if (!otmp->o_id) otmp->o_id = flags.ident++; /* ident overflowed */
otmp->timed = 0; /* not timed, yet */
otmp->lamplit = 0; /* ditto */
- obj->quan = num;
+ otmp->owornmask = 0L; /* new object isn't worn */
+ obj->quan -= num;
obj->owt = weight(obj);
- otmp->quan -= num;
+ otmp->quan = num;
otmp->owt = weight(otmp); /* -= obj->owt ? */
obj->nobj = otmp;
/* Only set nexthere when on the floor, nexthere is also used */
register int tmp=0;
int inrange, nearby, scared;
#ifdef GOLDOBJ
- struct obj *ygold, *lepgold;
+ struct obj *ygold = 0, *lepgold = 0;
#endif
/* Pre-movement adjustments */
(mdat->mlet == S_LEPRECHAUN && !u.ugold && (mtmp->mgold || rn2(2))) ||
#else
if (mdat->mlet == S_LEPRECHAUN) {
- ygold = findgold(invent);
- lepgold = findgold(mtmp->minvent);
+ ygold = findgold(invent);
+ lepgold = findgold(mtmp->minvent);
}
if(!nearby || mtmp->mflee || scared ||
* Vampires
*/
MON("vampire", S_VAMPIRE,
- LVL(10, 12, 1, 25, -8), (G_GENO|1),
+ LVL(10, 12, 1, 25, -8), (G_GENO|G_NOCORPSE|1),
A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_DRLI, 1, 6),
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE,
CLR_RED),
MON("vampire lord", S_VAMPIRE,
- LVL(12, 14, 0, 50, -9), (G_GENO|1),
+ LVL(12, 14, 0, 50, -9), (G_GENO|G_NOCORPSE|1),
A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_DRLI, 1, 8),
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
M3_INFRAVISIBLE, CLR_BLUE),
#if 0 /* DEFERRED */
MON("vampire mage", S_VAMPIRE,
- LVL(20, 14, -4, 50, -9), (G_GENO|1),
+ LVL(20, 14, -4, 50, -9), (G_GENO|G_NOCORPSE|1),
A(ATTK(AT_CLAW, AD_DRLI, 2, 8), ATTK(AT_BITE, AD_DRLI, 1, 8),
ATTK(AT_MAGC, AD_SPEL, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
singleobj = obj;
obj = (struct obj *) 0;
} else {
- singleobj = splitobj(obj, obj->quan - 1L);
+ singleobj = splitobj(obj, 1L);
obj_extract_self(singleobj);
}
case PM_ROGUE:
if (skill == P_DAGGER) multishot++;
break;
+ case PM_NINJA:
case PM_SAMURAI:
if (otmp->otyp == YA && mwep &&
mwep->otyp == YUMI) multishot++;
#undef WAND
/* coins ... - so far, gold is all there is */
-#define COIN(name,prob,metal) OBJECT( \
+#define COIN(name,prob,metal,worth) OBJECT( \
OBJ(name,(char *)0), BITS(0,1,0,0,0,0,0,0,0,0,0,P_NONE,metal), 0, \
- GOLD_CLASS, prob, 0, 1, 0, 0, 0, 0, 0, 0, HI_GOLD )
- COIN("gold piece", 1000, GOLD),
+ GOLD_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD )
+ COIN("gold piece", 1000, GOLD,1),
#undef COIN
/* gems ... - includes stones and rocks but not boulders */
-/* SCCS Id: @(#)objnam.c 3.3 2001/10/29 */
+/* SCCS Id: @(#)objnam.c 3.3 2002/01/04 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
makeplural(body_part(HAND)));
}
- otmp->owt = weight(otmp);
- if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160;
if (halfeaten && otmp->oclass == FOOD_CLASS) {
if (otmp->otyp == CORPSE)
otmp->oeaten = mons[otmp->corpsenm].cnutrit;
else otmp->oeaten = objects[otmp->otyp].oc_nutrition;
- otmp->owt /= 2;
- otmp->oeaten /= 2;
- if (!otmp->owt) otmp->owt = 1;
- if (!otmp->oeaten) otmp->oeaten = 1;
+ /* (do this adjustment before setting up object's weight) */
+ consume_oeaten(otmp, 1);
}
+ otmp->owt = weight(otmp);
+ if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160;
+
return(otmp);
}
#else
{"mail", (boolean *)0, TRUE},
#endif
+#ifdef TTY_GRAPHICS
+ {"msg_window", &iflags.prevmsg_window, FALSE},
+#else
+ {"msg_window", (boolean *)0, FALSE},
+#endif
#ifdef NEWS
{"news", &iflags.news, TRUE},
#else
boolean telekinesis; /* not picking it up directly by hand */
{
int res, nearload;
-#ifdef GOLDOBJ
- long umoney = money_cnt(invent);
-#endif
+#ifndef GOLDOBJ
const char *where = (obj->ox == u.ux && obj->oy == u.uy) ?
"here" : "there";
+#endif
if (obj->quan < count) {
impossible("pickup_object: count %ld > quan %ld?",
if (obj->oclass == GOLD_CLASS) flags.botl = 1;
#endif
if (obj->quan != count && obj->otyp != LOADSTONE)
- (void) splitobj(obj, count);
+ obj = splitobj(obj, count);
obj = pick_obj(obj);
if (uwep && uwep == obj) mrg_to_wielded = TRUE;
nearload = near_capacity();
- prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0, obj, count);
+ prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0,
+ obj, count);
mrg_to_wielded = FALSE;
return 1;
}
struct obj *goldob = mkgoldobj(contribution);
#else
struct obj *goldob;
- /* Find a money object to mess with */
- for (goldob = invent; goldob; goldob = goldob->nobj) ;
+ /* Find a money object to mess with */
+ for (goldob = invent; goldob; goldob = goldob->nobj) {
+ if (goldob->oclass == GOLD_CLASS) break;
+ }
if (goldob){
long contribution = rnd((int)min(LARGEST_INT, goldob->quan));
- if (contribution < goldob->quan) (void)splitobj(goldob, contribution);
- freeinv(goldob);
+ if (contribution < goldob->quan)
+ goldob = splitobj(goldob, contribution);
+ freeinv(goldob);
#endif
if (IS_THRONE(levl[u.ux][u.uy].typ)){
struct obj *coffers;
int *passed_info;
boolean *prev_loot;
{
- struct obj *otmp;
int c = -1;
int timepassed = 0;
- char qbuf[QBUFSZ];
#ifdef STEED
+ struct obj *otmp;
+ char qbuf[QBUFSZ];
+
/* 3.3.1 introduced the ability to remove saddle from a steed */
/* *passed_info is set to TRUE if a loot query was given. */
/* *prev_loot is set to TRUE if something was actually acquired in here. */
return res;
if (obj->quan != count && obj->otyp != LOADSTONE)
- (void) splitobj(obj, count);
+ obj = splitobj(obj, count);
/* Remove the object from the list. */
obj_extract_self(obj);
otmp, count);
if (is_gold) {
+#ifndef GOLDOBJ
dealloc_obj(obj);
+#endif
bot(); /* update character's gold piece count immediately */
}
return 1;
otmp = pick_list[i].item.a_obj;
count = pick_list[i].count;
if (count > 0 && count < otmp->quan) {
- otmp2 = splitobj(otmp, count);
+ otmp = splitobj(otmp, count);
/* special split case also handled by askchain() */
- if (otmp == uwep) setuwep(otmp2);
- if (otmp == uquiver) setuqwep(otmp2);
- if (otmp == uswapwep) setuswapwep(otmp2);
}
res = put_in ? in_container(otmp) : out_container(otmp);
if (res < 0)
/* with multiple merged potions, split off one and
just clear it */
if (potion->quan > 1L) {
- singlepotion = splitobj(potion, potion->quan - 1L);
+ singlepotion = splitobj(potion, 1L);
} else singlepotion = potion;
if(singlepotion->unpaid && costly_spot(u.ux, u.uy)) {
#ifndef GOLDOBJ
Sprintf(buf, "%ld Au", u.ugold);
#else
- /* FIXME: this neglects gold in containers (which will be gone by
- now if bones have been saved). For the !GOLDOBJ configuration,
- any such gold gets added into u.ugold by done(). */
- Sprintf(buf, "%ld Au", money_cnt(invent));
+ Sprintf(buf, "%ld Au", done_money);
#endif
buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
center(GOLD_LINE, buf);
boolean reading = (mechanism == BY_COOKIE ||
mechanism == BY_PAPER);
- if (reading && Blind) {
+ if (reading) {
+ /* deal with various things that prevent reading */
+ if (is_fainted() && mechanism == BY_COOKIE)
+ return;
+ else if (Blind) {
if (mechanism == BY_COOKIE)
pline(fortune_msg);
pline("What a pity that you cannot read it!");
- return;
+ return;
+ }
}
line = getrumor(truth, buf, reading ? FALSE : TRUE);
if (!*line)
return 0;
}
- if (ygold->quan > amount) splitobj(ygold, amount);
+ if (ygold->quan > amount) ygold = splitobj(ygold, amount);
freeinv(ygold);
add_to_minv(mon, ygold);
flags.botl = 1;
return;
}
- if (mongold->quan > amount) splitobj(mongold, amount);
+ if (mongold->quan > amount) mongold = splitobj(mongold, amount);
obj_extract_self(mongold);
if (!merge_choice(invent, mongold) && inv_cnt() >= 52) {
uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
thisused = bp->price * uquan;
totused += thisused;
- obj->quan = uquan; /* cheat doname */
obj->unpaid = 0; /* ditto */
/* Why 'x'? To match `I x', more or less. */
- buf_p = xprname(obj, (char *)0, 'x', FALSE, thisused);
- obj->quan = oquan; /* restore value */
+ buf_p = xprname(obj, (char *)0, 'x', FALSE, thisused, uquan);
#ifdef __SASC
/* SAS/C 6.2 can't cope for some reason */
sasc_bug(obj,save_unpaid);
totused += eshkp->debit;
buf_p = xprname((struct obj *)0,
"usage charges and/or other fees",
- GOLD_SYM, FALSE, eshkp->debit);
+ GOLD_SYM, FALSE, eshkp->debit, 0L);
putstr(datawin, 0, buf_p);
}
- buf_p = xprname((struct obj *)0, "Total:", '*', FALSE, totused);
+ buf_p = xprname((struct obj *)0, "Total:", '*', FALSE, totused, 0L);
putstr(datawin, 0, "");
putstr(datawin, 0, buf_p);
display_nhwindow(datawin, FALSE);
case M_AP_OBJECT:
for (i = 0; i < NUM_OBJECTS; i++)
- if (!strcmp(OBJ_NAME(objects[i]),
- m->appear_as.str))
+ if (OBJ_NAME(objects[i]) &&
+ !strcmp(OBJ_NAME(objects[i]),m->appear_as.str))
break;
if (i == NUM_OBJECTS) {
impossible(
-/* SCCS Id: @(#)steal.c 3.3 2001/10/15 */
+/* SCCS Id: @(#)steal.c 3.3 2002/01/04 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
const int gold_price = objects[GOLD_PIECE].oc_cost;
tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price;
tmp = min(tmp, ygold->quan);
- if (tmp < ygold->quan) splitobj(ygold, tmp);
+ if (tmp < ygold->quan) ygold = splitobj(ygold, tmp);
freeinv(ygold);
add_to_minv(mtmp, ygold);
Your("purse feels lighter.");
/* the following is true if successful on first of two attacks. */
if(!monnear(mtmp, u.ux, u.uy)) return(0);
+ /* food being eaten might already be used up but will not have
+ been removed from inventory yet; we don't want to steal that,
+ so this will cause it to be removed now */
+ if (occupation) (void) maybe_finished_meal(FALSE);
+
if (!invent || (inv_cnt() == 1 && uskin)) {
nothing_to_steal:
/* Not even a thousand men in armor can strip a naked man. */
teleds(nux, nuy)
register int nux,nuy;
{
- if (Punished) unplacebc();
+ boolean dont_teleport_ball = FALSE;
+
+ if (Punished) {
+ /* If they're teleporting to a position where the ball doesn't need
+ * to be moved, don't place the ball. Especially useful when this
+ * function is being called for crawling out of water instead of
+ * real teleportation.
+ */
+ if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
+ dont_teleport_ball = TRUE;
+ else
+ unplacebc();
+ }
u.utrap = 0;
u.ustuck = 0;
u.ux0 = u.ux;
u.uswldtim = u.uswallow = 0;
docrt();
}
- if (Punished) placebc();
+ if (Punished) {
+ if (dont_teleport_ball) {
+ int bc_control;
+ xchar ballx, bally, chainx, chainy;
+ boolean cause_delay;
+
+ /* this should only drag the chain (and never give a near-
+ capacity message) since we already checked ball distance */
+ drag_ball(u.ux, u.uy, &bc_control, &ballx, &bally, &chainx, &chainy, &cause_delay);
+ move_bc(0, bc_control, ballx, bally, chainx, chainy);
+ } else
+ placebc();
+ }
initrack(); /* teleports mess up tracking monsters without this */
update_player_regions();
#ifdef STEED
singleobj = otmp;
otmp = (struct obj *) 0;
} else {
- singleobj = splitobj(otmp, otmp->quan - 1L);
+ singleobj = splitobj(otmp, 1L);
obj_extract_self(singleobj);
}
newsym(x1,y1);
}
} else if(obj->oclass == POTION_CLASS) {
if (obj->quan > 1L)
- setworn(splitobj(obj, 1L), W_WEP);
+ obj = splitobj(obj, 1L);
else
setuwep((struct obj *)0);
freeinv(obj);
STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *));
STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long,BOOLEAN_P));
+STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *));
const struct worn {
long w_mask;
if (!obj) return;
if (obj == uwep || obj == uswapwep) u.twoweap = 0;
for(wp = worn; wp->w_mask; wp++)
- if(obj == *(wp->w_obj)) {
- *(wp->w_obj) = 0;
- p = objects[obj->otyp].oc_oprop;
- u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
- obj->owornmask &= ~wp->w_mask;
- if (obj->oartifact)
- set_artifact_intrinsic(obj, 0, wp->w_mask);
- if ((p = w_blocks(obj,wp->w_mask)) != 0)
- u.uprops[p].blocked &= ~wp->w_mask;
- }
+ if(obj == *(wp->w_obj)) {
+ *(wp->w_obj) = 0;
+ p = objects[obj->otyp].oc_oprop;
+ u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
+ obj->owornmask &= ~wp->w_mask;
+ if (obj->oartifact)
+ set_artifact_intrinsic(obj, 0, wp->w_mask);
+ if ((p = w_blocks(obj,wp->w_mask)) != 0)
+ u.uprops[p].blocked &= ~wp->w_mask;
+ }
update_inventory();
}
* it would forget spe and once again think the object is better
* than what it already has.
*/
- if (best && (ARM_BONUS(best) >= ARM_BONUS(obj))) continue;
+ if (best && (ARM_BONUS(best) + extra_pref(mon,best) >= ARM_BONUS(obj) + extra_pref(mon,obj)))
+ continue;
best = obj;
}
outer_break:
return;
}
+/* bias a monster's preferences towards armor that has special benefits. */
+/* currently only does speed boots, but might be expanded if monsters get to
+ use more armor abilities */
+static int
+extra_pref(struct monst *mon, struct obj *obj)
+{
+ if (obj) {
+ if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST)
+ return 20;
+ }
+ return 0;
+}
/*worn.c*/
case SPE_SLOW_MONSTER:
if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
mon_adjust_speed(mtmp, -1);
+ m_dowear(mtmp, FALSE); /* might want speed boots */
if (u.uswallow && (mtmp == u.ustuck) &&
is_whirly(mtmp->data)) {
You("disrupt %s!", mon_nam(mtmp));
}
break;
case WAN_SPEED_MONSTER:
- if (!resist(mtmp, otmp->oclass, 0, NOTELL))
+ if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
mon_adjust_speed(mtmp, 1);
+ m_dowear(mtmp, FALSE); /* might want speed boots */
+ }
break;
case WAN_UNDEAD_TURNING:
case SPE_TURN_UNDEAD:
if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data))
return (struct monst *)0;
mtmp = makemon(mtmp2->data,
- cc->x, cc->y, NO_MINVENT|MM_NOWAIT);
+ cc->x, cc->y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
if (!mtmp) return mtmp;
/* heal the monster */
wary_dog(mtmp, TRUE);
} else
mtmp = makemon(&mons[montype], x, y,
- NO_MINVENT|MM_NOWAIT);
+ NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
if (mtmp) {
if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) {
unsigned m_id;
x = obj->ox, y = obj->oy;
/* not useupf(), which charges */
if (obj->quan > 1L)
- (void) splitobj(obj, 1L);
+ obj = splitobj(obj, 1L);
delobj(obj);
newsym(x, y);
break;
/* if quan > 1 then some will survive intact */
if (obj->quan > 1L) {
if (obj->quan > LARGEST_INT)
- (void) splitobj(obj, (long)rnd(30000));
+ obj = splitobj(obj, (long)rnd(30000));
else
- (void) splitobj(obj, (long)rnd((int)obj->quan - 1));
+ obj = splitobj(obj, (long)rnd((int)obj->quan - 1));
}
/* appropriately add damage to bill */
register struct monst *mtmp;
register const char *force; /* usually either "." or "!" */
{
+ int pl = strcmp(str, makesingular(str));
+
if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp))
|| !flags.verbose)
- pline("%s hits it.", The(str));
- else pline("%s hits %s%s", The(str), mon_nam(mtmp), force);
+ pline("%s %s it.", The(str), pl ? "hit" : "hits");
+ else pline("%s %s %s%s", The(str), pl ? "hit" : "hits",
+ mon_nam(mtmp), force);
}
void
register const char *str;
register struct monst *mtmp;
{
- pline("%s misses %s.", The(str),
+ int pl = strcmp(str, makesingular(str));
+
+ pline("%s %s %s.", The(str), pl ? "miss" : "misses",
((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp))
&& flags.verbose) ?
mon_nam(mtmp) : "it");
#ifndef GOLDOBJ
u.ugold);
#else
- money_cnt(invent));
+ done_money);
#endif
buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
tomb_text(buf);
dlevel.setLabel(buf,(long)depth(&u.uz));
}
- gold.setLabel("Au:",(long)u.ugold);
+#ifndef GOLDOBJ
+ gold.setLabel("Au:", u.ugold);
+#else
+ gold.setLabel("Au:", money_cnt(invent));
+#endif
if (u.mtimedone) {
// You're a monster!
Sprintf(rip_line[NAME_LINE], "%s", plname);
/* Put $ on stone */
+#ifndef GOLDOBJ
Sprintf(rip_line[GOLD_LINE], "%ld Au", u.ugold);
+#else
+ Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money);
+#endif
/* Put together death description */
switch (killer_format) {
! It is not guaranteed that the window manager will honor the icon selection.
!NetHack*icon: nh56
!
-! If True, a popup for single character prompts such as y/n questions is _not_
-! used.
-!NetHack*slow: True
-!
+! If True, the default, a popup for single character prompts such as y/n
+! questions is _not_ used.
+NetHack*slow: True
+
! The number of lines the message window will show without scrolling.
!NetHack*message_lines: 12
!
static XtResource resources[] = {
{ "slow", "Slow", XtRBoolean, sizeof(Boolean),
- XtOffset(AppResources *,slow), XtRString, "False" },
+ XtOffset(AppResources *,slow), XtRString, "True" },
{ "autofocus", "AutoFocus", XtRBoolean, sizeof(Boolean),
XtOffset(AppResources *,autofocus), XtRString, "False" },
{ "message_line", "Message_line", XtRBoolean, sizeof(Boolean),
#ifndef GOLDOBJ
u.ugold);
#else
- money_cnt(invent));
+ done_money);
#endif
/* Put together death description */
switch (killer_format) {
#ifndef GOLDOBJ
u.ugold);
#else
- money_cnt(invent));
+ done_money);
#endif
Strcat(ripString, buf);
*bufp = 0;
}
if(c == '\020') { /* ctrl-P */
- if(!doprev)
- (void) tty_doprev_message(); /* need two initially */
- (void) tty_doprev_message();
- doprev = 1;
- continue;
- } else if(doprev) {
+ if (iflags.prevmsg_window) {
+ (void) tty_doprev_message();
+ tty_clear_nhwindow(WIN_MESSAGE);
+ cw->maxcol = cw->maxrow;
+ addtopl(query);
+ addtopl(" ");
+ *bufp = 0;
+ addtopl(obufp);
+ } else {
+ if (!doprev)
+ (void) tty_doprev_message();/* need two initially */
+ (void) tty_doprev_message();
+ doprev = 1;
+ continue;
+ }
+ } else if (doprev && !iflags.prevmsg_window) {
tty_clear_nhwindow(WIN_MESSAGE);
cw->maxcol = cw->maxrow;
doprev = 0;
{
register struct WinDesc *cw = wins[WIN_MESSAGE];
- ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */
- do {
- morc = 0;
- if (cw->maxcol == cw->maxrow)
- redotoplin(toplines);
- else if (cw->data[cw->maxcol])
- redotoplin(cw->data[cw->maxcol]);
- cw->maxcol--;
- if (cw->maxcol < 0) cw->maxcol = cw->rows-1;
- if (!cw->data[cw->maxcol])
- cw->maxcol = cw->maxrow;
- } while (morc == C('p'));
- ttyDisplay->dismiss_more = 0;
+ winid prevmsg_win;
+ int i;
+
+ if (iflags.prevmsg_window) {
+ prevmsg_win = create_nhwindow(NHW_MENU);
+ putstr(prevmsg_win, 0, "Message History");
+ putstr(prevmsg_win, 0, "");
+ i = cw->maxcol;
+ do {
+ if(cw->data[i] && strcmp(cw->data[i], "") )
+ putstr(prevmsg_win, 0, cw->data[i]);
+ i = (i + 1) % cw->rows;
+ } while (i != cw->maxcol);
+ putstr(prevmsg_win, 0, toplines);
+ display_nhwindow(prevmsg_win, TRUE);
+ destroy_nhwindow(prevmsg_win);
+ } else {
+ ttyDisplay->dismiss_more = C('p'); /* <ctrl/P> allowed at --More-- */
+ do {
+ morc = 0;
+ if (cw->maxcol == cw->maxrow)
+ redotoplin(toplines);
+ else if (cw->data[cw->maxcol])
+ redotoplin(cw->data[cw->maxcol]);
+ cw->maxcol--;
+ if (cw->maxcol < 0) cw->maxcol = cw->rows-1;
+ if (!cw->data[cw->maxcol])
+ cw->maxcol = cw->maxrow;
+ } while (morc == C('p'));
+ ttyDisplay->dismiss_more = 0;
+ }
return 0;
}
/* If there is room on the line, print message on same line */
/* But messages like "You die..." deserve their own line */
n0 = strlen(bp);
- if(ttyDisplay->toplin == 1 && cw->cury == 0 &&
+ if( (ttyDisplay->toplin == 1 ||
+ (cw->flags & WIN_STOP && iflags.prevmsg_window)) &&
+ cw->cury == 0 &&
n0 + (int)strlen(toplines) + 3 < CO-8 && /* room for --More-- */
(notdied = strncmp(bp, "You die", 7))) {
Strcat(toplines, " ");
if(!(cw->flags & WIN_STOP))
addtopl(bp);
return;
- } else if(!(cw->flags & WIN_STOP)) {
+ } else if (!(cw->flags & WIN_STOP && !iflags.prevmsg_window)) {
if(ttyDisplay->toplin == 1) more();
else if(cw->cury) { /* for when flags.toplin == 2 && cury > 1 */
docorner(1, cw->cury+1); /* reset cury = 0 if redraw screen */
do { /* loop until we get valid input */
q = lowc(readchar());
if (q == '\020') { /* ctrl-P */
- if(!doprev) (void) tty_doprev_message(); /* need two initially */
- (void) tty_doprev_message();
- doprev = 1;
+ if (iflags.prevmsg_window) {
+ (void) tty_doprev_message();
+ tty_clear_nhwindow(WIN_MESSAGE);
+ cw->maxcol = cw->maxrow;
+ addtopl(prompt);
+ } else {
+ if(!doprev) (void) tty_doprev_message(); /* need two initially */
+ (void) tty_doprev_message();
+ doprev = 1;
+ }
q = '\0'; /* force another loop iteration */
continue;
} else if (doprev) {
return;
}
- if(str == (const char*)0 || (cw->flags & WIN_CANCELLED))
+ if(str == (const char*)0 ||
+ ( (cw->flags & WIN_CANCELLED) &&
+ (cw->type != NHW_MESSAGE || !iflags.prevmsg_window) ))
return;
if(cw->type != NHW_MESSAGE)
str = compress_str(str);
/* this can only happen if we were reading and got interrupted */
ttyDisplay->toplin = 3;
/* do this twice; 1st time gets the Quit? message again */
- (void) tty_doprev_message();
+ if (!iflags.prevmsg_window)
+ (void) tty_doprev_message();
(void) tty_doprev_message();
ttyDisplay->intr++;
(void) fflush(stdout);