Merge pull request #7839 from infclass/kaffeine/fix-move-restrictions-incapsulation

Character: Fix m_MoveRestrictions and m_Core incapsulation
This commit is contained in:
Dennis Felsing 2024-01-21 22:40:22 +00:00 committed by GitHub
commit 50dc9de991
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 145 additions and 53 deletions

View file

@ -546,6 +546,19 @@ void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput)); mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
} }
void CCharacter::ReleaseHook()
{
m_Core.SetHookedPlayer(-1);
m_Core.m_HookState = HOOK_RETRACTED;
m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
}
void CCharacter::ResetHook()
{
ReleaseHook();
m_Core.m_HookPos = m_Core.m_Pos;
}
void CCharacter::ResetInput() void CCharacter::ResetInput()
{ {
m_Input.m_Direction = 0; m_Input.m_Direction = 0;
@ -1105,6 +1118,33 @@ void CCharacter::GiveAllWeapons()
} }
} }
void CCharacter::ResetVelocity()
{
m_Core.m_Vel = vec2(0, 0);
}
// The method is needed only to reproduce 'shotgun bug' ddnet#5258
// Use SetVelocity() instead.
void CCharacter::SetVelocity(const vec2 NewVelocity)
{
m_Core.m_Vel = ClampVel(m_MoveRestrictions, NewVelocity);
}
void CCharacter::SetRawVelocity(const vec2 NewVelocity)
{
m_Core.m_Vel = NewVelocity;
}
void CCharacter::AddVelocity(const vec2 Addition)
{
SetVelocity(m_Core.m_Vel + Addition);
}
void CCharacter::ApplyMoveRestrictions()
{
m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel);
}
CTeamsCore *CCharacter::TeamsCore() CTeamsCore *CCharacter::TeamsCore()
{ {
return GameWorld()->Teams(); return GameWorld()->Teams();

View file

@ -51,6 +51,8 @@ public:
void OnPredictedInput(CNetObj_PlayerInput *pNewInput); void OnPredictedInput(CNetObj_PlayerInput *pNewInput);
void OnDirectInput(CNetObj_PlayerInput *pNewInput); void OnDirectInput(CNetObj_PlayerInput *pNewInput);
void ReleaseHook();
void ResetHook();
void ResetInput(); void ResetInput();
void FireWeapon(); void FireWeapon();
@ -60,6 +62,12 @@ public:
void GiveNinja(); void GiveNinja();
void RemoveNinja(); void RemoveNinja();
void ResetVelocity();
void SetVelocity(vec2 NewVelocity);
void SetRawVelocity(vec2 NewVelocity);
void AddVelocity(vec2 Addition);
void ApplyMoveRestrictions();
bool m_IsLocal; bool m_IsLocal;
CTeamsCore *TeamsCore(); CTeamsCore *TeamsCore();
@ -81,7 +89,6 @@ public:
int m_TileIndex; int m_TileIndex;
int m_TileFIndex; int m_TileFIndex;
int m_MoveRestrictions;
bool m_LastRefillJumps; bool m_LastRefillJumps;
// Setters/Getters because i don't want to modify vanilla vars access modifiers // Setters/Getters because i don't want to modify vanilla vars access modifiers
@ -91,7 +98,7 @@ public:
void SetActiveWeapon(int ActiveWeap); void SetActiveWeapon(int ActiveWeap);
CCharacterCore GetCore() { return m_Core; } CCharacterCore GetCore() { return m_Core; }
void SetCore(CCharacterCore Core) { m_Core = Core; } void SetCore(CCharacterCore Core) { m_Core = Core; }
CCharacterCore *Core() { return &m_Core; } const CCharacterCore *Core() const { return &m_Core; }
bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; } bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; }
void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; } void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; }
int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; } int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; }
@ -145,6 +152,8 @@ private:
int m_ReloadTimer; int m_ReloadTimer;
int m_AttackTick; int m_AttackTick;
int m_MoveRestrictions;
// these are non-heldback inputs // these are non-heldback inputs
CNetObj_PlayerInput m_LatestPrevInput; CNetObj_PlayerInput m_LatestPrevInput;
CNetObj_PlayerInput m_LatestInput; CNetObj_PlayerInput m_LatestInput;

