diff --git a/dat/Bar-strt.lua b/dat/Bar-strt.lua index c3a98de04..17be92208 100644 --- a/dat/Bar-strt.lua +++ b/dat/Bar-strt.lua @@ -90,14 +90,8 @@ des.monster("giant eel", 36, 01) des.monster("giant eel", 37, 09) des.monster("giant eel", 39, 15) -- Monsters on siege duty. -des.monster({ id = "ogre", x=40, y=08, peaceful=0 }) -des.monster({ id = "ogre", x=41, y=06, peaceful=0 }) -des.monster({ id = "ogre", x=41, y=07, peaceful=0 }) -des.monster({ id = "ogre", x=41, y=08, peaceful=0 }) -des.monster({ id = "ogre", x=41, y=09, peaceful=0 }) -des.monster({ id = "ogre", x=41, y=10, peaceful=0 }) -des.monster({ id = "ogre", x=42, y=06, peaceful=0 }) -des.monster({ id = "ogre", x=42, y=07, peaceful=0 }) -des.monster({ id = "ogre", x=42, y=08, peaceful=0 }) -des.monster({ id = "ogre", x=42, y=09, peaceful=0 }) -des.monster({ id = "ogre", x=42, y=10, peaceful=0 }) +local ogrelocs = selection.floodfill(37,7) & selection.area(40,03, 45,20) +for i = 0, 11 do + local x,y = ogrelocs:rndcoord(1); + des.monster({ id = "ogre", coord={x,y}, peaceful=0 }) +end diff --git a/dat/Mon-strt.lua b/dat/Mon-strt.lua index 1add47ab6..a71975d5f 100644 --- a/dat/Mon-strt.lua +++ b/dat/Mon-strt.lua @@ -42,6 +42,8 @@ des.region({ region={24,06, 33,13}, lit=1, type="temple" }) des.replace_terrain({ region={00,00, 10,19}, fromterrain=".", toterrain="T", chance=10 }) des.replace_terrain({ region={65,00, 75,19}, fromterrain=".", toterrain="T", chance=10 }) +local spacelocs = selection.floodfill(05,04); + -- Portal arrival point des.terrain({05,04}, ".") des.levregion({ region = {05,04,05,04}, type="branch" }) @@ -83,22 +85,20 @@ des.monster("abbot", 33, 12) -- Non diggable walls des.non_diggable(selection.area(18,03,55,16)) -- Random traps -des.trap("dart",20,09) -des.trap("dart",20,10) +for i = 1, 2 do + local x,y = spacelocs:rndcoord(1); + des.trap("dart",x,y) +end des.trap() des.trap() des.trap() des.trap() -- Monsters on siege duty. -des.monster("earth elemental", 37, 01) -des.monster("earth elemental", 37, 18) -des.monster("earth elemental", 03, 03) -des.monster("earth elemental", 65, 04) -des.monster("earth elemental", 12, 11) -des.monster("earth elemental", 60, 12) -des.monster("earth elemental", 14, 08) -des.monster("earth elemental", 55, 00) -des.monster("xorn", 18, 18) -des.monster("xorn", 59, 10) -des.monster("xorn", 13, 09) -des.monster("xorn", 01, 17) +for i = 1, 8 do + local x,y = spacelocs:rndcoord(1); + des.monster("earth elemental", x, y) +end +for i = 1, 4 do + local x,y = spacelocs:rndcoord(1); + des.monster("xorn", x, y) +end diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 93599f07b..1a63ba915 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.128 $ $NHDT-Date: 1583926845 2020/03/11 11:40:45 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.137 $ $NHDT-Date: 1584482684 2020/03/17 22:04:44 $ General Fixes and Modified Features ----------------------------------- @@ -79,6 +79,11 @@ fix priest created inside temple wall fix vault guard occasionally encasing monsters in stone tone down scare monster by excluding humans and uniques lock the castle chest +revamp amnesia to forget skills instead of objects or maps +when Punished and carrying the iron ball and levitating, hurtling in the + opposite direction of a thrown object didn't bring along the chain +recognize "kirin" as alias for "ki-rin" when asked to create a monster +make unique swallowing monsters (Juiblex) resist magical digging from inside Fixes to 3.7.0-x Problems that Were Exposed Via git Repository @@ -129,6 +134,8 @@ tty: role and race selection menus weren't filtering out potential choices which got excluded by OPTIONS=align:!lawful or !neutral or !chaotic windows: update for new status condition fields X11: substantial overhaul of status display, both 'fancy' and 'tty-style' +X11: extend fancy status one-turn inverse video status-change highlighting to + hunger, encumbrance, and conditions General New Features diff --git a/include/dungeon.h b/include/dungeon.h index 7a5677761..75577dbfa 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -159,7 +159,7 @@ typedef struct branch { struct linfo { unsigned char flags; #define VISITED 0x01 /* hero has visited this level */ -#define FORGOTTEN 0x02 /* hero will forget this level when reached */ +/* 0x02 was FORGOTTEN, when amnesia made you forget maps */ #define LFILE_EXISTS 0x04 /* a level file exists for this level */ /* Note: VISITED and LFILE_EXISTS are currently almost always * set at the same time. However they _mean_ different things. diff --git a/include/extern.h b/include/extern.h index c2f891b93..015450055 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1583073988 2020/03/01 14:46:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.809 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1584405113 2020/03/17 00:31:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.814 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -666,7 +666,6 @@ E char *FDECL(get_annotation, (d_level *)); E int NDECL(donamelevel); E int NDECL(dooverview); E void FDECL(show_overview, (int, int)); -E void FDECL(forget_mapseen, (int)); E void FDECL(rm_mapseen, (int)); E void FDECL(init_mapseen, (d_level *)); E void NDECL(recalc_mapseen); @@ -907,6 +906,7 @@ E int NDECL(dopickup); E void NDECL(lookaround); E boolean FDECL(crawl_destination, (int, int)); E int NDECL(monster_nearby); +E void FDECL(end_running, (BOOLEAN_P)); E void FDECL(nomul, (int)); E void FDECL(unmul, (const char *)); E void FDECL(losehp, (int, const char *, BOOLEAN_P)); @@ -1509,6 +1509,7 @@ E void NDECL(kill_genocided_monsters); E void FDECL(golemeffects, (struct monst *, int, int)); E boolean FDECL(angry_guards, (BOOLEAN_P)); E void NDECL(pacify_guards); +E struct monst *FDECL(find_ghost_with_name, (char *)); E void FDECL(decide_to_shapeshift, (struct monst *, int)); E boolean FDECL(vamp_stone, (struct monst *)); E void NDECL(monst_globals_init); @@ -2166,10 +2167,6 @@ E char *FDECL(tshirt_text, (struct obj *, char *)); E int NDECL(doread); E boolean FDECL(is_chargeable, (struct obj *)); E void FDECL(recharge, (struct obj *, int)); -E void FDECL(forget_objects, (int)); -E void FDECL(forget_levels, (int)); -E void NDECL(forget_traps); -E void FDECL(forget_map, (int)); E int FDECL(seffects, (struct obj *)); E void FDECL(drop_boulder_on_player, (BOOLEAN_P, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); @@ -2956,6 +2953,7 @@ E void FDECL(unrestrict_weapon_skill, (int)); E void FDECL(use_skill, (int, int)); E void FDECL(add_weapon_skill, (int)); E void FDECL(lose_weapon_skill, (int)); +E void FDECL(drain_weapon_skill, (int)); E int FDECL(weapon_type, (struct obj *)); E int NDECL(uwep_skill_type); E int FDECL(weapon_hit_bonus, (struct obj *)); diff --git a/include/hack.h b/include/hack.h index 5d0d13484..feb24001e 100644 --- a/include/hack.h +++ b/include/hack.h @@ -477,6 +477,11 @@ enum bodypart_types { #define RANDOM_TIN (-2) #define HEALTHY_TIN (-3) +/* Corpse aging */ +#define TAINT_AGE (50L) /* age when corpses go bad */ +#define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */ +#define ROT_AGE (250L) /* age when corpses rot away */ + /* Some misc definitions */ #define POTION_OCCUPANT_CHANCE(n) (13 + 2 * (n)) #define WAND_BACKFIRE_CHANCE 100 diff --git a/src/allmain.c b/src/allmain.c index 073054cbc..a609b4244 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 allmain.c $NHDT-Date: 1580044340 2020/01/26 13:12:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ +/* NetHack 3.6 allmain.c $NHDT-Date: 1584405115 2020/03/17 00:31:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.143 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -178,6 +178,9 @@ boolean resuming; g.monstermoves++; /* [obsolete (for a long time...)] */ g.moves++; + if (flags.time && !g.context.run) + iflags.time_botl = TRUE; /* 'moves' just changed */ + /********************************/ /* once-per-turn things go here */ /********************************/ @@ -189,8 +192,6 @@ boolean resuming; if (u.ublesscnt) u.ublesscnt--; - if (flags.time && !g.context.run) - iflags.time_botl = TRUE; /* One possible result of prayer is healing. Whether or * not you get healed depends on your current hit points. @@ -436,8 +437,6 @@ boolean resuming; if (!g.multi) { /* lookaround may clear multi */ g.context.move = 0; - if (flags.time) - g.context.botl = TRUE; continue; } if (g.context.mv) { @@ -457,9 +456,6 @@ boolean resuming; } if (u.utotype) /* change dungeon level */ deferred_goto(); /* after rhack() */ - /* !g.context.move here: multiple movement command stopped */ - else if (flags.time && (!g.context.move || !g.context.mv)) - g.context.botl = TRUE; if (g.vision_full_recalc) vision_recalc(0); /* vision! */ diff --git a/src/botl.c b/src/botl.c index 3b29e348b..5fcfca6d8 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1583190980 2020/03/02 23:16:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.185 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1584350350 2020/03/16 09:19:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.186 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1117,10 +1117,11 @@ cond_menu(VOID_ARGS) } while (showmenu); if (res > 0) { - for (i = 0; i < CONDITION_COUNT; ++i) { - if (condtests[i].enabled != condtests[i].choice) + for (i = 0; i < CONDITION_COUNT; ++i) + if (condtests[i].enabled != condtests[i].choice) { condtests[i].enabled = condtests[i].choice; - } + g.context.botl = TRUE; + } } } diff --git a/src/dig.c b/src/dig.c index 7f08ce170..05cdbbdd7 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dig.c $NHDT-Date: 1578659784 2020/01/10 12:36:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.135 $ */ +/* NetHack 3.6 dig.c $NHDT-Date: 1584350347 2020/03/16 09:19:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -928,7 +928,7 @@ coord *cc; case 1: You("unearth a corpse."); if ((otmp = mk_tt_object(CORPSE, dig_x, dig_y)) != 0) - otmp->age -= 100; /* this is an *OLD* corpse */ + otmp->age -= (TAINT_AGE + 1); /* this is an *OLD* corpse */ break; case 2: if (!Blind) @@ -1409,7 +1409,10 @@ zap_dig() if (is_animal(mtmp->data)) You("pierce %s %s wall!", s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); - mtmp->mhp = 1; /* almost dead */ + if (unique_corpstat(mtmp->data)) + mtmp->mhp = (mtmp->mhp + 1) / 2; + else + mtmp->mhp = 1; /* almost dead */ expels(mtmp, mtmp->data, !is_animal(mtmp->data)); } return; @@ -1827,8 +1830,7 @@ boolean *dealloced; *dealloced = FALSE; if (otmp == uball) { unpunish(); - u.utrap = rn1(50, 20); - u.utraptype = TT_BURIEDBALL; + set_utrap((unsigned) rn1(50, 20), TT_BURIEDBALL); pline_The("iron ball gets buried!"); } /* after unpunish(), or might get deallocated chain */ diff --git a/src/do.c b/src/do.c index ab38386c8..31407013f 100644 --- a/src/do.c +++ b/src/do.c @@ -1461,12 +1461,14 @@ boolean at_stairs, falling, portal; if (!(g.level_info[new_ledger].flags & LFILE_EXISTS)) { /* entering this level for first time; make it now */ - if (g.level_info[new_ledger].flags & (FORGOTTEN | VISITED)) { + if (g.level_info[new_ledger].flags & (VISITED)) { impossible("goto_level: returning to discarded level?"); - g.level_info[new_ledger].flags &= ~(FORGOTTEN | VISITED); + g.level_info[new_ledger].flags &= ~(VISITED); } mklev(); new = TRUE; /* made the level */ + + familiar = (find_ghost_with_name(g.plname) != (struct monst *) 0); } else { /* returning to previously visited level; reload it */ nhfp = open_levelfile(new_ledger, whynot); @@ -1606,13 +1608,6 @@ boolean at_stairs, falling, portal; else if (Is_firelevel(&u.uz)) fumaroles(); - if (g.level_info[new_ledger].flags & FORGOTTEN) { - forget_map(ALL_MAP); /* forget the map */ - forget_traps(); /* forget all traps too */ - familiar = TRUE; - g.level_info[new_ledger].flags &= ~FORGOTTEN; - } - /* Reset the screen. */ vision_reset(); /* reset the blockages */ g.glyphmap_perlevel_flags = 0L; /* force per-level mapglyph() changes */ diff --git a/src/dogmove.c b/src/dogmove.c index a70c9c70a..57ebcb66a 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1181,6 +1181,10 @@ int after; /* this is extra fast monster movement */ } } } + + /* pet moved when attacking */ + if (mtmp->mx != omx || mtmp->my != omy) + return 0; } } diff --git a/src/dothrow.c b/src/dothrow.c index 3af418ecd..50e2f07bd 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1583073990 2020/03/01 14:46:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.183 $ */ +/* NetHack 3.6 dothrow.c $NHDT-Date: 1584398443 2020/03/16 22:40:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.184 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -714,8 +714,9 @@ int x, y; } } - /* Caller has already determined that dragging the ball is allowed */ - if (Punished && uball->where == OBJ_FLOOR) { + /* caller has already determined that dragging the ball is allowed; + if ball is carried we might still need to drag the chain */ + if (Punished) { int bc_control; xchar ballx, bally, chainx, chainy; boolean cause_delay; diff --git a/src/dungeon.c b/src/dungeon.c index 94712d465..26c28bf1a 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1958,7 +1958,7 @@ const char *nam; && dlev.dnum == valley_level.dnum)) && (/* either wizard mode or else seen and not forgotten */ wizard - || (g.level_info[idx].flags & (FORGOTTEN | VISITED)) + || (g.level_info[idx].flags & (VISITED)) == VISITED)) { lev = depth(&dlev); } @@ -1973,9 +1973,9 @@ const char *nam; idx &= 0x00FF; /* either wizard mode, or else _both_ sides of branch seen */ if (wizard - || (((g.level_info[idx].flags & (FORGOTTEN | VISITED)) + || (((g.level_info[idx].flags & (VISITED)) == VISITED) - && ((g.level_info[idxtoo].flags & (FORGOTTEN | VISITED)) + && ((g.level_info[idxtoo].flags & (VISITED)) == VISITED))) { if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo; @@ -2392,35 +2392,6 @@ const char *s; } -void -forget_mapseen(ledger_num) -int ledger_num; -{ - mapseen *mptr; - struct cemetery *bp; - - for (mptr = g.mapseenchn; mptr; mptr = mptr->next) - if (g.dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel - == ledger_num) - break; - - /* if not found, then nothing to forget */ - if (mptr) { - mptr->flags.forgot = 1; - mptr->br = (branch *) 0; - - /* custom names are erased, not just forgotten until revisited */ - if (mptr->custom) { - mptr->custom_lth = 0; - free((genericptr_t) mptr->custom); - mptr->custom = (char *) 0; - } - (void) memset((genericptr_t) mptr->msrooms, 0, sizeof mptr->msrooms); - for (bp = mptr->final_resting_place; bp; bp = bp->next) - bp->bonesknown = FALSE; - } -} - void rm_mapseen(ledger_num) int ledger_num; diff --git a/src/eat.c b/src/eat.c index a628ebb80..d745f8e3a 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 eat.c $NHDT-Date: 1577190688 2019/12/24 12:31:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.222 $ */ +/* NetHack 3.6 eat.c $NHDT-Date: 1584405116 2020/03/17 00:31:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.223 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3056,17 +3056,16 @@ boolean incr; switch (newhs) { case HUNGRY: if (Hallucination) { - You((!incr) ? "now have a lesser case of the munchies." - : "are getting the munchies."); + You(!incr ? "now have a lesser case of the munchies." + : "are getting the munchies."); } else - You((!incr) ? "only feel hungry now." - : (u.uhunger < 145) - ? "feel hungry." - : "are beginning to feel hungry."); + You(!incr ? "only feel hungry now." + : (u.uhunger < 145) ? "feel hungry." + : "are beginning to feel hungry."); if (incr && g.occupation && (g.occupation != eatfood && g.occupation != opentin)) stop_occupation(); - g.context.travel = g.context.travel1 = g.context.mv = g.context.run = 0; + end_running(TRUE); break; case WEAK: if (Hallucination) @@ -3079,14 +3078,13 @@ boolean incr; ? g.urole.name.m : "Elf"); else - You((!incr) - ? "feel weak now." - : (u.uhunger < 45) ? "feel weak." - : "are beginning to feel weak."); + You(!incr ? "feel weak now." + : (u.uhunger < 45) ? "feel weak." + : "are beginning to feel weak."); if (incr && g.occupation && (g.occupation != eatfood && g.occupation != opentin)) stop_occupation(); - g.context.travel = g.context.travel1 = g.context.mv = g.context.run = 0; + end_running(TRUE); break; } u.uhs = newhs; diff --git a/src/hack.c b/src/hack.c index 68ab503ff..33ddb5a2a 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1582799171 2020/02/27 10:26:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.249 $ */ +/* NetHack 3.6 hack.c $NHDT-Date: 1584405116 2020/03/17 00:31:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.250 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -954,7 +954,7 @@ int mode; if ((mode == TRAVP_TRAVEL || mode == TRAVP_VALID) && g.context.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1 && !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) { - g.context.run = 0; + end_running(FALSE); if (test_move(u.ux, u.uy, u.tx - u.ux, u.ty - u.uy, TEST_MOVE)) { if (mode == TRAVP_TRAVEL) { u.dx = u.tx - u.ux; @@ -1964,10 +1964,14 @@ domove_core() } if (g.context.run && flags.runmode != RUN_TPORT) { - /* display every step or every 7th step depending upon mode */ + /* for tport mode, don't display anything until we've stopped; + for normal (leap) mode, update display every 7th step + (relative to turn counter; ought to be to start of running); + for walk and crawl (visual debugging) modes, update the + display after every step */ if (flags.runmode != RUN_LEAP || !(g.moves % 7L)) { - if (flags.time) - iflags.time_botl = 1; + /* moveloop() suppresses time_botl when running */ + iflags.time_botl = flags.time; curs_on_u(); delay_output(); if (flags.runmode == RUN_CRAWL) { @@ -2927,6 +2931,21 @@ monster_nearby() return 0; } +void +end_running(and_travel) +boolean and_travel; +{ + /* moveloop() suppresses time_botl when context.run is non-zero; when + running stops, update 'time' even if other botl status is unchanged */ + if (flags.time && g.context.run) + iflags.time_botl = TRUE; + g.context.run = 0; + /* 'context.mv' isn't travel but callers who want to end travel + all clear it too */ + if (and_travel) + g.context.travel = g.context.travel1 = g.context.mv = 0; +} + void nomul(nval) int nval; @@ -2939,7 +2958,7 @@ int nval; g.multi = nval; if (nval == 0) g.multi_reason = NULL; - g.context.travel = g.context.travel1 = g.context.mv = g.context.run = 0; + end_running(TRUE); } /* called when a non-movement, multi-turn action has completed */ @@ -2947,7 +2966,7 @@ void unmul(msg_override) const char *msg_override; { - g.context.botl = 1; + g.context.botl = TRUE; g.multi = 0; /* caller will usually have done this already */ if (msg_override) g.nomovemsg = msg_override; @@ -3018,11 +3037,19 @@ register int n; register const char *knam; boolean k_format; { +#if 0 /* code below is prepared to handle negative 'loss' so don't add this + * until we've verified that no callers intentionally rely on that */ + if (n <= 0) { + impossible("hero losing %d hit points due to \"%s\"?", n, knam); + return; + } +#endif + g.context.botl = TRUE; /* u.uhp or u.mh is changing */ + end_running(TRUE); if (Upolyd) { u.mh -= n; if (u.mhmax < u.mh) u.mhmax = u.mh; - g.context.botl = 1; if (u.mh < 1) rehumanize(); else if (n > 0 && u.mh * 10 < u.mhmax && Unchanging) @@ -3033,9 +3060,6 @@ boolean k_format; u.uhp -= n; if (u.uhp > u.uhpmax) u.uhpmax = u.uhp; /* perhaps n was negative */ - else - g.context.travel = g.context.travel1 = g.context.mv = g.context.run = 0; - g.context.botl = 1; if (u.uhp < 1) { g.killer.format = k_format; if (g.killer.name != knam) /* the thing that killed you */ diff --git a/src/hacklib.c b/src/hacklib.c index 5d53bccbc..89905d194 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -73,6 +73,7 @@ void strbuf_nl_to_crlf (strbuf_t *) char * nonconst (const char *, char *) int swapbits (int, int, int) +UNUSED void shuffle_int_array (int *, int) =*/ #ifdef LINT #define Static /* pacify lint */ @@ -1301,4 +1302,23 @@ int val, bita, bitb; return (val ^ ((tmp << bita) | (tmp << bitb))); } +#if 0 +/* randomize the given list of numbers 0 <= i < count */ +static void +shuffle_int_array(indices, count) +int *indices; +int count; +{ + int i, iswap, temp; + + for (i = count - 1; i > 0; i--) { + if ((iswap = rn2(i + 1)) == i) + continue; + temp = indices[i]; + indices[i] = indices[iswap]; + indices[iswap] = temp; + } +} +#endif + /*hacklib.c*/ diff --git a/src/mhitu.c b/src/mhitu.c index df2c1892c..8b9bf128a 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1175,8 +1175,6 @@ register struct attack *mattk; } /* adjattrib gives dunce cap message when appropriate */ (void) adjattrib(A_INT, -rnd(2), FALSE); - forget_levels(25); /* lose memory of 25% of levels */ - forget_objects(25); /* lose memory of 25% of objects */ break; case AD_PLYS: hitmsg(mtmp, mattk); diff --git a/src/mklev.c b/src/mklev.c index 85127f6cc..414bd90b6 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1543,7 +1543,7 @@ coord *tm; otmp = mkcorpstat(CORPSE, NULL, &mons[victim_mnum], m.x, m.y, CORPSTAT_INIT); if (otmp) - otmp->age -= 51; /* died too long ago to eat */ + otmp->age -= (TAINT_AGE + 1); /* died too long ago to eat */ } } diff --git a/src/mkobj.c b/src/mkobj.c index 91e12b882..0248c873e 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1189,10 +1189,6 @@ struct obj *body; int rot_adjust; short action; -#define TAINT_AGE (50L) /* age when corpses go bad */ -#define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */ -#define ROT_AGE (250L) /* age when corpses rot away */ - /* lizards and lichen don't rot or revive */ if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return; diff --git a/src/mon.c b/src/mon.c index 8532d89f0..3fe0697b1 100644 --- a/src/mon.c +++ b/src/mon.c @@ -350,7 +350,7 @@ unsigned corpseflags; num = undead_to_corpse(mndx); corpstatflags |= CORPSTAT_INIT; obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); - obj->age -= 100; /* this is an *OLD* corpse */ + obj->age -= (TAINT_AGE + 1); /* this is an *OLD* corpse */ break; case PM_KOBOLD_MUMMY: case PM_DWARF_MUMMY: @@ -371,7 +371,7 @@ unsigned corpseflags; num = undead_to_corpse(mndx); corpstatflags |= CORPSTAT_INIT; obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); - obj->age -= 100; /* this is an *OLD* corpse */ + obj->age -= (TAINT_AGE + 1); /* this is an *OLD* corpse */ break; case PM_IRON_GOLEM: num = d(2, 6); @@ -4170,6 +4170,22 @@ pacify_guards() } } +struct monst * +find_ghost_with_name(str) +char *str; +{ + struct monst *mtmp; + + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp) + || mtmp->data != &mons[PM_GHOST] || !has_mname(mtmp)) + continue; + if (!strcmpi(MNAME(mtmp), str)) + return mtmp; + } + return (struct monst *) 0; +} + void mimic_hit_msg(mtmp, otyp) struct monst *mtmp; diff --git a/src/mondata.c b/src/mondata.c index 4ee2a6ffe..9672159ee 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -757,6 +757,7 @@ const char *in_str; /* Hyphenated names -- it would be nice to handle these via fuzzymatch() but it isn't able to ignore trailing stuff */ { "ki rin", PM_KI_RIN }, + { "kirin", PM_KI_RIN }, { "uruk hai", PM_URUK_HAI }, { "orc captain", PM_ORC_CAPTAIN }, { "woodland elf", PM_WOODLAND_ELF }, diff --git a/src/options.c b/src/options.c index e4532de29..4570bcf1f 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 options.c $NHDT-Date: 1583282760 2020/03/04 00:46:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.457 $ */ +/* NetHack 3.7 options.c $NHDT-Date: 1584350350 2020/03/16 09:19:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.459 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -7568,6 +7568,8 @@ doset() /* changing options via menu by Per Liboriussen */ check_gold_symbol(); reglyph_darkroom(); (void) doredraw(); + } else if (g.context.botl || g.context.botlx) { + bot(); } return 0; } diff --git a/src/read.c b/src/read.c index 87320dca8..18d2cfd2f 100644 --- a/src/read.c +++ b/src/read.c @@ -22,11 +22,6 @@ static char *FDECL(apron_text, (struct obj *, char *buf)); static void FDECL(stripspe, (struct obj *)); static void FDECL(p_glow1, (struct obj *)); static void FDECL(p_glow2, (struct obj *, const char *)); -static void FDECL(forget_single_object, (int)); -#if 0 /* not used */ -static void FDECL(forget_objclass, (int)); -#endif -static void FDECL(randomize, (int *, int)); static void FDECL(forget, (int)); static int FDECL(maybe_tame, (struct monst *, struct obj *)); static boolean FDECL(get_valid_stinking_cloud_pos, (int, int)); @@ -711,183 +706,13 @@ int curse_bless; } } -/* Forget known information about this object type. */ -static void -forget_single_object(obj_id) -int obj_id; -{ - objects[obj_id].oc_name_known = 0; - objects[obj_id].oc_pre_discovered = 0; /* a discovery when relearned */ - if (objects[obj_id].oc_uname) { - free((genericptr_t) objects[obj_id].oc_uname); - objects[obj_id].oc_uname = 0; - } - undiscover_object(obj_id); /* after clearing oc_name_known */ - - /* clear & free object names from matching inventory items too? */ -} - -#if 0 /* here if anyone wants it.... */ -/* Forget everything known about a particular object class. */ -static void -forget_objclass(oclass) -int oclass; -{ - int i; - - for (i = g.bases[oclass]; - i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) - forget_single_object(i); -} -#endif - -/* randomize the given list of numbers 0 <= i < count */ -static void -randomize(indices, count) -int *indices; -int count; -{ - int i, iswap, temp; - - for (i = count - 1; i > 0; i--) { - if ((iswap = rn2(i + 1)) == i) - continue; - temp = indices[i]; - indices[i] = indices[iswap]; - indices[iswap] = temp; - } -} - -/* Forget % of known objects. */ -void -forget_objects(percent) -int percent; -{ - int i, count; - int indices[NUM_OBJECTS]; - - if (percent == 0) - return; - if (percent <= 0 || percent > 100) { - impossible("forget_objects: bad percent %d", percent); - return; - } - - indices[0] = 0; /* lint suppression */ - for (count = 0, i = 1; i < NUM_OBJECTS; i++) - if (OBJ_DESCR(objects[i]) - && (objects[i].oc_name_known || objects[i].oc_uname)) - indices[count++] = i; - - if (count > 0) { - randomize(indices, count); - - /* forget first % of randomized indices */ - count = ((count * percent) + rn2(100)) / 100; - for (i = 0; i < count; i++) - forget_single_object(indices[i]); - } -} - -/* Forget some or all of map (depends on parameters). */ -void -forget_map(howmuch) -int howmuch; -{ - register int zx, zy; - - if (Sokoban) - return; - - g.known = TRUE; - for (zx = 0; zx < COLNO; zx++) - for (zy = 0; zy < ROWNO; zy++) - if (howmuch & ALL_MAP || rn2(7)) { - /* Zonk all memory of this location. */ - levl[zx][zy].seenv = 0; - levl[zx][zy].waslit = 0; - levl[zx][zy].glyph = GLYPH_UNEXPLORED; - g.lastseentyp[zx][zy] = STONE; - } - /* forget overview data for this level */ - forget_mapseen(ledger_no(&u.uz)); -} - -/* Forget all traps on the level. */ -void -forget_traps() -{ - register struct trap *trap; - - /* forget all traps (except the one the hero is in :-) */ - for (trap = g.ftrap; trap; trap = trap->ntrap) - if ((trap->tx != u.ux || trap->ty != u.uy) && (trap->ttyp != HOLE)) - trap->tseen = 0; -} - -/* - * Forget given % of all levels that the hero has visited and not forgotten, - * except this one. - */ -void -forget_levels(percent) -int percent; -{ - int i, count; - xchar maxl, this_lev; - int indices[MAXLINFO]; - - if (percent == 0) - return; - - if (percent <= 0 || percent > 100) { - impossible("forget_levels: bad percent %d", percent); - return; - } - - this_lev = ledger_no(&u.uz); - maxl = maxledgerno(); - - /* count & save indices of non-forgotten visited levels */ - /* Sokoban levels are pre-mapped for the player, and should stay - * so, or they become nearly impossible to solve. But try to - * shift the forgetting elsewhere by fiddling with percent - * instead of forgetting fewer levels. - */ - indices[0] = 0; /* lint suppression */ - for (count = 0, i = 0; i <= maxl; i++) - if ((g.level_info[i].flags & VISITED) - && !(g.level_info[i].flags & FORGOTTEN) && i != this_lev) { - if (ledger_to_dnum(i) == sokoban_dnum) - percent += 2; - else - indices[count++] = i; - } - - if (percent > 100) - percent = 100; - - if (count > 0) { - randomize(indices, count); - - /* forget first % of randomized indices */ - count = ((count * percent) + 50) / 100; - for (i = 0; i < count; i++) { - g.level_info[indices[i]].flags |= FORGOTTEN; - forget_mapseen(indices[i]); - } - } -} - /* * Forget some things (e.g. after reading a scroll of amnesia). When called, * the following are always forgotten: * - felt ball & chain - * - traps - * - part (6 out of 7) of the map + * - skill training * * Other things are subject to flags: - * howmuch & ALL_MAP = forget whole map * howmuch & ALL_SPELLS = forget all spells */ static void @@ -897,30 +722,11 @@ int howmuch; if (Punished) u.bc_felt = 0; /* forget felt ball&chain */ - forget_map(howmuch); - forget_traps(); - - /* 1 in 3 chance of forgetting some levels */ - if (!rn2(3)) - forget_levels(rn2(25)); - - /* 1 in 3 chance of forgetting some objects */ - if (!rn2(3)) - forget_objects(rn2(25)); - if (howmuch & ALL_SPELLS) losespells(); - /* - * Make sure that what was seen is restored correctly. To do this, - * we need to go blind for an instant --- turn off the display, - * then restart it. All this work is needed to correctly handle - * walls which are stone on one side and wall on the other. Turning - * off the seen bits above will make the wall revert to stone, but - * there are cases where we don't want this to happen. The easiest - * thing to do is to run it through the vision system again, which - * is always correct. - */ - docrt(); /* this correctly will reset vision */ + + /* Forget some skills. */ + drain_weapon_skill(rnd(howmuch ? 5 : 3)); } /* monster is hit by scroll of taming's effect */ @@ -1579,8 +1385,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ break; case SCR_AMNESIA: g.known = TRUE; - forget((!sblessed ? ALL_SPELLS : 0) - | (!confused || scursed ? ALL_MAP : 0)); + forget((!sblessed ? ALL_SPELLS : 0)); if (Hallucination) /* Ommmmmm! */ Your("mind releases itself from mundane concerns."); else if (!strncmpi(g.plname, "Maud", 4)) diff --git a/src/sit.c b/src/sit.c index 19d5dbdfe..8d26e2db8 100644 --- a/src/sit.c +++ b/src/sit.c @@ -210,7 +210,7 @@ dosit() /* Magical voice not affected by deafness */ pline("A voice echoes:"); - verbalize("Thy audience hath been summoned, %s!", + verbalize("Thine audience hath been summoned, %s!", flags.female ? "Dame" : "Sire"); while (cnt--) (void) makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS); diff --git a/src/sp_lev.c b/src/sp_lev.c index 9f0d3b943..abaeb7656 100755 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -453,8 +453,8 @@ boolean extras; /* get_level_extends() returns -1,-1 to COLNO,ROWNO at max */ if (miny < 0) miny = 0; - if (minx < 0) - minx = 0; + if (minx < 1) + minx = 1; if (maxx >= COLNO) maxx = (COLNO - 1); if (maxy >= ROWNO) diff --git a/src/spell.c b/src/spell.c index 5424f468c..ebf2f5d7d 100644 --- a/src/spell.c +++ b/src/spell.c @@ -397,8 +397,6 @@ learn(VOID_ARGS) book->spestudied++; exercise(A_WIS, TRUE); /* extra study */ } - /* make book become known even when spell is already - known, in case amnesia made you forget the book */ makeknown((int) booktype); } else { /* (spellid(i) == NO_SPELL) */ /* for a normal book, spestudied will be zero, but for diff --git a/src/teleport.c b/src/teleport.c index 64bba0c77..ba931b51e 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -719,11 +719,7 @@ boolean break_the_rules; /* True: wizard mode ^T */ if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12) && !can_teleport(g.youmonst.data))) { - /* Try to use teleport away spell. - Prior to 3.6.2 this used to require that you know the spellbook - (probably just intended as an optimization to skip the - lookup loop) but it is possible to know and cast a spell - after forgetting its book due to amnesia. */ + /* Try to use teleport away spell. */ for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (g.spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) break; diff --git a/src/uhitm.c b/src/uhitm.c index 71f393a14..e9d724129 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1581886869 2020/02/16 21:01:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.227 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1584405117 2020/03/17 00:31:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.228 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -366,14 +366,12 @@ register struct monst *mtmp; Strcpy(buf, y_monnam(mtmp)); buf[0] = highc(buf[0]); You("stop. %s is in the way!", buf); - g.context.travel = g.context.travel1 = g.context.mv = g.context.run - = 0; + end_running(TRUE); return TRUE; } else if ((mtmp->mfrozen || (!mtmp->mcanmove) || (mtmp->data->mmove == 0)) && rn2(6)) { pline("%s doesn't seem to move!", Monnam(mtmp)); - g.context.travel = g.context.travel1 = g.context.mv = g.context.run - = 0; + end_running(TRUE); return TRUE; } else return FALSE; diff --git a/src/weapon.c b/src/weapon.c index 4eb0dd6da..c3deda3a4 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1373,6 +1373,44 @@ int n; /* number of slots to lose; normally one */ } } +void +drain_weapon_skill(n) +int n; /* number of skills to drain */ +{ + int skill; + int i; + int tmpskills[P_NUM_SKILLS]; + + (void) memset((genericptr_t) tmpskills, 0, sizeof(tmpskills)); + + while (--n >= 0) { + if (u.skills_advanced) { + /* Pick a random skill, deleting it from the list. */ + i = rn2(u.skills_advanced); + skill = u.skill_record[i]; + tmpskills[skill] = 1; + for (; i < u.skills_advanced - 1; i++) { + u.skill_record[i] = u.skill_record[i + 1]; + } + u.skills_advanced--; + if (P_SKILL(skill) <= P_UNSKILLED) + panic("drain_weapon_skill (%d)", skill); + P_SKILL(skill)--; /* drop skill one level */ + /* refund slots used for skill */ + u.weapon_slots += slots_required(skill); + /* drain a random proportion of skill training */ + if (P_ADVANCE(skill)) + P_ADVANCE(skill) = rn2(P_ADVANCE(skill)); + } + } + + for (skill = 0; skill < P_NUM_SKILLS; skill++) + if (tmpskills[skill]) { + You("forget %syour training in %s.", + P_SKILL(skill) >= P_BASIC ? "some of " : "", P_NAME(skill)); + } +} + int weapon_type(obj) struct obj *obj; diff --git a/win/X11/winstat.c b/win/X11/winstat.c index 965d3859c..34b172cf4 100644 --- a/win/X11/winstat.c +++ b/win/X11/winstat.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winstat.c $NHDT-Date: 1582833042 2020/02/27 19:50:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.24 $ */ +/* NetHack 3.6 winstat.c $NHDT-Date: 1584482684 2020/03/17 22:04:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -1341,21 +1341,12 @@ static void hilight_label(w) Widget w; /* label widget */ { - Arg args[2]; - Pixel fg, bg; /* * This predates STATUS_HILITES. * It is used to show any changed item in inverse and gets * reset on the next turn. */ - - XtSetArg(args[0], XtNforeground, &fg); - XtSetArg(args[1], XtNbackground, &bg); - XtGetValues(w, args, TWO); - - XtSetArg(args[0], XtNforeground, bg); - XtSetArg(args[1], XtNbackground, fg); - XtSetValues(w, args, TWO); + swap_fg_bg(w); } static void @@ -1415,14 +1406,17 @@ long new_value; /* special cases: hunger and encumbrance */ if (attr_rec == &shown_stats[F_HUNGER]) { - XtSetArg(args[0], XtNlabel, hu_stat[new_value]); + Strcpy(buf, hu_stat[new_value]); + (void) mungspaces(buf); } else if (attr_rec == &shown_stats[F_ENCUMBER]) { - XtSetArg(args[0], XtNlabel, enc_stat[new_value]); + Strcpy(buf, enc_stat[new_value]); } else if (new_value) { - XtSetArg(args[0], XtNlabel, attr_rec->name); + Strcpy(buf, attr_rec->name); /* condition name On */ } else { - XtSetArg(args[0], XtNlabel, ""); + *buf = '\0'; /* condition name Off */ } + + XtSetArg(args[0], XtNlabel, buf); XtSetValues(attr_rec->w, args, ONE); } else { /* a value pair */ @@ -1532,18 +1526,28 @@ long new_value; } /* - * Now hilight the changed information. Names, time and score don't - * hilight. If first time, don't hilight. If already lit, don't do - * it again. + * Now highlight the changed information. Don't highlight Time because + * it's continually changing. For others, don't highlight if this is + * the first update. If already highlighted, don't change it unless + * it's being set to blank (where that item should be reset now instead + * of showing highlighted blank until the next expiration check). + * + * 3.7: highlight non-labelled 'name' items (conditions plus hunger + * and encumbrance) when they come On. For all conditions going Off, + * or changing to not-hungry or not-encumbered, there's nothing to + * highlight because the field becomes blank. */ - if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) { + if (attr_rec != &shown_stats[F_TIME]) { if (attr_rec->after_init) { - if (!attr_rec->set) { - if (attr_rec->type == SV_LABEL) + /* toggle if not highlighted and just set to nonblank or if + already highlighted and just set to blank */ + if (!attr_rec->set ^ !*buf) { + if (attr_rec->type == SV_LABEL || attr_rec->type == SV_NAME) hilight_label(attr_rec->w); else hilight_value(attr_rec->w); - attr_rec->set = TRUE; + + attr_rec->set = !attr_rec->set; } attr_rec->turn_count = 0; } else { @@ -1780,8 +1784,8 @@ check_turn_events() continue; if (sv->turn_count++ >= hilight_time) { - /* unhighlights by toggling a highlit item back off again */ - if (sv->type == SV_LABEL) + /* unhighlights by toggling a highlighted item back off again */ + if (sv->type == SV_LABEL || sv->type == SV_NAME) hilight_label(sv->w); else hilight_value(sv->w);