This commit is contained in:
Christoph Oelckers 2016-09-02 00:44:10 +02:00
commit 7135a6909c
5 changed files with 52 additions and 26 deletions

View file

@ -1057,6 +1057,7 @@ public:
int skillrespawncount; int skillrespawncount;
int TIDtoHate; // TID of things to hate (0 if none) int TIDtoHate; // TID of things to hate (0 if none)
FNameNoInit Species; // For monster families FNameNoInit Species; // For monster families
TObjPtr<AActor> alternative; // (Un)Morphed actors stored here. Those with the MF_UNMORPHED flag are the originals.
TObjPtr<AActor> tracer; // Thing being chased/attacked for tracers TObjPtr<AActor> tracer; // Thing being chased/attacked for tracers
TObjPtr<AActor> master; // Thing which spawned this one (prevents mutual attacks) TObjPtr<AActor> master; // Thing which spawned this one (prevents mutual attacks)
double Floorclip; // value to use for floor clipping double Floorclip; // value to use for floor clipping

View file

@ -38,7 +38,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
APlayerPawn *actor; APlayerPawn *actor;
actor = p->mo; actor = p->mo;
if (actor == NULL) if (actor == nullptr)
{ {
return false; return false;
} }
@ -55,7 +55,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
if ((p->mo->GetClass() == spawntype) if ((p->mo->GetClass() == spawntype)
&& (p->mo->PlayerFlags & PPF_CANSUPERMORPH) && (p->mo->PlayerFlags & PPF_CANSUPERMORPH)
&& (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE)) && (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE))
&& (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == NULL)) && (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == nullptr))
{ // Make a super chicken { // Make a super chicken
p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2));
} }
@ -65,7 +65,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
{ // Dead players cannot morph { // Dead players cannot morph
return false; return false;
} }
if (spawntype == NULL) if (spawntype == nullptr)
{ {
return false; return false;
} }
@ -94,7 +94,8 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
} }
morphed->Angles.Yaw = actor->Angles.Yaw; morphed->Angles.Yaw = actor->Angles.Yaw;
morphed->target = actor->target; morphed->target = actor->target;
morphed->tracer = actor; morphed->tracer = actor->tracer;
morphed->alternative = actor;
morphed->FriendPlayer = actor->FriendPlayer; morphed->FriendPlayer = actor->FriendPlayer;
morphed->DesignatedTeam = actor->DesignatedTeam; morphed->DesignatedTeam = actor->DesignatedTeam;
morphed->Score = actor->Score; morphed->Score = actor->Score;
@ -113,7 +114,8 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
morphed->flags2 |= actor->flags2 & MF2_FLY; morphed->flags2 |= actor->flags2 & MF2_FLY;
morphed->flags3 |= actor->flags3 & MF3_GHOST; morphed->flags3 |= actor->flags3 & MF3_GHOST;
AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE); AActor *eflash = Spawn(((enter_flash) ? enter_flash : RUNTIME_CLASS(ATeleportFog)), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE);
actor->player = NULL; actor->player = nullptr;
actor->alternative = morphed;
actor->flags &= ~(MF_SOLID|MF_SHOOTABLE); actor->flags &= ~(MF_SOLID|MF_SHOOTABLE);
actor->flags |= MF_UNMORPHED; actor->flags |= MF_UNMORPHED;
actor->renderflags |= RF_INVISIBLE; actor->renderflags |= RF_INVISIBLE;
@ -129,7 +131,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
p->Vel.X = p->Vel.Y = 0; p->Vel.X = p->Vel.Y = 0;
morphed->ObtainInventory (actor); morphed->ObtainInventory (actor);
// Remove all armor // Remove all armor
for (item = morphed->Inventory; item != NULL; ) for (item = morphed->Inventory; item != nullptr; )
{ {
AInventory *next = item->Inventory; AInventory *next = item->Inventory;
if (item->IsKindOf (RUNTIME_CLASS(AArmor))) if (item->IsKindOf (RUNTIME_CLASS(AArmor)))
@ -182,7 +184,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
// because the level or game is ended while morphed, // because the level or game is ended while morphed,
// by the time it gets executed the morphed player // by the time it gets executed the morphed player
// pawn instance may have already been destroyed. // pawn instance may have already been destroyed.
if (pmo == NULL || pmo->tracer == NULL) if (pmo == nullptr || pmo->alternative == nullptr)
{ {
return false; return false;
} }
@ -197,7 +199,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
return false; return false;
} }
mo = barrier_cast<APlayerPawn *>(pmo->tracer); mo = barrier_cast<APlayerPawn *>(pmo->alternative);
mo->SetOrigin (pmo->Pos(), false); mo->SetOrigin (pmo->Pos(), false);
mo->flags |= MF_SOLID; mo->flags |= MF_SOLID;
pmo->flags &= ~MF_SOLID; pmo->flags &= ~MF_SOLID;
@ -208,10 +210,14 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
player->morphTics = 2*TICRATE; player->morphTics = 2*TICRATE;
return false; return false;
} }
pmo->player = NULL; // No longer using tracer as morph storage. That is what 'alternative' is for.
// If the tracer has changed on the morph, change the original too.
mo->target = pmo->target;
mo->tracer = pmo->tracer;
pmo->player = nullptr;
// Remove the morph power if the morph is being undone prematurely. // Remove the morph power if the morph is being undone prematurely.
for (AInventory *item = pmo->Inventory, *next = NULL; item != NULL; item = next) for (AInventory *item = pmo->Inventory, *next = nullptr; item != nullptr; item = next)
{ {
next = item->Inventory; next = item->Inventory;
if (item->IsKindOf(RUNTIME_CLASS(APowerMorph))) if (item->IsKindOf(RUNTIME_CLASS(APowerMorph)))
@ -252,10 +258,10 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
player->morphTics = 0; player->morphTics = 0;
player->MorphedPlayerClass = 0; player->MorphedPlayerClass = 0;
player->MorphStyle = 0; player->MorphStyle = 0;
player->MorphExitFlash = NULL; player->MorphExitFlash = nullptr;
player->viewheight = mo->ViewHeight; player->viewheight = mo->ViewHeight;
AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true);
if (level2 != NULL) if (level2 != nullptr)
{ {
level2->Destroy (); level2->Destroy ();
} }
@ -310,31 +316,31 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
} }
} }
AActor *eflash = NULL; AActor *eflash = nullptr;
if (exit_flash != NULL) if (exit_flash != nullptr)
{ {
eflash = Spawn(exit_flash, pmo->Vec3Angle(20., mo->Angles.Yaw, TELEFOGHEIGHT), ALLOW_REPLACE); eflash = Spawn(exit_flash, pmo->Vec3Angle(20., mo->Angles.Yaw, TELEFOGHEIGHT), ALLOW_REPLACE);
if (eflash) eflash->target = mo; if (eflash) eflash->target = mo;
} }
mo->SetupWeaponSlots(); // Use original class's weapon slots. mo->SetupWeaponSlots(); // Use original class's weapon slots.
beastweap = player->ReadyWeapon; beastweap = player->ReadyWeapon;
if (player->PremorphWeapon != NULL) if (player->PremorphWeapon != nullptr)
{ {
player->PremorphWeapon->PostMorphWeapon (); player->PremorphWeapon->PostMorphWeapon ();
} }
else else
{ {
player->ReadyWeapon = player->PendingWeapon = NULL; player->ReadyWeapon = player->PendingWeapon = nullptr;
} }
if (correctweapon) if (correctweapon)
{ // Better "lose morphed weapon" semantics { // Better "lose morphed weapon" semantics
PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon);
if (morphweapon != NULL && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) if (morphweapon != nullptr && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
{ {
AWeapon *OriginalMorphWeapon = static_cast<AWeapon *>(mo->FindInventory (morphweapon)); AWeapon *OriginalMorphWeapon = static_cast<AWeapon *>(mo->FindInventory (morphweapon));
if ((OriginalMorphWeapon != NULL) && (OriginalMorphWeapon->GivenAsMorphWeapon)) if ((OriginalMorphWeapon != nullptr) && (OriginalMorphWeapon->GivenAsMorphWeapon))
{ // You don't get to keep your morphed weapon. { // You don't get to keep your morphed weapon.
if (OriginalMorphWeapon->SisterWeapon != NULL) if (OriginalMorphWeapon->SisterWeapon != nullptr)
{ {
OriginalMorphWeapon->SisterWeapon->Destroy (); OriginalMorphWeapon->SisterWeapon->Destroy ();
} }
@ -344,20 +350,21 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag,
} }
else // old behaviour (not really useful now) else // old behaviour (not really useful now)
{ // Assumptions made here are no longer valid { // Assumptions made here are no longer valid
if (beastweap != NULL) if (beastweap != nullptr)
{ // You don't get to keep your morphed weapon. { // You don't get to keep your morphed weapon.
if (beastweap->SisterWeapon != NULL) if (beastweap->SisterWeapon != nullptr)
{ {
beastweap->SisterWeapon->Destroy (); beastweap->SisterWeapon->Destroy ();
} }
beastweap->Destroy (); beastweap->Destroy ();
} }
} }
pmo->tracer = NULL; mo->alternative = nullptr;
pmo->alternative = nullptr;
pmo->Destroy (); pmo->Destroy ();
// Restore playerclass armor to its normal amount. // Restore playerclass armor to its normal amount.
AHexenArmor *hxarmor = mo->FindInventory<AHexenArmor>(); AHexenArmor *hxarmor = mo->FindInventory<AHexenArmor>();
if (hxarmor != NULL) if (hxarmor != nullptr)
{ {
hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0]; hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0];
} }
@ -517,9 +524,9 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
(actor->player->morphTics) && (actor->player->morphTics) &&
(actor->player->MorphStyle & MORPH_UNDOBYDEATH) && (actor->player->MorphStyle & MORPH_UNDOBYDEATH) &&
(actor->player->mo) && (actor->player->mo) &&
(actor->player->mo->tracer)) (actor->player->mo->alternative))
{ {
AActor *realme = actor->player->mo->tracer; AActor *realme = actor->player->mo->alternative;
int realstyle = actor->player->MorphStyle; int realstyle = actor->player->MorphStyle;
int realhealth = actor->health; int realhealth = actor->health;
if (P_UndoPlayerMorph(actor->player, actor->player, 0, !!(actor->player->MorphStyle & MORPH_UNDOBYDEATHFORCED))) if (P_UndoPlayerMorph(actor->player, actor->player, 0, !!(actor->player->MorphStyle & MORPH_UNDOBYDEATHFORCED)))

View file

@ -4449,6 +4449,8 @@ enum EACSFunctions
-106 : KickFromGame(2), -106 : KickFromGame(2),
*/ */
ACSF_CheckClass = 200,
// ZDaemon // ZDaemon
ACSF_GetTeamScore = 19620, // (int team) ACSF_GetTeamScore = 19620, // (int team)
ACSF_SetTeamScore, // (int team, int value) ACSF_SetTeamScore, // (int team, int value)
@ -6028,6 +6030,12 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
return false; return false;
} }
case ACSF_CheckClass:
{
const char *clsname = FBehavior::StaticLookupString(args[0]);
return !!PClass::FindActor(clsname);
}
default: default:
break; break;
} }

