From: cohrs Date: Mon, 7 Jan 2002 02:12:04 +0000 (+0000) Subject: sync changes since last snapshot X-Git-Tag: MOVE2GIT~3532 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c77073be31fbdcff16f6d73d1156f2306066f993;p=nethack sync changes since last snapshot --- diff --git a/dat/opthelp b/dat/opthelp index 599a5db4f..58848482d 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -71,6 +71,9 @@ timed_delay on unix and VMS, use a timer instead of sending 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 diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index af446c05f..69e1cd746 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1863,6 +1863,9 @@ Cannot be set with the `O' command. .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 diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index db6ef2784..4fcfd77ff 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2299,6 +2299,10 @@ Cannot be set with the `{\tt O}' command. 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 diff --git a/doc/buglist b/doc/buglist index 26aa1c306..6f45283cb 100644 --- a/doc/buglist +++ b/doc/buglist @@ -51,9 +51,6 @@ Drain life requires you to reach floor to wipe an engraving. 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] @@ -61,15 +58,6 @@ 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. @@ -96,18 +84,6 @@ inefficient when multiple objects are migrating. It might be better to place 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 @@ -128,9 +104,7 @@ The resistance delays are very slow on some machines and fine on others, with 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. diff --git a/doc/fixes33.2 b/doc/fixes33.2 index e76df65fa..5944b039e 100644 --- a/doc/fixes33.2 +++ b/doc/fixes33.2 @@ -349,6 +349,25 @@ make blindness with just 1 turn remaining be a candicate for repair by 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 @@ -378,6 +397,7 @@ X11: allow extra space added to map widget to be removed if widget shrinks 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 @@ -433,6 +453,8 @@ blessed gold detection now detects anything made of gold, not just 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 diff --git a/include/decl.h b/include/decl.h index 4a42858b4..db8a47f5c 100644 --- a/include/decl.h +++ b/include/decl.h @@ -171,6 +171,9 @@ E NEARDATA char *save_cm; 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]; diff --git a/include/extern.h b/include/extern.h index ecfd02a74..e6879155b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* 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. */ @@ -521,6 +521,8 @@ E int FDECL(eaten_stat, (int,struct obj *)); 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 ### */ @@ -751,7 +753,7 @@ E void FDECL(identify_pack, (int)); 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)); diff --git a/include/flag.h b/include/flag.h index 457c49e47..67d044ca6 100644 --- a/include/flag.h +++ b/include/flag.h @@ -216,6 +216,9 @@ struct instance_flags { 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; diff --git a/include/hack.h b/include/hack.h index dd163e6f9..2142d2626 100644 --- a/include/hack.h +++ b/include/hack.h @@ -138,6 +138,7 @@ NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ #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 */ diff --git a/src/allmain.c b/src/allmain.c index 2bfdb772b..d42e2658a 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* 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. */ @@ -415,7 +415,8 @@ void 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. diff --git a/src/apply.c b/src/apply.c index a2462bde0..19a73a3eb 100644 --- a/src/apply.c +++ b/src/apply.c @@ -936,7 +936,7 @@ register struct obj *obj; 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))); @@ -1107,7 +1107,7 @@ light_cocktail(obj) 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 */ diff --git a/src/ball.c b/src/ball.c index 30a7fdfb9..6f9536e97 100644 --- a/src/ball.c +++ b/src/ball.c @@ -345,7 +345,8 @@ xchar ballx, bally, chainx, chainy; /* only matter !before */ /* 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) @@ -368,27 +369,108 @@ boolean *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; } diff --git a/src/decl.c b/src/decl.c index 770c95aee..a079c67e8 100644 --- a/src/decl.c +++ b/src/decl.c @@ -48,6 +48,9 @@ NEARDATA char *save_cm = 0; 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 */ diff --git a/src/do.c b/src/do.c index cbf78d087..11b2c40c8 100644 --- a/src/do.c +++ b/src/do.c @@ -171,9 +171,10 @@ const char *verb; 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", @@ -523,31 +524,35 @@ void 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 */ } } @@ -597,7 +602,10 @@ int retry; { 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; @@ -657,11 +665,7 @@ int retry; 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); } diff --git a/src/dokick.c b/src/dokick.c index 2ed9ad52b..66a1369af 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -431,6 +431,11 @@ xchar x, y; 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); @@ -512,7 +517,7 @@ xchar x, y; 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), @@ -1267,6 +1272,10 @@ boolean shop_floor_obj; 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; diff --git a/src/dothrow.c b/src/dothrow.c index 799f3c48a..f398795c4 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -52,7 +52,12 @@ int shotlimit; 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 @@ -157,8 +162,7 @@ int shotlimit; 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) @@ -846,7 +850,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ if (is_ammo(obj)) { if (ammo_and_launcher(obj, uwep)) range++; - else + else if (obj->oclass != GEM_CLASS) range /= 2; } @@ -1482,9 +1486,10 @@ breaktest(obj) 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 @@ -1508,6 +1513,11 @@ boolean in_view; 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 diff --git a/src/eat.c b/src/eat.c index 05a89d476..e02a4c61c 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,4 +1,4 @@ -/* 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. */ @@ -40,7 +40,7 @@ STATIC_DCL int FDECL(edibility_prompts, (struct obj *)); 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]; @@ -303,9 +303,9 @@ register struct obj *otmp; { 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 @@ -1097,11 +1097,7 @@ no_opener: 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); @@ -1233,7 +1229,7 @@ eatcorpse(otmp) /* called when a corpse is selected as food */ (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 " : "", @@ -1800,10 +1796,10 @@ doeat() /* generic "eat" command funtion (see cmd.c) */ 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 */ @@ -1926,7 +1922,7 @@ doeat() /* generic "eat" command funtion (see cmd.c) */ otmp->orotten = TRUE; dont_start = TRUE; } - otmp->oeaten >>= 1; + consume_oeaten(otmp, 1); /* oeaten >>= 1 */ } else fprefx(otmp); } @@ -1979,10 +1975,10 @@ bite() 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(); @@ -2279,7 +2275,7 @@ floorfood(verb,corpsecheck) /* get food from floor or pack */ /* 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) || @@ -2382,6 +2378,74 @@ register struct obj *obj; 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*/ diff --git a/src/end.c b/src/end.c index 6dacd8a43..2986ade84 100644 --- a/src/end.c +++ b/src/end.c @@ -662,7 +662,7 @@ die: #ifndef GOLDOBJ u.ugold = umoney; #else - /* FIXME */ + done_money = umoney; #endif /* clean up unneeded windows */ diff --git a/src/explode.c b/src/explode.c index a16c3e8d7..de3160487 100644 --- a/src/explode.c +++ b/src/explode.c @@ -416,20 +416,18 @@ struct obj *obj; /* only scatter this obj */ 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; diff --git a/src/files.c b/src/files.c index ab959491a..9f6a50380 100644 --- a/src/files.c +++ b/src/files.c @@ -730,7 +730,7 @@ boolean uncomp; * end up being displayed after the error message. */ if (istty) - fflush(stdout); + wait_synch(); # endif if (f == 0) { /* child */ # ifdef TTY_GRAPHICS @@ -740,7 +740,7 @@ boolean uncomp; * 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 diff --git a/src/hack.c b/src/hack.c index 10b9b09b9..9639c6fbd 100644 --- a/src/hack.c +++ b/src/hack.c @@ -160,7 +160,11 @@ moverock() 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", diff --git a/src/invent.c b/src/invent.c index 92ceaeec8..de29ca9a7 100644 --- a/src/invent.c +++ b/src/invent.c @@ -51,8 +51,10 @@ register struct obj *otmp; #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; @@ -395,10 +397,7 @@ const char *drop_fmt, *drop_arg, *hold_msg; 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 { @@ -914,23 +913,26 @@ register const char *let,*word; 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 */ @@ -975,20 +977,17 @@ register const char *let,*word; 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); } @@ -1230,7 +1229,7 @@ nextclass: 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); @@ -1250,13 +1249,7 @@ nextclass: 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); } } } @@ -1411,32 +1404,33 @@ const char *prefix; 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. @@ -1458,6 +1452,8 @@ long cost; /* cost (for inventory of unpaid or expended items) */ (use_invlet ? obj->invlet : let), (txt ? txt : doname(obj)), (dot ? "." : "")); } + if (quan) obj->quan = savequan; + return li; } @@ -1566,8 +1562,8 @@ boolean want_reply; 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; } } @@ -1658,7 +1654,7 @@ dounpaid() pline("%s", xprname(otmp, distant_name(otmp, doname), marker ? otmp->invlet : CONTAINED_SYM, - TRUE, unpaid_cost(otmp))); + TRUE, unpaid_cost(otmp), 0L)); return; } @@ -1683,7 +1679,7 @@ dounpaid() 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++; } @@ -1709,7 +1705,7 @@ dounpaid() 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; } } @@ -1717,7 +1713,7 @@ dounpaid() } 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); } @@ -2291,7 +2287,7 @@ long numused; /* 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)) { diff --git a/src/makemon.c b/src/makemon.c index 55a092b20..b5127dc6c 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -751,6 +751,7 @@ register int mmflags; 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 */ @@ -818,10 +819,10 @@ register int mmflags; * 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)) { diff --git a/src/mkobj.c b/src/mkobj.c index a6d192088..b3592618d 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -217,10 +217,10 @@ rndmonnum() /* select a random, common monster type */ } /* - * 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) @@ -229,7 +229,7 @@ long 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 */ @@ -237,9 +237,10 @@ long num; 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 */ diff --git a/src/monmove.c b/src/monmove.c index 513a31ddd..9aca9b07f 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -297,7 +297,7 @@ register struct monst *mtmp; register int tmp=0; int inrange, nearby, scared; #ifdef GOLDOBJ - struct obj *ygold, *lepgold; + struct obj *ygold = 0, *lepgold = 0; #endif /* Pre-movement adjustments */ @@ -474,8 +474,8 @@ toofar: (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 || diff --git a/src/monst.c b/src/monst.c index 3009968e7..ed0a85e67 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1987,7 +1987,7 @@ struct permonst _mons2[] = { * 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, @@ -1995,7 +1995,7 @@ struct permonst _mons2[] = { 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, @@ -2004,7 +2004,7 @@ struct permonst _mons2[] = { 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, diff --git a/src/mthrowu.c b/src/mthrowu.c index 0ab90c99f..09b85f5eb 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -282,7 +282,7 @@ m_throw(mon, x, y, dx, dy, range, obj) singleobj = obj; obj = (struct obj *) 0; } else { - singleobj = splitobj(obj, obj->quan - 1L); + singleobj = splitobj(obj, 1L); obj_extract_self(singleobj); } @@ -557,6 +557,7 @@ struct monst *mtmp; case PM_ROGUE: if (skill == P_DAGGER) multishot++; break; + case PM_NINJA: case PM_SAMURAI: if (otmp->otyp == YA && mwep && mwep->otyp == YUMI) multishot++; diff --git a/src/objects.c b/src/objects.c index 7db3dc55b..caa8e3ae7 100644 --- a/src/objects.c +++ b/src/objects.c @@ -875,10 +875,10 @@ WAND((char *)0, "jeweled", 0, 150, 1, 0, IRON, HI_MINERAL), #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 */ diff --git a/src/objnam.c b/src/objnam.c index 056ff944a..0ad9650c8 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* 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. */ @@ -2430,17 +2430,16 @@ typfnd: 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); } diff --git a/src/options.c b/src/options.c index a9516f533..5e256906a 100644 --- a/src/options.c +++ b/src/options.c @@ -115,6 +115,11 @@ static struct Bool_Opt #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 diff --git a/src/pickup.c b/src/pickup.c index 35442ec7a..92b84c47c 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1081,11 +1081,10 @@ long count; 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?", @@ -1191,13 +1190,14 @@ boolean telekinesis; /* not picking it up directly by hand */ 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; } @@ -1406,12 +1406,15 @@ lootcont: 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; @@ -1515,11 +1518,12 @@ struct monst *mtmp; 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. */ @@ -1789,7 +1793,7 @@ register struct obj *obj; 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); @@ -1822,7 +1826,9 @@ register struct obj *obj; otmp, count); if (is_gold) { +#ifndef GOLDOBJ dealloc_obj(obj); +#endif bot(); /* update character's gold piece count immediately */ } return 1; @@ -2109,11 +2115,8 @@ boolean put_in; 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) diff --git a/src/potion.c b/src/potion.c index 03bb108fa..e94b941f5 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1817,7 +1817,7 @@ dodip() /* 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)) { diff --git a/src/rip.c b/src/rip.c index bda08ca9e..bb65e097e 100644 --- a/src/rip.c +++ b/src/rip.c @@ -111,10 +111,7 @@ int how; #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); diff --git a/src/rumors.c b/src/rumors.c index 387f9c394..6265d74a9 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -146,11 +146,16 @@ int mechanism; 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) diff --git a/src/shk.c b/src/shk.c index 3bbdf6b55..f9f464bfc 100644 --- a/src/shk.c +++ b/src/shk.c @@ -103,7 +103,7 @@ long amount; 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; @@ -131,7 +131,7 @@ long amount; 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) { @@ -2748,11 +2748,9 @@ int mode; /* 0: deliver count 1: paged */ 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); @@ -2768,10 +2766,10 @@ int mode; /* 0: deliver count 1: paged */ 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); diff --git a/src/sp_lev.c b/src/sp_lev.c index 9b1c71967..07ee028bc 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -850,8 +850,8 @@ struct mkroom *croom; 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( diff --git a/src/steal.c b/src/steal.c index 665c87710..a519bbdb3 100644 --- a/src/steal.c +++ b/src/steal.c @@ -1,4 +1,4 @@ -/* 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. */ @@ -123,7 +123,7 @@ register struct monst *mtmp; 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."); @@ -229,6 +229,11 @@ char *objnambuf; /* 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. */ diff --git a/src/teleport.c b/src/teleport.c index b347464c0..8d63c3e8e 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -204,7 +204,19 @@ void 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; @@ -228,7 +240,19 @@ register int nux,nuy; 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 diff --git a/src/trap.c b/src/trap.c index 9150c062e..0df175e05 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1160,7 +1160,7 @@ int style; singleobj = otmp; otmp = (struct obj *) 0; } else { - singleobj = splitobj(otmp, otmp->quan - 1L); + singleobj = splitobj(otmp, 1L); obj_extract_self(singleobj); } newsym(x1,y1); diff --git a/src/uhitm.c b/src/uhitm.c index 5167d818c..ee0d00172 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -634,7 +634,7 @@ int thrown; } } 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); diff --git a/src/worn.c b/src/worn.c index d468aaaba..8c1aa14fe 100644 --- a/src/worn.c +++ b/src/worn.c @@ -6,6 +6,7 @@ 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; @@ -114,16 +115,16 @@ register struct obj *obj; 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(); } @@ -404,7 +405,8 @@ boolean creation; * 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: @@ -667,4 +669,16 @@ boolean polyspot; 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*/ diff --git a/src/zap.c b/src/zap.c index d0f73a808..8c44d94f4 100644 --- a/src/zap.c +++ b/src/zap.c @@ -140,6 +140,7 @@ struct obj *otmp; 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)); @@ -149,8 +150,10 @@ struct obj *otmp; } 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: @@ -450,7 +453,7 @@ coord *cc; 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 */ @@ -610,7 +613,7 @@ register struct obj *obj; 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; @@ -666,7 +669,7 @@ register struct obj *obj; 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; @@ -1134,9 +1137,9 @@ struct obj *obj; /* 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 */ @@ -2504,10 +2507,13 @@ register const char *str; 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 @@ -2515,7 +2521,9 @@ miss(str,mtmp) 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"); diff --git a/sys/amiga/amirip.c b/sys/amiga/amirip.c index bd60aa321..c41110a4f 100644 --- a/sys/amiga/amirip.c +++ b/sys/amiga/amirip.c @@ -199,7 +199,7 @@ int how; #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); diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp index dd0f190e2..ac9c3b172 100644 --- a/win/Qt/qt_win.cpp +++ b/win/Qt/qt_win.cpp @@ -2441,7 +2441,11 @@ void NetHackQtStatusWindow::updateStats() 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! @@ -3166,7 +3170,11 @@ static char** rip_line=0; 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) { diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index dc1ab1768..df017456d 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -59,10 +59,10 @@ NetHack*message*translations: : input() ! 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 ! diff --git a/win/X11/winX.c b/win/X11/winX.c index 0b43eb970..2d767f2a6 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -902,7 +902,7 @@ static XtActionsRec actions[] = { 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), diff --git a/win/X11/wintext.c b/win/X11/wintext.c index ee0d7533c..21203ebcc 100644 --- a/win/X11/wintext.c +++ b/win/X11/wintext.c @@ -471,7 +471,7 @@ calculate_rip_text(int how) #ifndef GOLDOBJ u.ugold); #else - money_cnt(invent)); + done_money); #endif /* Put together death description */ switch (killer_format) { diff --git a/win/gnome/gnbind.c b/win/gnome/gnbind.c index 3fed89b24..a874fde2c 100644 --- a/win/gnome/gnbind.c +++ b/win/gnome/gnbind.c @@ -977,7 +977,7 @@ void gnome_outrip(winid wid, int how) #ifndef GOLDOBJ u.ugold); #else - money_cnt(invent)); + done_money); #endif Strcat(ripString, buf); diff --git a/win/tty/getline.c b/win/tty/getline.c index 1d9a725c0..3bee369c3 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -72,12 +72,22 @@ getlin_hook_proc hook; *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; diff --git a/win/tty/topl.c b/win/tty/topl.c index 98d4248e5..02d0df029 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -26,19 +26,37 @@ tty_doprev_message() { register struct WinDesc *cw = wins[WIN_MESSAGE]; - ttyDisplay->dismiss_more = C('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'); /* 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; } @@ -147,7 +165,9 @@ update_topl(bp) /* 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, " "); @@ -156,7 +176,7 @@ update_topl(bp) 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 */ @@ -279,9 +299,16 @@ char def; 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) { diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 0387e56fa..b281e9822 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1732,7 +1732,9 @@ tty_putstr(window, attr, str) 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); @@ -2215,7 +2217,8 @@ tty_wait_synch() /* 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);