void CFactoryCAI::GiveCommandReal(const Command& c, bool fromSynced) { // move is always allowed for factories (passed to units it produces) if ((c.id == CMD_SET_WANTED_MAX_SPEED) || ((c.id != CMD_MOVE) && !AllowedCommand(c))) { return; } map<int, BuildOption>::iterator boi = buildOptions.find(c.id); // not a build order so queue it to built units if (boi == buildOptions.end()) { if ((nonQueingCommands.find(c.id) != nonQueingCommands.end()) || (c.id == CMD_INSERT) || (c.id == CMD_REMOVE) || (!(c.options & SHIFT_KEY) && ((c.id == CMD_WAIT) || (c.id == CMD_SELFD)))) { CCommandAI::GiveAllowedCommand(c); return; } if (!(c.options & SHIFT_KEY)) { waitCommandsAI.ClearUnitQueue(owner, newUnitCommands); newUnitCommands.clear(); } if (c.id != CMD_STOP) { if ((c.id == CMD_WAIT) || (c.id == CMD_SELFD)) { if (!newUnitCommands.empty() && (newUnitCommands.back().id == c.id)) { if (c.id == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_back(); } else { newUnitCommands.push_back(c); } } else { bool dummy; if (CancelCommands(c, newUnitCommands, dummy) > 0) { return; } else { if (GetOverlapQueued(c, newUnitCommands).empty()) { newUnitCommands.push_back(c); } else { return; } } } } // the first new-unit build order can not be WAIT or SELFD while (!newUnitCommands.empty()) { const int id = newUnitCommands.front().id; if ((id == CMD_WAIT) || (id == CMD_SELFD)) { if (c.id == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_front(); } else { break; } } return; } BuildOption &bo = boi->second; int numItems = 1; if (c.options & SHIFT_KEY) { numItems *= 5; } if (c.options & CONTROL_KEY) { numItems *= 20; } if (c.options & RIGHT_MOUSE_KEY) { bo.numQued -= numItems; if (bo.numQued < 0) { bo.numQued = 0; } int numToErase = numItems; if (c.options & ALT_KEY) { for (unsigned int cmdNum = 0; cmdNum < commandQue.size() && numToErase; ++cmdNum) { if (commandQue[cmdNum].id == c.id) { commandQue[cmdNum].id = CMD_STOP; numToErase--; } } } else { for (int cmdNum = commandQue.size() - 1; cmdNum != -1 && numToErase; --cmdNum) { if (commandQue[cmdNum].id == c.id) { commandQue[cmdNum].id = CMD_STOP; numToErase--; } } } UpdateIconName(c.id,bo); SlowUpdate(); } else { if (c.options & ALT_KEY) { for (int a = 0; a < numItems; ++a) { if (repeatOrders) { Command nc(c); nc.options |= DONT_REPEAT; if (commandQue.empty()) { commandQue.push_front(nc); } else { commandQue.insert(commandQue.begin()+1, nc); } } else { commandQue.push_front(c); } } if (!repeatOrders) { building=false; CFactory* fac = (CFactory*)owner; fac->StopBuild(); } } else { for (int a = 0; a < numItems; ++a) { commandQue.push_back(c); } } bo.numQued += numItems; UpdateIconName(c.id, bo); SlowUpdate(); } }
void CCommandAI::GiveAllowedCommand(const Command& c, bool fromSynced) { if (ExecuteStateCommand(c)) { return; } switch (c.id) { case CMD_SELFD: { if (owner->unitDef->canSelfD) { if (!(c.options & SHIFT_KEY) || commandQue.empty()) { if (owner->selfDCountdown != 0) { owner->selfDCountdown = 0; } else { owner->selfDCountdown = owner->unitDef->selfDCountdown*2+1; } } else { if (commandQue.back().id == CMD_SELFD) { commandQue.pop_back(); } else { commandQue.push_back(c); } } } return; } case CMD_SET_WANTED_MAX_SPEED: { if (CanSetMaxSpeed() && (commandQue.empty() || (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED))) { // bail early, do not check for overlaps or queue cancelling commandQue.push_back(c); if (commandQue.size()==1 && !owner->beingBuilt) { SlowUpdate(); } } return; } case CMD_WAIT: { GiveWaitCommand(c); return; } case CMD_INSERT: { ExecuteInsert(c, fromSynced); return; } case CMD_REMOVE: { ExecuteRemove(c); return; } } // flush the queue for immediate commands if (!(c.options & SHIFT_KEY)) { if (!commandQue.empty()) { if ((commandQue.front().id == CMD_DGUN) || (commandQue.front().id == CMD_ATTACK) || (commandQue.front().id == CMD_AREA_ATTACK)) { owner->AttackUnit(0,true); } waitCommandsAI.ClearUnitQueue(owner, commandQue); commandQue.clear(); } inCommand=false; if(orderTarget){ DeleteDeathDependence(orderTarget); orderTarget=0; } } if (c.id == CMD_PATROL) { CCommandQueue::iterator ci = commandQue.begin(); for (; ci != commandQue.end() && ci->id != CMD_PATROL; ci++) { // just increment } if (ci == commandQue.end()) { if (commandQue.empty()) { Command c2; c2.id = CMD_PATROL; c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); c2.options = c.options; commandQue.push_back(c2); } else { do { ci--; if (ci->params.size() >= 3) { Command c2; c2.id = CMD_PATROL; c2.params = ci->params; c2.options = c.options; commandQue.push_back(c2); break; } else if (ci == commandQue.begin()) { Command c2; c2.id = CMD_PATROL; c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); c2.options = c.options; commandQue.push_back(c2); break; } } while (ci != commandQue.begin()); } } } // cancel duplicated commands bool first; if (CancelCommands(c, commandQue, first) > 0) { if (first) { Command stopCommand; stopCommand.id = CMD_STOP; commandQue.push_front(stopCommand); SlowUpdate(); } return; } // do not allow overlapping commands if (!GetOverlapQueued(c).empty()) { return; } if (c.id == CMD_ATTACK) { // avoid weaponless units moving to 0 distance when given attack order if (owner->weapons.empty() && (owner->unitDef->canKamikaze == false)) { Command c2; c2.id = CMD_STOP; commandQue.push_back(c2); return; } } commandQue.push_back(c); if (commandQue.size() == 1 && !owner->beingBuilt && !owner->stunned) { SlowUpdate(); } }
void CFactoryCAI::GiveCommandReal(const Command& c, bool fromSynced) { const int cmdID = c.GetID(); // move is always allowed for factories (passed to units it produces) if ((cmdID == CMD_SET_WANTED_MAX_SPEED) || ((cmdID != CMD_MOVE) && !AllowedCommand(c, fromSynced))) { return; } map<int, BuildOption>::iterator boi = buildOptions.find(cmdID); // not a build order (or a build order we do not support, eg. if multiple // factories of different types were selected) so queue it to built units if (boi == buildOptions.end()) { if (cmdID < 0) return; if ((nonQueingCommands.find(cmdID) != nonQueingCommands.end()) || (cmdID == CMD_INSERT) || (cmdID == CMD_REMOVE) || (!(c.options & SHIFT_KEY) && ((cmdID == CMD_WAIT) || (cmdID == CMD_SELFD)))) { CCommandAI::GiveAllowedCommand(c); return; } if (!(c.options & SHIFT_KEY)) { waitCommandsAI.ClearUnitQueue(owner, newUnitCommands); CCommandAI::ClearCommandDependencies(); newUnitCommands.clear(); } CCommandAI::AddCommandDependency(c); if (cmdID != CMD_STOP) { if ((cmdID == CMD_WAIT) || (cmdID == CMD_SELFD)) { if (!newUnitCommands.empty() && (newUnitCommands.back().GetID() == cmdID)) { if (cmdID == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_back(); } else { newUnitCommands.push_back(c); } } else { bool dummy; if (CancelCommands(c, newUnitCommands, dummy) > 0) { return; } else { if (GetOverlapQueued(c, newUnitCommands).empty()) { newUnitCommands.push_back(c); } else { return; } } } } // the first new-unit build order can not be WAIT or SELFD while (!newUnitCommands.empty()) { const Command& newUnitCommand = newUnitCommands.front(); const int id = newUnitCommand.GetID(); if ((id == CMD_WAIT) || (id == CMD_SELFD)) { if (cmdID == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_front(); } else { break; } } return; } BuildOption& bo = boi->second; int numItems = 1; if (c.options & SHIFT_KEY) { numItems *= 5; } if (c.options & CONTROL_KEY) { numItems *= 20; } if (c.options & RIGHT_MOUSE_KEY) { bo.numQued -= numItems; bo.numQued = std::max(bo.numQued, 0); int numToErase = numItems; if (c.options & ALT_KEY) { for (unsigned int cmdNum = 0; cmdNum < commandQue.size() && numToErase; ++cmdNum) { if (commandQue[cmdNum].GetID() == cmdID) { commandQue[cmdNum] = Command(CMD_STOP); numToErase--; } } } else { for (int cmdNum = commandQue.size() - 1; cmdNum != -1 && numToErase; --cmdNum) { if (commandQue[cmdNum].GetID() == cmdID) { commandQue[cmdNum] = Command(CMD_STOP); numToErase--; } } } UpdateIconName(cmdID, bo); SlowUpdate(); } else { if (c.options & ALT_KEY) { for (int a = 0; a < numItems; ++a) { if (repeatOrders) { Command nc(c); nc.options |= INTERNAL_ORDER; if (commandQue.empty()) { commandQue.push_front(nc); } else { commandQue.insert(commandQue.begin()+1, nc); } } else { commandQue.push_front(c); } } if (!repeatOrders) { CFactory* fac = static_cast<CFactory*>(owner); fac->StopBuild(); } } else { for (int a = 0; a < numItems; ++a) { commandQue.push_back(c); } } bo.numQued += numItems; UpdateIconName(cmdID, bo); SlowUpdate(); } }
/** * @brief Returns commands that overlap c, but will not be canceled by c * @return a vector containing commands that overlap c */ std::vector<Command> CCommandAI::GetOverlapQueued(const Command &c) { return GetOverlapQueued(c, commandQue); }
void CCommandAI::GiveAllowedCommand(const Command& c, bool fromSynced) { if (ExecuteStateCommand(c)) { return; } switch (c.GetID()) { case CMD_SELFD: { if (owner->unitDef->canSelfD) { if (!(c.options & SHIFT_KEY) || commandQue.empty()) { if (owner->selfDCountdown != 0) { owner->selfDCountdown = 0; } else { owner->selfDCountdown = owner->unitDef->selfDCountdown*2+1; } } else if (commandQue.back().GetID() == CMD_SELFD) { commandQue.pop_back(); } else { commandQue.push_back(c); } } return; } case CMD_SET_WANTED_MAX_SPEED: { if (CanSetMaxSpeed() && (commandQue.empty() || (commandQue.back().GetID() != CMD_SET_WANTED_MAX_SPEED))) { // bail early, do not check for overlaps or queue cancelling commandQue.push_back(c); if (commandQue.size()==1 && !owner->beingBuilt) { SlowUpdate(); } } return; } case CMD_WAIT: { GiveWaitCommand(c); return; } case CMD_INSERT: { ExecuteInsert(c, fromSynced); return; } case CMD_REMOVE: { ExecuteRemove(c); return; } } // flush the queue for immediate commands // NOTE: CMD_STOP can be a queued order (!) if (!(c.options & SHIFT_KEY)) { waitCommandsAI.ClearUnitQueue(owner, commandQue); ClearTargetLock((commandQue.empty())? Command(CMD_STOP): commandQue.front()); ClearCommandDependencies(); SetOrderTarget(NULL); // if c is an attack command, the actual order-target // gets set via ExecuteAttack (called from SlowUpdate // at the end of this function) commandQue.clear(); assert(commandQue.empty()); inCommand = false; } AddCommandDependency(c); if (c.GetID() == CMD_PATROL) { CCommandQueue::iterator ci = commandQue.begin(); for (; ci != commandQue.end() && ci->GetID() != CMD_PATROL; ++ci) { // just increment } if (ci == commandQue.end()) { if (commandQue.empty()) { Command c2(CMD_PATROL, c.options, owner->pos); commandQue.push_back(c2); } else { do { --ci; if (ci->params.size() >= 3) { Command c2(CMD_PATROL, c.options); c2.params = ci->params; commandQue.push_back(c2); break; } else if (ci == commandQue.begin()) { Command c2(CMD_PATROL, c.options, owner->pos); commandQue.push_back(c2); break; } } while (ci != commandQue.begin()); } } } // cancel duplicated commands bool first; if (CancelCommands(c, commandQue, first) > 0) { if (first) { Command stopCommand(CMD_STOP); commandQue.push_front(stopCommand); SlowUpdate(); } return; } // do not allow overlapping commands if (!GetOverlapQueued(c).empty()) { return; } if (c.GetID() == CMD_ATTACK) { // avoid weaponless units moving to 0 distance when given attack order if (owner->weapons.empty() && (!owner->unitDef->canKamikaze)) { Command c2(CMD_STOP); commandQue.push_back(c2); return; } } commandQue.push_back(c); if (commandQue.size() == 1 && !owner->beingBuilt && !owner->IsStunned()) { SlowUpdate(); } }