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; } } } } }