diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 48214c4c7..6afae78f8 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1364,9 +1364,15 @@ void APowerTargeter::EndEffect () Super::EndEffect(); if (Owner != nullptr && Owner->player != nullptr) { - Owner->player->GetPSprite(PSP_TARGETCENTER)->SetState(nullptr); - Owner->player->GetPSprite(PSP_TARGETLEFT)->SetState(nullptr); - Owner->player->GetPSprite(PSP_TARGETRIGHT)->SetState(nullptr); + // Calling GetPSprite here could crash if we're creating a new game. + // This is because P_SetupLevel nulls the player's mo before destroying + // every DThinker which in turn ends up calling this. + // However P_SetupLevel is only called after G_NewInit which calls + // every player's dtor which destroys all their psprites. + DPSprite *pspr; + if ((pspr = Owner->player->FindPSprite(PSP_TARGETCENTER)) != nullptr) pspr->SetState(nullptr); + if ((pspr = Owner->player->FindPSprite(PSP_TARGETLEFT)) != nullptr) pspr->SetState(nullptr); + if ((pspr = Owner->player->FindPSprite(PSP_TARGETRIGHT)) != nullptr) pspr->SetState(nullptr); } } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 26567e61d..b9ba6b932 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -177,14 +177,27 @@ DPSprite *player_t::FindPSprite(int layer) DPSprite *player_t::GetPSprite(PSPLayers layer) { - assert(ReadyWeapon != nullptr); + AInventory *oldcaller = nullptr; + AInventory *newcaller = nullptr; + + if (layer >= PSP_TARGETCENTER) + { + if (mo != nullptr) + { + newcaller = mo->FindInventory(RUNTIME_CLASS(APowerTargeter), true); + } + } + else + { + newcaller = ReadyWeapon; + } + + assert(newcaller != nullptr); - AInventory *oldcaller; DPSprite *pspr = FindPSprite(layer); if (pspr == nullptr) { - pspr = new DPSprite(this, ReadyWeapon, layer); - oldcaller = nullptr; + pspr = new DPSprite(this, newcaller, layer); } else { @@ -193,18 +206,13 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) // Always update the caller here in case we switched weapon // or if the layer was being used by an inventory item before. - pspr->Caller = ReadyWeapon; + pspr->Caller = newcaller; - if (ReadyWeapon != oldcaller) + if (newcaller != oldcaller) { // Only change the flags if this layer was created now or if we updated the caller. if (layer != PSP_FLASH) { // Only the flash layer should follow the weapon. pspr->Flags &= ~PSPF_ADDWEAPON; - - if (layer != PSP_WEAPON) - { // [RH] Don't bob the targeter. - pspr->Flags &= ~PSPF_ADDBOB; - } } } @@ -279,7 +287,7 @@ void DPSprite::SetState(FState *newstate, bool pending) Tics = newstate->GetTics(); // could be 0 if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon))) - { // The targeter layers are affected by this too. + { if (sv_fastweapons == 2 && ID == PSP_WEAPON) Tics = newstate->ActionFunc == nullptr ? 0 : 1; else if (sv_fastweapons == 3) @@ -1350,7 +1358,6 @@ void DPSprite::Tick() Tics--; // [BC] Apply double firing speed. - // This is applied to the targeter layers too. if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) && Tics && Owner->cheats & CF_DOUBLEFIRINGSPEED) Tics--; diff --git a/src/p_user.cpp b/src/p_user.cpp index cba8782f1..2ca7434d5 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3090,7 +3090,9 @@ void player_t::Serialize (FArchive &arc) << sx << sy << sprite << frame; - if (state != nullptr && ReadyWeapon != nullptr) + if (state != nullptr && + ((layer < PSP_TARGETCENTER && ReadyWeapon != nullptr) || + (layer >= PSP_TARGETCENTER && mo->FindInventory(RUNTIME_CLASS(APowerTargeter), true)))) { DPSprite *pspr; pspr = GetPSprite(PSPLayers(layer)); diff --git a/src/r_things.cpp b/src/r_things.cpp index 75630e859..caca6a11c 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1319,8 +1319,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double if (tex->UseType == FTexture::TEX_Null) return; - // The targeters aren't weapons. - isweapon = (pspr->GetID() < PSP_TARGETCENTER && pspr->GetCaller()->IsKindOf(RUNTIME_CLASS(AWeapon))); + isweapon = pspr->GetCaller()->IsKindOf(RUNTIME_CLASS(AWeapon)); if (pspr->firstTic) { // Can't interpolate the first tic.