2161: Small prediction fixes/update r=def- a=trml

I looked through the latest changes in the server code, and made some updates to the prediction with it. This includes the hammer-out-of-freeze server fix and a small fix for stopper prediction. Also cleaned up some code, and fixed predicted smoke-trails slightly so they don't go through walls in certain cases.

Co-authored-by: trml <trml@users.noreply.github.com>
This commit is contained in:
bors[bot] 2020-05-07 07:30:03 +00:00 committed by GitHub
commit 2649fb5234
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 81 additions and 130 deletions

View file

@ -285,7 +285,7 @@ void CItems::OnRender()
for(auto *pProj = (CProjectile*) GameClient()->m_PredictedWorld.FindFirst(CGameWorld::ENTTYPE_PROJECTILE); pProj; pProj = (CProjectile*) pProj->NextEntity())
{
CNetObj_Projectile Data;
if(pProj->m_Weapon != WEAPON_SHOTGUN || pProj->m_Explosive || pProj->m_Freeze)
if(pProj->m_Type != WEAPON_SHOTGUN || pProj->m_Explosive || pProj->m_Freeze)
pProj->FillExtraInfo(&Data);
else
pProj->FillInfo(&Data);
@ -324,12 +324,12 @@ void CItems::OnRender()
if(auto *pProj = (CProjectile*) GameClient()->m_GameWorld.FindMatch(Item.m_ID, Item.m_Type, pData))
{
if(pProj->m_LastRenderTick <= 0
&& (pProj->m_Weapon != WEAPON_SHOTGUN || (!pProj->m_Freeze && !pProj->m_Explosive)) // skip ddrace shotgun bullets
&& (pProj->m_Weapon == WEAPON_SHOTGUN || fabs(length(pProj->m_Direction) - 1.f) < 0.02) // workaround to skip grenades on ball mod
&& (pProj->m_Type != WEAPON_SHOTGUN || (!pProj->m_Freeze && !pProj->m_Explosive)) // skip ddrace shotgun bullets
&& (pProj->m_Type == WEAPON_SHOTGUN || fabs(length(pProj->m_Direction) - 1.f) < 0.02) // workaround to skip grenades on ball mod
&& (pProj->GetOwner() < 0 || !GameClient()->m_aClients[pProj->GetOwner()].m_IsPredictedLocal) // skip locally predicted projectiles
&& !Client()->SnapFindItem(IClient::SNAP_PREV, Item.m_Type, Item.m_ID))
{
ReconstructSmokeTrail((const CNetObj_Projectile *)pData, Item.m_ID, pProj->m_DestroyTick, pProj->m_LifeSpan);
ReconstructSmokeTrail((const CNetObj_Projectile *)pData, Item.m_ID, pProj->m_DestroyTick);
}
pProj->m_LastRenderTick = Client()->GameTick(g_Config.m_ClDummy);
continue;
@ -442,7 +442,7 @@ void CItems::AddExtraProjectile(CNetObj_Projectile *pProj)
}
}
void CItems::ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemID, int DestroyTick, int LifeSpan)
void CItems::ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemID, int DestroyTick)
{
bool LocalPlayerInGame = false;
@ -495,7 +495,6 @@ void CItems::ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemI
float T = Pt;
if(DestroyTick >= 0)
T = minimum(Pt, ((float)(DestroyTick - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy))/(float)SERVER_TICK_SPEED);
T = minimum(T, LifeSpan/(float)SERVER_TICK_SPEED);
float MinTrailSpan = 0.4f * ((pCurrent->m_Type == WEAPON_GRENADE) ? 0.5f : 0.25f);
float Step = maximum(Client()->FrameTimeAvg(), (pCurrent->m_Type == WEAPON_GRENADE) ? 0.02f : 0.01f);

View file

@ -27,7 +27,7 @@ public:
void AddExtraProjectile(CNetObj_Projectile *pProj);
void ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemID, int DestroyTick, int LifeSpan);
void ReconstructSmokeTrail(const CNetObj_Projectile *pCurrent, int ItemID, int DestroyTick);
};
#endif

View file

