git-svn-id: https://scorched3d.svn.sourceforge.net/svnroot/scorched3d/trunk/scorched...
[scorched3d/parasti.git] / src / common / target / TargetLife.cpp
blobbeb948a359acf8019d4cf63a09d3abe02011edfd
1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2009
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.
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.
16 // You should have received a copy of the GNU General Public License
17 // along with Scorched3D; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ////////////////////////////////////////////////////////////////////////////////
21 #include <target/TargetLife.h>
22 #include <target/TargetRenderer.h>
23 #include <target/TargetSpace.h>
24 #include <target/TargetState.h>
25 #include <target/Target.h>
26 #include <tank/TankType.h>
27 #include <engine/ScorchedContext.h>
28 #include <engine/ActionController.h>
29 #include <tankai/TankAIAdder.h>
30 #include <common/Defines.h>
31 #include <common/Logger.h>
33 TargetLife::TargetLife(ScorchedContext &context, unsigned int playerId) :
34 context_(context), sphereGeom_(true),
35 life_(0), maxLife_(1), target_(0),
36 size_(2, 2, 2), floatBoundingSize_(0.0f)
40 TargetLife::~TargetLife()
42 life_ = 0;
43 updateSpace();
46 void TargetLife::newGame()
48 setLife(maxLife_);
51 void TargetLife::setLife(fixed life)
53 life_ = life;
55 if (life_ >= maxLife_) life_ = maxLife_;
56 if (life_ < 1)
58 life_ = 0;
59 setRotation(0); // Updates space too
61 else
63 updateAABB();
64 updateSpace();
68 void TargetLife::setSize(FixedVector &size)
70 size_ = size;
72 updateAABB();
73 updateSpace();
76 void TargetLife::setTargetPositionAndRotation(FixedVector &pos, fixed rotation)
78 targetPosition_ = pos;
79 if (!context_.getServerMode()) targetPosition_.asVector(floatPosition_);
81 FixedVector zaxis(0, 0, 1);
82 quaternion_.setQuatFromAxisAndAngle(zaxis, rotation / 180 * fixed::XPI);
83 if (!context_.getServerMode()) quaternion_.getOpenGLRotationMatrix(floatRotMatrix_);
85 updateAABB();
86 updateSpace();
89 void TargetLife::setTargetPosition(FixedVector &pos)
91 targetPosition_ = pos;
92 if (!context_.getServerMode()) targetPosition_.asVector(floatPosition_);
94 updateSpace();
97 void TargetLife::setRotation(fixed rotation)
99 FixedVector zaxis(0, 0, 1);
100 quaternion_.setQuatFromAxisAndAngle(zaxis, rotation / 180 * fixed::XPI);
101 if (!context_.getServerMode()) quaternion_.getOpenGLRotationMatrix(floatRotMatrix_);
103 updateAABB();
104 updateSpace();
107 FixedVector &TargetLife::getCenterPosition()
109 static FixedVector result;
110 result = getTargetPosition();
111 result[2] += getSize()[2] / 2;
112 return result;
115 Vector &TargetLife::getFloatCenterPosition()
117 static Vector result;
118 result = getFloatPosition();
119 result[2] += getFloatAabbSize()[2] / 2.0f;
120 return result;
123 fixed TargetLife::collisionDistance(FixedVector &position)
125 FixedVector &currentPosition = getCenterPosition();
126 FixedVector direction = position - currentPosition;
127 fixed dist = 0;
129 // Get how close the explosion was
130 if (getBoundingSphere())
132 // Find how close the explosion was to the
133 // outside of the sphere
134 fixed sphereRadius = MAX(MAX(size_[0], size_[1]), size_[2]) / 2;
135 dist = direction.Magnitude() - sphereRadius;
136 if (dist < 0) dist = 0;
138 else
140 // Make the direction relative to the geom
141 // incase the geom has been rotated
142 FixedVector relativeDirection;
143 quaternion_.getRelativeVector(relativeDirection, direction);
145 // Find how close the explosion was to the
146 // outside edge of the cube
147 FixedVector touchPosition = relativeDirection;
149 // Check each size of the cube to see if the point is outside.
150 // If it is, then scale it back until the point sits on the
151 // outside edge of the cube.
152 int inner = 0;
153 for (int i=0; i<3; i++)
155 fixed halfSize = size_[i] / 2;
156 if (touchPosition[i] < -halfSize)
158 // Scale the point so it sits on this edge
159 fixed diff = -halfSize / touchPosition[i];
160 touchPosition *= diff;
162 else if (touchPosition[i] > halfSize)
164 // Scale the point so it sits on this edge
165 fixed diff = halfSize / touchPosition[i];
166 touchPosition *= diff;
168 else inner++; // The point is inside this edge
171 if (inner == 3)
173 // We are inside the cube
174 dist = 0;
176 else
178 // We are outside the cube
179 relativeDirection -= touchPosition;
180 dist = relativeDirection.Magnitude();
184 return dist;
187 bool TargetLife::collision(FixedVector &position)
189 FixedVector &currentPosition = getCenterPosition();
190 FixedVector direction = position - currentPosition;
192 // Check against bounding box
193 if (direction[0] < -aabbSize_[0] ||
194 direction[0] > aabbSize_[0] ||
195 direction[1] < -aabbSize_[1] ||
196 direction[1] > aabbSize_[1] ||
197 direction[2] < -aabbSize_[2] ||
198 direction[2] > aabbSize_[2])
200 return false;
203 // Check against actual bounds
204 if (sphereGeom_)
206 fixed radius = MAX(MAX(size_[0], size_[1]), size_[2]) / 2;
207 if (direction.Magnitude() > radius) return false;
209 else
211 // Make the direction relative to the geom
212 // incase the geom has been rotated
213 FixedVector relativeDirection;
214 quaternion_.getRelativeVector(relativeDirection, direction);
216 // Check each side of the cube to see if the point is inside it
217 int inner = 0;
218 for (int i=0; i<3; i++)
220 fixed halfSize = size_[i] / 2;
221 if (-halfSize < relativeDirection[i] &&
222 relativeDirection[i] < halfSize)
224 inner++; // The point is inside this edge
228 // We need the point to be inside each of the 6 edges
229 if (inner < 3) return false;
232 return true;
235 void TargetLife::setBoundingSphere(bool sphereGeom)
237 sphereGeom_ = sphereGeom;
239 updateAABB();
240 updateSpace();
243 void TargetLife::updateSpace()
245 if (target_->getRenderer()) target_->getRenderer()->moved();
246 context_.getTargetSpace().updateTarget(target_);
249 bool TargetLife::writeMessage(NetBuffer &buffer)
251 buffer.addToBuffer(maxLife_);
252 buffer.addToBuffer(life_);
253 buffer.addToBuffer(size_);
254 buffer.addToBuffer(velocity_);
255 buffer.addToBuffer(targetPosition_);
256 buffer.addToBuffer(quaternion_);
257 return true;
260 bool TargetLife::readMessage(NetBufferReader &reader)
262 life_ = 0; // Suppress target space updates
264 fixed newLife;
265 if (!reader.getFromBuffer(maxLife_))
267 Logger::log("TargetLife::maxLife_ read failed");
268 return false;
270 if (!reader.getFromBuffer(newLife))
272 Logger::log("TargetLife::life_ read failed");
273 return false;
276 FixedVector newSize;
277 if (!reader.getFromBuffer(newSize))
279 Logger::log("TargetLife::size_ read failed");
280 return false;
282 setSize(newSize);
284 if (!reader.getFromBuffer(velocity_))
286 Logger::log("TargetLife::velocity_ read failed");
287 return false;
290 FixedVector newPosition;
291 if (!reader.getFromBuffer(newPosition))
293 Logger::log("TargetLife::targetPosition_ read failed");
294 return false;
296 setTargetPosition(newPosition);
298 if (!reader.getFromBuffer(quaternion_))
300 Logger::log("TargetLife::quaternion_ read failed");
301 return false;
304 // Update target space
305 setLife(newLife);
307 return true;
310 void TargetLife::updateAABB()
312 if (sphereGeom_)
314 fixed radius = MAX(MAX(size_[0], size_[1]), size_[2]) / 2;
315 aabbSize_ = FixedVector(radius * 2, radius * 2, radius * 2);
317 else
319 for (int i=0; i<8; i++)
321 FixedVector position;
322 switch (i)
324 case 0:
325 position = FixedVector(size_[0], size_[1], size_[2]);
326 break;
327 case 1:
328 position = FixedVector(-size_[0], size_[1], size_[2]);
329 break;
330 case 2:
331 position = FixedVector(size_[0], -size_[1], size_[2]);
332 break;
333 case 3:
334 position = FixedVector(-size_[0], -size_[1], size_[2]);
335 break;
336 case 4:
337 position = FixedVector(size_[0], size_[1], -size_[2]);
338 break;
339 case 5:
340 position = FixedVector(-size_[0], size_[1], -size_[2]);
341 break;
342 case 6:
343 position = FixedVector(size_[0], -size_[1], -size_[2]);
344 break;
345 case 7:
346 position = FixedVector(-size_[0], -size_[1], -size_[2]);
347 break;
350 FixedVector result;
351 quaternion_.getRelativeVector(result, position);
353 if (i == 0) aabbSize_ = result;
354 else
356 aabbSize_[0] = MAX(aabbSize_[0], result[0]);
357 aabbSize_[1] = MAX(aabbSize_[1], result[1]);
358 aabbSize_[2] = MAX(aabbSize_[2], result[2]);
362 if (!context_.getServerMode())
364 aabbSize_.asVector(floatAabbSize_);
365 floatBoundingSize_ = floatAabbSize_.Max();