Randoloot/scripts/planets/expedition_controller.gd
2026-10-18 08:43:54 +02:00

235 lines
8.2 KiB
GDScript

extends Node
const UI := preload("res://scripts/planets/expedition_ui.gd")
var game: Node2D
var player: CharacterBody2D
var freighter: Node2D
var screen: Control
var _layer: CanvasLayer
var _prompt: PanelContainer
var _text: Label
var _scan_button: Button
var _land_button: Button
var _near_planet: Node2D
var _message := ""
var _message_time := 0.0
var _previous_pause := false
var _previous_docked := false
var _hud_was_visible := true
var _prompt_refresh_time := 0.0
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
name = "PlanetExpeditions"
get_tree().auto_accept_quit = false
freighter = Node2D.new()
freighter.name = "Freighter"
freighter.position = Vector2(480,-270)
game.add_child(freighter)
var sprite := Sprite2D.new()
sprite.texture = preload("res://assets/planets/freighter.png")
sprite.scale = Vector2.ONE * 190.0 / maxf(sprite.texture.get_width(),sprite.texture.get_height())
freighter.add_child(sprite)
var label := Label.new()
label.text = "FRACHTOWIEC [L]"
label.position = Vector2(-95,75)
label.add_theme_font_size_override("font_size",15)
label.add_theme_color_override("font_color",UI.CYAN)
freighter.add_child(label)
_layer = CanvasLayer.new()
_layer.layer = 60
add_child(_layer)
_prompt = UI.panel(_layer,Vector2(440,0))
var column := VBoxContainer.new()
_prompt.add_child(column)
_text = UI.label(column,"",14)
_text.custom_minimum_size.x = 420
_text.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
var row := HBoxContainer.new()
column.add_child(row)
_scan_button = UI.button(row,"SKANUJ [F]",scan_nearby)
_land_button = UI.button(row,"LĄDUJ [L]",land_nearby)
_prompt.hide()
get_viewport().size_changed.connect(_layout_prompt)
func combat_blocked() -> bool:
if float(player.get("landing_combat_lock")) > 0:
return true
for enemy in get_tree().get_nodes_in_group("enemies"):
if enemy is Node2D and player.global_position.distance_to(enemy.global_position) < 650:
return true
return false
func _process(delta: float) -> void:
_message_time = maxf(0, _message_time - delta)
if is_instance_valid(screen) or get_tree().paused or bool(player.get("_is_destroyed")):
_prompt.hide()
return
_prompt_refresh_time += delta
# Proximity hints do not need to rebuild at the rendering frame rate.
if delta > 0 and _prompt_refresh_time < 0.1:
return
_prompt_refresh_time = 0
_refresh_prompt()
func _refresh_prompt() -> void:
_near_planet = null
var best := INF
for planet in get_tree().get_nodes_in_group("scanner_planets"):
if not bool(planet.get("earthlike")):
continue
var distance: float = player.global_position.distance_to(planet.global_position) - float(planet.get("radius"))
if distance < 190 and distance < best:
best = distance
_near_planet = planet
var nearby_freighter := player.global_position.distance_squared_to(freighter.global_position) < 230.0 * 230.0
var has_destination := nearby_freighter or is_instance_valid(_near_planet)
if not has_destination and _message_time <= 0:
_prompt.hide()
# Never accumulate combat text while the hint is hidden.
if not _text.text.is_empty():
_text.text = ""
return
var blocked := combat_blocked()
if blocked:
_prompt.hide()
return
var text := ""
if _message_time > 0:
text = _message
elif nearby_freighter:
text = "FRACHTOWIEC · Hangar / Warsztat / Laboratorium"
else:
var profile: Dictionary = _near_planet.planet_profile
if GameState.captain.expedition.scans.has(profile.id):
text = preload("res://scripts/planets/planet_profiles.gd").scan_description(profile,GameState.captain)
else:
text = "%s / EARTHLIKE\nZeskanuj warunki przed lądowaniem." % profile.name
if blocked and _message_time <= 0:
text += "\nDokowanie i lądowanie zablokowane podczas walki."
var changed := _text.text != text or _scan_button.visible != (is_instance_valid(_near_planet) and not nearby_freighter) or _land_button.visible != has_destination
if _text.text != text:
_text.text = text
_scan_button.visible = is_instance_valid(_near_planet) and not nearby_freighter
_land_button.visible = has_destination
_land_button.text = "DOKUJ [L]" if nearby_freighter else "LĄDUJ [L]"
_land_button.disabled = blocked
_prompt.show()
if changed:
# A standalone PanelContainer otherwise keeps its previous large height.
_layout_prompt.call_deferred()
func _layout_prompt() -> void:
if not is_instance_valid(_prompt):
return
_prompt.size = Vector2(460, _prompt.get_combined_minimum_size().y)
var viewport_size := get_viewport().get_visible_rect().size
_prompt.position = Vector2((viewport_size.x - _prompt.size.x) * 0.5, maxf(16, viewport_size.y - _prompt.size.y - 160))
func _unhandled_key_input(event: InputEvent) -> void:
if is_instance_valid(screen) or get_tree().paused or not event.pressed or event.echo:
return
if event.keycode == KEY_F:
scan_nearby()
elif event.keycode == KEY_L:
land_nearby()
else:
return
get_viewport().set_input_as_handled()
func scan_nearby() -> void:
_refresh_prompt()
if not is_instance_valid(_near_planet):
return
GameState.captain.expedition.scan(_near_planet.planet_profile)
_message_time = 0
_refresh_prompt()
func land_nearby() -> void:
_refresh_prompt()
if is_instance_valid(screen) or bool(player.get("_is_destroyed")):
return
if combat_blocked():
_notice("Odsuń się od przeciwników i zakończ walkę.")
return
if player.global_position.distance_to(freighter.global_position) < 230:
open_freighter()
return
if not is_instance_valid(_near_planet):
return
var progress: Resource = GameState.captain.expedition
if not progress.scans.has(_near_planet.planet_profile.id):
scan_nearby()
return
if not progress.begin_visit(_near_planet.planet_profile):
_notice("Lądownik wymaga naprawy do 100% we frachtowcu.")
return
_enter()
screen = Control.new()
screen.set_script(preload("res://scripts/planets/surface_screen.gd"))
screen.captain = GameState.captain
screen.progress = progress
screen.flight_ship = player
screen.finished.connect(finish_surface)
_layer.add_child(screen)
func open_freighter() -> void:
_enter()
screen = Control.new()
screen.set_script(preload("res://scripts/planets/freighter_screen.gd"))
screen.captain = GameState.captain
screen.inventory = player.get_node("ShipInventory")
screen.closed.connect(_leave)
_layer.add_child(screen)
func _enter() -> void:
_previous_pause = get_tree().paused
_previous_docked = player.is_docked
_hud_was_visible = game.get_node("HUD/HUDRoot").visible
game.get_node("HUD/HUDRoot").hide()
player.is_docked = true
player.velocity = Vector2.ZERO
get_tree().paused = true
_prompt.hide()
func finish_surface(success: bool) -> void:
var progress: Resource = GameState.captain.expedition
var result: Dictionary = progress.finish_visit(GameState.captain,success)
progress.deliver_modules(player.get_node("ShipInventory"))
_leave()
var returned: Dictionary = result.get("materials",{}).duplicate()
if int(result.get("parts",0)) > 0: returned.parts = result.parts
if int(result.get("missiles",0)) > 0: returned.missile = result.missiles
if int(result.get("credits",0)) > 0: returned.credits = result.credits
var cargo_text := UI.material_text(returned)
_notice(("POWRÓT Z WYPRAWY · " + (cargo_text if not cargo_text.is_empty() else "brak łupu")) if result.get("success",false) else "LĄDOWNIK ZNISZCZONY · Utracono łup bieżącej wyprawy.")
if not progress.delivered_modules.is_empty():
_message += "\nBrak miejsca: %d modułów czeka we frachtowcu." % progress.delivered_modules.size()
func _leave() -> void:
if is_instance_valid(screen):
_layer.remove_child(screen)
screen.queue_free()
screen = null
player.is_docked = _previous_docked
game.get_node("HUD/HUDRoot").visible = _hud_was_visible
get_tree().paused = _previous_pause
func _notice(message: String) -> void:
_message = message
_message_time = 7
_prompt_refresh_time = 0.1
func _notification(what: int) -> void:
if what == NOTIFICATION_WM_CLOSE_REQUEST:
if GameState.captain.expedition.active:
GameState.captain.expedition.finish_visit(GameState.captain,true)
get_tree().quit()
func _exit_tree() -> void:
if is_instance_valid(GameState.captain) and GameState.captain.expedition.active:
GameState.captain.expedition.finish_visit(GameState.captain,true)
if is_instance_valid(screen):
get_tree().paused = _previous_pause
get_tree().auto_accept_quit = true