mobilecai.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,090 行 · 第 1/3 页
CPP
1,090 行
case CMD_SET_WANTED_MAX_SPEED: { ExecuteSetWantedMaxSpeed(c); return; }
case CMD_MOVE: { ExecuteMove(c); return; }
case CMD_PATROL: { ExecutePatrol(c); return; }
case CMD_FIGHT: { ExecuteFight(c); return; }
case CMD_GUARD: { ExecuteGuard(c); return; }
case CMD_LOAD_ONTO: { ExecuteLoadUnits(c); return; }
default: {
CCommandAI::SlowUpdate();
return;
}
}
}
/**
* @brief executes the set wanted max speed command
*/
void CMobileCAI::ExecuteSetWantedMaxSpeed(Command &c)
{
if (repeatOrders && (commandQue.size() >= 2) &&
(commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) {
commandQue.push_back(commandQue.front());
}
FinishCommand();
SlowUpdate();
return;
}
/**
* @brief executes the move command
*/
void CMobileCAI::ExecuteMove(Command &c)
{
float3 pos = float3(c.params[0], c.params[1], c.params[2]);
if(pos != goalPos){
SetGoal(pos, owner->pos);
}
if((owner->pos - goalPos).SqLength2D() < cancelDistance ||
owner->moveType->progressState == CMoveType::Failed){
FinishCommand();
}
return;
}
void CMobileCAI::ExecuteLoadUnits(Command &c){
CTransportUnit* tran = dynamic_cast<CTransportUnit*>(uh->units[(int)c.params[0]]);
if(!tran){
FinishCommand();
return;
}
if(!inCommand){
inCommand ^= true;
Command newCommand;
newCommand.id = CMD_LOAD_UNITS;
newCommand.params.push_back(owner->id);
newCommand.options = INTERNAL_ORDER | SHIFT_KEY;
tran->commandAI->GiveCommandReal(newCommand);
}
if(owner->transporter) {
FinishCommand();
return;
}
CUnit *unit = uh->units[(int)c.params[0]];
if (!unit) {
return;
}
float3 pos = unit->pos;
if((pos - goalPos).SqLength2D() > cancelDistance){
SetGoal(pos, owner->pos);
}
if((owner->pos - goalPos).SqLength2D() < cancelDistance){
StopMove();
}
if(owner->moveType->progressState == CMoveType::Failed){
}
return;
}
/**
* @brief Executes the Patrol command c
*/
void CMobileCAI::ExecutePatrol(Command &c)
{
assert(owner->unitDef->canPatrol);
assert(c.params.size() >= 3);
Command temp;
temp.id = CMD_FIGHT;
temp.params.push_back(c.params[0]);
temp.params.push_back(c.params[1]);
temp.params.push_back(c.params[2]);
temp.options = c.options | INTERNAL_ORDER;
commandQue.push_back(c);
commandQue.pop_front();
commandQue.push_front(temp);
if(owner->group){
owner->group->CommandFinished(owner->id, CMD_PATROL);
}
ExecuteFight(temp);
return;
}
/**
* @brief Executes the Fight command c
*/
void CMobileCAI::ExecuteFight(Command &c)
{
assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
if(c.params.size() == 1) {
if(orderTarget && owner->weapons.size() > 0
&& !owner->weapons.front()->AttackUnit(orderTarget, false)) {
CUnit* newTarget = helper->GetClosestEnemyUnit(
owner->pos, owner->maxRange, owner->allyteam);
if(owner->weapons.front()->AttackUnit(newTarget, false)) {
c.params[0] = newTarget->id;
inCommand = false;
} else {
owner->weapons.front()->AttackUnit(orderTarget, false);
}
}
ExecuteAttack(c);
return;
}
if(tempOrder){
inCommand = true;
tempOrder = false;
}
if(c.params.size()<3){ //this shouldnt happen but anyway ...
logOutput.Print("Error: got fight cmd with less than 3 params on %s in mobilecai",
owner->unitDef->humanName.c_str());
return;
}
if(c.params.size() >= 6){
if(!inCommand){
commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
}
} else {
// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
// rotated (only shortened) if we reach this because the previous return
// fight command finished by the 'if((curPos-pos).SqLength2D()<(64*64)){'
// condition, but is actually updated correctly if you click somewhere
// outside the area close to the line (for a new command).
commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
if ((owner->pos - commandPos1).SqLength2D() > (96 * 96)) {
commandPos1 = owner->pos;
}
}
float3 pos(c.params[0],c.params[1],c.params[2]);
if(!inCommand){
inCommand = true;
commandPos2 = pos;
lastUserGoal = commandPos2;
}
if(c.params.size() >= 6){
pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
}
if(pos!=goalPos){
SetGoal(pos, owner->pos);
}
if(owner->unitDef->canAttack && owner->fireState>=2){
float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
CUnit* enemy=helper->GetClosestEnemyUnit(
curPosOnLine, owner->maxRange + 100 * owner->moveState * owner->moveState,
owner->allyteam);
if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)
&& !(owner->unitDef->noChaseCategory & enemy->category)
&& !owner->weapons.empty()
&& !enemy->neutral){
Command c2;
c2.id=CMD_FIGHT;
c2.options=c.options|INTERNAL_ORDER;
c2.params.push_back(enemy->id);
PushOrUpdateReturnFight();
commandQue.push_front(c2);
inCommand=false;
tempOrder=true;
if(lastPC!=gs->frameNum){ //avoid infinite loops
lastPC=gs->frameNum;
SlowUpdate();
}
return;
}
}
if((owner->pos - goalPos).SqLength2D() < (64 * 64)
|| (owner->moveType->progressState == CMoveType::Failed)){
FinishCommand();
}
return;
}
/**
* @brief Executes the guard command c
*/
void CMobileCAI::ExecuteGuard(Command &c)
{
assert(owner->unitDef->canGuard);
assert(!c.params.empty());
if(int(c.params[0]) >= 0 && uh->units[int(c.params[0])] != NULL
&& UpdateTargetLostTimer(int(c.params[0]))){
CUnit* guarded = uh->units[int(c.params[0])];
if(owner->unitDef->canAttack && guarded->lastAttacker
&& guarded->lastAttack + 40 < gs->frameNum
&& (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
StopSlowGuard();
Command nc;
nc.id=CMD_ATTACK;
nc.params.push_back(guarded->lastAttacker->id);
nc.options = c.options;
commandQue.push_front(nc);
SlowUpdate();
return;
} else {
//float3 dif = guarded->speed * guarded->frontdir;
float3 dif = guarded->pos - owner->pos;
dif.Normalize();
float3 goal = guarded->pos - dif * (guarded->radius + owner->radius + 64);
if((goalPos - goal).SqLength2D() > 1600
|| (goalPos - owner->pos).SqLength2D()
< (owner->maxSpeed*30 + 1 + SQUARE_SIZE*2)
* (owner->maxSpeed*30 + 1 + SQUARE_SIZE*2)){
SetGoal(goal, owner->pos);
}
if((goal - owner->pos).SqLength2D() < 6400) {
StartSlowGuard(guarded->maxSpeed);
if((goal-owner->pos).SqLength2D() < 1800){
StopMove();
NonMoving();
}
} else {
StopSlowGuard();
}
}
} else {
FinishCommand();
}
return;
}
/**
* @brief Executes the stop command c
*/
void CMobileCAI::ExecuteStop(Command &c)
{
StopMove();
return CCommandAI::ExecuteStop(c);
}
/**
* @brief Executes the DGun command c
*/
void CMobileCAI::ExecuteDGun(Command &c)
{
if(uh->limitDgun && owner->unitDef->isCommander
&& owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius){
StopMove();
return FinishCommand();
}
ExecuteAttack(c);
}
/**
* @brief Causes this CMobileCAI to execute the attack order c
*/
void CMobileCAI::ExecuteAttack(Command &c)
{
assert(owner->unitDef->canAttack);
// limit how far away we fly
if (tempOrder && (owner->moveState < 2) && orderTarget
&& LinePointDist(ClosestPointOnLine(commandPos1, commandPos2, owner->pos),
commandPos2, orderTarget->pos)
> (500*owner->moveState + owner->maxRange)) {
StopMove();
FinishCommand();
return;
}
// check if we are in direct command of attacker
if (!inCommand) {
// don't start counting until the owner->AttackGround() order is given
owner->commandShotCount = -1;
if (c.params.size() == 1) {
int unitID = int(c.params[0]);
// check if we have valid target parameter and that we aren't attacking ourselves
if (uh->units[unitID] != 0 && uh->units[unitID] != owner) {
float3 fix = uh->units[unitID]->pos + owner->posErrorVector * 128;
float3 diff = float3(fix - owner->pos).Normalize();
if(owner->moveState > 0 || !tempOrder) {
SetGoal(fix - diff*uh->units[unitID]->radius, owner->pos);
}
// get ID of attack-order target unit
orderTarget = uh->units[unitID];
AddDeathDependence(orderTarget);
inCommand = true;
}
else {
// unit may not fire on itself, cancel order
StopMove();
FinishCommand();
return;
}
}
else {
// user gave force-fire attack command
float3 pos(c.params[0], c.params[1], c.params[2]);
SetGoal(pos, owner->pos);
inCommand = true;
}
}
else if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
// the trailing CMD_SET_WANTED_MAX_SPEED in a command pair does not count
if ((commandQue.size() > 2) || (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) {
StopMove();
FinishCommand();
return;
}
}
// if our target is dead or we lost it then stop attacking
// NOTE: unit should actually just continue to target area!
if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) {
// cancel keeppointingto
StopMove();
FinishCommand();
return;
}
// user clicked on enemy unit (note that we handle aircrafts slightly differently)
if (orderTarget) {
//bool b1 = owner->AttackUnit(orderTarget, c.id == CMD_DGUN);
bool b2 = false;
bool b3 = false;
bool b4 = false;
float edgeFactor = 0.f; // percent offset to target center
float3 diff = owner->pos - orderTarget->pos;
if (owner->weapons.size() > 0) {
if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) {
StopMove();
FinishCommand();
return;
}
CWeapon* w = owner->weapons.front();
// if we have at least one weapon then check if we
// can hit target with our first (meanest) one
b2 = w->TryTargetRotate(orderTarget, c.id == CMD_DGUN);
b3 = (w->range - (w->relWeaponPos).Length())
> (orderTarget->pos.distance(owner->pos));
b4 = w->TryTargetHeading(GetHeadingFromVector(-diff.x, -diff.z),
orderTarget->pos, orderTarget != NULL);
edgeFactor = fabs(w->targetBorder);
}
double diffLength2d = diff.Length2D();
// if w->AttackUnit() returned true then we are already
// in range with our biggest weapon so stop moving
// also make sure that we're not locked in close-in/in-range state loop
// due to rotates invoked by in-range or out-of-range states
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?