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