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 "unit_updater.h"
13 
14 #include <algorithm>
15 #include <cassert>
16 
17 #include "core_data.h"
18 #include "config.h"
19 #include "game.h"
20 #include "faction.h"
21 #include "network_manager.h"
22 #include "object.h"
23 #include "particle_type.h"
24 #include "projectile_type.h"
25 #include "path_finder.h"
26 #include "renderer.h"
27 #include "sound.h"
28 #include "sound_renderer.h"
29 #include "upgrade.h"
30 #include "unit.h"
31 
32 #include "leak_dumper.h"
33 
34 using namespace Shared::Graphics;
35 using namespace Shared::Util;
36 
37 namespace Glest{ namespace Game{
38 
39 // =====================================================
40 // 	class UnitUpdater
41 // =====================================================
42 
43 // ===================== PUBLIC ========================
44 
UnitUpdater()45 UnitUpdater::UnitUpdater() : mutexAttackWarnings(new Mutex(CODE_AT_LINE)),
46 		mutexUnitRangeCellsLookupItemCache(new Mutex(CODE_AT_LINE)) {
47     this->game= NULL;
48 	this->gui= NULL;
49 	this->gameCamera= NULL;
50 	this->world= NULL;
51 	this->map= NULL;
52 	this->console= NULL;
53 	this->scriptManager= NULL;
54 	this->pathFinder = NULL;
55 	//UnitRangeCellsLookupItemCacheTimerCount = 0;
56 	attackWarnRange=0;
57 }
58 
init(Game * game)59 void UnitUpdater::init(Game *game){
60 
61     this->game= game;
62 	this->gui= game->getGuiPtr();
63 	this->gameCamera= game->getGameCamera();
64 	this->world= game->getWorld();
65 	this->map= world->getMap();
66 	this->console= game->getConsole();
67 	this->scriptManager= game->getScriptManager();
68 	this->pathFinder = NULL;
69 	attackWarnRange=Config::getInstance().getFloat("AttackWarnRange","50.0");
70 	//UnitRangeCellsLookupItemCacheTimerCount = 0;
71 
72 	switch(this->game->getGameSettings()->getPathFinderType()) {
73 		case pfBasic:
74 			pathFinder = new PathFinder();
75 			pathFinder->init(map);
76 			break;
77 		default:
78 			throw megaglest_runtime_error("detected unsupported pathfinder type!");
79     }
80 }
81 
clearUnitPrecache(Unit * unit)82 void UnitUpdater::clearUnitPrecache(Unit *unit) {
83 	if(pathFinder != NULL) {
84 		pathFinder->clearUnitPrecache(unit);
85 	}
86 }
87 
removeUnitPrecache(Unit * unit)88 void UnitUpdater::removeUnitPrecache(Unit *unit) {
89 	if(pathFinder != NULL) {
90 		pathFinder->removeUnitPrecache(unit);
91 	}
92 }
93 
~UnitUpdater()94 UnitUpdater::~UnitUpdater() {
95 	//UnitRangeCellsLookupItemCache.clear();
96 
97 	delete pathFinder;
98 	pathFinder = NULL;
99 
100 	MutexSafeWrapper safeMutex(mutexAttackWarnings,string(__FILE__) + "_" + intToStr(__LINE__));
101 	while(attackWarnings.empty() == false) {
102 		AttackWarningData* awd = attackWarnings.back();
103 		attackWarnings.pop_back();
104 		delete awd;
105 	}
106 
107 	safeMutex.ReleaseLock();
108 
109 	delete mutexAttackWarnings;
110 	mutexAttackWarnings = NULL;
111 
112 	delete mutexUnitRangeCellsLookupItemCache;
113 	mutexUnitRangeCellsLookupItemCache = NULL;
114 }
115 
116 // ==================== progress skills ====================
117 
118 //skill dependent actions
updateUnit(Unit * unit)119 bool UnitUpdater::updateUnit(Unit *unit) {
120 	bool processUnitCommand = false;
121 
122 	Chrono chrono;
123 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
124 
125 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [START OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
126 
127 	SoundRenderer &soundRenderer= SoundRenderer::getInstance();
128 
129 	//play skill sound
130 	const SkillType *currSkill= unit->getCurrSkill();
131 
132 	for(SkillSoundList::const_iterator it= currSkill->getSkillSoundList()->begin(); it != currSkill->getSkillSoundList()->end(); ++it) {
133 		float soundStartTime= (*it)->getStartTime();
134 		if(soundStartTime >= unit->getLastAnimProgressAsFloat() && soundStartTime < unit->getAnimProgressAsFloat()) {
135 			if(map->getSurfaceCell(Map::toSurfCoords(unit->getPos()))->isVisible(world->getThisTeamIndex()) ||
136 				(game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)) {
137 				soundRenderer.playFx((*it)->getSoundContainer()->getRandSound(), unit->getCurrMidHeightVector(), gameCamera->getPos());
138 			}
139 		}
140 	}
141 
142 
143 	if (currSkill->getShake()) {
144 		float shakeStartTime = currSkill->getShakeStartTime();
145 		if (shakeStartTime >= unit->getLastAnimProgressAsFloat()
146 				&& shakeStartTime < unit->getAnimProgressAsFloat()) {
147 			bool visibleAffected=false;
148 			bool cameraViewAffected=false;
149 			bool cameraDistanceAffected=false;
150 			bool enabled=false;
151 			if (game->getWorld()->getThisFactionIndex() == unit->getFactionIndex()) {
152 				visibleAffected=currSkill->getShakeSelfVisible();
153 				cameraViewAffected=currSkill->getShakeSelfInCameraView();
154 				cameraDistanceAffected=currSkill->getShakeSelfCameraAffected();
155 				enabled=currSkill->getShakeSelfEnabled();
156 			} else if (unit->getTeam() == world->getThisTeamIndex()) {
157 				visibleAffected=currSkill->getShakeTeamVisible();
158 				cameraViewAffected=currSkill->getShakeTeamInCameraView();
159 				cameraDistanceAffected=currSkill->getShakeTeamCameraAffected();
160 				enabled=currSkill->getShakeTeamEnabled();
161 			} else {
162 				visibleAffected=currSkill->getShakeEnemyVisible();
163 				cameraViewAffected=currSkill->getShakeEnemyInCameraView();
164 				cameraDistanceAffected=currSkill->getShakeEnemyCameraAffected();
165 				enabled=currSkill->getShakeEnemyEnabled();
166 			}
167 
168 			bool visibility=(!visibleAffected)||(map->getSurfaceCell(Map::toSurfCoords(unit->getPos()))->isVisible(world->getThisTeamIndex()) ||
169 					(game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true));
170 
171 			bool cameraAffected=(!cameraViewAffected) || unit->getVisible();
172 
173 			if(visibility && cameraAffected && enabled) {
174 				game->getGameCameraPtr()->shake( currSkill->getShakeDuration(), currSkill->getShakeIntensity(),cameraDistanceAffected,unit->getCurrMidHeightVector());
175 			}
176 		}
177 	}
178 
179 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after playsound]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
180 
181 	unit->updateTimedParticles();
182 
183 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after playsound]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
184 
185 
186 	//start attack particle system
187 	if(unit->getCurrSkill()->getClass() == scDie) {
188 		const DieSkillType *dst= static_cast<const DieSkillType*>(unit->getCurrSkill());
189 
190 		if(dst->getSpawn() == true){
191 			float spawnStartTime = truncateDecimal<float>(dst->getSpawnStartTime(),6);
192 			float lastAnimProgress = truncateDecimal<float>(unit->getLastAnimProgressAsFloat(),6);
193 			float animProgress = truncateDecimal<float>(unit->getAnimProgressAsFloat(),6);
194 
195 			bool startSpawnNow = (spawnStartTime >= lastAnimProgress && spawnStartTime < animProgress);
196 			if(startSpawnNow){
197 				//	spawn the units
198 				spawn(unit, dst->getSpawnUnit(), dst->getSpawnUnitCount(),
199 						dst->getSpawnUnitHealthPercentMin(),
200 						dst->getSpawnUnitHealthPercentMax(),
201 						dst->getSpawnProbability());
202 			}
203 		}
204 	}
205 
206 	//start attack particle system
207 	if(unit->getCurrSkill()->getClass() == scAttack) {
208 		const AttackSkillType *ast= static_cast<const AttackSkillType*>(unit->getCurrSkill());
209 
210 		float attackStartTime = truncateDecimal<float>(ast->getAttackStartTime(),6);
211 		float lastAnimProgress = truncateDecimal<float>(unit->getLastAnimProgressAsFloat(),6);
212 		float animProgress = truncateDecimal<float>(unit->getAnimProgressAsFloat(),6);
213 		bool startAttackParticleSystemNow = false;
214 		if(ast->projectileTypes.empty() == true ){
215 			startAttackParticleSystemNow = (attackStartTime >= lastAnimProgress && attackStartTime < animProgress);
216 		}
217 		else {// start projectile attack
218 			for(ProjectileTypes::const_iterator it= ast->projectileTypes.begin(); it != ast->projectileTypes.end(); ++it) {
219 				attackStartTime= (*it)->getAttackStartTime();
220 				startAttackParticleSystemNow = (attackStartTime >= lastAnimProgress && attackStartTime < animProgress);
221 				if(startAttackParticleSystemNow==true) break;
222 			}
223 		}
224 
225 		char szBuf[8096]="";
226 		snprintf(szBuf,8095,"attackStartTime = %f, lastAnimProgress = %f, animProgress = %f startAttackParticleSystemNow = %d",attackStartTime,lastAnimProgress,animProgress,startAttackParticleSystemNow);
227 		unit->setNetworkCRCParticleLogInfo(szBuf);
228 
229 		if(startAttackParticleSystemNow == true) {
230 			startAttackParticleSystem(unit,lastAnimProgress,animProgress);
231 		}
232 	}
233 
234 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after attack particle system]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
235 
236 	bool update = unit->update();
237 
238 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after unit->update()]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
239 
240 	//printf("Update Unit [%d - %s] = %d\n",unit->getId(),unit->getType()->getName().c_str(),update);
241 
242 	//update unit
243 	if(update == true) {
244         //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
245 
246 		processUnitCommand = true;
247 		updateUnitCommand(unit,-1);
248 
249 		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after updateUnitCommand()]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
250 
251 		//if unit is out of EP, it stops
252 		if(unit->computeEp() == true) {
253 			bool reQueueHoldPosition = false;
254 			string holdPositionName = "";
255 			if(unit->getCurrCommand() != NULL &&
256 				unit->getCurrCommand()->getCommandType()->getClass() == ccAttackStopped) {
257 				reQueueHoldPosition = true;
258 				holdPositionName = unit->getCurrCommand()->getCommandType()->getName(false);
259 			}
260 
261 			unit->setCurrSkill(scStop);
262 			unit->cancelCommand();
263 
264 			if(reQueueHoldPosition == true) {
265 				//Search for a command that can produce the unit
266 				const UnitType *ut = unit->getType();
267 				for(int i= 0; i < ut->getCommandTypeCount(); ++i) {
268 					const CommandType* ct= ut->getCommandType(i);
269 					if(ct != NULL && ct->getClass() == ccAttackStopped) {
270 						const AttackStoppedCommandType *act= static_cast<const AttackStoppedCommandType*>(ct);
271 						if(act != NULL && act->getName(false) == holdPositionName) {
272 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
273 
274 							//printf("Re-Queing hold pos = %d, ep = %d skillep = %d skillname [%s]\n ",unit->getFaction()->reqsOk(act),unit->getEp(),act->getAttackSkillType()->getEpCost(),act->getName().c_str());
275 							if(unit->getFaction()->reqsOk(act) == true &&
276 								unit->getEp() >= act->getStopSkillType()->getEpCost()) {
277 								unit->giveCommand(new Command(act),true);
278 							}
279 
280 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
281 							break;
282 						}
283 					}
284 				}
285 			}
286 		}
287 		if(unit->getCurrSkill() != NULL && unit->getCurrSkill()->getClass() != scAttack) {
288 			// !!! Is this causing choppy network play somehow?
289 			//unit->computeHp();
290 		}
291 		else if(unit->getCommandSize() > 0) {
292 			Command *command= unit->getCurrCommand();
293 			if(command != NULL) {
294 
295 				const AttackCommandType *act= dynamic_cast<const AttackCommandType*>(command->getCommandType());
296 				if (act != NULL && act->getAttackSkillType() != NULL
297 						&& act->getAttackSkillType()->getSpawnUnit() != ""
298 						&& act->getAttackSkillType()->getSpawnUnitCount() > 0) {
299 					spawnAttack(unit, act->getAttackSkillType()->getSpawnUnit(),
300 							act->getAttackSkillType()->getSpawnUnitCount(), 100,
301 							100, 100,
302 							act->getAttackSkillType()->getSpawnUnitAtTarget());
303 				}
304 			}
305 		}
306 
307 		//move unit in cells
308 		if(unit->getCurrSkill()->getClass() == scMove) {
309 			world->moveUnitCells(unit, true);
310 
311 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after world->moveUnitCells()]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
312 
313 			//play water sound
314 			if(map->getCell(unit->getPos())->getHeight() < map->getWaterLevel() && unit->getCurrField() == fLand) {
315 				if(Config::getInstance().getBool("DisableWaterSounds","false") == false) {
316 					soundRenderer.playFx(
317 						CoreData::getInstance().getWaterSound(),
318 						unit->getCurrMidHeightVector(),
319 						gameCamera->getPos()
320 					);
321 
322 					if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after soundFx()]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
323 				}
324 			}
325 		}
326 	}
327 
328 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
329 
330 	//unit death
331 	if(unit->isDead() && unit->getCurrSkill()->getClass() != scDie) {
332 		unit->kill();
333 	}
334 
335 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
336 
337 	return processUnitCommand;
338 }
339 
spawn(Unit * unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability)340 void UnitUpdater::spawn(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability) {
341 	if(spawnUnit != "" && spawnUnitcount > 0) {
342 		int spawnCount = spawnUnitcount;
343 		for (int y=0; y < spawnCount; ++y) {
344 			if (probability > 0 && probability < 100
345 					&& unit->getRandom()->randRange(1, 100) <= probability) {
346 				continue;
347 			}
348 			Unit* spawned=this->spawnUnit(unit,spawnUnit);
349 			if(spawned!=NULL){
350 				if(healthMin>0 && healthMin<100 && healthMax>=healthMin && healthMax<=100){
351 					int damagePercent=100-unit->getRandom()->randRange(healthMin, healthMax);
352 					//printf("damagePercent=%d\n",damagePercent);
353 					spawned->decHp((spawned->getHp()*damagePercent)/100);
354 				}
355 			}
356 			// no stat count !!
357 			//world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
358 		}
359 	}
360 }
361 
spawnAttack(Unit * unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability,bool spawnUnitAtTarget,Vec2i targetPos)362 void UnitUpdater::spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability,bool spawnUnitAtTarget,Vec2i targetPos) {
363 	if(spawnUnit != "" && spawnUnitcount > 0) {
364 
365 		int spawnCount = spawnUnitcount;
366 		for (int y=0; y < spawnCount; ++y) {
367 			if (probability > 0 && probability < 100
368 					&& unit->getRandom()->randRange(1, 100) <= probability) {
369 				continue;
370 			}
371 			if(targetPos==Vec2i(-10,-10)) {
372 				targetPos=unit->getTargetPos();
373 			}
374 			Unit* spawned=this->spawnUnit(unit,spawnUnit,spawnUnitAtTarget?targetPos:unit->getCenteredPos());
375 			if(spawned!=NULL){
376 				if(healthMin>0 && healthMin<100 && healthMax>=healthMin && healthMax<=100){
377 					int damagePercent=100-unit->getRandom()->randRange(healthMin, healthMax);
378 					//printf("damagePercent=%d\n",damagePercent);
379 					spawned->decHp((spawned->getHp()*damagePercent)/100);
380 				}
381 				// no stat count !!
382 				// world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats());
383 				const CommandType *ct= spawned->getType()->getFirstAttackCommand(unit->getTargetField());
384 				if(ct == NULL){
385 					ct= spawned->computeCommandType(targetPos,map->getCell(targetPos)->getUnit(unit->getTargetField()));
386 				}
387 				if(ct != NULL){
388 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
389 					spawned->giveCommand(new Command(ct, targetPos));
390 				}
391 			}
392 		}
393 	}
394 }
395 
396 
spawnUnit(Unit * unit,string spawnUnit,Vec2i spawnPos)397 Unit* UnitUpdater::spawnUnit(Unit *unit,string spawnUnit,Vec2i spawnPos) {
398 	const FactionType *ft= unit->getFaction()->getType();
399 	const UnitType *spawnUnitType = ft->getUnitType(spawnUnit);
400 	Vec2i _spawnPos=spawnPos;
401 	if(_spawnPos==Vec2i(-10,-10)) {
402 		_spawnPos=unit->getCenteredPos();
403 	}
404 	if(spawnUnitType->getMaxUnitCount() > 0) {
405 		if(spawnUnitType->getMaxUnitCount() <= unit->getFaction()->getCountForMaxUnitCount(spawnUnitType)) {
406 			return NULL;
407 		}
408 	}
409 
410 	UnitPathInterface *newpath = NULL;
411 	switch(this->game->getGameSettings()->getPathFinderType()) {
412 		case pfBasic:
413 			newpath = new UnitPathBasic();
414 			break;
415 		default:
416 			throw megaglest_runtime_error("detected unsupported pathfinder type!");
417 	}
418 
419 	Unit *spawned= new Unit(world->getNextUnitId(unit->getFaction()), newpath,
420 							Vec2i(0), spawnUnitType, unit->getFaction(),
421 							world->getMap(), CardinalDir::NORTH);
422 
423 	bool placedSpawnUnit=world->placeUnit(_spawnPos, 10, spawned);
424 
425 	if(!placedSpawnUnit) {
426 		// This will also cleanup newPath
427 		delete spawned;
428 		spawned = NULL;
429 	}
430 	else {
431 		spawned->create();
432 		spawned->born(NULL);
433 		scriptManager->onUnitCreated(spawned);
434 	}
435 	return spawned;
436 }
437 
438 
439 // ==================== progress commands ====================
440 
441 //VERY IMPORTANT: compute next state depending on the first order of the list
updateUnitCommand(Unit * unit,int frameIndex)442 void UnitUpdater::updateUnitCommand(Unit *unit, int frameIndex) {
443 	try {
444 	bool minorDebugPerformance = false;
445 	Chrono chrono;
446 	if((minorDebugPerformance == true && frameIndex > 0) || SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
447 
448 	//if unit has command process it
449     bool hasCommand = (unit->anyCommand());
450 
451     if((minorDebugPerformance && frameIndex > 0) && chrono.getMillis() >= 1) printf("UnitUpdate [%d - %s] #1-unit threaded updates on frame: %d took [%lld] msecs\n",unit->getId(),unit->getType()->getName(false).c_str(),frameIndex,(long long int)chrono.getMillis());
452 
453 	int64 elapsed1 = 0;
454 	if(minorDebugPerformance && frameIndex > 0) elapsed1 = chrono.getMillis();
455 
456     if(hasCommand == true) {
457     	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit [%s] has command [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString(false).c_str(), unit->getCurrCommand()->toString(false).c_str());
458 
459     	bool commandUsesPathFinder = (frameIndex < 0);
460     	if(frameIndex > 0) {
461 			if(unit->getCurrCommand() != NULL && unit->getCurrCommand()->getCommandType() != NULL) {
462     			commandUsesPathFinder = unit->getCurrCommand()->getCommandType()->usesPathfinder();
463 
464     			// Clear previous cached unit data
465     			if(commandUsesPathFinder == true) {
466     				clearUnitPrecache(unit);
467     			}
468 			}
469     	}
470     	if(commandUsesPathFinder == true) {
471 			if(unit->getCurrCommand() != NULL && unit->getCurrCommand()->getCommandType() != NULL) {
472     			unit->getCurrCommand()->getCommandType()->update(this, unit, frameIndex);
473 			}
474     	}
475 
476     	if((minorDebugPerformance && frameIndex > 0) && (chrono.getMillis() - elapsed1) >= 1) {
477     		//CommandClass cc = unit->getCurrCommand()->getCommandType()->commandTypeClass;
478     		printf("UnitUpdate [%d - %s] #2-unit threaded updates on frame: %d commandUsesPathFinder = %d took [%lld] msecs\nCommand: %s\n",unit->getId(),unit->getType()->getName(false).c_str(),frameIndex,commandUsesPathFinder,(long long int)chrono.getMillis() - elapsed1,unit->getCurrCommand()->toString(false).c_str());
479     	}
480 	}
481 
482     if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
483 
484     if(frameIndex < 0) {
485 		//if no commands stop and add stop command
486 		if(unit->anyCommand() == false && unit->isOperative()) {
487 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
488 			if(unit->getType()->hasSkillClass(scStop)) {
489 				unit->setCurrSkill(scStop);
490 			}
491 			if(unit->getType()->hasCommandClass(ccStop)) {
492 				unit->giveCommand(new Command(unit->getType()->getFirstCtOfClass(ccStop)));
493 			}
494 		}
495     }
496     if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
497     if((minorDebugPerformance && frameIndex > 0) && chrono.getMillis() >= 1) printf("UnitUpdate [%d - %s] #3-unit threaded updates on frame: %d took [%lld] msecs\n",unit->getId(),unit->getType()->getName(false).c_str(),frameIndex,(long long int)chrono.getMillis());
498 
499 	}
500 	catch(const exception &ex) {
501 		//setRunningStatus(false);
502 
503 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
504 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
505 
506 		throw megaglest_runtime_error(ex.what());
507 	}
508 	catch(...) {
509 		char szBuf[8096]="";
510 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
511 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
512 		throw megaglest_runtime_error(szBuf);
513 	}
514 
515 }
516 
517 // ==================== updateStop ====================
518 
updateStop(Unit * unit,int frameIndex)519 void UnitUpdater::updateStop(Unit *unit, int frameIndex) {
520 	try {
521 	// Nothing to do
522 	if(frameIndex >= 0) {
523 		clearUnitPrecache(unit);
524 		return;
525 	}
526 
527 	Chrono chrono;
528 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
529 
530 	Command *command= unit->getCurrCommand();
531 	if(command == NULL) {
532 		throw megaglest_runtime_error("command == NULL");
533 	}
534     const StopCommandType *sct = static_cast<const StopCommandType*>(command->getCommandType());
535     Unit *sighted=NULL;
536 
537 
538     unit->setCurrSkill(sct->getStopSkillType());
539 
540     if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
541 
542 
543 	//we can attack any unit => attack it
544    	if(unit->getType()->hasSkillClass(scAttack)) {
545 
546    		int cmdTypeCount = unit->getType()->getCommandTypeCount();
547 
548 		for(int i = 0; i < cmdTypeCount; ++i) {
549 
550 			const CommandType *ct= unit->getType()->getCommandType(i);
551 
552 			//look for an attack skill
553 			const AttackSkillType *ast= NULL;
554 			if(ct->getClass() == ccAttack) {
555 				ast= static_cast<const AttackCommandType*>(ct)->getAttackSkillType();
556 			}
557 			else if(ct->getClass() == ccAttackStopped) {
558 				ast= static_cast<const AttackStoppedCommandType*>(ct)->getAttackSkillType();
559 			}
560 
561 
562 			//use it to attack
563 			if(ast != NULL) {
564 				if(attackableOnSight(unit, &sighted, ast, (frameIndex >= 0))) {
565 				    //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
566 					unit->giveCommand(new Command(ct, sighted->getPos()));
567 					break;
568 				}
569 			}
570 		}
571 		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
572 	}
573 	//see any unit and cant attack it => run
574 	else if(unit->getType()->hasCommandClass(ccMove)) {
575 		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
576 
577 		if(attackerOnSight(unit, &sighted, (frameIndex >= 0))) {
578 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
579 			Vec2i escapePos = unit->getPos() * 2 - sighted->getPos();
580 			//SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
581 			unit->giveCommand(new Command(unit->getType()->getFirstCtOfClass(ccMove), escapePos));
582 		}
583 
584 		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
585 	}
586 
587    	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
588 
589 	}
590 	catch(const exception &ex) {
591 		//setRunningStatus(false);
592 
593 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
594 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
595 
596 		throw megaglest_runtime_error(ex.what());
597 	}
598 	catch(...) {
599 		char szBuf[8096]="";
600 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
601 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
602 		throw megaglest_runtime_error(szBuf);
603 	}
604 
605 }
606 
607 // ==================== updateMove ====================
updateMove(Unit * unit,int frameIndex)608 void UnitUpdater::updateMove(Unit *unit, int frameIndex) {
609 	try {
610 	Chrono chrono;
611 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
612 
613     Command *command= unit->getCurrCommand();
614 	if(command == NULL) {
615 		throw megaglest_runtime_error("command == NULL");
616 	}
617     const MoveCommandType *mct= static_cast<const MoveCommandType*>(command->getCommandType());
618 
619 
620 	Vec2i pos= command->getUnit()!=NULL? command->getUnit()->getCenteredPos(): command->getPos();
621 
622 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
623 		char szBuf[8096]="";
624 		snprintf(szBuf,8096,"[updateMove] pos [%s] unit [%d - %s] cmd [%s]",pos.getString().c_str(),unit->getId(),unit->getFullName(false).c_str(),command->toString(false).c_str());
625 		unit->logSynchData(__FILE__,__LINE__,szBuf);
626 	}
627 
628 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
629 
630 
631 	TravelState tsValue = tsImpossible;
632 	switch(this->game->getGameSettings()->getPathFinderType()) {
633 		case pfBasic:
634 			tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex);
635 			break;
636 		default:
637 			throw megaglest_runtime_error("detected unsupported pathfinder type!");
638     }
639 
640 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
641 
642 
643 	if(frameIndex < 0) {
644 		switch (tsValue) {
645 		case tsMoving:
646 			unit->setCurrSkill(mct->getMoveSkillType());
647 			break;
648 
649 		case tsBlocked:
650 			unit->setCurrSkill(scStop);
651 			if(unit->getPath()->isBlocked()){
652 				unit->finishCommand();
653 			}
654 			break;
655 
656 		default:
657 			unit->finishCommand();
658 			break;
659 		}
660 	}
661 
662 
663 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
664 		char szBuf[8096]="";
665 		snprintf(szBuf,8096,"[updateMove] tsValue [%d]",tsValue);
666 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
667 	}
668 
669 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
670 
671 	}
672 	catch(const exception &ex) {
673 		//setRunningStatus(false);
674 
675 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
676 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
677 
678 		throw megaglest_runtime_error(ex.what());
679 	}
680 	catch(...) {
681 		char szBuf[8096]="";
682 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
683 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
684 		throw megaglest_runtime_error(szBuf);
685 	}
686 
687 }
688 
689 
690 // ==================== updateAttack ====================
691 
updateAttack(Unit * unit,int frameIndex)692 void UnitUpdater::updateAttack(Unit *unit, int frameIndex) {
693 	try {
694 
695 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
696 		char szBuf[8096]="";
697 		snprintf(szBuf,8096,"[updateAttack]");
698 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
699 	}
700 
701 	Chrono chrono;
702 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
703 
704 	Command *command= unit->getCurrCommand();
705 	if(command == NULL) {
706 
707 		if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
708 			char szBuf[8096]="";
709 			snprintf(szBuf,8096,"[updateAttack]");
710 			unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
711 		}
712 
713 		return;
714 	}
715     const AttackCommandType *act= static_cast<const AttackCommandType*>(command->getCommandType());
716 	if(act == NULL) {
717 
718 		if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
719 			char szBuf[8096]="";
720 			snprintf(szBuf,8096,"[updateAttack]");
721 			unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
722 		}
723 
724 		return;
725 	}
726 	Unit *target= NULL;
727 
728 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
729 
730 	if( (command->getUnit() == NULL || !(command->getUnit()->isAlive()) ) && unit->getCommandSize() > 1) {
731 
732 		if(frameIndex < 0) {
733 			unit->finishCommand(); // all queued "ground attacks" are skipped if somthing else is queued after them.
734 
735 			if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
736 				char szBuf[8096]="";
737 				snprintf(szBuf,8096,"[updateAttack]");
738 				unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
739 			}
740 		}
741 		return;
742 	}
743 
744 	//if found
745 	//if(frameIndex < 0) {
746 	{
747 		if(attackableOnRange(unit, &target, act->getAttackSkillType(),(frameIndex >= 0))) {
748     		if(frameIndex < 0) {
749 				if(unit->getEp() >= act->getAttackSkillType()->getEpCost()) {
750 					unit->setCurrSkill(act->getAttackSkillType());
751 					unit->setTarget(target);
752 				}
753 				else {
754 					unit->setCurrSkill(scStop);
755 				}
756 
757 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
758 					char szBuf[8096]="";
759 					snprintf(szBuf,8096,"[updateAttack]");
760 					unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
761 				}
762     		}
763     		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
764 		}
765 		else {
766 			//compute target pos
767 			Vec2i pos;
768 			if(command->getUnit() != NULL) {
769 				pos= command->getUnit()->getCenteredPos();
770 			}
771 			else if(attackableOnSight(unit, &target, act->getAttackSkillType(), (frameIndex >= 0))) {
772 				pos= target->getPos();
773 			}
774 			else {
775 				pos= command->getPos();
776 			}
777 
778 			if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
779 				char szBuf[8096]="";
780 				snprintf(szBuf,8096,"[updateAttack] pos [%s] unit->getPos() [%s]",pos.getString().c_str(),unit->getPos().getString().c_str());
781 				unit->logSynchData(__FILE__,__LINE__,szBuf);
782 			}
783 
784 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
785 
786 			TravelState tsValue = tsImpossible;
787 			//if(frameIndex < 0) {
788 			{
789 				//printf("In [%s::%s Line: %d] START pathfind for attacker [%d - %s]\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(), unit->getType()->getName().c_str());
790 				//fflush(stdout);
791 				switch(this->game->getGameSettings()->getPathFinderType()) {
792 					case pfBasic:
793 						tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex);
794 						break;
795 					default:
796 						throw megaglest_runtime_error("detected unsupported pathfinder type!");
797 				}
798 				//printf("In [%s::%s Line: %d] END pathfind for attacker [%d - %s]\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(), unit->getType()->getName().c_str());
799 				//fflush(stdout);
800 			}
801 
802 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
803 
804 			if(frameIndex < 0) {
805 				if(command->getUnit() != NULL && !command->getUnit()->isAlive() && unit->getCommandSize() > 1) {
806 					// don't run over to dead body if there is still something to do in the queue
807 					unit->finishCommand();
808 
809 					if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
810 						char szBuf[8096]="";
811 						snprintf(szBuf,8096,"[updateAttack]");
812 						unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
813 					}
814 				}
815 				else {
816 					//if unit arrives destPos order has ended
817 					if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0 &&
818 							SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynchMax).enabled == true) {
819 						char szBuf[8096]="";
820 						snprintf(szBuf,8096,"#1 [updateAttack] tsValue = %d",tsValue);
821 						unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
822 					}
823 
824 					switch (tsValue) {
825 						case tsMoving:
826 							unit->setCurrSkill(act->getMoveSkillType());
827 							break;
828 						case tsBlocked:
829 							if(unit->getPath()->isBlocked()) {
830 								unit->finishCommand();
831 							}
832 							break;
833 						default:
834 							unit->finishCommand();
835 							break;
836 						}
837 	/*
838 						case tsMoving:
839 							unit->setCurrSkill(act->getMoveSkillType());
840 
841 							{
842 								std::pair<bool,Unit *> beingAttacked = unitBeingAttacked(unit);
843 								if(beingAttacked.first == true) {
844 									Unit *enemy = beingAttacked.second;
845 									const AttackCommandType *act_forenemy = unit->getType()->getFirstAttackCommand(enemy->getCurrField());
846 									if(act_forenemy != NULL) {
847 										if(unit->getEp() >= act_forenemy->getAttackSkillType()->getEpCost()) {
848 											unit->setCurrSkill(act_forenemy->getAttackSkillType());
849 											unit->setTarget(enemy);
850 										}
851 										//aiInterface->giveCommand(i, act_forenemy, beingAttacked.second->getPos());
852 									}
853 									else {
854 										const AttackStoppedCommandType *asct_forenemy = unit->getType()->getFirstAttackStoppedCommand(enemy->getCurrField());
855 										if(asct_forenemy != NULL) {
856 											//aiInterface->giveCommand(i, asct_forenemy, beingAttacked.second->getCenteredPos());
857 											if(unit->getEp() >= asct_forenemy->getAttackSkillType()->getEpCost()) {
858 												unit->setCurrSkill(asct_forenemy->getAttackSkillType());
859 												unit->setTarget(enemy);
860 											}
861 										}
862 									}
863 								}
864 							}
865 
866 							break;
867 
868 						case tsBlocked:
869 							if(unit->getPath()->isBlocked()){
870 								unit->finishCommand();
871 							}
872 							break;
873 						default:
874 							unit->finishCommand();
875 					}
876 	*/
877 
878 					if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0 &&
879 							SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynchMax).enabled == true) {
880 						char szBuf[8096]="";
881 						snprintf(szBuf,8096,"#2 [updateAttack] tsValue = %d",tsValue);
882 						unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
883 					}
884 
885 				}
886 			}
887 
888 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
889 		}
890     }
891 
892     if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
893 
894 	}
895 	catch(const exception &ex) {
896 		//setRunningStatus(false);
897 
898 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Loc [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
899 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
900 
901 		throw megaglest_runtime_error(ex.what());
902 	}
903 	catch(...) {
904 		char szBuf[8096]="";
905 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
906 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
907 		throw megaglest_runtime_error(szBuf);
908 	}
909 
910 }
911 
912 
913 // ==================== updateAttackStopped ====================
914 
updateAttackStopped(Unit * unit,int frameIndex)915 void UnitUpdater::updateAttackStopped(Unit *unit, int frameIndex) {
916 	try {
917 
918 	// Nothing to do
919 	if(frameIndex >= 0) {
920 		if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex >= 0) {
921 			char szBuf[8096]="";
922 			snprintf(szBuf,8096,"[updateAttackStopped]");
923 			unit->logSynchDataThreaded(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
924 		}
925 		clearUnitPrecache(unit);
926 		return;
927 	}
928 
929 	Chrono chrono;
930 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
931 
932 	Command *command= unit->getCurrCommand();
933 	if(command == NULL) {
934 		throw megaglest_runtime_error("command == NULL");
935 	}
936 
937     const AttackStoppedCommandType *asct= static_cast<const AttackStoppedCommandType*>(command->getCommandType());
938     Unit *enemy=NULL;
939 
940 
941     if(unit->getCommandSize() > 1) {
942     	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
943     		char szBuf[8096]="";
944     		snprintf(szBuf,8096,"[updateAttackStopped]");
945     		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
946     	}
947 
948     	unit->finishCommand(); // attackStopped is skipped if somthing else is queued after this.
949     	return;
950     }
951 
952 
953     float distToUnit=-1;
954     std::pair<bool,Unit *> result = make_pair(false,(Unit *)NULL);
955     unitBeingAttacked(result, unit, asct->getAttackSkillType(), &distToUnit);
956 
957 
958 	if(result.first == true) {
959         unit->setCurrSkill(asct->getAttackSkillType());
960 		unit->setTarget(result.second);
961 
962     	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
963     		char szBuf[8096]="";
964     		snprintf(szBuf,8096,"[updateAttackStopped]");
965     		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
966     	}
967 	}
968 	else if(attackableOnRange(unit, &enemy, asct->getAttackSkillType(),(frameIndex >= 0))) {
969         unit->setCurrSkill(asct->getAttackSkillType());
970 		unit->setTarget(enemy);
971 
972     	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
973     		char szBuf[8096]="";
974     		snprintf(szBuf,8096,"[updateAttackStopped]");
975     		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
976     	}
977     }
978     else {
979         unit->setCurrSkill(asct->getStopSkillType());
980 
981     	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
982     		char szBuf[8096]="";
983     		snprintf(szBuf,8096,"[updateAttackStopped]");
984     		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
985     	}
986     }
987 
988     if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
989 
990 	}
991 	catch(const exception &ex) {
992 		//setRunningStatus(false);
993 
994 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
995 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
996 
997 		throw megaglest_runtime_error(ex.what());
998 	}
999 	catch(...) {
1000 		char szBuf[8096]="";
1001 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
1002 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
1003 		throw megaglest_runtime_error(szBuf);
1004 	}
1005 
1006 }
1007 
unitBeingAttacked(std::pair<bool,Unit * > & result,const Unit * unit,const AttackSkillType * ast,float * currentDistToUnit)1008 void UnitUpdater::unitBeingAttacked(std::pair<bool,Unit *> &result, const Unit *unit, const AttackSkillType *ast, float *currentDistToUnit) {
1009 	//std::pair<bool,Unit *> result = make_pair(false,(Unit *)NULL);
1010 
1011 	float distToUnit = -1;
1012 	if(currentDistToUnit != NULL) {
1013 		distToUnit = *currentDistToUnit;
1014 	}
1015 	if(ast != NULL) {
1016 		vector<Unit*> enemies = enemyUnitsOnRange(unit,ast);
1017 		for(unsigned j = 0; j < enemies.size(); ++j) {
1018 			Unit *enemy = enemies[j];
1019 
1020 			//printf("~~~~~~~~ Unit [%s - %d] enemy # %d found enemy [%s - %d] distToUnit = %f\n",unit->getFullName().c_str(),unit->getId(),j,enemy->getFullName().c_str(),enemy->getId(),unit->getCenteredPos().dist(enemy->getCenteredPos()));
1021 
1022 			if(distToUnit < 0 || unit->getCenteredPos().dist(enemy->getCenteredPos()) < distToUnit) {
1023 				distToUnit = unit->getCenteredPos().dist(enemy->getCenteredPos());
1024 				if(ast->getAttackRange() >= distToUnit){
1025 					result.first= true;
1026 					result.second= enemy;
1027 					break;
1028 				}
1029 			}
1030 		}
1031 	}
1032 
1033 	if(currentDistToUnit != NULL) {
1034 		*currentDistToUnit = distToUnit;
1035 	}
1036 
1037 //	if(result.first == true) {
1038 //		printf("~~~~~~~~ Unit [%s - %d] found enemy [%s - %d] distToUnit = %f\n",unit->getFullName().c_str(),unit->getId(),result.second->getFullName().c_str(),result.second->getId(),distToUnit);
1039 //	}
1040     //return result;
1041 }
1042 
unitBeingAttacked(const Unit * unit)1043 std::pair<bool,Unit *> UnitUpdater::unitBeingAttacked(const Unit *unit) {
1044 	std::pair<bool,Unit *> result = make_pair(false,(Unit *)NULL);
1045 
1046 	float distToUnit = -1;
1047 	for(unsigned int i = 0; i < (unsigned int)unit->getType()->getSkillTypeCount(); ++i) {
1048 		const SkillType *st = unit->getType()->getSkillType(i);
1049 		const AttackSkillType *ast = dynamic_cast<const AttackSkillType *>(st);
1050 		unitBeingAttacked(result, unit, ast, &distToUnit);
1051 	}
1052 
1053 //	if(result.first == true) {
1054 //		printf("~~~~~~~~ Unit [%s - %d] found enemy [%s - %d] distToUnit = %f\n",unit->getFullName().c_str(),unit->getId(),result.second->getFullName().c_str(),result.second->getId(),distToUnit);
1055 //	}
1056     return result;
1057 }
1058 
1059 // ==================== updateBuild ====================
1060 
updateBuild(Unit * unit,int frameIndex)1061 void UnitUpdater::updateBuild(Unit *unit, int frameIndex) {
1062 	try {
1063 
1064 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1065 		char szBuf[8096]="";
1066 		snprintf(szBuf,8096,"[updateBuild]");
1067 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
1068 	}
1069 
1070 	Chrono chrono;
1071 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
1072 
1073 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit [%s] will build using command [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString(false).c_str(), unit->getCurrCommand()->toString(false).c_str());
1074 
1075 	Command *command= unit->getCurrCommand();
1076 	if(command == NULL) {
1077 		throw megaglest_runtime_error("command == NULL");
1078 	}
1079 
1080     const BuildCommandType *bct= static_cast<const BuildCommandType*>(command->getCommandType());
1081 
1082 	if(unit->getCurrSkill() != NULL && unit->getCurrSkill()->getClass() != scBuild) {
1083 		if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1084 
1085         //if not building
1086         const UnitType *ut= command->getUnitType();
1087 
1088         if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1089 
1090 		TravelState tsValue = tsImpossible;
1091 		switch(this->game->getGameSettings()->getPathFinderType()) {
1092 			case pfBasic:
1093 				{
1094 				Vec2i buildPos = map->findBestBuildApproach(unit, command->getPos(), ut);
1095 
1096 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1097 					char szBuf[8096]="";
1098 					snprintf(szBuf,8096,"[updateBuild] unit->getPos() [%s] command->getPos() [%s] buildPos [%s]",
1099 							unit->getPos().getString().c_str(),command->getPos().getString().c_str(),buildPos.getString().c_str());
1100 					unit->logSynchData(__FILE__,__LINE__,szBuf);
1101 				}
1102 
1103 				tsValue = pathFinder->findPath(unit, buildPos, NULL, frameIndex);
1104 
1105 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1106 					char szBuf[8096]="";
1107 					snprintf(szBuf,8096,"[updateBuild] tsValue: %d",tsValue);
1108 					unit->logSynchData(__FILE__,__LINE__,szBuf);
1109 				}
1110 
1111 				}
1112 				break;
1113 			default:
1114 				throw megaglest_runtime_error("detected unsupported pathfinder type!");
1115 	    }
1116 
1117 		if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsValue = %d\n",__FILE__,__FUNCTION__,__LINE__,tsValue);
1118 
1119 		if(frameIndex < 0) {
1120 			switch (tsValue) {
1121 			case tsMoving:
1122 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsMoving\n",__FILE__,__FUNCTION__,__LINE__);
1123 
1124 				unit->setCurrSkill(bct->getMoveSkillType());
1125 				break;
1126 
1127 			case tsArrived:
1128 				{
1129 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived:\n",__FILE__,__FUNCTION__,__LINE__);
1130 
1131 				//if arrived destination
1132 				assert(ut);
1133 				if(ut == NULL) {
1134 					throw megaglest_runtime_error("ut == NULL");
1135 				}
1136 
1137 				bool canOccupyCell = false;
1138 				switch(this->game->getGameSettings()->getPathFinderType()) {
1139 					case pfBasic:
1140 						if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived about to call map->isFreeCells() for command->getPos() = %s, ut->getSize() = %d\n",__FILE__,__FUNCTION__,__LINE__,command->getPos().getString().c_str(),ut->getSize());
1141 						canOccupyCell = map->isFreeCells(command->getPos(), ut->getSize(), fLand);
1142 						break;
1143 					default:
1144 						throw megaglest_runtime_error("detected unsupported pathfinder type!");
1145 				}
1146 
1147 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] canOccupyCell = %d\n",__FILE__,__FUNCTION__,__LINE__,canOccupyCell);
1148 
1149 				if (canOccupyCell == true) {
1150 					const UnitType *builtUnitType= command->getUnitType();
1151 					CardinalDir facing = command->getFacing();
1152 
1153 					UnitPathInterface *newpath = NULL;
1154 					switch(this->game->getGameSettings()->getPathFinderType()) {
1155 						case pfBasic:
1156 							newpath = new UnitPathBasic();
1157 							break;
1158 						default:
1159 							throw megaglest_runtime_error("detected unsupported pathfinder type!");
1160 					}
1161 
1162 					Vec2i buildPos = command->getPos();
1163 					Unit *builtUnit= new Unit(world->getNextUnitId(unit->getFaction()), newpath, buildPos, builtUnitType, unit->getFaction(), world->getMap(), facing);
1164 
1165 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1166 
1167 					builtUnit->create();
1168 
1169 					if(builtUnitType->hasSkillClass(scBeBuilt) == false) {
1170 						throw megaglest_runtime_error("Unit [" + builtUnitType->getName(false) + "] has no be_built skill, producer was [" + intToStr(unit->getId()) + " - " + unit->getType()->getName(false) + "].");
1171 					}
1172 
1173 					builtUnit->setCurrSkill(scBeBuilt);
1174 
1175 					unit->setCurrSkill(bct->getBuildSkillType());
1176 					unit->setTarget(builtUnit);
1177 
1178 
1179 					map->prepareTerrain(builtUnit);
1180 
1181 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1182 
1183 					switch(this->game->getGameSettings()->getPathFinderType()) {
1184 						case pfBasic:
1185 							break;
1186 						default:
1187 							throw megaglest_runtime_error("detected unsupported pathfinder type!");
1188 					}
1189 
1190 					command->setUnit(builtUnit);
1191 
1192 
1193 					//play start sound
1194 					if(unit->getFactionIndex() == world->getThisFactionIndex() ||
1195 						(game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)) {
1196 						SoundRenderer::getInstance().playFx(
1197 							bct->getStartSound(),
1198 							unit->getCurrMidHeightVector(),
1199 							gameCamera->getPos());
1200 					}
1201 
1202 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,builtUnit->toString(false).c_str());
1203 				}
1204 				else {
1205 					//if there are no free cells
1206 					unit->cancelCommand();
1207 					unit->setCurrSkill(scStop);
1208 
1209 					if(unit->getFactionIndex() == world->getThisFactionIndex()) {
1210 						 console->addStdMessage("BuildingNoPlace");
1211 					}
1212 
1213 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got BuildingNoPlace\n",__FILE__,__FUNCTION__,__LINE__);
1214 				}
1215 				}
1216 				break;
1217 
1218 			case tsBlocked:
1219 				if(unit->getPath()->isBlocked()) {
1220 					unit->cancelCommand();
1221 
1222 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got tsBlocked\n",__FILE__,__FUNCTION__,__LINE__);
1223 				}
1224 				break;
1225 			}
1226 		}
1227 		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1228     }
1229     else {
1230     	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived unit = %s\n",__FILE__,__FUNCTION__,__LINE__,unit->toString(false).c_str());
1231 
1232     	if(frameIndex < 0) {
1233 			//if building
1234 			Unit *builtUnit = map->getCell(unit->getTargetPos())->getUnit(fLand);
1235 			if(builtUnit == NULL) {
1236 				builtUnit = map->getCell(unit->getTargetPos())->getUnitWithEmptyCellMap(fLand);
1237 			}
1238 
1239 			if(builtUnit != NULL) {
1240 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit = %s\n",__FILE__,__FUNCTION__,__LINE__,builtUnit->toString(false).c_str());
1241 			}
1242 
1243 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit = [%p]\n",__FILE__,__FUNCTION__,__LINE__,builtUnit);
1244 
1245 			//if unit is killed while building then u==NULL;
1246 			if(builtUnit != NULL && builtUnit != command->getUnit()) {
1247 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit is not the command's unit!\n",__FILE__,__FUNCTION__,__LINE__);
1248 
1249 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1250 					char szBuf[8096]="";
1251 					snprintf(szBuf,8096,"[updateBuild]");
1252 					unit->logSynchData(__FILE__,__LINE__,szBuf);
1253 				}
1254 
1255 				unit->setCurrSkill(scStop);
1256 			}
1257 			else if(builtUnit == NULL || builtUnit->isBuilt()) {
1258 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit is NULL or ALREADY built\n",__FILE__,__FUNCTION__,__LINE__);
1259 
1260 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1261 					char szBuf[8096]="";
1262 					snprintf(szBuf,8096,"[updateBuild]");
1263 					unit->logSynchData(__FILE__,__LINE__,szBuf);
1264 				}
1265 
1266 				unit->finishCommand();
1267 				unit->setCurrSkill(scStop);
1268 
1269 			}
1270 			else if(builtUnit == NULL || builtUnit->repair()) {
1271 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1272 
1273 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1274 					char szBuf[8096]="";
1275 					snprintf(szBuf,8096,"[updateBuild]");
1276 					unit->logSynchData(__FILE__,__LINE__,szBuf);
1277 				}
1278 
1279 				const CommandType *ct = (command != NULL ? command->getCommandType() : NULL);
1280 				//building finished
1281 				unit->finishCommand();
1282 				unit->setCurrSkill(scStop);
1283 
1284 				builtUnit->born(ct);
1285 				scriptManager->onUnitCreated(builtUnit);
1286 				if(unit->getFactionIndex() == world->getThisFactionIndex() ||
1287 					(game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)) {
1288 					SoundRenderer::getInstance().playFx(
1289 						bct->getBuiltSound(),
1290 						unit->getCurrMidHeightVector(),
1291 						gameCamera->getPos());
1292 				}
1293 			}
1294     	}
1295     	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1296     }
1297 
1298 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1299 
1300 	}
1301 	catch(const exception &ex) {
1302 		//setRunningStatus(false);
1303 
1304 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
1305 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1306 
1307 		throw megaglest_runtime_error(ex.what());
1308 	}
1309 	catch(...) {
1310 		char szBuf[8096]="";
1311 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
1312 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
1313 		throw megaglest_runtime_error(szBuf);
1314 	}
1315 
1316 }
1317 
1318 // ==================== updateHarvest ====================
updateHarvestEmergencyReturn(Unit * unit,int frameIndex)1319 void UnitUpdater::updateHarvestEmergencyReturn(Unit *unit, int frameIndex) {
1320 	try {
1321 
1322 	if(frameIndex >= 0) {
1323 		return;
1324 	}
1325 
1326 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1327 		char szBuf[8096]="";
1328 		snprintf(szBuf,8096,"[updateHarvestEmergencyReturn]");
1329 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
1330 	}
1331 
1332 	//printf("\n#1 updateHarvestEmergencyReturn\n");
1333 	Command *command= unit->getCurrCommand();
1334 	if(command != NULL) {
1335 		//printf("\n#2 updateHarvestEmergencyReturn\n");
1336 
1337 		//const HarvestCommandType *hct= dynamic_cast<const HarvestCommandType*>((command != NULL ? command->getCommandType() : NULL));
1338 		//if(hct != NULL) {
1339 		{
1340 			//printf("\n#3 updateHarvestEmergencyReturn\n");
1341 
1342 			const Vec2i unitTargetPos = command->getPos();
1343 			Cell *cell= map->getCell(unitTargetPos);
1344 			if(cell != NULL && cell->getUnit(unit->getCurrField()) != NULL) {
1345 				//printf("\n#4 updateHarvestEmergencyReturn\n");
1346 
1347 				Unit *targetUnit = cell->getUnit(unit->getCurrField());
1348 				if(targetUnit != NULL) {
1349 					//printf("\n#5 updateHarvestEmergencyReturn\n");
1350 					// Check if we can return whatever resources we have
1351 					if(targetUnit->getFactionIndex() == unit->getFactionIndex() &&
1352 						targetUnit->isOperative() == true && unit->getLoadType() != NULL &&
1353 						targetUnit->getType() != NULL && targetUnit->getType()->getStore(unit->getLoadType()) > 0) {
1354 						//printf("\n#6 updateHarvestEmergencyReturn\n");
1355 
1356 						const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction());
1357 						if(previousHarvestCmd != NULL) {
1358 							//printf("\n\n#1a return harvested resources\n\n");
1359 							NetworkCommand networkCommand(this->world,nctGiveCommand, unit->getId(), previousHarvestCmd->getId(), unit->getLastHarvestedResourcePos(),
1360 															-1, Unit::invalidId, -1, false, cst_None, -1, -1);
1361 
1362 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1363 
1364 							Command* new_command= this->game->getCommander()->buildCommand(&networkCommand);
1365 							new_command->setStateType(cst_EmergencyReturnResource);
1366 							new_command->setStateValue(1);
1367 							std::pair<CommandResult,string> cr= unit->checkCommand(new_command);
1368 							if(cr.first == crSuccess) {
1369 								//printf("\n\n#1b return harvested resources\n\n");
1370 
1371 								if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1372 								unit->replaceCurrCommand(new_command);
1373 
1374 								unit->setCurrSkill(previousHarvestCmd->getStopLoadedSkillType()); // make sure we use the right harvest animation
1375 							}
1376 							else {
1377 								//printf("\n\n#1c return harvested resources\n\n");
1378 
1379 								if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1380 								delete new_command;
1381 
1382 								unit->setCurrSkill(scStop);
1383 								unit->finishCommand();
1384 							}
1385 						}
1386 					}
1387 				}
1388 			}
1389 		}
1390 	}
1391 
1392 	}
1393 	catch(const exception &ex) {
1394 		//setRunningStatus(false);
1395 
1396 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
1397 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1398 
1399 		throw megaglest_runtime_error(ex.what());
1400 	}
1401 	catch(...) {
1402 		char szBuf[8096]="";
1403 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
1404 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
1405 		throw megaglest_runtime_error(szBuf);
1406 	}
1407 
1408 }
1409 
updateHarvest(Unit * unit,int frameIndex)1410 void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) {
1411 	try {
1412 
1413 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1414 		char szBuf[8096]="";
1415 		snprintf(szBuf,8096,"[updateHarvest]");
1416 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
1417 	}
1418 
1419 	Chrono chrono;
1420 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
1421 
1422 	Command *command= unit->getCurrCommand();
1423 	if(command == NULL) {
1424 		throw megaglest_runtime_error("command == NULL");
1425 	}
1426 
1427     const HarvestCommandType *hct= dynamic_cast<const HarvestCommandType*>(command->getCommandType());
1428     if(hct == NULL) {
1429     	throw megaglest_runtime_error("hct == NULL");
1430     }
1431 	Vec2i targetPos(-1);
1432 
1433 	//TravelState tsValue = tsImpossible;
1434 	//UnitPathInterface *path= unit->getPath();
1435 
1436 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1437 	//printf("In UpdateHarvest [%d - %s] unit->getCurrSkill()->getClass() = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getCurrSkill()->getClass());
1438 
1439 	Resource *harvestResource = NULL;
1440 	SurfaceCell *sc = map->getSurfaceCell(Map::toSurfCoords(command->getPos()));
1441 	if(sc != NULL) {
1442 		harvestResource = sc->getResource();
1443 	}
1444 
1445 	if(unit->getCurrSkill() != NULL && unit->getCurrSkill()->getClass() != scHarvest) {
1446 		bool forceReturnToStore = (command != NULL &&
1447 							command->getStateType() == cst_EmergencyReturnResource && command->getStateValue() == 1);
1448 
1449 		//if not working
1450 		if(unit->getLoadCount() == 0 ||
1451 			(forceReturnToStore == false && unit->getLoadType() != NULL &&
1452 			 harvestResource != NULL && (unit->getLoadCount() < hct->getMaxLoad()) &&
1453 			 harvestResource->getType() != NULL && unit->getLoadType() == harvestResource->getType())) {
1454 			//if not loaded go for resources
1455 			SurfaceCell *sc = map->getSurfaceCell(Map::toSurfCoords(command->getPos()));
1456 			if(sc != NULL) {
1457 				Resource *r = sc->getResource();
1458 				if(r != NULL && hct != NULL && hct->canHarvest(r->getType())) {
1459 					//if can harvest dest. pos
1460 					bool canHarvestDestPos = false;
1461 
1462 					if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1463 
1464 	    			switch(this->game->getGameSettings()->getPathFinderType()) {
1465 	    				case pfBasic:
1466 	    					{
1467 	    						const bool newHarvestPath = false;
1468 	    						bool isNearResource = false;
1469 	    						Vec2i clickPos = command->getOriginalPos();
1470 	    						if(newHarvestPath == true) {
1471 	    							isNearResource = map->isResourceNear(frameIndex,unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit, false,&clickPos);
1472 	    						}
1473 	    						else {
1474 	    							isNearResource = map->isResourceNear(frameIndex,unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit);
1475 	    						}
1476 	    						if(isNearResource == true) {
1477 	    							if((unit->getPos().dist(command->getPos()) < harvestDistance || unit->getPos().dist(targetPos) < harvestDistance) && isNearResource == true) {
1478 	    								canHarvestDestPos = true;
1479 	    							}
1480 	    						}
1481 	    						else if(newHarvestPath == true) {
1482 	    							if(clickPos != command->getOriginalPos()) {
1483 	    								//printf("%%----------- unit [%s - %d] CHANGING RESOURCE POS from [%s] to [%s]\n",unit->getFullName().c_str(),unit->getId(),command->getOriginalPos().getString().c_str(),clickPos.getString().c_str());
1484 
1485 										if(frameIndex < 0) {
1486 											if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1487 												char szBuf[8096]="";
1488 												snprintf(szBuf,8096,"[updateHarvest] clickPos [%s]",clickPos.getString().c_str());
1489 												unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
1490 											}
1491 
1492 	    									command->setPos(clickPos);
1493 										}
1494 	    							}
1495 	    						}
1496 	    					}
1497 	    					break;
1498 	    				default:
1499 	    					throw megaglest_runtime_error("detected unsupported pathfinder type!");
1500 	    			}
1501 
1502 	    			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1503 
1504 					if (canHarvestDestPos == true ) {
1505 						if(frameIndex < 0) {
1506 							if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1507 								char szBuf[8096]="";
1508 								snprintf(szBuf,8096,"[updateHarvest]");
1509 								unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
1510 							}
1511 
1512 							unit->setLastHarvestResourceTarget(NULL);
1513 						}
1514 
1515 						canHarvestDestPos = (map->getSurfaceCell(Map::toSurfCoords(targetPos)) != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource()->getType() != NULL);
1516 
1517 						if(canHarvestDestPos == true) {
1518 							if(frameIndex < 0) {
1519 								//if it finds resources it starts harvesting
1520 								unit->setCurrSkill(hct->getHarvestSkillType());
1521 								unit->setTargetPos(targetPos);
1522 								command->setPos(targetPos);
1523 
1524 								if(unit->getLoadType() == NULL || harvestResource == NULL ||
1525 								   harvestResource->getType() == NULL || unit->getLoadType() != harvestResource->getType()) {
1526 									unit->setLoadCount(0);
1527 								}
1528 
1529 								unit->getFaction()->addResourceTargetToCache(targetPos);
1530 
1531 								switch(this->game->getGameSettings()->getPathFinderType()) {
1532 									case pfBasic:
1533 										unit->setLoadType(r->getType());
1534 										break;
1535 									default:
1536 										throw megaglest_runtime_error("detected unsupported pathfinder type!");
1537 								}
1538 
1539 								if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1540 									char szBuf[8096]="";
1541 									snprintf(szBuf,8096,"[updateHarvest] targetPos [%s]",targetPos.getString().c_str());
1542 									unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
1543 								}
1544 							}
1545 							if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1546 						}
1547 					}
1548 					if(canHarvestDestPos == false) {
1549 						if(frameIndex < 0) {
1550 							if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1551 								char szBuf[8096]="";
1552 								snprintf(szBuf,8096,"[updateHarvest] targetPos [%s]",targetPos.getString().c_str());
1553 								unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
1554 							}
1555 
1556 							unit->setLastHarvestResourceTarget(&targetPos);
1557 						}
1558 
1559 						if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1560 
1561 						if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1562 							char szBuf[8096]="";
1563 							snprintf(szBuf,8096,"[updateHarvest] unit->getPos() [%s] command->getPos() [%s]",
1564 									unit->getPos().getString().c_str(),command->getPos().getString().c_str());
1565 							unit->logSynchData(__FILE__,__LINE__,szBuf);
1566 						}
1567 
1568 						//if not continue walking
1569 						bool wasStuck = false;
1570 						TravelState tsValue = tsImpossible;
1571 		    			switch(this->game->getGameSettings()->getPathFinderType()) {
1572 		    				case pfBasic:
1573 								tsValue = pathFinder->findPath(unit, command->getPos(), &wasStuck, frameIndex);
1574 								if (tsValue == tsMoving && frameIndex < 0) {
1575 									unit->setCurrSkill(hct->getMoveSkillType());
1576 								}
1577 		    					break;
1578 		    				default:
1579 		    					throw megaglest_runtime_error("detected unsupported pathfinder type!");
1580 		    			}
1581 
1582 		    			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1583 
1584 		    			// If the unit is blocked or Even worse 'stuck' then try to
1585 		    			// find the same resource type elsewhere, but close by
1586 		    			if((wasStuck == true || tsValue == tsBlocked) && unit->isAlive() == true) {
1587 		    				switch(this->game->getGameSettings()->getPathFinderType()) {
1588 								case pfBasic:
1589 									{
1590 										bool isNearResource = map->isResourceNear(frameIndex,unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit,true);
1591 										if(isNearResource == true) {
1592 											if((unit->getPos().dist(command->getPos()) < harvestDistance || unit->getPos().dist(targetPos) < harvestDistance) && isNearResource == true) {
1593 												canHarvestDestPos = true;
1594 											}
1595 										}
1596 									}
1597 									break;
1598 								default:
1599 									throw megaglest_runtime_error("detected unsupported pathfinder type!");
1600 							}
1601 
1602 							if (canHarvestDestPos == true) {
1603 								if(frameIndex < 0) {
1604 									unit->setLastHarvestResourceTarget(NULL);
1605 								}
1606 
1607 								canHarvestDestPos = (map->getSurfaceCell(Map::toSurfCoords(targetPos)) != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource()->getType() != NULL);
1608 								if(canHarvestDestPos == true) {
1609 									if(frameIndex < 0) {
1610 										//if it finds resources it starts harvesting
1611 										unit->setCurrSkill(hct->getHarvestSkillType());
1612 										unit->setTargetPos(targetPos);
1613 										command->setPos(targetPos);
1614 
1615 										if(unit->getLoadType() == NULL || harvestResource == NULL ||
1616 										   harvestResource->getType() == NULL || unit->getLoadType() != harvestResource->getType()) {
1617 											unit->setLoadCount(0);
1618 										}
1619 										unit->getFaction()->addResourceTargetToCache(targetPos);
1620 
1621 										switch(this->game->getGameSettings()->getPathFinderType()) {
1622 											case pfBasic:
1623 												unit->setLoadType(r->getType());
1624 												break;
1625 											default:
1626 												throw megaglest_runtime_error("detected unsupported pathfinder type!");
1627 										}
1628 									}
1629 								}
1630 
1631 								if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1632 							}
1633 
1634 							if(canHarvestDestPos == false) {
1635 								if(frameIndex < 0) {
1636 									unit->setLastHarvestResourceTarget(&targetPos);
1637 								}
1638 
1639 								if(targetPos.x >= 0) {
1640 									//if not continue walking
1641 
1642 									if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1643 										char szBuf[8096]="";
1644 										snprintf(szBuf,8096,"[updateHarvest #2] unit->getPos() [%s] command->getPos() [%s] targetPos [%s]",
1645 												unit->getPos().getString().c_str(),command->getPos().getString().c_str(),targetPos.getString().c_str());
1646 										unit->logSynchData(__FILE__,__LINE__,szBuf);
1647 									}
1648 
1649 									wasStuck = false;
1650 									TravelState tsValue = tsImpossible;
1651 									switch(this->game->getGameSettings()->getPathFinderType()) {
1652 										case pfBasic:
1653 											tsValue = pathFinder->findPath(unit, targetPos, &wasStuck, frameIndex);
1654 											if (tsValue == tsMoving && frameIndex < 0) {
1655 												unit->setCurrSkill(hct->getMoveSkillType());
1656 												command->setPos(targetPos);
1657 											}
1658 											break;
1659 										default:
1660 											throw megaglest_runtime_error("detected unsupported pathfinder type!");
1661 									}
1662 								}
1663 
1664 								if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1665 
1666 				    			if(wasStuck == true && frameIndex < 0) {
1667 									//if can't harvest, search for another resource
1668 									unit->setCurrSkill(scStop);
1669 									if(searchForResource(unit, hct) == false) {
1670 										unit->finishCommand();
1671 									}
1672 				    			}
1673 							}
1674 		    			}
1675 					}
1676 				}
1677 				else {
1678 					if(frameIndex < 0) {
1679 						//if can't harvest, search for another resource
1680 						unit->setCurrSkill(scStop);
1681 						if(searchForResource(unit, hct) == false) {
1682 							unit->finishCommand();
1683 						}
1684 					}
1685 					if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1686 				}
1687 			}
1688 
1689 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1690 		}
1691 		else {
1692 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1693 
1694 			//if loaded, return to store
1695 			Unit *store= world->nearestStore(unit->getPos(), unit->getFaction()->getIndex(), unit->getLoadType());
1696 			if(store != NULL) {
1697 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
1698 					char szBuf[8096]="";
1699 					snprintf(szBuf,8096,"[updateHarvest #3] unit->getPos() [%s] store->getCenteredPos() [%s]",
1700 							unit->getPos().getString().c_str(),store->getCenteredPos().getString().c_str());
1701 					unit->logSynchData(__FILE__,__LINE__,szBuf);
1702 				}
1703 
1704 				TravelState tsValue = tsImpossible;
1705 	    		switch(this->game->getGameSettings()->getPathFinderType()) {
1706 	    			case pfBasic:
1707 	    				tsValue = pathFinder->findPath(unit, store->getCenteredPos(), NULL, frameIndex);
1708 	    				break;
1709 	    			default:
1710 	    				throw megaglest_runtime_error("detected unsupported pathfinder type!");
1711 	    	    }
1712 
1713 	    		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1714 
1715 	    		if(frameIndex < 0) {
1716 					switch(tsValue) {
1717 					case tsMoving:
1718 						{
1719 						if (hct->canHarvest(unit->getLoadType()) == false) {
1720 							// hct has changed to a different harvest command.
1721 							const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction());
1722 							if(previousHarvestCmd != NULL) {
1723 								//printf("\n\n#1\n\n");
1724 								unit->setCurrSkill(previousHarvestCmd->getMoveLoadedSkillType()); // make sure we use the right harvest animation
1725 							}
1726 							else {
1727 								//printf("\n\n#2\n\n");
1728 								unit->setCurrSkill(hct->getMoveLoadedSkillType());
1729 							}
1730 						}
1731 						else {
1732 							unit->setCurrSkill(hct->getMoveLoadedSkillType());
1733 						}
1734 						}
1735 						break;
1736 					default:
1737 						break;
1738 					}
1739 
1740 					//world->changePosCells(unit,unit->getPos()+unit->getDest());
1741 					if(map->isNextTo(unit, store)) {
1742 						//update resources
1743 						int resourceAmount= unit->getLoadCount();
1744 						if(unit->getFaction()->getCpuControl())
1745 						{
1746 							int resourceMultiplierIndex=game->getGameSettings()->getResourceMultiplierIndex(unit->getFaction()->getIndex());
1747 							resourceAmount=(resourceAmount* (resourceMultiplierIndex +5))/10;
1748 						}
1749 						unit->getFaction()->incResourceAmount(unit->getLoadType(), resourceAmount);
1750 						world->getStats()->harvest(unit->getFactionIndex(), resourceAmount);
1751 
1752 						scriptManager->onResourceHarvested();
1753 
1754 						//if next to a store unload resources
1755 						unit->getPath()->clear();
1756 						unit->setCurrSkill(scStop);
1757 						unit->setLoadCount(0);
1758 
1759 						command->setPosToOriginalPos();
1760 					}
1761 	    		}
1762 	    		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1763 			}
1764 			else {
1765 				if(frameIndex < 0) {
1766 					unit->finishCommand();
1767 				}
1768 			}
1769 		}
1770 	}
1771 	else {
1772 		if(frameIndex < 0) {
1773 			//if working
1774 			//unit->setLastHarvestResourceTarget(NULL);
1775 
1776 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1777 
1778 			const Vec2i unitTargetPos = unit->getTargetPos();
1779 			SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unitTargetPos));
1780 			Resource *r= sc->getResource();
1781 
1782 			if (r != NULL) {
1783 				if (hct->canHarvest(r->getType()) == false ||
1784 					r->getType()->getName() != unit->getLoadType()->getName()) {
1785 					// hct has changed to a different harvest command.
1786 					if(r->getType()->getName() != unit->getLoadType()->getName()) {
1787 						const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction());
1788 						if(previousHarvestCmd != NULL) {
1789 							//printf("\n\n#1\n\n");
1790 							unit->setCurrSkill(previousHarvestCmd->getStopLoadedSkillType()); // make sure we use the right harvest animation
1791 						}
1792 						else {
1793 							//printf("\n\n#2\n\n");
1794 							unit->setCurrSkill(hct->getStopLoadedSkillType());
1795 						}
1796 					}
1797 					else if(hct->canHarvest(r->getType()) == false) {
1798 						const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction());
1799 						if(previousHarvestCmd != NULL) {
1800 							//printf("\n\n#3\n\n");
1801 							unit->setCurrSkill(previousHarvestCmd->getStopLoadedSkillType()); // make sure we use the right harvest animation
1802 						}
1803 						else {
1804 							//printf("\n\n#4\n\n");
1805 							unit->setCurrSkill(hct->getStopLoadedSkillType());
1806 						}
1807 					}
1808 					else {
1809 						//printf("\n\n#5 [%s] [%s]\n\n",r->getType()->getName().c_str(),unit->getLoadType()->getName().c_str());
1810 						unit->setCurrSkill(hct->getStopLoadedSkillType()); // this is actually the wrong animation
1811 					}
1812 					unit->getPath()->clear();
1813 
1814 					if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1815 				}
1816 				else {
1817 					// if there is a resource, continue working, until loaded
1818 					unit->update2();
1819 
1820 					unit->setLastHarvestedResourcePos(unitTargetPos);
1821 
1822 					if (unit->getProgress2() >= hct->getHitsPerUnit()) {
1823 						if (unit->getLoadCount() < hct->getMaxLoad()) {
1824 							unit->setProgress2(0);
1825 							unit->setLoadCount(unit->getLoadCount() + 1);
1826 
1827 							//if resource exausted, then delete it and stop
1828 							if (sc->decAmount(1)) {
1829 								//const ResourceType *rt = r->getType();
1830 								sc->deleteResource();
1831 								world->removeResourceTargetFromCache(unitTargetPos);
1832 
1833 								switch(this->game->getGameSettings()->getPathFinderType()) {
1834 									case pfBasic:
1835 										break;
1836 									default:
1837 										throw megaglest_runtime_error("detected unsupported pathfinder type!");
1838 								}
1839 
1840 								//printf("\n\n#6\n\n");
1841 								unit->setCurrSkill(hct->getStopLoadedSkillType());
1842 							}
1843 						}
1844 
1845 						if (unit->getLoadCount() >= hct->getMaxLoad()) {
1846 							//printf("\n\n#7\n\n");
1847 							unit->setCurrSkill(hct->getStopLoadedSkillType());
1848 							unit->getPath()->clear();
1849 						}
1850 					}
1851 
1852 					if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1853 				}
1854 			}
1855 			else {
1856 				//if there is no resource, just stop
1857 				//printf("\n\n#8\n\n");
1858 				unit->setCurrSkill(hct->getStopLoadedSkillType());
1859 			}
1860 		}
1861 	}
1862 
1863 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1864 
1865 	}
1866 	catch(const exception &ex) {
1867 		//setRunningStatus(false);
1868 
1869 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
1870 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1871 
1872 		throw megaglest_runtime_error(ex.what());
1873 	}
1874 	catch(...) {
1875 		char szBuf[8096]="";
1876 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
1877 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
1878 		throw megaglest_runtime_error(szBuf);
1879 	}
1880 
1881 }
1882 
SwapActiveCommand(Unit * unitSrc,Unit * unitDest)1883 void UnitUpdater::SwapActiveCommand(Unit *unitSrc, Unit *unitDest) {
1884 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1885 
1886 	if(unitSrc->getCommandSize() > 0 && unitDest->getCommandSize() > 0) {
1887 		if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1888 
1889 		Command *cmd1 = unitSrc->getCurrCommand();
1890 		Command *cmd2 = unitDest->getCurrCommand();
1891 		unitSrc->replaceCurrCommand(cmd2);
1892 		unitDest->replaceCurrCommand(cmd1);
1893 	}
1894 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1895 }
1896 
SwapActiveCommandState(Unit * unit,CommandStateType commandStateType,const CommandType * commandType,int originalValue,int newValue)1897 void UnitUpdater::SwapActiveCommandState(Unit *unit, CommandStateType commandStateType,
1898 										const CommandType *commandType,
1899 										int originalValue,int newValue) {
1900 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1901 
1902 	if(commandStateType == cst_linkedUnit) {
1903 		if(dynamic_cast<const BuildCommandType *>(commandType) != NULL) {
1904 
1905 			for(int i = 0; i < unit->getFaction()->getUnitCount(); ++i) {
1906 				Unit *peerUnit = unit->getFaction()->getUnit(i);
1907 				if(peerUnit != NULL) {
1908 					if(peerUnit->getCommandSize() > 0 ) {
1909 						if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1910 
1911 						Command *peerCommand = peerUnit->getCurrCommand();
1912 						//const BuildCommandType *bct = dynamic_cast<const BuildCommandType*>(peerCommand->getCommandType());
1913 						//if(bct != NULL) {
1914 						if(peerCommand != NULL) {
1915 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1916 
1917 							//if(command->getPos() == peerCommand->getPos()) {
1918 							if( peerCommand->getStateType() == commandStateType &&
1919 									peerCommand->getStateValue() == originalValue) {
1920 								if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1921 
1922 								peerCommand->setStateValue(newValue);
1923 							}
1924 						}
1925 					}
1926 				}
1927 			}
1928 
1929 		}
1930 	}
1931 
1932 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1933 }
1934 
findPeerUnitBuilder(Unit * unit)1935 Unit * UnitUpdater::findPeerUnitBuilder(Unit *unit) {
1936 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1937 
1938     Unit *foundUnitBuilder = NULL;
1939     if(unit->getCommandSize() > 0 ) {
1940 		Command *command = unit->getCurrCommand();
1941 		if(command != NULL) {
1942 			const RepairCommandType *rct= dynamic_cast<const RepairCommandType*>(command->getCommandType());
1943 			if(rct != NULL && command->getStateType() == cst_linkedUnit) {
1944 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] looking for command->getStateValue() = %d\n",__FILE__,__FUNCTION__,__LINE__,command->getStateValue());
1945 
1946                 Unit *firstLinkedPeerRepairer = NULL;
1947 
1948 				for(int i = 0; i < unit->getFaction()->getUnitCount(); ++i) {
1949 					Unit *peerUnit = unit->getFaction()->getUnit(i);
1950 					if(peerUnit != NULL) {
1951 						if(peerUnit->getCommandSize() > 0 ) {
1952 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1953 
1954 							Command *peerCommand = peerUnit->getCurrCommand();
1955 							const BuildCommandType *bct = dynamic_cast<const BuildCommandType*>(peerCommand->getCommandType());
1956 							if(bct != NULL) {
1957 								if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1958 
1959 								if(command->getStateValue() == peerUnit->getId()) {
1960 									if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1961 
1962 									foundUnitBuilder = peerUnit;
1963 									break;
1964 								}
1965 							}
1966 							else {
1967 								if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] **peer NOT building**, peerUnit = [%s]\n",__FILE__,__FUNCTION__,__LINE__,peerUnit->toString(false).c_str());
1968 
1969 							    if(firstLinkedPeerRepairer == NULL) {
1970                                     const RepairCommandType *prct = dynamic_cast<const RepairCommandType*>(peerCommand->getCommandType());
1971                                     if(prct != NULL) {
1972                                     	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1973 
1974                                         if(unit->getId() != peerUnit->getId() && command->getStateValue() == peerUnit->getId()) {
1975                                         	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1976 
1977                                             firstLinkedPeerRepairer = peerUnit;
1978                                         }
1979                                     }
1980 							    }
1981 							}
1982 						}
1983 					}
1984 				}
1985 
1986 				if(foundUnitBuilder == NULL && firstLinkedPeerRepairer != NULL) {
1987 				    foundUnitBuilder = firstLinkedPeerRepairer;
1988 				}
1989 			}
1990 		}
1991     }
1992 
1993     if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] returning foundUnitBuilder = [%s]\n",__FILE__,__FUNCTION__,__LINE__,(foundUnitBuilder != NULL ? foundUnitBuilder->toString(false).c_str() : "null"));
1994 
1995     return foundUnitBuilder;
1996 }
1997 
1998 // ==================== updateRepair ====================
1999 
updateRepair(Unit * unit,int frameIndex)2000 void UnitUpdater::updateRepair(Unit *unit, int frameIndex) {
2001 	try {
2002 
2003 	// Nothing to do
2004 	if(frameIndex >= 0) {
2005 		clearUnitPrecache(unit);
2006 		return;
2007 	}
2008 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
2009 		char szBuf[8096]="";
2010 		snprintf(szBuf,8096,"[updateRepair]");
2011 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
2012 	}
2013 
2014 	Chrono chrono;
2015 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
2016 
2017 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit = %p\n",__FILE__,__FUNCTION__,__LINE__,unit);
2018 
2019 	//if(unit != NULL) {
2020 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit doing the repair [%s] - %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getFullName(false).c_str(),unit->getId());
2021 	//}
2022     Command *command= unit->getCurrCommand();
2023     if(command == NULL) {
2024     	throw megaglest_runtime_error("command == NULL");
2025     }
2026 
2027     const RepairCommandType *rct= static_cast<const RepairCommandType*>(command->getCommandType());
2028     const CommandType *ct = (command != NULL ? command->getCommandType() : NULL);
2029 
2030     if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] rct = %p\n",__FILE__,__FUNCTION__,__LINE__,rct);
2031 
2032 	Unit *repaired = (command != NULL ? map->getCell(command->getPos())->getUnitWithEmptyCellMap(fLand) : NULL);
2033 	if(repaired == NULL && command != NULL) {
2034 		repaired = map->getCell(command->getPos())->getUnit(fLand);
2035 	}
2036 
2037 	if(repaired != NULL) {
2038 		if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit to repair [%s] - %d\n",__FILE__,__FUNCTION__,__LINE__,repaired->getFullName(false).c_str(),repaired->getId());
2039 	}
2040 
2041 	if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2042 
2043 	// Check if the 'repaired' unit is actually the peer unit in a multi-build?
2044 	Unit *peerUnitBuilder = findPeerUnitBuilder(unit);
2045 
2046 	if(peerUnitBuilder != NULL) {
2047 		SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit peer [%s] - %d\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder->getFullName(false).c_str(),peerUnitBuilder->getId());
2048 	}
2049 
2050 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2051 
2052 	// Ensure we have the right unit to repair
2053 	if(peerUnitBuilder != NULL) {
2054 		if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] peerUnitBuilder = %p\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder);
2055 
2056 		if(peerUnitBuilder->getCurrCommand()->getUnit() != NULL) {
2057 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] peerbuilder's unitid = %d\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder->getCurrCommand()->getUnit()->getId());
2058 			repaired = peerUnitBuilder->getCurrCommand()->getUnit();
2059 		}
2060 	}
2061 
2062 	bool nextToRepaired = repaired != NULL && map->isNextTo(unit, repaired);
2063 
2064 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2065 
2066 	peerUnitBuilder = NULL;
2067 	if(repaired == NULL) {
2068 		peerUnitBuilder = findPeerUnitBuilder(unit);
2069 		if(peerUnitBuilder != NULL) {
2070 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] peerUnitBuilder = %p\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder);
2071 
2072 			if(peerUnitBuilder->getCurrCommand()->getUnit() != NULL) {
2073 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] peerbuilder's unitid = %d\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder->getCurrCommand()->getUnit()->getId());
2074 				repaired = peerUnitBuilder->getCurrCommand()->getUnit();
2075 				nextToRepaired = repaired != NULL && map->isNextTo(unit, repaired);
2076 			}
2077 			else if(peerUnitBuilder->getCurrCommand()->getUnitType() != NULL) {
2078 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2079 				Vec2i buildPos = map->findBestBuildApproach(unit, command->getPos(), peerUnitBuilder->getCurrCommand()->getUnitType());
2080 
2081 				//nextToRepaired= (unit->getPos() == (command->getPos()-Vec2i(1)));
2082 				nextToRepaired = (unit->getPos() == buildPos);
2083 
2084 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] peerUnitBuilder = %p, nextToRepaired = %d\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder,nextToRepaired);
2085 
2086 				if(nextToRepaired == true) {
2087 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2088 					Command *peerCommand = peerUnitBuilder->getCurrCommand();
2089 					const RepairCommandType *rct = dynamic_cast<const RepairCommandType*>(peerCommand->getCommandType());
2090 					// If the peer is also scheduled to do a repair we CANNOT swap their commands or
2091 					// it will result in a stack overflow as each swaps the others repair command.
2092 					// We must convert this unit's repair into a build right now!
2093 					if(rct != NULL) {
2094 						if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2095 
2096 						const CommandType *ctbuild = unit->getType()->getFirstCtOfClass(ccBuild);
2097 						NetworkCommand networkCommand(this->world,nctGiveCommand, unit->getId(), ctbuild->getId(), command->getPos(),
2098 														command->getUnitType()->getId(), -1, CardinalDir::NORTH, true, command->getStateType(),
2099 														command->getStateValue());
2100 
2101 						if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2102 
2103 						Command* command= this->game->getCommander()->buildCommand(&networkCommand);
2104 						std::pair<CommandResult,string> cr= unit->checkCommand(command);
2105 						if(cr.first == crSuccess) {
2106 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2107 							unit->replaceCurrCommand(command);
2108 						}
2109 						else {
2110 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2111 							delete command;
2112 
2113 							unit->setCurrSkill(scStop);
2114 							unit->finishCommand();
2115 						}
2116 					}
2117 					else {
2118 						CommandStateType commandStateType = unit->getCurrCommand()->getStateType();
2119 						SwapActiveCommand(unit,peerUnitBuilder);
2120 						int oldPeerUnitId = peerUnitBuilder->getId();
2121 						int newPeerUnitId = unit->getId();
2122 						SwapActiveCommandState(unit,commandStateType,unit->getCurrCommand()->getCommandType(),oldPeerUnitId,newPeerUnitId);
2123 
2124 						// Give the swapped unit a fresh chance to help build in case they
2125 						// were or are about to be blocked
2126 						peerUnitBuilder->getPath()->clear();
2127 						peerUnitBuilder->setRetryCurrCommandCount(1);
2128 						updateUnitCommand(unit,-1);
2129 					}
2130 					return;
2131 				}
2132 			}
2133 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2134 		}
2135 	}
2136 	else {
2137 		if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit to repair[%s]\n",__FILE__,__FUNCTION__,__LINE__,repaired->getFullName(false).c_str());
2138 	}
2139 
2140 	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] repaired = %p, nextToRepaired = %d, unit->getCurrSkill()->getClass() = %d\n",__FILE__,__FUNCTION__,__LINE__,repaired,nextToRepaired,unit->getCurrSkill()->getClass());
2141 
2142 	//UnitPathInterface *path= unit->getPath();
2143 	if(unit->getCurrSkill()->getClass() != scRepair ||
2144 		(nextToRepaired == false && peerUnitBuilder == NULL)) {
2145 
2146 		if(command == NULL) {
2147 			throw megaglest_runtime_error("command == NULL");
2148 		}
2149 		Vec2i repairPos = command->getPos();
2150 		bool startRepairing = (repaired != NULL && rct->isRepairableUnitType(repaired->getType()) && repaired->isDamaged());
2151 
2152 		if(startRepairing == true) {
2153 			//printf("STARTING REPAIR, unit [%s - %d] for unit [%s - %d]\n",unit->getType()->getName().c_str(),unit->getId(),repaired->getType()->getName().c_str(),repaired->getId());
2154 //			for(unsigned int i = 0; i < rct->getRepairCount(); ++i) {
2155 //				const UnitType *rUnit = rct->getRepair(i);
2156 //				printf("Can repair unittype [%s]\n",rUnit->getName().c_str());
2157 //			}
2158 		}
2159 
2160 		if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] repairPos = %s, startRepairing = %d\n",__FILE__,__FUNCTION__,__LINE__,repairPos.getString().c_str(),startRepairing);
2161 
2162 		if(startRepairing == false && peerUnitBuilder != NULL) {
2163 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2164 			startRepairing = true;
2165 			// Since the unit to be built is not yet existing we need to tell the
2166 			// other units to move to the build position or else they get in the way
2167 
2168 			// No need to adjust repair pos since we already did this above via: Vec2i buildPos = map->findBestBuildApproach(unit->getPos(), command->getPos(), peerUnitBuilder->getCurrCommand()->getUnitType());
2169 			//repairPos = command->getPos()-Vec2i(1);
2170 		}
2171 
2172         //if not repairing
2173         if(startRepairing == true) {
2174         	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2175 
2176 			if(nextToRepaired == true) {
2177 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2178 				unit->setTarget(repaired);
2179 				unit->setCurrSkill(rct->getRepairSkillType());
2180 			}
2181 			else {
2182 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2183 
2184 				if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
2185 					char szBuf[8096]="";
2186 					snprintf(szBuf,8096,"[updateRepair] unit->getPos() [%s] command->getPos()() [%s] repairPos [%s]",unit->getPos().getString().c_str(),command->getPos().getString().c_str(),repairPos.getString().c_str());
2187 					unit->logSynchData(__FILE__,__LINE__,szBuf);
2188 				}
2189 
2190 				if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2191 
2192 				// If the repair command has no move skill and we are not next to
2193 				// the unit we cannot repair it
2194 				if(rct->getMoveSkillType() == NULL) {
2195 					//printf("CANCEL REPAIR NOT NEXT TO REPAIR UNIT\n");
2196 					//Vec2i repairPos = command->getPos();
2197 					//bool startRepairing = (repaired != NULL && rct->isRepairableUnitType(repaired->getType()) && repaired->isDamaged());
2198 					//bool nextToRepaired = repaired != NULL && map->isNextTo(unit, repaired);
2199 
2200 					//printf("repairPos [%s] startRepairing = %d nextToRepaired = %d unit->getPos() [%s] repaired->getPos() [%s]\n",repairPos.getString().c_str(),startRepairing,nextToRepaired,unit->getPos().getString().c_str(),repaired->getPos().getString().c_str());
2201 
2202 					console->addStdMessage("InvalidPosition");
2203 					unit->setCurrSkill(scStop);
2204 					unit->finishCommand();
2205 				}
2206 				else {
2207 					TravelState ts;
2208 					switch(this->game->getGameSettings()->getPathFinderType()) {
2209 						case pfBasic:
2210 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2211 
2212 							ts = pathFinder->findPath(unit, repairPos, NULL, frameIndex);
2213 							break;
2214 						default:
2215 							throw megaglest_runtime_error("detected unsupported pathfinder type!");
2216 					}
2217 
2218 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] ts = %d\n",__FILE__,__FUNCTION__,__LINE__,ts);
2219 
2220 					if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2221 
2222 					switch(ts) {
2223 					case tsMoving:
2224 						if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsMoving\n",__FILE__,__FUNCTION__,__LINE__);
2225 						unit->setCurrSkill(rct->getMoveSkillType());
2226 						break;
2227 					case tsBlocked:
2228 						if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsBlocked\n",__FILE__,__FUNCTION__,__LINE__);
2229 						if(unit->getPath()->isBlocked()) {
2230 							if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__);
2231 
2232 							if(unit->getRetryCurrCommandCount() > 0) {
2233 								if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] will retry command, unit->getRetryCurrCommandCount() = %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getRetryCurrCommandCount());
2234 								unit->setRetryCurrCommandCount(0);
2235 								unit->getPath()->clear();
2236 								updateUnitCommand(unit,-1);
2237 							}
2238 							else {
2239 								unit->finishCommand();
2240 							}
2241 						}
2242 						break;
2243 					default:
2244 						break;
2245 					}
2246 				}
2247 			}
2248         }
2249         else {
2250         	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__);
2251 
2252         	//console->addStdMessage("InvalidPosition");
2253        		unit->setCurrSkill(scStop);
2254        		unit->finishCommand();
2255        		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2256         }
2257     }
2258     else {
2259     	if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2260 		bool cancelRepair = false;
2261     	//if repairing
2262 		if(repaired != NULL) {
2263 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2264 			// Check if we can still repair the unit (may have morphed, etc)
2265 			bool canStillRepair = rct->isRepairableUnitType(repaired->getType());
2266 			if(canStillRepair == true) {
2267 				unit->setTarget(repaired);
2268 
2269 			}
2270 			else {
2271 				//printf("CANCELLING CURRENT REPAIR, unit [%s - %d] for unit [%s - %d]\n",unit->getType()->getName().c_str(),unit->getId(),repaired->getType()->getName().c_str(),repaired->getId());
2272 //				for(unsigned int i = 0; i < rct->getRepairCount(); ++i) {
2273 //					const UnitType *rUnit = rct->getRepair(i);
2274 //					printf("Can repair unittype [%s]\n",rUnit->getName().c_str());
2275 //				}
2276 				unit->setCurrSkill(scStop);
2277 				unit->finishCommand();
2278 				cancelRepair = true;
2279 			}
2280 		}
2281 		else if(peerUnitBuilder != NULL) {
2282 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2283 			unit->setTargetPos(command->getPos());
2284 		}
2285 
2286 		if(cancelRepair == false && (repaired == NULL || repaired->repair()) &&
2287 			peerUnitBuilder == NULL) {
2288 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__);
2289 
2290 			unit->setCurrSkill(scStop);
2291 			unit->finishCommand();
2292 
2293 			if(repaired != NULL && repaired->isBuilt() == false) {
2294 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2295 				repaired->born(ct);
2296 				scriptManager->onUnitCreated(repaired);
2297 			}
2298 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2299 		}
2300     }
2301 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2302 
2303 	}
2304 	catch(const exception &ex) {
2305 		//setRunningStatus(false);
2306 
2307 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
2308 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2309 
2310 		throw megaglest_runtime_error(ex.what());
2311 	}
2312 	catch(...) {
2313 		char szBuf[8096]="";
2314 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
2315 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
2316 		throw megaglest_runtime_error(szBuf);
2317 	}
2318 
2319 }
2320 
2321 // ==================== updateProduce ====================
2322 
updateProduce(Unit * unit,int frameIndex)2323 void UnitUpdater::updateProduce(Unit *unit, int frameIndex) {
2324 	try {
2325 
2326 	// Nothing to do
2327 	if(frameIndex >= 0) {
2328 		clearUnitPrecache(unit);
2329 		return;
2330 	}
2331 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
2332 		char szBuf[8096]="";
2333 		snprintf(szBuf,8096,"[updateProduce]");
2334 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
2335 	}
2336 
2337 	Chrono chrono;
2338 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
2339 
2340     Command *command= unit->getCurrCommand();
2341 	if(command == NULL) {
2342 		throw megaglest_runtime_error("command == NULL");
2343 	}
2344 
2345     const ProduceCommandType *pct= static_cast<const ProduceCommandType*>(command->getCommandType());
2346     Unit *produced;
2347 
2348     if(unit->getCurrSkill()->getClass() != scProduce) {
2349         //if not producing
2350         unit->setCurrSkill(pct->getProduceSkillType());
2351     }
2352     else {
2353     	const CommandType *ct = (command != NULL ? command->getCommandType() : NULL);
2354 
2355 		unit->update2();
2356 
2357 		if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2358 
2359         if(unit->getProgress2() > pct->getProduced()->getProductionTime()){
2360             unit->finishCommand();
2361             unit->setCurrSkill(scStop);
2362 
2363 			UnitPathInterface *newpath = NULL;
2364 			switch(this->game->getGameSettings()->getPathFinderType()) {
2365 				case pfBasic:
2366 					newpath = new UnitPathBasic();
2367 					break;
2368 				default:
2369 					throw megaglest_runtime_error("detected unsupported pathfinder type!");
2370 		    }
2371 
2372 			produced= new Unit(world->getNextUnitId(unit->getFaction()), newpath, Vec2i(0), pct->getProducedUnit(), unit->getFaction(), world->getMap(), CardinalDir::NORTH);
2373 
2374 			if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to place unit for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,produced->toString(false).c_str());
2375 
2376 			if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2377 
2378 			//place unit creates the unit
2379 			if(!world->placeUnit(unit->getCenteredPos(), 10, produced, false, frameIndex < 0)) {
2380 				if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] COULD NOT PLACE UNIT for unitID [%d]\n",__FILE__,__FUNCTION__,__LINE__,produced->getId());
2381 				delete produced;
2382 			}
2383 			else{
2384 				produced->create();
2385 				produced->born(ct);
2386 
2387 				world->getStats()->produce(unit->getFactionIndex(),produced->getType()->getCountUnitProductionInStats());
2388 				const CommandType *ct= produced->computeCommandType(unit->getMeetingPos());
2389 				if(ct != NULL) {
2390 					if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2391 					produced->giveCommand(new Command(ct, unit->getMeetingPos()));
2392 				}
2393 				scriptManager->onUnitCreated(produced);
2394 
2395 				if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2396 			}
2397         }
2398     }
2399 
2400     if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2401 
2402 	}
2403 	catch(const exception &ex) {
2404 		//setRunningStatus(false);
2405 
2406 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
2407 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2408 
2409 		throw megaglest_runtime_error(ex.what());
2410 	}
2411 	catch(...) {
2412 		char szBuf[8096]="";
2413 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN\n",__FILE__,__FUNCTION__,__LINE__);
2414 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
2415 		throw megaglest_runtime_error(szBuf);
2416 	}
2417 
2418 }
2419 
2420 
2421 // ==================== updateUpgrade ====================
2422 
updateUpgrade(Unit * unit,int frameIndex)2423 void UnitUpdater::updateUpgrade(Unit *unit, int frameIndex) {
2424 	try {
2425 
2426 	// Nothing to do
2427 	if(frameIndex >= 0) {
2428 		clearUnitPrecache(unit);
2429 		return;
2430 	}
2431 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
2432 		char szBuf[8096]="";
2433 		snprintf(szBuf,8096,"[updateUpgrade]");
2434 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
2435 	}
2436 
2437 	Chrono chrono;
2438 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
2439 
2440     Command *command= unit->getCurrCommand();
2441 	if(command == NULL) {
2442 		throw megaglest_runtime_error("command == NULL");
2443 	}
2444 
2445     const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(command->getCommandType());
2446 
2447 	if(unit->getCurrSkill()->getClass() != scUpgrade) {
2448 		//if not producing
2449 		unit->setCurrSkill(uct->getUpgradeSkillType());
2450     }
2451 	else {
2452 		//if producing
2453 		unit->update2();
2454         if(unit->getProgress2() > uct->getProduced()->getProductionTime()){
2455             unit->finishCommand();
2456             unit->setCurrSkill(scStop);
2457 			unit->getFaction()->finishUpgrade(uct->getProducedUpgrade());
2458         }
2459     }
2460 
2461 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2462 
2463 	}
2464 	catch(const exception &ex) {
2465 		//setRunningStatus(false);
2466 
2467 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
2468 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2469 
2470 		throw megaglest_runtime_error(ex.what());
2471 	}
2472 	catch(...) {
2473 		char szBuf[8096]="";
2474 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
2475 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
2476 		throw megaglest_runtime_error(szBuf);
2477 	}
2478 
2479 }
2480 
2481 // ==================== updateMorph ====================
2482 
updateMorph(Unit * unit,int frameIndex)2483 void UnitUpdater::updateMorph(Unit *unit, int frameIndex) {
2484 	try {
2485 
2486 	// Nothing to do
2487 	if(frameIndex >= 0) {
2488 		clearUnitPrecache(unit);
2489 		return;
2490 	}
2491 	if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) {
2492 		char szBuf[8096]="";
2493 		snprintf(szBuf,8096,"[updateMorph]");
2494 		unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf);
2495 	}
2496 
2497 	Chrono chrono;
2498 	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
2499 
2500 	Command *command= unit->getCurrCommand();
2501 	if(command == NULL) {
2502 		throw megaglest_runtime_error("command == NULL");
2503 	}
2504 
2505     const MorphCommandType *mct= static_cast<const MorphCommandType*>(command->getCommandType());
2506 
2507     if(unit->getCurrSkill()->getClass()!=scMorph){
2508 		//if not morphing, check space
2509 		if(map->canMorph(unit->getPos(),unit,mct->getMorphUnit())){
2510 			unit->setCurrSkill(mct->getMorphSkillType());
2511 			// block space for morphing units ( block space before and after morph ! )
2512 			map->putUnitCells(unit, unit->getPos(), false, frameIndex < 0);
2513 		}
2514 		else{
2515 			if(unit->getFactionIndex()==world->getThisFactionIndex()){
2516 				console->addStdMessage("InvalidPosition");
2517 			}
2518 			unit->cancelCommand();
2519 		}
2520     }
2521     else{
2522 		unit->update2();
2523         if(unit->getProgress2() > mct->getProduced()->getProductionTime()){
2524 			//int oldSize = 0;
2525 			//bool needMapUpdate = false;
2526 
2527     		switch(this->game->getGameSettings()->getPathFinderType()) {
2528     			case pfBasic:
2529     				break;
2530     			default:
2531     				throw megaglest_runtime_error("detected unsupported pathfinder type!");
2532     	    }
2533 
2534 			//finish the command
2535 			if(unit->morph(mct, frameIndex)){
2536 				unit->finishCommand();
2537 				if(gui->isSelected(unit)){
2538 					gui->onSelectionChanged();
2539 				}
2540 	    		switch(this->game->getGameSettings()->getPathFinderType()) {
2541 	    			case pfBasic:
2542 	    				break;
2543 	    			default:
2544 	    				throw megaglest_runtime_error("detected unsupported pathfinder type!");
2545 	    	    }
2546 
2547 				scriptManager->onUnitCreated(unit);
2548 			}
2549 			else{
2550 				unit->cancelCommand();
2551 				if(unit->getFactionIndex()==world->getThisFactionIndex()){
2552 					console->addStdMessage("InvalidPosition");
2553 				}
2554 			}
2555 			unit->setCurrSkill(scStop);
2556 
2557         }
2558     }
2559 
2560     if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
2561 
2562 	}
2563 	catch(const exception &ex) {
2564 		//setRunningStatus(false);
2565 
2566 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
2567 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
2568 
2569 		throw megaglest_runtime_error(ex.what());
2570 	}
2571 	catch(...) {
2572 		char szBuf[8096]="";
2573 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
2574 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
2575 		throw megaglest_runtime_error(szBuf);
2576 	}
2577 
2578 }
2579 
2580 
2581 // ==================== updateMove ====================
updateSwitchTeam(Unit * unit,int frameIndex)2582 void UnitUpdater::updateSwitchTeam(Unit *unit, int frameIndex) {
2583 }
2584 
2585 // ==================== updateAttack ====================
2586 
2587 // ==================== PRIVATE ====================
2588 
2589 // ==================== attack ====================
2590 
hit(Unit * attacker)2591 void UnitUpdater::hit(Unit *attacker){
2592 	hit(attacker, dynamic_cast<const AttackSkillType*>(attacker->getCurrSkill()), attacker->getTargetPos(), attacker->getTargetField(),100);
2593 }
2594 
hit(Unit * attacker,const AttackSkillType * ast,const Vec2i & targetPos,Field targetField,int damagePercent)2595 void UnitUpdater::hit(Unit *attacker, const AttackSkillType* ast, const Vec2i &targetPos, Field targetField, int damagePercent){
2596 	//hit attack positions
2597 	if(ast != NULL && ast->getSplash()) {
2598 		char szBuf[8096]="";
2599 		snprintf(szBuf,8095,"Unit hitting [UnitUpdater::hit] hasSplash = %d radius = %d damageall = %d",ast->getSplash(),ast->getSplashRadius(),ast->getSplashDamageAll());
2600 		attacker->addNetworkCRCDecHp(szBuf);
2601 
2602 		PosCircularIterator pci(map, targetPos, ast->getSplashRadius());
2603 		while(pci.next()) {
2604 			Unit *attacked= map->getCell(pci.getPos())->getUnit(targetField);
2605 			if(attacked != NULL) {
2606 				if(ast->getSplashDamageAll() ||
2607 						attacker->isAlly(attacked) == false ||
2608 						( targetPos.x == pci.getPos().x && targetPos.y == pci.getPos().y )) {
2609 
2610 					attacker->setLastAttackedUnitId(attacked->getId());
2611 					scriptManager->onUnitAttacking(attacker);
2612 
2613 					float distance = pci.getPos().dist(targetPos);
2614 					distance = truncateDecimal<float>(distance,6);
2615 					damage(attacker, ast, attacked, distance,damagePercent);
2616 			  	}
2617 			}
2618 		}
2619 	}
2620 	else {
2621 		Unit *attacked= map->getCell(targetPos)->getUnit(targetField);
2622 
2623 		char szBuf[8096]="";
2624 		snprintf(szBuf,8095,"Unit hitting [UnitUpdater::hit 2] attacked = %d",(attacked != NULL ? attacked->getId() : -1));
2625 		attacker->addNetworkCRCDecHp(szBuf);
2626 
2627 		if(attacked != NULL) {
2628 			damage(attacker, ast, attacked, 0.f,damagePercent);
2629 		}
2630 	}
2631 }
2632 
damage(Unit * attacker,const AttackSkillType * ast,Unit * attacked,float distance,int damagePercent)2633 void UnitUpdater::damage(Unit *attacker, const AttackSkillType* ast, Unit *attacked, float distance, int damagePercent) {
2634 	if(attacker == NULL) {
2635 		throw megaglest_runtime_error("attacker == NULL");
2636 	}
2637 	if(ast == NULL) {
2638 		throw megaglest_runtime_error("ast == NULL");
2639 	}
2640 	if(attacked == NULL) {
2641 		throw megaglest_runtime_error("attacked == NULL");
2642 	}
2643 
2644 	//get vars
2645 	float damage			= ast->getTotalAttackStrength(attacker->getTotalUpgrade());
2646 	int var					= ast->getAttackVar();
2647 	int armor				= attacked->getType()->getTotalArmor(attacked->getTotalUpgrade());
2648 	float damageMultiplier	= world->getTechTree()->getDamageMultiplier(ast->getAttackType(), attacked->getType()->getArmorType());
2649 	damageMultiplier = truncateDecimal<float>(damageMultiplier,6);
2650 
2651 	//compute damage
2652 	//damage += random.randRange(-var, var);
2653 	damage += attacker->getRandom()->randRange(-var, var, extractFileFromDirectoryPath(__FILE__) + intToStr(__LINE__));
2654 	damage /= distance+1;
2655 	damage -= armor;
2656 	damage *= damageMultiplier;
2657 	damage = truncateDecimal<float>(damage,6);
2658 
2659 	damage = (damage*damagePercent)/100;
2660 	if(damage < 1) {
2661 		damage= 1;
2662 	}
2663 	int damageVal = static_cast<int>(damage);
2664 
2665 	attacked->setLastAttackerUnitId(attacker->getId());
2666 
2667 	char szBuf[8096]="";
2668 	snprintf(szBuf,8095,"Unit hitting [UnitUpdater::damage] damageVal = %d",damageVal);
2669 	attacker->addNetworkCRCDecHp(szBuf);
2670 
2671 	//damage the unit
2672 	if(attacked->decHp(damageVal)) {
2673 		world->getStats()->kill(attacker->getFactionIndex(), attacked->getFactionIndex(), attacker->getTeam() != attacked->getTeam(),attacked->getType()->getCountUnitDeathInStats(),attacked->getType()->getCountUnitKillInStats());
2674 		if(attacked->getType()->getCountKillForUnitUpgrade() == true){
2675 			attacker->incKills(attacked->getTeam());
2676 		}
2677 
2678 		// Perform resource looting iff the attack is from a different faction
2679 		if(attacker->getFaction() != attacked->getFaction()) {
2680 			int lootableResourceCount = attacked->getType()->getLootableResourceCount();
2681 			for(int i = 0; i < lootableResourceCount; i++) {
2682 				LootableResource resource = attacked->getType()->getLootableResource(i);
2683 
2684 				// Figure out how much of the resource in question that the attacked unit's faction has
2685 				int factionTotalResource = 0;
2686 				for(int j = 0; j < attacked->getFaction()->getTechTree()->getResourceTypeCount(); j++) {
2687 					if(attacked->getFaction()->getTechTree()->getResourceType(j) == resource.getResourceType()) {
2688 						factionTotalResource = attacked->getFaction()->getResource(j)->getAmount();
2689 						break;
2690 					}
2691 				}
2692 
2693 				if(resource.isNegativeAllowed()) {
2694 					attacked->getFaction()->incResourceAmount(resource.getResourceType(), -(factionTotalResource * resource.getLossFactionPercent() / 100));
2695 					attacked->getFaction()->incResourceAmount(resource.getResourceType(), -resource.getLossValue());
2696 					attacker->getFaction()->incResourceAmount(resource.getResourceType(), factionTotalResource * resource.getAmountFactionPercent() / 100);
2697 					attacker->getFaction()->incResourceAmount(resource.getResourceType(), resource.getAmountValue());
2698 				}
2699 				// Can't take more resources than the faction has, otherwise we end up in the negatives
2700 				else {
2701 					attacked->getFaction()->incResourceAmount(resource.getResourceType(), -(std::min)(factionTotalResource * resource.getLossFactionPercent() / 100, factionTotalResource));
2702 					attacked->getFaction()->incResourceAmount(resource.getResourceType(), -(std::min)(resource.getLossValue(), factionTotalResource));
2703 					attacker->getFaction()->incResourceAmount(resource.getResourceType(), (std::min)(factionTotalResource * resource.getAmountFactionPercent() / 100, factionTotalResource));
2704 					attacker->getFaction()->incResourceAmount(resource.getResourceType(), (std::min)(resource.getAmountValue(), factionTotalResource));
2705 				}
2706 			}
2707 		}
2708 
2709 		switch(this->game->getGameSettings()->getPathFinderType()) {
2710 			case pfBasic:
2711 				break;
2712 			default:
2713 				throw megaglest_runtime_error("detected unsupported pathfinder type!");
2714 	    }
2715 
2716 		attacked->setCauseOfDeath(ucodAttacked);
2717 		scriptManager->onUnitDied(attacked);
2718 	}
2719 
2720 	if(attacked->isAlive() == true) {
2721 		scriptManager->onUnitAttacked(attacked);
2722 	}
2723 
2724 	// !!! Is this causing choppy network play somehow?
2725 	//attacker->computeHp();
2726 }
2727 
startAttackParticleSystem(Unit * unit,float lastAnimProgress,float animProgress)2728 void UnitUpdater::startAttackParticleSystem(Unit *unit, float lastAnimProgress, float animProgress){
2729 	Renderer &renderer= Renderer::getInstance();
2730 
2731 	//const AttackSkillType *ast= dynamic_cast<const AttackSkillType*>(unit->getCurrSkill());
2732 	const AttackSkillType *ast= static_cast<const AttackSkillType*>(unit->getCurrSkill());
2733 
2734 	if(ast == NULL) {
2735 		throw megaglest_runtime_error("Start attack particle ast == NULL!");
2736 	}
2737 
2738 	ParticleSystemTypeSplash *pstSplash= ast->getSplashParticleType();
2739 	bool hasProjectile = !ast->projectileTypes.empty();
2740 	Vec3f startPos= unit->getCurrVectorForParticlesystems();
2741 	Vec3f endPos= unit->getTargetVec();
2742 
2743 	//make particle system
2744 	const SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unit->getPos()));
2745 	const SurfaceCell *tsc= map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()));
2746 	bool visible= sc->isVisible(world->getThisTeamIndex()) || tsc->isVisible(world->getThisTeamIndex());
2747 	if(visible == false && world->showWorldForPlayer(world->getThisFactionIndex()) == true) {
2748 		visible = true;
2749 	}
2750 
2751 	//for(ProjectileParticleSystemTypes::const_iterator pit= unit->getCurrSkill()->projectileParticleSystemTypes.begin(); pit != unit->getCurrSkill()->projectileParticleSystemTypes.end(); ++pit) {
2752 	for(ProjectileTypes::const_iterator pt= ast->projectileTypes.begin(); pt != ast->projectileTypes.end(); ++pt) {
2753 		bool startAttackParticleSystemNow = ((*pt)->getAttackStartTime() >= lastAnimProgress && (*pt)->getAttackStartTime() < animProgress);
2754 		if(startAttackParticleSystemNow){
2755 			ProjectileParticleSystem *psProj= (*pt)->getProjectileParticleSystemType()->create(unit);
2756 			psProj->setPath(startPos, endPos);
2757 			psProj->setObserver(new ParticleDamager(unit,(*pt), this, gameCamera));
2758 			psProj->setVisible(visible);
2759 			if(unit->getFaction()->getTexture()) {
2760 				psProj->setFactionColor(unit->getFaction()->getTexture()->getPixmapConst()->getPixel3f(0,0));
2761 			}
2762 			renderer.manageParticleSystem(psProj, rsGame);
2763 			unit->addAttackParticleSystem(psProj);
2764 
2765 			if(pstSplash!=NULL){
2766 				SplashParticleSystem *psSplash= pstSplash->create(unit);
2767 				psSplash->setPos(endPos);
2768 				psSplash->setVisible(visible);
2769 				if(unit->getFaction()->getTexture()) {
2770 					psSplash->setFactionColor(unit->getFaction()->getTexture()->getPixmapConst()->getPixel3f(0,0));
2771 				}
2772 				renderer.manageParticleSystem(psSplash, rsGame);
2773 				unit->addAttackParticleSystem(psSplash);
2774 				psProj->link(psSplash);
2775 			}
2776 		}
2777 	}
2778 
2779 	// if no projectile, still deal damage..
2780 	if(hasProjectile == false) {
2781 		char szBuf[8096]="";
2782 		snprintf(szBuf,8095,"Unit hitting [startAttackParticleSystem] no proj");
2783 		unit->addNetworkCRCDecHp(szBuf);
2784 		hit(unit);
2785 		//splash
2786 		if(pstSplash != NULL) {
2787 			SplashParticleSystem *psSplash= pstSplash->create(unit);
2788 			psSplash->setPos(endPos);
2789 			psSplash->setVisible(visible);
2790 			if(unit->getFaction()->getTexture()) {
2791 				psSplash->setFactionColor(unit->getFaction()->getTexture()->getPixmapConst()->getPixel3f(0,0));
2792 			}
2793 			renderer.manageParticleSystem(psSplash, rsGame);
2794 			unit->addAttackParticleSystem(psSplash);
2795 		}
2796 	}
2797 }
2798 
2799 // ==================== misc ====================
2800 
2801 //looks for a resource of type rt, if rt==NULL looks for any
2802 //resource the unit can harvest
searchForResource(Unit * unit,const HarvestCommandType * hct)2803 bool UnitUpdater::searchForResource(Unit *unit, const HarvestCommandType *hct) {
2804     Vec2i pos= unit->getCurrCommand()->getPos();
2805 
2806     for(int radius= 0; radius < maxResSearchRadius; radius++) {
2807         for(int i = pos.x - radius; i <= pos.x + radius; ++i) {
2808             for(int j=pos.y - radius; j <= pos.y + radius; ++j) {
2809 				if(map->isInside(i, j)) {
2810 					Resource *r= map->getSurfaceCell(Map::toSurfCoords(Vec2i(i, j)))->getResource();
2811                     if(r != NULL) {
2812 						if(hct->canHarvest(r->getType())) {
2813 							const Vec2i newPos = Vec2i(i, j);
2814 							if(unit->isBadHarvestPos(newPos) == false) {
2815 								unit->getCurrCommand()->setPos(newPos);
2816 
2817 								return true;
2818 							}
2819                         }
2820                     }
2821                 }
2822             }
2823         }
2824     }
2825 
2826     return false;
2827 }
2828 
attackerOnSight(Unit * unit,Unit ** rangedPtr,bool evalMode)2829 bool UnitUpdater::attackerOnSight(Unit *unit, Unit **rangedPtr, bool evalMode){
2830 	int range = unit->getType()->getTotalSight(unit->getTotalUpgrade());
2831 	return unitOnRange(unit, range, rangedPtr, NULL,evalMode);
2832 }
2833 
attackableOnSight(Unit * unit,Unit ** rangedPtr,const AttackSkillType * ast,bool evalMode)2834 bool UnitUpdater::attackableOnSight(Unit *unit, Unit **rangedPtr, const AttackSkillType *ast, bool evalMode) {
2835 	int range = unit->getType()->getTotalSight(unit->getTotalUpgrade());
2836 	return unitOnRange(unit, range, rangedPtr, ast, evalMode);
2837 }
2838 
attackableOnRange(Unit * unit,Unit ** rangedPtr,const AttackSkillType * ast,bool evalMode)2839 bool UnitUpdater::attackableOnRange(Unit *unit, Unit **rangedPtr, const AttackSkillType *ast,bool evalMode) {
2840 	int range= ast->getTotalAttackRange(unit->getTotalUpgrade());
2841 	return unitOnRange(unit, range, rangedPtr, ast, evalMode);
2842 }
2843 
findCachedCellsEnemies(Vec2i center,int range,int size,vector<Unit * > & enemies,const AttackSkillType * ast,const Unit * unit,const Unit * commandTarget)2844 bool UnitUpdater::findCachedCellsEnemies(Vec2i center, int range, int size, vector<Unit*> &enemies,
2845 										 const AttackSkillType *ast, const Unit *unit,
2846 										 const Unit *commandTarget) {
2847 	bool result = false;
2848 	MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__));
2849 	std::map<Vec2i, std::map<int, std::map<int, UnitRangeCellsLookupItem > > >::iterator iterFind = UnitRangeCellsLookupItemCache.find(center);
2850 
2851 	if(iterFind != UnitRangeCellsLookupItemCache.end()) {
2852 		std::map<int, std::map<int, UnitRangeCellsLookupItem > >::iterator iterFind3 = iterFind->second.find(size);
2853 		if(iterFind3 != iterFind->second.end()) {
2854 			std::map<int, UnitRangeCellsLookupItem>::iterator iterFind4 = iterFind3->second.find(range);
2855 			if(iterFind4 != iterFind3->second.end()) {
2856 				result = true;
2857 
2858 				std::vector<Cell *> &cellList = iterFind4->second.rangeCellList;
2859 				for(int idx = 0; idx < (int)cellList.size(); ++idx) {
2860 					Cell *cell = cellList[idx];
2861 
2862 					findEnemiesForCell(ast,cell,unit,commandTarget,enemies);
2863 				}
2864 			}
2865 		}
2866 	}
2867 
2868 	return result;
2869 }
2870 
findEnemiesForCell(const AttackSkillType * ast,Cell * cell,const Unit * unit,const Unit * commandTarget,vector<Unit * > & enemies)2871 void UnitUpdater::findEnemiesForCell(const AttackSkillType *ast, Cell *cell, const Unit *unit,
2872 									 const Unit *commandTarget,vector<Unit*> &enemies) {
2873 	//all fields
2874 	for(int k = 0; k < fieldCount; k++) {
2875 		Field f= static_cast<Field>(k);
2876 
2877 		//check field
2878 		if((ast == NULL || ast->getAttackField(f))) {
2879 			Unit *possibleEnemy = cell->getUnit(f);
2880 
2881 			//check enemy
2882 			if(possibleEnemy != NULL && possibleEnemy->isAlive()) {
2883 				if((unit->isAlly(possibleEnemy) == false && commandTarget == NULL) ||
2884 					commandTarget == possibleEnemy) {
2885 
2886 					enemies.push_back(possibleEnemy);
2887 				}
2888 			}
2889 		}
2890 	}
2891 }
2892 
findEnemiesForCell(const Vec2i pos,int size,int sightRange,const Faction * faction,vector<Unit * > & enemies,bool attackersOnly) const2893 void UnitUpdater::findEnemiesForCell(const Vec2i pos, int size, int sightRange, const Faction *faction, vector<Unit*> &enemies, bool attackersOnly) const {
2894 	//all fields
2895 	for(int k = 0; k < fieldCount; k++) {
2896 		Field f= static_cast<Field>(k);
2897 
2898 		for(int i = pos.x - sightRange; i < pos.x + size + sightRange; ++i) {
2899 			for(int j = pos.y - sightRange; j < pos.y + size + sightRange; ++j) {
2900 				Vec2i testPos(i,j);
2901 				if( map->isInside(testPos) &&
2902 						map->isInsideSurface(map->toSurfCoords(testPos))) {
2903 					Cell *cell = map->getCell(testPos);
2904 					//check field
2905 					Unit *possibleEnemy = cell->getUnit(f);
2906 
2907 					//check enemy
2908 					if(possibleEnemy != NULL && possibleEnemy->isAlive()) {
2909 						if(faction->getTeam() != possibleEnemy->getTeam()) {
2910 							if(attackersOnly == true) {
2911 								if(possibleEnemy->getType()->hasCommandClass(ccAttack) || possibleEnemy->getType()->hasCommandClass(ccAttackStopped)) {
2912 									enemies.push_back(possibleEnemy);
2913 								}
2914 							}
2915 							else {
2916 								enemies.push_back(possibleEnemy);
2917 							}
2918 						}
2919 					}
2920 				}
2921 			}
2922 		}
2923 	}
2924 }
2925 
2926 //if the unit has any enemy on range
unitOnRange(Unit * unit,int range,Unit ** rangedPtr,const AttackSkillType * ast,bool evalMode)2927 bool UnitUpdater::unitOnRange(Unit *unit, int range, Unit **rangedPtr,
2928 							  const AttackSkillType *ast,bool evalMode) {
2929 	bool result=false;
2930 
2931 	try {
2932 	vector<Unit*> enemies;
2933     enemies.reserve(100);
2934 
2935 	//we check command target
2936 	const Unit *commandTarget = NULL;
2937 	if(unit->anyCommand() && unit->getCurrCommand() != NULL) {
2938 		commandTarget = static_cast<const Unit*>(unit->getCurrCommand()->getUnit());
2939 	}
2940 	if(commandTarget != NULL && commandTarget->isDead()) {
2941 		commandTarget = NULL;
2942 	}
2943 	//aux vars
2944 	int size 			= unit->getType()->getSize();
2945 	Vec2i center 		= unit->getPos();
2946 	Vec2f floatCenter	= unit->getFloatCenteredPos();
2947 
2948 	//bool foundInCache = true;
2949 	if(findCachedCellsEnemies(center,range,size,enemies,ast,
2950 							  unit,commandTarget) == false) {
2951 
2952 		//foundInCache = false;
2953 		//nearby cells
2954 		UnitRangeCellsLookupItem cacheItem;
2955 		for(int i = center.x - range; i < center.x + range + size; ++i) {
2956 			for(int j = center.y - range; j < center.y + range + size; ++j) {
2957 				//cells inside map and in range
2958 #ifdef USE_STREFLOP
2959 				if(map->isInside(i, j) && streflop::floor(static_cast<streflop::Simple>(floatCenter.dist(Vec2f((float)i, (float)j)))) <= (range+1)){
2960 #else
2961 				if(map->isInside(i, j) && floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)){
2962 #endif
2963 					Cell *cell = map->getCell(i,j);
2964 					findEnemiesForCell(ast,cell,unit,commandTarget,enemies);
2965 
2966 					cacheItem.rangeCellList.push_back(cell);
2967 				}
2968 			}
2969 		}
2970 
2971 
2972 		// Ok update our caches with the latest info
2973 		if(cacheItem.rangeCellList.empty() == false) {
2974 			MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__));
2975 
2976 			UnitRangeCellsLookupItemCache[center][size][range] = cacheItem;
2977 		}
2978 	}
2979 
2980 	//attack enemies that can attack first
2981 	float distToUnit= -1;
2982 	Unit* enemySeen= NULL;
2983 
2984 	float distToStandingUnit= -1;
2985 	Unit* attackingEnemySeen= NULL;
2986 	ControlType controlType= unit->getFaction()->getControlType();
2987 	bool isUltra= controlType == ctCpuUltra || controlType == ctNetworkCpuUltra;
2988 	bool isMega= controlType == ctCpuMega || controlType == ctNetworkCpuMega;
2989 
2990 
2991 	string randomInfoData = "enemies.size() = " + intToStr(enemies.size());
2992 
2993 	//printf("unit %d has control:%d\n",unit->getId(),controlType);
2994     for(int i = 0; i< (int)enemies.size(); ++i) {
2995     	Unit *enemy = enemies[i];
2996 
2997 
2998     	if(enemy != NULL && enemy->isAlive() == true) {
2999 
3000     		// Here we default to first enemy if no attackers found
3001     		if(enemySeen == NULL) {
3002                 *rangedPtr 	= enemy;
3003     			enemySeen 	= enemy;
3004                 result		= true;
3005     		}
3006 
3007     		//randomInfoData += " i = " + intToStr(i) + " alive = true result = " + intToStr(result);
3008 
3009     		// Attackers get first priority
3010     		if(enemy->getType()->hasSkillClass(scAttack) == true) {
3011 
3012     			float currentDist = unit->getCenteredPos().dist(enemy->getCenteredPos());
3013 
3014     			//randomInfoData += " currentDist = " + floatToStr(currentDist);
3015 
3016     			// Select closest attacking unit
3017     			if(distToUnit < 0 ||  currentDist< distToUnit) {
3018     				distToUnit = currentDist;
3019 					*rangedPtr	= enemies[i];
3020 					enemySeen	= enemies[i];
3021 					result		= true;
3022     			}
3023 
3024     			if(isUltra || isMega) {
3025 
3026         			if(distToStandingUnit < 0 || currentDist< distToStandingUnit) {
3027         			    if(enemies[i]->getCurrSkill()!=NULL && enemies[i]->getCurrSkill()->getClass()==scAttack) {
3028         			    	distToStandingUnit = currentDist;
3029         			    	attackingEnemySeen=enemies[i];
3030         			    }
3031         			}
3032     			}
3033     		}
3034     	}
3035     }
3036 
3037     if(evalMode == false && (isUltra || isMega)) {
3038 
3039     	unit->getRandom()->addLastCaller(randomInfoData);
3040 
3041     	if( attackingEnemySeen != NULL && unit->getRandom()->randRange(0,2,extractFileFromDirectoryPath(__FILE__) + intToStr(__LINE__)) != 2 ) {
3042     	//if( attackingEnemySeen != NULL) {
3043     		*rangedPtr 	= attackingEnemySeen;
3044     		enemySeen 	= attackingEnemySeen;
3045     		//printf("Da hat er wen gefunden:%s\n",enemySeen->getType()->getName(false).c_str());
3046     	}
3047     }
3048 
3049 	if(result == true) {
3050 
3051 		//const Unit* teamUnit	= NULL;
3052 		const Unit* enemyUnit	= NULL;
3053 		bool onlyEnemyUnits		= true;
3054 
3055 		if(unit->getTeam() == world->getThisTeamIndex()) {
3056 			//teamUnit		= unit;
3057 			enemyUnit		= enemySeen;
3058 			onlyEnemyUnits	= false;
3059 		}
3060 		else if(enemySeen->getTeam() == world->getThisTeamIndex()) {
3061 			//teamUnit		= enemySeen;
3062 			enemyUnit		= unit;
3063 			onlyEnemyUnits	= false;
3064 		}
3065 
3066 		if(evalMode == false && onlyEnemyUnits == false &&
3067 			enemyUnit->getTeam() != world->getThisTeamIndex()) {
3068 
3069 			Vec2f enemyFloatCenter	= enemyUnit->getFloatCenteredPos();
3070 			// find nearest Attack and cleanup old dates
3071 			AttackWarningData *nearest	= NULL;
3072 			float currentDistance		= 0.f;
3073 			float nearestDistance		= 0.f;
3074 
3075 
3076 			MutexSafeWrapper safeMutex(mutexAttackWarnings,string(__FILE__) + "_" + intToStr(__LINE__));
3077 			for(int i = (int)attackWarnings.size() - 1; i >= 0; --i) {
3078 				if(world->getFrameCount() - attackWarnings[i]->lastFrameCount > 200) { //after 200 frames attack break we warn again
3079 					AttackWarningData *toDelete =attackWarnings[i];
3080 					attackWarnings.erase(attackWarnings.begin()+i);
3081 					delete toDelete; // old one
3082 				}
3083 				else {
3084 #ifdef USE_STREFLOP
3085 					currentDistance = streflop::floor(static_cast<streflop::Simple>(enemyFloatCenter.dist(attackWarnings[i]->attackPosition))); // no need for streflops here!
3086 #else
3087 					currentDistance = floor(enemyFloatCenter.dist(attackWarnings[i]->attackPosition)); // no need for streflops here!
3088 #endif
3089 
3090 					if(nearest == NULL) {
3091 						nearest = attackWarnings[i];
3092 						nearestDistance = currentDistance;
3093 					}
3094 					else {
3095 						if(currentDistance < nearestDistance) {
3096 							nearest = attackWarnings[i];
3097 							nearestDistance = currentDistance;
3098 						}
3099 					}
3100 				}
3101 	    	}
3102 
3103 	    	if(nearest != NULL) {
3104 
3105 	    		// does it fit?
3106 	    		if(nearestDistance < attackWarnRange) {
3107 	    			// update entry with current values
3108 					nearest->lastFrameCount=world->getFrameCount();
3109 					nearest->attackPosition.x=enemyFloatCenter.x;
3110 					nearest->attackPosition.y=enemyFloatCenter.y;
3111 	    		}
3112 	    		else {
3113 	    			//Must be a different Attack!
3114 	    			nearest=NULL;  //set to null to force a new entry in next step
3115 	    		}
3116 	    	}
3117 	    	// add new attack
3118 	    	if(nearest == NULL) {
3119 	    		// no else!
3120 	    		AttackWarningData* awd= new AttackWarningData();
3121 	    		awd->lastFrameCount=world->getFrameCount();
3122 	    		awd->attackPosition.x=enemyFloatCenter.x;
3123 	    		awd->attackPosition.y=enemyFloatCenter.y;
3124 
3125 				MutexSafeWrapper safeMutex(mutexAttackWarnings,string(__FILE__) + "_" + intToStr(__LINE__));
3126 	    		attackWarnings.push_back(awd);
3127 
3128 	    		if(world->getAttackWarningsEnabled() == true) {
3129 
3130 	    			SoundRenderer::getInstance().playFx(CoreData::getInstance().getAttentionSound(),true);
3131 	    			world->addAttackEffects(enemyUnit);
3132 	    		}
3133 	    	}
3134 		}
3135 	}
3136 
3137 	}
3138 	catch(const exception &ex) {
3139 		//setRunningStatus(false);
3140 
3141 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
3142 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
3143 
3144 		throw megaglest_runtime_error(ex.what());
3145 	}
3146 	catch(...) {
3147 		char szBuf[8096]="";
3148 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
3149 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
3150 		throw megaglest_runtime_error(szBuf);
3151 	}
3152 
3153     return result;
3154 }
3155 
3156 
3157 //if the unit has any enemy on range
3158 vector<Unit*> UnitUpdater::enemyUnitsOnRange(const Unit *unit,const AttackSkillType *ast) {
3159 	vector<Unit*> enemies;
3160 	enemies.reserve(100);
3161 
3162 	try {
3163 
3164 
3165 	int range = unit->getType()->getTotalSight(unit->getTotalUpgrade());
3166 	if(ast != NULL) {
3167 
3168 		range = ast->getTotalAttackRange(unit->getTotalUpgrade());
3169 	}
3170 	//we check command target
3171 	const Unit *commandTarget = NULL;
3172 //	if(unit->anyCommand()) {
3173 //		commandTarget = static_cast<const Unit*>(unit->getCurrCommand()->getUnit());
3174 //	}
3175 //	if(commandTarget != NULL && commandTarget->isDead()) {
3176 //		commandTarget = NULL;
3177 //	}
3178 
3179 	//aux vars
3180 	int size 			= unit->getType()->getSize();
3181 	Vec2i center 		= unit->getPosNotThreadSafe();
3182 	Vec2f floatCenter	= unit->getFloatCenteredPos();
3183 
3184 	//bool foundInCache = true;
3185 	if(findCachedCellsEnemies(center,range,size,enemies,ast,
3186 							  unit,commandTarget) == false) {
3187 
3188 		//foundInCache = false;
3189 		//nearby cells
3190 		UnitRangeCellsLookupItem cacheItem;
3191 		for(int i = center.x - range; i < center.x + range + size; ++i) {
3192 			for(int j = center.y - range; j < center.y + range + size; ++j) {
3193 				//cells inside map and in range
3194 #ifdef USE_STREFLOP
3195 				if(map->isInside(i, j) && streflop::floor(static_cast<streflop::Simple>(floatCenter.dist(Vec2f((float)i, (float)j)))) <= (range+1)){
3196 #else
3197 				if(map->isInside(i, j) && floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)){
3198 #endif
3199 					Cell *cell = map->getCell(i,j);
3200 					findEnemiesForCell(ast,cell,unit,commandTarget,enemies);
3201 
3202 					cacheItem.rangeCellList.push_back(cell);
3203 				}
3204 			}
3205 		}
3206 
3207 		// Ok update our caches with the latest info
3208 		if(cacheItem.rangeCellList.empty() == false) {
3209 			MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__));
3210 
3211 			UnitRangeCellsLookupItemCache[center][size][range] = cacheItem;
3212 		}
3213 	}
3214 
3215 	}
3216 	catch(const exception &ex) {
3217 		//setRunningStatus(false);
3218 
3219 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
3220 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
3221 
3222 		throw megaglest_runtime_error(ex.what());
3223 	}
3224 	catch(...) {
3225 		char szBuf[8096]="";
3226 		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
3227 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
3228 		throw megaglest_runtime_error(szBuf);
3229 	}
3230 
3231 	return enemies;
3232 }
3233 
3234 
3235 void UnitUpdater::findUnitsForCell(Cell *cell, vector<Unit*> &units) {
3236 	//all fields
3237 	if(cell != NULL) {
3238 		for(int k = 0; k < fieldCount; k++) {
3239 			Field f= static_cast<Field>(k);
3240 
3241 			//check field
3242 			Unit *cellUnit = cell->getUnit(f);
3243 
3244 			if(cellUnit != NULL && cellUnit->isAlive()) {
3245 				// check if unit already is in list
3246 				bool found = false;
3247 				//printf("---- search for cellUnit=%d\n",cellUnit->getId());
3248 				for (unsigned int i = 0; i < units.size(); ++i) {
3249 					Unit *unitInList = units[i];
3250 					//printf("compare unitInList=%d cellUnit=%d\n",unitInList->getId(),cellUnit->getId());
3251 					if (unitInList->getId() == cellUnit->getId()){
3252 						found=true;
3253 						break;
3254 					}
3255 				}
3256 				if(found==false){
3257 					//printf(">>> adding cellUnit=%d\n",cellUnit->getId());
3258 					units.push_back(cellUnit);
3259 				}
3260 			}
3261 		}
3262 	}
3263 }
3264 
3265 vector<Unit*> UnitUpdater::findUnitsInRange(const Unit *unit, int radius) {
3266 	int range = radius;
3267 	vector<Unit*> units;
3268 
3269 	//aux vars
3270 	int size 			= unit->getType()->getSize();
3271 	Vec2i center 		= unit->getPosNotThreadSafe();
3272 	Vec2f floatCenter	= unit->getFloatCenteredPos();
3273 
3274 	//nearby cells
3275 	//UnitRangeCellsLookupItem cacheItem;
3276 	for(int i = center.x - range; i < center.x + range + size; ++i) {
3277 		for(int j = center.y - range; j < center.y + range + size; ++j) {
3278 			//cells inside map and in range
3279 #ifdef USE_STREFLOP
3280 			if(map->isInside(i, j) && streflop::floor(static_cast<streflop::Simple>(floatCenter.dist(Vec2f((float)i, (float)j)))) <= (range+1)){
3281 #else
3282 			if(map->isInside(i, j) && floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)){
3283 #endif
3284 				Cell *cell = map->getCell(i,j);
3285 				findUnitsForCell(cell,units);
3286 			}
3287 		}
3288 	}
3289 
3290 	return units;
3291 }
3292 
3293 string UnitUpdater::getUnitRangeCellsLookupItemCacheStats() {
3294 	string result = "";
3295 
3296 	int posCount = 0;
3297 	int sizeCount = 0;
3298 	int rangeCount = 0;
3299 	int rangeCountCellCount = 0;
3300 
3301 	MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__));
3302 	for(std::map<Vec2i, std::map<int, std::map<int, UnitRangeCellsLookupItem > > >::iterator iterMap1 = UnitRangeCellsLookupItemCache.begin();
3303 		iterMap1 != UnitRangeCellsLookupItemCache.end(); ++iterMap1) {
3304 		posCount++;
3305 
3306 		for(std::map<int, std::map<int, UnitRangeCellsLookupItem > >::iterator iterMap2 = iterMap1->second.begin();
3307 			iterMap2 != iterMap1->second.end(); ++iterMap2) {
3308 			sizeCount++;
3309 
3310 			for(std::map<int, UnitRangeCellsLookupItem>::iterator iterMap3 = iterMap2->second.begin();
3311 				iterMap3 != iterMap2->second.end(); ++iterMap3) {
3312 				rangeCount++;
3313 
3314 				rangeCountCellCount += (int)iterMap3->second.rangeCellList.size();
3315 			}
3316 		}
3317 	}
3318 
3319 	uint64 totalBytes = rangeCountCellCount * sizeof(Cell *);
3320 	totalBytes /= 1000;
3321 
3322 	char szBuf[8096]="";
3323 	snprintf(szBuf,8096,"pos [%d] size [%d] range [%d][%d] total KB: %s",posCount,sizeCount,rangeCount,rangeCountCellCount,formatNumber(totalBytes).c_str());
3324 	result = szBuf;
3325 	return result;
3326 }
3327 
3328 void UnitUpdater::saveGame(XmlNode *rootNode) {
3329 	std::map<string,string> mapTagReplacements;
3330 	XmlNode *unitupdaterNode = rootNode->addChild("UnitUpdater");
3331 
3332 //	const GameCamera *gameCamera;
3333 //	Gui *gui;
3334 //	Map *map;
3335 //	World *world;
3336 //	Console *console;
3337 //	ScriptManager *scriptManager;
3338 //	PathFinder *pathFinder;
3339 	pathFinder->saveGame(unitupdaterNode);
3340 //	Game *game;
3341 //	RandomGen random;
3342 	//unitupdaterNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements);
3343 //	float attackWarnRange;
3344 	unitupdaterNode->addAttribute("attackWarnRange",floatToStr(attackWarnRange,6), mapTagReplacements);
3345 //	AttackWarnings attackWarnings;
3346 //
3347 }
3348 
3349 void UnitUpdater::clearCaches() {
3350 	 if(pathFinder != NULL) {
3351 		 pathFinder->clearCaches();
3352 	 }
3353 }
3354 
3355 void UnitUpdater::loadGame(const XmlNode *rootNode) {
3356 	const XmlNode *unitupdaterNode = rootNode->getChild("UnitUpdater");
3357 
3358 	pathFinder->loadGame(unitupdaterNode);
3359 	//random.setLastNumber(unitupdaterNode->getAttribute("random")->getIntValue());
3360 //	float attackWarnRange;
3361 	attackWarnRange = unitupdaterNode->getAttribute("attackWarnRange")->getFloatValue();
3362 }
3363 // =====================================================
3364 //	class ParticleDamager
3365 // =====================================================
3366 
3367 ParticleDamager::ParticleDamager(Unit *attacker,const ProjectileType* projectileType, UnitUpdater *unitUpdater, const GameCamera *gameCamera){
3368 	this->gameCamera= gameCamera;
3369 	this->attackerRef= attacker;
3370 	this->projectileType= projectileType;
3371 	this->ast= static_cast<const AttackSkillType*>(attacker->getCurrSkill());
3372 	this->targetPos= attacker->getTargetPos();
3373 	this->targetField= attacker->getTargetField();
3374 	this->unitUpdater= unitUpdater;
3375 }
3376 
3377 void ParticleDamager::update(ParticleSystem *particleSystem) {
3378 	Unit *attacker= attackerRef.getUnit();
3379 
3380 	if(attacker != NULL) {
3381 		//string auditBeforeHit = particleSystem->toString();
3382 
3383 		char szBuf[8096]="";
3384 		snprintf(szBuf,8095,"Unit hitting [ParticleDamager::update] [%s] targetField = %d",targetPos.getString().c_str(),targetField);
3385 		attacker->addNetworkCRCDecHp(szBuf);
3386 
3387 		unitUpdater->hit(attacker, ast, targetPos, targetField, projectileType->getDamagePercentage());
3388 
3389 		//char szBuf[8096]="";
3390 		//snprintf(szBuf,8095,"ParticleDamager::update attacker particleSystem before: %s\nafter: %s",auditBeforeHit.c_str(),particleSystem->toString().c_str());
3391 		//attacker->setNetworkCRCParticleObserverLogInfo(szBuf);
3392 
3393 		//play sound
3394 		// Try to use the sound form the projetileType
3395 		StaticSound *projSound=projectileType->getHitSound();
3396 		if(projSound == NULL){
3397 			// use the sound from the skill
3398 			projSound= ast->getProjSound();
3399 		}
3400 		if(particleSystem->getVisible() && projSound != NULL) {
3401 			SoundRenderer::getInstance().playFx(projSound, attacker->getCurrMidHeightVector(), gameCamera->getPos());
3402 		}
3403 
3404 		//check for spawnattack
3405 		if(projectileType->getSpawnUnit()!="" && projectileType->getSpawnUnitcount()>0 ){
3406 			unitUpdater->spawnAttack(attacker, projectileType->getSpawnUnit(), 100,
3407 					100, 100, projectileType->getSpawnUnitcount(),
3408 					projectileType->getSpawnUnitAtTarget(), targetPos);
3409 		}
3410 
3411 		// check for shake and shake
3412 		if(projectileType->isShake()==true){
3413 			World *world=attacker->getFaction()->getWorld();
3414 			Map* map=world->getMap();
3415 			Game *game=world->getGame();
3416 
3417 			//Unit *attacked= map->getCell(targetPos)->getUnit(targetField);
3418 			Vec2i surfaceTargetPos=Map::toSurfCoords(targetPos);
3419 			bool visibility=(!projectileType->isShakeVisible())||(map->getSurfaceCell(surfaceTargetPos)->isVisible(world->getThisTeamIndex()) ||
3420 								(game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true));
3421 
3422 			bool isInCameraView=(!projectileType->isShakeInCameraView()) || Renderer::getInstance().posInCellQuadCache(surfaceTargetPos).first;
3423 
3424 			if(visibility && isInCameraView) {
3425 				game->getGameCameraPtr()->shake( projectileType->getShakeDuration(), projectileType->getShakeIntensity(),projectileType->isShakeCameraDistanceAffected(),map->getSurfaceCell(surfaceTargetPos)->getVertex());
3426 			}
3427 		}
3428 	}
3429 	particleSystem->setObserver(NULL);
3430 	delete this;
3431 }
3432 
3433 void ParticleDamager::saveGame(XmlNode *rootNode) {
3434 	std::map<string,string> mapTagReplacements;
3435 	XmlNode *particleDamagerNode = rootNode->addChild("ParticleDamager");
3436 
3437 //	UnitReference attackerRef;
3438 	attackerRef.saveGame(particleDamagerNode);
3439 
3440 //	const AttackSkillType* ast;
3441 	particleDamagerNode->addAttribute("astName",ast->getName(), mapTagReplacements);
3442 	particleDamagerNode->addAttribute("astClass",intToStr(ast->getClass()), mapTagReplacements);
3443 //	UnitUpdater *unitUpdater;
3444 //	const GameCamera *gameCamera;
3445 //	Vec2i targetPos;
3446 	particleDamagerNode->addAttribute("targetPos",targetPos.getString(), mapTagReplacements);
3447 //	Field targetField;
3448 	particleDamagerNode->addAttribute("targetField",intToStr(targetField), mapTagReplacements);
3449 }
3450 
3451 void ParticleDamager::loadGame(const XmlNode *rootNode, void *genericData) {
3452 	const XmlNode *particleDamagerNode = rootNode->getChild("ParticleDamager");
3453 
3454 	std::pair<Game *,Unit *> *pairData = (std::pair<Game *,Unit *>*)genericData;
3455 	//UnitType *ut, Game *game
3456 	attackerRef.loadGame(particleDamagerNode,pairData->first->getWorld());
3457 
3458 	//random.setLastNumber(particleSystemNode->getAttribute("random")->getIntValue());
3459 
3460 	//	const AttackSkillType* ast;
3461 	string astName = particleDamagerNode->getAttribute("astName")->getValue();
3462 	SkillClass astClass = static_cast<SkillClass>(particleDamagerNode->getAttribute("astClass")->getIntValue());
3463 	ast = dynamic_cast<const AttackSkillType*>(pairData->second->getType()->getSkillType(astName,astClass));
3464 	//	UnitUpdater *unitUpdater;
3465 	unitUpdater = pairData->first->getWorld()->getUnitUpdater();
3466 	//	const GameCamera *gameCamera;
3467 	gameCamera = pairData->first->getGameCamera();
3468 	//	Vec2i targetPos;
3469 	targetPos = Vec2i::strToVec2(particleDamagerNode->getAttribute("targetPos")->getValue());
3470 	//	Field targetField;
3471 	targetField = static_cast<Field>(particleDamagerNode->getAttribute("targetField")->getIntValue());
3472 }
3473 
3474 }}//end namespace
3475