Accessory sorting due to price.
[scorched3d.git] / src / common / weapons / AccessoryStore.cpp
blob895981cb14f4904dda4b8b43f032e2d7bbdb4a5a
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 <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>
30 AccessoryStore::AccessoryStore() : muzzleFlash_(0)
35 AccessoryStore::~AccessoryStore()
40 bool AccessoryStore::parseFile(
41 ScorchedContext &context, ProgressCounter *counter)
43 if (counter) counter->setNewOp(LANG_RESOURCE("LOADING_WEAPONS", "Loading Weapons"));
45 std::string fileName = S3D::getDataFile("data/accessories.xml");
46 clearAccessories();
48 XMLFile file;
49 if (!file.readFile(fileName.c_str()))
51 S3D::dialogMessage("AccessoryStore", S3D::formatStringBuffer(
52 "Failed to parse \"%s\"\n%s",
53 fileName.c_str(),
54 file.getParserError()));
55 return false;
58 // Check file exists
59 if (!file.getRootNode())
61 S3D::dialogMessage("AccessoryStore", S3D::formatStringBuffer(
62 "Failed to find accessory file \"%s\"",
63 fileName.c_str()));
64 return false;
67 // Itterate all of the accessories in the file
68 int noChildren = file.getRootNode()->getChildren().size();
69 int childCount = 0;
70 XMLNode *currentNode = 0;
71 while (file.getRootNode()->getNamedChild("accessory", currentNode, false))
73 if (counter) counter->setNewPercentage(
74 float(++childCount) / float(noChildren) * 100.0f);
76 // Parse the accessory
77 AccessoryCreateContext createContext(context);
78 Accessory *accessory = new Accessory();
79 if (!accessory->parseXML(createContext, currentNode))
81 return currentNode->returnError(
82 S3D::formatStringBuffer("Failed to create accessory \"%s\"",
83 accessory->getName()));
86 // Check uniqueness
87 if (findByPrimaryAccessoryName(accessory->getName()))
89 return currentNode->returnError(
90 S3D::formatStringBuffer("Accessory \"%s\" already exists",
91 accessory->getName()));
94 // Add the accessory
95 tabGroups_.insert(accessory->getTabGroupName());
96 accessories_.push_back(accessory);
98 // Add weapons to death animations, weighted by arms level
99 if (accessory->getAction()->getType() == AccessoryPart::AccessoryWeapon)
101 Weapon *weapon = (Weapon *) accessory->getAction();
102 if (0 == strcmp(accessory->getName(), "WeaponMuzzle"))
104 muzzleFlash_ = weapon;
106 else if (0 == strcmp(accessory->getName(), "WeaponDeathAnimation"))
108 deathAnimation_ = weapon;
112 // Add to the map so references can find it
113 parsingNodes_[accessory->getName()] = currentNode;
116 if (!muzzleFlash_)
118 return file.getRootNode()->returnError(
119 "Failed to find WeaponMuzzle weapon used for muzzle flash.");
121 if (!deathAnimation_)
123 return file.getRootNode()->returnError(
124 "Failed to find WeaponDeathAnimation weapon used for tank explosions.");
127 // Clear mapping as it now contains invalid pointers
128 parsingNodes_.clear();
129 return file.getRootNode()->failChildren();
132 AccessoryPart *AccessoryStore::createAccessoryPart(
133 AccessoryCreateContext &context,
134 Accessory *parent, XMLNode *currentNode)
136 XMLNode *typeNode = 0;
137 if (!currentNode->getNamedParameter("type", typeNode)) return false;
139 AccessoryPart *accessoryPart =
140 AccessoryMetaRegistration::getNewAccessory(typeNode->getContent(), this);
141 if (!accessoryPart)
143 S3D::dialogMessage("AccessoryStore", S3D::formatStringBuffer(
144 "Failed to find accessory part type \"%s\"",
145 typeNode->getContent()));
146 return 0;
148 // Set the parent accessory
149 accessoryPart->setParent(parent);
151 // Tell this accessory instance to initialize its settings from
152 // the current accessory xml definition node
153 if (!accessoryPart->parseXML(context, currentNode)) return 0;
155 // There should not be any children left
156 // Any that are, are children that have not been
157 // handled by the parse routine
158 if (!currentNode->failChildren()) return 0;
159 DIALOG_ASSERT(accessoryPart->getParent());
161 // Add the accessory
162 accessoryParts_.push_back(accessoryPart);
163 return accessoryPart;
166 void AccessoryStore::sortList(std::list<Accessory *> &accList, int sortKey)
168 if (sortKey)
170 std::vector<Accessory *> accVector;
171 std::list<Accessory *>::iterator itor;
172 for (itor = accList.begin();
173 itor != accList.end();
174 itor++)
176 accVector.push_back(*itor);
179 // Crudely sort by name or price
180 // stl sort method list is broken in visual c 6
181 // bubble sort
182 bool changed = true;
183 while (changed)
185 changed = false;
186 for (int i=0; i<int(accVector.size())-1; i++)
188 bool swap = false;
190 // When sorting by price, use accessory name as a
191 // secondary sort key.
193 if ((sortKey == SortName) ||
194 (sortKey == SortPrice && accVector[i]->getPrice() == accVector[i + 1]->getPrice()))
196 swap = strcmp(accVector[i]->getName(), accVector[i + 1]->getName()) < 0;
198 else if (sortKey == SortPrice)
200 swap = accVector[i]->getPrice() < accVector[i + 1]->getPrice();
203 if (swap)
205 Accessory *tmp = accVector[i];
206 accVector[i] = accVector[i+1];
207 accVector[i+1] = tmp;
208 changed = true;
209 break;
214 accList.clear();
215 for (int i=0; i<int(accVector.size()); i++)
217 accList.push_front(accVector[i]);
220 else
222 std::set<Accessory *> accessorySet;
223 std::list<Accessory *>::iterator setItor;
224 for (setItor = accList.begin();
225 setItor != accList.end();
226 setItor++)
228 Accessory *accessory = *setItor;
229 accessorySet.insert(accessory);
232 accList.clear();
233 std::list<Accessory *>::iterator itor;
234 for (itor = accessories_.begin();
235 itor != accessories_.end();
236 itor++)
238 Accessory *accessory = *itor;
239 if (accessorySet.find(accessory) != accessorySet.end())
241 accList.push_back(accessory);
247 std::list<Accessory *> AccessoryStore::getAllAccessoriesByTabGroup(
248 const char *tabgroup, int sortKey)
250 std::list<Accessory *> result;
251 std::list<Accessory *>::iterator itor;
252 for (itor = accessories_.begin();
253 itor != accessories_.end();
254 itor++)
256 Accessory *accessory = (*itor);
257 if (0 == strcmp(tabgroup, accessory->getTabGroupName()))
259 result.push_back(*itor);
263 if (sortKey) sortList(result, sortKey);
264 return result;
267 std::list<Accessory *> AccessoryStore::getAllAccessories(int sortKey)
269 std::list<Accessory *> result;
270 std::list<Accessory *>::iterator itor;
271 for (itor = accessories_.begin();
272 itor != accessories_.end();
273 itor++)
275 result.push_back(*itor);
278 if (sortKey) sortList(result, sortKey);
279 return result;
282 Weapon *AccessoryStore::getMuzzelFlash()
284 return muzzleFlash_;
287 Weapon *AccessoryStore::getDeathAnimation()
289 return deathAnimation_;
292 Accessory *AccessoryStore::findByPrimaryAccessoryName(const char *name)
294 std::list<Accessory *>::iterator itor;
295 for (itor = accessories_.begin();
296 itor != accessories_.end();
297 itor++)
299 Accessory *accessory = (*itor);
300 if (strcmp(accessory->getName(), name) == 0)
302 return accessory;
305 return 0;
308 Accessory *AccessoryStore::findByAccessoryId(unsigned int id)
310 std::list<Accessory *>::iterator itor;
311 for (itor = accessories_.begin();
312 itor != accessories_.end();
313 itor++)
315 Accessory *accessory = (*itor);
316 if (accessory->getAccessoryId() == id)
318 return accessory;
321 return 0;
324 AccessoryPart *AccessoryStore::findAccessoryPartByAccessoryId(unsigned int id, const char *type)
326 std::list<AccessoryPart *>::iterator itor;
327 for (itor = accessoryParts_.begin();
328 itor != accessoryParts_.end();
329 itor++)
331 AccessoryPart *accessoryPart = (*itor);
332 if (accessoryPart->getParent()->getAccessoryId() == id &&
333 0 == strcmp(accessoryPart->getAccessoryTypeName(), type))
335 return accessoryPart;
338 return 0;
341 AccessoryPart *AccessoryStore::findByAccessoryPartId(unsigned int id)
343 std::list<AccessoryPart *>::iterator itor;
344 for (itor = accessoryParts_.begin();
345 itor != accessoryParts_.end();
346 itor++)
348 AccessoryPart *accessoryPart = (*itor);
349 if (accessoryPart->getAccessoryPartId() == id)
351 return accessoryPart;
354 return 0;
357 void AccessoryStore::clearAccessories()
359 AccessoryPart::resetAccessoryPartIds();
360 Accessory::resetAccessoryIds();
361 muzzleFlash_ = 0;
362 deathAnimation_ = 0;
363 while (!accessories_.empty())
365 Accessory *accessory = accessories_.front();
366 accessories_.pop_front();
367 delete accessory;
369 while (!accessoryParts_.empty())
371 AccessoryPart *accessoryPart = accessoryParts_.front();
372 accessoryParts_.pop_front();
373 delete accessoryPart;
377 bool AccessoryStore::writeWeapon(NetBuffer &buffer, Weapon *weapon)
379 return writeAccessoryPart(buffer, weapon);
382 Weapon *AccessoryStore::readWeapon(NetBufferReader &reader)
384 AccessoryPart *accessoryPart = readAccessoryPart(reader);
385 if (accessoryPart &&
386 accessoryPart->getType() == AccessoryPart::AccessoryWeapon)
388 return ((Weapon *) accessoryPart);
390 return 0;
393 bool AccessoryStore::writeAccessoryPart(NetBuffer &buffer, AccessoryPart *part)
395 if (part) buffer.addToBuffer(part->getAccessoryPartId());
396 else buffer.addToBuffer((unsigned int) 0);
397 return true;
400 AccessoryPart *AccessoryStore::readAccessoryPart(NetBufferReader &reader)
402 unsigned int partId;
403 if (!reader.getFromBuffer(partId)) return 0;
404 AccessoryPart *accessoryPart = findByAccessoryPartId(partId);
405 if (accessoryPart &&
406 accessoryPart->getAccessoryPartId() == partId)
408 return accessoryPart;
410 return 0;
413 bool AccessoryStore::writeEconomyToBuffer(NetBuffer &buffer)
415 std::list<Accessory *> accessories = getAllAccessories();
416 buffer.addToBuffer((int) accessories.size());
418 std::list<Accessory *>::iterator itor;
419 for (itor = accessories.begin();
420 itor != accessories.end();
421 itor++)
423 Accessory *accessory = (*itor);
424 buffer.addToBuffer(accessory->getAccessoryId());
425 buffer.addToBuffer(accessory->getPrice());
426 buffer.addToBuffer(accessory->getSellPrice());
428 return true;
431 bool AccessoryStore::readEconomyFromBuffer(NetBufferReader &reader)
433 int noAccessories = 0;
434 if (!reader.getFromBuffer(noAccessories)) return false;
435 for (int a=0; a<noAccessories; a++)
437 unsigned int accessoryId = 0;
438 int price = 0, sellPrice = 0;
439 if (!reader.getFromBuffer(accessoryId)) return false;
440 if (!reader.getFromBuffer(price)) return false;
441 if (!reader.getFromBuffer(sellPrice)) return false;
443 Accessory *accessory = findByAccessoryId(accessoryId);
444 if (!accessory) return false;
445 accessory->setPrice(price);
446 accessory->setSellPrice(sellPrice);
448 return true;