Attached Files |
-
newTransportMethods 0.17.diff (40,783 bytes) 2007-09-11 23:56
Index: Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- Sim/MoveTypes/groundmovetype.cpp (revision 4358)
+++ Sim/MoveTypes/groundmovetype.cpp (working copy)
@@ -129,8 +129,10 @@
deltaSpeed(0),
deltaHeading(0),
skidding(false),
- flying(false),
+ flying(false),
skidRotSpeed(0),
+ dropSpeed(0.2),
+ dropHeight(0),
floatOnWater(false),
skidRotVector(UpVector),
skidRotSpeed2(0),
@@ -195,13 +197,20 @@
&& (!floatOnWater || ground->GetHeight(owner->midPos.x, owner->midPos.z) > 0))
{
skidding = true;
- }
+ }
if(skidding){
UpdateSkid();
return;
}
+ if(owner->falling) {
+ //set drop height when we start to drop
+ //dropHeight = owner->midPos.y; //test
+ UpdateControlledDrop();
+ return;
+ }
+
if(owner->stunned){
owner->cob->Call(COBFN_StopMoving);
owner->speed=ZeroVector;
@@ -282,7 +291,7 @@
if(nextDeltaSpeedUpdate<=gs->frameNum){
wantedSpeed = pathId ? requestedSpeed : 0;
- //If arriving at waypoint, then need to slow down, or may pass it.
+ //If arriving at waypoint, then need to slow down, or may pass it.
if(!owner->commandAI->HasMoreMoveCommands()
&& currentDistanceToWaypoint < BreakingDistance(currentSpeed) + SQUARE_SIZE) {
wantedSpeed = std::min((float)wantedSpeed, (float)(sqrt(currentDistanceToWaypoint * -owner->mobility->maxBreaking)));
@@ -309,7 +318,8 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!owner->falling) //need this to stop jitter when falling, but may be causing crash?
+ owner->pos.y=wh;
}
if(owner->pos!=oldPos){
@@ -323,9 +333,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
- owner->speed=owner->pos-oldPos;
+ owner->speed = owner->pos - oldPos;
owner->midPos = owner->pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
oldPos=owner->pos;
@@ -367,10 +378,13 @@
logOutput.Print("Unit restart %i",owner->id);
StartEngine();
}
+
+
+
owner->pos.CheckInBounds(); //just kindly move it into the map again instead of deleteing
-
- float wh; //need the following if the ground change height when unit stand still
+ float wh;
+ //need the following if the ground change height when unit stand still
if(floatOnWater){
wh = ground->GetHeight(owner->pos.x, owner->pos.z);
if(wh==0)
@@ -378,8 +392,12 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
+ //owner->pos.y=wh;
+
if(!(owner->pos==oldSlowUpdatePos)){
oldSlowUpdatePos=owner->pos;
@@ -574,7 +592,7 @@
if(skidding){
speed+=impulse;
- impulse=ZeroVector;
+ impulse=ZeroVector;
}
float3 groundNormal=ground->GetNormal(owner->pos.x,owner->pos.z);
@@ -817,6 +835,46 @@
}
}
+
+void CGroundMoveType::UpdateControlledDrop(void)
+{
+ float3& speed=owner->speed;
+ float3& pos=owner->pos;
+ float3& midPos=(float3)owner->midPos;
+
+
+ if(owner->falling){
+
+ owner->cob->Call("Falling"); //start/continue parachute animation
+ speed.y+=gs->gravity*dropSpeed;
+ midPos += speed;
+ pos = midPos - owner->frontdir * owner->relMidPos.z
+ - owner->updir * owner->relMidPos.y
+ - owner->rightdir * owner->relMidPos.x;
+
+ owner->midPos.y = owner->pos.y + owner->relMidPos.y;
+
+ if(midPos.y < 0)
+ speed*=0.90;
+
+ float wh;
+
+ if(floatOnWater)
+ wh = ground->GetHeight(midPos.x, midPos.z);
+ else
+ wh = ground->GetHeight2(midPos.x, midPos.z);
+
+ if(wh > midPos.y-owner->relMidPos.y){
+ owner->falling = false;
+ midPos.y=wh+owner->relMidPos.y-speed.y*0.8;
+ owner->cob->Call("Landed"); //stop parachute animation
+ }
+
+
+
+ }
+}
+
float CGroundMoveType::GetFlyTime(float3 pos, float3 speed)
{
return 0;
Index: Sim/MoveTypes/groundmovetype.h
===================================================================
--- Sim/MoveTypes/groundmovetype.h (revision 4358)
+++ Sim/MoveTypes/groundmovetype.h (working copy)
@@ -73,6 +73,7 @@
unsigned int nonMovingFailures; //how many times we have requested a path from the same place
int moveType;
+
bool floatOnWater;
@@ -107,6 +108,7 @@
void UpdateSkid(void);
void CheckCollisionSkid(void);
+ void UpdateControlledDrop(void);
float GetFlyTime(float3 pos, float3 speed);
void CalcSkidRot(void);
@@ -114,6 +116,8 @@
bool flying;
float skidRotSpeed;
+ float dropSpeed;
+ float dropHeight;
float3 skidRotVector;
float skidRotSpeed2;
float skidRotPos2;
Index: Sim/MoveTypes/TAAirMoveType.cpp
===================================================================
--- Sim/MoveTypes/TAAirMoveType.cpp (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.cpp (working copy)
@@ -15,9 +15,11 @@
#include "Sim/Misc/GeometricObjects.h"
#include "Mobility.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
+#include "Sim/Units/CommandAI/CommandAI.h"
CR_BIND_DERIVED(CTAAirMoveType, CMoveType, (NULL));
+
CR_REG_METADATA(CTAAirMoveType, (
CR_MEMBER(dontCheckCol),
@@ -45,6 +47,8 @@
CR_MEMBER(decRate),
CR_MEMBER(altitudeRate),
+
+
CR_MEMBER(breakDistance),
CR_MEMBER(dontLand),
CR_MEMBER(lastMoveRate),
@@ -67,6 +71,7 @@
));
+
CTAAirMoveType::CTAAirMoveType(CUnit* owner) :
CMoveType(owner),
aircraftState(AIRCRAFT_LANDED),
@@ -144,6 +149,8 @@
void CTAAirMoveType::SetState(AircraftState newState)
{
+ float3 &pos=owner->pos;
+
if (newState == aircraftState)
return;
@@ -175,10 +182,10 @@
// ownerActivated = false;
// owner->cob->Call(COBFN_Deactivate);
// }
- break;
+ break;
case AIRCRAFT_HOVERING:
wantedHeight = orgWantedHeight;
- wantedSpeed = ZeroVector;
+ wantedSpeed = ZeroVector; //test
// fall through...
default:
owner->physicalState = CSolidObject::Flying;
@@ -225,7 +232,7 @@
SetState(AIRCRAFT_FLYING);
break;
case AIRCRAFT_CRASHING:
- break;
+ break;
}
//logOutput.Print("Moving to %f %f %f", pos.x, pos.y, pos.z);
@@ -236,7 +243,7 @@
void CTAAirMoveType::StartMoving(float3 pos, float goalRadius, float speed)
{
- //logOutput.Print("airmove: Ignoring startmoving speed");
+ //logOutput.Print("airmove: Ignoring startmoving speed"); //test
StartMoving(pos, goalRadius);
}
@@ -273,8 +280,7 @@
void CTAAirMoveType::ExecuteStop()
{
- wantToStop = false;
-// logOutput.Print("Executing stop");
+ wantToStop = false;
switch (aircraftState) {
case AIRCRAFT_TAKEOFF:
SetState(AIRCRAFT_LANDING);
@@ -302,8 +308,7 @@
}
void CTAAirMoveType::StopMoving()
-{
-// logOutput.Print("stop order");
+{
wantToStop = true;
forceHeading=false;
owner->isMoving=false;
@@ -320,7 +325,6 @@
void CTAAirMoveType::UpdateLanded()
{
float3 &pos = owner->pos;
-
//dont place on ground if we are on a repair pad
if (padStatus == 0) {
if (owner -> unitDef -> canSubmerge)
@@ -358,9 +362,12 @@
void CTAAirMoveType::UpdateHovering()
{
float driftSpeed = owner->unitDef->dlHoverFactor;
+ float3 dir = goalPos - owner->pos;
- // move towards goal position
- float3 dir = goalPos - owner->pos;
+ // move towards goal position if its not immediately behind us when we have more waypoints to get to
+ if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1 )
+ dir = owner->frontdir;
+
wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f;
// damping
@@ -379,9 +386,15 @@
//Direction to where we would like to be
float3 dir = goalPos - pos;
+ //dont change direction for waypoints we just flew over and missed slightly
+ if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1 )
+ dir = owner->frontdir;
+
+
owner->restTime=0;
//are we there yet?
+ //TODO - add code to stop aircraft stopping for intermediate waypoints (according to pretedermined tag)
// logOutput.Print("max drift %f %i %f %f",maxDrift,waitCounter,dir.Length2D(),fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight));
bool closeToGoal=dir.SqLength2D() < maxDrift*maxDrift && fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight)<maxDrift;
if(flyState==FLY_ATTACKING)
@@ -393,7 +406,7 @@
if(dontLand || (++waitCounter<55 && dynamic_cast<CTransportUnit*>(owner)) || !autoLand){ //transport aircrafts need some time to detect that they can pickup
if (dynamic_cast<CTransportUnit*>(owner)) {
wantedSpeed=ZeroVector;
- if(waitCounter>60){
+ if(waitCounter>55){ //was 60 - causes too much judder when at 60
wantedHeight=orgWantedHeight;
}
} else
@@ -409,7 +422,7 @@
// break;
waitCounter++;
if (waitCounter > 100) {
- //logOutput.Print("moving circlepos");
+ logOutput.Print("moving circlepos");
if(owner->unitDef->airStrafe){
float3 relPos = pos - circlingPos;
if(relPos.x<0.0001f && relPos.x>-0.0001f)
@@ -489,30 +502,38 @@
float realMax = maxSpeed;
float dist=dir.Length2D();
- //If we are close to our goal, we should go slow enough to be able to break in time
- //if in attack mode dont slow down
- if (flyState!=FLY_ATTACKING && dist < breakDistance) {
- realMax = dist/(speed.Length2D()+0.01f) * decRate;
- //logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax);
- }
+ //If we are close to our goal, we should go slow enough to be able to break in time
+ //new additional rule:
+ //if in attack mode or have more this is an intermediate waypoint dont
+ //slow down except if near ground level
+
+ //if (flyState!=FLY_ATTACKING && dist < breakDistance) { //old code
+ if ((flyState!=FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands() ) || (pos.y - ground->GetHeight(pos.x, pos.z) < orgWantedHeight/2)) {
+ realMax = dist/(speed.Length2D()+0.01f) * decRate;
+ //logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax); //test
+ }
- wantedSpeed = dir.Normalize() * realMax;
+ wantedSpeed = dir.Normalize() * realMax;
+ UpdateAirPhysics();
- UpdateAirPhysics();
+ //Point toward goal or forward - unless we just passed it to get to another goal
+ if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
+ dir = circlingPos - pos;
+ }
+ else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1 ) {
+ dir = owner->frontdir;
+ }
+ else {
+ dir = goalPos - pos;
+ }
+ if(dir.SqLength2D()>1)
+ wantedHeading = GetHeadingFromVector(dir.x, dir.z);
- //Point toward goal or forward
- if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
- dir = circlingPos - pos;
- } else {
- dir = goalPos - pos;
- }
- if(dir.SqLength2D()>1)
- wantedHeading = GetHeadingFromVector(dir.x, dir.z);
+
}
-
void CTAAirMoveType::UpdateLanding()
{
float3 &pos = owner->pos;
@@ -720,6 +741,10 @@
pos+=speed;
}
+
+
+
+
void CTAAirMoveType::UpdateMoveRate()
{
int curRate;
Index: Sim/MoveTypes/TAAirMoveType.h
===================================================================
--- Sim/MoveTypes/TAAirMoveType.h (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.h (working copy)
@@ -7,7 +7,7 @@
class CTAAirMoveType :
public CMoveType
{
- CR_DECLARE(CTAAirMoveType);
+ CR_DECLARE(CTAAirMoveType);
public:
enum AircraftState{
AIRCRAFT_LANDED,
@@ -15,7 +15,7 @@
AIRCRAFT_LANDING,
AIRCRAFT_CRASHING,
AIRCRAFT_TAKEOFF,
- AIRCRAFT_HOVERING // this is what happens to aircraft with dontLand=1 in fbi
+ AIRCRAFT_HOVERING // this is what happens to aircraft with dontLand=1 in fbi
} aircraftState;
enum FlyState {
@@ -71,6 +71,7 @@
float3 oldGoalPos; //goalpos to resume flying to after landing
bool autoLand;
+
CTAAirMoveType(CUnit* owner);
~CTAAirMoveType(void);
@@ -95,7 +96,7 @@
//Helpers for (multiple) state handlers
void UpdateHeading();
void UpdateBanking(bool noBanking);
- void UpdateAirPhysics();
+ void UpdateAirPhysics();
void UpdateMoveRate();
void SetGoal(float3 newPos, float distance);
Index: Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- Sim/Units/CommandAI/TransportCAI.cpp (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.cpp (working copy)
@@ -19,6 +19,7 @@
#include "Rendering/UnitModels/3DOParser.h"
#include "mmgr.h"
+
static void ScriptCallback(int retCode,void* p1,void* p2)
{
((CTransportCAI*)p1)->ScriptReady();
@@ -47,6 +48,16 @@
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";
@@ -84,10 +95,11 @@
}
Command& c=commandQue.front();
switch(c.id){
- case CMD_LOAD_UNITS: { ExecuteLoadUnits(c); return; }
- case CMD_UNLOAD_UNITS: { ExecuteUnloadUnits(c); return; }
+ 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;
}
@@ -200,114 +212,72 @@
return;
}
}
+
+ isFirstIteration=true;
+ startingDropPos = float3(-1,-1,-1);
+
return;
}
void CTransportCAI::ExecuteUnloadUnits(Command &c)
-{
- 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];
- float3 found;
- CUnit* unitToUnload=((CTransportUnit*)owner)->transported.front().unit;
- bool canUnload=FindEmptySpot(pos,max(16.0f,radius),unitToUnload->radius,found,unitToUnload);
- 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;
+{
+//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;
+
+ case UNLOAD_CRASHFLOOD:
+ if (owner->unitDef->canfly)
+ UnloadUnits_CrashFlood(c,transport);
+ else
+ UnloadUnits_Land(c,transport);
+ break;
+
+ default:UnloadUnits_Land(c,transport); break;
+ }
+
}
+
+
+
void CTransportCAI::ExecuteUnloadUnit(Command &c)
{
CTransportUnit* transport = (CTransportUnit*)owner;
- if (inCommand) {
- if (!owner->cob->busy) {
- // if(scriptReady)
- FinishCommand();
- }
- }
- else {
- const std::list<CTransportUnit::TransportedUnit>& transList =
- transport->transported;
+
+ //new methods
+ switch(unloadType){
+ case UNLOAD_LAND: UnloadLand(c); break;
- if (transList.empty()) {
- FinishCommand();
- return;
- }
+ case UNLOAD_DROP:
+ if (owner->unitDef->canfly)
+ UnloadDrop(c);
+ else
+ UnloadLand(c);
+ break;
+
+ case UNLOAD_LANDFLOOD: UnloadLandFlood(c); break;
- float3 pos(c.params[0], c.params[1], c.params[2]);
- if(goalPos.distance2D(pos) > 20){
- SetGoal(pos, owner->pos);
- }
-
- CUnit* unit = NULL;
- if (c.params.size() < 4) {
- unit = transList.front().unit;
- }
- else {
- const int unitID = (int)c.params[3];
- std::list<CTransportUnit::TransportedUnit>::const_iterator it;
- for (it = transList.begin(); it != transList.end(); ++it) {
- CUnit* carried = it->unit;
- if (unitID == carried->id) {
- unit = carried;
- break;
- }
- }
- if (unit == NULL) {
- FinishCommand();
- return;
- }
- }
-
- if (pos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
- CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
- if (am != NULL) {
- // handle air transports differently
- pos.y = ground->GetHeight(pos.x, pos.z);
- const float3 wantedPos = pos + UpVector * unit->model->height;
- SetGoal(wantedPos, owner->pos);
- am->SetWantedAltitude(unit->model->height);
- am->maxDrift = 1;
- if ((owner->pos.distance(wantedPos) < 8) &&
- (owner->updir.dot(UpVector) > 0.99f)) {
- transport->DetachUnit(unit);
- if (transport->transported.empty()) {
- am->dontLand = false;
- owner->cob->Call("EndTransport");
- }
- const float3 fix = owner->pos + owner->frontdir * 20;
- SetGoal(fix, owner->pos); //move the transport away slightly
- FinishCommand();
- }
- } else {
- inCommand = true;
- scriptReady = false;
- StopMove();
- std::vector<int> args;
- args.push_back(transList.front().unit->id);
- args.push_back(PACKXZ(pos.x, pos.z));
- owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
- }
- }
+ case UNLOAD_CRASHFLOOD:
+ if (owner->unitDef->canfly)
+ UnloadCrashFlood(c);
+ else
+ UnloadLand(c);
+ break;
+
+ default: UnloadLand(c); break;
}
- return;
}
void CTransportCAI::ScriptReady(void)
@@ -342,11 +312,30 @@
return true;
}
+//
+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::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
{
// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
- if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
+ if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) {
for (int a=0;a<100;++a) {
float3 delta(1,0,1);
while(delta.SqLength2D()>1){
@@ -390,7 +379,7 @@
float3 pos(x,ground->GetApproximateHeight(x,y),y);
if(!qf->GetUnitsExact(pos,emptyRadius+8).empty())
continue;
- found=pos;
+ found=pos;
return true;
}
}
@@ -398,6 +387,60 @@
return false;
}
+
+bool CTransportCAI::FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots) {
+ //should only really 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(CTAAirMoveType* am=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) {
+//select suitable spots according to directions we are allowed to exit transport from
+ //TODO
+ return false;
+}
+//
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
CUnit* best=0;
@@ -442,10 +485,14 @@
// return CMD_UNLOAD_UNITS;
}
+
+
+
+
void CTransportCAI::DrawCommands(void)
{
lineDrawer.StartPath(owner->midPos, cmdColors.start);
-
+
if (owner->selfDCountdown != 0) {
lineDrawer.DrawIconAtLastPos(CMD_SELFD);
}
@@ -494,6 +541,7 @@
break;
}
case CMD_LOAD_UNITS:{
+
if(ci->params.size()==4){
const float3 endPos(ci->params[0],ci->params[1],ci->params[2]);
lineDrawer.DrawLineAndIcon(ci->id, endPos, cmdColors.load);
@@ -511,18 +559,21 @@
break;
}
case CMD_UNLOAD_UNITS:{
- if(ci->params.size()==4){
+
+ if(ci->params.size()==4){
const float3 endPos(ci->params[0],ci->params[1],ci->params[2]);
lineDrawer.DrawLineAndIcon(ci->id, endPos, cmdColors.unload);
lineDrawer.Break(endPos, cmdColors.unload);
glSurfaceCircle(endPos, ci->params[3], 20);
- lineDrawer.RestartSameColor();
+ lineDrawer.RestartSameColor();
}
break;
}
case CMD_UNLOAD_UNIT:{
+
const float3 endPos(ci->params[0],ci->params[1],ci->params[2]);
lineDrawer.DrawLineAndIcon(ci->id, endPos, cmdColors.unload);
+
break;
}
case CMD_WAIT:{
@@ -539,6 +590,385 @@
}
+//
+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;
+ }
+ float3 pos(c.params[0],c.params[1],c.params[2]);
+ float radius=c.params[3];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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 ) {
+ dropSpots.clear();
+ startingDropPos = pos;
+
+ approachVector = startingDropPos-owner->pos;
+ approachVector.Normalize();
+ canUnload = FindEmptyDropSpots(pos, pos + approachVector*max(16.0f,radius), dropSpots);
+
+ } else if (!dropSpots.empty() ) {
+ //make sure we check current spot infront of us each unload
+ pos = dropSpots.back(); //take last landing pos as new start spot
+ canUnload = dropSpots.size() > 0;
+ }
+
+ if( canUnload ){
+ if(SpotIsClear(dropSpots.back(),((CTransportUnit*)owner)->transported.front().unit)) {
+ float3 pos = dropSpots.back();
+ Command c2;
+ c2.id=CMD_UNLOAD_UNIT;
+ c2.params.push_back(pos.x);
+ c2.params.push_back(pos.y);
+ c2.params.push_back(pos.z);
+ c2.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c2);
+
+ SlowUpdate();
+ isFirstIteration = false;
+ return;
+ } else {
+ dropSpots.pop_back();
+ }
+ } else {
+
+ startingDropPos = float3(-1,-1,-1);
+ isFirstIteration=true;
+ dropSpots.clear();
+ FinishCommand();
+ }
+}
+
+void CTransportCAI::UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport) {
+
+}
+void CTransportCAI::UnloadUnits_LandFlood(Command& c, CTransportUnit* transport) {
+ 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];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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);
+
+ if (isFirstIteration ) {
+ Command c1;
+ c1.id=CMD_MOVE;
+ c1.params.push_back(pos.x);
+ c1.params.push_back(pos.y);
+ c1.params.push_back(pos.z);
+ c1.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c1);
+ startingDropPos = pos;
+ }
+
+ SlowUpdate();
+ return;
+ } else {
+ FinishCommand();
+ }
+ return;
+
+}
+
+
+//
+void CTransportCAI::UnloadLand(Command& c) {
+ //default unload
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ // if(scriptReady)
+ FinishCommand();
+ }
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
+
+ if (transList.empty()) {
+ FinishCommand();
+ return;
+ }
+
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if(goalPos.distance2D(pos) > 20){
+ SetGoal(pos, owner->pos);
+ }
+
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
+ }
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
+ }
+
+ if (pos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+ if (am != NULL) {
+ // handle air transports differently
+ pos.y = ground->GetHeight(pos.x, pos.z);
+ const float3 wantedPos = pos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(unit->model->height);
+ am->maxDrift = 1;
+ if ((owner->pos.distance(wantedPos) < 8) &&
+ (owner->updir.dot(UpVector) > 0.99f)) {
+ transport->DetachUnit(unit);
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ }
+ const float3 fix = owner->pos + owner->frontdir * 20;
+ SetGoal(fix, owner->pos); //move the transport away slightly
+ FinishCommand();
+ }
+ } else {
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ }
+ }
+ }
+ return;
+
+}
+
+
+
+void CTransportCAI::UnloadDrop(Command& c) {
+
+ //fly over and drop unit
+ if(inCommand){
+ if(!owner->cob->busy)
+ //if(scriptReady)
+ FinishCommand();
+ } else {
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
+ }
+
+ float3 pos(c.params[0],c.params[1],c.params[2]); //head towards goal
+
+ //note that taairmovetype must be modified to allow non stop movement through goals for this to work well
+ if(goalPos.distance2D(pos)>20){
+ SetGoal(pos,owner->pos);
+ lastDropPos = pos;
+ }
+
+
+
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){
+
+ pos.y=ground->GetHeight(pos.x,pos.z);
+ CUnit* unit=((CTransportUnit*)owner)->transported.front().unit;
+ am->maxDrift=1;
+
+ //if near target or have past it accidentally- drop unit
+ float t1 = owner->pos.distance2D(pos);
+ bool t2 = (((pos - owner->pos).Normalize()).distance(owner->frontdir.Normalize()) > 0.5 && owner->pos.distance2D(pos)< 205);
+
+ if(t1 < 40 || t2) {
+ am->dontLand=true;
+ //owner->cob->Call("EndTransport");
+ ((CTransportUnit*)owner)->DetachUnitFromAir(unit,pos);
+ dropSpots.pop_back();
+
+ if (dropSpots.empty()) {
+ float3 fix = owner->pos+owner->frontdir*200;
+ SetGoal(fix,owner->pos);//move the transport away after last drop
+ }
+ FinishCommand();
+ }
+
+ } else {
+ inCommand=true;
+ scriptReady=false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(((CTransportUnit*)owner)->transported.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop",args,ScriptCallback,this,0);
+ }
+
+ }
+
+}
+
+void CTransportCAI::UnloadCrashFlood(Command& c) {
+
+}
+void CTransportCAI::UnloadLandFlood(Command& c) {
+ //land, then release all units at once
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ //if(scriptReady)
+ FinishCommand();
+ }
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
+
+ if (transList.empty()) {
+ FinishCommand();
+ return;
+ }
+
+ //check units are all carried
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
+ }
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
+ }
+
+ //move to position
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if (isFirstIteration) {
+ if(goalPos.distance2D(pos) > 20){
+ SetGoal(startingDropPos, owner->pos);
+
+ }
+ }
+
+ if (startingDropPos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+
+ //create aircraft movetype instance
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+
+ if (am != NULL) {
+ //lower to ground
+ startingDropPos.y = ground->GetHeight(startingDropPos.x,startingDropPos.z);
+ const float3 wantedPos = startingDropPos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(1);
+ am->maxDrift = 1;
+ am->dontLand = false;
+ isFirstIteration = false;
+
+ //once at ground
+ if (owner->pos.y - ground->GetHeight(wantedPos.x,wantedPos.z) < 8) {
+
+ am->SetState(am->AIRCRAFT_LANDED);//nail it to the ground before it tries jumping up, only to land again...
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); //call this so that other animations such as opening doors may be started
+ transport->DetachUnitFromAir(unit,pos);
+
+ FinishCommand();
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ am->UpdateLanded();
+ }
+ }
+
+ } else {
+
+ //land transports
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ //owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ transport->DetachUnitFromAir(unit,pos);
+ isFirstIteration = false;
+ FinishCommand();
+ if (transport->transported.empty())
+ owner->cob->Call("EndTransport");
+
+ }
+ }
+ }
+ return;
+}
+
void CTransportCAI::FinishCommand(void)
{
if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType))
Index: Sim/Units/CommandAI/TransportCAI.h
===================================================================
--- Sim/Units/CommandAI/TransportCAI.h (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.h (working copy)
@@ -2,7 +2,13 @@
#define TRANSPORTCAI_H
#include "MobileCAI.h"
+#include "Sim/MoveTypes/TAAirMoveType.h"
+#define UNLOAD_LAND 0
+#define UNLOAD_DROP 1
+#define UNLOAD_LANDFLOOD 2
+#define UNLOAD_CRASHFLOOD 3
+
class CTransportCAI :
public CMobileCAI
{
@@ -16,6 +22,9 @@
bool CanTransport(CUnit* unit);
bool FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload);
+ bool FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots);
+ bool FindEmptyFloodSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots, std::vector<float3> exitDirs);
+
CUnit* FindUnitToTransport(float3 center, float radius);
int GetDefaultCmd(CUnit* pointed,CFeature* feature);
void DrawCommands(void);
@@ -29,6 +38,31 @@
int toBeTransportedUnitId;
bool scriptReady;
int lastCall;
+
+private:
+
+
+ void UnloadUnits_Land(Command& c, CTransportUnit* transport);
+ void UnloadUnits_Drop(Command& c, CTransportUnit* transport);
+ void UnloadUnits_LandFlood(Command& c, CTransportUnit* transport);
+ void UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport); //incomplete
+ //
+ void UnloadNormal(Command& c);
+ void UnloadLand(Command& c);
+ void UnloadDrop(Command& c); //parachute drop units
+ void UnloadLandFlood(Command& c); //land and dispatch units all at once
+ void UnloadCrashFlood(Command& c); //slam into landscape abruptly and dispatch units all at once (incomplete)
+ //
+ bool SpotIsClear(float3 pos, CUnit* u);
+
+
+ std::list<float3> dropSpots;
+ int unloadType;
+ bool isFirstIteration;
+ float3 startingDropPos;
+ float3 lastDropPos;
+ float3 approachVector; //direction from which we travel to drop point
+ float3 endDropPos;
};
Index: Sim/Units/Unit.cpp
===================================================================
--- Sim/Units/Unit.cpp (revision 4358)
+++ Sim/Units/Unit.cpp (working copy)
@@ -120,6 +120,7 @@
lastSlowUpdate(0),
los(0),
userAttackPos(0,0,0),
+ falling(false),
crashing(false),
cob(0),
bonusShieldDir(1,0,0),
@@ -1520,6 +1521,8 @@
globalAI->UnitCreated(this); // FIXME -- add builder?
}
+
+
void CUnit::UpdateTerrainType()
{
if (curTerrainType != lastTerrainType) {
@@ -1951,6 +1954,17 @@
Draw();
}
+void CUnit::Drop(float3 parentPos,float3 parentDir) {
+ //drop unit from position
+ float landingHeight = ground->GetApproximateHeight(pos.x, pos.z);
+ falling = true;
+ this->pos.y = parentPos.y - height;
+ this->frontdir = parentDir;
+ this->frontdir.y = 0;
+ this->speed.y = 0;
+
+}
+
void CUnit::hitByWeaponIdCallback(int retCode, void *p1, void *p2)
{
((CUnit*)p1)->weaponHitMod = retCode*0.01f;
Index: Sim/Units/Unit.h
===================================================================
--- Sim/Units/Unit.h (revision 4358)
+++ Sim/Units/Unit.h (working copy)
@@ -287,6 +287,7 @@
std::string tooltip;
+ bool falling; //for units being dropped from transports (parachute drops)
bool crashing;
bool isDead; //prevent damage from hitting an already dead unit (causing multi wreck etc)
@@ -357,6 +358,7 @@
virtual void IncomingMissile(CMissileProjectile* missile);
void TempHoldFire(void);
void ReleaseTempHoldFire(void);
+ void Drop(float3 parentPos,float3 parentDir); //start this unit in freefall from parent unit
virtual void DrawS3O(void);
void PostLoad();
static void hitByWeaponIdCallback(int retCode, void *p1, void *p2);
Index: Sim/Units/UnitDef.h
===================================================================
--- Sim/Units/UnitDef.h (revision 4358)
+++ Sim/Units/UnitDef.h (working copy)
@@ -280,6 +280,7 @@
float loadingRadius; //for transports
int transportCapacity;
int transportSize;
+ int transportUnloadMethod; //0 - land unload, 1 - flyover drop, 2 - land flood, 3 - crashland flood
bool isAirBase;
float transportMass;
bool holdSteady;
Index: Sim/Units/UnitDefHandler.cpp
===================================================================
--- Sim/Units/UnitDefHandler.cpp (revision 4358)
+++ Sim/Units/UnitDefHandler.cpp (working copy)
@@ -366,6 +366,7 @@
ud.holdSteady = udTable.GetBool("holdSteady", true);
ud.releaseHeld = udTable.GetBool("releaseHeld", false);
ud.transportByEnemy = udTable.GetBool("transportByEnemy", true);
+ ud.transportUnloadMethod = udTable.GetInt("transportUnloadMethod" , 0);//0 normal, 1 parachute drop, 2 land flood
ud.wingDrag = udTable.GetFloat("wingDrag", 0.07f); // drag caused by wings
ud.wingAngle = udTable.GetFloat("wingAngle", 0.08f); // angle between front and the wing plane
Index: Sim/Units/UnitTypes/TransportUnit.cpp
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.cpp (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.cpp (working copy)
@@ -219,3 +219,80 @@
}
}
}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit, float3 pos)
+{
+
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ loshandler->MoveUnit(unit,false);
+ unit->moveType->useHeading=true;
+
+ //add an additional move command for after we land
+ Command c;
+ c.id=CMD_MOVE;
+ c.params.push_back(pos.x);
+ c.params.push_back(pos.y);
+ c.params.push_back(pos.z);
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir);
+ //TODO - add call to some animation for drop sequence
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+
+ break;
+ }
+ }
+
+}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit)
+{
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ unit->Block();
+
+ loshandler->MoveUnit(unit,false);
+ unit->moveType->useHeading=true;
+
+ Command c;
+ c.id=CMD_STOP;
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir);
+ //TODO - add call to some animation for drop sequence
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+
+ break;
+ }
+ }
+}
Index: Sim/Units/UnitTypes/TransportUnit.h
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.h (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.h (working copy)
@@ -32,6 +32,8 @@
void KillUnit(bool selfDestruct,bool reclaimed, CUnit *attacker);
void AttachUnit(CUnit* unit, int piece);
void DetachUnit(CUnit* unit);
+ void DetachUnitFromAir(CUnit* unit,float3 pos);//moves to position after
+ void DetachUnitFromAir(CUnit* unit);
bool CanTransport(CUnit* unit);
};
-
newTransportMethods 0.18.diff (44,783 bytes) 2007-09-16 17:49
Index: Lua/LuaUnitDefs.cpp
===================================================================
--- Lua/LuaUnitDefs.cpp (revision 4358)
+++ Lua/LuaUnitDefs.cpp (working copy)
@@ -861,15 +861,18 @@
ADD_INT("buildangle", ud.buildangle);
// transport stuff
- ADD_INT( "transportCapacity", ud.transportCapacity);
- ADD_INT( "transportSize", ud.transportSize);
- ADD_FLOAT("transportMass", ud.transportMass);
- ADD_FLOAT("loadingRadius", ud.loadingRadius);
- ADD_BOOL( "isAirBase", ud.isAirBase);
- ADD_BOOL( "isFirePlatform", ud.isfireplatform);
- ADD_BOOL( "holdSteady", ud.holdSteady);
- ADD_BOOL( "releaseHeld", ud.releaseHeld);
- ADD_BOOL( "transportByEnemy", ud.transportByEnemy);
+ ADD_INT( "transportCapacity", ud.transportCapacity);
+ ADD_INT( "transportSize", ud.transportSize);
+ ADD_FLOAT("transportMass", ud.transportMass);
+ ADD_FLOAT("loadingRadius", ud.loadingRadius);
+ ADD_BOOL( "isAirBase", ud.isAirBase);
+ ADD_BOOL( "isFirePlatform", ud.isfireplatform);
+ ADD_BOOL( "holdSteady", ud.holdSteady);
+ ADD_BOOL( "releaseHeld", ud.releaseHeld);
+ ADD_BOOL( "transportByEnemy", ud.transportByEnemy);
+ ADD_INT("transportUnloadMethod",ud.transportUnloadMethod); //new
+ ADD_FLOAT( "fallSpeed", ud.fallSpeed); //new
+ ADD_FLOAT( "unitFallSpeed", ud.unitFallSpeed); //new
ADD_BOOL( "startCloaked", ud.startCloaked);
ADD_FLOAT("cloakCost", ud.cloakCost);
Index: Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- Sim/MoveTypes/groundmovetype.cpp (revision 4358)
+++ Sim/MoveTypes/groundmovetype.cpp (working copy)
@@ -129,8 +129,10 @@
deltaSpeed(0),
deltaHeading(0),
skidding(false),
- flying(false),
+ flying(false),
skidRotSpeed(0),
+
+ dropHeight(0),
floatOnWater(false),
skidRotVector(UpVector),
skidRotSpeed2(0),
@@ -195,13 +197,19 @@
&& (!floatOnWater || ground->GetHeight(owner->midPos.x, owner->midPos.z) > 0))
{
skidding = true;
- }
+ }
if(skidding){
UpdateSkid();
return;
}
+ if(owner->falling) {
+ //set drop height when we start to drop
+ UpdateControlledDrop();
+ return;
+ }
+
if(owner->stunned){
owner->cob->Call(COBFN_StopMoving);
owner->speed=ZeroVector;
@@ -282,7 +290,7 @@
if(nextDeltaSpeedUpdate<=gs->frameNum){
wantedSpeed = pathId ? requestedSpeed : 0;
- //If arriving at waypoint, then need to slow down, or may pass it.
+ //If arriving at waypoint, then need to slow down, or may pass it.
if(!owner->commandAI->HasMoreMoveCommands()
&& currentDistanceToWaypoint < BreakingDistance(currentSpeed) + SQUARE_SIZE) {
wantedSpeed = std::min((float)wantedSpeed, (float)(sqrt(currentDistanceToWaypoint * -owner->mobility->maxBreaking)));
@@ -309,7 +317,8 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!owner->falling) //need this to stop jitter when falling, but may be causing crash?
+ owner->pos.y=wh;
}
if(owner->pos!=oldPos){
@@ -323,9 +332,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
- owner->speed=owner->pos-oldPos;
+ owner->speed = owner->pos - oldPos;
owner->midPos = owner->pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
oldPos=owner->pos;
@@ -367,10 +377,13 @@
logOutput.Print("Unit restart %i",owner->id);
StartEngine();
}
+
+
+
owner->pos.CheckInBounds(); //just kindly move it into the map again instead of deleteing
-
- float wh; //need the following if the ground change height when unit stand still
+ float wh;
+ //need the following if the ground change height when unit stand still
if(floatOnWater){
wh = ground->GetHeight(owner->pos.x, owner->pos.z);
if(wh==0)
@@ -378,8 +391,12 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
+ //owner->pos.y=wh;
+
if(!(owner->pos==oldSlowUpdatePos)){
oldSlowUpdatePos=owner->pos;
@@ -549,7 +566,7 @@
}
owner->frontdir = GetVectorFromHeading(heading);
- if(owner->upright){
+ if(owner->upright) {
owner->updir=UpVector;
owner->rightdir=owner->frontdir.cross(owner->updir);
} else {
@@ -557,7 +574,7 @@
owner->rightdir=owner->frontdir.cross(owner->updir);
owner->rightdir.Normalize();
owner->frontdir=owner->updir.cross(owner->rightdir);
- }
+ }
owner->heading=heading;
flatFrontDir=owner->frontdir;
flatFrontDir.y=0;
@@ -574,7 +591,7 @@
if(skidding){
speed+=impulse;
- impulse=ZeroVector;
+ impulse=ZeroVector;
}
float3 groundNormal=ground->GetNormal(owner->pos.x,owner->pos.z);
@@ -817,6 +834,55 @@
}
}
+
+void CGroundMoveType::UpdateControlledDrop(void)
+{
+ float3& speed=owner->speed;
+ float3& pos=owner->pos;
+ float3& midPos=(float3)owner->midPos;
+
+
+
+ if(owner->falling){
+
+ //set us upright
+
+
+ owner->cob->Call("Falling"); //start/continue parachute animation
+
+ speed.y += gs->gravity*owner->fallSpeed;
+
+ if(owner->speed.y > 0) //sometimes the dropped unit gets an upward force, still unsure where its coming from
+ owner->speed.y = 0;
+
+ midPos += speed;
+ pos = midPos - owner->frontdir * owner->relMidPos.z
+ - owner->updir * owner->relMidPos.y
+ - owner->rightdir * owner->relMidPos.x;
+
+ owner->midPos.y = owner->pos.y + owner->relMidPos.y;
+
+ if(midPos.y < 0)
+ speed*=0.90;
+
+ float wh;
+
+ if(floatOnWater)
+ wh = ground->GetHeight(midPos.x, midPos.z);
+ else
+ wh = ground->GetHeight2(midPos.x, midPos.z);
+
+ if(wh > midPos.y-owner->relMidPos.y){
+ owner->falling = false;
+ midPos.y = wh + owner->relMidPos.y - speed.y*0.8;
+ owner->cob->Call("Landed"); //stop parachute animation
+ }
+
+
+
+ }
+}
+
float CGroundMoveType::GetFlyTime(float3 pos, float3 speed)
{
return 0;
Index: Sim/MoveTypes/groundmovetype.h
===================================================================
--- Sim/MoveTypes/groundmovetype.h (revision 4358)
+++ Sim/MoveTypes/groundmovetype.h (working copy)
@@ -73,6 +73,7 @@
unsigned int nonMovingFailures; //how many times we have requested a path from the same place
int moveType;
+
bool floatOnWater;
@@ -107,6 +108,7 @@
void UpdateSkid(void);
void CheckCollisionSkid(void);
+ void UpdateControlledDrop(void);
float GetFlyTime(float3 pos, float3 speed);
void CalcSkidRot(void);
@@ -114,6 +116,8 @@
bool flying;
float skidRotSpeed;
+ float dropSpeed;
+ float dropHeight;
float3 skidRotVector;
float skidRotSpeed2;
float skidRotPos2;
Index: Sim/MoveTypes/TAAirMoveType.cpp
===================================================================
--- Sim/MoveTypes/TAAirMoveType.cpp (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.cpp (working copy)
@@ -15,9 +15,11 @@
#include "Sim/Misc/GeometricObjects.h"
#include "Mobility.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
+#include "Sim/Units/CommandAI/CommandAI.h"
CR_BIND_DERIVED(CTAAirMoveType, CMoveType, (NULL));
+
CR_REG_METADATA(CTAAirMoveType, (
CR_MEMBER(dontCheckCol),
@@ -45,6 +47,8 @@
CR_MEMBER(decRate),
CR_MEMBER(altitudeRate),
+
+
CR_MEMBER(breakDistance),
CR_MEMBER(dontLand),
CR_MEMBER(lastMoveRate),
@@ -67,6 +71,7 @@
));
+
CTAAirMoveType::CTAAirMoveType(CUnit* owner) :
CMoveType(owner),
aircraftState(AIRCRAFT_LANDED),
@@ -144,6 +149,8 @@
void CTAAirMoveType::SetState(AircraftState newState)
{
+ float3 &pos=owner->pos;
+
if (newState == aircraftState)
return;
@@ -175,10 +182,10 @@
// ownerActivated = false;
// owner->cob->Call(COBFN_Deactivate);
// }
- break;
+ break;
case AIRCRAFT_HOVERING:
wantedHeight = orgWantedHeight;
- wantedSpeed = ZeroVector;
+ wantedSpeed = ZeroVector; //test
// fall through...
default:
owner->physicalState = CSolidObject::Flying;
@@ -225,7 +232,7 @@
SetState(AIRCRAFT_FLYING);
break;
case AIRCRAFT_CRASHING:
- break;
+ break;
}
//logOutput.Print("Moving to %f %f %f", pos.x, pos.y, pos.z);
@@ -236,7 +243,7 @@
void CTAAirMoveType::StartMoving(float3 pos, float goalRadius, float speed)
{
- //logOutput.Print("airmove: Ignoring startmoving speed");
+ //logOutput.Print("airmove: Ignoring startmoving speed"); //test
StartMoving(pos, goalRadius);
}
@@ -273,8 +280,7 @@
void CTAAirMoveType::ExecuteStop()
{
- wantToStop = false;
-// logOutput.Print("Executing stop");
+ wantToStop = false;
switch (aircraftState) {
case AIRCRAFT_TAKEOFF:
SetState(AIRCRAFT_LANDING);
@@ -302,8 +308,7 @@
}
void CTAAirMoveType::StopMoving()
-{
-// logOutput.Print("stop order");
+{
wantToStop = true;
forceHeading=false;
owner->isMoving=false;
@@ -320,7 +325,6 @@
void CTAAirMoveType::UpdateLanded()
{
float3 &pos = owner->pos;
-
//dont place on ground if we are on a repair pad
if (padStatus == 0) {
if (owner -> unitDef -> canSubmerge)
@@ -358,9 +362,12 @@
void CTAAirMoveType::UpdateHovering()
{
float driftSpeed = owner->unitDef->dlHoverFactor;
+ float3 dir = goalPos - owner->pos;
- // move towards goal position
- float3 dir = goalPos - owner->pos;
+ // move towards goal position if its not immediately behind us when we have more waypoints to get to
+ if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1 )
+ dir = owner->frontdir;
+
wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f;
// damping
@@ -379,9 +386,15 @@
//Direction to where we would like to be
float3 dir = goalPos - pos;
+ //dont change direction for waypoints we just flew over and missed slightly
+ if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1 )
+ dir = owner->frontdir;
+
+
owner->restTime=0;
//are we there yet?
+ //TODO - add code to stop aircraft stopping for intermediate waypoints (according to pretedermined tag)
// logOutput.Print("max drift %f %i %f %f",maxDrift,waitCounter,dir.Length2D(),fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight));
bool closeToGoal=dir.SqLength2D() < maxDrift*maxDrift && fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight)<maxDrift;
if(flyState==FLY_ATTACKING)
@@ -393,7 +406,7 @@
if(dontLand || (++waitCounter<55 && dynamic_cast<CTransportUnit*>(owner)) || !autoLand){ //transport aircrafts need some time to detect that they can pickup
if (dynamic_cast<CTransportUnit*>(owner)) {
wantedSpeed=ZeroVector;
- if(waitCounter>60){
+ if(waitCounter>55){ //was 60 - causes too much judder when at 60
wantedHeight=orgWantedHeight;
}
} else
@@ -409,7 +422,7 @@
// break;
waitCounter++;
if (waitCounter > 100) {
- //logOutput.Print("moving circlepos");
+ logOutput.Print("moving circlepos");
if(owner->unitDef->airStrafe){
float3 relPos = pos - circlingPos;
if(relPos.x<0.0001f && relPos.x>-0.0001f)
@@ -489,30 +502,38 @@
float realMax = maxSpeed;
float dist=dir.Length2D();
- //If we are close to our goal, we should go slow enough to be able to break in time
- //if in attack mode dont slow down
- if (flyState!=FLY_ATTACKING && dist < breakDistance) {
- realMax = dist/(speed.Length2D()+0.01f) * decRate;
- //logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax);
- }
+ //If we are close to our goal, we should go slow enough to be able to break in time
+ //new additional rule:
+ //if in attack mode or have more this is an intermediate waypoint dont
+ //slow down except if near ground level
+
+ //if (flyState!=FLY_ATTACKING && dist < breakDistance) { //old code
+ if ((flyState!=FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands() ) || (pos.y - ground->GetHeight(pos.x, pos.z) < orgWantedHeight/2)) {
+ realMax = dist/(speed.Length2D()+0.01f) * decRate;
+ //logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax); //test
+ }
- wantedSpeed = dir.Normalize() * realMax;
+ wantedSpeed = dir.Normalize() * realMax;
+ UpdateAirPhysics();
- UpdateAirPhysics();
+ //Point toward goal or forward - unless we just passed it to get to another goal
+ if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
+ dir = circlingPos - pos;
+ }
+ else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1 ) {
+ dir = owner->frontdir;
+ }
+ else {
+ dir = goalPos - pos;
+ }
+ if(dir.SqLength2D()>1)
+ wantedHeading = GetHeadingFromVector(dir.x, dir.z);
- //Point toward goal or forward
- if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
- dir = circlingPos - pos;
- } else {
- dir = goalPos - pos;
- }
- if(dir.SqLength2D()>1)
- wantedHeading = GetHeadingFromVector(dir.x, dir.z);
+
}
-
void CTAAirMoveType::UpdateLanding()
{
float3 &pos = owner->pos;
@@ -720,6 +741,10 @@
pos+=speed;
}
+
+
+
+
void CTAAirMoveType::UpdateMoveRate()
{
int curRate;
Index: Sim/MoveTypes/TAAirMoveType.h
===================================================================
--- Sim/MoveTypes/TAAirMoveType.h (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.h (working copy)
@@ -7,7 +7,7 @@
class CTAAirMoveType :
public CMoveType
{
- CR_DECLARE(CTAAirMoveType);
+ CR_DECLARE(CTAAirMoveType);
public:
enum AircraftState{
AIRCRAFT_LANDED,
@@ -15,7 +15,7 @@
AIRCRAFT_LANDING,
AIRCRAFT_CRASHING,
AIRCRAFT_TAKEOFF,
- AIRCRAFT_HOVERING // this is what happens to aircraft with dontLand=1 in fbi
+ AIRCRAFT_HOVERING // this is what happens to aircraft with dontLand=1 in fbi
} aircraftState;
enum FlyState {
@@ -71,6 +71,7 @@
float3 oldGoalPos; //goalpos to resume flying to after landing
bool autoLand;
+
CTAAirMoveType(CUnit* owner);
~CTAAirMoveType(void);
@@ -95,7 +96,7 @@
//Helpers for (multiple) state handlers
void UpdateHeading();
void UpdateBanking(bool noBanking);
- void UpdateAirPhysics();
+ void UpdateAirPhysics();
void UpdateMoveRate();
void SetGoal(float3 newPos, float distance);
Index: Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- Sim/Units/CommandAI/TransportCAI.cpp (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.cpp (working copy)
@@ -19,6 +19,7 @@
#include "Rendering/UnitModels/3DOParser.h"
#include "mmgr.h"
+
static void ScriptCallback(int retCode,void* p1,void* p2)
{
((CTransportCAI*)p1)->ScriptReady();
@@ -47,6 +48,16 @@
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";
@@ -84,10 +95,11 @@
}
Command& c=commandQue.front();
switch(c.id){
- case CMD_LOAD_UNITS: { ExecuteLoadUnits(c); return; }
- case CMD_UNLOAD_UNITS: { ExecuteUnloadUnits(c); return; }
+ 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;
}
@@ -200,121 +212,58 @@
return;
}
}
+
+ isFirstIteration=true;
+ startingDropPos = float3(-1,-1,-1);
+
return;
}
+void CTransportCAI::ExecuteUnloadUnits(Command &c)
+{
+//new Methods
+ CTransportUnit* transport=(CTransportUnit*)owner;
-void CTransportCAI::ExecuteUnloadUnits(Command &c)
-{
- 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];
- float3 found;
- CUnit* unitToUnload=((CTransportUnit*)owner)->transported.front().unit;
- bool canUnload=FindEmptySpot(pos,max(16.0f,radius),unitToUnload->radius,found,unitToUnload);
- 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;
+
+ 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)
{
CTransportUnit* transport = (CTransportUnit*)owner;
- if (inCommand) {
- if (!owner->cob->busy) {
- // if(scriptReady)
- FinishCommand();
- }
- }
- else {
- const std::list<CTransportUnit::TransportedUnit>& transList =
- transport->transported;
+
+ //new methods
+ switch(unloadType){
+ case UNLOAD_LAND: UnloadLand(c); break;
- if (transList.empty()) {
- FinishCommand();
- return;
- }
+ case UNLOAD_DROP:
+ if (owner->unitDef->canfly)
+ UnloadDrop(c);
+ else
+ UnloadLand(c);
+ break;
+
+ case UNLOAD_LANDFLOOD: UnloadLandFlood(c); break;
- float3 pos(c.params[0], c.params[1], c.params[2]);
- if(goalPos.distance2D(pos) > 20){
- SetGoal(pos, owner->pos);
- }
-
- CUnit* unit = NULL;
- if (c.params.size() < 4) {
- unit = transList.front().unit;
- }
- else {
- const int unitID = (int)c.params[3];
- std::list<CTransportUnit::TransportedUnit>::const_iterator it;
- for (it = transList.begin(); it != transList.end(); ++it) {
- CUnit* carried = it->unit;
- if (unitID == carried->id) {
- unit = carried;
- break;
- }
- }
- if (unit == NULL) {
- FinishCommand();
- return;
- }
- }
-
- if (pos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
- CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
- if (am != NULL) {
- // handle air transports differently
- pos.y = ground->GetHeight(pos.x, pos.z);
- const float3 wantedPos = pos + UpVector * unit->model->height;
- SetGoal(wantedPos, owner->pos);
- am->SetWantedAltitude(unit->model->height);
- am->maxDrift = 1;
- if ((owner->pos.distance(wantedPos) < 8) &&
- (owner->updir.dot(UpVector) > 0.99f)) {
- transport->DetachUnit(unit);
- if (transport->transported.empty()) {
- am->dontLand = false;
- owner->cob->Call("EndTransport");
- }
- const float3 fix = owner->pos + owner->frontdir * 20;
- SetGoal(fix, owner->pos); //move the transport away slightly
- FinishCommand();
- }
- } else {
- inCommand = true;
- scriptReady = false;
- StopMove();
- std::vector<int> args;
- args.push_back(transList.front().unit->id);
- args.push_back(PACKXZ(pos.x, pos.z));
- owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
- }
- }
+ default: UnloadLand(c); break;
}
- return;
}
-
void CTransportCAI::ScriptReady(void)
{
scriptReady = true; // NOTE: does not seem to be used
}
-
bool CTransportCAI::CanTransport(CUnit* unit)
{
CTransportUnit* transport=(CTransportUnit*)owner;
@@ -342,11 +291,24 @@
return true;
}
+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::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
{
// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
- if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
+ if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) {
for (int a=0;a<100;++a) {
float3 delta(1,0,1);
while(delta.SqLength2D()>1){
@@ -390,7 +352,7 @@
float3 pos(x,ground->GetApproximateHeight(x,y),y);
if(!qf->GetUnitsExact(pos,emptyRadius+8).empty())
continue;
- found=pos;
+ found=pos;
return true;
}
}
@@ -398,6 +360,60 @@
return false;
}
+
+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(CTAAirMoveType* am=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) {
+//select suitable spots according to directions we are allowed to exit transport from
+ //TODO
+ return false;
+}
+//
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
CUnit* best=0;
@@ -414,7 +430,6 @@
}
return best;
}
-
int CTransportCAI::GetDefaultCmd(CUnit* pointed, CFeature* feature)
{
if (pointed) {
@@ -441,11 +456,10 @@
// else
// return CMD_UNLOAD_UNITS;
}
-
void CTransportCAI::DrawCommands(void)
{
lineDrawer.StartPath(owner->midPos, cmdColors.start);
-
+
if (owner->selfDCountdown != 0) {
lineDrawer.DrawIconAtLastPos(CMD_SELFD);
}
@@ -494,6 +508,7 @@
break;
}
case CMD_LOAD_UNITS:{
+
if(ci->params.size()==4){
const float3 endPos(ci->params[0],ci->params[1],ci->params[2]);
lineDrawer.DrawLineAndIcon(ci->id, endPos, cmdColors.load);
@@ -511,18 +526,21 @@
break;
}
case CMD_UNLOAD_UNITS:{
- if(ci->params.size()==4){
+
+ if(ci->params.size()==4){
const float3 endPos(ci->params[0],ci->params[1],ci->params[2]);
lineDrawer.DrawLineAndIcon(ci->id, endPos, cmdColors.unload);
lineDrawer.Break(endPos, cmdColors.unload);
glSurfaceCircle(endPos, ci->params[3], 20);
- lineDrawer.RestartSameColor();
+ lineDrawer.RestartSameColor();
}
break;
}
case CMD_UNLOAD_UNIT:{
+
const float3 endPos(ci->params[0],ci->params[1],ci->params[2]);
lineDrawer.DrawLineAndIcon(ci->id, endPos, cmdColors.unload);
+
break;
}
case CMD_WAIT:{
@@ -539,6 +557,384 @@
}
+//
+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;
+ }
+ float3 pos(c.params[0],c.params[1],c.params[2]);
+ float radius=c.params[3];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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 ) {
+ dropSpots.clear();
+ startingDropPos = pos;
+
+ approachVector = startingDropPos-owner->pos;
+ approachVector.Normalize();
+ canUnload = FindEmptyDropSpots(pos, pos + approachVector*max(16.0f,radius), dropSpots);
+
+ } else if (!dropSpots.empty() ) {
+ //make sure we check current spot infront of us each unload
+ pos = dropSpots.back(); //take last landing pos as new start spot
+ canUnload = dropSpots.size() > 0;
+ }
+
+ if( canUnload ){
+ if(SpotIsClear(dropSpots.back(),((CTransportUnit*)owner)->transported.front().unit)) {
+ float3 pos = dropSpots.back();
+ Command c2;
+ c2.id=CMD_UNLOAD_UNIT;
+ c2.params.push_back(pos.x);
+ c2.params.push_back(pos.y);
+ c2.params.push_back(pos.z);
+ c2.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c2);
+
+ SlowUpdate();
+ isFirstIteration = false;
+ return;
+ } else {
+ dropSpots.pop_back();
+ }
+ } else {
+
+ startingDropPos = float3(-1,-1,-1);
+ isFirstIteration=true;
+ dropSpots.clear();
+ FinishCommand();
+ }
+}
+void CTransportCAI::UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport) {
+ //TODO - fly into the ground, doing damage to units at landing pos, then unload.
+ //needs heavy modification of TAAirMoveType
+}
+void CTransportCAI::UnloadUnits_LandFlood(Command& c, CTransportUnit* transport) {
+ 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];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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);
+
+ if (isFirstIteration ) {
+ Command c1;
+ c1.id=CMD_MOVE;
+ c1.params.push_back(pos.x);
+ c1.params.push_back(pos.y);
+ c1.params.push_back(pos.z);
+ c1.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c1);
+ startingDropPos = pos;
+ }
+
+ SlowUpdate();
+ return;
+ } else {
+ FinishCommand();
+ }
+ return;
+
+}
+
+
+//
+void CTransportCAI::UnloadLand(Command& c) {
+ //default unload
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ // if(scriptReady)
+ FinishCommand();
+ }
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
+
+ if (transList.empty()) {
+ FinishCommand();
+ return;
+ }
+
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if(goalPos.distance2D(pos) > 20){
+ SetGoal(pos, owner->pos);
+ }
+
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
+ }
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
+ }
+
+ if (pos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+ if (am != NULL) {
+ // handle air transports differently
+ pos.y = ground->GetHeight(pos.x, pos.z);
+ const float3 wantedPos = pos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(unit->model->height);
+ am->maxDrift = 1;
+ if ((owner->pos.distance(wantedPos) < 8) &&
+ (owner->updir.dot(UpVector) > 0.99f)) {
+ transport->DetachUnit(unit);
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ }
+ const float3 fix = owner->pos + owner->frontdir * 20;
+ SetGoal(fix, owner->pos); //move the transport away slightly
+ FinishCommand();
+ }
+ } else {
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ }
+ }
+ }
+ return;
+
+}
+void CTransportCAI::UnloadDrop(Command& c) {
+
+ //fly over and drop unit
+ if(inCommand){
+ if(!owner->cob->busy)
+ //if(scriptReady)
+ FinishCommand();
+ } else {
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
+ }
+
+ float3 pos(c.params[0],c.params[1],c.params[2]); //head towards goal
+
+ //note that taairmovetype must be modified to allow non stop movement through goals for this to work well
+ if(goalPos.distance2D(pos)>20){
+ SetGoal(pos,owner->pos);
+ lastDropPos = pos;
+ }
+
+
+
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){
+
+ pos.y=ground->GetHeight(pos.x,pos.z);
+ CUnit* unit=((CTransportUnit*)owner)->transported.front().unit;
+ am->maxDrift=1;
+
+ //if near target or have past it accidentally- drop unit
+ if(owner->pos.distance2D(pos) < 40 || (((pos - owner->pos).Normalize()).distance(owner->frontdir.Normalize()) > 0.5 && owner->pos.distance2D(pos)< 205)) {
+ am->dontLand=true;
+ owner->cob->Call("EndTransport"); //test
+ ((CTransportUnit*)owner)->DetachUnitFromAir(unit,pos);
+ dropSpots.pop_back();
+
+ if (dropSpots.empty()) {
+ float3 fix = owner->pos+owner->frontdir*200;
+ SetGoal(fix,owner->pos);//move the transport away after last drop
+ }
+ FinishCommand();
+ }
+
+ } else {
+ inCommand=true;
+ scriptReady=false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(((CTransportUnit*)owner)->transported.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop",args,ScriptCallback,this,0);
+ }
+
+ }
+
+}
+void CTransportCAI::UnloadCrashFlood(Command& c) {
+
+}
+void CTransportCAI::UnloadLandFlood(Command& c) {
+ //land, then release all units at once
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ //if(scriptReady)
+ FinishCommand();
+ }
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
+
+ if (transList.empty()) {
+ FinishCommand();
+ return;
+ }
+
+ //check units are all carried
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
+ }
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
+ }
+
+ //move to position
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if (isFirstIteration) {
+ if(goalPos.distance2D(pos) > 20){
+ SetGoal(startingDropPos, owner->pos);
+
+ }
+ }
+
+ if (startingDropPos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+
+
+ //create aircraft movetype instance
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+
+
+ if (am != NULL) {
+ //lower to ground
+
+ startingDropPos.y = ground->GetHeight(startingDropPos.x,startingDropPos.z);
+ const float3 wantedPos = startingDropPos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(1);
+ am->maxDrift = 1;
+ am->dontLand = false;
+
+ //when on our way down start animations for unloading gear
+ if (isFirstIteration) {
+ owner->cob->Call("StartUnload");
+ }
+ isFirstIteration = false;
+
+ //once at ground
+ if (owner->pos.y - ground->GetHeight(wantedPos.x,wantedPos.z) < 8) {
+
+ am->SetState(am->AIRCRAFT_LANDED);//nail it to the ground before it tries jumping up, only to land again...
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); //call this so that other animations such as opening doors may be started
+ transport->DetachUnitFromAir(unit,pos);
+
+ FinishCommand();
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ am->UpdateLanded();
+ }
+ }
+
+ } else {
+
+ //land transports
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ transport->DetachUnitFromAir(unit,pos);
+ isFirstIteration = false;
+ FinishCommand();
+ if (transport->transported.empty())
+ owner->cob->Call("EndTransport");
+
+ }
+ }
+ }
+ return;
+}
void CTransportCAI::FinishCommand(void)
{
if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType))
@@ -551,7 +947,6 @@
}
CMobileCAI::FinishCommand();
}
-
bool CTransportCAI::LoadStillValid(CUnit* unit){
if(commandQue.size() < 2){
return false;
@@ -560,4 +955,4 @@
return !(cmd.id == CMD_LOAD_UNITS && cmd.params.size() == 4
&& unit->pos.distance2D(
float3(cmd.params[0], cmd.params[1], cmd.params[2])) > cmd.params[3]*2);
-}
+}
\ No newline at end of file
Index: Sim/Units/CommandAI/TransportCAI.h
===================================================================
--- Sim/Units/CommandAI/TransportCAI.h (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.h (working copy)
@@ -2,7 +2,13 @@
#define TRANSPORTCAI_H
#include "MobileCAI.h"
+#include "Sim/MoveTypes/TAAirMoveType.h"
+#define UNLOAD_LAND 0
+#define UNLOAD_DROP 1
+#define UNLOAD_LANDFLOOD 2
+#define UNLOAD_CRASHFLOOD 3
+
class CTransportCAI :
public CMobileCAI
{
@@ -16,6 +22,9 @@
bool CanTransport(CUnit* unit);
bool FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload);
+ bool FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots);
+ bool FindEmptyFloodSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots, std::vector<float3> exitDirs);
+
CUnit* FindUnitToTransport(float3 center, float radius);
int GetDefaultCmd(CUnit* pointed,CFeature* feature);
void DrawCommands(void);
@@ -29,6 +38,31 @@
int toBeTransportedUnitId;
bool scriptReady;
int lastCall;
+
+private:
+
+
+ void UnloadUnits_Land(Command& c, CTransportUnit* transport);
+ void UnloadUnits_Drop(Command& c, CTransportUnit* transport);
+ void UnloadUnits_LandFlood(Command& c, CTransportUnit* transport);
+ void UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport); //incomplete
+ //
+ void UnloadNormal(Command& c);
+ void UnloadLand(Command& c);
+ void UnloadDrop(Command& c); //parachute drop units
+ void UnloadLandFlood(Command& c); //land and dispatch units all at once
+ void UnloadCrashFlood(Command& c); //slam into landscape abruptly and dispatch units all at once (incomplete)
+ //
+ bool SpotIsClear(float3 pos, CUnit* u);
+
+
+ std::list<float3> dropSpots;
+ int unloadType;
+ bool isFirstIteration;
+ float3 startingDropPos;
+ float3 lastDropPos;
+ float3 approachVector; //direction from which we travel to drop point
+ float3 endDropPos;
};
Index: Sim/Units/Unit.cpp
===================================================================
--- Sim/Units/Unit.cpp (revision 4358)
+++ Sim/Units/Unit.cpp (working copy)
@@ -120,6 +120,8 @@
lastSlowUpdate(0),
los(0),
userAttackPos(0,0,0),
+ falling(false),
+ fallSpeed(0.2),
crashing(false),
cob(0),
bonusShieldDir(1,0,0),
@@ -1520,6 +1522,8 @@
globalAI->UnitCreated(this); // FIXME -- add builder?
}
+
+
void CUnit::UpdateTerrainType()
{
if (curTerrainType != lastTerrainType) {
@@ -1951,6 +1955,18 @@
Draw();
}
+void CUnit::Drop(float3 parentPos,float3 parentDir, CUnit* parent) {
+ //drop unit from position
+
+ this->fallSpeed = this->unitDef->unitFallSpeed > 0 ? this->unitDef->unitFallSpeed : parent->unitDef->fallSpeed;
+ float landingHeight = ground->GetApproximateHeight(pos.x, pos.z);
+ falling = true;
+ this->pos.y = parentPos.y - height;
+ this->frontdir = parentDir;
+ this->frontdir.y = 0;
+ this->speed.y = 0;
+}
+
void CUnit::hitByWeaponIdCallback(int retCode, void *p1, void *p2)
{
((CUnit*)p1)->weaponHitMod = retCode*0.01f;
@@ -1988,7 +2004,6 @@
return;
}
-
unsigned int CUnit::CalcLOD(unsigned int lastLOD) const
{
if (lastLOD == 0) { return 0; }
@@ -2004,7 +2019,6 @@
return lastLOD;
}
-
unsigned int CUnit::CalcShadowLOD(unsigned int lastLOD) const
{
return CalcLOD(lastLOD); // FIXME
@@ -2027,7 +2041,6 @@
return lastLOD;
}
-
/******************************************************************************/
void CUnit::PostLoad()
Index: Sim/Units/Unit.h
===================================================================
--- Sim/Units/Unit.h (revision 4358)
+++ Sim/Units/Unit.h (working copy)
@@ -287,8 +287,11 @@
std::string tooltip;
- bool crashing;
- bool isDead; //prevent damage from hitting an already dead unit (causing multi wreck etc)
+ bool falling; //for units being dropped from transports (parachute drops)
+ float fallSpeed;
+ bool crashing;
+ bool isDead; //prevent damage from hitting an already dead unit (causing multi wreck etc)
+
float3 bonusShieldDir; //units takes less damage when attacked from this dir (encourage flanking fire)
float bonusShieldSaved; //how much the bonus shield can turn upon an attack(zeroed when attacked, slowly increase)
@@ -357,6 +360,7 @@
virtual void IncomingMissile(CMissileProjectile* missile);
void TempHoldFire(void);
void ReleaseTempHoldFire(void);
+ void Drop(float3 parentPos,float3 parentDir,CUnit* parent); //start this unit in freefall from parent unit
virtual void DrawS3O(void);
void PostLoad();
static void hitByWeaponIdCallback(int retCode, void *p1, void *p2);
Index: Sim/Units/UnitDef.h
===================================================================
--- Sim/Units/UnitDef.h (revision 4358)
+++ Sim/Units/UnitDef.h (working copy)
@@ -280,6 +280,9 @@
float loadingRadius; //for transports
int transportCapacity;
int transportSize;
+ int transportUnloadMethod; //0 - land unload, 1 - flyover drop, 2 - land flood
+ float fallSpeed; //dictates fall speed of all transported units
+ float unitFallSpeed; //sets the transported units fbi, overrides fallSpeed
bool isAirBase;
float transportMass;
bool holdSteady;
Index: Sim/Units/UnitDefHandler.cpp
===================================================================
--- Sim/Units/UnitDefHandler.cpp (revision 4358)
+++ Sim/Units/UnitDefHandler.cpp (working copy)
@@ -366,6 +366,9 @@
ud.holdSteady = udTable.GetBool("holdSteady", true);
ud.releaseHeld = udTable.GetBool("releaseHeld", false);
ud.transportByEnemy = udTable.GetBool("transportByEnemy", true);
+ ud.transportUnloadMethod = udTable.GetInt("transportUnloadMethod" , 0);//0 normal, 1 parachute drop, 2 land flood
+ ud.fallSpeed = udTable.GetFloat("fallSpeed", 0.2); //global drop speed for all air dropped units
+ ud.unitFallSpeed = udTable.GetFloat("unitFallSpeed", 0); //specific drop speed, overrides fallSpeed
ud.wingDrag = udTable.GetFloat("wingDrag", 0.07f); // drag caused by wings
ud.wingAngle = udTable.GetFloat("wingAngle", 0.08f); // angle between front and the wing plane
Index: Sim/Units/UnitTypes/TransportUnit.cpp
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.cpp (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.cpp (working copy)
@@ -219,3 +219,82 @@
}
}
}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit, float3 pos)
+{
+
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ loshandler->MoveUnit(unit,false);
+
+
+ //add an additional move command for after we land
+ Command c;
+ c.id=CMD_MOVE;
+ c.params.push_back(pos.x);
+ c.params.push_back(pos.y);
+ c.params.push_back(pos.z);
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport(); //in test
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this); //in test
+
+ break;
+ }
+ }
+
+}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit)
+{
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ unit->Block();
+
+ loshandler->MoveUnit(unit,false);
+ //unit->moveType->useHeading=true;
+
+ Command c;
+ c.id=CMD_STOP;
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport(); //in test
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this); //in test
+
+ break;
+ }
+ }
+}
Index: Sim/Units/UnitTypes/TransportUnit.h
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.h (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.h (working copy)
@@ -32,6 +32,8 @@
void KillUnit(bool selfDestruct,bool reclaimed, CUnit *attacker);
void AttachUnit(CUnit* unit, int piece);
void DetachUnit(CUnit* unit);
+ void DetachUnitFromAir(CUnit* unit,float3 pos);//moves to position after
+ void DetachUnitFromAir(CUnit* unit);
bool CanTransport(CUnit* unit);
};
-
newTransportMethods 0.19 .diff (35,981 bytes) 2007-09-16 23:03
Index: Lua/LuaUnitDefs.cpp
===================================================================
--- Lua/LuaUnitDefs.cpp (revision 4358)
+++ Lua/LuaUnitDefs.cpp (working copy)
@@ -870,7 +870,10 @@
ADD_BOOL( "holdSteady", ud.holdSteady);
ADD_BOOL( "releaseHeld", ud.releaseHeld);
ADD_BOOL( "transportByEnemy", ud.transportByEnemy);
-
+ ADD_INT("transportUnloadMethod",ud.transportUnloadMethod);
+ ADD_FLOAT( "fallSpeed", ud.fallSpeed);
+ ADD_FLOAT( "unitFallSpeed", ud.unitFallSpeed);
+
ADD_BOOL( "startCloaked", ud.startCloaked);
ADD_FLOAT("cloakCost", ud.cloakCost);
ADD_FLOAT("cloakCostMoving", ud.cloakCostMoving);
Index: Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- Sim/MoveTypes/groundmovetype.cpp (revision 4358)
+++ Sim/MoveTypes/groundmovetype.cpp (working copy)
@@ -130,6 +130,7 @@
deltaHeading(0),
skidding(false),
flying(false),
+ dropHeight(0),
skidRotSpeed(0),
floatOnWater(false),
skidRotVector(UpVector),
@@ -202,6 +203,12 @@
return;
}
+ //set drop height when we start to drop
+ if(owner->falling) {
+ UpdateControlledDrop();
+ return;
+ }
+
if(owner->stunned){
owner->cob->Call(COBFN_StopMoving);
owner->speed=ZeroVector;
@@ -309,7 +316,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+
+ //need this to stop jitter when falling
+ if (!owner->falling)
+ owner->pos.y=wh;
}
if(owner->pos!=oldPos){
@@ -323,8 +333,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
owner->speed=owner->pos-oldPos;
owner->midPos = owner->pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
oldPos=owner->pos;
@@ -378,8 +390,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
if(!(owner->pos==oldSlowUpdatePos)){
oldSlowUpdatePos=owner->pos;
@@ -549,7 +563,7 @@
}
owner->frontdir = GetVectorFromHeading(heading);
- if(owner->upright){
+ if (owner->upright) {
owner->updir=UpVector;
owner->rightdir=owner->frontdir.cross(owner->updir);
} else {
@@ -713,6 +727,54 @@
CheckCollisionSkid();
}
+void CGroundMoveType::UpdateControlledDrop(void)
+{
+ float3& speed=owner->speed;
+ float3& pos=owner->pos;
+ float3& midPos=(float3)owner->midPos;
+
+
+
+ if(owner->falling){
+
+ //set us upright
+
+
+ owner->cob->Call("Falling"); //start/continue parachute animation
+
+ speed.y += gs->gravity*owner->fallSpeed;
+
+ if(owner->speed.y > 0) //sometimes the dropped unit gets an upward force, still unsure where its coming from
+ owner->speed.y = 0;
+
+ midPos += speed;
+ pos = midPos - owner->frontdir * owner->relMidPos.z
+ - owner->updir * owner->relMidPos.y
+ - owner->rightdir * owner->relMidPos.x;
+
+ owner->midPos.y = owner->pos.y + owner->relMidPos.y;
+
+ if(midPos.y < 0)
+ speed*=0.90;
+
+ float wh;
+
+ if(floatOnWater)
+ wh = ground->GetHeight(midPos.x, midPos.z);
+ else
+ wh = ground->GetHeight2(midPos.x, midPos.z);
+
+ if(wh > midPos.y-owner->relMidPos.y){
+ owner->falling = false;
+ midPos.y = wh + owner->relMidPos.y - speed.y*0.8;
+ owner->cob->Call("Landed"); //stop parachute animation
+ }
+
+
+
+ }
+}
+
void CGroundMoveType::CheckCollisionSkid(void)
{
float3& pos=owner->pos;
Index: Sim/MoveTypes/groundmovetype.h
===================================================================
--- Sim/MoveTypes/groundmovetype.h (revision 4358)
+++ Sim/MoveTypes/groundmovetype.h (working copy)
@@ -106,6 +106,7 @@
void ChangeHeading(short wantedHeading);
void UpdateSkid(void);
+ void UpdateControlledDrop(void);
void CheckCollisionSkid(void);
float GetFlyTime(float3 pos, float3 speed);
void CalcSkidRot(void);
@@ -113,6 +114,8 @@
bool skidding;
bool flying;
float skidRotSpeed;
+ float dropSpeed;
+ float dropHeight;
float3 skidRotVector;
float skidRotSpeed2;
Index: Sim/MoveTypes/TAAirMoveType.cpp
===================================================================
--- Sim/MoveTypes/TAAirMoveType.cpp (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.cpp (working copy)
@@ -15,6 +15,7 @@
#include "Sim/Misc/GeometricObjects.h"
#include "Mobility.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
+#include "Sim/Units/CommandAI/CommandAI.h"
CR_BIND_DERIVED(CTAAirMoveType, CMoveType, (NULL));
@@ -357,10 +358,13 @@
// Move the unit around a bit.. and when it gets too far away from goal position it switches to normal flying instead
void CTAAirMoveType::UpdateHovering()
{
- float driftSpeed = owner->unitDef->dlHoverFactor;
+ float driftSpeed = owner->unitDef->dlHoverFactor;
+ float3 dir = goalPos - owner->pos;
- // move towards goal position
- float3 dir = goalPos - owner->pos;
+ // move towards goal position if its not immediately behind us when we have more waypoints to get to
+ if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1 )
+ dir = owner->frontdir;
+
wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f;
// damping
@@ -381,6 +385,10 @@
float3 dir = goalPos - pos;
owner->restTime=0;
+ //dont change direction for waypoints we just flew over and missed slightly
+ if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1 )
+ dir = owner->frontdir;
+
//are we there yet?
// logOutput.Print("max drift %f %i %f %f",maxDrift,waitCounter,dir.Length2D(),fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight));
bool closeToGoal=dir.SqLength2D() < maxDrift*maxDrift && fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight)<maxDrift;
@@ -490,8 +498,11 @@
float dist=dir.Length2D();
//If we are close to our goal, we should go slow enough to be able to break in time
- //if in attack mode dont slow down
- if (flyState!=FLY_ATTACKING && dist < breakDistance) {
+ //new additional rule:
+ //if in attack mode or have more this is an intermediate waypoint dont
+ //slow down except if near ground level
+
+ if ((flyState!=FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands() ) || (pos.y - ground->GetHeight(pos.x, pos.z) < orgWantedHeight/2)) {
realMax = dist/(speed.Length2D()+0.01f) * decRate;
//logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax);
}
@@ -501,12 +512,17 @@
UpdateAirPhysics();
- //Point toward goal or forward
+ //Point toward goal or forward - unless we just passed it to get to another goal
if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
dir = circlingPos - pos;
- } else {
+ }
+ else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1 ) {
+ dir = owner->frontdir;
+ }
+ else {
dir = goalPos - pos;
}
+
if(dir.SqLength2D()>1)
wantedHeading = GetHeadingFromVector(dir.x, dir.z);
}
Index: Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- Sim/Units/CommandAI/TransportCAI.cpp (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.cpp (working copy)
@@ -47,6 +47,15 @@
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";
@@ -84,10 +93,11 @@
}
Command& c=commandQue.front();
switch(c.id){
- case CMD_LOAD_UNITS: { ExecuteLoadUnits(c); return; }
+ 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;
}
@@ -200,11 +210,209 @@
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)
+{
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ //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->mass>=100000 || unit->beingBuilt)
+ return false;
+ // don't transport cloaked enemies
+ if (unit->isCloaked && !gs->AlliedTeams(unit->team, owner->team))
+ return false;
+ if(unit->unitDef->canhover && (modInfo->transportHover==0))
+ return false;
+ if(unit->unitDef->floater && (modInfo->transportShip==0))
+ return false;
+ if(unit->unitDef->canfly && (modInfo->transportAir==0))
+ return false;
+ // if not a hover, not a floater and not a flier, then it's probably ground unit
+ if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
+ return false;
+ if(unit->xsize > owner->unitDef->transportSize*2)
+ return false;
+ if(!transport->CanTransport(unit))
+ return false;
+ if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
+ return false;
+
+ return true;
+}
+
+bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
+{
+// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
+ if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
+ for (int a=0;a<100;++a) {
+ float3 delta(1,0,1);
+ while(delta.SqLength2D()>1){
+ delta.x=(gs->randFloat()-0.5f)*2;
+ delta.z=(gs->randFloat()-0.5f)*2;
+ }
+ 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(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
+ float dy=y-center.z;
+ float rx=radius*radius-dy*dy;
+ if(rx<=0)
+ continue;
+ rx=sqrt(rx);
+ for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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(CTAAirMoveType* am=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) {
+//select suitable spots according to directions we are allowed to exit transport from
+ //TODO
+ return false;
+}
+//
+//
+void CTransportCAI::UnloadUnits_Land(Command& c, CTransportUnit* transport) {
if(lastCall==gs->frameNum) //avoid infinite loops
return;
lastCall=gs->frameNum;
@@ -215,8 +423,9 @@
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
float3 found;
- CUnit* unitToUnload=((CTransportUnit*)owner)->transported.front().unit;
- bool canUnload=FindEmptySpot(pos,max(16.0f,radius),unitToUnload->radius,found,unitToUnload);
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
if(canUnload){
Command c2;
c2.id=CMD_UNLOAD_UNIT;
@@ -231,18 +440,122 @@
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;
-void CTransportCAI::ExecuteUnloadUnit(Command &c)
-{
- CTransportUnit* transport = (CTransportUnit*)owner;
- if (inCommand) {
- if (!owner->cob->busy) {
- // if(scriptReady)
+ 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 ) {
+ dropSpots.clear();
+ startingDropPos = pos;
+
+ approachVector = startingDropPos-owner->pos;
+ approachVector.Normalize();
+ canUnload = FindEmptyDropSpots(pos, pos + approachVector*max(16.0f,radius), dropSpots);
+
+ } else if (!dropSpots.empty() ) {
+ //make sure we check current spot infront of us each unload
+ pos = dropSpots.back(); //take last landing pos as new start spot
+ canUnload = dropSpots.size() > 0;
+ }
+
+ if( canUnload ){
+ if(SpotIsClear(dropSpots.back(),((CTransportUnit*)owner)->transported.front().unit)) {
+ float3 pos = dropSpots.back();
+ Command c2;
+ c2.id=CMD_UNLOAD_UNIT;
+ c2.params.push_back(pos.x);
+ c2.params.push_back(pos.y);
+ c2.params.push_back(pos.z);
+ c2.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c2);
+
+ SlowUpdate();
+ isFirstIteration = false;
+ return;
+ } else {
+ dropSpots.pop_back();
+ }
+ } else {
+
+ startingDropPos = float3(-1,-1,-1);
+ isFirstIteration=true;
+ dropSpots.clear();
+ FinishCommand();
+ }
+}
+void CTransportCAI::UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport) {
+ //TODO - fly into the ground, doing damage to units at landing pos, then unload.
+ //needs heavy modification of TAAirMoveType
+}
+void CTransportCAI::UnloadUnits_LandFlood(Command& c, CTransportUnit* transport) {
+ if(lastCall==gs->frameNum) //avoid infinite loops
+ return;
+ lastCall=gs->frameNum;
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
}
- else {
+ float3 pos(c.params[0],c.params[1],c.params[2]);
+ float radius=c.params[3];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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);
+
+ if (isFirstIteration ) {
+ Command c1;
+ c1.id=CMD_MOVE;
+ c1.params.push_back(pos.x);
+ c1.params.push_back(pos.y);
+ c1.params.push_back(pos.z);
+ c1.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c1);
+ startingDropPos = pos;
+ }
+
+ SlowUpdate();
+ return;
+ } else {
+ FinishCommand();
+ }
+ return;
+
+}
+
+
+//
+void CTransportCAI::UnloadLand(Command& c) {
+ //default unload
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ // if(scriptReady)
+ FinishCommand();
+ }
+ } else {
const std::list<CTransportUnit::TransportedUnit>& transList =
transport->transported;
@@ -259,8 +572,7 @@
CUnit* unit = NULL;
if (c.params.size() < 4) {
unit = transList.front().unit;
- }
- else {
+ } else {
const int unitID = (int)c.params[3];
std::list<CTransportUnit::TransportedUnit>::const_iterator it;
for (it = transList.begin(); it != transList.end(); ++it) {
@@ -286,7 +598,7 @@
am->SetWantedAltitude(unit->model->height);
am->maxDrift = 1;
if ((owner->pos.distance(wantedPos) < 8) &&
- (owner->updir.dot(UpVector) > 0.99f)) {
+ (owner->updir.dot(UpVector) > 0.99f)) {
transport->DetachUnit(unit);
if (transport->transported.empty()) {
am->dontLand = false;
@@ -307,97 +619,164 @@
}
}
}
- return;
-}
+ return;
-void CTransportCAI::ScriptReady(void)
-{
- scriptReady = true; // NOTE: does not seem to be used
}
+void CTransportCAI::UnloadDrop(Command& c) {
+
+ //fly over and drop unit
+ if(inCommand){
+ if(!owner->cob->busy)
+ //if(scriptReady)
+ FinishCommand();
+ } else {
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
+ }
-bool CTransportCAI::CanTransport(CUnit* unit)
-{
- CTransportUnit* transport=(CTransportUnit*)owner;
+ float3 pos(c.params[0],c.params[1],c.params[2]); //head towards goal
+
+ //note that taairmovetype must be modified to allow non stop movement through goals for this to work well
+ if(goalPos.distance2D(pos)>20){
+ SetGoal(pos,owner->pos);
+ lastDropPos = pos;
+ }
+
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){
+
+ pos.y=ground->GetHeight(pos.x,pos.z);
+ CUnit* unit=((CTransportUnit*)owner)->transported.front().unit;
+ am->maxDrift=1;
- 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->unitDef->canhover && (modInfo->transportHover==0))
- return false;
- if(unit->unitDef->floater && (modInfo->transportShip==0))
- return false;
- if(unit->unitDef->canfly && (modInfo->transportAir==0))
- return false;
- // if not a hover, not a floater and not a flier, then it's probably ground unit
- if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
- return false;
- if(unit->xsize > owner->unitDef->transportSize*2)
- return false;
- if(!transport->CanTransport(unit))
- return false;
- if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
- return false;
+ //if near target or have past it accidentally- drop unit
+ if(owner->pos.distance2D(pos) < 40 || (((pos - owner->pos).Normalize()).distance(owner->frontdir.Normalize()) > 0.5 && owner->pos.distance2D(pos)< 205)) {
+ am->dontLand=true;
+ owner->cob->Call("EndTransport"); //test
+ ((CTransportUnit*)owner)->DetachUnitFromAir(unit,pos);
+ dropSpots.pop_back();
- return true;
+ if (dropSpots.empty()) {
+ float3 fix = owner->pos+owner->frontdir*200;
+ SetGoal(fix,owner->pos);//move the transport away after last drop
+ }
+ FinishCommand();
+ }
+ } else {
+ inCommand=true;
+ scriptReady=false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(((CTransportUnit*)owner)->transported.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop",args,ScriptCallback,this,0);
+ }
+ }
}
-
-bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
-{
-// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
- if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
- for (int a=0;a<100;++a) {
- float3 delta(1,0,1);
- while(delta.SqLength2D()>1){
- delta.x=(gs->randFloat()-0.5f)*2;
- delta.z=(gs->randFloat()-0.5f)*2;
+void CTransportCAI::UnloadCrashFlood(Command& c) {
+ //TODO - will require heavy modification of TAAirMoveType.cpp
+}
+void CTransportCAI::UnloadLandFlood(Command& c) {
+ //land, then release all units at once
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ //if(scriptReady)
+ FinishCommand();
}
- float3 pos=center+delta*radius;
- pos.y=ground->GetHeight(pos.x,pos.z);
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
- 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;
+ if (transList.empty()) {
+ FinishCommand();
+ return;
}
- } else {
- for(float y=max(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
- float dy=y-center.z;
- float rx=radius*radius-dy*dy;
- if(rx<=0)
- continue;
- rx=sqrt(rx);
- for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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;
+
+ //check units are all carried
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
}
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
}
+
+ //move to position
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if (isFirstIteration) {
+ if(goalPos.distance2D(pos) > 20)
+ SetGoal(startingDropPos, owner->pos);
+ }
+
+ if (startingDropPos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+ //create aircraft movetype instance
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+
+ if (am != NULL) {
+ //lower to ground
+
+ startingDropPos.y = ground->GetHeight(startingDropPos.x,startingDropPos.z);
+ const float3 wantedPos = startingDropPos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(1);
+ am->maxDrift = 1;
+ am->dontLand = false;
+
+ //when on our way down start animations for unloading gear
+ if (isFirstIteration) {
+ owner->cob->Call("StartUnload");
+ }
+ isFirstIteration = false;
+
+ //once at ground
+ if (owner->pos.y - ground->GetHeight(wantedPos.x,wantedPos.z) < 8) {
+
+ am->SetState(am->AIRCRAFT_LANDED);//nail it to the ground before it tries jumping up, only to land again...
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); //call this so that other animations such as opening doors may be started
+ transport->DetachUnitFromAir(unit,pos);
+
+ FinishCommand();
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ am->UpdateLanded();
+ }
+ }
+ } else {
+
+ //land transports
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ transport->DetachUnitFromAir(unit,pos);
+ isFirstIteration = false;
+ FinishCommand();
+ if (transport->transported.empty())
+ owner->cob->Call("EndTransport");
+ }
+ }
}
- return false;
+ return;
}
-
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
CUnit* best=0;
Index: Sim/Units/CommandAI/TransportCAI.h
===================================================================
--- Sim/Units/CommandAI/TransportCAI.h (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.h (working copy)
@@ -2,6 +2,12 @@
#define TRANSPORTCAI_H
#include "MobileCAI.h"
+#include "Sim/MoveTypes/TAAirMoveType.h"
+
+#define UNLOAD_LAND 0
+#define UNLOAD_DROP 1
+#define UNLOAD_LANDFLOOD 2
+#define UNLOAD_CRASHFLOOD 3
class CTransportCAI :
public CMobileCAI
@@ -16,6 +22,8 @@
bool CanTransport(CUnit* unit);
bool FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload);
+ bool FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots);
+ bool FindEmptyFloodSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots, std::vector<float3> exitDirs);
CUnit* FindUnitToTransport(float3 center, float radius);
int GetDefaultCmd(CUnit* pointed,CFeature* feature);
void DrawCommands(void);
@@ -29,6 +37,27 @@
int toBeTransportedUnitId;
bool scriptReady;
int lastCall;
+
+private:
+ void UnloadUnits_Land(Command& c, CTransportUnit* transport);
+ void UnloadUnits_Drop(Command& c, CTransportUnit* transport);
+ void UnloadUnits_LandFlood(Command& c, CTransportUnit* transport);
+ void UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport); //incomplete
+
+ void UnloadNormal(Command& c);
+ void UnloadLand(Command& c);
+ void UnloadDrop(Command& c); //parachute drop units
+ void UnloadLandFlood(Command& c); //land and dispatch units all at once
+ void UnloadCrashFlood(Command& c); //slam into landscape abruptly and dispatch units all at once (incomplete)
+
+ bool SpotIsClear(float3 pos, CUnit* u);
+ std::list<float3> dropSpots;
+ int unloadType;
+ bool isFirstIteration;
+ float3 startingDropPos;
+ float3 lastDropPos;
+ float3 approachVector; //direction from which we travel to drop point
+ float3 endDropPos;
};
Index: Sim/Units/Unit.cpp
===================================================================
--- Sim/Units/Unit.cpp (revision 4358)
+++ Sim/Units/Unit.cpp (working copy)
@@ -107,6 +107,8 @@
rightdir(-1,0,0),
updir(0,1,0),
upright(true),
+ falling(false),
+ fallSpeed(0.2),
maxRange(0),
haveTarget(false),
lastAttacker(0),
@@ -355,6 +357,17 @@
}
+void CUnit::Drop(float3 parentPos,float3 parentDir, CUnit* parent) {
+ //drop unit from position
+
+ this->fallSpeed = this->unitDef->unitFallSpeed > 0 ? this->unitDef->unitFallSpeed : parent->unitDef->fallSpeed;
+ float landingHeight = ground->GetApproximateHeight(pos.x, pos.z);
+ falling = true;
+ this->pos.y = parentPos.y - height;
+ this->frontdir = parentDir;
+ this->frontdir.y = 0;
+ this->speed.y = 0;
+}
void CUnit::EnableScriptMoveType()
{
if (usingScriptMoveType) {
Index: Sim/Units/Unit.h
===================================================================
--- Sim/Units/Unit.h (revision 4358)
+++ Sim/Units/Unit.h (working copy)
@@ -289,6 +289,8 @@
bool crashing;
bool isDead; //prevent damage from hitting an already dead unit (causing multi wreck etc)
+ bool falling; //for units being dropped from transports (parachute drops)
+ float fallSpeed;
float3 bonusShieldDir; //units takes less damage when attacked from this dir (encourage flanking fire)
float bonusShieldSaved; //how much the bonus shield can turn upon an attack(zeroed when attacked, slowly increase)
@@ -357,6 +359,7 @@
virtual void IncomingMissile(CMissileProjectile* missile);
void TempHoldFire(void);
void ReleaseTempHoldFire(void);
+ void Drop(float3 parentPos,float3 parentDir,CUnit* parent); //start this unit in freefall from parent unit
virtual void DrawS3O(void);
void PostLoad();
static void hitByWeaponIdCallback(int retCode, void *p1, void *p2);
Index: Sim/Units/UnitDef.h
===================================================================
--- Sim/Units/UnitDef.h (revision 4358)
+++ Sim/Units/UnitDef.h (working copy)
@@ -285,6 +285,9 @@
bool holdSteady;
bool releaseHeld;
bool transportByEnemy;
+ int transportUnloadMethod; //0 - land unload, 1 - flyover drop, 2 - land flood
+ float fallSpeed; //dictates fall speed of all transported units
+ float unitFallSpeed; //sets the transported units fbi, overrides fallSpeed
bool canCloak; //if the unit can cloak
bool startCloaked; //if the units want to start out cloaked
Index: Sim/Units/UnitDefHandler.cpp
===================================================================
--- Sim/Units/UnitDefHandler.cpp (revision 4358)
+++ Sim/Units/UnitDefHandler.cpp (working copy)
@@ -366,6 +366,9 @@
ud.holdSteady = udTable.GetBool("holdSteady", true);
ud.releaseHeld = udTable.GetBool("releaseHeld", false);
ud.transportByEnemy = udTable.GetBool("transportByEnemy", true);
+ ud.transportUnloadMethod = udTable.GetInt("transportUnloadMethod" , 0); //0 normal, 1 parachute drop, 2 land flood
+ ud.fallSpeed = udTable.GetFloat("fallSpeed", 0.2); //drop speed for all units dropped from this transport
+ ud.unitFallSpeed = udTable.GetFloat("unitFallSpeed", 0); //specific unit drop speed, overrides fallSpeed
ud.wingDrag = udTable.GetFloat("wingDrag", 0.07f); // drag caused by wings
ud.wingAngle = udTable.GetFloat("wingAngle", 0.08f); // angle between front and the wing plane
Index: Sim/Units/UnitTypes/TransportUnit.cpp
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.cpp (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.cpp (working copy)
@@ -219,3 +219,79 @@
}
}
}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit, float3 pos) {
+
+ if(unit->transporter != this)
+ return;
+
+ for (list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if (ti->unit==unit) {
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ loshandler->MoveUnit(unit,false);
+
+ //add an additional move command for after we land
+ Command c;
+ c.id=CMD_MOVE;
+ c.params.push_back(pos.x);
+ c.params.push_back(pos.y);
+ c.params.push_back(pos.z);
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+
+}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit)
+{
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ unit->Block();
+
+ loshandler->MoveUnit(unit,false);
+
+ Command c;
+ c.id=CMD_STOP;
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+}
\ No newline at end of file
Index: Sim/Units/UnitTypes/TransportUnit.h
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.h (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.h (working copy)
@@ -33,6 +33,8 @@
void AttachUnit(CUnit* unit, int piece);
void DetachUnit(CUnit* unit);
bool CanTransport(CUnit* unit);
+ void DetachUnitFromAir(CUnit* unit,float3 pos); //moves to position after
+ void DetachUnitFromAir(CUnit* unit);
};
-
newTransportMethods 0.20 .diff (36,841 bytes) 2007-09-17 22:29
Index: Lua/LuaUnitDefs.cpp
===================================================================
--- Lua/LuaUnitDefs.cpp (revision 4358)
+++ Lua/LuaUnitDefs.cpp (working copy)
@@ -870,7 +870,10 @@
ADD_BOOL( "holdSteady", ud.holdSteady);
ADD_BOOL( "releaseHeld", ud.releaseHeld);
ADD_BOOL( "transportByEnemy", ud.transportByEnemy);
-
+ ADD_INT("transportUnloadMethod",ud.transportUnloadMethod);
+ ADD_FLOAT( "fallSpeed", ud.fallSpeed);
+ ADD_FLOAT( "unitFallSpeed", ud.unitFallSpeed);
+
ADD_BOOL( "startCloaked", ud.startCloaked);
ADD_FLOAT("cloakCost", ud.cloakCost);
ADD_FLOAT("cloakCostMoving", ud.cloakCostMoving);
Index: Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- Sim/MoveTypes/groundmovetype.cpp (revision 4358)
+++ Sim/MoveTypes/groundmovetype.cpp (working copy)
@@ -36,7 +36,7 @@
CR_REG_METADATA(CGroundMoveType, (
CR_MEMBER(baseTurnRate),
CR_MEMBER(turnRate),
- CR_MEMBER(accRate),
+ CR_MEMBER(accRate),
CR_MEMBER(wantedSpeed),
CR_MEMBER(currentSpeed),
@@ -88,6 +88,8 @@
CR_MEMBER(skidding),
CR_MEMBER(flying),
CR_MEMBER(skidRotSpeed),
+ CR_MEMBER(dropSpeed),
+ CR_MEMBER(dropHeight),
CR_MEMBER(skidRotVector),
CR_MEMBER(skidRotSpeed2),
@@ -130,6 +132,7 @@
deltaHeading(0),
skidding(false),
flying(false),
+ dropHeight(0),
skidRotSpeed(0),
floatOnWater(false),
skidRotVector(UpVector),
@@ -202,6 +205,12 @@
return;
}
+ //set drop height when we start to drop
+ if(owner->falling) {
+ UpdateControlledDrop();
+ return;
+ }
+
if(owner->stunned){
owner->cob->Call(COBFN_StopMoving);
owner->speed=ZeroVector;
@@ -309,7 +318,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+
+ //need this to stop jitter when falling
+ if (!owner->falling)
+ owner->pos.y=wh;
}
if(owner->pos!=oldPos){
@@ -323,8 +335,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
owner->speed=owner->pos-oldPos;
owner->midPos = owner->pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
oldPos=owner->pos;
@@ -378,8 +392,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
if(!(owner->pos==oldSlowUpdatePos)){
oldSlowUpdatePos=owner->pos;
@@ -549,7 +565,7 @@
}
owner->frontdir = GetVectorFromHeading(heading);
- if(owner->upright){
+ if (owner->upright) {
owner->updir=UpVector;
owner->rightdir=owner->frontdir.cross(owner->updir);
} else {
@@ -713,6 +729,54 @@
CheckCollisionSkid();
}
+void CGroundMoveType::UpdateControlledDrop(void)
+{
+ float3& speed=owner->speed;
+ float3& pos=owner->pos;
+ float3& midPos=(float3)owner->midPos;
+
+
+
+ if(owner->falling){
+
+ //set us upright
+
+
+ owner->cob->Call("Falling"); //start/continue parachute animation
+
+ speed.y += gs->gravity*owner->fallSpeed;
+
+ if(owner->speed.y > 0) //sometimes the dropped unit gets an upward force, still unsure where its coming from
+ owner->speed.y = 0;
+
+ midPos += speed;
+ pos = midPos - owner->frontdir * owner->relMidPos.z
+ - owner->updir * owner->relMidPos.y
+ - owner->rightdir * owner->relMidPos.x;
+
+ owner->midPos.y = owner->pos.y + owner->relMidPos.y;
+
+ if(midPos.y < 0)
+ speed*=0.90;
+
+ float wh;
+
+ if(floatOnWater)
+ wh = ground->GetHeight(midPos.x, midPos.z);
+ else
+ wh = ground->GetHeight2(midPos.x, midPos.z);
+
+ if(wh > midPos.y-owner->relMidPos.y){
+ owner->falling = false;
+ midPos.y = wh + owner->relMidPos.y - speed.y*0.8;
+ owner->cob->Call("Landed"); //stop parachute animation
+ }
+
+
+
+ }
+}
+
void CGroundMoveType::CheckCollisionSkid(void)
{
float3& pos=owner->pos;
Index: Sim/MoveTypes/groundmovetype.h
===================================================================
--- Sim/MoveTypes/groundmovetype.h (revision 4358)
+++ Sim/MoveTypes/groundmovetype.h (working copy)
@@ -106,6 +106,7 @@
void ChangeHeading(short wantedHeading);
void UpdateSkid(void);
+ void UpdateControlledDrop(void);
void CheckCollisionSkid(void);
float GetFlyTime(float3 pos, float3 speed);
void CalcSkidRot(void);
@@ -113,6 +114,8 @@
bool skidding;
bool flying;
float skidRotSpeed;
+ float dropSpeed;
+ float dropHeight;
float3 skidRotVector;
float skidRotSpeed2;
Index: Sim/MoveTypes/TAAirMoveType.cpp
===================================================================
--- Sim/MoveTypes/TAAirMoveType.cpp (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.cpp (working copy)
@@ -15,6 +15,7 @@
#include "Sim/Misc/GeometricObjects.h"
#include "Mobility.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
+#include "Sim/Units/CommandAI/CommandAI.h"
CR_BIND_DERIVED(CTAAirMoveType, CMoveType, (NULL));
@@ -357,10 +358,13 @@
// Move the unit around a bit.. and when it gets too far away from goal position it switches to normal flying instead
void CTAAirMoveType::UpdateHovering()
{
- float driftSpeed = owner->unitDef->dlHoverFactor;
+ float driftSpeed = owner->unitDef->dlHoverFactor;
+ float3 dir = goalPos - owner->pos;
- // move towards goal position
- float3 dir = goalPos - owner->pos;
+ // move towards goal position if its not immediately behind us when we have more waypoints to get to
+ if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1 )
+ dir = owner->frontdir;
+
wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f;
// damping
@@ -381,6 +385,10 @@
float3 dir = goalPos - pos;
owner->restTime=0;
+ //dont change direction for waypoints we just flew over and missed slightly
+ if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1 )
+ dir = owner->frontdir;
+
//are we there yet?
// logOutput.Print("max drift %f %i %f %f",maxDrift,waitCounter,dir.Length2D(),fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight));
bool closeToGoal=dir.SqLength2D() < maxDrift*maxDrift && fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight)<maxDrift;
@@ -490,8 +498,11 @@
float dist=dir.Length2D();
//If we are close to our goal, we should go slow enough to be able to break in time
- //if in attack mode dont slow down
- if (flyState!=FLY_ATTACKING && dist < breakDistance) {
+ //new additional rule:
+ //if in attack mode or have more this is an intermediate waypoint dont
+ //slow down except if near ground level
+
+ if ((flyState!=FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands() ) || (pos.y - ground->GetHeight(pos.x, pos.z) < orgWantedHeight/2)) {
realMax = dist/(speed.Length2D()+0.01f) * decRate;
//logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax);
}
@@ -501,12 +512,17 @@
UpdateAirPhysics();
- //Point toward goal or forward
+ //Point toward goal or forward - unless we just passed it to get to another goal
if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
dir = circlingPos - pos;
- } else {
+ }
+ else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1 ) {
+ dir = owner->frontdir;
+ }
+ else {
dir = goalPos - pos;
}
+
if(dir.SqLength2D()>1)
wantedHeading = GetHeadingFromVector(dir.x, dir.z);
}
Index: Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- Sim/Units/CommandAI/TransportCAI.cpp (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.cpp (working copy)
@@ -30,6 +30,7 @@
CR_MEMBER(toBeTransportedUnitId),
CR_MEMBER(scriptReady),
CR_MEMBER(lastCall),
+ CR_MEMBER(unloadType),
CR_RESERVED(16)
));
@@ -47,6 +48,15 @@
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";
@@ -84,10 +94,11 @@
}
Command& c=commandQue.front();
switch(c.id){
- case CMD_LOAD_UNITS: { ExecuteLoadUnits(c); return; }
+ 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;
}
@@ -200,11 +211,209 @@
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)
+{
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ //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->mass>=100000 || unit->beingBuilt)
+ return false;
+ // don't transport cloaked enemies
+ if (unit->isCloaked && !gs->AlliedTeams(unit->team, owner->team))
+ return false;
+ if(unit->unitDef->canhover && (modInfo->transportHover==0))
+ return false;
+ if(unit->unitDef->floater && (modInfo->transportShip==0))
+ return false;
+ if(unit->unitDef->canfly && (modInfo->transportAir==0))
+ return false;
+ // if not a hover, not a floater and not a flier, then it's probably ground unit
+ if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
+ return false;
+ if(unit->xsize > owner->unitDef->transportSize*2)
+ return false;
+ if(!transport->CanTransport(unit))
+ return false;
+ if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
+ return false;
+
+ return true;
+}
+
+bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
+{
+// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
+ if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
+ for (int a=0;a<100;++a) {
+ float3 delta(1,0,1);
+ while(delta.SqLength2D()>1){
+ delta.x=(gs->randFloat()-0.5f)*2;
+ delta.z=(gs->randFloat()-0.5f)*2;
+ }
+ 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(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
+ float dy=y-center.z;
+ float rx=radius*radius-dy*dy;
+ if(rx<=0)
+ continue;
+ rx=sqrt(rx);
+ for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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(CTAAirMoveType* am=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) {
+//select suitable spots according to directions we are allowed to exit transport from
+ //TODO
+ return false;
+}
+//
+//
+void CTransportCAI::UnloadUnits_Land(Command& c, CTransportUnit* transport) {
if(lastCall==gs->frameNum) //avoid infinite loops
return;
lastCall=gs->frameNum;
@@ -215,8 +424,9 @@
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
float3 found;
- CUnit* unitToUnload=((CTransportUnit*)owner)->transported.front().unit;
- bool canUnload=FindEmptySpot(pos,max(16.0f,radius),unitToUnload->radius,found,unitToUnload);
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
if(canUnload){
Command c2;
c2.id=CMD_UNLOAD_UNIT;
@@ -231,18 +441,122 @@
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;
-void CTransportCAI::ExecuteUnloadUnit(Command &c)
-{
- CTransportUnit* transport = (CTransportUnit*)owner;
- if (inCommand) {
- if (!owner->cob->busy) {
- // if(scriptReady)
+ 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 ) {
+ dropSpots.clear();
+ startingDropPos = pos;
+
+ approachVector = startingDropPos-owner->pos;
+ approachVector.Normalize();
+ canUnload = FindEmptyDropSpots(pos, pos + approachVector*max(16.0f,radius), dropSpots);
+
+ } else if (!dropSpots.empty() ) {
+ //make sure we check current spot infront of us each unload
+ pos = dropSpots.back(); //take last landing pos as new start spot
+ canUnload = dropSpots.size() > 0;
+ }
+
+ if( canUnload ){
+ if(SpotIsClear(dropSpots.back(),((CTransportUnit*)owner)->transported.front().unit)) {
+ float3 pos = dropSpots.back();
+ Command c2;
+ c2.id=CMD_UNLOAD_UNIT;
+ c2.params.push_back(pos.x);
+ c2.params.push_back(pos.y);
+ c2.params.push_back(pos.z);
+ c2.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c2);
+
+ SlowUpdate();
+ isFirstIteration = false;
+ return;
+ } else {
+ dropSpots.pop_back();
+ }
+ } else {
+
+ startingDropPos = float3(-1,-1,-1);
+ isFirstIteration=true;
+ dropSpots.clear();
+ FinishCommand();
+ }
+}
+void CTransportCAI::UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport) {
+ //TODO - fly into the ground, doing damage to units at landing pos, then unload.
+ //needs heavy modification of TAAirMoveType
+}
+void CTransportCAI::UnloadUnits_LandFlood(Command& c, CTransportUnit* transport) {
+ if(lastCall==gs->frameNum) //avoid infinite loops
+ return;
+ lastCall=gs->frameNum;
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
}
- else {
+ float3 pos(c.params[0],c.params[1],c.params[2]);
+ float radius=c.params[3];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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);
+
+ if (isFirstIteration ) {
+ Command c1;
+ c1.id=CMD_MOVE;
+ c1.params.push_back(pos.x);
+ c1.params.push_back(pos.y);
+ c1.params.push_back(pos.z);
+ c1.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c1);
+ startingDropPos = pos;
+ }
+
+ SlowUpdate();
+ return;
+ } else {
+ FinishCommand();
+ }
+ return;
+
+}
+
+
+//
+void CTransportCAI::UnloadLand(Command& c) {
+ //default unload
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ // if(scriptReady)
+ FinishCommand();
+ }
+ } else {
const std::list<CTransportUnit::TransportedUnit>& transList =
transport->transported;
@@ -259,8 +573,7 @@
CUnit* unit = NULL;
if (c.params.size() < 4) {
unit = transList.front().unit;
- }
- else {
+ } else {
const int unitID = (int)c.params[3];
std::list<CTransportUnit::TransportedUnit>::const_iterator it;
for (it = transList.begin(); it != transList.end(); ++it) {
@@ -286,7 +599,7 @@
am->SetWantedAltitude(unit->model->height);
am->maxDrift = 1;
if ((owner->pos.distance(wantedPos) < 8) &&
- (owner->updir.dot(UpVector) > 0.99f)) {
+ (owner->updir.dot(UpVector) > 0.99f)) {
transport->DetachUnit(unit);
if (transport->transported.empty()) {
am->dontLand = false;
@@ -307,97 +620,164 @@
}
}
}
- return;
-}
+ return;
-void CTransportCAI::ScriptReady(void)
-{
- scriptReady = true; // NOTE: does not seem to be used
}
+void CTransportCAI::UnloadDrop(Command& c) {
+
+ //fly over and drop unit
+ if(inCommand){
+ if(!owner->cob->busy)
+ //if(scriptReady)
+ FinishCommand();
+ } else {
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
+ }
-bool CTransportCAI::CanTransport(CUnit* unit)
-{
- CTransportUnit* transport=(CTransportUnit*)owner;
+ float3 pos(c.params[0],c.params[1],c.params[2]); //head towards goal
+
+ //note that taairmovetype must be modified to allow non stop movement through goals for this to work well
+ if(goalPos.distance2D(pos)>20){
+ SetGoal(pos,owner->pos);
+ lastDropPos = pos;
+ }
+
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){
+
+ pos.y=ground->GetHeight(pos.x,pos.z);
+ CUnit* unit=((CTransportUnit*)owner)->transported.front().unit;
+ am->maxDrift=1;
- 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->unitDef->canhover && (modInfo->transportHover==0))
- return false;
- if(unit->unitDef->floater && (modInfo->transportShip==0))
- return false;
- if(unit->unitDef->canfly && (modInfo->transportAir==0))
- return false;
- // if not a hover, not a floater and not a flier, then it's probably ground unit
- if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
- return false;
- if(unit->xsize > owner->unitDef->transportSize*2)
- return false;
- if(!transport->CanTransport(unit))
- return false;
- if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
- return false;
+ //if near target or have past it accidentally- drop unit
+ if(owner->pos.distance2D(pos) < 40 || (((pos - owner->pos).Normalize()).distance(owner->frontdir.Normalize()) > 0.5 && owner->pos.distance2D(pos)< 205)) {
+ am->dontLand=true;
+ owner->cob->Call("EndTransport"); //test
+ ((CTransportUnit*)owner)->DetachUnitFromAir(unit,pos);
+ dropSpots.pop_back();
- return true;
+ if (dropSpots.empty()) {
+ float3 fix = owner->pos+owner->frontdir*200;
+ SetGoal(fix,owner->pos);//move the transport away after last drop
+ }
+ FinishCommand();
+ }
+ } else {
+ inCommand=true;
+ scriptReady=false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(((CTransportUnit*)owner)->transported.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop",args,ScriptCallback,this,0);
+ }
+ }
}
-
-bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
-{
-// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
- if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
- for (int a=0;a<100;++a) {
- float3 delta(1,0,1);
- while(delta.SqLength2D()>1){
- delta.x=(gs->randFloat()-0.5f)*2;
- delta.z=(gs->randFloat()-0.5f)*2;
+void CTransportCAI::UnloadCrashFlood(Command& c) {
+ //TODO - will require heavy modification of TAAirMoveType.cpp
+}
+void CTransportCAI::UnloadLandFlood(Command& c) {
+ //land, then release all units at once
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ //if(scriptReady)
+ FinishCommand();
}
- float3 pos=center+delta*radius;
- pos.y=ground->GetHeight(pos.x,pos.z);
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
- 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;
+ if (transList.empty()) {
+ FinishCommand();
+ return;
}
- } else {
- for(float y=max(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
- float dy=y-center.z;
- float rx=radius*radius-dy*dy;
- if(rx<=0)
- continue;
- rx=sqrt(rx);
- for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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;
+
+ //check units are all carried
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
}
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
}
+
+ //move to position
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if (isFirstIteration) {
+ if(goalPos.distance2D(pos) > 20)
+ SetGoal(startingDropPos, owner->pos);
+ }
+
+ if (startingDropPos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+ //create aircraft movetype instance
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+
+ if (am != NULL) {
+ //lower to ground
+
+ startingDropPos.y = ground->GetHeight(startingDropPos.x,startingDropPos.z);
+ const float3 wantedPos = startingDropPos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(1);
+ am->maxDrift = 1;
+ am->dontLand = false;
+
+ //when on our way down start animations for unloading gear
+ if (isFirstIteration) {
+ owner->cob->Call("StartUnload");
+ }
+ isFirstIteration = false;
+
+ //once at ground
+ if (owner->pos.y - ground->GetHeight(wantedPos.x,wantedPos.z) < 8) {
+
+ am->SetState(am->AIRCRAFT_LANDED);//nail it to the ground before it tries jumping up, only to land again...
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); //call this so that other animations such as opening doors may be started
+ transport->DetachUnitFromAir(unit,pos);
+
+ FinishCommand();
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ am->UpdateLanded();
+ }
+ }
+ } else {
+
+ //land transports
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ transport->DetachUnitFromAir(unit,pos);
+ isFirstIteration = false;
+ FinishCommand();
+ if (transport->transported.empty())
+ owner->cob->Call("EndTransport");
+ }
+ }
}
- return false;
+ return;
}
-
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
CUnit* best=0;
Index: Sim/Units/CommandAI/TransportCAI.h
===================================================================
--- Sim/Units/CommandAI/TransportCAI.h (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.h (working copy)
@@ -2,6 +2,12 @@
#define TRANSPORTCAI_H
#include "MobileCAI.h"
+#include "Sim/MoveTypes/TAAirMoveType.h"
+
+#define UNLOAD_LAND 0
+#define UNLOAD_DROP 1
+#define UNLOAD_LANDFLOOD 2
+#define UNLOAD_CRASHFLOOD 3
class CTransportCAI :
public CMobileCAI
@@ -14,8 +20,11 @@
void SlowUpdate(void);
void ScriptReady(void);
+ int unloadType;
bool CanTransport(CUnit* unit);
bool FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload);
+ bool FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots);
+ bool FindEmptyFloodSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots, std::vector<float3> exitDirs);
CUnit* FindUnitToTransport(float3 center, float radius);
int GetDefaultCmd(CUnit* pointed,CFeature* feature);
void DrawCommands(void);
@@ -29,6 +38,26 @@
int toBeTransportedUnitId;
bool scriptReady;
int lastCall;
+
+private:
+ void UnloadUnits_Land(Command& c, CTransportUnit* transport);
+ void UnloadUnits_Drop(Command& c, CTransportUnit* transport);
+ void UnloadUnits_LandFlood(Command& c, CTransportUnit* transport);
+ void UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport); //incomplete
+
+ void UnloadNormal(Command& c);
+ void UnloadLand(Command& c);
+ void UnloadDrop(Command& c); //parachute drop units
+ void UnloadLandFlood(Command& c); //land and dispatch units all at once
+ void UnloadCrashFlood(Command& c); //slam into landscape abruptly and dispatch units all at once (incomplete)
+
+ bool SpotIsClear(float3 pos, CUnit* u);
+ std::list<float3> dropSpots;
+ bool isFirstIteration;
+ float3 startingDropPos;
+ float3 lastDropPos;
+ float3 approachVector; //direction from which we travel to drop point
+ float3 endDropPos;
};
Index: Sim/Units/Unit.cpp
===================================================================
--- Sim/Units/Unit.cpp (revision 4358)
+++ Sim/Units/Unit.cpp (working copy)
@@ -107,6 +107,8 @@
rightdir(-1,0,0),
updir(0,1,0),
upright(true),
+ falling(false),
+ fallSpeed(0.2),
maxRange(0),
haveTarget(false),
lastAttacker(0),
@@ -355,6 +357,17 @@
}
+void CUnit::Drop(float3 parentPos,float3 parentDir, CUnit* parent) {
+ //drop unit from position
+
+ this->fallSpeed = this->unitDef->unitFallSpeed > 0 ? this->unitDef->unitFallSpeed : parent->unitDef->fallSpeed;
+ float landingHeight = ground->GetApproximateHeight(pos.x, pos.z);
+ falling = true;
+ this->pos.y = parentPos.y - height;
+ this->frontdir = parentDir;
+ this->frontdir.y = 0;
+ this->speed.y = 0;
+}
void CUnit::EnableScriptMoveType()
{
if (usingScriptMoveType) {
@@ -2251,6 +2264,8 @@
CR_MEMBER(tooltip),
CR_MEMBER(crashing),
CR_MEMBER(isDead),
+ CR_MEMBER(falling),
+ CR_MEMBER(fallSpeed),
CR_MEMBER(bonusShieldDir),
CR_MEMBER(bonusShieldSaved),
Index: Sim/Units/Unit.h
===================================================================
--- Sim/Units/Unit.h (revision 4358)
+++ Sim/Units/Unit.h (working copy)
@@ -289,6 +289,8 @@
bool crashing;
bool isDead; //prevent damage from hitting an already dead unit (causing multi wreck etc)
+ bool falling; //for units being dropped from transports (parachute drops)
+ float fallSpeed;
float3 bonusShieldDir; //units takes less damage when attacked from this dir (encourage flanking fire)
float bonusShieldSaved; //how much the bonus shield can turn upon an attack(zeroed when attacked, slowly increase)
@@ -357,6 +359,7 @@
virtual void IncomingMissile(CMissileProjectile* missile);
void TempHoldFire(void);
void ReleaseTempHoldFire(void);
+ void Drop(float3 parentPos,float3 parentDir,CUnit* parent); //start this unit in freefall from parent unit
virtual void DrawS3O(void);
void PostLoad();
static void hitByWeaponIdCallback(int retCode, void *p1, void *p2);
Index: Sim/Units/UnitDef.h
===================================================================
--- Sim/Units/UnitDef.h (revision 4358)
+++ Sim/Units/UnitDef.h (working copy)
@@ -285,6 +285,9 @@
bool holdSteady;
bool releaseHeld;
bool transportByEnemy;
+ int transportUnloadMethod; //0 - land unload, 1 - flyover drop, 2 - land flood
+ float fallSpeed; //dictates fall speed of all transported units
+ float unitFallSpeed; //sets the transported units fbi, overrides fallSpeed
bool canCloak; //if the unit can cloak
bool startCloaked; //if the units want to start out cloaked
Index: Sim/Units/UnitDefHandler.cpp
===================================================================
--- Sim/Units/UnitDefHandler.cpp (revision 4358)
+++ Sim/Units/UnitDefHandler.cpp (working copy)
@@ -366,6 +366,9 @@
ud.holdSteady = udTable.GetBool("holdSteady", true);
ud.releaseHeld = udTable.GetBool("releaseHeld", false);
ud.transportByEnemy = udTable.GetBool("transportByEnemy", true);
+ ud.transportUnloadMethod = udTable.GetInt("transportUnloadMethod" , 0); //0 normal, 1 parachute drop, 2 land flood
+ ud.fallSpeed = udTable.GetFloat("fallSpeed", 0.2); //drop speed for all units dropped from this transport
+ ud.unitFallSpeed = udTable.GetFloat("unitFallSpeed", 0); //specific unit drop speed, overrides fallSpeed
ud.wingDrag = udTable.GetFloat("wingDrag", 0.07f); // drag caused by wings
ud.wingAngle = udTable.GetFloat("wingAngle", 0.08f); // angle between front and the wing plane
Index: Sim/Units/UnitTypes/TransportUnit.cpp
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.cpp (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.cpp (working copy)
@@ -219,3 +219,79 @@
}
}
}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit, float3 pos) {
+
+ if(unit->transporter != this)
+ return;
+
+ for (list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if (ti->unit==unit) {
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ loshandler->MoveUnit(unit,false);
+
+ //add an additional move command for after we land
+ Command c;
+ c.id=CMD_MOVE;
+ c.params.push_back(pos.x);
+ c.params.push_back(pos.y);
+ c.params.push_back(pos.z);
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+
+}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit)
+{
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ unit->Block();
+
+ loshandler->MoveUnit(unit,false);
+
+ Command c;
+ c.id=CMD_STOP;
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+}
\ No newline at end of file
Index: Sim/Units/UnitTypes/TransportUnit.h
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.h (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.h (working copy)
@@ -33,6 +33,8 @@
void AttachUnit(CUnit* unit, int piece);
void DetachUnit(CUnit* unit);
bool CanTransport(CUnit* unit);
+ void DetachUnitFromAir(CUnit* unit,float3 pos); //moves to position after
+ void DetachUnitFromAir(CUnit* unit);
};
-
newTransportMethods 0.21 .diff (37,194 bytes) 2007-09-22 15:18
Index: Lua/LuaUnitDefs.cpp
===================================================================
--- Lua/LuaUnitDefs.cpp (revision 4358)
+++ Lua/LuaUnitDefs.cpp (working copy)
@@ -870,7 +870,10 @@
ADD_BOOL( "holdSteady", ud.holdSteady);
ADD_BOOL( "releaseHeld", ud.releaseHeld);
ADD_BOOL( "transportByEnemy", ud.transportByEnemy);
-
+ ADD_INT("transportUnloadMethod",ud.transportUnloadMethod);
+ ADD_FLOAT( "fallSpeed", ud.fallSpeed);
+ ADD_FLOAT( "unitFallSpeed", ud.unitFallSpeed);
+
ADD_BOOL( "startCloaked", ud.startCloaked);
ADD_FLOAT("cloakCost", ud.cloakCost);
ADD_FLOAT("cloakCostMoving", ud.cloakCostMoving);
Index: Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- Sim/MoveTypes/groundmovetype.cpp (revision 4358)
+++ Sim/MoveTypes/groundmovetype.cpp (working copy)
@@ -36,7 +36,7 @@
CR_REG_METADATA(CGroundMoveType, (
CR_MEMBER(baseTurnRate),
CR_MEMBER(turnRate),
- CR_MEMBER(accRate),
+ CR_MEMBER(accRate),
CR_MEMBER(wantedSpeed),
CR_MEMBER(currentSpeed),
@@ -88,6 +88,8 @@
CR_MEMBER(skidding),
CR_MEMBER(flying),
CR_MEMBER(skidRotSpeed),
+ CR_MEMBER(dropSpeed),
+ CR_MEMBER(dropHeight),
CR_MEMBER(skidRotVector),
CR_MEMBER(skidRotSpeed2),
@@ -130,6 +132,7 @@
deltaHeading(0),
skidding(false),
flying(false),
+ dropHeight(0),
skidRotSpeed(0),
floatOnWater(false),
skidRotVector(UpVector),
@@ -202,6 +205,12 @@
return;
}
+ //set drop height when we start to drop
+ if(owner->falling) {
+ UpdateControlledDrop();
+ return;
+ }
+
if(owner->stunned){
owner->cob->Call(COBFN_StopMoving);
owner->speed=ZeroVector;
@@ -309,7 +318,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+
+ //need this to stop jitter when falling
+ if (!owner->falling)
+ owner->pos.y=wh;
}
if(owner->pos!=oldPos){
@@ -323,8 +335,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
owner->speed=owner->pos-oldPos;
owner->midPos = owner->pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
oldPos=owner->pos;
@@ -378,8 +392,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
if(!(owner->pos==oldSlowUpdatePos)){
oldSlowUpdatePos=owner->pos;
@@ -549,7 +565,7 @@
}
owner->frontdir = GetVectorFromHeading(heading);
- if(owner->upright){
+ if (owner->upright) {
owner->updir=UpVector;
owner->rightdir=owner->frontdir.cross(owner->updir);
} else {
@@ -713,6 +729,54 @@
CheckCollisionSkid();
}
+void CGroundMoveType::UpdateControlledDrop(void)
+{
+ float3& speed=owner->speed;
+ float3& pos=owner->pos;
+ float3& midPos=(float3)owner->midPos;
+
+
+
+ if(owner->falling){
+
+ //set us upright
+
+
+ owner->cob->Call("Falling"); //start/continue parachute animation
+
+ speed.y += gs->gravity*owner->fallSpeed;
+
+ if(owner->speed.y > 0) //sometimes the dropped unit gets an upward force, still unsure where its coming from
+ owner->speed.y = 0;
+
+ midPos += speed;
+ pos = midPos - owner->frontdir * owner->relMidPos.z
+ - owner->updir * owner->relMidPos.y
+ - owner->rightdir * owner->relMidPos.x;
+
+ owner->midPos.y = owner->pos.y + owner->relMidPos.y;
+
+ if(midPos.y < 0)
+ speed*=0.90;
+
+ float wh;
+
+ if(floatOnWater)
+ wh = ground->GetHeight(midPos.x, midPos.z);
+ else
+ wh = ground->GetHeight2(midPos.x, midPos.z);
+
+ if(wh > midPos.y-owner->relMidPos.y){
+ owner->falling = false;
+ midPos.y = wh + owner->relMidPos.y - speed.y*0.8;
+ owner->cob->Call("Landed"); //stop parachute animation
+ }
+
+
+
+ }
+}
+
void CGroundMoveType::CheckCollisionSkid(void)
{
float3& pos=owner->pos;
Index: Sim/MoveTypes/groundmovetype.h
===================================================================
--- Sim/MoveTypes/groundmovetype.h (revision 4358)
+++ Sim/MoveTypes/groundmovetype.h (working copy)
@@ -106,6 +106,7 @@
void ChangeHeading(short wantedHeading);
void UpdateSkid(void);
+ void UpdateControlledDrop(void);
void CheckCollisionSkid(void);
float GetFlyTime(float3 pos, float3 speed);
void CalcSkidRot(void);
@@ -113,6 +114,8 @@
bool skidding;
bool flying;
float skidRotSpeed;
+ float dropSpeed;
+ float dropHeight;
float3 skidRotVector;
float skidRotSpeed2;
Index: Sim/MoveTypes/TAAirMoveType.cpp
===================================================================
--- Sim/MoveTypes/TAAirMoveType.cpp (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.cpp (working copy)
@@ -15,6 +15,7 @@
#include "Sim/Misc/GeometricObjects.h"
#include "Mobility.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
+#include "Sim/Units/CommandAI/CommandAI.h"
CR_BIND_DERIVED(CTAAirMoveType, CMoveType, (NULL));
@@ -357,10 +358,13 @@
// Move the unit around a bit.. and when it gets too far away from goal position it switches to normal flying instead
void CTAAirMoveType::UpdateHovering()
{
- float driftSpeed = owner->unitDef->dlHoverFactor;
+ float driftSpeed = owner->unitDef->dlHoverFactor;
+ float3 dir = goalPos - owner->pos;
- // move towards goal position
- float3 dir = goalPos - owner->pos;
+ // move towards goal position if its not immediately behind us when we have more waypoints to get to
+ if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1 )
+ dir = owner->frontdir;
+
wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f;
// damping
@@ -381,6 +385,10 @@
float3 dir = goalPos - pos;
owner->restTime=0;
+ //dont change direction for waypoints we just flew over and missed slightly
+ if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1 )
+ dir = owner->frontdir;
+
//are we there yet?
// logOutput.Print("max drift %f %i %f %f",maxDrift,waitCounter,dir.Length2D(),fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight));
bool closeToGoal=dir.SqLength2D() < maxDrift*maxDrift && fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight)<maxDrift;
@@ -490,8 +498,11 @@
float dist=dir.Length2D();
//If we are close to our goal, we should go slow enough to be able to break in time
- //if in attack mode dont slow down
- if (flyState!=FLY_ATTACKING && dist < breakDistance) {
+ //new additional rule:
+ //if in attack mode or have more this is an intermediate waypoint dont
+ //slow down except if near ground level
+
+ if ((flyState!=FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands() ) || (pos.y - ground->GetHeight(pos.x, pos.z) < orgWantedHeight/2)) {
realMax = dist/(speed.Length2D()+0.01f) * decRate;
//logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax);
}
@@ -501,12 +512,17 @@
UpdateAirPhysics();
- //Point toward goal or forward
+ //Point toward goal or forward - unless we just passed it to get to another goal
if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
dir = circlingPos - pos;
- } else {
+ }
+ else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1 ) {
+ dir = owner->frontdir;
+ }
+ else {
dir = goalPos - pos;
}
+
if(dir.SqLength2D()>1)
wantedHeading = GetHeadingFromVector(dir.x, dir.z);
}
Index: Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- Sim/Units/CommandAI/TransportCAI.cpp (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.cpp (working copy)
@@ -18,6 +18,7 @@
#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)
{
@@ -30,6 +31,12 @@
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)
));
@@ -47,6 +54,15 @@
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";
@@ -84,10 +100,11 @@
}
Command& c=commandQue.front();
switch(c.id){
- case CMD_LOAD_UNITS: { ExecuteLoadUnits(c); return; }
+ 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;
}
@@ -200,11 +217,209 @@
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)
+{
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ //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->mass>=100000 || unit->beingBuilt)
+ return false;
+ // don't transport cloaked enemies
+ if (unit->isCloaked && !gs->AlliedTeams(unit->team, owner->team))
+ return false;
+ if(unit->unitDef->canhover && (modInfo->transportHover==0))
+ return false;
+ if(unit->unitDef->floater && (modInfo->transportShip==0))
+ return false;
+ if(unit->unitDef->canfly && (modInfo->transportAir==0))
+ return false;
+ // if not a hover, not a floater and not a flier, then it's probably ground unit
+ if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
+ return false;
+ if(unit->xsize > owner->unitDef->transportSize*2)
+ return false;
+ if(!transport->CanTransport(unit))
+ return false;
+ if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
+ return false;
+
+ return true;
+}
+
+bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
+{
+// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
+ if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
+ for (int a=0;a<100;++a) {
+ float3 delta(1,0,1);
+ while(delta.SqLength2D()>1){
+ delta.x=(gs->randFloat()-0.5f)*2;
+ delta.z=(gs->randFloat()-0.5f)*2;
+ }
+ 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(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
+ float dy=y-center.z;
+ float rx=radius*radius-dy*dy;
+ if(rx<=0)
+ continue;
+ rx=sqrt(rx);
+ for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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(CTAAirMoveType* am=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) {
+//select suitable spots according to directions we are allowed to exit transport from
+ //TODO
+ return false;
+}
+//
+//
+void CTransportCAI::UnloadUnits_Land(Command& c, CTransportUnit* transport) {
if(lastCall==gs->frameNum) //avoid infinite loops
return;
lastCall=gs->frameNum;
@@ -215,8 +430,9 @@
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
float3 found;
- CUnit* unitToUnload=((CTransportUnit*)owner)->transported.front().unit;
- bool canUnload=FindEmptySpot(pos,max(16.0f,radius),unitToUnload->radius,found,unitToUnload);
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
if(canUnload){
Command c2;
c2.id=CMD_UNLOAD_UNIT;
@@ -231,18 +447,122 @@
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;
-void CTransportCAI::ExecuteUnloadUnit(Command &c)
-{
- CTransportUnit* transport = (CTransportUnit*)owner;
- if (inCommand) {
- if (!owner->cob->busy) {
- // if(scriptReady)
+ 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 ) {
+ dropSpots.clear();
+ startingDropPos = pos;
+
+ approachVector = startingDropPos-owner->pos;
+ approachVector.Normalize();
+ canUnload = FindEmptyDropSpots(pos, pos + approachVector*max(16.0f,radius), dropSpots);
+
+ } else if (!dropSpots.empty() ) {
+ //make sure we check current spot infront of us each unload
+ pos = dropSpots.back(); //take last landing pos as new start spot
+ canUnload = dropSpots.size() > 0;
+ }
+
+ if( canUnload ){
+ if(SpotIsClear(dropSpots.back(),((CTransportUnit*)owner)->transported.front().unit)) {
+ float3 pos = dropSpots.back();
+ Command c2;
+ c2.id=CMD_UNLOAD_UNIT;
+ c2.params.push_back(pos.x);
+ c2.params.push_back(pos.y);
+ c2.params.push_back(pos.z);
+ c2.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c2);
+
+ SlowUpdate();
+ isFirstIteration = false;
+ return;
+ } else {
+ dropSpots.pop_back();
+ }
+ } else {
+
+ startingDropPos = float3(-1,-1,-1);
+ isFirstIteration=true;
+ dropSpots.clear();
+ FinishCommand();
+ }
+}
+void CTransportCAI::UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport) {
+ //TODO - fly into the ground, doing damage to units at landing pos, then unload.
+ //needs heavy modification of TAAirMoveType
+}
+void CTransportCAI::UnloadUnits_LandFlood(Command& c, CTransportUnit* transport) {
+ if(lastCall==gs->frameNum) //avoid infinite loops
+ return;
+ lastCall=gs->frameNum;
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
}
- else {
+ float3 pos(c.params[0],c.params[1],c.params[2]);
+ float radius=c.params[3];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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);
+
+ if (isFirstIteration ) {
+ Command c1;
+ c1.id=CMD_MOVE;
+ c1.params.push_back(pos.x);
+ c1.params.push_back(pos.y);
+ c1.params.push_back(pos.z);
+ c1.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c1);
+ startingDropPos = pos;
+ }
+
+ SlowUpdate();
+ return;
+ } else {
+ FinishCommand();
+ }
+ return;
+
+}
+
+
+//
+void CTransportCAI::UnloadLand(Command& c) {
+ //default unload
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ // if(scriptReady)
+ FinishCommand();
+ }
+ } else {
const std::list<CTransportUnit::TransportedUnit>& transList =
transport->transported;
@@ -259,8 +579,7 @@
CUnit* unit = NULL;
if (c.params.size() < 4) {
unit = transList.front().unit;
- }
- else {
+ } else {
const int unitID = (int)c.params[3];
std::list<CTransportUnit::TransportedUnit>::const_iterator it;
for (it = transList.begin(); it != transList.end(); ++it) {
@@ -286,7 +605,7 @@
am->SetWantedAltitude(unit->model->height);
am->maxDrift = 1;
if ((owner->pos.distance(wantedPos) < 8) &&
- (owner->updir.dot(UpVector) > 0.99f)) {
+ (owner->updir.dot(UpVector) > 0.99f)) {
transport->DetachUnit(unit);
if (transport->transported.empty()) {
am->dontLand = false;
@@ -307,97 +626,164 @@
}
}
}
- return;
-}
+ return;
-void CTransportCAI::ScriptReady(void)
-{
- scriptReady = true; // NOTE: does not seem to be used
}
+void CTransportCAI::UnloadDrop(Command& c) {
+
+ //fly over and drop unit
+ if(inCommand){
+ if(!owner->cob->busy)
+ //if(scriptReady)
+ FinishCommand();
+ } else {
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
+ }
-bool CTransportCAI::CanTransport(CUnit* unit)
-{
- CTransportUnit* transport=(CTransportUnit*)owner;
+ float3 pos(c.params[0],c.params[1],c.params[2]); //head towards goal
+
+ //note that taairmovetype must be modified to allow non stop movement through goals for this to work well
+ if(goalPos.distance2D(pos)>20){
+ SetGoal(pos,owner->pos);
+ lastDropPos = pos;
+ }
+
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){
+
+ pos.y=ground->GetHeight(pos.x,pos.z);
+ CUnit* unit=((CTransportUnit*)owner)->transported.front().unit;
+ am->maxDrift=1;
- 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->unitDef->canhover && (modInfo->transportHover==0))
- return false;
- if(unit->unitDef->floater && (modInfo->transportShip==0))
- return false;
- if(unit->unitDef->canfly && (modInfo->transportAir==0))
- return false;
- // if not a hover, not a floater and not a flier, then it's probably ground unit
- if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
- return false;
- if(unit->xsize > owner->unitDef->transportSize*2)
- return false;
- if(!transport->CanTransport(unit))
- return false;
- if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
- return false;
+ //if near target or have past it accidentally- drop unit
+ if(owner->pos.distance2D(pos) < 40 || (((pos - owner->pos).Normalize()).distance(owner->frontdir.Normalize()) > 0.5 && owner->pos.distance2D(pos)< 205)) {
+ am->dontLand=true;
+ owner->cob->Call("EndTransport"); //test
+ ((CTransportUnit*)owner)->DetachUnitFromAir(unit,pos);
+ dropSpots.pop_back();
- return true;
+ if (dropSpots.empty()) {
+ float3 fix = owner->pos+owner->frontdir*200;
+ SetGoal(fix,owner->pos);//move the transport away after last drop
+ }
+ FinishCommand();
+ }
+ } else {
+ inCommand=true;
+ scriptReady=false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(((CTransportUnit*)owner)->transported.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop",args,ScriptCallback,this,0);
+ }
+ }
}
-
-bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
-{
-// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
- if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
- for (int a=0;a<100;++a) {
- float3 delta(1,0,1);
- while(delta.SqLength2D()>1){
- delta.x=(gs->randFloat()-0.5f)*2;
- delta.z=(gs->randFloat()-0.5f)*2;
+void CTransportCAI::UnloadCrashFlood(Command& c) {
+ //TODO - will require heavy modification of TAAirMoveType.cpp
+}
+void CTransportCAI::UnloadLandFlood(Command& c) {
+ //land, then release all units at once
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ //if(scriptReady)
+ FinishCommand();
}
- float3 pos=center+delta*radius;
- pos.y=ground->GetHeight(pos.x,pos.z);
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
- 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;
+ if (transList.empty()) {
+ FinishCommand();
+ return;
}
- } else {
- for(float y=max(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
- float dy=y-center.z;
- float rx=radius*radius-dy*dy;
- if(rx<=0)
- continue;
- rx=sqrt(rx);
- for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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;
+
+ //check units are all carried
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
}
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
}
+
+ //move to position
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if (isFirstIteration) {
+ if(goalPos.distance2D(pos) > 20)
+ SetGoal(startingDropPos, owner->pos);
+ }
+
+ if (startingDropPos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+ //create aircraft movetype instance
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+
+ if (am != NULL) {
+ //lower to ground
+
+ startingDropPos.y = ground->GetHeight(startingDropPos.x,startingDropPos.z);
+ const float3 wantedPos = startingDropPos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(1);
+ am->maxDrift = 1;
+ am->dontLand = false;
+
+ //when on our way down start animations for unloading gear
+ if (isFirstIteration) {
+ owner->cob->Call("StartUnload");
+ }
+ isFirstIteration = false;
+
+ //once at ground
+ if (owner->pos.y - ground->GetHeight(wantedPos.x,wantedPos.z) < 8) {
+
+ am->SetState(am->AIRCRAFT_LANDED);//nail it to the ground before it tries jumping up, only to land again...
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); //call this so that other animations such as opening doors may be started
+ transport->DetachUnitFromAir(unit,pos);
+
+ FinishCommand();
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ am->UpdateLanded();
+ }
+ }
+ } else {
+
+ //land transports
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ transport->DetachUnitFromAir(unit,pos);
+ isFirstIteration = false;
+ FinishCommand();
+ if (transport->transported.empty())
+ owner->cob->Call("EndTransport");
+ }
+ }
}
- return false;
+ return;
}
-
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
CUnit* best=0;
Index: Sim/Units/CommandAI/TransportCAI.h
===================================================================
--- Sim/Units/CommandAI/TransportCAI.h (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.h (working copy)
@@ -2,6 +2,12 @@
#define TRANSPORTCAI_H
#include "MobileCAI.h"
+#include "Sim/MoveTypes/TAAirMoveType.h"
+
+#define UNLOAD_LAND 0
+#define UNLOAD_DROP 1
+#define UNLOAD_LANDFLOOD 2
+#define UNLOAD_CRASHFLOOD 3
class CTransportCAI :
public CMobileCAI
@@ -14,8 +20,11 @@
void SlowUpdate(void);
void ScriptReady(void);
+ int unloadType;
bool CanTransport(CUnit* unit);
bool FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload);
+ bool FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots);
+ bool FindEmptyFloodSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots, std::vector<float3> exitDirs);
CUnit* FindUnitToTransport(float3 center, float radius);
int GetDefaultCmd(CUnit* pointed,CFeature* feature);
void DrawCommands(void);
@@ -29,6 +38,26 @@
int toBeTransportedUnitId;
bool scriptReady;
int lastCall;
+
+private:
+ void UnloadUnits_Land(Command& c, CTransportUnit* transport);
+ void UnloadUnits_Drop(Command& c, CTransportUnit* transport);
+ void UnloadUnits_LandFlood(Command& c, CTransportUnit* transport);
+ void UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport); //incomplete
+
+ void UnloadNormal(Command& c);
+ void UnloadLand(Command& c);
+ void UnloadDrop(Command& c); //parachute drop units
+ void UnloadLandFlood(Command& c); //land and dispatch units all at once
+ void UnloadCrashFlood(Command& c); //slam into landscape abruptly and dispatch units all at once (incomplete)
+
+ bool SpotIsClear(float3 pos, CUnit* u);
+ std::list<float3> dropSpots;
+ bool isFirstIteration;
+ float3 startingDropPos;
+ float3 lastDropPos;
+ float3 approachVector; //direction from which we travel to drop point
+ float3 endDropPos;
};
Index: Sim/Units/Unit.cpp
===================================================================
--- Sim/Units/Unit.cpp (revision 4358)
+++ Sim/Units/Unit.cpp (working copy)
@@ -107,6 +107,8 @@
rightdir(-1,0,0),
updir(0,1,0),
upright(true),
+ falling(false),
+ fallSpeed(0.2),
maxRange(0),
haveTarget(false),
lastAttacker(0),
@@ -355,6 +357,17 @@
}
+void CUnit::Drop(float3 parentPos,float3 parentDir, CUnit* parent) {
+ //drop unit from position
+
+ this->fallSpeed = this->unitDef->unitFallSpeed > 0 ? this->unitDef->unitFallSpeed : parent->unitDef->fallSpeed;
+ float landingHeight = ground->GetApproximateHeight(pos.x, pos.z);
+ falling = true;
+ this->pos.y = parentPos.y - height;
+ this->frontdir = parentDir;
+ this->frontdir.y = 0;
+ this->speed.y = 0;
+}
void CUnit::EnableScriptMoveType()
{
if (usingScriptMoveType) {
@@ -2251,6 +2264,8 @@
CR_MEMBER(tooltip),
CR_MEMBER(crashing),
CR_MEMBER(isDead),
+ CR_MEMBER(falling),
+ CR_MEMBER(fallSpeed),
CR_MEMBER(bonusShieldDir),
CR_MEMBER(bonusShieldSaved),
Index: Sim/Units/Unit.h
===================================================================
--- Sim/Units/Unit.h (revision 4358)
+++ Sim/Units/Unit.h (working copy)
@@ -289,6 +289,8 @@
bool crashing;
bool isDead; //prevent damage from hitting an already dead unit (causing multi wreck etc)
+ bool falling; //for units being dropped from transports (parachute drops)
+ float fallSpeed;
float3 bonusShieldDir; //units takes less damage when attacked from this dir (encourage flanking fire)
float bonusShieldSaved; //how much the bonus shield can turn upon an attack(zeroed when attacked, slowly increase)
@@ -357,6 +359,7 @@
virtual void IncomingMissile(CMissileProjectile* missile);
void TempHoldFire(void);
void ReleaseTempHoldFire(void);
+ void Drop(float3 parentPos,float3 parentDir,CUnit* parent); //start this unit in freefall from parent unit
virtual void DrawS3O(void);
void PostLoad();
static void hitByWeaponIdCallback(int retCode, void *p1, void *p2);
Index: Sim/Units/UnitDef.h
===================================================================
--- Sim/Units/UnitDef.h (revision 4358)
+++ Sim/Units/UnitDef.h (working copy)
@@ -285,6 +285,9 @@
bool holdSteady;
bool releaseHeld;
bool transportByEnemy;
+ int transportUnloadMethod; //0 - land unload, 1 - flyover drop, 2 - land flood
+ float fallSpeed; //dictates fall speed of all transported units
+ float unitFallSpeed; //sets the transported units fbi, overrides fallSpeed
bool canCloak; //if the unit can cloak
bool startCloaked; //if the units want to start out cloaked
Index: Sim/Units/UnitDefHandler.cpp
===================================================================
--- Sim/Units/UnitDefHandler.cpp (revision 4358)
+++ Sim/Units/UnitDefHandler.cpp (working copy)
@@ -366,6 +366,9 @@
ud.holdSteady = udTable.GetBool("holdSteady", true);
ud.releaseHeld = udTable.GetBool("releaseHeld", false);
ud.transportByEnemy = udTable.GetBool("transportByEnemy", true);
+ ud.transportUnloadMethod = udTable.GetInt("transportUnloadMethod" , 0); //0 normal, 1 parachute drop, 2 land flood
+ ud.fallSpeed = udTable.GetFloat("fallSpeed", 0.2); //drop speed for all units dropped from this transport
+ ud.unitFallSpeed = udTable.GetFloat("unitFallSpeed", 0); //specific unit drop speed, overrides fallSpeed
ud.wingDrag = udTable.GetFloat("wingDrag", 0.07f); // drag caused by wings
ud.wingAngle = udTable.GetFloat("wingAngle", 0.08f); // angle between front and the wing plane
Index: Sim/Units/UnitTypes/TransportUnit.cpp
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.cpp (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.cpp (working copy)
@@ -219,3 +219,79 @@
}
}
}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit, float3 pos) {
+
+ if(unit->transporter != this)
+ return;
+
+ for (list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if (ti->unit==unit) {
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ loshandler->MoveUnit(unit,false);
+
+ //add an additional move command for after we land
+ Command c;
+ c.id=CMD_MOVE;
+ c.params.push_back(pos.x);
+ c.params.push_back(pos.y);
+ c.params.push_back(pos.z);
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+
+}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit)
+{
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ unit->Block();
+
+ loshandler->MoveUnit(unit,false);
+
+ Command c;
+ c.id=CMD_STOP;
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+}
\ No newline at end of file
Index: Sim/Units/UnitTypes/TransportUnit.h
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.h (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.h (working copy)
@@ -33,6 +33,8 @@
void AttachUnit(CUnit* unit, int piece);
void DetachUnit(CUnit* unit);
bool CanTransport(CUnit* unit);
+ void DetachUnitFromAir(CUnit* unit,float3 pos); //moves to position after
+ void DetachUnitFromAir(CUnit* unit);
};
-
newTransportMethods 0.22 .diff (37,213 bytes) 2007-09-22 15:27
Index: Lua/LuaUnitDefs.cpp
===================================================================
--- Lua/LuaUnitDefs.cpp (revision 4358)
+++ Lua/LuaUnitDefs.cpp (working copy)
@@ -870,7 +870,10 @@
ADD_BOOL( "holdSteady", ud.holdSteady);
ADD_BOOL( "releaseHeld", ud.releaseHeld);
ADD_BOOL( "transportByEnemy", ud.transportByEnemy);
-
+ ADD_INT("transportUnloadMethod",ud.transportUnloadMethod);
+ ADD_FLOAT( "fallSpeed", ud.fallSpeed);
+ ADD_FLOAT( "unitFallSpeed", ud.unitFallSpeed);
+
ADD_BOOL( "startCloaked", ud.startCloaked);
ADD_FLOAT("cloakCost", ud.cloakCost);
ADD_FLOAT("cloakCostMoving", ud.cloakCostMoving);
Index: Sim/MoveTypes/groundmovetype.cpp
===================================================================
--- Sim/MoveTypes/groundmovetype.cpp (revision 4358)
+++ Sim/MoveTypes/groundmovetype.cpp (working copy)
@@ -36,7 +36,7 @@
CR_REG_METADATA(CGroundMoveType, (
CR_MEMBER(baseTurnRate),
CR_MEMBER(turnRate),
- CR_MEMBER(accRate),
+ CR_MEMBER(accRate),
CR_MEMBER(wantedSpeed),
CR_MEMBER(currentSpeed),
@@ -88,6 +88,8 @@
CR_MEMBER(skidding),
CR_MEMBER(flying),
CR_MEMBER(skidRotSpeed),
+ CR_MEMBER(dropSpeed),
+ CR_MEMBER(dropHeight),
CR_MEMBER(skidRotVector),
CR_MEMBER(skidRotSpeed2),
@@ -130,6 +132,7 @@
deltaHeading(0),
skidding(false),
flying(false),
+ dropHeight(0),
skidRotSpeed(0),
floatOnWater(false),
skidRotVector(UpVector),
@@ -202,6 +205,12 @@
return;
}
+ //set drop height when we start to drop
+ if(owner->falling) {
+ UpdateControlledDrop();
+ return;
+ }
+
if(owner->stunned){
owner->cob->Call(COBFN_StopMoving);
owner->speed=ZeroVector;
@@ -309,7 +318,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+
+ //need this to stop jitter when falling
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
}
if(owner->pos!=oldPos){
@@ -323,8 +335,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
owner->speed=owner->pos-oldPos;
owner->midPos = owner->pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
oldPos=owner->pos;
@@ -378,8 +392,10 @@
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
- owner->pos.y=wh;
+ if (!(owner->falling || owner->Flying))
+ owner->pos.y=wh;
+
if(!(owner->pos==oldSlowUpdatePos)){
oldSlowUpdatePos=owner->pos;
@@ -549,7 +565,7 @@
}
owner->frontdir = GetVectorFromHeading(heading);
- if(owner->upright){
+ if (owner->upright) {
owner->updir=UpVector;
owner->rightdir=owner->frontdir.cross(owner->updir);
} else {
@@ -713,6 +729,54 @@
CheckCollisionSkid();
}
+void CGroundMoveType::UpdateControlledDrop(void)
+{
+ float3& speed=owner->speed;
+ float3& pos=owner->pos;
+ float3& midPos=(float3)owner->midPos;
+
+
+
+ if(owner->falling){
+
+ //set us upright
+
+
+ owner->cob->Call("Falling"); //start/continue parachute animation
+
+ speed.y += gs->gravity*owner->fallSpeed;
+
+ if(owner->speed.y > 0) //sometimes the dropped unit gets an upward force, still unsure where its coming from
+ owner->speed.y = 0;
+
+ midPos += speed;
+ pos = midPos - owner->frontdir * owner->relMidPos.z
+ - owner->updir * owner->relMidPos.y
+ - owner->rightdir * owner->relMidPos.x;
+
+ owner->midPos.y = owner->pos.y + owner->relMidPos.y;
+
+ if(midPos.y < 0)
+ speed*=0.90;
+
+ float wh;
+
+ if(floatOnWater)
+ wh = ground->GetHeight(midPos.x, midPos.z);
+ else
+ wh = ground->GetHeight2(midPos.x, midPos.z);
+
+ if(wh > midPos.y-owner->relMidPos.y){
+ owner->falling = false;
+ midPos.y = wh + owner->relMidPos.y - speed.y*0.8;
+ owner->cob->Call("Landed"); //stop parachute animation
+ }
+
+
+
+ }
+}
+
void CGroundMoveType::CheckCollisionSkid(void)
{
float3& pos=owner->pos;
Index: Sim/MoveTypes/groundmovetype.h
===================================================================
--- Sim/MoveTypes/groundmovetype.h (revision 4358)
+++ Sim/MoveTypes/groundmovetype.h (working copy)
@@ -106,6 +106,7 @@
void ChangeHeading(short wantedHeading);
void UpdateSkid(void);
+ void UpdateControlledDrop(void);
void CheckCollisionSkid(void);
float GetFlyTime(float3 pos, float3 speed);
void CalcSkidRot(void);
@@ -113,6 +114,8 @@
bool skidding;
bool flying;
float skidRotSpeed;
+ float dropSpeed;
+ float dropHeight;
float3 skidRotVector;
float skidRotSpeed2;
Index: Sim/MoveTypes/TAAirMoveType.cpp
===================================================================
--- Sim/MoveTypes/TAAirMoveType.cpp (revision 4358)
+++ Sim/MoveTypes/TAAirMoveType.cpp (working copy)
@@ -15,6 +15,7 @@
#include "Sim/Misc/GeometricObjects.h"
#include "Mobility.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
+#include "Sim/Units/CommandAI/CommandAI.h"
CR_BIND_DERIVED(CTAAirMoveType, CMoveType, (NULL));
@@ -357,10 +358,13 @@
// Move the unit around a bit.. and when it gets too far away from goal position it switches to normal flying instead
void CTAAirMoveType::UpdateHovering()
{
- float driftSpeed = owner->unitDef->dlHoverFactor;
+ float driftSpeed = owner->unitDef->dlHoverFactor;
+ float3 dir = goalPos - owner->pos;
- // move towards goal position
- float3 dir = goalPos - owner->pos;
+ // move towards goal position if its not immediately behind us when we have more waypoints to get to
+ if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1 )
+ dir = owner->frontdir;
+
wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f;
// damping
@@ -381,6 +385,10 @@
float3 dir = goalPos - pos;
owner->restTime=0;
+ //dont change direction for waypoints we just flew over and missed slightly
+ if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1 )
+ dir = owner->frontdir;
+
//are we there yet?
// logOutput.Print("max drift %f %i %f %f",maxDrift,waitCounter,dir.Length2D(),fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight));
bool closeToGoal=dir.SqLength2D() < maxDrift*maxDrift && fabs(ground->GetHeight(pos.x,pos.z)-pos.y+wantedHeight)<maxDrift;
@@ -490,8 +498,11 @@
float dist=dir.Length2D();
//If we are close to our goal, we should go slow enough to be able to break in time
- //if in attack mode dont slow down
- if (flyState!=FLY_ATTACKING && dist < breakDistance) {
+ //new additional rule:
+ //if in attack mode or have more this is an intermediate waypoint dont
+ //slow down except if near ground level
+
+ if ((flyState!=FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands() ) || (pos.y - ground->GetHeight(pos.x, pos.z) < orgWantedHeight/2)) {
realMax = dist/(speed.Length2D()+0.01f) * decRate;
//logOutput.Print("Break! %f %f %f", maxSpeed, dir.Length2D(), realMax);
}
@@ -501,12 +512,17 @@
UpdateAirPhysics();
- //Point toward goal or forward
+ //Point toward goal or forward - unless we just passed it to get to another goal
if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
dir = circlingPos - pos;
- } else {
+ }
+ else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() && dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1 ) {
+ dir = owner->frontdir;
+ }
+ else {
dir = goalPos - pos;
}
+
if(dir.SqLength2D()>1)
wantedHeading = GetHeadingFromVector(dir.x, dir.z);
}
Index: Sim/Units/CommandAI/TransportCAI.cpp
===================================================================
--- Sim/Units/CommandAI/TransportCAI.cpp (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.cpp (working copy)
@@ -18,6 +18,7 @@
#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)
{
@@ -30,6 +31,12 @@
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)
));
@@ -47,6 +54,15 @@
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";
@@ -84,10 +100,11 @@
}
Command& c=commandQue.front();
switch(c.id){
- case CMD_LOAD_UNITS: { ExecuteLoadUnits(c); return; }
+ 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;
}
@@ -200,11 +217,209 @@
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)
+{
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ //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->mass>=100000 || unit->beingBuilt)
+ return false;
+ // don't transport cloaked enemies
+ if (unit->isCloaked && !gs->AlliedTeams(unit->team, owner->team))
+ return false;
+ if(unit->unitDef->canhover && (modInfo->transportHover==0))
+ return false;
+ if(unit->unitDef->floater && (modInfo->transportShip==0))
+ return false;
+ if(unit->unitDef->canfly && (modInfo->transportAir==0))
+ return false;
+ // if not a hover, not a floater and not a flier, then it's probably ground unit
+ if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
+ return false;
+ if(unit->xsize > owner->unitDef->transportSize*2)
+ return false;
+ if(!transport->CanTransport(unit))
+ return false;
+ if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
+ return false;
+
+ return true;
+}
+
+bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
+{
+// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
+ if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
+ for (int a=0;a<100;++a) {
+ float3 delta(1,0,1);
+ while(delta.SqLength2D()>1){
+ delta.x=(gs->randFloat()-0.5f)*2;
+ delta.z=(gs->randFloat()-0.5f)*2;
+ }
+ 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(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
+ float dy=y-center.z;
+ float rx=radius*radius-dy*dy;
+ if(rx<=0)
+ continue;
+ rx=sqrt(rx);
+ for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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(CTAAirMoveType* am=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) {
+//select suitable spots according to directions we are allowed to exit transport from
+ //TODO
+ return false;
+}
+//
+//
+void CTransportCAI::UnloadUnits_Land(Command& c, CTransportUnit* transport) {
if(lastCall==gs->frameNum) //avoid infinite loops
return;
lastCall=gs->frameNum;
@@ -215,8 +430,9 @@
float3 pos(c.params[0],c.params[1],c.params[2]);
float radius=c.params[3];
float3 found;
- CUnit* unitToUnload=((CTransportUnit*)owner)->transported.front().unit;
- bool canUnload=FindEmptySpot(pos,max(16.0f,radius),unitToUnload->radius,found,unitToUnload);
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
if(canUnload){
Command c2;
c2.id=CMD_UNLOAD_UNIT;
@@ -231,18 +447,122 @@
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;
-void CTransportCAI::ExecuteUnloadUnit(Command &c)
-{
- CTransportUnit* transport = (CTransportUnit*)owner;
- if (inCommand) {
- if (!owner->cob->busy) {
- // if(scriptReady)
+ 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 ) {
+ dropSpots.clear();
+ startingDropPos = pos;
+
+ approachVector = startingDropPos-owner->pos;
+ approachVector.Normalize();
+ canUnload = FindEmptyDropSpots(pos, pos + approachVector*max(16.0f,radius), dropSpots);
+
+ } else if (!dropSpots.empty() ) {
+ //make sure we check current spot infront of us each unload
+ pos = dropSpots.back(); //take last landing pos as new start spot
+ canUnload = dropSpots.size() > 0;
+ }
+
+ if( canUnload ){
+ if(SpotIsClear(dropSpots.back(),((CTransportUnit*)owner)->transported.front().unit)) {
+ float3 pos = dropSpots.back();
+ Command c2;
+ c2.id=CMD_UNLOAD_UNIT;
+ c2.params.push_back(pos.x);
+ c2.params.push_back(pos.y);
+ c2.params.push_back(pos.z);
+ c2.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c2);
+
+ SlowUpdate();
+ isFirstIteration = false;
+ return;
+ } else {
+ dropSpots.pop_back();
+ }
+ } else {
+
+ startingDropPos = float3(-1,-1,-1);
+ isFirstIteration=true;
+ dropSpots.clear();
+ FinishCommand();
+ }
+}
+void CTransportCAI::UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport) {
+ //TODO - fly into the ground, doing damage to units at landing pos, then unload.
+ //needs heavy modification of TAAirMoveType
+}
+void CTransportCAI::UnloadUnits_LandFlood(Command& c, CTransportUnit* transport) {
+ if(lastCall==gs->frameNum) //avoid infinite loops
+ return;
+ lastCall=gs->frameNum;
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
}
- else {
+ float3 pos(c.params[0],c.params[1],c.params[2]);
+ float radius=c.params[3];
+ float3 found;
+ //((CTransportUnit*)owner)->transported
+
+ bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found,((CTransportUnit*)owner)->transported.front().unit);
+ 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);
+
+ if (isFirstIteration ) {
+ Command c1;
+ c1.id=CMD_MOVE;
+ c1.params.push_back(pos.x);
+ c1.params.push_back(pos.y);
+ c1.params.push_back(pos.z);
+ c1.options=c.options | INTERNAL_ORDER;
+ commandQue.push_front(c1);
+ startingDropPos = pos;
+ }
+
+ SlowUpdate();
+ return;
+ } else {
+ FinishCommand();
+ }
+ return;
+
+}
+
+
+//
+void CTransportCAI::UnloadLand(Command& c) {
+ //default unload
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ // if(scriptReady)
+ FinishCommand();
+ }
+ } else {
const std::list<CTransportUnit::TransportedUnit>& transList =
transport->transported;
@@ -259,8 +579,7 @@
CUnit* unit = NULL;
if (c.params.size() < 4) {
unit = transList.front().unit;
- }
- else {
+ } else {
const int unitID = (int)c.params[3];
std::list<CTransportUnit::TransportedUnit>::const_iterator it;
for (it = transList.begin(); it != transList.end(); ++it) {
@@ -286,7 +605,7 @@
am->SetWantedAltitude(unit->model->height);
am->maxDrift = 1;
if ((owner->pos.distance(wantedPos) < 8) &&
- (owner->updir.dot(UpVector) > 0.99f)) {
+ (owner->updir.dot(UpVector) > 0.99f)) {
transport->DetachUnit(unit);
if (transport->transported.empty()) {
am->dontLand = false;
@@ -307,97 +626,164 @@
}
}
}
- return;
-}
+ return;
-void CTransportCAI::ScriptReady(void)
-{
- scriptReady = true; // NOTE: does not seem to be used
}
+void CTransportCAI::UnloadDrop(Command& c) {
+
+ //fly over and drop unit
+ if(inCommand){
+ if(!owner->cob->busy)
+ //if(scriptReady)
+ FinishCommand();
+ } else {
+ if(((CTransportUnit*)owner)->transported.empty()){
+ FinishCommand();
+ return;
+ }
-bool CTransportCAI::CanTransport(CUnit* unit)
-{
- CTransportUnit* transport=(CTransportUnit*)owner;
+ float3 pos(c.params[0],c.params[1],c.params[2]); //head towards goal
+
+ //note that taairmovetype must be modified to allow non stop movement through goals for this to work well
+ if(goalPos.distance2D(pos)>20){
+ SetGoal(pos,owner->pos);
+ lastDropPos = pos;
+ }
+
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){
+
+ pos.y=ground->GetHeight(pos.x,pos.z);
+ CUnit* unit=((CTransportUnit*)owner)->transported.front().unit;
+ am->maxDrift=1;
- 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->unitDef->canhover && (modInfo->transportHover==0))
- return false;
- if(unit->unitDef->floater && (modInfo->transportShip==0))
- return false;
- if(unit->unitDef->canfly && (modInfo->transportAir==0))
- return false;
- // if not a hover, not a floater and not a flier, then it's probably ground unit
- if(!unit->unitDef->canhover && !unit->unitDef->floater && !unit->unitDef->canfly && (modInfo->transportGround==0))
- return false;
- if(unit->xsize > owner->unitDef->transportSize*2)
- return false;
- if(!transport->CanTransport(unit))
- return false;
- if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass)
- return false;
+ //if near target or have past it accidentally- drop unit
+ if(owner->pos.distance2D(pos) < 40 || (((pos - owner->pos).Normalize()).distance(owner->frontdir.Normalize()) > 0.5 && owner->pos.distance2D(pos)< 205)) {
+ am->dontLand=true;
+ owner->cob->Call("EndTransport"); //test
+ ((CTransportUnit*)owner)->DetachUnitFromAir(unit,pos);
+ dropSpots.pop_back();
- return true;
+ if (dropSpots.empty()) {
+ float3 fix = owner->pos+owner->frontdir*200;
+ SetGoal(fix,owner->pos);//move the transport away after last drop
+ }
+ FinishCommand();
+ }
+ } else {
+ inCommand=true;
+ scriptReady=false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(((CTransportUnit*)owner)->transported.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop",args,ScriptCallback,this,0);
+ }
+ }
}
-
-bool CTransportCAI::FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload)
-{
-// std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
- if (dynamic_cast<CTAAirMoveType*>(owner->moveType)) { //handle air transports differently
- for (int a=0;a<100;++a) {
- float3 delta(1,0,1);
- while(delta.SqLength2D()>1){
- delta.x=(gs->randFloat()-0.5f)*2;
- delta.z=(gs->randFloat()-0.5f)*2;
+void CTransportCAI::UnloadCrashFlood(Command& c) {
+ //TODO - will require heavy modification of TAAirMoveType.cpp
+}
+void CTransportCAI::UnloadLandFlood(Command& c) {
+ //land, then release all units at once
+ CTransportUnit* transport = (CTransportUnit*)owner;
+ if (inCommand) {
+ if (!owner->cob->busy) {
+ //if(scriptReady)
+ FinishCommand();
}
- float3 pos=center+delta*radius;
- pos.y=ground->GetHeight(pos.x,pos.z);
+ } else {
+ const std::list<CTransportUnit::TransportedUnit>& transList =
+ transport->transported;
- 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;
+ if (transList.empty()) {
+ FinishCommand();
+ return;
}
- } else {
- for(float y=max(0.0f,center.z-radius);y<min(float(gs->mapx*SQUARE_SIZE),center.z+radius);y+=SQUARE_SIZE){
- float dy=y-center.z;
- float rx=radius*radius-dy*dy;
- if(rx<=0)
- continue;
- rx=sqrt(rx);
- for(float x=max(0.0f,center.x-rx);x<min(float(gs->mapx*SQUARE_SIZE),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;
+
+ //check units are all carried
+ CUnit* unit = NULL;
+ if (c.params.size() < 4) {
+ unit = transList.front().unit;
+ } else {
+ const int unitID = (int)c.params[3];
+ std::list<CTransportUnit::TransportedUnit>::const_iterator it;
+ for (it = transList.begin(); it != transList.end(); ++it) {
+ CUnit* carried = it->unit;
+ if (unitID == carried->id) {
+ unit = carried;
+ break;
+ }
}
+ if (unit == NULL) {
+ FinishCommand();
+ return;
+ }
}
+
+ //move to position
+ float3 pos(c.params[0], c.params[1], c.params[2]);
+ if (isFirstIteration) {
+ if(goalPos.distance2D(pos) > 20)
+ SetGoal(startingDropPos, owner->pos);
+ }
+
+ if (startingDropPos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) {
+ //create aircraft movetype instance
+ CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType);
+
+ if (am != NULL) {
+ //lower to ground
+
+ startingDropPos.y = ground->GetHeight(startingDropPos.x,startingDropPos.z);
+ const float3 wantedPos = startingDropPos + UpVector * unit->model->height;
+ SetGoal(wantedPos, owner->pos);
+ am->SetWantedAltitude(1);
+ am->maxDrift = 1;
+ am->dontLand = false;
+
+ //when on our way down start animations for unloading gear
+ if (isFirstIteration) {
+ owner->cob->Call("StartUnload");
+ }
+ isFirstIteration = false;
+
+ //once at ground
+ if (owner->pos.y - ground->GetHeight(wantedPos.x,wantedPos.z) < 8) {
+
+ am->SetState(am->AIRCRAFT_LANDED);//nail it to the ground before it tries jumping up, only to land again...
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); //call this so that other animations such as opening doors may be started
+ transport->DetachUnitFromAir(unit,pos);
+
+ FinishCommand();
+ if (transport->transported.empty()) {
+ am->dontLand = false;
+ owner->cob->Call("EndTransport");
+ am->UpdateLanded();
+ }
+ }
+ } else {
+
+ //land transports
+ inCommand = true;
+ scriptReady = false;
+ StopMove();
+ std::vector<int> args;
+ args.push_back(transList.front().unit->id);
+ args.push_back(PACKXZ(pos.x, pos.z));
+ owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0);
+ transport->DetachUnitFromAir(unit,pos);
+ isFirstIteration = false;
+ FinishCommand();
+ if (transport->transported.empty())
+ owner->cob->Call("EndTransport");
+ }
+ }
}
- return false;
+ return;
}
-
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
CUnit* best=0;
Index: Sim/Units/CommandAI/TransportCAI.h
===================================================================
--- Sim/Units/CommandAI/TransportCAI.h (revision 4358)
+++ Sim/Units/CommandAI/TransportCAI.h (working copy)
@@ -2,6 +2,12 @@
#define TRANSPORTCAI_H
#include "MobileCAI.h"
+#include "Sim/MoveTypes/TAAirMoveType.h"
+
+#define UNLOAD_LAND 0
+#define UNLOAD_DROP 1
+#define UNLOAD_LANDFLOOD 2
+#define UNLOAD_CRASHFLOOD 3
class CTransportCAI :
public CMobileCAI
@@ -14,8 +20,11 @@
void SlowUpdate(void);
void ScriptReady(void);
+ int unloadType;
bool CanTransport(CUnit* unit);
bool FindEmptySpot(float3 center, float radius,float emptyRadius, float3& found, CUnit* unitToUnload);
+ bool FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots);
+ bool FindEmptyFloodSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots, std::vector<float3> exitDirs);
CUnit* FindUnitToTransport(float3 center, float radius);
int GetDefaultCmd(CUnit* pointed,CFeature* feature);
void DrawCommands(void);
@@ -29,6 +38,26 @@
int toBeTransportedUnitId;
bool scriptReady;
int lastCall;
+
+private:
+ void UnloadUnits_Land(Command& c, CTransportUnit* transport);
+ void UnloadUnits_Drop(Command& c, CTransportUnit* transport);
+ void UnloadUnits_LandFlood(Command& c, CTransportUnit* transport);
+ void UnloadUnits_CrashFlood(Command& c, CTransportUnit* transport); //incomplete
+
+ void UnloadNormal(Command& c);
+ void UnloadLand(Command& c);
+ void UnloadDrop(Command& c); //parachute drop units
+ void UnloadLandFlood(Command& c); //land and dispatch units all at once
+ void UnloadCrashFlood(Command& c); //slam into landscape abruptly and dispatch units all at once (incomplete)
+
+ bool SpotIsClear(float3 pos, CUnit* u);
+ std::list<float3> dropSpots;
+ bool isFirstIteration;
+ float3 startingDropPos;
+ float3 lastDropPos;
+ float3 approachVector; //direction from which we travel to drop point
+ float3 endDropPos;
};
Index: Sim/Units/Unit.cpp
===================================================================
--- Sim/Units/Unit.cpp (revision 4358)
+++ Sim/Units/Unit.cpp (working copy)
@@ -107,6 +107,8 @@
rightdir(-1,0,0),
updir(0,1,0),
upright(true),
+ falling(false),
+ fallSpeed(0.2),
maxRange(0),
haveTarget(false),
lastAttacker(0),
@@ -355,6 +357,17 @@
}
+void CUnit::Drop(float3 parentPos,float3 parentDir, CUnit* parent) {
+ //drop unit from position
+
+ this->fallSpeed = this->unitDef->unitFallSpeed > 0 ? this->unitDef->unitFallSpeed : parent->unitDef->fallSpeed;
+ float landingHeight = ground->GetApproximateHeight(pos.x, pos.z);
+ falling = true;
+ this->pos.y = parentPos.y - height;
+ this->frontdir = parentDir;
+ this->frontdir.y = 0;
+ this->speed.y = 0;
+}
void CUnit::EnableScriptMoveType()
{
if (usingScriptMoveType) {
@@ -2251,6 +2264,8 @@
CR_MEMBER(tooltip),
CR_MEMBER(crashing),
CR_MEMBER(isDead),
+ CR_MEMBER(falling),
+ CR_MEMBER(fallSpeed),
CR_MEMBER(bonusShieldDir),
CR_MEMBER(bonusShieldSaved),
Index: Sim/Units/Unit.h
===================================================================
--- Sim/Units/Unit.h (revision 4358)
+++ Sim/Units/Unit.h (working copy)
@@ -289,6 +289,8 @@
bool crashing;
bool isDead; //prevent damage from hitting an already dead unit (causing multi wreck etc)
+ bool falling; //for units being dropped from transports (parachute drops)
+ float fallSpeed;
float3 bonusShieldDir; //units takes less damage when attacked from this dir (encourage flanking fire)
float bonusShieldSaved; //how much the bonus shield can turn upon an attack(zeroed when attacked, slowly increase)
@@ -357,6 +359,7 @@
virtual void IncomingMissile(CMissileProjectile* missile);
void TempHoldFire(void);
void ReleaseTempHoldFire(void);
+ void Drop(float3 parentPos,float3 parentDir,CUnit* parent); //start this unit in freefall from parent unit
virtual void DrawS3O(void);
void PostLoad();
static void hitByWeaponIdCallback(int retCode, void *p1, void *p2);
Index: Sim/Units/UnitDef.h
===================================================================
--- Sim/Units/UnitDef.h (revision 4358)
+++ Sim/Units/UnitDef.h (working copy)
@@ -285,6 +285,9 @@
bool holdSteady;
bool releaseHeld;
bool transportByEnemy;
+ int transportUnloadMethod; //0 - land unload, 1 - flyover drop, 2 - land flood
+ float fallSpeed; //dictates fall speed of all transported units
+ float unitFallSpeed; //sets the transported units fbi, overrides fallSpeed
bool canCloak; //if the unit can cloak
bool startCloaked; //if the units want to start out cloaked
Index: Sim/Units/UnitDefHandler.cpp
===================================================================
--- Sim/Units/UnitDefHandler.cpp (revision 4358)
+++ Sim/Units/UnitDefHandler.cpp (working copy)
@@ -366,6 +366,9 @@
ud.holdSteady = udTable.GetBool("holdSteady", true);
ud.releaseHeld = udTable.GetBool("releaseHeld", false);
ud.transportByEnemy = udTable.GetBool("transportByEnemy", true);
+ ud.transportUnloadMethod = udTable.GetInt("transportUnloadMethod" , 0); //0 normal, 1 parachute drop, 2 land flood
+ ud.fallSpeed = udTable.GetFloat("fallSpeed", 0.2); //drop speed for all units dropped from this transport
+ ud.unitFallSpeed = udTable.GetFloat("unitFallSpeed", 0); //specific unit drop speed, overrides fallSpeed
ud.wingDrag = udTable.GetFloat("wingDrag", 0.07f); // drag caused by wings
ud.wingAngle = udTable.GetFloat("wingAngle", 0.08f); // angle between front and the wing plane
Index: Sim/Units/UnitTypes/TransportUnit.cpp
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.cpp (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.cpp (working copy)
@@ -219,3 +219,79 @@
}
}
}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit, float3 pos) {
+
+ if(unit->transporter != this)
+ return;
+
+ for (list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if (ti->unit==unit) {
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ loshandler->MoveUnit(unit,false);
+
+ //add an additional move command for after we land
+ Command c;
+ c.id=CMD_MOVE;
+ c.params.push_back(pos.x);
+ c.params.push_back(pos.y);
+ c.params.push_back(pos.z);
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+
+}
+
+void CTransportUnit::DetachUnitFromAir(CUnit* unit)
+{
+ if(unit->transporter != this)
+ return;
+
+ for(list<TransportedUnit>::iterator ti=transported.begin();ti!=transported.end();++ti){
+ if(ti->unit==unit){
+ this->DeleteDeathDependence(unit);
+ unit->DeleteDeathDependence(this);
+ unit->transporter=0;
+ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(moveType))
+ unit->moveType->useHeading=true;
+ unit->stunned=false; // de-stun in case it isfireplatform=0
+ unit->Block();
+
+ loshandler->MoveUnit(unit,false);
+
+ Command c;
+ c.id=CMD_STOP;
+ unit->commandAI->GiveCommand(c);
+
+ transportCapacityUsed-=ti->size;
+ transportMassUsed-=ti->mass;
+ transported.erase(ti);
+
+ unit->Drop(this->pos,this->frontdir,this);
+ unit->moveType->LeaveTransport();
+ unit->CalculateTerrainType();
+ unit->UpdateTerrainType();
+ luaCallIns.UnitUnloaded(unit, this);
+
+ break;
+ }
+ }
+}
\ No newline at end of file
Index: Sim/Units/UnitTypes/TransportUnit.h
===================================================================
--- Sim/Units/UnitTypes/TransportUnit.h (revision 4358)
+++ Sim/Units/UnitTypes/TransportUnit.h (working copy)
@@ -33,6 +33,8 @@
void AttachUnit(CUnit* unit, int piece);
void DetachUnit(CUnit* unit);
bool CanTransport(CUnit* unit);
+ void DetachUnitFromAir(CUnit* unit,float3 pos); //moves to position after
+ void DetachUnitFromAir(CUnit* unit);
};
|
---|