1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2009
4 // This file is part of Scorched3D.
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 <weapons/WeaponAimedOver.h>
22 #include <weapons/AccessoryStore.h>
23 #include <engine/ActionController.h>
24 #include <landscapemap/LandscapeMaps.h>
25 #include <tank/Tank.h>
26 #include <tank/TankLib.h>
27 #include <tank/TankPosition.h>
28 #include <common/Defines.h>
29 #include <common/OptionsTransient.h>
33 REGISTER_ACCESSORY_SOURCE(WeaponAimedOver
);
35 WeaponAimedOver::WeaponAimedOver() :
41 WeaponAimedOver::~WeaponAimedOver()
46 bool WeaponAimedOver::parseXML(AccessoryCreateContext
&context
, XMLNode
*accessoryNode
)
48 if (!Weapon::parseXML(context
, accessoryNode
)) return false;
50 // Get the next weapon
52 if (!accessoryNode
->getNamedChild("aimedweapon", subNode
)) return false;
54 // Check next weapon is correct type
55 AccessoryPart
*accessory
= context
.getAccessoryStore().
56 createAccessoryPart(context
, parent_
, subNode
);
57 if (!accessory
|| accessory
->getType() != AccessoryPart::AccessoryWeapon
)
59 return subNode
->returnError("Failed to find sub weapon, not a weapon");
61 aimedWeapon_
= (Weapon
*) accessory
;
63 // Get the accessory warheads
64 if (!accessoryNode
->getNamedChild("nowarheads", warHeads_
)) return false;
66 // Get the accessory aimed distance
67 if (!accessoryNode
->getNamedChild("maxaimdistance", maxAimedDistance_
)) return false;
69 // Get the accessory percentage miss chance
70 if (!accessoryNode
->getNamedChild("percentagemiss", percentageMissChance_
)) return false;
72 // Get the accessory percentage miss chance
73 if (!accessoryNode
->getNamedChild("inaccuracy", maxInacuracy_
)) return false;
78 void WeaponAimedOver::fireWeapon(ScorchedContext
&context
,
79 WeaponFireContext
&weaponContext
, FixedVector
&sentPosition
, FixedVector
&oldvelocity
)
81 FixedVector position
= sentPosition
;
83 // Make sure that this position is above ground
84 fixed minHeight
= context
.getLandscapeMaps().getGroundMaps().getInterpHeight(
85 position
[0], position
[1]);
86 if (position
[2] < minHeight
+ fixed(true, 5000))
88 position
[2] = minHeight
+ fixed(true, 5000);
93 // This will return MAX_FLT when there is no roof
94 fixed maxHeight
= context
.getLandscapeMaps().getRoofMaps().getInterpRoofHeight(
95 position
[0] / 4, position
[1] / 4);
96 if (position
[2] > maxHeight
- 1)
99 position
[2] = maxHeight
- 1;
103 // Get all of the distances of the tanks less than maxAimedDistance_ away
104 std::list
<std::pair
<fixed
, Tank
*> > sortedTanks
;
105 TankLib::getTanksSortedByDistance(
110 maxAimedDistance_
.getValue(context
));
112 // Add all of these distances together
114 std::list
<std::pair
<fixed
, Tank
*> >::iterator itor
;
115 for (itor
= sortedTanks
.begin();
116 itor
!= sortedTanks
.end();
119 totalDist
+= (*itor
).first
;
122 // Turn distance into a probablity that we will fire a the tank
124 if (sortedTanks
.size() == 1)
130 for (itor
= sortedTanks
.begin();
131 itor
!= sortedTanks
.end();
134 (*itor
).first
= totalDist
- (*itor
).first
;
135 maxDist
+= (*itor
).first
;
139 RandomGenerator
&random
= context
.getActionController().getRandom();
141 // Add a percetage that we will not fire at any tank
142 maxDist
*= (percentageMissChance_
.getValue(context
) / 100) + 1;
145 for (int i
=0; i
<warHeads_
; i
++)
148 fixed dist
= maxDist
* random
.getRandFixed();
150 // Find which tank fits this probability
153 for (itor
= sortedTanks
.begin();
154 itor
!= sortedTanks
.end();
157 distC
+= (*itor
).first
;
160 shootAt
= (*itor
).second
;
165 // Calcuate the angle for the shot
166 fixed angleXYDegs
= random
.getRandFixed() * 360;
167 fixed angleYZDegs
= random
.getRandFixed() * 30 + 50;
168 fixed power
= random
.getRandFixed() * 300 + 150;
171 // We have a tank to aim at
172 // Aim a shot towards it
173 TankLib::getShotTowardsPosition(
177 shootAt
->getPosition().getTankPosition(),
178 angleXYDegs
, angleYZDegs
, power
);
179 power
*= fixed(true, 6000);
181 angleXYDegs
+= (random
.getRandFixed() * maxInacuracy_
.getValue(context
)) -
182 (maxInacuracy_
.getValue(context
) / 2);
183 angleYZDegs
+= (random
.getRandFixed() * maxInacuracy_
.getValue(context
)) -
184 (maxInacuracy_
.getValue(context
) / 2);
186 if (ceiling
) angleYZDegs
+= 180;
189 FixedVector
&velocity
= TankLib::getVelocityVector(
190 angleXYDegs
, angleYZDegs
);
193 aimedWeapon_
->fireWeapon(
194 context
, weaponContext
, position
, velocity
);