void CFactoryCAI::SlowUpdate() { if (commandQue.empty() || owner->beingBuilt) { return; } CFactory* fac=(CFactory*)owner; unsigned int oldSize; do { Command& c=commandQue.front(); oldSize=commandQue.size(); map<int,BuildOption>::iterator boi; if((boi=buildOptions.find(c.id))!=buildOptions.end()){ const UnitDef *def = unitDefHandler->GetUnitByName(boi->second.name); if(building){ if(!fac->curBuild && !fac->quedBuild){ building=false; if(owner->group) owner->group->CommandFinished(owner->id,commandQue.front().id); if(!repeatOrders || c.options & DONT_REPEAT) boi->second.numQued--; UpdateIconName(c.id,boi->second); FinishCommand(); } // This can only be true if two factories started building // the restricted unit in the same simulation frame else if(uh->unitsByDefs[owner->team][def->id].size() > def->maxThisUnit){ //unit restricted? CFactory* fac=(CFactory*)owner; building = false; fac->StopBuild(); CancelRestrictedUnit(c, boi->second); } } else { const UnitDef *def = unitDefHandler->GetUnitByName(boi->second.name); if(luaRules && !luaRules->AllowUnitCreation(def, owner, NULL)) { if(!repeatOrders || c.options & DONT_REPEAT){ boi->second.numQued--; } UpdateIconName(c.id,boi->second); FinishCommand(); } else if(uh->unitsByDefs[owner->team][def->id].size() >= def->maxThisUnit){ //unit restricted? CancelRestrictedUnit(c, boi->second); } else if(uh->maxUnits>gs->Team(owner->team)->units.size()){ //max unitlimit reached? fac->StartBuild(boi->second.fullName); building=true; } } } else { switch(c.id){ case CMD_STOP: { ExecuteStop(c); break; } default: { CCommandAI::SlowUpdate(); return; } } } } while ((oldSize != commandQue.size()) && !commandQue.empty()); return; }
void CBuilderCAI::SlowUpdate() { if (commandQue.empty()) { CMobileCAI::SlowUpdate(); return; } if (owner->stunned) { return; } CBuilder* fac = (CBuilder*)owner; Command& c = commandQue.front(); if (OutOfImmobileRange(c)) { FinishCommand(); return; } map<int, string>::iterator boi = buildOptions.find(c.id); if (!owner->beingBuilt && boi != buildOptions.end()) { const UnitDef* ud = unitDefHandler->GetUnitByName(boi->second); const float radius = GetUnitDefRadius(ud, c.id); if (inCommand) { if (building) { if (f3SqDist(build.pos, fac->pos) > Square(fac->buildDistance + radius - 8.0f)) { owner->moveType->StartMoving(build.pos, fac->buildDistance * 0.5f + radius); } else { StopMove(); // needed since above startmoving cancels this owner->moveType->KeepPointingTo(build.pos, (fac->buildDistance + radius) * 0.6f, false); } if (!fac->curBuild && !fac->terraforming) { building = false; StopMove(); //cancel the effect of KeepPointingTo FinishCommand(); } // This can only be true if two builders started building // the restricted unit in the same simulation frame else if (uh->unitsByDefs[owner->team][build.def->id].size() > build.def->maxThisUnit) { // unit restricted building = false; fac->StopBuild(); CancelRestrictedUnit(boi->second); } } else { build.Parse(c); if (uh->unitsByDefs[owner->team][build.def->id].size() >= build.def->maxThisUnit) { // unit restricted, don't bother moving all the way // to the construction site first before telling us // (since greyed-out icons can still be clicked etc, // would be better to prevent that but doesn't cover // case where limit reached while builder en-route) CancelRestrictedUnit(boi->second); StopMove(); } else { build.pos = helper->Pos2BuildPos(build); const float sqdist = f3SqDist(build.pos, fac->pos); if ((sqdist < Square(fac->buildDistance * 0.6f + radius)) || (!owner->unitDef->canmove && (sqdist <= Square(fac->buildDistance + radius - 8.0f)))) { StopMove(); if (luaRules && !luaRules->AllowUnitCreation(build.def, owner, &build.pos)) { FinishCommand(); } else if (uh->maxUnits > (int) teamHandler->Team(owner->team)->units.size()) { // max unitlimit reached buildRetries++; owner->moveType->KeepPointingTo(build.pos, fac->buildDistance * 0.7f + radius, false); if (fac->StartBuild(build) || (buildRetries > 20)) { building = true; } else { ENTER_MIXED; if ((owner->team == gu->myTeam) && !(buildRetries & 7)) { logOutput.Print("%s: Build pos blocked", owner->unitDef->humanName.c_str()); logOutput.SetLastMsgPos(owner->pos); } ENTER_SYNCED; helper->BuggerOff(build.pos, radius); NonMoving(); } } } else { if (owner->moveType->progressState == AMoveType::Failed) { if (++buildRetries > 5) { StopMove(); FinishCommand(); } } SetGoal(build.pos, owner->pos, fac->buildDistance * 0.4f + radius); } } } } else { //!inCommand BuildInfo bi; bi.pos.x=floor(c.params[0]/SQUARE_SIZE+0.5f)*SQUARE_SIZE; bi.pos.z=floor(c.params[2]/SQUARE_SIZE+0.5f)*SQUARE_SIZE; bi.pos.y=c.params[1]; CFeature* f=0; if (c.params.size()==4) bi.buildFacing = int(c.params[3]); bi.def = unitDefHandler->GetUnitByName(boi->second); uh->TestUnitBuildSquare(bi,f,owner->allyteam); if (f) { if (!owner->unitDef->canReclaim || !f->def->reclaimable) { // FIXME user shouldn't be able to queue buildings on top of features // in the first place (in this case). StopMove(); FinishCommand(); } else { Command c2; c2.id=CMD_RECLAIM; c2.options=0; c2.params.push_back(f->id+MAX_UNITS); commandQue.push_front(c2); SlowUpdate(); //this assumes that the reclaim command can never return directly without having reclaimed the target } } else { inCommand=true; SlowUpdate(); } } return; } switch (c.id) { case CMD_STOP: { ExecuteStop(c); return; } case CMD_REPAIR: { ExecuteRepair(c); return; } case CMD_CAPTURE: { ExecuteCapture(c); return; } case CMD_GUARD: { ExecuteGuard(c); return; } case CMD_RECLAIM: { ExecuteReclaim(c); return; } case CMD_RESURRECT: { ExecuteResurrect(c); return; } case CMD_PATROL: { ExecutePatrol(c); return; } case CMD_FIGHT: { ExecuteFight(c); return; } case CMD_RESTORE: { ExecuteRestore(c); return; } default: { CMobileCAI::SlowUpdate(); return; } } }
void CBuilderCAI::ExecuteBuildCmd(Command& c) { CBuilder* builder = (CBuilder*) owner; map<int, string>::iterator boi = buildOptions.find(c.GetID()); if (boi == buildOptions.end()) return; if (!inCommand) { BuildInfo bi; bi.pos.x = floor(c.params[0] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE; bi.pos.z = floor(c.params[2] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE; bi.pos.y = c.params[1]; if (c.params.size() == 4) bi.buildFacing = abs((int)c.params[3]) % NUM_FACINGS; bi.def = unitDefHandler->GetUnitDefByName(boi->second); CFeature* f = NULL; uh->TestUnitBuildSquare(bi, f, owner->allyteam, true); if (f != NULL) { if (!bi.def->isFeature || bi.def->wreckName != f->def->name) { ReclaimFeature(f); } else { FinishCommand(); } } else { inCommand = true; build.Parse(c); ExecuteBuildCmd(c); } return; } assert(build.def); const float radius = GetBuildOptionRadius(build.def, c.GetID()); if (building) { MoveInBuildRange(build.pos, radius); if (!builder->curBuild && !builder->terraforming) { building = false; StopMove(); // cancel the effect of KeepPointingTo FinishCommand(); } // This can only be true if two builders started building // the restricted unit in the same simulation frame else if (uh->unitsByDefs[owner->team][build.def->id].size() > build.def->maxThisUnit) { // unit restricted building = false; builder->StopBuild(); CancelRestrictedUnit(boi->second); } } else { if (uh->unitsByDefs[owner->team][build.def->id].size() >= build.def->maxThisUnit) { // unit restricted, don't bother moving all the way // to the construction site first before telling us // (since greyed-out icons can still be clicked etc, // would be better to prevent that but doesn't cover // case where limit reached while builder en-route) CancelRestrictedUnit(boi->second); StopMove(); return; } build.pos = helper->Pos2BuildPos(build, true); // we are on the way to the buildpos, meanwhile it can happen // that another builder already finished our buildcmd or blocked // the buildpos with another building (skip our buildcmd then) const bool checkBuildPos = (gs->frameNum % (5 * UNIT_SLOWUPDATE_RATE)) < UNIT_SLOWUPDATE_RATE; //FIXME add a per-unit solution to better balance the load? CFeature* feature = NULL; if (checkBuildPos && !uh->TestUnitBuildSquare(build, feature, owner->allyteam, true)) { if (!feature) { const int yardxpos = int(build.pos.x + 4) / SQUARE_SIZE; const int yardypos = int(build.pos.z + 4) / SQUARE_SIZE; const CSolidObject* s = groundBlockingObjectMap->GroundBlocked(yardxpos, yardypos); const CUnit* u = dynamic_cast<const CUnit*>(s); if (u != NULL) { const bool canAssist = u->beingBuilt && owner->unitDef->canAssist && (!u->soloBuilder || (u->soloBuilder == owner)); if ((u->unitDef != build.def) || !canAssist) { StopMove(); FinishCommand(); return; } } } } if (MoveInBuildRange(build.pos, radius, true)) { if (luaRules && !luaRules->AllowUnitCreation(build.def, owner, &build)) { StopMove(); // cancel KeepPointingTo FinishCommand(); } else if (!teamHandler->Team(owner->team)->AtUnitLimit()) { // unit-limit not yet reached CFeature* f = NULL; bool waitstance = false; if (builder->StartBuild(build, f, waitstance) || (++buildRetries > 30)) { building = true; } else if (f != NULL && (!build.def->isFeature || build.def->wreckName != f->def->name)) { inCommand = false; ReclaimFeature(f); } else if (!waitstance) { const float fpSqRadius = (build.def->xsize * build.def->xsize + build.def->zsize * build.def->zsize); const float fpRadius = (math::sqrt(fpSqRadius) * 0.5f) * SQUARE_SIZE; // tell everything within the radius of the soon-to-be buildee // to get out of the way; using the model radius is not correct // because this can be shorter than half the footprint diagonal helper->BuggerOff(build.pos, std::max(radius, fpRadius), false, true, owner->team, NULL); NonMoving(); } } } else { if (owner->moveType->progressState == AMoveType::Failed) { if (++buildRetries > 5) { StopMove(); FinishCommand(); } } } } }
void CBuilderCAI::ExecuteBuildCmd(Command& c) { const map<int, string>::const_iterator boi = buildOptions.find(c.GetID()); if (boi == buildOptions.end()) return; if (!inCommand) { BuildInfo bi; bi.pos.x = math::floor(c.params[0] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE; bi.pos.z = math::floor(c.params[2] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE; bi.pos.y = c.params[1]; if (c.params.size() == 4) bi.buildFacing = abs((int)c.params[3]) % NUM_FACINGS; bi.def = unitDefHandler->GetUnitDefByName(boi->second); CFeature* f = NULL; CGameHelper::TestUnitBuildSquare(bi, f, owner->allyteam, true); if (f != NULL) { if (!bi.def->isFeature || bi.def->wreckName != f->def->name) { ReclaimFeature(f); } else { FinishCommand(); } return; } inCommand = true; build.Parse(c); } assert(build.def->id == -c.GetID() && build.def->id != 0); const float buildeeRadius = GetBuildOptionRadius(build.def, c.GetID()); if (building) { // keep moving until 3D distance to buildPos is LEQ our buildDistance MoveInBuildRange(build.pos, 0.0f); if (!ownerBuilder->curBuild && !ownerBuilder->terraforming) { building = false; StopMove(); // cancel the effect of KeepPointingTo FinishCommand(); } // This can only be true if two builders started building // the restricted unit in the same simulation frame else if (unitHandler->unitsByDefs[owner->team][build.def->id].size() > build.def->maxThisUnit) { // unit restricted building = false; ownerBuilder->StopBuild(); CancelRestrictedUnit(boi->second); } } else { if (unitHandler->unitsByDefs[owner->team][build.def->id].size() >= build.def->maxThisUnit) { // unit restricted, don't bother moving all the way // to the construction site first before telling us // (since greyed-out icons can still be clicked etc, // would be better to prevent that but doesn't cover // case where limit reached while builder en-route) CancelRestrictedUnit(boi->second); StopMove(); return; } build.pos = CGameHelper::Pos2BuildPos(build, true); // keep moving until until 3D distance to buildPos is LEQ our buildDistance if (MoveInBuildRange(build.pos, 0.0f, true)) { if (IsBuildPosBlocked(build)) { StopMove(); FinishCommand(); return; } if (!eventHandler.AllowUnitCreation(build.def, owner, &build)) { StopMove(); // cancel KeepPointingTo FinishCommand(); return; } if (teamHandler->Team(owner->team)->AtUnitLimit()) { return; } CFeature* f = NULL; bool waitstance = false; if (ownerBuilder->StartBuild(build, f, waitstance) || (++buildRetries > 30)) { building = true; } else if (f != NULL && (!build.def->isFeature || build.def->wreckName != f->def->name)) { inCommand = false; ReclaimFeature(f); } else if (!waitstance) { const float fpSqRadius = (build.def->xsize * build.def->xsize + build.def->zsize * build.def->zsize); const float fpRadius = (math::sqrt(fpSqRadius) * 0.5f) * SQUARE_SIZE; // tell everything within the radius of the soon-to-be buildee // to get out of the way; using the model radius is not correct // because this can be shorter than half the footprint diagonal CGameHelper::BuggerOff(build.pos, std::max(buildeeRadius, fpRadius), false, true, owner->team, NULL); NonMoving(); } } else { if (owner->moveType->progressState == AMoveType::Failed) { if (++buildRetries > 5) { StopMove(); FinishCommand(); return; } } // we are on the way to the buildpos, meanwhile it can happen // that another builder already finished our buildcmd or blocked // the buildpos with another building (skip our buildcmd then) if ((++randomCounter % 5) == 0) { if (IsBuildPosBlocked(build)) { StopMove(); FinishCommand(); return; } } } } }