buildercai.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,458 行 · 第 1/3 页
CPP
1,458 行
{
CBuilder* fac=(CBuilder*)owner;
assert(owner->unitDef->canRepair || owner->unitDef->canAssist);
if (c.params.size() == 1) { //repair unit
CUnit* unit = uh->units[(int)c.params[0]];
if (tempOrder && owner->moveState == 1) { //limit how far away we go
if (unit && LinePointDist(commandPos1, commandPos2, unit->pos) > 500) {
StopMove();
FinishCommand();
return;
}
}
if (unit && (unit->health < unit->maxHealth) &&
((unit != owner) || owner->unitDef->canSelfRepair) &&
(!unit->soloBuilder || (unit->soloBuilder == owner)) &&
UpdateTargetLostTimer((int)c.params[0])) {
if (f3Dist(unit->pos, fac->pos) < fac->buildDistance+unit->radius-8) {
StopMove();
fac->SetRepairTarget(unit);
owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9f+unit->radius, false);
} else {
if (f3Dist(goalPos, unit->pos) > 1) {
SetGoal(unit->pos,owner->pos, fac->buildDistance*0.9f+unit->radius);
}
}
} else {
StopMove();
FinishCommand();
}
}
else { // repair area
float3 pos(c.params[0], c.params[1], c.params[2]);
float radius=c.params[3];
if (FindRepairTargetAndRepair(pos, radius, c.options, false)) {
inCommand=false;
SlowUpdate();
return;
}
if (!(c.options & ALT_KEY)) {
FinishCommand();
}
}
return;
}
void CBuilderCAI::ExecuteCapture(Command& c)
{
assert(owner->unitDef->canCapture);
CBuilder* fac=(CBuilder*)owner;
if (c.params.size() == 1) { //capture unit
CUnit* unit=uh->units[(int)c.params[0]];
if (unit && unit->team!=owner->team && UpdateTargetLostTimer((int)c.params[0])) {
if (f3Dist(unit->pos, fac->pos) < fac->buildDistance+unit->radius-8) {
StopMove();
fac->SetCaptureTarget(unit);
owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9f+unit->radius, false);
} else {
if (f3Dist(goalPos, unit->pos) > 1) {
SetGoal(unit->pos,owner->pos, fac->buildDistance*0.9f+unit->radius);
}
}
} else {
StopMove();
FinishCommand();
}
}
else { // capture area
float3 pos(c.params[0], c.params[1], c.params[2]);
float radius = c.params[3];
if (FindCaptureTargetAndCapture(pos, radius, c.options)) {
inCommand = false;
SlowUpdate();
return;
}
if (!(c.options & ALT_KEY)) {
FinishCommand();
}
}
return;
}
void CBuilderCAI::ExecuteGuard(Command& c)
{
assert(owner->unitDef->canGuard);
CBuilder* fac=(CBuilder*)owner;
CUnit* guarded=uh->units[(int)c.params[0]];
if (guarded && guarded!=owner && UpdateTargetLostTimer((int)c.params[0])) {
if (CBuilder* b=dynamic_cast<CBuilder*>(guarded)) {
if (b->terraforming) {
if (f3Dist(fac->pos, b->terraformCenter) <
(fac->buildDistance * 0.8f) + (b->terraformRadius * 0.7f)) {
StopMove();
owner->moveType->KeepPointingTo(b->terraformCenter, fac->buildDistance*0.9f, false);
fac->HelpTerraform(b);
} else {
StopSlowGuard();
SetGoal(b->terraformCenter,fac->pos,fac->buildDistance*0.7f+b->terraformRadius*0.6f);
}
return;
} else if (b->curReclaim && owner->unitDef->canReclaim){
StopSlowGuard();
if(!ReclaimObject(b->curReclaim)){
StopMove();
}
return;
} else {
fac->StopBuild();
}
if (b->curBuild &&
(!b->curBuild->soloBuilder || (b->curBuild->soloBuilder == owner)) &&
(( b->curBuild->beingBuilt && owner->unitDef->canAssist) ||
(!b->curBuild->beingBuilt && owner->unitDef->canRepair))) {
StopSlowGuard();
Command nc;
nc.id=CMD_REPAIR;
nc.options=c.options;
nc.params.push_back(b->curBuild->id);
commandQue.push_front(nc);
inCommand=false;
SlowUpdate();
return;
}
}
if(CFactory* f=dynamic_cast<CFactory*>(guarded)){
if (f->curBuild &&
(!f->curBuild->soloBuilder || (f->curBuild->soloBuilder == owner)) &&
(( f->curBuild->beingBuilt && owner->unitDef->canAssist) ||
(!f->curBuild->beingBuilt && owner->unitDef->canRepair))) {
StopSlowGuard();
Command nc;
nc.id=CMD_REPAIR;
nc.options=c.options;
nc.params.push_back(f->curBuild->id);
commandQue.push_front(nc);
inCommand=false;
// SlowUpdate();
return;
}
}
if (IsUnitBeingReclaimedByFriend(guarded))
return;
float3 curPos = owner->pos;
float3 dif = guarded->pos - curPos;
dif.Normalize();
float3 goal = guarded->pos - dif * (fac->buildDistance * 0.5f);
if (f3SqLen(guarded->pos - curPos) >
(fac->buildDistance*1.1f + guarded->radius) *
(fac->buildDistance*1.1f + guarded->radius)) {
StopSlowGuard();
}
if (f3SqLen(guarded->pos - curPos) <
(fac->buildDistance*0.9f + guarded->radius) *
(fac->buildDistance*0.9f + guarded->radius)) {
StartSlowGuard(guarded->maxSpeed);
StopMove();
// logOutput.Print("should point with type 3?");
owner->moveType->KeepPointingTo(guarded->pos,
fac->buildDistance*0.9f+guarded->radius, false);
if ((guarded->health < guarded->maxHealth) &&
(!guarded->soloBuilder || (guarded->soloBuilder == owner)) &&
(( guarded->beingBuilt && owner->unitDef->canAssist) ||
(!guarded->beingBuilt && owner->unitDef->canRepair))) {
StopSlowGuard();
Command nc;
nc.id=CMD_REPAIR;
nc.options=c.options;
nc.params.push_back(guarded->id);
commandQue.push_front(nc);
inCommand=false;
return;
} else {
NonMoving();
}
} else {
if (f3SqLen(goalPos - goal) > 4000
|| f3SqLen(goalPos - owner->pos) <
(owner->maxSpeed*30 + 1 + SQUARE_SIZE*2) *
(owner->maxSpeed*30 + 1 + SQUARE_SIZE*2)){
SetGoal(goal,curPos);
}
}
} else {
FinishCommand();
}
return;
}
void CBuilderCAI::ExecuteReclaim(Command& c)
{
assert(owner->unitDef->canReclaim);
if(c.params.size()==1){
int id=(int) c.params[0];
if (id >= MAX_UNITS) { //reclaim feature
const CFeatureSet& fset = featureHandler->GetActiveFeatures();
CFeatureSet::const_iterator it = fset.find(id - MAX_UNITS);
if (it != fset.end()) {
CFeature* feature = *it;
if(!ReclaimObject(feature)){
StopMove();
FinishCommand();
}
} else {
StopMove();
FinishCommand();
}
RemoveUnitFromReclaimers(owner);
} else { //reclaim unit
CUnit* unit=uh->units[id];
if(unit && unit!=owner && unit->unitDef->reclaimable && UpdateTargetLostTimer(id)){
if(!ReclaimObject(unit)){
StopMove();
FinishCommand();
} else {
AddUnitToReclaimers(owner);
}
} else {
RemoveUnitFromReclaimers(owner);
FinishCommand();
}
}
} else if(c.params.size()==4){//area reclaim
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
const bool recAnyTeam = ((c.options & CONTROL_KEY) != 0);
RemoveUnitFromReclaimers(owner);
if (FindReclaimableFeatureAndReclaim(pos, radius, c.options, true, recAnyTeam)) {
inCommand=false;
SlowUpdate();
return;
}
if(!(c.options & ALT_KEY)){
FinishCommand();
}
} else { //wrong number of parameters
RemoveUnitFromReclaimers(owner);
FinishCommand();
}
return;
}
void CBuilderCAI::ExecuteResurrect(Command& c)
{
assert(owner->unitDef->canResurrect);
CBuilder* fac=(CBuilder*)owner;
if(c.params.size()==1){
int id=(int)c.params[0];
if(id>=MAX_UNITS){ //resurrect feature
CFeatureSet::const_iterator it = featureHandler->GetActiveFeatures().find(id - MAX_UNITS);
if (it != featureHandler->GetActiveFeatures().end() && (*it)->createdFromUnit != "") {
CFeature* feature = *it;
if (f3Dist(feature->pos, fac->pos) < fac->buildDistance*0.9f+feature->radius) {
StopMove();
owner->moveType->KeepPointingTo(feature->pos, fac->buildDistance*0.9f+feature->radius, false);
fac->SetResurrectTarget(feature);
} else {
if (f3Dist(goalPos, feature->pos) > 1) {
SetGoal(feature->pos,owner->pos, fac->buildDistance*0.8f+feature->radius);
} else {
if(owner->moveType->progressState==CMoveType::Failed){
StopMove();
FinishCommand();
}
}
}
} else {
if(fac->lastResurrected && uh->units[fac->lastResurrected] && owner->unitDef->canRepair){ //resurrection finished, start repair
c.id=CMD_REPAIR; //kind of hackery to overwrite the current order i suppose
c.params.clear();
c.params.push_back(fac->lastResurrected);
c.options|=INTERNAL_ORDER;
fac->lastResurrected=0;
inCommand=false;
SlowUpdate();
return;
}
StopMove();
FinishCommand();
}
} else { //resurrect unit
FinishCommand();
}
} else if(c.params.size()==4){//area resurect
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
if(FindResurrectableFeatureAndResurrect(pos,radius,c.options)){
inCommand=false;
SlowUpdate();
return;
}
if(!(c.options & ALT_KEY)){
FinishCommand();
}
} else { //wrong number of parameters
FinishCommand();
}
return;
}
void CBuilderCAI::ExecutePatrol(Command& c)
{
assert(owner->unitDef->canPatrol);
if(c.params.size()<3){ //this shouldnt happen but anyway ...
logOutput.Print("Error: got patrol cmd with less than 3 params on %s in buildercai",
owner->unitDef->humanName.c_str());
return;
}
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);
}
SlowUpdate();
return;
}
void CBuilderCAI::ExecuteFight(Command& c)
{
assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
CBuilder* fac=(CBuilder*)owner;
if(tempOrder){
tempOrder=false;
inCommand=true;
}
if(c.params.size()<3){ //this shouldnt happen but anyway ...
logOutput.Print("Error: got fight cmd with less than 3 params on %s in BuilderCAI",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 (f3SqLen(owner->pos - commandPos1) > (96 * 96)) {
commandPos1 = owner->pos;
}
}
float3 pos(c.params[0],c.params[1],c.params[2]);
if (!inCommand) {
inCommand = true;
commandPos2 = pos;
}
if (c.params.size() >= 6) {
pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
}
if (pos!=goalPos) {
SetGoal(pos, owner->pos);
}
float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
if ((owner->unitDef->canRepair || owner->unitDef->canAssist) &&
FindRepairTargetAndRepair(curPosOnLine, 300*owner->moveState+fac->buildDistance-8,c.options,true)){
tempOrder = true;
inCommand = false;
if (lastPC1 != gs->frameNum) { //avoid infinite loops
lastPC1 = gs->frameNum;
SlowUpdate();
}
return;
}
if (owner->unitDef->canReclaim &&
FindReclaimableFeatureAndReclaim(curPosOnLine,300,c.options,false, false)) {
tempOrder = true;
inCommand = false;
if (lastPC2 != gs->frameNum) { //avoid infinite loops
lastPC2 = gs->frameNum;
SlowUpdate();
}
return;
}
if (f3SqLen(owner->pos - pos) < (64*64)) {
FinishCommand();
return;
}
if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done){
StopMove();
} else if(owner->moveType->progressState!=CMoveType::Active){
owner->moveType->StartMoving(goalPos, 8);
}
return;
}
void CBuilderCAI::ExecuteRestore(Command& c)
{
assert(owner->unitDef->canRestore);
CBuilder* fac=(CBuilder*)owner;
if(inCommand){
if(!fac->terraforming){
FinishCommand();
}
} else if(owner->unitDef->canRestore){
float3 pos(c.params[0],c.params[1],c.params[2]);
pos.y = ground->GetHeight2(pos.x,pos.y);
float radius(c.params[3]);
if (radius>200) radius = 200;
if (f3Dist(fac->pos, pos) < fac->buildDistance-1) {
StopMove();
fac->StartRestore(pos,radius);
owner->moveType->KeepPointingTo(pos, fac->buildDistance*0.9f, false);
inCommand=true;
} else {
SetGoal(pos,owner->pos, fac->buildDistance*0.9f);
}
}
return;
}
int CBuilderCAI::GetDefaultCmd(CUnit* pointed, CFeature* feature)
{
if (pointed) {
if (!gs->Ally(gu->myAllyTeam, pointed->allyteam)) {
if (owner->unitDef->canAttack && (owner->maxRange > 0)) {
return CMD_ATTACK;
} else if (owner->unitDef->canReclaim && pointed->unitDef->reclaimable) {
return CMD_RECLAIM;
}
} else {
CTransportCAI* tran = dynamic_cast<CTransportCAI*>(pointed->commandAI);
if ((pointed->health < pointed->maxHealth) &&
(!pointed->soloBuilder || (pointed->soloBuilder == owner)) &&
(( pointed->beingBuilt && owner->unitDef->canAssist) ||
(!pointed->beingBuilt && owner->unitDef->canRepair))) {
return CMD_REPAIR;
} else if (tran && tran->CanTransport(owner)) {
return CMD_LOAD_ONTO;
} else if (owner->unitDef->canGuard) {
return CMD_GUARD;
}
}
}
if (feature) {
if (owner->unitDef->canResurrect && !feature->createdFromUnit.empty()) {
return CMD_RESURRECT;
} else if(owner->unitDef->canReclaim && feature->def->reclaimable) {
return CMD_RECLAIM;
}
}
return CMD_MOVE;
}
void CBuilderCAI::AddUnitToReclaimers(CUnit* unit)
{
reclaimers.insert(unit);
}
void CBuilderCAI::RemoveUnitFromReclaimers(CUnit* unit)
{
reclaimers.erase(unit);
}
/** check if a unit is being reclaimed by a friendly con.
we assume that there won't be a lot of reclaimers because performance would suck
if there were. ideally reclaimers should be assigned on a per-unit basis, but
this requires tracking of deaths, which albeit already done isn't exactly simple
to follow.
TODO easy: store reclaiming units per allyteam
TODO harder: update reclaimers as they start/finish reclaims and/or die */
bool CBuilderCAI::IsUnitBeingReclaimedByFriend(CUnit* unit)
{
bool retval = false;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?