/// Returns true if indicated position is a suitable landing spot bool CTAAirMoveType::CanLandAt(const float3& pos) const { if (dontLand) { return false; } if (!autoLand) { return false; } if (!pos.IsInBounds()) { return false; } if ((ground->GetApproximateHeight(pos.x, pos.z) < 0.0f) && !(owner->unitDef->floater || owner->unitDef->canSubmerge)) { return false; } const int2 mp = owner->GetMapPos(pos); for (int z = mp.y; z < mp.y + owner->zsize; z++) { for (int x = mp.x; x < mp.x + owner->xsize; x++) { const CObject* o = groundBlockingObjectMap->GroundBlockedUnsafe(z * gs->mapx + x); if (o && o != owner) { return false; } } } return true; }
/// Returns true if indicated position is a suitable landing spot bool CHoverAirMoveType::CanLandAt(const float3& pos) const { if (forceHeading) return true; if (!CanLand(false)) return false; if (!pos.IsInBounds()) return false; const UnitDef* ud = owner->unitDef; const float gah = CGround::GetApproximateHeight(pos.x, pos.z); if ((gah < 0.0f) && !(ud->floatOnWater || ud->canSubmerge)) { return false; } const int2 mp = owner->GetMapPos(pos); for (int z = mp.y; z < mp.y + owner->zsize; z++) { for (int x = mp.x; x < mp.x + owner->xsize; x++) { if (groundBlockingObjectMap->GroundBlocked(x, z, owner)) { return false; } } } return true; }
//Returns true if indicated position is a suitable landing spot bool CTAAirMoveType::CanLandAt(float3 pos) { if (dontLand) return false; if (!autoLand) return false; if (!pos.IsInBounds()) return false; float h = ground->GetApproximateHeight(pos.x, pos.z); if ((h < 0) && !(owner -> unitDef -> floater || owner -> unitDef -> canSubmerge)) return false; float3 tpos = owner->pos; owner->pos = pos; int2 mp = owner->GetMapPos(); owner->pos = tpos; for (int z = mp.y; z < mp.y + owner->ysize; z++) { for (int x = mp.x; x < mp.x + owner->xsize; x++) { CObject* o = groundBlockingObjectMap->GroundBlockedUnsafe(z * gs->mapx + x); if (o && o != owner) { return false; } } } return true; }
void CDefenseMatrix::MaskBadBuildSpot(float3 pos) { if (pos.IsInBounds()) { const int f3multiplier = 8 * THREATRES; const int x = (int) (pos.x / f3multiplier); const int y = (int) (pos.z / f3multiplier); BuildMaskArray[y * ai->pather->PathMapXSize + x] = 1; } }
bool CTAAirMoveType::Update() { float3& pos = owner->pos; float3& speed = owner->speed; // This is only set to false after the plane has finished constructing if (useHeading) { useHeading = false; SetState(AIRCRAFT_TAKEOFF); } if (owner->stunned || owner->beingBuilt) { wantedSpeed = ZeroVector; wantToStop = true; } // Allow us to stop if wanted if (wantToStop) { ExecuteStop(); } const float3 lastSpeed = speed; if (owner->fpsControlPlayer != NULL) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = pos + speed; float3 flatForward = forward; flatForward.y = 0.0f; flatForward.Normalize(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { speed = ZeroVector; } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } else { if (reservedPad) { CUnit* unit = reservedPad->GetUnit(); const float3 relPos = unit->script->GetPiecePos(reservedPad->GetPiece()); const float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x; if (padStatus == 0) { if (aircraftState != AIRCRAFT_FLYING && aircraftState != AIRCRAFT_TAKEOFF) SetState(AIRCRAFT_FLYING); goalPos = pos; if (pos.SqDistance2D(owner->pos) < 400*400) { padStatus = 1; } } else if (padStatus == 1) { if (aircraftState != AIRCRAFT_FLYING) { SetState(AIRCRAFT_FLYING); } flyState = FLY_LANDING; goalPos = pos; reservedLandingPos = pos; wantedHeight = pos.y - ground->GetHeightAboveWater(pos.x, pos.z); if (owner->pos.SqDistance(pos) < 9 || aircraftState == AIRCRAFT_LANDED) { padStatus = 2; } } else { if (aircraftState != AIRCRAFT_LANDED) SetState(AIRCRAFT_LANDED); owner->pos = pos; owner->AddBuildPower(unit->unitDef->buildSpeed / 30, unit); owner->currentFuel = std::min(owner->unitDef->maxFuel, owner->currentFuel + (owner->unitDef->maxFuel / (GAME_SPEED * owner->unitDef->refuelTime))); if (owner->health >= owner->maxHealth - 1 && owner->currentFuel >= owner->unitDef->maxFuel) { airBaseHandler->LeaveLandingPad(reservedPad); reservedPad = NULL; padStatus = 0; goalPos = oldGoalPos; SetState(AIRCRAFT_TAKEOFF); } } } // Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: break; } } // Banking requires deltaSpeed.y = 0 deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); owner->UpdateMidPos(); return (HandleCollisions()); }
bool CHoverAirMoveType::Update() { const float3 lastPos = owner->pos; const float4 lastSpd = owner->speed; AAirMoveType::Update(); if ((owner->IsStunned() && !owner->IsCrashing()) || owner->beingBuilt) { wantedSpeed = ZeroVector; UpdateAirPhysics(); return (HandleCollisions(collide && !owner->beingBuilt && (padStatus == PAD_STATUS_FLYING) && (aircraftState != AIRCRAFT_TAKEOFF))); } // allow us to stop if wanted (changes aircraft state) if (wantToStop) ExecuteStop(); if (aircraftState != AIRCRAFT_CRASHING) { if (owner->UnderFirstPersonControl()) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = lastPos + owner->speed; float3 flatForward = forward; flatForward.Normalize2D(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { owner->SetVelocityAndSpeed(ZeroVector); } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } if (reservedPad != NULL) { MoveToRepairPad(); if (padStatus >= PAD_STATUS_LANDING) { flyState = FLY_LANDING; } } } switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: { UpdateAirPhysics(); if ((CGround::GetHeightAboveWater(owner->pos.x, owner->pos.z) + 5.0f + owner->radius) > owner->pos.y) { owner->ClearPhysicalStateBit(CSolidObject::PSTATE_BIT_CRASHING); owner->KillUnit(NULL, true, false); } else { #define SPIN_DIR(o) ((o->id & 1) * 2 - 1) wantedHeading = GetHeadingFromVector(owner->rightdir.x * SPIN_DIR(owner), owner->rightdir.z * SPIN_DIR(owner)); wantedHeight = 0.0f; #undef SPIN_DIR } new CSmokeProjectile(owner, owner->midPos, gs->randVector() * 0.08f, 100 + gs->randFloat() * 50, 5, 0.2f, 0.4f); } break; } if (lastSpd == ZeroVector && owner->speed != ZeroVector) { owner->script->StartMoving(false); } if (lastSpd != ZeroVector && owner->speed == ZeroVector) { owner->script->StopMoving(); } // Banking requires deltaSpeed.y = 0 deltaSpeed = owner->speed - lastSpd; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); return (HandleCollisions(collide && !owner->beingBuilt && (padStatus == PAD_STATUS_FLYING) && (aircraftState != AIRCRAFT_TAKEOFF))); }
bool CHoverAirMoveType::Update() { float3& pos = owner->pos; float3& speed = owner->speed; AAirMoveType::Update(); if (owner->stunned || owner->beingBuilt) { wantedSpeed = ZeroVector; wantToStop = true; } // Allow us to stop if wanted if (wantToStop) { ExecuteStop(); } const float3 lastSpeed = speed; if (owner->fpsControlPlayer != NULL) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = pos + speed; float3 flatForward = forward; flatForward.y = 0.0f; flatForward.Normalize(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { speed = ZeroVector; } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } else { if (reservedPad != NULL) { MoveToRepairPad(); if (padStatus >= 1) { flyState = FLY_LANDING; } } // Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: break; } } // Banking requires deltaSpeed.y = 0 deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); return (HandleCollisions()); }
void CFactory::SendToEmptySpot(CUnit* unit) { const float searchRadius = radius * 4.0f + unit->radius * 4.0f; const int numSteps = 36; const float3 exitPos = pos + frontdir*(radius + unit->radius); float3 foundPos = pos + frontdir * searchRadius; const float3 tempPos = foundPos; for (int x = 0; x < numSteps; ++x) { const float a = searchRadius * math::cos(x * PI / (numSteps * 0.5f)); const float b = searchRadius * math::sin(x * PI / (numSteps * 0.5f)); float3 testPos = pos + frontdir * a + rightdir * b; if (!testPos.IsInBounds()) continue; // don't pick spots behind the factory (because // units will want to path through it when open // which slows down production) if ((testPos - pos).dot(frontdir) < 0.0f) continue; testPos.y = CGround::GetHeightAboveWater(testPos.x, testPos.z); if (quadField->GetSolidsExact(testPos, unit->radius * 1.5f, 0xFFFFFFFF, CSolidObject::CSTATE_BIT_SOLIDOBJECTS).empty()) { foundPos = testPos; break; } } if (foundPos == tempPos) { // no empty spot found, pick one randomly so units do not pile up even more // also make sure not to loop forever if we happen to be facing a map border foundPos.y = 0.0f; do { const float x = ((gs->randInt() * 1.0f) / RANDINT_MAX) * numSteps; const float a = searchRadius * math::cos(x * PI / (numSteps * 0.5f)); const float b = searchRadius * math::sin(x * PI / (numSteps * 0.5f)); foundPos.x = pos.x + frontdir.x * a + rightdir.x * b; foundPos.z = pos.z + frontdir.z * a + rightdir.z * b; foundPos.y += 1.0f; } while ((!foundPos.IsInBounds() || (foundPos - pos).dot(frontdir) < 0.0f) && (foundPos.y < 100.0f)); foundPos.y = CGround::GetHeightAboveWater(foundPos.x, foundPos.z); } // first queue a temporary waypoint outside the factory // (otherwise units will try to turn before exiting when // foundPos lies behind exit and cause jams / get stuck) // we assume this temporary point is not itself blocked // // NOTE: // MobileCAI::AutoGenerateTarget inserts a _third_ // command when |foundPos - tempPos| >= 100 elmos, // because MobileCAI::FinishCommand only updates // lastUserGoal for non-internal orders --> the // final order given here should not be internal // (and should also be more than CMD_CANCEL_DIST // elmos distant from foundPos) // if (!unit->unitDef->canfly && exitPos.IsInBounds()) { Command c0(CMD_MOVE, SHIFT_KEY, exitPos); unit->commandAI->GiveCommand(c0); } Command c1(CMD_MOVE, SHIFT_KEY, foundPos); unit->commandAI->GiveCommand(c1); }