Untitled

 avatar
unknown
python
3 months ago
16 kB
4
Indexable
#
# TODO: A mission to fly to the nearby launchpad for refuel.
#
# This mission shall teach how to orient the vehicle using the heading
# indicator, and how to use the RCS thrusters to translate the spacecraft
# horizontally. During this mission, by taking off and landing on the nearby
# launchpad, the player shall learn the basics of horizontal flight, useful
# during landing from orbital or suborbital flights.
#
# The final objective of the mission shall be landing on the other launchpad.
# Once the landing happens, the spacecraft shall be automatically fully
# refueled.
#
# Objectives:
#   - teach about heading (cardinal directions, compass, etc?)
#   - let take off and hover above the ground
#   - let rotate vertically using roll controls (Q/E) towards the other
#     launchpad, orienting roughly towards N
#   - let fly towards the other launchpad using RCS thrusters for translation
#     (I/K and J/L)
#   - once above the other launchpad, let land on it
#   - congratulate the player and refuel the spaceship
#
# Tips:
#   - Use the Gui.hint() for showing a hint to the player for some 3D object in
#     the cockpit, in a form of a colored arrow. There are some utility "anchor"
#     3D nodes, meant to be used highlighting the related controls. Most
#     instruments on the dashboard have anchors, open the
#     spacecraft/dumpster/interior.tscn scene and search for "anchor".
#
#   - Use the Gui.prompt() for prompting messages and optionally, waiting for
#     confirmation. It supports the `await` keyword and allows for sequential
#     asynchronous programming of tutorial-like steps.
#
extends Mission

const Camera = preload("res://camera.gd")

const _CURENT_LAUNCHPAD_SPAWN_POINT = "/root/Main/World/Asteroid/JunoBase/Launchpad/SpawnPoint"
const _OTHER_LAUNCHPAD_SPAWN_POINT = "/root/Main/World/Asteroid/JunoBase/Launchpad2/SpawnPoint"
const _DUMPSTER_CAMERA = "/root/Main/World/Dumpster/Assembly/Camera"
const _DUMPSTER = "/root/Main/World/Dumpster"

const _LAUNCHPAD_SCENE = "res://buildings/launchpad/launchpad.tscn"

const ANIMATION_LENGTH = 2.0


