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 <actions/ShotProjectile.h>
22 #include <actions/CameraPositionAction.h>
23 #ifndef S3D_SERVER
24 #include <sprites/MissileActionRenderer.h>
25 #include <tankgraph/RenderTracer.h>
26 #endif
27 #include <landscapemap/LandscapeMaps.h>
28 #include <landscapedef/LandscapeTex.h>
29 #include <tank/TankViewPoints.h>
30 #include <target/TargetContainer.h>
31 #include <tankai/TankAI.h>
32 #include <tanket/Tanket.h>
33 #include <common/Defines.h>
34 #include <common/OptionsScorched.h>
35 #include <common/Logger.h>
36 #include <engine/ScorchedContext.h>
37 #include <engine/ActionController.h>
38 #include <weapons/AccessoryStore.h>
39 #include <math.h>
40
ShotProjectile(FixedVector & startPosition,FixedVector & velocity,WeaponProjectile * weapon,WeaponFireContext & weaponContext,unsigned int flareType,fixed spinSpeed,const Vector & spinAxis)41 ShotProjectile::ShotProjectile(FixedVector &startPosition, FixedVector &velocity,
42 WeaponProjectile *weapon, WeaponFireContext &weaponContext,
43 unsigned int flareType,
44 fixed spinSpeed, const Vector &spinAxis) :
45 PhysicsParticle(weaponContext.getInternalContext().getReferenced()),
46 startPosition_(startPosition), velocity_(velocity),
47 weapon_(weapon), weaponContext_(weaponContext),
48 flareType_(flareType), vPoint_(0),
49 snapTime_(fixed(true, 2000)), up_(false),
50 totalTime_(0), simulateTime_(0),
51 spinSpeed_(spinSpeed), spinAxis_(spinAxis),
52 groups_(0), physicsSpin_(0)
53 {
54 }
55
init()56 void ShotProjectile::init()
57 {
58 fixed weaponScale = weapon_->getScale(*context_);
59 #ifndef S3D_SERVER
60 if (!context_->getServerMode())
61 {
62 setActionRender(new MissileActionRenderer(flareType_,
63 weaponScale.asFloat(),
64 spinSpeed_.asFloat(),
65 spinAxis_));
66
67 if (!weapon_->getNoCameraTrack())
68 {
69 vPoint_ = new TankViewPointProvider();
70 vPoint_->incrementReference();
71 FixedVector velocity = velocity_;
72 velocity[2] = 10;
73 vPoint_->setValues(startPosition_, velocity);
74
75 CameraPositionAction *positionAction = new CameraPositionAction(
76 weaponContext_.getPlayerId(),
77 vPoint_,
78 5,
79 10,
80 false);
81 context_->getActionController().addAction(positionAction);
82 }
83 }
84 #endif // #ifndef S3D_SERVER
85
86 PhysicsParticleInfo info(ParticleTypeShot, weaponContext_.getPlayerId(), this);
87 setPhysics(info, startPosition_, velocity_,
88 0, 0, weapon_->getWindFactor(*context_), weapon_->getGravityFactor(*context_),
89 getWeapon()->getUnder(),
90 false, getWeapon()->getWallCollision());
91 thrustTime_ = getWeapon()->getThrustTime(*context_);
92 thrustAmount_ = getWeapon()->getThrustAmount(*context_);
93 timedCollision_ = getWeapon()->getTimedCollision(*context_);
94 heightCollision_ = getWeapon()->getHeightCollision(*context_);
95 wobbleSpin_ = getWeapon()->getWobbleSpin(*context_);
96 wobbleAmount_= getWeapon()->getWobbleAmount(*context_);
97 drag_ = getWeapon()->getDrag(*context_);
98 stepSize_ = getWeapon()->getStepSize() *
99 fixed(true, context_->getOptionsGame().getWeaponSpeed());
100
101 if (weapon_->getLocalGroups().hasGroups() || weapon_->getGlobalGroups().hasGroups())
102 {
103 groups_ = new ParticleGroup(*context_, this, &weaponContext_);
104 weapon_->getLocalGroups().addToGroups(weaponContext_.getInternalContext().getLocalGroups(), groups_);
105 weapon_->getGlobalGroups().addToGroups(context_->getObjectGroups(), groups_);
106 }
107 }
108
getActionDetails()109 std::string ShotProjectile::getActionDetails()
110 {
111 return S3D::formatStringBuffer("%s %s %s",
112 startPosition_.asQuickString(),
113 velocity_.asQuickString(),
114 weapon_->getParent()->getName());
115 }
116
~ShotProjectile()117 ShotProjectile::~ShotProjectile()
118 {
119 if (vPoint_) vPoint_->decrementReference();
120 delete groups_;
121 }
122
collision(PhysicsParticleObject & position,ScorchedCollisionId collisionId)123 void ShotProjectile::collision(PhysicsParticleObject &position,
124 ScorchedCollisionId collisionId)
125 {
126 if (!collision_)
127 {
128 // Tell all AIs about this collision
129 std::map<unsigned int, Tanket *> &tanks =
130 context_->getTargetContainer().getTankets();
131 std::map<unsigned int, Tanket *>::iterator itor;
132 for (itor = tanks.begin();
133 itor != tanks.end();
134 ++itor)
135 {
136 Tanket *tanket = (*itor).second;
137 TankAI *ai = tanket->getTankAI();
138 if (ai)
139 {
140 if (tanket->getAlive())
141 {
142 ai->shotLanded(collisionId,
143 getWeapon(), getPlayerId(),
144 getCurrentPosition().asVector());
145 }
146 }
147 }
148
149 bool doColl = true;
150
151 // Apex collisions dud if they collide with the ground
152 // unless no dud is set
153 if (getWeapon()->getApexCollision() && !getWeapon()->getApexNoDud())
154 {
155 doColl = false;
156 }
157 if ((getWeapon()->getTimedCollision(*context_) > 0) && getWeapon()->getTimedDud())
158 {
159 doColl = false;
160 }
161
162 if (doColl) doCollision(position.getPosition());
163 }
164 PhysicsParticle::collision(position, collisionId);
165 }
166
simulate(fixed frameTime,bool & remove)167 void ShotProjectile::simulate(fixed frameTime, bool &remove)
168 {
169 totalTime_ += frameTime;
170
171 // Water collision
172 if (!remove &&
173 getWeapon()->getWaterCollision())
174 {
175 fixed waterHeight = -10;
176 LandscapeTex &tex = *context_->getLandscapeMaps().getDefinitions().getTex();
177 if (tex.border->getType() == LandscapeTexType::eWater)
178 {
179 LandscapeTexBorderWater *water =
180 (LandscapeTexBorderWater *) tex.border;
181
182 waterHeight = water->height;
183 }
184
185 if (getCurrentPosition()[2] < waterHeight)
186 {
187 doCollision(getCurrentPosition());
188 remove = true;
189 }
190 }
191
192 // Apex collision
193 if (!remove &&
194 getWeapon()->getApexCollision())
195 {
196 if (getCurrentVelocity()[2] > 0) up_ = true;
197 else if (up_)
198 {
199 doCollision(getCurrentPosition());
200 remove = true;
201 }
202 }
203
204 // Apex collision
205 if (!remove &&
206 heightCollision_ > 0)
207 {
208 if (getCurrentVelocity()[2] < 0)
209 {
210 fixed landHeight = context_->getLandscapeMaps().
211 getGroundMaps().getInterpHeight(
212 getCurrentPosition()[0], getCurrentPosition()[1]);
213 if (getCurrentPosition()[2] <= heightCollision_ + landHeight)
214 {
215 doCollision(getCurrentPosition());
216 remove = true;
217 }
218 }
219 }
220
221 if (wobbleSpin_ > 0)
222 {
223 FixedVector up(0, 0, 1);
224 FixedVector velocityPerp = (velocity_.Normalize() * up).Normalize();
225 FixedVector forceDir = ((velocityPerp * physicsSpin_.cos()) * wobbleAmount_ * velocity_.Magnitude() / 50);
226 applyOffset(forceDir);
227
228 physicsSpin_ += wobbleSpin_;
229 }
230
231 // Thrust
232 if (thrustAmount_ > 0)
233 {
234 if (totalTime_ < thrustTime_ ||
235 thrustTime_ == 0)
236 {
237 FixedVector direction = getCurrentVelocity();
238 direction.StoreNormalize();
239 direction *= thrustAmount_;
240 applyForce(direction);
241 }
242 }
243
244 // Drag
245 if (drag_ > 0)
246 {
247 FixedVector direction = getCurrentVelocity();
248 direction *= -drag_;
249 applyForce(direction);
250 }
251
252 // Timed collision
253 if (!remove &&
254 timedCollision_ > 0)
255 {
256 if (totalTime_ > timedCollision_)
257 {
258 doCollision(getCurrentPosition());
259 remove = true;
260 }
261 }
262
263 // Shot path
264 #ifndef S3D_SERVER
265 if (!context_->getServerMode())
266 {
267 if (getWeapon()->getShowShotPath())
268 {
269 snapTime_ += frameTime;
270 if (snapTime_.asFloat() > 0.1f || remove)
271 {
272 Vector up (0.0f, 0.0f, 1.0f);
273 RenderTracer::TracerLinePoint point;
274 point.position = getCurrentPosition().asVector();
275 point.cross = (getCurrentVelocity().asVector() * up).Normalize();
276 positions_.push_back(point);
277 snapTime_ = 0;
278 }
279 }
280 }
281 #endif // #ifndef S3D_SERVER
282
283 simulateTime_ += frameTime;
284 while (simulateTime_ > stepSize_)
285 {
286 PhysicsParticle::simulate(stepSize_, remove);
287 simulateTime_ -= stepSize_;
288 }
289
290 if (vPoint_)
291 {
292 FixedVector velocity = -getCurrentVelocity();
293 velocity[2] = 10;
294 vPoint_->setValues(getCurrentPosition(), velocity);
295 }
296 }
297
doCollision(FixedVector & position)298 void ShotProjectile::doCollision(FixedVector &position)
299 {
300 #ifndef S3D_SERVER
301 if (!context_->getServerMode())
302 {
303 if (getWeapon()->getShowShotPath())
304 {
305 RenderTracer::instance()->
306 addSmokeTracer(weaponContext_.getPlayerId(),
307 position.asVector(), positions_);
308 }
309 else if (getWeapon()->getShowEndPoint())
310 {
311 RenderTracer::instance()->
312 addTracer(weaponContext_.getPlayerId(), position.asVector());
313 }
314 }
315 #endif // #ifndef S3D_SERVER
316
317 FixedVector velocity;
318 getWeapon()->getCollisionAction()->fire(
319 *context_, weaponContext_, position, getCurrentVelocity());
320 }
321
322