@ -20,46 +20,6 @@
#include <game/client/prediction/entities/laser.h>
#include <game/client/prediction/entities/pickup.h>
class CGameClient;
class CWeaponData
{
public:
int m_Tick;
vec2 m_Pos;
vec2 m_Direction;
vec2 StartPos() { return m_Pos + m_Direction * 28.0f * 0.75f; }
};
class CLocalProjectile
{
public:
int m_Active;
CGameClient *m_pGameClient;
CWorldCore *m_pWorld;
CCollision *m_pCollision;
vec2 m_Direction;
vec2 m_Pos;
int m_StartTick;
int m_Type;
int m_Owner;
int m_Weapon;
bool m_Explosive;
int m_Bouncing;
bool m_Freeze;
bool m_ExtraInfo;
vec2 GetPos(float Time);
void CreateExplosion(vec2 Pos, int LocalClientID);
void Tick(int CurrentTick, int GameTickSpeed, int LocalClientID);
void Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, const CNetObj_Projectile *pProj);
void Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, vec2 Vel, vec2 Pos, int StartTick, int Type, int Owner, int Weapon, bool Explosive, int Bouncing, bool Freeze, bool ExtraInfo);
bool GameLayerClipped(vec2 CheckPos);
void Deactivate() { m_Active = 0; }
};
class CGameInfo
{
public:

View file

@ -25,6 +25,7 @@ void CCharacter::SetWeapon(int W)
void CCharacter::SetSolo(bool Solo)
{
m_Core.m_Solo = Solo;
TeamsCore()->SetSolo(GetCID(), Solo);
}
@ -69,7 +70,7 @@ void CCharacter::HandleJetpack()
return;
// check for ammo
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
{
return;
}
@ -83,7 +84,7 @@ void CCharacter::HandleJetpack()
float Strength = GetTuning(m_TuneZone)->m_JetpackStrength;
if(!m_TuneZone)
Strength = m_LastJetpackStrength;
TakeDamage(Direction * -1.0f * (Strength / 100.0f / 6.11f), g_pData->m_Weapons.m_Hammer.m_pBase->m_Damage, GetCID(), m_Core.m_ActiveWeapon);
TakeDamage(Direction * -1.0f * (Strength / 100.0f / 6.11f), 0, GetCID(), m_Core.m_ActiveWeapon);
}
}
}
@ -190,7 +191,7 @@ void CCharacter::HandleNinja()
void CCharacter::DoWeaponSwitch()
{
// make sure we can switch
if(m_ReloadTimer != 0 || m_QueuedWeapon == -1 || m_aWeapons[WEAPON_NINJA].m_Got)
if(m_ReloadTimer != 0 || m_QueuedWeapon == -1 || m_aWeapons[WEAPON_NINJA].m_Got || !m_aWeapons[m_QueuedWeapon].m_Got)
return;
// switch Weapon
@ -264,7 +265,9 @@ void CCharacter::FireWeapon()
bool FullAuto = false;
if(m_Core.m_ActiveWeapon == WEAPON_GRENADE || m_Core.m_ActiveWeapon == WEAPON_SHOTGUN || m_Core.m_ActiveWeapon == WEAPON_LASER)
FullAuto = true;
if (m_Jetpack && m_Core.m_ActiveWeapon == WEAPON_GUN)
if(m_Jetpack && m_Core.m_ActiveWeapon == WEAPON_GUN)
FullAuto = true;
if(m_FrozenLastTick)
FullAuto = true;
// don't fire hammer when player is deep and sv_deepfly is disabled
@ -283,7 +286,7 @@ void CCharacter::FireWeapon()
return;
// check for ammo
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
{
return;
}
@ -322,7 +325,7 @@ void CCharacter::FireWeapon()
float Strength = GetTuning(m_TuneZone)->m_HammerStrength;
vec2 Temp = pTarget->m_Core.m_Vel + normalize(Dir + vec2(0.f, -1.1f)) * 10.0f;
Temp = pTarget->Core()->LimitVel(Temp);
Temp = ClampVel(pTarget->m_MoveRestrictions, Temp);
Temp -= pTarget->m_Core.m_Vel;
vec2 Force = vec2(0.f, -1.0f) + Temp;
@ -373,8 +376,7 @@ void CCharacter::FireWeapon()
0,//Freeze
0,//Explosive
0,//Force
-1,//SoundImpact
WEAPON_GUN//Weapon
-1//SoundImpact
);
}
} break;
@ -402,8 +404,7 @@ void CCharacter::FireWeapon()
0,//Freeze
0,//Explosive
0,//Force
-1,//SoundImpact
WEAPON_SHOTGUN//Weapon
-1//SoundImpact
);
}
}
@ -430,8 +431,7 @@ void CCharacter::FireWeapon()
0,//Freeze
true,//Explosive
0,//Force
SOUND_GRENADE_EXPLODE,//SoundImpact
WEAPON_GRENADE//Weapon
SOUND_GRENADE_EXPLODE//SoundImpact
);//SoundImpact
} break;
@ -484,18 +484,6 @@ void CCharacter::HandleWeapons()
return;
}
bool CCharacter::GiveWeapon(int Weapon, int Ammo)
{
if(m_aWeapons[Weapon].m_Ammo < g_pData->m_Weapons.m_aId[Weapon].m_Maxammo || !m_aWeapons[Weapon].m_Got)
{
m_aWeapons[Weapon].m_Got = true;
if(!m_FreezeTime)
m_aWeapons[Weapon].m_Ammo = minimum(g_pData->m_Weapons.m_aId[Weapon].m_Maxammo, Ammo);
return true;
}
return false;
}
void CCharacter::GiveNinja()
{
m_Ninja.m_ActivationTick = GameWorld()->GameTick();
@ -510,13 +498,14 @@ void CCharacter::GiveNinja()
void CCharacter::OnPredictedInput(CNetObj_PlayerInput *pNewInput)
{
// copy new input
mem_copy(&m_SavedInput, pNewInput, sizeof(m_SavedInput));
mem_copy(&m_Input, pNewInput, sizeof(m_Input));
//m_NumInputs++;
// it is not allowed to aim in the center
if(m_Input.m_TargetX == 0 && m_Input.m_TargetY == 0)
m_Input.m_TargetY = -1;
mem_copy(&m_SavedInput, &m_Input, sizeof(m_SavedInput));
}
void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
@ -567,7 +556,8 @@ void CCharacter::TickDefered()
bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
{
m_Core.ApplyForce(Force);
vec2 Temp = m_Core.m_Vel + Force;
m_Core.m_Vel = ClampVel(m_MoveRestrictions, Temp);
return true;
}
@ -646,7 +636,7 @@ void CCharacter::HandleSkippableTiles(int Index)
}
else
TempVel += Direction * Force;
m_Core.m_Vel = m_Core.LimitVel(TempVel);
m_Core.m_Vel = ClampVel(m_MoveRestrictions, TempVel);
}
}
}
@ -666,12 +656,12 @@ void CCharacter::HandleTiles(int Index)
m_MoveRestrictions = Collision()->GetMoveRestrictions(IsSwitchActiveCb, this, m_Pos);
// stopper
m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel);
if(m_MoveRestrictions&CANTMOVE_DOWN)
if(m_Core.m_Vel.y > 0 && (m_MoveRestrictions&CANTMOVE_DOWN))
{
m_Core.m_Jumped = 0;
m_Core.m_JumpedTotal = 0;
}
m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel);
if(!GameWorld()->m_WorldConfig.m_PredictTiles)
return;
@ -706,10 +696,12 @@ void CCharacter::HandleTiles(int Index)
if(((m_TileIndex == TILE_EHOOK_START) || (m_TileFIndex == TILE_EHOOK_START)) && !m_EndlessHook)
{
m_EndlessHook = true;
m_Core.m_EndlessHook = true;
}
else if(((m_TileIndex == TILE_EHOOK_END) || (m_TileFIndex == TILE_EHOOK_END)) && m_EndlessHook)
{
m_EndlessHook = false;
m_Core.m_EndlessHook = false;
}
// collide with others
@ -736,10 +728,12 @@ void CCharacter::HandleTiles(int Index)
if(((m_TileIndex == TILE_SUPER_START) || (m_TileFIndex == TILE_SUPER_START)) && !m_SuperJump)
{
m_SuperJump = true;
m_Core.m_EndlessJump = true;
}
else if(((m_TileIndex == TILE_SUPER_END) || (m_TileFIndex == TILE_SUPER_END)) && m_SuperJump)
{
m_SuperJump = false;
m_Core.m_EndlessJump = false;
}
// walljump
@ -757,10 +751,12 @@ void CCharacter::HandleTiles(int Index)
if(((m_TileIndex == TILE_JETPACK_START) || (m_TileFIndex == TILE_JETPACK_START)) && !m_Jetpack)
{
m_Jetpack = true;
m_Core.m_Jetpack = true;
}
else if(((m_TileIndex == TILE_JETPACK_END) || (m_TileFIndex == TILE_JETPACK_END)) && m_Jetpack)
{
m_Jetpack = false;
m_Core.m_Jetpack = false;
}
// solo part
@ -872,6 +868,8 @@ void CCharacter::DDRacePostCoreTick()
if (m_EndlessHook)
m_Core.m_HookTick = 0;
m_FrozenLastTick = false;
if (m_DeepFreeze && !m_Super)
Freeze();
@ -907,11 +905,6 @@ bool CCharacter::Freeze(int Seconds)
return false;
if (m_FreezeTick < GameWorld()->GameTick() - GameWorld()->GameTickSpeed() || Seconds == -1)
{
for(int i = 0; i < NUM_WEAPONS; i++)
if(m_aWeapons[i].m_Got)
{
m_aWeapons[i].m_Ammo = 0;
}
m_FreezeTime = Seconds == -1 ? Seconds : Seconds * GameWorld()->GameTickSpeed();
m_FreezeTick = GameWorld()->GameTick();
return true;
@ -928,26 +921,46 @@ bool CCharacter::UnFreeze()
{
if (m_FreezeTime > 0)
{
for(int i=0;i<NUM_WEAPONS;i++)
m_aWeapons[i].m_Ammo = -1;
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Got)
m_Core.m_ActiveWeapon = WEAPON_GUN;
m_FreezeTime = 0;
m_FreezeTick = 0;
if (m_Core.m_ActiveWeapon==WEAPON_HAMMER) m_ReloadTimer = 0;
m_FrozenLastTick = true;
return true;
}
return false;
}
void CCharacter::GiveWeapon(int Weapon, bool Remove)
{
if(Weapon == WEAPON_NINJA)
{
if(Remove)
RemoveNinja();
else
GiveNinja();
return;
}
if(Remove)
{
if(GetActiveWeapon() == Weapon)
SetActiveWeapon(WEAPON_GUN);
}
else
{
m_aWeapons[Weapon].m_Ammo = -1;
}
m_aWeapons[Weapon].m_Got = !Remove;
}
void CCharacter::GiveAllWeapons()
{
for(int i=WEAPON_GUN;i<NUM_WEAPONS-1;i++)
{
m_aWeapons[i].m_Got = true;
if(!m_FreezeTime) m_aWeapons[i].m_Ammo = -1;
GiveWeapon(i);
}
return;
}
CTeamsCore* CCharacter::TeamsCore()
@ -1001,6 +1014,7 @@ void CCharacter::ResetPrediction()
m_FreezeTime = 0;
m_FreezeTick = 0;
m_DeepFreeze = 0;
m_FrozenLastTick = false;
m_Super = false;
for(int w = 0; w < NUM_WEAPONS; w++)
{

View file

@ -55,7 +55,7 @@ public:
bool TakeDamage(vec2 Force, int Dmg, int From, int Weapon);
bool GiveWeapon(int Weapon, int Ammo);
void GiveWeapon(int Weapon, bool Remove = false);
void GiveNinja();
void RemoveNinja();
@ -77,6 +77,7 @@ public:
bool m_NinjaJetpack;
int m_FreezeTime;
int m_FreezeTick;
bool m_FrozenLastTick;
bool m_DeepFreeze;
bool m_EndlessHook;
enum

View file

@ -34,12 +34,9 @@ void CPickup::Tick()
{
if(pChr->GetWeaponGot(i))
{
if(!(pChr->m_FreezeTime && i == WEAPON_NINJA))
{
pChr->SetWeaponGot(i, false);
pChr->SetWeaponAmmo(i, 0);
sound = true;
}
pChr->SetWeaponGot(i, false);
pChr->SetWeaponAmmo(i, 0);
sound = true;
}
}
pChr->SetNinjaActivationDir(vec2(0,0));
@ -47,13 +44,13 @@ void CPickup::Tick()
pChr->SetNinjaCurrentMoveTime(0);
if (sound)
pChr->SetLastWeapon(WEAPON_GUN);
if(!pChr->m_FreezeTime && pChr->GetActiveWeapon() >= WEAPON_SHOTGUN)
if(pChr->GetActiveWeapon() >= WEAPON_SHOTGUN)
pChr->SetActiveWeapon(WEAPON_HAMMER);
break;
case POWERUP_WEAPON:
if(m_Subtype >= 0 && m_Subtype < NUM_WEAPONS && (!pChr->GetWeaponGot(m_Subtype) || (pChr->GetWeaponAmmo(m_Subtype) != -1 && !pChr->m_FreezeTime)))
pChr->GiveWeapon(m_Subtype, -1);
if(m_Subtype >= 0 && m_Subtype < NUM_WEAPONS && (!pChr->GetWeaponGot(m_Subtype) || pChr->GetWeaponAmmo(m_Subtype) != -1))
pChr->GiveWeapon(m_Subtype);
break;
case POWERUP_NINJA:

View file

@ -17,7 +17,6 @@ CProjectile::CProjectile
bool Explosive,
float Force,
int SoundImpact,
int Weapon,
int Layer,
int Number
)
@ -30,7 +29,6 @@ CProjectile::CProjectile
m_Owner = Owner;
m_Force = Force;
m_SoundImpact = SoundImpact;
m_Weapon = Weapon;
m_StartTick = GameWorld()->GameTick();
m_Explosive = Explosive;
@ -84,7 +82,7 @@ void CProjectile::Tick()
CCharacter *pTargetChr = GameWorld()->IntersectCharacter(PrevPos, ColPos, m_Freeze ? 1.0f : 6.0f, ColPos, pOwnerChar, m_Owner);
if(GameWorld()->m_WorldConfig.m_IsSolo && !(m_Weapon == WEAPON_SHOTGUN && GameWorld()->m_WorldConfig.m_IsDDRace))
if(GameWorld()->m_WorldConfig.m_IsSolo && !(m_Type == WEAPON_SHOTGUN && GameWorld()->m_WorldConfig.m_IsDDRace))
pTargetChr = 0;
if(m_LifeSpan > -1)
@ -106,9 +104,9 @@ void CProjectile::Tick()
if( ((pTargetChr && (pOwnerChar ? !(pOwnerChar->m_Hit&CCharacter::DISABLE_HIT_GRENADE) : g_Config.m_SvHit || m_Owner == -1 || pTargetChr == pOwnerChar)) || Collide || GameLayerClipped(CurPos)) && !isWeaponCollide)
{
if(m_Explosive && (!pTargetChr || (pTargetChr && (!m_Freeze || (m_Weapon == WEAPON_SHOTGUN && Collide)))))
if(m_Explosive && (!pTargetChr || (pTargetChr && (!m_Freeze || (m_Type == WEAPON_SHOTGUN && Collide)))))
{
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Weapon, m_Owner == -1, (!pTargetChr ? -1 : pTargetChr->Team()),
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pTargetChr ? -1 : pTargetChr->Team()),
(m_Owner != -1)? TeamMask : -1LL);
}
else if(pTargetChr && m_Freeze && ((m_Layer == LAYER_SWITCH && Collision()->m_pSwitchers[m_Number].m_Status[pTargetChr->Team()]) || m_Layer != LAYER_SWITCH))
@ -127,7 +125,7 @@ void CProjectile::Tick()
m_Direction.y = 0;
m_Pos += m_Direction;
}
else if (m_Weapon == WEAPON_GUN)
else if (m_Type == WEAPON_GUN)
{
GameWorld()->DestroyEntity(this);
}
@ -144,7 +142,7 @@ void CProjectile::Tick()
int64_t TeamMask = -1LL;
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Weapon, m_Owner == -1, (!pOwnerChar ? -1 : pOwnerChar->Team()),
GameWorld()->CreateExplosion(ColPos, m_Owner, m_Type, m_Owner == -1, (!pOwnerChar ? -1 : pOwnerChar->Team()),
(m_Owner != -1)? TeamMask : -1LL);
}
GameWorld()->DestroyEntity(this);
@ -170,20 +168,20 @@ CProjectile::CProjectile(CGameWorld *pGameWorld, int ID, CNetObj_Projectile *pPr
m_Bouncing = m_Freeze = 0;
m_Explosive = (pProj->m_Type == WEAPON_GRENADE) && (fabs(1.0f - length(m_Direction)) < 0.015f);
}
m_Type = m_Weapon = pProj->m_Type;
m_Type = pProj->m_Type;
m_StartTick = pProj->m_StartTick;
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0;
int Lifetime = 20 * GameWorld()->GameTickSpeed();
m_SoundImpact = -1;
if(m_Weapon == WEAPON_GRENADE)
if(m_Type == WEAPON_GRENADE)
{
Lifetime = GetTuning(m_TuneZone)->m_GrenadeLifetime * GameWorld()->GameTickSpeed();
m_SoundImpact = SOUND_GRENADE_EXPLODE;
}
else if(m_Weapon == WEAPON_GUN)
else if(m_Type == WEAPON_GUN)
Lifetime = GetTuning(m_TuneZone)->m_GunLifetime * GameWorld()->GameTickSpeed();
else if(m_Weapon == WEAPON_SHOTGUN && !GameWorld()->m_WorldConfig.m_IsDDRace)
else if(m_Type == WEAPON_SHOTGUN && !GameWorld()->m_WorldConfig.m_IsDDRace)
Lifetime = GetTuning(m_TuneZone)->m_ShotgunLifetime * GameWorld()->GameTickSpeed();
m_LifeSpan = Lifetime - (pGameWorld->GameTick() - m_StartTick);
m_ID = ID;
@ -232,7 +230,7 @@ void CProjectile::FillExtraInfo(CNetObj_Projectile *pProj)
bool CProjectile::Match(CProjectile *pProj)
{
if(pProj->m_Weapon != m_Weapon)
if(pProj->m_Type != m_Type)
return false;
if(pProj->m_StartTick != m_StartTick)
return false;

View file

@ -24,7 +24,6 @@ public:
bool Explosive,
float Force,
int SoundImpact,
int Weapon,
int Layer = 0,
int Number = 0
);
@ -50,7 +49,6 @@ private:
int m_Owner;
int m_Type;
int m_SoundImpact;
int m_Weapon;
float m_Force;
int m_StartTick;
bool m_Explosive;

