int CCommandAI::CancelCommands(const Command &c, CCommandQueue& q, bool& first) { first = false; int cancelCount = 0; while (true) { CCommandQueue::iterator ci = GetCancelQueued(c, q); if (ci == q.end()) { return cancelCount; } first = first || (ci == q.begin()); cancelCount++; CCommandQueue::iterator firstErase = ci; CCommandQueue::iterator lastErase = ci; ++ci; if ((ci != q.end()) && (ci->GetID() == CMD_SET_WANTED_MAX_SPEED)) { lastErase = ci; cancelCount++; ++ci; } if ((ci != q.end()) && (ci->GetID() == CMD_WAIT)) { waitCommandsAI.RemoveWaitCommand(owner, *ci); lastErase = ci; cancelCount++; ++ci; } ++lastErase; // STL: erase the range [first, last) q.erase(firstErase, lastErase); if (c.GetID() >= 0) { return cancelCount; // only delete one non-build order } } return cancelCount; }
bool CCommandAI::HasMoreMoveCommands() { if (commandQue.size() <= 1) return false; // skip the first command for (CCommandQueue::iterator i = ++commandQue.begin(); i != commandQue.end(); ++i) { switch (i->GetID()) { case CMD_AREA_ATTACK: case CMD_ATTACK: case CMD_CAPTURE: case CMD_FIGHT: case CMD_GUARD: case CMD_LOAD_UNITS: case CMD_MANUALFIRE: case CMD_MOVE: case CMD_PATROL: case CMD_RECLAIM: case CMD_REPAIR: case CMD_RESTORE: case CMD_RESURRECT: case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: return true; case CMD_DEATHWAIT: case CMD_GATHERWAIT: case CMD_SELFD: case CMD_SQUADWAIT: case CMD_STOP: case CMD_TIMEWAIT: case CMD_WAIT: return false; default: // build commands are no different from reclaim or repair commands // in that they can require a unit to move, so return true when we // have one if (i->IsBuildCommand()) return true; } } return false; }
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 if (!(c.options & SHIFT_KEY)) { if (!commandQue.empty()) { const int& cmd_id = commandQue.front().GetID(); if ((cmd_id == CMD_MANUALFIRE) || (cmd_id == CMD_ATTACK) || (cmd_id == CMD_AREA_ATTACK)) { owner->AttackUnit(0,true); } waitCommandsAI.ClearUnitQueue(owner, commandQue); ClearCommandDependencies(); commandQue.clear(); } inCommand=false; SetOrderTarget(NULL); } 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); c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); 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); c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); 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 == false)) { Command c2(CMD_STOP); commandQue.push_back(c2); return; } } commandQue.push_back(c); if (commandQue.size() == 1 && !owner->beingBuilt && !owner->stunned) { SlowUpdate(); } }