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 <tankai/TankAIWeaponSets.h>
22 #include <tank/Tank.h>
23 #include <tank/TankScore.h>
24 #include <tank/TankAccessories.h>
25 #include <server/ScorchedServer.h>
26 #include <common/OptionsScorched.h>
27 #include <common/OptionsTransient.h>
28 #include <weapons/AccessoryStore.h>
29 #include <XML/XMLFile.h>
31 TankAIWeaponSets
*TankAIWeaponSets::instance()
33 static TankAIWeaponSets instance
;
37 TankAIWeaponSets::TankAIWeaponSets()
42 TankAIWeaponSets::~TankAIWeaponSets()
46 bool TankAIWeaponSets::parseConfig()
49 std::string fileName
= S3D::getDataFile("data/tankaiweaponsets.xml");
50 if (!file
.readFile(fileName
.c_str()))
52 S3D::dialogMessage("TankAIWeaponSets", S3D::formatStringBuffer(
53 "Failed to parse \"%s\":%s\n",
55 file
.getParserError()));
58 if (!file
.getRootNode())
60 S3D::dialogMessage("TankAIWeaponSets", S3D::formatStringBuffer(
61 "Failed to weapon sets definition file \"%s\"",
66 XMLNode
*weaponsetNode
= 0;
67 while (file
.getRootNode()->getNamedChild("weaponset", weaponsetNode
, false))
70 if (!weaponSet
.parseConfig(weaponsetNode
)) return false;
71 weaponSets_
[weaponSet
.name
] = weaponSet
;
74 return file
.getRootNode()->failChildren();
77 TankAIWeaponSets::WeaponSet
*TankAIWeaponSets::getWeaponSet(const char *name
)
79 std::map
<std::string
, WeaponSet
>::iterator findItor
=
80 weaponSets_
.find(name
);
81 if (findItor
== weaponSets_
.end()) return 0;
83 return &findItor
->second
;
86 bool TankAIWeaponSets::WeaponSet::parseConfig(XMLNode
*node
)
88 if (!node
->getNamedChild("name", name
)) return false;
89 XMLNode
*setNode
= 0, *weaponNode
= 0;
90 if (!node
->getNamedChild("set", setNode
)) return false;
91 while (setNode
->getNamedChild("weapon", weaponNode
, false))
93 WeaponSetEntry weapon
;
94 if (!weapon
.parseConfig(weaponNode
)) return false;
95 weapons
.push_back(weapon
);
98 return node
->failChildren();
101 void TankAIWeaponSets::WeaponSet::buyWeapons(Tank
*tank
, bool lastRound
)
105 // Get all of the weapons we can buy
106 std::multimap
<unsigned int, WeaponSetEntry
*> potentialWeapons
;
107 std::vector
<WeaponSetEntry
>::iterator itor
;
108 for (itor
= weapons
.begin();
109 itor
!= weapons
.end();
112 WeaponSetEntry
&weapon
= *itor
;
113 if (weapon
.weaponValid(tank
, lastRound
))
115 potentialWeapons
.insert(
116 std::pair
<unsigned int, WeaponSetEntry
*>
117 (weapon
.prioritybuy
, &weapon
));
120 if (potentialWeapons
.empty()) break;
122 // Choose one of the potential weapons
123 // from the list of the highest priority
124 std::vector
<WeaponSetEntry
*> priorityWeapons
;
125 std::multimap
<unsigned int, WeaponSetEntry
*>::reverse_iterator ritor
;
126 for (ritor
= potentialWeapons
.rbegin();
127 ritor
!= potentialWeapons
.rend();
130 WeaponSetEntry
*weapon
= ritor
->second
;
131 priorityWeapons
.push_back(weapon
);
132 if (weapon
->prioritybuy
< priorityWeapons
.back()->prioritybuy
) break;
134 WeaponSetEntry
*choosenWeapon
= priorityWeapons
[rand() % priorityWeapons
.size()];
135 Accessory
*choosenAccessory
= choosenWeapon
->accessory
;
138 tank
->getAccessories().add(choosenAccessory
, choosenAccessory
->getBundle());
139 tank
->getScore().setMoney(tank
->getScore().getMoney() -
140 choosenAccessory
->getPrice());
144 Accessory
*TankAIWeaponSets::WeaponSet::
145 getTankAccessoryByType(Tank
*tank
, const char *getType
)
147 DIALOG_ASSERT(WeaponSetEntry::checkType(getType
));
149 WeaponSetEntry
*result
= 0;
151 std::vector
<WeaponSetEntry
>::iterator itor
;
152 for (itor
= weapons
.begin();
153 itor
!= weapons
.end();
156 WeaponSetEntry
¤t
= *itor
;
157 if (current
.type
== getType
)
159 if ((10 - current
.accessory
->getArmsLevel()) <=
160 ScorchedServer::instance()->getOptionsTransient().getArmsLevel() ||
161 ScorchedServer::instance()->getOptionsGame().getGiveAllWeapons())
163 if (tank
->getAccessories().canUse(current
.accessory
))
166 result
->priorityuse
< current
.priorityuse
)
175 return (result
?result
->accessory
:0);
178 bool TankAIWeaponSets::WeaponSetEntry::parseConfig(XMLNode
*node
)
181 if (!node
->getNamedChild("name", name
)) return false;
182 accessory
= ScorchedServer::instance()->getAccessoryStore().
183 findByPrimaryAccessoryName(name
.c_str());
186 return node
->returnError(
187 S3D::formatStringBuffer("Unknown accessory %s", name
.c_str()));
190 if (!node
->getNamedChild("buymin", buymin
)) return false;
191 if (!node
->getNamedChild("buymax", buymax
)) return false;
192 if (!node
->getNamedChild("moneymin", moneymin
)) return false;
193 if (!node
->getNamedChild("moneymax", moneymax
)) return false;
194 if (!node
->getNamedChild("prioritybuy", prioritybuy
)) return false;
195 if (!node
->getNamedChild("priorityuse", priorityuse
)) return false;
196 if (!node
->getNamedChild("type", type
)) return false;
198 if (!checkType(type
.c_str()))
200 return node
->returnError(
201 S3D::formatStringBuffer("Unknown type %s", type
.c_str()));
204 return node
->failChildren();
207 bool TankAIWeaponSets::WeaponSetEntry::checkType(const char *type
)
209 if (0 != strcmp(type
, "explosionhuge") &&
210 0 != strcmp(type
, "explosionlarge") &&
211 0 != strcmp(type
, "explosionsmall") &&
212 0 != strcmp(type
, "uncover") &&
213 0 != strcmp(type
, "digger") &&
214 0 != strcmp(type
, "roller") &&
215 0 != strcmp(type
, "napalm") &&
216 0 != strcmp(type
, "laser") &&
217 0 != strcmp(type
, "shield") &&
218 0 != strcmp(type
, "other") &&
219 0 != strcmp(type
, "fuel") &&
220 0 != strcmp(type
, "autodefense") &&
221 0 != strcmp(type
, "parachute"))
228 bool TankAIWeaponSets::WeaponSetEntry::weaponValid(Tank
*tank
, bool lastRound
)
230 int currentCount
= tank
->getAccessories().getAccessoryCount(accessory
);
231 int currentMoney
= tank
->getScore().getMoney();
233 int maxCount
= accessory
->getMaximumNumber();
234 if (currentCount
>= maxCount
) return false;
236 if (currentCount
< 0) return false;
237 if (currentMoney
< accessory
->getPrice()) return false;
239 if ((10 - accessory
->getArmsLevel()) <=
240 ScorchedServer::instance()->getOptionsTransient().getArmsLevel() ||
241 ScorchedServer::instance()->getOptionsGame().getGiveAllWeapons()) {}
244 if (type
== "autodefense")
246 // Don't buy autodefense when simultaneous
247 if (ScorchedServer::instance()->getOptionsGame().getTurnType() ==
248 OptionsGame::TurnSimultaneous
)
256 if (currentCount
> buymin
) return false;
257 if ((currentMoney
< moneymin
&& moneymin
!= 0) ||
258 (currentMoney
> moneymax
&& moneymax
!= 0)) return false;