bool CTransportCAI::AllowedCommand(const Command& c, bool fromSynced) { if (!CMobileCAI::AllowedCommand(c, fromSynced)) { return false; } switch (c.GetID()) { case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: { const CTransportUnit* transport = static_cast<CTransportUnit*>(owner); const std::list<CTransportUnit::TransportedUnit>& transportees = transport->GetTransportedUnits(); // allow unloading empty transports for easier setup of transport bridges if (transportees.empty()) return true; if (c.GetParamsCount() == 5) { if (fromSynced) { // point transported buildings (...) in their wanted direction after unloading for (auto it = transportees.begin(); it != transportees.end(); ++it) { CBuilding* building = dynamic_cast<CBuilding*>(it->unit); if (building == NULL) continue; building->buildFacing = std::abs(int(c.GetParam(4))) % NUM_FACINGS; } } } if (c.GetParamsCount() >= 4) { // find unload positions for transportees (WHY can this run in unsynced context?) for (auto it = transportees.begin(); it != transportees.end(); ++it) { CUnit* u = it->unit; const float radius = (c.GetID() == CMD_UNLOAD_UNITS)? c.GetParam(3): 0.0f; const float spread = u->radius * transport->unitDef->unloadSpread; float3 foundPos; if (FindEmptySpot(c.GetPos(0), radius, spread, foundPos, u, fromSynced)) { return true; } // FIXME: support arbitrary unloading order for other unload types also if (unloadType != UNLOAD_LAND) { return false; } } // no empty spot found for any transported unit return false; } break; } } return true; }
bool CAirCAI::SelectNewAreaAttackTargetOrPos(const Command& ac) { assert(ac.GetID() == CMD_AREA_ATTACK || (ac.GetID() == CMD_ATTACK && ac.GetParamsCount() >= 3)); if (ac.GetID() == CMD_ATTACK) { FinishCommand(); return false; } const float3& pos = ac.GetPos(0); const float radius = ac.params[3]; std::vector<int> enemyUnitIDs; CGameHelper::GetEnemyUnits(pos, radius, owner->allyteam, enemyUnitIDs); if (enemyUnitIDs.empty()) { float3 attackPos = pos + (gs->randVector() * radius); attackPos.y = CGround::GetHeightAboveWater(attackPos.x, attackPos.z); owner->AttackGround(attackPos, (ac.options & INTERNAL_ORDER) == 0, false); SetGoal(attackPos, owner->pos); } else { // note: the range of randFloat() is inclusive of 1.0f const unsigned int unitIdx = std::min<int>(gs->randFloat() * enemyUnitIDs.size(), enemyUnitIDs.size() - 1); const unsigned int unitID = enemyUnitIDs[unitIdx]; CUnit* targetUnit = unitHandler->GetUnitUnsafe(unitID); SetOrderTarget(targetUnit); owner->AttackUnit(targetUnit, (ac.options & INTERNAL_ORDER) == 0, false); SetGoal(targetUnit->pos, owner->pos); } return true; }
void CSelectedUnitsHandlerAI::GiveCommandNet(Command &c, int player) { const std::vector<int>& netSelected = selectedUnitsHandler.netSelected[player]; std::vector<int>::const_iterator ui; const int nbrOfSelectedUnits = netSelected.size(); const int cmd_id = c.GetID(); if (nbrOfSelectedUnits < 1) { // no units to command } else if ((cmd_id == CMD_ATTACK) && ( (c.GetParamsCount() == 6) || ((c.GetParamsCount() == 4) && (c.GetParam(3) > 0.001f)) )) { SelectAttack(c, player); } else if (nbrOfSelectedUnits == 1) { // a single unit selected CUnit* unit = unitHandler->GetUnit(*netSelected.begin()); if (unit != nullptr) { unit->commandAI->GiveCommand(c, true); if (MayRequireSetMaxSpeedCommand(c)) AddUnitSetMaxSpeedCommand(unit, c.options); if (cmd_id == CMD_WAIT) { if (player == gu->myPlayerNum) { waitCommandsAI.AcknowledgeCommand(c); } } } } // User Move Front Command: // // CTRL: Group Front/Speed command // // User Move Command: // // ALT: Group Front command // ALT+CTRL: Group Front/Speed command // CTRL: Group Locked/Speed command (maintain relative positions) // // User Patrol and Fight Commands: // // CTRL: Group Locked/Speed command (maintain relative positions) // ALT+CTRL: Group Locked command (maintain relative positions) // else if (((cmd_id == CMD_MOVE) || (cmd_id == CMD_FIGHT)) && (c.GetParamsCount() == 6)) { CalculateGroupData(player, !!(c.options & SHIFT_KEY)); MakeFrontMove(&c, player); const bool groupSpeed = !!(c.options & CONTROL_KEY); for (ui = netSelected.begin(); ui != netSelected.end(); ++ui) { CUnit* unit = unitHandler->GetUnit(*ui); if (unit != nullptr) { if (groupSpeed) { AddGroupSetMaxSpeedCommand(unit, c.options); } else { AddUnitSetMaxSpeedCommand(unit, c.options); } } } } else if ((cmd_id == CMD_MOVE) && (c.options & ALT_KEY)) { CalculateGroupData(player, !!(c.options & SHIFT_KEY)); // use the vector from the middle of group to new pos as forward dir const float3 pos(c.GetParam(0), c.GetParam(1), c.GetParam(2)); float3 frontdir = pos - centerCoor; frontdir.y = 0.0f; frontdir.ANormalize(); const float3 sideDir = frontdir.cross(UpVector); // calculate so that the units form in an aproximate square float length = 100.0f + (math::sqrt((float)nbrOfSelectedUnits) * 32.0f); // push back some extra params so it confer with a front move c.PushPos(pos + (sideDir * length)); MakeFrontMove(&c, player); const bool groupSpeed = !!(c.options & CONTROL_KEY); for (ui = netSelected.begin(); ui != netSelected.end(); ++ui) { CUnit* unit = unitHandler->GetUnit(*ui); if (unit != nullptr) { if (groupSpeed) { AddGroupSetMaxSpeedCommand(unit, c.options); } else { AddUnitSetMaxSpeedCommand(unit, c.options); } } } } else if ((c.options & CONTROL_KEY) && ((cmd_id == CMD_MOVE) || (cmd_id == CMD_PATROL) || (cmd_id == CMD_FIGHT))) { CalculateGroupData(player, !!(c.options & SHIFT_KEY)); const bool groupSpeed = !(c.options & ALT_KEY); for (ui = netSelected.begin(); ui != netSelected.end(); ++ui) { CUnit* unit = unitHandler->GetUnit(*ui); if (unit != nullptr) { // Modifying the destination relative to the center of the group Command uc = c; float3 midPos; if (c.options & SHIFT_KEY) { midPos = LastQueuePosition(unit); } else { midPos = unit->midPos; } uc.params[CMDPARAM_MOVE_X] += midPos.x - centerCoor.x; uc.params[CMDPARAM_MOVE_Y] += midPos.y - centerCoor.y; uc.params[CMDPARAM_MOVE_Z] += midPos.z - centerCoor.z; unit->commandAI->GiveCommand(uc, false); if (groupSpeed) { AddGroupSetMaxSpeedCommand(unit, c.options); } else { AddUnitSetMaxSpeedCommand(unit, c.options); } } } } else { for (ui = netSelected.begin(); ui != netSelected.end(); ++ui) { CUnit* unit = unitHandler->GetUnit(*ui); if (unit != nullptr) { // appending a CMD_SET_WANTED_MAX_SPEED command to // every command is a little bit wasteful, n'est pas? unit->commandAI->GiveCommand(c, false); if (MayRequireSetMaxSpeedCommand(c)) { AddUnitSetMaxSpeedCommand(unit, c.options); } } } if (cmd_id == CMD_WAIT) { if (player == gu->myPlayerNum) { waitCommandsAI.AcknowledgeCommand(c); } } } }