From 4967c296ab9c4056d617b401bfd37889967a0155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Sun, 30 Apr 2023 12:43:31 +0200 Subject: [PATCH] Fix segfaults when P_RemoveMobj is called from MobjSpawn hook --- src/b_bot.c | 3 + src/g_demo.c | 143 ++++---- src/p_enemy.c | 914 ++++++++++++++++++++++++++++++------------------ src/p_floor.c | 3 + src/p_inter.c | 261 ++++++++------ src/p_local.h | 2 +- src/p_map.c | 2 + src/p_mobj.c | 851 +++++++++++++++++++++++++++++--------------- src/p_polyobj.c | 2 + src/p_user.c | 439 ++++++++++++++--------- 10 files changed, 1670 insertions(+), 950 deletions(-) diff --git a/src/b_bot.c b/src/b_bot.c index d1465f891..aa9ccd33e 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -613,6 +613,9 @@ void B_HandleFlightIndicator(player_t *player) // otherwise, spawn it P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY)); + if (P_MobjWasRemoved(tails->hnext)) + return; // we can't spawn one, so it can't exist + P_SetTarget(&tails->hnext->target, tails); P_SetTarget(&tails->hnext->hprev, tails); P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR); diff --git a/src/g_demo.c b/src/g_demo.c index 0403da16d..d1d1a4a11 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -795,32 +795,40 @@ void G_GhostTicker(void) if (type == MT_GHOST) { mobj = P_SpawnGhostMobj(g->mo); // does a large portion of the work for us - mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|tr_trans60<frame = (mobj->frame & ~FF_FRAMEMASK)|tr_trans60<mo, 0, 0, -FixedDiv(FixedMul(g->mo->info->height, g->mo->scale) - g->mo->height,3*FRACUNIT), MT_THOK); - mobj->sprite = states[mobjinfo[type].spawnstate].sprite; - mobj->frame = (states[mobjinfo[type].spawnstate].frame & FF_FRAMEMASK) | tr_trans60<color = g->mo->color; - mobj->skin = g->mo->skin; - P_SetScale(mobj, (mobj->destscale = g->mo->scale)); - - if (type == MT_THOK) // spintrail-specific modification for MT_THOK + if (!P_MobjWasRemoved(mobj)) { - mobj->frame = FF_TRANS80; - mobj->fuse = mobj->tics; + mobj->sprite = states[mobjinfo[type].spawnstate].sprite; + mobj->frame = (states[mobjinfo[type].spawnstate].frame & FF_FRAMEMASK) | tr_trans60<color = g->mo->color; + mobj->skin = g->mo->skin; + P_SetScale(mobj, (mobj->destscale = g->mo->scale)); + + if (type == MT_THOK) // spintrail-specific modification for MT_THOK + { + mobj->frame = FF_TRANS80; + mobj->fuse = mobj->tics; + } + mobj->tics = -1; // nope. } - mobj->tics = -1; // nope. } - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_UnsetThingPosition(mobj); - mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... - P_SetThingPosition(mobj); - if (!mobj->fuse) - mobj->fuse = 8; - P_SetTarget(&mobj->target, g->mo); + + if (!P_MobjWasRemoved(mobj)) + { + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_UnsetThingPosition(mobj); + mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... + P_SetThingPosition(mobj); + if (!mobj->fuse) + mobj->fuse = 8; + P_SetTarget(&mobj->target, g->mo); + } } } if (xziptic & EZT_HIT) @@ -844,6 +852,8 @@ void G_GhostTicker(void) || health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad. continue; poof = P_SpawnMobj(x, y, z, MT_GHOST); + if (P_MobjWasRemoved(poof)) + continue; poof->angle = angle; poof->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... poof->health = 0; @@ -889,19 +899,22 @@ void G_GhostTicker(void) if (follow) P_RemoveMobj(follow); P_SetTarget(&follow, P_SpawnMobjFromMobj(g->mo, 0, 0, 0, MT_GHOST)); - P_SetTarget(&follow->tracer, g->mo); - follow->tics = -1; - temp = READINT16(g->p)<height = FixedMul(follow->scale, temp); + if (!P_MobjWasRemoved(follow)) + { + P_SetTarget(&follow->tracer, g->mo); + follow->tics = -1; + temp = READINT16(g->p)<height = FixedMul(follow->scale, temp); - if (followtic & FZT_LINKDRAW) - follow->flags2 |= MF2_LINKDRAW; + if (followtic & FZT_LINKDRAW) + follow->flags2 |= MF2_LINKDRAW; - if (followtic & FZT_COLORIZED) - follow->colorized = true; + if (followtic & FZT_COLORIZED) + follow->colorized = true; - if (followtic & FZT_SKIN) - follow->skin = &skins[READUINT8(g->p)]; + if (followtic & FZT_SKIN) + follow->skin = &skins[READUINT8(g->p)]; + } } if (follow) { @@ -1094,28 +1107,35 @@ void G_ReadMetalTic(mobj_t *metal) else { mobj = P_SpawnMobjFromMobj(metal, 0, 0, -FixedDiv(FixedMul(metal->info->height, metal->scale) - metal->height,3*FRACUNIT), MT_THOK); - mobj->sprite = states[mobjinfo[type].spawnstate].sprite; - mobj->frame = states[mobjinfo[type].spawnstate].frame; - mobj->angle = metal->angle; - mobj->color = metal->color; - mobj->skin = metal->skin; - P_SetScale(mobj, (mobj->destscale = metal->scale)); - - if (type == MT_THOK) // spintrail-specific modification for MT_THOK + if (!P_MobjWasRemoved(mobj)) { - mobj->frame = FF_TRANS70; - mobj->fuse = mobj->tics; + mobj->sprite = states[mobjinfo[type].spawnstate].sprite; + mobj->frame = states[mobjinfo[type].spawnstate].frame; + mobj->angle = metal->angle; + mobj->color = metal->color; + mobj->skin = metal->skin; + P_SetScale(mobj, (mobj->destscale = metal->scale)); + + if (type == MT_THOK) // spintrail-specific modification for MT_THOK + { + mobj->frame = FF_TRANS70; + mobj->fuse = mobj->tics; + } + mobj->tics = -1; // nope. } - mobj->tics = -1; // nope. } - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_UnsetThingPosition(mobj); - mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... - P_SetThingPosition(mobj); - if (!mobj->fuse) - mobj->fuse = 8; - P_SetTarget(&mobj->target, metal); + + if (!P_MobjWasRemoved(mobj)) + { + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_UnsetThingPosition(mobj); + mobj->flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY; // make an ATTEMPT to curb crazy SOCs fucking stuff up... + P_SetThingPosition(mobj); + if (!mobj->fuse) + mobj->fuse = 8; + P_SetTarget(&mobj->target, metal); + } } } if (xziptic & EZT_SPRITE) @@ -1137,19 +1157,22 @@ void G_ReadMetalTic(mobj_t *metal) if (follow) P_RemoveMobj(follow); P_SetTarget(&follow, P_SpawnMobjFromMobj(metal, 0, 0, 0, MT_GHOST)); - P_SetTarget(&follow->tracer, metal); - follow->tics = -1; - temp = READINT16(metal_p)<height = FixedMul(follow->scale, temp); + if (!P_MobjWasRemoved(follow)) + { + P_SetTarget(&follow->tracer, metal); + follow->tics = -1; + temp = READINT16(metal_p)<height = FixedMul(follow->scale, temp); - if (followtic & FZT_LINKDRAW) - follow->flags2 |= MF2_LINKDRAW; + if (followtic & FZT_LINKDRAW) + follow->flags2 |= MF2_LINKDRAW; - if (followtic & FZT_COLORIZED) - follow->colorized = true; + if (followtic & FZT_COLORIZED) + follow->colorized = true; - if (followtic & FZT_SKIN) - follow->skin = &skins[READUINT8(metal_p)]; + if (followtic & FZT_SKIN) + follow->skin = &skins[READUINT8(metal_p)]; + } } if (follow) { @@ -2218,7 +2241,9 @@ void G_AddGhost(char *defdemoname) { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. fixed_t z,f,c; fixed_t offset = mthing->z << FRACBITS; - gh->mo = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS, 0, MT_GHOST); + P_SetTarget(&gh->mo, P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS, 0, MT_GHOST)); + if (P_MobjWasRemoved(gh->mo)) + return; gh->mo->angle = FixedAngle(mthing->angle << FRACBITS); f = gh->mo->floorz; c = gh->mo->ceilingz - mobjinfo[MT_PLAYER].height; diff --git a/src/p_enemy.c b/src/p_enemy.c index 63d430eb6..6cc68e744 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1200,7 +1200,8 @@ static void P_SharpDust(mobj_t *actor, mobjtype_t type, angle_t ang) -P_ReturnThrustX(actor, ang, 16<angle, actor->radius), actor->height/3, MT_PARTICLE); + if (P_MobjWasRemoved(flume)) + return; + flume->destscale = actor->scale*3; P_SetScale(flume, flume->destscale); P_SetTarget(&flume->target, actor); @@ -1328,12 +1332,15 @@ void A_FaceStabHurl(mobj_t *actor) { if (!hwork->hnext) P_SetTarget(&hwork->hnext, P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_FACESTABBERSPEAR)); - hwork = hwork->hnext; - hwork->angle = actor->angle + ANGLE_90; - hwork->destscale = FixedSqrt(step*basesize); - P_SetScale(hwork, hwork->destscale); - hwork->fuse = 2; - P_MoveOrigin(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<hnext)) + { + hwork = hwork->hnext; + hwork->angle = actor->angle + ANGLE_90; + hwork->destscale = FixedSqrt(step*basesize); + P_SetScale(hwork, hwork->destscale); + hwork->fuse = 2; + P_MoveOrigin(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<info->raisestate); + if (P_MobjWasRemoved(newchain)) + continue; P_SetTarget(&prevchain->target, newchain); prevchain = newchain; } @@ -2324,10 +2335,13 @@ static void P_VultureHoverParticle(mobj_t *actor) fixed_t pz = P_FloorzAtPos(px, py, actor->z, actor->height); dust = P_SpawnMobj(px, py, pz, MT_ARIDDUST); - P_SetMobjState(dust, (statenum_t)(dust->state - states + P_RandomRange(0, 2))); - P_Thrust(dust, angle, FixedDiv(12*FRACUNIT, max(FRACUNIT, fdist/2))); - dust->momx += actor->momx; - dust->momy += actor->momy; + if (!P_MobjWasRemoved(dust)) + { + P_SetMobjState(dust, (statenum_t)(dust->state - states + P_RandomRange(0, 2))); + P_Thrust(dust, angle, FixedDiv(12*FRACUNIT, max(FRACUNIT, fdist/2))); + dust->momx += actor->momx; + dust->momy += actor->momy; + } angle += ANGLE_45; } } @@ -2422,6 +2436,8 @@ void A_VultureBlast(mobj_t *actor) { angle_t fa = ((i*(angle_t)ANGLE_45) >> ANGLETOFINESHIFT) & FINEMASK; dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -faasin), actor->y + 48*FixedMul(FINECOSINE(fa), faacos), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE); + if (P_MobjWasRemoved(dust)) + continue; P_SetScale(dust, 4*FRACUNIT); dust->destscale = FRACUNIT; @@ -2491,10 +2507,13 @@ void A_VultureFly(mobj_t *actor) P_VultureHoverParticle(actor); dust = P_SpawnMobj(actor->x + P_RandomFixed() - FRACUNIT/2, actor->y + P_RandomFixed() - FRACUNIT/2, actor->z + actor->height/2 + P_RandomFixed() - FRACUNIT/2, MT_PARTICLE); - P_SetScale(dust, 2*FRACUNIT); - dust->destscale = FRACUNIT/3; - dust->scalespeed = FRACUNIT/40; - dust->fuse = TICRATE*2; + if (!P_MobjWasRemoved(dust)) + { + P_SetScale(dust, 2*FRACUNIT); + dust->destscale = FRACUNIT/3; + dust->scalespeed = FRACUNIT/40; + dust->fuse = TICRATE*2; + } actor->momx += FixedDiv(dx, dm)*2; actor->momy += FixedDiv(dy, dm)*2; @@ -2693,6 +2712,8 @@ void A_LobShot(mobj_t *actor) z = actor->z + FixedMul(locvar2*FRACUNIT, actor->scale); shot = P_SpawnMobj(actor->x, actor->y, z, locvar1); + if (P_MobjWasRemoved(shot)) + return; if (actor->type == MT_BLACKEGGMAN) { @@ -3074,15 +3095,21 @@ void A_Boss1Laser(mobj_t *actor) S_StartSound(actor, mobjinfo[locvar1].seesound); point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); - point->angle = actor->angle; - point->fuse = dur+1; - P_SetTarget(&point->target, actor->target); - P_SetTarget(&actor->target, point); + if (!P_MobjWasRemoved(point)) + { + point->angle = actor->angle; + point->fuse = dur+1; + P_SetTarget(&point->target, actor->target); + P_SetTarget(&actor->target, point); + } } angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); point = P_SpawnMobj(x, y, z, locvar1); + if (P_MobjWasRemoved(point)) + return; + P_SetTarget(&point->target, actor); point->angle = actor->angle; speed = point->radius; @@ -3093,6 +3120,9 @@ void A_Boss1Laser(mobj_t *actor) for (i = 0; i < 256; i++) { mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type); + if (P_MobjWasRemoved(mo)) + continue; + mo->angle = point->angle; mo->color = LASERCOLORS[((UINT8)(i + 3*dur) >> 2) % sizeof(LASERCOLORS)]; // codeing P_UnsetThingPosition(mo); @@ -3105,9 +3135,12 @@ void A_Boss1Laser(mobj_t *actor) if (mo->info->meleestate) { mobj_t *mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_PARTICLE); - mo2->flags2 |= MF2_LINKDRAW; - P_SetTarget(&mo2->tracer, actor); - P_SetMobjState(mo2, mo->info->meleestate); + if (!P_MobjWasRemoved(mo2)) + { + mo2->flags2 |= MF2_LINKDRAW; + P_SetTarget(&mo2->tracer, actor); + P_SetMobjState(mo2, mo->info->meleestate); + } } } @@ -3125,37 +3158,42 @@ void A_Boss1Laser(mobj_t *actor) if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1 && dur & 1) { point = P_SpawnMobj(x, y, floorz, MT_EGGMOBILE_FIRE); - point->angle = actor->angle; - point->destscale = actor->scale; - P_SetScale(point, point->destscale); - P_SetTarget(&point->target, actor); - P_MobjCheckWater(point); - if (point->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) + if (!P_MobjWasRemoved(point)) { - for (i = 0; i < 2; i++) + point->angle = actor->angle; + point->destscale = actor->scale; + P_SetScale(point, point->destscale); + P_SetTarget(&point->target, actor); + P_MobjCheckWater(point); + if (point->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) { - UINT8 size = 3; - mobj_t *steam = P_SpawnMobj(x, y, point->watertop - size*mobjinfo[MT_DUST].height, MT_DUST); - P_SetScale(steam, size*actor->scale); - P_SetObjectMomZ(steam, FRACUNIT + 2*P_RandomFixed(), true); - P_InstaThrust(steam, FixedAngle(P_RandomKey(360)*FRACUNIT), 2*P_RandomFixed()); - if (point->info->painsound) - S_StartSound(steam, point->info->painsound); - } - } - else - { - fixed_t distx = P_ReturnThrustX(point, point->angle, point->radius); - fixed_t disty = P_ReturnThrustY(point, point->angle, point->radius); - if (P_TryMove(point, point->x + distx, point->y + disty, false) // prevents the sprite from clipping into the wall or dangling off ledges - && P_TryMove(point, point->x - 2*distx, point->y - 2*disty, false) - && P_TryMove(point, point->x + distx, point->y + disty, false)) - { - if (point->info->seesound) - S_StartSound(point, point->info->seesound); + for (i = 0; i < 2; i++) + { + UINT8 size = 3; + mobj_t *steam = P_SpawnMobj(x, y, point->watertop - size*mobjinfo[MT_DUST].height, MT_DUST); + if (P_MobjWasRemoved(steam)) + continue; + P_SetScale(steam, size*actor->scale); + P_SetObjectMomZ(steam, FRACUNIT + 2*P_RandomFixed(), true); + P_InstaThrust(steam, FixedAngle(P_RandomKey(360)*FRACUNIT), 2*P_RandomFixed()); + if (point->info->painsound) + S_StartSound(steam, point->info->painsound); + } } else - P_RemoveMobj(point); + { + fixed_t distx = P_ReturnThrustX(point, point->angle, point->radius); + fixed_t disty = P_ReturnThrustY(point, point->angle, point->radius); + if (P_TryMove(point, point->x + distx, point->y + disty, false) // prevents the sprite from clipping into the wall or dangling off ledges + && P_TryMove(point, point->x - 2*distx, point->y - 2*disty, false) + && P_TryMove(point, point->x + distx, point->y + disty, false)) + { + if (point->info->seesound) + S_StartSound(point, point->info->seesound); + } + else + P_RemoveMobj(point); + } } } @@ -3499,6 +3537,8 @@ void A_BossScream(mobj_t *actor) z = actor->z + FixedMul((P_RandomByte()<<(FRACBITS-2)) - 8*FRACUNIT, actor->scale); mo = P_SpawnMobj(x, y, z, explodetype); + if (P_MobjWasRemoved(mo)) + return; if (actor->eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; mo->destscale = actor->scale; @@ -3625,6 +3665,9 @@ void A_1upThinker(mobj_t *actor) if (!actor->tracer) { P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY)); + if (P_MobjWasRemoved(actor->tracer)) + return; + P_SetTarget(&actor->tracer->target, actor); actor->tracer->skin = &skins[players[closestplayer].skin]; // required here to prevent spr2 default showing stand for a single frame P_SetMobjState(actor->tracer, actor->info->seestate); @@ -3686,31 +3729,40 @@ void A_MonitorPop(mobj_t *actor) return; } - newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item); - P_SetTarget(&newmobj->target, actor->target); // Transfer target - if (item == MT_1UP_ICON) { if (actor->tracer) // Remove the old lives icon. P_RemoveMobj(actor->tracer); + } - if (!newmobj->target - || !newmobj->target->player - || !newmobj->target->skin - || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) - {} // No lives icon for this player, use the default. - else - { // Spawn the lives icon. - mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&livesico->target, newmobj); - P_SetTarget(&newmobj->tracer, livesico); + newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item); + if (!P_MobjWasRemoved(newmobj)) + { + P_SetTarget(&newmobj->target, actor->target); // Transfer target - livesico->color = newmobj->target->player->mo->color; - livesico->skin = &skins[newmobj->target->player->skin]; - P_SetMobjState(livesico, newmobj->info->seestate); + if (item == MT_1UP_ICON) + { + if (!newmobj->target + || !newmobj->target->player + || !newmobj->target->skin + || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) + {} // No lives icon for this player, use the default. + else + { // Spawn the lives icon. + mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); + if (!P_MobjWasRemoved(livesico)) + { + P_SetTarget(&livesico->target, newmobj); + P_SetTarget(&newmobj->tracer, livesico); - // We're using the overlay, so use the overlay 1up sprite (no text) - newmobj->sprite = SPR_TV1P; + livesico->color = newmobj->target->player->mo->color; + livesico->skin = &skins[newmobj->target->player->skin]; + P_SetMobjState(livesico, newmobj->info->seestate); + } + + // We're using the overlay, so use the overlay 1up sprite (no text) + newmobj->sprite = SPR_TV1P; + } } } @@ -3773,30 +3825,36 @@ void A_GoldMonitorPop(mobj_t *actor) // Note: the icon spawns 1 fracunit higher newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 14*FRACUNIT, item); - P_SetTarget(&newmobj->target, actor->target); // Transfer target - - if (item == MT_1UP_ICON) + if (!P_MobjWasRemoved(newmobj)) { - if (actor->tracer) // Remove the old lives icon. - P_RemoveMobj(actor->tracer); + P_SetTarget(&newmobj->target, actor->target); // Transfer target - if (!newmobj->target - || !newmobj->target->player - || !newmobj->target->skin - || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) - {} // No lives icon for this player, use the default. - else - { // Spawn the lives icon. - mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&livesico->target, newmobj); - P_SetTarget(&newmobj->tracer, livesico); + if (item == MT_1UP_ICON) + { + if (actor->tracer) // Remove the old lives icon. + P_RemoveMobj(actor->tracer); - livesico->color = newmobj->target->player->mo->color; - livesico->skin = &skins[newmobj->target->player->skin]; - P_SetMobjState(livesico, newmobj->info->seestate); + if (!newmobj->target + || !newmobj->target->player + || !newmobj->target->skin + || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0) + {} // No lives icon for this player, use the default. + else + { // Spawn the lives icon. + mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY); + if (!P_MobjWasRemoved(livesico)) + { + P_SetTarget(&livesico->target, newmobj); + P_SetTarget(&newmobj->tracer, livesico); - // We're using the overlay, so use the overlay 1up sprite (no text) - newmobj->sprite = SPR_TV1P; + livesico->color = newmobj->target->player->mo->color; + livesico->skin = &skins[newmobj->target->player->skin]; + P_SetMobjState(livesico, newmobj->info->seestate); + } + + // We're using the overlay, so use the overlay 1up sprite (no text) + newmobj->sprite = SPR_TV1P; + } } } @@ -3841,7 +3899,13 @@ void A_GoldMonitorSparkle(mobj_t *actor) yofs = FINECOSINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS); for (i = FRACUNIT*2; i <= FRACUNIT*3; i += FRACUNIT/2) - P_SetObjectMomZ(P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE), i, false); + { + mobj_t *sparkle = P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE); + if (P_MobjWasRemoved(sparkle)) + continue; + + P_SetObjectMomZ(sparkle, i, false); + } } // Function: A_Explode @@ -3963,56 +4027,73 @@ static void P_DoBossVictory(mobj_t *mo) static void P_SpawnBoss1Junk(mobj_t *mo) { mobj_t *mo2 = P_SpawnMobjFromMobj(mo, - P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSEGLZ1); + P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSEGLZ1); + } mo2 = P_SpawnMobjFromMobj(mo, P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSEGLZ2); + if (!P_MobjWasRemoved(mo2)) + { + mo2->angle = mo->angle; + P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSEGLZ2); + } } static void P_SpawnBoss2Junk(mobj_t *mo) { mobj_t *mo2 = P_SpawnMobjFromMobj(mo, - P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSTANK1); + P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSTANK1); + } mo2 = P_SpawnMobjFromMobj(mo, P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSTANK2); + if (!P_MobjWasRemoved(mo2)) + { + mo2->angle = mo->angle; + P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSTANK2); + } mo2 = P_SpawnMobjFromMobj(mo, 0, 0, mobjinfo[MT_EGGMOBILE2].height + (32<angle = mo->angle; - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - mo2->momz += mo->momz; - P_SetMobjState(mo2, S_BOSSSPIGOT); + if (!P_MobjWasRemoved(mo2)) + { + mo2->angle = mo->angle; + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + mo2->momz += mo->momz; + P_SetMobjState(mo2, S_BOSSSPIGOT); + } } static void P_SpawnBoss3Junk(mobj_t *mo) { mobj_t *mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK); + if (P_MobjWasRemoved(mo2)) + return; mo2->angle = mo->angle; P_SetMobjState(mo2, S_BOSSSEBH1); } @@ -4052,26 +4133,36 @@ static void P_DoBoss5Death(mobj_t *mo) mo->tracer->y - P_ReturnThrustY(mo->tracer, mo->tracer->angle, speed*time), mo->tracer->floorz + (256+1)*FRACUNIT, MT_FSGNB); - P_SetTarget(&pole->tracer, P_SpawnMobj( - pole->x, pole->y, - pole->z - 256*FRACUNIT, - MT_FSGNB)); - P_SetTarget(&pole->tracer->tracer, P_SpawnMobj( - pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT), - pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT), - pole->z + 256*FRACUNIT, - MT_FSGNA)); - pole->tracer->flags |= MF_NOCLIPTHING; - P_SetScale(pole, (pole->destscale = 2*FRACUNIT)); - P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT)); - pole->angle = pole->tracer->angle = mo->tracer->angle; - pole->tracer->tracer->angle = pole->angle - ANGLE_90; - pole->momx = P_ReturnThrustX(pole, pole->angle, speed); - pole->momy = P_ReturnThrustY(pole, pole->angle, speed); - pole->tracer->momx = pole->momx; - pole->tracer->momy = pole->momy; - pole->tracer->tracer->momx = pole->momx; - pole->tracer->tracer->momy = pole->momy; + if (!P_MobjWasRemoved(pole)) + { + P_SetScale(pole, (pole->destscale = 2*FRACUNIT)); + pole->momx = P_ReturnThrustX(pole, pole->angle, speed); + pole->momy = P_ReturnThrustY(pole, pole->angle, speed); + P_SetTarget(&pole->tracer, P_SpawnMobj( + pole->x, pole->y, + pole->z - 256*FRACUNIT, + MT_FSGNB)); + if (!P_MobjWasRemoved(pole->tracer)) + { + pole->tracer->flags |= MF_NOCLIPTHING; + P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT)); + pole->angle = pole->tracer->angle = mo->tracer->angle; + pole->tracer->momx = pole->momx; + pole->tracer->momy = pole->momy; + + P_SetTarget(&pole->tracer->tracer, P_SpawnMobj( + pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT), + pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT), + pole->z + 256*FRACUNIT, + MT_FSGNA)); + if (!P_MobjWasRemoved(pole->tracer->tracer)) + { + pole->tracer->tracer->angle = pole->angle - ANGLE_90; + pole->tracer->tracer->momx = pole->momx; + pole->tracer->tracer->momy = pole->momy; + } + } + } } } else @@ -4731,9 +4822,12 @@ void A_AttractChase(mobj_t *actor) { mobj_t *newring; newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); - newring->momx = actor->momx; - newring->momy = actor->momy; - newring->momz = actor->momz; + if (!P_MobjWasRemoved(newring)) + { + newring->momx = actor->momx; + newring->momy = actor->momy; + newring->momz = actor->momz; + } P_RemoveMobj(actor); return; } @@ -4813,9 +4907,12 @@ void A_DropMine(mobj_t *actor) // Use raisestate instead of MT_MINE mine = P_SpawnMobj(actor->x, actor->y, z, (mobjtype_t)actor->info->raisestate); - if (actor->eflags & MFE_VERTICALFLIP) - mine->eflags |= MFE_VERTICALFLIP; - mine->momz = actor->momz + actor->pmomz; + if (!P_MobjWasRemoved(mine)) + { + if (actor->eflags & MFE_VERTICALFLIP) + mine->eflags |= MFE_VERTICALFLIP; + mine->momz = actor->momz + actor->pmomz; + } S_StartSound(actor, actor->info->attacksound); } @@ -5138,11 +5235,13 @@ void A_SignSpin(mobj_t *actor) if (actor->tracer == NULL || P_MobjWasRemoved(actor->tracer)) return; for (i = -1; i < 2; i += 2) { - P_SpawnMobjFromMobj(actor, + mobj_t *spinmobj = P_SpawnMobjFromMobj(actor, P_ReturnThrustX(actor, actor->tracer->angle, i * actor->radius), P_ReturnThrustY(actor, actor->tracer->angle, i * actor->radius), (actor->eflags & MFE_VERTICALFLIP) ? 0 : actor->height, - actor->info->painchance)->destscale >>= 1; + actor->info->painchance); + if (!P_MobjWasRemoved(spinmobj)) + spinmobj->destscale >>= 1; } } @@ -5202,8 +5301,11 @@ void A_SignPlayer(mobj_t *actor) if (actor->tracer->tracer == NULL || P_MobjWasRemoved(actor->tracer->tracer)) { ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY); - P_SetTarget(&ov->target, actor->tracer); - P_SetTarget(&actor->tracer->tracer, ov); + if (!P_MobjWasRemoved(ov)) + { + P_SetTarget(&ov->target, actor->tracer); + P_SetTarget(&actor->tracer->tracer, ov); + } } else ov = actor->tracer->tracer; @@ -5263,33 +5365,36 @@ void A_SignPlayer(mobj_t *actor) signcolor = skincolors[facecolor].invcolor; } - if (skin) - { - if (skin->sprites[SPR2_SIGN].numframes) // player face + if (!P_MobjWasRemoved(ov)) + { + if (skin) { - ov->color = facecolor; - ov->skin = skin; - if ((statenum_t)(ov->state-states) != actor->info->seestate) - P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN + if (skin->sprites[SPR2_SIGN].numframes) // player face + { + ov->color = facecolor; + ov->skin = skin; + if ((statenum_t)(ov->state-states) != actor->info->seestate) + P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN + } + else // CLEAR! sign + { + ov->color = SKINCOLOR_NONE; + ov->skin = NULL; // needs to be NULL in the case of SF_HIRES characters + if ((statenum_t)(ov->state-states) != actor->info->missilestate) + P_SetMobjState(ov, actor->info->missilestate); // S_CLEARSIGN + } } - else // CLEAR! sign + else // Eggman face { ov->color = SKINCOLOR_NONE; - ov->skin = NULL; // needs to be NULL in the case of SF_HIRES characters - if ((statenum_t)(ov->state-states) != actor->info->missilestate) - P_SetMobjState(ov, actor->info->missilestate); // S_CLEARSIGN + ov->skin = NULL; + if ((statenum_t)(ov->state-states) != actor->info->meleestate) + P_SetMobjState(ov, actor->info->meleestate); // S_EGGMANSIGN + if (!signcolor) + signcolor = SKINCOLOR_CARBON; + facecolor = signcolor; } - } - else // Eggman face - { - ov->color = SKINCOLOR_NONE; - ov->skin = NULL; - if ((statenum_t)(ov->state-states) != actor->info->meleestate) - P_SetMobjState(ov, actor->info->meleestate); // S_EGGMANSIGN - if (!signcolor) - signcolor = SKINCOLOR_CARBON; - facecolor = signcolor; - } + } actor->tracer->color = signcolor; if (signcolor && signcolor < numskincolors) @@ -5480,12 +5585,14 @@ void A_JetbThink(mobj_t *actor) // use raisestate instead of MT_MINE bomb = P_SpawnMobj(actor->x, actor->y, actor->z - FixedMul((32<scale), (mobjtype_t)actor->info->raisestate); - - P_SetTarget(&bomb->target, actor); - bomb->destscale = actor->scale; - P_SetScale(bomb, actor->scale); - actor->reactiontime = TICRATE; // one second - S_StartSound(actor, actor->info->attacksound); + if (!P_MobjWasRemoved(bomb)) + { + P_SetTarget(&bomb->target, actor); + bomb->destscale = actor->scale; + P_SetScale(bomb, actor->scale); + actor->reactiontime = TICRATE; // one second + S_StartSound(actor, actor->info->attacksound); + } } } else if (((actor->z - FixedMul((32<scale)) < thefloor) && !((thefloor + FixedMul((32<scale) + actor->height) > actor->ceilingz)) @@ -5631,9 +5738,12 @@ void A_MinusDigging(mobj_t *actor) } par = P_SpawnMobj(actor->x, actor->y, mz, MT_MINUSDIRT); - if (actor->eflags & MFE_VERTICALFLIP) - par->eflags |= MFE_VERTICALFLIP; - P_TryMove(par, x, y, false); + if (!P_MobjWasRemoved(par)) + { + if (actor->eflags & MFE_VERTICALFLIP) + par->eflags |= MFE_VERTICALFLIP; + P_TryMove(par, x, y, false); + } // If close enough, prepare to attack if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < actor->radius*2) @@ -5644,6 +5754,8 @@ void A_MinusDigging(mobj_t *actor) // Spawn growing dirt pile. par = P_SpawnMobj(actor->x, actor->y, mz, MT_MINUSDIRT); + if (P_MobjWasRemoved(par)) + return; P_SetMobjState(par, actor->info->raisestate); P_SetScale(par, actor->scale*2); if (actor->eflags & MFE_VERTICALFLIP) @@ -5714,6 +5826,8 @@ void A_MinusPopup(mobj_t *actor) for (i = 1; i <= num; i++) { mobj_t *rock = P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_ROCKCRUMBLE1); + if (P_MobjWasRemoved(rock)) + continue; P_Thrust(rock, ani*i, FRACUNIT); P_SetObjectMomZ(rock, 3*FRACUNIT, false); P_SetScale(rock, rock->scale/3); @@ -5751,6 +5865,8 @@ void A_MinusCheck(mobj_t *actor) for (i = 1; i <= num; i++) { mobj_t *rock = P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_ROCKCRUMBLE1); + if (P_MobjWasRemoved(rock)) + continue; P_Thrust(rock, ani*i, FRACUNIT); P_SetObjectMomZ(rock, 3*FRACUNIT, false); P_SetScale(rock, rock->scale/3); @@ -6262,6 +6378,8 @@ void A_RockSpawn(mobj_t *actor) dist += actor->spawnpoint->args[2] ? P_RandomByte() * (FRACUNIT/32) : 0; // random oomph mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK); + if (P_MobjWasRemoved(mo)) + return; P_SetMobjState(mo, mobjinfo[type].spawnstate); mo->angle = FixedAngle(actor->spawnpoint->angle << FRACBITS); @@ -6298,6 +6416,8 @@ void A_SlingAppear(mobj_t *actor) actor->friction = 128; hprev = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLGRABCHAIN); + if (P_MobjWasRemoved(hprev)) + return; P_SetTarget(&hprev->tracer, actor); P_SetTarget(&hprev->hprev, actor); P_SetTarget(&actor->hnext, hprev); @@ -6309,13 +6429,16 @@ void A_SlingAppear(mobj_t *actor) while (mlength > 0) { spawnee = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLMACECHAIN); - P_SetTarget(&spawnee->tracer, actor); - P_SetTarget(&spawnee->hprev, hprev); - P_SetTarget(&hprev->hnext, spawnee); - hprev = spawnee; + if (!P_MobjWasRemoved(spawnee)) + { + P_SetTarget(&spawnee->tracer, actor); + P_SetTarget(&spawnee->hprev, hprev); + P_SetTarget(&hprev->hnext, spawnee); + hprev = spawnee; - spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; - spawnee->movecount = mlength; + spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; + spawnee->movecount = mlength; + } mlength--; } @@ -6575,6 +6698,8 @@ void A_OldRingExplode(mobj_t *actor) { const angle_t fa = (i*FINEANGLES/16) & FINEMASK; mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); + if (P_MobjWasRemoved(mo)) + continue; P_SetTarget(&mo->target, actor->target); // Transfer target so player gets the points mo->momx = FixedMul(FINECOSINE(fa),ns); @@ -6601,33 +6726,37 @@ void A_OldRingExplode(mobj_t *actor) { } mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); - - P_SetTarget(&mo->target, actor->target); - mo->momz = ns; - mo->flags2 |= MF2_DEBRIS; - mo->fuse = TICRATE/5; - - if (changecolor) + if (!P_MobjWasRemoved(mo)) { - if (!(gametyperules & GTR_TEAMS)) - mo->color = actor->target->color; //copy color - else if (actor->target->player->ctfteam == 2) - mo->color = skincolor_bluering; + P_SetTarget(&mo->target, actor->target); + mo->momz = ns; + mo->flags2 |= MF2_DEBRIS; + mo->fuse = TICRATE/5; + + if (changecolor) + { + if (!(gametyperules & GTR_TEAMS)) + mo->color = actor->target->color; //copy color + else if (actor->target->player->ctfteam == 2) + mo->color = skincolor_bluering; + } } mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); - - P_SetTarget(&mo->target, actor->target); - mo->momz = -ns; - mo->flags2 |= MF2_DEBRIS; - mo->fuse = TICRATE/5; - - if (changecolor) + if (!P_MobjWasRemoved(mo)) { - if (!(gametyperules & GTR_TEAMS)) - mo->color = actor->target->color; //copy color - else if (actor->target->player->ctfteam == 2) - mo->color = skincolor_bluering; + P_SetTarget(&mo->target, actor->target); + mo->momz = -ns; + mo->flags2 |= MF2_DEBRIS; + mo->fuse = TICRATE/5; + + if (changecolor) + { + if (!(gametyperules & GTR_TEAMS)) + mo->color = actor->target->color; //copy color + else if (actor->target->player->ctfteam == 2) + mo->color = skincolor_bluering; + } } } @@ -7263,23 +7392,26 @@ void A_Boss2Chase(mobj_t *actor) fa = (actor->movedir*FINEANGLES/8) & FINEMASK; goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance); - goop->momx = FixedMul(FINECOSINE(fa),ns); - goop->momy = FixedMul(FINESINE(fa),ns); - goop->momz = FixedMul(4*FRACUNIT, actor->scale); - goop->fuse = 10*TICRATE; - - if (actor->info->attacksound) - S_StartAttackSound(actor, actor->info->attacksound); - - if (P_RandomChance(FRACUNIT/2)) + if (!P_MobjWasRemoved(goop)) { - goop->momx *= 2; - goop->momy *= 2; - } - else if (P_RandomChance(129*FRACUNIT/256)) - { - goop->momx *= 3; - goop->momy *= 3; + goop->momx = FixedMul(FINECOSINE(fa),ns); + goop->momy = FixedMul(FINESINE(fa),ns); + goop->momz = FixedMul(4*FRACUNIT, actor->scale); + goop->fuse = 10*TICRATE; + + if (actor->info->attacksound) + S_StartAttackSound(actor, actor->info->attacksound); + + if (P_RandomChance(FRACUNIT/2)) + { + goop->momx *= 2; + goop->momy *= 2; + } + else if (P_RandomChance(129*FRACUNIT/256)) + { + goop->momx *= 3; + goop->momy *= 3; + } } actor->flags2 |= MF2_JUSTATTACKED; @@ -7320,6 +7452,8 @@ void A_Boss2Pogo(mobj_t *actor) fa = (actor->movedir*FINEANGLES/8) & FINEMASK; goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance); + if (P_MobjWasRemoved(goop)) + continue; goop->momx = FixedMul(FINECOSINE(fa),ns); goop->momy = FixedMul(FINESINE(fa),ns); goop->momz = FixedMul(4*FRACUNIT, actor->scale); @@ -7640,7 +7774,8 @@ void A_Boss2PogoTarget(mobj_t *actor) if (actor->info->missilestate) // spawn the pogo stick collision box { mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate); - P_SetTarget(&pogo->target, actor); + if (!P_MobjWasRemoved(pogo)) + P_SetTarget(&pogo->target, actor); } actor->reactiontime = 1; @@ -8131,6 +8266,8 @@ void A_Boss1Spikeballs(mobj_t *actor) return; ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL); + if (P_MobjWasRemoved(ball)) + return; P_SetTarget(&ball->target, actor); ball->movedir = FixedAngle(FixedMul(FixedDiv(locvar1<threshold = ball->radius + actor->radius + ball->info->painchance; @@ -8315,19 +8452,22 @@ void A_Boss3ShockThink(mobj_t *actor) snew = P_SpawnMobj((x0 >> 1) + (x1 >> 1), (y0 >> 1) + (y1 >> 1), (actor->z >> 1) + (snext->z >> 1), actor->type); - snew->momx = (actor->momx + snext->momx) >> 1; - snew->momy = (actor->momy + snext->momy) >> 1; - snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? - snew->angle = (actor->angle + snext->angle) >> 1; - P_SetTarget(&snew->target, actor->target); - snew->fuse = actor->fuse; + if (!P_MobjWasRemoved(snew)) + { + snew->momx = (actor->momx + snext->momx) >> 1; + snew->momy = (actor->momy + snext->momy) >> 1; + snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? + snew->angle = (actor->angle + snext->angle) >> 1; + P_SetTarget(&snew->target, actor->target); + snew->fuse = actor->fuse; - P_SetScale(snew, actor->scale); - snew->destscale = actor->destscale; - snew->scalespeed = actor->scalespeed; + P_SetScale(snew, actor->scale); + snew->destscale = actor->destscale; + snew->scalespeed = actor->scalespeed; - P_SetTarget(&actor->hnext, snew); - P_SetTarget(&snew->hnext, snext); + P_SetTarget(&actor->hnext, snew); + P_SetTarget(&snew->hnext, snext); + } } } } @@ -8462,10 +8602,13 @@ void A_SmokeTrailer(mobj_t *actor) if (actor->eflags & MFE_VERTICALFLIP) { th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z + actor->height - FixedMul(mobjinfo[locvar1].height, actor->scale), locvar1); - th->flags2 |= MF2_OBJECTFLIP; + if (!P_MobjWasRemoved(th)) + th->flags2 |= MF2_OBJECTFLIP; } else th = P_SpawnMobj(actor->x-actor->momx, actor->y-actor->momy, actor->z, locvar1); + if (P_MobjWasRemoved(th)) + return; P_SetObjectMomZ(th, FRACUNIT, false); th->destscale = actor->scale; P_SetScale(th, actor->scale); @@ -8502,6 +8645,8 @@ void A_SpawnObjectAbsolute(mobj_t *actor) type = (mobjtype_t)(locvar2&65535); mo = P_SpawnMobj(x<angle = actor->angle; @@ -8544,6 +8689,8 @@ void A_SpawnObjectRelative(mobj_t *actor) mo = P_SpawnMobj(actor->x + FixedMul(x<scale), actor->y + FixedMul(y<scale), (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), type); + if (P_MobjWasRemoved(mo)) + return; // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn mo->angle = actor->angle; @@ -9205,12 +9352,15 @@ void A_BossJetFume(mobj_t *actor) jetz = actor->z + FixedMul(38*FRACUNIT, actor->scale); filler = P_SpawnMobj(jetx, jety, jetz, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->fuse = 56; + if (!P_MobjWasRemoved(filler)) + { + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->fuse = 56; + } if (actor->eflags & MFE_VERTICALFLIP) jetz = actor->z + actor->height - FixedMul(12*FRACUNIT + mobjinfo[MT_JETFUME1].height, actor->scale); @@ -9220,22 +9370,28 @@ void A_BossJetFume(mobj_t *actor) filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), jety + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), jetz, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->fuse = 57; + if (!P_MobjWasRemoved(filler)) + { + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->fuse = 57; + } filler = P_SpawnMobj(jetx + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), jety + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(24*FRACUNIT, actor->scale)), jetz, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->fuse = 58; + if (!P_MobjWasRemoved(filler)) + { + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->fuse = 58; + } P_SetTarget(&actor->tracer, filler); } @@ -9263,14 +9419,17 @@ void A_BossJetFume(mobj_t *actor) else if (locvar1 == 2) // Metal Sonic jet fumes { filler = P_SpawnMobj(actor->x, actor->y, actor->z, MT_JETFUME1); - P_SetTarget(&filler->target, actor); - filler->fuse = 59; - P_SetTarget(&actor->tracer, filler); - P_SetScale(filler, (filler->destscale = actor->scale/3)); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; - filler->color = SKINCOLOR_ICY; - filler->colorized = true; + if (!P_MobjWasRemoved(filler)) + { + P_SetTarget(&filler->target, actor); + filler->fuse = 59; + P_SetTarget(&actor->tracer, filler); + P_SetScale(filler, (filler->destscale = actor->scale/3)); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + filler->color = SKINCOLOR_ICY; + filler->colorized = true; + } } else if (locvar1 == 3) // Boss 4 jet flame { @@ -9280,12 +9439,15 @@ void A_BossJetFume(mobj_t *actor) else jetz = actor->z - 50*actor->scale; filler = P_SpawnMobj(actor->x, actor->y, jetz, MT_JETFLAME); - P_SetTarget(&filler->target, actor); - // Boss 4 already uses its tracer for other things - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; + if (!P_MobjWasRemoved(filler)) + { + P_SetTarget(&filler->target, actor); + // Boss 4 already uses its tracer for other things + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + } } else if (locvar1 == 4) // Boss 4 Spectator Eggrobo jet flame { @@ -9300,12 +9462,15 @@ void A_BossJetFume(mobj_t *actor) jetx = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, movefactor*actor->scale) - P_ReturnThrustX(actor, actor->angle, 19*actor->scale); jety = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, movefactor*actor->scale) - P_ReturnThrustY(actor, actor->angle, 19*actor->scale); filler = P_SpawnMobj(jetx, jety, jetz, MT_EGGROBO1JET); - filler->movefactor = movefactor; - P_SetTarget(&filler->target, actor); - filler->destscale = actor->scale; - P_SetScale(filler, filler->destscale); - if (actor->eflags & MFE_VERTICALFLIP) - filler->flags2 |= MF2_OBJECTFLIP; + if (!P_MobjWasRemoved(filler)) + { + filler->movefactor = movefactor; + P_SetTarget(&filler->target, actor); + filler->destscale = actor->scale; + P_SetScale(filler, filler->destscale); + if (actor->eflags & MFE_VERTICALFLIP) + filler->flags2 |= MF2_OBJECTFLIP; + } if (movefactor <= 0) break; movefactor = -movefactor; @@ -11007,6 +11172,8 @@ void A_TrapShot(mobj_t *actor) type, frontoff, (INT16)(locvar2 & 65535), vertoff); missile = P_SpawnMobj(x, y, z, type); + if (P_MobjWasRemoved(missile)) + return; if (actor->eflags & MFE_VERTICALFLIP) missile->flags2 |= MF2_OBJECTFLIP; @@ -11077,18 +11244,21 @@ void A_VileTarget(mobj_t *actor) actor->target->y, actor->target->z + ((actor->target->eflags & MFE_VERTICALFLIP) ? actor->target->height - mobjinfo[fogtype].height : 0), fogtype); - if (actor->target->eflags & MFE_VERTICALFLIP) + if (!P_MobjWasRemoved(fog)) { - fog->eflags |= MFE_VERTICALFLIP; - fog->flags2 |= MF2_OBJECTFLIP; - } - fog->destscale = actor->target->scale; - P_SetScale(fog, fog->destscale); + if (actor->target->eflags & MFE_VERTICALFLIP) + { + fog->eflags |= MFE_VERTICALFLIP; + fog->flags2 |= MF2_OBJECTFLIP; + } + fog->destscale = actor->target->scale; + P_SetScale(fog, fog->destscale); - P_SetTarget(&actor->tracer, fog); - P_SetTarget(&fog->target, actor); - P_SetTarget(&fog->tracer, actor->target); - A_VileFire(fog); + P_SetTarget(&actor->tracer, fog); + P_SetTarget(&fog->target, actor); + P_SetTarget(&fog->tracer, actor->target); + A_VileFire(fog); + } } else { @@ -11108,19 +11278,22 @@ void A_VileTarget(mobj_t *actor) players[i].mo->y, players[i].mo->z + ((players[i].mo->eflags & MFE_VERTICALFLIP) ? players[i].mo->height - mobjinfo[fogtype].height : 0), fogtype); - if (players[i].mo->eflags & MFE_VERTICALFLIP) + if (!P_MobjWasRemoved(fog)) { - fog->eflags |= MFE_VERTICALFLIP; - fog->flags2 |= MF2_OBJECTFLIP; - } - fog->destscale = players[i].mo->scale; - P_SetScale(fog, fog->destscale); + if (players[i].mo->eflags & MFE_VERTICALFLIP) + { + fog->eflags |= MFE_VERTICALFLIP; + fog->flags2 |= MF2_OBJECTFLIP; + } + fog->destscale = players[i].mo->scale; + P_SetScale(fog, fog->destscale); - if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now - P_SetTarget(&actor->tracer, fog); - P_SetTarget(&fog->target, actor); - P_SetTarget(&fog->tracer, players[i].mo); - A_VileFire(fog); + if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now + P_SetTarget(&actor->tracer, fog); + P_SetTarget(&fog->target, actor); + P_SetTarget(&fog->tracer, players[i].mo); + A_VileFire(fog); + } } } } @@ -11590,6 +11763,8 @@ void A_BrakLobShot(mobj_t *actor) typeOfShot = MT_CANNONBALL; else typeOfShot = (mobjtype_t)locvar1; shot = P_SpawnMobj(actor->x, actor->y, actor->z + FixedMul(locvar2*FRACUNIT, actor->scale), typeOfShot); + if (P_MobjWasRemoved(shot)) + return; if (shot->info->seesound) S_StartSound(shot, shot->info->seesound); P_SetTarget(&shot->target, actor); // where it came from @@ -11656,6 +11831,8 @@ void A_NapalmScatter(mobj_t *actor) const angle_t fa = (i*FINEANGLES/numToShoot) & FINEMASK; mo = P_SpawnMobj(actor->x, actor->y, actor->z, typeOfShot); + if (P_MobjWasRemoved(mo)) + continue; P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot mo->angle = fa << ANGLETOFINESHIFT; @@ -11681,6 +11858,8 @@ void A_SpawnFreshCopy(mobj_t *actor) return; newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); + if (P_MobjWasRemoved(newObject)) + return; newObject->flags2 = actor->flags2 & MF2_AMBUSH; newObject->angle = actor->angle; newObject->color = actor->color; @@ -11716,6 +11895,8 @@ mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz } flicky = P_SpawnMobjFromMobj(actor, offsx, offsy, 0, flickytype); + if (P_MobjWasRemoved(flicky)) + return NULL; flicky->angle = actor->angle; if (flickytype == MT_SEED) @@ -11827,8 +12008,11 @@ void A_FlickyCenter(mobj_t *actor) if (!actor->tracer) { mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false, 0); - P_SetTarget(&flicky->target, actor); - P_SetTarget(&actor->tracer, flicky); + if (!P_MobjWasRemoved(flicky)) + { + P_SetTarget(&flicky->target, actor); + P_SetTarget(&actor->tracer, flicky); + } if (actor->spawnpoint) { @@ -11863,18 +12047,21 @@ void A_FlickyCenter(mobj_t *actor) locvar1 = flickytype; } - if (actor->flags & MF_GRENADEBOUNCE) // in-place - actor->tracer->fuse = 0; - else if (actor->flags & MF_SLIDEME) // aimless + if (!P_MobjWasRemoved(flicky)) { - actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly. - actor->tracer->angle = P_RandomKey(180)*ANG2; - } - else //orbit - actor->tracer->fuse = FRACUNIT; + if (actor->flags & MF_GRENADEBOUNCE) // in-place + actor->tracer->fuse = 0; + else if (actor->flags & MF_SLIDEME) // aimless + { + actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly. + actor->tracer->angle = P_RandomKey(180)*ANG2; + } + else //orbit + actor->tracer->fuse = FRACUNIT; - if (locvar1 == MT_FLICKY_08) - P_InternalFlickySetColor(actor->tracer, actor->extravalue2); + if (locvar1 == MT_FLICKY_08) + P_InternalFlickySetColor(actor->tracer, actor->extravalue2); + } actor->extravalue2 = 0; } @@ -11885,7 +12072,8 @@ void A_FlickyCenter(mobj_t *actor) fixed_t originy = actor->movefactor; fixed_t originz = actor->watertop; - actor->tracer->fuse = FRACUNIT; + if (!P_MobjWasRemoved(actor->tracer)) + actor->tracer->fuse = FRACUNIT; // Impose default home radius if flicky orbits around player if (!actor->extravalue1) @@ -11917,6 +12105,8 @@ void P_InternalFlickyBubble(mobj_t *actor) return; overlay = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY); + if (P_MobjWasRemoved(overlay)) + return; P_SetMobjStateNF(overlay, mobjinfo[actor->type].raisestate); P_SetTarget(&actor->tracer, overlay); P_SetTarget(&overlay->target, actor); @@ -12291,7 +12481,8 @@ void A_FlameParticle(mobj_t *actor) P_RandomRange(rad, -rad)<frame = actor->frame; if (!(locvar1 & 1)) @@ -12477,6 +12670,8 @@ void A_MineExplode(mobj_t *actor) actor->y+P_RandomRange(-dist, dist)*FRACUNIT, actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT, type); + if (P_MobjWasRemoved(b)) + continue; fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z; fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx)); b->momx = FixedDiv(dx, dm)*3; @@ -12605,6 +12800,8 @@ void A_SpawnParticleRelative(mobj_t *actor) mo = P_SpawnMobj(actor->x + FixedMul(x<scale), actor->y + FixedMul(y<scale), (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), MT_PARTICLE); + if (P_MobjWasRemoved(mo)) + return; // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn mo->angle = actor->angle; @@ -12997,11 +13194,14 @@ void A_DoNPCSkid(mobj_t *actor) if (!(leveltime % 3)) { mobj_t *particle = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_SPINDUST); - particle->tics = 10; + if (!P_MobjWasRemoved(particle)) + { + particle->tics = 10; - P_SetScale(particle, 2*actor->scale/3); - particle->destscale = actor->scale; - P_SetObjectMomZ(particle, FRACUNIT, false); + P_SetScale(particle, 2*actor->scale/3); + particle->destscale = actor->scale; + P_SetObjectMomZ(particle, FRACUNIT, false); + } } } @@ -13304,11 +13504,18 @@ void A_Boss5MakeJunk(mobj_t *actor) if (actor->extravalue2 > 10) { mobj_t *front = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_VWREF); - broked = P_SpawnMobjFromMobj(front, 0, 0, 0, MT_VWREB); - front->z = broked->z = front->z - broked->height; - P_SetObjectMomZ(front, (4<momz = front->momz; - broked->fuse = front->fuse = (actor->height+(2*front->height))/front->momz; + if (!P_MobjWasRemoved(front)) + { + P_SetObjectMomZ(front, (4<z -= broked->height; + broked->z = front->z; + broked->momz = front->momz; + broked->fuse = front->fuse = (actor->height+(2*front->height))/front->momz; + } + } } if (!(actor->colorized = !actor->colorized)) actor->frame |= FF_FULLBRIGHT; @@ -13322,6 +13529,8 @@ void A_Boss5MakeJunk(mobj_t *actor) while (i--) { broked = P_SpawnMobjFromMobj(actor, 0, 0, FRACUNIT, MT_BROKENROBOT); + if (P_MobjWasRemoved(broked)) + continue; if (locvar2 & 2) broked->fuse = TICRATE; else @@ -13339,13 +13548,17 @@ void A_Boss5MakeJunk(mobj_t *actor) if (locvar2 & 2) { broked = P_SpawnMobjFromMobj(actor, 0, 0, 64<fuse = states[S_FANG_INTRO12].tics+10; - P_SetMobjState(broked, S_ALART1); + if (!P_MobjWasRemoved(broked)) + { + S_StartSound(broked, sfx_alart); + broked->fuse = states[S_FANG_INTRO12].tics+10; + P_SetMobjState(broked, S_ALART1); + } } else if (locvar2 & 1) { - broked->z += broked->momz; + if (!P_MobjWasRemoved(broked)) + broked->z += broked->momz; S_StartSound(actor, sfx_s3kccs); actor->flags &= ~MF_NOCLIPTHING; } @@ -13404,6 +13617,8 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi z, mobjtype ); + if (P_MobjWasRemoved(dust)) + continue; dust->angle = ang*i + ANGLE_90; P_SetScale(dust, FixedMul(initscale, scale)); @@ -13556,9 +13771,12 @@ void A_DustDevilThink(mobj_t *actor) if (P_IsObjectOnGround(actor)) { angle_t dustang = ((P_RandomRange(0, 7)*ANGLE_45)>>ANGLETOFINESHIFT) & FINEMASK; mobj_t *dust = P_SpawnMobj(actor->x + 96 * FixedMul(scale, FINECOSINE(dustang)), actor->y + 96 * FixedMul(scale, FINESINE(dustang)), actor->z, MT_ARIDDUST); - P_SetMobjState(dust, dust->info->spawnstate + P_RandomRange(0, 2)); - dust->destscale = scale * 3; - P_SetScale(dust, dust->destscale); + if (!P_MobjWasRemoved(dust)) + { + P_SetMobjState(dust, dust->info->spawnstate + P_RandomRange(0, 2)); + dust->destscale = scale * 3; + P_SetScale(dust, dust->destscale); + } } actor->extravalue1++; @@ -13574,6 +13792,8 @@ void A_DustDevilThink(mobj_t *actor) fixed_t pz = actor->z; layer = P_SpawnMobj(px, py, pz, MT_DUSTLAYER); + if (P_MobjWasRemoved(layer)) + continue; layer->momz = 5 * scale; layer->angle = ANGLE_90 + ANGLE_90*i; layer->extravalue1 = TICRATE * 3; @@ -13759,6 +13979,8 @@ void A_DebrisRandom(mobj_t *actor) static mobj_t *P_TrainSeg(mobj_t *src, fixed_t x, fixed_t y, fixed_t z, angle_t ang, spritenum_t spr, UINT32 frame) { mobj_t *s = P_SpawnMobj(x, y, z, MT_TRAINSEG); + if (P_MobjWasRemoved(s)) + return NULL; s->fuse = 16*TICRATE; s->sprite = spr; s->frame = frame|FF_PAPERSPRITE; @@ -13911,7 +14133,7 @@ static void P_SnapperLegPlace(mobj_t *mo) // Move as many legs as available. seg = seg->tracer; - do + while (seg) { o1 = seg->extravalue1; o2 = seg->extravalue2; @@ -13936,7 +14158,7 @@ static void P_SnapperLegPlace(mobj_t *mo) seg->angle = R_PointToAngle2(mo->x, mo->y, seg->x, seg->y); seg = seg->tracer; - } while (seg); + } } // @@ -13960,6 +14182,12 @@ void A_SnapperSpawn(mobj_t *actor) // It spawns 1 head. seg = P_SpawnMobjFromMobj(actor, 0, 0, 0, headtype); + if (P_MobjWasRemoved(seg)) + { + // if we can't spawn the head, don't spawn the snapper at all + P_RemoveMobj(actor); + return; + } P_SetTarget(&ptr->tracer, seg); ptr = seg; @@ -13967,6 +14195,8 @@ void A_SnapperSpawn(mobj_t *actor) for (i = 1; i <= 4; i++) { seg = P_SpawnMobjFromMobj(actor, 0, 0, 0, legtype); + if (P_MobjWasRemoved(seg)) + continue; P_SetTarget(&ptr->tracer, seg); ptr = seg; @@ -14068,7 +14298,8 @@ void A_SnapperThinker(mobj_t *actor) if (actor->reactiontime < 4) { mobj_t *dust = P_SpawnMobj(x0, y0, actor->z, MT_SPINDUST); - P_Thrust(dust, ang + ANGLE_180 + FixedAngle(P_RandomRange(-20, 20)*FRACUNIT), speed*FRACUNIT); + if (!P_MobjWasRemoved(dust)) + P_Thrust(dust, ang + ANGLE_180 + FixedAngle(P_RandomRange(-20, 20)*FRACUNIT), speed*FRACUNIT); } if (actor->extravalue2 == 0) @@ -14178,6 +14409,8 @@ void A_MinecartSparkThink(mobj_t *actor) for (i = 1; i <= 8; i++) { mobj_t *trail = P_SpawnMobj(actor->x - dx*i, actor->y - dy*i, actor->z - dz*i, MT_PARTICLE); + if (P_MobjWasRemoved(trail)) + continue; trail->tics = 2; trail->sprite = actor->sprite; P_SetScale(trail, trail->scale/4); @@ -14263,7 +14496,8 @@ void A_LavafallLava(mobj_t *actor) return; lavafall = P_SpawnMobjFromMobj(actor, 0, 0, -8*FRACUNIT, MT_LAVAFALL_LAVA); - lavafall->momz = -P_MobjFlip(actor)*25*FRACUNIT; + if (!P_MobjWasRemoved(lavafall)) + lavafall->momz = -P_MobjFlip(actor)*25*FRACUNIT; } // Function: A_FallingLavaCheck @@ -14338,9 +14572,18 @@ void A_SpawnPterabytes(mobj_t *actor) c = FINECOSINE(fa); s = FINESINE(fa); waypoint = P_SpawnMobjFromMobj(actor, FixedMul(c, rad), FixedMul(s, rad), 0, MT_PTERABYTEWAYPOINT); + if (P_MobjWasRemoved(waypoint)) + continue; + waypoint->angle = ang + ANGLE_90; P_SetTarget(&waypoint->tracer, actor); ptera = P_SpawnMobjFromMobj(waypoint, 0, 0, 0, MT_PTERABYTE); + if (P_MobjWasRemoved(ptera)) + { + P_RemoveMobj(waypoint); + continue; + } + ptera->angle = waypoint->angle; P_SetTarget(&ptera->tracer, waypoint); ptera->extravalue1 = 0; @@ -14388,14 +14631,17 @@ void A_RolloutSpawn(mobj_t *actor) || P_MobjWasRemoved(actor->target) || P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) > locvar1) { - actor->target = P_SpawnMobj(actor->x, actor->y, actor->z, locvar2); - actor->target->flags2 |= (actor->flags2 & (MF2_AMBUSH | MF2_OBJECTFLIP)) | MF2_SLIDEPUSH; - actor->target->eflags |= (actor->eflags & MFE_VERTICALFLIP); - - if (actor->target->flags2 & MF2_AMBUSH) + P_SetTarget(&actor->target, P_SpawnMobj(actor->x, actor->y, actor->z, locvar2)); + if (!P_MobjWasRemoved(actor->target)) { - actor->target->color = SKINCOLOR_SUPERRUST3; - actor->target->colorized = true; + actor->target->flags2 |= (actor->flags2 & (MF2_AMBUSH | MF2_OBJECTFLIP)) | MF2_SLIDEPUSH; + actor->target->eflags |= (actor->eflags & MFE_VERTICALFLIP); + + if (actor->target->flags2 & MF2_AMBUSH) + { + actor->target->color = SKINCOLOR_SUPERRUST3; + actor->target->colorized = true; + } } } } @@ -14516,6 +14762,8 @@ void A_DragonbomberSpawn(mobj_t *actor) x = P_ReturnThrustX(mo, mo->angle, -mo->radius << 1); y = P_ReturnThrustY(mo, mo->angle, -mo->radius << 1); segment = P_SpawnMobjFromMobj(mo, x, y, 0, MT_DRAGONTAIL); + if (P_MobjWasRemoved(segment)) + continue; P_SetTarget(&segment->target, mo); P_SetTarget(&mo->tracer, segment); segment->angle = mo->angle; @@ -14524,6 +14772,8 @@ void A_DragonbomberSpawn(mobj_t *actor) for (i = 0; i < 2; i++) // spawn wings { mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_DRAGONWING); + if (P_MobjWasRemoved(mo)) + continue; P_SetTarget(&mo->target, actor); mo->movedir = ANGLE_90 + i * ANGLE_180; } diff --git a/src/p_floor.c b/src/p_floor.c index 9c24f5851..dcb96a3b2 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -1921,6 +1921,9 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) for (c = topz; c > bottomz; c -= spacing) { spawned = P_SpawnMobj(a, b, c, type); + if (P_MobjWasRemoved(spawned)) + continue; + spawned->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones if (fromcenter) diff --git a/src/p_inter.c b/src/p_inter.c index 8bc5c95e4..73d6b707f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -199,6 +199,9 @@ void P_DoNightsScore(player_t *player) player->linktimer = nightslinktics; } + if (P_MobjWasRemoved(dummymo)) + return; + if (player->linkcount < 10) { if (player->bonustime) @@ -1214,7 +1217,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { // A flicky orbits us now mobj_t *flickyobj = P_SpawnMobj(toucher->x, toucher->y, toucher->z + toucher->info->height, MT_NIGHTOPIANHELPER); - P_SetTarget(&flickyobj->target, toucher); + if (!P_MobjWasRemoved(flickyobj)) + P_SetTarget(&flickyobj->target, toucher); player->powers[pw_nights_helper] = (UINT16)special->info->speed; } @@ -1225,7 +1229,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (playeringame[i] && players[i].mo && players[i].powers[pw_carry] == CR_NIGHTSMODE) { players[i].powers[pw_nights_helper] = (UINT16)special->info->speed; flickyobj = P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z + players[i].mo->info->height, MT_NIGHTOPIANHELPER); - P_SetTarget(&flickyobj->target, players[i].mo); + if (!P_MobjWasRemoved(flickyobj)) + P_SetTarget(&flickyobj->target, players[i].mo); } if (special->info->deathsound != sfx_None) S_StartSound(NULL, special->info->deathsound); @@ -1734,9 +1739,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!player->bot && player->bot != BOT_MPAI && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART && !(player->powers[pw_ignorelatch] & (1<<15))) { mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART); - P_SetTarget(&mcart->target, toucher); - mcart->angle = toucher->angle = player->drawangle = special->angle; - mcart->friction = FRACUNIT; + if (!P_MobjWasRemoved(mcart)) + { + P_SetTarget(&mcart->target, toucher); + mcart->angle = toucher->angle = player->drawangle = special->angle; + mcart->friction = FRACUNIT; + } P_ResetPlayer(player); player->pflags |= PF_JUMPDOWN; @@ -2506,7 +2514,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget break; } - P_SetMobjState(scoremobj, scorestate); + if (!P_MobjWasRemoved(scoremobj)) + P_SetMobjState(scoremobj, scorestate); source->player->scoreadd = locscoreadd; } @@ -2667,6 +2676,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget mo = P_SpawnMobj(inflictor->x + inflictor->momx, inflictor->y + inflictor->momy, inflictor->z + (inflictor->height / 2) + inflictor->momz, MT_EXTRALARGEBUBBLE); else mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE); + if (P_MobjWasRemoved(mo)) + break; mo->destscale = target->scale; P_SetScale(mo, mo->destscale); P_SetMobjState(mo, mo->info->raisestate); @@ -2745,8 +2756,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget mo->angle = FixedAngle((P_RandomKey(36)*10)<angle = mo->angle; - P_SetMobjState(mo2, S_BOSSSEBH2); + if (!P_MobjWasRemoved(mo2)) + { + mo2->angle = mo->angle; + P_SetMobjState(mo2, S_BOSSSEBH2); + } if (++i == 2) // we've already removed 2 of these, let's stop now break; @@ -2845,7 +2859,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (flip) momz *= -1; #define makechunk(angtweak, xmov, ymov) \ + do {\ chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);\ + if (P_MobjWasRemoved(chunk))\ + break;\ P_SetMobjState(chunk, target->info->xdeathstate);\ chunk->health = 0;\ chunk->angle = angtweak;\ @@ -2855,7 +2872,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget chunk->y += ymov;\ P_SetThingPosition(chunk);\ P_InstaThrust(chunk,chunk->angle, 4*scale);\ - chunk->momz = momz + chunk->momz = momz;\ + } while (0) makechunk(ang + ANGLE_180, -xoffs, -yoffs); makechunk(ang, xoffs, yoffs); @@ -2868,20 +2886,23 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget momz *= -1; chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE); - P_SetMobjState(chunk, target->info->deathstate); - chunk->health = 0; - chunk->angle = ang + ANGLE_180; - P_UnsetThingPosition(chunk); - chunk->flags = MF_NOCLIP; - chunk->x -= xoffs; - chunk->y -= yoffs; - if (flip) - chunk->z -= 12*scale; - else - chunk->z += 12*scale; - P_SetThingPosition(chunk); - P_InstaThrust(chunk, chunk->angle, 2*scale); - chunk->momz = momz; + if (!P_MobjWasRemoved(chunk)) + { + P_SetMobjState(chunk, target->info->deathstate); + chunk->health = 0; + chunk->angle = ang + ANGLE_180; + P_UnsetThingPosition(chunk); + chunk->flags = MF_NOCLIP; + chunk->x -= xoffs; + chunk->y -= yoffs; + if (flip) + chunk->z -= 12*scale; + else + chunk->z += 12*scale; + P_SetThingPosition(chunk); + P_InstaThrust(chunk, chunk->angle, 2*scale); + chunk->momz = momz; + } P_SetMobjState(target, target->info->deathstate); target->health = 0; @@ -2890,7 +2911,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->flags = MF_NOCLIP; target->x += xoffs; target->y += yoffs; - target->z = chunk->z; + if (flip) + target->z -= 12*scale; + else + target->z += 12*scale; P_SetThingPosition(target); P_InstaThrust(target, target->angle, 2*scale); target->momz = momz; @@ -2913,21 +2937,25 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget sprflip = P_RandomChance(FRACUNIT/2); #define makechunk(angtweak, xmov, ymov) \ - chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\ - P_SetMobjState(chunk, target->info->xdeathstate);\ - chunk->health = 0;\ - chunk->angle = target->angle;\ - P_UnsetThingPosition(chunk);\ - chunk->flags = MF_NOCLIP;\ - chunk->x += xmov - forwardxoffs;\ - chunk->y += ymov - forwardyoffs;\ - P_SetThingPosition(chunk);\ - P_InstaThrust(chunk, angtweak, 4*scale);\ - chunk->momz = P_RandomRange(5, 7)*scale;\ - if (flip)\ - chunk->momz *= -1;\ - if (sprflip)\ - chunk->frame |= FF_VERTICALFLIP + do {\ + chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\ + if (P_MobjWasRemoved(chunk))\ + break;\ + P_SetMobjState(chunk, target->info->xdeathstate);\ + chunk->health = 0;\ + chunk->angle = target->angle;\ + P_UnsetThingPosition(chunk);\ + chunk->flags = MF_NOCLIP;\ + chunk->x += xmov - forwardxoffs;\ + chunk->y += ymov - forwardyoffs;\ + P_SetThingPosition(chunk);\ + P_InstaThrust(chunk, angtweak, 4*scale);\ + chunk->momz = P_RandomRange(5, 7)*scale;\ + if (flip)\ + chunk->momz *= -1;\ + if (sprflip)\ + chunk->frame |= FF_VERTICALFLIP;\ + } while (0) makechunk(ang + ANGLE_180, -xoffs, -yoffs); sprflip = !sprflip; @@ -2939,21 +2967,23 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget sprflip = P_RandomChance(FRACUNIT/2); chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE); - - P_SetMobjState(chunk, target->info->deathstate); - chunk->health = 0; - chunk->angle = target->angle; - P_UnsetThingPosition(chunk); - chunk->flags = MF_NOCLIP; - chunk->x += forwardxoffs - xoffs; - chunk->y += forwardyoffs - yoffs; - P_SetThingPosition(chunk); - P_InstaThrust(chunk, ang + ANGLE_180, 2*scale); - chunk->momz = P_RandomRange(5, 7)*scale; - if (flip) - chunk->momz *= -1; - if (sprflip) - chunk->frame |= FF_VERTICALFLIP; + if (!P_MobjWasRemoved(chunk)) + { + P_SetMobjState(chunk, target->info->deathstate); + chunk->health = 0; + chunk->angle = target->angle; + P_UnsetThingPosition(chunk); + chunk->flags = MF_NOCLIP; + chunk->x += forwardxoffs - xoffs; + chunk->y += forwardyoffs - yoffs; + P_SetThingPosition(chunk); + P_InstaThrust(chunk, ang + ANGLE_180, 2*scale); + chunk->momz = P_RandomRange(5, 7)*scale; + if (flip) + chunk->momz *= -1; + if (sprflip) + chunk->frame |= FF_VERTICALFLIP; + } P_SetMobjState(target, target->info->deathstate); target->health = 0; @@ -3829,6 +3859,8 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) z += player->mo->height - mobjinfo[objType].height; mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType); + if (P_MobjWasRemoved(mo)) + continue; mo->fuse = 8*TICRATE; P_SetTarget(&mo->target, player->mo); @@ -3962,6 +3994,9 @@ void P_PlayerWeaponPanelBurst(player_t *player) z += player->mo->height - mobjinfo[weptype].height; mo = P_SpawnMobj(player->mo->x, player->mo->y, z, weptype); + if (P_MobjWasRemoved(mo)) + continue; + mo->reactiontime = ammoamt; mo->flags2 |= MF2_DONTRESPAWN; mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); @@ -3995,13 +4030,13 @@ void P_PlayerWeaponAmmoBurst(player_t *player) mobj_t *mo; angle_t fa; fixed_t ns; - INT32 i = 0; + INT32 i; fixed_t z; mobjtype_t weptype = 0; powertype_t power = 0; - while (true) + for (i = 0;; i++) { if (player->powers[pw_bouncering]) { @@ -4046,6 +4081,8 @@ void P_PlayerWeaponAmmoBurst(player_t *player) z += player->mo->height - mobjinfo[weptype].height; mo = P_SpawnMobj(player->mo->x, player->mo->y, z, weptype); + if (P_MobjWasRemoved(mo)) + continue; mo->health = player->powers[power]; mo->flags2 |= MF2_DONTRESPAWN; mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); @@ -4071,8 +4108,6 @@ void P_PlayerWeaponAmmoBurst(player_t *player) if (i & 1) P_SetObjectMomZ(mo, 3*FRACUNIT, true); - - i++; } } @@ -4097,45 +4132,50 @@ void P_PlayerWeaponPanelOrAmmoBurst(player_t *player) player->ringweapons &= ~rwflag; \ SETUP_DROP(pickup) \ mo = P_SpawnMobj(player->mo->x, player->mo->y, z, pickup); \ - mo->reactiontime = 0; \ - mo->flags2 |= MF2_DONTRESPAWN; \ - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \ - P_SetTarget(&mo->target, player->mo); \ - mo->fuse = 12*TICRATE; \ - mo->destscale = player->mo->scale; \ - P_SetScale(mo, player->mo->scale); \ - mo->momx = FixedMul(FINECOSINE(fa),ns); \ - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \ - mo->momy = FixedMul(FINESINE(fa),ns); \ - P_SetObjectMomZ(mo, 4*FRACUNIT, false); \ - if (i & 1) \ - P_SetObjectMomZ(mo, 4*FRACUNIT, true); \ - if (player->mo->eflags & MFE_VERTICALFLIP) \ - mo->flags2 |= MF2_OBJECTFLIP; \ - ++i; \ + if (!P_MobjWasRemoved(mo)) \ + { \ + mo->reactiontime = 0; \ + mo->flags2 |= MF2_DONTRESPAWN; \ + mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \ + P_SetTarget(&mo->target, player->mo); \ + mo->fuse = 12*TICRATE; \ + mo->destscale = player->mo->scale; \ + P_SetScale(mo, player->mo->scale); \ + mo->momx = FixedMul(FINECOSINE(fa),ns); \ + if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \ + mo->momy = FixedMul(FINESINE(fa),ns); \ + P_SetObjectMomZ(mo, 4*FRACUNIT, false); \ + if (i & 1) \ + P_SetObjectMomZ(mo, 4*FRACUNIT, true); \ + if (player->mo->eflags & MFE_VERTICALFLIP) \ + mo->flags2 |= MF2_OBJECTFLIP; \ + } \ } \ else if (player->powers[power] > 0) \ { \ SETUP_DROP(ammo) \ mo = P_SpawnMobj(player->mo->x, player->mo->y, z, ammo); \ - mo->health = player->powers[power]; \ - mo->flags2 |= MF2_DONTRESPAWN; \ - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \ - P_SetTarget(&mo->target, player->mo); \ - mo->fuse = 12*TICRATE; \ - mo->destscale = player->mo->scale; \ - P_SetScale(mo, player->mo->scale); \ - mo->momx = FixedMul(FINECOSINE(fa),ns); \ - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \ - mo->momy = FixedMul(FINESINE(fa),ns); \ - P_SetObjectMomZ(mo, 3*FRACUNIT, false); \ - if (i & 1) \ - P_SetObjectMomZ(mo, 3*FRACUNIT, true); \ - if (player->mo->eflags & MFE_VERTICALFLIP) \ - mo->flags2 |= MF2_OBJECTFLIP; \ - player->powers[power] = 0; \ - ++i; \ - } + if (!P_MobjWasRemoved(mo)) \ + { \ + mo->health = player->powers[power]; \ + mo->flags2 |= MF2_DONTRESPAWN; \ + mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \ + P_SetTarget(&mo->target, player->mo); \ + mo->fuse = 12*TICRATE; \ + mo->destscale = player->mo->scale; \ + P_SetScale(mo, player->mo->scale); \ + mo->momx = FixedMul(FINECOSINE(fa),ns); \ + if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \ + mo->momy = FixedMul(FINESINE(fa),ns); \ + P_SetObjectMomZ(mo, 3*FRACUNIT, false); \ + if (i & 1) \ + P_SetObjectMomZ(mo, 3*FRACUNIT, true); \ + if (player->mo->eflags & MFE_VERTICALFLIP) \ + mo->flags2 |= MF2_OBJECTFLIP; \ + player->powers[power] = 0; \ + } \ + } \ + ++i DROP_WEAPON(RW_BOUNCE, MT_BOUNCEPICKUP, MT_BOUNCERING, pw_bouncering); DROP_WEAPON(RW_RAIL, MT_RAILPICKUP, MT_RAILRING, pw_railring); @@ -4259,23 +4299,26 @@ void P_PlayerEmeraldBurst(player_t *player, boolean toss) momy = 0; mo = P_SpawnMobj(player->mo->x, player->mo->y, z, MT_FLINGEMERALD); - mo->health = 1; - mo->threshold = stoneflag; - mo->flags2 |= (MF2_DONTRESPAWN|MF2_SLIDEPUSH); - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetTarget(&mo->target, player->mo); - mo->fuse = 12*TICRATE; - P_SetMobjState(mo, statenum); - - mo->momx = momx; - mo->momy = momy; - - P_SetObjectMomZ(mo, 3*FRACUNIT, false); - - if (player->mo->eflags & MFE_VERTICALFLIP) + if (!P_MobjWasRemoved(mo)) { - mo->momz = -mo->momz; - mo->flags2 |= MF2_OBJECTFLIP; + mo->health = 1; + mo->threshold = stoneflag; + mo->flags2 |= (MF2_DONTRESPAWN|MF2_SLIDEPUSH); + mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); + P_SetTarget(&mo->target, player->mo); + mo->fuse = 12*TICRATE; + P_SetMobjState(mo, statenum); + + mo->momx = momx; + mo->momy = momy; + + P_SetObjectMomZ(mo, 3*FRACUNIT, false); + + if (player->mo->eflags & MFE_VERTICALFLIP) + { + mo->momz = -mo->momz; + mo->flags2 |= MF2_OBJECTFLIP; + } } if (toss) @@ -4303,6 +4346,8 @@ void P_PlayerFlagBurst(player_t *player, boolean toss) type = MT_BLUEFLAG; flag = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, type); + if (P_MobjWasRemoved(flag)) + return; if (player->mo->eflags & MFE_VERTICALFLIP) { diff --git a/src/p_local.h b/src/p_local.h index cc060e4ee..b9d07fe24 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -282,7 +282,7 @@ mobjtype_t P_GetMobjtype(UINT16 mthingtype); void P_RespawnSpecials(void); -mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); +mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...); void P_RecalcPrecipInSector(sector_t *sector); void P_PrecipitationEffects(void); diff --git a/src/p_map.c b/src/p_map.c index a7d1f4abd..fc91c8f49 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2861,6 +2861,8 @@ boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) { boolean moveok; mobj_t *hack = P_SpawnMobjFromMobj(thing, 0, 0, 0, MT_RAY); + if (P_MobjWasRemoved(hack)) + return false; hack->radius = thing->radius; hack->height = thing->height; diff --git a/src/p_mobj.c b/src/p_mobj.c index 9e7110de3..920b60272 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -914,29 +914,41 @@ void P_ExplodeMissile(mobj_t *mo) P_RadiusAttack(mo, mo, 96*FRACUNIT, 0, true); explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); - P_SetScale(explodemo, mo->scale); - explodemo->destscale = mo->destscale; - explodemo->momx += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale); - explodemo->momy += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale); - S_StartSound(explodemo, sfx_pop); + if (!P_MobjWasRemoved(explodemo)) + { + P_SetScale(explodemo, mo->scale); + explodemo->destscale = mo->destscale; + explodemo->momx += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale); + explodemo->momy += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale); + S_StartSound(explodemo, sfx_pop); + } explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); - P_SetScale(explodemo, mo->scale); - explodemo->destscale = mo->destscale; - explodemo->momx += (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale); - explodemo->momy -= (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale); - S_StartSound(explodemo, sfx_dmpain); + if (!P_MobjWasRemoved(explodemo)) + { + P_SetScale(explodemo, mo->scale); + explodemo->destscale = mo->destscale; + explodemo->momx += (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale); + explodemo->momy -= (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale); + S_StartSound(explodemo, sfx_dmpain); + } explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); - P_SetScale(explodemo, mo->scale); - explodemo->destscale = mo->destscale; - explodemo->momx -= (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale); - explodemo->momy += (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale); - S_StartSound(explodemo, sfx_pop); + if (!P_MobjWasRemoved(explodemo)) + { + P_SetScale(explodemo, mo->scale); + explodemo->destscale = mo->destscale; + explodemo->momx -= (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale); + explodemo->momy += (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale); + S_StartSound(explodemo, sfx_pop); + } explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); - P_SetScale(explodemo, mo->scale); - explodemo->destscale = mo->destscale; - explodemo->momx -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale); - explodemo->momy -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale); - S_StartSound(explodemo, sfx_cybdth); + if (!P_MobjWasRemoved(explodemo)) + { + P_SetScale(explodemo, mo->scale); + explodemo->destscale = mo->destscale; + explodemo->momx -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale); + explodemo->momy -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale); + S_StartSound(explodemo, sfx_cybdth); + } } mo->flags &= ~MF_MISSILE; @@ -3091,6 +3103,8 @@ boolean P_SceneryZMovement(mobj_t *mo) { prandom = P_RandomByte(); explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_SMALLBUBBLE); + if (P_MobjWasRemoved(explodemo)) + continue; explodemo->momx += ((prandom & 0x0F) << (FRACBITS-2)) * (i & 2 ? -1 : 1); explodemo->momy += ((prandom & 0xF0) << (FRACBITS-6)) * (i & 1 ? -1 : 1); explodemo->destscale = mo->scale; @@ -3362,13 +3376,19 @@ void P_MobjCheckWater(mobj_t *mobj) if (mobj->eflags & MFE_VERTICALFLIP) { splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[splishtype].height, mobj->scale), splishtype); - splish->flags2 |= MF2_OBJECTFLIP; - splish->eflags |= MFE_VERTICALFLIP; + if (!P_MobjWasRemoved(splish)) + { + splish->flags2 |= MF2_OBJECTFLIP; + splish->eflags |= MFE_VERTICALFLIP; + } } else splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype); - splish->destscale = mobj->scale; - P_SetScale(splish, mobj->scale); + if (!P_MobjWasRemoved(splish)) + { + splish->destscale = mobj->scale; + P_SetScale(splish, mobj->scale); + } } // skipping stone! @@ -3398,13 +3418,19 @@ void P_MobjCheckWater(mobj_t *mobj) if (mobj->eflags & MFE_VERTICALFLIP) { splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[splishtype].height, mobj->scale), splishtype); - splish->flags2 |= MF2_OBJECTFLIP; - splish->eflags |= MFE_VERTICALFLIP; + if (!P_MobjWasRemoved(splish)) + { + splish->flags2 |= MF2_OBJECTFLIP; + splish->eflags |= MFE_VERTICALFLIP; + } } else splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype); - splish->destscale = mobj->scale; - P_SetScale(splish, mobj->scale); + if (!P_MobjWasRemoved(splish)) + { + splish->destscale = mobj->scale; + P_SetScale(splish, mobj->scale); + } } } @@ -4414,11 +4440,14 @@ static void P_Boss3Thinker(mobj_t *mobj) } dummy = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->mass); - dummy->angle = mobj->angle; - dummy->threshold = way1; - P_SetTarget(&dummy->tracer, mobj); - dummy->movefactor = mobj->movefactor; - dummy->cusval = mobj->cusval; + if (!P_MobjWasRemoved(dummy)) + { + dummy->angle = mobj->angle; + dummy->threshold = way1; + P_SetTarget(&dummy->tracer, mobj); + dummy->movefactor = mobj->movefactor; + dummy->cusval = mobj->cusval; + } way2 = P_RandomKey(8-3); if (way2 >= curpath) @@ -4437,11 +4466,14 @@ static void P_Boss3Thinker(mobj_t *mobj) } dummy = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->mass); - dummy->angle = mobj->angle; - dummy->threshold = way2; - P_SetTarget(&dummy->tracer, mobj); - dummy->movefactor = mobj->movefactor; - dummy->cusval = mobj->cusval; + if (!P_MobjWasRemoved(dummy)) + { + dummy->angle = mobj->angle; + dummy->threshold = way2; + P_SetTarget(&dummy->tracer, mobj); + dummy->movefactor = mobj->movefactor; + dummy->cusval = mobj->cusval; + } CONS_Debug(DBG_GAMELOGIC, "Eggman path %d - Dummy selected paths %d and %d\n", way0, way1, way2); if (mobj->spawnpoint) @@ -4559,6 +4591,8 @@ static void P_Boss3Thinker(mobj_t *mobj) for (i = 0; i < numtospawn; i++) { shock = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SHOCKWAVE); + if (P_MobjWasRemoved(shock)) + continue; P_SetTarget(&shock->target, mobj); shock->fuse = shock->info->painchance; @@ -4578,7 +4612,8 @@ static void P_Boss3Thinker(mobj_t *mobj) ang += interval; sprev = shock; } - S_StartSound(mobj, shock->info->seesound); + if (!P_MobjWasRemoved(shock)) + S_StartSound(mobj, shock->info->seesound); // look for a new target P_BossTargetPlayer(mobj, true); @@ -4828,12 +4863,17 @@ static void P_Boss4Thinker(mobj_t *mobj) for (arm = 0; arm <3 ; arm++) { seg = P_SpawnMobj(mobj->x, mobj->y, z, MT_EGGMOBILE4_MACE); + if (P_MobjWasRemoved(seg)) + continue; + P_SetTarget(&base->tracer, seg); base = seg; P_SetTarget(&seg->target, mobj); for (i = 0; i < 9; i++) { P_SetTarget(&seg->hnext, P_SpawnMobj(mobj->x, mobj->y, z, MT_EGGMOBILE4_MACE)); + if (P_MobjWasRemoved(seg->hnext)) + continue; P_SetTarget(&seg->hnext->hprev, seg); seg = seg->hnext; } @@ -5104,9 +5144,12 @@ static void P_Boss7Thinker(mobj_t *mobj) if (mobj->health >= mobj->info->spawnhealth && (leveltime & 14) == 0) { mobj_t *smoke = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height, MT_SMOKE); - smoke->destscale = mobj->destscale; - P_SetScale(smoke, smoke->destscale); - smoke->momz = FixedMul(FRACUNIT, smoke->scale); + if (!P_MobjWasRemoved(smoke)) + { + smoke->destscale = mobj->destscale; + P_SetScale(smoke, smoke->destscale); + smoke->momz = FixedMul(FRACUNIT, smoke->scale); + } } if (mobj->state == &states[S_BLACKEGG_STND] && mobj->tics == mobj->state->tics) @@ -5380,6 +5423,8 @@ static void P_Boss7Thinker(mobj_t *mobj) y = mobj->y + FixedMul(FINECOSINE(fa),ns); mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); + if (P_MobjWasRemoved(mo2)) + continue; ns = 16 * FRACUNIT; mo2->momx = FixedMul(FINESINE(fa),ns); mo2->momy = FixedMul(FINECOSINE(fa),ns); @@ -5573,76 +5618,84 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj_t *missile; missile = P_SpawnMissile(mobj, mobj->target, MT_MSGATHER); - S_StopSound(missile); - if (mobj->extravalue1 >= 2) - P_SetScale(missile, FRACUNIT>>1); - missile->destscale = missile->scale>>1; - missile->fuse = TICRATE/2; - missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse; - missile->z -= missile->height/2; - missile->momx *= -1; - missile->momy *= -1; - missile->momz *= -1; + if (!P_MobjWasRemoved(missile)) + { + S_StopSound(missile); + if (mobj->extravalue1 >= 2) + P_SetScale(missile, FRACUNIT>>1); + missile->destscale = missile->scale>>1; + missile->fuse = TICRATE/2; + missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse; + missile->z -= missile->height/2; + missile->momx *= -1; + missile->momy *= -1; + missile->momz *= -1; - if (mobj->extravalue1 == 2) - { - UINT8 i; - mobj_t *spread; - for (i = 0; i < 5; i++) + if (mobj->extravalue1 == 2) { - if (i == 2) - continue; - spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); - spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2); - P_InstaThrust(spread,spread->angle,-spread->info->speed); - spread->momz = missile->momz; - P_SetScale(spread, missile->scale); - spread->destscale = missile->destscale; - spread->scalespeed = missile->scalespeed; - spread->fuse = missile->fuse; - P_UnsetThingPosition(spread); - spread->x -= spread->fuse*spread->momx; - spread->y -= spread->fuse*spread->momy; - spread->z -= spread->fuse*spread->momz; - P_SetThingPosition(spread); - } - P_InstaThrust(missile,missile->angle,-missile->info->speed); - } - else if (mobj->extravalue1 >= 3) - { - UINT8 i; - mobj_t *spread; - mobj->target->z -= (4*missile->height); - for (i = 0; i < 5; i++) - { - if (i != 2) + UINT8 i; + mobj_t *spread; + for (i = 0; i < 5; i++) { - spread = P_SpawnMissile(mobj, mobj->target, missile->type); + if (i == 2) + continue; + spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); + if (P_MobjWasRemoved(spread)) + continue; + + spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2); + P_InstaThrust(spread,spread->angle,-spread->info->speed); + spread->momz = missile->momz; P_SetScale(spread, missile->scale); spread->destscale = missile->destscale; + spread->scalespeed = missile->scalespeed; spread->fuse = missile->fuse; - spread->z -= spread->height/2; - spread->momx *= -1; - spread->momy *= -1; - spread->momz *= -1; P_UnsetThingPosition(spread); spread->x -= spread->fuse*spread->momx; spread->y -= spread->fuse*spread->momy; spread->z -= spread->fuse*spread->momz; P_SetThingPosition(spread); } - mobj->target->z += missile->height*2; + P_InstaThrust(missile,missile->angle,-missile->info->speed); } - mobj->target->z -= (6*missile->height); + else if (mobj->extravalue1 >= 3) + { + UINT8 i; + mobj_t *spread; + mobj->target->z -= (4*missile->height); + for (i = 0; i < 5; i++) + { + if (i != 2) + { + spread = P_SpawnMissile(mobj, mobj->target, missile->type); + if (P_MobjWasRemoved(spread)) + continue; + P_SetScale(spread, missile->scale); + spread->destscale = missile->destscale; + spread->fuse = missile->fuse; + spread->z -= spread->height/2; + spread->momx *= -1; + spread->momy *= -1; + spread->momz *= -1; + P_UnsetThingPosition(spread); + spread->x -= spread->fuse*spread->momx; + spread->y -= spread->fuse*spread->momy; + spread->z -= spread->fuse*spread->momz; + P_SetThingPosition(spread); + } + mobj->target->z += missile->height*2; + } + mobj->target->z -= (6*missile->height); + } + + P_UnsetThingPosition(missile); + missile->x -= missile->fuse*missile->momx; + missile->y -= missile->fuse*missile->momy; + missile->z -= missile->fuse*missile->momz; + P_SetThingPosition(missile); + + S_StartSound(mobj, sfx_s3kb3); } - - P_UnsetThingPosition(missile); - missile->x -= missile->fuse*missile->momx; - missile->y -= missile->fuse*missile->momy; - missile->z -= missile->fuse*missile->momz; - P_SetThingPosition(missile); - - S_StartSound(mobj, sfx_s3kb3); } } } @@ -5660,29 +5713,32 @@ static void P_Boss9Thinker(mobj_t *mobj) if (spawner && dist) { mobj_t *missile = P_SpawnMissile(spawner, mobj, MT_MSGATHER); - missile->fuse = (dist/P_AproxDistance(missile->momx, missile->momy)); - if (missile->fuse <= 0) // Prevents a division by zero when calculating missile->scalespeed - missile->fuse = 1; + if (!P_MobjWasRemoved(missile)) + { + missile->fuse = (dist/P_AproxDistance(missile->momx, missile->momy)); + if (missile->fuse <= 0) // Prevents a division by zero when calculating missile->scalespeed + missile->fuse = 1; - if (missile->fuse > mobj->fuse) - { - P_RemoveMobj(missile); - } - else - { - if (mobj->health > mobj->info->damage) + if (missile->fuse > mobj->fuse) { - P_SetScale(missile, FRACUNIT/3); - missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power + P_RemoveMobj(missile); } else { - P_SetScale(missile, FRACUNIT/5); - missile->color = SKINCOLOR_SUNSET; // sonic cd electric power + if (mobj->health > mobj->info->damage) + { + P_SetScale(missile, FRACUNIT/3); + missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power + } + else + { + P_SetScale(missile, FRACUNIT/5); + missile->color = SKINCOLOR_SUNSET; // sonic cd electric power + } + missile->destscale = missile->scale*2; + missile->scalespeed = abs(missile->scale - missile->destscale)/missile->fuse; + missile->colorized = true; } - missile->destscale = missile->scale*2; - missile->scalespeed = abs(missile->scale - missile->destscale)/missile->fuse; - missile->colorized = true; } } @@ -5716,6 +5772,7 @@ static void P_Boss9Thinker(mobj_t *mobj) // threshold is used for attacks/maneuvers. if (mobj->threshold && mobj->movecount != 2) { + mobj_t *ghost; fixed_t speed = 20*FRACUNIT + FixedMul(40*FRACUNIT, FixedDiv((mobj->info->spawnhealth - mobj->health)<info->spawnhealth<target, mobj->info->speed); - if (mobj->extravalue1 >= 2) + if (!P_MobjWasRemoved(missile)) { - missile->destscale = FRACUNIT>>1; - P_SetScale(missile, missile->destscale); - } - missile->fuse = 3*TICRATE; - missile->z -= missile->height/2; - - if (mobj->extravalue1 == 2) - { - UINT8 i; - mobj_t *spread; - for (i = 0; i < 5; i++) + if (mobj->extravalue1 >= 2) { - if (i == 2) - continue; - spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); - spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2); - P_InstaThrust(spread,spread->angle,spread->info->speed); - spread->momz = missile->momz; - spread->destscale = FRACUNIT>>1; - P_SetScale(spread, spread->destscale); - spread->fuse = missile->fuse; + missile->destscale = FRACUNIT>>1; + P_SetScale(missile, missile->destscale); } - P_InstaThrust(missile,missile->angle,missile->info->speed); - } - else if (mobj->extravalue1 >= 3) - { - UINT8 i; - mobj_t *spread; - mobj->target->z -= (2*missile->height); - for (i = 0; i < 5; i++) + missile->fuse = 3*TICRATE; + missile->z -= missile->height/2; + + if (mobj->extravalue1 == 2) { - if (i != 2) + UINT8 i; + mobj_t *spread; + for (i = 0; i < 5; i++) { - spread = P_SpawnMissile(mobj, mobj->target, missile->type); + if (i == 2) + continue; + spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); + if (P_MobjWasRemoved(spread)) + continue; + + spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2); + P_InstaThrust(spread,spread->angle,spread->info->speed); + spread->momz = missile->momz; spread->destscale = FRACUNIT>>1; P_SetScale(spread, spread->destscale); spread->fuse = missile->fuse; - spread->z -= spread->height/2; } - mobj->target->z += missile->height; + P_InstaThrust(missile,missile->angle,missile->info->speed); + } + else if (mobj->extravalue1 >= 3) + { + UINT8 i; + mobj_t *spread; + mobj->target->z -= (2*missile->height); + for (i = 0; i < 5; i++) + { + if (i != 2) + { + spread = P_SpawnMissile(mobj, mobj->target, missile->type); + if (!P_MobjWasRemoved(spread)) + { + spread->destscale = FRACUNIT>>1; + P_SetScale(spread, spread->destscale); + spread->fuse = missile->fuse; + spread->z -= spread->height/2; + } + } + mobj->target->z += missile->height; + } + mobj->target->z -= (3*missile->height); } - mobj->target->z -= (3*missile->height); } } else @@ -5837,7 +5903,9 @@ static void P_Boss9Thinker(mobj_t *mobj) return; } - P_SpawnGhostMobj(mobj)->colorized = false; + ghost = P_SpawnGhostMobj(mobj); + if (!P_MobjWasRemoved(ghost)) + ghost->colorized = false; // Vector form dodge! mobj->angle += mobj->movedir; @@ -5935,8 +6003,11 @@ static void P_Boss9Thinker(mobj_t *mobj) if (mobj->health > mobj->info->damage) { // No more bubble if we're broken (pinch phase) mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT); - P_SetTarget(&mobj->hprev, shield); - P_SetTarget(&shield->target, mobj); + if (!P_MobjWasRemoved(shield)) + { + P_SetTarget(&mobj->hprev, shield); + P_SetTarget(&shield->target, mobj); + } // Attack 2: Energy shot! switch (mobj->health) @@ -6271,7 +6342,8 @@ void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT finalz = z + v.z; mobj = P_SpawnMobj(finalx, finaly, finalz, type); - mobj->z -= mobj->height/2; + if (!P_MobjWasRemoved(mobj)) + mobj->z -= mobj->height/2; } } @@ -6312,6 +6384,8 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb finalz = z + v.z; mobj = P_SpawnMobj(finalx, finaly, finalz, type); + if (P_MobjWasRemoved(mobj)) + continue; mobj->z -= mobj->height>>1; @@ -6960,6 +7034,8 @@ static void P_KoopaThinker(mobj_t *koopa) { mobj_t *flame; flame = P_SpawnMobj(koopa->x - koopa->radius + FixedMul(5*FRACUNIT, koopa->scale), koopa->y, koopa->z + (P_RandomByte()<<(FRACBITS-2)), MT_KOOPAFLAME); + if (P_MobjWasRemoved(flame)) + return; flame->momx = -FixedMul(flame->info->speed, flame->scale); S_StartSound(flame, sfx_koopfr); } @@ -6967,6 +7043,8 @@ static void P_KoopaThinker(mobj_t *koopa) { mobj_t *hammer; hammer = P_SpawnMobj(koopa->x - koopa->radius, koopa->y, koopa->z + koopa->height, MT_HAMMER); + if (P_MobjWasRemoved(hammer)) + return; hammer->momx = FixedMul(-5*FRACUNIT, hammer->scale); hammer->momz = FixedMul(7*FRACUNIT, hammer->scale); } @@ -6985,6 +7063,9 @@ static void P_SpawnMinecartSegments(mobj_t *mobj, boolean mode) for (i = 0; i < 4; i++) { seg = P_SpawnMobj(x, y, z, MT_MINECARTSEG); + if (P_MobjWasRemoved(seg)) + continue; + P_SetMobjState(seg, (statenum_t)(S_MINECARTSEG_FRONT + i)); if (i >= 2) seg->extravalue1 = (i == 2) ? -18 : 18; // make -20/20 when papersprite projection fixed @@ -7040,6 +7121,8 @@ static void P_PyreFlyBurn(mobj_t *mobj, fixed_t hoffs, INT16 vrange, mobjtype_t fixed_t yoffs = FixedMul(FINESINE(fa), mobj->radius + hoffs); fixed_t zoffs = P_RandomRange(-vrange, vrange)*FRACUNIT; mobj_t *particle = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, zoffs, mobjtype); + if (P_MobjWasRemoved(particle)) + return; particle->momz = momz; particle->flags2 |= MF2_LINKDRAW; P_SetTarget(&particle->tracer, mobj); @@ -7198,6 +7281,8 @@ static void P_FlameJetSceneryThink(mobj_t *mobj) mobj->fuse -= 2; flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); + if (P_MobjWasRemoved(flame)) + return; P_SetMobjState(flame, S_FLAMEJETFLAME4); flame->angle = mobj->angle; @@ -7236,6 +7321,8 @@ static void P_VerticalFlameJetSceneryThink(mobj_t *mobj) mobj->fuse--; flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); + if (P_MobjWasRemoved(flame)) + return; strength = (mobj->movedir ? mobj->movedir : 80)<<(FRACBITS-2); @@ -7309,13 +7396,16 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj) mobj->y + FixedMul(FixedMul(mobj->friction, mobj->scale), FINESINE(mobj->angle >> ANGLETOFINESHIFT)), mobj->z, (mobjtype_t)mobj->threshold); - P_SetScale(spawn, mobj->scale); - spawn->momz = FixedMul(mobj->movefactor, spawn->scale); - spawn->destscale = spawn->scale/100; - spawn->scalespeed = spawn->scale/mobj->health; - spawn->tics = (tic_t)mobj->health; - spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP); - spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + if (!P_MobjWasRemoved(spawn)) + { + P_SetScale(spawn, mobj->scale); + spawn->momz = FixedMul(mobj->movefactor, spawn->scale); + spawn->destscale = spawn->scale/100; + spawn->scalespeed = spawn->scale/mobj->health; + spawn->tics = (tic_t)mobj->health; + spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP); + spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + } mobj->angle += mobj->movedir; } @@ -7527,13 +7617,16 @@ static void P_RosySceneryThink(mobj_t *mobj) if (makeheart) { mobj_t *cdlhrt = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_CDLHRT); - cdlhrt->destscale = (5*mobj->scale) >> 4; - P_SetScale(cdlhrt, cdlhrt->destscale); - cdlhrt->fuse = (5*TICRATE) >> 1; - cdlhrt->momz = mobj->scale; - P_SetTarget(&cdlhrt->target, mobj); - cdlhrt->extravalue1 = mobj->x; - cdlhrt->extravalue2 = mobj->y; + if (!P_MobjWasRemoved(cdlhrt)) + { + cdlhrt->destscale = (5*mobj->scale) >> 4; + P_SetScale(cdlhrt, cdlhrt->destscale); + cdlhrt->fuse = (5*TICRATE) >> 1; + cdlhrt->momz = mobj->scale; + P_SetTarget(&cdlhrt->target, mobj); + cdlhrt->extravalue1 = mobj->x; + cdlhrt->extravalue2 = mobj->y; + } } } } @@ -7660,13 +7753,16 @@ static void P_MobjSceneryThink(mobj_t *mobj) && */ (mobj->target->player->pflags & PF_SHIELDABILITY)) { mobj_t *whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct - P_SetMobjState(whoosh, mobj->info->raisestate); - whoosh->destscale = whoosh->scale << 1; - whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale); - whoosh->height = 38*whoosh->scale; - whoosh->fuse = 10; - whoosh->flags |= MF_NOCLIPHEIGHT; - whoosh->momz = mobj->target->momz; // Stay reasonably centered for a few frames + if (!P_MobjWasRemoved(whoosh)) + { + P_SetMobjState(whoosh, mobj->info->raisestate); + whoosh->destscale = whoosh->scale << 1; + whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale); + whoosh->height = 38*whoosh->scale; + whoosh->fuse = 10; + whoosh->flags |= MF_NOCLIPHEIGHT; + whoosh->momz = mobj->target->momz; // Stay reasonably centered for a few frames + } mobj->target->player->pflags &= ~PF_SHIELDABILITY; // prevent eternal whoosh } /* FALLTHRU */ @@ -8007,8 +8103,11 @@ static boolean P_MobjBossThink(mobj_t *mobj) P_RandomRange(rad, -rad) << FRACBITS, P_RandomRange(hei / 2, hei) << FRACBITS, MT_SMOKE); - P_SetObjectMomZ(particle, 2 << FRACBITS, false); - particle->momz += mobj->momz; + if (!P_MobjWasRemoved(particle)) + { + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } } if (mobj->flags2 & MF2_SKULLFLY) #if 1 @@ -8017,8 +8116,11 @@ static boolean P_MobjBossThink(mobj_t *mobj) { mobj_t *spawnmobj; spawnmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->painchance); - P_SetTarget(&spawnmobj->target, mobj); - spawnmobj->color = SKINCOLOR_GREY; + if (!P_MobjWasRemoved(spawnmobj)) + { + P_SetTarget(&spawnmobj->target, mobj); + spawnmobj->color = SKINCOLOR_GREY; + } } #endif P_Boss1Thinker(mobj); @@ -8033,8 +8135,11 @@ static boolean P_MobjBossThink(mobj_t *mobj) P_RandomRange(rad, -rad) << FRACBITS, P_RandomRange(hei/2, hei) << FRACBITS, MT_SMOKE); - P_SetObjectMomZ(particle, 2 << FRACBITS, false); - particle->momz += mobj->momz; + if (!P_MobjWasRemoved(particle)) + { + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } } P_Boss2Thinker(mobj); break; @@ -8048,8 +8153,11 @@ static boolean P_MobjBossThink(mobj_t *mobj) P_RandomRange(rad, -rad) << FRACBITS, P_RandomRange(hei/2, hei) << FRACBITS, MT_SMOKE); - P_SetObjectMomZ(particle, 2 << FRACBITS, false); - particle->momz += mobj->momz; + if (!P_MobjWasRemoved(particle)) + { + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } } P_Boss3Thinker(mobj); break; @@ -8063,8 +8171,11 @@ static boolean P_MobjBossThink(mobj_t *mobj) P_RandomRange(rad, -rad) << FRACBITS, P_RandomRange(hei/2, hei) << FRACBITS, MT_SMOKE); - P_SetObjectMomZ(particle, 2 << FRACBITS, false); - particle->momz += mobj->momz; + if (!P_MobjWasRemoved(particle)) + { + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } } P_Boss4Thinker(mobj); break; @@ -8192,6 +8303,9 @@ static boolean P_MobjDeadThink(mobj_t *mobj) y = mobj->y + FixedMul(FINECOSINE(fa), ns); mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); + if (P_MobjWasRemoved(mo2)) + continue; + P_SetMobjStateNF(mo2, S_XPLD_EGGTRAP); // so the flickies don't lose their target if they spawn ns = 4*FRACUNIT; mo2->momx = FixedMul(FINESINE(fa), ns); @@ -8237,7 +8351,8 @@ static boolean P_MobjDeadThink(mobj_t *mobj) mobj->y + (P_RandomRange(r, -r) << FRACBITS), mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), MT_SONIC3KBOSSEXPLODE); - S_StartSound(explosion, sfx_s3kb4); + if (!P_MobjWasRemoved(explosion)) + S_StartSound(explosion, sfx_s3kb4); } if (mobj->movedir == DMG_DROWNED) P_SetObjectMomZ(mobj, -FRACUNIT/2, true); // slower fall from drowning @@ -8255,7 +8370,8 @@ static boolean P_MobjDeadThink(mobj_t *mobj) mobj->y + (P_RandomRange(r, -r) << FRACBITS), mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), MT_SONIC3KBOSSEXPLODE); - S_StartSound(explosion, sfx_s3kb4); + if (!P_MobjWasRemoved(explosion)) + S_StartSound(explosion, sfx_s3kb4); } P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); } @@ -8353,9 +8469,12 @@ static void P_ArrowThink(mobj_t *mobj) if (leveltime & 1) { mobj_t *dust = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_PARTICLE); - dust->tics = 18; - dust->scalespeed = 4096; - dust->destscale = FRACUNIT/32; + if (!P_MobjWasRemoved(dust)) + { + dust->tics = 18; + dust->scalespeed = 4096; + dust->destscale = FRACUNIT/32; + } } } else @@ -8958,6 +9077,9 @@ static boolean P_TurretThink(mobj_t *mobj) y = mobj->y + FixedMul(FINECOSINE(fa), ns); mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); + if (P_MobjWasRemoved(mo2)) + continue; + ns = FixedMul(16*FRACUNIT, mobj->scale); mo2->momx = FixedMul(FINESINE(fa), ns); mo2->momy = FixedMul(FINECOSINE(fa), ns); @@ -9179,10 +9301,13 @@ static void P_DragonbomberThink(mobj_t *mobj) if (segment != mobj) // found an unactivated segment? { mobj_t *mine = P_SpawnMobjFromMobj(segment, 0, 0, 0, segment->info->painchance); - mine->angle = segment->angle; - P_InstaThrust(mine, mobj->angle, P_AproxDistance(mobj->momx, mobj->momy) >> 1); - P_SetObjectMomZ(mine, -2*FRACUNIT, true); - S_StartSound(mine, mine->info->seesound); + if (!P_MobjWasRemoved(mine)) + { + mine->angle = segment->angle; + P_InstaThrust(mine, mobj->angle, P_AproxDistance(mobj->momx, mobj->momy) >> 1); + P_SetObjectMomZ(mine, -2*FRACUNIT, true); + S_StartSound(mine, mine->info->seesound); + } P_SetMobjState(segment, segment->info->raisestate); mobj->threshold = mobj->info->painchance; } @@ -9401,9 +9526,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (!mobj->threshold && !mobj->target && mobj->reactiontime) { mobj_t *emerald = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->reactiontime); - emerald->threshold = 42; - P_SetTarget(&mobj->target, emerald); - P_SetTarget(&emerald->target, mobj); + if (!P_MobjWasRemoved(emerald)) + { + emerald->threshold = 42; + P_SetTarget(&mobj->target, emerald); + P_SetTarget(&emerald->target, mobj); + } } } break; @@ -9745,6 +9873,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_TRAINDUSTSPAWNER: if (leveltime % 5 == 0) { mobj_t* traindust = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PARTICLE); + if (P_MobjWasRemoved(traindust)) + break; traindust->flags = MF_SCENERY; P_SetMobjState(traindust, S_TRAINDUST); traindust->frame = P_RandomRange(0, 8)|FF_TRANS90; @@ -9758,6 +9888,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_TRAINSTEAMSPAWNER: if (leveltime % 5 == 0) { mobj_t *steam = P_SpawnMobj(mobj->x + FRACUNIT*P_SignedRandom()/2, mobj->y + FRACUNIT*P_SignedRandom()/2, mobj->z, MT_PARTICLE); + if (P_MobjWasRemoved(steam)) + break; P_SetMobjState(steam, S_TRAINSTEAM); steam->frame = P_RandomRange(0, 1)|FF_TRANS90; steam->tics = TICRATE*8; @@ -9959,7 +10091,8 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); // Transfer flags2 (ambush, strongbox, objectflip) - newmobj->flags2 = mobj->flags2; + if (!P_MobjWasRemoved(newmobj)) + newmobj->flags2 = mobj->flags2; P_RemoveMobj(mobj); // make sure they disappear } @@ -9981,6 +10114,8 @@ static void P_FlagFuseThink(mobj_t *mobj) else z = ss->sector->floorheight + z; flagmo = P_SpawnMobj(x, y, z, mobj->type); + if (P_MobjWasRemoved(flagmo)) + return; flagmo->spawnpoint = mobj->spawnpoint; if (mobj->spawnpoint->options & MTF_OBJECTFLIP) { @@ -10418,12 +10553,15 @@ void P_PushableThinker(mobj_t *mobj) z = ss->sector->floorheight; spawnmo = P_SpawnMobj(x, y, z, mobj->type); - spawnmo->spawnpoint = mobj->spawnpoint; - P_UnsetThingPosition(spawnmo); - spawnmo->flags = mobj->flags; - P_SetThingPosition(spawnmo); - spawnmo->flags2 = mobj->flags2; - spawnmo->flags |= MF_PUSHABLE; + if (!P_MobjWasRemoved(spawnmo)) + { + spawnmo->spawnpoint = mobj->spawnpoint; + P_UnsetThingPosition(spawnmo); + spawnmo->flags = mobj->flags; + P_SetThingPosition(spawnmo); + spawnmo->flags2 = mobj->flags2; + spawnmo->flags |= MF_PUSHABLE; + } P_RemoveMobj(mobj); break; default: @@ -10575,27 +10713,17 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) // // P_SpawnMobj // -mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) +mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...) { const mobjinfo_t *info = &mobjinfo[type]; SINT8 sc = -1; state_t *st; mobj_t *mobj; + int status; + va_list args; if (type == MT_NULL) - { -#if 0 -#ifdef PARANOIA - I_Error("Tried to spawn MT_NULL\n"); -#endif return NULL; -#endif - // Hack: Some code assumes that P_SpawnMobj can never return NULL - // So replace MT_NULL with MT_RAY in the meantime - // Remove when dealt properly - CONS_Debug(DBG_GAMELOGIC, "Tried to spawn MT_NULL, using MT_RAY\n"); - type = MT_RAY; - } mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); @@ -10687,9 +10815,27 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Set shadowscale here, before spawn hook so that Lua can change it mobj->shadowscale = P_DefaultMobjShadowScale(mobj); + if (!(mobj->flags & MF_NOTHINK)) + P_AddThinker(THINK_MOBJ, &mobj->thinker); + + + if (type == MT_PLAYER) + { + // when spawning MT_PLAYER, set mobj->player before calling MobjSpawn hook to prevent P_RemoveMobj from succeeding on player mobj. + va_start(args, type); + mobj->player = va_arg(args, player_t *); + va_end(args); + } + + // increment mobj reference, so we don't get a dangling reference in case MobjSpawn calls P_RemoveMobj + mobj->thinker.references++; + // DANGER! This can cause P_SpawnMobj to return NULL! // Avoid using P_RemoveMobj on the newly created mobj in "MobjSpawn" Lua hooks! - if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjSpawn))) + status = LUA_HookMobj(mobj, MOBJ_HOOK(MobjSpawn)); + mobj->thinker.references--; + + if (status) { if (P_MobjWasRemoved(mobj)) return NULL; @@ -10711,6 +10857,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BLACKEGGMAN: { mobj_t *spawn = P_SpawnMobj(mobj->x, mobj->z, mobj->z+mobj->height-16*FRACUNIT, MT_BLACKEGGMAN_HELPER); + if (P_MobjWasRemoved(spawn)) + break; + spawn->destscale = mobj->scale; P_SetScale(spawn, mobj->scale); P_SetTarget(&spawn->target, mobj); @@ -10726,6 +10875,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_EGGGUARD: { mobj_t *spawn = P_SpawnMobj(x, y, z, MT_EGGSHIELD); + if (P_MobjWasRemoved(spawn)) + break; + spawn->destscale = mobj->scale; P_SetScale(spawn, mobj->scale); P_SetTarget(&mobj->tracer, spawn); @@ -10741,6 +10893,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) for (i = 0; i < mobj->info->damage; i++) { ball = P_SpawnMobj(x, y, z, mobj->info->painchance); + if (P_MobjWasRemoved(ball)) + continue; + ball->destscale = mobj->scale; P_SetScale(ball, mobj->scale); P_SetTarget(&ball->target, mobj); @@ -10760,6 +10915,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) for (q = 0; q < mobj->info->painchance; q++) { ball = P_SpawnMobj(x, y, z, mobj->info->mass); + if (P_MobjWasRemoved(ball)) + continue; + ball->destscale = mobj->scale; P_SetScale(ball, mobj->scale); P_SetTarget(&lastball->tracer, ball); @@ -10771,18 +10929,24 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_CRUSHSTACEAN: { mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CRUSHCLAW); - bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; - P_SetTarget(&mobj->tracer, bigmeatyclaw); - P_SetTarget(&bigmeatyclaw->tracer, mobj); + if (!P_MobjWasRemoved(bigmeatyclaw)) + { + bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); + P_SetTarget(&mobj->tracer, bigmeatyclaw); + P_SetTarget(&bigmeatyclaw->tracer, mobj); + } mobj->reactiontime >>= 1; } break; case MT_BANPYURA: { mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BANPSPRING); - bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; - P_SetTarget(&mobj->tracer, bigmeatyclaw); - P_SetTarget(&bigmeatyclaw->tracer, mobj); + if (!P_MobjWasRemoved(bigmeatyclaw)) + { + bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); + P_SetTarget(&mobj->tracer, bigmeatyclaw); + P_SetTarget(&bigmeatyclaw->tracer, mobj); + } mobj->reactiontime >>= 1; } break; @@ -10797,6 +10961,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) for (i = 0; i <= 16; i++) // probably should be < but staying authentic to the Lua version { cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, ((mobj->type == MT_WAVINGFLAG1) ? MT_WAVINGFLAGSEG1 : MT_WAVINGFLAGSEG2));; + if (P_MobjWasRemoved(cur)) + continue; + P_SetTarget(&prev->tracer, cur); cur->extravalue1 = i; prev = cur; @@ -10834,11 +11001,17 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { mobj_t *fire; fire = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_SPINBOBERT_FIRE1); - P_SetTarget(&fire->target, mobj); - P_SetTarget(&mobj->hnext, fire); + if (!P_MobjWasRemoved(fire)) + { + P_SetTarget(&fire->target, mobj); + P_SetTarget(&mobj->hnext, fire); + } fire = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_SPINBOBERT_FIRE2); - P_SetTarget(&fire->target, mobj); - P_SetTarget(&mobj->hprev, fire); + if (!P_MobjWasRemoved(fire)) + { + P_SetTarget(&fire->target, mobj); + P_SetTarget(&mobj->hprev, fire); + } } break; case MT_REDRING: // Make MT_REDRING red by default @@ -10855,8 +11028,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_EGGCAPSULE: mobj->reactiontime = 0; mobj->extravalue1 = mobj->cvmem =\ - mobj->cusval = mobj->movecount =\ - mobj->lastlook = mobj->extravalue2 = -1; + mobj->cusval = mobj->movecount =\ + mobj->lastlook = mobj->extravalue2 = -1; break; case MT_REDTEAMRING: mobj->color = skincolor_redteam; @@ -10892,6 +11065,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_OILLAMP: { mobj_t* overlay = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + if (P_MobjWasRemoved(overlay)) + break; P_SetTarget(&overlay->target, mobj); P_SetMobjState(overlay, S_OILLAMPFLARE); break; @@ -10901,13 +11076,19 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->flags2 |= MF2_INVERTAIMABLE; break; case MT_MINECARTEND: - P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID)); - mobj->tracer->angle = mobj->angle + ANGLE_90; + { + mobj_t *mcsolid = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID); + if (P_MobjWasRemoved(mcsolid)) + break; + P_SetTarget(&mobj->tracer, mcsolid); + mcsolid->angle = mobj->angle + ANGLE_90; + } break; case MT_TORCHFLOWER: { mobj_t *fire = P_SpawnMobjFromMobj(mobj, 0, 0, 46*FRACUNIT, MT_FLAME); - P_SetTarget(&mobj->target, fire); + if (!P_MobjWasRemoved(fire)) + P_SetTarget(&mobj->target, fire); break; } case MT_PYREFLY: @@ -10916,10 +11097,16 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->fuse = 100; break; case MT_SIGN: - P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY)); - P_SetTarget(&mobj->tracer->target, mobj); - P_SetMobjState(mobj->tracer, S_SIGNBOARD); - mobj->tracer->movedir = ANGLE_90; + { + mobj_t *sign = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); + if (P_MobjWasRemoved(sign)) + break; + + P_SetTarget(&mobj->tracer, sign); + P_SetTarget(&sign->target, mobj); + P_SetMobjState(sign, S_SIGNBOARD); + sign->movedir = ANGLE_90; + } default: break; } @@ -10942,9 +11129,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } } - if (!(mobj->flags & MF_NOTHINK)) - P_AddThinker(THINK_MOBJ, &mobj->thinker); - if (mobj->skin) // correct inadequecies above. { mobj->sprite2 = P_GetSkinSprite2(mobj->skin, (mobj->frame & FF_FRAMEMASK), NULL); @@ -11553,8 +11737,10 @@ void P_SpawnPlayer(INT32 playernum) if ((netgame || multiplayer) && ((gametyperules & GTR_SPAWNINVUL) || leveltime) && !p->spectator && !(maptol & TOL_NIGHTS)) p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent - mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER); - (mobj->player = p)->mo = mobj; + // MT_PLAYER cannot be removed, so this shouldn't be able to return NULL. + mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER, p); + I_Assert(mobj != NULL); + p->mo = mobj; mobj->angle = 0; @@ -11605,10 +11791,13 @@ void P_SpawnPlayer(INT32 playernum) if (p == players) // this is totally the wrong place to do this aaargh. { mobj_t *idya = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_GOTEMERALD); - idya->health = 0; // for identification - P_SetTarget(&idya->target, mobj); - P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate); - P_SetTarget(&mobj->tracer, idya); + if (!P_MobjWasRemoved(idya)) + { + idya->health = 0; // for identification + P_SetTarget(&idya->target, mobj); + P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate); + P_SetTarget(&mobj->tracer, idya); + } } } else if (sstimer) @@ -12357,8 +12546,10 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) mphase = (FixedAngle(mphase << FRACBITS) >> ANGLETOFINESHIFT); mroll = (FixedAngle(mroll << FRACBITS) >> ANGLETOFINESHIFT); -#define makemace(mobjtype, dist, moreflags2) {\ +#define makemace(mobjtype, dist, moreflags2) do {\ spawnee = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\ + if (P_MobjWasRemoved(spawnee))\ + break;\ P_SetTarget(&spawnee->tracer, mobj);\ spawnee->threshold = mphase;\ spawnee->friction = mroll;\ @@ -12371,7 +12562,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) P_SetTarget(&hprev->hnext, spawnee);\ P_SetTarget(&spawnee->hprev, hprev);\ hprev = spawnee;\ -} +} while (0) mdosound = (mspeed && !(mthing->args[8] & TMM_SILENT)); mdocenter = (macetype && (mthing->args[8] & TMM_CENTERLINK)); @@ -12436,7 +12627,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) if (!mwidth) { - if (mdosound && mnumspokes <= mmin) // Can it make a sound? + if (!P_MobjWasRemoved(spawnee) && mdosound && mnumspokes <= mmin) // Can it make a sound? spawnee->flags2 |= MF2_BOSSNOTRAP; } else @@ -12449,7 +12640,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) while ((mwidthset -= widthfactor) > -mwidth) { makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); - if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? + if (!P_MobjWasRemoved(spawnee) && mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? spawnee->flags2 |= MF2_BOSSNOTRAP; } } @@ -12458,7 +12649,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) while ((mwidthset += widthfactor) < -mwidth) { makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); - if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? + if (!P_MobjWasRemoved(spawnee) && mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? spawnee->flags2 |= MF2_BOSSNOTRAP; } } @@ -12640,15 +12831,21 @@ static boolean P_SetupNiGHTSDrone(mapthing_t *mthing, mobj_t *mobj) mobj_t *droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN); P_SetTarget(&mobj->target, goalpost); - P_SetTarget(&goalpost->target, sparkle); - P_SetTarget(&goalpost->tracer, droneman); + if (!P_MobjWasRemoved(goalpost)) + { + P_SetTarget(&goalpost->target, sparkle); + P_SetTarget(&goalpost->tracer, droneman); + } // correct Z position if (flip) { - P_MoveOrigin(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset); - P_MoveOrigin(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset); - P_MoveOrigin(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset); + if (!P_MobjWasRemoved(goalpost)) + P_MoveOrigin(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset); + if (!P_MobjWasRemoved(sparkle)) + P_MoveOrigin(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset); + if (!P_MobjWasRemoved(droneman)) + P_MoveOrigin(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset); } // Remember position preference for later @@ -12670,9 +12867,12 @@ static boolean P_SetupNiGHTSDrone(mapthing_t *mthing, mobj_t *mobj) } // Remember old Z position and flags for correction detection - goalpost->movefactor = mobj->z; - goalpost->friction = mobj->height; - goalpost->threshold = mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE); + if (!P_MobjWasRemoved(goalpost)) + { + goalpost->movefactor = mobj->z; + goalpost->friction = mobj->height; + goalpost->threshold = mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE); + } } return true; } @@ -12690,30 +12890,54 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) statenum_t rollerstate = strong ? S_REDBOOSTERROLLER : S_YELLOWBOOSTERROLLER; mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle - ANGLE_90; - P_SetMobjState(seg, facestate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle - ANGLE_90; + P_SetMobjState(seg, facestate); + } seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle + ANGLE_90; - P_SetMobjState(seg, facestate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle + ANGLE_90; + P_SetMobjState(seg, facestate); + } seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; - P_SetMobjState(seg, leftstate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle; + P_SetMobjState(seg, leftstate); + } seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; - P_SetMobjState(seg, rightstate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle; + P_SetMobjState(seg, rightstate); + } seg = P_SpawnMobjFromMobj(mobj, 13*(x1 + x2), 13*(y1 + y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, rollerstate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + } seg = P_SpawnMobjFromMobj(mobj, 13*(x1 - x2), 13*(y1 - y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, rollerstate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + } seg = P_SpawnMobjFromMobj(mobj, -13*(x1 + x2), -13*(y1 + y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, rollerstate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + } seg = P_SpawnMobjFromMobj(mobj, -13*(x1 - x2), -13*(y1 - y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, rollerstate); + if (!P_MobjWasRemoved(seg)) + { + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + } return true; } @@ -12721,6 +12945,9 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) static mobj_t *P_MakeSoftwareCorona(mobj_t *mo, INT32 height) { mobj_t *corona = P_SpawnMobjFromMobj(mo, 0, 0, height<sprite = SPR_FLAM; corona->frame = (FF_FULLBRIGHT|FF_TRANS90|12); corona->tics = -1; @@ -12856,6 +13083,9 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (mthing->args[0]) { mobj_t *corona = P_MakeSoftwareCorona(mobj, 20); + if (P_MobjWasRemoved(corona)) + break; + P_SetScale(corona, (corona->destscale = mobj->scale*3)); P_SetTarget(&mobj->tracer, corona); } @@ -12864,11 +13094,17 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (!(mthing->args[0] & TMFH_NOFLAME)) // Spawn the fire { mobj_t *flame = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); + if (P_MobjWasRemoved(flame)) + break; + P_SetTarget(&flame->target, mobj); flame->flags2 |= MF2_BOSSNOTRAP; if (mthing->args[0] & TMFH_CORONA) { mobj_t *corona = P_MakeSoftwareCorona(flame, 20); + if (P_MobjWasRemoved(corona)) + break; + P_SetScale(corona, (corona->destscale = flame->scale*3)); P_SetTarget(&flame->tracer, corona); } @@ -12885,6 +13121,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (!(mthing->args[0])) // take the torch out of the crafting recipe { mobj_t *overlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); + if (P_MobjWasRemoved(overlay)) + break; P_SetTarget(&overlay->target, mobj); P_SetMobjState(overlay, mobj->info->raisestate); } @@ -12964,9 +13202,15 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean case MT_THZTREE: { // Spawn the branches angle_t mobjangle = FixedAngle((mthing->angle % 113) << FRACBITS); - P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; - P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; - P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; + mobj_t *branch = P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH); + if (!P_MobjWasRemoved(branch)) + branch->angle = mobjangle + ANGLE_22h; + branch = P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH); + if (!P_MobjWasRemoved(branch)) + branch->angle = mobjangle + ANGLE_157h; + branch = P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH); + if (!P_MobjWasRemoved(branch)) + branch->angle = mobjangle + ANGLE_270; } break; case MT_TUTORIALPLANT: @@ -12976,26 +13220,34 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean for (i = 0; i < 6; i++) { segment = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_TUTORIALLEAF); + if (P_MobjWasRemoved(segment)) + continue; segment->angle = mobj->angle + FixedAngle(i*60*FRACUNIT); P_SetMobjState(segment, S_TUTORIALLEAF1 + mthing->args[0]); } for (i = 0; i < 3; i++) { segment = P_SpawnMobjFromMobj(mobj, 0, 0, 112*FRACUNIT, MT_TUTORIALFLOWER); + if (P_MobjWasRemoved(segment)) + continue; segment->angle = mobj->angle + FixedAngle(i*120*FRACUNIT); P_SetMobjState(segment, S_TUTORIALFLOWER1 + mthing->args[0]); } - P_SetMobjState(P_SpawnMobjFromMobj(mobj, 0, 0, 112*FRACUNIT, MT_TUTORIALFLOWERF), S_TUTORIALFLOWERF1 + mthing->args[0]); + segment = P_SpawnMobjFromMobj(mobj, 0, 0, 112*FRACUNIT, MT_TUTORIALFLOWERF); + if (!P_MobjWasRemoved(segment)) + P_SetMobjState(segment, S_TUTORIALFLOWERF1 + mthing->args[0]); } break; case MT_CEZPOLE1: case MT_CEZPOLE2: { // Spawn the banner angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS); - P_SpawnMobjFromMobj(mobj, + mobj_t *banner = P_SpawnMobjFromMobj(mobj, P_ReturnThrustX(mobj, mobjangle, 4 << FRACBITS), P_ReturnThrustY(mobj, mobjangle, 4 << FRACBITS), - 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90; + 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2)); + if (!P_MobjWasRemoved(banner)) + banner->angle = mobjangle + ANGLE_90; } break; case MT_HHZTREE_TOP: @@ -13004,8 +13256,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj_t* leaf; #define doleaf(x, y) \ leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ - leaf->angle = mobjangle;\ - P_SetMobjState(leaf, leaf->info->seestate);\ + if (!P_MobjWasRemoved(leaf))\ + {\ + leaf->angle = mobjangle;\ + P_SetMobjState(leaf, leaf->info->seestate);\ + }\ mobjangle += ANGLE_90 doleaf(FRACUNIT, 0); doleaf(0, FRACUNIT); @@ -13044,8 +13299,9 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; fixed_t xoffs = FINECOSINE(fa); fixed_t yoffs = FINESINE(fa); - mobj_t* leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF); - leaf->angle = angle; + mobj_t *leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF); + if (!P_MobjWasRemoved(leaf)) + leaf->angle = angle; angle += ANGLE_45; } break; @@ -13082,6 +13338,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean { mobj_t* elecmobj; elecmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_CYBRAKDEMON_ELECTRIC_BARRIER); + if (P_MobjWasRemoved(elecmobj)) + break; P_SetTarget(&elecmobj->target, mobj); elecmobj->angle = FixedAngle(mthing->angle << FRACBITS); elecmobj->destscale = mobj->scale*2; @@ -13136,6 +13394,12 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), mobj->z, MT_WALLSPIKEBASE); + if (P_MobjWasRemoved(base)) + { + // if we can't spawn the base, don't spawn the spike at all. + P_RemoveMobj(mobj); + return false; + } base->angle = mobjangle + ANGLE_90; base->destscale = mobj->destscale; P_SetScale(base, mobj->scale); @@ -13311,6 +13575,8 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, boolean doangle = true; mobj = P_SpawnMobj(x, y, z, i); + if (mobj == NULL) + return NULL; mobj->spawnpoint = mthing; P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale)); @@ -13405,6 +13671,9 @@ void P_SpawnHoop(mapthing_t *mthing) fixed_t z = P_GetMobjSpawnHeight(MT_HOOP, x, y, mthing->z << FRACBITS, 0, false, mthing->scale); hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); + if (P_MobjWasRemoved(hoopcenter)) + return; + hoopcenter->spawnpoint = mthing; hoopcenter->z -= hoopcenter->height/2; @@ -13435,6 +13704,8 @@ void P_SpawnHoop(mapthing_t *mthing) FV4_Copy(&v, FM_MultMatrixVec4(&yawmatrix, &v, &res)); mobj = P_SpawnMobj(x + v.x, y + v.y, z + v.z, MT_HOOP); + if (P_MobjWasRemoved(mobj)) + continue; mobj->z -= mobj->height/2; if (maptol & TOL_XMAS) @@ -13479,6 +13750,8 @@ void P_SpawnHoop(mapthing_t *mthing) FV4_Copy(&v, FM_MultMatrixVec4(&yawmatrix, &v, &res)); mobj = P_SpawnMobj(x + v.x, y + v.y, z + v.z, MT_HOOPCOLLIDE); + if (P_MobjWasRemoved(mobj)) + continue; mobj->z -= mobj->height/2; // Link all the collision sprites together. @@ -13752,6 +14025,8 @@ mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type, z -= FixedMul(mobjinfo[type].height, source->scale); th = P_SpawnMobj(x, y, z, type); + if (P_MobjWasRemoved(th)) + return NULL; if (source->eflags & MFE_VERTICALFLIP) th->flags2 |= MF2_OBJECTFLIP; @@ -13814,6 +14089,8 @@ mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t z -= FixedMul(mobjinfo[type].height, source->scale); th = P_SpawnMobj(x, y, z, type); + if (P_MobjWasRemoved(th)) + return NULL; if (source->eflags & MFE_VERTICALFLIP) th->flags2 |= MF2_OBJECTFLIP; @@ -13879,6 +14156,8 @@ mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za, z -= FixedMul(mobjinfo[type].height, source->scale); th = P_SpawnMobj(x, y, z, type); + if (P_MobjWasRemoved(th)) + return NULL; if (source->eflags & MFE_VERTICALFLIP) th->flags2 |= MF2_OBJECTFLIP; @@ -13949,6 +14228,8 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type) z -= FixedMul(mobjinfo[type].height, source->scale); th = P_SpawnMobj(source->x, source->y, z, type); + if (P_MobjWasRemoved(th)) + return NULL; if (source->eflags & MFE_VERTICALFLIP) th->flags2 |= MF2_OBJECTFLIP; @@ -14050,6 +14331,8 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai z = source->z + source->height/3; th = P_SpawnMobj(x, y, z, type); + if (P_MobjWasRemoved(th)) + return NULL; if (source->eflags & MFE_VERTICALFLIP) th->flags2 |= MF2_OBJECTFLIP; diff --git a/src/p_polyobj.c b/src/p_polyobj.c index b207bb740..331bc5c7f 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1243,6 +1243,8 @@ boolean Polyobj_rotate(polyobj_t *po, angle_t delta, boolean turnplayers, boolea // Returns NULL if no such polyobject exists. polyobj_t *Polyobj_GetForNum(INT32 id) { + if (numPolyObjects == 0) + return NULL; INT32 curidx = PolyObjects[id % numPolyObjects].first; while (curidx != numPolyObjects && PolyObjects[curidx].id != id) diff --git a/src/p_user.c b/src/p_user.c index d441a7e81..658a35711 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -394,6 +394,8 @@ void P_GiveFinishFlags(player_t *player) fixed_t xoffs = FINECOSINE(fa); fixed_t yoffs = FINESINE(fa); mobj_t* flag = P_SpawnMobjFromMobj(player->mo, xoffs, yoffs, 0, MT_FINISHFLAG); + if (P_MobjWasRemoved(flag)) + continue; flag->angle = angle; angle += FixedAngle(120*FRACUNIT); @@ -1826,6 +1828,9 @@ void P_SpawnShieldOrb(player_t *player) } shieldobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, orbtype); + if (P_MobjWasRemoved(shieldobj)) + return; + shieldobj->flags2 |= MF2_SHIELD; P_SetTarget(&shieldobj->target, player->mo); if ((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) @@ -1840,21 +1845,30 @@ void P_SpawnShieldOrb(player_t *player) if (shieldobj->info->seestate) { ov = P_SpawnMobj(shieldobj->x, shieldobj->y, shieldobj->z, MT_OVERLAY); - P_SetTarget(&ov->target, shieldobj); - P_SetMobjState(ov, shieldobj->info->seestate); - P_SetTarget(&shieldobj->tracer, ov); + if (!P_MobjWasRemoved(ov)) + { + P_SetTarget(&ov->target, shieldobj); + P_SetMobjState(ov, shieldobj->info->seestate); + P_SetTarget(&shieldobj->tracer, ov); + } } if (shieldobj->info->meleestate) { ov = P_SpawnMobj(shieldobj->x, shieldobj->y, shieldobj->z, MT_OVERLAY); - P_SetTarget(&ov->target, shieldobj); - P_SetMobjState(ov, shieldobj->info->meleestate); + if (!P_MobjWasRemoved(ov)) + { + P_SetTarget(&ov->target, shieldobj); + P_SetMobjState(ov, shieldobj->info->meleestate); + } } if (shieldobj->info->missilestate) { ov = P_SpawnMobj(shieldobj->x, shieldobj->y, shieldobj->z, MT_OVERLAY); - P_SetTarget(&ov->target, shieldobj); - P_SetMobjState(ov, shieldobj->info->missilestate); + if (!P_MobjWasRemoved(ov)) + { + P_SetTarget(&ov->target, shieldobj); + P_SetMobjState(ov, shieldobj->info->missilestate); + } } if (player->powers[pw_shield] & SH_FORCE) { @@ -1950,6 +1964,8 @@ void P_SetPower(player_t *player, powertype_t power, UINT16 value) mobj_t *P_SpawnGhostMobj(mobj_t *mobj) { mobj_t *ghost = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_GHOST); + if (P_MobjWasRemoved(ghost)) + return NULL; P_SetTarget(&ghost->target, mobj); @@ -1992,9 +2008,12 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) if (mobj->player && mobj->player->followmobj) { mobj_t *ghost2 = P_SpawnGhostMobj(mobj->player->followmobj); - P_SetTarget(&ghost2->tracer, ghost); - P_SetTarget(&ghost->tracer, ghost2); - ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW); + if (!P_MobjWasRemoved(ghost2)) + { + P_SetTarget(&ghost2->tracer, ghost); + P_SetTarget(&ghost->tracer, ghost2); + ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW); + } } // Copy interpolation data :) @@ -2043,6 +2062,8 @@ void P_SpawnThokMobj(player_t *player) zheight = player->mo->ceilingz - FixedMul(mobjinfo[type].height, player->mo->scale); mobj = P_SpawnMobj(player->mo->x, player->mo->y, zheight, type); + if (P_MobjWasRemoved(mobj)) + return; // set to player's angle, just in case mobj->angle = player->drawangle; @@ -2066,7 +2087,8 @@ void P_SpawnThokMobj(player_t *player) } } - P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do + if (!P_MobjWasRemoved(mobj)) + P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do G_GhostAddThok(); } @@ -2104,6 +2126,8 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type) zheight = player->mo->ceilingz - FixedMul(mobjinfo[type].height, player->mo->scale); mobj = P_SpawnMobj(player->mo->x, player->mo->y, zheight, type); + if (P_MobjWasRemoved(mobj)) + return; // set to player's angle, just in case mobj->angle = player->drawangle; @@ -2128,7 +2152,8 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type) } } - P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do + if (!P_MobjWasRemoved(mobj)) + P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do } /** Called when \p player finishes the level. @@ -2352,15 +2377,18 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) while (i < 5) { missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); - P_SetTarget(&missile->target, player->mo); - missile->angle = throwang + player->drawangle; - P_Thrust(missile, player->drawangle + ANGLE_90, - P_ReturnThrustY(missile, throwang, mu)); // side to side component - P_Thrust(missile, player->drawangle, mu2); // forward component - P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); - missile->momz += player->mo->pmomz; - missile->fuse = TICRATE/2; - missile->extravalue2 = ev; + if (!P_MobjWasRemoved(missile)) + { + P_SetTarget(&missile->target, player->mo); + missile->angle = throwang + player->drawangle; + P_Thrust(missile, player->drawangle + ANGLE_90, + P_ReturnThrustY(missile, throwang, mu)); // side to side component + P_Thrust(missile, player->drawangle, mu2); // forward component + P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); + missile->momz += player->mo->pmomz; + missile->fuse = TICRATE/2; + missile->extravalue2 = ev; + } i++; throwang += ANG30; @@ -2912,24 +2940,29 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player) : player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, FixedMul(player->mo->scale, player->shieldscale)); mobj_t *numbermobj = P_SpawnMobj(player->mo->x, player->mo->y, height, MT_DROWNNUMBERS); - - timeleft /= (2*TICRATE); // To be strictly accurate it'd need to be ((timeleft/TICRATE) - 1)/2, but integer division rounds down for us - - if (player->charflags & SF_MACHINE) + if (!P_MobjWasRemoved(numbermobj)) { - S_StartSound(player->mo, sfx_buzz1); - timeleft += 6; + timeleft /= (2*TICRATE); // To be strictly accurate it'd need to be ((timeleft/TICRATE) - 1)/2, but integer division rounds down for us + + if (player->charflags & SF_MACHINE) + { + S_StartSound(player->mo, sfx_buzz1); + timeleft += 6; + } + else + S_StartSound(player->mo, sfx_dwnind); + + if (!P_MobjWasRemoved(numbermobj)) + { + if (timeleft) // Don't waste time setting the state if the time is 0. + P_SetMobjState(numbermobj, numbermobj->info->spawnstate+timeleft); + + P_SetTarget(&numbermobj->target, player->mo); + numbermobj->threshold = 40; + numbermobj->destscale = player->mo->scale; + P_SetScale(numbermobj, player->mo->scale); + } } - else - S_StartSound(player->mo, sfx_dwnind); - - if (timeleft) // Don't waste time setting the state if the time is 0. - P_SetMobjState(numbermobj, numbermobj->info->spawnstate+timeleft); - - P_SetTarget(&numbermobj->target, player->mo); - numbermobj->threshold = 40; - numbermobj->destscale = player->mo->scale; - P_SetScale(numbermobj, player->mo->scale); } // Underwater timer runs out else if (timeleft == 1) @@ -2988,8 +3021,11 @@ static void P_CheckInvincibilityTimer(player_t *player) else if (leveltime % (TICRATE/7) == 0) { mobj_t *sparkle = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_IVSP); - sparkle->destscale = player->mo->scale; - P_SetScale(sparkle, player->mo->scale); + if (!P_MobjWasRemoved(sparkle)) + { + sparkle->destscale = player->mo->scale; + P_SetScale(sparkle, player->mo->scale); + } } // Resume normal music stuff. @@ -3044,7 +3080,8 @@ static void P_DoBubbleBreath(player_t *player) y += (P_RandomRange(r, -r)<mo->height>>FRACBITS)<mo->x + stirwaterx, player->mo->y + stirwatery, stirwaterz, MT_SMALLBUBBLE); - bubble->destscale = player->mo->scale; - P_SetScale(bubble,bubble->destscale); + if (!P_MobjWasRemoved(bubble)) + { + bubble->destscale = player->mo->scale; + P_SetScale(bubble,bubble->destscale); + } bubble = P_SpawnMobj( player->mo->x - stirwaterx, player->mo->y - stirwatery, stirwaterz, MT_SMALLBUBBLE); - bubble->destscale = player->mo->scale; - P_SetScale(bubble,bubble->destscale); + if (!P_MobjWasRemoved(bubble)) + { + bubble->destscale = player->mo->scale; + P_SetScale(bubble,bubble->destscale); + } } } @@ -3110,22 +3153,25 @@ static void P_DoPlayerHeadSigns(player_t *player) if (player->pflags & PF_TAGIT && !P_IsLocalPlayer(player)) { mobj_t* it = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TAG); - it->x = player->mo->x; - it->y = player->mo->y; - it->z = player->mo->z; - it->old_x = player->mo->old_x; - it->old_y = player->mo->old_y; - it->old_z = player->mo->old_z; + if (!P_MobjWasRemoved(it)) + { + it->x = player->mo->x; + it->y = player->mo->y; + it->z = player->mo->z; + it->old_x = player->mo->old_x; + it->old_y = player->mo->old_y; + it->old_z = player->mo->old_z; - if (!(player->mo->eflags & MFE_VERTICALFLIP)) - { - it->z += player->mo->height; - it->old_z += player->mo->height; - } - else - { - it->z -= mobjinfo[MT_TAG].height; - it->old_z -= mobjinfo[MT_TAG].height; + if (!(player->mo->eflags & MFE_VERTICALFLIP)) + { + it->z += player->mo->height; + it->old_z += player->mo->height; + } + else + { + it->z -= mobjinfo[MT_TAG].height; + it->old_z -= mobjinfo[MT_TAG].height; + } } } } @@ -3150,22 +3196,25 @@ static void P_DoPlayerHeadSigns(player_t *player) } sign = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_GOTFLAG); - sign->x = player->mo->x; - sign->y = player->mo->y; - sign->z = player->mo->z + zofs; - sign->old_x = player->mo->old_x; - sign->old_y = player->mo->old_y; - sign->old_z = player->mo->old_z + zofs; - - if (player_is_flipped) + if (!P_MobjWasRemoved(sign)) { - sign->eflags |= MFE_VERTICALFLIP; - } + sign->x = player->mo->x; + sign->y = player->mo->y; + sign->z = player->mo->z + zofs; + sign->old_x = player->mo->old_x; + sign->old_y = player->mo->old_y; + sign->old_z = player->mo->old_z + zofs; - if (player->gotflag & GF_REDFLAG) - sign->frame = 1|FF_FULLBRIGHT; - else //if (player->gotflag & GF_BLUEFLAG) - sign->frame = 2|FF_FULLBRIGHT; + if (player_is_flipped) + { + sign->eflags |= MFE_VERTICALFLIP; + } + + if (player->gotflag & GF_REDFLAG) + sign->frame = 1|FF_FULLBRIGHT; + else //if (player->gotflag & GF_BLUEFLAG) + sign->frame = 2|FF_FULLBRIGHT; + } } } } @@ -4270,8 +4319,11 @@ static void P_DoSuperStuff(player_t *player) && !(leveltime % TICRATE) && (player->mo->momx || player->mo->momy)) { spark = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK); - spark->destscale = player->mo->scale; - P_SetScale(spark, player->mo->scale); + if (!P_MobjWasRemoved(spark)) + { + spark->destscale = player->mo->scale; + P_SetScale(spark, player->mo->scale); + } } // Ran out of rings while super! @@ -4544,6 +4596,8 @@ static void P_DoSpinDashDust(player_t *player) INT32 prandom[3]; for (i = 0; i <= (leveltime%7)/2; i++) { // 1, 2, 3 or 4 particles particle = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_SPINDUST); + if (P_MobjWasRemoved(particle)) + return; if (player->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) // overrides fire version P_SetMobjState(particle, S_SPINDUST_BUBBLE1); @@ -4691,7 +4745,8 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) if (P_IsLocalPlayer(player)) // Only display it on your own view. { mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockon); + if (!P_MobjWasRemoved(visual)) + P_SetTarget(&visual->target, lockon); } } if ((cmd->buttons & BT_SPIN) && !(player->pflags & PF_SPINDOWN)) @@ -4832,10 +4887,13 @@ void P_DoJumpShield(player_t *player) for (i = 0; i < numangles; i++) { spark = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_THUNDERCOIN_SPARK); - P_InstaThrust(spark, travelangle + i*(ANGLE_MAX/numangles), FixedMul(4*FRACUNIT, spark->scale)); - if (i % 2) - P_SetObjectMomZ(spark, -4*FRACUNIT, false); - spark->fuse = 18; + if (!P_MobjWasRemoved(spark)) + { + P_InstaThrust(spark, travelangle + i*(ANGLE_MAX/numangles), FixedMul(4*FRACUNIT, spark->scale)); + if (i % 2) + P_SetObjectMomZ(spark, -4*FRACUNIT, false); + spark->fuse = 18; + } } #undef limitangle #undef numangles @@ -4942,14 +5000,17 @@ void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type) yo, player->mo->height/2 + zo, type); - P_SetTarget(&missile->target, player->mo); - P_SetScale(missile, (missile->destscale >>= 1)); - missile->angle = ang + movang; - missile->fuse = TICRATE/2; - missile->extravalue2 = (99*FRACUNIT)/100; - missile->momx = xo; - missile->momy = yo; - missile->momz = zo; + if (!P_MobjWasRemoved(missile)) + { + P_SetTarget(&missile->target, player->mo); + P_SetScale(missile, (missile->destscale >>= 1)); + missile->angle = ang + movang; + missile->fuse = TICRATE/2; + missile->extravalue2 = (99*FRACUNIT)/100; + missile->momx = xo; + missile->momy = yo; + missile->momz = zo; + } ang += ANGLE_45; } @@ -5046,8 +5107,11 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock if (dovis) { visual = P_SpawnMobj(lockonshield->x, lockonshield->y, lockonshield->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockonshield); - P_SetMobjStateNF(visual, visual->info->spawnstate+1); + if (!P_MobjWasRemoved(visual)) + { + P_SetTarget(&visual->target, lockonshield); + P_SetMobjStateNF(visual, visual->info->spawnstate+1); + } } } } @@ -5153,7 +5217,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (P_IsLocalPlayer(player)) // Only display it on your own view. { visual = P_SpawnMobj(lockonthok->x, lockonthok->y, lockonthok->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockonthok); + if (!P_MobjWasRemoved(visual)) + P_SetTarget(&visual->target, lockonthok); } } @@ -6848,10 +6913,14 @@ static void P_DoNiGHTSCapsule(player_t *player) // Spawn a 'pop' for every 2 tics if (!((tictimer - firstpoptic) % 2)) - S_StartSound(P_SpawnMobj(player->capsule->x + ((P_SignedRandom()/2)<capsule->y + ((P_SignedRandom()/2)<capsule->z + (player->capsule->height/2) + ((P_SignedRandom()/2)<capsule->x + ((P_SignedRandom()/2)<capsule->y + ((P_SignedRandom()/2)<capsule->z + (player->capsule->height/2) + ((P_SignedRandom()/2)<mo, 0, 0, player->mo->height, MT_GOTEMERALD); - emmo->health = em; // for identification - P_SetTarget(&emmo->target, player->mo); - P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); - P_SetTarget(&player->mo->tracer, emmo); + if (!P_MobjWasRemoved(emmo)) + { + emmo->health = em; // for identification + P_SetTarget(&emmo->target, player->mo); + P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); + P_SetTarget(&player->mo->tracer, emmo); + } } // Okay, we're doing this down here because we're handling time weirdly for co-op special stages @@ -6934,19 +7006,22 @@ static void P_DoNiGHTSCapsule(player_t *player) P_InstaThrust(flicky, flicky->angle, 8*FRACUNIT); }*/ mobj_t *idya = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height, MT_GOTEMERALD); - idya->extravalue2 = player->mare/5; - idya->health = player->mare + 1; // for identification - P_SetTarget(&idya->target, player->mo); - P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate + ((player->mare + 1) % 5)); - - if (player->mo->tracer) + if (!P_MobjWasRemoved(idya)) { - P_SetTarget(&idya->hnext, player->mo->tracer); - idya->extravalue1 = (angle_t)(player->mo->tracer->extravalue1 - 72*ANG1); - if (idya->extravalue1 > player->mo->tracer->extravalue1) - idya->extravalue1 -= (72*ANG1)/idya->extravalue1; + idya->extravalue2 = player->mare/5; + idya->health = player->mare + 1; // for identification + P_SetTarget(&idya->target, player->mo); + P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate + ((player->mare + 1) % 5)); + + if (player->mo->tracer) + { + P_SetTarget(&idya->hnext, player->mo->tracer); + idya->extravalue1 = (angle_t)(player->mo->tracer->extravalue1 - 72*ANG1); + if (idya->extravalue1 > player->mo->tracer->extravalue1) + idya->extravalue1 -= (72*ANG1)/idya->extravalue1; + } + P_SetTarget(&player->mo->tracer, idya); } - P_SetTarget(&player->mo->tracer, idya); } for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mare == player->mare) @@ -7271,19 +7346,25 @@ static void P_NiGHTSMovement(player_t *player) z -= FixedMul(mobjinfo[MT_NIGHTSPARKLE].height, player->mo->scale); firstmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle+ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle+ANGLE_90, spawndist), z, MT_NIGHTSPARKLE); - secondmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle-ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle-ANGLE_90, spawndist), z, MT_NIGHTSPARKLE); - - firstmobj->destscale = secondmobj->destscale = player->mo->scale; - P_SetTarget(&firstmobj->target, player->mo); - P_SetScale(firstmobj, player->mo->scale); - P_SetTarget(&secondmobj->target, player->mo); - P_SetScale(secondmobj, player->mo->scale); - - // Superloop turns sparkles red - if (player->powers[pw_nights_superloop]) + if (!P_MobjWasRemoved(firstmobj)) { - P_SetMobjState(firstmobj, mobjinfo[MT_NIGHTSPARKLE].seestate); - P_SetMobjState(secondmobj, mobjinfo[MT_NIGHTSPARKLE].seestate); + firstmobj->destscale = player->mo->scale; + P_SetTarget(&firstmobj->target, player->mo); + P_SetScale(firstmobj, player->mo->scale); + // Superloop turns sparkles red + if (player->powers[pw_nights_superloop]) + P_SetMobjState(firstmobj, mobjinfo[MT_NIGHTSPARKLE].seestate); + } + secondmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle-ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle-ANGLE_90, spawndist), z, MT_NIGHTSPARKLE); + if (!P_MobjWasRemoved(secondmobj)) + { + secondmobj->destscale = player->mo->scale; + P_SetTarget(&secondmobj->target, player->mo); + P_SetScale(secondmobj, player->mo->scale); + + // Superloop turns sparkles red + if (player->powers[pw_nights_superloop]) + P_SetMobjState(secondmobj, mobjinfo[MT_NIGHTSPARKLE].seestate); } } @@ -7291,9 +7372,12 @@ static void P_NiGHTSMovement(player_t *player) // It also spawns every tic to avoid failed paraloops { mobj_t *helpermobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_NIGHTSLOOPHELPER); - helpermobj->fuse = player->mo->fuse = leveltime; - P_SetTarget(&helpermobj->target, player->mo); - P_SetScale(helpermobj, player->mo->scale); + if (!P_MobjWasRemoved(helpermobj)) + { + helpermobj->fuse = player->mo->fuse = leveltime; + P_SetTarget(&helpermobj->target, player->mo); + P_SetScale(helpermobj, player->mo->scale); + } } if (player->bumpertime) @@ -7482,19 +7566,22 @@ static void P_NiGHTSMovement(player_t *player) mobjtype_t splishtype = (player->mo->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH; mobj_t *water = P_SpawnMobj(player->mo->x, player->mo->y, ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[splishtype].height, player->mo->scale) : player->mo->watertop), splishtype); - if (player->mo->eflags & MFE_GOOWATER) - S_StartSound(water, sfx_ghit); - else if (player->mo->eflags & MFE_TOUCHLAVA) - S_StartSound(water, sfx_splash); - else - S_StartSound(water, sfx_wslap); - if (player->mo->eflags & MFE_VERTICALFLIP) + if (!P_MobjWasRemoved(water)) { - water->flags2 |= MF2_OBJECTFLIP; - water->eflags |= MFE_VERTICALFLIP; + if (player->mo->eflags & MFE_GOOWATER) + S_StartSound(water, sfx_ghit); + else if (player->mo->eflags & MFE_TOUCHLAVA) + S_StartSound(water, sfx_splash); + else + S_StartSound(water, sfx_wslap); + if (player->mo->eflags & MFE_VERTICALFLIP) + { + water->flags2 |= MF2_OBJECTFLIP; + water->eflags |= MFE_VERTICALFLIP; + } + water->destscale = player->mo->scale; + P_SetScale(water, player->mo->scale); } - water->destscale = player->mo->scale; - P_SetScale(water, player->mo->scale); } if (player->mo->momx || player->mo->momy) @@ -7727,6 +7814,8 @@ void P_ElementalFire(player_t *player, boolean cropcircle) for (i = 0; i < numangles; i++) { flame = P_SpawnMobj(player->mo->x, player->mo->y, ground, MT_SPINFIRE); + if (P_MobjWasRemoved(flame)) + continue; flame->flags &= ~MF_NOGRAVITY; P_SetTarget(&flame->target, player->mo); flame->angle = travelangle + i*(ANGLE_MAX/numangles); @@ -7764,6 +7853,8 @@ void P_ElementalFire(player_t *player, boolean cropcircle) } flame = P_SpawnMobj(newx, newy, ground, MT_SPINFIRE); + if (P_MobjWasRemoved(flame)) + continue; P_SetTarget(&flame->target, player->mo); flame->angle = travelangle; flame->fuse = TICRATE*6; @@ -7805,6 +7896,8 @@ void P_SpawnSkidDust(player_t *player, fixed_t radius, boolean sound) mobj_t *particle; particle = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_SPINDUST); + if (P_MobjWasRemoved(particle)) + return; if (radius >>= FRACBITS) { P_UnsetThingPosition(particle); @@ -8391,19 +8484,22 @@ void P_MovePlayer(player_t *player) mobjtype_t splishtype = (player->mo->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH; mobj_t *water = P_SpawnMobj(player->mo->x - P_ReturnThrustX(NULL, player->mo->angle, player->mo->radius), player->mo->y - P_ReturnThrustY(NULL, player->mo->angle, player->mo->radius), ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[splishtype].height, player->mo->scale) : player->mo->watertop), splishtype); - if (player->mo->eflags & MFE_GOOWATER) - S_StartSound(water, sfx_ghit); - else if (player->mo->eflags & MFE_TOUCHLAVA) - S_StartSound(water, sfx_splash); - else - S_StartSound(water, sfx_wslap); - if (player->mo->eflags & MFE_VERTICALFLIP) + if (!P_MobjWasRemoved(water)) { - water->flags2 |= MF2_OBJECTFLIP; - water->eflags |= MFE_VERTICALFLIP; + if (player->mo->eflags & MFE_GOOWATER) + S_StartSound(water, sfx_ghit); + else if (player->mo->eflags & MFE_TOUCHLAVA) + S_StartSound(water, sfx_splash); + else + S_StartSound(water, sfx_wslap); + if (player->mo->eflags & MFE_VERTICALFLIP) + { + water->flags2 |= MF2_OBJECTFLIP; + water->eflags |= MFE_VERTICALFLIP; + } + water->destscale = player->mo->scale; + P_SetScale(water, player->mo->scale); } - water->destscale = player->mo->scale; - P_SetScale(water, player->mo->scale); } // Little water sound while touching water - just a nicety. @@ -10821,6 +10917,8 @@ static void P_SpawnSparks(mobj_t *mo, angle_t maindir) fixed_t fm = (maindir >> ANGLETOFINESHIFT) & FINEMASK; spark = P_SpawnMobj(mo->x - b2*s + b1*c, mo->y + b2*c + b1*s, mo->z, MT_MINECARTSPARK); + if (P_MobjWasRemoved(spark)) + return; spark->momx = mo->momx + r1 + 8*FINECOSINE(fm); spark->momy = mo->momy + r2 + 8*FINESINE(fm); spark->momz = mo->momz + r3; @@ -12066,17 +12164,20 @@ void P_PlayerThink(player_t *player) if ((player->powers[pw_super] || player->powers[pw_sneakers]) && (player->speed + abs(player->mo->momz)) > FixedMul(20*FRACUNIT,player->mo->scale)) { mobj_t *gmobj = P_SpawnGhostMobj(player->mo); - gmobj->fuse = 2; - if (gmobj->tracer) - gmobj->tracer->fuse = 2; - if (leveltime & 1) + if (!P_MobjWasRemoved(gmobj)) { - gmobj->frame &= ~FF_TRANSMASK; - gmobj->frame |= tr_trans70<fuse = 2; if (gmobj->tracer) + gmobj->tracer->fuse = 2; + if (leveltime & 1) { - gmobj->tracer->frame &= ~FF_TRANSMASK; - gmobj->tracer->frame |= tr_trans70<frame &= ~FF_TRANSMASK; + gmobj->frame |= tr_trans70<tracer) + { + gmobj->tracer->frame &= ~FF_TRANSMASK; + gmobj->tracer->frame |= tr_trans70<normalspeed >= skins[player->skin].normalspeed*2) { mobj_t *ghost = P_SpawnGhostMobj(player->mo); // Spawns afterimages - ghost->fuse = 2; // Makes the images fade quickly - if (ghost->tracer && !P_MobjWasRemoved(ghost->tracer)) - ghost->tracer->fuse = ghost->fuse; + if (!P_MobjWasRemoved(ghost)) + { + ghost->fuse = 2; // Makes the images fade quickly + if (ghost->tracer && !P_MobjWasRemoved(ghost->tracer)) + ghost->tracer->fuse = ghost->fuse; + } } } else if (dashmode) @@ -12889,15 +12993,18 @@ void P_PlayerAfterThink(player_t *player) if (!player->followmobj || P_MobjWasRemoved(player->followmobj)) { P_SetTarget(&player->followmobj, P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem)); - P_SetTarget(&player->followmobj->tracer, player->mo); - switch (player->followmobj->type) + if (!P_MobjWasRemoved(player->followmobj)) { - case MT_METALJETFUME: - player->followmobj->colorized = true; - break; - default: - player->followmobj->flags2 |= MF2_LINKDRAW; - break; + P_SetTarget(&player->followmobj->tracer, player->mo); + switch (player->followmobj->type) + { + case MT_METALJETFUME: + player->followmobj->colorized = true; + break; + default: + player->followmobj->flags2 |= MF2_LINKDRAW; + break; + } } }