From 267daeaa0fb611b91fbe90ca61184d1635fc8748 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 23 Jan 2024 15:42:19 -0800 Subject: [PATCH] supply chest fixes for "odd encumbrance behavior" Changing the quantity to 2 (50:50 chance) when creating a potion of healing (also 50:50 chance for each attempt) to place inside a supply chest wasn't updating the potion stack's weight, resulting in the odd encumbrance behavior that was reported last December. Taking the stack out of the container doesn't fix the weight but drinking one of the potions splits the stack of 2 into two stacks of 1 and does update the weight for both. That gives the hero higher encumbrance when the formerly weightless one has its proper weight. Finishing drinking the potion uses it up, removing second potion's weight again. When below an encumbrance threshold by the weight of one potion or less, player will see encumbrance increase and then decrease, with healing message given before both due to sequencing. Supply chests weren't having their own weight updated when they were populated, so would behave as if empty if hero carried them around. Removing something, breaking something by kicking the chest, or adding something would update its weight to match its contents. I also noticed a refutation (or should that be rebuttable?) to my own remarks in this: | commit cd91d0630b4aac8b502713715b29a696ece5d765 | Author: PatR | Date: Sat Dec 30 17:10:39 2023 -0800 | | github issue #1180 - humans and murder | | Issue reported by Umbire: reviving a human corpse into a human | monster and then killing it entails murder penalty even when it is | hostile. | | This is probably a non-issue. Human monsters tend to not leave | human corpses, they leave shopkeeper corpses or sergeant corpses [...] Dead fake hero corpses placed at trap locations on early levels are leaving plain human|dwarf|elf|gnome|orc corpses rather than fake player monster ones (which are always human but resurrect as player monsters rather than as plain humans), so there are more plain human corpses now than there were in 3.6.x or early to-be-3.7. I've added a comment about the situation. --- doc/fixes3-7-0.txt | 7 +++++ src/mklev.c | 78 +++++++++++++++++++++++++++------------------- src/mkobj.c | 25 ++++++++++----- 3 files changed, 71 insertions(+), 39 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 06ead54eb..532a4b454 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1838,6 +1838,13 @@ farlook at something that was on top of an engraving or grave would report the engraving text or headstone epitaph along with the 'something' when carrying 52 items (excluding gold), hero couldn't pick up a thrown, stolen, or dropped item which was split off from a still-carried stack +supply chests on early levels weighed the same as empty chests until something + was added or removed +stacked pair of potions of healing in supply chest weighed same as one potion; + drinking one of the two gave a healing message, then both had their + weight updated as their stack was split; if close to an encumbrance + threshold, new weight would trigger an encumbrance increase message, + immediately followed a decrease message when the potion got used up Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/mklev.c b/src/mklev.c index 4c5f1488f..82550beba 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -949,29 +949,27 @@ fill_ordinary_room( supply_chest->olocked = !!(rn2(6)); do { - /* 50% this is a potion of healing */ - if (rn2(2)) { - otyp = POT_HEALING; - } else { - static const int supply_items[] = { - POT_EXTRA_HEALING, - POT_SPEED, - POT_GAIN_ENERGY, - SCR_ENCHANT_WEAPON, - SCR_ENCHANT_ARMOR, - SCR_CONFUSE_MONSTER, - SCR_SCARE_MONSTER, - WAN_DIGGING, - SPE_HEALING, - }; + static const int supply_items[] = { + POT_EXTRA_HEALING, + POT_SPEED, + POT_GAIN_ENERGY, + SCR_ENCHANT_WEAPON, + SCR_ENCHANT_ARMOR, + SCR_CONFUSE_MONSTER, + SCR_SCARE_MONSTER, + WAN_DIGGING, + SPE_HEALING, + }; - otyp = ROLL_FROM(supply_items); - } + /* 50% this is a potion of healing */ + otyp = rn2(2) ? POT_HEALING : ROLL_FROM(supply_items); otmp = mksobj(otyp, TRUE, FALSE); - if (otyp == POT_HEALING && rn2(2)) + if (otyp == POT_HEALING && rn2(2)) { otmp->quan = 2; + otmp->owt = weight(otmp); + } cursed = otmp->cursed; - add_to_container(supply_chest, otmp); + add_to_container(supply_chest, otmp); /* owt updated below */ ++tryct; if (tryct == 50) { @@ -1004,21 +1002,29 @@ fill_ordinary_room( otmp = mkobj(oclass, FALSE); if (oclass == SPBOOK_no_NOVEL) { - /* bias towards lower level by generating again - and taking the lower-level book */ - struct obj *otmp2 = mkobj(oclass, FALSE); + int pass, maxpass = (depth(&u.uz) > 2) ? 2 : 3; - if (objects[otmp->otyp].oc_level - <= objects[otmp2->otyp].oc_level) { - dealloc_obj(otmp2); - } else { - dealloc_obj(otmp); - otmp = otmp2; + /* bias towards lower level by generating again + and taking the lower-level book; do that three + times if on level 1 or 2, twice when deeper */ + for (pass = 1; pass <= maxpass; ++pass) { + struct obj *otmp2 = mkobj(oclass, FALSE); + + if (objects[otmp->otyp].oc_level + <= objects[otmp2->otyp].oc_level) { + dealloc_obj(otmp2); + } else { + dealloc_obj(otmp); + otmp = otmp2; + } } } - add_to_container(supply_chest, otmp); + add_to_container(supply_chest, otmp); /* owt updated below */ } + /* add_to_container() doesn't update the container's weight */ + supply_chest->owt = weight(supply_chest); + skip_chests = TRUE; /* don't want a second chest in this room */ } } @@ -1029,7 +1035,8 @@ fill_ordinary_room( * of rooms; about 5 - 7.5% for 2 boxes, least likely * when few rooms; chance for 3 or more is negligible. */ - if (!rn2(gn.nroom * 5 / 2) && somexyspace(croom, &pos) && !skip_chests) + /*assert(gn.nroom > 0); // must be true because we're filling a room*/ + if (!skip_chests && rn2(gn.nroom * 5 / 2) && somexyspace(croom, &pos)) (void) mksobj_at(rn2(3) ? LARGE_BOX : CHEST, pos.x, pos.y, TRUE, FALSE); @@ -1702,8 +1709,7 @@ mktrap_victim(struct trap *ttmp) otmp = mksobj(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE, TRUE, FALSE); otmp->quan = 1; - otmp->blessed = 0; - otmp->cursed = 1; + curse(otmp); otmp->owt = weight(otmp); place_object(otmp, x, y); } @@ -1711,6 +1717,14 @@ mktrap_victim(struct trap *ttmp) default: /* the most common race */ victim_mnum = PM_HUMAN; + /* + * FIXME: + * If resurrected, this corpse will produce a plain human. + * PM_HUMAN is used as a placeholder for zombie/mummy/vampire + * corpses and doesn't ordinarily occur as a living monster. + * Maybe we should generate and attach montraits for a very low + * level fake player? + */ break; } otmp = mkcorpstat(CORPSE, NULL, &mons[victim_mnum], x, y, diff --git a/src/mkobj.c b/src/mkobj.c index 7cc5ae225..7d9ed3461 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -220,6 +220,8 @@ mkobj_erosions(struct obj *otmp) } } +/* make a random object of class 'let' at a specific location; + 'let' might be random class; place_object() will validate */ struct obj * mkobj_at(char let, coordxy x, coordxy y, boolean artif) { @@ -230,8 +232,12 @@ mkobj_at(char let, coordxy x, coordxy y, boolean artif) return otmp; } +/* make a specific object at a specific location */ struct obj * -mksobj_at(int otyp, coordxy x, coordxy y, boolean init, boolean artif) +mksobj_at( + int otyp, + coordxy x, coordxy y, + boolean init, boolean artif) { struct obj *otmp; @@ -240,12 +246,13 @@ mksobj_at(int otyp, coordxy x, coordxy y, boolean init, boolean artif) return otmp; } + +/* used for extra orctown loot */ struct obj * mksobj_migr_to_species( int otyp, - unsigned int mflags2, - boolean init, - boolean artif) + unsigned mflags2, + boolean init, boolean artif) { struct obj *otmp; @@ -371,6 +378,7 @@ mkbox_cnts(struct obj *box) } (void) add_to_container(box, otmp); } + /* caller will update box->owt */ } /* select a random, common monster type */ @@ -848,8 +856,7 @@ unknow_object(struct obj *obj) obj->known = objects[obj->otyp].oc_uses_known ? 0 : 1; } -/* do some initialization to a newly created object. - object otyp must be set. */ +/* do some initialization to newly created object; otyp must already be set */ static void mksobj_init(struct obj *otmp, boolean artif) { @@ -1124,7 +1131,7 @@ mksobj_init(struct obj *otmp, boolean artif) otmp->corpsenm = rndmonnum(); if (!verysmall(&mons[otmp->corpsenm]) && rn2(level_difficulty() / 2 + 10) > 10) - (void) add_to_container(otmp, + (void) add_to_container(otmp, /* callber will update owt */ mkobj(SPBOOK_no_NOVEL, FALSE)); } /* boulder init'd below in the 'regardless of !init' code */ @@ -2578,6 +2585,10 @@ add_to_minv(struct monst *mon, struct obj *obj) /* * Add obj to container, make sure obj is "free". Returns (merged) obj. * The input obj may be deleted in the process. + * + * Caveat: this does not update the container's weight [possibly to + * prevent that from being recalculated repeatedly when adding multiple + * items]. */ struct obj * add_to_container(struct obj *container, struct obj *obj)