1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <target/TargetSpace.h>
22 #include <target/TargetLife.h>
23 #include <target/TargetShield.h>
24 #include <target/TargetState.h>
25 #include <weapons/Accessory.h>
26 #include <weapons/ShieldRound.h>
27 #include <weapons/ShieldSquare.h>
28 #include <engine/ScorchedContext.h>
29 #include <engine/Simulator.h>
30 #include <common/OptionsScorched.h>
31 #include <common/Logger.h>
32
TargetSpace()33 TargetSpace::TargetSpace() :
34 spaceX_(-128), spaceY_(-128),
35 spaceW_(1024), spaceH_(1024),
36 spaceSq_(4), context_(0)
37 {
38 spaceWSq_ = (spaceW_ / spaceSq_);
39 spaceHSq_ = (spaceH_ / spaceSq_);
40 noSquares_ = spaceWSq_ * spaceHSq_;
41 squares_ = new Square[noSquares_];
42 for (int i=0; i<noSquares_; i++) squares_[i].squarenum = i;
43 }
44
~TargetSpace()45 TargetSpace::~TargetSpace()
46 {
47 delete [] squares_;
48 }
49
clear()50 void TargetSpace::clear()
51 {
52 for (int i=0; i<noSquares_; i++) squares_[i].targets.clear();
53 }
54
updateTarget(Target * target)55 void TargetSpace::updateTarget(Target *target)
56 {
57 if (!target->getAlive() ||
58 target->getTargetState().getNoCollision())
59 {
60 removeTarget(target);
61 }
62 else
63 {
64 static std::vector<Square*> squares;
65 squares.clear();
66 getSquares(target, squares);
67
68 bool same = false;
69 if (squares.size() == target->getLife().getSpaceContainment().squares.size())
70 {
71 same = true;
72 for (unsigned int i=0; i<squares.size(); i++)
73 {
74 if (squares[i]->squarenum != target->getLife().getSpaceContainment().squares[i])
75 {
76 same = false;
77 break;
78 }
79 }
80 }
81
82 if (!same)
83 {
84 removeTarget(target);
85 std::vector<Square*>::iterator itor;
86 for (itor = squares.begin();
87 itor != squares.end();
88 ++itor)
89 {
90 Square *square = *itor;
91 target->getLife().getSpaceContainment().squares.push_back(square->squarenum);
92 square->targets.insert(std::pair<unsigned int, Target*>(target->getPlayerId(), target));
93 }
94 }
95 }
96 }
97
getSquares(Target * target,std::vector<Square * > & squares)98 void TargetSpace::getSquares(Target *target, std::vector<Square*> &squares)
99 {
100 // Set the bounding constaints
101 int x = target->getLife().getTargetPosition()[0].asInt();
102 int y = target->getLife().getTargetPosition()[1].asInt();
103 int w = target->getLife().getAabbSize()[0].asInt();
104 int h = target->getLife().getAabbSize()[1].asInt();
105
106 // Update bounding constraints for shield
107 Accessory *shieldAcc = target->getShield().getCurrentShield();
108 if (shieldAcc)
109 {
110 Shield *shield = (Shield *) shieldAcc->getAction();
111 if (shield->getRound())
112 {
113 ShieldRound *round = (ShieldRound *) shield;
114
115 w = MAX(w, (round->getActualRadius() * 2).asInt());
116 h = MAX(h, (round->getActualRadius() * 2).asInt());
117 }
118 else
119 {
120 ShieldSquare *square = (ShieldSquare *) shield;
121
122 w = MAX(w, (square->getSize()[0] * 2).asInt());
123 h = MAX(h, (square->getSize()[1] * 2).asInt());
124 }
125 }
126
127 // Find the bounding box coords
128 int halfW = w / 2;
129 int halfH = h / 2;
130 int minX = x - halfW - 1;
131 int minY = y - halfH - 1;
132 int maxX = x + halfW + 1;
133 int maxY = y + halfH + 1;
134
135 // Find the square positions
136 normalizeCoords(minX, minY);
137 normalizeCoords(maxX, maxY);
138
139 // Find the square numbers
140 for (int b=minY; b<=maxY; b++)
141 {
142 for (int a=minX; a<=maxX; a++)
143 {
144 int num = spaceHSq_ * b + a;
145 DIALOG_ASSERT(num >= 0 && num < noSquares_);
146
147 Square *square = &squares_[num];
148 squares.push_back(square);
149 }
150 }
151 }
152
removeTarget(Target * target)153 void TargetSpace::removeTarget(Target *target)
154 {
155 std::vector<int> &squares = target->getLife().getSpaceContainment().squares;
156 while (!squares.empty())
157 {
158 int squareNum = squares.back();
159 squares.pop_back();
160
161 Square *square = &squares_[squareNum];
162 square->targets.erase(target->getPlayerId());
163 }
164 }
165
getCollision(FixedVector & position)166 Target *TargetSpace::getCollision(FixedVector &position)
167 {
168 int x = position[0].asInt();
169 int y = position[1].asInt();
170
171 // Find the square positions
172 normalizeCoords(x, y);
173
174 int num = spaceHSq_ * y + x;
175 DIALOG_ASSERT(num >= 0 && num < noSquares_);
176
177 Square *square = &squares_[num];
178
179 Target *result = 0;
180 std::map<unsigned int, Target *> &potentialTargets = square->targets;
181 std::map<unsigned int, Target *>::iterator itor;
182 for (itor = potentialTargets.begin();
183 itor != potentialTargets.end();
184 ++itor)
185 {
186 Target *target = (*itor).second;
187 if (!target->getAlive())
188 {
189 Logger::log(S3D::formatStringBuffer("ERROR: Dead target %u:%s in space",
190 target->getPlayerId(), target->getCStrName().c_str()));
191 continue;
192 }
193
194 Accessory *shieldAcc = target->getShield().getCurrentShield();
195 if (shieldAcc)
196 {
197 Shield *shield = (Shield *) shieldAcc->getAction();
198 FixedVector direction = position - target->getLife().getTargetPosition();
199 if (shield->inShield(direction))
200 {
201 result = target;
202 break;
203 }
204 }
205
206 if (target->getLife().collision(position))
207 {
208 result = target;
209 break;
210 }
211 }
212
213 if (context_->getOptionsGame().getActionSyncCheck() &&
214 context_->getOptionsGame().getActionCollisionSyncCheck())
215 {
216 std::string targets;
217 if (result)
218 {
219 targets.append(S3D::formatStringBuffer("%u:%s ",
220 result->getPlayerId(),
221 result->getLife().getTargetPosition().asQuickString()));
222 }
223
224 context_->getSimulator().addSyncCheck(
225 S3D::formatStringBuffer("CollisionSet : %s %s",
226 position.asQuickString(),
227 targets.c_str()));
228 }
229
230 return result;
231 }
232
getCollisionSet(FixedVector & position,fixed radius,std::map<unsigned int,Target * > & collisionTargets,bool ignoreHeight)233 void TargetSpace::getCollisionSet(FixedVector &position, fixed radius,
234 std::map<unsigned int, Target *> &collisionTargets,
235 bool ignoreHeight)
236 {
237 int x = position[0].asInt();
238 int y = position[1].asInt();
239 int w = radius.asInt();
240 int h = radius.asInt();
241
242 // Find the bounding box coords
243 int halfW = w; // Not need 1/2 as its the radius thats passed in
244 int halfH = h;
245 int minX = x - halfW - 1;
246 int minY = y - halfH - 1;
247 int maxX = x + halfW + 1;
248 int maxY = y + halfH + 1;
249
250 // Find the square positions
251 normalizeCoords(minX, minY);
252 normalizeCoords(maxX, maxY);
253
254 // Find the square numbers
255 std::map<unsigned int, Target *>::iterator itor;
256 for (int b=minY; b<=maxY; b++)
257 {
258 for (int a=minX; a<=maxX; a++)
259 {
260 int num = spaceHSq_ * b + a;
261 DIALOG_ASSERT(num >= 0 && num < noSquares_);
262
263 Square *square = &squares_[num];
264
265 std::map<unsigned int, Target *> &potentialTargets =
266 square->targets;
267 for (itor = potentialTargets.begin();
268 itor != potentialTargets.end();
269 ++itor)
270 {
271 Target *target = (*itor).second;
272 if (!target->getAlive())
273 {
274 Logger::log(S3D::formatStringBuffer("ERROR: Dead target %u:%s in space",
275 target->getPlayerId(), target->getCStrName().c_str()));
276 continue;
277 }
278
279 FixedVector checkPos = position;
280 if (ignoreHeight)
281 {
282 FixedVector centerPos = target->getLife().getCenterPosition();
283 checkPos[2] = centerPos[2];
284 }
285 fixed distance = target->getLife().collisionDistance(checkPos);
286 if (distance < radius)
287 {
288 collisionTargets[target->getPlayerId()] = target;
289 }
290 }
291 }
292 }
293
294 if (context_->getOptionsGame().getActionSyncCheck() &&
295 context_->getOptionsGame().getActionCollisionSyncCheck())
296 {
297 std::string targets;
298 std::map<unsigned int, Target *>::iterator itor;
299 for (itor = collisionTargets.begin();
300 itor != collisionTargets.end();
301 ++itor)
302 {
303 targets.append(S3D::formatStringBuffer("%u:%s ",
304 itor->second->getPlayerId(),
305 itor->second->getLife().getTargetPosition().asQuickString()));
306 }
307
308 context_->getSimulator().addSyncCheck(
309 S3D::formatStringBuffer("CollisionSet : %s %s \"%s\"",
310 position.asQuickString(),
311 radius.asQuickString(),
312 targets.c_str()));
313 }
314 }
315
316 #ifndef S3D_SERVER
317 #include <GLEXT/GLState.h>
318 #include <client/ScorchedClient.h>
319 #include <landscapemap/LandscapeMaps.h>
320
drawBox(Vector & position,Vector & size)321 static void drawBox(Vector &position, Vector &size)
322 {
323 float wid = size[0];
324 float hgt = size[1];
325 float dep = size[2];
326 glPushMatrix();
327 glTranslatef(position[0], position[1], position[2]);
328 glBegin(GL_LINE_LOOP);
329 // Top
330 glNormal3f(0,1,0);
331 glVertex3f(-wid/2,hgt/2,dep/2);
332 glVertex3f(wid/2,hgt/2,dep/2);
333 glVertex3f(wid/2,hgt/2,-dep/2);
334 glVertex3f(-wid/2,hgt/2,-dep/2);
335 glEnd();
336 glBegin(GL_LINE_LOOP);
337 // Back
338 glNormal3f(0,0,1);
339 glVertex3f(-wid/2,hgt/2,dep/2);
340 glVertex3f(-wid/2,-hgt/2,dep/2);
341 glVertex3f(wid/2,-hgt/2,dep/2);
342 glVertex3f(wid/2,hgt/2,dep/2);
343 glEnd();
344 glBegin(GL_LINE_LOOP);
345 // Front
346 glNormal3f(0,0,-1);
347 glVertex3f(-wid/2,hgt/2,-dep/2);
348 glVertex3f(wid/2,hgt/2,-dep/2);
349 glVertex3f(wid/2,-hgt/2,-dep/2);
350 glVertex3f(-wid/2,-hgt/2,-dep/2);
351 glEnd();
352 glBegin(GL_LINE_LOOP);
353 // Left
354 glNormal3f(1,0,0);
355 glVertex3f(wid/2,hgt/2,-dep/2);
356 glVertex3f(wid/2,hgt/2,dep/2);
357 glVertex3f(wid/2,-hgt/2,dep/2);
358 glVertex3f(wid/2,-hgt/2,-dep/2);
359 glEnd();
360 glBegin(GL_LINE_LOOP);
361 // Right
362 glNormal3f(-1,0,0);
363 glVertex3f(-wid/2,hgt/2,dep/2);
364 glVertex3f(-wid/2,hgt/2,-dep/2);
365 glVertex3f(-wid/2,-hgt/2,-dep/2);
366 glVertex3f(-wid/2,-hgt/2,dep/2);
367 glEnd();
368 glBegin(GL_LINE_LOOP);
369 // Bottom
370 glNormal3f(0,-1,0);
371 glVertex3f(-wid/2,-hgt/2,dep/2);
372 glVertex3f(-wid/2,-hgt/2,-dep/2);
373 glVertex3f(wid/2,-hgt/2,-dep/2);
374 glVertex3f(wid/2,-hgt/2,dep/2);
375 glEnd();
376 glPopMatrix();
377 }
378
draw()379 void TargetSpace::draw()
380 {
381 GLState glState(GLState::TEXTURE_OFF | GLState::LIGHTING_OFF);
382
383 for (int b=0; b<spaceHSq_; b++)
384 {
385 for (int a=0; a<spaceWSq_; a++)
386 {
387 int num = spaceHSq_ * b + a;
388 DIALOG_ASSERT(num >= 0 && num < noSquares_);
389
390 Square *square = &squares_[num];
391 if (square->targets.empty())
392 {
393 continue;
394 }
395
396 Vector position(a * spaceSq_ + spaceX_ + spaceSq_ / 2,
397 b * spaceSq_ + spaceY_ + spaceSq_ / 2, 0);
398 position[2] =
399 ScorchedClient::instance()->getLandscapeMaps().
400 getGroundMaps().getHeight((int) position[0], (int) position[1]).asFloat() - 7.0f;
401 Vector size(spaceSq_, spaceSq_, 20);
402
403 if (position[0] > ScorchedClient::instance()->getLandscapeMaps().
404 getGroundMaps().getLandscapeWidth() ||
405 position[1] > ScorchedClient::instance()->getLandscapeMaps().
406 getGroundMaps().getLandscapeHeight())
407 {
408 continue;
409 }
410
411 glColor3f(1.0f, 0.0f, 0.0f);
412 drawBox(position, size);
413
414 glBegin(GL_LINES);
415 std::map<unsigned int, Target *>::iterator itor;
416 for (itor = square->targets.begin();
417 itor != square->targets.end();
418 ++itor)
419 {
420 Target *target = (*itor).second;
421 glVertex3fv(target->getLife().getFloatPosition());
422 glVertex3f(position[0], position[1], position[2] + 10.0f);
423 }
424 glEnd();
425 }
426 }
427 }
428 #endif
429