From 04c59fff0a80e244a1e7bfba8d64c5d0b5550d6c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 15 Mar 2020 11:29:32 +0200 Subject: [PATCH 01/14] Major amnesia revamp Instead of forgetting maps and objects, make amnesia forget skills. Forgetting maps and objects could be circumvented with taking notes, or by using an external tool to remember the forgotten levels. Forgetting skills allows the player to optionally go down another skill path, if they trained the wrong weapon in the early game. Amnesia still forgets spells. As a replacement for the deja vu messages when entering a forgotten level, those messages will now indicate a ghost with your own name existing on the level, given only when the level is entered for the first time. These changes based on fiqhack, with some adjustments. --- doc/fixes37.0 | 1 + include/dungeon.h | 2 +- include/extern.h | 7 +- src/do.c | 13 +--- src/dungeon.c | 35 +-------- src/mhitu.c | 2 - src/mon.c | 16 ++++ src/read.c | 187 ++-------------------------------------------- src/spell.c | 2 - src/teleport.c | 6 +- src/weapon.c | 39 ++++++++++ 11 files changed, 72 insertions(+), 238 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 93599f07b..56685a76e 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -79,6 +79,7 @@ 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 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository 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..4224e421c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); @@ -1509,6 +1508,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 +2166,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 +2952,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/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/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/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/mon.c b/src/mon.c index 8532d89f0..77c7bf073 100644 --- a/src/mon.c +++ b/src/mon.c @@ -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/read.c b/src/read.c index 87320dca8..abca909bb 100644 --- a/src/read.c +++ b/src/read.c @@ -22,10 +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 *)); @@ -711,36 +707,6 @@ 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) @@ -758,136 +724,13 @@ int count; } } -/* 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 +740,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 +1403,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/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/weapon.c b/src/weapon.c index 4eb0dd6da..d6e5f98b6 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1373,6 +1373,45 @@ 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]; + int tmpidx = 0; + + (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; From abbfabd49834f6fc8b468cec475d5285970432fd Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Mar 2020 08:58:07 +0200 Subject: [PATCH 02/14] Prevent ogres in trees in barbarian quest start --- dat/Bar-strt.lua | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) 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 From f6a282ec99983a4222e66fe128831a72b9370a76 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 16 Mar 2020 02:19:28 -0700 Subject: [PATCH 03/14] botl fixes Add a couple of missing status updates. --- src/botl.c | 9 +++++---- src/dig.c | 5 ++--- src/options.c | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) 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..9579b66b7 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. */ @@ -1827,8 +1827,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/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; } From 408321b4f77efeb20885b84f4ba66dfee5d7f955 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Mar 2020 11:27:33 +0200 Subject: [PATCH 04/14] Use TAINT_AGE for old corpses instead of hardcoded value --- include/hack.h | 5 +++++ src/dig.c | 2 +- src/mklev.c | 2 +- src/mkobj.c | 4 ---- src/mon.c | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) 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/dig.c b/src/dig.c index 9579b66b7..64dc5f117 100644 --- a/src/dig.c +++ b/src/dig.c @@ -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) 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 77c7bf073..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); From 9862d2c934f791f72f89ae68bc7ae358dcd3667b Mon Sep 17 00:00:00 2001 From: Patric Mueller Date: Mon, 16 Mar 2020 10:32:09 +0100 Subject: [PATCH 05/14] Use correct archaic form for "thine audience" Closes GitHub issue #313. --- src/sit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); From 712f545119071d715ad64179660414c591dab64d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Mar 2020 11:46:08 +0200 Subject: [PATCH 06/14] Move, rename, and comment out unused function --- src/hacklib.c | 20 ++++++++++++++++++++ src/read.c | 18 ------------------ src/weapon.c | 1 - 3 files changed, 20 insertions(+), 19 deletions(-) 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/read.c b/src/read.c index abca909bb..18d2cfd2f 100644 --- a/src/read.c +++ b/src/read.c @@ -22,7 +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(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)); @@ -707,23 +706,6 @@ int curse_bless; } } -/* 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 some things (e.g. after reading a scroll of amnesia). When called, * the following are always forgotten: diff --git a/src/weapon.c b/src/weapon.c index d6e5f98b6..c3deda3a4 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1380,7 +1380,6 @@ int n; /* number of skills to drain */ int skill; int i; int tmpskills[P_NUM_SKILLS]; - int tmpidx = 0; (void) memset((genericptr_t) tmpskills, 0, sizeof(tmpskills)); From 44ba4a9e96af9002a061c225fc0189e4bb183600 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Mar 2020 22:10:37 +0200 Subject: [PATCH 07/14] Don't flip column 0 --- src/sp_lev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) From 15019248aebf09dae0e98c5aa3eac62daf66205b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Mar 2020 22:13:17 +0200 Subject: [PATCH 08/14] Fix pet location inconsistency ... if the pet attacked hero or another monster by eg. swallowing them, the pet's location might've changed during that attack. Count it as movement, so return immediately. --- src/dogmove.c | 4 ++++ 1 file changed, 4 insertions(+) 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; } } From 8ccc9773aa9f2e51981e0dda8cc3f8e982b8b9bb Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 16 Mar 2020 15:40:52 -0700 Subject: [PATCH 09/14] fix #K608 - ball and chain distance warning This fixes the reported situation of recoiling from a throw while levitating and carrying the ball not bringing the chain but it might introduce other problems. If it does, drag_ball() would be the place to fix that, not hurtle_step(). Separate bug (not fixed): throwing while the ball is on the floor ought to let you recoil to as far as the chain will reach but it just yields "you feel a tug from the ball" and you don't recoil at all. --- doc/fixes37.0 | 4 +++- src/dothrow.c | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 56685a76e..46d09741e 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.135 $ $NHDT-Date: 1584398443 2020/03/16 22:40:43 $ General Fixes and Modified Features ----------------------------------- @@ -80,6 +80,8 @@ 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 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository 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; From 40d19525c3be7bba60a553cb539a5864e7e3089d Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 16 Mar 2020 17:32:12 -0700 Subject: [PATCH 10/14] updating 'time' status Handling botl updates for 'time' was inconsistent. Set the flag to do that when moves is incremented (where the update is suppressed if running) or when running stops short. losehp() would cancel running/traveling if called when in normal form but not if called when polymorphed, so theoretically you could take damage and keep on running. I don't have a test case to verify that. --- include/extern.h | 3 ++- src/allmain.c | 12 ++++-------- src/eat.c | 24 +++++++++++------------- src/hack.c | 46 +++++++++++++++++++++++++++++++++++----------- src/uhitm.c | 8 +++----- 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/include/extern.h b/include/extern.h index 4224e421c..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. */ @@ -906,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)); 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/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/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; From a57894cedbdd18e3f9c4e1d982988b14741a9632 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 17 Mar 2020 18:09:33 +0200 Subject: [PATCH 11/14] Prevent monsters in trees in monk quest start --- dat/Mon-strt.lua | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) 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 From 750d2fe560e4bbdc775be600bca8fb587cff1ab4 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 17 Mar 2020 19:06:32 +0200 Subject: [PATCH 12/14] Alias "kirin" for "ki-rin" --- doc/fixes37.0 | 1 + src/mondata.c | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 46d09741e..cb564f0d5 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -82,6 +82,7 @@ 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 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository 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 }, From 3546b2f0167735e722d70bc7502580061266a153 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 17 Mar 2020 15:04:54 -0700 Subject: [PATCH 13/14] X11 'fancy' status condition highlighting X11's "fancy status" does its own highlighting that predates STATUS_HILITES, showing things which have changed in inverse video for a turn. However, it excluded conditions plus hunger and encumbrance. Make it highlight those similarly when they come On (and when they change from one non-blank state to another in the case of hunger or encumbrance). There's no corresponding unhighlight when going Off because they're blanked out instead. --- doc/fixes37.0 | 4 +++- win/X11/winstat.c | 52 +++++++++++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index cb564f0d5..16e3a4feb 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.135 $ $NHDT-Date: 1584398443 2020/03/16 22:40:43 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.137 $ $NHDT-Date: 1584482684 2020/03/17 22:04:44 $ General Fixes and Modified Features ----------------------------------- @@ -133,6 +133,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/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); From 9ab6994eae995bb78f200251e6b8b96414ec48ac Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 18 Mar 2020 09:16:22 +0200 Subject: [PATCH 14/14] Make Juiblex resist magical digging from inside Juiblex should be a little bit harder to beat than zapping a digging wand once you've gotten swallowed and then whacking him once. Make his HP halve every time you zap digging instead of setting it to 1. Change via UnNetHack. --- doc/fixes37.0 | 1 + src/dig.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 16e3a4feb..1a63ba915 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -83,6 +83,7 @@ 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 diff --git a/src/dig.c b/src/dig.c index 64dc5f117..05cdbbdd7 100644 --- a/src/dig.c +++ b/src/dig.c @@ -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;