2025-07-18 06:25 CEST

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0000630Spring engineGeneralpublic2007-09-22 16:46
Reporterrusty 
Assigned Toimbaczek 
PrioritynormalSeverityfeatureReproducibilityalways
StatusresolvedResolutionfixed 
Product Version 
Target VersionFixed in Version 
Summary0000630: Patch for 2 new transport unload methods
Description
FBI Tags added:
    transportUnloadMethod = <integer>;
    0 - land unload, 1 - flyover drop, 2 - land flood
 
classes modified:
    UnitDefHandler,UnitDef,GroundMoveType, TransportCAI, Unit, transportUnit

known bugs: land transports using the land flood method, always unload to the same spot rather than spreading the units out, this is minor and still provides a faster means of unloading
TagsNo tags attached.
Checked infolog.txt for Errors
Attached Files
  • diff file icon 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);
     };
     
    
    diff file icon newTransportMethods 0.17.diff (40,783 bytes) 2007-09-11 23:56 +
  • diff file icon 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);
     };
     
    
    diff file icon newTransportMethods 0.18.diff (44,783 bytes) 2007-09-16 17:49 +
  • diff file icon 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);
     };
     
     
    
    diff file icon newTransportMethods 0.19 .diff (35,981 bytes) 2007-09-16 23:03 +
  • diff file icon 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);
     };
     
     
    
    diff file icon newTransportMethods 0.20 .diff (36,841 bytes) 2007-09-17 22:29 +
  • diff file icon 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);
     };
     
     
    
    diff file icon newTransportMethods 0.21 .diff (37,194 bytes) 2007-09-22 15:18 +
  • diff file icon 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);
     };
     
     
    
    diff file icon newTransportMethods 0.22 .diff (37,213 bytes) 2007-09-22 15:27 +

-Relationships
+Relationships

-Notes

~0001250

Argh (reporter)

Please commit, I'd like to test and evaluate these methods.

~0001254

rusty (reporter)

Additional information I forgot to mention:

Para-dropped units call the cob scripts 'falling' and 'landed' so that you may start and stop a falling animation.

~0001255

KDR_11k (reporter)

Argh, compile a custom build.

~0001256

imbaczek (reporter)

the patch has some broken whitespace, please fix that. also, it doesn't export new attributes to Lua, which may be a problem.

~0001258

rusty (reporter)

Admittedly, this patch only has the core functionality implemented - to show what is being done. There are afew other minor aesthetics and tags I need to add - such as the drop speed of the transported units and preventing units being occasionally bunched up together when being air dropped.

I'll look into adding lua properties.

~0001259

KDR_11k (reporter)

Aren't new attributes always available to Lua in the SVN because they're read by the Lua parser?

~0001261

imbaczek (reporter)

I don't know TBH. Better to be on the safe side until trepan confirms/denies.

~0001264

rusty (reporter)

Last edited: 2007-09-16 17:58

[new transport methods patch v 0.18]
    
Added tags:
transportUnloadMethod = <integer>;
    0 - land unload, 1 - flyover drop, 2 - land flood

fallSpeed = <float>
unitFallSpeed = <float>

These dictate the speed of units being dropped from the transport.
fallSpeed is used on the transports fbi file, to dictate the speed of all units it drops, unitFallSpeed is used on each transported unit to override fallSpeed.

Transport AI now calls the cob function:
'StartUnload'
which is called once when transport starts to lower during land flood method.

Dropped units call the cob functions:
'falling' and 'landed' so that you may start and stop a parachute animation.
                    

Added lua properties for transportUnloadMethod, fallSpeed, and unitFallSpeed.

~0001265

imbaczek (reporter)

there still are is some whitespace stuff, e.g. look at this hunk:

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),

the only difference is that in your patch there's some trailing whitespace. there's more of that.

also, in general, be conservative in changing whitespace like that:

- 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);

it was perfectly fine as it was, makes the patch bloated and doesn't do anything useful.

yes, I'm picky ^_^

there are some legitimate whitespace changes, too, e.g.

@@ -549,7 +566,7 @@
     }
 
     owner->frontdir = GetVectorFromHeading(heading);
- if(owner->upright){
+ if(owner->upright) {

but in general, it makes the patch harder to review.

~0001268

rusty (reporter)

Removed all the white space, and generally tidied things up.
Good to go?

~0001269

imbaczek (reporter)

almost good. you didn't add CR_MEMBER declarations for new unit, cai and movetype members, this will break savegames and possibly some other stuff.

other than that, it looks good. when you add the missing cr_members, I think I'll commit that so the modders can play around with this a bit.

~0001271

rusty (reporter)

CR_MEMBER declarations added for all public variables.

~0001272

imbaczek (reporter)

I'm not sure if public is enough. Private stuff needs to be serialized, too.

~0001285

rusty (reporter)

Last edited: 2007-09-22 15:28

CR_MEMBER declarations added for All members, and jitter seen on flying/falling ground units has been resolved.

~0001287

imbaczek (reporter)

committed in r4424, thanks.

modders, please test.
+Notes

-Issue History
Date Modified Username Field Change
2007-09-11 23:56 rusty New Issue
2007-09-11 23:56 rusty File Added: newTransportMethods 0.17.diff
2007-09-12 01:55 Argh Note Added: 0001250
2007-09-12 23:05 rusty Note Added: 0001254
2007-09-13 12:55 KDR_11k Note Added: 0001255
2007-09-14 12:01 imbaczek Note Added: 0001256
2007-09-14 21:38 rusty Note Added: 0001258
2007-09-15 11:30 KDR_11k Note Added: 0001259
2007-09-15 13:38 imbaczek Note Added: 0001261
2007-09-16 17:49 rusty File Added: newTransportMethods 0.18.diff
2007-09-16 17:58 rusty Note Added: 0001264
2007-09-16 17:58 rusty Note Edited: 0001264
2007-09-16 18:13 imbaczek Note Added: 0001265
2007-09-16 23:03 rusty File Added: newTransportMethods 0.19 .diff
2007-09-16 23:04 rusty Note Added: 0001268
2007-09-17 02:45 imbaczek Note Added: 0001269
2007-09-17 22:29 rusty File Added: newTransportMethods 0.20 .diff
2007-09-17 22:29 rusty Note Added: 0001271
2007-09-18 02:14 imbaczek Note Added: 0001272
2007-09-22 15:18 rusty File Added: newTransportMethods 0.21 .diff
2007-09-22 15:20 rusty Note Added: 0001285
2007-09-22 15:27 rusty File Added: newTransportMethods 0.22 .diff
2007-09-22 15:28 rusty Note Edited: 0001285
2007-09-22 16:45 imbaczek Note Added: 0001287
2007-09-22 16:46 imbaczek Status new => resolved
2007-09-22 16:46 imbaczek Resolution open => fixed
2007-09-22 16:46 imbaczek Assigned To => imbaczek
+Issue History