1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "Projectile.h"
4 #include "Map/MapInfo.h"
5 #include "Rendering/Colors.h"
6 #include "Rendering/GL/VertexArray.h"
7 #include "Sim/Projectiles/ProjectileHandler.h"
8 #include "Sim/Misc/QuadField.h"
9 #include "Sim/Units/Unit.h"
10 #include "Sim/Units/UnitHandler.h"
11 #include "System/Matrix44f.h"
12
13 CR_BIND_DERIVED(CProjectile, CExpGenSpawnable, )
14
15 CR_REG_METADATA(CProjectile,
16 (
17 CR_MEMBER(synced),
18 CR_MEMBER(weapon),
19 CR_MEMBER(piece),
20 CR_MEMBER(hitscan),
21
22 CR_MEMBER(luaMoveCtrl),
23 CR_MEMBER(checkCol),
24 CR_MEMBER(ignoreWater),
25 CR_MEMBER(deleteMe),
26
27 CR_MEMBER(castShadow),
28 CR_MEMBER(drawSorted),
29
30 CR_MEMBER_BEGINFLAG(CM_Config),
31 CR_MEMBER(dir),
32 CR_MEMBER_ENDFLAG(CM_Config),
33 CR_MEMBER(drawPos),
34
35 CR_MEMBER(mygravity),
36 CR_IGNORED(sortDist),
37
38 CR_MEMBER(ownerID),
39 CR_MEMBER(teamID),
40 CR_MEMBER(cegID),
41
42 CR_MEMBER(projectileType),
43 CR_MEMBER(collisionFlags),
44
45 CR_MEMBER(qfCellData)
46 ))
47
48 CR_BIND(CProjectile::QuadFieldCellData, )
49
50
51
52 //////////////////////////////////////////////////////////////////////
53 // Construction/Destruction
54 //////////////////////////////////////////////////////////////////////
55 bool CProjectile::inArray = false;
56 CVertexArray* CProjectile::va = NULL;
57
58
CProjectile()59 CProjectile::CProjectile()
60 : synced(false)
61 , weapon(false)
62 , piece(false)
63 , hitscan(false)
64
65 , luaMoveCtrl(false)
66 , checkCol(true)
67 , ignoreWater(false)
68 , deleteMe(false)
69
70 , castShadow(false)
71 , drawSorted(true)
72
73 , mygravity(mapInfo? mapInfo->map.gravity: 0.0f)
74
75 , ownerID(-1u)
76 , teamID(-1u)
77 , cegID(-1u)
78
79 , projectileType(-1u)
80 , collisionFlags(0)
81 {
82 }
83
CProjectile(const float3 & pos,const float3 & spd,const CUnit * owner,bool isSynced,bool isWeapon,bool isPiece,bool isHitScan)84 CProjectile::CProjectile(
85 const float3& pos,
86 const float3& spd,
87 const CUnit* owner,
88 bool isSynced,
89 bool isWeapon,
90 bool isPiece,
91 bool isHitScan
92 ): CExpGenSpawnable(pos, spd)
93
94 , synced(isSynced)
95 , weapon(isWeapon)
96 , piece(isPiece)
97 , hitscan(isHitScan)
98
99 , luaMoveCtrl(false)
100 , checkCol(true)
101 , ignoreWater(false)
102 , deleteMe(false)
103
104 , castShadow(false)
105 , drawSorted(true)
106
107 , dir(ZeroVector) // set via Init()
108 , mygravity(mapInfo? mapInfo->map.gravity: 0.0f)
109
110 , ownerID(-1u)
111 , teamID(-1u)
112 , cegID(-1u)
113
114 , projectileType(-1u)
115 , collisionFlags(0)
116 {
117 SetRadiusAndHeight(1.7f, 0.0f);
118 Init(owner, ZeroVector);
119 }
120
Detach()121 void CProjectile::Detach() {
122 // SYNCED
123 if (synced) {
124 quadField->RemoveProjectile(this);
125 }
126 CExpGenSpawnable::Detach();
127 }
128
~CProjectile()129 CProjectile::~CProjectile() {
130 // UNSYNCED
131 assert(!synced || detached);
132 }
133
Init(const CUnit * owner,const float3 & offset)134 void CProjectile::Init(const CUnit* owner, const float3& offset)
135 {
136 if (owner != NULL) {
137 // must be set before the AddProjectile call
138 ownerID = owner->id;
139 teamID = owner->team;
140 }
141 if (!hitscan) {
142 SetPosition(pos + offset);
143 SetVelocityAndSpeed(speed);
144 }
145 if (!weapon && !piece) {
146 // NOTE:
147 // new CWeapon- and CPieceProjectile*'s add themselves
148 // to CProjectileHandler (other code needs to be able
149 // to dyna-cast CProjectile*'s to those derived types,
150 // and adding them here would throw away too much RTTI)
151 projectileHandler->AddProjectile(this);
152 }
153 if (synced && !weapon) {
154 quadField->AddProjectile(this);
155 }
156 }
157
158
Update()159 void CProjectile::Update()
160 {
161 if (luaMoveCtrl)
162 return;
163
164 SetPosition(pos + speed);
165 SetVelocityAndSpeed(speed + (UpVector * mygravity));
166 }
167
168
Collision()169 void CProjectile::Collision()
170 {
171 deleteMe = true;
172 checkCol = false;
173 }
174
Collision(CUnit * unit)175 void CProjectile::Collision(CUnit* unit)
176 {
177 Collision();
178 }
179
Collision(CFeature * feature)180 void CProjectile::Collision(CFeature* feature)
181 {
182 Collision();
183 }
184
185
DrawOnMinimap(CVertexArray & lines,CVertexArray & points)186 void CProjectile::DrawOnMinimap(CVertexArray& lines, CVertexArray& points)
187 {
188 points.AddVertexQC(pos, color4::whiteA);
189 }
190
DrawArray()191 int CProjectile::DrawArray()
192 {
193 va->DrawArrayTC(GL_QUADS);
194
195 // draw-index gets divided by 24 because each element is
196 // 12 + 4 + 4 + 4 = 24 bytes in size (pos + u + v + color)
197 // for each type of "projectile"
198 const int idx = (va->drawIndex() / 24);
199
200 va = GetVertexArray();
201 va->Initialize();
202 inArray = false;
203
204 return idx;
205 }
206
owner() const207 CUnit* CProjectile::owner() const {
208 // NOTE:
209 // this death dependency optimization using "ownerID" is logically flawed:
210 // because ID's are reused it could return a unit that is not the original
211 // owner (unlikely however unless ID's get recycled very rapidly)
212 CUnit* unit = unitHandler->GetUnit(ownerID);
213
214 return unit;
215 }
216
GetTransformMatrix(bool offsetPos) const217 CMatrix44f CProjectile::GetTransformMatrix(bool offsetPos) const {
218 float3 xdir;
219 float3 ydir;
220
221 if (math::fabs(dir.y) < 0.95f) {
222 xdir = dir.cross(UpVector);
223 xdir.SafeANormalize();
224 } else {
225 xdir.x = 1.0f;
226 }
227
228 ydir = xdir.cross(dir);
229
230 return (CMatrix44f(drawPos + (dir * radius * 0.9f * offsetPos), -xdir, ydir, dir));
231 }
232
233