commandai.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,512 行 · 第 1/3 页
CPP
1,512 行
#include "StdAfx.h"
#include "CommandAI.h"
#include "FactoryCAI.h"
#include "LineDrawer.h"
#include "ExternalAI/GlobalAIHandler.h"
#include "ExternalAI/Group.h"
#include "Game/GameHelper.h"
#include "Game/SelectedUnits.h"
#include "Game/WaitCommandsAI.h"
#include "Game/UI/CommandColors.h"
#include "Game/UI/CursorIcons.h"
#include "Rendering/GL/myGL.h"
#include "Rendering/GL/glExtra.h"
#include "Lua/LuaCallInHandler.h"
#include "Lua/LuaRules.h"
#include "Sim/Misc/Feature.h"
#include "Sim/Misc/FeatureHandler.h"
#include "Sim/MoveTypes/MoveType.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Units/UnitDefHandler.h"
#include "Sim/Units/Unit.h"
#include "Sim/Units/UnitHandler.h"
#include "Sim/Units/UnitTypes/Factory.h"
#include "Sim/Weapons/WeaponDefHandler.h"
#include "Sim/Weapons/Weapon.h"
#include "Map/Ground.h"
#include "LoadSaveInterface.h"
#include "LogOutput.h"
#include "myMath.h"
#include "mmgr.h"
#include "creg/STL_Set.h"
#include "creg/STL_Deque.h"
#define TARGET_LOST_TIMER 120 // in calls to SlowUpdate() (approx. once every second)
CR_BIND(CCommandQueue, );
CR_REG_METADATA(CCommandQueue, (
CR_MEMBER(queue),
CR_MEMBER(tagCounter),
CR_ENUM_MEMBER(queueType)
));
CR_BIND_DERIVED(CCommandAI, CObject, );
CR_REG_METADATA(CCommandAI, (
CR_MEMBER(stockpileWeapon),
CR_MEMBER(possibleCommands),
CR_MEMBER(commandQue),
CR_MEMBER(nonQueingCommands),
CR_MEMBER(lastUserCommand),
CR_MEMBER(selfDCountdown),
CR_MEMBER(lastFinishCommand),
CR_MEMBER(owner),
CR_MEMBER(orderTarget),
CR_MEMBER(targetDied),
CR_MEMBER(inCommand),
CR_MEMBER(selected),
CR_MEMBER(repeatOrders),
CR_MEMBER(lastSelectedCommandPage),
CR_MEMBER(unimportantMove),
CR_MEMBER(targetLostTimer),
CR_RESERVED(64),
CR_POSTLOAD(PostLoad)
));
CCommandAI::CCommandAI()
: lastUserCommand(-1000),
orderTarget(0),
targetDied(false),
inCommand(false),
selected(false),
owner(owner),
stockpileWeapon(0),
lastSelectedCommandPage(0),
repeatOrders(false),
lastFinishCommand(0),
unimportantMove(false),
targetLostTimer(TARGET_LOST_TIMER)
{}
CCommandAI::CCommandAI(CUnit* owner)
: lastUserCommand(-1000),
orderTarget(0),
targetDied(false),
inCommand(false),
selected(false),
owner(owner),
stockpileWeapon(0),
lastSelectedCommandPage(0),
repeatOrders(false),
lastFinishCommand(0),
unimportantMove(false),
targetLostTimer(TARGET_LOST_TIMER)
{
owner->commandAI=this;
CommandDescription c;
c.id=CMD_STOP;
c.action="stop";
c.type=CMDTYPE_ICON;
c.name="Stop";
c.mouseicon=c.name;
c.hotkey="s";
c.tooltip="Stop: Cancel the units current actions";
possibleCommands.push_back(c);
if (isAttackCapable()) {
c.id=CMD_ATTACK;
c.action="attack";
c.type=CMDTYPE_ICON_UNIT_OR_MAP;
c.name="Attack";
c.mouseicon=c.name;
c.hotkey="a";
c.tooltip="Attack: Attacks an unit or a position on the ground";
possibleCommands.push_back(c);
}
if (owner->unitDef->canDGun) {
c.id=CMD_DGUN;
c.action="dgun";
c.type=CMDTYPE_ICON_MAP;
c.name="DGun";
c.mouseicon=c.name;
c.hotkey="d";
c.tooltip="DGun: Attacks using the units special weapon";
possibleCommands.push_back(c);
}
c.id=CMD_WAIT;
c.action="wait";
c.type=CMDTYPE_ICON;
c.name="Wait";
c.mouseicon=c.name;
c.hotkey="w";
c.onlyKey=true;
c.tooltip="Wait: Tells the unit to wait until another units handles him";
possibleCommands.push_back(c);
// nonQueingCommands.insert(CMD_WAIT);
c.id = CMD_TIMEWAIT;
c.action = "timewait";
c.type = CMDTYPE_NUMBER;
c.name = "TimeWait";
c.mouseicon=c.name;
c.hotkey = "";
c.onlyKey = true;
c.tooltip = "TimeWait: Wait for a period of time before continuing";
c.params.push_back("1"); // min
c.params.push_back("60"); // max
possibleCommands.push_back(c);
c.params.clear();
// only for games with 2 ally teams -- checked later
c.id = CMD_DEATHWAIT;
c.action = "deathwait";
c.type = CMDTYPE_ICON_UNIT_OR_RECTANGLE;
c.name = "DeathWait";
c.mouseicon=c.name;
c.hotkey = "";
c.onlyKey = true;
c.tooltip = "DeathWait: Wait until units die before continuing";
possibleCommands.push_back(c);
c.id = CMD_SQUADWAIT;
c.action = "squadwait";
c.type = CMDTYPE_NUMBER;
c.name = "SquadWait";
c.mouseicon=c.name;
c.hotkey = "";
c.onlyKey = true;
c.tooltip = "SquadWait: Wait for a number of units to arrive before continuing";
c.params.push_back("2"); // min
c.params.push_back("100"); // max
possibleCommands.push_back(c);
c.params.clear();
c.id = CMD_GATHERWAIT;
c.action = "gatherwait";
c.type = CMDTYPE_ICON;
c.name = "GatherWait";
c.mouseicon=c.name;
c.hotkey = "";
c.onlyKey = true;
c.tooltip = "GatherWait: Wait until all units arrive before continuing";
possibleCommands.push_back(c);
if (owner->unitDef->canSelfD) {
c.id = CMD_SELFD;
c.action = "selfd";
c.type = CMDTYPE_ICON;
c.name = "SelfD";
c.mouseicon = c.name;
c.hotkey = "Ctrl+d";
c.onlyKey = true;
c.tooltip = "SelfD: Tells the unit to self destruct";
possibleCommands.push_back(c);
}
// nonQueingCommands.insert(CMD_SELFD);
c.onlyKey=false;
c.hotkey="";
if (!owner->unitDef->noAutoFire) {
if(!owner->unitDef->weapons.empty() || owner->unitDef->type=="Factory"/* || owner->unitDef->canKamikaze*/){
c.id=CMD_FIRE_STATE;
c.action="firestate";
c.type=CMDTYPE_ICON_MODE;
c.name="Fire state";
c.mouseicon=c.name;
c.params.push_back("2");
c.params.push_back("Hold fire");
c.params.push_back("Return fire");
c.params.push_back("Fire at will");
c.tooltip="Fire State: Sets under what conditions an\n unit will start to fire at enemy units\n without an explicit attack order";
possibleCommands.push_back(c);
nonQueingCommands.insert(CMD_FIRE_STATE);
}
} else {
owner->fireState = 0;
}
if (owner->unitDef->canmove || owner->unitDef->builder) {
c.params.clear();
c.id=CMD_MOVE_STATE;
c.action="movestate";
c.type=CMDTYPE_ICON_MODE;
c.name="Move state";
c.mouseicon=c.name;
c.params.push_back("1");
c.params.push_back("Hold pos");
c.params.push_back("Maneuver");
c.params.push_back("Roam");
c.tooltip="Move State: Sets how far out of its way\n an unit will move to attack enemies";
possibleCommands.push_back(c);
owner->moveState=1;
nonQueingCommands.insert(CMD_MOVE_STATE);
} else {
owner->moveState=0;
}
if (owner->unitDef->canRepeat) {
c.params.clear();
c.id=CMD_REPEAT;
c.action="repeat";
c.type=CMDTYPE_ICON_MODE;
c.name="Repeat";
c.mouseicon=c.name;
c.params.push_back("0");
c.params.push_back("Repeat off");
c.params.push_back("Repeat on");
c.tooltip="Repeat: If on the unit will continously\n push finished orders to the end of its\n order que";
possibleCommands.push_back(c);
nonQueingCommands.insert(CMD_REPEAT);
}
if (owner->unitDef->highTrajectoryType>1) {
c.params.clear();
c.id=CMD_TRAJECTORY;
c.action="trajectory";
c.type=CMDTYPE_ICON_MODE;
c.name="Trajectory";
c.mouseicon=c.name;
c.params.push_back("0");
c.params.push_back("Low traj");
c.params.push_back("High traj");
c.tooltip="Trajectory: If set to high, weapons that\n support it will try to fire in a higher\n trajectory than usual (experimental)";
possibleCommands.push_back(c);
nonQueingCommands.insert(CMD_TRAJECTORY);
}
if (owner->unitDef->onoffable) {
c.params.clear();
c.id=CMD_ONOFF;
c.action="onoff";
c.type=CMDTYPE_ICON_MODE;
c.name="Active state";
c.mouseicon=c.name;
c.hotkey="x";
if (owner->unitDef->activateWhenBuilt) {
c.params.push_back("1");
} else {
c.params.push_back("0");
}
c.params.push_back(" Off ");
c.params.push_back(" On ");
c.tooltip="Active State: Sets the active state of the unit to on or off";
possibleCommands.push_back(c);
nonQueingCommands.insert(CMD_ONOFF);
c.hotkey="";
}
if (owner->unitDef->canCloak) {
c.params.clear();
c.id=CMD_CLOAK;
c.action="cloak";
c.type=CMDTYPE_ICON_MODE;
c.name="Cloak state";
c.mouseicon=c.name;
c.hotkey="k";
if (owner->unitDef->startCloaked) {
c.params.push_back("1");
} else {
c.params.push_back("0");
}
c.params.push_back("UnCloaked");
c.params.push_back("Cloaked");
c.tooltip="Cloak State: Sets wheter the unit is cloaked or not";
possibleCommands.push_back(c);
nonQueingCommands.insert(CMD_CLOAK);
c.hotkey="";
}
}
CCommandAI::~CCommandAI()
{
if(orderTarget){
DeleteDeathDependence(orderTarget);
orderTarget=0;
}
}
void CCommandAI::PostLoad()
{
selected=false;//HACK: selected list does not serialized
}
vector<CommandDescription>& CCommandAI::GetPossibleCommands()
{
return possibleCommands;
}
bool CCommandAI::isAttackCapable() const
{
const UnitDef* ud = owner->unitDef;
return (ud->canAttack && (!ud->weapons.empty() || ud->canKamikaze || (ud->type == "Factory")));
}
static inline bool isCommandInMap(const Command& c)
{
if (c.params.size() >= 3 &&
(c.params[0] < 0.f || c.params[2] < 0.f
|| c.params[0] > gs->mapx*SQUARE_SIZE
|| c.params[2] > gs->mapy*SQUARE_SIZE))
return false;
return true;
}
bool CCommandAI::AllowedCommand(const Command& c)
{
// check if the command is in the map first
switch (c.id) {
case CMD_MOVE:
case CMD_ATTACK:
case CMD_AREA_ATTACK:
case CMD_RECLAIM:
case CMD_REPAIR:
case CMD_RESURRECT:
case CMD_PATROL:
case CMD_RESTORE:
case CMD_FIGHT:
case CMD_DGUN:
case CMD_UNLOAD_UNIT:
case CMD_UNLOAD_UNITS:
if (!isCommandInMap(c)) { return false; }
break;
default:
// build commands
if (c.id < 0 && !isCommandInMap(c)) { return false; }
break;
}
const UnitDef* ud = owner->unitDef;
int maxHeightDiff = 200;
switch (c.id) {
case CMD_ATTACK:
maxHeightDiff = 10;
case CMD_DGUN: {
if (!isAttackCapable())
return false;
if (c.params.size() == 3) {
// check if attack ground is really attack ground
if (fabs(c.params[1] - ground->GetHeight2(c.params[0], c.params[2])) >
maxHeightDiff) {
return false;
}
}
break;
}
case CMD_MOVE: if (!ud->canmove) return false; break;
case CMD_FIGHT: if (!ud->canFight) return false; break;
case CMD_GUARD: if (!ud->canGuard) return false; break;
case CMD_PATROL: if (!ud->canPatrol) return false; break;
case CMD_CAPTURE: if (!ud->canCapture) return false; break;
case CMD_RECLAIM: if (!ud->canReclaim) return false; break;
case CMD_RESTORE: if (!ud->canRestore) return false; break;
case CMD_RESURRECT: if (!ud->canResurrect) return false; break;
case CMD_REPAIR: {
if (!ud->canRepair && !ud->canAssist) return false; break;
}
}
if ((c.id == CMD_RECLAIM) && (c.params.size() == 1)) {
const int unitID = (int) c.params[0];
if (unitID < MAX_UNITS) { // not a feature
CUnit* unit = uh->units[unitID];
if (unit && !unit->unitDef->reclaimable)
return false;
} else {
const CFeatureSet& fset = featureHandler->GetActiveFeatures();
CFeatureSet::const_iterator f = fset.find(unitID - MAX_UNITS);
if (f != fset.end() && !(*f)->def->reclaimable)
return false;
}
}
if ((c.id == CMD_REPAIR) && (c.params.size() == 1)) {
CUnit* unit = uh->units[(int) c.params[0]];
if (unit && ((unit->beingBuilt && !ud->canAssist) || (!unit->beingBuilt && !ud->canRepair)))
return false;
}
if (c.id == CMD_FIRE_STATE && (c.params.empty() || ud->noAutoFire || (ud->weapons.empty() && ud->type != "Factory")))
return false;
if (c.id == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder)))
return false;
if (c.id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat))
return false;
if (c.id == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType < 2))
return false;
if (c.id == CMD_ONOFF && (c.params.empty() || !ud->onoffable || owner->beingBuilt))
return false;
if (c.id == CMD_CLOAK && (c.params.empty() || !ud->canCloak))
return false;
if (c.id == CMD_STOCKPILE && !stockpileWeapon)
return false;
return true;
}
void CCommandAI::GiveCommand(const Command& c, bool fromSynced)
{
if (luaRules && !luaRules->AllowCommand(owner, c, fromSynced)) {
return;
}
this->GiveCommandReal(c); // send to the sub-classes
}
void CCommandAI::GiveCommandReal(const Command& c)
{
if (!AllowedCommand(c)) {
return;
}
GiveAllowedCommand(c);
}
inline void CCommandAI::SetCommandDescParam0(const Command& c)
{
vector<CommandDescription>::iterator cdi;
for (cdi = possibleCommands.begin(); cdi != possibleCommands.end(); ++cdi) {
if (cdi->id == c.id) {
char t[10];
SNPRINTF(t, 10, "%d", (int)c.params[0]);
cdi->params[0] = t;
return;
}
}
}
bool CCommandAI::ExecuteStateCommand(const Command& c)
{
switch (c.id) {
case CMD_FIRE_STATE: {
owner->fireState = (int)c.params[0];
SetCommandDescParam0(c);
selectedUnits.PossibleCommandChange(owner);
return true;
}
case CMD_MOVE_STATE: {
owner->moveState = (int)c.params[0];
SetCommandDescParam0(c);
selectedUnits.PossibleCommandChange(owner);
return true;
}
case CMD_REPEAT: {
repeatOrders = !!c.params[0];
SetCommandDescParam0(c);
selectedUnits.PossibleCommandChange(owner);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?