diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index ba11b8b90..24d7ec690 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1492,6 +1492,7 @@ artifact gifts are rebalanced (easier to obtain; higher-value sacrifices are the first gift; artifacts you can't use well are less likely) luck gains from sacrificing are limited by the value of the sacrifice failed #untrap could move hero diagonally into or out of an open doorway +remember box is trapped after finding the trap Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/doc/lua.adoc b/doc/lua.adoc index eea32e7d7..e9962a174 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -849,6 +849,7 @@ The table parameter accepts the following: | eroded | int | Object erosion | locked | boolean | Is the object locked? | trapped | boolean | Is the object trapped? +| trap_known | boolean | If container is trapped, is it obvious? | recharged | boolean | Is the object recharged? | greased | boolean | Is the object greased? | broken | boolean | Is the object broken? diff --git a/include/obj.h b/include/obj.h index f43d94f81..7d716c518 100644 --- a/include/obj.h +++ b/include/obj.h @@ -141,9 +141,9 @@ struct obj { * they have no locks */ Bitfield(pickup_prev, 1); /* was picked up previously */ Bitfield(ghostly, 1); /* it just got placed into a bones file */ + Bitfield(tknown, 1); /* trap status known for chests */ #if 0 /* not implemented */ - Bitfield(tknown, 1); /* trap status known for chests */ Bitfield(eknown, 1); /* effect known for wands zapped or rings worn when * not seen yet after being picked up while blind * [maybe for remaining stack of used potion too] */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 661160f1c..2f32a4b86 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 112 +#define EDITLEVEL 113 /* * Development status possibilities. diff --git a/include/sp_lev.h b/include/sp_lev.h index d4d4d8c4b..3a9a18d34 100644 --- a/include/sp_lev.h +++ b/include/sp_lev.h @@ -156,7 +156,7 @@ typedef struct { int quan; short buried; short lit; - short eroded, locked, trapped, recharged, invis, greased, broken, + short eroded, locked, trapped, tknown, recharged, invis, greased, broken, achievement; } object; diff --git a/src/detect.c b/src/detect.c index 7ccce8911..172f4704c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -930,6 +930,8 @@ detect_obj_traps( continue; } if (Is_box(otmp) && otmp->otrapped) { + otmp->tknown = 1; + otmp->dknown = 1; result |= u_at(x, y) ? OTRAP_HERE : OTRAP_THERE; if (ft) { flash_glyph_at(x, y, trapglyph, FOUND_FLASH_COUNT); diff --git a/src/lock.c b/src/lock.c index fa8fb22f8..640083041 100644 --- a/src/lock.c +++ b/src/lock.c @@ -105,11 +105,12 @@ picklock(void) : (gx.xlock.door->doormask & D_TRAPPED) != 0) && gx.xlock.magic_key) { gx.xlock.chance += 20; /* less effort needed next time */ - /* unfortunately we don't have a 'tknown' flag to record - "known to be trapped" so declining to disarm and then - retrying lock manipulation will find it all over again */ - if (y_n("You find a trap! Do you want to try to disarm it?") - == 'y') { + if (!gx.xlock.door) { + if (!gx.xlock.box->tknown) + You("find a trap!"); + gx.xlock.box->tknown = 1; + } + if (y_n("Do you want to try to disarm it?") == 'y') { const char *what; boolean alreadyunlocked; @@ -120,6 +121,7 @@ picklock(void) alreadyunlocked = !(gx.xlock.door->doormask & D_LOCKED); } else { gx.xlock.box->otrapped = 0; + gx.xlock.box->tknown = 0; what = (gx.xlock.box->otyp == CHEST) ? "chest" : "box"; alreadyunlocked = !gx.xlock.box->olocked; } diff --git a/src/mkobj.c b/src/mkobj.c index e332502bd..1ec69aa7d 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -852,6 +852,7 @@ unknow_object(struct obj *obj) obj->bknown = obj->rknown = 0; obj->cknown = obj->lknown = 0; + obj->tknown = 0; /* for an existing object, awareness of charges or enchantment has gone poof... [object types which don't use the known flag have it set True for some reason] */ @@ -1000,6 +1001,7 @@ mksobj_init(struct obj *otmp, boolean artif) case LARGE_BOX: otmp->olocked = !!(rn2(5)); otmp->otrapped = !(rn2(10)); + otmp->tknown = otmp->otrapped && !rn2(100); /* obvious trap */ FALLTHROUGH; /*FALLTHRU*/ case ICE_BOX: diff --git a/src/nhlobj.c b/src/nhlobj.c index ca2f74e17..6e97c3b87 100644 --- a/src/nhlobj.c +++ b/src/nhlobj.c @@ -295,6 +295,7 @@ l_obj_to_table(lua_State *L) nhl_add_table_entry_int(L, "dknown", obj->dknown); nhl_add_table_entry_int(L, "bknown", obj->bknown); nhl_add_table_entry_int(L, "rknown", obj->rknown); + nhl_add_table_entry_int(L, "tknown", obj->tknown); if (obj->oclass == POTION_CLASS) nhl_add_table_entry_int(L, "odiluted", obj->odiluted); else diff --git a/src/objnam.c b/src/objnam.c index 14227bc5c..a445564d5 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1334,6 +1334,9 @@ doname_base( Strcat(prefix, "uncursed "); } + /* "a large trapped box" would perhaps be more correct */ + if (Is_box(obj) && obj->otrapped && obj->tknown && obj->dknown) + Strcat(prefix,"trapped "); if (lknown && Is_box(obj)) { if (obj->obroken) /* 3.6.0 used "unlockable" here but that could be misunderstood diff --git a/src/sp_lev.c b/src/sp_lev.c index a429ba10b..135a72dec 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2277,6 +2277,8 @@ create_object(object *o, struct mkroom *croom) } if (o->trapped == 0 || o->trapped == 1) otmp->otrapped = o->trapped; + if (o->trapped && (o->tknown == 0 || o->tknown == 1)) + otmp->tknown = o->tknown; otmp->greased = o->greased ? 1 : 0; if (o->quan > 0 && objects[otmp->otyp].oc_merge) { @@ -3517,7 +3519,7 @@ lspo_object(lua_State *L) 0, /* quan */ 0, /* buried */ 0, /* lit */ - 0, 0, 0, 0, /* eroded, locked, trapped, recharged */ + 0, 0, 0, 0, 0, /* eroded, locked, trapped, tknown, recharged */ 0, 0, 0, 0, /* invis, greased, broken, achievement */ }; #if 0 @@ -3537,6 +3539,7 @@ lspo_object(lua_State *L) tmpobj.spe = -127; tmpobj.quan = -1; tmpobj.trapped = -1; + tmpobj.tknown = -1; tmpobj.locked = -1; tmpobj.corpsenm = NON_PM; @@ -3590,6 +3593,7 @@ lspo_object(lua_State *L) tmpobj.eroded = get_table_int_opt(L, "eroded", 0); tmpobj.locked = get_table_boolean_opt(L, "locked", -1); tmpobj.trapped = get_table_boolean_opt(L, "trapped", -1); + tmpobj.tknown = get_table_boolean_opt(L, "trap_known", -1); tmpobj.recharged = get_table_int_opt(L, "recharged", 0); tmpobj.greased = get_table_boolean_opt(L, "greased", 0); tmpobj.broken = get_table_boolean_opt(L, "broken", 0); diff --git a/src/trap.c b/src/trap.c index d1be7d9b5..0ee5db704 100644 --- a/src/trap.c +++ b/src/trap.c @@ -65,6 +65,7 @@ staticfn void clear_conjoined_pits(struct trap *); staticfn boolean adj_nonconjoined_pit(struct trap *); staticfn int try_lift(struct monst *, struct trap *, int, boolean); staticfn int help_monster_out(struct monst *, struct trap *); +staticfn void disarm_box(struct obj *, boolean, boolean); staticfn void untrap_box(struct obj *, boolean, boolean); #if 0 staticfn void join_adjacent_pits(struct trap *); @@ -5687,6 +5688,32 @@ help_monster_out( return 1; } +staticfn void +disarm_box(struct obj *box, boolean force, boolean confused) +{ + if (box->otrapped) { + int ch = ACURR(A_DEX) + u.ulevel; + + if (Role_if(PM_ROGUE)) + ch *= 2; + if (!force && (confused || Fumbling + || rnd(75 + level_difficulty() / 2) > ch)) { + (void) chest_trap(box, FINGER, TRUE); + /* 'box' might be gone now */ + } else { + You("disarm it!"); + box->otrapped = 0; + box->tknown = 0; + more_experienced(8, 0); + newexplevel(); + } + exercise(A_DEX, TRUE); + } else { + pline("That %s was not trapped.", xname(box)); + box->tknown = 0; + } +} + /* check a particular container for a trap and optionally disarm it */ staticfn void untrap_box( @@ -5696,32 +5723,19 @@ untrap_box( { if ((box->otrapped && (force || (!confused && rn2(MAXULEV + 1 - u.ulevel) < 10))) + || box->tknown || (!force && confused && !rn2(3))) { - You("find a trap on %s!", the(xname(box))); + if (!(box->tknown && box->dknown)) + You("find a trap on %s!", the(xname(box))); + else + pline("There's a trap on %s.", the(xname(box))); + box->tknown = 1; + box->dknown = 1; if (!confused) exercise(A_WIS, TRUE); - if (ynq("Disarm it?") == 'y') { - if (box->otrapped) { - int ch = ACURR(A_DEX) + u.ulevel; - - if (Role_if(PM_ROGUE)) - ch *= 2; - if (!force && (confused || Fumbling - || rnd(75 + level_difficulty() / 2) > ch)) { - (void) chest_trap(box, FINGER, TRUE); - /* 'box' might be gone now */ - } else { - You("disarm it!"); - box->otrapped = 0; - more_experienced(8, 0); - newexplevel(); - } - exercise(A_DEX, TRUE); - } else { - pline("That %s was not trapped.", xname(box)); - } - } + if (ynq("Disarm it?") == 'y') + disarm_box(box, force, confused); } else { You("find no traps on %s.", the(xname(box))); } @@ -5882,20 +5896,28 @@ untrap( whether any had been found but not attempted to untrap; now at most one per move may be checked and we only continue on to door handling if they are all declined */ - for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) - if (Is_box(otmp)) { + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) { + if (!Is_box(otmp)) + continue; + if (otmp->tknown && otmp->dknown) + (void) safe_qbuf(qbuf, "Disarm this ", NULL, + otmp, xname, ansimpleoname, "a box"); + else (void) safe_qbuf(qbuf, "There is ", " here. Check it for traps?", otmp, doname, ansimpleoname, "a box"); - switch (ynq(qbuf)) { + switch (ynq(qbuf)) { case 'q': return 0; case 'y': - untrap_box(otmp, force, confused); + if (otmp->tknown && otmp->dknown) + disarm_box(otmp, force, confused); + else + untrap_box(otmp, force, confused); return 1; /* even for 'no' at "Disarm it?" prompt */ } /* 'n' => continue to next box */ - } + } There("are no other chests or boxes here."); } @@ -6170,6 +6192,7 @@ chest_trap( if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ obj->ox = cc.x, obj->oy = cc.y; + otmp->tknown = 0; otmp->otrapped = 0; /* trap is one-shot; clear flag first in case chest kills you and ends up in bones file */ You(disarm ? "set it off!" : "trigger a trap!");