View file

@ -124,8 +124,7 @@ void CDragger::DraggerBeamTick()
// In the center of the dragger a tee does not experience speed-up // In the center of the dragger a tee does not experience speed-up
else if(distance(pTarget->m_Pos, m_Pos) > 28) else if(distance(pTarget->m_Pos, m_Pos) > 28)
{ {
vec2 Temp = pTarget->Core()->m_Vel + (normalize(m_Pos - pTarget->m_Pos) * m_Strength); pTarget->AddVelocity(normalize(m_Pos - pTarget->m_Pos) * m_Strength);
pTarget->Core()->m_Vel = ClampVel(pTarget->m_MoveRestrictions, Temp);
} }
} }

View file

@ -47,36 +47,39 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
m_Energy = -1; m_Energy = -1;
if(m_Type == WEAPON_SHOTGUN) if(m_Type == WEAPON_SHOTGUN)
{ {
vec2 Temp; float Strength;
float Strength = GetTuning(m_TuneZone)->m_ShotgunStrength; if(!m_TuneZone)
Strength = Tuning()->m_ShotgunStrength;
else
Strength = TuningList()[m_TuneZone].m_ShotgunStrength;
const vec2 &HitPos = pHit->Core()->m_Pos; const vec2 &HitPos = pHit->Core()->m_Pos;
if(!g_Config.m_SvOldLaser) if(!g_Config.m_SvOldLaser)
{ {
if(m_PrevPos != HitPos) if(m_PrevPos != HitPos)
{ {
Temp = pHit->Core()->m_Vel + normalize(m_PrevPos - HitPos) * Strength; pHit->AddVelocity(normalize(m_PrevPos - HitPos) * Strength);
pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp);
} }
else else
{ {
pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; pHit->SetRawVelocity(StackedLaserShotgunBugSpeed);
} }
} }
else if(g_Config.m_SvOldLaser && pOwnerChar) else if(g_Config.m_SvOldLaser && pOwnerChar)
{ {
if(pOwnerChar->Core()->m_Pos != HitPos) if(pOwnerChar->Core()->m_Pos != HitPos)
{ {
Temp = pHit->Core()->m_Vel + normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength; pHit->AddVelocity(normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength);
pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp);
} }
else else
{ {
pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; pHit->SetRawVelocity(StackedLaserShotgunBugSpeed);
} }
} }
else else
{ {
pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, pHit->Core()->m_Vel); // Re-apply move restrictions as a part of 'shotgun bug' reproduction
pHit->ApplyMoveRestrictions();
} }
} }
else if(m_Type == WEAPON_LASER) else if(m_Type == WEAPON_LASER)

View file

