breaking migrated objects

Allow migrated objects to break on arrival.  Added code to obj_delivery to
cause this, along with a flag to keep breakage from occurring.  The new
flag isn't used yet, because all the current object migration involve
objects that were moving/dropping.  To help make this change, rloco now
returns whether the object was placed or not, so caller can know if an obj
pointer is still valid or not.

Making the breakage messages for MIGR_NEAR_PLAYER objects show up after the
new level is displayed required some effort (rather than while the old level
was still displayed, which was confusing), due to the needs of goto_level.
- obj_delivery now has 2 passes, one for before player arrives, another after,
allowing the two cases to be treated differently
- goto_level calls obj_delivery twice (run_timers is not called twice,
since the run required before the level is displayed will have already run
any timers on migrating object)
- kill_genocided_monsters now kills eggs on the migrating_objs list too
This commit is contained in:
cohrs
2003-10-18 22:55:42 +00:00
parent 4cbdae2d3b
commit b2ffe64968
12 changed files with 46 additions and 17 deletions
+1
View File
@@ -39,6 +39,7 @@ hiding monsters don't hide under cockatrice/chickatrice corpses
"sound" option renamed to "acoustics" "sound" option renamed to "acoustics"
deafness now a full-fledged attribute deafness now a full-fledged attribute
water should flow into pits from broken wand of digging 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 Platform- and/or Interface-Specific Fixes
+1
View File
@@ -142,6 +142,7 @@ typedef struct branch {
#define MIGR_SSTAIRS 7 /* dungeon branch */ #define MIGR_SSTAIRS 7 /* dungeon branch */
#define MIGR_PORTAL 8 /* magic portal */ #define MIGR_PORTAL 8 /* magic portal */
#define MIGR_NEAR_PLAYER 9 /* mon: followers; obj: trap door */ #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) */ /* level information (saved via ledger number) */
+2 -2
View File
@@ -429,7 +429,7 @@ E boolean FDECL(ghitm, (struct monst *,struct obj *));
E void FDECL(container_impact_dmg, (struct obj *)); E void FDECL(container_impact_dmg, (struct obj *));
E int NDECL(dokick); E int NDECL(dokick);
E boolean FDECL(ship_object, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); 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 schar FDECL(down_gate, (XCHAR_P,XCHAR_P));
E void FDECL(impact_drop, (struct obj *,XCHAR_P,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 boolean FDECL(tele_restrict, (struct monst *));
E void FDECL(mtele_trap, (struct monst *, struct trap *,int)); E void FDECL(mtele_trap, (struct monst *, struct trap *,int));
E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *,BOOLEAN_P,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 int NDECL(random_teleport_level);
E boolean FDECL(u_teleport_mon, (struct monst *,BOOLEAN_P)); E boolean FDECL(u_teleport_mon, (struct monst *,BOOLEAN_P));
+4 -1
View File
@@ -1188,7 +1188,7 @@ boolean at_stairs, falling, portal;
} }
if (Punished) placebc(); if (Punished) placebc();
obj_delivery(); /* before killing geno'd monsters' eggs */ obj_delivery(FALSE);
losedogs(); losedogs();
kill_genocided_monsters(); /* for those wiped out while in limbo */ 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 */ /* give room entrance message, if any */
check_special_room(FALSE); check_special_room(FALSE);
/* deliver objects traveling with player */
obj_delivery(TRUE);
/* Check whether we just entered Gehennom. */ /* Check whether we just entered Gehennom. */
if (!In_hell(&u.uz0) && Inhell) { if (!In_hell(&u.uz0) && Inhell) {
if (Is_valley(&u.uz)) { if (Is_valley(&u.uz)) {
+1 -2
View File
@@ -372,8 +372,7 @@ boolean with_you;
obj->owornmask = 0L; obj->owornmask = 0L;
if (xlocale && ylocale) if (xlocale && ylocale)
place_object(obj, xlocale, ylocale); place_object(obj, xlocale, ylocale);
else { else if (rloco(obj)) {
rloco(obj);
get_obj_location(obj, &xlocale, &ylocale, 0); get_obj_location(obj, &xlocale, &ylocale, 0);
} }
} }
+27 -5
View File
@@ -1137,10 +1137,12 @@ schar loc;
} }
} }
/* player or missile impacts location, causing objects to fall down */
void void
impact_drop(missile, x, y, dlev) impact_drop(missile, x, y, dlev)
struct obj *missile; struct obj *missile; /* caused impact, won't drop itself */
xchar x, y, dlev; xchar x, y; /* location affected */
xchar dlev; /* if !0 send to dlev near player */
{ {
schar toloc; schar toloc;
register struct obj *obj, *obj2; register struct obj *obj, *obj2;
@@ -1379,18 +1381,26 @@ boolean shop_floor_obj;
} }
void void
obj_delivery() obj_delivery(near_hero)
boolean near_hero;
{ {
register struct obj *otmp, *otmp2; register struct obj *otmp, *otmp2;
register int nx, ny; register int nx, ny;
long where; long where;
boolean nobreak;
for (otmp = migrating_objs; otmp; otmp = otmp2) { for (otmp = migrating_objs; otmp; otmp = otmp2) {
otmp2 = otmp->nobj; otmp2 = otmp->nobj;
if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue; if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue;
obj_extract_self(otmp);
where = otmp->owornmask; /* destination code */ 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; otmp->owornmask = 0L;
switch ((int)where) { switch ((int)where) {
@@ -1408,13 +1418,25 @@ obj_delivery()
} }
if (nx > 0) { if (nx > 0) {
place_object(otmp, nx, ny); 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); stackobj(otmp);
(void)scatter(nx, ny, rnd(2), 0, otmp); (void)scatter(nx, ny, rnd(2), 0, otmp);
} else { /* random location */ } else { /* random location */
/* set dummy coordinates because there's no /* set dummy coordinates because there's no
current position for rloco() to update */ current position for rloco() to update */
otmp->ox = otmp->oy = 0; otmp->ox = otmp->oy = 0;
rloco(otmp); if (rloco(otmp) && !nobreak && breaktest(otmp)) {
/* assume it broke before player arrived, no messages */
delobj(otmp);
}
} }
} }
} }
+1 -1
View File
@@ -185,7 +185,7 @@ moverock()
You("push %s and suddenly it disappears!", You("push %s and suddenly it disappears!",
the(xname(otmp))); the(xname(otmp)));
if (ttmp->ttyp == TELEP_TRAP) if (ttmp->ttyp == TELEP_TRAP)
rloco(otmp); (void)rloco(otmp);
else { else {
int newlev = random_teleport_level(); int newlev = random_teleport_level();
d_level dest; d_level dest;
+1 -1
View File
@@ -896,7 +896,7 @@ boolean init;
impossible("making corpstat type %d", objtype); impossible("making corpstat type %d", objtype);
if (x == 0 && y == 0) { /* special case - random placement */ if (x == 0 && y == 0) { /* special case - random placement */
otmp = mksobj(objtype, init, FALSE); otmp = mksobj(objtype, init, FALSE);
if (otmp) rloco(otmp); if (otmp) (void)rloco(otmp);
} else } else
otmp = mksobj_at(objtype, x, y, init, FALSE); otmp = mksobj_at(objtype, x, y, init, FALSE);
if (otmp) { if (otmp) {
+1
View File
@@ -2682,6 +2682,7 @@ kill_genocided_monsters()
kill_eggs(invent); kill_eggs(invent);
kill_eggs(fobj); kill_eggs(fobj);
kill_eggs(migrating_objs);
kill_eggs(level.buriedobjlist); kill_eggs(level.buriedobjlist);
} }
+5 -3
View File
@@ -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) rloco(obj)
register struct obj *obj; register struct obj *obj;
{ {
@@ -1138,7 +1139,7 @@ register struct obj *obj;
int try_limit = 4000; int try_limit = 4000;
if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) { if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
if (revive_corpse(obj)) return; if (revive_corpse(obj)) return FALSE;
} }
obj_extract_self(obj); obj_extract_self(obj);
@@ -1159,7 +1160,7 @@ register struct obj *obj;
dndest.nhx, dndest.nhy))))); dndest.nhx, dndest.nhy)))));
if (flooreffects(obj, tx, ty, "fall")) { if (flooreffects(obj, tx, ty, "fall")) {
return; return FALSE;
} else if (otx == 0 && oty == 0) { } else if (otx == 0 && oty == 0) {
; /* fell through a trap door; no update of old loc needed */ ; /* fell through a trap door; no update of old loc needed */
} else { } else {
@@ -1175,6 +1176,7 @@ register struct obj *obj;
} }
place_object(obj, tx, ty); place_object(obj, tx, ty);
newsym(tx, ty); newsym(tx, ty);
return TRUE;
} }
/* Returns an absolute depth */ /* Returns an absolute depth */
+1 -1
View File
@@ -1436,7 +1436,7 @@ int style;
You_hear("a rumbling stop abruptly."); You_hear("a rumbling stop abruptly.");
singleobj->otrapped = 0; singleobj->otrapped = 0;
if (t->ttyp == TELEP_TRAP) if (t->ttyp == TELEP_TRAP)
rloco(singleobj); (void)rloco(singleobj);
else { else {
int newlev = random_teleport_level(); int newlev = random_teleport_level();
d_level dest; d_level dest;
+1 -1
View File
@@ -1547,7 +1547,7 @@ struct obj *obj, *otmp;
break; break;
case WAN_TELEPORTATION: case WAN_TELEPORTATION:
case SPE_TELEPORT_AWAY: case SPE_TELEPORT_AWAY:
rloco(obj); (void) rloco(obj);
break; break;
case WAN_MAKE_INVISIBLE: case WAN_MAKE_INVISIBLE:
#ifdef INVISIBLE_OBJECTS #ifdef INVISIBLE_OBJECTS