// // Calculate the outer limits and the center of the group coordinates. // void CSelectedUnitsHandlerAI::CalculateGroupData(int player, bool queueing) { //Finding the highest, lowest and weighted central positional coordinates among the selected units. float3 sumCoor, minCoor, maxCoor; float3 mobileSumCoor = sumCoor; sumLength = 0; int mobileUnits = 0; minMaxSpeed = 1e9f; for (auto ui = selectedUnitsHandler.netSelected[player].begin(); ui != selectedUnitsHandler.netSelected[player].end(); ++ui) { CUnit* unit = unitHandler->GetUnit(*ui); if (unit != nullptr) { const UnitDef* ud = unit->unitDef; sumLength += (int)((ud->xsize + ud->zsize)/2); float3 unitPos; if (queueing) { unitPos = LastQueuePosition(unit); } else { unitPos = unit->midPos; } if(unitPos.x < minCoor.x) minCoor.x = unitPos.x; else if(unitPos.x > maxCoor.x) maxCoor.x = unitPos.x; if(unitPos.y < minCoor.y) minCoor.y = unitPos.y; else if(unitPos.y > maxCoor.y) maxCoor.y = unitPos.y; if(unitPos.z < minCoor.z) minCoor.z = unitPos.z; else if(unitPos.z > maxCoor.z) maxCoor.z = unitPos.z; sumCoor += unitPos; if (unit->commandAI->CanSetMaxSpeed()) { mobileUnits++; mobileSumCoor += unitPos; const float maxSpeed = unit->moveType->GetMaxSpeed(); if (maxSpeed < minMaxSpeed) { minMaxSpeed = maxSpeed; } } } } avgLength = sumLength/selectedUnitsHandler.netSelected[player].size(); //Weighted center if(mobileUnits > 0) centerCoor = mobileSumCoor / mobileUnits; else centerCoor = sumCoor / selectedUnitsHandler.netSelected[player].size(); }
void CSelectedUnitsAI::GiveCommandNet(Command &c, int player) { const vector<int>& netSelected = selectedUnits.netSelected[player]; vector<int>::const_iterator ui; int nbrOfSelectedUnits = netSelected.size(); if (nbrOfSelectedUnits < 1) { // no units to command } else if ((c.id == CMD_ATTACK) && ((c.params.size() == 6) || ((c.params.size() == 4) && (c.params[3] > 0.001f)))) { SelectAttack(c, player); } else if (nbrOfSelectedUnits == 1) { // a single unit selected CUnit* unit = uh->units[*netSelected.begin()]; if(unit) { unit->commandAI->GiveCommand(c, false); if (MayRequireSetMaxSpeedCommand(c)) { AddUnitSetMaxSpeedCommand(unit, c.options); } if (c.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 (((c.id == CMD_MOVE) || (c.id == CMD_FIGHT)) && (c.params.size() == 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 = uh->units[*ui]; if(unit) { if (groupSpeed) { AddGroupSetMaxSpeedCommand(unit, c.options); } else { AddUnitSetMaxSpeedCommand(unit, c.options); } } } } else if ((c.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.params[0], c.params[1], c.params[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 + (sqrt((float)nbrOfSelectedUnits) * 32.0f); // push back some extra params so it confer with a front move c.params.push_back(pos.x + (sideDir.x * length)); c.params.push_back(pos.y + (sideDir.y * length)); c.params.push_back(pos.z + (sideDir.z * length)); MakeFrontMove(&c, player); const bool groupSpeed = !!(c.options & CONTROL_KEY); for(ui = netSelected.begin(); ui != netSelected.end(); ++ui) { CUnit* unit = uh->units[*ui]; if(unit) { if (groupSpeed) { AddGroupSetMaxSpeedCommand(unit, c.options); } else { AddUnitSetMaxSpeedCommand(unit, c.options); } } } } else if ((c.options & CONTROL_KEY) && ((c.id == CMD_MOVE) || (c.id == CMD_PATROL) || (c.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 = uh->units[*ui]; if (unit) { // 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 = uh->units[*ui]; if (unit) { // 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 (c.id == CMD_WAIT) { if (player == gu->myPlayerNum) { waitCommandsAI.AcknowledgeCommand(c); } } } }
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; } } } }