@ -116,7 +116,7 @@ void CGameWorld::InsertEntity(CEntity *pEnt, bool Last)
if(ID >= 0 && ID < MAX_CLIENTS) if(ID >= 0 && ID < MAX_CLIENTS)
{ {
m_apCharacters[ID] = pChar; m_apCharacters[ID] = pChar;
m_Core.m_apCharacters[ID] = pChar->Core(); m_Core.m_apCharacters[ID] = &pChar->m_Core;
} }
pChar->SetCoreWorld(this); pChar->SetCoreWorld(this);
} }
@ -309,12 +309,9 @@ void CGameWorld::ReleaseHooked(int ClientID)
CCharacter *pChr = (CCharacter *)CGameWorld::FindFirst(CGameWorld::ENTTYPE_CHARACTER); CCharacter *pChr = (CCharacter *)CGameWorld::FindFirst(CGameWorld::ENTTYPE_CHARACTER);
for(; pChr; pChr = (CCharacter *)pChr->TypeNext()) for(; pChr; pChr = (CCharacter *)pChr->TypeNext())
{ {
CCharacterCore *pCore = pChr->Core(); if(pChr->Core()->HookedPlayer() == ClientID && !pChr->IsSuper())
if(pCore->HookedPlayer() == ClientID)
{ {
pCore->SetHookedPlayer(-1); pChr->ReleaseHook();
pCore->m_HookState = HOOK_RETRACTED;
pCore->m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
} }
} }
} }
@ -557,7 +554,7 @@ void CGameWorld::NetObjEnd()
if(pHookedChar->m_MarkedForDestroy) if(pHookedChar->m_MarkedForDestroy)
{ {
pHookedChar->m_Pos = pHookedChar->m_Core.m_Pos = pChar->m_Core.m_HookPos; pHookedChar->m_Pos = pHookedChar->m_Core.m_Pos = pChar->m_Core.m_HookPos;
pHookedChar->m_Core.m_Vel = vec2(0, 0); pHookedChar->ResetVelocity();
mem_zero(&pHookedChar->m_SavedInput, sizeof(pHookedChar->m_SavedInput)); mem_zero(&pHookedChar->m_SavedInput, sizeof(pHookedChar->m_SavedInput));
pHookedChar->m_SavedInput.m_TargetY = -1; pHookedChar->m_SavedInput.m_TargetY = -1;
pHookedChar->m_KeepHooked = true; pHookedChar->m_KeepHooked = true;
@ -577,7 +574,7 @@ void CGameWorld::NetObjEnd()
if(ID >= 0 && ID < MAX_CLIENTS) if(ID >= 0 && ID < MAX_CLIENTS)
{ {
m_apCharacters[ID] = pChar; m_apCharacters[ID] = pChar;
m_Core.m_apCharacters[ID] = pChar->Core(); m_Core.m_apCharacters[ID] = &pChar->m_Core;
} }
} }
} }

View file

@ -1593,7 +1593,7 @@ void CGameContext::ConTeleTo(IConsole::IResult *pResult, void *pUserData)
// Teleport tee // Teleport tee
pSelf->Teleport(pCallingCharacter, Pos); pSelf->Teleport(pCallingCharacter, Pos);
pCallingCharacter->UnFreeze(); pCallingCharacter->UnFreeze();
pCallingCharacter->Core()->m_Vel = vec2(0, 0); pCallingCharacter->ResetVelocity();
pCallingPlayer->m_LastTeleTee.Save(pCallingCharacter); pCallingPlayer->m_LastTeleTee.Save(pCallingCharacter);
} }
@ -1670,7 +1670,7 @@ void CGameContext::ConTeleXY(IConsole::IResult *pResult, void *pUserData)
// Teleport tee // Teleport tee
pSelf->Teleport(pCallingCharacter, Pos); pSelf->Teleport(pCallingCharacter, Pos);
pCallingCharacter->UnFreeze(); pCallingCharacter->UnFreeze();
pCallingCharacter->Core()->m_Vel = vec2(0, 0); pCallingCharacter->ResetVelocity();
pCallingPlayer->m_LastTeleTee.Save(pCallingCharacter); pCallingPlayer->m_LastTeleTee.Save(pCallingCharacter);
} }
@ -1722,7 +1722,7 @@ void CGameContext::ConTeleCursor(IConsole::IResult *pResult, void *pUserData)
} }
pSelf->Teleport(pChr, Pos); pSelf->Teleport(pChr, Pos);
pChr->UnFreeze(); pChr->UnFreeze();
pChr->Core()->m_Vel = vec2(0, 0); pChr->ResetVelocity();
pPlayer->m_LastTeleTee.Save(pChr); pPlayer->m_LastTeleTee.Save(pChr);
} }

View file

