commandai.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,512 行 · 第 1/3 页
CPP
1,512 行
return true;
}
case CMD_TRAJECTORY: {
owner->useHighTrajectory = !!c.params[0];
SetCommandDescParam0(c);
selectedUnits.PossibleCommandChange(owner);
return true;
}
case CMD_ONOFF: {
if (c.params[0] == 1) {
owner->Activate();
} else if (c.params[0] == 0) {
owner->Deactivate();
}
SetCommandDescParam0(c);
selectedUnits.PossibleCommandChange(owner);
return true;
}
case CMD_CLOAK: {
if (c.params[0] == 1) {
owner->wantCloak = true;
} else if(c.params[0]==0) {
owner->wantCloak = false;
owner->curCloakTimeout = gs->frameNum + owner->cloakTimeout;
}
SetCommandDescParam0(c);
selectedUnits.PossibleCommandChange(owner);
return true;
}
case CMD_STOCKPILE: {
int change = 1;
if (c.options & RIGHT_MOUSE_KEY) { change *= -1; }
if (c.options & SHIFT_KEY) { change *= 5; }
if (c.options & CONTROL_KEY) { change *= 20; }
stockpileWeapon->numStockpileQued += change;
if (stockpileWeapon->numStockpileQued < 0) {
stockpileWeapon->numStockpileQued = 0;
}
UpdateStockpileIcon();
return true;
}
}
return false;
}
void CCommandAI::GiveAllowedCommand(const Command& c)
{
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);
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++);
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 CCommandAI::GiveWaitCommand(const Command& c)
{
if (commandQue.empty()) {
commandQue.push_back(c);
return;
}
else if (c.options & SHIFT_KEY) {
if (commandQue.back().id == CMD_WAIT) {
waitCommandsAI.RemoveWaitCommand(owner, commandQue.back());
commandQue.pop_back();
} else {
commandQue.push_back(c);
return;
}
}
else if (commandQue.front().id == CMD_WAIT) {
waitCommandsAI.RemoveWaitCommand(owner, commandQue.front());
commandQue.pop_front();
}
else {
// shutdown the current order
owner->AttackUnit(0, true);
StopMove();
inCommand = false;
targetDied = false;
unimportantMove = false;
commandQue.push_front(c);
return;
}
if (commandQue.empty()) {
if (!owner->group) {
globalAI->UnitIdle(owner);
}
luaCallIns.UnitIdle(owner);
}
return;
}
void CCommandAI::ExecuteInsert(const Command& c)
{
if (c.params.size() < 3) {
return;
}
// make the command
Command newCmd;
newCmd.id = (int)c.params[1];
newCmd.options = (unsigned char)c.params[2];
for (int p = 3; p < (int)c.params.size(); p++) {
newCmd.params.push_back(c.params[p]);
}
// validate the command
if (!AllowedCommand(newCmd)) {
return;
}
CCommandQueue* queue = &commandQue;
bool facBuildQueue = false;
CFactoryCAI* facCAI = dynamic_cast<CFactoryCAI*>(this);
if (facCAI) {
if (c.options & CONTROL_KEY) {
// check the build order
const map<int, CFactoryCAI::BuildOption>& bOpts = facCAI->buildOptions;
if ((newCmd.id != CMD_STOP) && (newCmd.id != CMD_WAIT) &&
((newCmd.id >= 0) || (bOpts.find(newCmd.id) == bOpts.end()))) {
return;
}
facBuildQueue = true;
} else {
// use the new commands
queue = &facCAI->newUnitCommands;
}
}
// FIXME: handle CMD_LOOPBACKATTACK, etc...
CCommandQueue::iterator insertIt = queue->begin();
if (c.options & ALT_KEY) {
// treat param0 as a position
int pos = (int)c.params[0];
const int qsize = (int)queue->size();
if (pos < 0) {
pos = qsize + pos + 1; // convert the negative index
if (pos < 0) {
pos = 0;
}
}
if (pos > qsize) {
pos = qsize;
}
std::advance(insertIt, pos);
}
else {
// treat param0 as a command tag
const int tag = (int)c.params[0];
CCommandQueue::iterator ci;
bool found = false;
for (ci = queue->begin(); ci != queue->end(); ++ci) {
const Command& qc = *ci;
if (qc.tag == tag) {
insertIt = ci;
found = true;
break;
}
}
if (!found) {
return;
}
if ((c.options & RIGHT_MOUSE_KEY) && (insertIt != queue->end())) {
insertIt++; // insert after the tagged command
}
}
if (facBuildQueue) {
facCAI->InsertBuildCommand(insertIt, newCmd);
if (!owner->stunned) {
SlowUpdate();
}
return;
}
// shutdown the current order if the insertion is at the beginning
if (!queue->empty() && (insertIt == queue->begin())) {
inCommand = false;
targetDied = false;
unimportantMove = false;
orderTarget = NULL;
const Command& cmd = commandQue.front();
if (owner->group) {
owner->group->CommandFinished(owner->id, cmd.id);
}
luaCallIns.UnitCmdDone(owner, cmd.id, cmd.tag);
}
queue->insert(insertIt, newCmd);
if (!owner->stunned) {
SlowUpdate();
}
return;
}
void CCommandAI::ExecuteRemove(const Command& c)
{
// disable repeating during the removals
const bool prevRepeat = repeatOrders;
repeatOrders = false;
CCommandQueue* queue = &commandQue;
bool facBuildQueue = false;
CFactoryCAI* facCAI = dynamic_cast<CFactoryCAI*>(this);
if (facCAI) {
if (c.options & CONTROL_KEY) {
// check the build order
facBuildQueue = true;
} else {
// use the new commands
queue = &facCAI->newUnitCommands;
}
}
if ((c.params.size() <= 0) || (queue->size() <= 0)) {
return;
}
// erase commands by a list of command types
bool active = false;
for (int p = 0; p < (int)c.params.size(); p++) {
const int removeValue = (int)c.params[p]; // tag or id
if (facBuildQueue && (removeValue == 0) && !(c.options & ALT_KEY)) {
continue; // don't remove tag=0 commands from build queues, they
// are used the same way that CMD_STOP is, to void orders
}
CCommandQueue::iterator ci;
do {
for (ci = queue->begin(); ci != queue->end(); ++ci) {
const Command& qc = *ci;
if (c.options & ALT_KEY) {
if (qc.id != removeValue) { continue; }
} else {
if (qc.tag != removeValue) { continue; }
}
if (qc.id == CMD_WAIT) {
waitCommandsAI.RemoveWaitCommand(owner, qc);
}
if (facBuildQueue) {
facCAI->RemoveBuildCommand(ci);
ci = queue->begin();
break; // the removal may have corrupted the iterator
}
if (!facCAI && (ci == queue->begin())) {
if (!active) {
active = true;
FinishCommand();
ci = queue->begin();
break;
}
active = true;
}
queue->erase(ci);
ci = queue->begin();
break; // the removal may have corrupted the iterator
}
}
while (ci != queue->end());
}
repeatOrders = prevRepeat;
return;
}
/**
* @brief Determins if c will cancel a queued command
* @return true if c will cancel a queued command
**/
bool CCommandAI::WillCancelQueued(Command &c)
{
return (this->GetCancelQueued(c, commandQue) != this->commandQue.end());
}
/**
* @brief Finds the queued command that would be canceled by the Command c
* @return An iterator located at the command, or commandQue.end() if no such queued command exsists
**/
CCommandQueue::iterator CCommandAI::GetCancelQueued(const Command &c,
CCommandQueue& q)
{
CCommandQueue::iterator ci = q.end();
while (ci != q.begin()) {
ci--; //iterate from the end and dont check the current order
const Command& t = *ci;
if (((c.id == t.id) || ((c.id < 0) && (t.id < 0))
|| (t.id == CMD_FIGHT && c.id == CMD_ATTACK && t.params.size() == 1))
&& (t.params.size() == c.params.size())) {
if (c.params.size() == 1) {
// assume the param is a unit of feature id
if ((t.params[0] == c.params[0]) &&
(t.id != CMD_SET_WANTED_MAX_SPEED)) {
return ci;
}
}
else if (c.params.size() >= 3) {
if (c.id < 0) {
BuildInfo bc(c);
BuildInfo bt(t);
if (bc.def && bt.def
&& fabs(bc.pos.x - bt.pos.x) * 2 <= max(bc.GetXSize(), bt.GetXSize()) * SQUARE_SIZE
&& fabs(bc.pos.z - bt.pos.z) * 2 <= max(bc.GetYSize(), bt.GetYSize()) * SQUARE_SIZE) {
return ci;
}
} else {
// assume this means that the first 3 makes a position
float3 cp(c.params[0], c.params[1], c.params[2]);
float3 tp(t.params[0], t.params[1], t.params[2]);
if ((cp - tp).SqLength2D() < (17.0f * 17.0f)) {
return ci;
}
}
}
}
}
return q.end();
}
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->id == CMD_SET_WANTED_MAX_SPEED)) {
lastErase = ci;
cancelCount++;
ci++;
}
if ((ci != q.end()) && (ci->id == CMD_WAIT)) {
waitCommandsAI.RemoveWaitCommand(owner, *ci);
lastErase = ci;
cancelCount++;
ci++;
}
lastErase++; // STL: erase the range [first, last)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?