git-svn-id: https://scorched3d.svn.sourceforge.net/svnroot/scorched3d/trunk/scorched...
[scorched3d/parasti.git] / src / common / weapons / WeaponAimedOver.cpp
blobfdab11e511b45cb41d3504e5421c0bb4da06ad21
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 <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>
30 #include <list>
31 #include <math.h>
33 REGISTER_ACCESSORY_SOURCE(WeaponAimedOver);
35 WeaponAimedOver::WeaponAimedOver() :
36 warHeads_(0)
41 WeaponAimedOver::~WeaponAimedOver()
46 bool WeaponAimedOver::parseXML(AccessoryCreateContext &context, XMLNode *accessoryNode)
48 if (!Weapon::parseXML(context, accessoryNode)) return false;
50 // Get the next weapon
51 XMLNode *subNode = 0;
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;
75 return true;
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);
91 bool ceiling = false;
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)
98 ceiling = true;
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(
106 context,
107 position,
108 sortedTanks,
110 maxAimedDistance_.getValue(context));
112 // Add all of these distances together
113 fixed totalDist = 0;
114 std::list<std::pair<fixed, Tank *> >::iterator itor;
115 for (itor = sortedTanks.begin();
116 itor != sortedTanks.end();
117 itor++)
119 totalDist += (*itor).first;
122 // Turn distance into a probablity that we will fire a the tank
123 fixed maxDist = 0;
124 if (sortedTanks.size() == 1)
126 maxDist = totalDist;
128 else
130 for (itor = sortedTanks.begin();
131 itor != sortedTanks.end();
132 itor++)
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;
144 // For each war head
145 for (int i=0; i<warHeads_; i++)
147 // Random probablity
148 fixed dist = maxDist * random.getRandFixed();
150 // Find which tank fits this probability
151 Tank *shootAt = 0;
152 fixed distC = 0;
153 for (itor = sortedTanks.begin();
154 itor != sortedTanks.end();
155 itor++)
157 distC += (*itor).first;
158 if (dist < distC)
160 shootAt = (*itor).second;
161 break;
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;
169 if (shootAt)
171 // We have a tank to aim at
172 // Aim a shot towards it
173 TankLib::getShotTowardsPosition(
174 context,
175 random,
176 position,
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;
188 // Create the shot
189 FixedVector &velocity = TankLib::getVelocityVector(
190 angleXYDegs, angleYZDegs);
191 velocity *= power;
193 aimedWeapon_->fireWeapon(
194 context, weaponContext, position, velocity);