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.h"
13 
14 #include <algorithm>
15 #include <cassert>
16 
17 #include "resource_type.h"
18 #include "unit.h"
19 #include "util.h"
20 #include "sound_renderer.h"
21 #include "renderer.h"
22 #include "tech_tree.h"
23 #include "game.h"
24 #include "config.h"
25 #include "randomgen.h"
26 #include "leak_dumper.h"
27 
28 using namespace Shared::Util;
29 using Shared::Util::RandomGen;
30 
31 namespace Glest { namespace Game {
32 
operator ()(const int l,const int r)33 bool CommandGroupUnitSorterId::operator()(const int l, const int r) {
34 	const Unit *lUnit = faction->findUnit(l);
35 	const Unit *rUnit = faction->findUnit(r);
36 
37 	if(!lUnit) {
38 		printf("Error lUnit == NULL for id = %d factionIndex = %d\n",l,faction->getIndex());
39 
40 		for(unsigned int i = 0; i < (unsigned int)faction->getUnitCount(); ++i) {
41 			printf("%u / %d id = %d [%s]\n",i,faction->getUnitCount(),faction->getUnit(i)->getId(),faction->getUnit(i)->getType()->getName(false).c_str());
42 		}
43 	}
44 	if(!rUnit) {
45 		printf("Error rUnit == NULL for id = %d factionIndex = %d\n",r,faction->getIndex());
46 
47 		for(unsigned int i = 0; i < (unsigned int)faction->getUnitCount(); ++i) {
48 			printf("%u / %d id = %d [%s]\n",i,faction->getUnitCount(),faction->getUnit(i)->getId(),faction->getUnit(i)->getType()->getName(false).c_str());
49 		}
50 	}
51 
52 	CommandGroupUnitSorter sorter;
53 	return sorter.compare(lUnit, rUnit);
54 }
55 
operator ()(const Unit * l,const Unit * r)56 bool CommandGroupUnitSorter::operator()(const Unit *l, const Unit *r) {
57 	return compare(l, r);
58 }
59 
compare(const Unit * l,const Unit * r)60 bool CommandGroupUnitSorter::compare(const Unit *l, const Unit *r) {
61 	//printf("l [%p] r [%p] <>",l,r);
62 
63 	if(!l) {
64 		printf("Error l == NULL\n");
65 	}
66 	if(!r) {
67 		printf("Error r == NULL\n");
68 	}
69 
70 	assert(l && r);
71 
72 	if(l == NULL || r == NULL)
73 		printf("Unit l [%s - %d] r [%s - %d]\n",
74 			(l != NULL ? l->getType()->getName(false).c_str() : "null"),
75 			(l != NULL ? l->getId() : -1),
76 			(r != NULL ? r->getType()->getName(false).c_str() : "null"),
77 			(r != NULL ? r->getId() : -1));
78 
79 
80 	bool result = false;
81 	// If comparer is null or dead
82 	if(r == NULL || r->isAlive() == false) {
83 		// if source is null or dead also
84 		if((l == NULL || l->isAlive() == false)) {
85 			return false;
86 		}
87 		return true;
88 	}
89 	else if((l == NULL || l->isAlive() == false)) {
90 		return false;
91 	}
92 
93 //	const Command *command= l->getCurrrentCommandThreadSafe();
94 //	const Command *commandPeer = r->getCurrrentCommandThreadSafe();
95 	const Command *command= l->getCurrCommand();
96 	const Command *commandPeer = r->getCurrCommand();
97 
98 	//Command *command= this->unit->getCurrCommand();
99 
100 	// Are we moving or attacking
101 	if( command != NULL && command->getCommandType() != NULL &&
102 			(command->getCommandType()->getClass() == ccMove ||
103 			 command->getCommandType()->getClass() == ccAttack)  &&
104 		command->getUnitCommandGroupId() > 0) {
105 		int curCommandGroupId = command->getUnitCommandGroupId();
106 
107 		//Command *commandPeer = j.unit->getCurrrentCommandThreadSafe();
108 		//Command *commandPeer = j.unit->getCurrCommand();
109 
110 		// is comparer a valid command
111 		if(commandPeer == NULL || commandPeer->getCommandType() == NULL) {
112 			result = true;
113 		}
114 		// is comparer command the same type?
115 		else if(commandPeer->getCommandType()->getClass() !=
116 				command->getCommandType()->getClass()) {
117 			result = true;
118 		}
119 		// is comparer command groupid invalid?
120 		else if(commandPeer->getUnitCommandGroupId() < 0) {
121 			result = true;
122 		}
123 		// If comparer command group id is less than current group id
124 		else if(curCommandGroupId != commandPeer->getUnitCommandGroupId()) {
125 			result = curCommandGroupId < commandPeer->getUnitCommandGroupId();
126 		}
127 		else {
128 			float unitDist = l->getCenteredPos().dist(command->getPos());
129 			float unitDistPeer = r->getCenteredPos().dist(commandPeer->getPos());
130 
131 			// Closest unit in commandgroup
132 			result = (unitDist < unitDistPeer);
133 		}
134 	}
135 	else if(command == NULL && commandPeer != NULL) {
136 		result = false;
137 	}
138 //	else if(command == NULL && j.unit->getCurrrentCommandThreadSafe() == NULL) {
139 //		return this->unit->getId() < j.unit->getId();
140 //	}
141 	else {
142 		//Command *commandPeer = j.unit->getCurrrentCommandThreadSafe();
143 		//if( commandPeer != NULL && commandPeer->getCommandType() != NULL &&
144 		//	(commandPeer->getCommandType()->getClass() != ccMove &&
145 		//	 commandPeer->getCommandType()->getClass() != ccAttack)) {
146 			result = (l->getId() < r->getId());
147 		//}
148 		//else {
149 		//	result = (l->getId() < r->getId());
150 		//}
151 	}
152 
153 	//printf("Sorting, unit [%d - %s] cmd [%s] | unit2 [%d - %s] cmd [%s] result = %d\n",this->unit->getId(),this->unit->getFullName().c_str(),(this->unit->getCurrCommand() == NULL ? "NULL" : this->unit->getCurrCommand()->toString().c_str()),j.unit->getId(),j.unit->getFullName().c_str(),(j.unit->getCurrCommand() == NULL ? "NULL" : j.unit->getCurrCommand()->toString().c_str()),result);
154 
155 	return result;
156 }
157 
sortUnitsByCommandGroups()158 void Faction::sortUnitsByCommandGroups() {
159 	MutexSafeWrapper safeMutex(unitsMutex,string(__FILE__) + "_" + intToStr(__LINE__));
160 	//printf("====== sortUnitsByCommandGroups for faction # %d [%s] unitCount = %d\n",this->getIndex(),this->getType()->getName().c_str(),units.size());
161 	//for(unsigned int i = 0; i < units.size(); ++i) {
162 	//	printf("%d / %d [%p] <>",i,units.size(),&units[i]);
163 //	//	printf("i = %d [%p]\n",i,&units[i]);
164 //		if(Unit::isUnitDeleted(units[i]) == true) {
165 //			printf("i = %d [%p]\n",i,&units[i]);
166 //			throw megaglest_runtime_error("unit already deleted!");
167 //		}
168 	//}
169 	//printf("\nSorting\n");
170 
171 	//std::sort(units.begin(),units.end(),CommandGroupUnitSorter());
172 
173 	//printf("====== Done sorting for faction # %d [%s] unitCount = %d\n",this->getIndex(),this->getType()->getName().c_str(),units.size());
174 
175 	//unsigned int originalUnitSize = (unsigned int)units.size();
176 
177 	std::vector<int> unitIds;
178 	for(unsigned int i = 0; i < units.size(); ++i) {
179 		int unitId = units[i]->getId();
180 		if(this->findUnit(unitId) == NULL) {
181 			printf("#1 Error unitId not found for id = %d [%s] factionIndex = %d\n",unitId,units[i]->getType()->getName(false).c_str(),this->getIndex());
182 
183 			for(unsigned int j = 0; j < units.size(); ++j) {
184 				printf("%u / %d id = %d [%s]\n",j,(int)units.size(),units[j]->getId(),units[j]->getType()->getName(false).c_str());
185 			}
186 		}
187 		unitIds.push_back(unitId);
188 	}
189 	CommandGroupUnitSorterId sorter;
190 	sorter.faction = this;
191 	std::stable_sort(unitIds.begin(),unitIds.end(),sorter);
192 
193 	units.clear();
194 	for(unsigned int i = 0; i < unitIds.size(); ++i) {
195 
196 		int unitId = unitIds[i];
197 		if(this->findUnit(unitId) == NULL) {
198 			printf("#2 Error unitId not found for id = %d factionIndex = %d\n",unitId,this->getIndex());
199 
200 			for(unsigned int j = 0; j < units.size(); ++j) {
201 				printf("%u / %d id = %d [%s]\n",j,(int)units.size(),units[j]->getId(),units[j]->getType()->getName(false).c_str());
202 			}
203 		}
204 
205 		units.push_back(this->findUnit(unitId));
206 	}
207 
208 	//assert(originalUnitSize == units.size());
209 }
210 
211 // =====================================================
212 //	class FactionThread
213 // =====================================================
214 
FactionThread(Faction * faction)215 FactionThread::FactionThread(Faction *faction) : BaseThread() {
216 	this->triggerIdMutex = new Mutex(CODE_AT_LINE);
217 	this->faction = faction;
218 	this->masterController = NULL;
219 	uniqueID = "FactionThread";
220 }
221 
~FactionThread()222 FactionThread::~FactionThread() {
223 	this->faction = NULL;
224 	this->masterController = NULL;
225 	delete this->triggerIdMutex;
226 	this->triggerIdMutex = NULL;
227 }
228 
setQuitStatus(bool value)229 void FactionThread::setQuitStatus(bool value) {
230 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d value = %d\n",__FILE__,__FUNCTION__,__LINE__,value);
231 
232 	BaseThread::setQuitStatus(value);
233 	if(value == true) {
234 		signalPathfinder(-1);
235 	}
236 
237 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
238 }
239 
signalPathfinder(int frameIndex)240 void FactionThread::signalPathfinder(int frameIndex) {
241 	if(frameIndex >= 0) {
242 		static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
243 		MutexSafeWrapper safeMutex(triggerIdMutex,mutexOwnerId);
244 		this->frameIndex.first = frameIndex;
245 		this->frameIndex.second = false;
246 
247 		safeMutex.ReleaseLock();
248 	}
249 	semTaskSignalled.signal();
250 }
251 
setTaskCompleted(int frameIndex)252 void FactionThread::setTaskCompleted(int frameIndex) {
253 	if(frameIndex >= 0) {
254 		static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
255 		MutexSafeWrapper safeMutex(triggerIdMutex,mutexOwnerId);
256 		if(this->frameIndex.first == frameIndex) {
257 			this->frameIndex.second = true;
258 		}
259 		safeMutex.ReleaseLock();
260 	}
261 }
262 
canShutdown(bool deleteSelfIfShutdownDelayed)263 bool FactionThread::canShutdown(bool deleteSelfIfShutdownDelayed) {
264 	bool ret = (getExecutingTask() == false);
265 	if(ret == false && deleteSelfIfShutdownDelayed == true) {
266 	    setDeleteSelfOnExecutionDone(deleteSelfIfShutdownDelayed);
267 	    deleteSelfIfRequired();
268 	    signalQuit();
269 	}
270 
271 	return ret;
272 }
273 
isSignalPathfinderCompleted(int frameIndex)274 bool FactionThread::isSignalPathfinderCompleted(int frameIndex) {
275 	if(getRunningStatus() == false) {
276 		return true;
277 	}
278 	static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
279 	MutexSafeWrapper safeMutex(triggerIdMutex,mutexOwnerId);
280 	//bool result = (event != NULL ? event->eventCompleted : true);
281 	bool result = (this->frameIndex.first == frameIndex && this->frameIndex.second == true);
282 
283 	//if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] worker thread this = %p, this->frameIndex.first = %d, this->frameIndex.second = %d\n",__FILE__,__FUNCTION__,__LINE__,this,this->frameIndex.first,this->frameIndex.second);
284 
285 	safeMutex.ReleaseLock();
286 	return result;
287 }
288 
execute()289 void FactionThread::execute() {
290 	string codeLocation = "1";
291     RunningStatusSafeWrapper runningStatus(this);
292 	try {
293 		//setRunningStatus(true);
294 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
295 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** STARTING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this);
296 
297 		bool minorDebugPerformance = false;
298 		Chrono chrono;
299 
300 		codeLocation = "2";
301 		//unsigned int idx = 0;
302 		for(;this->faction != NULL;) {
303 			if(getQuitStatus() == true) {
304 				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
305 				break;
306 			}
307 
308 			semTaskSignalled.waitTillSignalled();
309 
310 			codeLocation = "3";
311 			//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
312 			static string masterSlaveOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
313 			MasterSlaveThreadControllerSafeWrapper safeMasterController(masterController,20000,masterSlaveOwnerId);
314 			//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
315 
316 			if(getQuitStatus() == true) {
317 				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
318 				break;
319 			}
320 
321 			static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
322             MutexSafeWrapper safeMutex(triggerIdMutex,mutexOwnerId);
323             bool executeTask = (this->frameIndex.first >= 0);
324 			int currentTriggeredFrameIndex = this->frameIndex.first;
325 
326             //if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] frameIndex = %d this = %p executeTask = %d\n",__FILE__,__FUNCTION__,__LINE__,frameIndex.first, this, executeTask);
327 
328             safeMutex.ReleaseLock();
329 
330 			codeLocation = "5";
331             //printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
332 
333             if(executeTask == true) {
334 				codeLocation = "6";
335 				ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);
336 
337 				if(this->faction == NULL) {
338 					throw megaglest_runtime_error("this->faction == NULL");
339 				}
340 				World *world = this->faction->getWorld();
341 				if(world == NULL) {
342 					throw megaglest_runtime_error("world == NULL");
343 				}
344 
345 				codeLocation = "7";
346 				//Config &config= Config::getInstance();
347 				//bool sortedUnitsAllowed = config.getBool("AllowGroupedUnitCommands","true");
348 				bool sortedUnitsAllowed = false;
349 				if(sortedUnitsAllowed == true) {
350 					this->faction->sortUnitsByCommandGroups();
351 				}
352 
353 				codeLocation = "8";
354 				static string mutexOwnerId2 = string(__FILE__) + string("_") + intToStr(__LINE__);
355 				MutexSafeWrapper safeMutex(faction->getUnitMutex(),mutexOwnerId2);
356 
357 				//if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
358 				if(minorDebugPerformance) chrono.start();
359 
360 				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
361 
362 				codeLocation = "9";
363 				int unitCount = this->faction->getUnitCount();
364 				for(int j = 0; j < unitCount; ++j) {
365 					codeLocation = "10";
366 					Unit *unit = this->faction->getUnit(j);
367 					if(unit == NULL) {
368 						throw megaglest_runtime_error("unit == NULL");
369 					}
370 
371 					codeLocation = "11";
372 					int64 elapsed1 = 0;
373 					if(minorDebugPerformance) elapsed1 = chrono.getMillis();
374 
375 					bool update = unit->needToUpdate();
376 
377 					codeLocation = "12";
378 					if(minorDebugPerformance && (chrono.getMillis() - elapsed1) >= 1) printf("Faction [%d - %s] #1-unit threaded updates on frame: %d for [%d] unit # %d, unitCount = %d, took [%lld] msecs\n",faction->getStartLocationIndex(),faction->getType()->getName(false).c_str(),currentTriggeredFrameIndex,faction->getUnitPathfindingListCount(),j,unitCount,(long long int)chrono.getMillis() - elapsed1);
379 
380 					//update = true;
381 					if(update == true)
382 					{
383 						codeLocation = "13";
384 						if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
385 							int64 updateProgressValue = unit->getUpdateProgress();
386 							int64 speed = unit->getCurrSkill()->getTotalSpeed(unit->getTotalUpgrade());
387 							int64 df = unit->getDiagonalFactor();
388 							int64 hf = unit->getHeightFactor();
389 							bool changedActiveCommand = unit->isChangedActiveCommand();
390 
391 							char szBuf[8096]="";
392 							snprintf(szBuf,8096,"unit->needToUpdate() returned: %d updateProgressValue: %lld speed: %lld changedActiveCommand: %d df: %lld hf: %lld",update,(long long int)updateProgressValue,(long long int)speed,changedActiveCommand,(long long int)df,(long long int)hf);
393 							unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf);
394 						}
395 
396 						int64 elapsed2 = 0;
397 						if(minorDebugPerformance) elapsed2 = chrono.getMillis();
398 
399 						if(world->getUnitUpdater() == NULL) {
400 							throw megaglest_runtime_error("world->getUnitUpdater() == NULL");
401 						}
402 
403 						world->getUnitUpdater()->updateUnitCommand(unit,currentTriggeredFrameIndex);
404 
405 						codeLocation = "15";
406 						if(minorDebugPerformance && (chrono.getMillis() - elapsed2) >= 1) printf("Faction [%d - %s] #2-unit threaded updates on frame: %d for [%d] unit # %d, unitCount = %d, took [%lld] msecs\n",faction->getStartLocationIndex(),faction->getType()->getName(false).c_str(),currentTriggeredFrameIndex,faction->getUnitPathfindingListCount(),j,unitCount,(long long int)chrono.getMillis() - elapsed2);
407 					}
408 					else {
409 						codeLocation = "16";
410 						if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
411 							int64 updateProgressValue = unit->getUpdateProgress();
412 							int64 speed = unit->getCurrSkill()->getTotalSpeed(unit->getTotalUpgrade());
413 							int64 df = unit->getDiagonalFactor();
414 							int64 hf = unit->getHeightFactor();
415 							bool changedActiveCommand = unit->isChangedActiveCommand();
416 
417 							char szBuf[8096]="";
418 							snprintf(szBuf,8096,"unit->needToUpdate() returned: %d updateProgressValue: %lld speed: %lld changedActiveCommand: %d df: %lld hf: %lld",update,(long long int)updateProgressValue,(long long int)speed,changedActiveCommand,(long long int)df,(long long int)hf);
419 							unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf);
420 						}
421 					}
422 				}
423 
424 				codeLocation = "17";
425 				if(minorDebugPerformance && chrono.getMillis() >= 1) printf("Faction [%d - %s] threaded updates on frame: %d for [%d] units took [%lld] msecs\n",faction->getStartLocationIndex(),faction->getType()->getName(false).c_str(),currentTriggeredFrameIndex,faction->getUnitPathfindingListCount(),(long long int)chrono.getMillis());
426 
427 				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
428 
429 				safeMutex.ReleaseLock();
430 
431 				codeLocation = "18";
432 				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
433 
434 				setTaskCompleted(currentTriggeredFrameIndex);
435 
436 				//printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
437             }
438 
439             //printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
440 
441 			codeLocation = "19";
442 			if(getQuitStatus() == true) {
443 				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
444 				break;
445 			}
446 		}
447 
448 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
449 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** ENDING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this);
450 	}
451 	catch(const exception &ex) {
452 		//setRunningStatus(false);
453 
454 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Loc [%s] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,codeLocation.c_str(),ex.what());
455 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
456 
457 		throw megaglest_runtime_error(ex.what());
458 	}
459 	catch(...) {
460 		char szBuf[8096]="";
461 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error Loc [%s]\n",__FILE__,__FUNCTION__,__LINE__,codeLocation.c_str());
462 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
463 		throw megaglest_runtime_error(szBuf);
464 	}
465 
466 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
467 }
468 
469 
470 // =====================================================
471 // 	class Faction
472 // =====================================================
473 
Faction()474 Faction::Faction() {
475 	init();
476 }
477 
init()478 void Faction::init() {
479 	unitsMutex = new Mutex(CODE_AT_LINE);
480 	texture = NULL;
481 	//lastResourceTargettListPurge = 0;
482 	cachingDisabled=false;
483 	factionDisconnectHandled=false;
484 	workerThread = NULL;
485 
486 	world=NULL;
487 	scriptManager=NULL;
488 	factionType=NULL;
489 	index=0;
490 	teamIndex=0;
491 	startLocationIndex=0;
492 	thisFaction=false;
493 	currentSwitchTeamVoteFactionIndex = -1;
494 	allowSharedTeamUnits = false;
495 
496 	loadWorldNode = NULL;
497 	techTree = NULL;
498 
499 	control = ctClosed;
500 
501 	overridePersonalityType = fpt_EndCount;
502 
503 	upgradeManager = UpgradeManager();
504 }
505 
~Faction()506 Faction::~Faction() {
507 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
508 
509 	//Renderer &renderer= Renderer::getInstance();
510 
511 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
512 
513 	//renderer.endTexture(rsGame,texture);
514 	//texture->end();
515 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
516 
517 	if(workerThread != NULL) {
518 		workerThread->signalQuit();
519 		if(workerThread->shutdownAndWait() == true) {
520 			delete workerThread;
521 		}
522 		workerThread = NULL;
523 	}
524 
525 	MutexSafeWrapper safeMutex(unitsMutex,string(__FILE__) + "_" + intToStr(__LINE__));
526 	deleteValues(units.begin(), units.end());
527 	units.clear();
528 
529 	safeMutex.ReleaseLock();
530 
531 	//delete texture;
532 	texture = NULL;
533 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
534 
535 	delete unitsMutex;
536 	unitsMutex = NULL;
537 
538 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
539 }
540 
end()541 void Faction::end() {
542 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
543 
544 	if(workerThread != NULL) {
545 		workerThread->signalQuit();
546 		if(workerThread->shutdownAndWait() == true) {
547 			delete workerThread;
548 		}
549 		workerThread = NULL;
550 	}
551 
552 	MutexSafeWrapper safeMutex(unitsMutex,string(__FILE__) + "_" + intToStr(__LINE__));
553 	deleteValues(units.begin(), units.end());
554 	units.clear();
555 
556 	safeMutex.ReleaseLock();
557 
558 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
559 }
560 
notifyUnitAliveStatusChange(const Unit * unit)561 void Faction::notifyUnitAliveStatusChange(const Unit *unit) {
562 	if(unit != NULL) {
563 		if(unit->isAlive() == true) {
564 			aliveUnitListCache[unit->getId()] = unit;
565 
566 			if(unit->getType()->isMobile() == true) {
567 				mobileUnitListCache[unit->getId()] = unit;
568 			}
569 		}
570 		else {
571 			aliveUnitListCache.erase(unit->getId());
572 			mobileUnitListCache.erase(unit->getId());
573 			beingBuiltUnitListCache.erase(unit->getId());
574 		}
575 	}
576 }
577 
notifyUnitTypeChange(const Unit * unit,const UnitType * newType)578 void Faction::notifyUnitTypeChange(const Unit *unit, const UnitType *newType) {
579 	if(unit != NULL) {
580 		if(unit->getType()->isMobile() == true) {
581 			mobileUnitListCache.erase(unit->getId());
582 		}
583 
584 		if(newType != NULL && newType->isMobile() == true) {
585 			mobileUnitListCache[unit->getId()] = unit;
586 		}
587 	}
588 }
589 
notifyUnitSkillTypeChange(const Unit * unit,const SkillType * newType)590 void Faction::notifyUnitSkillTypeChange(const Unit *unit, const SkillType *newType) {
591 	if(unit != NULL) {
592 		if(unit->isBeingBuilt() == true) {
593 			beingBuiltUnitListCache.erase(unit->getId());
594 		}
595 		if(newType != NULL && newType->getClass() == scBeBuilt) {
596 			beingBuiltUnitListCache[unit->getId()] = unit;
597 		}
598 	}
599 }
600 
hasAliveUnits(bool filterMobileUnits,bool filterBuiltUnits) const601 bool Faction::hasAliveUnits(bool filterMobileUnits, bool filterBuiltUnits) const {
602 	bool result = false;
603 	if(aliveUnitListCache.empty() == false) {
604 		if(filterMobileUnits == true) {
605 			result = (mobileUnitListCache.empty() == false);
606 		}
607 		else {
608 			result = true;
609 		}
610 
611 		if(result == true && filterBuiltUnits == true) {
612 			result = (beingBuiltUnitListCache.empty() == true);
613 		}
614 	}
615 	return result;
616 }
617 
getPersonalityType() const618 FactionPersonalityType Faction::getPersonalityType() const {
619 	if(overridePersonalityType != fpt_EndCount) {
620 		return overridePersonalityType;
621 	}
622 	return factionType->getPersonalityType();
623 }
624 
getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const625 int Faction::getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const {
626 	return factionType->getAIBehaviorStaticOverideValue(type);
627 }
628 
addUnitToMovingList(int unitId)629 void Faction::addUnitToMovingList(int unitId) {
630 	unitsMovingList[unitId] = getWorld()->getFrameCount();
631 }
removeUnitFromMovingList(int unitId)632 void Faction::removeUnitFromMovingList(int unitId) {
633 	unitsMovingList.erase(unitId);
634 }
635 
getUnitMovingListCount()636 int Faction::getUnitMovingListCount() {
637 	return (int)unitsMovingList.size();
638 }
639 
addUnitToPathfindingList(int unitId)640 void Faction::addUnitToPathfindingList(int unitId) {
641 	//printf("ADD (1) Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
642 	unitsPathfindingList[unitId] = getWorld()->getFrameCount();
643 	//printf("ADD (2) Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
644 }
removeUnitFromPathfindingList(int unitId)645 void Faction::removeUnitFromPathfindingList(int unitId) {
646 	unitsPathfindingList.erase(unitId);
647 }
648 
getUnitPathfindingListCount()649 int Faction::getUnitPathfindingListCount() {
650 	//printf("GET Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
651 	return (int)unitsPathfindingList.size();
652 }
653 
clearUnitsPathfinding()654 void Faction::clearUnitsPathfinding() {
655 	//printf("CLEAR Faction [%d - %s] threaded updates for [%d] units\n",this->getStartLocationIndex(),this->getType()->getName().c_str(),unitsPathfindingList.size());
656 	if(unitsPathfindingList.empty() == false) {
657 		unitsPathfindingList.clear();
658 	}
659 }
660 
canUnitsPathfind()661 bool Faction::canUnitsPathfind() {
662 	bool result = true;
663 	if(control == ctCpuEasy  || control == ctCpu ||
664 	   control == ctCpuUltra || control == ctCpuMega) {
665 		//printf("AI player for faction index: %d (%s) current pathfinding: %d\n",index,factionType->getName().c_str(),getUnitPathfindingListCount());
666 
667 		const int MAX_UNITS_PATHFINDING_PER_FRAME = 10;
668 		result = (getUnitPathfindingListCount() <= MAX_UNITS_PATHFINDING_PER_FRAME);
669 		if(result == false) {
670 			//printf("WARNING limited AI player for faction index: %d (%s) current pathfinding: %d\n",index,factionType->getName().c_str(),getUnitPathfindingListCount());
671 		}
672 	}
673 	return result;
674 }
675 
setLockedUnitForFaction(const UnitType * ut,bool lock)676 void Faction::setLockedUnitForFaction(const UnitType *ut, bool lock) {
677 	if (lock) {
678 		lockedUnits.insert(ut);
679 	} else {
680 		std::set<const UnitType*>::iterator it;
681 		it=lockedUnits.find(ut);
682 		if(it!=lockedUnits.end()) {
683 			lockedUnits.erase(it);
684 		}
685 	}
686 
687 }
688 
signalWorkerThread(int frameIndex)689 void Faction::signalWorkerThread(int frameIndex) {
690 	if(workerThread != NULL) {
691 		workerThread->signalPathfinder(frameIndex);
692 	}
693 }
694 
isWorkerThreadSignalCompleted(int frameIndex)695 bool Faction::isWorkerThreadSignalCompleted(int frameIndex) {
696 	if(workerThread != NULL) {
697 		return workerThread->isSignalPathfinderCompleted(frameIndex);
698 	}
699 	return true;
700 }
701 
702 
init(FactionType * factionType,ControlType control,TechTree * techTree,Game * game,int factionIndex,int teamIndex,int startLocationIndex,bool thisFaction,bool giveResources,const XmlNode * loadWorldNode)703 void Faction::init(
704 	FactionType *factionType, ControlType control, TechTree *techTree, Game *game,
705 	int factionIndex, int teamIndex, int startLocationIndex, bool thisFaction, bool giveResources,
706 	const XmlNode *loadWorldNode)
707 {
708 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
709 
710 	this->techTree = techTree;
711 	this->loadWorldNode = loadWorldNode;
712 	this->control= control;
713 	this->factionType= factionType;
714 	this->startLocationIndex= startLocationIndex;
715 	this->index= factionIndex;
716 	this->teamIndex= teamIndex;
717 	this->thisFaction= thisFaction;
718 	this->world= game->getWorld();
719 	this->scriptManager= game->getScriptManager();
720 	//cachingDisabled = (Config::getInstance().getBool("DisableCaching","false") == true);
721 	cachingDisabled = false;
722 
723 	resources.resize(techTree->getResourceTypeCount());
724 	store.resize(techTree->getResourceTypeCount());
725 
726 	if(loadWorldNode == NULL) {
727 		for(int index = 0; index < techTree->getResourceTypeCount(); ++index) {
728 			const ResourceType *rt	= techTree->getResourceType(index);
729 			int resourceAmount		= giveResources ? factionType->getStartingResourceAmount(rt): 0;
730 			resources[index].init(rt, resourceAmount);
731 			store[index].init(rt, 0);
732 
733 			this->world->initTeamResource(rt,this->teamIndex,0);
734 		}
735 	}
736 	//initialize cache
737 	for(int index = 0; index < techTree->getResourceTypeCount(); ++index) {
738 		const ResourceType *rt	= techTree->getResourceType(index);
739 		this->updateUnitTypeWithResourceCostCache(rt);
740 	}
741 
742 	texture= Renderer::getInstance().newTexture2D(rsGame);
743 	string data_path = getGameReadWritePath(GameConstants::path_data_CacheLookupKey);
744 	if(texture) {
745 		string playerTexture = getGameCustomCoreDataPath(data_path, "data/core/faction_textures/faction" + intToStr(startLocationIndex) + ".tga");
746 		texture->load(playerTexture);
747 	}
748 
749 	if(loadWorldNode != NULL) {
750 		loadGame(loadWorldNode, this->index,game->getGameSettings(),game->getWorld());
751 	}
752 
753 	if( game->getGameSettings()->getPathFinderType() == pfBasic) {
754 		if(workerThread != NULL) {
755 			workerThread->signalQuit();
756 			if(workerThread->shutdownAndWait() == true) {
757 				delete workerThread;
758 			}
759 			workerThread = NULL;
760 		}
761 		static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
762 		this->workerThread = new FactionThread(this);
763 		this->workerThread->setUniqueID(mutexOwnerId);
764 		this->workerThread->start();
765 	}
766 
767 	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
768 }
769 
770 // ================== get ==================
771 
hasUnitTypeWithResourceCostInCache(const ResourceType * rt) const772 bool Faction::hasUnitTypeWithResourceCostInCache(const ResourceType *rt) const {
773 	std::string resourceTypeName = rt->getName(false);
774 	std::map<std::string, bool>::const_iterator iterFind = resourceTypeCostCache.find(resourceTypeName);
775 	if(iterFind != resourceTypeCostCache.end()) {
776 		return iterFind->second;
777 	}
778 	return false;
779 }
updateUnitTypeWithResourceCostCache(const ResourceType * rt)780 void Faction::updateUnitTypeWithResourceCostCache(const ResourceType *rt) {
781 	std::string resourceTypeName = rt->getName(false);
782 
783 	if(resourceTypeCostCache.find(resourceTypeName) == resourceTypeCostCache.end()) {
784 		resourceTypeCostCache[resourceTypeName] = hasUnitTypeWithResouceCost(rt);
785 	}
786 }
787 
hasUnitTypeWithResouceCost(const ResourceType * rt)788 bool Faction::hasUnitTypeWithResouceCost(const ResourceType *rt) {
789 	for(int factionUnitTypeIndex = 0;
790 			factionUnitTypeIndex < getType()->getUnitTypeCount();
791 				++factionUnitTypeIndex) {
792 
793 		const UnitType *ut = getType()->getUnitType(factionUnitTypeIndex);
794 		if(ut->getCost(rt) != NULL) {
795 			return true;
796 		}
797 	}
798 	return false;
799 }
800 
getResource(const ResourceType * rt,bool localFactionOnly) const801 const Resource *Faction::getResource(const ResourceType *rt,bool localFactionOnly) const {
802 
803 	if(localFactionOnly == false &&
804 			world != NULL &&
805 				world->getGame() != NULL) {
806 
807 		Game *game = world->getGame();
808 		if(game->isFlagType1BitEnabled(ft1_allow_shared_team_resources) == true) {
809 			return world->getResourceForTeam(rt, this->getTeam());
810 		}
811 	}
812 
813 	for(int index = 0; index < (int)resources.size(); ++index) {
814 		if(rt == resources[index].getType()) {
815 			return &resources[index];
816 		}
817 	}
818 
819 	printf("ERROR cannot find resource type [%s] in list:\n",(rt != NULL ? rt->getName().c_str() : "null"));
820 	for(int i=0; i < (int)resources.size(); ++i){
821 		printf("Index %d [%s]",i,resources[i].getType()->getName().c_str());
822 	}
823 
824 	assert(false);
825 	return NULL;
826 }
827 
getStoreAmount(const ResourceType * rt,bool localFactionOnly) const828 int Faction::getStoreAmount(const ResourceType *rt,bool localFactionOnly) const {
829 
830 	if(localFactionOnly == false &&
831 			world != NULL &&
832 				world->getGame() != NULL) {
833 
834 		Game *game = world->getGame();
835 		if(game->isFlagType1BitEnabled(ft1_allow_shared_team_resources) == true) {
836 			return world->getStoreAmountForTeam(rt, this->getTeam());
837 		}
838 	}
839 
840 	for(int index =0 ; index < (int)store.size(); ++index) {
841 		if(rt == store[index].getType()) {
842 			return store[index].getAmount();
843 		}
844 	}
845 	printf("ERROR cannot find store type [%s] in list:\n",(rt != NULL ? rt->getName().c_str() : "null"));
846 	for(int i=0; i < (int)store.size(); ++i){
847 		printf("Index %d [%s]",i,store[i].getType()->getName().c_str());
848 	}
849 
850 	assert(false);
851 	return 0;
852 }
853 
getCpuControl(bool enableServerControlledAI,bool isNetworkGame,NetworkRole role) const854 bool Faction::getCpuControl(bool enableServerControlledAI,bool isNetworkGame, NetworkRole role) const {
855 	bool result = false;
856 	if(enableServerControlledAI == false || isNetworkGame == false) {
857 			result = (control == ctCpuEasy ||control == ctCpu || control == ctCpuUltra || control == ctCpuMega);
858 	}
859 	else {
860 		if(isNetworkGame == true) {
861 			if(role == nrServer) {
862 				result = (control == ctCpuEasy ||control == ctCpu || control == ctCpuUltra || control == ctCpuMega);
863 			}
864 			else {
865 				result = (control == ctNetworkCpuEasy ||control == ctNetworkCpu || control == ctNetworkCpuUltra || control == ctNetworkCpuMega);
866 			}
867 		}
868 	}
869 
870 	return result;
871 }
872 
getCpuControl() const873 bool Faction::getCpuControl() const {
874 	return 	control == ctCpuEasy 		||control == ctCpu 			|| control == ctCpuUltra 		|| control == ctCpuMega ||
875 			control == ctNetworkCpuEasy ||control == ctNetworkCpu 	|| control == ctNetworkCpuUltra || control == ctNetworkCpuMega;
876 }
877 
878 // ==================== upgrade manager ====================
879 
startUpgrade(const UpgradeType * ut)880 void Faction::startUpgrade(const UpgradeType *ut){
881 	upgradeManager.startUpgrade(ut, index);
882 }
883 
cancelUpgrade(const UpgradeType * ut)884 void Faction::cancelUpgrade(const UpgradeType *ut){
885 	upgradeManager.cancelUpgrade(ut);
886 }
887 
finishUpgrade(const UpgradeType * ut)888 void Faction::finishUpgrade(const UpgradeType *ut){
889 	upgradeManager.finishUpgrade(ut);
890 	if(world->getThisFaction()!=NULL && this->getIndex()==world->getThisFaction()->getIndex()){
891 		Console *console=world->getGame()->getConsole();
892 		console->addStdMessage("UpgradeFinished",": " + formatString(ut->getName(true)));
893 	}
894 	for(int i=0; i<getUnitCount(); ++i){
895 		getUnit(i)->applyUpgrade(ut);
896 	}
897 }
898 
899 // ==================== reqs ====================
900 
901 //checks if all required units and upgrades are present and maxUnitCount is within limit
reqsOk(const RequirableType * rt) const902 bool Faction::reqsOk(const RequirableType *rt) const {
903 	assert(rt != NULL);
904 	//required units
905     for(int i = 0; i < rt->getUnitReqCount(); ++i) {
906         bool found = false;
907         for(int j = 0; j < getUnitCount(); ++j) {
908 			Unit *unit= getUnit(j);
909             const UnitType *ut= unit->getType();
910             if(rt->getUnitReq(i) == ut && unit->isOperative()) {
911                 found= true;
912                 break;
913             }
914         }
915 		if(found == false) {
916 			if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__, __LINE__);
917             return false;
918 		}
919     }
920 
921 	//required upgrades
922     for(int i = 0; i < rt->getUpgradeReqCount(); ++i) {
923 		if(upgradeManager.isUpgraded(rt->getUpgradeReq(i)) == false) {
924 			if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__, __LINE__);
925 			return false;
926 		}
927     }
928 
929     if(dynamic_cast<const UnitType *>(rt) != NULL ) {
930     	const UnitType *producedUnitType= dynamic_cast<const UnitType *>(rt);
931    		if(producedUnitType != NULL && producedUnitType->getMaxUnitCount() > 0) {
932 			if(producedUnitType->getMaxUnitCount() <= getCountForMaxUnitCount(producedUnitType)) {
933 				if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__, __LINE__);
934 		        return false;
935 			}
936    		}
937 
938    		if(producedUnitType != NULL && isUnitLocked(producedUnitType)) {
939    			return false;
940    		}
941     }
942 
943 	return true;
944 }
945 
getCountForMaxUnitCount(const UnitType * unitType) const946 int Faction::getCountForMaxUnitCount(const UnitType *unitType) const{
947 	int count=0;
948 	//calculate current unit count
949    	for(int j=0; j<getUnitCount(); ++j){
950 		Unit *unit= getUnit(j);
951         const UnitType *currentUt= unit->getType();
952         if(unitType==currentUt && unit->isOperative()){
953             count++;
954         }
955         //check if there is any command active which already produces this unit
956         count=count+unit->getCountOfProducedUnits(unitType);
957     }
958 	return count;
959 }
960 
961 
reqsOk(const CommandType * ct) const962 bool Faction::reqsOk(const CommandType *ct) const {
963 	assert(ct != NULL);
964 	if(ct == NULL) {
965 	    throw megaglest_runtime_error("In [Faction::reqsOk] ct == NULL");
966 	}
967 
968 	if(ct->getProduced() != NULL && reqsOk(ct->getProduced()) == false) {
969 		if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] reqsOk FAILED\n",__FILE__,__FUNCTION__,__LINE__);
970 		return false;
971 	}
972 
973 	if(ct->getClass() == ccUpgrade) {
974 		const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(ct);
975 		if(upgradeManager.isUpgradingOrUpgraded(uct->getProducedUpgrade())) {
976 			if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] upgrade check FAILED\n",__FILE__,__FUNCTION__,__LINE__);
977 			return false;
978 		}
979 	}
980 
981 	return reqsOk(static_cast<const RequirableType*>(ct));
982 }
983 
984 // ================== cost application ==================
985 
986 //apply costs except static production (start building/production)
applyCosts(const ProducibleType * p,const CommandType * ct)987 bool Faction::applyCosts(const ProducibleType *p,const CommandType *ct) {
988 	bool ignoreResourceCosts = false;
989 	if(ct != NULL && ct->getClass() == ccMorph) {
990 		const MorphCommandType *mct = dynamic_cast<const MorphCommandType *>(ct);
991 		if(mct != NULL) {
992 			ignoreResourceCosts = mct->getIgnoreResourceRequirements();
993 		}
994 	}
995 
996 	if(ignoreResourceCosts == false) {
997 		if(checkCosts(p,ct) == false) {
998 			return false;
999 		}
1000 
1001 		assert(p != NULL);
1002 		//for each unit cost spend it
1003 		//pass 2, decrease resources, except negative static costs (ie: farms)
1004 		for(int i=0; i<p->getCostCount(); ++i) {
1005 			const Resource *r= p->getCost(i);
1006 			if(r == NULL) {
1007 				char szBuf[8096]="";
1008 				snprintf(szBuf,8096,"cannot apply costs for p [%s] %d of %d costs resource is null",p->getName(false).c_str(),i,p->getCostCount());
1009 				throw megaglest_runtime_error(szBuf);
1010 			}
1011 
1012 			const ResourceType *rt= r->getType();
1013 			if(rt == NULL) {
1014 				char szBuf[8096]="";
1015 				snprintf(szBuf,8096,"cannot apply costs for p [%s] %d of %d costs resourcetype [%s] is null",p->getName(false).c_str(),i,p->getCostCount(),r->getDescription(false).c_str());
1016 				throw megaglest_runtime_error(szBuf);
1017 			}
1018 			int cost= r->getAmount();
1019 			if((cost > 0 || (rt->getClass() != rcStatic)) && rt->getClass() != rcConsumable) {
1020 				incResourceAmount(rt, -(cost));
1021 			}
1022 
1023 		}
1024 	}
1025     return true;
1026 }
1027 
1028 //apply discount (when a morph ends)
applyDiscount(const ProducibleType * p,int discount)1029 void Faction::applyDiscount(const ProducibleType *p, int discount)
1030 {
1031 	assert(p != NULL);
1032 	//increase resources
1033 	for(int i=0; i<p->getCostCount(); ++i)
1034 	{
1035 		const ResourceType *rt= p->getCost(i)->getType();
1036 		assert(rt != NULL);
1037         int cost= p->getCost(i)->getAmount();
1038 		if((cost > 0 || (rt->getClass() != rcStatic)) && rt->getClass() != rcConsumable)
1039 		{
1040             incResourceAmount(rt, cost*discount/100);
1041 		}
1042     }
1043 }
1044 
1045 //apply static production (for starting units)
applyStaticCosts(const ProducibleType * p,const CommandType * ct)1046 void Faction::applyStaticCosts(const ProducibleType *p,const CommandType *ct) {
1047 	assert(p != NULL);
1048 	bool ignoreResourceCosts = false;
1049 	if(ct != NULL && ct->getClass() == ccMorph) {
1050 		const MorphCommandType *mct = dynamic_cast<const MorphCommandType *>(ct);
1051 		if(mct != NULL) {
1052 			ignoreResourceCosts = mct->getIgnoreResourceRequirements();
1053 		}
1054 	}
1055 
1056 	if(ignoreResourceCosts == false) {
1057 		//decrease static resources
1058 		for(int i=0; i < p->getCostCount(); ++i) {
1059 			const ResourceType *rt= p->getCost(i)->getType();
1060 			//assert(rt != NULL);
1061 			if(rt == NULL) {
1062 				throw megaglest_runtime_error(string(__FUNCTION__) + " rt == NULL for ProducibleType [" + p->getName(false) + "] index: " + intToStr(i));
1063 			}
1064 			if(rt->getClass() == rcStatic) {
1065 				int cost= p->getCost(i)->getAmount();
1066 				if(cost > 0) {
1067 					incResourceAmount(rt, -cost);
1068 				}
1069 			}
1070 		}
1071 	}
1072 }
1073 
1074 //apply static production (when a mana source is done)
applyStaticProduction(const ProducibleType * p,const CommandType * ct)1075 void Faction::applyStaticProduction(const ProducibleType *p,const CommandType *ct) {
1076 	assert(p != NULL);
1077 
1078 	bool ignoreResourceCosts = false;
1079 	if(ct != NULL && ct->getClass() == ccMorph) {
1080 		const MorphCommandType *mct = dynamic_cast<const MorphCommandType *>(ct);
1081 		if(mct != NULL) {
1082 			ignoreResourceCosts = mct->getIgnoreResourceRequirements();
1083 		}
1084 	}
1085 
1086 	if(ignoreResourceCosts == false) {
1087 		//decrease static resources
1088 		for(int i=0; i<p->getCostCount(); ++i) {
1089 			const ResourceType *rt= p->getCost(i)->getType();
1090 			assert(rt != NULL);
1091 			if(rt->getClass() == rcStatic) {
1092 				int cost= p->getCost(i)->getAmount();
1093 				if(cost < 0) {
1094 					incResourceAmount(rt, -cost);
1095 				}
1096 			}
1097 		}
1098 	}
1099 }
1100 
1101 //deapply all costs except static production (usually when a building is cancelled)
deApplyCosts(const ProducibleType * p,const CommandType * ct)1102 void Faction::deApplyCosts(const ProducibleType *p,const CommandType *ct) {
1103 	assert(p != NULL);
1104 
1105 	bool ignoreResourceCosts = false;
1106 	if(ct != NULL && ct->getClass() == ccMorph) {
1107 		const MorphCommandType *mct = dynamic_cast<const MorphCommandType *>(ct);
1108 		if(mct != NULL) {
1109 			ignoreResourceCosts = mct->getIgnoreResourceRequirements();
1110 		}
1111 	}
1112 
1113 	if(ignoreResourceCosts == false) {
1114 		//increase resources
1115 		for(int i=0; i<p->getCostCount(); ++i) {
1116 			const ResourceType *rt= p->getCost(i)->getType();
1117 			assert(rt != NULL);
1118 			int cost= p->getCost(i)->getAmount();
1119 			if((cost > 0 || (rt->getClass() != rcStatic)) && rt->getClass() != rcConsumable) {
1120 				incResourceAmount(rt, cost);
1121 			}
1122 		}
1123 	}
1124 }
1125 
1126 //deapply static costs (usually when a unit dies)
deApplyStaticCosts(const ProducibleType * p,const CommandType * ct)1127 void Faction::deApplyStaticCosts(const ProducibleType *p,const CommandType *ct) {
1128 	assert(p != NULL);
1129 
1130 	bool ignoreResourceCosts = false;
1131 	if(ct != NULL && ct->getClass() == ccMorph) {
1132 		const MorphCommandType *mct = dynamic_cast<const MorphCommandType *>(ct);
1133 		if(mct != NULL) {
1134 			ignoreResourceCosts = mct->getIgnoreResourceRequirements();
1135 		}
1136 	}
1137 
1138 	if(ignoreResourceCosts == false) {
1139 		//decrease resources
1140 		for(int i=0; i<p->getCostCount(); ++i) {
1141 			const ResourceType *rt= p->getCost(i)->getType();
1142 			assert(rt != NULL);
1143 			if(rt->getClass() == rcStatic) {
1144 				if(rt->getRecoup_cost() == true) {
1145 					int cost= p->getCost(i)->getAmount();
1146 					incResourceAmount(rt, cost);
1147 				}
1148 			}
1149 		}
1150 	}
1151 }
1152 
1153 //deapply static costs, but not negative costs, for when building gets killed
deApplyStaticConsumption(const ProducibleType * p,const CommandType * ct)1154 void Faction::deApplyStaticConsumption(const ProducibleType *p,const CommandType *ct) {
1155 	assert(p != NULL);
1156 
1157 	bool ignoreResourceCosts = false;
1158 	if(ct != NULL && ct->getClass() == ccMorph) {
1159 		const MorphCommandType *mct = dynamic_cast<const MorphCommandType *>(ct);
1160 		if(mct != NULL) {
1161 			ignoreResourceCosts = mct->getIgnoreResourceRequirements();
1162 		}
1163 	}
1164 
1165 	if(ignoreResourceCosts == false) {
1166 		//decrease resources
1167 		for(int i=0; i<p->getCostCount(); ++i) {
1168 			const ResourceType *rt= p->getCost(i)->getType();
1169 			assert(rt != NULL);
1170 			if(rt->getClass() == rcStatic) {
1171 				int cost= p->getCost(i)->getAmount();
1172 				if(cost > 0) {
1173 					incResourceAmount(rt, cost);
1174 				}
1175 			}
1176 		}
1177 	}
1178 }
1179 
1180 //apply resource on interval (cosumable resouces)
applyCostsOnInterval(const ResourceType * rtApply)1181 void Faction::applyCostsOnInterval(const ResourceType *rtApply) {
1182 
1183 	// For each Resource type we store in the int a total consumed value, then
1184 	// a vector of units that consume the resource type
1185 	std::map<const ResourceType *, std::pair<int, std::vector<Unit *> > > resourceIntervalUsage;
1186 
1187 	// count up consumables usage for the interval
1188 	for(int j = 0; j < getUnitCount(); ++j) {
1189 		Unit *unit = getUnit(j);
1190 		if(unit->isOperative() == true) {
1191 			for(int k = 0; k < unit->getType()->getCostCount(); ++k) {
1192 				const Resource *resource = unit->getType()->getCost(k);
1193 				if(resource->getType() == rtApply && resource->getType()->getClass() == rcConsumable && resource->getAmount() != 0) {
1194 					if(resourceIntervalUsage.find(resource->getType()) == resourceIntervalUsage.end()) {
1195 						resourceIntervalUsage[resource->getType()] = make_pair<int, std::vector<Unit *> >(0,std::vector<Unit *>());
1196 					}
1197 					// Negative cost means accumulate the resource type
1198 					resourceIntervalUsage[resource->getType()].first += -resource->getAmount();
1199 
1200 					// If the cost > 0 then the unit is a consumer
1201 					if(resource->getAmount() > 0) {
1202 						resourceIntervalUsage[resource->getType()].second.push_back(unit);
1203 					}
1204 				}
1205 			}
1206 		}
1207 	}
1208 
1209 	// Apply consumable resource usage
1210 	if(resourceIntervalUsage.empty() == false) {
1211 		for(std::map<const ResourceType *, std::pair<int, std::vector<Unit *> > >::iterator iter = resourceIntervalUsage.begin();
1212 																							iter != resourceIntervalUsage.end();
1213 																							++iter) {
1214 			// Apply resource type usage to faction resource store
1215 			const ResourceType *rt = iter->first;
1216 			int resourceTypeUsage = iter->second.first;
1217 			incResourceAmount(rt, resourceTypeUsage);
1218 
1219 			// Check if we have any unit consumers
1220 			if(getResource(rt)->getAmount() < 0) {
1221 				resetResourceAmount(rt);
1222 
1223 				// Apply consequences to consumer units of this resource type
1224 				std::vector<Unit *> &resourceConsumers = iter->second.second;
1225 
1226 				for(int i = 0; i < (int)resourceConsumers.size(); ++i) {
1227 					Unit *unit = resourceConsumers[i];
1228 
1229 					//decrease unit hp
1230 					if(scriptManager->getPlayerModifiers(this->index)->getConsumeEnabled() == true) {
1231 						bool decHpResult = unit->decHp(unit->getType()->getTotalMaxHp(unit->getTotalUpgrade()) / 3);
1232 						if(decHpResult) {
1233 							unit->setCauseOfDeath(ucodStarvedResource);
1234 							world->getStats()->die(unit->getFactionIndex(),unit->getType()->getCountUnitDeathInStats());
1235 							scriptManager->onUnitDied(unit);
1236 						}
1237 						StaticSound *sound= static_cast<const DieSkillType *>(unit->getType()->getFirstStOfClass(scDie))->getSound();
1238 						if(sound != NULL &&
1239 							(thisFaction == true || world->showWorldForPlayer(world->getThisTeamIndex()) == true)) {
1240 							SoundRenderer::getInstance().playFx(sound);
1241 						}
1242 					}
1243 				}
1244 			}
1245 		}
1246 	}
1247 }
1248 
checkCosts(const ProducibleType * pt,const CommandType * ct)1249 bool Faction::checkCosts(const ProducibleType *pt,const CommandType *ct) {
1250 	assert(pt != NULL);
1251 
1252 	bool ignoreResourceCosts = false;
1253 	if(ct != NULL && ct->getClass() == ccMorph) {
1254 		const MorphCommandType *mct = dynamic_cast<const MorphCommandType *>(ct);
1255 		if(mct != NULL) {
1256 			ignoreResourceCosts = mct->getIgnoreResourceRequirements();
1257 		}
1258 		//printf("Checking costs = %d for commandtype:\n%s\n",ignoreResourceCosts,mct->getDesc(NULL).c_str());
1259 	}
1260 
1261 	if(ignoreResourceCosts == false) {
1262 		//for each unit cost check if enough resources
1263 		for(int i = 0; i < pt->getCostCount(); ++i) {
1264 			const ResourceType *rt= pt->getCost(i)->getType();
1265 			int cost= pt->getCost(i)->getAmount();
1266 			if(cost > 0) {
1267 				int available= getResource(rt)->getAmount();
1268 				if(cost > available){
1269 					return false;
1270 				}
1271 			}
1272 		}
1273 	}
1274 
1275 	return true;
1276 }
1277 
1278 // ================== diplomacy ==================
1279 
isAlly(const Faction * faction)1280 bool Faction::isAlly(const Faction *faction) {
1281 	assert(faction != NULL);
1282 	return (teamIndex == faction->getTeam() ||
1283 			faction->getTeam() == GameConstants::maxPlayers -1 + fpt_Observer);
1284 }
1285 
1286 // ================== misc ==================
1287 
incResourceAmount(const ResourceType * rt,int amount)1288 void Faction::incResourceAmount(const ResourceType *rt, int amount) {
1289 	if (world != NULL && world->getGame() != NULL
1290 			&& world->getGame()->isFlagType1BitEnabled(
1291 					ft1_allow_shared_team_resources) == true) {
1292 		for(int i=0; i < (int)resources.size(); ++i) {
1293 			Resource *r= &resources[i];
1294 			if(r->getType()==rt) {
1295 				r->setAmount(r->getAmount()+amount);
1296 				if(r->getType()->getClass() != rcStatic && (getResource(rt,false)->getAmount()+amount)>getStoreAmount(rt,false)) {
1297 					r->setAmount(getStoreAmount(rt,false)-(getResource(rt,false)->getAmount()-r->getAmount()));
1298 				}
1299 				return;
1300 			}
1301 		}
1302 	} else {
1303 		for(int i=0; i < (int)resources.size(); ++i) {
1304 			Resource *r= &resources[i];
1305 			if(r->getType()==rt) {
1306 				r->setAmount(r->getAmount()+amount);
1307 				if(r->getType()->getClass() != rcStatic && r->getAmount()>getStoreAmount(rt)) {
1308 					r->setAmount(getStoreAmount(rt));
1309 				}
1310 				return;
1311 			}
1312 		}
1313 	}
1314 	assert(false);
1315 }
1316 
setResourceBalance(const ResourceType * rt,int balance)1317 void Faction::setResourceBalance(const ResourceType *rt, int balance){
1318 	for(int i=0; i < (int)resources.size(); ++i){
1319 		Resource *r= &resources[i];
1320 		if(r->getType()==rt){
1321 			r->setBalance(balance);
1322 			return;
1323 		}
1324 	}
1325 	assert(false);
1326 }
1327 
findUnit(int id) const1328 Unit *Faction::findUnit(int id) const {
1329 	UnitMap::const_iterator itFound = unitMap.find(id);
1330 	if(itFound == unitMap.end()) {
1331 		return NULL;
1332 	}
1333 	return itFound->second;
1334 }
1335 
addUnit(Unit * unit)1336 void Faction::addUnit(Unit *unit) {
1337 	MutexSafeWrapper safeMutex(unitsMutex,string(__FILE__) + "_" + intToStr(__LINE__));
1338 	units.push_back(unit);
1339 	unitMap[unit->getId()] = unit;
1340 }
1341 
removeUnit(Unit * unit)1342 void Faction::removeUnit(Unit *unit){
1343 	MutexSafeWrapper safeMutex(unitsMutex,string(__FILE__) + "_" + intToStr(__LINE__));
1344 
1345 	assert(units.size()==unitMap.size());
1346 
1347 	int unitId = unit->getId();
1348 	for(int i=0; i < (int)units.size(); ++i) {
1349 		if(units[i]->getId() == unitId) {
1350 			units.erase(units.begin()+i);
1351 			unitMap.erase(unitId);
1352 			assert(units.size() == unitMap.size());
1353 			return;
1354 		}
1355 	}
1356 
1357 	throw megaglest_runtime_error("Could not remove unit from faction!");
1358 	//assert(false);
1359 }
1360 
addStore(const UnitType * unitType)1361 void Faction::addStore(const UnitType *unitType) {
1362 	assert(unitType != NULL);
1363 	for(int newUnitStoredResourceIndex = 0;
1364 			newUnitStoredResourceIndex < unitType->getStoredResourceCount();
1365 			++newUnitStoredResourceIndex) {
1366 		const Resource *newUnitStoredResource = unitType->getStoredResource(newUnitStoredResourceIndex);
1367 
1368 		for(int currentStoredResourceIndex = 0;
1369 				currentStoredResourceIndex < (int)store.size();
1370 				++currentStoredResourceIndex) {
1371 			Resource *storedResource= &store[currentStoredResourceIndex];
1372 
1373 			if(storedResource->getType() == newUnitStoredResource->getType()) {
1374 				storedResource->setAmount(storedResource->getAmount() + newUnitStoredResource->getAmount());
1375 			}
1376 		}
1377 	}
1378 }
1379 
removeStore(const UnitType * unitType)1380 void Faction::removeStore(const UnitType *unitType){
1381 	assert(unitType != NULL);
1382 	for(int i=0; i<unitType->getStoredResourceCount(); ++i){
1383 		const Resource *r= unitType->getStoredResource(i);
1384 		for(int j=0; j < (int)store.size(); ++j){
1385 			Resource *storedResource= &store[j];
1386 			if(storedResource->getType() == r->getType()){
1387 				storedResource->setAmount(storedResource->getAmount() - r->getAmount());
1388 			}
1389 		}
1390 	}
1391 	limitResourcesToStore();
1392 }
1393 
limitResourcesToStore()1394 void Faction::limitResourcesToStore() {
1395 	if (world != NULL && world->getGame() != NULL
1396 			&& world->getGame()->isFlagType1BitEnabled(
1397 					ft1_allow_shared_team_resources) == true) {
1398 		for(int i=0; i < (int)resources.size(); ++i) {
1399 			Resource *r= &resources[i];
1400 			const ResourceType *rt= r->getType();
1401 			if(rt->getClass() != rcStatic && (getResource(rt,false)->getAmount())>getStoreAmount(rt,false)) {
1402 				r->setAmount(getStoreAmount(rt,false)-(getResource(rt,false)->getAmount()-r->getAmount()));
1403 			}
1404 		}
1405 	} else {
1406 		for(int i=0; i < (int)resources.size(); ++i) {
1407 			Resource *r= &resources[i];
1408 			Resource *s= &store[i];
1409 			if(r->getType()->getClass() != rcStatic && r->getAmount()>s->getAmount()) {
1410 				r->setAmount(s->getAmount());
1411 			}
1412 		}
1413 	}
1414 }
1415 
resetResourceAmount(const ResourceType * rt)1416 void Faction::resetResourceAmount(const ResourceType *rt){
1417 	for(int i=0; i < (int)resources.size(); ++i){
1418 		if(resources[i].getType()==rt){
1419 			resources[i].setAmount(0);
1420 			return;
1421 		}
1422 	}
1423 	assert(false);
1424 }
1425 
isResourceTargetInCache(const Vec2i & pos,bool incrementUseCounter)1426 bool Faction::isResourceTargetInCache(const Vec2i &pos, bool incrementUseCounter) {
1427 	bool result = false;
1428 
1429 	if(cachingDisabled == false) {
1430 		if(cacheResourceTargetList.empty() == false) {
1431 			std::map<Vec2i,int>::iterator iter = cacheResourceTargetList.find(pos);
1432 
1433 			result = (iter != cacheResourceTargetList.end());
1434 			if(result == true && incrementUseCounter == true) {
1435 				iter->second++;
1436 			}
1437 		}
1438 	}
1439 
1440 	return result;
1441 }
1442 
addResourceTargetToCache(const Vec2i & pos,bool incrementUseCounter)1443 void Faction::addResourceTargetToCache(const Vec2i &pos,bool incrementUseCounter) {
1444 	if(cachingDisabled == false) {
1445 
1446 		bool duplicateEntry = isResourceTargetInCache(pos,incrementUseCounter);
1447 		//bool duplicateEntry = false;
1448 
1449 		if(duplicateEntry == false) {
1450 			cacheResourceTargetList[pos] = 1;
1451 
1452 			if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
1453 				char szBuf[8096]="";
1454 				snprintf(szBuf,8096,"[addResourceTargetToCache] pos [%s]cacheResourceTargetList.size() [" MG_SIZE_T_SPECIFIER "]",
1455 								pos.getString().c_str(),cacheResourceTargetList.size());
1456 
1457 				//unit->logSynchData(szBuf);
1458 				SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"----------------------------------- START [%d] ------------------------------------------------\n",getFrameCount());
1459 				SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"[%s::%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__);
1460 				SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"%s\n",szBuf);
1461 				SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"------------------------------------ END [%d] -------------------------------------------------\n",getFrameCount());
1462 			}
1463 		}
1464 	}
1465 }
1466 
removeResourceTargetFromCache(const Vec2i & pos)1467 void Faction::removeResourceTargetFromCache(const Vec2i &pos) {
1468 	if(cachingDisabled == false) {
1469 		if(cacheResourceTargetList.empty() == false) {
1470 			std::map<Vec2i,int>::iterator iter = cacheResourceTargetList.find(pos);
1471 
1472 			if(iter != cacheResourceTargetList.end()) {
1473 				cacheResourceTargetList.erase(pos);
1474 
1475 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
1476 					char szBuf[8096]="";
1477 					snprintf(szBuf,8096,"[removeResourceTargetFromCache] pos [%s]cacheResourceTargetList.size() [" MG_SIZE_T_SPECIFIER "]",
1478 									pos.getString().c_str(),cacheResourceTargetList.size());
1479 
1480 					//unit->logSynchData(szBuf);
1481 					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"----------------------------------- START [%d] ------------------------------------------------\n",getFrameCount());
1482 					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"[%s::%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__);
1483 					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"%s\n",szBuf);
1484 					SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"------------------------------------ END [%d] -------------------------------------------------\n",getFrameCount());
1485 				}
1486 			}
1487 		}
1488 	}
1489 }
1490 
addCloseResourceTargetToCache(const Vec2i & pos)1491 void Faction::addCloseResourceTargetToCache(const Vec2i &pos) {
1492 	if(cachingDisabled == false) {
1493 		if(cachedCloseResourceTargetLookupList.find(pos) == cachedCloseResourceTargetLookupList.end()) {
1494 			const Map *map = world->getMap();
1495 			const int harvestDistance = 5;
1496 
1497 			for(int j = -harvestDistance; j <= harvestDistance; ++j) {
1498 				for(int k = -harvestDistance; k <= harvestDistance; ++k) {
1499 					Vec2i newPos = pos + Vec2i(j,k);
1500 					if(isResourceTargetInCache(newPos) == false) {
1501 						if(map->isInside(newPos.x, newPos.y)) {
1502 							Resource *r = map->getSurfaceCell(map->toSurfCoords(newPos))->getResource();
1503 							if(r != NULL) {
1504 								addResourceTargetToCache(newPos);
1505 								//cacheResourceTargetList[newPos] = 1;
1506 							}
1507 						}
1508 					}
1509 				}
1510 			}
1511 
1512 			cachedCloseResourceTargetLookupList[pos] = true;
1513 		}
1514 	}
1515 }
1516 
getClosestResourceTypeTargetFromCache(Unit * unit,const ResourceType * type,int frameIndex)1517 Vec2i Faction::getClosestResourceTypeTargetFromCache(Unit *unit, const ResourceType *type, int frameIndex) {
1518 	Vec2i result(-1);
1519 
1520 	if(cachingDisabled == false) {
1521 		if(cacheResourceTargetList.empty() == false) {
1522 			if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
1523 				char szBuf[8096]="";
1524 				snprintf(szBuf,8096,"cacheResourceTargetList.size() [" MG_SIZE_T_SPECIFIER "]",cacheResourceTargetList.size());
1525 
1526 				if(frameIndex < 0) {
1527 					unit->logSynchData(__FILE__,__LINE__,szBuf);
1528 				}
1529 				else {
1530 					unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf);
1531 				}
1532 			}
1533 
1534 
1535 			std::vector<Vec2i> deleteList;
1536 
1537 			const int harvestDistance = 5;
1538 			const Map *map = world->getMap();
1539 			Vec2i pos = unit->getPos();
1540 
1541 			bool foundCloseResource = false;
1542 			// First look immediately around the unit's position
1543 
1544 			// 0 means start looking leftbottom to top right
1545 //			if(Thread::isCurrentThreadMainThread() == false) {
1546 //				throw megaglest_runtime_error("#1 Invalid access to Faction random from outside main thread current id = " +
1547 //						intToStr(Thread::getCurrentThreadId()) + " main = " + intToStr(Thread::getMainThreadId()));
1548 //			}
1549 			int tryRadius = random.randRange(0,1);
1550 			//int tryRadius = unit->getRandom(true)->randRange(0,1);
1551 			//int tryRadius = 0;
1552 			if(tryRadius == 0) {
1553 				for(int j = -harvestDistance; j <= harvestDistance && foundCloseResource == false; ++j) {
1554 					for(int k = -harvestDistance; k <= harvestDistance && foundCloseResource == false; ++k) {
1555 						Vec2i newPos = pos + Vec2i(j,k);
1556 						if(map->isInside(newPos) == true && isResourceTargetInCache(newPos) == false) {
1557 							const SurfaceCell *sc = map->getSurfaceCell(map->toSurfCoords(newPos));
1558 							if( sc != NULL && sc->getResource() != NULL) {
1559 								const Resource *resource = sc->getResource();
1560 								if(resource->getType() != NULL && resource->getType() == type) {
1561 									if(result.x < 0 || unit->getPos().dist(newPos) < unit->getPos().dist(result)) {
1562 										if(unit->isBadHarvestPos(newPos) == false) {
1563 											result = newPos;
1564 											foundCloseResource = true;
1565 											break;
1566 										}
1567 									}
1568 								}
1569 							}
1570 							else {
1571 								deleteList.push_back(newPos);
1572 							}
1573 						}
1574 					}
1575 				}
1576 			}
1577 			// start looking topright to leftbottom
1578 			else {
1579 				for(int j = harvestDistance; j >= -harvestDistance && foundCloseResource == false; --j) {
1580 					for(int k = harvestDistance; k >= -harvestDistance && foundCloseResource == false; --k) {
1581 						Vec2i newPos = pos + Vec2i(j,k);
1582 						if(map->isInside(newPos) == true && isResourceTargetInCache(newPos) == false) {
1583 							const SurfaceCell *sc = map->getSurfaceCell(map->toSurfCoords(newPos));
1584 							if( sc != NULL && sc->getResource() != NULL) {
1585 								const Resource *resource = sc->getResource();
1586 								if(resource->getType() != NULL && resource->getType() == type) {
1587 									if(result.x < 0 || unit->getPos().dist(newPos) < unit->getPos().dist(result)) {
1588 										if(unit->isBadHarvestPos(newPos) == false) {
1589 											result = newPos;
1590 											foundCloseResource = true;
1591 											break;
1592 										}
1593 									}
1594 								}
1595 							}
1596 							else {
1597 								deleteList.push_back(newPos);
1598 							}
1599 						}
1600 					}
1601 				}
1602 			}
1603 
1604 			if(foundCloseResource == false) {
1605 				// Now check the whole cache
1606 				for(std::map<Vec2i,int>::iterator iter = cacheResourceTargetList.begin();
1607 											  iter != cacheResourceTargetList.end() && foundCloseResource == false;
1608 											  ++iter) {
1609 					const Vec2i &cache = iter->first;
1610 					if(map->isInside(cache) == true) {
1611 						const SurfaceCell *sc = map->getSurfaceCell(map->toSurfCoords(cache));
1612 						if( sc != NULL && sc->getResource() != NULL) {
1613 							const Resource *resource = sc->getResource();
1614 							if(resource->getType() != NULL && resource->getType() == type) {
1615 								if(result.x < 0 || unit->getPos().dist(cache) < unit->getPos().dist(result)) {
1616 									if(unit->isBadHarvestPos(cache) == false) {
1617 										result = cache;
1618 										// Close enough to our position, no more looking
1619 										if(unit->getPos().dist(result) <= (harvestDistance * 2)) {
1620 											foundCloseResource = true;
1621 											break;
1622 										}
1623 									}
1624 								}
1625 							}
1626 						}
1627 						else {
1628 							deleteList.push_back(cache);
1629 						}
1630 					}
1631 					else {
1632 						deleteList.push_back(cache);
1633 					}
1634 				}
1635 			}
1636 
1637 			if(deleteList.empty() == false) {
1638 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
1639 					char szBuf[8096]="";
1640 					snprintf(szBuf,8096,"[cleaning old resource targets] deleteList.size() [" MG_SIZE_T_SPECIFIER "] cacheResourceTargetList.size() [" MG_SIZE_T_SPECIFIER "] result [%s]",
1641 										deleteList.size(),cacheResourceTargetList.size(),result.getString().c_str());
1642 
1643 					if(frameIndex < 0) {
1644 						unit->logSynchData(__FILE__,__LINE__,szBuf);
1645 					}
1646 					else {
1647 						unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf);
1648 					}
1649 				}
1650 
1651 				cleanupResourceTypeTargetCache(&deleteList,frameIndex);
1652 			}
1653 		}
1654 	}
1655 
1656 	return result;
1657 }
1658 
1659 // CANNOT MODIFY the cache here since the AI calls this method and the AI is only controlled
1660 // by the server for network games and it would cause out of synch since clients do not call
1661 // this method so DO NOT modify the cache here!
getClosestResourceTypeTargetFromCache(const Vec2i & pos,const ResourceType * type)1662 Vec2i Faction::getClosestResourceTypeTargetFromCache(const Vec2i &pos, const ResourceType *type) {
1663 	Vec2i result(-1);
1664 	if(cachingDisabled == false) {
1665 		if(cacheResourceTargetList.empty() == false) {
1666 			//std::vector<Vec2i> deleteList;
1667 
1668 			const int harvestDistance = 5;
1669 			const Map *map = world->getMap();
1670 
1671 			bool foundCloseResource = false;
1672 
1673 			// 0 means start looking leftbottom to top right
1674 //			if(Thread::isCurrentThreadMainThread() == false) {
1675 //				throw megaglest_runtime_error("#2 Invalid access to Faction random from outside main thread current id = " +
1676 //						intToStr(Thread::getCurrentThreadId()) + " main = " + intToStr(Thread::getMainThreadId()));
1677 //			}
1678 			int tryRadius = random.randRange(0,1);
1679 			if(tryRadius == 0) {
1680 				// First look immediately around the given position
1681 				for(int j = -harvestDistance; j <= harvestDistance && foundCloseResource == false; ++j) {
1682 					for(int k = -harvestDistance; k <= harvestDistance && foundCloseResource == false; ++k) {
1683 						Vec2i newPos = pos + Vec2i(j,k);
1684 						if(map->isInside(newPos) == true && isResourceTargetInCache(newPos) == false) {
1685 							const SurfaceCell *sc = map->getSurfaceCell(map->toSurfCoords(newPos));
1686 							if( sc != NULL && sc->getResource() != NULL) {
1687 								const Resource *resource = sc->getResource();
1688 								if(resource->getType() != NULL && resource->getType() == type) {
1689 									if(result.x < 0 || pos.dist(newPos) < pos.dist(result)) {
1690 										result = newPos;
1691 										foundCloseResource = true;
1692 										break;
1693 									}
1694 								}
1695 							}
1696 							//else {
1697 							//	deleteList.push_back(newPos);
1698 							//}
1699 						}
1700 					}
1701 				}
1702 			}
1703 			else {
1704 				// First look immediately around the given position
1705 				for(int j = harvestDistance; j >= -harvestDistance && foundCloseResource == false; --j) {
1706 					for(int k = harvestDistance; k >= -harvestDistance && foundCloseResource == false; --k) {
1707 						Vec2i newPos = pos + Vec2i(j,k);
1708 						if(map->isInside(newPos) == true && isResourceTargetInCache(newPos) == false) {
1709 							const SurfaceCell *sc = map->getSurfaceCell(map->toSurfCoords(newPos));
1710 							if( sc != NULL && sc->getResource() != NULL) {
1711 								const Resource *resource = sc->getResource();
1712 								if(resource->getType() != NULL && resource->getType() == type) {
1713 									if(result.x < 0 || pos.dist(newPos) < pos.dist(result)) {
1714 										result = newPos;
1715 										foundCloseResource = true;
1716 										break;
1717 									}
1718 								}
1719 							}
1720 							//else {
1721 							//	deleteList.push_back(newPos);
1722 							//}
1723 						}
1724 					}
1725 				}
1726 			}
1727 
1728 			if(foundCloseResource == false) {
1729 				// Now check the whole cache
1730 				for(std::map<Vec2i,int>::iterator iter = cacheResourceTargetList.begin();
1731 											  iter != cacheResourceTargetList.end() && foundCloseResource == false;
1732 											  ++iter) {
1733 					const Vec2i &cache = iter->first;
1734 					if(map->isInside(cache) == true) {
1735 						const SurfaceCell *sc = map->getSurfaceCell(map->toSurfCoords(cache));
1736 						if( sc != NULL && sc->getResource() != NULL) {
1737 							const Resource *resource = sc->getResource();
1738 							if(resource->getType() != NULL && resource->getType() == type) {
1739 								if(result.x < 0 || pos.dist(cache) < pos.dist(result)) {
1740 									result = cache;
1741 									// Close enough to our position, no more looking
1742 									if(pos.dist(result) <= (harvestDistance * 2)) {
1743 										foundCloseResource = true;
1744 										break;
1745 									}
1746 								}
1747 							}
1748 						}
1749 						//else {
1750 						//	deleteList.push_back(cache);
1751 						//}
1752 					}
1753 					//else {
1754 					//	deleteList.push_back(cache);
1755 					//}
1756 				}
1757 			}
1758 		}
1759 	}
1760 
1761 	return result;
1762 }
1763 
cleanupResourceTypeTargetCache(std::vector<Vec2i> * deleteListPtr,int frameIndex)1764 void Faction::cleanupResourceTypeTargetCache(std::vector<Vec2i> *deleteListPtr,int frameIndex) {
1765 	if(cachingDisabled == false) {
1766 		if(cacheResourceTargetList.empty() == false) {
1767 			const int cleanupInterval = (GameConstants::updateFps * 5);
1768 			bool needToCleanup = (getFrameCount() % cleanupInterval == 0);
1769 
1770 			if(deleteListPtr != NULL || needToCleanup == true) {
1771 				std::vector<Vec2i> deleteList;
1772 
1773 				if(deleteListPtr != NULL) {
1774 					deleteList = *deleteListPtr;
1775 				}
1776 				else {
1777 					for(std::map<Vec2i,int>::iterator iter = cacheResourceTargetList.begin();
1778 												  iter != cacheResourceTargetList.end(); ++iter) {
1779 						const Vec2i &cache = iter->first;
1780 
1781 						if(world->getMap()->getSurfaceCell(world->getMap()->toSurfCoords(cache)) != NULL) {
1782 							Resource *resource = world->getMap()->getSurfaceCell(world->getMap()->toSurfCoords(cache))->getResource();
1783 							if(resource == NULL) {
1784 								deleteList.push_back(cache);
1785 							}
1786 						}
1787 						else {
1788 							deleteList.push_back(cache);
1789 						}
1790 					}
1791 				}
1792 
1793 				if(deleteList.empty() == false) {
1794 					if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
1795 						char szBuf[8096]="";
1796 						snprintf(szBuf,8096,"[cleaning old resource targets] deleteList.size() [" MG_SIZE_T_SPECIFIER "] cacheResourceTargetList.size() [" MG_SIZE_T_SPECIFIER "], needToCleanup [%d]",
1797 											deleteList.size(),cacheResourceTargetList.size(),needToCleanup);
1798 						//unit->logSynchData(szBuf);
1799 
1800 						char szBuf1[8096]="";
1801 						snprintf(szBuf1,8096,"----------------------------------- START [%d] ------------------------------------------------\n",getFrameCount());
1802 						string logDataText = szBuf1;
1803 
1804 						snprintf(szBuf1,8096,"[%s::%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__);
1805 						logDataText += szBuf1;
1806 
1807 						snprintf(szBuf1,8096,"%s\n",szBuf);
1808 						logDataText += szBuf1;
1809 
1810 						snprintf(szBuf1,8096,"------------------------------------ END [%d] -------------------------------------------------\n",getFrameCount());
1811 						logDataText += szBuf1;
1812 
1813 						if(frameIndex < 0) {
1814 							SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"%s",logDataText.c_str());
1815 						}
1816 						else {
1817 							addWorldSynchThreadedLogList(logDataText);
1818 						}
1819 					}
1820 
1821 					for(int i = 0; i < (int)deleteList.size(); ++i) {
1822 						Vec2i &cache = deleteList[i];
1823 						cacheResourceTargetList.erase(cache);
1824 					}
1825 				}
1826 			}
1827 		}
1828 	}
1829 }
1830 
1831 //std::vector<Vec2i> Faction::findCachedPath(const Vec2i &target, Unit *unit) {
1832 //	std::vector<Vec2i> result;
1833 //	if(cachingDisabled == false) {
1834 //		if(successfulPathFinderTargetList.find(target) == successfulPathFinderTargetList.end()) {
1835 //			// Lets find the shortest and most successful path already taken by a
1836 //			// similar sized unit
1837 //
1838 //			bool foundCachedPath = false;
1839 //			std::vector<FactionPathSuccessCache> &cacheList = successfulPathFinderTargetList[target];
1840 //			int unitSize = unit->getType()->getSize();
1841 //			for(int i = 0; i < cacheList.size(); ++i) {
1842 //				FactionPathSuccessCache &cache = cacheList[i];
1843 //				if(cache.unitSize <= unitSize) {
1844 //					vector<std::pair<vector<Vec2i>, int> > &pathQueue = cache.pathQueue;
1845 //
1846 //					for(int j = 0; j < pathQueue.size(); ++j) {
1847 //						// Now start at the end of the path and see how many nodes
1848 //						// until we reach a cell near the unit's current position
1849 //						std::pair<vector<Vec2i>, int> &path = pathQueue[j];
1850 //
1851 //						for(int k = path.first.size() - 1; k >= 0; --k) {
1852 //							if(world->getMap()->canMove(unit, unit->getPos(), path.first[k]) == true) {
1853 //								if(foundCachedPath == false) {
1854 //									for(int l = k; l < path.first.size(); ++l) {
1855 //										result.push_back(path.first[l]);
1856 //									}
1857 //								}
1858 //								else {
1859 //									if(result.size() > (path.first.size() - k)) {
1860 //										for(int l = k; l < path.first.size(); ++l) {
1861 //											result.push_back(path.first[l]);
1862 //										}
1863 //									}
1864 //								}
1865 //								foundCachedPath = true;
1866 //
1867 //								break;
1868 //							}
1869 //						}
1870 //					}
1871 //				}
1872 //			}
1873 //		}
1874 //	}
1875 //
1876 //	return result;
1877 //}
1878 
1879 //void Faction::addCachedPath(const Vec2i &target, Unit *unit) {
1880 //	if(cachingDisabled == false) {
1881 //		if(successfulPathFinderTargetList.find(target) == successfulPathFinderTargetList.end()) {
1882 //			FactionPathSuccessCache cache;
1883 //			cache.unitSize = unit->getType()->getSize();
1884 //			cache.pathQueue.push_back(make_pair<vector<Vec2i>, int>(unit->getCurrentTargetPathTaken().second,1));
1885 //			successfulPathFinderTargetList[target].push_back(cache);
1886 //		}
1887 //		else {
1888 //			bool finishedAdd = false;
1889 //			std::pair<Vec2i,std::vector<Vec2i> > currentTargetPathTaken = unit->getCurrentTargetPathTaken();
1890 //			std::vector<FactionPathSuccessCache> &cacheList = successfulPathFinderTargetList[target];
1891 //			int unitSize = unit->getType()->getSize();
1892 //
1893 //			for(int i = 0; i < cacheList.size() && finishedAdd == false; ++i) {
1894 //				FactionPathSuccessCache &cache = cacheList[i];
1895 //				if(cache.unitSize <= unitSize) {
1896 //					vector<std::pair<vector<Vec2i>, int> > &pathQueue = cache.pathQueue;
1897 //
1898 //					for(int j = 0; j < pathQueue.size() && finishedAdd == false; ++j) {
1899 //						// Now start at the end of the path and see how many nodes are the same
1900 //						std::pair<vector<Vec2i>, int> &path = pathQueue[j];
1901 //						int minPathSize = std::min(path.first.size(),currentTargetPathTaken.second.size());
1902 //						int intersectIndex = -1;
1903 //
1904 //						for(int k = 0; k < minPathSize; ++k) {
1905 //							if(path.first[path.first.size() - k - 1] != currentTargetPathTaken.second[currentTargetPathTaken.second.size() - k - 1]) {
1906 //								intersectIndex = k;
1907 //								break;
1908 //							}
1909 //						}
1910 //
1911 //						// New path is same or longer than old path so replace
1912 //						// old path with new
1913 //						if(intersectIndex + 1 == path.first.size()) {
1914 //							path.first = currentTargetPathTaken.second;
1915 //							path.second++;
1916 //							finishedAdd = true;
1917 //						}
1918 //						// Old path is same or longer than new path so
1919 //						// do nothing
1920 //						else if(intersectIndex + 1 == currentTargetPathTaken.second.size()) {
1921 //							path.second++;
1922 //							finishedAdd = true;
1923 //						}
1924 //					}
1925 //
1926 //					// If new path is >= 10 cells add it
1927 //					if(finishedAdd == false && currentTargetPathTaken.second.size() >= 10) {
1928 //						pathQueue.push_back(make_pair<vector<Vec2i>, int>(currentTargetPathTaken.second,1));
1929 //					}
1930 //				}
1931 //			}
1932 //		}
1933 //	}
1934 //}
1935 
deletePixels()1936 void Faction::deletePixels() {
1937 	if(factionType != NULL) {
1938 		factionType->deletePixels();
1939 	}
1940 }
1941 
findClosestUnitWithSkillClass(const Vec2i & pos,const CommandClass & cmdClass,const std::vector<SkillClass> & skillClassList,const UnitType * unitType)1942 Unit * Faction::findClosestUnitWithSkillClass(	const Vec2i &pos,const CommandClass &cmdClass,
1943 												const std::vector<SkillClass> &skillClassList,
1944 												const UnitType *unitType) {
1945 	Unit *result = NULL;
1946 
1947 /*
1948 	std::map<CommandClass,std::map<int,int> >::iterator iterFind = cacheUnitCommandClassList.find(cmdClass);
1949 	if(iterFind != cacheUnitCommandClassList.end()) {
1950 		for(std::map<int,int>::iterator iter = iterFind->second.begin();
1951 				iter != iterFind->second.end(); ++iter) {
1952 			Unit *curUnit = findUnit(iter->second);
1953 			if(curUnit != NULL) {
1954 
1955 				const CommandType *cmdType = curUnit->getType()->getFirstCtOfClass(cmdClass);
1956 				bool isUnitPossibleCandidate = (cmdType != NULL);
1957 				if(skillClassList.empty() == false) {
1958 					isUnitPossibleCandidate = false;
1959 
1960 					for(int j = 0; j < skillClassList.size(); ++j) {
1961 						SkillClass skValue = skillClassList[j];
1962 						if(curUnit->getCurrSkill()->getClass() == skValue) {
1963 							isUnitPossibleCandidate = true;
1964 							break;
1965 						}
1966 					}
1967 				}
1968 
1969 				if(isUnitPossibleCandidate == true) {
1970 					if(result == NULL || curUnit->getPos().dist(pos) < result->getPos().dist(pos)) {
1971 						result = curUnit;
1972 					}
1973 				}
1974 			}
1975 		}
1976 	}
1977 */
1978 
1979 	if(result == NULL) {
1980 		for(int i = 0; i < getUnitCount(); ++i) {
1981 			Unit *curUnit = getUnit(i);
1982 
1983 			bool isUnitPossibleCandidate = false;
1984 
1985 			const CommandType *cmdType = curUnit->getType()->getFirstCtOfClass(cmdClass);
1986 			if(cmdType != NULL) {
1987 				const RepairCommandType *rct = dynamic_cast<const RepairCommandType *>(cmdType);
1988 				if(rct != NULL && rct->isRepairableUnitType(unitType)) {
1989 					isUnitPossibleCandidate = true;
1990 				}
1991 			}
1992 			else {
1993 				isUnitPossibleCandidate = false;
1994 			}
1995 
1996 			if(isUnitPossibleCandidate == true && skillClassList.empty() == false) {
1997 				isUnitPossibleCandidate = false;
1998 
1999 				for(int j = 0; j < (int)skillClassList.size(); ++j) {
2000 					SkillClass skValue = skillClassList[j];
2001 					if(curUnit->getCurrSkill()->getClass() == skValue) {
2002 						isUnitPossibleCandidate = true;
2003 						break;
2004 					}
2005 				}
2006 			}
2007 
2008 
2009 			if(isUnitPossibleCandidate == true) {
2010 				//cacheUnitCommandClassList[cmdClass][curUnit->getId()] = curUnit->getId();
2011 
2012 				if(result == NULL || curUnit->getPos().dist(pos) < result->getPos().dist(pos)) {
2013 					result = curUnit;
2014 				}
2015 			}
2016 		}
2017 	}
2018 	return result;
2019 }
2020 
getFrameCount()2021 int Faction::getFrameCount() {
2022 	int frameCount = 0;
2023 	const Game *game = Renderer::getInstance().getGame();
2024 	if(game != NULL && game->getWorld() != NULL) {
2025 		frameCount = game->getWorld()->getFrameCount();
2026 	}
2027 
2028 	return frameCount;
2029 }
2030 
getFirstSwitchTeamVote() const2031 const SwitchTeamVote * Faction::getFirstSwitchTeamVote() const {
2032 	const SwitchTeamVote *vote = NULL;
2033 	if(switchTeamVotes.empty() == false) {
2034 		for(std::map<int,SwitchTeamVote>::const_iterator iterMap = switchTeamVotes.begin();
2035 				iterMap != switchTeamVotes.end(); ++iterMap) {
2036 			const SwitchTeamVote &curVote = iterMap->second;
2037 			if(curVote.voted == false) {
2038 				vote = &curVote;
2039 				break;
2040 			}
2041 		}
2042 	}
2043 
2044 	return vote;
2045 }
2046 
getSwitchTeamVote(int factionIndex)2047 SwitchTeamVote * Faction::getSwitchTeamVote(int factionIndex) {
2048 	SwitchTeamVote *vote = NULL;
2049 	if(switchTeamVotes.find(factionIndex) != switchTeamVotes.end()) {
2050 		vote = &switchTeamVotes[factionIndex];
2051 	}
2052 
2053 	return vote;
2054 }
2055 
setSwitchTeamVote(SwitchTeamVote & vote)2056 void Faction::setSwitchTeamVote(SwitchTeamVote &vote) {
2057 	switchTeamVotes[vote.factionIndex] = vote;
2058 }
2059 
canCreateUnit(const UnitType * ut,bool checkBuild,bool checkProduce,bool checkMorph) const2060 bool Faction::canCreateUnit(const UnitType *ut, bool checkBuild, bool checkProduce, bool checkMorph) const {
2061 	// Now check that at least 1 other unit can produce, build or morph this unit
2062 	bool foundUnit = false;
2063 	for(int l = 0; l < this->getUnitCount() && foundUnit == false; ++l) {
2064 		const UnitType *unitType2 = this->getUnit(l)->getType();
2065 
2066 		for(int j = 0; j < unitType2->getCommandTypeCount() && foundUnit == false; ++j) {
2067 			const CommandType *cmdType = unitType2->getCommandType(j);
2068 			if(cmdType != NULL) {
2069 				// Check if this is a produce command
2070 				if(checkProduce == true && cmdType->getClass() == ccProduce) {
2071 					const ProduceCommandType *produce = dynamic_cast<const ProduceCommandType *>(cmdType);
2072 					if(produce != NULL) {
2073 						const UnitType *produceUnit = produce->getProducedUnit();
2074 
2075 						if( produceUnit != NULL &&
2076 							ut->getId() != unitType2->getId() &&
2077 							ut->getName(false) == produceUnit->getName(false)) {
2078 							 foundUnit = true;
2079 							 break;
2080 						}
2081 					}
2082 				}
2083 				// Check if this is a build command
2084 				else if(checkBuild == true && cmdType->getClass() == ccBuild) {
2085 					const BuildCommandType *build = dynamic_cast<const BuildCommandType *>(cmdType);
2086 					if(build != NULL) {
2087 						for(int k = 0; k < build->getBuildingCount() && foundUnit == false; ++k) {
2088 							const UnitType *buildUnit = build->getBuilding(k);
2089 
2090 							if( buildUnit != NULL &&
2091 								ut->getId() != unitType2->getId() &&
2092 								ut->getName(false) == buildUnit->getName(false)) {
2093 								 foundUnit = true;
2094 								 break;
2095 							}
2096 						}
2097 					}
2098 				}
2099 				// Check if this is a morph command
2100 				else if(checkMorph == true && cmdType->getClass() == ccMorph) {
2101 					const MorphCommandType *morph = dynamic_cast<const MorphCommandType *>(cmdType);
2102 					if(morph != NULL) {
2103 						const UnitType *morphUnit = morph->getMorphUnit();
2104 
2105 						if( morphUnit != NULL &&
2106 							ut->getId() != unitType2->getId() &&
2107 							ut->getName(false) == morphUnit->getName(false)) {
2108 							 foundUnit = true;
2109 							 break;
2110 						}
2111 					}
2112 				}
2113 			}
2114 		}
2115 	}
2116 
2117 	return foundUnit;
2118 }
2119 
clearCaches()2120 void Faction::clearCaches() {
2121 	cacheResourceTargetList.clear();
2122 	cachedCloseResourceTargetLookupList.clear();
2123 
2124 	//aliveUnitListCache.clear();
2125 	//mobileUnitListCache.clear();
2126 	//beingBuiltUnitListCache.clear();
2127 
2128 	unsigned int unitCount = this->getUnitCount();
2129 	for(unsigned int i = 0; i < unitCount; ++i) {
2130 		Unit *unit = this->getUnit(i);
2131 		if(unit != NULL) {
2132 			unit->clearCaches();
2133 		}
2134 	}
2135 }
2136 
getCacheKBytes(uint64 * cache1Size,uint64 * cache2Size,uint64 * cache3Size,uint64 * cache4Size,uint64 * cache5Size)2137 uint64 Faction::getCacheKBytes(uint64 *cache1Size, uint64 *cache2Size, uint64 *cache3Size, uint64 *cache4Size, uint64 *cache5Size) {
2138 	uint64 cache1Count = 0;
2139 	uint64 cache2Count = 0;
2140 	uint64 cache3Count = 0;
2141 	uint64 cache4Count = 0;
2142 	uint64 cache5Count = 0;
2143 
2144 	for(std::map<Vec2i,int>::iterator iterMap1 = cacheResourceTargetList.begin();
2145 		iterMap1 != cacheResourceTargetList.end(); ++iterMap1) {
2146 		cache1Count++;
2147 	}
2148 	for(std::map<Vec2i,bool>::iterator iterMap1 = cachedCloseResourceTargetLookupList.begin();
2149 		iterMap1 != cachedCloseResourceTargetLookupList.end(); ++iterMap1) {
2150 		cache2Count++;
2151 	}
2152 	for(std::map<int,const Unit *>::iterator iterMap1 = aliveUnitListCache.begin();
2153 		iterMap1 != aliveUnitListCache.end(); ++iterMap1) {
2154 		cache3Count++;
2155 	}
2156 	for(std::map<int,const Unit *>::iterator iterMap1 = mobileUnitListCache.begin();
2157 		iterMap1 != mobileUnitListCache.end(); ++iterMap1) {
2158 		cache4Count++;
2159 	}
2160 	for(std::map<int,const Unit *>::iterator iterMap1 = beingBuiltUnitListCache.begin();
2161 		iterMap1 != beingBuiltUnitListCache.end(); ++iterMap1) {
2162 		cache5Count++;
2163 	}
2164 
2165 	if(cache1Size) {
2166 		*cache1Size = cache1Count;
2167 	}
2168 	if(cache2Size) {
2169 		*cache2Size = cache2Count;
2170 	}
2171 	if(cache3Size) {
2172 		*cache3Size = cache3Count;
2173 	}
2174 	if(cache4Size) {
2175 		*cache4Size = cache4Count;
2176 	}
2177 	if(cache5Size) {
2178 		*cache5Size = cache5Count;
2179 	}
2180 
2181 	uint64 totalBytes = cache1Count * sizeof(int);
2182 	totalBytes += cache2Count * sizeof(bool);
2183 	totalBytes += cache3Count * (sizeof(int) + sizeof(const Unit *));
2184 	totalBytes += cache4Count * (sizeof(int) + sizeof(const Unit *));
2185 	totalBytes += cache5Count * (sizeof(int) + sizeof(const Unit *));
2186 
2187 	totalBytes /= 1000;
2188 
2189 	return totalBytes;
2190 }
2191 
getCacheStats()2192 string Faction::getCacheStats() {
2193 	string result = "";
2194 
2195 	int cache1Count = 0;
2196 	int cache2Count = 0;
2197 
2198 	for(std::map<Vec2i,int>::iterator iterMap1 = cacheResourceTargetList.begin();
2199 		iterMap1 != cacheResourceTargetList.end(); ++iterMap1) {
2200 		cache1Count++;
2201 	}
2202 	for(std::map<Vec2i,bool>::iterator iterMap1 = cachedCloseResourceTargetLookupList.begin();
2203 		iterMap1 != cachedCloseResourceTargetLookupList.end(); ++iterMap1) {
2204 		cache2Count++;
2205 	}
2206 
2207 	uint64 totalBytes = cache1Count * sizeof(int);
2208 	totalBytes += cache2Count * sizeof(bool);
2209 
2210 	totalBytes /= 1000;
2211 
2212 	char szBuf[8096]="";
2213 	snprintf(szBuf,8096,"cache1Count [%d] cache2Count [%d] total KB: %s",cache1Count,cache2Count,formatNumber(totalBytes).c_str());
2214 	result = szBuf;
2215 	return result;
2216 }
2217 
toString(bool crcMode) const2218 std::string Faction::toString(bool crcMode) const {
2219 	std::string result = "FactionIndex = " + intToStr(this->index) + "\n";
2220     result += "teamIndex = " + intToStr(this->teamIndex) + "\n";
2221     result += "startLocationIndex = " + intToStr(this->startLocationIndex) + "\n";
2222     if(crcMode == false) {
2223     	result += "thisFaction = " + intToStr(this->thisFaction) + "\n";
2224     	result += "control = " + intToStr(this->control) + "\n";
2225     }
2226 
2227     if(this->factionType != NULL) {
2228     	result += this->factionType->toString() + "\n";
2229     }
2230 
2231 	result += this->upgradeManager.toString() + "\n";
2232 
2233 	result += "ResourceCount = " + intToStr(resources.size()) + "\n";
2234 	for(int idx = 0; idx < (int)resources.size(); idx ++) {
2235 		result += "index = " + intToStr(idx) + " " + resources[idx].toString() + "\n";
2236 	}
2237 
2238 	result += "StoreCount = " + intToStr(store.size()) + "\n";
2239 	for(int idx = 0; idx < (int)store.size(); idx ++) {
2240 		result += "index = " + intToStr(idx) + " " + store[idx].toString()  + "\n";
2241 	}
2242 
2243 	result += "Allies = " + intToStr(allies.size()) + "\n";
2244 	for(int idx = 0; idx < (int)allies.size(); idx ++) {
2245 		result += "index = " + intToStr(idx) + " name: " + allies[idx]->factionType->getName(false) + " factionindex = " + intToStr(allies[idx]->index)  + "\n";
2246 	}
2247 
2248 	result += "Units = " + intToStr(units.size()) + "\n";
2249 	for(int idx = 0; idx < (int)units.size(); idx ++) {
2250 		result += units[idx]->toString(crcMode) + "\n";
2251 	}
2252 
2253 	return result;
2254 }
2255 
saveGame(XmlNode * rootNode)2256 void Faction::saveGame(XmlNode *rootNode) {
2257 	std::map<string,string> mapTagReplacements;
2258 	XmlNode *factionNode = rootNode->addChild("Faction");
2259 
2260 	upgradeManager.saveGame(factionNode);
2261 	for(unsigned int i = 0; i < resources.size(); ++i) {
2262 		Resource &resource = resources[i];
2263 		resource.saveGame(factionNode);
2264 	}
2265 	XmlNode *storeNode = factionNode->addChild("Store");
2266 	for(unsigned int i = 0; i < store.size(); ++i) {
2267 		Resource &resource = store[i];
2268 		resource.saveGame(storeNode);
2269 	}
2270 
2271 	for(unsigned int i = 0; i < allies.size(); ++i) {
2272 		Faction *ally = allies[i];
2273 		XmlNode *allyNode = factionNode->addChild("Ally");
2274 		allyNode->addAttribute("allyFactionIndex",intToStr(ally->getIndex()), mapTagReplacements);
2275 	}
2276 	for(unsigned int i = 0; i < units.size(); ++i) {
2277 		Unit *unit = units[i];
2278 		unit->saveGame(factionNode);
2279 	}
2280 
2281 	factionNode->addAttribute("control",intToStr(control), mapTagReplacements);
2282 
2283 	factionNode->addAttribute("overridePersonalityType",intToStr(overridePersonalityType), mapTagReplacements);
2284 	factionNode->addAttribute("factiontype",factionType->getName(false), mapTagReplacements);
2285 	factionNode->addAttribute("index",intToStr(index), mapTagReplacements);
2286 	factionNode->addAttribute("teamIndex",intToStr(teamIndex), mapTagReplacements);
2287 	factionNode->addAttribute("startLocationIndex",intToStr(startLocationIndex), mapTagReplacements);
2288 	factionNode->addAttribute("thisFaction",intToStr(thisFaction), mapTagReplacements);
2289 
2290 	for(std::map<Vec2i,int>::iterator iterMap = cacheResourceTargetList.begin();
2291 			iterMap != cacheResourceTargetList.end(); ++iterMap) {
2292 		XmlNode *cacheResourceTargetListNode = factionNode->addChild("cacheResourceTargetList");
2293 
2294 		cacheResourceTargetListNode->addAttribute("key",iterMap->first.getString(), mapTagReplacements);
2295 		cacheResourceTargetListNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements);
2296 	}
2297 
2298 	for(std::map<Vec2i,bool>::iterator iterMap = cachedCloseResourceTargetLookupList.begin();
2299 			iterMap != cachedCloseResourceTargetLookupList.end(); ++iterMap) {
2300 		XmlNode *cachedCloseResourceTargetLookupListNode = factionNode->addChild("cachedCloseResourceTargetLookupList");
2301 
2302 		cachedCloseResourceTargetLookupListNode->addAttribute("key",iterMap->first.getString(), mapTagReplacements);
2303 		cachedCloseResourceTargetLookupListNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements);
2304 	}
2305 
2306 	factionNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements);
2307 	factionNode->addAttribute("currentSwitchTeamVoteFactionIndex",intToStr(currentSwitchTeamVoteFactionIndex), mapTagReplacements);
2308 	factionNode->addAttribute("allowSharedTeamUnits",intToStr(allowSharedTeamUnits), mapTagReplacements);
2309 
2310 	for(std::set<const UnitType*>::iterator iterMap = lockedUnits.begin();
2311 			iterMap != lockedUnits.end(); ++iterMap) {
2312 		XmlNode *lockedUnitsListNode = factionNode->addChild("lockedUnitList");
2313 		const UnitType *ut=*iterMap;
2314 
2315 		lockedUnitsListNode->addAttribute("value",ut->getName(false), mapTagReplacements);
2316 	}
2317 
2318 	for(std::map<int,int>::iterator iterMap = unitsMovingList.begin();
2319 			iterMap != unitsMovingList.end(); ++iterMap) {
2320 		XmlNode *unitsMovingListNode = factionNode->addChild("unitsMovingList");
2321 
2322 		unitsMovingListNode->addAttribute("key",intToStr(iterMap->first), mapTagReplacements);
2323 		unitsMovingListNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements);
2324 	}
2325 
2326 	for(std::map<int,int>::iterator iterMap = unitsPathfindingList.begin();
2327 			iterMap != unitsPathfindingList.end(); ++iterMap) {
2328 		XmlNode *unitsPathfindingListNode = factionNode->addChild("unitsPathfindingList");
2329 
2330 		unitsPathfindingListNode->addAttribute("key",intToStr(iterMap->first), mapTagReplacements);
2331 		unitsPathfindingListNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements);
2332 	}
2333 }
2334 
loadGame(const XmlNode * rootNode,int factionIndex,GameSettings * settings,World * world)2335 void Faction::loadGame(const XmlNode *rootNode, int factionIndex,GameSettings *settings,World *world) {
2336 	XmlNode *factionNode = NULL;
2337 	vector<XmlNode *> factionNodeList = rootNode->getChildList("Faction");
2338 	for(unsigned int i = 0; i < factionNodeList.size(); ++i) {
2339 		XmlNode *node = factionNodeList[i];
2340 		if(node->getAttribute("index")->getIntValue() == factionIndex) {
2341 			factionNode = node;
2342 			break;
2343 		}
2344 	}
2345 
2346 	if(factionNode != NULL) {
2347 
2348 		allies.clear();
2349 		vector<XmlNode *> allyNodeList = factionNode->getChildList("Ally");
2350 		for(unsigned int i = 0; i < allyNodeList.size(); ++i) {
2351 			XmlNode *allyNode = allyNodeList[i];
2352 
2353 			int allyFactionIndex = allyNode->getAttribute("allyFactionIndex")->getIntValue();
2354 			allies.push_back(world->getFaction(allyFactionIndex));
2355 		}
2356 
2357 		vector<XmlNode *> unitNodeList = factionNode->getChildList("Unit");
2358 		for(unsigned int i = 0; i < unitNodeList.size(); ++i) {
2359 			XmlNode *unitNode = unitNodeList[i];
2360 			Unit *unit = Unit::loadGame(unitNode,settings,this, world);
2361 			this->addUnit(unit);
2362 		}
2363 
2364 		for(unsigned int i = 0; i < resources.size(); ++i) {
2365 			Resource &resource = resources[i];
2366 			resource.loadGame(factionNode,i,techTree);
2367 		}
2368 		XmlNode *storeNode = factionNode->getChild("Store");
2369 		for(unsigned int i = 0; i < store.size(); ++i) {
2370 			Resource &resource = store[i];
2371 			resource.loadGame(storeNode,i,techTree);
2372 		}
2373 
2374 		upgradeManager.loadGame(factionNode,this);
2375 
2376 		control = static_cast<ControlType>(factionNode->getAttribute("control")->getIntValue());
2377 
2378 		if(factionNode->hasAttribute("overridePersonalityType") == true) {
2379 			overridePersonalityType = static_cast<FactionPersonalityType>(factionNode->getAttribute("overridePersonalityType")->getIntValue());
2380 		}
2381 
2382 		teamIndex = factionNode->getAttribute("teamIndex")->getIntValue();
2383 
2384 		startLocationIndex = factionNode->getAttribute("startLocationIndex")->getIntValue();
2385 
2386 		thisFaction = factionNode->getAttribute("thisFaction")->getIntValue() != 0;
2387 
2388 		if(factionNode->hasAttribute("allowSharedTeamUnits") == true) {
2389 			allowSharedTeamUnits = factionNode->getAttribute("allowSharedTeamUnits")->getIntValue() != 0;
2390 		}
2391 
2392 		vector<XmlNode *> cacheResourceTargetListNodeList = factionNode->getChildList("cacheResourceTargetList");
2393 		for(unsigned int i = 0; i < cacheResourceTargetListNodeList.size(); ++i) {
2394 			XmlNode *cacheResourceTargetListNode = cacheResourceTargetListNodeList[i];
2395 
2396 			Vec2i vec = Vec2i::strToVec2(cacheResourceTargetListNode->getAttribute("key")->getValue());
2397 			cacheResourceTargetList[vec] = cacheResourceTargetListNode->getAttribute("value")->getIntValue();
2398 		}
2399 		vector<XmlNode *> cachedCloseResourceTargetLookupListNodeList = factionNode->getChildList("cachedCloseResourceTargetLookupList");
2400 		for(unsigned int i = 0; i < cachedCloseResourceTargetLookupListNodeList.size(); ++i) {
2401 			XmlNode *cachedCloseResourceTargetLookupListNode = cachedCloseResourceTargetLookupListNodeList[i];
2402 
2403 			Vec2i vec = Vec2i::strToVec2(cachedCloseResourceTargetLookupListNode->getAttribute("key")->getValue());
2404 			cachedCloseResourceTargetLookupList[vec] = cachedCloseResourceTargetLookupListNode->getAttribute("value")->getIntValue() != 0;
2405 		}
2406 
2407 		random.setLastNumber(factionNode->getAttribute("random")->getIntValue());
2408 
2409 		vector<XmlNode *> lockedUnitsListNodeList = factionNode->getChildList("lockedUnitList");
2410 		for(unsigned int i = 0; i < lockedUnitsListNodeList.size(); ++i) {
2411 			XmlNode *lockedUnitsListNode = lockedUnitsListNodeList[i];
2412 
2413 			string unitName = lockedUnitsListNode->getAttribute("value")->getValue();
2414 			lockedUnits.insert(getType()->getUnitType(unitName));
2415 		}
2416 
2417 		vector<XmlNode *> unitsMovingListNodeList = factionNode->getChildList("unitsMovingList");
2418 		for(unsigned int i = 0; i < unitsMovingListNodeList.size(); ++i) {
2419 			XmlNode *unitsMovingListNode = unitsMovingListNodeList[i];
2420 
2421 			int unitId = unitsMovingListNode->getAttribute("key")->getIntValue();
2422 			unitsMovingList[unitId] = unitsMovingListNode->getAttribute("value")->getIntValue();
2423 		}
2424 		vector<XmlNode *> unitsPathfindingListNodeList = factionNode->getChildList("unitsPathfindingList");
2425 		for(unsigned int i = 0; i < unitsPathfindingListNodeList.size(); ++i) {
2426 			XmlNode *unitsPathfindingListNode = unitsPathfindingListNodeList[i];
2427 
2428 			int unitId = unitsPathfindingListNode->getAttribute("key")->getIntValue();
2429 			unitsPathfindingList[unitId] = unitsPathfindingListNode->getAttribute("value")->getIntValue();
2430 		}
2431 	}
2432 }
2433 
getCRC()2434 Checksum Faction::getCRC() {
2435 	const bool consoleDebug = false;
2436 
2437 	Checksum crcForFaction;
2438 
2439 	// UpgradeManager upgradeManager;
2440 
2441 	for(unsigned int i = 0; i < resources.size(); ++i) {
2442 		Resource &resource = resources[i];
2443 		//crcForFaction.addSum(resource.getCRC().getSum());
2444 		uint32 crc = resource.getCRC().getSum();
2445 		crcForFaction.addBytes(&crc,sizeof(uint32));
2446 	}
2447 
2448 	if(consoleDebug) {
2449 		if(getWorld()->getFrameCount() % 40 == 0) {
2450 			printf("#1 Frame #: %d Faction: %d CRC: %u\n",getWorld()->getFrameCount(),index,crcForFaction.getSum());
2451 		}
2452 	}
2453 
2454 	for(unsigned int i = 0; i < store.size(); ++i) {
2455 		Resource &resource = store[i];
2456 		//crcForFaction.addSum(resource.getCRC().getSum());
2457 		uint32 crc = resource.getCRC().getSum();
2458 		crcForFaction.addBytes(&crc,sizeof(uint32));
2459 	}
2460 
2461 	if(consoleDebug) {
2462 		if(getWorld()->getFrameCount() % 40 == 0) {
2463 			printf("#2 Frame #: %d Faction: %d CRC: %u\n",getWorld()->getFrameCount(),index,crcForFaction.getSum());
2464 		}
2465 	}
2466 
2467 	for(unsigned int i = 0; i < units.size(); ++i) {
2468 		Unit *unit = units[i];
2469 		//crcForFaction.addSum(unit->getCRC().getSum());
2470 		uint32 crc = unit->getCRC().getSum();
2471 		crcForFaction.addBytes(&crc,sizeof(uint32));
2472 	}
2473 
2474 	if(consoleDebug) {
2475 		if(getWorld()->getFrameCount() % 40 == 0) {
2476 			printf("#3 Frame #: %d Faction: %d CRC: %u\n",getWorld()->getFrameCount(),index,crcForFaction.getSum());
2477 		}
2478 	}
2479 
2480 	return crcForFaction;
2481 }
2482 
addCRC_DetailsForWorldFrame(int worldFrameCount,bool isNetworkServer)2483 void Faction::addCRC_DetailsForWorldFrame(int worldFrameCount,bool isNetworkServer) {
2484 	unsigned int MAX_FRAME_CACHE = 250;
2485 	if(isNetworkServer == true) {
2486 		MAX_FRAME_CACHE += 250;
2487 	}
2488 	crcWorldFrameDetails[worldFrameCount] = this->toString(true);
2489 	//if(worldFrameCount <= 0) printf("Adding world frame: %d log entries: %lld\n",worldFrameCount,(long long int)crcWorldFrameDetails.size());
2490 
2491 	for(unsigned int i = 0; i < units.size(); ++i) {
2492 		Unit *unit = units[i];
2493 
2494 		unit->getRandom()->clearLastCaller();
2495 		unit->clearNetworkCRCDecHpList();
2496 		unit->clearParticleInfo();
2497 	}
2498 
2499 	if((unsigned int)crcWorldFrameDetails.size() > MAX_FRAME_CACHE) {
2500 		//printf("===> Removing older world frame log entries: %lld\n",(long long int)crcWorldFrameDetails.size());
2501 
2502 		for(;(unsigned int)crcWorldFrameDetails.size() - MAX_FRAME_CACHE > 0;) {
2503 			crcWorldFrameDetails.erase(crcWorldFrameDetails.begin());
2504 		}
2505 	}
2506 }
2507 
getCRC_DetailsForWorldFrame(int worldFrameCount)2508 string Faction::getCRC_DetailsForWorldFrame(int worldFrameCount) {
2509 	if(crcWorldFrameDetails.empty()) {
2510 		return "";
2511 	}
2512 	return crcWorldFrameDetails[worldFrameCount];
2513 }
2514 
getCRC_DetailsForWorldFrameIndex(int worldFrameIndex) const2515 std::pair<int,string> Faction::getCRC_DetailsForWorldFrameIndex(int worldFrameIndex) const {
2516 	if(crcWorldFrameDetails.empty()) {
2517 		return make_pair<int,string>(0,"");
2518 	}
2519 	std::map<int,string>::const_iterator iterMap = crcWorldFrameDetails.begin();
2520 	std::advance( iterMap, worldFrameIndex );
2521 	if(iterMap == crcWorldFrameDetails.end()) {
2522 		return make_pair<int,string>(0,"");
2523 	}
2524 	return std::pair<int,string>(iterMap->first,iterMap->second);
2525 }
2526 
getCRC_DetailsForWorldFrames() const2527 string Faction::getCRC_DetailsForWorldFrames() const {
2528 	string result = "";
2529 	for(std::map<int,string>::const_iterator iterMap = crcWorldFrameDetails.begin();
2530 			iterMap != crcWorldFrameDetails.end(); ++iterMap) {
2531 		result += string("============================================================================\n");
2532 		result += string("** world frame: ") + intToStr(iterMap->first) + string(" detail: ") + iterMap->second;
2533 	}
2534 	return result;
2535 }
2536 
getCRC_DetailsForWorldFrameCount() const2537 uint64 Faction::getCRC_DetailsForWorldFrameCount() const {
2538 	return crcWorldFrameDetails.size();
2539 }
2540 
2541 }}//end namespace
2542