@ -77,8 +77,7 @@ void CGameContext::MoveCharacter(int ClientID, int X, int Y, bool Raw)
if(!pChr) if(!pChr)
return; return;
pChr->Core()->m_Pos.x += ((Raw) ? 1 : 32) * X; pChr->Move(vec2((Raw ? 1 : 32) * X, Raw ? 1 : 32) * Y);
pChr->Core()->m_Pos.y += ((Raw) ? 1 : 32) * Y;
pChr->m_DDRaceState = DDRACE_CHEAT; pChr->m_DDRaceState = DDRACE_CHEAT;
} }
@ -348,7 +347,7 @@ void CGameContext::ModifyWeapons(IConsole::IResult *pResult, void *pUserData,
void CGameContext::Teleport(CCharacter *pChr, vec2 Pos) void CGameContext::Teleport(CCharacter *pChr, vec2 Pos)
{ {
pChr->Core()->m_Pos = Pos; pChr->SetPosition(Pos);
pChr->m_Pos = Pos; pChr->m_Pos = Pos;
pChr->m_PrevPos = Pos; pChr->m_PrevPos = Pos;
pChr->m_DDRaceState = DDRACE_CHEAT; pChr->m_DDRaceState = DDRACE_CHEAT;
@ -412,7 +411,7 @@ void CGameContext::ConTeleport(IConsole::IResult *pResult, void *pUserData)
} }
pSelf->Teleport(pChr, Pos); pSelf->Teleport(pChr, Pos);
pChr->UnFreeze(); pChr->UnFreeze();
pChr->Core()->m_Vel = vec2(0, 0); pChr->SetVelocity(vec2(0, 0));
} }
} }

View file

@ -262,7 +262,7 @@ void CCharacter::HandleNinja()
Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(GetProximityRadius(), GetProximityRadius()), GroundElasticity); Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(GetProximityRadius(), GetProximityRadius()), GroundElasticity);
// reset velocity so the client doesn't predict stuff // reset velocity so the client doesn't predict stuff
m_Core.m_Vel = vec2(0.f, 0.f); ResetVelocity();
// check if we Hit anything along the way // check if we Hit anything along the way
{ {
@ -698,11 +698,16 @@ void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput)); mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
} }
void CCharacter::ResetHook() void CCharacter::ReleaseHook()
{ {
m_Core.SetHookedPlayer(-1); m_Core.SetHookedPlayer(-1);
m_Core.m_HookState = HOOK_RETRACTED; m_Core.m_HookState = HOOK_RETRACTED;
m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT; m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
}
void CCharacter::ResetHook()
{
ReleaseHook();
m_Core.m_HookPos = m_Core.m_Pos; m_Core.m_HookPos = m_Core.m_Pos;
} }
@ -1640,7 +1645,7 @@ void CCharacter::HandleTiles(int Index)
m_Core.m_Jumped = 0; m_Core.m_Jumped = 0;
m_Core.m_JumpedTotal = 0; m_Core.m_JumpedTotal = 0;
} }
m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel); ApplyMoveRestrictions();
// handle switch tiles // handle switch tiles
if(Collision()->GetSwitchType(MapIndex) == TILE_SWITCHOPEN && Team() != TEAM_SUPER && Collision()->GetSwitchNumber(MapIndex) > 0) if(Collision()->GetSwitchType(MapIndex) == TILE_SWITCHOPEN && Team() != TEAM_SUPER && Collision()->GetSwitchNumber(MapIndex) > 0)
@ -2357,6 +2362,43 @@ CClientMask CCharacter::TeamMask()
return Teams()->TeamMask(Team(), -1, GetPlayer()->GetCID()); return Teams()->TeamMask(Team(), -1, GetPlayer()->GetCID());
} }
void CCharacter::SetPosition(const vec2 &Position)
{
m_Core.m_Pos = Position;
}
void CCharacter::Move(vec2 RelPos)
{
m_Core.m_Pos += RelPos;
}
void CCharacter::ResetVelocity()
{
m_Core.m_Vel = vec2(0, 0);
}
void CCharacter::SetVelocity(vec2 NewVelocity)
{
m_Core.m_Vel = ClampVel(m_MoveRestrictions, NewVelocity);
}
// The method is needed only to reproduce 'shotgun bug' ddnet#5258
// Use SetVelocity() instead.
void CCharacter::SetRawVelocity(vec2 NewVelocity)
{
m_Core.m_Vel = NewVelocity;
}
void CCharacter::AddVelocity(vec2 Addition)
{
SetVelocity(m_Core.m_Vel + Addition);
}
void CCharacter::ApplyMoveRestrictions()
{
m_Core.m_Vel = ClampVel(m_MoveRestrictions, m_Core.m_Vel);
}
void CCharacter::SwapClients(int Client1, int Client2) void CCharacter::SwapClients(int Client1, int Client2)
{ {
const int HookedPlayer = m_Core.HookedPlayer(); const int HookedPlayer = m_Core.HookedPlayer();

View file

@ -60,6 +60,7 @@ public:
void OnPredictedInput(CNetObj_PlayerInput *pNewInput); void OnPredictedInput(CNetObj_PlayerInput *pNewInput);
void OnDirectInput(CNetObj_PlayerInput *pNewInput); void OnDirectInput(CNetObj_PlayerInput *pNewInput);
void ReleaseHook();
void ResetHook(); void ResetHook();
void ResetInput(); void ResetInput();
void FireWeapon(); void FireWeapon();
@ -88,6 +89,15 @@ public:
class CPlayer *GetPlayer() { return m_pPlayer; } class CPlayer *GetPlayer() { return m_pPlayer; }
CClientMask TeamMask(); CClientMask TeamMask();
void SetPosition(const vec2 &Position);
void Move(vec2 RelPos);
void ResetVelocity();
void SetVelocity(vec2 NewVelocity);
void SetRawVelocity(vec2 NewVelocity);
void AddVelocity(vec2 Addition);
void ApplyMoveRestrictions();
private: private:
// player controlling this character // player controlling this character
class CPlayer *m_pPlayer; class CPlayer *m_pPlayer;
@ -106,6 +116,8 @@ private:
int m_ReloadTimer; int m_ReloadTimer;
int m_AttackTick; int m_AttackTick;
int m_MoveRestrictions;
int m_DamageTaken; int m_DamageTaken;
int m_EmoteType; int m_EmoteType;
@ -201,8 +213,6 @@ public:
int m_TileIndex; int m_TileIndex;
int m_TileFIndex; int m_TileFIndex;
int m_MoveRestrictions;
int64_t m_LastStartWarning; int64_t m_LastStartWarning;
int64_t m_LastRescue; int64_t m_LastRescue;
bool m_LastRefillJumps; bool m_LastRefillJumps;
@ -226,7 +236,7 @@ public:
void SetArmor(int Armor) { m_Armor = Armor; } void SetArmor(int Armor) { m_Armor = Armor; }
CCharacterCore GetCore() { return m_Core; } CCharacterCore GetCore() { return m_Core; }
void SetCore(CCharacterCore Core) { m_Core = Core; } void SetCore(CCharacterCore Core) { m_Core = Core; }
CCharacterCore *Core() { return &m_Core; } const CCharacterCore *Core() const { return &m_Core; }
bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; } bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; }
void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; } void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; }
int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; } int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; }

