bool CTransportCAI::SpotIsClearIgnoreSelf(float3 pos, CUnit* unitToUnload) { if (!static_cast<CTransportUnit*>(owner)->CanLoadUnloadAtPos(pos, unitToUnload)) { return false; } if (unitToUnload->moveDef && ground->GetSlope(pos.x,pos.z) > unitToUnload->moveDef->maxSlope) { return false; } const std::vector<CUnit*>& units = quadField->GetUnitsExact(pos, std::max(1.0f, math::ceil(unitToUnload->radius / SQUARE_SIZE)) * SQUARE_SIZE); CTransportUnit* me = static_cast<CTransportUnit*>(owner); for (std::vector<CUnit*>::const_iterator it = units.begin(); it != units.end(); ++it) { // check if the units are in the transport bool found = false; for (std::list<CTransportUnit::TransportedUnit>::const_iterator it2 = me->GetTransportedUnits().begin(); it2 != me->GetTransportedUnits().end(); ++it2) { if (it2->unit == *it) { found = true; break; } } if (!found && (*it != owner)) { return false; } } return true; }
void CUnitScript::DropUnit(int u) { #ifndef _CONSOLE CTransportUnit* tu = dynamic_cast<CTransportUnit*>(unit); if (tu && uh->units[u]) { tu->DetachUnit(uh->units[u]); } #endif }
void CTransportCAI::UnloadDrop(Command& c) { CTransportUnit* transport = static_cast<CTransportUnit*>(owner); // fly over and drop unit if (inCommand) { if (!owner->script->IsBusy()) { FinishCommand(); } } else { const std::list<CTransportUnit::TransportedUnit>& transportees = transport->GetTransportedUnits(); if (transportees.empty() || dropSpots.empty()) { FinishCommand(); return; } float3 pos = c.GetPos(0); // head towards goal // note that HoverAirMoveType must be modified to allow non stop movement // through goals for this to work well if (goalPos.SqDistance2D(pos) > 400) { SetGoal(pos, owner->pos); lastDropPos = pos; } CHoverAirMoveType* am = dynamic_cast<CHoverAirMoveType*>(owner->moveType); CUnit* transportee = (transportees.front()).unit; if (am != NULL) { pos.y = ground->GetHeightAboveWater(pos.x, pos.z); am->maxDrift = 1; // if near target or have past it accidentally- drop unit if (owner->pos.SqDistance2D(pos) < 1600 || (((pos - owner->pos).Normalize()).SqDistance(owner->frontdir.Normalize()) > 0.25 && owner->pos.SqDistance2D(pos)< (205*205))) { am->dontLand = true; owner->script->EndTransport(); transport->DetachUnitFromAir(transportee, pos); dropSpots.pop_back(); if (dropSpots.empty()) { SetGoal(owner->pos + owner->frontdir * 200, owner->pos); // move the transport away after last drop } FinishCommand(); } } else { inCommand = true; StopMove(); owner->script->TransportDrop(transportee, pos); } } }
void CUnitScript::AttachUnit(int piece, int u) { // -1 is valid, indicates that the unit should be hidden if ((piece >= 0) && (!PieceExists(piece))) { ShowScriptError("Invalid piecenumber for attach"); return; } #ifndef _CONSOLE CTransportUnit* tu = dynamic_cast<CTransportUnit*>(unit); if (tu && uh->units[u]) { tu->AttachUnit(uh->units[u], piece); } #endif }
bool CTransportCAI::FindEmptyDropSpots(float3 startpos, float3 endpos, std::list<float3>& dropSpots) { //should only be used by air CTransportUnit* transport = static_cast<CTransportUnit*>(owner); //dropSpots.clear(); float gap = 25.5; // TODO - set tag for this? float3 dir = endpos - startpos; dir.Normalize(); float3 nextPos = startpos; float3 pos; std::list<CTransportUnit::TransportedUnit>::const_iterator ti = transport->GetTransportedUnits().begin(); dropSpots.push_front(nextPos); // first spot if (ti != transport->GetTransportedUnits().end()) { nextPos += dir * (gap + ti->unit->radius); ++ti; } // remaining spots if (dynamic_cast<CHoverAirMoveType*>(owner->moveType)) { while (ti != transport->GetTransportedUnits().end() && startpos.SqDistance(nextPos) < startpos.SqDistance(endpos)) { nextPos += dir * (ti->unit->radius); nextPos.y = ground->GetHeightAboveWater(nextPos.x, nextPos.z); // check landing spot is ok for landing on if (!SpotIsClear(nextPos,ti->unit)) continue; dropSpots.push_front(nextPos); nextPos += dir * (gap + ti->unit->radius); ++ti; } return true; } return false; }
void CTransportCAI::UnloadLandFlood(Command& c) { //land, then release all units at once CTransportUnit* transport = static_cast<CTransportUnit*>(owner); CUnit* transportee = NULL; if (inCommand) { if (!owner->script->IsBusy()) { FinishCommand(); } } else { const std::list<CTransportUnit::TransportedUnit>& transportees = transport->GetTransportedUnits(); if (transportees.empty()) { FinishCommand(); return; } if (c.params.size() < 4) { transportee = (transportees.front()).unit; } else { const int unitID = c.params[3]; for (auto it = transportees.begin(); it != transportees.end(); ++it) { CUnit* carried = it->unit; if (unitID == carried->id) { transportee = carried; break; } } if (transportee == NULL) { FinishCommand(); return; } } // move to position float3 pos = c.GetPos(0); if (isFirstIteration) { if (goalPos.SqDistance2D(pos) > 400) { SetGoal(startingDropPos, owner->pos); } } if (startingDropPos.SqDistance2D(owner->pos) < Square(owner->unitDef->loadingRadius * 0.9f)) { CHoverAirMoveType* am = dynamic_cast<CHoverAirMoveType*>(owner->moveType); if (am != NULL) { // lower to ground startingDropPos.y = CGround::GetHeightAboveWater(startingDropPos.x, startingDropPos.z); const float3 wantedPos = startingDropPos + UpVector * transportee->model->height; SetGoal(wantedPos, owner->pos); am->SetWantedAltitude(1.0f); am->SetAllowLanding(true); am->maxDrift = 1.0f; // when on our way down start animations for unloading gear if (isFirstIteration) { owner->script->StartUnload(); } isFirstIteration = false; // once at ground if (owner->pos.y - CGround::GetHeightAboveWater(wantedPos.x, wantedPos.z) < SQUARE_SIZE) { // nail it to the ground before it tries jumping up, only to land again... am->SetState(am->AIRCRAFT_LANDED); // call this so that other animations such as opening doors may be started owner->script->TransportDrop((transportees.front()).unit, pos); transport->DetachUnitFromAir(transportee, pos); FinishCommand(); if (transportees.empty()) { am->SetAllowLanding(true); owner->script->EndTransport(); am->UpdateLanded(); } } } else { // land transports inCommand = true; isFirstIteration = false; StopMove(); owner->script->TransportDrop((transportees.front()).unit, pos); transport->DetachUnitFromAir(transportee, pos); FinishCommand(); if (transportees.empty()) { owner->script->EndTransport(); } } } } }
void CTransportCAI::UnloadLand(Command& c) { // default unload CTransportUnit* transport = static_cast<CTransportUnit*>(owner); CUnit* transportee = NULL; float3 wantedPos = c.GetPos(0); if (inCommand) { if (!owner->script->IsBusy()) { FinishCommand(); } } else { const std::list<CTransportUnit::TransportedUnit>& transportees = transport->GetTransportedUnits(); if (transportees.empty()) { FinishCommand(); return; } SetGoal(wantedPos, owner->pos); if (c.params.size() < 4) { // unload the first transportee transportee = (transportees.front()).unit; } else { const int unitID = c.params[3]; // unload a specific transportee for (auto it = transportees.begin(); it != transportees.end(); ++it) { CUnit* carried = it->unit; if (unitID == carried->id) { transportee = carried; break; } } if (transportee == NULL) { FinishCommand(); return; } } if (wantedPos.SqDistance2D(owner->pos) < Square(owner->unitDef->loadingRadius * 0.9f)) { CHoverAirMoveType* am = dynamic_cast<CHoverAirMoveType*>(owner->moveType); wantedPos.y = static_cast<CTransportUnit*>(owner)->GetTransporteeWantedHeight(wantedPos, transportee); if (am != NULL) { // handle air transports differently SetGoal(wantedPos, owner->pos); am->SetWantedAltitude(wantedPos.y - CGround::GetHeightAboveWater(wantedPos.x, wantedPos.z)); am->ForceHeading(static_cast<CTransportUnit*>(owner)->GetTransporteeWantedHeading(transportee)); am->maxDrift = 1.0f; // FIXME: kill the hardcoded constants, use the command's radius // NOTE: 2D distance-check would mean units get dropped from air const bool b1 = (owner->pos.SqDistance(wantedPos) < Square(AIRTRANSPORT_DOCKING_RADIUS)); const bool b2 = (std::abs(owner->heading - am->GetForcedHeading()) < AIRTRANSPORT_DOCKING_ANGLE); const bool b3 = (owner->updir.dot(UpVector) > 0.99f); if (b1 && b2 && b3) { wantedPos.y -= transportee->radius; if (!SpotIsClearIgnoreSelf(wantedPos, transportee)) { // chosen spot is no longer clear to land, choose a new one // if a new spot cannot be found, don't unload at all float3 newWantedPos; if (FindEmptySpot(wantedPos, std::max(16.0f * SQUARE_SIZE, transportee->radius * 4.0f), transportee->radius, newWantedPos, transportee)) { c.SetPos(0, newWantedPos); SetGoal(newWantedPos + UpVector * transportee->model->height, owner->pos); return; } } else { transport->DetachUnit(transportee); if (transportees.empty()) { am->SetAllowLanding(true); owner->script->EndTransport(); } } // move the transport away slightly SetGoal(owner->pos + owner->frontdir * 20.0f, owner->pos); FinishCommand(); } } else { inCommand = true; StopMove(); owner->script->TransportDrop(transportee, wantedPos); } } } }
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::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; 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)) { am->dontLand = false; owner->cob->Call("EndTransport"); transport->DetachUnit(unit); 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::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::UnloadLand(Command& c) { //default unload CTransportUnit* transport = static_cast<CTransportUnit*>(owner); if (inCommand) { if (!owner->script->IsBusy()) { FinishCommand(); } } else { const std::list<CTransportUnit::TransportedUnit>& transList = transport->GetTransportedUnits(); if (transList.empty()) { FinishCommand(); return; } float3 pos = c.GetPos(0); if (goalPos.SqDistance2D(pos) > 400) { 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.SqDistance2D(owner->pos) < Square(owner->unitDef->loadingRadius * 0.9f)) { CHoverAirMoveType* am = dynamic_cast<CHoverAirMoveType*>(owner->moveType); pos.y = static_cast<CTransportUnit*>(owner)->GetLoadUnloadHeight(pos, unit); if (am != NULL) { // handle air transports differently SetGoal(pos, owner->pos); am->SetWantedAltitude(pos.y - ground->GetHeightAboveWater(pos.x, pos.z)); float unloadHeading = static_cast<CTransportUnit*>(owner)->GetLoadUnloadHeading(unit); am->ForceHeading(unloadHeading); am->maxDrift = 1; if ((owner->pos.SqDistance(pos) < 64) && (owner->updir.dot(UpVector) > 0.99f) && math::fabs(owner->heading - unloadHeading) < AIRTRANSPORT_DOCKING_ANGLE) { pos.y -= unit->radius; if (!SpotIsClearIgnoreSelf(pos, unit)) { // chosen spot is no longer clear to land, choose a new one // if a new spot cannot be found, don't unload at all float3 newpos; if (FindEmptySpot(pos, std::max(16.0f * SQUARE_SIZE, unit->radius * 4.0f), unit->radius, newpos, unit)) { c.SetPos(0, newpos); SetGoal(newpos + UpVector * unit->model->height, owner->pos); return; } } else { transport->DetachUnit(unit); if (transport->GetTransportedUnits().empty()) { am->dontLand = false; owner->script->EndTransport(); } } const float3 fix = owner->pos + owner->frontdir * 20; SetGoal(fix, owner->pos); // move the transport away slightly FinishCommand(); } } else { inCommand = true; StopMove(); owner->script->TransportDrop(unit, pos); } } } }
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); }