1/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
2#include "plasma.h"
3
4#include "character.h"
5
6#include <engine/server.h>
7
8#include <generated/protocol.h>
9
10#include <game/server/gamecontext.h>
11#include <game/teamscore.h>
12
13const float PLASMA_ACCEL = 1.1f;
14
15CPlasma::CPlasma(CGameWorld *pGameWorld, vec2 Pos, vec2 Dir, bool Freeze,
16 bool Explosive, int ForClientId) :
17 CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER)
18{
19 m_Pos = Pos;
20 m_Core = Dir;
21 m_Freeze = Freeze;
22 m_Explosive = Explosive;
23 m_ForClientId = ForClientId;
24 m_EvalTick = Server()->Tick();
25 m_LifeTime = Server()->TickSpeed() * 1.5f;
26
27 GameWorld()->InsertEntity(pEntity: this);
28}
29
30void CPlasma::Tick()
31{
32 // A plasma bullet has only a limited lifetime
33 if(m_LifeTime == 0)
34 {
35 Reset();
36 return;
37 }
38 CCharacter *pTarget = GameServer()->GetPlayerChar(ClientId: m_ForClientId);
39 // Without a target, a plasma bullet has no reason to live
40 if(!pTarget)
41 {
42 Reset();
43 return;
44 }
45 m_LifeTime--;
46 Move();
47 HitCharacter(pTarget);
48 // Plasma bullets may explode twice if they would hit both a player and an obstacle in the next move step
49 HitObstacle(pTarget);
50}
51
52void CPlasma::Move()
53{
54 m_Pos += m_Core;
55 m_Core *= PLASMA_ACCEL;
56}
57
58bool CPlasma::HitCharacter(CCharacter *pTarget)
59{
60 vec2 IntersectPos;
61 CCharacter *pHitPlayer = GameServer()->m_World.IntersectCharacter(
62 Pos0: m_Pos, Pos1: m_Pos + m_Core, Radius: 0.0f, NewPos&: IntersectPos, pNotThis: nullptr, CollideWith: m_ForClientId);
63 if(!pHitPlayer)
64 {
65 return false;
66 }
67
68 // Super player should not be able to stop the plasma bullets
69 if(pHitPlayer->Team() == TEAM_SUPER)
70 {
71 return false;
72 }
73
74 m_Freeze ? pHitPlayer->Freeze() : pHitPlayer->UnFreeze();
75 if(m_Explosive)
76 {
77 // Plasma Turrets are very precise weapons only one tee gets speed from it,
78 // other tees near the explosion remain unaffected
79 GameServer()->CreateExplosion(
80 Pos: m_Pos, Owner: m_ForClientId, Weapon: WEAPON_GRENADE, NoDamage: true, ActivatedTeam: pTarget->Team(), Mask: pTarget->TeamMask());
81 }
82 Reset();
83 return true;
84}
85
86bool CPlasma::HitObstacle(CCharacter *pTarget)
87{
88 // Check if the plasma bullet is stopped by a solid block or a laser stopper
89 int HasIntersection = GameServer()->Collision()->IntersectNoLaser(Pos0: m_Pos, Pos1: m_Pos + m_Core, pOutCollision: nullptr, pOutBeforeCollision: nullptr);
90 if(HasIntersection)
91 {
92 if(m_Explosive)
93 {
94 // Even in the case of an explosion due to a collision with obstacles, only one player is affected
95 GameServer()->CreateExplosion(
96 Pos: m_Pos, Owner: m_ForClientId, Weapon: WEAPON_GRENADE, NoDamage: true, ActivatedTeam: pTarget->Team(), Mask: pTarget->TeamMask());
97 }
98 Reset();
99 return true;
100 }
101 return false;
102}
103
104void CPlasma::Reset()
105{
106 m_MarkedForDestroy = true;
107}
108
109void CPlasma::Snap(int SnappingClient)
110{
111 // Only players who can see the targeted player can see the plasma bullet
112 CCharacter *pTarget = GameServer()->GetPlayerChar(ClientId: m_ForClientId);
113 if(!pTarget || !pTarget->CanSnapCharacter(SnappingClient))
114 {
115 return;
116 }
117
118 // Only players with the plasma bullet in their field of view or who want to see everything will receive the snap
119 if(NetworkClipped(SnappingClient))
120 return;
121
122 int SnappingClientVersion = GameServer()->GetClientVersion(ClientId: SnappingClient);
123
124 int Subtype = (m_Explosive ? 1 : 0) | (m_Freeze ? 2 : 0);
125 GameServer()->SnapLaserObject(Context: CSnapContext(SnappingClientVersion, Server()->IsSixup(ClientId: SnappingClient), SnappingClient), SnapId: GetId(),
126 To: m_Pos, From: m_Pos, StartTick: m_EvalTick, Owner: m_ForClientId, LaserType: LASERTYPE_PLASMA, Subtype, SwitchNumber: m_Number);
127}
128
129void CPlasma::SwapClients(int Client1, int Client2)
130{
131 m_ForClientId = m_ForClientId == Client1 ? Client2 : (m_ForClientId == Client2 ? Client1 : m_ForClientId);
132}
133