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