inline void CSelectedUnitsAI::AddUnitSetMaxSpeedCommand(CUnit* unit, unsigned char options) { // sets the wanted speed of this unit to its max speed CCommandAI* cai = unit->commandAI; if (cai->CanSetMaxSpeed()) { Command c(CMD_SET_WANTED_MAX_SPEED, options); c.AddParam(unit->moveType->GetMaxSpeed()); cai->GiveCommand(c, false); } }
inline void CSelectedUnitsAI::AddUnitSetMaxSpeedCommand(CUnit* unit, unsigned char options) { // sets the wanted speed of this unit to its max speed CCommandAI* cai = unit->commandAI; if (cai->CanSetMaxSpeed()) { Command c; c.id = CMD_SET_WANTED_MAX_SPEED; c.options = options; c.params.push_back(unit->maxSpeed); cai->GiveCommand(c, false); } }
inline void CSelectedUnitsAI::AddGroupSetMaxSpeedCommand(CUnit* unit, unsigned char options) { // sets the wanted speed of this unit to the group minimum // (note: was being divided by GAME_SPEED, but minMaxSpeed // is already in units per frame) CCommandAI* cai = unit->commandAI; if (cai->CanSetMaxSpeed()) { Command c(CMD_SET_WANTED_MAX_SPEED, options); c.AddParam(minMaxSpeed); cai->GiveCommand(c, false); } }
inline void CSelectedUnitsAI::AddGroupSetMaxSpeedCommand(CUnit* unit, unsigned char options) { // sets the wanted speed of this unit to the group minimum CCommandAI* cai = unit->commandAI; if (cai->CanSetMaxSpeed()) { Command c; c.id = CMD_SET_WANTED_MAX_SPEED; c.options = options; c.params.push_back(minMaxSpeed / 30.0f); cai->GiveCommand(c); } }
inline void CSelectedUnitsHandlerAI::AddGroupSetMaxSpeedCommand(CUnit* unit, unsigned char options) { // sets the wanted speed of this unit to that of // the group's current-slowest member (minMaxSpeed // is derived from GetMaxSpeed, not GetMaxSpeedDef) CCommandAI* cai = unit->commandAI; if (cai->CanSetMaxSpeed()) { Command c(CMD_SET_WANTED_MAX_SPEED, options, minMaxSpeed); cai->GiveCommand(c, false); } }
inline void CSelectedUnitsHandlerAI::AddUnitSetMaxSpeedCommand(CUnit* unit, unsigned char options) { // this sets the WANTED maximum speed of <unit> // (via the CommandAI --> MoveType chain) to be // equal to its current ACTUAL maximum (not the // UnitDef maximum, which can be overridden by // scripts) CCommandAI* cai = unit->commandAI; if (cai->CanSetMaxSpeed()) { Command c(CMD_SET_WANTED_MAX_SPEED, options, unit->moveType->GetMaxSpeed()); cai->GiveCommand(c, false); } }
void CSelectedUnitsAI::SelectAttack(const Command& cmd, int player) { vector<int> targets; const float3 pos0(cmd.params[0], cmd.params[1], cmd.params[2]); if (cmd.params.size() == 4) { SelectCircleUnits(pos0, cmd.params[3], targets, player); } else { const float3 pos1(cmd.params[3], cmd.params[4], cmd.params[5]); SelectRectangleUnits(pos0, pos1, targets, player); } const int targetsCount = (int)targets.size(); if (targets.size() <= 0) { return; } const vector<int>& selected = selectedUnits.netSelected[player]; const int selectedCount = (int)selected.size(); if (selectedCount <= 0) { return; } Command attackCmd; attackCmd.id = CMD_ATTACK; attackCmd.options = cmd.options; attackCmd.params.push_back(0.0f); // dummy // delete the attack commands and bail for CONTROL_KEY if (cmd.options & CONTROL_KEY) { attackCmd.options |= SHIFT_KEY; for (int s = 0; s < selectedCount; s++) { CUnit* unit = uh->units[selected[s]]; if (unit == NULL) { continue; } CCommandAI* commandAI = uh->units[selected[s]]->commandAI; for (int t = 0; t < targetsCount; t++) { attackCmd.params[0] = targets[t]; if (commandAI->WillCancelQueued(attackCmd)) { commandAI->GiveCommand(attackCmd, false); } } } return; } const bool queueing = !!(cmd.options & SHIFT_KEY); // get the group center float3 midPos(0.0f, 0.0f, 0.0f); int realCount = 0; for (int s = 0; s < selectedCount; s++) { CUnit* unit = uh->units[selected[s]]; if (unit == NULL) { continue; } if (queueing) { midPos += LastQueuePosition(unit); } else { midPos += unit->midPos; } realCount++; } if (realCount <= 0) { return; } midPos /= (float)realCount; // sort the targets vector<DistInfo> distVec; int t; for (t = 0; t < targetsCount; t++) { DistInfo di; di.unitID = targets[t]; CUnit* unit = uh->units[di.unitID]; const float3 unitPos = queueing ? LastQueuePosition(unit) : float3(unit->midPos); di.dist = (unitPos - midPos).SqLength2D(); distVec.push_back(di); } sort(distVec.begin(), distVec.end()); // give the commands for (int s = 0; s < selectedCount; s++) { if (!queueing) { // clear it for the first command attackCmd.options &= ~SHIFT_KEY; } CUnit* unit = uh->units[selected[s]]; if (unit == NULL) { continue; } CCommandAI* commandAI = unit->commandAI; for (t = 0; t < targetsCount; t++) { attackCmd.params[0] = distVec[t].unitID; if (!queueing || !commandAI->WillCancelQueued(attackCmd)) { commandAI->GiveCommand(attackCmd, false); AddUnitSetMaxSpeedCommand(unit, attackCmd.options); // following commands are always queued attackCmd.options |= SHIFT_KEY; } } } }
void CSelectedUnitsHandlerAI::SelectAttack(const Command& cmd, int player) { std::vector<int> targets; if (cmd.params.size() == 4) { SelectCircleUnits(cmd.GetPos(0), cmd.params[3], player, targets); } else { SelectRectangleUnits(cmd.GetPos(0), cmd.GetPos(3), player, targets); } if (targets.empty()) return; const bool queueing = !!(cmd.options & SHIFT_KEY); const std::vector<int>& selected = selectedUnitsHandler.netSelected[player]; const unsigned int targetsCount = targets.size(); const unsigned int selectedCount = selected.size(); if (selectedCount == 0) return; Command attackCmd(CMD_ATTACK, cmd.options, 0.0f); // delete the attack commands and bail for CONTROL_KEY if (cmd.options & CONTROL_KEY) { attackCmd.options |= SHIFT_KEY; for (unsigned int s = 0; s < selectedCount; s++) { const CUnit* unit = unitHandler->GetUnit( selected[s] ); if (unit == nullptr) continue; CCommandAI* commandAI = unit->commandAI; for (unsigned int t = 0; t < targetsCount; t++) { attackCmd.params[0] = targets[t]; if (commandAI->WillCancelQueued(attackCmd)) { commandAI->GiveCommand(attackCmd, false); } } } return; } // get the group center float3 midPos; unsigned int realCount = 0; for (unsigned int s = 0; s < selectedCount; s++) { CUnit* unit = unitHandler->GetUnit(selected[s]); if (unit == nullptr) continue; if (queueing) { midPos += LastQueuePosition(unit); } else { midPos += unit->midPos; } realCount++; } if (realCount == 0) return; midPos /= realCount; // sort the targets std::vector<DistInfo> distVec; for (unsigned int t = 0; t < targetsCount; t++) { const CUnit* unit = unitHandler->GetUnit( targets[t] ); const float3 unitPos = float3(unit->midPos); DistInfo di; di.unitID = targets[t]; di.dist = (unitPos - midPos).SqLength2D(); distVec.push_back(di); } stable_sort(distVec.begin(), distVec.end()); // give the commands for (unsigned int s = 0; s < selectedCount; s++) { if (!queueing) { // clear it for the first command attackCmd.options &= ~SHIFT_KEY; } CUnit* unit = unitHandler->GetUnit(selected[s]); if (unit == nullptr) continue; CCommandAI* commandAI = unit->commandAI; for (unsigned t = 0; t < targetsCount; t++) { attackCmd.params[0] = distVec[t].unitID; if (!queueing || !commandAI->WillCancelQueued(attackCmd)) { commandAI->GiveCommand(attackCmd, false); AddUnitSetMaxSpeedCommand(unit, attackCmd.options); // following commands are always queued attackCmd.options |= SHIFT_KEY; } } } }
void CFactory::AssignBuildeeOrders(CUnit* unit) { CCommandAI* unitCAI = unit->commandAI; CCommandQueue& unitCmdQue = unitCAI->commandQue; const CFactoryCAI* factoryCAI = static_cast<CFactoryCAI*>(commandAI); const CCommandQueue& factoryCmdQue = factoryCAI->newUnitCommands; if (factoryCmdQue.empty() && unitCmdQue.empty()) { SendToEmptySpot(unit); return; } Command c(CMD_MOVE); if (!unit->unitDef->canfly) { // HACK: when a factory has a rallypoint set far enough away // to trigger the non-admissable path estimators, we want to // avoid units getting stuck inside by issuing them an extra // move-order. However, this order can *itself* cause the PF // system to consider the path blocked if the extra waypoint // falls within the factory's confines, so use a wide berth. const float xs = unitDef->xsize * SQUARE_SIZE * 0.5f; const float zs = unitDef->zsize * SQUARE_SIZE * 0.5f; float tmpDst = 2.0f; float3 tmpPos = unit->pos + (frontdir * this->radius * tmpDst); if (buildFacing == FACING_NORTH || buildFacing == FACING_SOUTH) { while ((tmpPos.z >= unit->pos.z - zs && tmpPos.z <= unit->pos.z + zs)) { tmpDst += 0.5f; tmpPos = unit->pos + (frontdir * this->radius * tmpDst); } } else { while ((tmpPos.x >= unit->pos.x - xs && tmpPos.x <= unit->pos.x + xs)) { tmpDst += 0.5f; tmpPos = unit->pos + (frontdir * this->radius * tmpDst); } } c.PushPos(tmpPos.cClampInBounds()); } else { // dummy rallypoint for aircraft c.PushPos(unit->pos); } if (unitCmdQue.empty()) { unitCAI->GiveCommand(c); // copy factory orders for new unit for (CCommandQueue::const_iterator ci = factoryCmdQue.begin(); ci != factoryCmdQue.end(); ++ci) { Command c = *ci; c.options |= SHIFT_KEY; if (c.GetID() == CMD_MOVE) { const float3 p1 = c.GetPos(0); const float3 p2 = float3(p1.x + gs->randFloat() * TWOPI, p1.y, p1.z + gs->randFloat() * TWOPI); // apply a small amount of random jitter to move commands // such that new units do not all share the same goal-pos // and start forming a "trail" back to the factory exit c.SetPos(0, p2); } unitCAI->GiveCommand(c); } } else { unitCmdQue.push_front(c); } }