int CTransportCAI::GetDefaultCmd(CUnit* pointed, CFeature* feature)
{
	if (pointed) {
		if (!gs->Ally(gu->myAllyTeam, pointed->allyteam)) {
			if (owner->unitDef->canAttack) {
				return CMD_ATTACK;
			} else if (CanTransport(pointed)) {
				return CMD_LOAD_UNITS; // comm napping?
			}
		} else {
			if (CanTransport(pointed)) {
				return CMD_LOAD_UNITS;
			} else if (owner->unitDef->canGuard) {
				return CMD_GUARD;
			}
		}
	}
//	if(((CTransportUnit*)owner)->transported.empty())
	if (owner->unitDef->canmove) {
		return CMD_MOVE;
	} else {
		return CMD_STOP;
	}
//	else
//		return CMD_UNLOAD_UNITS;
}
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
	CUnit* bestUnit = NULL;
	float bestDist = std::numeric_limits<float>::max();

	const std::vector<CUnit*>& units = quadField->GetUnitsExact(center, radius);

	for (std::vector<CUnit*>::const_iterator ui = units.begin(); ui != units.end(); ++ui) {
		CUnit* unit = (*ui);
		float dist = unit->pos.SqDistance2D(owner->pos);

		if (unit->loadingTransportId != -1 && unit->loadingTransportId != owner->id) {
			CUnit* trans = unitHandler->GetUnitUnsafe(unit->loadingTransportId);
			if ((trans != NULL) && teamHandler->AlliedTeams(owner->team, trans->team)) {
				continue; // don't refuse to load comm only because the enemy is trying to nap it at the same time
			}
		}
		if (dist >= bestDist)
			continue;
		if (!CanTransport(unit))
			continue;

		if (unit->losStatus[owner->allyteam] & (LOS_INRADAR | LOS_INLOS)) {
			bestDist = dist;
			bestUnit = unit;
		}
	}

	return bestUnit;
}
void CTransportUnit::AttachUnit(CUnit* unit, int piece)
{
	DetachUnit(unit);

	if (!CanTransport(unit))
		return;

	AddDeathDependence(unit);
	unit->AddDeathDependence (this);
	unit->transporter = this;
	unit->toBeTransported=false;
	if (!unitDef->isfireplatform) {
		unit->stunned=true;	//make sure unit doesnt fire etc in transport
		selectedUnits.RemoveUnit(unit);
	}
	unit->UnBlock();
	loshandler->FreeInstance(unit->los);
	unit->los=0;
	if (dynamic_cast<CTAAirMoveType*>(moveType)) {
		unit->moveType->useHeading=false;
	}
	TransportedUnit tu;
	tu.unit=unit;
	tu.piece=piece;
	tu.size=unit->xsize/2;
	tu.mass=unit->mass;
	transportCapacityUsed+=tu.size;
	transportMassUsed+=tu.mass;
	transported.push_back(tu);

	unit->CalculateTerrainType();
	unit->UpdateTerrainType();

	luaCallIns.UnitLoaded(unit, this);
}
int CTransportCAI::GetDefaultCmd(const CUnit* pointed, const CFeature* feature)
{
	if (pointed) {
		if (!teamHandler->Ally(gu->myAllyTeam, pointed->allyteam)) {
			if (owner->unitDef->canAttack) {
				return CMD_ATTACK;
			} else if (CanTransport(pointed)) {
				return CMD_LOAD_UNITS; // comm napping?
			}
		} else {
			if (CanTransport(pointed)) {
				return CMD_LOAD_UNITS;
			} else if (owner->unitDef->canGuard) {
				return CMD_GUARD;
			}
		}
	}

	if (owner->unitDef->canmove) {
		return CMD_MOVE;
	}

	return CMD_STOP;
}
CUnit* CTransportCAI::FindUnitToTransport(float3 center, float radius)
{
	CUnit* best=0;
	float bestDist=100000000;
	std::vector<CUnit*> units=qf->GetUnitsExact(center,radius);
	for(std::vector<CUnit*>::iterator ui=units.begin();ui!=units.end();++ui){
		CUnit* unit=(*ui);
		float dist=unit->pos.distance2D(owner->pos);
		if(CanTransport(unit) && dist<bestDist && !unit->toBeTransported){
			bestDist=dist;
			best=unit;
		}
	}
	return best;
}
int CTransportCAI::GetDefaultCmd(CUnit* pointed,CFeature* feature)
{
	if(pointed){
		if(!gs->Ally(gu->myAllyTeam,pointed->allyteam)){
			return CMD_ATTACK;
		} else {
			if(CanTransport(pointed))
				return CMD_LOAD_UNITS;
			else
				return CMD_GUARD;
		}
	}
//	if(((CTransportUnit*)owner)->transported.empty())
		return CMD_MOVE;
//	else
//		return CMD_UNLOAD_UNITS;
}
/**
**  Wait for transporter.
**
**  @param unit  Pointer to unit.
**
**  @return      True if ship arrived/present, False otherwise.
*/
static int WaitForTransporter(CUnit *unit)
{
	CUnit *trans;

	if (unit->Wait) {
		unit->Wait--;
		return 0;
	}

	trans = unit->Orders[0]->Goal;

	if (!trans || !CanTransport(trans, unit)) {
		// FIXME: destination destroyed??
		unit->Wait = 6;
		return 0;
	}

	if (!trans->IsVisibleAsGoal(unit->Player)) {
		DebugPrint("Transporter Gone\n");
		trans->RefsDecrease();
		unit->Orders[0]->Goal = NoUnitP;
		unit->Wait = 6;
		return 0;
	}

	if (MapDistanceBetweenUnits(unit, trans) == 1) {
		// enter transporter
		return 1;
	}

	//
	// FIXME: any enemies in range attack them, while waiting.
	//

	// n0b0dy: This means we have to search with a smaller range.
	// It happens only when you reach the shore,and the transporter
	// is not there. The unit searches with a big range, so it thinks
	// it's there. This is why we reset the search. The transporter
	// should be a lot closer now, so it's not as bad as it seems.
	unit->SubAction = 0;
	unit->Orders[0]->Range = 1;
	// Uhh wait a bit.
	unit->Wait = 10;

	return 0;
}
Exemple #8
0
/**
**  Wait for transporter.
**
**  @param unit  Pointer to unit.
**
**  @return      True if ship arrived/present, False otherwise.
*/
bool COrder_Board::WaitForTransporter(CUnit &unit)
{

	if (unit.Wait) {
		unit.Wait--;
		return false;
	}

	const CUnit *trans = this->GetGoal();

	if (!trans || !CanTransport(*trans, unit)) {
		// FIXME: destination destroyed??
		unit.Wait = 6;
		return false;
	}

	if (!trans->IsVisibleAsGoal(*unit.Player)) {
		DebugPrint("Transporter Gone\n");
		this->ClearGoal();
		unit.Wait = 6;
		return false;
	}

	if (unit.MapDistanceTo(*trans) == 1) {
		// enter transporter
		return true;
	}

	// FIXME: any enemies in range attack them, while waiting.

	// n0b0dy: This means we have to search with a smaller range.
	// It happens only when you reach the shore,and the transporter
	// is not there. The unit searches with a big range, so it thinks
	// it's there. This is why we reset the search. The transporter
	// should be a lot closer now, so it's not as bad as it seems.
	this->State = State_Init;
	this->Range = 1;
	// Uhh wait a bit.
	unit.Wait = 10;

	return false;
}
Exemple #9
0
/**
**  Load all unit before attack.
**
**  @param aiForce force to group.
*/
static void AiGroupAttackerForTransport(AiForce &aiForce)
{
	Assert(aiForce.State == AiForceAttackingState_Boarding);

	unsigned int nbToTransport = 0;
	unsigned int transporterIndex = 0;
	bool forceIsReady = true;

	for (; transporterIndex < aiForce.Size(); ++transporterIndex) {
		const CUnit &unit = *aiForce.Units[transporterIndex];

		if (unit.Type->CanTransport() && unit.Type->MaxOnBoard - unit.BoardCount > 0) {
			nbToTransport = unit.Type->MaxOnBoard - unit.BoardCount;
			break;
		}
	}
	if (transporterIndex == aiForce.Size()) {
		aiForce.State = AiForceAttackingState_AttackingWithTransporter;
		return ;
	}
	for (unsigned int i = 0; i < aiForce.Size(); ++i) {
		const CUnit &unit = *aiForce.Units[i];
		const CUnit &transporter = *aiForce.Units[transporterIndex];

		if (CanTransport(transporter, unit) && unit.Container == NULL) {
			forceIsReady = false;
			break;
		}
	}
	if (forceIsReady == true) {
		aiForce.State = AiForceAttackingState_AttackingWithTransporter;
		return ;
	}
	for (unsigned int i = 0; i < aiForce.Size(); ++i) {
		CUnit &unit = *aiForce.Units[i];
		CUnit &transporter = *aiForce.Units[transporterIndex];

		if (unit.CurrentAction() == UnitActionBoard
			&& static_cast<COrder_Board *>(unit.CurrentOrder())->GetGoal() == &transporter) {
			CommandFollow(transporter, unit, 0);
		}
		if (CanTransport(transporter, unit) && (unit.IsIdle() 
			|| (unit.CurrentAction() == UnitActionBoard && !unit.Moving 
			&& static_cast<COrder_Board *>(unit.CurrentOrder())->GetGoal() != &transporter)) && unit.Container == NULL) {
				CommandBoard(unit, transporter, FlushCommands);
				CommandFollow(transporter, unit, 0);
				if (--nbToTransport == 0) { // full : next transporter.
					for (++transporterIndex; transporterIndex < aiForce.Size(); ++transporterIndex) {
						const CUnit &nextTransporter = *aiForce.Units[transporterIndex];

						if (nextTransporter.Type->CanTransport()) {
							nbToTransport = nextTransporter.Type->MaxOnBoard - nextTransporter.BoardCount;
							break ;
						}
					}
					if (transporterIndex == aiForce.Size()) { // No more transporter.
						break ;
					}
				}
		}
	}
}
void CTransportCAI::ExecuteLoadUnits(Command& c)
{
	CTransportUnit* transport = reinterpret_cast<CTransportUnit*>(owner);

	if (c.params.size() == 1) {
		// load single unit
		CUnit* unit = unitHandler->GetUnit(c.params[0]);

		if (unit == NULL) {
			FinishCommand();
			return;
		}

		if (c.options & INTERNAL_ORDER) {
			if (unit->commandAI->commandQue.empty()) {
				if (!LoadStillValid(unit)) {
					FinishCommand();
					return;
				}
			} else {
				Command& currentUnitCommand = unit->commandAI->commandQue[0];

				if ((currentUnitCommand.GetID() == CMD_LOAD_ONTO) && (currentUnitCommand.params.size() == 1) && (int(currentUnitCommand.params[0]) == owner->id)) {
					if ((unit->moveType->progressState == AMoveType::Failed) && (owner->moveType->progressState == AMoveType::Failed)) {
						unit->commandAI->FinishCommand();
						FinishCommand();
						return;
					}
				} else if (!LoadStillValid(unit)) {
					FinishCommand();
					return;
				}
			}
		}

		if (inCommand) {
			if (!owner->script->IsBusy()) {
				FinishCommand();
			}
			return;
		}
		if (unit != NULL && CanTransport(unit) && UpdateTargetLostTimer(int(c.params[0]))) {
			SetTransportee(unit);

			const float sqDist = unit->pos.SqDistance2D(owner->pos);
			const bool inLoadingRadius = (sqDist <= Square(owner->unitDef->loadingRadius));

			CTransportUnit* trans = static_cast<CTransportUnit*>(owner);
			CHoverAirMoveType* am = dynamic_cast<CHoverAirMoveType*>(owner->moveType);

			// subtract 1 square to account for PFS/GMT inaccuracy
			const bool outOfRange = (goalPos.SqDistance2D(unit->pos) > Square(owner->unitDef->loadingRadius - SQUARE_SIZE));
			const bool moveCloser = (!inLoadingRadius && (!owner->IsMoving() || (am != NULL && am->aircraftState != AAirMoveType::AIRCRAFT_FLYING)));

			if (outOfRange || moveCloser) {
				SetGoal(unit->pos, owner->pos, std::min(64.0f, owner->unitDef->loadingRadius));
			}

			if (inLoadingRadius) {
				if (am != NULL) {
					// handle air transports differently
					float3 wantedPos = unit->pos;
					wantedPos.y = trans->GetTransporteeWantedHeight(wantedPos, unit);

					// calls am->StartMoving() which sets forceHeading to false (and also
					// changes aircraftState, possibly in mid-pickup) --> must check that
					// wantedPos == goalPos using some epsilon tolerance
					// we do not want the forceHeading change at point of pickup because
					// am->UpdateHeading() will suddenly notice a large deltaHeading and
					// break the DOCKING_ANGLE constraint so call am->ForceHeading() next
					SetGoal(wantedPos, owner->pos, 1.0f);

					am->ForceHeading(trans->GetTransporteeWantedHeading(unit));
					am->SetWantedAltitude(wantedPos.y - CGround::GetHeightAboveWater(wantedPos.x, wantedPos.z));
					am->maxDrift = 1.0f;

					// FIXME: kill the hardcoded constants, use the command's radius
					const bool b1 = (owner->pos.SqDistance(wantedPos) < Square(AIRTRANSPORT_DOCKING_RADIUS));
					const bool b2 = (std::abs(owner->heading - unit->heading) < AIRTRANSPORT_DOCKING_ANGLE);
					const bool b3 = (owner->updir.dot(UpVector) > 0.995f);

					if (b1 && b2 && b3) {
						am->SetAllowLanding(false);
						am->SetWantedAltitude(0.0f);

						owner->script->BeginTransport(unit);
						SetTransportee(NULL);
						transport->AttachUnit(unit, owner->script->QueryTransport(unit));

						FinishCommand();
						return;
					}
				} else {
					inCommand = true;

					StopMove();
					owner->script->TransportPickup(unit);
				}
			} else if (owner->moveType->progressState == AMoveType::Failed && sqDist < (200 * 200)) {
				// if we're pretty close already but CGroundMoveType fails because it considers
				// the goal clogged (with the future passenger...), just try to move to the
				// point halfway between the transport and the passenger.
				SetGoal((unit->pos + owner->pos) * 0.5f, owner->pos);
			}
		} else {
			FinishCommand();
		}
	} else if (c.params.size() == 4) { // area-load
		if (lastCall == gs->frameNum) { // avoid infinite loops
			return;
		}

		lastCall = gs->frameNum;

		const float3 pos = c.GetPos(0);
		const float radius = c.params[3];

		CUnit* unit = FindUnitToTransport(pos, radius);

		if (unit && CanTransport(unit)) {
			Command c2(CMD_LOAD_UNITS, c.options|INTERNAL_ORDER, unit->id);
			commandQue.push_front(c2);
			inCommand = false;

			SlowUpdate();
			return;
		} else {
			FinishCommand();
			return;
		}
	}

	isFirstIteration = true;
	startingDropPos = -OnesVector;
}
void CTransportCAI::SlowUpdate(void)
{
	if(commandQue.empty()){
		CMobileCAI::SlowUpdate();
		return;
	}

	CTransportUnit* transport=(CTransportUnit*)owner;
	Command& c=commandQue.front();
	switch(c.id){
	case CMD_LOAD_UNITS:
		if(c.params.size()==1){		//load single unit
			if(transport->transportCapacityUsed >= owner->unitDef->transportCapacity){
				FinishCommand();
				return;
			}
			if(inCommand){
				if(!owner->cob->busy)
					FinishCommand();
				return;
			}
			CUnit* unit=uh->units[(int)c.params[0]];
			if(unit && CanTransport(unit)){
				toBeTransportedUnitId=unit->id;
				unit->toBeTransported=true;
				if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass){
					FinishCommand();
					return;
				}
				if(goalPos.distance2D(unit->pos)>10){
					float3 fix = unit->pos;
					SetGoal(fix,owner->pos,64);
				}
				if(unit->pos.distance2D(owner->pos)<owner->unitDef->loadingRadius*0.9){
					if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){		//handle air transports differently
						float3 wantedPos=unit->pos+UpVector*unit->model->height;
						SetGoal(wantedPos,owner->pos);
						am->dontCheckCol=true;
						am->ForceHeading(unit->heading);
						am->SetWantedAltitude(unit->model->height);
						am->maxDrift=1;
						//info->AddLine("cai dist %f %f %f",owner->pos.distance(wantedPos),owner->pos.distance2D(wantedPos),owner->pos.y-wantedPos.y);
						if(owner->pos.distance(wantedPos)<4 && abs(owner->heading-unit->heading)<50 && owner->updir.dot(UpVector)>0.995){
							am->dontCheckCol=false;
							am->dontLand=true;
							std::vector<int> args;
							args.push_back((int)(unit->model->height*65536));
							owner->cob->Call("BeginTransport",args);
							std::vector<int> args2;
							args2.push_back(0);
							args2.push_back((int)(unit->model->height*65536));
							owner->cob->Call("QueryTransport",args2);
							((CTransportUnit*)owner)->AttachUnit(unit,args2[0]);
							am->SetWantedAltitude(0);
							FinishCommand();
							return;
						}
					} else {
						inCommand=true;
						scriptReady=false;
						StopMove();
						std::vector<int> args;
						args.push_back(unit->id);
						owner->cob->Call("TransportPickup",args,ScriptCallback,this,0);
					}
				}
			} else {
				FinishCommand();
			}
		} else if(c.params.size()==4){		//load in radius
			if(lastCall==gs->frameNum)	//avoid infinite loops
				return;
			lastCall=gs->frameNum;
			float3 pos(c.params[0],c.params[1],c.params[2]);
			float radius=c.params[3];
			CUnit* unit=FindUnitToTransport(pos,radius);
			if(unit && ((CTransportUnit*)owner)->transportCapacityUsed < owner->unitDef->transportCapacity){
				Command c2;
				c2.id=CMD_LOAD_UNITS;
				c2.params.push_back(unit->id);
				c2.options=c.options | INTERNAL_ORDER;
				commandQue.push_front(c2);
				inCommand=false;
				SlowUpdate();
				return;
			} else {
				FinishCommand();
				return;
			}
		}
		break;
	case CMD_UNLOAD_UNITS:{
		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;
		bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found);
		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();
		}
		break;}
	case CMD_UNLOAD_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]);
			if(goalPos.distance2D(pos)>20){
				SetGoal(pos,owner->pos);
			}
			if(pos.distance2D(owner->pos)<owner->unitDef->loadingRadius*0.9){
				if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){		//handle air transports differently
					pos.y=ground->GetHeight(pos.x,pos.z);
					CUnit* unit=((CTransportUnit*)owner)->transported.front().unit;
					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.99){
						am->dontLand=false;
						owner->cob->Call("EndTransport");
						((CTransportUnit*)owner)->DetachUnit(unit);
						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(((CTransportUnit*)owner)->transported.front().unit->id);
					args.push_back(PACKXZ(pos.x, pos.z));
					owner->cob->Call("TransportDrop",args,ScriptCallback,this,0);
				}
			}
		}
		break;
	default:
		CMobileCAI::SlowUpdate();
		break;
	}
}
Exemple #12
0
void CTransportUnit::AttachUnit(CUnit* unit, int piece)
{
	assert(unit != this);

	if (unit->transporter == this) {
		// assume we are already transporting this unit,
		// and just want to move it to a different piece
		// with script logic (this means the UnitLoaded
		// event is only sent once)
		std::list<TransportedUnit>::iterator transporteesIt;

		for (transporteesIt = transportedUnits.begin(); transporteesIt != transportedUnits.end(); ++transporteesIt) {
			TransportedUnit& tu = *transporteesIt;

			if (tu.unit == unit) {
				tu.piece = piece;
				break;
			}
		}

		return;
	} else {
		// handle transfers from another transport to us
		// (can still fail depending on CanTransport())
		if (unit->transporter != NULL) {
			unit->transporter->DetachUnit(unit);
		}
	}

	// covers the case where unit->transporter != NULL
	if (!CanTransport(unit)) {
		return;
	}

	AddDeathDependence(unit, DEPENDENCE_TRANSPORTEE);
	unit->AddDeathDependence(this, DEPENDENCE_TRANSPORTER);

	unit->transporter = this;
	unit->toBeTransported = false;
	unit->stunned = !unitDef->isFirePlatform;

	if (unit->stunned) {
		// make sure unit does not fire etc in transport
		selectedUnits.RemoveUnit(unit);
	}

	unit->UnBlock();
	loshandler->FreeInstance(unit->los);
	radarhandler->RemoveUnit(unit);

	// do not remove unit from QF, otherwise projectiles
	// will not be able to connect with (ie. damage) it
	//
	// for NON-stunned transportees, QF position is kept
	// up-to-date by MoveType::SlowUpdate, otherwise by
	// ::Update
	//
	// qf->RemoveUnit(unit);

	unit->los = NULL;

	if (CBuilding* building = dynamic_cast<CBuilding*>(unit)) {
		unitLoader->RestoreGround(unit);
		groundDecals->RemoveBuilding(building, NULL);
	}

	if (dynamic_cast<CHoverAirMoveType*>(moveType)) {
		unit->moveType->useHeading = false;
	}

	TransportedUnit tu;
		tu.unit = unit;
		tu.piece = piece;
		tu.size = unit->xsize / 2;
		tu.mass = unit->mass;

	transportCapacityUsed += tu.size;
	transportMassUsed += tu.mass;
	transportedUnits.push_back(tu);

	unit->CalculateTerrainType();
	unit->UpdateTerrainType();

	eventHandler.UnitLoaded(unit, this);
	commandAI->BuggerOff(pos, -1.0f); // make sure not to get buggered off :) by transportee
}
void CTransportCAI::ExecuteLoadUnits(Command &c)
{
	CTransportUnit* transport=(CTransportUnit*)owner;
	if(c.params.size()==1){		//load single unit
		if(transport->transportCapacityUsed >= owner->unitDef->transportCapacity){
			FinishCommand();
			return;
		}
		CUnit* unit=uh->units[(int)c.params[0]];
		if (!unit) {
			FinishCommand();
			return;
		}
		if(c.options & INTERNAL_ORDER) {
			if(unit->commandAI->commandQue.empty()){
				if(!LoadStillValid(unit)){
					FinishCommand();
					return;
				}
			} else {
				Command & currentUnitCommand = unit->commandAI->commandQue[0];
				if(currentUnitCommand.id == CMD_LOAD_ONTO && currentUnitCommand.params.size() == 1 && int(currentUnitCommand.params[0]) == owner->id){
					if((unit->moveType->progressState == CMoveType::Failed) && (owner->moveType->progressState == CMoveType::Failed)){
						unit->commandAI->FinishCommand();
						FinishCommand();
						return;
					}
				} else if(!LoadStillValid(unit)) {
					FinishCommand();
					return;
				}
			}
		}
		if(inCommand){
			if(!owner->cob->busy)
				FinishCommand();
			return;
		}
		if(unit && CanTransport(unit) && UpdateTargetLostTimer(int(c.params[0]))){
			toBeTransportedUnitId=unit->id;
			unit->toBeTransported=true;
			if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass){
				FinishCommand();
				return;
			}
			if(goalPos.distance2D(unit->pos)>10){
				float3 fix = unit->pos;
				SetGoal(fix,owner->pos,64);
			}
			if(unit->pos.distance2D(owner->pos)<owner->unitDef->loadingRadius*0.9f){
				if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){		//handle air transports differently
					float3 wantedPos=unit->pos+UpVector*unit->model->height;
					SetGoal(wantedPos,owner->pos);
					am->dontCheckCol=true;
					am->ForceHeading(unit->heading);
					am->SetWantedAltitude(unit->model->height);
					am->maxDrift=1;
					//logOutput.Print("cai dist %f %f %f",owner->pos.distance(wantedPos),owner->pos.distance2D(wantedPos),owner->pos.y-wantedPos.y);
					if(owner->pos.distance(wantedPos)<4 && abs(owner->heading-unit->heading)<50 && owner->updir.dot(UpVector)>0.995f){
						am->dontCheckCol=false;
						am->dontLand=true;
						std::vector<int> args;
						args.push_back((int)(unit->model->height*65536));
						owner->cob->Call("BeginTransport",args);
						std::vector<int> args2;
						args2.push_back(0);
						args2.push_back((int)(unit->model->height*65536));
						owner->cob->Call("QueryTransport",args2);
						((CTransportUnit*)owner)->AttachUnit(unit,args2[0]);
						am->SetWantedAltitude(0);
						FinishCommand();
						return;
					}
				} else {
					inCommand=true;
					scriptReady=false;
					StopMove();
					std::vector<int> args;
					args.push_back(unit->id);
					owner->cob->Call("TransportPickup",args,ScriptCallback,this,0);
				}
			}
		} else {
			FinishCommand();
		}
	} else if(c.params.size()==4){		//load in radius
		if(lastCall==gs->frameNum)	//avoid infinite loops
			return;
		lastCall=gs->frameNum;
		float3 pos(c.params[0],c.params[1],c.params[2]);
		float radius=c.params[3];
		CUnit* unit=FindUnitToTransport(pos,radius);
		if(unit && ((CTransportUnit*)owner)->transportCapacityUsed < owner->unitDef->transportCapacity){
			Command c2;
			c2.id=CMD_LOAD_UNITS;
			c2.params.push_back(unit->id);
			c2.options=c.options | INTERNAL_ORDER;
			commandQue.push_front(c2);
			inCommand=false;
			SlowUpdate();
			return;
		} else {
			FinishCommand();
			return;
		}
	}
	return;
}
Exemple #14
0
void CTransportCAI::ExecuteLoadUnits(Command& c)
{
	CTransportUnit* transport = reinterpret_cast<CTransportUnit*>(owner);

	if (c.params.size() == 1) {
		// load single unit
		CUnit* unit = unitHandler->GetUnit(c.params[0]);

		if (!unit) {
			FinishCommand();
			return;
		}
		if (c.options & INTERNAL_ORDER) {
			if (unit->commandAI->commandQue.empty()) {
				if (!LoadStillValid(unit)) {
					FinishCommand();
					return;
				}
			} else {
				Command& currentUnitCommand = unit->commandAI->commandQue[0];
				if ((currentUnitCommand.GetID() == CMD_LOAD_ONTO) && (currentUnitCommand.params.size() == 1) && (int(currentUnitCommand.params[0]) == owner->id)) {
					if ((unit->moveType->progressState == AMoveType::Failed) && (owner->moveType->progressState == AMoveType::Failed)) {
						unit->commandAI->FinishCommand();
						FinishCommand();
						return;
					}
				} else if (!LoadStillValid(unit)) {
					FinishCommand();
					return;
				}
			}
		}
		if (inCommand) {
			if (!owner->script->IsBusy()) {
				FinishCommand();
			}
			return;
		}
		if (unit && CanTransport(unit) && UpdateTargetLostTimer(int(c.params[0]))) {
			SetTransportee(unit);

			const float sqDist = unit->pos.SqDistance2D(owner->pos);
			const bool inLoadingRadius = (sqDist <= Square(owner->unitDef->loadingRadius));
			
			CHoverAirMoveType* am = dynamic_cast<CHoverAirMoveType*>(owner->moveType);

			// subtracting 1 square to account for pathfinder/groundmovetype inaccuracy
			if (goalPos.SqDistance2D(unit->pos) > Square(owner->unitDef->loadingRadius - SQUARE_SIZE) || 
				(!inLoadingRadius && (!owner->isMoving || (am && am->aircraftState != AAirMoveType::AIRCRAFT_FLYING)))) {
				SetGoal(unit->pos, owner->pos, std::min(64.0f, owner->unitDef->loadingRadius));
			}

			if (inLoadingRadius) {
				if (am) { // handle air transports differently
					float3 wantedPos = unit->pos;
					wantedPos.y = static_cast<CTransportUnit*>(owner)->GetLoadUnloadHeight(wantedPos, unit);
					SetGoal(wantedPos, owner->pos);

					am->loadingUnits = true;
					am->ForceHeading(static_cast<CTransportUnit*>(owner)->GetLoadUnloadHeading(unit));
					am->SetWantedAltitude(wantedPos.y - ground->GetHeightAboveWater(wantedPos.x, wantedPos.z));
					am->maxDrift = 1;

					if ((owner->pos.SqDistance(wantedPos) < Square(AIRTRANSPORT_DOCKING_RADIUS)) &&
						(abs(owner->heading-unit->heading) < AIRTRANSPORT_DOCKING_ANGLE) &&
						(owner->updir.dot(UpVector) > 0.995f))
					{
						am->loadingUnits = false;
						am->dontLand = true;

						owner->script->BeginTransport(unit);
						SetTransportee(NULL);
						transport->AttachUnit(unit, owner->script->QueryTransport(unit));
						am->SetWantedAltitude(0);

						FinishCommand();
						return;
					}
				} else {
					inCommand = true;

					StopMove();
					owner->script->TransportPickup(unit);
				}
			} else if (owner->moveType->progressState == AMoveType::Failed && sqDist < (200 * 200)) {
				// if we're pretty close already but CGroundMoveType fails because it considers
				// the goal clogged (with the future passenger...), just try to move to the
				// point halfway between the transport and the passenger.
				SetGoal((unit->pos + owner->pos) * 0.5f, owner->pos);
			}
		} else {
			FinishCommand();
		}
	} else if (c.params.size() == 4) { // area-load
		if (lastCall == gs->frameNum) { // avoid infinite loops
			return;
		}

		lastCall = gs->frameNum;

		const float3 pos = c.GetPos(0);
		const float radius = c.params[3];

		CUnit* unit = FindUnitToTransport(pos, radius);

		if (unit && CanTransport(unit)) {
			Command c2(CMD_LOAD_UNITS, c.options|INTERNAL_ORDER, unit->id);
			commandQue.push_front(c2);
			inCommand = false;

			SlowUpdate();
			return;
		} else {
			FinishCommand();
			return;
		}
	}

	isFirstIteration = true;
	startingDropPos = float3(-1.0f, -1.0f, -1.0f);
}