transportcai.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 973 行 · 第 1/2 页
CPP
973 行
#include "StdAfx.h"
#include "TransportCAI.h"
#include "LineDrawer.h"
#include "Sim/Units/UnitHandler.h"
#include "Sim/Units/Unit.h"
#include "Sim/Units/COB/CobInstance.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
#include "Map/Ground.h"
#include "Sim/Misc/QuadField.h"
#include "Game/UI/CommandColors.h"
#include "Game/UI/CursorIcons.h"
#include "LogOutput.h"
#include "Rendering/GL/myGL.h"
#include "Rendering/GL/glExtra.h"
#include "Game/GameHelper.h"
#include "Sim/MoveTypes/TAAirMoveType.h"
#include "Sim/ModInfo.h"
#include "Rendering/UnitModels/3DOParser.h"
#include "mmgr.h"
#include "creg/STL_List.h"
static void ScriptCallback(int retCode,void* p1,void* p2)
{
((CTransportCAI*)p1)->ScriptReady();
}
CR_BIND_DERIVED(CTransportCAI,CMobileCAI , );
CR_REG_METADATA(CTransportCAI, (
CR_MEMBER(toBeTransportedUnitId),
CR_MEMBER(scriptReady),
CR_MEMBER(lastCall),
CR_MEMBER(unloadType),
CR_MEMBER(dropSpots),
CR_MEMBER(isFirstIteration),
CR_MEMBER(lastDropPos),
CR_MEMBER(approachVector),
CR_MEMBER(endDropPos),
CR_RESERVED(16)
));
CTransportCAI::CTransportCAI()
: CMobileCAI(),
lastCall(0),
scriptReady(false),
toBeTransportedUnitId(-1)
{}
CTransportCAI::CTransportCAI(CUnit* owner)
: CMobileCAI(owner),
lastCall(0),
scriptReady(false),
toBeTransportedUnitId(-1)
{
//for new transport methods
dropSpots.clear();
approachVector= float3(0,0,0);
unloadType = owner->unitDef->transportUnloadMethod;
startingDropPos = float3(-1,-1,-1);
lastDropPos = float3(-1,-1,-1);
endDropPos = float3(-1,-1,-1);
isFirstIteration = true;
//
CommandDescription c;
c.id=CMD_LOAD_UNITS;
c.action="loadunits";
c.type=CMDTYPE_ICON_UNIT_OR_AREA;
c.name="Load units";
c.mouseicon=c.name;
c.hotkey="l";
c.tooltip="Sets the transport to load a unit or units within an area";
possibleCommands.push_back(c);
c.id=CMD_UNLOAD_UNITS;
c.action="unloadunits";
c.type=CMDTYPE_ICON_AREA;
c.name="Unload units";
c.mouseicon=c.name;
c.hotkey="u";
c.tooltip="Sets the transport to unload units in an area";
possibleCommands.push_back(c);
}
CTransportCAI::~CTransportCAI(void)
{
if(toBeTransportedUnitId!=-1){
if(uh->units[toBeTransportedUnitId])
uh->units[toBeTransportedUnitId]->toBeTransported=false;
toBeTransportedUnitId=-1;
}
}
void CTransportCAI::SlowUpdate(void)
{
if(commandQue.empty()){
CMobileCAI::SlowUpdate();
return;
}
Command& c=commandQue.front();
switch(c.id){
case CMD_LOAD_UNITS: { ExecuteLoadUnits(c); dropSpots.clear(); return; }
case CMD_UNLOAD_UNITS: { ExecuteUnloadUnits(c); return; }
case CMD_UNLOAD_UNIT: { ExecuteUnloadUnit(c); return; }
default:{
dropSpots.clear();
CMobileCAI::SlowUpdate();
return;
}
}
}
void CTransportCAI::ExecuteLoadUnits(Command &c)
{
CTransportUnit* transport=(CTransportUnit*)owner;
if(c.params.size()==1){ //load single unit
if(transport->transportCapacityUsed >= owner->unitDef->transportCapacity){
FinishCommand();
return;
}
CUnit* unit=uh->units[(int)c.params[0]];
if (!unit) {
FinishCommand();
return;
}
if(c.options & INTERNAL_ORDER) {
if(unit->commandAI->commandQue.empty()){
if(!LoadStillValid(unit)){
FinishCommand();
return;
}
} else {
Command & currentUnitCommand = unit->commandAI->commandQue[0];
if(currentUnitCommand.id == CMD_LOAD_ONTO && currentUnitCommand.params.size() == 1 && int(currentUnitCommand.params[0]) == owner->id){
if((unit->moveType->progressState == CMoveType::Failed) && (owner->moveType->progressState == CMoveType::Failed)){
unit->commandAI->FinishCommand();
FinishCommand();
return;
}
} else if(!LoadStillValid(unit)) {
FinishCommand();
return;
}
}
}
if(inCommand){
if(!owner->cob->busy)
FinishCommand();
return;
}
if(unit && CanTransport(unit) && UpdateTargetLostTimer(int(c.params[0]))){
toBeTransportedUnitId=unit->id;
unit->toBeTransported=true;
if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass){
FinishCommand();
return;
}
if(goalPos.distance2D(unit->pos)>10){
float3 fix = unit->pos;
SetGoal(fix,owner->pos,64);
}
if(unit->pos.distance2D(owner->pos)<owner->unitDef->loadingRadius*0.9f){
if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){ //handle air transports differently
float3 wantedPos=unit->pos+UpVector*unit->model->height;
SetGoal(wantedPos,owner->pos);
am->dontCheckCol=true;
am->ForceHeading(unit->heading);
am->SetWantedAltitude(unit->model->height);
am->maxDrift=1;
//logOutput.Print("cai dist %f %f %f",owner->pos.distance(wantedPos),owner->pos.distance2D(wantedPos),owner->pos.y-wantedPos.y);
if(owner->pos.distance(wantedPos)<4 && abs(owner->heading-unit->heading)<50 && owner->updir.dot(UpVector)>0.995f){
am->dontCheckCol=false;
am->dontLand=true;
std::vector<int> args;
args.push_back((int)(unit->model->height*65536));
owner->cob->Call("BeginTransport",args);
std::vector<int> args2;
args2.push_back(0);
args2.push_back((int)(unit->model->height*65536));
owner->cob->Call("QueryTransport",args2);
((CTransportUnit*)owner)->AttachUnit(unit,args2[0]);
am->SetWantedAltitude(0);
FinishCommand();
return;
}
} else {
inCommand=true;
scriptReady=false;
StopMove();
std::vector<int> args;
args.push_back(unit->id);
owner->cob->Call("TransportPickup",args,ScriptCallback,this,0);
}
}
} else {
FinishCommand();
}
} else if(c.params.size()==4){ //load in radius
if(lastCall==gs->frameNum) //avoid infinite loops
return;
lastCall=gs->frameNum;
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
CUnit* unit=FindUnitToTransport(pos,radius);
if(unit && ((CTransportUnit*)owner)->transportCapacityUsed < owner->unitDef->transportCapacity){
Command c2;
c2.id=CMD_LOAD_UNITS;
c2.params.push_back(unit->id);
c2.options=c.options | INTERNAL_ORDER;
commandQue.push_front(c2);
inCommand=false;
SlowUpdate();
return;
} else {
FinishCommand();
return;
}
}
isFirstIteration=true;
startingDropPos = float3(-1,-1,-1);
return;
}
void CTransportCAI::ExecuteUnloadUnits(Command &c)
{
//new Methods
CTransportUnit* transport=(CTransportUnit*)owner;
switch(unloadType) {
case UNLOAD_LAND: UnloadUnits_Land(c,transport); break;
case UNLOAD_DROP:
if (owner->unitDef->canfly)
UnloadUnits_Drop(c,transport);
else
UnloadUnits_Land(c,transport);
break;
case UNLOAD_LANDFLOOD: UnloadUnits_LandFlood(c,transport); break;
default:UnloadUnits_Land(c,transport); break;
}
}
void CTransportCAI::ExecuteUnloadUnit(Command &c)
{
//new methods
switch (unloadType) {
case UNLOAD_LAND: UnloadLand(c); break;
case UNLOAD_DROP:
if (owner->unitDef->canfly)
UnloadDrop(c);
else
UnloadLand(c);
break;
case UNLOAD_LANDFLOOD: UnloadLandFlood(c); break;
default: UnloadLand(c); break;
}
}
void CTransportCAI::ScriptReady(void)
{
scriptReady = true; // NOTE: does not seem to be used
}
bool CTransportCAI::CanTransport(CUnit* unit)
{
CTransportUnit* transport=(CTransportUnit*)owner;
if (unit->unitDef->cantBeTransported)
return false;
if(unit->mass>=100000 || unit->beingBuilt)
return false;
// don't transport cloaked enemies
if (unit->isCloaked && !gs->AlliedTeams(unit->team, owner->team))
return false;
if(unit->xsize > owner->unitDef->transportSize*2)
return false;
if(unit->xsize < owner->unitDef->minTransportSize*2)
return false;
if(unit->mass < owner->unitDef->minTransportMass)
return false;
if(!transport->CanTransport(unit))
return false;
if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
return false;
return true;
}
// FindEmptySpot(pos, max(16.0f, radius), spread, found, u);
bool CTransportCAI::FindEmptySpot(float3 center, float radius, float emptyRadius, float3& found, CUnit* unitToUnload)
{
if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) {
// handle air transports differently
for (int a = 0; a < 100; ++a) {
float3 delta(1, 0, 1);
float3 tmp;
do {
delta.x = (gs->randFloat() - 0.5f) * 2;
delta.z = (gs->randFloat() - 0.5f) * 2;
tmp = center + delta * radius;
} while (delta.SqLength2D() > 1
|| tmp.x < emptyRadius || tmp.z < emptyRadius
|| tmp.x >= gs->mapx * SQUARE_SIZE - emptyRadius
|| tmp.z >= gs->mapy * SQUARE_SIZE - emptyRadius);
float3 pos = center + delta * radius;
pos.y = ground->GetHeight(pos.x, pos.z);
float unloadPosHeight = ground->GetApproximateHeight(pos.x, pos.z);
if (unloadPosHeight < (0 - unitToUnload->unitDef->maxWaterDepth))
continue;
if (unloadPosHeight > (0 - unitToUnload->unitDef->minWaterDepth))
continue;
// Don't unload anything on slopes
if (unitToUnload->unitDef->movedata
&& ground->GetSlope(pos.x, pos.z) > unitToUnload->unitDef->movedata->maxSlope)
continue;
if (!qf->GetUnitsExact(pos, emptyRadius + 8).empty())
continue;
found = pos;
return true;
}
} else {
for (float y = max(emptyRadius, center.z - radius); y < min(float(gs->mapy * SQUARE_SIZE - emptyRadius), center.z + radius); y += SQUARE_SIZE) {
float dy = y - center.z;
float rx = radius * radius - dy * dy;
if (rx <= emptyRadius)
continue;
rx = sqrt(rx);
for (float x = max(emptyRadius, center.x - rx); x < min(float(gs->mapx * SQUARE_SIZE - emptyRadius), center.x + rx); x += SQUARE_SIZE) {
float unloadPosHeight = ground->GetApproximateHeight(x, y);
if (unloadPosHeight < (0 - unitToUnload->unitDef->maxWaterDepth))
continue;
if (unloadPosHeight > (0 - unitToUnload->unitDef->minWaterDepth))
continue;
// Don't unload anything on slopes
if (unitToUnload->unitDef->movedata
&& ground->GetSlope(x, y) > unitToUnload->unitDef->movedata->maxSlope)
continue;
float3 pos(x, ground->GetApproximateHeight(x, y), y);
if (!qf->GetUnitsExact(pos, emptyRadius + 8).empty())
continue;
found = pos;
return true;
}
}
}
return false;
}
bool CTransportCAI::SpotIsClear(float3 pos,CUnit* unitToUnload) {
float unloadPosHeight=ground->GetApproximateHeight(pos.x,pos.z);
if(unloadPosHeight<(0-unitToUnload->unitDef->maxWaterDepth))
return false;
if(unloadPosHeight>(0-unitToUnload->unitDef->minWaterDepth))
return false;
if(ground->GetSlope(pos.x,pos.z) > unitToUnload->unitDef->movedata->maxSlope)
return false;
if(!qf->GetUnitsExact(pos,unitToUnload->radius+8).empty())
return false;
return true;
}
bool CTransportCAI::FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots) {
//should only be used by air
CTransportUnit* transport=(CTransportUnit*)owner;
//dropSpots.clear();
float gap = 25.5; //TODO - set tag for this?
float3 dir = endpos - startpos;
dir.Normalize();
float3 nextPos = startpos;
float3 pos;
list<CTransportUnit::TransportedUnit>::iterator ti = transport->transported.begin();
dropSpots.push_front(nextPos);
//first spot
if (ti!=transport->transported.end()) {
//float3 p = nextPos; //test to make intended land spots visible
//inMapDrawer->CreatePoint(p,ti->unit->unitDef->name);
//p.z +=transport->transportCapacityUsed*5;
nextPos += dir*(gap + ti->unit->radius);
ti++;
}
//remaining spots
if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) {
while (ti != transport->transported.end() && startpos.distance(nextPos) < startpos.distance(endpos)) {
nextPos += dir*(ti->unit->radius);
nextPos.y = ground->GetHeight(nextPos.x, nextPos.z);
//check landing spot is ok for landing on
if (!SpotIsClear(nextPos,ti->unit))
continue;
dropSpots.push_front(nextPos);
//float3 p = nextPos; //test to make intended land spots visible
//inMapDrawer->CreatePoint(p,ti->unit->unitDef->name);
//p.z +=transport->transportCapacityUsed*5;
nextPos += dir*(gap + ti->unit->radius);
ti++;
}
return true;
}
return false;
}
bool CTransportCAI::FindEmptyFloodSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots, std::vector<float3> exitDirs) {
// TODO: select suitable spots according to directions we are allowed to exit transport from
return false;
}
void CTransportCAI::UnloadUnits_Land(Command& c, CTransportUnit* transport) {
if (lastCall == gs->frameNum) {
// avoid infinite loops
return;
}
lastCall = gs->frameNum;
if (((CTransportUnit*) owner)->transported.empty()) {
FinishCommand();
return;
}
CUnit* u = ((CTransportUnit*) owner)->transported.front().unit;
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius = c.params[3];
float spread = u->radius * ((CTransportUnit*) owner)->unitDef->unloadSpread;
float3 found;
bool canUnload = FindEmptySpot(pos, max(16.0f, radius), spread, found, u);
if (canUnload) {
Command c2;
c2.id = CMD_UNLOAD_UNIT;
c2.params.push_back(found.x);
c2.params.push_back(found.y);
c2.params.push_back(found.z);
c2.options = c.options | INTERNAL_ORDER;
commandQue.push_front(c2);
SlowUpdate();
return;
} else {
FinishCommand();
}
return;
}
void CTransportCAI::UnloadUnits_Drop(Command& c, CTransportUnit* transport) {
//called repeatedly for each unit till units are unloaded
if(lastCall==gs->frameNum) //avoid infinite loops
return;
lastCall=gs->frameNum;
if(((CTransportUnit*)owner)->transported.empty() ){
FinishCommand();
return;
}
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
bool canUnload = false;
//at the start of each user command
if (isFirstIteration ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?