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 | |
14 | CLight::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 | |
31 | bool 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 | |
45 | void 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 | |
72 | void 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 | |
80 | void CLight::Reset() |
81 | { |
82 | m_MarkedForDestroy = true; |
83 | } |
84 | |
85 | void 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 | |
104 | void 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 | |