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