Arcology Update

updated textures and collision on Young Arcology
This commit is contained in:
scorpion21211-cmd
2026-10-10 00:39:35 -04:00
parent 84e22fe12e
commit 369a0e2b52
59 changed files with 467 additions and 9438 deletions
+121 -120
View File
@@ -1,5 +1,6 @@
extends CharacterBody3D
## PASTE 2026-09-27 — Station volume includes pads. Habitat trimesh collision + stair step.
## PASTE 2026-10-10 — Habitat trimesh. View stairs + port ring are floors.
@export var speed: float = 5.5
@export var sprint_speed: float = 9.0
@@ -75,6 +76,8 @@ const WALK_FLOORS: Array[String] = [
"Yard_Bridges", "Yard_Stairs", "Yard_CollarWalk", "Yard_Piers",
"Dock_Gallery", "Dock_Threshold",
"Elev_Landings", "Fusion_Basemat", "Fusion_AmbulatoryWide",
"Fusion_HeaderStands",
"Port_Ring",
"Live_Terraces",
]
const WALK_WALLS: Array[String] = [
@@ -117,14 +120,34 @@ var interact_cd: float = 0.0
var jump_anim_cd: float = 0.0
var _crust_on: bool = false
var _moon_colliders: Array[PhysicsBody3D] = []
var _movement_input: Vector2 = Vector2.ZERO
var _fire_requested: bool = false
func _ensure_action(action: String, keycode: Key) -> void:
if not InputMap.has_action(action):
InputMap.add_action(action)
for ev in InputMap.action_get_events(action):
if ev is InputEventKey and (ev as InputEventKey).physical_keycode == keycode:
return
var evk := InputEventKey.new()
evk.physical_keycode = keycode
InputMap.action_add_event(action, evk)
func _ensure_default_actions() -> void:
_ensure_action("interact", KEY_F)
_ensure_action("mag_boots", KEY_C)
_ensure_action("toggle_mag_boots", KEY_C)
_ensure_action("toggle_pistol", KEY_G)
_ensure_action("reload", KEY_R)
_ensure_action("toggle_inventory", KEY_TAB)
_ensure_action("toggle_first_person", KEY_V)
_ensure_action("sprint", KEY_SHIFT)
_ensure_action("eva_roll_left", KEY_Q)
_ensure_action("eva_roll_right", KEY_E)
func _ready() -> void:
GameplayInput.command_requested.connect(_handle_gameplay_command)
GameplayInput.transient_input_cleared.connect(_clear_player_input)
GameplayInput.set_context(GameplayInput.Context.ON_FOOT)
_ensure_default_actions()
scale = Vector3.ONE
safe_margin = 0.05
floor_snap_length = 0.45
@@ -363,7 +386,6 @@ func _find_l5_spawn() -> Node3D:
func set_in_vehicle(value: bool) -> void:
in_vehicle = value
_clear_player_input()
if value:
pressurized = true
_set_moon_surface_visible(true)
@@ -389,10 +411,7 @@ func _update_waist_aim() -> void:
look_loader.set_aim_pitch(pitch)
## Updates device-independent camera look before existing visual camera smoothing.
func _process(delta: float) -> void:
if not in_vehicle:
_update_player_look(delta)
if first_person:
_cam_pos_target = _fp_cam_pos()
_update_fp_meshes()
@@ -707,17 +726,92 @@ func _set_alt_look(on: bool) -> void:
camera_pivot.rotation.z = 0.0
## Keeps development shortcuts separate from remappable gameplay controls.
func _unhandled_input(event: InputEvent) -> void:
if in_vehicle or not GameplayInput.gameplay_enabled():
if in_vehicle:
return
if vendor_menu and vendor_menu.visible:
if event.is_action_pressed("ui_cancel"):
close_vendor_menu()
return
if event is InputEventKey and event.keycode == KEY_QUOTELEFT:
if event.pressed:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
if not get_tree().paused and not (vendor_menu and vendor_menu.visible):
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
return
if event is InputEventKey and event.keycode == KEY_ALT:
_set_alt_look(event.pressed)
return
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT:
if pistol_drawn:
ads = event.pressed
_apply_camera_mode(false)
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
if pistol_drawn:
_try_fire()
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
if _is_eva():
# Whole-body look in 1P and 3P EVA. World-Y yaw felt broken after a roll.
rotate_object_local(Vector3.UP, -event.relative.x * mouse_sensitivity)
rotate_object_local(Vector3.RIGHT, -event.relative.y * mouse_sensitivity)
if camera_pivot:
camera_pivot.rotation = Vector3.ZERO
elif first_person:
if free_looking:
# Euler SET — rotate_x+rotate_y on a pitched pivot was the warp.
free_look_yaw -= event.relative.x * mouse_sensitivity
free_look_pitch -= event.relative.y * mouse_sensitivity
free_look_pitch = clamp(free_look_pitch, deg_to_rad(-78), deg_to_rad(62))
free_look_yaw = clamp(free_look_yaw, deg_to_rad(-75), deg_to_rad(75))
camera_pivot.rotation = Vector3(free_look_pitch, free_look_yaw, 0.0)
else:
rotate_y(-event.relative.x * mouse_sensitivity)
camera_pivot.rotate_x(-event.relative.y * mouse_sensitivity)
camera_pivot.rotation.x = clamp(camera_pivot.rotation.x, deg_to_rad(-78), deg_to_rad(85))
elif free_looking:
free_look_yaw -= event.relative.x * free_look_sensitivity
free_look_pitch -= event.relative.y * free_look_sensitivity
free_look_pitch = clamp(free_look_pitch, deg_to_rad(-80), deg_to_rad(80))
if camera_pivot:
camera_pivot.rotation.y = free_look_yaw
camera_pivot.rotation.x = free_look_pitch
else:
rotate_y(-event.relative.x * mouse_sensitivity)
camera_pivot.rotate_x(-event.relative.y * mouse_sensitivity)
camera_pivot.rotation.x = clamp(camera_pivot.rotation.x, deg_to_rad(-78), deg_to_rad(55))
if event is InputEventKey and event.pressed and not event.echo:
match event.keycode:
KEY_1:
_toggle_pistol()
KEY_F3:
_debug_fp_eye()
KEY_F4:
if look_loader and look_loader.has_method("cycle_arm_axis"):
look_loader.cycle_arm_axis()
if event.is_action_pressed("interact"):
if can_interact and current_interactable:
_try_interact()
if event.is_action_pressed("mag_boots"):
mag_boots_on = not mag_boots_on
if mag_boots_on:
eva_peak_height = 0.0
velocity = velocity.slide(_walk_up()) * 0.35
_align_walk(_walk_up())
_reset_camera_to_walk()
print("Mag Boots: ", "ON" if mag_boots_on else "OFF")
if event.is_action_pressed("toggle_pistol"):
_toggle_pistol()
if event.is_action_pressed("reload"):
_reload_pistol()
if event.is_action_pressed("toggle_inventory"):
inventory_open = not inventory_open
if event.is_action_pressed("toggle_first_person"):
if in_vehicle:
return
first_person = not first_person
_set_alt_look(false)
_apply_camera_mode(false)
if event.is_action_pressed("ui_page_up"):
food = min(food + 25.0, 100.0)
if event.is_action_pressed("ui_page_down"):
@@ -734,93 +828,6 @@ func _unhandled_input(event: InputEvent) -> void:
banner.hide_banner()
## Dispatches device-independent commands only while the player owns control.
func _handle_gameplay_command(action: StringName, command_context: int) -> void:
if in_vehicle or command_context != GameplayInput.Context.ON_FOOT or GameplayInput.context != command_context:
return
match action:
&"interact":
if can_interact and current_interactable:
_try_interact()
&"combat_fire":
_fire_requested = pistol_drawn
&"combat_reload":
_reload_pistol()
&"combat_toggle_weapon":
_toggle_pistol()
&"character_toggle_inventory":
inventory_open = not inventory_open
&"toggle_view":
first_person = not first_person
_set_alt_look(false)
_apply_camera_mode(false)
&"character_toggle_mag_boots":
_toggle_magnetic_boots()
## Toggles boots without changing the existing landing or gravity mechanics.
func _toggle_magnetic_boots() -> void:
mag_boots_on = not mag_boots_on
if mag_boots_on:
eva_peak_height = 0.0
velocity = velocity.slide(_walk_up()) * 0.35
_align_walk(_walk_up())
_reset_camera_to_walk()
print("Mag Boots: ", "ON" if mag_boots_on else "OFF")
## Clears pending shots and held camera states at input ownership boundaries.
func _clear_player_input() -> void:
_movement_input = Vector2.ZERO
_fire_requested = false
ads = false
_set_alt_look(false)
_apply_camera_mode(false)
## Combines mouse displacement and time-scaled controller turn rate once per frame.
func _update_player_look(delta: float) -> void:
var cursor_released := GameplayInput.is_held(&"release_cursor")
if GameplayInput.gameplay_enabled():
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE if cursor_released else Input.MOUSE_MODE_CAPTURED
var next_freelook := GameplayInput.is_held(&"freelook")
if next_freelook != free_looking:
_set_alt_look(next_freelook)
var next_aim := pistol_drawn and GameplayInput.is_held(&"combat_aim")
if next_aim != ads:
ads = next_aim
_apply_camera_mode(false)
var mouse_displacement := GameplayInput.consume_mouse_displacement()
if cursor_released:
return
var sensitivity := free_look_sensitivity if free_looking and not first_person else mouse_sensitivity
_apply_player_look(mouse_displacement * sensitivity + GameplayInput.read_controller_look(delta))
## Applies radians of yaw/pitch to existing walking, freelook, and body-local EVA modes.
func _apply_player_look(look_delta: Vector2) -> void:
if camera_pivot == null or look_delta == Vector2.ZERO:
return
if _is_eva():
rotate_object_local(Vector3.UP, -look_delta.x)
rotate_object_local(Vector3.RIGHT, -look_delta.y)
camera_pivot.rotation = Vector3.ZERO
elif free_looking:
free_look_yaw -= look_delta.x
free_look_pitch -= look_delta.y
var minimum_pitch := deg_to_rad(-78.0) if first_person else deg_to_rad(-80.0)
var maximum_pitch := deg_to_rad(62.0) if first_person else deg_to_rad(80.0)
free_look_pitch = clampf(free_look_pitch, minimum_pitch, maximum_pitch)
if first_person:
free_look_yaw = clampf(free_look_yaw, deg_to_rad(-75.0), deg_to_rad(75.0))
camera_pivot.rotation = Vector3(free_look_pitch, free_look_yaw, 0.0)
else:
rotate_y(-look_delta.x)
var maximum_pitch := deg_to_rad(85.0) if first_person else deg_to_rad(55.0)
camera_pivot.rotation.x = clampf(camera_pivot.rotation.x - look_delta.y, deg_to_rad(-78.0), maximum_pitch)
## Samples movement once and consumes queued jump/fire requests on physics ticks.
func _physics_process(delta: float) -> void:
_update_crust_exception()
if fire_cd > 0.0:
@@ -834,12 +841,6 @@ func _physics_process(delta: float) -> void:
if vendor_menu and vendor_menu.visible:
velocity = Vector3.ZERO
return
_movement_input = GameplayInput.read_movement()
var jump_requested := GameplayInput.consume_jump_request()
if _fire_requested:
_fire_requested = false
if GameplayInput.gameplay_enabled() and pistol_drawn:
_try_fire()
if is_on_floor():
coyote_time = 0.14
else:
@@ -848,15 +849,17 @@ func _physics_process(delta: float) -> void:
var gvec: Vector3 = _soi_gravity()
if _is_eva():
_set_body_visible(true)
var roll_input := GameplayInput.read_axis(&"eva_roll_left", &"eva_roll_right")
rotate_object_local(Vector3.FORWARD, roll_input * 2.2 * delta)
if Input.is_action_pressed("eva_roll_left") or Input.is_key_pressed(KEY_Q):
rotate_object_local(Vector3.FORWARD, -2.2 * delta)
if Input.is_action_pressed("eva_roll_right") or Input.is_key_pressed(KEY_E):
rotate_object_local(Vector3.FORWARD, 2.2 * delta)
if gvec.length() > 0.01:
velocity += gvec * delta
var input_dir_eva: Vector2 = _movement_input
if input_dir_eva.length() > 0.001:
var input_dir_eva: Vector2 = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
if input_dir_eva.length() > 0.1:
var thrust: Vector3 = (
-transform.basis.z * -input_dir_eva.y + transform.basis.x * input_dir_eva.x
) * speed * 0.35
).normalized() * speed * 0.35
velocity += thrust * delta
move_and_slide()
_process_needs(delta)
@@ -876,13 +879,13 @@ func _physics_process(delta: float) -> void:
else:
g_amt = maxf(g_amt, MOON_G)
velocity += -up * g_amt * delta
var input_dir: Vector2 = _movement_input
var input_dir: Vector2 = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var direction: Vector3 = (transform.basis * Vector3(input_dir.x, 0.0, input_dir.y)).slide(up)
if direction.length() > 0.001:
direction = direction.normalized() * input_dir.length()
direction = direction.normalized()
else:
direction = Vector3.ZERO
var want_sprint: bool = GameplayInput.sprint_enabled and input_dir.y < -0.12
var want_sprint: bool = Input.is_action_pressed("sprint") and input_dir.y < -0.12
var current_speed: float = sprint_speed if want_sprint else speed
if ads and pistol_drawn:
current_speed *= ads_sprint_scale if want_sprint else ads_walk_scale
@@ -904,13 +907,13 @@ func _physics_process(delta: float) -> void:
velocity = v_h + up * v_up
# Jump LAST so floor rebuild cannot eat or replace the impulse.
var can_jump: bool = is_on_floor() or coyote_time > 0.0
if jump_requested and can_jump:
if Input.is_action_just_pressed("ui_accept") and can_jump:
coyote_time = 0.0
jump_anim_cd = 0.45
var jv: float = 1.7 if mag_boots_on else 6.4
velocity = velocity.slide(up) + up * jv
print("JUMP boots=", mag_boots_on, " jv=", jv, " g=", g_amt, " floor=", is_on_floor())
if is_on_floor() and not jump_requested:
if is_on_floor() and not Input.is_action_just_pressed("ui_accept"):
_try_step(up)
move_and_slide()
_keep_walk_upright()
@@ -1033,7 +1036,6 @@ func open_vendor_menu() -> void:
func close_vendor_menu() -> void:
if vendor_menu:
vendor_menu.visible = false
GameplayInput.set_menu_open(vendor_menu, false)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
@@ -1056,10 +1058,10 @@ func _update_animations() -> void:
_play_move_anim("Idle")
return
# Stick, not velocity — accel must not pick the clip.
var stick: Vector2 = _movement_input
var stick: Vector2 = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var strafe: float = clampf(stick.x, -1.0, 1.0)
var back: float = clampf(stick.y, -1.0, 1.0)
var want_sprint: bool = GameplayInput.sprint_enabled and stick.y < -0.12
var want_sprint: bool = Input.is_action_pressed("sprint") and stick.y < -0.12
var run_amt: float = 1.0 if want_sprint else 0.0
if look_loader and look_loader.has_method("set_loco"):
look_loader.set_loco(strafe, back, run_amt, dt, _is_aiming())
@@ -1074,7 +1076,7 @@ func _update_animations() -> void:
func _update_hud() -> void:
if needs_label:
var interact_text: String = " [%s] Use" % GameplayInput.binding_label(&"interact") if can_interact else ""
var interact_text: String = " [F] Use" if can_interact else ""
var gun_text: String = ""
if pistol_drawn:
gun_text = " | PISTOL %d/%d%s" % [pistol_ammo, pistol_reserve, " ADS" if ads else ""]
@@ -1283,4 +1285,3 @@ func _try_step(up: Vector3) -> void:
if lift < 0.04 or lift > STEP_HEIGHT:
return
global_position += up * (lift + 0.02)