View file

@ -389,6 +389,11 @@ void AActor::Serialize(FArchive &arc)
arc << SpriteRotation; arc << SpriteRotation;
} }
if (SaveVersion >= 4550)
{
arc << alternative;
}
{ {
FString tagstr; FString tagstr;
if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag;
@ -1806,6 +1811,11 @@ double P_XYMovement (AActor *mo, DVector2 scroll)
mo->Vel.X *= fac; mo->Vel.X *= fac;
mo->Vel.Y *= fac; mo->Vel.Y *= fac;
} }
const double VELOCITY_THRESHOLD = 5000; // don't let it move faster than this. Fixed point overflowed at 32768 but that's too much to make this safe.
if (mo->Vel.LengthSquared() >= VELOCITY_THRESHOLD*VELOCITY_THRESHOLD)
{
mo->Vel.MakeResize(VELOCITY_THRESHOLD);
}
move = mo->Vel; move = mo->Vel;
// [RH] Carrying sectors didn't work with low speeds in BOOM. This is // [RH] Carrying sectors didn't work with low speeds in BOOM. This is
// because BOOM relied on the speed being fast enough to accumulate // because BOOM relied on the speed being fast enough to accumulate

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the // Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got. // SVN revision ever got.
#define SAVEVER 4549 #define SAVEVER 4550
#define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)