View file

@ -71,8 +71,7 @@ void CDraggerBeam::Tick()
// In the center of the dragger a tee does not experience speed-up // In the center of the dragger a tee does not experience speed-up
else if(distance(pTarget->m_Pos, m_Pos) > 28) else if(distance(pTarget->m_Pos, m_Pos) > 28)
{ {
vec2 Temp = pTarget->Core()->m_Vel + (normalize(m_Pos - pTarget->m_Pos) * m_Strength); pTarget->AddVelocity(normalize(m_Pos - pTarget->m_Pos) * m_Strength);
pTarget->Core()->m_Vel = ClampVel(pTarget->m_MoveRestrictions, Temp);
} }
} }

View file

@ -44,9 +44,9 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
bool pDontHitSelf = g_Config.m_SvOldLaser || (m_Bounces == 0 && !m_WasTele); bool pDontHitSelf = g_Config.m_SvOldLaser || (m_Bounces == 0 && !m_WasTele);
if(pOwnerChar ? (!pOwnerChar->LaserHitDisabled() && m_Type == WEAPON_LASER) || (!pOwnerChar->ShotgunHitDisabled() && m_Type == WEAPON_SHOTGUN) : g_Config.m_SvHit) if(pOwnerChar ? (!pOwnerChar->LaserHitDisabled() && m_Type == WEAPON_LASER) || (!pOwnerChar->ShotgunHitDisabled() && m_Type == WEAPON_SHOTGUN) : g_Config.m_SvHit)
pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner); pHit = GameWorld()->IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner);
else else
pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner, pOwnerChar); pHit = GameWorld()->IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner, pOwnerChar);
if(!pHit || (pHit == pOwnerChar && g_Config.m_SvOldLaser) || (pHit != pOwnerChar && pOwnerChar ? (pOwnerChar->LaserHitDisabled() && m_Type == WEAPON_LASER) || (pOwnerChar->ShotgunHitDisabled() && m_Type == WEAPON_SHOTGUN) : !g_Config.m_SvHit)) if(!pHit || (pHit == pOwnerChar && g_Config.m_SvOldLaser) || (pHit != pOwnerChar && pOwnerChar ? (pOwnerChar->LaserHitDisabled() && m_Type == WEAPON_LASER) || (pOwnerChar->ShotgunHitDisabled() && m_Type == WEAPON_SHOTGUN) : !g_Config.m_SvHit))
return false; return false;
@ -55,42 +55,39 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
m_Energy = -1; m_Energy = -1;
if(m_Type == WEAPON_SHOTGUN) if(m_Type == WEAPON_SHOTGUN)
{ {
vec2 Temp;
float Strength; float Strength;
if(!m_TuneZone) if(!m_TuneZone)
Strength = Tuning()->m_ShotgunStrength; Strength = Tuning()->m_ShotgunStrength;
else else
Strength = TuningList()[m_TuneZone].m_ShotgunStrength; Strength = TuningList()[m_TuneZone].m_ShotgunStrength;
vec2 &HitPos = pHit->Core()->m_Pos; const vec2 &HitPos = pHit->Core()->m_Pos;
if(!g_Config.m_SvOldLaser) if(!g_Config.m_SvOldLaser)
{ {
if(m_PrevPos != HitPos) if(m_PrevPos != HitPos)
{ {
Temp = pHit->Core()->m_Vel + normalize(m_PrevPos - HitPos) * Strength; pHit->AddVelocity(normalize(m_PrevPos - HitPos) * Strength);
pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp);
} }
else else
{ {
pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; pHit->SetRawVelocity(StackedLaserShotgunBugSpeed);
} }
} }
else if(g_Config.m_SvOldLaser && pOwnerChar) else if(g_Config.m_SvOldLaser && pOwnerChar)
{ {
if(pOwnerChar->Core()->m_Pos != HitPos) if(pOwnerChar->Core()->m_Pos != HitPos)
{ {
Temp = pHit->Core()->m_Vel + normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength; pHit->AddVelocity(normalize(pOwnerChar->Core()->m_Pos - HitPos) * Strength);
pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp);
} }
else else
{ {
pHit->Core()->m_Vel = StackedLaserShotgunBugSpeed; pHit->SetRawVelocity(StackedLaserShotgunBugSpeed);
} }
} }
else else
{ {
pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, pHit->Core()->m_Vel); // Re-apply move restrictions as a part of 'shotgun bug' reproduction
pHit->ApplyMoveRestrictions();
} }
} }
else if(m_Type == WEAPON_LASER) else if(m_Type == WEAPON_LASER)

View file

@ -361,12 +361,9 @@ void CGameWorld::ReleaseHooked(int ClientID)
CCharacter *pChr = (CCharacter *)CGameWorld::FindFirst(CGameWorld::ENTTYPE_CHARACTER); CCharacter *pChr = (CCharacter *)CGameWorld::FindFirst(CGameWorld::ENTTYPE_CHARACTER);
for(; pChr; pChr = (CCharacter *)pChr->TypeNext()) for(; pChr; pChr = (CCharacter *)pChr->TypeNext())
{ {
CCharacterCore *pCore = pChr->Core(); if(pChr->Core()->HookedPlayer() == ClientID && !pChr->IsSuper())
if(pCore->HookedPlayer() == ClientID && !pChr->IsSuper())
{ {
pCore->SetHookedPlayer(-1); pChr->ReleaseHook();
pCore->m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
pCore->m_HookState = HOOK_RETRACTED;
} }
} }
} }