1/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
2#include "light.h"
3
4#include "character.h"
5
6#include <engine/server.h>
7
8#include <generated/protocol.h>
9
10#include <game/mapitems.h>
11#include <game/server/gamecontext.h>
12#include <game/server/player.h>
13#include <game/teamscore.h>
14
15CLight::CLight(CGameWorld *pGameWorld, vec2 Pos, float Rotation, int Length,
16 int Layer, int Number) :
17 CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER)
18{
19 m_To = vec2(0.0f, 0.0f);
20 m_Core = vec2(0.0f, 0.0f);
21 m_Layer = Layer;
22 m_Number = Number;
23 m_Tick = (Server()->TickSpeed() * 0.15f);
24 m_Pos = Pos;
25 m_Rotation = Rotation;
26 m_Length = Length;
27 m_EvalTick = Server()->Tick();
28 GameWorld()->InsertEntity(pEntity: this);
29 Step();
30}
31
32bool CLight::HitCharacter()
33{
34 std::vector<CCharacter *> vpHitCharacters = GameServer()->m_World.IntersectedCharacters(Pos0: m_Pos, Pos1: m_To, Radius: 0.0f, pNotThis: nullptr);
35 if(vpHitCharacters.empty())
36 return false;
37 for(auto *pChar : vpHitCharacters)
38 {
39 if(m_Layer == LAYER_SWITCH && m_Number > 0 && !Switchers()[m_Number].m_aStatus[pChar->Team()])
40 continue;
41 pChar->Freeze();
42 }
43 return true;
44}
45
46void CLight::Move()
47{
48 if(m_Speed != 0)
49 {
50 if((m_CurveLength >= m_Length && m_Speed > 0) || (m_CurveLength <= 0 && m_Speed < 0))
51 m_Speed = -m_Speed;
52 m_CurveLength += m_Speed * m_Tick + m_LengthL;
53 m_LengthL = 0;
54 if(m_CurveLength > m_Length)
55 {
56 m_LengthL = m_CurveLength - m_Length;
57 m_CurveLength = m_Length;
58 }
59 else if(m_CurveLength < 0)
60 {
61 m_LengthL = 0 + m_CurveLength;
62 m_CurveLength = 0;
63 }
64 }
65
66 m_Rotation += m_AngularSpeed * m_Tick;
67 if(m_Rotation > pi * 2)
68 m_Rotation -= pi * 2;
69 else if(m_Rotation < 0)
70 m_Rotation += pi * 2;
71}
72
73void CLight::Step()
74{
75 Move();
76 const vec2 Direction = vec2(std::sin(x: m_Rotation), std::cos(x: m_Rotation));
77 const vec2 NextPosition = m_Pos + normalize(v: Direction) * m_CurveLength;
78 GameServer()->Collision()->IntersectNoLaser(Pos0: m_Pos, Pos1: NextPosition, pOutCollision: &m_To, pOutBeforeCollision: nullptr);
79}
80
81void CLight::Reset()
82{
83 m_MarkedForDestroy = true;
84}
85
86void CLight::Tick()
87{
88 if(Server()->Tick() % (int)(Server()->TickSpeed() * 0.15f) == 0)
89 {
90 m_EvalTick = Server()->Tick();
91 GameServer()->Collision()->MoverSpeed(x: m_Pos.x, y: m_Pos.y, pSpeed: &m_Core);
92 m_Pos += m_Core;
93 Step();
94 }
95
96 HitCharacter();
97}
98
99void CLight::Snap(int SnappingClient)
100{
101 if(NetworkClipped(SnappingClient, CheckPos: m_Pos) && NetworkClipped(SnappingClient, CheckPos: m_To))
102 return;
103
104 int SnappingClientVersion = GameServer()->GetClientVersion(ClientId: SnappingClient);
105
106 CCharacter *pChr = GameServer()->GetPlayerChar(ClientId: SnappingClient);
107
108 if(SnappingClient != SERVER_DEMO_CLIENT && (GameServer()->m_apPlayers[SnappingClient]->GetTeam() == TEAM_SPECTATORS || GameServer()->m_apPlayers[SnappingClient]->IsPaused()) && GameServer()->m_apPlayers[SnappingClient]->SpectatorId() != SPEC_FREEVIEW)
109 pChr = GameServer()->GetPlayerChar(ClientId: GameServer()->m_apPlayers[SnappingClient]->SpectatorId());
110
111 vec2 From = m_Pos;
112 int StartTick = -1;
113
114 if(pChr && pChr->Team() == TEAM_SUPER)
115 {
116 From = m_Pos;
117 }
118 else if(pChr && m_Layer == LAYER_SWITCH && m_Number > 0 && Switchers()[m_Number].m_aStatus[pChr->Team()])
119 {
120 From = m_To;
121 }
122 // light on game and switch layer with a number 0 is always on
123 else if(m_Layer != LAYER_SWITCH || (m_Layer == LAYER_SWITCH && m_Number == 0))
124 {
125 From = m_To;
126 }
127
128 if(SnappingClientVersion < VERSION_DDNET_ENTITY_NETOBJS)
129 {
130 int Tick = (Server()->Tick() % Server()->TickSpeed()) % 6;
131 if(pChr && pChr->IsAlive() && m_Layer == LAYER_SWITCH && m_Number > 0 && !Switchers()[m_Number].m_aStatus[pChr->Team()] && Tick)
132 return;
133
134 StartTick = m_EvalTick;
135 if(StartTick < Server()->Tick() - 4)
136 StartTick = Server()->Tick() - 4;
137 else if(StartTick > Server()->Tick())
138 StartTick = Server()->Tick();
139 }
140
141 GameServer()->SnapLaserObject(Context: CSnapContext(SnappingClientVersion, Server()->IsSixup(ClientId: SnappingClient), SnappingClient), SnapId: GetId(),
142 To: m_Pos, From, StartTick, Owner: -1, LaserType: LASERTYPE_FREEZE, Subtype: 0, SwitchNumber: m_Number);
143}
144