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