From 71113a697111604f044c91ff3c84075251190be7 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 31 May 2016 00:08:17 -0700 Subject: [PATCH] detecting chest and door traps When confused gold detection finds a door trap or a chest trap, it puts a bear trap glyph/tile on the map at that location. (They disappear once they're within sight.) Those should be given their own glyphs so that they can have their own tiles, but this doesn't do that. What it does do is describe such fake bear traps as "trapped door" or "trapped chest" when examined with far-look. The '^' command--if used while blind so that '^' hasn't disappeared yet--needs to catch up: it says "I can't see a trap there" when the adjacent '^' is a fake bear trap. --- doc/fixes36.1 | 4 +- include/extern.h | 2 + src/detect.c | 103 ++++++++++++++++++++++++++++++++++------------- src/pager.c | 12 +++++- 4 files changed, 90 insertions(+), 31 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index fbb8b5a9b..a7549db82 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -272,8 +272,10 @@ reviving one of a stack of N corpses in a shop charged a usage fee for all N; remaining N-1 were owned by hero if carried but by shop if on floor gremlin wailing in agony should wake up nearby monsters add more lighting variance to the second bigroom variant -when getpost was picking a location, typing '^' to move to the next known trap +when getpos was picking a location, typing '^' to move to the next known trap skipped some detected traps if their location was unseen +describe detected door traps and chest traps as trapped door and trapped chest + instead of bear trap; bear trap tile is still used on map though Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 1a20b24f2..4c5cb8e64 100644 --- a/include/extern.h +++ b/include/extern.h @@ -236,6 +236,8 @@ E void NDECL(decl_init); /* ### detect.c ### */ +E boolean FDECL(trapped_chest_at, (int, int, int)); +E boolean FDECL(trapped_door_at, (int, int, int)); E struct obj *FDECL(o_in, (struct obj *, CHAR_P)); E struct obj *FDECL(o_material, (struct obj *, unsigned)); E int FDECL(gold_detect, (struct obj *)); diff --git a/src/detect.c b/src/detect.c index 3726db68a..07b93227f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -22,8 +22,44 @@ STATIC_PTR void FDECL(findone, (int, int, genericptr_t)); STATIC_PTR void FDECL(openone, (int, int, genericptr_t)); STATIC_DCL int FDECL(mfind0, (struct monst *, BOOLEAN_P)); -/* Recursively search obj for an object in class oclass and return 1st found - */ +/* this is checking whether a trap symbol represents a trapped chest, + not whether a trapped chest is actually present */ +boolean +trapped_chest_at(ttyp, x, y) +int ttyp; +int x, y; +{ + if (!glyph_is_trap(glyph_at(x, y))) + return FALSE; + if (ttyp != BEAR_TRAP || (Hallucination && rn2(20))) + return FALSE; + /* presence of any trappable container will do */ + return (sobj_at(CHEST, x, y) || sobj_at(LARGE_BOX, x, y)) ? TRUE : FALSE; +} + +/* this is checking whether a trap symbol represents a trapped door, + not whether the door here is actually trapped */ +boolean +trapped_door_at(ttyp, x, y) +int ttyp; +int x, y; +{ + struct rm *lev; + + if (!glyph_is_trap(glyph_at(x, y))) + return FALSE; + if (ttyp != BEAR_TRAP || (Hallucination && rn2(20))) + return FALSE; + lev = &levl[x][y]; + if (!IS_DOOR(lev->typ)) + return FALSE; + if ((lev->doormask & (D_NODOOR | D_BROKEN | D_ISOPEN)) != 0 + && trapped_chest_at(ttyp, x, y)) + return FALSE; + return TRUE; +} + +/* recursively search obj for an object in class oclass, return 1st found */ struct obj * o_in(obj, oclass) struct obj *obj; @@ -39,7 +75,7 @@ char oclass; for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (otmp->oclass == oclass) return otmp; - else if (Has_contents(otmp) && (temp = o_in(otmp, oclass))) + else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)) != 0) return temp; } return (struct obj *) 0; @@ -64,7 +100,7 @@ unsigned material; if (objects[otmp->otyp].oc_material == material) return otmp; else if (Has_contents(otmp) - && (temp = o_material(otmp, material))) + && (temp = o_material(otmp, material)) != 0) return temp; } return (struct obj *) 0; @@ -179,7 +215,7 @@ register struct obj *sobj; if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { known = TRUE; goto outgoldmap; /* skip further searching */ - } else + } else { for (obj = mtmp->minvent; obj; obj = obj->nobj) if (sobj->blessed && o_material(obj, GOLD)) { known = TRUE; @@ -188,6 +224,7 @@ register struct obj *sobj; known = TRUE; goto outgoldmap; /* skip further searching */ } + } } /* look for gold objects */ @@ -208,6 +245,7 @@ register struct obj *sobj; adjust message if you have gold in your inventory */ if (sobj) { char buf[BUFSZ]; + if (youmonst.data == &mons[PM_GOLD_GOLEM]) { Sprintf(buf, "You feel like a million %s!", currency(2L)); } else if (hidden_gold() || money_cnt(invent)) @@ -232,13 +270,13 @@ outgoldmap: u.uinwater = u.uburied = 0; /* Discover gold locations. */ for (obj = fobj; obj; obj = obj->nobj) { - if (sobj->blessed && (temp = o_material(obj, GOLD))) { + if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; } map_object(temp, 1); - } else if ((temp = o_in(obj, COIN_CLASS))) { + } else if ((temp = o_in(obj, COIN_CLASS)) != 0) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; @@ -251,24 +289,27 @@ outgoldmap: continue; /* probably overkill here */ if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { struct obj gold; + gold = zeroobj; /* ensure oextra is cleared too */ gold.otyp = GOLD_PIECE; + gold.quan = (long) rnd(10); /* usually more than 1 */ gold.ox = mtmp->mx; gold.oy = mtmp->my; map_object(&gold, 1); - } else + } else { for (obj = mtmp->minvent; obj; obj = obj->nobj) - if (sobj->blessed && (temp = o_material(obj, GOLD))) { + if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp, 1); break; - } else if ((temp = o_in(obj, COIN_CLASS))) { + } else if ((temp = o_in(obj, COIN_CLASS)) != 0) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp, 1); break; } + } } newsym(u.ux, u.uy); u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; @@ -505,7 +546,7 @@ int class; /* an object class, 0 for all */ * Map all buried objects first. */ for (obj = level.buriedobjlist; obj; obj = obj->nobj) - if (!class || (otmp = o_in(obj, class))) { + if (!class || (otmp = o_in(obj, class)) != 0) { if (class) { if (otmp != obj) { otmp->ox = obj->ox; @@ -526,8 +567,8 @@ int class; /* an object class, 0 for all */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) for (obj = level.objects[x][y]; obj; obj = obj->nexthere) - if ((!class && !boulder) || (otmp = o_in(obj, class)) - || (otmp = o_in(obj, boulder))) { + if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0 + || (otmp = o_in(obj, boulder)) != 0) { if (class || boulder) { if (otmp != obj) { otmp->ox = obj->ox; @@ -544,8 +585,8 @@ int class; /* an object class, 0 for all */ if (DEADMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) - if ((!class && !boulder) || (otmp = o_in(obj, class)) - || (otmp = o_in(obj, boulder))) { + if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0 + || (otmp = o_in(obj, boulder)) != 0) { if (!class && !boulder) otmp = obj; otmp->ox = mtmp->mx; /* at monster location */ @@ -558,8 +599,9 @@ int class; /* an object class, 0 for all */ && (!class || class == objects[mtmp->mappearance].oc_class)) { struct obj temp; - temp.oextra = (struct oextra *) 0; + temp = zeroobj; temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */ + temp.quan = 1L; temp.ox = mtmp->mx; temp.oy = mtmp->my; temp.corpsenm = PM_TENGU; /* if mimicing a corpse */ @@ -567,8 +609,10 @@ int class; /* an object class, 0 for all */ } else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) { struct obj gold; + gold = zeroobj; /* ensure oextra is cleared too */ gold.otyp = GOLD_PIECE; + gold.quan = (long) rnd(10); /* usually more than 1 */ gold.ox = mtmp->mx; gold.oy = mtmp->my; map_object(&gold, 1); @@ -585,7 +629,6 @@ int class; /* an object class, 0 for all */ * and the detected object covers a known pool? */ docrt(); /* this will correctly reset vision */ - if (Underwater) under_water(2); if (u.uburied) @@ -675,7 +718,7 @@ int src_cursed; if (Hallucination || src_cursed) { struct obj obj; /* fake object */ - obj.oextra = (struct oextra *) 0; + obj = zeroobj; if (trap) { obj.ox = trap->tx; obj.oy = trap->ty; @@ -683,7 +726,9 @@ int src_cursed; obj.ox = x; obj.oy = y; } - obj.otyp = (src_cursed) ? GOLD_PIECE : random_object(); + obj.otyp = !Hallucination ? GOLD_PIECE : random_object(); + obj.quan = (long) ((obj.otyp == GOLD_PIECE) ? rnd(10) + : objects[obj.otyp].oc_merge ? rnd(2) : 1); obj.corpsenm = random_monster(); /* if otyp == CORPSE */ map_object(&obj, 1); } else if (trap) { @@ -691,6 +736,8 @@ int src_cursed; trap->tseen = 1; } else { struct trap temp_trap; /* fake trap */ + + (void) memset((genericptr_t) &temp_trap, 0, sizeof temp_trap); temp_trap.tx = x; temp_trap.ty = y; temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */ @@ -735,8 +782,7 @@ int how; /* 1 for misleading map feedback */ */ int trap_detect(sobj) -register struct obj *sobj; -/* sobj is null if crystal ball, *scroll if gold detection scroll */ +struct obj *sobj; /* null if crystal ball, *scroll if gold detection scroll */ { register struct trap *ttmp; struct monst *mon; @@ -759,8 +805,7 @@ register struct obj *sobj; else found = TRUE; } - if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0)) - != OTRAP_NONE) { + if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0)) != OTRAP_NONE) { if (tr & OTRAP_THERE) goto outtrapmap; else @@ -798,6 +843,7 @@ register struct obj *sobj; /* traps exist, but only under me - no separate display required */ Your("%s itch.", makeplural(body_part(TOE))); return 0; + outtrapmap: cls(); @@ -993,10 +1039,10 @@ struct obj **optr; nomul(-rnd(10)); multi_reason = "gazing into a crystal ball"; nomovemsg = ""; - if (obj->spe <= 0) + if (obj->spe <= 0) { pline_The("vision is unclear."); - else { - int class; + } else { + int class, i; int ret = 0; makeknown(CRYSTAL_BALL); @@ -1019,11 +1065,10 @@ struct obj **optr; case '^': ret = trap_detect((struct obj *) 0); break; - default: { - int i = rn2(SIZE(level_detects)); + default: + i = rn2(SIZE(level_detects)); You_see("%s, %s.", level_detects[i].what, level_distance(level_detects[i].where)); - } ret = 0; break; } diff --git a/src/pager.c b/src/pager.c index 2e4256eeb..0dfbbf5a2 100644 --- a/src/pager.c +++ b/src/pager.c @@ -379,7 +379,17 @@ char *buf, *monbuf; } else if (glyph_is_trap(glyph)) { int tnum = what_trap(glyph_to_trap(glyph)); - Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation); + /* Trap detection displays a bear trap at locations having + * a trapped door or trapped container or both. + * TODO: we should create actual trap types for doors and + * chests so that they can have their own glyphs and tiles. + */ + if (trapped_chest_at(tnum, x, y)) + Strcpy(buf, "trapped chest"); /* might actually be a large box */ + else if (trapped_door_at(tnum, x, y)) + Strcpy(buf, "trapped door"); /* not "trap door"... */ + else + Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation); } else if (glyph_is_warning(glyph)) { int warnindx = glyph_to_warning(glyph); -- 2.40.0