diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 796683f36..675fb7a18 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -39,6 +39,7 @@ hiding monsters don't hide under cockatrice/chickatrice corpses "sound" option renamed to "acoustics" deafness now a full-fledged attribute water should flow into pits from broken wand of digging +objects that fall thru trapdoors, et al, can break on impact Platform- and/or Interface-Specific Fixes diff --git a/include/dungeon.h b/include/dungeon.h index 24ba41367..d1da2657e 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -142,6 +142,7 @@ typedef struct branch { #define MIGR_SSTAIRS 7 /* dungeon branch */ #define MIGR_PORTAL 8 /* magic portal */ #define MIGR_NEAR_PLAYER 9 /* mon: followers; obj: trap door */ +#define MIGR_NOBREAK 1024 /* bitmask: don't break on delivery */ /* level information (saved via ledger number) */ diff --git a/include/extern.h b/include/extern.h index 784ce7f32..ca03362fb 100644 --- a/include/extern.h +++ b/include/extern.h @@ -429,7 +429,7 @@ E boolean FDECL(ghitm, (struct monst *,struct obj *)); E void FDECL(container_impact_dmg, (struct obj *)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); -E void NDECL(obj_delivery); +E void FDECL(obj_delivery, (BOOLEAN_P)); E schar FDECL(down_gate, (XCHAR_P,XCHAR_P)); E void FDECL(impact_drop, (struct obj *,XCHAR_P,XCHAR_P,XCHAR_P)); @@ -1955,7 +1955,7 @@ E boolean FDECL(rloc, (struct monst *, BOOLEAN_P)); E boolean FDECL(tele_restrict, (struct monst *)); E void FDECL(mtele_trap, (struct monst *, struct trap *,int)); E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *,BOOLEAN_P,int)); -E void FDECL(rloco, (struct obj *)); +E boolean FDECL(rloco, (struct obj *)); E int NDECL(random_teleport_level); E boolean FDECL(u_teleport_mon, (struct monst *,BOOLEAN_P)); diff --git a/src/do.c b/src/do.c index 4e06a45bb..816065a35 100644 --- a/src/do.c +++ b/src/do.c @@ -1188,7 +1188,7 @@ boolean at_stairs, falling, portal; } if (Punished) placebc(); - obj_delivery(); /* before killing geno'd monsters' eggs */ + obj_delivery(FALSE); losedogs(); kill_genocided_monsters(); /* for those wiped out while in limbo */ /* @@ -1248,6 +1248,9 @@ boolean at_stairs, falling, portal; /* give room entrance message, if any */ check_special_room(FALSE); + /* deliver objects traveling with player */ + obj_delivery(TRUE); + /* Check whether we just entered Gehennom. */ if (!In_hell(&u.uz0) && Inhell) { if (Is_valley(&u.uz)) { diff --git a/src/dog.c b/src/dog.c index 536a19a38..476404836 100644 --- a/src/dog.c +++ b/src/dog.c @@ -372,8 +372,7 @@ boolean with_you; obj->owornmask = 0L; if (xlocale && ylocale) place_object(obj, xlocale, ylocale); - else { - rloco(obj); + else if (rloco(obj)) { get_obj_location(obj, &xlocale, &ylocale, 0); } } diff --git a/src/dokick.c b/src/dokick.c index 65dd15d62..b9f7e11d3 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1137,10 +1137,12 @@ schar loc; } } +/* player or missile impacts location, causing objects to fall down */ void impact_drop(missile, x, y, dlev) -struct obj *missile; -xchar x, y, dlev; +struct obj *missile; /* caused impact, won't drop itself */ +xchar x, y; /* location affected */ +xchar dlev; /* if !0 send to dlev near player */ { schar toloc; register struct obj *obj, *obj2; @@ -1379,18 +1381,26 @@ boolean shop_floor_obj; } void -obj_delivery() +obj_delivery(near_hero) +boolean near_hero; { register struct obj *otmp, *otmp2; register int nx, ny; long where; + boolean nobreak; for (otmp = migrating_objs; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue; - obj_extract_self(otmp); where = otmp->owornmask; /* destination code */ + nobreak = (where & MIGR_NOBREAK) != 0; + where &= ~MIGR_NOBREAK; + + if ((!near_hero && where == MIGR_NEAR_PLAYER) || + (near_hero && where != MIGR_NEAR_PLAYER)) continue; + + obj_extract_self(otmp); otmp->owornmask = 0L; switch ((int)where) { @@ -1408,13 +1418,25 @@ obj_delivery() } if (nx > 0) { place_object(otmp, nx, ny); + if (!nobreak && !IS_SOFT(levl[nx][ny].typ)) { + if (where == MIGR_NEAR_PLAYER) { + if (breaks(otmp, nx, ny)) continue; + } else if (breaktest(otmp)) { + /* assume it broke before player arrived, no messages */ + delobj(otmp); + continue; + } + } stackobj(otmp); (void)scatter(nx, ny, rnd(2), 0, otmp); } else { /* random location */ /* set dummy coordinates because there's no current position for rloco() to update */ otmp->ox = otmp->oy = 0; - rloco(otmp); + if (rloco(otmp) && !nobreak && breaktest(otmp)) { + /* assume it broke before player arrived, no messages */ + delobj(otmp); + } } } } diff --git a/src/hack.c b/src/hack.c index ff4b2efb9..51f5c9d02 100644 --- a/src/hack.c +++ b/src/hack.c @@ -185,7 +185,7 @@ moverock() You("push %s and suddenly it disappears!", the(xname(otmp))); if (ttmp->ttyp == TELEP_TRAP) - rloco(otmp); + (void)rloco(otmp); else { int newlev = random_teleport_level(); d_level dest; diff --git a/src/mkobj.c b/src/mkobj.c index 880e35251..73f5a8397 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -896,7 +896,7 @@ boolean init; impossible("making corpstat type %d", objtype); if (x == 0 && y == 0) { /* special case - random placement */ otmp = mksobj(objtype, init, FALSE); - if (otmp) rloco(otmp); + if (otmp) (void)rloco(otmp); } else otmp = mksobj_at(objtype, x, y, init, FALSE); if (otmp) { diff --git a/src/mon.c b/src/mon.c index e87752656..960d98f94 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2682,6 +2682,7 @@ kill_genocided_monsters() kill_eggs(invent); kill_eggs(fobj); + kill_eggs(migrating_objs); kill_eggs(level.buriedobjlist); } diff --git a/src/teleport.c b/src/teleport.c index 1c15e69a2..5b678be6b 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1129,7 +1129,8 @@ int in_sight; } -void +/* place object randomly, returns FALSE if it's gone (eg broken) as a result */ +boolean rloco(obj) register struct obj *obj; { @@ -1138,7 +1139,7 @@ register struct obj *obj; int try_limit = 4000; if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) { - if (revive_corpse(obj)) return; + if (revive_corpse(obj)) return FALSE; } obj_extract_self(obj); @@ -1159,7 +1160,7 @@ register struct obj *obj; dndest.nhx, dndest.nhy))))); if (flooreffects(obj, tx, ty, "fall")) { - return; + return FALSE; } else if (otx == 0 && oty == 0) { ; /* fell through a trap door; no update of old loc needed */ } else { @@ -1175,6 +1176,7 @@ register struct obj *obj; } place_object(obj, tx, ty); newsym(tx, ty); + return TRUE; } /* Returns an absolute depth */ diff --git a/src/trap.c b/src/trap.c index 1fec73bd7..063dfabf5 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1436,7 +1436,7 @@ int style; You_hear("a rumbling stop abruptly."); singleobj->otrapped = 0; if (t->ttyp == TELEP_TRAP) - rloco(singleobj); + (void)rloco(singleobj); else { int newlev = random_teleport_level(); d_level dest; diff --git a/src/zap.c b/src/zap.c index b2c92111f..189f2f45c 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1547,7 +1547,7 @@ struct obj *obj, *otmp; break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: - rloco(obj); + (void) rloco(obj); break; case WAN_MAKE_INVISIBLE: #ifdef INVISIBLE_OBJECTS