ddnet/src/game/server/entities/dragger_beam.cpp

127 lines
3.4 KiB
C++
Raw Normal View History

2022-05-02 18:31:17 +00:00
/* See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
#include "dragger_beam.h"
#include "character.h"
#include "dragger.h"
2022-05-02 18:31:17 +00:00
#include <engine/config.h>
#include <engine/server.h>
#include <game/generated/protocol.h>
#include <game/server/gamecontext.h>
#include <game/server/gamemodes/DDRace.h>
#include <game/server/player.h>
#include <game/server/teams.h>
CDraggerBeam::CDraggerBeam(CGameWorld *pGameWorld, CDragger *pDragger, vec2 Pos, float Strength, bool IgnoreWalls,
int ForClientID, int Layer, int Number) :
2022-05-02 18:31:17 +00:00
CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER)
{
m_pDragger = pDragger;
m_Pos = Pos;
m_Strength = Strength;
m_IgnoreWalls = IgnoreWalls;
2022-05-02 18:31:17 +00:00
m_ForClientID = ForClientID;
m_Active = true;
m_Layer = Layer;
m_Number = Number;
2022-05-02 18:31:17 +00:00
m_EvalTick = Server()->Tick();
GameWorld()->InsertEntity(this);
2022-05-02 18:31:17 +00:00
}
void CDraggerBeam::Tick()
{
if(!m_Active)
{
return;
}
// Drag only if the player is reachable and alive
CCharacter *pTarget = GameServer()->GetPlayerChar(m_ForClientID);
if(!pTarget)
{
Reset();
return;
}
// The following checks are necessary, because the checks in CDragger::LookForPlayersToDrag only take place every 150ms
// When the dragger is disabled for the target player's team, the dragger beam dissolves
if(m_Layer == LAYER_SWITCH && m_Number > 0 &&
!GameServer()->Collision()->m_pSwitchers[m_Number].m_Status[pTarget->Team()])
{
Reset();
return;
}
// When the dragger can no longer reach the target player, the dragger beam dissolves
2022-05-02 18:31:17 +00:00
int IsReachable =
m_IgnoreWalls ?
!GameServer()->Collision()->IntersectNoLaserNW(m_Pos, pTarget->m_Pos, 0, 0) :
!GameServer()->Collision()->IntersectNoLaser(m_Pos, pTarget->m_Pos, 0, 0);
if(!IsReachable ||
2022-05-16 14:24:18 +00:00
distance(pTarget->m_Pos, m_Pos) >= g_Config.m_SvDraggerRange || !pTarget->IsAlive())
2022-05-02 18:31:17 +00:00
{
Reset();
return;
}
// In the center of the dragger a tee does not experience speed-up
else if(distance(pTarget->m_Pos, m_Pos) > 28)
2022-05-02 18:31:17 +00:00
{
vec2 Temp = pTarget->Core()->m_Vel + (normalize(m_Pos - pTarget->m_Pos) * m_Strength);
pTarget->Core()->m_Vel = ClampVel(pTarget->m_MoveRestrictions, Temp);
}
}
void CDraggerBeam::SetPos(vec2 Pos)
{
m_Pos = Pos;
}
void CDraggerBeam::Reset()
{
m_MarkedForDestroy = true;
m_Active = false;
m_pDragger->RemoveDraggerBeam(m_ForClientID);
}
2022-05-02 18:31:17 +00:00
void CDraggerBeam::Snap(int SnappingClient)
{
if(!m_Active)
{
return;
}
// Only players who can see the player attached to the dragger can see the dragger beam
2022-05-02 18:31:17 +00:00
CCharacter *pTarget = GameServer()->GetPlayerChar(m_ForClientID);
2022-05-25 14:27:19 +00:00
if(!pTarget || !pTarget->CanSnapCharacter(SnappingClient))
2022-05-02 18:31:17 +00:00
{
return;
}
// Only players with the dragger beam in their field of view or who want to see everything will receive the snap
vec2 TargetPos = vec2(pTarget->m_Pos.x, pTarget->m_Pos.y);
if(distance(pTarget->m_Pos, m_Pos) >= g_Config.m_SvDraggerRange || NetworkClippedLine(SnappingClient, m_Pos, TargetPos))
2022-05-02 18:31:17 +00:00
{
return;
}
CNetObj_Laser *obj = static_cast<CNetObj_Laser *>(
Server()->SnapNewItem(NETOBJTYPE_LASER, GetID(), sizeof(CNetObj_Laser)));
if(!obj)
{
return;
}
obj->m_X = (int)m_Pos.x;
obj->m_Y = (int)m_Pos.y;
obj->m_FromX = (int)TargetPos.x;
obj->m_FromY = (int)TargetPos.y;
int StartTick = m_EvalTick;
if(StartTick < Server()->Tick() - 4)
{
StartTick = Server()->Tick() - 4;
}
else if(StartTick > Server()->Tick())
{
StartTick = Server()->Tick();
}
obj->m_StartTick = StartTick;
}