1 // ==============================================================
2 //	This file is part of Glest (www.glest.org)
3 //
4 //	Copyright (C) 2001-2008 Martiño Figueroa
5 //
6 //	You can redistribute this code and/or modify it under
7 //	the terms of the GNU General Public License as published
8 //	by the Free Software Foundation; either version 2 of the
9 //	License, or (at your option) any later version
10 // ==============================================================
11 
12 #include "faction_type.h"
13 
14 #include "logger.h"
15 #include "util.h"
16 #include "xml_parser.h"
17 #include "tech_tree.h"
18 #include "resource.h"
19 #include "renderer.h"
20 #include "platform_util.h"
21 #include "game_util.h"
22 #include "conversion.h"
23 #include "leak_dumper.h"
24 
25 using namespace Shared::Util;
26 using namespace Shared::Xml;
27 
28 namespace Glest{ namespace Game{
29 
30 // ======================================================
31 //          Class FactionType
32 // ======================================================
33 
FactionType()34 FactionType::FactionType() {
35 	music			= NULL;
36 	personalityType = fpt_Normal;
37 	isLinked		= false;
38 	healthbarheight= -100.0f;
39 	healthbarthickness= 0.11f;
40 	healthbarVisible=hbvUndefined;
41 	healthbarBorderTextureEnabled=false;
42 	healthbarBackgroundTextureEnabled=false;
43 	healthbarLineBorder=true;
44 	healthbarTexture=NULL;
45 	healthbarBackgroundTexture=NULL;
46 	flatParticlePositions=false;
47 }
48 
49 //load a faction, given a directory
load(const string & factionName,const TechTree * techTree,Checksum * checksum,Checksum * techtreeChecksum,std::map<string,vector<pair<string,string>>> & loadedFileList,bool validationMode)50 void FactionType::load(const string &factionName, const TechTree *techTree, Checksum* checksum,
51 		Checksum *techtreeChecksum,
52 		std::map<string,vector<pair<string, string> > > &loadedFileList,
53 		bool validationMode) {
54 
55 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
56 
57 	string techTreePath = techTree->getPath();
58 	string techTreeName=techTree->getNameUntranslated();
59 	string currentPath = "";
60 
61 	//open xml file
62 	string path="";
63 	XmlTree xmlTree;
64 	const XmlNode *factionNode;
65 
66 	//printf("\n>>> factionname=%s\n",factionName.c_str());
67 	for(bool realFactionPathFound=false;realFactionPathFound == false;) {
68 		currentPath = techTreePath + "factions/" + factionName;
69 		endPathWithSlash(currentPath);
70 
71 	    name= lastDir(currentPath);
72 
73 	    // Add special Observer Faction
74 	    //Lang &lang= Lang::getInstance();
75 	    if(name == formatString(GameConstants::OBSERVER_SLOTNAME)) {
76 	    	personalityType = fpt_Observer;
77 	    }
78 
79 	    if(personalityType == fpt_Normal) {
80 			string tmppath= currentPath + factionName +".xml";
81 			std::map<string,string> mapExtraTagReplacementValues;
82 	//		mapExtraTagReplacementValues["$COMMONDATAPATH"] = techTreePath + "/commondata/";
83 			//printf("current $COMMONDATAPATH = %s\n",mapExtraTagReplacementValues["$COMMONDATAPATH"].c_str());
84 			XmlTree xmlTree;
85 			xmlTree.load(tmppath, Properties::getTagReplacementValues(&mapExtraTagReplacementValues));
86 
87 
88 			const XmlNode *rootNode= xmlTree.getRootNode();
89 
90 			if(rootNode->getName()=="link") {
91 				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"Faction [%s] is a linked faction\n",name.c_str());
92 
93 				isLinked = true;
94 				const XmlNode *techTreeNode= rootNode->getChild("techtree");
95 				const string linkedTechTreeName=techTreeNode->getAttribute("name")->getRestrictedValue();
96 	//			const XmlNode *factionLinkNode= rootNode->getChild("faction");
97 	//			string linkedFactionName=factionLinkNode->getAttribute("name")->getRestrictedValue();
98 				string linkedTechTreePath=techTree->findPath(linkedTechTreeName);
99 				techTreePath=linkedTechTreePath;
100 				endPathWithSlash(techTreePath);
101 				techTreeName=linkedTechTreeName;
102 
103 				string linkedCurrentPath = techTreePath + "factions/" + factionName;
104 				endPathWithSlash(linkedCurrentPath);
105 				string linkedTmppath= linkedCurrentPath + factionName +".xml";
106 
107 				//printf("linkedTmppath [%s] linkedCurrentPath [%s]\n",linkedTmppath.c_str(),linkedCurrentPath.c_str());
108 
109 				loadedFileList[linkedTmppath].push_back(make_pair(linkedCurrentPath,linkedCurrentPath));
110 				loadedFileList[tmppath].push_back(make_pair(currentPath,currentPath));
111 				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"techTreePath [%s] techTreeName [%s]\n",techTreePath.c_str(),techTreeName.c_str());
112 			}
113 			else {
114 				// stop looking for new path, no more links ...
115 				//xmlTree.load(tmppath, Properties::getTagReplacementValues(&mapExtraTagReplacementValues));
116 
117 				loadedFileList[tmppath].push_back(make_pair(currentPath,currentPath));
118 
119 				realFactionPathFound=true;
120 				//printf("techPath found! %s\n",tmppath.c_str());
121 
122 				path=tmppath;
123 			}
124 	    }
125 	    else {
126 	    	break;
127 	    }
128 	}
129 
130 	char szBuf[8096]="";
131 	snprintf(szBuf,8096,Lang::getInstance().getString("LogScreenGameLoadingFactionType","",true).c_str(),formatString(this->getName()).c_str());
132 	Logger::getInstance().add(szBuf, true);
133 
134 	if(personalityType == fpt_Normal) {
135 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"Loading faction [%s] currentPath [%s]\n",path.c_str(),currentPath.c_str());
136 
137 		checksum->addFile(path);
138 		techtreeChecksum->addFile(path);
139 
140 		// a1) preload units
141 		//string unitsPath= currentPath + "units/*.";
142 		string unitsPath= currentPath + "units/";
143 		vector<string> unitFilenames;
144 		//findAll(unitsPath, unitFilenames);
145 		findDirs(unitsPath, unitFilenames,false,false);
146 
147 		unitTypes.resize(unitFilenames.size());
148 
149 		for(int i = 0; i < (int)unitTypes.size(); ++i) {
150 			string str= currentPath + "units/" + unitFilenames[i];
151 			unitTypes[i].preLoad(str);
152 
153 			SDL_PumpEvents();
154 		}
155 
156 		// a2) preload upgrades
157 		//string upgradesPath= currentPath + "upgrades/*.";
158 		string upgradesPath= currentPath + "upgrades/";
159 		vector<string> upgradeFilenames;
160 		//findAll(upgradesPath, upgradeFilenames, false, false);
161 		findDirs(upgradesPath, upgradeFilenames,false,false);
162 
163 		upgradeTypes.resize(upgradeFilenames.size());
164 		for(int i = 0; i < (int)upgradeTypes.size(); ++i) {
165 			string str= currentPath + "upgrades/" + upgradeFilenames[i];
166 			upgradeTypes[i].preLoad(str);
167 
168 			SDL_PumpEvents();
169 		}
170 
171 		// b1) load units
172 		try {
173 			Logger &logger= Logger::getInstance();
174 			int progressBaseValue=logger.getProgress();
175 			for(int i = 0; i < (int)unitTypes.size(); ++i) {
176 				string str= currentPath + "units/" + unitTypes[i].getName();
177 
178 				try {
179 					unitTypes[i].loaddd(i, str, techTree,techTreePath, this, checksum,techtreeChecksum,
180 						loadedFileList,validationMode);
181 					logger.setProgress(progressBaseValue+(int)((((double)i + 1.0) / (double)unitTypes.size()) * 100.0/techTree->getTypeCount()));
182 					SDL_PumpEvents();
183 				}
184 				catch(megaglest_runtime_error& ex) {
185 					if(validationMode == false) {
186 						throw;
187 					}
188 					else {
189 						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
190 					}
191 				}
192 			}
193 		}
194 	    catch(megaglest_runtime_error& ex) {
195 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
196 			throw megaglest_runtime_error("Error loading units: "+ currentPath + "\nMessage: " + ex.what(),!ex.wantStackTrace());
197 	    }
198 		catch(const exception &e) {
199 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,e.what());
200 			throw megaglest_runtime_error("Error loading units: "+ currentPath + "\nMessage: " + e.what());
201 		}
202 
203 		// b2) load upgrades
204 		try{
205 			for(int i = 0; i < (int)upgradeTypes.size(); ++i) {
206 				string str= currentPath + "upgrades/" + upgradeTypes[i].getName();
207 
208 				try {
209 					upgradeTypes[i].load(str, techTree, this, checksum,
210 							techtreeChecksum,loadedFileList,validationMode);
211 				}
212 				catch(megaglest_runtime_error& ex) {
213 					if(validationMode == false) {
214 						throw;
215 					}
216 					else {
217 						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
218 					}
219 				}
220 
221 				SDL_PumpEvents();
222 			}
223 		}
224 		catch(const exception &e){
225 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,e.what());
226 			throw megaglest_runtime_error("Error loading upgrades: "+ currentPath + "\n" + e.what());
227 		}
228 
229 		string tmppath= currentPath + factionName +".xml";
230 
231 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"Loading faction xml [%s]\n",tmppath.c_str());
232 
233 		std::map<string,string> mapExtraTagReplacementValues;
234 		mapExtraTagReplacementValues["$COMMONDATAPATH"] = techTreePath + "/commondata/";
235 		//printf("current $COMMONDATAPATH = %s\n",mapExtraTagReplacementValues["$COMMONDATAPATH"].c_str());
236 		xmlTree.load(tmppath, Properties::getTagReplacementValues(&mapExtraTagReplacementValues));
237 
238 
239 		factionNode=xmlTree.getRootNode();
240 		//read starting resources
241 		//printf("factionNode->getName()=%s",factionNode->getName().c_str());
242 		const XmlNode *startingResourcesNode= factionNode->getChild("starting-resources");
243 
244 		startingResources.resize(startingResourcesNode->getChildCount());
245 		for(int i = 0; i < (int)startingResources.size(); ++i) {
246 			const XmlNode *resourceNode= startingResourcesNode->getChild("resource", i);
247 			string name= resourceNode->getAttribute("name")->getRestrictedValue();
248 			int amount= resourceNode->getAttribute("amount")->getIntValue();
249 
250 			try {
251 				startingResources[i].init(techTree->getResourceType(name), amount);
252 			}
253 			catch(megaglest_runtime_error& ex) {
254 				if(validationMode == false) {
255 					throw;
256 				}
257 				else {
258 					SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\nFor FactionType: %s for StartResource: %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what(),this->name.c_str(),name.c_str());
259 				}
260 			}
261 
262 			SDL_PumpEvents();
263 		}
264 
265 		//read starting units
266 		const XmlNode *startingUnitsNode= factionNode->getChild("starting-units");
267 		for(int i = 0; i < (int)startingUnitsNode->getChildCount(); ++i) {
268 			const XmlNode *unitNode= startingUnitsNode->getChild("unit", i);
269 			string name= unitNode->getAttribute("name")->getRestrictedValue();
270 			int amount= unitNode->getAttribute("amount")->getIntValue();
271 			startingUnits.push_back(PairPUnitTypeInt(getUnitType(name), amount));
272 
273 			SDL_PumpEvents();
274 		}
275 
276 		//read music
277 		const XmlNode *musicNode= factionNode->getChild("music");
278 		bool value= musicNode->getAttribute("value")->getBoolValue();
279 		if(value) {
280 			music= new StrSound();
281 			music->open(musicNode->getAttribute("path")->getRestrictedValue(currentPath));
282 			loadedFileList[musicNode->getAttribute("path")->getRestrictedValue(currentPath)].push_back(make_pair(path,musicNode->getAttribute("path")->getRestrictedValue()));
283 		}
284 
285 		if(factionNode->hasChild("flat-particle-positions")) {
286 			const XmlNode *node= factionNode->getChild("flat-particle-positions");
287 			flatParticlePositions = node->getAttribute("value")->getBoolValue();
288 		}
289 
290 		//healthbar
291 		if(factionNode->hasChild("healthbar")) {
292 			const XmlNode *healthbarNode= factionNode->getChild("healthbar");
293 			if(healthbarNode->hasChild("height")) {
294 				healthbarheight= healthbarNode->getChild("height")->getAttribute("value")->getFloatValue();
295 			}
296 			if(healthbarNode->hasChild("thickness")) {
297 				healthbarthickness= healthbarNode->getChild("thickness")->getAttribute("value")->getFloatValue(0.f, 1.f);
298 			}
299 			if(healthbarNode->hasChild("visible")) {
300 				string healthbarVisibleString=healthbarNode->getChild("visible")->getAttribute("value")->getValue();
301 				vector<string> v=split(healthbarVisibleString,"|");
302 				for (int i = 0; i < (int)v.size(); ++i) {
303 					string current=trim(v[i]);
304 					if(current=="always") {
305 						healthbarVisible=healthbarVisible|hbvAlways;
306 					} else if(current=="selected") {
307 						healthbarVisible=healthbarVisible|hbvSelected;
308 					} else if(current=="ifNeeded") {
309 						healthbarVisible=healthbarVisible|hbvIfNeeded;
310 					} else if(current=="off") {
311 						healthbarVisible=healthbarVisible|hbvOff;
312 					} else {
313 						throw megaglest_runtime_error("Unknown Healthbar Visible Option: " + current, true);
314 					}
315 				}
316 			}
317 			if(healthbarNode->hasChild("borderTexture")) {
318 				healthbarBorderTextureEnabled=healthbarNode->getChild("borderTexture")->getAttribute("enabled")->getBoolValue();
319 				if(healthbarBorderTextureEnabled && healthbarNode->getChild("borderTexture")->hasAttribute("path")) {
320 					healthbarTexture= Renderer::getInstance().newTexture2D(rsGame);
321 					if(healthbarTexture) {
322 						healthbarTexture->load(healthbarNode->getChild("borderTexture")->getAttribute("path")->getRestrictedValue(currentPath));
323 					}
324 					loadedFileList[healthbarNode->getChild("borderTexture")->getAttribute("path")->getRestrictedValue(currentPath)].push_back(make_pair(path,healthbarNode->getChild("borderTexture")->getAttribute("path")->getRestrictedValue()));
325 					}
326 				}
327 			if(healthbarNode->hasChild("backgroundTexture")) {
328 				healthbarBackgroundTextureEnabled=healthbarNode->getChild("backgroundTexture")->getAttribute("enabled")->getBoolValue();
329 				if(healthbarBackgroundTextureEnabled && healthbarNode->getChild("backgroundTexture")->hasAttribute("path")) {
330 					healthbarBackgroundTexture= Renderer::getInstance().newTexture2D(rsGame);
331 					if(healthbarBackgroundTexture) {
332 						healthbarBackgroundTexture->load(healthbarNode->getChild("backgroundTexture")->getAttribute("path")->getRestrictedValue(currentPath));
333 					}
334 					loadedFileList[healthbarNode->getChild("backgroundTexture")->getAttribute("path")->getRestrictedValue(currentPath)].push_back(make_pair(path,healthbarNode->getChild("backgroundTexture")->getAttribute("path")->getRestrictedValue()));
335 				}
336 			}
337 			if(healthbarNode->hasChild("lineBorder")) {
338 				healthbarLineBorder= healthbarNode->getChild("lineBorder")->getAttribute("enabled")->getBoolValue();
339 			}
340 
341 		}
342 
343 		//read ai behavior
344 		if(factionNode->hasChild("ai-behavior") == true) {
345 			const XmlNode *aiNode= factionNode->getChild("ai-behavior");
346 			if(aiNode->hasAttribute("min-static-resource-count") == true) {
347 				mapAIBehaviorStaticOverrideValues[aibsvcMinStaticResourceCount] = aiNode->getAttribute("min-static-resource-count")->getIntValue();
348 			}
349 
350 			if(aiNode->hasChild("static-values") == true) {
351 				const XmlNode *aiNodeUnits= aiNode->getChild("static-values");
352 				for(int i = 0; i < (int)aiNodeUnits->getChildCount(); ++i) {
353 					const XmlNode *unitNode= aiNodeUnits->getChild("static", i);
354 					AIBehaviorStaticValueCategory type  = aibsvcMaxBuildRadius;
355 					if(unitNode->hasAttribute("type") == true) {
356 						type  = static_cast<AIBehaviorStaticValueCategory>(
357 								unitNode->getAttribute("type")->getIntValue());
358 					}
359 					else {
360 						type = EnumParser<AIBehaviorStaticValueCategory>::getEnum(
361 								unitNode->getAttribute("type-name")->getValue());
362 						//printf("Discovered overriden static value for AI, type = %d, value = %d\n",type,value);
363 					}
364 
365 					int value = unitNode->getAttribute("value")->getIntValue();
366 					mapAIBehaviorStaticOverrideValues[type]=value;
367 					//printf("Discovered overriden static value for AI, type = %d, value = %d\n",type,value);
368 				}
369 			}
370 
371 			if(aiNode->hasChild("worker-units") == true) {
372 				const XmlNode *aiNodeUnits= aiNode->getChild("worker-units");
373 				for(int i = 0; i < (int)aiNodeUnits->getChildCount(); ++i) {
374 					const XmlNode *unitNode= aiNodeUnits->getChild("unit", i);
375 					string name= unitNode->getAttribute("name")->getRestrictedValue();
376 					int minimum= unitNode->getAttribute("minimum")->getIntValue();
377 
378 					mapAIBehaviorUnitCategories[aibcWorkerUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum));
379 				}
380 			}
381 			if(aiNode->hasChild("warrior-units") == true) {
382 				const XmlNode *aiNodeUnits= aiNode->getChild("warrior-units");
383 				for(int i = 0; i < (int)aiNodeUnits->getChildCount(); ++i) {
384 					const XmlNode *unitNode= aiNodeUnits->getChild("unit", i);
385 					string name= unitNode->getAttribute("name")->getRestrictedValue();
386 					int minimum= unitNode->getAttribute("minimum")->getIntValue();
387 
388 					mapAIBehaviorUnitCategories[aibcWarriorUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum));
389 				}
390 			}
391 			if(aiNode->hasChild("resource-producer-units") == true) {
392 				const XmlNode *aiNodeUnits= aiNode->getChild("resource-producer-units");
393 				for(int i = 0; i < (int)aiNodeUnits->getChildCount(); ++i) {
394 					const XmlNode *unitNode= aiNodeUnits->getChild("unit", i);
395 					string name= unitNode->getAttribute("name")->getRestrictedValue();
396 					int minimum= unitNode->getAttribute("minimum")->getIntValue();
397 
398 					mapAIBehaviorUnitCategories[aibcResourceProducerUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum));
399 				}
400 			}
401 			if(aiNode->hasChild("building-units") == true) {
402 				const XmlNode *aiNodeUnits= aiNode->getChild("building-units");
403 				for(int i = 0; i < (int)aiNodeUnits->getChildCount(); ++i) {
404 					const XmlNode *unitNode= aiNodeUnits->getChild("unit", i);
405 					string name= unitNode->getAttribute("name")->getRestrictedValue();
406 					int minimum= unitNode->getAttribute("minimum")->getIntValue();
407 
408 					mapAIBehaviorUnitCategories[aibcBuildingUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum));
409 				}
410 			}
411 
412 			if(aiNode->hasChild("upgrades") == true) {
413 				const XmlNode *aiNodeUpgrades= aiNode->getChild("upgrades");
414 				for(int i = 0; i < (int)aiNodeUpgrades->getChildCount(); ++i) {
415 					const XmlNode *upgradeNode= aiNodeUpgrades->getChild("upgrade", i);
416 					string name= upgradeNode->getAttribute("name")->getRestrictedValue();
417 
418 					vctAIBehaviorUpgrades.push_back(getUpgradeType(name));
419 				}
420 			}
421 		}
422 	}
423 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
424 }
425 
getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const426 int FactionType::getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const {
427 	int result = INT_MAX;
428 	std::map<AIBehaviorStaticValueCategory, int >::const_iterator iterFind =
429 			mapAIBehaviorStaticOverrideValues.find(type);
430 	if(iterFind != mapAIBehaviorStaticOverrideValues.end()) {
431 		result = iterFind->second;
432 	}
433 	return result;
434 }
435 
getAIBehaviorUnits(AIBehaviorUnitCategory category) const436 const std::vector<FactionType::PairPUnitTypeInt> FactionType::getAIBehaviorUnits(AIBehaviorUnitCategory category) const {
437 	std::map<AIBehaviorUnitCategory, std::vector<PairPUnitTypeInt> >::const_iterator iterFind = mapAIBehaviorUnitCategories.find(category);
438 	if(iterFind != mapAIBehaviorUnitCategories.end()) {
439 		return iterFind->second;
440 	}
441 	return std::vector<FactionType::PairPUnitTypeInt>();
442 }
443 
~FactionType()444 FactionType::~FactionType(){
445 	delete music;
446 	music = NULL;
447 }
448 
validateFactionType()449 std::vector<std::string> FactionType::validateFactionType() {
450 	std::vector<std::string> results;
451 
452 	const uint32 MAX_BITRATE_WARNING = 200000;
453 	StrSound *factionMusic = getMusic();
454 	if(factionMusic != NULL && factionMusic->getInfo()->getBitRate() > MAX_BITRATE_WARNING) {
455 		char szBuf[8096]="";
456 		snprintf(szBuf,8096,"The Faction [%s] has the music [%s]\nwhich has a bitrate of [%u] which may cause some sound drivers to crash, please use a bitrate of %d or less!",this->getName().c_str(),factionMusic->getFileName().c_str(),factionMusic->getInfo()->getBitRate(),MAX_BITRATE_WARNING);
457 		results.push_back(szBuf);
458 	}
459 
460     for(int i=0; i < (int)unitTypes.size(); ++i){
461     	UnitType &unitType = unitTypes[i];
462 
463     	for(int i = 0; i < (int)unitType.getSelectionSounds().getSounds().size(); ++i) {
464     		StaticSound *sound = unitType.getSelectionSounds().getSounds()[i];
465     		if(sound != NULL && sound->getInfo()->getBitRate() > MAX_BITRATE_WARNING) {
466 				char szBuf[8096]="";
467 				snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the sound [%s]\nwhich has a bitrate of [%u] which may cause some sound drivers to crash, please use a bitrate of %d or less!",unitType.getName().c_str(),this->getName().c_str(),sound->getFileName().c_str(),sound->getInfo()->getBitRate(),MAX_BITRATE_WARNING);
468 				results.push_back(szBuf);
469     		}
470     	}
471     	for(int i = 0; i < (int)unitType.getCommandSounds().getSounds().size(); ++i) {
472     		StaticSound *sound = unitType.getCommandSounds().getSounds()[i];
473     		if(sound != NULL && sound->getInfo()->getBitRate() > MAX_BITRATE_WARNING) {
474 				char szBuf[8096]="";
475 				snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the sound [%s]\nwhich has a bitrate of [%u] which may cause some sound drivers to crash, please use a bitrate of %d or less!",unitType.getName().c_str(),this->getName().c_str(),sound->getFileName().c_str(),sound->getInfo()->getBitRate(),MAX_BITRATE_WARNING);
476 				results.push_back(szBuf);
477     		}
478     	}
479 
480     	int morphCommandCount = 0;
481     	for(int j = 0; j < (int)unitType.getCommandTypeCount(); ++j) {
482     		const CommandType *cmdType = unitType.getCommandType(j);
483     		if(cmdType != NULL) {
484     	    	// Check every unit's commands to validate that for every upgrade-requirements
485     	    	// upgrade we have a unit that can do the upgrade in the faction.
486 				for(int k = 0; k < cmdType->getUpgradeReqCount(); ++k) {
487 					const UpgradeType *upgradeType = cmdType->getUpgradeReq(k);
488 
489 					if(upgradeType != NULL) {
490 						// Now lets find a unit that can produced-upgrade this upgrade
491 						bool foundUpgraderUnit = false;
492 						for(int l=0; l < (int)unitTypes.size() && foundUpgraderUnit == false; ++l){
493 							UnitType &unitType2 = unitTypes[l];
494 							for(int m = 0; m < unitType2.getCommandTypeCount() && foundUpgraderUnit == false; ++m) {
495 								const CommandType *cmdType2 = unitType2.getCommandType(m);
496 								if(cmdType2 != NULL && dynamic_cast<const UpgradeCommandType *>(cmdType2) != NULL) {
497 									const UpgradeCommandType *uct = dynamic_cast<const UpgradeCommandType *>(cmdType2);
498 									if(uct != NULL) {
499 										const UpgradeType *upgradeType2 = uct->getProducedUpgrade();
500 										if(upgradeType2 != NULL && upgradeType2->getName() == upgradeType->getName()) {
501 											 foundUpgraderUnit = true;
502 											 break;
503 										}
504 									}
505 								}
506 							}
507 						}
508 
509 						if(foundUpgraderUnit == false) {
510 							char szBuf[8096]="";
511 							snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the command [%s]\nwhich has upgrade requirement [%s] but there are no units able to perform the upgrade!",unitType.getName().c_str(),this->getName().c_str(),cmdType->getName().c_str(),upgradeType->getName().c_str());
512 							results.push_back(szBuf);
513 						}
514 					}
515 				}
516 
517 				// Ensure for each build type command that the build units
518 				// exist in this faction
519 				if(cmdType->getClass() == ccBuild) {
520 					const BuildCommandType *build = dynamic_cast<const BuildCommandType *>(cmdType);
521 					if(build == NULL) {
522 						throw megaglest_runtime_error("build == NULL");
523 					}
524 					for(int k = 0; k < build->getBuildingCount(); ++k) {
525 						const UnitType *buildUnit = build->getBuilding(k);
526 
527 						// Now lets find the unit that we should be able to build
528 						bool foundUnit = false;
529 						for(int l=0; l < (int)unitTypes.size() && foundUnit == false; ++l){
530 							UnitType &unitType2 = unitTypes[l];
531 							if(unitType2.getName() == buildUnit->getName()) {
532 								foundUnit = true;
533 
534 								// Now also validate the the unit to be built
535 								// has a be_built_skill
536 						    	if(buildUnit->hasSkillClass(scBeBuilt) == false) {
537 									char szBuf[8096]="";
538 									snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the command [%s]\nwhich can build the Unit [%s] but the Unit to be built\ndoes not have the skill class [be_built_skill] in this faction!",unitType.getName().c_str(),this->getName().c_str(),cmdType->getName().c_str(),buildUnit->getName().c_str());
539 									results.push_back(szBuf);
540 						    	}
541 
542 						    	break;
543 							}
544 						}
545 
546 						if(foundUnit == false) {
547 							char szBuf[8096]="";
548 							snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the command [%s]\nwhich can build the Unit [%s] but the Unit to be built does not exist in this faction!",unitType.getName().c_str(),this->getName().c_str(),cmdType->getName().c_str(),buildUnit->getName().c_str());
549 							results.push_back(szBuf);
550 						}
551 					}
552 				}
553 				// Ensure for each repair type command that the repair units
554 				// exist in this faction
555 				if(cmdType->getClass() == ccRepair) {
556 					const RepairCommandType *repair = dynamic_cast<const RepairCommandType *>(cmdType);
557 					if(repair == NULL) {
558 						throw megaglest_runtime_error("repair == NULL");
559 					}
560 					for(int k = 0; k < repair->getRepairCount(); ++k) {
561 						const UnitType *repairUnit = repair->getRepair(k);
562 
563 						// Now lets find the unit that we should be able to repair
564 						bool foundUnit = false;
565 						for(int l=0; l < (int)unitTypes.size() && foundUnit == false; ++l){
566 							UnitType &unitType2 = unitTypes[l];
567 							if(unitType2.getName() == repairUnit->getName()) {
568 								 foundUnit = true;
569 								 break;
570 							}
571 						}
572 
573 						if(foundUnit == false) {
574 							char szBuf[8096]="";
575 							snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the command [%s]\nwhich can repair the Unit [%s] but the Unit to be repaired does not exist in this faction!",unitType.getName().c_str(),this->getName().c_str(),cmdType->getName().c_str(),repairUnit->getName().c_str());
576 							results.push_back(szBuf);
577 						}
578 					}
579 				}
580 				// Ensure for each morph type command that the morph units
581 				// exist in this faction
582 				if(cmdType->getClass() == ccMorph) {
583 					const MorphCommandType *morph = dynamic_cast<const MorphCommandType *>(cmdType);
584 					if(morph != NULL) {
585 						morphCommandCount++;
586 						const UnitType *morphUnit = morph->getMorphUnit();
587 
588 						// Now lets find the unit that we should be able to morph
589 						// to
590 						bool foundUnit = false;
591 						for(int l=0; l < (int)unitTypes.size() && foundUnit == false; ++l){
592 							UnitType &unitType2 = unitTypes[l];
593 							if(unitType2.getName() == morphUnit->getName()) {
594 								 foundUnit = true;
595 								 break;
596 							}
597 						}
598 
599 						if(foundUnit == false) {
600 							char szBuf[8096]="";
601 							snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the command [%s]\nwhich can morph into the Unit [%s] but the Unit to be morphed to does not exist in this faction!",unitType.getName().c_str(),this->getName().c_str(),cmdType->getName().c_str(),morphUnit->getName().c_str());
602 							results.push_back(szBuf);
603 						}
604 					}
605 				}
606     		}
607     	}
608 
609     	const int maxMorphsAllowed = 6;
610 		if(morphCommandCount > maxMorphsAllowed) {
611 			char szBuf[8096]="";
612 			snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has more than %d morph commands which is too many to display in the UI!",unitType.getName().c_str(),this->getName().c_str(),maxMorphsAllowed);
613 			results.push_back(szBuf);
614 		}
615 
616 		// Check every unit's unit requirements to validate that for every unit-requirements
617 		// we have the units required in the faction.
618 		for(int j = 0; j < unitType.getUnitReqCount(); ++j) {
619 			const UnitType *unitType2 = unitType.getUnitReq(j);
620 			if(unitType2 != NULL) {
621 				// Now lets find the required unit
622 				bool foundUnit = false;
623 				for(int l=0; l < (int)unitTypes.size() && foundUnit == false; ++l){
624 					UnitType &unitType3 = unitTypes[l];
625 
626 					if(unitType2->getName() == unitType3.getName()) {
627 						foundUnit = true;
628 						break;
629 					}
630 				}
631 
632 				if(foundUnit == false) {
633 					char szBuf[8096]="";
634 					snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the required Unit [%s]\nbut the required unit does not exist in this faction!",unitType.getName().c_str(),this->getName().c_str(),unitType2->getName().c_str());
635 					results.push_back(szBuf);
636 				}
637 			}
638 		}
639 
640 		// Now check that at least 1 other unit can produce, build or morph this unit
641 		bool foundUnit = false;
642 		for(int l=0; l < (int)unitTypes.size() && foundUnit == false; ++l){
643 			UnitType &unitType2 = unitTypes[l];
644 
645 	    	for(int j = 0; j < unitType2.getCommandTypeCount() && foundUnit == false; ++j) {
646 	    		const CommandType *cmdType = unitType2.getCommandType(j);
647 	    		if(cmdType != NULL) {
648 	    			// Check if this is a produce command
649 	    			if(cmdType->getClass() == ccProduce) {
650 	    				const ProduceCommandType *produce = dynamic_cast<const ProduceCommandType *>(cmdType);
651 						if(produce != NULL) {
652 							const UnitType *produceUnit = produce->getProducedUnit();
653 
654 							if( produceUnit != NULL &&
655 								unitType.getId() != unitType2.getId() &&
656 								unitType.getName() == produceUnit->getName()) {
657 								 foundUnit = true;
658 								 break;
659 							}
660 						}
661 	    			}
662 	    			// Check if this is a build command
663 					if(cmdType->getClass() == ccBuild) {
664 						const BuildCommandType *build = dynamic_cast<const BuildCommandType *>(cmdType);
665 						if(build == NULL) {
666 							throw megaglest_runtime_error("build == NULL");
667 						}
668 						for(int k = 0; k < build->getBuildingCount() && foundUnit == false; ++k) {
669 							const UnitType *buildUnit = build->getBuilding(k);
670 
671 							if( buildUnit != NULL &&
672 								unitType.getId() != unitType2.getId() &&
673 								unitType.getName() == buildUnit->getName()) {
674 								 foundUnit = true;
675 								 break;
676 							}
677 						}
678 						if(foundUnit == true) {
679 							break;
680 						}
681 					}
682 					// Check if this is a morph command
683 					if(cmdType->getClass() == ccMorph) {
684 							const MorphCommandType *morph = dynamic_cast<const MorphCommandType *>(cmdType);
685 							if(morph == NULL) {
686 								throw megaglest_runtime_error("morph == NULL");
687 							}
688 							const UnitType *morphUnit = morph->getMorphUnit();
689 
690 							if( morphUnit != NULL &&
691 									unitType.getId() != unitType2.getId() &&
692 									unitType.getName() == morphUnit->getName()) {
693 									 foundUnit = true;
694 									 break;
695 							}
696 					}
697 
698 	    			// Check if this is an attack command with spawned units on attack
699 					if(cmdType->getClass() == ccAttack) {
700 						const AttackCommandType *act= dynamic_cast<const AttackCommandType*>(cmdType);
701 						if( act != NULL && act->getAttackSkillType() != NULL &&
702 							act->getAttackSkillType()->getSpawnUnit() != "" && act->getAttackSkillType()->getSpawnUnitCount() > 0) {
703 
704 							if( unitType.getId() != unitType2.getId() &&
705 								unitType.getName() == act->getAttackSkillType()->getSpawnUnit()) {
706 								 foundUnit = true;
707 								 break;
708 							}
709 						}
710 					}
711 	    		}
712 	    	}
713 		}
714 
715 		if(foundUnit == false) {
716 			//printf("Problem for unit [%s] unitTypes.size() = " MG_SIZE_T_SPECIFIER "\n",unitType.getName().c_str(),unitTypes.size());
717 
718 			char szBuf[8096]="";
719 			snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has no other units that can produce, build or morph into it in this faction!",unitType.getName().c_str(),this->getName().c_str());
720 			results.push_back(szBuf);
721 		}
722 
723         // Ensure that all attack skill types have valid values
724         if(unitType.hasSkillClass(scAttack) == true) {
725             for(int j = 0; j < unitType.getSkillTypeCount(); ++j) {
726                 const SkillType *st = unitType.getSkillType(j);
727                 if(st != NULL && dynamic_cast<const AttackSkillType *>(st) != NULL) {
728                     const AttackSkillType *ast = dynamic_cast<const AttackSkillType *>(st);
729                     if(ast != NULL && ast->getAttackVar() < 0) {
730                         char szBuf[8096]="";
731                         snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the skill [%s] with an INVALID attack var value which is < 0 [%d]!",unitType.getName().c_str(),this->getName().c_str(),ast->getName().c_str(),ast->getAttackVar());
732                         results.push_back(szBuf);
733                     }
734                 }
735             }
736         }
737         // end
738 
739         // Check if the unit has both be_built and harvest skills, this may cause issues
740         // with the AI
741         if(unitType.hasSkillClass(scBeBuilt) == true && unitType.hasSkillClass(scHarvest) == true) {
742 			char szBuf[8096]="";
743 			snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has both a bebuilt and harvest skill which will cause AI problems for CPU players!",unitType.getName().c_str(),this->getName().c_str());
744 			results.push_back(szBuf);
745         }
746         // end
747 
748         // Check if the unit has harvest skills but not move, meaning they cannot
749         // harvest the resource
750         if(unitType.hasSkillClass(scHarvest) == true && unitType.hasSkillClass(scMove) == false) {
751 			char szBuf[8096]="";
752 			snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has a harvest skill but no move skill so it cannot harvest!",unitType.getName().c_str(),this->getName().c_str());
753 			results.push_back(szBuf);
754         }
755         // end
756 
757     }
758 
759     return results;
760 }
761 
validateFactionTypeResourceTypes(vector<ResourceType> & resourceTypes)762 std::vector<std::string> FactionType::validateFactionTypeResourceTypes(vector<ResourceType> &resourceTypes) {
763 	std::vector<std::string> results;
764 
765     for(int i=0; i < (int)unitTypes.size(); ++i) {
766     	UnitType &unitType = unitTypes[i];
767 
768 		// Check every unit's required resources to validate that for every resource-requirements
769 		// we have a resource in the faction.
770     	for(int j = 0; j < unitType.getCostCount() ; ++j) {
771     		const Resource *r = unitType.getCost(j);
772     		if(r != NULL && r->getType() != NULL) {
773     			bool foundResourceType = false;
774     			// Now lets find a matching faction resource type for the unit
775     			for(int k=0; k < (int)resourceTypes.size(); ++k){
776     				ResourceType &rt = resourceTypes[k];
777 
778 					if(r->getType()->getName() == rt.getName()) {
779 						foundResourceType = true;
780 						break;
781 					}
782 				}
783 
784 				if(foundResourceType == false) {
785 					char szBuf[8096]="";
786 					snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the resource req [%s]\nbut there are no such resources in this tech!",unitType.getName().c_str(),this->getName().c_str(),r->getType()->getName().c_str());
787 					results.push_back(szBuf);
788 				}
789     		}
790     	}
791 
792 		// Check every unit's stored resources to validate that for every resources-stored
793 		// we have a resource in the faction.
794 		for(int j = 0; j < unitType.getStoredResourceCount() ; ++j) {
795 			const Resource *r = unitType.getStoredResource(j);
796 			if(r != NULL && r->getType() != NULL) {
797 				bool foundResourceType = false;
798 				// Now lets find a matching faction resource type for the unit
799 				for(int k=0; k < (int)resourceTypes.size(); ++k){
800 					ResourceType &rt = resourceTypes[k];
801 
802 					if(r->getType()->getName() == rt.getName()) {
803 						foundResourceType = true;
804 						break;
805 					}
806 				}
807 
808 				if(foundResourceType == false) {
809 					char szBuf[8096]="";
810 					snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the stored resource [%s]\nbut there are no such resources in this tech!",unitType.getName().c_str(),this->getName().c_str(),r->getType()->getName().c_str());
811 					results.push_back(szBuf);
812 				}
813 			}
814 		}
815 
816     	for(int j = 0; j < unitType.getCommandTypeCount(); ++j) {
817     		const CommandType *cmdType = unitType.getCommandType(j);
818     		if(cmdType != NULL) {
819 				// Ensure for each harvest type command that the resource
820 				// exist in this faction
821 				if(cmdType->getClass() == ccHarvest) {
822 					const HarvestCommandType *harvest = dynamic_cast<const HarvestCommandType *>(cmdType);
823 					if(harvest == NULL) {
824 						throw megaglest_runtime_error("harvest == NULL");
825 					}
826 					for(int k = 0; k < harvest->getHarvestedResourceCount(); ++k) {
827 						const ResourceType *harvestResource = harvest->getHarvestedResource(k);
828 
829 						bool foundResourceType = false;
830 						// Now lets find a matching faction resource type for the unit
831 						for(int k=0; k < (int)resourceTypes.size(); ++k){
832 							ResourceType &rt = resourceTypes[k];
833 
834 							if(harvestResource->getName() == rt.getName()) {
835 								foundResourceType = true;
836 								break;
837 							}
838 						}
839 
840 						if(foundResourceType == false) {
841 							char szBuf[8096]="";
842 							snprintf(szBuf,8096,"The Unit [%s] in Faction [%s] has the command [%s] which can harvest the resource [%s]\nbut there are no such resources in this tech!",unitType.getName().c_str(),this->getName().c_str(),cmdType->getName().c_str(),harvestResource->getName().c_str());
843 							results.push_back(szBuf);
844 						}
845 					}
846 				}
847     		}
848     	}
849     }
850 
851     return results;
852 }
853 
validateFactionTypeUpgradeTypes()854 std::vector<std::string> FactionType::validateFactionTypeUpgradeTypes() {
855 	std::vector<std::string> results;
856 
857 	// For each upgrade type make sure there is at least 1 unit that can produce
858 	// the upgrade
859 	for(int i = 0; i < (int)upgradeTypes.size(); ++i) {
860 		const UpgradeType &upgradeType = upgradeTypes[i];
861 
862 		// First find a unit with a command type to upgrade to this Upgrade type
863 		bool foundUnit = false;
864 	    for(int j=0; j < (int)unitTypes.size() && foundUnit == false; ++j){
865 	    	UnitType &unitType = unitTypes[j];
866 	    	for(int k = 0; k < unitType.getCommandTypeCount() && foundUnit == false; ++k) {
867 				const CommandType *cmdType = unitType.getCommandType(k);
868 				if(cmdType != NULL) {
869 					// Ensure for each build type command that the build units
870 					// exist in this faction
871 					if(cmdType->getClass() == ccUpgrade) {
872 						const UpgradeCommandType *upgrade = dynamic_cast<const UpgradeCommandType *>(cmdType);
873 						if(upgrade != NULL) {
874 							const UpgradeType *upgradeType2 = upgrade->getProducedUpgrade();
875 
876 							if(upgradeType2 != NULL && upgradeType.getName() == upgradeType2->getName()) {
877 								 foundUnit = true;
878 								 break;
879 							}
880 						}
881 					}
882 				}
883 	    	}
884 	    }
885 
886 		if(foundUnit == false) {
887 			char szBuf[8096]="";
888 			snprintf(szBuf,8096,"The Upgrade Type [%s] in Faction [%s] has no Unit able to produce this upgrade in this faction!",upgradeType.getName().c_str(),this->getName().c_str());
889 			results.push_back(szBuf);
890 		}
891 	}
892 
893     return results;
894 }
895 
896 // ==================== get ====================
897 
getUnitType(const string & name) const898 const UnitType *FactionType::getUnitType(const string &name) const{
899     for(int i=0; i < (int)unitTypes.size();i++){
900 		if(unitTypes[i].getName(false)==name){
901             return &unitTypes[i];
902 		}
903     }
904 
905     printf("In [%s::%s Line: %d] scanning [%s] size = " MG_SIZE_T_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),unitTypes.size());
906     for(int i=0; i < (int)unitTypes.size();i++){
907     	printf("In [%s::%s Line: %d] scanning [%s] idx = %d [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),i,unitTypes[i].getName(false).c_str());
908     }
909 
910     if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] scanning [%s] size = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),unitTypes.size());
911     for(int i=0; i < (int)unitTypes.size();i++){
912     	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] scanning [%s] idx = %d [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),i,unitTypes[i].getName(false).c_str());
913     }
914 
915 	throw megaglest_runtime_error("Unit type not found: [" + name + "] in faction type [" + this->name + "]",true);
916 }
917 
getUnitTypeById(int id) const918 const UnitType *FactionType::getUnitTypeById(int id) const{
919     for(int i=0; i < (int)unitTypes.size();i++){
920 		if(unitTypes[i].getId() == id) {
921             return &unitTypes[i];
922 		}
923     }
924 
925     printf("In [%s::%s Line: %d] scanning [%d] size = " MG_SIZE_T_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,id,unitTypes.size());
926     for(int i=0; i < (int)unitTypes.size();i++){
927     	printf("In [%s::%s Line: %d] scanning [%s] idx = %d [%s][%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),i,unitTypes[i].getName(false).c_str(),unitTypes[i].getId());
928     }
929 
930     if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] scanning [%s] size = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),unitTypes.size());
931     for(int i=0; i < (int)unitTypes.size();i++){
932     	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] scanning [%s] idx = %d [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),i,unitTypes[i].getName(false).c_str());
933     }
934 
935 	throw megaglest_runtime_error("Unit type not found: [" + intToStr(id) + "] in faction type [" + this->name + "]",true);
936 }
937 
getUpgradeType(const string & name) const938 const UpgradeType *FactionType::getUpgradeType(const string &name) const{
939     for(int i=0; i < (int)upgradeTypes.size();i++){
940 		if(upgradeTypes[i].getName()==name){
941             return &upgradeTypes[i];
942 		}
943     }
944 
945     printf("In [%s::%s Line: %d] scanning [%s] size = " MG_SIZE_T_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),unitTypes.size());
946     for(int i=0; i < (int)upgradeTypes.size();i++){
947     	printf("In [%s::%s Line: %d] scanning [%s] idx = %d [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),i,upgradeTypes[i].getName().c_str());
948     }
949 
950     if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] scanning [%s] size = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),unitTypes.size());
951     for(int i=0; i < (int)upgradeTypes.size();i++){
952     	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] scanning [%s] idx = %d [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,name.c_str(),i,upgradeTypes[i].getName().c_str());
953     }
954 
955 	throw megaglest_runtime_error("Upgrade type not found: [" + name + "] in faction type [" + this->name + "]",true);
956 }
957 
getStartingResourceAmount(const ResourceType * resourceType) const958 int FactionType::getStartingResourceAmount(const ResourceType *resourceType) const{
959 	for(int i=0; i < (int)startingResources.size(); ++i){
960 		if(startingResources[i].getType()==resourceType){
961 			return startingResources[i].getAmount();
962 		}
963 	}
964 	return 0;
965 }
966 
deletePixels()967 void FactionType::deletePixels() {
968 	for(int i = 0; i < (int)unitTypes.size(); ++i) {
969 		UnitType &unitType = unitTypes[i];
970 		Texture2D *texture = unitType.getMeetingPointImage();
971 		if(texture != NULL) {
972 			texture->deletePixels();
973 		}
974 	}
975 }
976 
factionUsesResourceType(const ResourceType * rt) const977 bool FactionType::factionUsesResourceType(const ResourceType *rt) const {
978 	bool factionUsesResourceType = false;
979 	if(rt != NULL) {
980 		for(unsigned int j = 0; factionUsesResourceType == false && j < (unsigned int)this->getUnitTypeCount(); ++j) {
981 			const UnitType *ut= this->getUnitType(j);
982 			for(int k = 0; factionUsesResourceType == false && k < ut->getCostCount(); ++k) {
983 				const Resource *costResource = ut->getCost(k);
984 				//printf("#1 factionUsesResourceType, unit [%s] resource [%s] cost [%s]\n",ut->getName().c_str(),rt->getName().c_str(),costResource->getType()->getName().c_str());
985 
986 				if(costResource != NULL && costResource->getType() != NULL &&
987 						costResource->getType()->getName() == rt->getName()) {
988 					factionUsesResourceType = true;
989 					break;
990 				}
991 			}
992 			if(factionUsesResourceType == false) {
993 				for(unsigned int k = 0; factionUsesResourceType == false && k < (unsigned int)ut->getCommandTypeCount(); ++k) {
994 					const CommandType *commandType = ut->getCommandType(k);
995 					if(commandType != NULL && commandType->getClass() == ccHarvest) {
996 						const HarvestCommandType *hct = dynamic_cast<const HarvestCommandType *>(commandType);
997 						if(hct != NULL && hct->getHarvestedResourceCount() > 0) {
998 							for(unsigned int l = 0; factionUsesResourceType == false && l < (unsigned int)hct->getHarvestedResourceCount(); ++l) {
999 								//printf("#2 factionUsesResourceType, unit [%s] resource [%s] harvest [%s]\n",ut->getName().c_str(),rt->getName().c_str(),hct->getHarvestedResource(l)->getName().c_str());
1000 
1001 								if(hct->getHarvestedResource(l)->getName() == rt->getName()) {
1002 									factionUsesResourceType = true;
1003 									break;
1004 								}
1005 							}
1006 						}
1007 					}
1008 				}
1009 			}
1010 		}
1011 	}
1012 	return factionUsesResourceType;
1013 }
1014 
toString() const1015 std::string FactionType::toString() const {
1016 	std::string result = "Faction Name: " + name + "\n";
1017 
1018 	result += "Unit Type List count = " + intToStr(this->getUnitTypeCount()) + "\n";
1019     for(int i=0; i < (int)unitTypes.size();i++) {
1020 		result += unitTypes[i].toString() + "\n";
1021     }
1022 
1023 	result += "Upgrade Type List count = " + intToStr(this->getUpgradeTypeCount()) + "\n";
1024     for(int i=0; i < (int)upgradeTypes.size();i++) {
1025 		result += "index: " + intToStr(i) + " " + upgradeTypes[i].getReqDesc(false) + "\n";
1026     }
1027 
1028 	return result;
1029 }
1030 
getName(bool translatedValue) const1031 string FactionType::getName(bool translatedValue) const {
1032 	if(translatedValue == false) return name;
1033 
1034 	Lang &lang = Lang::getInstance();
1035 	return lang.getTechTreeString("FactionName_" + name,name.c_str());
1036 }
1037 
1038 
1039 }}//end namespace
1040