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 <XML/XMLFile.h>
22 #include <common/Defines.h>
23 #include <common/Logger.h>
24 #include <weapons/AccessoryStore.h>
25 #include <weapons/Weapon.h>
26 #include <lang/LangResource.h>
27 #include <math.h>
28 #include <stdio.h>
29
AccessoryStore()30 AccessoryStore::AccessoryStore() : muzzleFlash_(0)
31 {
32
33 }
34
~AccessoryStore()35 AccessoryStore::~AccessoryStore()
36 {
37 clearAccessories();
38 }
39
clearAccessories()40 void AccessoryStore::clearAccessories()
41 {
42 AccessoryPart::resetAccessoryPartIds();
43 Accessory::resetAccessoryIds();
44 muzzleFlash_ = 0;
45 deathAnimation_ = 0;
46 while (!accessories_.empty())
47 {
48 Accessory *accessory = accessories_.front();
49 accessories_.pop_front();
50 delete accessory;
51 }
52 accessoryParts_.clear();
53 tabGroups_.clear();
54 }
55
parseFile(ScorchedContext & context,ProgressCounter * counter)56 bool AccessoryStore::parseFile(
57 ScorchedContext &context, ProgressCounter *counter)
58 {
59 if (counter) counter->setNewOp(LANG_RESOURCE("LOADING_WEAPONS", "Loading Weapons"));
60
61 std::string fileName = S3D::getModFile("data/accessories.xml");
62 clearAccessories();
63
64 XMLFile file;
65 if (!file.readFile(fileName.c_str()))
66 {
67 S3D::dialogMessage("AccessoryStore", S3D::formatStringBuffer(
68 "Failed to parse \"%s\"\n%s",
69 fileName.c_str(),
70 file.getParserError()));
71 return false;
72 }
73
74 // Check file exists
75 if (!file.getRootNode())
76 {
77 S3D::dialogMessage("AccessoryStore", S3D::formatStringBuffer(
78 "Failed to find accessory file \"%s\"",
79 fileName.c_str()));
80 return false;
81 }
82
83 // Itterate all of the accessories in the file
84 int noChildren = (int) file.getRootNode()->getChildren().size();
85 int childCount = 0;
86 XMLNode *currentNode = 0;
87 while (file.getRootNode()->getNamedChild("accessory", currentNode, false))
88 {
89 if (counter) counter->setNewPercentage(
90 float(++childCount) / float(noChildren) * 100.0f);
91
92 // Parse the accessory
93 AccessoryCreateContext createContext(context);
94 Accessory *accessory = new Accessory();
95 if (!accessory->parseXML(createContext, currentNode))
96 {
97 return currentNode->returnError(
98 S3D::formatStringBuffer("Failed to create accessory \"%s\"",
99 accessory->getName()));
100 }
101
102 // Check uniqueness
103 if (findByPrimaryAccessoryName(accessory->getName()))
104 {
105 return currentNode->returnError(
106 S3D::formatStringBuffer("Accessory \"%s\" already exists",
107 accessory->getName()));
108 }
109
110 if (!accessory->getNoBuy() &&
111 accessory->getMaximumNumber() != 0)
112 {
113 tabGroups_.insert(accessory->getTabGroupName());
114 }
115
116 // Add the accessory
117 accessories_.push_back(accessory);
118
119 // Add weapons to death animations, weighted by arms level
120 if (accessory->getAction()->getType() == AccessoryPart::AccessoryWeapon)
121 {
122 Weapon *weapon = (Weapon *) accessory->getAction();
123 if (0 == strcmp(accessory->getName(), "WeaponMuzzle"))
124 {
125 muzzleFlash_ = weapon;
126 }
127 else if (0 == strcmp(accessory->getName(), "WeaponDeathAnimation"))
128 {
129 deathAnimation_ = weapon;
130 }
131 }
132
133 // Add to the map so references can find it
134 parsingNodes_[accessory->getName()] = currentNode;
135 }
136
137 if (!muzzleFlash_)
138 {
139 return file.getRootNode()->returnError(
140 "Failed to find WeaponMuzzle weapon used for muzzle flash.");
141 }
142 if (!deathAnimation_)
143 {
144 return file.getRootNode()->returnError(
145 "Failed to find WeaponDeathAnimation weapon used for tank explosions.");
146 }
147
148 // Clear mapping as it now contains invalid pointers
149 parsingNodes_.clear();
150 return file.getRootNode()->failChildren();
151 }
152
createAccessoryPart(AccessoryCreateContext & context,Accessory * parent,XMLNode * currentNode)153 AccessoryPart *AccessoryStore::createAccessoryPart(
154 AccessoryCreateContext &context,
155 Accessory *parent, XMLNode *currentNode)
156 {
157 XMLNode *typeNode = 0;
158 if (!currentNode->getNamedParameter("type", typeNode)) return 0;
159
160 AccessoryPart *accessoryPart =
161 AccessoryMetaRegistration::getNewAccessory(typeNode->getContent(), this);
162 if (!accessoryPart)
163 {
164 S3D::dialogMessage("AccessoryStore", S3D::formatStringBuffer(
165 "Failed to find accessory part type \"%s\"",
166 typeNode->getContent()));
167 return 0;
168 }
169 // Set the parent accessory
170 accessoryPart->setParent(parent);
171
172 // Tell this accessory instance to initialize its settings from
173 // the current accessory xml definition node
174 if (!accessoryPart->parseXML(context, currentNode)) return 0;
175
176 // There should not be any children left
177 // Any that are, are children that have not been
178 // handled by the parse routine
179 if (!currentNode->failChildren()) return 0;
180 DIALOG_ASSERT(accessoryPart->getParent());
181
182 // Add the accessory
183 accessoryParts_.push_back(accessoryPart);
184 return accessoryPart;
185 }
186
sortList(std::list<Accessory * > & accList,int sortKey)187 void AccessoryStore::sortList(std::list<Accessory *> &accList, int sortKey)
188 {
189 if (sortKey)
190 {
191 std::vector<Accessory *> accVector;
192 std::list<Accessory *>::iterator itor;
193 for (itor = accList.begin();
194 itor != accList.end();
195 ++itor)
196 {
197 accVector.push_back(*itor);
198 }
199
200 // Crudely sort by name or price
201 // stl sort method list is broken in visual c 6
202 // bubble sort
203 bool changed = true;
204 while (changed)
205 {
206 changed = false;
207 for (int i=0; i<int(accVector.size())-1; i++)
208 {
209 bool swap = false;
210
211 // When sorting by price, use accessory name as a
212 // secondary sort key.
213
214 if ((sortKey == SortName) ||
215 (sortKey == SortPrice && accVector[i]->getPrice() == accVector[i + 1]->getPrice()))
216 {
217 swap = strcmp(accVector[i]->getName(), accVector[i + 1]->getName()) < 0;
218 }
219 else if (sortKey == SortPrice)
220 {
221 swap = accVector[i]->getPrice() < accVector[i + 1]->getPrice();
222 }
223
224 if (swap)
225 {
226 Accessory *tmp = accVector[i];
227 accVector[i] = accVector[i+1];
228 accVector[i+1] = tmp;
229 changed = true;
230 break;
231 }
232 }
233 }
234
235 accList.clear();
236 for (int i=0; i<int(accVector.size()); i++)
237 {
238 accList.push_front(accVector[i]);
239 }
240 }
241 else
242 {
243 std::set<Accessory *> accessorySet;
244 std::list<Accessory *>::iterator setItor;
245 for (setItor = accList.begin();
246 setItor != accList.end();
247 ++setItor)
248 {
249 Accessory *accessory = *setItor;
250 accessorySet.insert(accessory);
251 }
252
253 accList.clear();
254 std::list<Accessory *>::iterator itor;
255 for (itor = accessories_.begin();
256 itor != accessories_.end();
257 ++itor)
258 {
259 Accessory *accessory = *itor;
260 if (accessorySet.find(accessory) != accessorySet.end())
261 {
262 accList.push_back(accessory);
263 }
264 }
265 }
266 }
267
getAllAccessoriesByTabGroup(const char * tabgroup,int sortKey)268 std::list<Accessory *> AccessoryStore::getAllAccessoriesByTabGroup(
269 const char *tabgroup, int sortKey)
270 {
271 std::list<Accessory *> result;
272 std::list<Accessory *>::iterator itor;
273 for (itor = accessories_.begin();
274 itor != accessories_.end();
275 ++itor)
276 {
277 Accessory *accessory = (*itor);
278 if (0 == strcmp(tabgroup, accessory->getTabGroupName()))
279 {
280 result.push_back(*itor);
281 }
282 }
283
284 if (sortKey) sortList(result, sortKey);
285 return result;
286 }
287
getAllAccessories(int sortKey)288 std::list<Accessory *> AccessoryStore::getAllAccessories(int sortKey)
289 {
290 std::list<Accessory *> result;
291 std::list<Accessory *>::iterator itor;
292 for (itor = accessories_.begin();
293 itor != accessories_.end();
294 ++itor)
295 {
296 result.push_back(*itor);
297 }
298
299 if (sortKey) sortList(result, sortKey);
300 return result;
301 }
302
getMuzzelFlash()303 Weapon *AccessoryStore::getMuzzelFlash()
304 {
305 return muzzleFlash_;
306 }
307
getDeathAnimation()308 Weapon *AccessoryStore::getDeathAnimation()
309 {
310 return deathAnimation_;
311 }
312
findByPrimaryAccessoryName(const char * name)313 Accessory *AccessoryStore::findByPrimaryAccessoryName(const char *name)
314 {
315 std::list<Accessory *>::iterator itor;
316 for (itor = accessories_.begin();
317 itor != accessories_.end();
318 ++itor)
319 {
320 Accessory *accessory = (*itor);
321 if (strcmp(accessory->getName(), name) == 0)
322 {
323 return accessory;
324 }
325 }
326 return 0;
327 }
328
findByAccessoryId(unsigned int id)329 Accessory *AccessoryStore::findByAccessoryId(unsigned int id)
330 {
331 std::list<Accessory *>::iterator itor;
332 for (itor = accessories_.begin();
333 itor != accessories_.end();
334 ++itor)
335 {
336 Accessory *accessory = (*itor);
337 if (accessory->getAccessoryId() == id)
338 {
339 return accessory;
340 }
341 }
342 return 0;
343 }
344
findAccessoryPartByAccessoryId(unsigned int id,const char * type)345 AccessoryPart *AccessoryStore::findAccessoryPartByAccessoryId(unsigned int id, const char *type)
346 {
347 std::list<AccessoryPart *>::iterator itor;
348 for (itor = accessoryParts_.begin();
349 itor != accessoryParts_.end();
350 ++itor)
351 {
352 AccessoryPart *accessoryPart = (*itor);
353 if (accessoryPart->getParent()->getAccessoryId() == id &&
354 0 == strcmp(accessoryPart->getAccessoryTypeName(), type))
355 {
356 return accessoryPart;
357 }
358 }
359 return 0;
360 }
361
findByAccessoryPartId(unsigned int id)362 AccessoryPart *AccessoryStore::findByAccessoryPartId(unsigned int id)
363 {
364 std::list<AccessoryPart *>::iterator itor;
365 for (itor = accessoryParts_.begin();
366 itor != accessoryParts_.end();
367 ++itor)
368 {
369 AccessoryPart *accessoryPart = (*itor);
370 if (accessoryPart->getAccessoryPartId() == id)
371 {
372 return accessoryPart;
373 }
374 }
375 return 0;
376 }
377
writeWeapon(NamedNetBuffer & buffer,Weapon * weapon)378 bool AccessoryStore::writeWeapon(NamedNetBuffer &buffer, Weapon *weapon)
379 {
380 return writeAccessoryPart(buffer, weapon);
381 }
382
readWeapon(NetBufferReader & reader,Weapon * & weapon)383 bool AccessoryStore::readWeapon(NetBufferReader &reader, Weapon *&weapon)
384 {
385 weapon = 0;
386
387 AccessoryPart *accessoryPart;
388 if (!readAccessoryPart(reader, accessoryPart)) return false;
389 if (!accessoryPart) return true;
390 if (accessoryPart->getType() == AccessoryPart::AccessoryWeapon)
391 {
392 weapon = ((Weapon *) accessoryPart);
393 return true;
394 }
395 return false;
396 }
397
writeAccessoryPart(NamedNetBuffer & buffer,AccessoryPart * part)398 bool AccessoryStore::writeAccessoryPart(NamedNetBuffer &buffer, AccessoryPart *part)
399 {
400 if (part) buffer.addToBufferNamed("accessoryId", part->getAccessoryPartId());
401 else buffer.addToBufferNamed("accessoryId", (unsigned int) 0);
402 return true;
403 }
404
readAccessoryPart(NetBufferReader & reader,AccessoryPart * & part)405 bool AccessoryStore::readAccessoryPart(NetBufferReader &reader, AccessoryPart *&part)
406 {
407 part = 0;
408
409 unsigned int partId;
410 if (!reader.getFromBuffer(partId)) return false;
411 if (partId == 0) return true;
412
413 AccessoryPart *accessoryPart = findByAccessoryPartId(partId);
414 if (accessoryPart &&
415 accessoryPart->getAccessoryPartId() == partId)
416 {
417 part = accessoryPart;
418 return true;
419 }
420 return false;
421 }
422
writeEconomyToBuffer(NetBuffer & buffer)423 bool AccessoryStore::writeEconomyToBuffer(NetBuffer &buffer)
424 {
425 std::list<Accessory *> accessories = getAllAccessories();
426 buffer.addToBuffer((int) accessories.size());
427
428 std::list<Accessory *>::iterator itor;
429 for (itor = accessories.begin();
430 itor != accessories.end();
431 ++itor)
432 {
433 Accessory *accessory = (*itor);
434 buffer.addToBuffer(accessory->getAccessoryId());
435 buffer.addToBuffer(accessory->getPrice());
436 buffer.addToBuffer(accessory->getSellPrice());
437 }
438 return true;
439 }
440
readEconomyFromBuffer(NetBufferReader & reader)441 bool AccessoryStore::readEconomyFromBuffer(NetBufferReader &reader)
442 {
443 int noAccessories = 0;
444 if (!reader.getFromBuffer(noAccessories)) return false;
445 for (int a=0; a<noAccessories; a++)
446 {
447 unsigned int accessoryId = 0;
448 int price = 0, sellPrice = 0;
449 if (!reader.getFromBuffer(accessoryId)) return false;
450 if (!reader.getFromBuffer(price)) return false;
451 if (!reader.getFromBuffer(sellPrice)) return false;
452
453 Accessory *accessory = findByAccessoryId(accessoryId);
454 if (!accessory) return false;
455 accessory->setPrice(price);
456 accessory->setSellPrice(sellPrice);
457 }
458 return true;
459 }
460