Пример #1
0
/// 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;
}
void Game_Vehicle::Update() {
	Game_Character::Update();
	Game_Character::UpdateSprite();
	SyncWithPlayer();

	if (type == Airship) {
		if (IsAscending()) {
			data.remaining_ascent -= 8;
			if (!IsAscending())
				walk_animation = true;
		} else if (IsDescending()) {
			data.remaining_descent -= 8;
			if (!IsDescending()) {
				if (CanLand()) {
					SetLayer(RPG::EventPage::Layers_same);
					driving = false;
					data.flying = false;
					walk_animation = false;
					pattern = 1;
				} else {
					// Can't land here, ascend again
					data.remaining_ascent = SCREEN_TILE_WIDTH;
				}
			}
		}
	}
}
Пример #3
0
void CHoverAirMoveType::ExecuteStop()
{
	wantToStop = false;
	wantedSpeed = ZeroVector;
	SetGoal(owner->pos);
	ClearLandingPos();

	switch (aircraftState) {
		case AIRCRAFT_TAKEOFF: {
			if (CanLand(IsUnitBusy(owner))) {
				SetState(AIRCRAFT_LANDING);
				// trick to land directly
				waitCounter = GAME_SPEED;
				break;
			}
		} // fall through
		case AIRCRAFT_FLYING: {

			if (CanLand(IsUnitBusy(owner))) {
				SetState(AIRCRAFT_LANDING);
			} else {
				SetState(AIRCRAFT_HOVERING);
			}
		} break;

		case AIRCRAFT_LANDING: {
			if (!CanLand(IsUnitBusy(owner)))
				SetState(AIRCRAFT_HOVERING);

		} break;
		case AIRCRAFT_LANDED: {} break;
		case AIRCRAFT_CRASHING: {} break;

		case AIRCRAFT_HOVERING: {
			if (CanLand(IsUnitBusy(owner))) {
				// land immediately, otherwise keep hovering
				SetState(AIRCRAFT_LANDING);
				waitCounter = GAME_SPEED;
			}
		} break;
	}
}
Пример #4
0
void CHoverAirMoveType::ExecuteStop()
{
	wantToStop = false;
	wantedSpeed = ZeroVector;

	switch (aircraftState) {
		case AIRCRAFT_TAKEOFF: {
			if (CanLand()) {
				SetState(AIRCRAFT_LANDING);
				// trick to land directly
				waitCounter = GAME_SPEED;
				break;
			}
		} // fall through
		case AIRCRAFT_FLYING: {
			goalPos = owner->pos;

			if (CanLand()) {
				SetState(AIRCRAFT_LANDING);
			} else {
				SetState(AIRCRAFT_HOVERING);
			}
		} break;

		case AIRCRAFT_LANDING: {} break;
		case AIRCRAFT_LANDED: {} break;
		case AIRCRAFT_CRASHING: {} break;

		case AIRCRAFT_HOVERING: {
			if (CanLand()) {
				// land immediately
				SetState(AIRCRAFT_LANDING);
				waitCounter = GAME_SPEED;
			}
		} break;
	}
}
Пример #5
0
void CHoverAirMoveType::SetAllowLanding(bool allowLanding)
{
	dontLand = !allowLanding;

	if (CanLand(false))
		return;

	if (aircraftState != AIRCRAFT_LANDED && aircraftState != AIRCRAFT_LANDING)
		return;

	// do not start hovering if still (un)loading a unit
	if (forceHeading)
		return;

	SetState(AIRCRAFT_HOVERING);
}
Пример #6
0
void CHoverAirMoveType::SetAllowLanding(bool allowLanding)
{
	dontLand = !allowLanding;

	if (CanLand())
		return;

	if (aircraftState != AIRCRAFT_LANDED && aircraftState != AIRCRAFT_LANDING)
		return;

	// do not start hovering if still loading units
	if (loadingUnits)
		return;

	SetState(AIRCRAFT_HOVERING);
}
Пример #7
0
void Game_Vehicle::Update(bool process_movement) {

	if (!process_movement) {
		return;
	}

	if (IsAboard()) {
		SyncWithPlayer();
	} else {
		Game_Character::UpdateMovement();
	}

	if (type == Airship) {
		if (IsStopping()) {
			if (IsAscending()) {
				data()->remaining_ascent = data()->remaining_ascent - 8;
			} else if (IsDescending()) {
				data()->remaining_descent = data()->remaining_descent - 8;
				if (!IsDescending()) {
					if (CanLand()) {
						Main_Data::game_player->UnboardingFinished();
						SetFlying(false);
						Main_Data::game_player->SetFlying(false);
					} else {
						// Can't land here, ascend again
						data()->remaining_ascent = SCREEN_TILE_SIZE;
					}
				}
			}
		}
	}

	if (type == Airship) {
		UpdateAnimationAirship();
	} else {
		UpdateAnimationShip();
	}
}
Пример #8
0
void CHoverAirMoveType::UpdateFlying()
{
	const float3& pos = owner->pos;
	// const float4& spd = owner->speed;

	// Direction to where we would like to be
	float3 goalVec = goalPos - pos;

	owner->restTime = 0;

	// don't change direction for waypoints we just flew over and missed slightly
	if (flyState != FLY_LANDING && owner->commandAI->HasMoreMoveCommands()) {
		float3 goalDir = goalVec;

		if ((goalDir != ZeroVector) && (goalVec.dot(goalDir.UnsafeANormalize()) < 1.0f)) {
			goalVec = owner->frontdir;
		}
	}

	const float goalDistSq2D = goalVec.SqLength2D();
	const float gHeight = UseSmoothMesh()?
		std::max(smoothGround->GetHeight(pos.x, pos.z), CGround::GetApproximateHeight(pos.x, pos.z)):
		CGround::GetHeightAboveWater(pos.x, pos.z);

	const bool closeToGoal = (flyState == FLY_ATTACKING)?
		(goalDistSq2D < (             400.0f)):
		(goalDistSq2D < (maxDrift * maxDrift)) && (math::fabs(gHeight + wantedHeight - pos.y) < maxDrift);

	if (closeToGoal) {
		switch (flyState) {
			case FLY_CRUISING: {
				// NOTE: should CMD_LOAD_ONTO be here?
				const bool isTransporter = (dynamic_cast<CTransportUnit*>(owner) != NULL);
				const bool hasLoadCmds = isTransporter &&
					!owner->commandAI->commandQue.empty() &&
					(owner->commandAI->commandQue.front().GetID() == CMD_LOAD_ONTO ||
					 owner->commandAI->commandQue.front().GetID() == CMD_LOAD_UNITS);
				// [?] transport aircraft need some time to detect that they can pickup
				const bool canLoad = isTransporter && (++waitCounter < ((GAME_SPEED << 1) - 5));
				const bool isBusy = IsUnitBusy(owner);

				if (!CanLand(isBusy) || (canLoad && hasLoadCmds)) {
					wantedSpeed = ZeroVector;

					if (isTransporter) {
						if (waitCounter > (GAME_SPEED << 1)) {
							wantedHeight = orgWantedHeight;
						}

						SetState(AIRCRAFT_HOVERING);
						return;
					} else {
						if (!isBusy) {
							wantToStop = true;

							// NOTE:
							//   this is not useful, next frame UpdateFlying()
							//   will change it to _LANDING because wantToStop
							//   is now true
							SetState(AIRCRAFT_HOVERING);
							return;
						}
					}
				} else {
					wantedHeight = orgWantedHeight;

					SetState(AIRCRAFT_LANDING);
					return;
				}
			} break;

			case FLY_CIRCLING: {
				if ((++waitCounter) > ((GAME_SPEED * 3) + 10)) {
					if (airStrafe) {
						float3 relPos = pos - circlingPos;

						if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
							relPos.x = 0.0001f;
						}

						static CMatrix44f rot(0.0f, fastmath::PI / 4.0f, 0.0f);

						// make sure the point is on the circle, go there in a straight line
						goalPos = circlingPos + (rot.Mul(relPos.Normalize2D()) * goalDistance);
					}
					waitCounter = 0;
				}
			} break;

			case FLY_ATTACKING: {
				if (airStrafe) {
					float3 relPos = pos - circlingPos;

					if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
						relPos.x = 0.0001f;
					}

					CMatrix44f rot;

					if (gs->randFloat() > 0.5f) {
						rot.RotateY(0.6f + gs->randFloat() * 0.6f);
					} else {
						rot.RotateY(-(0.6f + gs->randFloat() * 0.6f));
					}

					// Go there in a straight line
					goalPos = circlingPos + (rot.Mul(relPos.Normalize2D()) * goalDistance);
				}
			} break;

			case FLY_LANDING: {
			} break;
		}
	}

	// not "close" to goal yet, so keep going
	// use 2D math since goal is on the ground
	// but we are not
	goalVec.y = 0.0f;

	// if we are close to our goal, we should
	// adjust speed st. we never overshoot it
	// (by respecting current brake-distance)
	const float curSpeed = owner->speed.Length2D();
	const float brakeDist = (0.5f * curSpeed * curSpeed) / decRate;
	const float goalDist = goalVec.Length() + 0.1f;
	const float goalSpeed =
		(maxSpeed          ) * (goalDist >  brakeDist) +
		(curSpeed - decRate) * (goalDist <= brakeDist);

	if (goalDist > goalSpeed) {
		// update our velocity and heading so long as goal is still
		// further away than the distance we can cover in one frame
		// we must use a variable-size "dead zone" to avoid freezing
		// in mid-air or oscillation behavior at very close distances
		// NOTE:
		//   wantedSpeed is a vector, so even aircraft with turnRate=0
		//   are coincidentally able to reach any goal by side-strafing
		wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z);
		wantedSpeed = (goalVec / goalDist) * goalSpeed;
	} else {
		// switch to hovering (if !CanLand()))
		if (flyState != FLY_ATTACKING) {
			ExecuteStop();
		}
	}

	// redundant, done in Update()
	// UpdateHeading();
	UpdateAirPhysics();

	// Point toward goal or forward - unless we just passed it to get to another goal
	if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
		goalVec = circlingPos - pos;
	} else {
		const bool b0 = (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands()));
		const bool b1 = (goalDist < brakeDist && goalDist > 1.0f);

		if (b0 && b1) {
			goalVec = owner->frontdir;
		} else {
			goalVec = goalPos - pos;
		}
	}

	if (goalVec.SqLength2D() > 1.0f) {
		// update heading again in case goalVec changed
		wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z);
	}
}