View file

@ -156,11 +156,10 @@ void CGameWorld::RemoveEntity(CEntity *pEnt)
m_Core.m_apCharacters[ID] = 0;
}
}
pEnt->m_pParent = 0;
if(m_IsValidCopy && m_pParent && m_pParent->m_pChild == this)
if(pEnt->m_pParent)
pEnt->m_pParent->m_DestroyTick = GameTick();
if(m_IsValidCopy && m_pParent && m_pParent->m_pChild == this && pEnt->m_pParent)
pEnt->m_pParent->m_DestroyTick = GameTick();
pEnt->m_pParent = 0;
}
void CGameWorld::RemoveEntities()

View file

@ -592,13 +592,3 @@ bool CCharacterCore::IsSwitchActiveCb(int Number, void *pUser)
return pThis->Collision()->m_pSwitchers[Number].m_Status[pThis->m_pTeams->Team(pThis->m_Id)];
return false;
}
vec2 CCharacterCore::LimitVel(vec2 Vel)
{
return ClampVel(m_MoveRestrictions, Vel);
}
void CCharacterCore::ApplyForce(vec2 Force)
{
m_Vel = LimitVel(m_Vel + Force);
}

View file

@ -257,11 +257,6 @@ public:
int m_FreezeEnd;
bool m_DeepFrozen;
// Caps the given velocity according to the current set of stoppers
// that the character is affected by.
vec2 LimitVel(vec2 Vel);
void ApplyForce(vec2 Force);
private:
CTeamsCore *m_pTeams;