# Objective 0 - Reaction Control System
func _objective_0_rsc(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	await Gui.prompt("To complete serious missions we need much more fuel.")
	
	# Show the Fuel Indicator
	_hint('Fuel')
	if not await Gui.prompt("As you can see, this fuel won’t get us far — no epic space adventures on an empty tank!"):
		return
	_hint('')
	
	var messages = [
		"We will refuel at the other launchpad — it’s hiding in plain sight next to that giant tower!",
		"We need the main engine to hover and RCS thrusters to maneuver.",
		"The Reaction Control System (RCS) is a set of thrusters placed around your ship to help you maneuver.",
		"‘Reaction’ — fire thrusters on one side, move the other. Newton’s third law, you know.",
	]
	while !obj.canceled and messages:
		if not await Gui.prompt(messages.pop_front()):
			return
	
	await Gui.prompt("Enough theory - let's lift off and try it!")
	
	obj.completed = true

# Objective 1 - Take off and hover above the ground
func _objective_1_take_over(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	Gui.prompt("Lift off and hover at 20m. Shall be easy for you!", false)
	while !obj.canceled:
		await Game.tick
		if Game.get_local_vehicle().get_assembly().is_engine_enabled(0) and Game.get_local_vehicle().get_vectors().surface_position.length() > .5:
			break
	
	var hover_start_time: int = 0
	var desired_height: int = 20

	while not obj.canceled:
		await Game.tick
		var vehicle = Game.get_local_vehicle()
		var altitude = vehicle.get_vectors().surface_position.length()
		var diff = absf(altitude - desired_height)

		# If within +- 1m -> sub-mission compledted
		if diff < 1:
			var elapsed: float = (Time.get_ticks_msec() - hover_start_time) / 1000.0
			# When 1 second passed, complete the mission
			if elapsed > 1.0:
				#print('final vehicle translation vector = ', vehicle.translation)
				print('surface_position = ', vehicle.get_vectors().surface_position)
				break
		else:
			Gui.prompt("Yoohoo! Reach an altitude of 20m.", false, true, _NO_ANIM)
	
	if obj.canceled:
		return

	obj.completed = true

# Objective 2 - Push forward/backward using the RCS thrusters
func _objective_2_rcs_forward_and_backward(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	if not await Gui.prompt("Time to fire up those thrusters!"):
		return
	
	# Enter the external view mode
	Gui.prompt("Press [color=$H]TAB[/color] to switch to external view.", false)
	while !obj.canceled:
		await Game.tick
		if Game.get_view_mode() == Game.ViewMode.EXTERNAL:
			break
	
	var rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_forward_pressed = false
	
	# RSC throttle forward
	Gui.prompt("Press [color=$H]I[/color] shortly to give a push [color=$H]forward[/color] by activating the [color=$H]rear[/color] thrusters.", false)
	while !obj.canceled:
		await Game.tick
		var rcs_prop_consumed_after = Game.get_local_vehicle().rcs_propellant_consumed
		
		# Check if a player tried to press I character to move forward
		is_forward_pressed = is_forward_pressed or Input.is_key_pressed(KEY_I)
		
		if rcs_prop_consumed_after - rcs_prop_consumed_before > .05 and is_forward_pressed:
			break
	
	rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_backward_pressed = false
	
	# RSC throttle backward
	Gui.prompt("Press [color=$H]K[/color] shortly to give a push [color=$H]backward[/color] by activating the [color=$H]front[/color] thrusters.", false)
	while !obj.canceled:
		await Game.tick
		var rcs_prop_consumed_after = Game.get_local_vehicle().rcs_propellant_consumed
		
		# Check if a player tried to press K characters to move backward
		is_backward_pressed = is_backward_pressed or Input.is_key_pressed(KEY_K)
		
		if rcs_prop_consumed_after - rcs_prop_consumed_before > .05 and is_backward_pressed:
			break
		
	if obj.canceled:
		return
	
	obj.completed = true

# Objective 3 - Push right/left using the RCS thrusters
func _objective_3_rcs_push_left(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	if not await Gui.prompt("Left and right thrusters are next!"):
		return
	
	var rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_left_pressed = false
	
	# RSC throttle left
	Gui.prompt("Press [color=$H]J[/color] shortly to give a push [color=$H]left[/color] by activating the [color=$H]right[/color] thrusters.", false)
	while !obj.canceled:
		await Game.tick
		var rcs_prop_consumed_after = Game.get_local_vehicle().rcs_propellant_consumed
		
		# Check if a player tried to press J character to move left
		is_left_pressed = is_left_pressed or Input.is_key_pressed(KEY_J)
		
		if rcs_prop_consumed_after - rcs_prop_consumed_before > .05 and is_left_pressed:
			break
	
	rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_right_pressed = false
	
	# RSC throttle right
	Gui.prompt("Press [color=$H]L[/color] shortly to give a push [color=$H]right[/color] by activating the [color=$H]left[/color] thrusters.", false)
	while !obj.canceled:
		await Game.tick
		var rcs_prop_consumed_after = Game.get_local_vehicle().rcs_propellant_consumed
		
		# Check if a player tried to press L character to move right
		is_right_pressed = is_right_pressed or Input.is_key_pressed(KEY_L)
		
		if rcs_prop_consumed_after - rcs_prop_consumed_before > .05 and is_right_pressed:
			break
	
	if obj.canceled:
		return
	
	obj.completed = true

# Objective 5 - Push right using the RCS thrusters
func _objective_5_rcs_push_right(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	var rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_right_pressed = false
	
	# RSC throttle right
	Gui.prompt("Press [color=$H]L[/color] shortly to give a push [color=$H]right[/color] by activating the [color=$H]left[/color] thrusters.", false)
	while !obj.canceled:
		await Game.tick
		var rcs_prop_consumed_after = Game.get_local_vehicle().rcs_propellant_consumed
		
		# Check if a player tried to press L character to move right
		is_right_pressed = is_right_pressed or Input.is_key_pressed(KEY_L)
		
		if rcs_prop_consumed_after - rcs_prop_consumed_before > .05 and is_right_pressed:
			break
	
	# Enter the internal view mode
	Gui.prompt("Press [color=$H]TAB[/color] to switch back to interior view.", false)
	while !obj.canceled:
		await Game.tick
		if Game.get_view_mode() == Game.ViewMode.INTERNAL:
			break
	
	# Make sure a player is controlling the speed and position in the air
	Gui.prompt("Still at 20m? Double-check!", false)
	var hover_start_time: int = 0
	var desired_altitude: int = 20

	while not obj.canceled:
		await Game.tick
		var vehicle = Game.get_local_vehicle()
		var altitude = vehicle.get_vectors().surface_position.length()
		var diff = altitude - desired_altitude

		# If within +- 1m -> sub-mission compledted
		if diff < 1 and diff > 0:
			var elapsed: float = (Time.get_ticks_msec() - hover_start_time) / 1000.0
			# When 1 second passed, complete the mission
			if elapsed > 1.0:
				break
		else:
			Gui.prompt("Get back to an altitude of 20m.", false, true, _NO_ANIM)
	
	if obj.canceled:
		return
	
	obj.completed = true

# Objective 6 - Push up using the RCS thrusters
func _objective_6_rcs_push_up(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	if not await Gui.prompt("Let’s figure out how to fire the top and bottom RCS thrusters!"):
		return
	
	# Enter the external view mode
	Gui.prompt("Press [color=$H]TAB[/color] to switch to external view.", false)
	while !obj.canceled:
		await Game.tick
		if Game.get_view_mode() == Game.ViewMode.EXTERNAL:
			break
	
	var rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_up_pressed = false
	
	# RSC throttle up
	Gui.prompt("Press [color=$H]O[/color] shortly to give a push [color=$H]up[/color] by activating the [color=$H]bottom[/color] thrusters.", false)
	while !obj.canceled:
		await Game.tick
		var rcs_prop_consumed_after = Game.get_local_vehicle().rcs_propellant_consumed
		
		# Check if a player tried to press O character to move up
		is_up_pressed = is_up_pressed or Input.is_key_pressed(KEY_O)
		
		if rcs_prop_consumed_after - rcs_prop_consumed_before > .05 and is_up_pressed:
			break
		
	if obj.canceled:
		return
	
	obj.completed = true

# Objective 7 - Push down using the RCS thrusters
func _objective_7_rcs_push_down(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	var rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_down_pressed = false
	
	# RSC throttle down
	Gui.prompt("Press [color=$H]U[/color] shortly to give a push [color=$H]down[/color] by activating the [color=$H]top[/color] thrusters.", false)
	while !obj.canceled:
		await Game.tick
		var rcs_prop_consumed_after = Game.get_local_vehicle().rcs_propellant_consumed
		
		# Check if a player tried to press U character to move down
		is_down_pressed = is_down_pressed or Input.is_key_pressed(KEY_U)
		
		if rcs_prop_consumed_after - rcs_prop_consumed_before > .05 and is_down_pressed:
			break
	
	# Enter the internal view mode
	Gui.prompt("Press [color=$H]TAB[/color] to switch back to interior view.", false)
	while !obj.canceled:
		await Game.tick
		if Game.get_view_mode() == Game.ViewMode.INTERNAL:
			break
	
	# Make sure a player is controlling the speed and position in the air
	Gui.prompt("Still at 20m? Stay there!", false)
	var hover_start_time: int = 0
	var desired_altitude: int = 20

	while not obj.canceled:
		await Game.tick
		var vehicle = Game.get_local_vehicle()
		var altitude = vehicle.get_vectors().surface_position.length()
		var diff = altitude - desired_altitude

		# If within +- 1m -> sub-mission compledted
		if diff < 1 and diff > 0:
			var elapsed: float = (Time.get_ticks_msec() - hover_start_time) / 1000.0
			# When 1 second passed, complete the mission
			if elapsed > 1.0:
				break
		else:
			Gui.prompt("Get back to an altitude of 20m.", false, true, _NO_ANIM)
	
	if obj.canceled:
		return
	
	obj.completed = true

# Objective 8 - Fly towards the other launchpad using RCS thrusters for tranlation
func _objective_8_fly_with_rcs(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	var rcs_prop_consumed_before = Game.get_local_vehicle().rcs_propellant_consumed
	var is_backward_pressed = false
	var is_forward_pressed = false
	
	Gui.prompt("Now fly to the other launchpad using the RCS.", false)
	while !obj.canceled:
		await Game.tick
		if Input.is_key_pressed(KEY_I):
			break
	
	_hint('OrbitalSpeed')
	Gui.prompt("Try to keep your speed around 3m/s!", false, true, _NO_ANIM)
	await _pause(5)
	_hint('')
	
	var maximum_threshold = 30.0
	var desired_threshold = 7.0
	var measurement_gap = 10.0
	
	var first_launchpad = Game.get_node(_CURENT_LAUNCHPAD_SPAWN_POINT) as Marker3D
	var second_launchpad = Game.get_node(_OTHER_LAUNCHPAD_SPAWN_POINT) as Marker3D
	
	var pos_first = first_launchpad.global_position
	var pos_second = second_launchpad.global_position
	var half_way_position = absf(pos_second.y - pos_first.y) / 2

	while not obj.canceled:
		await Game.tick
		var vehicle = Game.get_local_vehicle()
		var vehicle_position = vehicle.get_absolute_position()
		
		var diff_y = vehicle_position.y - second_launchpad.global_position.y
		
		if diff_y < half_way_position + measurement_gap and diff_y > maximum_threshold:
			Gui.prompt("You're already halfway there!", false, true, _NO_ANIM)
		
		if diff_y < maximum_threshold and diff_y > desired_threshold:
			Gui.prompt("Approaching our refuel spot! Control your speed and direction.", false, true, _NO_ANIM)
		
		if diff_y < desired_threshold and diff_y > 0:
			Gui.prompt("You are above the launchpad! Press [color=$H]K[/color] to hover above it. ", false, true, _NO_ANIM)
			
			var altitude = vehicle.get_vectors().surface_position.length_squared()
			var speed = vehicle.get_relative_velocity().length_squared()
			var landed = altitude < 1 and speed < 0.01
			
			if landed:
				# Cast a ray from the vehicle towards the center of the body
				var from = vehicle.to_global(Vector3.UP)
				var to = vehicle.get_orbited_body().get_absolute_position()
				var query = PhysicsRayQueryParameters3D.create(from, to)
				query.exclude = [vehicle.get_rid()]
				var result = vehicle.get_world_3d().direct_space_state.intersect_ray(query)
	
				# If the ray picked the launchpad, then we landed straight on top of
				# it; complete the objective
				if result and result.collider.scene_file_path == _LAUNCHPAD_SCENE:
					vehicle.propellant_consumed = 0
					vehicle.rcs_propellant_consumed = 0
					
					obj.completed = true
				# Otherwise we landed somewhere else; fail the objective
				else:
					await Gui.prompt("Well... at least you tried! But uh, any ideas on how we’re refueling now?")
					await Gui.prompt("[color=red]Try again![/color]")
					obj.failed = true
				break
		
		if diff_y + measurement_gap < 0:
			Gui.prompt("Oops... it looks like you overshot the launchpad.", false, true, _NO_ANIM)
	
	if obj.canceled:
		return
	
	obj.completed = true

# Objective 9 - Let land on it
func _objective_9_refuel(obj: Objective):
	Gui.prompt_canceled.connect(func (): obj.canceled = true, CONNECT_ONE_SHOT)
	
	_hint('Switch')
	Gui.prompt("Don't forget to turn off the engines! Remember, safety - first!", false)
	while !obj.canceled:
		await Game.tick
		if not Game.get_local_vehicle().get_assembly().is_engine_enabled(0):
			break
	_hint('')
	
	_hint('Fuel')
	await Gui.prompt("Congratulations, pilot! Your fuel tanks are now fuller than a black hole’s appetite!")
	_hint('')

	obj.completed = true
Editor is loading...
Leave a Comment