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