// ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2001-2008 MartiƱo Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "unit_updater.h" #include #include #include "core_data.h" #include "config.h" #include "game.h" #include "faction.h" #include "network_manager.h" #include "object.h" #include "particle_type.h" #include "projectile_type.h" #include "path_finder.h" #include "renderer.h" #include "sound.h" #include "sound_renderer.h" #include "upgrade.h" #include "unit.h" #include "leak_dumper.h" using namespace Shared::Graphics; using namespace Shared::Util; namespace Glest{ namespace Game{ // ===================================================== // class UnitUpdater // ===================================================== time_t UnitRangeCellsLookupItem::lastDebug = 0; // ===================== PUBLIC ======================== UnitUpdater::UnitUpdater() : mutexAttackWarnings(new Mutex(CODE_AT_LINE)), mutexUnitRangeCellsLookupItemCache(new Mutex(CODE_AT_LINE)) { this->game= NULL; this->gui= NULL; this->gameCamera= NULL; this->world= NULL; this->map= NULL; this->console= NULL; this->scriptManager= NULL; this->pathFinder = NULL; //UnitRangeCellsLookupItemCacheTimerCount = 0; attackWarnRange=0; } void UnitUpdater::init(Game *game){ this->game= game; this->gui= game->getGuiPtr(); this->gameCamera= game->getGameCamera(); this->world= game->getWorld(); this->map= world->getMap(); this->console= game->getConsole(); this->scriptManager= game->getScriptManager(); this->pathFinder = NULL; attackWarnRange=Config::getInstance().getFloat("AttackWarnRange","50.0"); //UnitRangeCellsLookupItemCacheTimerCount = 0; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: pathFinder = new PathFinder(); pathFinder->init(map); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } } void UnitUpdater::clearUnitPrecache(Unit *unit) { if(pathFinder != NULL) { pathFinder->clearUnitPrecache(unit); } } void UnitUpdater::removeUnitPrecache(Unit *unit) { if(pathFinder != NULL) { pathFinder->removeUnitPrecache(unit); } } UnitUpdater::~UnitUpdater() { //UnitRangeCellsLookupItemCache.clear(); delete pathFinder; pathFinder = NULL; MutexSafeWrapper safeMutex(mutexAttackWarnings,string(__FILE__) + "_" + intToStr(__LINE__)); while(attackWarnings.empty() == false) { AttackWarningData* awd = attackWarnings.back(); attackWarnings.pop_back(); delete awd; } safeMutex.ReleaseLock(); delete mutexAttackWarnings; mutexAttackWarnings = NULL; delete mutexUnitRangeCellsLookupItemCache; mutexUnitRangeCellsLookupItemCache = NULL; } // ==================== progress skills ==================== //skill dependent actions bool UnitUpdater::updateUnit(Unit *unit) { bool processUnitCommand = false; Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); 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()); SoundRenderer &soundRenderer= SoundRenderer::getInstance(); //play skill sound const SkillType *currSkill= unit->getCurrSkill(); for(SkillSoundList::const_iterator it= currSkill->getSkillSoundList()->begin(); it != currSkill->getSkillSoundList()->end(); ++it) { float soundStartTime= (*it)->getStartTime(); if(soundStartTime >= unit->getLastAnimProgressAsFloat() && soundStartTime < unit->getAnimProgressAsFloat()) { if(map->getSurfaceCell(Map::toSurfCoords(unit->getPos()))->isVisible(world->getThisTeamIndex()) || (game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)) { soundRenderer.playFx((*it)->getSoundContainer()->getRandSound(), unit->getCurrMidHeightVector(), gameCamera->getPos()); } } } if (currSkill->getShake()) { float shakeStartTime = currSkill->getShakeStartTime(); if (shakeStartTime >= unit->getLastAnimProgressAsFloat() && shakeStartTime < unit->getAnimProgressAsFloat()) { bool visibleAffected=false; bool cameraViewAffected=false; bool cameraDistanceAffected=false; bool enabled=false; if (game->getWorld()->getThisFactionIndex() == unit->getFactionIndex()) { visibleAffected=currSkill->getShakeSelfVisible(); cameraViewAffected=currSkill->getShakeSelfInCameraView(); cameraDistanceAffected=currSkill->getShakeSelfCameraAffected(); enabled=currSkill->getShakeSelfEnabled(); } else if (unit->getTeam() == world->getThisTeamIndex()) { visibleAffected=currSkill->getShakeTeamVisible(); cameraViewAffected=currSkill->getShakeTeamInCameraView(); cameraDistanceAffected=currSkill->getShakeTeamCameraAffected(); enabled=currSkill->getShakeTeamEnabled(); } else { visibleAffected=currSkill->getShakeEnemyVisible(); cameraViewAffected=currSkill->getShakeEnemyInCameraView(); cameraDistanceAffected=currSkill->getShakeEnemyCameraAffected(); enabled=currSkill->getShakeEnemyEnabled(); } bool visibility=(!visibleAffected)||(map->getSurfaceCell(Map::toSurfCoords(unit->getPos()))->isVisible(world->getThisTeamIndex()) || (game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)); bool cameraAffected=(!cameraViewAffected) || unit->getVisible(); if(visibility && cameraAffected && enabled) { game->getGameCameraPtr()->shake( currSkill->getShakeDuration(), currSkill->getShakeIntensity(),cameraDistanceAffected,unit->getCurrMidHeightVector()); } } } 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()); unit->updateTimedParticles(); 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()); //start attack particle system if(unit->getCurrSkill()->getClass() == scDie) { const DieSkillType *dst= static_cast(unit->getCurrSkill()); if(dst->getSpawn() == true){ float spawnStartTime = truncateDecimal(dst->getSpawnStartTime(),6); float lastAnimProgress = truncateDecimal(unit->getLastAnimProgressAsFloat(),6); float animProgress = truncateDecimal(unit->getAnimProgressAsFloat(),6); bool startSpawnNow = (spawnStartTime >= lastAnimProgress && spawnStartTime < animProgress); if(startSpawnNow){ // spawn the units spawn(unit, dst->getSpawnUnit(), dst->getSpawnUnitCount(), dst->getSpawnUnitHealthPercentMin(), dst->getSpawnUnitHealthPercentMax(), dst->getSpawnProbability()); } } } //start attack particle system if(unit->getCurrSkill()->getClass() == scAttack) { const AttackSkillType *ast= static_cast(unit->getCurrSkill()); float attackStartTime = truncateDecimal(ast->getAttackStartTime(),6); float lastAnimProgress = truncateDecimal(unit->getLastAnimProgressAsFloat(),6); float animProgress = truncateDecimal(unit->getAnimProgressAsFloat(),6); bool startAttackParticleSystemNow = false; if(ast->projectileTypes.empty() == true ){ startAttackParticleSystemNow = (attackStartTime >= lastAnimProgress && attackStartTime < animProgress); } else {// start projectile attack for(ProjectileTypes::const_iterator it= ast->projectileTypes.begin(); it != ast->projectileTypes.end(); ++it) { attackStartTime= (*it)->getAttackStartTime(); startAttackParticleSystemNow = (attackStartTime >= lastAnimProgress && attackStartTime < animProgress); if(startAttackParticleSystemNow==true) break; } } char szBuf[8096]=""; snprintf(szBuf,8095,"attackStartTime = %f, lastAnimProgress = %f, animProgress = %f startAttackParticleSystemNow = %d",attackStartTime,lastAnimProgress,animProgress,startAttackParticleSystemNow); unit->setNetworkCRCParticleLogInfo(szBuf); if(startAttackParticleSystemNow == true) { startAttackParticleSystem(unit,lastAnimProgress,animProgress); } } 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()); bool update = unit->update(); 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()); //printf("Update Unit [%d - %s] = %d\n",unit->getId(),unit->getType()->getName().c_str(),update); //update unit if(update == true) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); processUnitCommand = true; updateUnitCommand(unit,-1); 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()); //if unit is out of EP, it stops if(unit->computeEp() == true) { bool reQueueHoldPosition = false; string holdPositionName = ""; if(unit->getCurrCommand() != NULL && unit->getCurrCommand()->getCommandType()->getClass() == ccAttackStopped) { reQueueHoldPosition = true; holdPositionName = unit->getCurrCommand()->getCommandType()->getName(false); } unit->setCurrSkill(scStop); unit->cancelCommand(); if(reQueueHoldPosition == true) { //Search for a command that can produce the unit const UnitType *ut = unit->getType(); for(int i= 0; i < ut->getCommandTypeCount(); ++i) { const CommandType* ct= ut->getCommandType(i); if(ct != NULL && ct->getClass() == ccAttackStopped) { const AttackStoppedCommandType *act= static_cast(ct); if(act != NULL && act->getName(false) == holdPositionName) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //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()); if(unit->getFaction()->reqsOk(act) == true && unit->getEp() >= act->getStopSkillType()->getEpCost()) { unit->giveCommand(new Command(act),true); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); break; } } } } } if(unit->getCurrSkill() != NULL && unit->getCurrSkill()->getClass() != scAttack) { // !!! Is this causing choppy network play somehow? //unit->computeHp(); } else if (unit->getCurrSkill() != NULL && unit->getCurrSkill()->getClass() == scAttack) { const AttackSkillType *attackSkill = dynamic_cast(unit->getCurrSkill()); if (attackSkill != NULL && attackSkill->getSpawnUnit() != "" && attackSkill->getSpawnUnitCount() > 0) { spawnAttack(unit, attackSkill->getSpawnUnit(), attackSkill->getSpawnUnitCount(), 100, 100, 100, attackSkill->getSpawnUnitAtTarget()); } } //move unit in cells if(unit->getCurrSkill()->getClass() == scMove) { world->moveUnitCells(unit, true); 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()); //play water sound if(map->getCell(unit->getPos())->getHeight() < map->getWaterLevel() && unit->getCurrField() == fLand) { if(Config::getInstance().getBool("DisableWaterSounds","false") == false) { soundRenderer.playFx( CoreData::getInstance().getWaterSound(), unit->getCurrMidHeightVector(), gameCamera->getPos() ); 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()); } } } } 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()); //unit death if(unit->isDead() && unit->getCurrSkill()->getClass() != scDie) { unit->kill(); } 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()); return processUnitCommand; } void UnitUpdater::spawn(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability) { if(spawnUnit != "" && spawnUnitcount > 0) { int spawnCount = spawnUnitcount; for (int y=0; y < spawnCount; ++y) { if (probability > 0 && probability < 100 && unit->getRandom()->randRange(1, 100) <= probability) { continue; } Unit* spawned=this->spawnUnit(unit,spawnUnit); if(spawned!=NULL){ if(healthMin>0 && healthMin<100 && healthMax>=healthMin && healthMax<=100){ int damagePercent=100-unit->getRandom()->randRange(healthMin, healthMax); //printf("damagePercent=%d\n",damagePercent); spawned->decHp((spawned->getHp()*damagePercent)/100); } } // no stat count !! //world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats()); } } } void UnitUpdater::spawnAttack(Unit *unit,string spawnUnit,int spawnUnitcount,int healthMin,int healthMax,int probability,bool spawnUnitAtTarget,Vec2i targetPos) { if(spawnUnit != "" && spawnUnitcount > 0) { int spawnCount = spawnUnitcount; for (int y=0; y < spawnCount; ++y) { if (probability > 0 && probability < 100 && unit->getRandom()->randRange(1, 100) <= probability) { continue; } if(targetPos==Vec2i(-10,-10)) { targetPos=unit->getTargetPos(); } Unit* spawned=this->spawnUnit(unit,spawnUnit,spawnUnitAtTarget?targetPos:unit->getCenteredPos()); if(spawned!=NULL){ if(healthMin>0 && healthMin<100 && healthMax>=healthMin && healthMax<=100){ int damagePercent=100-unit->getRandom()->randRange(healthMin, healthMax); //printf("damagePercent=%d\n",damagePercent); spawned->decHp((spawned->getHp()*damagePercent)/100); } // no stat count !! // world->getStats()->produce(unit->getFactionIndex(),spawned->getType()->getCountUnitProductionInStats()); const CommandType *ct= spawned->getType()->getFirstAttackCommand(unit->getTargetField()); if(ct == NULL){ ct= spawned->computeCommandType(targetPos,map->getCell(targetPos)->getUnit(unit->getTargetField())); } if(ct != NULL){ if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); spawned->giveCommand(new Command(ct, targetPos)); } } } } } Unit* UnitUpdater::spawnUnit(Unit *unit,string spawnUnit,Vec2i spawnPos) { const FactionType *ft= unit->getFaction()->getType(); const UnitType *spawnUnitType = ft->getUnitType(spawnUnit); Vec2i _spawnPos=spawnPos; if(_spawnPos==Vec2i(-10,-10)) { _spawnPos=unit->getCenteredPos(); } if(spawnUnitType->getMaxUnitCount() > 0) { if(spawnUnitType->getMaxUnitCount() <= unit->getFaction()->getCountForMaxUnitCount(spawnUnitType)) { return NULL; } } UnitPathInterface *newpath = NULL; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: newpath = new UnitPathBasic(); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } Unit *spawned= new Unit(world->getNextUnitId(unit->getFaction()), newpath, Vec2i(0), spawnUnitType, unit->getFaction(), world->getMap(), CardinalDir(CardinalDir::NORTH)); bool placedSpawnUnit=world->placeUnit(_spawnPos, 10, spawned); if(!placedSpawnUnit) { // This will also cleanup newPath delete spawned; spawned = NULL; } else { spawned->create(); spawned->born(NULL); scriptManager->onUnitCreated(spawned); } return spawned; } // ==================== progress commands ==================== //VERY IMPORTANT: compute next state depending on the first order of the list void UnitUpdater::updateUnitCommand(Unit *unit, int frameIndex) { try { bool minorDebugPerformance = false; Chrono chrono; if((minorDebugPerformance == true && frameIndex > 0) || SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); //if unit has command process it bool hasCommand = (unit->anyCommand()); 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()); int64 elapsed1 = 0; if(minorDebugPerformance && frameIndex > 0) elapsed1 = chrono.getMillis(); if(hasCommand == true) { 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()); bool commandUsesPathFinder = (frameIndex < 0); if(frameIndex > 0) { if(unit->getCurrCommand() != NULL && unit->getCurrCommand()->getCommandType() != NULL) { commandUsesPathFinder = unit->getCurrCommand()->getCommandType()->usesPathfinder(); // Clear previous cached unit data if(commandUsesPathFinder == true) { clearUnitPrecache(unit); } } } if(commandUsesPathFinder == true) { if(unit->getCurrCommand() != NULL && unit->getCurrCommand()->getCommandType() != NULL) { unit->getCurrCommand()->getCommandType()->update(this, unit, frameIndex); } } if((minorDebugPerformance && frameIndex > 0) && (chrono.getMillis() - elapsed1) >= 1) { //CommandClass cc = unit->getCurrCommand()->getCommandType()->commandTypeClass; 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()); } } 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()); if(frameIndex < 0) { //if no commands stop and add stop command if(unit->anyCommand() == false && unit->isOperative()) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(unit->getType()->hasSkillClass(scStop)) { unit->setCurrSkill(scStop); } if(unit->getType()->hasCommandClass(ccStop)) { unit->giveCommand(new Command(unit->getType()->getFirstCtOfClass(ccStop))); } } } 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()); 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateStop ==================== void UnitUpdater::updateStop(Unit *unit, int frameIndex) { try { // Nothing to do if(frameIndex >= 0) { clearUnitPrecache(unit); return; } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const StopCommandType *sct = static_cast(command->getCommandType()); Unit *sighted=NULL; unit->setCurrSkill(sct->getStopSkillType()); 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()); //we can attack any unit => attack it if(unit->getType()->hasSkillClass(scAttack)) { int cmdTypeCount = unit->getType()->getCommandTypeCount(); for(int i = 0; i < cmdTypeCount; ++i) { const CommandType *ct= unit->getType()->getCommandType(i); //look for an attack skill const AttackSkillType *ast= NULL; if(ct->getClass() == ccAttack) { ast= static_cast(ct)->getAttackSkillType(); } else if(ct->getClass() == ccAttackStopped) { ast= static_cast(ct)->getAttackSkillType(); } //use it to attack if(ast != NULL) { if(attackableOnSight(unit, &sighted, ast, (frameIndex >= 0))) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->giveCommand(new Command(ct, sighted->getPos())); break; } } } 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()); } //see any unit and cant attack it => run else if(unit->getType()->hasCommandClass(ccMove)) { 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()); if(attackerOnSight(unit, &sighted, (frameIndex >= 0))) { 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()); Vec2i escapePos = unit->getPos() * 2 - sighted->getPos(); //SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->giveCommand(new Command(unit->getType()->getFirstCtOfClass(ccMove), escapePos)); } 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()); } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateMove ==================== void UnitUpdater::updateMove(Unit *unit, int frameIndex) { try { Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const MoveCommandType *mct= static_cast(command->getCommandType()); Vec2i pos= command->getUnit()!=NULL? command->getUnit()->getCenteredPos(): command->getPos(); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; 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()); unit->logSynchData(__FILE__,__LINE__,szBuf); } 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()); TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } 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()); if(frameIndex < 0) { switch (tsValue) { case tsMoving: unit->setCurrSkill(mct->getMoveSkillType()); break; case tsBlocked: unit->setCurrSkill(scStop); if(unit->getPath()->isBlocked()){ unit->finishCommand(); } break; default: unit->finishCommand(); break; } } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateMove] tsValue [%d]",tsValue); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateAttack ==================== void UnitUpdater::updateAttack(Unit *unit, int frameIndex) { try { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttack]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttack]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } return; } const AttackCommandType *act= static_cast(command->getCommandType()); if(act == NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttack]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } return; } Unit *target= NULL; 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()); if(attackableOnRange(unit, &target, act->getAttackSkillType(),(frameIndex >= 0))) { if(frameIndex < 0) { if(unit->getEp() >= act->getAttackSkillType()->getEpCost()) { unit->setCurrSkill(act->getAttackSkillType()); unit->setTarget(target); } else { unit->setCurrSkill(scStop); } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttack]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } } 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()); } else { //compute target pos Vec2i pos; if(command->getUnit() != NULL) { pos= command->getUnit()->getCenteredPos(); } else if(attackableOnSight(unit, &target, act->getAttackSkillType(), (frameIndex >= 0))) { pos= target->getPos(); } else { pos= command->getPos(); } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttack] pos [%s] unit->getPos() [%s]",pos.getString().c_str(),unit->getPos().getString().c_str()); unit->logSynchData(__FILE__,__LINE__,szBuf); } 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()); TravelState tsValue = tsImpossible; //if(frameIndex < 0) { { //printf("In [%s::%s Line: %d] START pathfind for attacker [%d - %s]\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(), unit->getType()->getName().c_str()); //fflush(stdout); switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } //printf("In [%s::%s Line: %d] END pathfind for attacker [%d - %s]\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(), unit->getType()->getName().c_str()); //fflush(stdout); } 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()); if(frameIndex < 0) { if(command->getUnit() != NULL && !command->getUnit()->isAlive() && unit->getCommandSize() > 1) { // don't run over to dead body if there is still something to do in the queue unit->finishCommand(); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttack]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } } else { //if unit arrives destPos order has ended if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0 && SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynchMax).enabled == true) { char szBuf[8096]=""; snprintf(szBuf,8096,"#1 [updateAttack] tsValue = %d",tsValue); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } switch (tsValue) { case tsMoving: unit->setCurrSkill(act->getMoveSkillType()); break; case tsBlocked: if(unit->getPath()->isBlocked()) { unit->finishCommand(); } break; default: unit->finishCommand(); break; } /* case tsMoving: unit->setCurrSkill(act->getMoveSkillType()); { std::pair beingAttacked = unitBeingAttacked(unit); if(beingAttacked.first == true) { Unit *enemy = beingAttacked.second; const AttackCommandType *act_forenemy = unit->getType()->getFirstAttackCommand(enemy->getCurrField()); if(act_forenemy != NULL) { if(unit->getEp() >= act_forenemy->getAttackSkillType()->getEpCost()) { unit->setCurrSkill(act_forenemy->getAttackSkillType()); unit->setTarget(enemy); } //aiInterface->giveCommand(i, act_forenemy, beingAttacked.second->getPos()); } else { const AttackStoppedCommandType *asct_forenemy = unit->getType()->getFirstAttackStoppedCommand(enemy->getCurrField()); if(asct_forenemy != NULL) { //aiInterface->giveCommand(i, asct_forenemy, beingAttacked.second->getCenteredPos()); if(unit->getEp() >= asct_forenemy->getAttackSkillType()->getEpCost()) { unit->setCurrSkill(asct_forenemy->getAttackSkillType()); unit->setTarget(enemy); } } } } } break; case tsBlocked: if(unit->getPath()->isBlocked()){ unit->finishCommand(); } break; default: unit->finishCommand(); } */ if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0 && SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynchMax).enabled == true) { char szBuf[8096]=""; snprintf(szBuf,8096,"#2 [updateAttack] tsValue = %d",tsValue); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } } } 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()); } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Loc [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateAttackStopped ==================== void UnitUpdater::updateAttackStopped(Unit *unit, int frameIndex) { try { // Nothing to do if(frameIndex >= 0) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex >= 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttackStopped]"); unit->logSynchDataThreaded(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } clearUnitPrecache(unit); return; } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const AttackStoppedCommandType *asct= static_cast(command->getCommandType()); Unit *enemy=NULL; if(unit->getCommandSize() > 1) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttackStopped]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } unit->finishCommand(); // attackStopped is skipped if somthing else is queued after this. return; } float distToUnit=-1; std::pair result = make_pair(false,(Unit *)NULL); unitBeingAttacked(result, unit, asct->getAttackSkillType(), &distToUnit); if(result.first == true) { unit->setCurrSkill(asct->getAttackSkillType()); unit->setTarget(result.second); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttackStopped]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } } else if(attackableOnRange(unit, &enemy, asct->getAttackSkillType(),(frameIndex >= 0))) { unit->setCurrSkill(asct->getAttackSkillType()); unit->setTarget(enemy); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttackStopped]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } } else { unit->setCurrSkill(asct->getStopSkillType()); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateAttackStopped]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } void UnitUpdater::unitBeingAttacked(std::pair &result, const Unit *unit, const AttackSkillType *ast, float *currentDistToUnit) { //std::pair result = make_pair(false,(Unit *)NULL); float distToUnit = -1; if(currentDistToUnit != NULL) { distToUnit = *currentDistToUnit; } if(ast != NULL) { vector enemies = enemyUnitsOnRange(unit,ast); for(unsigned j = 0; j < enemies.size(); ++j) { Unit *enemy = enemies[j]; //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())); if(distToUnit < 0 || unit->getCenteredPos().dist(enemy->getCenteredPos()) < distToUnit) { distToUnit = unit->getCenteredPos().dist(enemy->getCenteredPos()); if(ast->getAttackRange() >= distToUnit){ result.first= true; result.second= enemy; break; } } } } if(currentDistToUnit != NULL) { *currentDistToUnit = distToUnit; } // if(result.first == true) { // 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); // } //return result; } std::pair UnitUpdater::unitBeingAttacked(const Unit *unit) { std::pair result = make_pair(false,(Unit *)NULL); float distToUnit = -1; for(unsigned int i = 0; i < (unsigned int)unit->getType()->getSkillTypeCount(); ++i) { const SkillType *st = unit->getType()->getSkillType(i); const AttackSkillType *ast = dynamic_cast(st); unitBeingAttacked(result, unit, ast, &distToUnit); } // if(result.first == true) { // 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); // } return result; } // ==================== updateBuild ==================== void UnitUpdater::updateBuild(Unit *unit, int frameIndex) { try { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateBuild]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); 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()); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const BuildCommandType *bct= static_cast(command->getCommandType()); if(unit->getCurrSkill() != NULL && unit->getCurrSkill()->getClass() != scBuild) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //if not building const UnitType *ut= command->getUnitType(); 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()); TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: { Vec2i buildPos = map->findBestBuildApproach(unit, command->getPos(), ut); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateBuild] unit->getPos() [%s] command->getPos() [%s] buildPos [%s]", unit->getPos().getString().c_str(),command->getPos().getString().c_str(),buildPos.getString().c_str()); unit->logSynchData(__FILE__,__LINE__,szBuf); } tsValue = pathFinder->findPath(unit, buildPos, NULL, frameIndex); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateBuild] tsValue: %d",tsValue); unit->logSynchData(__FILE__,__LINE__,szBuf); } } break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsValue = %d\n",__FILE__,__FUNCTION__,__LINE__,tsValue); if(frameIndex < 0) { switch (tsValue) { case tsMoving: if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsMoving\n",__FILE__,__FUNCTION__,__LINE__); unit->setCurrSkill(bct->getMoveSkillType()); break; case tsArrived: { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived:\n",__FILE__,__FUNCTION__,__LINE__); //if arrived destination assert(ut); if(ut == NULL) { throw megaglest_runtime_error("ut == NULL"); } bool canOccupyCell = false; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: 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()); canOccupyCell = map->isFreeCells(command->getPos(), ut->getSize(), fLand); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] canOccupyCell = %d\n",__FILE__,__FUNCTION__,__LINE__,canOccupyCell); if (canOccupyCell == true) { const UnitType *builtUnitType= command->getUnitType(); CardinalDir facing = command->getFacing(); UnitPathInterface *newpath = NULL; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: newpath = new UnitPathBasic(); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } Vec2i buildPos = command->getPos(); Unit *builtUnit= new Unit(world->getNextUnitId(unit->getFaction()), newpath, buildPos, builtUnitType, unit->getFaction(), world->getMap(), facing); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); builtUnit->create(); if(builtUnitType->hasSkillClass(scBeBuilt) == false) { throw megaglest_runtime_error("Unit [" + builtUnitType->getName(false) + "] has no be_built skill, producer was [" + intToStr(unit->getId()) + " - " + unit->getType()->getName(false) + "]."); } builtUnit->setCurrSkill(scBeBuilt); unit->setCurrSkill(bct->getBuildSkillType()); unit->setTarget(builtUnit); map->prepareTerrain(builtUnit); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } command->setUnit(builtUnit); //play start sound if(unit->getFactionIndex() == world->getThisFactionIndex() || (game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)) { SoundRenderer::getInstance().playFx( bct->getStartSound(), unit->getCurrMidHeightVector(), gameCamera->getPos()); } 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()); } else { //if there are no free cells unit->cancelCommand(); unit->setCurrSkill(scStop); if(unit->getFactionIndex() == world->getThisFactionIndex()) { console->addStdMessage("BuildingNoPlace"); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got BuildingNoPlace\n",__FILE__,__FUNCTION__,__LINE__); } } break; case tsBlocked: if(unit->getPath()->isBlocked()) { unit->cancelCommand(); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] got tsBlocked\n",__FILE__,__FUNCTION__,__LINE__); } break; } } 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()); } else { 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()); if(frameIndex < 0) { //if building Unit *builtUnit = map->getCell(unit->getTargetPos())->getUnit(fLand); if(builtUnit == NULL) { builtUnit = map->getCell(unit->getTargetPos())->getUnitWithEmptyCellMap(fLand); } if(builtUnit != NULL) { 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()); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] builtUnit = [%p]\n",__FILE__,__FUNCTION__,__LINE__,builtUnit); //if unit is killed while building then u==NULL; if(builtUnit != NULL && builtUnit != command->getUnit()) { 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__); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateBuild]"); unit->logSynchData(__FILE__,__LINE__,szBuf); } unit->setCurrSkill(scStop); } else if(builtUnit == NULL || builtUnit->isBuilt()) { 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__); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateBuild]"); unit->logSynchData(__FILE__,__LINE__,szBuf); } unit->finishCommand(); unit->setCurrSkill(scStop); } else if(builtUnit == NULL || builtUnit->repair()) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateBuild]"); unit->logSynchData(__FILE__,__LINE__,szBuf); } const CommandType *ct = (command != NULL ? command->getCommandType() : NULL); //building finished unit->finishCommand(); unit->setCurrSkill(scStop); builtUnit->born(ct); scriptManager->onUnitCreated(builtUnit); if(unit->getFactionIndex() == world->getThisFactionIndex() || (game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)) { SoundRenderer::getInstance().playFx( bct->getBuiltSound(), unit->getCurrMidHeightVector(), gameCamera->getPos()); } } } 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()); } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateHarvest ==================== void UnitUpdater::updateHarvestEmergencyReturn(Unit *unit, int frameIndex) { try { if(frameIndex >= 0) { return; } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvestEmergencyReturn]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } //printf("\n#1 updateHarvestEmergencyReturn\n"); Command *command= unit->getCurrCommand(); if(command != NULL) { //printf("\n#2 updateHarvestEmergencyReturn\n"); //const HarvestCommandType *hct= dynamic_cast((command != NULL ? command->getCommandType() : NULL)); //if(hct != NULL) { { //printf("\n#3 updateHarvestEmergencyReturn\n"); const Vec2i unitTargetPos = command->getPos(); Cell *cell= map->getCell(unitTargetPos); if(cell != NULL && cell->getUnit(unit->getCurrField()) != NULL) { //printf("\n#4 updateHarvestEmergencyReturn\n"); Unit *targetUnit = cell->getUnit(unit->getCurrField()); if(targetUnit != NULL) { //printf("\n#5 updateHarvestEmergencyReturn\n"); // Check if we can return whatever resources we have if(targetUnit->getFactionIndex() == unit->getFactionIndex() && targetUnit->isOperative() == true && unit->getLoadType() != NULL && targetUnit->getType() != NULL && targetUnit->getType()->getStore(unit->getLoadType()) > 0) { //printf("\n#6 updateHarvestEmergencyReturn\n"); const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction()); if(previousHarvestCmd != NULL) { //printf("\n\n#1a return harvested resources\n\n"); NetworkCommand networkCommand(this->world,nctGiveCommand, unit->getId(), previousHarvestCmd->getId(), unit->getLastHarvestedResourcePos(), -1, -1, Unit::invalidId, -1, false, cst_None, -1, -1); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Command* new_command= this->game->getCommander()->buildCommand(&networkCommand); new_command->setStateType(cst_EmergencyReturnResource); new_command->setStateValue(1); std::pair cr= unit->checkCommand(new_command); if(cr.first == crSuccess) { //printf("\n\n#1b return harvested resources\n\n"); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->replaceCurrCommand(new_command); unit->setCurrSkill(previousHarvestCmd->getStopLoadedSkillType()); // make sure we use the right harvest animation } else { //printf("\n\n#1c return harvested resources\n\n"); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); delete new_command; unit->setCurrSkill(scStop); unit->finishCommand(); } } } } } } } } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { try { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const HarvestCommandType *hct= dynamic_cast(command->getCommandType()); if(hct == NULL) { throw megaglest_runtime_error("hct == NULL"); } Vec2i targetPos(-1); //TravelState tsValue = tsImpossible; //UnitPathInterface *path= unit->getPath(); 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()); //printf("In UpdateHarvest [%d - %s] unit->getCurrSkill()->getClass() = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getCurrSkill()->getClass()); Resource *harvestResource = NULL; SurfaceCell *sc = map->getSurfaceCell(Map::toSurfCoords(command->getPos())); if(sc != NULL) { harvestResource = sc->getResource(); } if(unit->getCurrSkill() != NULL && unit->getCurrSkill()->getClass() != scHarvest) { bool forceReturnToStore = (command != NULL && command->getStateType() == cst_EmergencyReturnResource && command->getStateValue() == 1); //if not working if(unit->getLoadCount() == 0 || (forceReturnToStore == false && unit->getLoadType() != NULL && harvestResource != NULL && (unit->getLoadCount() < hct->getMaxLoad()) && harvestResource->getType() != NULL && unit->getLoadType() == harvestResource->getType())) { //if not loaded go for resources SurfaceCell *sc = map->getSurfaceCell(Map::toSurfCoords(command->getPos())); if(sc != NULL) { Resource *r = sc->getResource(); if(r != NULL && hct != NULL && hct->canHarvest(r->getType())) { //if can harvest dest. pos bool canHarvestDestPos = false; 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()); switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: { const bool newHarvestPath = false; bool isNearResource = false; Vec2i clickPos = command->getOriginalPos(); if(newHarvestPath == true) { isNearResource = map->isResourceNear(frameIndex,unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit, false,&clickPos); } else { isNearResource = map->isResourceNear(frameIndex,unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit); } if(isNearResource == true) { if((unit->getPos().dist(command->getPos()) < harvestDistance || unit->getPos().dist(targetPos) < harvestDistance) && isNearResource == true) { canHarvestDestPos = true; } } else if(newHarvestPath == true) { if(clickPos != command->getOriginalPos()) { //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()); if(frameIndex < 0) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest] clickPos [%s]",clickPos.getString().c_str()); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } command->setPos(clickPos); } } } } break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } 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()); if (canHarvestDestPos == true ) { if(frameIndex < 0) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } unit->setLastHarvestResourceTarget(NULL); } canHarvestDestPos = (map->getSurfaceCell(Map::toSurfCoords(targetPos)) != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource()->getType() != NULL); if(canHarvestDestPos == true) { if(frameIndex < 0) { //if it finds resources it starts harvesting unit->setCurrSkill(hct->getHarvestSkillType()); unit->setTargetPos(targetPos); command->setPos(targetPos); if(unit->getLoadType() == NULL || harvestResource == NULL || harvestResource->getType() == NULL || unit->getLoadType() != harvestResource->getType()) { unit->setLoadCount(0); } unit->getFaction()->addResourceTargetToCache(targetPos); switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: unit->setLoadType(r->getType()); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest] targetPos [%s]",targetPos.getString().c_str()); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } } 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()); } } if(canHarvestDestPos == false) { if(frameIndex < 0) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest] targetPos [%s]",targetPos.getString().c_str()); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } unit->setLastHarvestResourceTarget(&targetPos); } 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()); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest] unit->getPos() [%s] command->getPos() [%s]", unit->getPos().getString().c_str(),command->getPos().getString().c_str()); unit->logSynchData(__FILE__,__LINE__,szBuf); } //if not continue walking bool wasStuck = false; TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: tsValue = pathFinder->findPath(unit, command->getPos(), &wasStuck, frameIndex); if (tsValue == tsMoving && frameIndex < 0) { unit->setCurrSkill(hct->getMoveSkillType()); } break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } 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()); // If the unit is blocked or Even worse 'stuck' then try to // find the same resource type elsewhere, but close by if((wasStuck == true || tsValue == tsBlocked) && unit->isAlive() == true) { switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: { bool isNearResource = map->isResourceNear(frameIndex,unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit,true); if(isNearResource == true) { if((unit->getPos().dist(command->getPos()) < harvestDistance || unit->getPos().dist(targetPos) < harvestDistance) && isNearResource == true) { canHarvestDestPos = true; } } } break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } if (canHarvestDestPos == true) { if(frameIndex < 0) { unit->setLastHarvestResourceTarget(NULL); } canHarvestDestPos = (map->getSurfaceCell(Map::toSurfCoords(targetPos)) != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource() != NULL && map->getSurfaceCell(Map::toSurfCoords(targetPos))->getResource()->getType() != NULL); if(canHarvestDestPos == true) { if(frameIndex < 0) { //if it finds resources it starts harvesting unit->setCurrSkill(hct->getHarvestSkillType()); unit->setTargetPos(targetPos); command->setPos(targetPos); if(unit->getLoadType() == NULL || harvestResource == NULL || harvestResource->getType() == NULL || unit->getLoadType() != harvestResource->getType()) { unit->setLoadCount(0); } unit->getFaction()->addResourceTargetToCache(targetPos); switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: unit->setLoadType(r->getType()); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } } } 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()); } if(canHarvestDestPos == false) { if(frameIndex < 0) { unit->setLastHarvestResourceTarget(&targetPos); } if(targetPos.x >= 0) { //if not continue walking if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest #2] unit->getPos() [%s] command->getPos() [%s] targetPos [%s]", unit->getPos().getString().c_str(),command->getPos().getString().c_str(),targetPos.getString().c_str()); unit->logSynchData(__FILE__,__LINE__,szBuf); } wasStuck = false; TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: tsValue = pathFinder->findPath(unit, targetPos, &wasStuck, frameIndex); if (tsValue == tsMoving && frameIndex < 0) { unit->setCurrSkill(hct->getMoveSkillType()); command->setPos(targetPos); } break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } } 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()); if(wasStuck == true && frameIndex < 0) { //if can't harvest, search for another resource unit->setCurrSkill(scStop); if(searchForResource(unit, hct) == false) { unit->finishCommand(); } } } } } } else { if(frameIndex < 0) { //if can't harvest, search for another resource unit->setCurrSkill(scStop); if(searchForResource(unit, hct) == false) { unit->finishCommand(); } } 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()); } } 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()); } else { 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()); //if loaded, return to store Unit *store= world->nearestStore(unit->getPos(), unit->getFaction()->getIndex(), unit->getLoadType()); if(store != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateHarvest #3] unit->getPos() [%s] store->getCenteredPos() [%s]", unit->getPos().getString().c_str(),store->getCenteredPos().getString().c_str()); unit->logSynchData(__FILE__,__LINE__,szBuf); } TravelState tsValue = tsImpossible; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: tsValue = pathFinder->findPath(unit, store->getCenteredPos(), NULL, frameIndex); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } 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()); if(frameIndex < 0) { switch(tsValue) { case tsMoving: { if (hct->canHarvest(unit->getLoadType()) == false) { // hct has changed to a different harvest command. const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction()); if(previousHarvestCmd != NULL) { //printf("\n\n#1\n\n"); unit->setCurrSkill(previousHarvestCmd->getMoveLoadedSkillType()); // make sure we use the right harvest animation } else { //printf("\n\n#2\n\n"); unit->setCurrSkill(hct->getMoveLoadedSkillType()); } } else { unit->setCurrSkill(hct->getMoveLoadedSkillType()); } } break; default: break; } //world->changePosCells(unit,unit->getPos()+unit->getDest()); if(map->isNextTo(unit, store)) { //update resources int resourceAmount= unit->getLoadCount(); if(unit->getFaction()->getCpuControl()) { int resourceMultiplierIndex=game->getGameSettings()->getResourceMultiplierIndex(unit->getFaction()->getIndex()); resourceAmount=(resourceAmount* (resourceMultiplierIndex +5))/10; } unit->getFaction()->incResourceAmount(unit->getLoadType(), resourceAmount); world->getStats()->harvest(unit->getFactionIndex(), resourceAmount); scriptManager->onResourceHarvested(); //if next to a store unload resources unit->getPath()->clear(); unit->setCurrSkill(scStop); unit->setLoadCount(0); command->setPosToOriginalPos(); } } 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()); } else { if(frameIndex < 0) { unit->finishCommand(); } } } } else { if(frameIndex < 0) { //if working //unit->setLastHarvestResourceTarget(NULL); 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()); const Vec2i unitTargetPos = unit->getTargetPos(); SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unitTargetPos)); Resource *r= sc->getResource(); if (r != NULL) { if (hct->canHarvest(r->getType()) == false || r->getType()->getName() != unit->getLoadType()->getName()) { // hct has changed to a different harvest command. if(r->getType()->getName() != unit->getLoadType()->getName()) { const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction()); if(previousHarvestCmd != NULL) { //printf("\n\n#1\n\n"); unit->setCurrSkill(previousHarvestCmd->getStopLoadedSkillType()); // make sure we use the right harvest animation } else { //printf("\n\n#2\n\n"); unit->setCurrSkill(hct->getStopLoadedSkillType()); } } else if(hct->canHarvest(r->getType()) == false) { const HarvestCommandType *previousHarvestCmd = unit->getType()->getFirstHarvestCommand(unit->getLoadType(),unit->getFaction()); if(previousHarvestCmd != NULL) { //printf("\n\n#3\n\n"); unit->setCurrSkill(previousHarvestCmd->getStopLoadedSkillType()); // make sure we use the right harvest animation } else { //printf("\n\n#4\n\n"); unit->setCurrSkill(hct->getStopLoadedSkillType()); } } else { //printf("\n\n#5 [%s] [%s]\n\n",r->getType()->getName().c_str(),unit->getLoadType()->getName().c_str()); unit->setCurrSkill(hct->getStopLoadedSkillType()); // this is actually the wrong animation } unit->getPath()->clear(); 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()); } else { // if there is a resource, continue working, until loaded unit->update2(); unit->setLastHarvestedResourcePos(unitTargetPos); if (unit->getProgress2() >= hct->getHitsPerUnit()) { if (unit->getLoadCount() < hct->getMaxLoad()) { unit->setProgress2(0); unit->setLoadCount(unit->getLoadCount() + 1); //if resource exausted, then delete it and stop if (sc->decAmount(1)) { //const ResourceType *rt = r->getType(); sc->deleteResource(); world->removeResourceTargetFromCache(unitTargetPos); switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } //printf("\n\n#6\n\n"); unit->setCurrSkill(hct->getStopLoadedSkillType()); } } if (unit->getLoadCount() >= hct->getMaxLoad()) { //printf("\n\n#7\n\n"); unit->setCurrSkill(hct->getStopLoadedSkillType()); unit->getPath()->clear(); } } 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()); } } else { //if there is no resource, just stop //printf("\n\n#8\n\n"); unit->setCurrSkill(hct->getStopLoadedSkillType()); } } } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } void UnitUpdater::SwapActiveCommand(Unit *unitSrc, Unit *unitDest) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(unitSrc->getCommandSize() > 0 && unitDest->getCommandSize() > 0) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Command *cmd1 = unitSrc->getCurrCommand(); Command *cmd2 = unitDest->getCurrCommand(); unitSrc->replaceCurrCommand(cmd2); unitDest->replaceCurrCommand(cmd1); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void UnitUpdater::SwapActiveCommandState(Unit *unit, CommandStateType commandStateType, const CommandType *commandType, int originalValue,int newValue) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(commandStateType == cst_linkedUnit) { if(dynamic_cast(commandType) != NULL) { for(int i = 0; i < unit->getFaction()->getUnitCount(); ++i) { Unit *peerUnit = unit->getFaction()->getUnit(i); if(peerUnit != NULL) { if(peerUnit->getCommandSize() > 0 ) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Command *peerCommand = peerUnit->getCurrCommand(); //const BuildCommandType *bct = dynamic_cast(peerCommand->getCommandType()); //if(bct != NULL) { if(peerCommand != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //if(command->getPos() == peerCommand->getPos()) { if( peerCommand->getStateType() == commandStateType && peerCommand->getStateValue() == originalValue) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); peerCommand->setStateValue(newValue); } } } } } } } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } Unit * UnitUpdater::findPeerUnitBuilder(Unit *unit) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Unit *foundUnitBuilder = NULL; if(unit->getCommandSize() > 0 ) { Command *command = unit->getCurrCommand(); if(command != NULL) { const RepairCommandType *rct= dynamic_cast(command->getCommandType()); if(rct != NULL && command->getStateType() == cst_linkedUnit) { 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()); Unit *firstLinkedPeerRepairer = NULL; for(int i = 0; i < unit->getFaction()->getUnitCount(); ++i) { Unit *peerUnit = unit->getFaction()->getUnit(i); if(peerUnit != NULL) { if(peerUnit->getCommandSize() > 0 ) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Command *peerCommand = peerUnit->getCurrCommand(); const BuildCommandType *bct = dynamic_cast(peerCommand->getCommandType()); if(bct != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(command->getStateValue() == peerUnit->getId()) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); foundUnitBuilder = peerUnit; break; } } else { 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()); if(firstLinkedPeerRepairer == NULL) { const RepairCommandType *prct = dynamic_cast(peerCommand->getCommandType()); if(prct != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(unit->getId() != peerUnit->getId() && command->getStateValue() == peerUnit->getId()) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); firstLinkedPeerRepairer = peerUnit; } } } } } } } if(foundUnitBuilder == NULL && firstLinkedPeerRepairer != NULL) { foundUnitBuilder = firstLinkedPeerRepairer; } } } } 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")); return foundUnitBuilder; } // ==================== updateRepair ==================== void UnitUpdater::updateRepair(Unit *unit, int frameIndex) { try { // Nothing to do if(frameIndex >= 0) { clearUnitPrecache(unit); return; } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateRepair]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit = %p\n",__FILE__,__FUNCTION__,__LINE__,unit); //if(unit != NULL) { 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()); //} Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const RepairCommandType *rct= static_cast(command->getCommandType()); const CommandType *ct = (command != NULL ? command->getCommandType() : NULL); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] rct = %p\n",__FILE__,__FUNCTION__,__LINE__,rct); Unit *repaired = (command != NULL ? map->getCell(command->getPos())->getUnitWithEmptyCellMap(fLand) : NULL); if(repaired == NULL && command != NULL) { repaired = map->getCell(command->getPos())->getUnit(fLand); } if(repaired != NULL) { 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()); } if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); // Check if the 'repaired' unit is actually the peer unit in a multi-build? Unit *peerUnitBuilder = findPeerUnitBuilder(unit); if(peerUnitBuilder != NULL) { SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit peer [%s] - %d\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder->getFullName(false).c_str(),peerUnitBuilder->getId()); } 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()); // Ensure we have the right unit to repair if(peerUnitBuilder != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] peerUnitBuilder = %p\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder); if(peerUnitBuilder->getCurrCommand()->getUnit() != NULL) { 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()); repaired = peerUnitBuilder->getCurrCommand()->getUnit(); } } bool nextToRepaired = repaired != NULL && map->isNextTo(unit, repaired); 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()); peerUnitBuilder = NULL; if(repaired == NULL) { peerUnitBuilder = findPeerUnitBuilder(unit); if(peerUnitBuilder != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] peerUnitBuilder = %p\n",__FILE__,__FUNCTION__,__LINE__,peerUnitBuilder); if(peerUnitBuilder->getCurrCommand()->getUnit() != NULL) { 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()); repaired = peerUnitBuilder->getCurrCommand()->getUnit(); nextToRepaired = repaired != NULL && map->isNextTo(unit, repaired); } else if(peerUnitBuilder->getCurrCommand()->getUnitType() != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Vec2i buildPos = map->findBestBuildApproach(unit, command->getPos(), peerUnitBuilder->getCurrCommand()->getUnitType()); //nextToRepaired= (unit->getPos() == (command->getPos()-Vec2i(1))); nextToRepaired = (unit->getPos() == buildPos); 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); if(nextToRepaired == true) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Command *peerCommand = peerUnitBuilder->getCurrCommand(); const RepairCommandType *rct = dynamic_cast(peerCommand->getCommandType()); // If the peer is also scheduled to do a repair we CANNOT swap their commands or // it will result in a stack overflow as each swaps the others repair command. // We must convert this unit's repair into a build right now! if(rct != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); const CommandType *ctbuild = unit->getType()->getFirstCtOfClass(ccBuild); NetworkCommand networkCommand(this->world,nctGiveCommand, unit->getId(), ctbuild->getId(), command->getPos(), command->getUnitType()->getId(), -1, -1, CardinalDir(CardinalDir::NORTH), true, command->getStateType(), command->getStateValue()); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Command* command= this->game->getCommander()->buildCommand(&networkCommand); std::pair cr= unit->checkCommand(command); if(cr.first == crSuccess) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->replaceCurrCommand(command); } else { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); delete command; unit->setCurrSkill(scStop); unit->finishCommand(); } } else { CommandStateType commandStateType = unit->getCurrCommand()->getStateType(); SwapActiveCommand(unit,peerUnitBuilder); int oldPeerUnitId = peerUnitBuilder->getId(); int newPeerUnitId = unit->getId(); SwapActiveCommandState(unit,commandStateType,unit->getCurrCommand()->getCommandType(),oldPeerUnitId,newPeerUnitId); // Give the swapped unit a fresh chance to help build in case they // were or are about to be blocked peerUnitBuilder->getPath()->clear(); peerUnitBuilder->setRetryCurrCommandCount(1); updateUnitCommand(unit,-1); } return; } } 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()); } } else { 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()); } 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()); //UnitPathInterface *path= unit->getPath(); if(unit->getCurrSkill()->getClass() != scRepair || (nextToRepaired == false && peerUnitBuilder == NULL)) { if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } Vec2i repairPos = command->getPos(); bool startRepairing = (repaired != NULL && rct->isRepairableUnitType(repaired->getType()) && repaired->isDamaged()); if(startRepairing == true) { //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()); // for(unsigned int i = 0; i < rct->getRepairCount(); ++i) { // const UnitType *rUnit = rct->getRepair(i); // printf("Can repair unittype [%s]\n",rUnit->getName().c_str()); // } } 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); if(startRepairing == false && peerUnitBuilder != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); startRepairing = true; // Since the unit to be built is not yet existing we need to tell the // other units to move to the build position or else they get in the way // No need to adjust repair pos since we already did this above via: Vec2i buildPos = map->findBestBuildApproach(unit->getPos(), command->getPos(), peerUnitBuilder->getCurrCommand()->getUnitType()); //repairPos = command->getPos()-Vec2i(1); } //if not repairing if(startRepairing == true) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(nextToRepaired == true) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->setTarget(repaired); unit->setCurrSkill(rct->getRepairSkillType()); } else { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; 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()); unit->logSynchData(__FILE__,__LINE__,szBuf); } 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()); // If the repair command has no move skill and we are not next to // the unit we cannot repair it if(rct->getMoveSkillType() == NULL) { //printf("CANCEL REPAIR NOT NEXT TO REPAIR UNIT\n"); //Vec2i repairPos = command->getPos(); //bool startRepairing = (repaired != NULL && rct->isRepairableUnitType(repaired->getType()) && repaired->isDamaged()); //bool nextToRepaired = repaired != NULL && map->isNextTo(unit, repaired); //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()); console->addStdMessage("InvalidPosition"); unit->setCurrSkill(scStop); unit->finishCommand(); } else { TravelState ts; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); ts = pathFinder->findPath(unit, repairPos, NULL, frameIndex); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] ts = %d\n",__FILE__,__FUNCTION__,__LINE__,ts); 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()); switch(ts) { case tsMoving: if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsMoving\n",__FILE__,__FUNCTION__,__LINE__); unit->setCurrSkill(rct->getMoveSkillType()); break; case tsBlocked: if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsBlocked\n",__FILE__,__FUNCTION__,__LINE__); if(unit->getPath()->isBlocked()) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__); if(unit->getRetryCurrCommandCount() > 0) { 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()); unit->setRetryCurrCommandCount(0); unit->getPath()->clear(); updateUnitCommand(unit,-1); } else { unit->finishCommand(); } } break; default: break; } } } } else { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__); //console->addStdMessage("InvalidPosition"); unit->setCurrSkill(scStop); unit->finishCommand(); 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()); } } else { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); bool cancelRepair = false; //if repairing if(repaired != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); // Check if we can still repair the unit (may have morphed, etc) bool canStillRepair = rct->isRepairableUnitType(repaired->getType()); if(canStillRepair == true) { unit->setTarget(repaired); } else { //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()); // for(unsigned int i = 0; i < rct->getRepairCount(); ++i) { // const UnitType *rUnit = rct->getRepair(i); // printf("Can repair unittype [%s]\n",rUnit->getName().c_str()); // } unit->setCurrSkill(scStop); unit->finishCommand(); cancelRepair = true; } } else if(peerUnitBuilder != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->setTargetPos(command->getPos()); } if(cancelRepair == false && (repaired == NULL || repaired->repair()) && peerUnitBuilder == NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] about to call [scStop]\n",__FILE__,__FUNCTION__,__LINE__); unit->setCurrSkill(scStop); unit->finishCommand(); if(repaired != NULL && repaired->isBuilt() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); repaired->born(ct); scriptManager->onUnitCreated(repaired); } 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()); } } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateProduce ==================== void UnitUpdater::updateProduce(Unit *unit, int frameIndex) { try { // Nothing to do if(frameIndex >= 0) { clearUnitPrecache(unit); return; } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateProduce]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const ProduceCommandType *pct= static_cast(command->getCommandType()); Unit *produced; if(unit->getCurrSkill()->getClass() != scProduce) { //if not producing unit->setCurrSkill(pct->getProduceSkillType()); } else { const CommandType *ct = (command != NULL ? command->getCommandType() : NULL); unit->update2(); 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()); if(unit->getProgress2() > pct->getProduced()->getProductionTime()){ unit->finishCommand(); unit->setCurrSkill(scStop); UnitPathInterface *newpath = NULL; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: newpath = new UnitPathBasic(); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } produced= new Unit(world->getNextUnitId(unit->getFaction()), newpath, Vec2i(0), pct->getProducedUnit(), unit->getFaction(), world->getMap(), CardinalDir(CardinalDir::NORTH)); 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()); 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()); //place unit creates the unit if(!world->placeUnit(unit->getCenteredPos(), 10, produced, false, frameIndex < 0)) { 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()); delete produced; } else{ produced->create(); produced->born(ct); world->getStats()->produce(unit->getFactionIndex(),produced->getType()->getCountUnitProductionInStats()); const CommandType *ct= produced->computeCommandType(unit->getMeetingPos()); if(ct != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); produced->giveCommand(new Command(ct, unit->getMeetingPos())); } scriptManager->onUnitCreated(produced); 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()); } } } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateUpgrade ==================== void UnitUpdater::updateUpgrade(Unit *unit, int frameIndex) { try { // Nothing to do if(frameIndex >= 0) { clearUnitPrecache(unit); return; } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateUpgrade]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const UpgradeCommandType *uct= static_cast(command->getCommandType()); if(unit->getCurrSkill()->getClass() != scUpgrade) { //if not producing unit->setCurrSkill(uct->getUpgradeSkillType()); } else { //if producing unit->update2(); if(unit->getProgress2() > uct->getProduced()->getProductionTime()){ unit->finishCommand(); unit->setCurrSkill(scStop); unit->getFaction()->finishUpgrade(uct->getProducedUpgrade()); } } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateMorph ==================== void UnitUpdater::updateMorph(Unit *unit, int frameIndex) { try { // Nothing to do if(frameIndex >= 0) { clearUnitPrecache(unit); return; } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { char szBuf[8096]=""; snprintf(szBuf,8096,"[updateMorph]"); unit->logSynchData(extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__,szBuf); } Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); Command *command= unit->getCurrCommand(); if(command == NULL) { throw megaglest_runtime_error("command == NULL"); } const MorphCommandType *mct= static_cast(command->getCommandType()); if(unit->getCurrSkill()->getClass()!=scMorph){ //if not morphing, check space if(map->canMorph(unit->getPos(),unit,mct->getMorphUnit())){ unit->setCurrSkill(mct->getMorphSkillType()); // block space for morphing units ( block space before and after morph ! ) map->putUnitCells(unit, unit->getPos(), false, frameIndex < 0); } else{ if(unit->getFactionIndex()==world->getThisFactionIndex()){ console->addStdMessage("InvalidPosition"); } unit->cancelCommand(); } } else{ unit->update2(); if(unit->getProgress2() > mct->getProduced()->getProductionTime()){ //int oldSize = 0; //bool needMapUpdate = false; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } //finish the command if(unit->morph(mct, frameIndex)){ unit->finishCommand(); if(gui->isSelected(unit)){ gui->onSelectionChanged(); } switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } scriptManager->onUnitCreated(unit); } else{ unit->cancelCommand(); if(unit->getFactionIndex()==world->getThisFactionIndex()){ console->addStdMessage("InvalidPosition"); } } unit->setCurrSkill(scStop); } } 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()); } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } } // ==================== updateMove ==================== void UnitUpdater::updateSwitchTeam(Unit *unit, int frameIndex) { } // ==================== updateAttack ==================== // ==================== PRIVATE ==================== // ==================== attack ==================== void UnitUpdater::hit(Unit *attacker){ hit(attacker, dynamic_cast(attacker->getCurrSkill()), attacker->getTargetPos(), attacker->getTargetField(),100); } void UnitUpdater::hit(Unit *attacker, const AttackSkillType* ast, const Vec2i &targetPos, Field targetField, int damagePercent){ //hit attack positions if(ast != NULL && ast->getSplash()) { char szBuf[8096]=""; snprintf(szBuf,8095,"Unit hitting [UnitUpdater::hit] hasSplash = %d radius = %d damageall = %d",ast->getSplash(),ast->getSplashRadius(),ast->getSplashDamageAll()); attacker->addNetworkCRCDecHp(szBuf); PosCircularIterator pci(map, targetPos, ast->getSplashRadius()); while(pci.next()) { Unit *attacked= map->getCell(pci.getPos())->getUnit(targetField); if(attacked != NULL) { if(ast->getSplashDamageAll() || attacker->isAlly(attacked) == false || ( targetPos.x == pci.getPos().x && targetPos.y == pci.getPos().y )) { attacker->setLastAttackedUnitId(attacked->getId()); scriptManager->onUnitAttacking(attacker); float distance = pci.getPos().dist(targetPos); distance = truncateDecimal(distance,6); damage(attacker, ast, attacked, distance,damagePercent); } } } } else { Unit *attacked= map->getCell(targetPos)->getUnit(targetField); char szBuf[8096]=""; snprintf(szBuf,8095,"Unit hitting [UnitUpdater::hit 2] attacked = %d",(attacked != NULL ? attacked->getId() : -1)); attacker->addNetworkCRCDecHp(szBuf); if(attacked != NULL) { damage(attacker, ast, attacked, 0.f,damagePercent); } } } void UnitUpdater::damage(Unit *attacker, const AttackSkillType* ast, Unit *attacked, float distance, int damagePercent) { if(attacker == NULL) { throw megaglest_runtime_error("attacker == NULL"); } if(ast == NULL) { throw megaglest_runtime_error("ast == NULL"); } if(attacked == NULL) { throw megaglest_runtime_error("attacked == NULL"); } //get vars float damage = ast->getTotalAttackStrength(attacker->getTotalUpgrade()); int var = ast->getAttackVar(); int armor = attacked->getType()->getTotalArmor(attacked->getTotalUpgrade()); float damageMultiplier = world->getTechTree()->getDamageMultiplier(ast->getAttackType(), attacked->getType()->getArmorType()); damageMultiplier = truncateDecimal(damageMultiplier,6); //compute damage //damage += random.randRange(-var, var); damage += attacker->getRandom()->randRange(-var, var, extractFileFromDirectoryPath(__FILE__) + intToStr(__LINE__)); damage /= distance+1; damage -= armor; damage *= damageMultiplier; damage = truncateDecimal(damage,6); damage = (damage*damagePercent)/100; if(damage < 1) { damage= 1; } int damageVal = static_cast(damage); attacked->setLastAttackerUnitId(attacker->getId()); char szBuf[8096]=""; snprintf(szBuf,8095,"Unit hitting [UnitUpdater::damage] damageVal = %d",damageVal); attacker->addNetworkCRCDecHp(szBuf); //damage the unit if(attacked->decHp(damageVal)) { world->getStats()->kill(attacker->getFactionIndex(), attacked->getFactionIndex(), attacker->getTeam() != attacked->getTeam(),attacked->getType()->getCountUnitDeathInStats(),attacked->getType()->getCountUnitKillInStats()); if(attacked->getType()->getCountKillForUnitUpgrade() == true){ attacker->incKills(attacked->getTeam()); } // Perform resource looting iff the attack is from a different faction if(attacker->getFaction() != attacked->getFaction()) { int lootableResourceCount = attacked->getType()->getLootableResourceCount(); for(int i = 0; i < lootableResourceCount; i++) { LootableResource resource = attacked->getType()->getLootableResource(i); // Figure out how much of the resource in question that the attacked unit's faction has int factionTotalResource = 0; for(int j = 0; j < attacked->getFaction()->getTechTree()->getResourceTypeCount(); j++) { if(attacked->getFaction()->getTechTree()->getResourceType(j) == resource.getResourceType()) { factionTotalResource = attacked->getFaction()->getResource(j)->getAmount(); break; } } if(resource.isNegativeAllowed()) { attacked->getFaction()->incResourceAmount(resource.getResourceType(), -(factionTotalResource * resource.getLossFactionPercent() / 100)); attacked->getFaction()->incResourceAmount(resource.getResourceType(), -resource.getLossValue()); attacker->getFaction()->incResourceAmount(resource.getResourceType(), factionTotalResource * resource.getAmountFactionPercent() / 100); attacker->getFaction()->incResourceAmount(resource.getResourceType(), resource.getAmountValue()); } // Can't take more resources than the faction has, otherwise we end up in the negatives else { attacked->getFaction()->incResourceAmount(resource.getResourceType(), -(std::min)(factionTotalResource * resource.getLossFactionPercent() / 100, factionTotalResource)); attacked->getFaction()->incResourceAmount(resource.getResourceType(), -(std::min)(resource.getLossValue(), factionTotalResource)); attacker->getFaction()->incResourceAmount(resource.getResourceType(), (std::min)(factionTotalResource * resource.getAmountFactionPercent() / 100, factionTotalResource)); attacker->getFaction()->incResourceAmount(resource.getResourceType(), (std::min)(resource.getAmountValue(), factionTotalResource)); } } } switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } attacked->setCauseOfDeath(ucodAttacked); scriptManager->onUnitDied(attacked); } if(attacked->isAlive() == true) { scriptManager->onUnitAttacked(attacked); } // !!! Is this causing choppy network play somehow? //attacker->computeHp(); } void UnitUpdater::startAttackParticleSystem(Unit *unit, float lastAnimProgress, float animProgress){ Renderer &renderer= Renderer::getInstance(); //const AttackSkillType *ast= dynamic_cast(unit->getCurrSkill()); const AttackSkillType *ast= static_cast(unit->getCurrSkill()); if(ast == NULL) { throw megaglest_runtime_error("Start attack particle ast == NULL!"); } ParticleSystemTypeSplash *pstSplash= ast->getSplashParticleType(); bool hasProjectile = !ast->projectileTypes.empty(); Vec3f startPos= unit->getCurrVectorForParticlesystems(); Vec3f endPos= unit->getTargetVec(); //make particle system const SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unit->getPos())); const SurfaceCell *tsc= map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos())); bool visible= sc->isVisible(world->getThisTeamIndex()) || tsc->isVisible(world->getThisTeamIndex()); if(visible == false && world->showWorldForPlayer(world->getThisFactionIndex()) == true) { visible = true; } //for(ProjectileParticleSystemTypes::const_iterator pit= unit->getCurrSkill()->projectileParticleSystemTypes.begin(); pit != unit->getCurrSkill()->projectileParticleSystemTypes.end(); ++pit) { for(ProjectileTypes::const_iterator pt= ast->projectileTypes.begin(); pt != ast->projectileTypes.end(); ++pt) { bool startAttackParticleSystemNow = ((*pt)->getAttackStartTime() >= lastAnimProgress && (*pt)->getAttackStartTime() < animProgress); if(startAttackParticleSystemNow){ ProjectileParticleSystem *psProj= (*pt)->getProjectileParticleSystemType()->create(unit); psProj->setPath(startPos, endPos); psProj->setObserver(new ParticleDamager(unit,(*pt), this, gameCamera)); psProj->setVisible(visible); if(unit->getFaction()->getTexture()) { psProj->setFactionColor(unit->getFaction()->getTexture()->getPixmapConst()->getPixel3f(0,0)); } renderer.manageParticleSystem(psProj, rsGame); unit->addAttackParticleSystem(psProj); if(pstSplash!=NULL){ SplashParticleSystem *psSplash= pstSplash->create(unit); psSplash->setPos(endPos); psSplash->setVisible(visible); if(unit->getFaction()->getTexture()) { psSplash->setFactionColor(unit->getFaction()->getTexture()->getPixmapConst()->getPixel3f(0,0)); } renderer.manageParticleSystem(psSplash, rsGame); unit->addAttackParticleSystem(psSplash); psProj->link(psSplash); } } } // if no projectile, still deal damage.. if(hasProjectile == false) { char szBuf[8096]=""; snprintf(szBuf,8095,"Unit hitting [startAttackParticleSystem] no proj"); unit->addNetworkCRCDecHp(szBuf); hit(unit); //splash if(pstSplash != NULL) { SplashParticleSystem *psSplash= pstSplash->create(unit); psSplash->setPos(endPos); psSplash->setVisible(visible); if(unit->getFaction()->getTexture()) { psSplash->setFactionColor(unit->getFaction()->getTexture()->getPixmapConst()->getPixel3f(0,0)); } renderer.manageParticleSystem(psSplash, rsGame); unit->addAttackParticleSystem(psSplash); } } } // ==================== misc ==================== //looks for a resource of type rt, if rt==NULL looks for any //resource the unit can harvest bool UnitUpdater::searchForResource(Unit *unit, const HarvestCommandType *hct) { Vec2i pos= unit->getCurrCommand()->getPos(); for(int radius= 0; radius < maxResSearchRadius; radius++) { for(int i = pos.x - radius; i <= pos.x + radius; ++i) { for(int j=pos.y - radius; j <= pos.y + radius; ++j) { if(map->isInside(i, j)) { Resource *r= map->getSurfaceCell(Map::toSurfCoords(Vec2i(i, j)))->getResource(); if(r != NULL) { if(hct->canHarvest(r->getType())) { const Vec2i newPos = Vec2i(i, j); if(unit->isBadHarvestPos(newPos) == false) { unit->getCurrCommand()->setPos(newPos); return true; } } } } } } } return false; } bool UnitUpdater::attackerOnSight(Unit *unit, Unit **rangedPtr, bool evalMode){ int range = unit->getType()->getTotalSight(unit->getTotalUpgrade()); return unitOnRange(unit, range, rangedPtr, NULL,evalMode); } bool UnitUpdater::attackableOnSight(Unit *unit, Unit **rangedPtr, const AttackSkillType *ast, bool evalMode) { int range = unit->getType()->getTotalSight(unit->getTotalUpgrade()); return unitOnRange(unit, range, rangedPtr, ast, evalMode); } bool UnitUpdater::attackableOnRange(Unit *unit, Unit **rangedPtr, const AttackSkillType *ast,bool evalMode) { int range= ast->getTotalAttackRange(unit->getTotalUpgrade()); return unitOnRange(unit, range, rangedPtr, ast, evalMode); } bool UnitUpdater::findCachedCellsEnemies(Vec2i center, int range, int size, vector &enemies, const AttackSkillType *ast, const Unit *unit, const Unit *commandTarget) { bool result = false; MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__)); std::map > >::iterator iterFind = UnitRangeCellsLookupItemCache.find(center); if(iterFind != UnitRangeCellsLookupItemCache.end()) { std::map >::iterator iterFind3 = iterFind->second.find(size); if(iterFind3 != iterFind->second.end()) { std::map::iterator iterFind4 = iterFind3->second.find(range); if(iterFind4 != iterFind3->second.end()) { result = true; std::vector &cellList = iterFind4->second.rangeCellList; for(int idx = 0; idx < (int)cellList.size(); ++idx) { Cell *cell = cellList[idx]; findEnemiesForCell(ast,cell,unit,commandTarget,enemies); } } } } return result; } void UnitUpdater::findEnemiesForCell(const AttackSkillType *ast, Cell *cell, const Unit *unit, const Unit *commandTarget,vector &enemies) { //all fields for(int k = 0; k < fieldCount; k++) { Field f= static_cast(k); //check field if((ast == NULL || ast->getAttackField(f))) { Unit *possibleEnemy = cell->getUnit(f); //check enemy if(possibleEnemy != NULL && possibleEnemy->isAlive()) { if((unit->isAlly(possibleEnemy) == false && commandTarget == NULL) || commandTarget == possibleEnemy) { enemies.push_back(possibleEnemy); } } } } } void UnitUpdater::findEnemiesForCell(const Vec2i pos, int size, int sightRange, const Faction *faction, vector &enemies, bool attackersOnly) const { //all fields for(int k = 0; k < fieldCount; k++) { Field f= static_cast(k); for(int i = pos.x - sightRange; i < pos.x + size + sightRange; ++i) { for(int j = pos.y - sightRange; j < pos.y + size + sightRange; ++j) { Vec2i testPos(i,j); if( map->isInside(testPos) && map->isInsideSurface(map->toSurfCoords(testPos))) { Cell *cell = map->getCell(testPos); //check field Unit *possibleEnemy = cell->getUnit(f); //check enemy if(possibleEnemy != NULL && possibleEnemy->isAlive()) { if(faction->getTeam() != possibleEnemy->getTeam()) { if(attackersOnly == true) { if(possibleEnemy->getType()->hasCommandClass(ccAttack) || possibleEnemy->getType()->hasCommandClass(ccAttackStopped)) { enemies.push_back(possibleEnemy); } } else { enemies.push_back(possibleEnemy); } } } } } } } } //if the unit has any enemy on range bool UnitUpdater::unitOnRange(Unit *unit, int range, Unit **rangedPtr, const AttackSkillType *ast,bool evalMode) { bool result=false; try { vector enemies; enemies.reserve(100); //we check command target const Unit *commandTarget = NULL; if(unit->anyCommand() && unit->getCurrCommand() != NULL) { commandTarget = static_cast(unit->getCurrCommand()->getUnit()); } if(commandTarget != NULL && commandTarget->isDead()) { commandTarget = NULL; } //aux vars int size = unit->getType()->getSize(); Vec2i center = unit->getPos(); Vec2f floatCenter = unit->getFloatCenteredPos(); //bool foundInCache = true; if(findCachedCellsEnemies(center,range,size,enemies,ast, unit,commandTarget) == false) { //foundInCache = false; //nearby cells UnitRangeCellsLookupItem cacheItem; for(int i = center.x - range; i < center.x + range + size; ++i) { for(int j = center.y - range; j < center.y + range + size; ++j) { //cells inside map and in range #ifdef USE_STREFLOP if(map->isInside(i, j) && streflop::floor(static_cast(floatCenter.dist(Vec2f((float)i, (float)j)))) <= (range+1)) #else if(map->isInside(i, j) && floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)) #endif { Cell *cell = map->getCell(i,j); findEnemiesForCell(ast,cell,unit,commandTarget,enemies); cacheItem.rangeCellList.push_back(cell); } } } // Ok update our caches with the latest info if(cacheItem.rangeCellList.empty() == false) { MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__)); UnitRangeCellsLookupItemCache[center][size][range] = cacheItem; } } //attack enemies that can attack first float distToUnit= -1; Unit* enemySeen= NULL; std::vector fightingEnemiesInRange; std::vector damagedFightingEnemiesInRange; Unit* myFightingEnemyInRange= NULL; float distToStandingUnit= -1; Unit* attackingEnemySeen= NULL; ControlType controlType= unit->getFaction()->getControlType(); bool isUltra= controlType == ctCpuUltra || controlType == ctNetworkCpuUltra; bool isMega= controlType == ctCpuMega || controlType == ctNetworkCpuMega; string randomInfoData = "enemies.size() = " + intToStr(enemies.size()); //printf("unit %d has control:%d\n",unit->getId(),controlType); for(int i = 0; i< (int)enemies.size(); ++i) { Unit *enemy = enemies[i]; if(enemy != NULL && enemy->isAlive() == true) { // Here we default to first enemy if no attackers found if(enemySeen == NULL) { *rangedPtr = enemy; enemySeen = enemy; result = true; } //randomInfoData += " i = " + intToStr(i) + " alive = true result = " + intToStr(result); // Attackers get first priority if(enemy->getType()->hasSkillClass(scAttack) == true) { float currentDist = unit->getCenteredPos().dist(enemy->getCenteredPos()); //randomInfoData += " currentDist = " + floatToStr(currentDist); // Select closest attacking unit if (distToUnit < 0 || currentDist < distToUnit) { distToUnit = currentDist; *rangedPtr = enemy; enemySeen = enemy; result = true; } if (distToStandingUnit < 0 || currentDist < distToStandingUnit) { if (enemy->getCurrSkill() != NULL && enemy->getCurrSkill()->getClass() == scAttack) { distToStandingUnit = currentDist; attackingEnemySeen = enemy; } } if (enemy->getCurrSkill() != NULL && enemy->getCurrSkill()->getClass() == scAttack) { if(enemy->getId()==unit->getLastAttackedUnitId()) myFightingEnemyInRange=enemy; AttackSkillType* ast = (AttackSkillType*) (enemy->getCurrSkill()); int enemyAttackRange = ast->getTotalAttackRange(unit->getTotalUpgrade()); if (enemyAttackRange > 1) { fightingEnemiesInRange.push_back(enemy); if( unit->getHpRatio()<0.9){ damagedFightingEnemiesInRange.push_back(enemy); } } } } } } if (evalMode == false) { bool doUltra = false; if (isMega) { if (myFightingEnemyInRange != NULL) { //printf("Choosed my good old friend\n"); *rangedPtr = myFightingEnemyInRange; enemySeen = myFightingEnemyInRange; } else { unit->getRandom()->addLastCaller(randomInfoData); bool doit = unit->getRandom()->randRange(0, 2, extractFileFromDirectoryPath(__FILE__) + intToStr(__LINE__)) < 2; //printf("fightingEnemiesInRange.size()=%d\n",fightingEnemiesInRange.size()); if (fightingEnemiesInRange.size() > 0 && doit) { std::vector * unitList; if (damagedFightingEnemiesInRange.size() > 0) unitList = &damagedFightingEnemiesInRange; else unitList = &fightingEnemiesInRange; //printf("Choosing new one\n"); int myChoice = unit->getRandom()->randRange(1, unitList->size(), extractFileFromDirectoryPath(__FILE__) + intToStr(__LINE__)); //printf("myChoice=%d\n", myChoice); Unit* choosenOne = (*unitList)[myChoice - 1]; //printf("choosenOne=%s team=%d\n", choosenOne->getType()->getName().c_str(), choosenOne->getFactionIndex()); *rangedPtr = choosenOne; enemySeen = choosenOne; } else doUltra = true;; } } if ((isUltra || doUltra)) { unit->getRandom()->addLastCaller(randomInfoData); bool doit = unit->getRandom()->randRange(0, 2, extractFileFromDirectoryPath(__FILE__) + intToStr(__LINE__)) != 2; if (attackingEnemySeen != NULL && doit) { *rangedPtr = attackingEnemySeen; enemySeen = attackingEnemySeen; } } } if(result == true) { //const Unit* teamUnit = NULL; const Unit* enemyUnit = NULL; bool onlyEnemyUnits = true; if(unit->getTeam() == world->getThisTeamIndex()) { //teamUnit = unit; enemyUnit = enemySeen; onlyEnemyUnits = false; } else if(enemySeen->getTeam() == world->getThisTeamIndex()) { //teamUnit = enemySeen; enemyUnit = unit; onlyEnemyUnits = false; } if(evalMode == false && onlyEnemyUnits == false && enemyUnit->getTeam() != world->getThisTeamIndex()) { Vec2f enemyFloatCenter = enemyUnit->getFloatCenteredPos(); // find nearest Attack and cleanup old dates AttackWarningData *nearest = NULL; float currentDistance = 0.f; float nearestDistance = 0.f; MutexSafeWrapper safeMutex(mutexAttackWarnings,string(__FILE__) + "_" + intToStr(__LINE__)); for(int i = (int)attackWarnings.size() - 1; i >= 0; --i) { if(world->getFrameCount() - attackWarnings[i]->lastFrameCount > 200) { //after 200 frames attack break we warn again AttackWarningData *toDelete =attackWarnings[i]; attackWarnings.erase(attackWarnings.begin()+i); delete toDelete; // old one } else { #ifdef USE_STREFLOP currentDistance = streflop::floor(static_cast(enemyFloatCenter.dist(attackWarnings[i]->attackPosition))); // no need for streflops here! #else currentDistance = floor(enemyFloatCenter.dist(attackWarnings[i]->attackPosition)); // no need for streflops here! #endif if(nearest == NULL) { nearest = attackWarnings[i]; nearestDistance = currentDistance; } else { if(currentDistance < nearestDistance) { nearest = attackWarnings[i]; nearestDistance = currentDistance; } } } } if(nearest != NULL) { // does it fit? if(nearestDistance < attackWarnRange) { // update entry with current values nearest->lastFrameCount=world->getFrameCount(); nearest->attackPosition.x=enemyFloatCenter.x; nearest->attackPosition.y=enemyFloatCenter.y; } else { //Must be a different Attack! nearest=NULL; //set to null to force a new entry in next step } } // add new attack if(nearest == NULL) { // no else! AttackWarningData* awd= new AttackWarningData(); awd->lastFrameCount=world->getFrameCount(); awd->attackPosition.x=enemyFloatCenter.x; awd->attackPosition.y=enemyFloatCenter.y; MutexSafeWrapper safeMutex(mutexAttackWarnings,string(__FILE__) + "_" + intToStr(__LINE__)); attackWarnings.push_back(awd); if(world->getAttackWarningsEnabled() == true) { SoundRenderer::getInstance().playFx(CoreData::getInstance().getAttentionSound(),true); world->addAttackEffects(enemyUnit); } } } } } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } return result; } //if the unit has any enemy on range vector UnitUpdater::enemyUnitsOnRange(const Unit *unit,const AttackSkillType *ast) { vector enemies; enemies.reserve(100); try { int range = unit->getType()->getTotalSight(unit->getTotalUpgrade()); if(ast != NULL) { range = ast->getTotalAttackRange(unit->getTotalUpgrade()); } //we check command target const Unit *commandTarget = NULL; // if(unit->anyCommand()) { // commandTarget = static_cast(unit->getCurrCommand()->getUnit()); // } // if(commandTarget != NULL && commandTarget->isDead()) { // commandTarget = NULL; // } //aux vars int size = unit->getType()->getSize(); Vec2i center = unit->getPosNotThreadSafe(); Vec2f floatCenter = unit->getFloatCenteredPos(); //bool foundInCache = true; if(findCachedCellsEnemies(center,range,size,enemies,ast, unit,commandTarget) == false) { //foundInCache = false; //nearby cells UnitRangeCellsLookupItem cacheItem; for(int i = center.x - range; i < center.x + range + size; ++i) { for(int j = center.y - range; j < center.y + range + size; ++j) { //cells inside map and in range #ifdef USE_STREFLOP if(map->isInside(i, j) && streflop::floor(static_cast(floatCenter.dist(Vec2f((float)i, (float)j)))) <= (range+1)){ #else if(map->isInside(i, j) && floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)){ #endif Cell *cell = map->getCell(i,j); findEnemiesForCell(ast,cell,unit,commandTarget,enemies); cacheItem.rangeCellList.push_back(cell); } } } // Ok update our caches with the latest info if(cacheItem.rangeCellList.empty() == false) { MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__)); UnitRangeCellsLookupItemCache[center][size][range] = cacheItem; } } } catch(const exception &ex) { //setRunningStatus(false); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); throw megaglest_runtime_error(ex.what()); } catch(...) { char szBuf[8096]=""; snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); throw megaglest_runtime_error(szBuf); } return enemies; } void UnitUpdater::findUnitsForCell(Cell *cell, vector &units) { //all fields if(cell != NULL) { for(int k = 0; k < fieldCount; k++) { Field f= static_cast(k); //check field Unit *cellUnit = cell->getUnit(f); if(cellUnit != NULL && cellUnit->isAlive()) { // check if unit already is in list bool found = false; //printf("---- search for cellUnit=%d\n",cellUnit->getId()); for (unsigned int i = 0; i < units.size(); ++i) { Unit *unitInList = units[i]; //printf("compare unitInList=%d cellUnit=%d\n",unitInList->getId(),cellUnit->getId()); if (unitInList->getId() == cellUnit->getId()){ found=true; break; } } if(found==false){ //printf(">>> adding cellUnit=%d\n",cellUnit->getId()); units.push_back(cellUnit); } } } } } vector UnitUpdater::findUnitsInRange(const Unit *unit, int radius) { int range = radius; vector units; //aux vars int size = unit->getType()->getSize(); Vec2i center = unit->getPosNotThreadSafe(); Vec2f floatCenter = unit->getFloatCenteredPos(); //nearby cells //UnitRangeCellsLookupItem cacheItem; for(int i = center.x - range; i < center.x + range + size; ++i) { for(int j = center.y - range; j < center.y + range + size; ++j) { //cells inside map and in range #ifdef USE_STREFLOP if(map->isInside(i, j) && streflop::floor(static_cast(floatCenter.dist(Vec2f((float)i, (float)j)))) <= (range+1)){ #else if(map->isInside(i, j) && floor(floatCenter.dist(Vec2f((float)i, (float)j))) <= (range+1)){ #endif Cell *cell = map->getCell(i,j); findUnitsForCell(cell,units); } } } return units; } string UnitUpdater::getUnitRangeCellsLookupItemCacheStats() { string result = ""; int posCount = 0; int sizeCount = 0; int rangeCount = 0; int rangeCountCellCount = 0; MutexSafeWrapper safeMutex(mutexUnitRangeCellsLookupItemCache,string(__FILE__) + "_" + intToStr(__LINE__)); for(std::map > >::iterator iterMap1 = UnitRangeCellsLookupItemCache.begin(); iterMap1 != UnitRangeCellsLookupItemCache.end(); ++iterMap1) { posCount++; for(std::map >::iterator iterMap2 = iterMap1->second.begin(); iterMap2 != iterMap1->second.end(); ++iterMap2) { sizeCount++; for(std::map::iterator iterMap3 = iterMap2->second.begin(); iterMap3 != iterMap2->second.end(); ++iterMap3) { rangeCount++; rangeCountCellCount += (int)iterMap3->second.rangeCellList.size(); } } } uint64 totalBytes = rangeCountCellCount * sizeof(Cell *); totalBytes /= 1000; char szBuf[8096]=""; snprintf(szBuf,8096,"pos [%d] size [%d] range [%d][%d] total KB: %s",posCount,sizeCount,rangeCount,rangeCountCellCount,formatNumber(totalBytes).c_str()); result = szBuf; return result; } void UnitUpdater::saveGame(XmlNode *rootNode) { std::map mapTagReplacements; XmlNode *unitupdaterNode = rootNode->addChild("UnitUpdater"); // const GameCamera *gameCamera; // Gui *gui; // Map *map; // World *world; // Console *console; // ScriptManager *scriptManager; // PathFinder *pathFinder; pathFinder->saveGame(unitupdaterNode); // Game *game; // RandomGen random; //unitupdaterNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements); // float attackWarnRange; unitupdaterNode->addAttribute("attackWarnRange",floatToStr(attackWarnRange,6), mapTagReplacements); // AttackWarnings attackWarnings; // } void UnitUpdater::clearCaches() { if(pathFinder != NULL) { pathFinder->clearCaches(); } } void UnitUpdater::loadGame(const XmlNode *rootNode) { const XmlNode *unitupdaterNode = rootNode->getChild("UnitUpdater"); pathFinder->loadGame(unitupdaterNode); //random.setLastNumber(unitupdaterNode->getAttribute("random")->getIntValue()); // float attackWarnRange; attackWarnRange = unitupdaterNode->getAttribute("attackWarnRange")->getFloatValue(); } // ===================================================== // class ParticleDamager // ===================================================== ParticleDamager::ParticleDamager(Unit *attacker,const ProjectileType* projectileType, UnitUpdater *unitUpdater, const GameCamera *gameCamera){ this->gameCamera= gameCamera; this->attackerRef= attacker; this->projectileType= projectileType; this->ast= static_cast(attacker->getCurrSkill()); this->targetPos= attacker->getTargetPos(); this->targetField= attacker->getTargetField(); this->unitUpdater= unitUpdater; } void ParticleDamager::update(ParticleSystem *particleSystem) { Unit *attacker= attackerRef.getUnit(); if(attacker != NULL) { //string auditBeforeHit = particleSystem->toString(); char szBuf[8096]=""; snprintf(szBuf,8095,"Unit hitting [ParticleDamager::update] [%s] targetField = %d",targetPos.getString().c_str(),targetField); attacker->addNetworkCRCDecHp(szBuf); unitUpdater->hit(attacker, ast, targetPos, targetField, projectileType->getDamagePercentage()); //char szBuf[8096]=""; //snprintf(szBuf,8095,"ParticleDamager::update attacker particleSystem before: %s\nafter: %s",auditBeforeHit.c_str(),particleSystem->toString().c_str()); //attacker->setNetworkCRCParticleObserverLogInfo(szBuf); //play sound // Try to use the sound form the projetileType StaticSound *projSound=projectileType->getHitSound(); if(projSound == NULL){ // use the sound from the skill projSound= ast->getProjSound(); } if(particleSystem->getVisible() && projSound != NULL) { SoundRenderer::getInstance().playFx(projSound, attacker->getCurrMidHeightVector(), gameCamera->getPos()); } //check for spawnattack if(projectileType->getSpawnUnit()!="" && projectileType->getSpawnUnitcount()>0 ){ unitUpdater->spawnAttack(attacker, projectileType->getSpawnUnit(), projectileType->getSpawnUnitcount(), 100, 100, 100, projectileType->getSpawnUnitAtTarget(), targetPos); } // check for shake and shake if(projectileType->isShake()==true){ World *world=attacker->getFaction()->getWorld(); Map* map=world->getMap(); Game *game=world->getGame(); //Unit *attacked= map->getCell(targetPos)->getUnit(targetField); Vec2i surfaceTargetPos=Map::toSurfCoords(targetPos); bool visibility=(!projectileType->isShakeVisible())||(map->getSurfaceCell(surfaceTargetPos)->isVisible(world->getThisTeamIndex()) || (game->getWorld()->showWorldForPlayer(game->getWorld()->getThisTeamIndex()) == true)); bool isInCameraView=(!projectileType->isShakeInCameraView()) || Renderer::getInstance().posInCellQuadCache(surfaceTargetPos).first; if(visibility && isInCameraView) { game->getGameCameraPtr()->shake( projectileType->getShakeDuration(), projectileType->getShakeIntensity(),projectileType->isShakeCameraDistanceAffected(),map->getSurfaceCell(surfaceTargetPos)->getVertex()); } } } particleSystem->setObserver(NULL); delete this; } void ParticleDamager::saveGame(XmlNode *rootNode) { std::map mapTagReplacements; XmlNode *particleDamagerNode = rootNode->addChild("ParticleDamager"); // UnitReference attackerRef; attackerRef.saveGame(particleDamagerNode); // const AttackSkillType* ast; particleDamagerNode->addAttribute("astName",ast->getName(), mapTagReplacements); particleDamagerNode->addAttribute("astClass",intToStr(ast->getClass()), mapTagReplacements); // UnitUpdater *unitUpdater; // const GameCamera *gameCamera; // Vec2i targetPos; particleDamagerNode->addAttribute("targetPos",targetPos.getString(), mapTagReplacements); // Field targetField; particleDamagerNode->addAttribute("targetField",intToStr(targetField), mapTagReplacements); } void ParticleDamager::loadGame(const XmlNode *rootNode, void *genericData) { const XmlNode *particleDamagerNode = rootNode->getChild("ParticleDamager"); std::pair *pairData = (std::pair*)genericData; //UnitType *ut, Game *game attackerRef.loadGame(particleDamagerNode,pairData->first->getWorld()); //random.setLastNumber(particleSystemNode->getAttribute("random")->getIntValue()); // const AttackSkillType* ast; string astName = particleDamagerNode->getAttribute("astName")->getValue(); SkillClass astClass = static_cast(particleDamagerNode->getAttribute("astClass")->getIntValue()); ast = dynamic_cast(pairData->second->getType()->getSkillType(astName,astClass)); // UnitUpdater *unitUpdater; unitUpdater = pairData->first->getWorld()->getUnitUpdater(); // const GameCamera *gameCamera; gameCamera = pairData->first->getGameCamera(); // Vec2i targetPos; targetPos = Vec2i::strToVec2(particleDamagerNode->getAttribute("targetPos")->getValue()); // Field targetField; targetField = static_cast(particleDamagerNode->getAttribute("targetField")->getIntValue()); } }}//end namespace