Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Normalize EOL for all files that Git considers text files.
|
||||||
|
* text=auto eol=lf
|
||||||
|
*.afphoto filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.debug filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.dll filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.dylib filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.exr filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.fbx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.glb filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.gltf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.hdr filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ogg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.psd filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.release filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.res filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.so filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.stl filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tif filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Use this report form if you encounter a bug.
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Cogito and Godot Engine Version:**
|
||||||
|
Please insert which version number you were using when you encountered the bug.
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**Reproduction steps:**
|
||||||
|
Please describe the steps taken to reproduce the bug.
|
||||||
|
Please include any error messages and debug logs.
|
||||||
|
|
||||||
|
**Expected behavior:**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots:**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: Discussion
|
||||||
|
about: Use this template if you want to open a discussion instead of a specific issue.
|
||||||
|
title: ''
|
||||||
|
labels: discussion
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Discussion:**
|
||||||
|
_Describe what specific topic or feature you want to discuss. Ask any questions you are seeking information or opinions on._
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
/android/
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[gd_scene format=3 uid="uid://d1emcjtgqmu31"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://br0vxsoinqwe1" path="res://Scenes/Scripts/habitat_builder.gd" id="1_cr4kg"]
|
||||||
|
|
||||||
|
[node name="Node3D" type="Node3D" unique_id=1465062391]
|
||||||
|
|
||||||
|
[node name="HabitatBuilder" type="Node" parent="." unique_id=1836044845]
|
||||||
|
script = ExtResource("1_cr4kg")
|
||||||
|
young_embed_m = 40.0
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Phazorknight
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
This is the standard FREE version of the Modular SciFi MegaKit, which only contains
|
||||||
|
a portion of the models . You can buy the PRO version which has all the models,
|
||||||
|
or the SOURCE version which has all the models and also includes Unity(URP), Unreal Engine and Godot projects
|
||||||
|
with custom shaders already set up.
|
||||||
|
|
||||||
|
You can get the other versions from the website https://quaternius.com
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
License:
|
||||||
|
CC0 1.0 Universal (CC0 1.0)
|
||||||
|
Public Domain Dedication
|
||||||
|
https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
|
------------------------------------------------------
|
||||||
|
Models by @Quaternius
|
||||||
|
Consider supporting me on Patreon!
|
||||||
|
|
||||||
|
https://www.patreon.com/quaternius
|
||||||
|
|
||||||
|
-------------------------------------------------------
|
||||||
|
Join the Discord Server:
|
||||||
|
https://discord.gg/vJqnRUYRfT
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://3j8q2ljffqjp"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bf63eg11cuqij" path="res://Kyle's Rock Pack/Kyle Fuji/Scenes/Textures/T_flag.png" id="1_3fh8f"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
cull_mode = 2
|
||||||
|
albedo_texture = ExtResource("1_3fh8f")
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[gd_resource type="StandardMaterial3D" format=3 uid="uid://c1mm1y80k6872"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,45 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://j1hw1m4qj2at"
|
||||||
|
path="res://.godot/imported/flag.glb-fe545f4d774c55d809d86958009a1051.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Scenes/Models/flag.glb"
|
||||||
|
dest_files=["res://.godot/imported/flag.glb-fe545f4d774c55d809d86958009a1051.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
mesh_library/use_node_names_as_mesh_names=false
|
||||||
|
array_mesh/deduplicate_surfaces=true
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
gltf/naming_version=2
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
|
gltf/texture_map_mode=0
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,45 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://dlbqbjm60jqyc"
|
||||||
|
path="res://.godot/imported/flag_pole.glb-c5f6f3f40eba4f0eae5b3f172d409e4a.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Scenes/Models/flag_pole.glb"
|
||||||
|
dest_files=["res://.godot/imported/flag_pole.glb-c5f6f3f40eba4f0eae5b3f172d409e4a.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
mesh_library/use_node_names_as_mesh_names=false
|
||||||
|
array_mesh/deduplicate_surfaces=true
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
gltf/naming_version=2
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
|
gltf/texture_map_mode=0
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[gd_scene format=3 uid="uid://byn3aoaubhy14"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://b6eo746yujjtr" path="res://character assets/Characters/BlueSoldier_Male.gltf" id="1_igigs"]
|
||||||
|
|
||||||
|
[node name="Node3D" type="Node3D" unique_id=301609784]
|
||||||
|
|
||||||
|
[node name="BlueSoldier_Male" parent="." unique_id=1455949063 instance=ExtResource("1_igigs")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.46351385, 0, 0.793349)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://dsuep54iqmwqv"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://j1hw1m4qj2at" path="res://Kyle's Rock Pack/Kyle Fuji/Scenes/Models/flag.glb" id="1_s1rd0"]
|
||||||
|
[ext_resource type="Material" uid="uid://3j8q2ljffqjp" path="res://Kyle's Rock Pack/Kyle Fuji/Scenes/Materials/M_flag.tres" id="2_s1rd0"]
|
||||||
|
|
||||||
|
[node name="flag" instance=ExtResource("1_s1rd0")]
|
||||||
|
|
||||||
|
[node name="flag" parent="." index="0"]
|
||||||
|
transform = Transform3D(0.36920106, 0.00010158674, 0.00026268276, 0.00026271862, -0.00012781133, -0.36920106, -0.00010149403, 0.36920115, -0.00012788495, 0, 1.5941696, 0)
|
||||||
|
material_override = ExtResource("2_s1rd0")
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://cfo28kg1g1tln"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dlbqbjm60jqyc" path="res://Kyle's Rock Pack/Kyle Fuji/Scenes/Models/flag_pole.glb" id="1_0l7o7"]
|
||||||
|
[ext_resource type="Material" uid="uid://c1mm1y80k6872" path="res://Kyle's Rock Pack/Kyle Fuji/Scenes/Materials/M_flag_pole.tres" id="2_472wk"]
|
||||||
|
|
||||||
|
[node name="flag_pole" instance=ExtResource("1_0l7o7")]
|
||||||
|
|
||||||
|
[node name="flag_pole" parent="." index="0"]
|
||||||
|
material_override = ExtResource("2_472wk")
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://d0l38f4125c54"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dsuep54iqmwqv" path="res://Kyle's Rock Pack/Kyle Fuji/Scenes/Prefabs/flag helpers/flag_cloth.tscn" id="1_s1rd0"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cfo28kg1g1tln" path="res://Kyle's Rock Pack/Kyle Fuji/Scenes/Prefabs/flag helpers/flag_pole.tscn" id="2_0bfkk"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_s1rd0"]
|
||||||
|
size = Vector3(1.0652161, 2.0059204, 0.19836426)
|
||||||
|
|
||||||
|
[node name="flag" type="Node3D" groups=["flag_group"]]
|
||||||
|
transform = Transform3D(2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0)
|
||||||
|
|
||||||
|
[node name="flag" parent="." groups=["flag_group"] instance=ExtResource("1_s1rd0")]
|
||||||
|
|
||||||
|
[node name="flag_pole" parent="." groups=["flag_group"] instance=ExtResource("2_0bfkk")]
|
||||||
|
|
||||||
|
[node name="StaticBody3D" type="StaticBody3D" parent="." groups=["flag_group"]]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" groups=["flag_group"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.43354797, 0.99716187, 0.0067749023)
|
||||||
|
shape = SubResource("BoxShape3D_s1rd0")
|
||||||
Binary file not shown.
@@ -0,0 +1,46 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://ccu6j1dlrj0ll"
|
||||||
|
path="res://.godot/imported/RPG-Character-Bones.FBX-69d8ffcb296c2c499cb24733622b9379.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Scenes/RPG-Character-Bones.FBX"
|
||||||
|
dest_files=["res://.godot/imported/RPG-Character-Bones.FBX-69d8ffcb296c2c499cb24733622b9379.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
mesh_library/use_node_names_as_mesh_names=false
|
||||||
|
array_mesh/deduplicate_surfaces=true
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=true
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
fbx/importer=0
|
||||||
|
fbx/allow_geometry_helper_nodes=false
|
||||||
|
fbx/embedded_image_handling=1
|
||||||
|
fbx/naming_version=2
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var health_restore: float = 25.0
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_health"):
|
||||||
|
player.add_health(health_restore)
|
||||||
|
print("You rest for a while. Health restored.")
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d2cfgmuwrsr3y
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Beer Can"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://4dys8ga8ap02
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
extends Camera3D
|
||||||
|
|
||||||
|
@onready var capsule: Node3D = get_node("/root/Node3D/EscapeCapsule")
|
||||||
|
|
||||||
|
func _physics_process(_delta):
|
||||||
|
if not capsule:
|
||||||
|
return
|
||||||
|
|
||||||
|
var nose_dir = capsule.global_transform.basis.y
|
||||||
|
var up_dir = -capsule.global_transform.basis.z
|
||||||
|
|
||||||
|
global_position = capsule.global_position + nose_dir * 4.0
|
||||||
|
look_at(capsule.global_position + nose_dir * 30.0, up_dir)
|
||||||
|
|
||||||
|
# Fix upside-down
|
||||||
|
rotate_object_local(Vector3.FORWARD, deg_to_rad(180))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://di78d53y38p67
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
extends CharacterBody3D
|
||||||
|
|
||||||
|
# How fast the player moves in meters per second.
|
||||||
|
@export var speed = 14
|
||||||
|
# The downward acceleration when in the air, in meters per second squared.
|
||||||
|
@export var fall_acceleration = 75
|
||||||
|
@export var mouse_sensitivity = 0.002
|
||||||
|
const JUMP_VELOCITY = 25
|
||||||
|
|
||||||
|
var target_velocity = Vector3.ZERO
|
||||||
|
# Reference to your camera pivot or camera
|
||||||
|
@onready var pivot = $Pivot
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Captures the mouse cursor so it stays in the game window
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
rotate_y(-event.relative.x * mouse_sensitivity)
|
||||||
|
pivot.rotate_x(-event.relative.y * mouse_sensitivity)
|
||||||
|
pivot.rotation.x = clamp(pivot.rotation.x, deg_to_rad(-60), deg_to_rad(60))
|
||||||
|
|
||||||
|
if event.is_action_pressed("ui_cancel"):
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||||
|
|
||||||
|
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
|
||||||
|
if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE:
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
var direction = Vector3.ZERO
|
||||||
|
|
||||||
|
# need to map to WASD to make it work with WASD
|
||||||
|
if Input.is_action_pressed("ui_right"):
|
||||||
|
direction.x += 1
|
||||||
|
if Input.is_action_pressed("ui_left"):
|
||||||
|
direction.x -= 1
|
||||||
|
if Input.is_action_pressed("ui_down"):
|
||||||
|
direction.z += 1
|
||||||
|
if Input.is_action_pressed("ui_up"):
|
||||||
|
direction.z -= 1
|
||||||
|
|
||||||
|
if direction != Vector3.ZERO:
|
||||||
|
direction = direction.normalized()
|
||||||
|
direction = (transform.basis * direction).normalized()
|
||||||
|
|
||||||
|
# Ground Velocity
|
||||||
|
target_velocity.x = direction.x * speed
|
||||||
|
target_velocity.z = direction.z * speed
|
||||||
|
|
||||||
|
# Vertical Velocity
|
||||||
|
if not is_on_floor(): # If in the air, fall towards the floor. Literally gravity
|
||||||
|
target_velocity.y = target_velocity.y - (fall_acceleration * delta)
|
||||||
|
|
||||||
|
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
||||||
|
target_velocity.y = JUMP_VELOCITY
|
||||||
|
|
||||||
|
# Moving the Character
|
||||||
|
velocity = target_velocity
|
||||||
|
move_and_slide()
|
||||||
|
for i in get_slide_collision_count():
|
||||||
|
var collision = get_slide_collision(i)
|
||||||
|
var collided_object = collision.get_collider()
|
||||||
|
if collided_object.is_in_group("flag_group"):
|
||||||
|
$win_label.set_text("You Win!")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://flm6ps54u0c4
|
||||||
@@ -0,0 +1,459 @@
|
|||||||
|
extends Control
|
||||||
|
## Look preview + culture/job lore. Compact grid. No Dock Chaplain.
|
||||||
|
|
||||||
|
var name_input: LineEdit
|
||||||
|
var background_list: Control
|
||||||
|
var confirm_button: Button
|
||||||
|
var back_button: Button
|
||||||
|
var description_label: Label
|
||||||
|
var bonus_label: Label
|
||||||
|
var culture_list: Control
|
||||||
|
var look_world: Node3D
|
||||||
|
var preview_cam: Camera3D
|
||||||
|
var sex_male: Button
|
||||||
|
var sex_female: Button
|
||||||
|
var name_head: Label
|
||||||
|
var name_body: Label
|
||||||
|
var name_legs: Label
|
||||||
|
var name_feet: Label
|
||||||
|
|
||||||
|
const MALE_FBX := "res://character assets/All together/FBX/Humans_Master.fbx"
|
||||||
|
const FEMALE_FBX := "res://character assets/All together/FBX women/All together.fbx"
|
||||||
|
|
||||||
|
const MALE_HEADS := ["Casual_Head", "Casual2_Head", "Worker_Head", "Farmer_Head", "Adventurer_Head", "Punk_Head", "Suit_Head", "Swat_Head", "SpaceSuit_Head"]
|
||||||
|
const MALE_BODIES := ["Casual_Body", "Casual2_Body", "Worker_Body", "Farmer_Body", "Adventurer_Body", "Punk_Body", "Suit_Body", "Swat_Body", "SpaceSuit_Body"]
|
||||||
|
const MALE_LEGS := ["Casual_Legs", "Casual2_Legs", "Worker_Legs", "Farmer_Pants", "Adventurer_Legs", "Punk_Legs", "Suit_Legs", "Swat_Legs", "SpaceSuit_Legs"]
|
||||||
|
const MALE_FEET := ["Casual_Feet", "Casual2_Feet", "Worker_Feet", "Farmer_Feet", "Adventurer_Feet", "Punk_Feet", "Suit_Feet", "Swat_Feet", "SpaceSuit_Feet"]
|
||||||
|
const FEMALE_HEADS := ["Casual_Head", "Worker_Head", "Suit_Head", "Formal_Head", "Formad_Head", "Adventurer_Head", "Punk_Head", "Soldier_Head", "SciFi_Head"]
|
||||||
|
const FEMALE_BODIES := ["Casual_Body", "Worker_Body", "Suit_Body", "Formal_Body", "Adventurer_Body", "Punk_Body", "Soldier_Body", "SciFi_Body"]
|
||||||
|
const FEMALE_LEGS := ["Casual_Legs", "Worker_Legs", "Suit_Legs", "Formal_Legs", "Adventurer_Legs", "Punk_Legs", "Soldier_Legs", "SciFi_Legs"]
|
||||||
|
const FEMALE_FEET := ["Casual_Feet", "Worker_Feet", "Suit_Feet", "Formal_Feet", "Adventurer_Feet", "Punk_Feet", "Soldier_Feet", "SciFi_Feet"]
|
||||||
|
|
||||||
|
var sex: String = "male"
|
||||||
|
var idx := {"head": 0, "body": 0, "legs": 0, "feet": 0}
|
||||||
|
var preview_male: Node3D = null
|
||||||
|
var preview_female: Node3D = null
|
||||||
|
|
||||||
|
var cultures := [
|
||||||
|
{"id": "naf", "name": "North American", "desc": "You grew up under the NAF eagle — Mexico to Panama welded into one machine. English and Spanish in the same breath, carriers in the black, and a simple article of faith: the hemisphere holds, or nothing does."},
|
||||||
|
{"id": "eaa", "name": "East Asian", "desc": "EAA orthodoxy: long plans, short mercy. Beijing's shadow, Korean steel, Vietnamese patience. You learned early that the loudest claim in the room is rarely the one that survives."},
|
||||||
|
{"id": "european", "name": "European", "desc": "Old flags, thin coalitions, and the sound of Russia testing the locks. Paris, Berlin, London, Warsaw — still arguing while the sky hardens. You left with a ticket and no illusions about unity."},
|
||||||
|
{"id": "russian", "name": "Russian", "desc": "Victory parades and rationed truth. Ukraine was the lesson; the Baltics are the rumor that keeps generals warm. Orthodox steel, long winters, and a state that still treats the map as unfinished business."},
|
||||||
|
{"id": "brazilian", "name": "Brazilian", "desc": "Southern empire blood. Industry, orbit yards, and a continent that refuses to kneel to the north. You carry the heat of a country that builds its own guns and names its own heroes."},
|
||||||
|
{"id": "independent", "name": "Independent", "desc": "No anthem owns you. Station brats, belt orphans, passport ghosts — you answer to contracts, crew, and the thin margin between air and vacuum."}
|
||||||
|
]
|
||||||
|
|
||||||
|
var backgrounds := [
|
||||||
|
{"id": "dock_worker", "name": "Dock Worker", "desc": "Hard vacuum on one side of the hatch, warehouse stink on the other. You stacked the mass that keeps Young alive and learned every lie a shipping manifest can tell.", "bonuses": {"money": 90}},
|
||||||
|
{"id": "junior_engineer", "name": "Junior Engineer", "desc": "When the lights brown out, they call you. Breakers, scrubbers, jury-rigged miracles — you keep the arcology's pulse steady with a multitool and bad coffee.", "bonuses": {"money": 100}},
|
||||||
|
{"id": "med_tech", "name": "Med Tech", "desc": "Blood on the deck plating, timers on the monitors. You stabilize what the station breaks and don't ask whether the patient salutes the same flag you do.", "bonuses": {"money": 95, "health": 10}},
|
||||||
|
{"id": "smuggler", "name": "Smuggler", "desc": "Customs is a suggestion; the real map is drawn in debts. You moved what official channels refused to name — and you got paid in silence and credits.", "bonuses": {"money": 120}},
|
||||||
|
{"id": "security_cadet", "name": "Security Cadet", "desc": "Badge, route, rules of engagement written by people who sleep in better modules. You've already learned how fast procedure burns when someone runs.", "bonuses": {"money": 85, "health": 5}},
|
||||||
|
{"id": "botanist", "name": "Botanist", "desc": "Oxygen has a green face. You worked the trays and towers that turn waste into breath — the quietest strategic asset on the Moon.", "bonuses": {"money": 80, "food": 15}},
|
||||||
|
{"id": "skiff_pilot", "name": "Skiff Pilot", "desc": "Low and fast over dead regolith. Hop routes, run supplies, and trust the aerospace skills that keep you off the crater floor.", "bonuses": {"money": 105}},
|
||||||
|
{"id": "life_support_tech", "name": "Life Support Tech", "desc": "Pressure, CO₂, water loops — the boring systems that kill everyone when they fail. You listened to the station the way a doctor listens to a chest.", "bonuses": {"money": 95}},
|
||||||
|
{"id": "university_aide", "name": "University Aide", "desc": "Tsiolkovsky Hall: fusion on the chalkboard, rumors in the aisle. Dr Ernesto talks brachistochrones like scripture. You fetched the data and heard the future early.", "bonuses": {"money": 75}},
|
||||||
|
{"id": "unemployed", "name": "Unemployed", "desc": "No contract, no module lease, no one to vouch. Just a name on a transit list and a short window to become necessary.", "bonuses": {"money": 40}}
|
||||||
|
]
|
||||||
|
|
||||||
|
var selected_culture: Dictionary = {}
|
||||||
|
var selected_background: Dictionary = {}
|
||||||
|
var background_buttons: Array[Button] = []
|
||||||
|
var culture_buttons: Array[Button] = []
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
name_input = _find("NameInput") as LineEdit
|
||||||
|
background_list = _find("BackgroundL") as Control
|
||||||
|
if background_list == null:
|
||||||
|
background_list = _find("BackgroundList") as Control
|
||||||
|
confirm_button = _find("ConfirmButton") as Button
|
||||||
|
back_button = _find("BackButton") as Button
|
||||||
|
description_label = _find("DescriptionL") as Label
|
||||||
|
if description_label == null:
|
||||||
|
description_label = _find("DescriptionLabel") as Label
|
||||||
|
bonus_label = _find("BonusLabel") as Label
|
||||||
|
culture_list = _find("CultureList") as Control
|
||||||
|
look_world = _find("LookWorld") as Node3D
|
||||||
|
preview_cam = _find("LookCam") as Camera3D
|
||||||
|
sex_male = _find("SexMale") as Button
|
||||||
|
sex_female = _find("SexFemale") as Button
|
||||||
|
name_head = _find("Name_Head") as Label
|
||||||
|
name_body = _find("Name_Body") as Label
|
||||||
|
name_legs = _find("Name_Legs") as Label
|
||||||
|
name_feet = _find("Name_Feet") as Label
|
||||||
|
var vp := _find("SubViewport") as SubViewport
|
||||||
|
if vp:
|
||||||
|
vp.own_world_3d = true
|
||||||
|
vp.transparent_bg = false
|
||||||
|
vp.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||||||
|
if description_label:
|
||||||
|
description_label.visible = true
|
||||||
|
description_label.add_theme_font_size_override("font_size", 14)
|
||||||
|
description_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
|
description_label.custom_minimum_size = Vector2(0, 88)
|
||||||
|
description_label.max_lines_visible = 8
|
||||||
|
description_label.clip_text = false
|
||||||
|
description_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
|
if bonus_label:
|
||||||
|
bonus_label.visible = true
|
||||||
|
bonus_label.add_theme_font_size_override("font_size", 14)
|
||||||
|
bonus_label.custom_minimum_size = Vector2(0, 22)
|
||||||
|
bonus_label.max_lines_visible = 2
|
||||||
|
bonus_label.clip_text = false
|
||||||
|
if confirm_button:
|
||||||
|
confirm_button.pressed.connect(_on_confirm)
|
||||||
|
if back_button:
|
||||||
|
back_button.pressed.connect(_on_back)
|
||||||
|
if sex_male:
|
||||||
|
sex_male.pressed.connect(func() -> void: _set_sex("male"))
|
||||||
|
if sex_female:
|
||||||
|
sex_female.pressed.connect(func() -> void: _set_sex("female"))
|
||||||
|
_wire_cycle("Prev_Head", "Next_Head", "head")
|
||||||
|
_wire_cycle("Prev_Body", "Next_Body", "body")
|
||||||
|
_wire_cycle("Prev_Legs", "Next_Legs", "legs")
|
||||||
|
_wire_cycle("Prev_Feet", "Next_Feet", "feet")
|
||||||
|
if culture_list is GridContainer:
|
||||||
|
(culture_list as GridContainer).columns = 3
|
||||||
|
if background_list is GridContainer:
|
||||||
|
(background_list as GridContainer).columns = 2
|
||||||
|
_wire_culture_buttons()
|
||||||
|
_spawn_previews()
|
||||||
|
_build_background_buttons()
|
||||||
|
if cultures.size() > 0:
|
||||||
|
_select_culture(cultures[0])
|
||||||
|
if backgrounds.size() > 0:
|
||||||
|
_select_background(backgrounds[0])
|
||||||
|
_set_sex("male")
|
||||||
|
|
||||||
|
|
||||||
|
func _find(n: String) -> Node:
|
||||||
|
return find_child(n, true, false)
|
||||||
|
|
||||||
|
|
||||||
|
func _size_grid_button(btn: Button) -> void:
|
||||||
|
btn.custom_minimum_size = Vector2(0, 24)
|
||||||
|
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
btn.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
|
||||||
|
|
||||||
|
func _wire_cycle(prev_name: String, next_name: String, slot: String) -> void:
|
||||||
|
var prev_b := _find(prev_name) as Button
|
||||||
|
var next_b := _find(next_name) as Button
|
||||||
|
if prev_b:
|
||||||
|
prev_b.pressed.connect(func() -> void: _cycle(slot, -1))
|
||||||
|
if next_b:
|
||||||
|
next_b.pressed.connect(func() -> void: _cycle(slot, 1))
|
||||||
|
|
||||||
|
|
||||||
|
func _wire_culture_buttons() -> void:
|
||||||
|
culture_buttons.clear()
|
||||||
|
if culture_list == null:
|
||||||
|
return
|
||||||
|
var map := {
|
||||||
|
"Culture_NA": "naf", "Culture_NAF": "naf",
|
||||||
|
"Culture_EA": "eaa", "Culture_EAA": "eaa",
|
||||||
|
"Culture_Eur": "european", "Culture_European": "european",
|
||||||
|
"Culture_Ru": "russian", "Culture_Russian": "russian",
|
||||||
|
"Culture_Br": "brazilian", "Culture_Brazilian": "brazilian",
|
||||||
|
"Culture_In": "independent", "Culture_Independent": "independent",
|
||||||
|
}
|
||||||
|
for child in culture_list.get_children():
|
||||||
|
if not (child is Button):
|
||||||
|
continue
|
||||||
|
var btn := child as Button
|
||||||
|
var cid: String = str(map.get(btn.name, ""))
|
||||||
|
if cid.is_empty():
|
||||||
|
continue
|
||||||
|
var data: Dictionary = {}
|
||||||
|
for c in cultures:
|
||||||
|
if c["id"] == cid:
|
||||||
|
data = c
|
||||||
|
break
|
||||||
|
if data.is_empty():
|
||||||
|
continue
|
||||||
|
btn.toggle_mode = true
|
||||||
|
_size_grid_button(btn)
|
||||||
|
btn.pressed.connect(_on_culture_pressed.bind(data, btn))
|
||||||
|
culture_buttons.append(btn)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_culture_pressed(data: Dictionary, btn: Button) -> void:
|
||||||
|
_select_culture(data)
|
||||||
|
for b in culture_buttons:
|
||||||
|
b.button_pressed = (b == btn)
|
||||||
|
|
||||||
|
|
||||||
|
func _select_culture(data: Dictionary) -> void:
|
||||||
|
selected_culture = data
|
||||||
|
_refresh_desc()
|
||||||
|
|
||||||
|
|
||||||
|
func _build_background_buttons() -> void:
|
||||||
|
if background_list == null:
|
||||||
|
push_error("BackgroundL / BackgroundList missing — jobs cannot spawn")
|
||||||
|
return
|
||||||
|
for child in background_list.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
background_buttons.clear()
|
||||||
|
for bg in backgrounds:
|
||||||
|
var btn := Button.new()
|
||||||
|
btn.text = str(bg["name"])
|
||||||
|
btn.toggle_mode = true
|
||||||
|
_size_grid_button(btn)
|
||||||
|
btn.pressed.connect(_on_background_pressed.bind(bg, btn))
|
||||||
|
background_list.add_child(btn)
|
||||||
|
background_buttons.append(btn)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_background_pressed(bg: Dictionary, btn: Button) -> void:
|
||||||
|
_select_background(bg)
|
||||||
|
for b in background_buttons:
|
||||||
|
b.button_pressed = (b == btn)
|
||||||
|
|
||||||
|
|
||||||
|
func _select_background(bg: Dictionary) -> void:
|
||||||
|
selected_background = bg
|
||||||
|
_refresh_desc()
|
||||||
|
if bonus_label:
|
||||||
|
var bonuses: Dictionary = bg.get("bonuses", {})
|
||||||
|
var money: int = int(bonuses.get("money", 0))
|
||||||
|
var extra: PackedStringArray = []
|
||||||
|
if bonuses.has("food"):
|
||||||
|
extra.append("Food +%s" % str(bonuses["food"]))
|
||||||
|
if bonuses.has("health"):
|
||||||
|
extra.append("Health +%s" % str(bonuses["health"]))
|
||||||
|
var extra_txt := (", " + ", ".join(extra)) if extra.size() > 0 else ""
|
||||||
|
bonus_label.text = "Starting bonus: %d credits%s" % [money, extra_txt]
|
||||||
|
|
||||||
|
|
||||||
|
func _refresh_desc() -> void:
|
||||||
|
var parts: PackedStringArray = []
|
||||||
|
if not selected_culture.is_empty():
|
||||||
|
parts.append(str(selected_culture.get("desc", "")))
|
||||||
|
if not selected_background.is_empty():
|
||||||
|
parts.append(str(selected_background.get("desc", "")))
|
||||||
|
var body := "\n\n".join(parts)
|
||||||
|
if description_label:
|
||||||
|
description_label.visible = true
|
||||||
|
description_label.text = body
|
||||||
|
if bonus_label == null and description_label and not selected_background.is_empty():
|
||||||
|
var bonuses: Dictionary = selected_background.get("bonuses", {})
|
||||||
|
var money: int = int(bonuses.get("money", 0))
|
||||||
|
description_label.text = body + "\n\nStarting bonus: %d credits" % money
|
||||||
|
|
||||||
|
|
||||||
|
func _spawn_previews() -> void:
|
||||||
|
if look_world == null:
|
||||||
|
push_warning("LookWorld missing — Look preview will be empty")
|
||||||
|
return
|
||||||
|
_ensure_look_stage()
|
||||||
|
preview_male = _instance_fbx(MALE_FBX)
|
||||||
|
preview_female = _instance_fbx(FEMALE_FBX)
|
||||||
|
if preview_male:
|
||||||
|
preview_male.name = "PreviewMale"
|
||||||
|
look_world.add_child(preview_male)
|
||||||
|
if preview_female:
|
||||||
|
preview_female.name = "PreviewFemale"
|
||||||
|
look_world.add_child(preview_female)
|
||||||
|
print("Look spawn male=", preview_male, " female=", preview_female, " cam=", preview_cam)
|
||||||
|
if preview_cam:
|
||||||
|
preview_cam.current = true
|
||||||
|
preview_cam.position = Vector3(0.0, 1.08, 5.4)
|
||||||
|
preview_cam.rotation_degrees = Vector3(-4.0, 0.0, 0.0)
|
||||||
|
preview_cam.fov = 34.0
|
||||||
|
|
||||||
|
|
||||||
|
func _ensure_look_stage() -> void:
|
||||||
|
if look_world.get_node_or_null("LookFill") == null:
|
||||||
|
var fill := OmniLight3D.new()
|
||||||
|
fill.name = "LookFill"
|
||||||
|
fill.light_energy = 1.6
|
||||||
|
fill.omni_range = 14.0
|
||||||
|
fill.position = Vector3(0.5, 2.0, 2.2)
|
||||||
|
look_world.add_child(fill)
|
||||||
|
if look_world.get_node_or_null("LookEnv") == null:
|
||||||
|
var we := WorldEnvironment.new()
|
||||||
|
we.name = "LookEnv"
|
||||||
|
var env := Environment.new()
|
||||||
|
env.background_mode = Environment.BG_COLOR
|
||||||
|
env.background_color = Color(0.10, 0.11, 0.13)
|
||||||
|
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
|
||||||
|
env.ambient_light_color = Color(0.78, 0.78, 0.82)
|
||||||
|
env.ambient_light_energy = 1.0
|
||||||
|
we.environment = env
|
||||||
|
look_world.add_child(we)
|
||||||
|
|
||||||
|
|
||||||
|
func _instance_fbx(path: String) -> Node3D:
|
||||||
|
if not ResourceLoader.exists(path):
|
||||||
|
push_warning("Missing character file: " + path)
|
||||||
|
return null
|
||||||
|
var res = load(path)
|
||||||
|
if res == null:
|
||||||
|
return null
|
||||||
|
var inst: Node = res.instantiate()
|
||||||
|
if inst is Node3D:
|
||||||
|
(inst as Node3D).position = Vector3.ZERO
|
||||||
|
(inst as Node3D).rotation_degrees = Vector3.ZERO
|
||||||
|
(inst as Node3D).scale = Vector3.ONE
|
||||||
|
return inst as Node3D
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
func _lists() -> Dictionary:
|
||||||
|
if sex == "male":
|
||||||
|
return {"head": MALE_HEADS, "body": MALE_BODIES, "legs": MALE_LEGS, "feet": MALE_FEET}
|
||||||
|
return {"head": FEMALE_HEADS, "body": FEMALE_BODIES, "legs": FEMALE_LEGS, "feet": FEMALE_FEET}
|
||||||
|
|
||||||
|
|
||||||
|
func _active_preview() -> Node3D:
|
||||||
|
return preview_male if sex == "male" else preview_female
|
||||||
|
|
||||||
|
|
||||||
|
func _set_sex(s: String) -> void:
|
||||||
|
sex = s
|
||||||
|
idx = {"head": 0, "body": 0, "legs": 0, "feet": 0}
|
||||||
|
if preview_male:
|
||||||
|
preview_male.visible = (s == "male")
|
||||||
|
if preview_female:
|
||||||
|
preview_female.visible = (s == "female")
|
||||||
|
_apply_look()
|
||||||
|
|
||||||
|
|
||||||
|
func _cycle(slot: String, dir: int) -> void:
|
||||||
|
var arr: Array = _lists()[slot]
|
||||||
|
if arr.is_empty():
|
||||||
|
return
|
||||||
|
idx[slot] = posmod(idx[slot] + dir, arr.size())
|
||||||
|
_apply_look()
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_look() -> void:
|
||||||
|
var root := _active_preview()
|
||||||
|
if root == null:
|
||||||
|
return
|
||||||
|
var lists := _lists()
|
||||||
|
var keep: Array[String] = [
|
||||||
|
str(lists["head"][idx["head"]]),
|
||||||
|
str(lists["body"][idx["body"]]),
|
||||||
|
str(lists["legs"][idx["legs"]]),
|
||||||
|
str(lists["feet"][idx["feet"]]),
|
||||||
|
]
|
||||||
|
_hide_all_geometry(root)
|
||||||
|
for mesh_name in keep:
|
||||||
|
_show_mesh(root, mesh_name)
|
||||||
|
_hide_other_slots(root, keep)
|
||||||
|
if name_head:
|
||||||
|
name_head.text = lists["head"][idx["head"]].replace("_Head", "").replace("Formad", "Formal")
|
||||||
|
if name_body:
|
||||||
|
name_body.text = lists["body"][idx["body"]].replace("_Body", "")
|
||||||
|
if name_legs:
|
||||||
|
name_legs.text = lists["legs"][idx["legs"]].replace("_Legs", "").replace("_Pants", "")
|
||||||
|
if name_feet:
|
||||||
|
name_feet.text = lists["feet"][idx["feet"]].replace("_Feet", "")
|
||||||
|
_play_idle(root)
|
||||||
|
|
||||||
|
|
||||||
|
func _hide_all_geometry(root: Node) -> void:
|
||||||
|
var stack: Array[Node] = [root]
|
||||||
|
while stack.size() > 0:
|
||||||
|
var n: Node = stack.pop_back()
|
||||||
|
if n is VisualInstance3D:
|
||||||
|
n.visible = false
|
||||||
|
for c in n.get_children():
|
||||||
|
stack.append(c)
|
||||||
|
|
||||||
|
|
||||||
|
func _show_mesh(root: Node, mesh_name: String) -> void:
|
||||||
|
var node := root.find_child(mesh_name, true, false)
|
||||||
|
if node == null:
|
||||||
|
return
|
||||||
|
_show_tree(node)
|
||||||
|
|
||||||
|
|
||||||
|
func _show_tree(n: Node) -> void:
|
||||||
|
n.visible = true
|
||||||
|
if n is VisualInstance3D:
|
||||||
|
n.visible = true
|
||||||
|
for c in n.get_children():
|
||||||
|
_show_tree(c)
|
||||||
|
|
||||||
|
|
||||||
|
func _hide_other_slots(root: Node, keep: Array[String]) -> void:
|
||||||
|
var stack: Array[Node] = [root]
|
||||||
|
while stack.size() > 0:
|
||||||
|
var n: Node = stack.pop_back()
|
||||||
|
if _is_slot_root(n.name) and keep.find(n.name) == -1:
|
||||||
|
_hide_tree(n)
|
||||||
|
else:
|
||||||
|
for c in n.get_children():
|
||||||
|
stack.append(c)
|
||||||
|
|
||||||
|
|
||||||
|
func _hide_tree(n: Node) -> void:
|
||||||
|
n.visible = false
|
||||||
|
if n is VisualInstance3D:
|
||||||
|
n.visible = false
|
||||||
|
for c in n.get_children():
|
||||||
|
_hide_tree(c)
|
||||||
|
|
||||||
|
|
||||||
|
func _is_slot_root(mesh_name: String) -> bool:
|
||||||
|
return (
|
||||||
|
mesh_name.ends_with("_Head")
|
||||||
|
or mesh_name.ends_with("_Body")
|
||||||
|
or mesh_name.ends_with("_Legs")
|
||||||
|
or mesh_name.ends_with("_Feet")
|
||||||
|
or mesh_name.ends_with("_Pants")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _play_idle(root: Node) -> void:
|
||||||
|
var anim: AnimationPlayer = root.find_child("AnimationPlayer", true, false)
|
||||||
|
if anim == null:
|
||||||
|
return
|
||||||
|
for clip in ["CharacterArmature|Idle", "Idle"]:
|
||||||
|
if anim.has_animation(clip):
|
||||||
|
anim.play(clip)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
func _look_payload() -> Dictionary:
|
||||||
|
var lists := _lists()
|
||||||
|
return {
|
||||||
|
"sex": sex,
|
||||||
|
"head": lists["head"][idx["head"]],
|
||||||
|
"body": lists["body"][idx["body"]],
|
||||||
|
"legs": lists["legs"][idx["legs"]],
|
||||||
|
"feet": lists["feet"][idx["feet"]],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func _on_confirm() -> void:
|
||||||
|
var player_name := "Colonist"
|
||||||
|
if name_input:
|
||||||
|
player_name = name_input.text.strip_edges()
|
||||||
|
if player_name.is_empty():
|
||||||
|
player_name = "Colonist"
|
||||||
|
if selected_background.is_empty() and backgrounds.size() > 0:
|
||||||
|
selected_background = backgrounds[0]
|
||||||
|
if selected_culture.is_empty() and cultures.size() > 0:
|
||||||
|
selected_culture = cultures[0]
|
||||||
|
var data := {
|
||||||
|
"player_name": player_name,
|
||||||
|
"appearance": _look_payload(),
|
||||||
|
"culture_id": selected_culture.get("id", ""),
|
||||||
|
"culture_name": selected_culture.get("name", ""),
|
||||||
|
"background_id": selected_background.get("id", ""),
|
||||||
|
"background_name": selected_background.get("name", ""),
|
||||||
|
"bonuses": selected_background.get("bonuses", {}),
|
||||||
|
}
|
||||||
|
Engine.set_meta("player_creation_data", data)
|
||||||
|
print("Creation packed: ", data)
|
||||||
|
get_tree().change_scene_to_file("res://Scenes/main.tscn")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_back() -> void:
|
||||||
|
get_tree().change_scene_to_file("res://Scenes/main_menu.tscn")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cxrxrk0qt15dl
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Circuit Board"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b0oppy8q64xry
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Cooking Knife"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cley0rs8im7v3
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Dried Noodles"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://c5j656olsdtjs
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
extends Node3D
|
||||||
|
## Earth impostor — from Luna you are always far; show a disc inside far plane.
|
||||||
|
|
||||||
|
@export var real_earth_path: NodePath = ^".."
|
||||||
|
@export var surface_path: NodePath = ^"../EarthSurface"
|
||||||
|
@export var impostor_mesh_path: NodePath = ^"ImposterSphere"
|
||||||
|
|
||||||
|
@export var switch_distance: float = 150000.0
|
||||||
|
@export var visual_distance: float = 120000.0
|
||||||
|
@export var real_radius: float = 637100.0
|
||||||
|
|
||||||
|
var _real: Node3D
|
||||||
|
var _surface: Node3D
|
||||||
|
var _mesh: MeshInstance3D
|
||||||
|
var _base_radius: float = 0.5
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_real = get_node_or_null(real_earth_path) as Node3D
|
||||||
|
_surface = get_node_or_null(surface_path) as Node3D
|
||||||
|
_mesh = get_node_or_null(impostor_mesh_path) as MeshInstance3D
|
||||||
|
|
||||||
|
if _mesh and _mesh.mesh is SphereMesh:
|
||||||
|
_base_radius = maxf((_mesh.mesh as SphereMesh).radius, 0.5)
|
||||||
|
|
||||||
|
if _mesh:
|
||||||
|
_mesh.visible = false
|
||||||
|
# Keep YOUR material/texture; only force unshaded so it reads in space
|
||||||
|
var src_mat: Material = _mesh.get_active_material(0)
|
||||||
|
if src_mat is StandardMaterial3D:
|
||||||
|
var mat: StandardMaterial3D = (src_mat as StandardMaterial3D).duplicate()
|
||||||
|
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
_mesh.material_override = mat
|
||||||
|
|
||||||
|
print("EarthImposter ready | real=", _real, " surface=", _surface, " mesh=", _mesh)
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if _real == null or _mesh == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var viewer: Node3D = FloatingOrigin.focus
|
||||||
|
if viewer == null or not is_instance_valid(viewer):
|
||||||
|
_mesh.visible = false
|
||||||
|
return
|
||||||
|
|
||||||
|
var to_body: Vector3 = _real.global_position - viewer.global_position
|
||||||
|
var dist: float = to_body.length()
|
||||||
|
if dist < 1.0:
|
||||||
|
_mesh.visible = false
|
||||||
|
return
|
||||||
|
|
||||||
|
# Close approach only: real surface
|
||||||
|
if dist < switch_distance:
|
||||||
|
_mesh.visible = false
|
||||||
|
if _surface:
|
||||||
|
_surface.visible = true
|
||||||
|
return
|
||||||
|
|
||||||
|
# Far (normal from Luna): impostor on
|
||||||
|
# Leave EarthSurface visible until you confirm the disc — then you can hide it
|
||||||
|
var dir: Vector3 = to_body / dist
|
||||||
|
_mesh.global_position = viewer.global_position + dir * visual_distance
|
||||||
|
|
||||||
|
var visual_radius: float = real_radius * (visual_distance / dist)
|
||||||
|
visual_radius = clampf(visual_radius, 8000.0, 150000.0)
|
||||||
|
_mesh.scale = Vector3.ONE * (visual_radius / _base_radius)
|
||||||
|
_mesh.visible = true
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ikbkmt7sby7a
|
||||||
@@ -0,0 +1,632 @@
|
|||||||
|
extends CharacterBody3D
|
||||||
|
## Kestrel EC-01 capsule — flight, cameras, enter/exit.
|
||||||
|
## Hull clips + plumes live on child "Kestrel" via kestrel_driver.gd.
|
||||||
|
|
||||||
|
@onready var interaction_area: Area3D = $InteractionArea
|
||||||
|
@onready var camera_pivot: Node3D = get_node_or_null("CameraPivot")
|
||||||
|
@onready var capsule_camera: Camera3D = get_node_or_null("CameraPivot/CapsuleCamera")
|
||||||
|
@onready var third_person_camera: Camera3D = $ThirdPersonCamera
|
||||||
|
@onready var interact_prompt: Label = get_node_or_null("/root/Node3D/HUD/InteractPrompt")
|
||||||
|
@onready var pause_menu: Control = get_node_or_null("/root/Node3D/HUD/PauseMenu")
|
||||||
|
@onready var body_collision: CollisionShape3D = get_node_or_null("CollisionShape3D")
|
||||||
|
@onready var flight_label: Label = get_node_or_null("/root/Node3D/HUD/FlightLabel")
|
||||||
|
@onready var kestrel: Node3D = get_node_or_null("Kestrel")
|
||||||
|
|
||||||
|
var player_inside: bool = false
|
||||||
|
var player_ref: CharacterBody3D = null
|
||||||
|
var using_third_person: bool = false
|
||||||
|
var f_was_down: bool = false
|
||||||
|
|
||||||
|
var mass: float = 6500.0
|
||||||
|
var thrust_force: float = 180000.0
|
||||||
|
var rotation_speed: float = 1.8
|
||||||
|
var surface_friction: float = 6.0
|
||||||
|
|
||||||
|
const MOON_RADIUS: float = 173700.0
|
||||||
|
const MOON_G: float = 1.62
|
||||||
|
const MOON_SOI: float = 400000.0
|
||||||
|
const EARTH_RADIUS: float = 637100.0
|
||||||
|
const EARTH_G: float = 9.81
|
||||||
|
const EARTH_SOI: float = 20000000.0
|
||||||
|
const CAM_FAR: float = 1000000.0
|
||||||
|
const NEAR_SURFACE_MARGIN: float = 300.0
|
||||||
|
|
||||||
|
var _moon_colliders: Array[CollisionObject3D] = []
|
||||||
|
var _crust_exception: bool = false
|
||||||
|
|
||||||
|
var free_look: bool = false
|
||||||
|
var look_sensitivity: float = 0.003
|
||||||
|
var orbit_yaw: float = 0.0
|
||||||
|
var orbit_pitch: float = 0.4
|
||||||
|
var orbit_distance: float = 14.0
|
||||||
|
var orbit_pitch_min: float = -1.2
|
||||||
|
var orbit_pitch_max: float = 1.2
|
||||||
|
var cockpit_yaw: float = 0.0
|
||||||
|
var cockpit_pitch: float = 0.0
|
||||||
|
var cockpit_look_limit_yaw: float = 1.45
|
||||||
|
var cockpit_look_limit_up: float = 1.0
|
||||||
|
var cockpit_look_limit_down: float = 0.55
|
||||||
|
var head_local: Transform3D = Transform3D.IDENTITY
|
||||||
|
|
||||||
|
var telem_body: String = "—"
|
||||||
|
var telem_alt: float = 0.0
|
||||||
|
var telem_speed: float = 0.0
|
||||||
|
var telem_vspeed: float = 0.0
|
||||||
|
var telem_hspeed: float = 0.0
|
||||||
|
var telem_vcirc: float = 0.0
|
||||||
|
var telem_dh: float = 0.0
|
||||||
|
var telem_earth_rng: float = 0.0
|
||||||
|
var telem_thrust: bool = false
|
||||||
|
var telem_has_alt: bool = false
|
||||||
|
|
||||||
|
var _gear_down: bool = true
|
||||||
|
var _hatch_crew_open: bool = false
|
||||||
|
var _hatch_dock_open: bool = false
|
||||||
|
var _ladder_out: bool = false
|
||||||
|
var _cabin_dim: bool = false
|
||||||
|
var _v_was: bool = false
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_ensure_actions()
|
||||||
|
if interaction_area:
|
||||||
|
interaction_area.monitoring = true
|
||||||
|
interaction_area.monitorable = true
|
||||||
|
interaction_area.body_entered.connect(_on_body_entered)
|
||||||
|
interaction_area.body_exited.connect(_on_body_exited)
|
||||||
|
if camera_pivot:
|
||||||
|
camera_pivot.top_level = false
|
||||||
|
head_local = camera_pivot.transform
|
||||||
|
if capsule_camera:
|
||||||
|
capsule_camera.near = 0.05
|
||||||
|
capsule_camera.far = CAM_FAR
|
||||||
|
capsule_camera.current = false
|
||||||
|
if third_person_camera:
|
||||||
|
third_person_camera.near = 0.1
|
||||||
|
third_person_camera.far = CAM_FAR
|
||||||
|
third_person_camera.current = false
|
||||||
|
if flight_label:
|
||||||
|
flight_label.visible = false
|
||||||
|
_bind_kestrel()
|
||||||
|
_collect_moon_colliders()
|
||||||
|
call_deferred("_update_crust_exception")
|
||||||
|
|
||||||
|
|
||||||
|
func _bind_kestrel() -> void:
|
||||||
|
if kestrel == null:
|
||||||
|
kestrel = get_node_or_null("Kestrel")
|
||||||
|
print("Kestrel hull=", kestrel, " driver=", kestrel.get_script() if kestrel else null)
|
||||||
|
|
||||||
|
|
||||||
|
func _hull() -> Node:
|
||||||
|
return kestrel if kestrel else null
|
||||||
|
|
||||||
|
|
||||||
|
func _set_hull(prop: String, value: Variant) -> void:
|
||||||
|
var h := _hull()
|
||||||
|
if h and prop in h:
|
||||||
|
h.set(prop, value)
|
||||||
|
|
||||||
|
|
||||||
|
func _moon() -> Node3D:
|
||||||
|
return get_node_or_null("/root/Node3D/SolarSystem/Moon") as Node3D
|
||||||
|
|
||||||
|
|
||||||
|
func _earth() -> Node3D:
|
||||||
|
return get_node_or_null("/root/Node3D/SolarSystem/Earth") as Node3D
|
||||||
|
|
||||||
|
|
||||||
|
func _habitat() -> Node3D:
|
||||||
|
return get_node_or_null("/root/Node3D/SolarSystem/Moon/LovellAnchor/Station/Habitat") as Node3D
|
||||||
|
|
||||||
|
|
||||||
|
func _collect_moon_colliders() -> void:
|
||||||
|
_moon_colliders.clear()
|
||||||
|
var moon := _moon()
|
||||||
|
if moon == null:
|
||||||
|
return
|
||||||
|
for n in moon.find_children("*", "PhysicsBody3D", true, false):
|
||||||
|
if n == self:
|
||||||
|
continue
|
||||||
|
if str(n.name).begins_with("Shell"):
|
||||||
|
continue
|
||||||
|
if str(n.name).begins_with("Moon") and n is CollisionObject3D:
|
||||||
|
_moon_colliders.append(n as CollisionObject3D)
|
||||||
|
|
||||||
|
|
||||||
|
func _inside_young() -> bool:
|
||||||
|
var habitat := _habitat()
|
||||||
|
if habitat == null:
|
||||||
|
return false
|
||||||
|
var lp: Vector3 = habitat.to_local(global_position)
|
||||||
|
var radial: float = Vector2(lp.x, lp.z).length()
|
||||||
|
return radial < 2000.0 and lp.y < 80.0 and lp.y > -120.0
|
||||||
|
|
||||||
|
|
||||||
|
func _update_crust_exception() -> void:
|
||||||
|
var want: bool = _inside_young()
|
||||||
|
if want == _crust_exception:
|
||||||
|
return
|
||||||
|
_crust_exception = want
|
||||||
|
for body in _moon_colliders:
|
||||||
|
if not is_instance_valid(body):
|
||||||
|
continue
|
||||||
|
if want:
|
||||||
|
add_collision_exception_with(body)
|
||||||
|
else:
|
||||||
|
remove_collision_exception_with(body)
|
||||||
|
|
||||||
|
|
||||||
|
func _active_gravity() -> Dictionary:
|
||||||
|
var moon := _moon()
|
||||||
|
if moon:
|
||||||
|
var d_m: float = global_position.distance_to(moon.global_position)
|
||||||
|
if d_m >= 1.0 and d_m <= MOON_SOI:
|
||||||
|
var to_c: Vector3 = moon.global_position - global_position
|
||||||
|
return {
|
||||||
|
"name": "Luna",
|
||||||
|
"center": moon.global_position,
|
||||||
|
"radius": MOON_RADIUS,
|
||||||
|
"g": MOON_G,
|
||||||
|
"accel": to_c.normalized() * MOON_G,
|
||||||
|
"dist": d_m
|
||||||
|
}
|
||||||
|
var earth := _earth()
|
||||||
|
if earth:
|
||||||
|
var d_e: float = global_position.distance_to(earth.global_position)
|
||||||
|
if d_e >= 1.0 and d_e <= EARTH_SOI:
|
||||||
|
var to_c2: Vector3 = earth.global_position - global_position
|
||||||
|
return {
|
||||||
|
"name": "Earth",
|
||||||
|
"center": earth.global_position,
|
||||||
|
"radius": EARTH_RADIUS,
|
||||||
|
"g": EARTH_G,
|
||||||
|
"accel": to_c2.normalized() * EARTH_G,
|
||||||
|
"dist": d_e
|
||||||
|
}
|
||||||
|
return {"name": "—", "center": Vector3.ZERO, "radius": 0.0, "g": 0.0, "accel": Vector3.ZERO, "dist": 0.0}
|
||||||
|
|
||||||
|
|
||||||
|
func _gravity_accel() -> Vector3:
|
||||||
|
return _active_gravity()["accel"]
|
||||||
|
|
||||||
|
|
||||||
|
func _update_telemetry() -> void:
|
||||||
|
telem_speed = velocity.length()
|
||||||
|
telem_thrust = Input.is_key_pressed(KEY_SPACE)
|
||||||
|
var earth := _earth()
|
||||||
|
if earth:
|
||||||
|
telem_earth_rng = maxf(0.0, global_position.distance_to(earth.global_position) - EARTH_RADIUS)
|
||||||
|
else:
|
||||||
|
telem_earth_rng = 0.0
|
||||||
|
var body: Dictionary = _active_gravity()
|
||||||
|
telem_body = str(body["name"])
|
||||||
|
if telem_body == "—":
|
||||||
|
telem_has_alt = false
|
||||||
|
telem_alt = 0.0
|
||||||
|
telem_vspeed = 0.0
|
||||||
|
telem_hspeed = telem_speed
|
||||||
|
telem_vcirc = 0.0
|
||||||
|
telem_dh = 0.0
|
||||||
|
return
|
||||||
|
telem_has_alt = true
|
||||||
|
var r: float = float(body["dist"])
|
||||||
|
var rad: float = float(body["radius"])
|
||||||
|
var g: float = float(body["g"])
|
||||||
|
telem_alt = r - rad
|
||||||
|
var radial: Vector3 = (global_position - body["center"]).normalized()
|
||||||
|
telem_vspeed = velocity.dot(radial)
|
||||||
|
telem_hspeed = (velocity - radial * telem_vspeed).length()
|
||||||
|
telem_vcirc = sqrt(g * rad * rad / r) if r > 1.0 else 0.0
|
||||||
|
telem_dh = telem_hspeed - telem_vcirc
|
||||||
|
|
||||||
|
|
||||||
|
func _update_flight_hud() -> void:
|
||||||
|
if flight_label == null or not player_inside:
|
||||||
|
return
|
||||||
|
flight_label.visible = true
|
||||||
|
var mode := "3P" if using_third_person else "1P"
|
||||||
|
var thr := "THRUST" if telem_thrust else "IDLE"
|
||||||
|
var vs_sign := "+" if telem_vspeed >= 0.0 else ""
|
||||||
|
var alt_line: String
|
||||||
|
var vcirc_line: String
|
||||||
|
var dh_line: String
|
||||||
|
if telem_has_alt:
|
||||||
|
alt_line = "ALT %8.0f m\n" % telem_alt
|
||||||
|
vcirc_line = "VCIRC %8.1f m/s\n" % telem_vcirc
|
||||||
|
var dh_sign := "+" if telem_dh >= 0.0 else ""
|
||||||
|
dh_line = "ΔH %s%7.1f m/s\n" % [dh_sign, telem_dh]
|
||||||
|
else:
|
||||||
|
alt_line = "ALT —\n"
|
||||||
|
vcirc_line = "VCIRC —\n"
|
||||||
|
dh_line = "ΔH —\n"
|
||||||
|
flight_label.text = (
|
||||||
|
"[%s] %s | BODY %s\n" % [mode, thr, telem_body]
|
||||||
|
+ alt_line
|
||||||
|
+ "SPD %8.1f m/s\n" % telem_speed
|
||||||
|
+ "VS %s%7.1f m/s\n" % [vs_sign, telem_vspeed]
|
||||||
|
+ "H %8.1f m/s\n" % telem_hspeed
|
||||||
|
+ vcirc_line
|
||||||
|
+ dh_line
|
||||||
|
+ "EARTH %8.0f m" % telem_earth_rng
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _clear_flight_hud() -> void:
|
||||||
|
if flight_label:
|
||||||
|
flight_label.visible = false
|
||||||
|
flight_label.text = ""
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
if body.is_in_group("player"):
|
||||||
|
player_ref = body
|
||||||
|
if interact_prompt and not player_inside:
|
||||||
|
interact_prompt.text = "Press F to Enter"
|
||||||
|
interact_prompt.visible = true
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_exited(body: Node3D) -> void:
|
||||||
|
if body.is_in_group("player") and not player_inside:
|
||||||
|
player_ref = null
|
||||||
|
if interact_prompt:
|
||||||
|
interact_prompt.visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if not player_inside:
|
||||||
|
return
|
||||||
|
if event.is_action_pressed("ui_cancel"):
|
||||||
|
if pause_menu and pause_menu.has_method("open_pause") and player_ref:
|
||||||
|
pause_menu.open_pause(player_ref)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
return
|
||||||
|
if _event_toggles(event, "capsule_gear", KEY_G):
|
||||||
|
_gear_down = not _gear_down
|
||||||
|
_set_hull("gear_deploy", 1.0 if _gear_down else 0.0)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
elif _event_toggles(event, "capsule_hatch_crew", KEY_H):
|
||||||
|
_hatch_crew_open = not _hatch_crew_open
|
||||||
|
_set_hull("hatch_crew_open", 1.0 if _hatch_crew_open else 0.0)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
elif _event_toggles(event, "capsule_hatch_dock", KEY_J):
|
||||||
|
_hatch_dock_open = not _hatch_dock_open
|
||||||
|
_set_hull("hatch_dock_open", 1.0 if _hatch_dock_open else 0.0)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
elif _event_toggles(event, "capsule_ladder", KEY_L):
|
||||||
|
_ladder_out = not _ladder_out
|
||||||
|
_set_hull("hatch_ladder_deploy", 1.0 if _ladder_out else 0.0)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
elif _event_toggles(event, "capsule_instruments", KEY_I):
|
||||||
|
_set_hull("instruments_demo", 1.0)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
elif _event_toggles(event, "capsule_cabin_light", KEY_K):
|
||||||
|
_cabin_dim = not _cabin_dim
|
||||||
|
_set_hull("cabin_dim", _cabin_dim)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
|
func _ensure_actions() -> void:
|
||||||
|
var binds := {
|
||||||
|
"interact": KEY_F,
|
||||||
|
"toggle_first_person": KEY_V,
|
||||||
|
"capsule_gear": KEY_G,
|
||||||
|
"capsule_hatch_crew": KEY_H,
|
||||||
|
"capsule_hatch_dock": KEY_J,
|
||||||
|
"capsule_ladder": KEY_L,
|
||||||
|
"capsule_instruments": KEY_I,
|
||||||
|
"capsule_cabin_light": KEY_K,
|
||||||
|
}
|
||||||
|
for action in binds.keys():
|
||||||
|
if InputMap.has_action(action):
|
||||||
|
continue
|
||||||
|
InputMap.add_action(action)
|
||||||
|
var ev := InputEventKey.new()
|
||||||
|
ev.physical_keycode = binds[action]
|
||||||
|
InputMap.action_add_event(action, ev)
|
||||||
|
|
||||||
|
|
||||||
|
func _event_toggles(event: InputEvent, action: String, key: Key) -> bool:
|
||||||
|
if InputMap.has_action(action) and event.is_action_pressed(action):
|
||||||
|
return true
|
||||||
|
if event is InputEventKey and event.pressed and not event.echo and event.physical_keycode == key:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _act_pressed(action: String) -> bool:
|
||||||
|
return InputMap.has_action(action) and Input.is_action_pressed(action)
|
||||||
|
|
||||||
|
|
||||||
|
func _act_just(action: String) -> bool:
|
||||||
|
return InputMap.has_action(action) and Input.is_action_just_pressed(action)
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
var interact_now := _act_just("interact") or _just_key(KEY_F)
|
||||||
|
if not player_inside and player_ref and interact_now:
|
||||||
|
f_was_down = true
|
||||||
|
enter_capsule()
|
||||||
|
return
|
||||||
|
if not player_inside:
|
||||||
|
f_was_down = Input.is_physical_key_pressed(KEY_F)
|
||||||
|
_update_crust_exception()
|
||||||
|
return
|
||||||
|
if interact_now and not f_was_down:
|
||||||
|
f_was_down = true
|
||||||
|
exit_capsule()
|
||||||
|
return
|
||||||
|
f_was_down = _act_pressed("interact") or Input.is_physical_key_pressed(KEY_F)
|
||||||
|
if _act_just("toggle_first_person"):
|
||||||
|
toggle_camera()
|
||||||
|
elif not InputMap.has_action("toggle_first_person") and _just_key(KEY_V):
|
||||||
|
toggle_camera()
|
||||||
|
var was_free = free_look
|
||||||
|
free_look = Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
|
||||||
|
if was_free and not free_look and not using_third_person:
|
||||||
|
cockpit_yaw = 0.0
|
||||||
|
cockpit_pitch = 0.0
|
||||||
|
if Input.is_key_pressed(KEY_ALT):
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
else:
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
|
handle_flight(delta)
|
||||||
|
_update_telemetry()
|
||||||
|
_update_flight_hud()
|
||||||
|
if using_third_person:
|
||||||
|
update_third_person_camera()
|
||||||
|
if third_person_camera and not third_person_camera.current:
|
||||||
|
third_person_camera.make_current()
|
||||||
|
else:
|
||||||
|
update_cockpit_camera()
|
||||||
|
if capsule_camera and not capsule_camera.current:
|
||||||
|
capsule_camera.make_current()
|
||||||
|
|
||||||
|
|
||||||
|
func _just_key(key: Key) -> bool:
|
||||||
|
var down := Input.is_physical_key_pressed(key)
|
||||||
|
if key == KEY_V:
|
||||||
|
var edge := down and not _v_was
|
||||||
|
_v_was = down
|
||||||
|
return edge
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if not player_inside:
|
||||||
|
return
|
||||||
|
if Input.is_key_pressed(KEY_ALT):
|
||||||
|
return
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
if using_third_person:
|
||||||
|
orbit_yaw -= event.relative.x * look_sensitivity
|
||||||
|
orbit_pitch += event.relative.y * look_sensitivity
|
||||||
|
orbit_pitch = clampf(orbit_pitch, orbit_pitch_min, orbit_pitch_max)
|
||||||
|
elif free_look:
|
||||||
|
cockpit_yaw -= event.relative.x * look_sensitivity
|
||||||
|
cockpit_pitch -= event.relative.y * look_sensitivity
|
||||||
|
cockpit_yaw = clamp(cockpit_yaw, -cockpit_look_limit_yaw, cockpit_look_limit_yaw)
|
||||||
|
cockpit_pitch = clamp(cockpit_pitch, -cockpit_look_limit_down, cockpit_look_limit_up)
|
||||||
|
|
||||||
|
|
||||||
|
func enter_capsule() -> void:
|
||||||
|
if player_inside or player_ref == null:
|
||||||
|
return
|
||||||
|
player_inside = true
|
||||||
|
if interact_prompt:
|
||||||
|
interact_prompt.visible = false
|
||||||
|
player_ref.reparent(self)
|
||||||
|
player_ref.position = Vector3(0, 0.5, 0)
|
||||||
|
player_ref.rotation = Vector3.ZERO
|
||||||
|
player_ref.set_physics_process(false)
|
||||||
|
player_ref.set_process(true)
|
||||||
|
player_ref.set_process_input(false)
|
||||||
|
player_ref.set_process_unhandled_input(false)
|
||||||
|
if player_ref.has_method("set_in_vehicle"):
|
||||||
|
player_ref.set_in_vehicle(true)
|
||||||
|
var player_col = player_ref.get_node_or_null("CollisionShape3D")
|
||||||
|
if player_col:
|
||||||
|
player_col.disabled = true
|
||||||
|
var player_cam = player_ref.get_node_or_null("CameraPivot/Camera3D")
|
||||||
|
if player_cam:
|
||||||
|
player_cam.current = false
|
||||||
|
player_ref.visible = false
|
||||||
|
cockpit_yaw = 0.0
|
||||||
|
cockpit_pitch = 0.0
|
||||||
|
orbit_yaw = 0.0
|
||||||
|
orbit_pitch = 0.4
|
||||||
|
using_third_person = false
|
||||||
|
f_was_down = true
|
||||||
|
free_look = false
|
||||||
|
if camera_pivot:
|
||||||
|
camera_pivot.top_level = false
|
||||||
|
camera_pivot.transform = head_local
|
||||||
|
if third_person_camera:
|
||||||
|
third_person_camera.current = false
|
||||||
|
if capsule_camera:
|
||||||
|
capsule_camera.near = 0.05
|
||||||
|
capsule_camera.far = CAM_FAR
|
||||||
|
capsule_camera.current = true
|
||||||
|
capsule_camera.make_current()
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
FloatingOrigin.set_focus(self)
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
|
if flight_label:
|
||||||
|
flight_label.visible = true
|
||||||
|
_update_crust_exception()
|
||||||
|
|
||||||
|
|
||||||
|
func exit_capsule() -> void:
|
||||||
|
if not player_inside or player_ref == null:
|
||||||
|
return
|
||||||
|
var exiting_player: CharacterBody3D = player_ref
|
||||||
|
player_inside = false
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
free_look = false
|
||||||
|
f_was_down = false
|
||||||
|
using_third_person = false
|
||||||
|
_set_hull("abort_burn", false)
|
||||||
|
_set_hull("rcs_direction", 0)
|
||||||
|
_clear_flight_hud()
|
||||||
|
if body_collision:
|
||||||
|
body_collision.disabled = false
|
||||||
|
if is_instance_valid(camera_pivot):
|
||||||
|
camera_pivot.top_level = false
|
||||||
|
camera_pivot.transform = head_local
|
||||||
|
if is_instance_valid(capsule_camera):
|
||||||
|
capsule_camera.current = false
|
||||||
|
if is_instance_valid(third_person_camera):
|
||||||
|
third_person_camera.current = false
|
||||||
|
var station := get_node_or_null("/root/Node3D/SolarSystem/Moon/LovellAnchor/Station")
|
||||||
|
var dest: Node = station if station else get_tree().current_scene
|
||||||
|
exiting_player.reparent(dest)
|
||||||
|
exiting_player.global_position = global_position + global_transform.basis.y * 4.0
|
||||||
|
var player_cam_pivot = exiting_player.get_node_or_null("CameraPivot")
|
||||||
|
if player_cam_pivot:
|
||||||
|
player_cam_pivot.rotation = Vector3.ZERO
|
||||||
|
exiting_player.visible = true
|
||||||
|
exiting_player.set_physics_process(true)
|
||||||
|
exiting_player.set_process(true)
|
||||||
|
exiting_player.set_process_input(true)
|
||||||
|
exiting_player.set_process_unhandled_input(true)
|
||||||
|
exiting_player.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
|
var player_col = exiting_player.get_node_or_null("CollisionShape3D")
|
||||||
|
if player_col:
|
||||||
|
player_col.disabled = false
|
||||||
|
if exiting_player.has_method("set_in_vehicle"):
|
||||||
|
exiting_player.set_in_vehicle(false)
|
||||||
|
var player_cam = exiting_player.get_node_or_null("CameraPivot/Camera3D")
|
||||||
|
if player_cam:
|
||||||
|
player_cam.current = true
|
||||||
|
player_cam.make_current()
|
||||||
|
if exiting_player.has_method("restore_from_vehicle"):
|
||||||
|
exiting_player.restore_from_vehicle()
|
||||||
|
FloatingOrigin.set_focus(exiting_player)
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
|
player_ref = null
|
||||||
|
|
||||||
|
|
||||||
|
func toggle_camera() -> void:
|
||||||
|
using_third_person = not using_third_person
|
||||||
|
if using_third_person:
|
||||||
|
if capsule_camera:
|
||||||
|
capsule_camera.current = false
|
||||||
|
if third_person_camera:
|
||||||
|
third_person_camera.near = 0.1
|
||||||
|
third_person_camera.far = CAM_FAR
|
||||||
|
third_person_camera.make_current()
|
||||||
|
else:
|
||||||
|
if third_person_camera:
|
||||||
|
third_person_camera.current = false
|
||||||
|
if camera_pivot:
|
||||||
|
camera_pivot.top_level = false
|
||||||
|
camera_pivot.transform = head_local
|
||||||
|
if capsule_camera:
|
||||||
|
capsule_camera.make_current()
|
||||||
|
|
||||||
|
|
||||||
|
func update_cockpit_camera() -> void:
|
||||||
|
if not camera_pivot:
|
||||||
|
return
|
||||||
|
camera_pivot.top_level = false
|
||||||
|
var b: Basis = head_local.basis
|
||||||
|
b = b.rotated(b.x, cockpit_pitch)
|
||||||
|
b = b.rotated(b.y, cockpit_yaw)
|
||||||
|
b = b.orthonormalized()
|
||||||
|
if abs(b.determinant()) < 0.5:
|
||||||
|
camera_pivot.transform = head_local
|
||||||
|
return
|
||||||
|
camera_pivot.transform = Transform3D(b, head_local.origin)
|
||||||
|
|
||||||
|
|
||||||
|
func update_third_person_camera() -> void:
|
||||||
|
if not third_person_camera:
|
||||||
|
return
|
||||||
|
var cy := cos(orbit_yaw)
|
||||||
|
var sy := sin(orbit_yaw)
|
||||||
|
var cp := cos(orbit_pitch)
|
||||||
|
var sp := sin(orbit_pitch)
|
||||||
|
var offset := Vector3(sy * cp, sp, cy * cp) * orbit_distance
|
||||||
|
var local_off := Vector3(offset.x, -offset.z, offset.y)
|
||||||
|
var cam_pos := global_position + global_transform.basis * local_off
|
||||||
|
third_person_camera.global_position = cam_pos
|
||||||
|
var target := global_position + global_transform.basis.y * 1.5
|
||||||
|
var forward := target - cam_pos
|
||||||
|
if forward.length_squared() < 0.0001:
|
||||||
|
return
|
||||||
|
forward = forward.normalized()
|
||||||
|
var ref_up := global_transform.basis.z
|
||||||
|
if abs(forward.dot(ref_up)) > 0.92:
|
||||||
|
ref_up = global_transform.basis.x
|
||||||
|
var right := ref_up.cross(forward)
|
||||||
|
if right.length_squared() < 0.0001:
|
||||||
|
return
|
||||||
|
right = right.normalized()
|
||||||
|
var up := forward.cross(right).normalized()
|
||||||
|
var cam_basis := Basis(-right, up, -forward).orthonormalized()
|
||||||
|
if abs(cam_basis.determinant()) < 0.5:
|
||||||
|
return
|
||||||
|
third_person_camera.global_basis = cam_basis
|
||||||
|
|
||||||
|
|
||||||
|
func handle_flight(delta: float) -> void:
|
||||||
|
_update_crust_exception()
|
||||||
|
var input_pitch := 0.0
|
||||||
|
var input_roll := 0.0
|
||||||
|
var input_yaw := 0.0
|
||||||
|
if Input.is_key_pressed(KEY_W):
|
||||||
|
input_pitch -= 1.0
|
||||||
|
if Input.is_key_pressed(KEY_S):
|
||||||
|
input_pitch += 1.0
|
||||||
|
if Input.is_key_pressed(KEY_A):
|
||||||
|
input_yaw += 1.0
|
||||||
|
if Input.is_key_pressed(KEY_D):
|
||||||
|
input_yaw -= 1.0
|
||||||
|
if Input.is_key_pressed(KEY_Q):
|
||||||
|
input_roll -= 1.0
|
||||||
|
if Input.is_key_pressed(KEY_E):
|
||||||
|
input_roll += 1.0
|
||||||
|
rotate_object_local(Vector3.RIGHT, input_pitch * rotation_speed * delta)
|
||||||
|
rotate_object_local(Vector3.FORWARD, -input_yaw * rotation_speed * delta)
|
||||||
|
rotate_object_local(Vector3.UP, input_roll * rotation_speed * delta)
|
||||||
|
var thrusting := Input.is_key_pressed(KEY_SPACE)
|
||||||
|
_set_hull("abort_burn", thrusting)
|
||||||
|
_set_hull("att_pitch", input_pitch)
|
||||||
|
_set_hull("att_yaw", input_yaw)
|
||||||
|
_set_hull("att_roll", input_roll)
|
||||||
|
_set_hull("rcs_direction", 0)
|
||||||
|
var acceleration: Vector3 = _gravity_accel()
|
||||||
|
if thrusting:
|
||||||
|
acceleration += global_transform.basis.y * (thrust_force / mass)
|
||||||
|
velocity += acceleration * delta
|
||||||
|
var near_surface := is_on_floor() or _crust_exception
|
||||||
|
if not near_surface:
|
||||||
|
var moon := _moon()
|
||||||
|
if moon and global_position.distance_to(moon.global_position) < MOON_RADIUS + NEAR_SURFACE_MARGIN:
|
||||||
|
near_surface = true
|
||||||
|
var earth := _earth()
|
||||||
|
if earth and global_position.distance_to(earth.global_position) < EARTH_RADIUS + NEAR_SURFACE_MARGIN:
|
||||||
|
near_surface = true
|
||||||
|
if near_surface:
|
||||||
|
if body_collision:
|
||||||
|
body_collision.disabled = false
|
||||||
|
move_and_slide()
|
||||||
|
if is_on_floor():
|
||||||
|
velocity.x = move_toward(velocity.x, 0.0, surface_friction * delta)
|
||||||
|
velocity.z = move_toward(velocity.z, 0.0, surface_friction * delta)
|
||||||
|
if velocity.length() < 0.08:
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
else:
|
||||||
|
if body_collision:
|
||||||
|
body_collision.disabled = true
|
||||||
|
global_position += velocity * delta
|
||||||
|
PhysicsServer3D.body_set_state(
|
||||||
|
get_rid(),
|
||||||
|
PhysicsServer3D.BODY_STATE_TRANSFORM,
|
||||||
|
global_transform
|
||||||
|
)
|
||||||
|
PhysicsServer3D.body_set_state(
|
||||||
|
get_rid(),
|
||||||
|
PhysicsServer3D.BODY_STATE_LINEAR_VELOCITY,
|
||||||
|
velocity
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://1udl42sp42sp
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
extends Node
|
||||||
|
## Sibling FO. Shift registered world roots.
|
||||||
|
## Move focus only when it is NOT already under a root (capsule = sibling).
|
||||||
|
## Never zero velocity.
|
||||||
|
|
||||||
|
const THRESHOLD: float = 50000.0
|
||||||
|
const COOLDOWN: float = 0.25
|
||||||
|
|
||||||
|
var focus: Node3D = null
|
||||||
|
var _shift_roots: Array[Node3D] = []
|
||||||
|
var _cooldown: float = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
|
|
||||||
|
|
||||||
|
func set_focus(node: Node3D) -> void:
|
||||||
|
focus = node
|
||||||
|
|
||||||
|
|
||||||
|
func register_root(node: Node3D) -> void:
|
||||||
|
if node == null:
|
||||||
|
return
|
||||||
|
if not _shift_roots.has(node):
|
||||||
|
_shift_roots.append(node)
|
||||||
|
print("FloatingOrigin registered: ", node.name)
|
||||||
|
|
||||||
|
|
||||||
|
func unregister_root(node: Node3D) -> void:
|
||||||
|
_shift_roots.erase(node)
|
||||||
|
|
||||||
|
|
||||||
|
func shift(offset: Vector3) -> void:
|
||||||
|
if offset.length_squared() < 1.0:
|
||||||
|
return
|
||||||
|
_apply_shift(offset)
|
||||||
|
_cooldown = COOLDOWN
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
if _cooldown > 0.0:
|
||||||
|
_cooldown -= delta
|
||||||
|
return
|
||||||
|
if focus == null or not is_instance_valid(focus) or not focus.is_inside_tree():
|
||||||
|
return
|
||||||
|
if _shift_roots.is_empty():
|
||||||
|
return
|
||||||
|
var fp: Vector3 = focus.global_position
|
||||||
|
if fp.length() < THRESHOLD:
|
||||||
|
return
|
||||||
|
_apply_shift(-fp)
|
||||||
|
_cooldown = COOLDOWN
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_shift(offset: Vector3) -> void:
|
||||||
|
for root in _shift_roots:
|
||||||
|
if is_instance_valid(root) and root.is_inside_tree():
|
||||||
|
root.global_position += offset
|
||||||
|
if is_instance_valid(focus) and focus.is_inside_tree() and not _focus_under_a_root():
|
||||||
|
focus.global_position += offset
|
||||||
|
_sync_focus_physics()
|
||||||
|
print("FloatingOrigin shift: ", offset, " focus now: ", focus.global_position if focus else Vector3.ZERO)
|
||||||
|
|
||||||
|
|
||||||
|
func _focus_under_a_root() -> bool:
|
||||||
|
var n: Node = focus
|
||||||
|
while n != null:
|
||||||
|
if n is Node3D and _shift_roots.has(n as Node3D):
|
||||||
|
return true
|
||||||
|
n = n.get_parent()
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _sync_focus_physics() -> void:
|
||||||
|
if focus == null or not is_instance_valid(focus):
|
||||||
|
return
|
||||||
|
if not (focus is CharacterBody3D):
|
||||||
|
return
|
||||||
|
var body := focus as CharacterBody3D
|
||||||
|
var saved_vel: Vector3 = body.velocity
|
||||||
|
PhysicsServer3D.body_set_state(
|
||||||
|
body.get_rid(),
|
||||||
|
PhysicsServer3D.BODY_STATE_TRANSFORM,
|
||||||
|
body.global_transform
|
||||||
|
)
|
||||||
|
PhysicsServer3D.body_set_state(
|
||||||
|
body.get_rid(),
|
||||||
|
PhysicsServer3D.BODY_STATE_LINEAR_VELOCITY,
|
||||||
|
saved_vel
|
||||||
|
)
|
||||||
|
body.velocity = saved_vel
|
||||||
|
if body.has_method("reset_physics_interpolation"):
|
||||||
|
body.reset_physics_interpolation()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ckl5inm8ugypo
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
const SAVE_PATH := "user://save_slot_1.json"
|
||||||
|
var has_save: bool = false
|
||||||
|
var play_elapsed: float = 0.0
|
||||||
|
var demo_limit: float = 36000.0
|
||||||
|
var scramble_at: float = 35280.0
|
||||||
|
var scramble_started: bool = false
|
||||||
|
var clock_paused: bool = false
|
||||||
|
var game_year: int = 2066
|
||||||
|
var game_month: int = 9
|
||||||
|
var game_day: int = 14
|
||||||
|
var game_hour: float = 8.0
|
||||||
|
var time_scale: float = 1.0
|
||||||
|
signal scramble_begun
|
||||||
|
signal time_scale_changed(new_scale: float)
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
has_save = FileAccess.file_exists(SAVE_PATH)
|
||||||
|
process_mode = Node.PROCESS_MODE_PAUSABLE
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if clock_paused:
|
||||||
|
return
|
||||||
|
var stepped: float = delta * time_scale
|
||||||
|
play_elapsed += stepped
|
||||||
|
_advance_game_clock(stepped)
|
||||||
|
if not scramble_started and play_elapsed >= scramble_at:
|
||||||
|
scramble_started = true
|
||||||
|
scramble_begun.emit()
|
||||||
|
print("SCRAMBLE: Unknown Vessels Inbound")
|
||||||
|
|
||||||
|
|
||||||
|
func set_time_scale(scale: float) -> void:
|
||||||
|
time_scale = clampf(scale, 0.0, 4.0)
|
||||||
|
time_scale_changed.emit(time_scale)
|
||||||
|
print("Time scale: x", time_scale)
|
||||||
|
|
||||||
|
|
||||||
|
func _advance_game_clock(game_seconds: float) -> void:
|
||||||
|
game_hour += game_seconds / 3600.0
|
||||||
|
while game_hour >= 24.0:
|
||||||
|
game_hour -= 24.0
|
||||||
|
game_day += 1
|
||||||
|
var days_in_month: int = _days_in_month(game_year, game_month)
|
||||||
|
if game_day > days_in_month:
|
||||||
|
game_day = 1
|
||||||
|
game_month += 1
|
||||||
|
if game_month > 12:
|
||||||
|
game_month = 1
|
||||||
|
game_year += 1
|
||||||
|
|
||||||
|
|
||||||
|
func _days_in_month(_year: int, month: int) -> int:
|
||||||
|
match month:
|
||||||
|
1, 3, 5, 7, 8, 10, 12:
|
||||||
|
return 31
|
||||||
|
4, 6, 9, 11:
|
||||||
|
return 30
|
||||||
|
2:
|
||||||
|
return 28
|
||||||
|
_:
|
||||||
|
return 30
|
||||||
|
|
||||||
|
|
||||||
|
func get_time_string() -> String:
|
||||||
|
var h: int = int(game_hour)
|
||||||
|
var m: int = int((game_hour - float(h)) * 60.0)
|
||||||
|
var s: int = int((game_hour - float(h) - float(m) / 60.0) * 3600.0)
|
||||||
|
var month_names := ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||||
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||||
|
var mon: String = month_names[game_month]
|
||||||
|
var scale_txt := ""
|
||||||
|
if time_scale == 0.0:
|
||||||
|
scale_txt = " PAUSED"
|
||||||
|
elif time_scale > 1.0:
|
||||||
|
scale_txt = " x%d" % int(time_scale)
|
||||||
|
return "%d %s %d %02d:%02d:%02d%s" % [game_day, mon, game_year, h, m, s, scale_txt]
|
||||||
|
|
||||||
|
|
||||||
|
func get_play_remaining_string() -> String:
|
||||||
|
var left: float = max(demo_limit - play_elapsed, 0.0)
|
||||||
|
var h: int = int(left / 3600.0)
|
||||||
|
var m: int = int((left - float(h) * 3600.0) / 60.0)
|
||||||
|
var sec: int = int(left) % 60
|
||||||
|
return "%02d:%02d:%02d" % [h, m, sec]
|
||||||
|
|
||||||
|
|
||||||
|
func save_game(player: Node) -> void:
|
||||||
|
if player == null:
|
||||||
|
return
|
||||||
|
var look = {}
|
||||||
|
if "appearance" in player:
|
||||||
|
look = player.appearance
|
||||||
|
var data := {
|
||||||
|
"player_name": player.player_name,
|
||||||
|
"background_id": player.background_id,
|
||||||
|
"background_name": player.background_name,
|
||||||
|
"culture_id": player.culture_id if "culture_id" in player else "",
|
||||||
|
"culture_name": player.culture_name if "culture_name" in player else "",
|
||||||
|
"appearance": look,
|
||||||
|
"money": player.money,
|
||||||
|
"food": player.food,
|
||||||
|
"health": player.health,
|
||||||
|
"oxygen": player.oxygen,
|
||||||
|
"inventory": player.inventory.duplicate(),
|
||||||
|
"position": {
|
||||||
|
"x": player.global_position.x,
|
||||||
|
"y": player.global_position.y,
|
||||||
|
"z": player.global_position.z
|
||||||
|
},
|
||||||
|
"play_elapsed": play_elapsed,
|
||||||
|
"scramble_started": scramble_started,
|
||||||
|
"game_year": game_year,
|
||||||
|
"game_month": game_month,
|
||||||
|
"game_day": game_day,
|
||||||
|
"game_hour": game_hour,
|
||||||
|
"time_scale": time_scale
|
||||||
|
}
|
||||||
|
var file := FileAccess.open(SAVE_PATH, FileAccess.WRITE)
|
||||||
|
if file:
|
||||||
|
file.store_string(JSON.stringify(data))
|
||||||
|
file.close()
|
||||||
|
has_save = true
|
||||||
|
print("Game saved")
|
||||||
|
|
||||||
|
|
||||||
|
func load_game_data() -> Dictionary:
|
||||||
|
if not FileAccess.file_exists(SAVE_PATH):
|
||||||
|
return {}
|
||||||
|
var file := FileAccess.open(SAVE_PATH, FileAccess.READ)
|
||||||
|
if file == null:
|
||||||
|
return {}
|
||||||
|
var text := file.get_as_text()
|
||||||
|
file.close()
|
||||||
|
var parsed = JSON.parse_string(text)
|
||||||
|
if typeof(parsed) == TYPE_DICTIONARY:
|
||||||
|
return parsed
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
func apply_loaded_clock(data: Dictionary) -> void:
|
||||||
|
play_elapsed = float(data.get("play_elapsed", 0.0))
|
||||||
|
scramble_started = bool(data.get("scramble_started", false))
|
||||||
|
game_year = int(data.get("game_year", 2066))
|
||||||
|
game_month = int(data.get("game_month", 9))
|
||||||
|
game_day = int(data.get("game_day", 14))
|
||||||
|
game_hour = float(data.get("game_hour", 8.0))
|
||||||
|
time_scale = float(data.get("time_scale", 1.0))
|
||||||
|
clock_paused = false
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b3o7ua8cv55tq
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://br0vxsoinqwe1
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Dried Noodles"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bigf78nt5im5v
|
||||||
@@ -0,0 +1,646 @@
|
|||||||
|
extends Node3D
|
||||||
|
## Player/Body look loader. PASTE 2026-09-12 22:54 — 1P always gun-out eye ride
|
||||||
|
## 8-way = yaw CreatedBody toward the stick + Walk/Run.
|
||||||
|
## No AnimationTree. Waist fold AFTER clip via SkeletonModifier3D.
|
||||||
|
|
||||||
|
const MALE_FBX := "res://character assets/All together/FBX/Humans_Master.fbx"
|
||||||
|
const FEMALE_FBX := "res://character assets/All together/FBX women/All together.fbx"
|
||||||
|
|
||||||
|
const CLIP_ALIASES := {
|
||||||
|
"Idle": ["Idle"],
|
||||||
|
"Walk": ["Walk"],
|
||||||
|
"Run": ["Run"],
|
||||||
|
"Run_Back": ["Run_Back", "RunBack"],
|
||||||
|
"Run_Left": ["Run_Left", "RunLeft"],
|
||||||
|
"Run_Right": ["Run_Right", "RunRight"],
|
||||||
|
"Jump": ["Jump"],
|
||||||
|
"Interact": ["Interact", "Pickup", "PickUp"],
|
||||||
|
"Idle_Gun": ["Idle_Gun", "Idle_Gun_Pointing", "Gun_Idle"],
|
||||||
|
"AimIdle": ["Idle_Gun_Pointing", "Idle_Gun", "Gun_Idle", "Aim_Idle"],
|
||||||
|
"AimWalk": ["Walk_Shoot", "WalkShoot", "Gun_Walk", "Walk_Gun", "Walk"],
|
||||||
|
"Walk_Shoot": ["Walk_Shoot", "WalkShoot", "Gun_Walk", "Walk"],
|
||||||
|
"AimRun": ["Run_Shoot", "RunShoot", "Gun_Run", "Run_Gun", "Run"],
|
||||||
|
"Run_Shoot": ["Run_Shoot", "RunShoot", "Run"],
|
||||||
|
"Gun_Shoot": ["Gun_Shoot", "Pistol_Shoot", "Shoot", "Idle_Gun_Shoot"],
|
||||||
|
"Idle_Gun_Shoot": ["Idle_Gun_Shoot", "Gun_Shoot", "Idle_Gun_Pointing"],
|
||||||
|
}
|
||||||
|
|
||||||
|
var current: Node3D = null
|
||||||
|
var anim: AnimationPlayer = null
|
||||||
|
var last_keep: Array[String] = []
|
||||||
|
var _logged_names: bool = false
|
||||||
|
var hide_head: bool = false
|
||||||
|
var show_pistol: bool = false
|
||||||
|
|
||||||
|
var _skel: Skeleton3D = null
|
||||||
|
var _bone_abdomen: int = -1
|
||||||
|
var _bone_torso: int = -1
|
||||||
|
var _bone_chest: int = -1
|
||||||
|
var _bone_head: int = -1
|
||||||
|
var _bone_rarm: int = -1
|
||||||
|
var _bone_larm: int = -1
|
||||||
|
var _bone_rfore: int = -1
|
||||||
|
var _bone_lfore: int = -1
|
||||||
|
var _aim_pitch: float = 0.0
|
||||||
|
var _aim_enabled: bool = false
|
||||||
|
var _logged_bones: bool = false
|
||||||
|
var _mod: SkeletonModifier3D = null
|
||||||
|
var _dbg: float = 0.0
|
||||||
|
|
||||||
|
var tree: AnimationTree = null
|
||||||
|
var _walk_bs: AnimationNodeBlendSpace2D = null
|
||||||
|
var _run_bs: AnimationNodeBlendSpace2D = null
|
||||||
|
var _aim_walk_bs: AnimationNodeBlendSpace2D = null
|
||||||
|
var _aim_run_bs: AnimationNodeBlendSpace2D = null
|
||||||
|
var _mode: String = ""
|
||||||
|
var _blend_pos: Vector2 = Vector2.ZERO
|
||||||
|
var _run_amt: float = 0.0
|
||||||
|
var _aiming: bool = false
|
||||||
|
var _fire_lock: float = 0.0
|
||||||
|
var _ride_fp: bool = false
|
||||||
|
var _fp_cam: Camera3D = null
|
||||||
|
var _fp_pivot: Node3D = null
|
||||||
|
var arm_axis_id: int = 2
|
||||||
|
|
||||||
|
|
||||||
|
class AimBend extends SkeletonModifier3D:
|
||||||
|
var host: Node
|
||||||
|
func _process_modification() -> void:
|
||||||
|
if host and host.has_method("_apply_waist_now"):
|
||||||
|
host._apply_waist_now()
|
||||||
|
|
||||||
|
|
||||||
|
func apply_look(appearance: Dictionary) -> AnimationPlayer:
|
||||||
|
_clear_old()
|
||||||
|
var sex := str(appearance.get("sex", "male"))
|
||||||
|
var path := MALE_FBX if sex == "male" else FEMALE_FBX
|
||||||
|
if not ResourceLoader.exists(path):
|
||||||
|
push_warning("Look file missing: " + path)
|
||||||
|
return null
|
||||||
|
var packed = load(path)
|
||||||
|
if packed == null:
|
||||||
|
return null
|
||||||
|
var inst: Node = packed.instantiate()
|
||||||
|
if not (inst is Node3D):
|
||||||
|
return null
|
||||||
|
current = inst as Node3D
|
||||||
|
current.name = "CreatedBody"
|
||||||
|
current.position = Vector3.ZERO
|
||||||
|
current.rotation_degrees = Vector3.ZERO
|
||||||
|
current.scale = Vector3.ONE * 1.3
|
||||||
|
add_child(current)
|
||||||
|
last_keep = [
|
||||||
|
str(appearance.get("head", "Casual_Head")),
|
||||||
|
str(appearance.get("body", "Casual_Body")),
|
||||||
|
str(appearance.get("legs", "Casual_Legs")),
|
||||||
|
str(appearance.get("feet", "Casual_Feet")),
|
||||||
|
]
|
||||||
|
anim = current.find_child("AnimationPlayer", true, false) as AnimationPlayer
|
||||||
|
if anim:
|
||||||
|
anim.speed_scale = 1.0
|
||||||
|
anim.root_motion_track = NodePath()
|
||||||
|
_loop_locomotion(anim)
|
||||||
|
print("Look clips: ", anim.get_animation_list())
|
||||||
|
_cache_skeleton()
|
||||||
|
_build_loco_tree()
|
||||||
|
_apply_keep(current, last_keep)
|
||||||
|
call_deferred("_apply_keep_deferred")
|
||||||
|
return anim
|
||||||
|
|
||||||
|
|
||||||
|
func _resolve_clip(logical: String) -> String:
|
||||||
|
if anim == null:
|
||||||
|
return ""
|
||||||
|
var names: Array = CLIP_ALIASES.get(logical, [logical])
|
||||||
|
var candidates: Array[String] = []
|
||||||
|
for n in names:
|
||||||
|
candidates.append("CharacterArmature|%s" % n)
|
||||||
|
candidates.append(str(n))
|
||||||
|
for clip in candidates:
|
||||||
|
if anim.has_animation(clip):
|
||||||
|
return clip
|
||||||
|
for clip in anim.get_animation_list():
|
||||||
|
for n in names:
|
||||||
|
if clip.ends_with(str(n)) or clip.contains(str(n)):
|
||||||
|
return clip
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
func play_clip(logical: String, speed_scale: float = 1.0) -> void:
|
||||||
|
if anim == null:
|
||||||
|
return
|
||||||
|
if tree:
|
||||||
|
tree.active = false
|
||||||
|
var clip := _resolve_clip(logical)
|
||||||
|
if clip.is_empty():
|
||||||
|
return
|
||||||
|
var a: Animation = anim.get_animation(clip)
|
||||||
|
if a:
|
||||||
|
var looped := logical in [
|
||||||
|
"Idle", "Walk", "Run", "Run_Back", "Run_Left", "Run_Right",
|
||||||
|
"Idle_Gun", "AimIdle", "AimWalk", "AimRun", "Walk_Shoot", "Run_Shoot"
|
||||||
|
]
|
||||||
|
a.loop_mode = Animation.LOOP_LINEAR if looped else Animation.LOOP_NONE
|
||||||
|
anim.speed_scale = speed_scale
|
||||||
|
if anim.current_animation != clip:
|
||||||
|
anim.play(clip)
|
||||||
|
elif not anim.is_playing():
|
||||||
|
anim.play(clip)
|
||||||
|
_apply_keep(current, last_keep)
|
||||||
|
|
||||||
|
|
||||||
|
func _loop_locomotion(player: AnimationPlayer) -> void:
|
||||||
|
for logical in [
|
||||||
|
"Idle", "Walk", "Run", "Run_Back", "Run_Left", "Run_Right",
|
||||||
|
"Idle_Gun", "AimIdle", "AimWalk", "AimRun", "Walk_Shoot", "Run_Shoot"
|
||||||
|
]:
|
||||||
|
var clip := _resolve_clip(logical)
|
||||||
|
if clip.is_empty():
|
||||||
|
continue
|
||||||
|
var a: Animation = player.get_animation(clip)
|
||||||
|
if a:
|
||||||
|
a.loop_mode = Animation.LOOP_LINEAR
|
||||||
|
|
||||||
|
|
||||||
|
func _clip_node(logical: String) -> AnimationNodeAnimation:
|
||||||
|
var n := AnimationNodeAnimation.new()
|
||||||
|
var clip := _resolve_clip(logical)
|
||||||
|
if clip.is_empty():
|
||||||
|
clip = _resolve_clip("Idle")
|
||||||
|
if clip.is_empty():
|
||||||
|
clip = logical
|
||||||
|
n.animation = StringName(clip)
|
||||||
|
n.resource_name = logical
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
func _add_pt(bs: AnimationNodeBlendSpace2D, logical: String, pos: Vector2, label: String) -> void:
|
||||||
|
var node := _clip_node(logical)
|
||||||
|
bs.add_blend_point(node, pos)
|
||||||
|
var idx: int = bs.get_blend_point_count() - 1
|
||||||
|
if bs.has_method("set_blend_point_name"):
|
||||||
|
bs.call("set_blend_point_name", idx, StringName(label))
|
||||||
|
|
||||||
|
|
||||||
|
func _make_space(_idle: String, fwd: String, back: String, left: String, right: String) -> AnimationNodeBlendSpace2D:
|
||||||
|
var bs := AnimationNodeBlendSpace2D.new()
|
||||||
|
# Discrete = one whole clip. Interpolating Walk with Run_Left is clown shoes.
|
||||||
|
bs.blend_mode = AnimationNodeBlendSpace2D.BLEND_MODE_DISCRETE_CARRY
|
||||||
|
bs.min_space = Vector2(-1.0, -1.0)
|
||||||
|
bs.max_space = Vector2(1.0, 1.0)
|
||||||
|
bs.snap = Vector2(0.0, 0.0)
|
||||||
|
_add_pt(bs, fwd, Vector2(0.0, -1.0), "fwd")
|
||||||
|
_add_pt(bs, back, Vector2(0.0, 1.0), "back")
|
||||||
|
_add_pt(bs, left, Vector2(-1.0, 0.0), "left")
|
||||||
|
_add_pt(bs, right, Vector2(1.0, 0.0), "right")
|
||||||
|
_add_pt(bs, fwd, Vector2(-0.71, -0.71), "fwd_left")
|
||||||
|
_add_pt(bs, fwd, Vector2(0.71, -0.71), "fwd_right")
|
||||||
|
_add_pt(bs, back, Vector2(-0.71, 0.71), "back_left")
|
||||||
|
_add_pt(bs, back, Vector2(0.71, 0.71), "back_right")
|
||||||
|
return bs
|
||||||
|
|
||||||
|
|
||||||
|
func _build_loco_tree() -> void:
|
||||||
|
# No AnimationTree. Quaternius has no Walk_Left/Walk_Right — blending
|
||||||
|
# Walk with Run_Left is clown shoes. One clip per octant instead.
|
||||||
|
if tree and is_instance_valid(tree):
|
||||||
|
tree.queue_free()
|
||||||
|
tree = null
|
||||||
|
_walk_bs = null
|
||||||
|
_run_bs = null
|
||||||
|
_aim_walk_bs = null
|
||||||
|
_aim_run_bs = null
|
||||||
|
_mode = "idle"
|
||||||
|
_blend_pos = Vector2.ZERO
|
||||||
|
_run_amt = 0.0
|
||||||
|
print("Loco clips walk=", _resolve_clip("Walk"),
|
||||||
|
" left=", _resolve_clip("Run_Left"),
|
||||||
|
" right=", _resolve_clip("Run_Right"),
|
||||||
|
" back=", _resolve_clip("Run_Back"),
|
||||||
|
" run=", _resolve_clip("Run"),
|
||||||
|
" aimIdle=", _resolve_clip("AimIdle"))
|
||||||
|
|
||||||
|
|
||||||
|
func play_fire(aiming_now: bool = false) -> void:
|
||||||
|
var logical: String = "Idle_Gun_Shoot" if aiming_now else "Gun_Shoot"
|
||||||
|
play_clip(logical)
|
||||||
|
var clip := _resolve_clip(logical)
|
||||||
|
var dur: float = 0.26
|
||||||
|
if anim and not clip.is_empty() and anim.has_animation(clip):
|
||||||
|
dur = maxf(0.16, anim.get_animation(clip).length * 0.82)
|
||||||
|
_fire_lock = dur
|
||||||
|
|
||||||
|
|
||||||
|
func set_loco(strafe: float, back: float, run_amount: float, delta: float = 0.016, aiming: bool = false) -> void:
|
||||||
|
_aiming = aiming
|
||||||
|
if tree and tree.active:
|
||||||
|
tree.active = false
|
||||||
|
if _fire_lock > 0.0:
|
||||||
|
_fire_lock = maxf(_fire_lock - delta, 0.0)
|
||||||
|
if aiming:
|
||||||
|
_face_move(0.0, delta, 14.0)
|
||||||
|
return
|
||||||
|
if aiming:
|
||||||
|
_face_move(0.0, delta, 14.0)
|
||||||
|
var aim_stick := Vector2(clampf(strafe, -1.0, 1.0), clampf(back, -1.0, 1.0))
|
||||||
|
_blend_pos = aim_stick.normalized() if aim_stick.length() >= 0.16 else Vector2.ZERO
|
||||||
|
_run_amt = run_amount if aim_stick.length() >= 0.16 else 0.0
|
||||||
|
if aim_stick.length() < 0.16:
|
||||||
|
_mode = "aim_idle"
|
||||||
|
play_clip("AimIdle")
|
||||||
|
elif run_amount > 0.5:
|
||||||
|
_mode = "aim_run"
|
||||||
|
play_clip("AimRun")
|
||||||
|
else:
|
||||||
|
_mode = "aim_walk"
|
||||||
|
play_clip("AimWalk")
|
||||||
|
return
|
||||||
|
var target := Vector2(clampf(strafe, -1.0, 1.0), clampf(back, -1.0, 1.0))
|
||||||
|
if target.length() < 0.16:
|
||||||
|
_face_move(0.0, delta, 10.0)
|
||||||
|
_blend_pos = Vector2.ZERO
|
||||||
|
_run_amt = 0.0
|
||||||
|
if show_pistol or hide_head:
|
||||||
|
_mode = "idle_gun"
|
||||||
|
play_clip("Idle_Gun")
|
||||||
|
else:
|
||||||
|
_mode = "idle"
|
||||||
|
play_clip("Idle")
|
||||||
|
return
|
||||||
|
_blend_pos = target.normalized()
|
||||||
|
_run_amt = 1.0 if run_amount > 0.5 else 0.0
|
||||||
|
# S / SA / SD — backpedal, no 180 spin
|
||||||
|
if _blend_pos.y > 0.2:
|
||||||
|
_face_move(0.0, delta, 12.0)
|
||||||
|
_mode = "Run_Back"
|
||||||
|
play_clip("Run_Back")
|
||||||
|
return
|
||||||
|
# Pure A / D — sidestep, keep facing camera-forward
|
||||||
|
if absf(_blend_pos.x) >= 0.62 and absf(_blend_pos.y) <= 0.42:
|
||||||
|
_face_move(0.0, delta, 14.0)
|
||||||
|
var side: String = "Run_Left" if _blend_pos.x < 0.0 else "Run_Right"
|
||||||
|
_mode = side
|
||||||
|
play_clip(side)
|
||||||
|
return
|
||||||
|
# W / WA / WD — face the stick + Walk/Run
|
||||||
|
var yaw := atan2(-_blend_pos.x, maxf(-_blend_pos.y, 0.001))
|
||||||
|
yaw = clampf(yaw, deg_to_rad(-90.0), deg_to_rad(90.0))
|
||||||
|
_face_move(yaw, delta, 16.0)
|
||||||
|
var logical: String = "Run" if _run_amt > 0.5 else "Walk"
|
||||||
|
_mode = logical
|
||||||
|
var pace: float = 0.92 + _run_amt * 0.18 if logical == "Run" else 0.88 + target.length() * 0.14
|
||||||
|
play_clip(logical, pace)
|
||||||
|
|
||||||
|
|
||||||
|
func _face_move(yaw: float, delta: float, rate: float) -> void:
|
||||||
|
if current == null or not is_instance_valid(current):
|
||||||
|
return
|
||||||
|
current.rotation.y = lerp_angle(current.rotation.y, yaw, clampf(rate * delta, 0.0, 1.0))
|
||||||
|
|
||||||
|
|
||||||
|
func set_first_person(fp: bool) -> void:
|
||||||
|
hide_head = fp
|
||||||
|
print("Look 1P=", fp, " idle=Idle_Gun" if fp else " idle=Idle")
|
||||||
|
if current != null and is_instance_valid(current):
|
||||||
|
_apply_keep(current, last_keep)
|
||||||
|
|
||||||
|
|
||||||
|
func set_pistol_drawn(drawn: bool) -> void:
|
||||||
|
show_pistol = drawn
|
||||||
|
if current != null and is_instance_valid(current):
|
||||||
|
_apply_keep(current, last_keep)
|
||||||
|
|
||||||
|
|
||||||
|
func set_meshes_visible(v: bool) -> void:
|
||||||
|
if current == null:
|
||||||
|
return
|
||||||
|
if v:
|
||||||
|
_apply_keep(current, last_keep)
|
||||||
|
else:
|
||||||
|
_hide_all_visuals(current)
|
||||||
|
|
||||||
|
|
||||||
|
func set_aim_pitch(radians: float) -> void:
|
||||||
|
if not _aim_enabled:
|
||||||
|
_aim_pitch = 0.0
|
||||||
|
return
|
||||||
|
_aim_pitch = clampf(radians, deg_to_rad(-50.0), deg_to_rad(65.0))
|
||||||
|
|
||||||
|
|
||||||
|
func get_head_global_pos() -> Vector3:
|
||||||
|
if _skel == null or not is_instance_valid(_skel) or _bone_head < 0:
|
||||||
|
return Vector3.INF
|
||||||
|
var pose: Transform3D = _skel.get_bone_global_pose(_bone_head)
|
||||||
|
return _skel.to_global(pose.origin)
|
||||||
|
|
||||||
|
|
||||||
|
func set_fp_ride(cam: Camera3D, pivot: Node3D, on: bool) -> void:
|
||||||
|
_fp_cam = cam
|
||||||
|
_fp_pivot = pivot
|
||||||
|
_ride_fp = on and cam != null
|
||||||
|
|
||||||
|
|
||||||
|
func set_aim_enabled(on: bool) -> void:
|
||||||
|
_aim_enabled = on
|
||||||
|
if not on:
|
||||||
|
_aim_pitch = 0.0
|
||||||
|
if _mod:
|
||||||
|
_mod.active = on
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
_dbg += delta
|
||||||
|
if _dbg < 4.0:
|
||||||
|
return
|
||||||
|
_dbg = 0.0
|
||||||
|
print("Loco dbg mode=", _mode,
|
||||||
|
" pos=", snapped(_blend_pos, Vector2(0.01, 0.01)),
|
||||||
|
" run=", snappedf(_run_amt, 0.01),
|
||||||
|
" aim=", _aiming,
|
||||||
|
" player=", anim.current_animation if anim else "?")
|
||||||
|
if _aim_enabled:
|
||||||
|
print("AimFold on pitch=", snappedf(rad_to_deg(_aim_pitch), 0.1),
|
||||||
|
" abd=", _bone_name(_bone_abdomen),
|
||||||
|
" torso=", _bone_name(_bone_torso),
|
||||||
|
" chest=", _bone_name(_bone_chest),
|
||||||
|
" mod=", _mod != null, " active=", _mod.active if _mod else false)
|
||||||
|
|
||||||
|
|
||||||
|
func _cache_skeleton() -> void:
|
||||||
|
_skel = null
|
||||||
|
_bone_abdomen = -1
|
||||||
|
_bone_torso = -1
|
||||||
|
_bone_chest = -1
|
||||||
|
_bone_head = -1
|
||||||
|
_bone_rarm = -1
|
||||||
|
_bone_larm = -1
|
||||||
|
_bone_rfore = -1
|
||||||
|
_bone_lfore = -1
|
||||||
|
_mod = null
|
||||||
|
if current == null:
|
||||||
|
return
|
||||||
|
_skel = current.find_child("Skeleton3D", true, false) as Skeleton3D
|
||||||
|
if _skel == null:
|
||||||
|
push_warning("Look: no Skeleton3D on CreatedBody")
|
||||||
|
return
|
||||||
|
_bone_abdomen = _find_exact(["Abdomen", "mixamorig_Spine", "mixamorig:Spine", "Spine"])
|
||||||
|
_bone_torso = _find_exact(["Torso", "mixamorig_Spine1", "mixamorig:Spine1", "Spine1"])
|
||||||
|
_bone_chest = _find_exact(["Chest", "mixamorig_Spine2", "mixamorig:Spine2", "Spine2", "UpperChest"])
|
||||||
|
_bone_head = _find_exact(["Head", "mixamorig_Head", "mixamorig:Head"])
|
||||||
|
_bone_rarm = _find_limb(["mixamorig_RightArm", "mixamorig:RightArm", "RightArm", "Arm.R"])
|
||||||
|
_bone_larm = _find_limb(["mixamorig_LeftArm", "mixamorig:LeftArm", "LeftArm", "Arm.L"])
|
||||||
|
_bone_rfore = _find_limb(["mixamorig_RightForeArm", "mixamorig:RightForeArm", "RightForeArm", "ForeArm.R"])
|
||||||
|
_bone_lfore = _find_limb(["mixamorig_LeftForeArm", "mixamorig:LeftForeArm", "LeftForeArm", "ForeArm.L"])
|
||||||
|
_mod = AimBend.new()
|
||||||
|
_mod.name = "AimBend"
|
||||||
|
_mod.host = self
|
||||||
|
_mod.active = false
|
||||||
|
_skel.add_child(_mod)
|
||||||
|
if not _logged_bones:
|
||||||
|
_logged_bones = true
|
||||||
|
print("Look skeleton=", _skel.name,
|
||||||
|
" abd=", _bone_name(_bone_abdomen),
|
||||||
|
" torso=", _bone_name(_bone_torso),
|
||||||
|
" chest=", _bone_name(_bone_chest),
|
||||||
|
" head=", _bone_name(_bone_head),
|
||||||
|
" rarm=", _bone_name(_bone_rarm),
|
||||||
|
" larm=", _bone_name(_bone_larm),
|
||||||
|
" modifier=AimBend")
|
||||||
|
|
||||||
|
|
||||||
|
func _find_exact(names: Array[String]) -> int:
|
||||||
|
if _skel == null:
|
||||||
|
return -1
|
||||||
|
for bone_key in names:
|
||||||
|
var idx: int = _skel.find_bone(bone_key)
|
||||||
|
if idx >= 0:
|
||||||
|
var low := _skel.get_bone_name(idx).to_lower()
|
||||||
|
var want_head := "head" in bone_key.to_lower()
|
||||||
|
if "shoulder" in low or "arm" in low or "neck" in low:
|
||||||
|
continue
|
||||||
|
if "head" in low and not want_head:
|
||||||
|
continue
|
||||||
|
return idx
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
func _find_limb(names: Array[String]) -> int:
|
||||||
|
if _skel == null:
|
||||||
|
return -1
|
||||||
|
for bone_key in names:
|
||||||
|
var idx: int = _skel.find_bone(bone_key)
|
||||||
|
if idx >= 0:
|
||||||
|
return idx
|
||||||
|
for i in range(_skel.get_bone_count()):
|
||||||
|
var raw: String = _skel.get_bone_name(i)
|
||||||
|
var low: String = raw.to_lower()
|
||||||
|
for bone_key in names:
|
||||||
|
var want: String = bone_key.to_lower()
|
||||||
|
if low == want or low.contains(want):
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
func _bone_name(idx: int) -> String:
|
||||||
|
if _skel == null or idx < 0:
|
||||||
|
return str(idx)
|
||||||
|
return "%s(%d)" % [_skel.get_bone_name(idx), idx]
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_waist_now() -> void:
|
||||||
|
if _skel == null:
|
||||||
|
return
|
||||||
|
if _aim_enabled:
|
||||||
|
var pitch: float = -_aim_pitch
|
||||||
|
if hide_head:
|
||||||
|
# 1P: lean the whole torso so the gun and shoes enter the lens.
|
||||||
|
_set_fold(_bone_abdomen, pitch * 0.40)
|
||||||
|
_set_fold(_bone_torso, pitch * 0.22)
|
||||||
|
_set_fold(_bone_chest, pitch * 0.08)
|
||||||
|
var axis: Vector3 = Vector3.FORWARD
|
||||||
|
match arm_axis_id:
|
||||||
|
0:
|
||||||
|
axis = Vector3.RIGHT
|
||||||
|
1:
|
||||||
|
axis = Vector3.UP
|
||||||
|
_:
|
||||||
|
axis = Vector3.FORWARD
|
||||||
|
var arm_amt: float = 0.22
|
||||||
|
if _aim_pitch > 0.0:
|
||||||
|
arm_amt = 0.36
|
||||||
|
_set_fold_axis(_bone_rarm, pitch * arm_amt, axis)
|
||||||
|
_set_fold_axis(_bone_larm, pitch * arm_amt * 0.55, axis)
|
||||||
|
else:
|
||||||
|
_set_fold(_bone_abdomen, pitch * 0.42)
|
||||||
|
_set_fold(_bone_torso, pitch * 0.38)
|
||||||
|
_set_fold(_bone_chest, pitch * 0.28)
|
||||||
|
_snap_fp_eye()
|
||||||
|
|
||||||
|
|
||||||
|
func _snap_fp_eye() -> void:
|
||||||
|
if not _ride_fp or _fp_pivot == null or _skel == null or _bone_head < 0:
|
||||||
|
return
|
||||||
|
var pose: Transform3D = _skel.get_bone_global_pose(_bone_head)
|
||||||
|
var xf: Transform3D = _skel.global_transform * pose
|
||||||
|
var body: Node3D = _fp_pivot.get_parent() as Node3D
|
||||||
|
var face := Vector3.FORWARD
|
||||||
|
var up := Vector3.UP
|
||||||
|
if body:
|
||||||
|
face = -body.global_transform.basis.z
|
||||||
|
face.y = 0.0
|
||||||
|
if face.length_squared() < 0.0001:
|
||||||
|
face = -body.global_transform.basis.z
|
||||||
|
face = face.normalized()
|
||||||
|
up = body.global_transform.basis.y.normalized()
|
||||||
|
else:
|
||||||
|
face = xf.basis.z.normalized()
|
||||||
|
up = xf.basis.y.normalized()
|
||||||
|
_fp_pivot.global_position = xf.origin + face * 0.03 + up * 0.12
|
||||||
|
|
||||||
|
|
||||||
|
func _set_fold(idx: int, angle: float) -> void:
|
||||||
|
_set_fold_axis(idx, angle, Vector3.RIGHT)
|
||||||
|
|
||||||
|
|
||||||
|
func _set_fold_axis(idx: int, angle: float, axis: Vector3) -> void:
|
||||||
|
if idx < 0 or _skel == null:
|
||||||
|
return
|
||||||
|
if absf(angle) < 0.0005:
|
||||||
|
return
|
||||||
|
var pose: Quaternion = _skel.get_bone_pose_rotation(idx)
|
||||||
|
_skel.set_bone_pose_rotation(idx, pose * Quaternion(axis.normalized(), angle))
|
||||||
|
|
||||||
|
|
||||||
|
func cycle_arm_axis() -> void:
|
||||||
|
arm_axis_id = (arm_axis_id + 1) % 3
|
||||||
|
print("ARM AXIS ", ["X (RIGHT)", "Y (UP)", "Z (FORWARD)"][arm_axis_id])
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_keep_deferred() -> void:
|
||||||
|
if current != null and is_instance_valid(current):
|
||||||
|
_apply_keep(current, last_keep)
|
||||||
|
if _skel == null:
|
||||||
|
_cache_skeleton()
|
||||||
|
|
||||||
|
|
||||||
|
func _clear_old() -> void:
|
||||||
|
current = null
|
||||||
|
anim = null
|
||||||
|
if tree and is_instance_valid(tree):
|
||||||
|
tree.queue_free()
|
||||||
|
tree = null
|
||||||
|
_walk_bs = null
|
||||||
|
_run_bs = null
|
||||||
|
_aim_walk_bs = null
|
||||||
|
_aim_run_bs = null
|
||||||
|
_mode = ""
|
||||||
|
_blend_pos = Vector2.ZERO
|
||||||
|
_run_amt = 0.0
|
||||||
|
_aiming = false
|
||||||
|
_fire_lock = 0.0
|
||||||
|
_skel = null
|
||||||
|
_mod = null
|
||||||
|
_bone_abdomen = -1
|
||||||
|
_bone_torso = -1
|
||||||
|
_bone_chest = -1
|
||||||
|
_bone_head = -1
|
||||||
|
_bone_rarm = -1
|
||||||
|
_bone_larm = -1
|
||||||
|
_bone_rfore = -1
|
||||||
|
_bone_lfore = -1
|
||||||
|
_logged_bones = false
|
||||||
|
_aim_enabled = false
|
||||||
|
_aim_pitch = 0.0
|
||||||
|
_ride_fp = false
|
||||||
|
_fp_cam = null
|
||||||
|
_fp_pivot = null
|
||||||
|
for child in get_children():
|
||||||
|
child.hide()
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func _hide_all_visuals(root: Node) -> void:
|
||||||
|
var stack: Array[Node] = [root]
|
||||||
|
while stack.size() > 0:
|
||||||
|
var n: Node = stack.pop_back()
|
||||||
|
if n is GeometryInstance3D:
|
||||||
|
n.visible = false
|
||||||
|
for c in n.get_children():
|
||||||
|
stack.append(c)
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_keep(root: Node, keep: Array[String]) -> void:
|
||||||
|
if root == null or keep.is_empty():
|
||||||
|
return
|
||||||
|
var shown: PackedStringArray = []
|
||||||
|
var hidden: PackedStringArray = []
|
||||||
|
var stack: Array[Node] = [root]
|
||||||
|
while stack.size() > 0:
|
||||||
|
var n: Node = stack.pop_back()
|
||||||
|
if n is GeometryInstance3D:
|
||||||
|
var lab := _label(n)
|
||||||
|
var keep_this := _matches_keep(n, keep) and not _is_banned(lab)
|
||||||
|
if show_pistol and _is_pistol_label(lab):
|
||||||
|
keep_this = true
|
||||||
|
if hide_head and _is_head_label(lab):
|
||||||
|
keep_this = false
|
||||||
|
n.visible = keep_this
|
||||||
|
if keep_this:
|
||||||
|
shown.append(_label(n))
|
||||||
|
else:
|
||||||
|
hidden.append(_label(n))
|
||||||
|
for c in n.get_children():
|
||||||
|
stack.append(c)
|
||||||
|
if not _logged_names:
|
||||||
|
_logged_names = true
|
||||||
|
print("Look keep=", keep)
|
||||||
|
print("Look SHOWN (", shown.size(), "): ", shown)
|
||||||
|
print("Look HIDDEN (", hidden.size(), "): ", hidden)
|
||||||
|
|
||||||
|
|
||||||
|
func _label(n: Node) -> String:
|
||||||
|
var label := n.name
|
||||||
|
if n is MeshInstance3D:
|
||||||
|
var mi := n as MeshInstance3D
|
||||||
|
if mi.mesh and not mi.mesh.resource_name.is_empty():
|
||||||
|
label = "%s|%s" % [n.name, mi.mesh.resource_name]
|
||||||
|
return label
|
||||||
|
|
||||||
|
|
||||||
|
func _matches_keep(n: Node, keep: Array[String]) -> bool:
|
||||||
|
var labels: Array[String] = [n.name]
|
||||||
|
if n is MeshInstance3D:
|
||||||
|
var mi := n as MeshInstance3D
|
||||||
|
if mi.mesh and not mi.mesh.resource_name.is_empty():
|
||||||
|
labels.append(mi.mesh.resource_name)
|
||||||
|
for label in labels:
|
||||||
|
for k in keep:
|
||||||
|
if k.is_empty():
|
||||||
|
continue
|
||||||
|
if label == k or label.begins_with(k):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _is_head_label(mesh_name: String) -> bool:
|
||||||
|
var low := mesh_name.to_lower()
|
||||||
|
if "pistol" in low:
|
||||||
|
return false
|
||||||
|
return ("_head" in low) or low.ends_with("head") or ("hair" in low) or ("hat" in low) or ("neck" in low)
|
||||||
|
|
||||||
|
|
||||||
|
func _is_pistol_label(mesh_name: String) -> bool:
|
||||||
|
return mesh_name.contains("Pistol") or mesh_name.contains("pistol")
|
||||||
|
|
||||||
|
|
||||||
|
func _is_banned(mesh_name: String) -> bool:
|
||||||
|
var n := mesh_name
|
||||||
|
return (
|
||||||
|
n.begins_with("Horse")
|
||||||
|
or n.contains("Horse")
|
||||||
|
or n.begins_with("King")
|
||||||
|
or n.begins_with("Witch")
|
||||||
|
or n.begins_with("Medieval")
|
||||||
|
or n.begins_with("Beach")
|
||||||
|
or n.begins_with("Sword")
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bh5kr1365v1bq
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@onready var new_game_button: Button = $CenterRoot/MenuColumn/NewGameButton
|
||||||
|
@onready var continue_button: Button = $CenterRoot/MenuColumn/ContinueButton
|
||||||
|
@onready var quit_button: Button = $CenterRoot/MenuColumn/QuitButton
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
if new_game_button:
|
||||||
|
new_game_button.pressed.connect(_on_new_game)
|
||||||
|
if continue_button:
|
||||||
|
continue_button.pressed.connect(_on_continue)
|
||||||
|
if quit_button:
|
||||||
|
quit_button.pressed.connect(_on_quit)
|
||||||
|
if continue_button:
|
||||||
|
continue_button.disabled = not GameState.has_save
|
||||||
|
|
||||||
|
|
||||||
|
func _on_new_game() -> void:
|
||||||
|
get_tree().change_scene_to_file("res://Scenes/character_creation.tscn")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_continue() -> void:
|
||||||
|
Engine.set_meta("load_save", true)
|
||||||
|
get_tree().change_scene_to_file("res://Scenes/main.tscn")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_quit() -> void:
|
||||||
|
get_tree().quit()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cb6r3wpwg73jg
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Marijuana Seeds"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://03eo5b1lwlm7
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
extends Node3D
|
||||||
|
## Swap only when the real Moon is about to leave the far plane.
|
||||||
|
## At handover the disc matches the real angular size. It shrinks with distance.
|
||||||
|
## A late boost only kicks in when the disc would become a speck (Earth).
|
||||||
|
|
||||||
|
@export var real_moon_path: NodePath = ^".."
|
||||||
|
@export var surface_high_path: NodePath = ^"../SurfaceHigh"
|
||||||
|
@export var impostor_mesh_path: NodePath = ^"ImposterSphere"
|
||||||
|
@export var switch_distance: float = 850000.0
|
||||||
|
@export var visual_distance: float = 280000.0
|
||||||
|
@export var real_radius: float = 173700.0
|
||||||
|
@export var far_boost_start: float = 2500000.0
|
||||||
|
@export var far_boost_end: float = 20000000.0
|
||||||
|
@export var far_boost: float = 5.0
|
||||||
|
|
||||||
|
var _real_moon: Node3D
|
||||||
|
var _surface_high: Node3D
|
||||||
|
var _surface_low: Node3D
|
||||||
|
var _mesh: MeshInstance3D
|
||||||
|
var _base_radius: float = 0.5
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_real_moon = get_node_or_null(real_moon_path) as Node3D
|
||||||
|
_surface_high = get_node_or_null(surface_high_path) as Node3D
|
||||||
|
if _surface_high == null and _real_moon:
|
||||||
|
_surface_high = _real_moon.get_node_or_null("SurfaceHigh") as Node3D
|
||||||
|
if _real_moon:
|
||||||
|
_surface_low = _real_moon.get_node_or_null("SurfaceLow") as Node3D
|
||||||
|
_mesh = get_node_or_null(impostor_mesh_path) as MeshInstance3D
|
||||||
|
if _mesh == null:
|
||||||
|
_mesh = find_child("ImposterSphere", true, false) as MeshInstance3D
|
||||||
|
if _mesh:
|
||||||
|
_mesh.top_level = true
|
||||||
|
_mesh.visible = false
|
||||||
|
_mesh.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||||
|
if _mesh.mesh is SphereMesh:
|
||||||
|
var sm := _mesh.mesh as SphereMesh
|
||||||
|
_base_radius = maxf(sm.radius, 0.5)
|
||||||
|
sm.radial_segments = maxi(sm.radial_segments, 32)
|
||||||
|
sm.rings = maxi(sm.rings, 16)
|
||||||
|
var mat := _mesh.get_active_material(0)
|
||||||
|
if mat == null:
|
||||||
|
mat = _mesh.material_override
|
||||||
|
if mat is StandardMaterial3D:
|
||||||
|
var copy := (mat as StandardMaterial3D).duplicate() as StandardMaterial3D
|
||||||
|
copy.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
_mesh.material_override = copy
|
||||||
|
print("MoonImposter ready switch=", switch_distance, " mesh=", _mesh)
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
|
||||||
|
func _hide_real(hide: bool) -> void:
|
||||||
|
if _surface_high:
|
||||||
|
_surface_high.visible = not hide
|
||||||
|
if _surface_low:
|
||||||
|
_surface_low.visible = not hide
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if _real_moon == null or _mesh == null:
|
||||||
|
return
|
||||||
|
var viewer: Node3D = FloatingOrigin.focus
|
||||||
|
if viewer == null or not is_instance_valid(viewer):
|
||||||
|
_mesh.visible = false
|
||||||
|
return
|
||||||
|
if _real_moon.has_meta("hide_crust") and bool(_real_moon.get_meta("hide_crust")):
|
||||||
|
_mesh.visible = false
|
||||||
|
_hide_real(true)
|
||||||
|
return
|
||||||
|
var to_moon: Vector3 = _real_moon.global_position - viewer.global_position
|
||||||
|
var dist: float = to_moon.length()
|
||||||
|
if dist < switch_distance:
|
||||||
|
_mesh.visible = false
|
||||||
|
_hide_real(false)
|
||||||
|
return
|
||||||
|
_hide_real(true)
|
||||||
|
var dir: Vector3 = to_moon / maxf(dist, 1.0)
|
||||||
|
_mesh.global_position = viewer.global_position + dir * visual_distance
|
||||||
|
var exact: float = real_radius * (visual_distance / dist)
|
||||||
|
var t: float = 0.0
|
||||||
|
if dist > far_boost_start:
|
||||||
|
t = clampf((dist - far_boost_start) / maxf(far_boost_end - far_boost_start, 1.0), 0.0, 1.0)
|
||||||
|
var visual_radius: float = exact * lerpf(1.0, far_boost, t)
|
||||||
|
visual_radius = clampf(visual_radius, 200.0, visual_distance * 0.85)
|
||||||
|
_mesh.scale = Vector3.ONE * (visual_radius / _base_radius)
|
||||||
|
_mesh.visible = true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://db5dujh3xfuky
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Multitool"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dc246e7164y2f
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@onready var resume_button: Button = $PauseButtons/ResumeButton
|
||||||
|
@onready var save_button: Button = $PauseButtons/SaveButton
|
||||||
|
@onready var quit_button: Button = $PauseButtons/QuitToMenuButton
|
||||||
|
var player: Node = null
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
visible = false
|
||||||
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
|
if resume_button:
|
||||||
|
resume_button.pressed.connect(_on_resume)
|
||||||
|
if save_button:
|
||||||
|
save_button.pressed.connect(_on_save)
|
||||||
|
if quit_button:
|
||||||
|
quit_button.pressed.connect(_on_quit_to_menu)
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if not event.is_action_pressed("ui_cancel"):
|
||||||
|
return
|
||||||
|
var banner := get_node_or_null("/root/Node3D/HUD/ScrambleBanner")
|
||||||
|
if banner and banner.visible:
|
||||||
|
return
|
||||||
|
if visible or get_tree().paused:
|
||||||
|
_on_resume()
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
return
|
||||||
|
var p := get_tree().get_first_node_in_group("player")
|
||||||
|
if p == null:
|
||||||
|
p = get_node_or_null("/root/Node3D/Player")
|
||||||
|
if p:
|
||||||
|
open_pause(p)
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
|
func open_pause(player_ref: Node) -> void:
|
||||||
|
player = player_ref
|
||||||
|
visible = true
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
get_tree().paused = true
|
||||||
|
|
||||||
|
|
||||||
|
func _on_resume() -> void:
|
||||||
|
visible = false
|
||||||
|
get_tree().paused = false
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
|
|
||||||
|
|
||||||
|
func _on_save() -> void:
|
||||||
|
if player:
|
||||||
|
GameState.save_game(player)
|
||||||
|
else:
|
||||||
|
var p := get_tree().get_first_node_in_group("player")
|
||||||
|
if p:
|
||||||
|
GameState.save_game(p)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_quit_to_menu() -> void:
|
||||||
|
get_tree().paused = false
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
get_tree().change_scene_to_file("res://Scenes/main_menu.tscn")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://soef5g0d1u0a
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Beer Can"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dfqr8db8q1y4b
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
@tool
|
||||||
|
extends Node3D
|
||||||
|
## Hollow planet collision. Attach to Moon or Earth.
|
||||||
|
## SphereShape3D is a SOLID ball — anything inside the radius gets ejected.
|
||||||
|
## This builds a concave surface (triangles only) with an optional station hole.
|
||||||
|
## Visual mesh stays on SurfaceHigh. Collision matches that radius.
|
||||||
|
|
||||||
|
@export var surface_mesh_path: NodePath = ^"SurfaceHigh"
|
||||||
|
@export var old_body_path: NodePath = ^"MoonBody"
|
||||||
|
@export var hole_anchor_path: NodePath = ^"LovellAnchor"
|
||||||
|
@export var hole_radius_m: float = 205.0
|
||||||
|
@export var segments: int = 48
|
||||||
|
@export var rings: int = 32
|
||||||
|
@export var rebuild_shell: bool = false:
|
||||||
|
set(v):
|
||||||
|
rebuild_shell = false
|
||||||
|
if v:
|
||||||
|
build()
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
build()
|
||||||
|
|
||||||
|
|
||||||
|
func build() -> void:
|
||||||
|
var radius: float = _visual_radius()
|
||||||
|
if radius < 10.0:
|
||||||
|
push_warning("PlanetShell: no radius from SurfaceHigh")
|
||||||
|
return
|
||||||
|
_disable_solid_body()
|
||||||
|
var hole_dir := Vector3.ZERO
|
||||||
|
var hole_cos := 1.0
|
||||||
|
var anchor := get_node_or_null(hole_anchor_path) as Node3D
|
||||||
|
if anchor and hole_radius_m > 1.0:
|
||||||
|
var to_a: Vector3 = anchor.global_position - global_position
|
||||||
|
if to_a.length() > 1.0:
|
||||||
|
hole_dir = global_transform.basis.inverse() * to_a.normalized()
|
||||||
|
hole_dir = hole_dir.normalized()
|
||||||
|
var ang: float = atan(hole_radius_m / radius)
|
||||||
|
hole_cos = cos(ang)
|
||||||
|
var faces := _make_faces(radius, hole_dir, hole_cos)
|
||||||
|
var body := get_node_or_null("ShellBody") as StaticBody3D
|
||||||
|
if body == null:
|
||||||
|
body = StaticBody3D.new()
|
||||||
|
body.name = "ShellBody"
|
||||||
|
add_child(body)
|
||||||
|
body.owner = _scene_root()
|
||||||
|
body.transform = Transform3D()
|
||||||
|
body.collision_layer = 1
|
||||||
|
body.collision_mask = 1
|
||||||
|
var col := body.get_node_or_null("CollisionShape3D") as CollisionShape3D
|
||||||
|
if col == null:
|
||||||
|
col = CollisionShape3D.new()
|
||||||
|
col.name = "CollisionShape3D"
|
||||||
|
body.add_child(col)
|
||||||
|
col.owner = body.owner
|
||||||
|
var shape := ConcavePolygonShape3D.new()
|
||||||
|
shape.set_faces(faces)
|
||||||
|
col.shape = shape
|
||||||
|
col.transform = Transform3D()
|
||||||
|
print("PlanetShell ", name, " radius=", radius, " faces=", faces.size() / 3, " hole=", hole_dir != Vector3.ZERO, " anchor=", anchor)
|
||||||
|
|
||||||
|
|
||||||
|
func _visual_radius() -> float:
|
||||||
|
var high := get_node_or_null(surface_mesh_path) as MeshInstance3D
|
||||||
|
if high and high.mesh is SphereMesh:
|
||||||
|
var sm := high.mesh as SphereMesh
|
||||||
|
var rad: float = sm.radius
|
||||||
|
if sm.height > rad * 1.5:
|
||||||
|
rad = sm.height * 0.5
|
||||||
|
var scl: float = maxf(high.scale.x, maxf(high.scale.y, high.scale.z))
|
||||||
|
rad *= scl
|
||||||
|
if rad > 100.0:
|
||||||
|
return rad
|
||||||
|
return 173700.0
|
||||||
|
|
||||||
|
|
||||||
|
func _disable_solid_body() -> void:
|
||||||
|
var old := get_node_or_null(old_body_path)
|
||||||
|
if old == null:
|
||||||
|
return
|
||||||
|
var col := old.get_node_or_null("CollisionShape3D") as CollisionShape3D
|
||||||
|
if col:
|
||||||
|
col.disabled = true
|
||||||
|
if old is CollisionObject3D:
|
||||||
|
(old as CollisionObject3D).collision_layer = 0
|
||||||
|
(old as CollisionObject3D).collision_mask = 0
|
||||||
|
print("PlanetShell: MoonBody DISABLED (solid sphere ejects)")
|
||||||
|
|
||||||
|
|
||||||
|
func _make_faces(radius: float, hole_dir: Vector3, hole_cos: float) -> PackedVector3Array:
|
||||||
|
var faces := PackedVector3Array()
|
||||||
|
var segs: int = maxi(12, segments)
|
||||||
|
var rgs: int = maxi(8, rings)
|
||||||
|
var use_hole: bool = hole_dir.length_squared() > 0.5
|
||||||
|
for lat in range(rgs):
|
||||||
|
var t0: float = float(lat) / float(rgs) * PI - PI * 0.5
|
||||||
|
var t1: float = float(lat + 1) / float(rgs) * PI - PI * 0.5
|
||||||
|
var y0: float = sin(t0)
|
||||||
|
var y1: float = sin(t1)
|
||||||
|
var r0: float = cos(t0)
|
||||||
|
var r1: float = cos(t1)
|
||||||
|
for lon in range(segs):
|
||||||
|
var a0: float = float(lon) / float(segs) * TAU
|
||||||
|
var a1: float = float(lon + 1) / float(segs) * TAU
|
||||||
|
var p00 := Vector3(r0 * cos(a0), y0, r0 * sin(a0)) * radius
|
||||||
|
var p10 := Vector3(r0 * cos(a1), y0, r0 * sin(a1)) * radius
|
||||||
|
var p01 := Vector3(r1 * cos(a0), y1, r1 * sin(a0)) * radius
|
||||||
|
var p11 := Vector3(r1 * cos(a1), y1, r1 * sin(a1)) * radius
|
||||||
|
_add_tri(faces, p00, p01, p11, hole_dir, hole_cos, use_hole)
|
||||||
|
_add_tri(faces, p00, p11, p10, hole_dir, hole_cos, use_hole)
|
||||||
|
return faces
|
||||||
|
|
||||||
|
|
||||||
|
func _add_tri(faces: PackedVector3Array, a: Vector3, b: Vector3, c: Vector3, hole_dir: Vector3, hole_cos: float, use_hole: bool) -> void:
|
||||||
|
if use_hole:
|
||||||
|
var mid: Vector3 = (a + b + c) / 3.0
|
||||||
|
if mid.length_squared() < 0.001:
|
||||||
|
return
|
||||||
|
if mid.normalized().dot(hole_dir) >= hole_cos:
|
||||||
|
return
|
||||||
|
# Both windings. Concave shells are one-sided; a flipped face is a hole you fall through.
|
||||||
|
faces.append(a)
|
||||||
|
faces.append(b)
|
||||||
|
faces.append(c)
|
||||||
|
faces.append(a)
|
||||||
|
faces.append(c)
|
||||||
|
faces.append(b)
|
||||||
|
|
||||||
|
|
||||||
|
func _scene_root() -> Node:
|
||||||
|
if Engine.is_editor_hint() and get_tree() and get_tree().edited_scene_root:
|
||||||
|
return get_tree().edited_scene_root
|
||||||
|
return owner if owner else self
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://2fx6webb7m8d
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Plasma Cutter (Damaged)"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cdo20owmglm22
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
|||||||
|
uid://bqssr0j8iphme
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Protein Paste"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ch56mng5ltaqf
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Ration Pack"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cl275qnxinw8q
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var rng = RandomNumberGenerator.new()
|
||||||
|
var materials = [
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_arid_rocks_1.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_arid_rocks_2.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_arid_rocks_3.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_mossy_rocks_1.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_mossy_rocks_2.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_sand_stone_rocks.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_snow_rocks_1.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_snow_rocks_2.tres",
|
||||||
|
"res://Kyle's Rock Pack/Kyle Fuji/Materials/M_snow_rocks_3.tres"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
rng.randomize()
|
||||||
|
var my_random_number = rng.randi_range(0, len(materials) - 1)
|
||||||
|
|
||||||
|
var NEW_MATERIAL = load(materials[my_random_number])
|
||||||
|
var nodes = get_tree().get_nodes_in_group("change_material")
|
||||||
|
for node in nodes:
|
||||||
|
for child in node.get_children():
|
||||||
|
if child is MeshInstance3D:
|
||||||
|
child.material_override = NEW_MATERIAL
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b6oobwtp7lnw0
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
var alarm_label: Label
|
||||||
|
var dismiss_button: Button
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
visible = false
|
||||||
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
|
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||||
|
|
||||||
|
alarm_label = find_child("AlarmLabel", true, false) as Label
|
||||||
|
dismiss_button = find_child("DismissButton", true, false) as Button
|
||||||
|
|
||||||
|
if dismiss_button:
|
||||||
|
dismiss_button.pressed.connect(hide_banner)
|
||||||
|
|
||||||
|
if not GameState.scramble_begun.is_connected(_on_scramble):
|
||||||
|
GameState.scramble_begun.connect(_on_scramble)
|
||||||
|
|
||||||
|
func _on_scramble() -> void:
|
||||||
|
visible = true
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
|
||||||
|
if alarm_label == null:
|
||||||
|
alarm_label = find_child("AlarmLabel", true, false) as Label
|
||||||
|
|
||||||
|
if alarm_label:
|
||||||
|
alarm_label.modulate = Color.WHITE
|
||||||
|
alarm_label.self_modulate = Color.WHITE
|
||||||
|
alarm_label.add_theme_color_override("font_color", Color.WHITE)
|
||||||
|
alarm_label.add_theme_font_size_override("font_size", 22)
|
||||||
|
alarm_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
alarm_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||||
|
alarm_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
|
alarm_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
alarm_label.text = "PRIORITY ALERT — PEOPLE'S PRIVATEER FLEET INBOUND\nUnregistered prize crews on approach. All hands to extraction. ~10 minutes."
|
||||||
|
|
||||||
|
print("SCRAMBLE: PPF inbound")
|
||||||
|
|
||||||
|
func hide_banner() -> void:
|
||||||
|
if not visible:
|
||||||
|
return
|
||||||
|
visible = false
|
||||||
|
if not get_tree().paused:
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
|
print("SCRAMBLE banner dismissed")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b1brrhkbw71xg
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Scrap Metal"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://oljblbitud3n
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
@export var item_name: String = "Soy Bean Seeds"
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
if player.has_method("add_item"):
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Picked up: ", item_name)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dobhysl1n6hi1
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
|
@onready var btn_pause: Button = $BtnPause
|
||||||
|
@onready var btn_x1: Button = $BtnX1
|
||||||
|
@onready var btn_x2: Button = $BtnX2
|
||||||
|
@onready var btn_x4: Button = $BtnX4
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
|
|
||||||
|
btn_pause.pressed.connect(_on_pause)
|
||||||
|
btn_x1.pressed.connect(_on_x1)
|
||||||
|
btn_x2.pressed.connect(_on_x2)
|
||||||
|
btn_x4.pressed.connect(_on_x4)
|
||||||
|
|
||||||
|
if GameState.has_signal("time_scale_changed"):
|
||||||
|
GameState.time_scale_changed.connect(_on_scale_changed)
|
||||||
|
|
||||||
|
_on_scale_changed(GameState.time_scale)
|
||||||
|
|
||||||
|
func _on_pause() -> void:
|
||||||
|
GameState.set_time_scale(0.0)
|
||||||
|
|
||||||
|
func _on_x1() -> void:
|
||||||
|
GameState.set_time_scale(1.0)
|
||||||
|
|
||||||
|
func _on_x2() -> void:
|
||||||
|
GameState.set_time_scale(2.0)
|
||||||
|
|
||||||
|
func _on_x4() -> void:
|
||||||
|
GameState.set_time_scale(4.0)
|
||||||
|
|
||||||
|
func _on_scale_changed(new_scale: float) -> void:
|
||||||
|
btn_pause.disabled = is_equal_approx(new_scale, 0.0)
|
||||||
|
btn_x1.disabled = is_equal_approx(new_scale, 1.0)
|
||||||
|
btn_x2.disabled = is_equal_approx(new_scale, 2.0)
|
||||||
|
btn_x4.disabled = is_equal_approx(new_scale, 4.0)
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://sxr03xjwmthe
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
extends Node3D
|
||||||
|
## Keep the sun disc inside the cockpit far plane. Aim SunLight.
|
||||||
|
## Never leave the disc sitting on the Moon.
|
||||||
|
|
||||||
|
@export var sun_disc_path: NodePath = ^"SunDisc"
|
||||||
|
@export var sun_light_path: NodePath = ^"../SunLight"
|
||||||
|
@export var sun_direction: Vector3 = Vector3(-0.82, 0.45, 0.35)
|
||||||
|
@export var visual_distance: float = 220000.0
|
||||||
|
@export var visual_radius: float = 9000.0
|
||||||
|
|
||||||
|
var _mesh: MeshInstance3D
|
||||||
|
var _light: DirectionalLight3D
|
||||||
|
var _base_radius: float = 0.5
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_mesh = get_node_or_null(sun_disc_path) as MeshInstance3D
|
||||||
|
if _mesh == null:
|
||||||
|
_mesh = find_child("SunDisc", true, false) as MeshInstance3D
|
||||||
|
if _mesh and _mesh.mesh is SphereMesh:
|
||||||
|
_base_radius = maxf((_mesh.mesh as SphereMesh).radius, 0.5)
|
||||||
|
_light = get_node_or_null(sun_light_path) as DirectionalLight3D
|
||||||
|
if _light == null:
|
||||||
|
_light = get_node_or_null("../SunLight") as DirectionalLight3D
|
||||||
|
sun_direction = sun_direction.normalized()
|
||||||
|
_aim_light()
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
|
||||||
|
func _aim_light() -> void:
|
||||||
|
if _light == null:
|
||||||
|
return
|
||||||
|
var target: Vector3 = _light.global_position - sun_direction
|
||||||
|
if target.is_equal_approx(_light.global_position):
|
||||||
|
return
|
||||||
|
_light.look_at(target, Vector3.UP)
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if _mesh == null:
|
||||||
|
return
|
||||||
|
var viewer: Node3D = FloatingOrigin.focus
|
||||||
|
var origin: Vector3 = viewer.global_position if viewer and is_instance_valid(viewer) else global_position
|
||||||
|
_mesh.global_position = origin + sun_direction * visual_distance
|
||||||
|
_mesh.scale = Vector3.ONE * (visual_radius / _base_radius)
|
||||||
|
_mesh.visible = true
|
||||||
|
_aim_light()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d1o7uwk5jbs5j
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
print("Terminal accessed by player")
|
||||||
|
|
||||||
|
# Simple reaction for now
|
||||||
|
if player.has_method("add_oxygen"):
|
||||||
|
player.add_oxygen(15.0) # restore a little oxygen
|
||||||
|
print("Oxygen partially restored")
|
||||||
|
|
||||||
|
# Later this will open a real menu
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://drvd2kgxl2l2s
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extends StaticBody3D
|
||||||
|
|
||||||
|
func on_interact(player: Node) -> void:
|
||||||
|
var menu = get_node_or_null("/root/Node3D/VendorUI/VendorMenu")
|
||||||
|
if menu and menu.has_method("open_menu"):
|
||||||
|
menu.open_menu(player)
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
else:
|
||||||
|
print("Vendor menu not found")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dnf3scbnf3qvx
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
var player: Node = null
|
||||||
|
@onready var close_button: Button = $MenuPanel/MainVBox/CloseButton
|
||||||
|
|
||||||
|
# ===== SELL BUTTONS =====
|
||||||
|
@onready var sell_buttons = {
|
||||||
|
"Marijuana Seeds": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_MarijuanaSeeds,
|
||||||
|
"Soy Bean Seeds": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_SoyBeanSeeds,
|
||||||
|
"Ration Pack": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_RationPack,
|
||||||
|
"Dried Noodles": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_DriedNoodles,
|
||||||
|
"Protein Paste": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_ProteinPaste,
|
||||||
|
"Scrap Metal": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_ScrapMetal,
|
||||||
|
"Multitool": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_Multitool,
|
||||||
|
"Plasma Cutter (Damaged)": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_PlasmaCutter,
|
||||||
|
"Cooking Knife": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_CookingKnife,
|
||||||
|
"Circuit Board": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_CircuitBoard,
|
||||||
|
"Beer Can": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_BeerCan,
|
||||||
|
"Hotdog": $MenuPanel/MainVBox/MainColumns/SellVBox/Sell_Hotdog
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===== BUY BUTTONS =====
|
||||||
|
@onready var buy_buttons = {
|
||||||
|
"Ration Pack": $MenuPanel/MainVBox/MainColumns/BuyVBox/Buy_RationPack,
|
||||||
|
"Dried Noodles": $MenuPanel/MainVBox/MainColumns/BuyVBox/Buy_DriedNoodles,
|
||||||
|
"Protein Paste": $MenuPanel/MainVBox/MainColumns/BuyVBox/Buy_ProteinPaste,
|
||||||
|
"Beer Can": $MenuPanel/MainVBox/MainColumns/BuyVBox/Buy_BeerCan,
|
||||||
|
"Hotdog": $MenuPanel/MainVBox/MainColumns/BuyVBox/Buy_Hotdog
|
||||||
|
}
|
||||||
|
|
||||||
|
var sell_prices = {
|
||||||
|
"Marijuana Seeds": 40,
|
||||||
|
"Soy Bean Seeds": 25,
|
||||||
|
"Ration Pack": 18,
|
||||||
|
"Dried Noodles": 10,
|
||||||
|
"Protein Paste": 14,
|
||||||
|
"Scrap Metal": 15,
|
||||||
|
"Multitool": 50,
|
||||||
|
"Plasma Cutter (Damaged)": 65,
|
||||||
|
"Cooking Knife": 28,
|
||||||
|
"Circuit Board": 42,
|
||||||
|
"Beer Can": 8,
|
||||||
|
"Hotdog": 8
|
||||||
|
}
|
||||||
|
|
||||||
|
var buy_prices = {
|
||||||
|
"Ration Pack": 15,
|
||||||
|
"Dried Noodles": 12,
|
||||||
|
"Protein Paste": 16,
|
||||||
|
"Beer Can": 10,
|
||||||
|
"Hotdog": 15
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
for item_name in sell_buttons.keys():
|
||||||
|
var button = sell_buttons[item_name]
|
||||||
|
if button:
|
||||||
|
button.pressed.connect(_sell.bind(item_name, sell_prices[item_name]))
|
||||||
|
else:
|
||||||
|
print("Missing sell button for: ", item_name)
|
||||||
|
|
||||||
|
for item_name in buy_buttons.keys():
|
||||||
|
var button = buy_buttons[item_name]
|
||||||
|
if button:
|
||||||
|
button.pressed.connect(_buy.bind(item_name, buy_prices[item_name]))
|
||||||
|
else:
|
||||||
|
print("Missing buy button for: ", item_name)
|
||||||
|
|
||||||
|
if close_button:
|
||||||
|
close_button.pressed.connect(_on_close_pressed)
|
||||||
|
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
func open_menu(player_ref: Node) -> void:
|
||||||
|
player = player_ref
|
||||||
|
visible = true
|
||||||
|
_update_button_states()
|
||||||
|
print("Vendor menu opened")
|
||||||
|
|
||||||
|
func _update_button_states() -> void:
|
||||||
|
if player == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
for item_name in sell_buttons.keys():
|
||||||
|
var button = sell_buttons[item_name]
|
||||||
|
if button:
|
||||||
|
button.disabled = not player.inventory.has(item_name)
|
||||||
|
|
||||||
|
for item_name in buy_buttons.keys():
|
||||||
|
var button = buy_buttons[item_name]
|
||||||
|
if button:
|
||||||
|
button.disabled = player.money < buy_prices[item_name]
|
||||||
|
|
||||||
|
func _sell(item_name: String, price: int) -> void:
|
||||||
|
if player == null:
|
||||||
|
return
|
||||||
|
if player.remove_item(item_name):
|
||||||
|
player.add_money(price)
|
||||||
|
print("Sold ", item_name, " for ", price, " credits")
|
||||||
|
_update_button_states()
|
||||||
|
else:
|
||||||
|
print("You don't have ", item_name)
|
||||||
|
|
||||||
|
func _buy(item_name: String, price: int) -> void:
|
||||||
|
if player == null:
|
||||||
|
return
|
||||||
|
if player.money >= price:
|
||||||
|
player.add_money(-price)
|
||||||
|
player.add_item(item_name)
|
||||||
|
print("Bought ", item_name)
|
||||||
|
_update_button_states()
|
||||||
|
else:
|
||||||
|
print("Not enough credits")
|
||||||
|
|
||||||
|
func _on_close_pressed() -> void:
|
||||||
|
visible = false
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bbr0judkwyfhb
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,41 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bf63eg11cuqij"
|
||||||
|
path.s3tc="res://.godot/imported/T_flag.png-1a69bfd8a15b78e7f98590a98c6f7426.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Scenes/Textures/T_flag.png"
|
||||||
|
dest_files=["res://.godot/imported/T_flag.png-1a69bfd8a15b78e7f98590a98c6f7426.s3tc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
@@ -0,0 +1,45 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://dy4q76vua88y"
|
||||||
|
path="res://.godot/imported/Unarmed_RM.glb-ba307165329601e24032bf470389b5ea.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Scenes/Unarmed_RM.glb"
|
||||||
|
dest_files=["res://.godot/imported/Unarmed_RM.glb-ba307165329601e24032bf470389b5ea.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
mesh_library/use_node_names_as_mesh_names=false
|
||||||
|
array_mesh/deduplicate_surfaces=true
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
gltf/naming_version=2
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
|
gltf/texture_map_mode=1
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
[gd_scene format=3 uid="uid://ccio4xdkkad5u"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cxrxrk0qt15dl" path="res://Scenes/Scripts/character_creation.gd" id="1_r633d"]
|
||||||
|
|
||||||
|
[node name="CharacterCreation" type="Control" unique_id=436175007]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_r633d")
|
||||||
|
|
||||||
|
[node name="Background" type="ColorRect" parent="." unique_id=1949662708]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
color = Color(0.043137256, 0.05490196, 0.078431375, 1)
|
||||||
|
|
||||||
|
[node name="CenterRoot" type="MarginContainer" parent="." unique_id=464110165]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_constants/margin_left = 24
|
||||||
|
theme_override_constants/margin_top = 24
|
||||||
|
theme_override_constants/margin_right = 24
|
||||||
|
theme_override_constants/margin_bottom = 24
|
||||||
|
|
||||||
|
[node name="Page" type="VBoxContainer" parent="CenterRoot" unique_id=1781904031]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="CenterRoot/Page" unique_id=382334510]
|
||||||
|
custom_minimum_size = Vector2(400, 36)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Create Your Character"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="NameInput" type="LineEdit" parent="CenterRoot/Page" unique_id=1431403709]
|
||||||
|
custom_minimum_size = Vector2(360, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
placeholder_text = "Enter Name..."
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="MainSplit" type="HBoxContainer" parent="CenterRoot/Page" unique_id=1268834436]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="LookRow" type="HBoxContainer" parent="CenterRoot/Page/MainSplit" unique_id=883755372]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="LookPreview" type="SubViewportContainer" parent="CenterRoot/Page/MainSplit/LookRow" unique_id=1109688710]
|
||||||
|
custom_minimum_size = Vector2(360, 420)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 4
|
||||||
|
stretch = true
|
||||||
|
|
||||||
|
[node name="SubViewport" type="SubViewport" parent="CenterRoot/Page/MainSplit/LookRow/LookPreview" unique_id=905654693]
|
||||||
|
own_world_3d = true
|
||||||
|
handle_input_locally = false
|
||||||
|
size = Vector2i(360, 420)
|
||||||
|
render_target_update_mode = 4
|
||||||
|
|
||||||
|
[node name="LookWorld" type="Node3D" parent="CenterRoot/Page/MainSplit/LookRow/LookPreview/SubViewport" unique_id=2053829353]
|
||||||
|
|
||||||
|
[node name="LookCam" type="Camera3D" parent="CenterRoot/Page/MainSplit/LookRow/LookPreview/SubViewport/LookWorld" unique_id=1932382112]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.99026805, 0.1391731, 0, -0.1391731, 0.99026805, 0, 1.5, 3.5)
|
||||||
|
current = true
|
||||||
|
|
||||||
|
[node name="LookKey" type="DirectionalLight3D" parent="CenterRoot/Page/MainSplit/LookRow/LookPreview/SubViewport/LookWorld" unique_id=254093398]
|
||||||
|
transform = Transform3D(0.76604444, -0.3686878, 0.52654076, 0, 0.81915206, 0.57357645, -0.6427876, -0.43938506, 0.62750685, 0, 0, 0)
|
||||||
|
|
||||||
|
[node name="LookControls" type="VBoxContainer" parent="CenterRoot/Page/MainSplit/LookRow" unique_id=2037784678]
|
||||||
|
custom_minimum_size = Vector2(168, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="SexRow" type="HBoxContainer" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=369989045]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="SexMale" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/SexRow" unique_id=505283771]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Male"
|
||||||
|
|
||||||
|
[node name="SexFemale" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/SexRow" unique_id=1592599057]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Female"
|
||||||
|
|
||||||
|
[node name="LabHead" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=2104734069]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Head"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="RowHead" type="HBoxContainer" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=1403190168]
|
||||||
|
custom_minimum_size = Vector2(140, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Prev_Head" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowHead" unique_id=2040372778]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "<"
|
||||||
|
|
||||||
|
[node name="Name_Head" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowHead" unique_id=506497795]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Casual"
|
||||||
|
|
||||||
|
[node name="Next_Head" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowHead" unique_id=487423449]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = ">"
|
||||||
|
|
||||||
|
[node name="LabBody" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=1014135234]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Body"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="RowBody" type="HBoxContainer" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=1422286663]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Prev_Body" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowBody" unique_id=1417818257]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "<"
|
||||||
|
|
||||||
|
[node name="Name_Body" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowBody" unique_id=797862923]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Casual"
|
||||||
|
|
||||||
|
[node name="Next_Body" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowBody" unique_id=1566826248]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = ">"
|
||||||
|
|
||||||
|
[node name="LabLegs" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=734720409]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Legs"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="RowLegs" type="HBoxContainer" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=393100881]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Prev_Legs" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowLegs" unique_id=462280303]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "<"
|
||||||
|
|
||||||
|
[node name="Name_Legs" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowLegs" unique_id=1084594247]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Casual"
|
||||||
|
|
||||||
|
[node name="Next_Legs" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowLegs" unique_id=402072381]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = ">"
|
||||||
|
|
||||||
|
[node name="LabFeet" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=1826945463]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Feet"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="RowFeet" type="HBoxContainer" parent="CenterRoot/Page/MainSplit/LookRow/LookControls" unique_id=816382406]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Prev_Feet" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowFeet" unique_id=1638885196]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "<"
|
||||||
|
|
||||||
|
[node name="Name_Feet" type="Label" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowFeet" unique_id=1924000265]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Casual"
|
||||||
|
|
||||||
|
[node name="Next_Feet" type="Button" parent="CenterRoot/Page/MainSplit/LookRow/LookControls/RowFeet" unique_id=1591763969]
|
||||||
|
custom_minimum_size = Vector2(36, 32)
|
||||||
|
layout_mode = 2
|
||||||
|
text = ">"
|
||||||
|
|
||||||
|
[node name="Scroll" type="ScrollContainer" parent="CenterRoot/Page/MainSplit" unique_id=273031910]
|
||||||
|
custom_minimum_size = Vector2(480, 560)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="FormColumn" type="VBoxContainer" parent="CenterRoot/Page/MainSplit/Scroll" unique_id=1432553215]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
|
||||||
|
[node name="CultureLabel" type="Label" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=1835217621]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Culture"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="CultureList" type="GridContainer" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=684724774]
|
||||||
|
layout_mode = 2
|
||||||
|
columns = 3
|
||||||
|
|
||||||
|
[node name="Culture_NAF" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn/CultureList" unique_id=849092527]
|
||||||
|
custom_minimum_size = Vector2(0, 36)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "North American"
|
||||||
|
|
||||||
|
[node name="Culture_EAA" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn/CultureList" unique_id=44970011]
|
||||||
|
custom_minimum_size = Vector2(0, 36)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "East Asian"
|
||||||
|
|
||||||
|
[node name="Culture_Russian" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn/CultureList" unique_id=1133102118]
|
||||||
|
custom_minimum_size = Vector2(0, 36)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Russian"
|
||||||
|
|
||||||
|
[node name="Culture_European" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn/CultureList" unique_id=677544509]
|
||||||
|
custom_minimum_size = Vector2(0, 36)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "European"
|
||||||
|
|
||||||
|
[node name="Culture_Brazilian" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn/CultureList" unique_id=1802695568]
|
||||||
|
custom_minimum_size = Vector2(0, 36)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Brazilian"
|
||||||
|
|
||||||
|
[node name="Culture_Independent" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn/CultureList" unique_id=576443035]
|
||||||
|
custom_minimum_size = Vector2(0, 36)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Independent "
|
||||||
|
|
||||||
|
[node name="JobLabel" type="Label" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=1978424005]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Starting Profession"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="BackgroundList" type="GridContainer" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=452359861]
|
||||||
|
layout_mode = 2
|
||||||
|
columns = 2
|
||||||
|
|
||||||
|
[node name="DescriptionLabel" type="Label" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=1359111642]
|
||||||
|
custom_minimum_size = Vector2(80, 64)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Select a culture and profession."
|
||||||
|
autowrap_mode = 2
|
||||||
|
|
||||||
|
[node name="BonusLabel" type="Label" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=613114403]
|
||||||
|
custom_minimum_size = Vector2(22, 24)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Starting bonus: —"
|
||||||
|
autowrap_mode = 2
|
||||||
|
|
||||||
|
[node name="ConfirmButton" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=224306]
|
||||||
|
custom_minimum_size = Vector2(32, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
text = "Begin"
|
||||||
|
|
||||||
|
[node name="BackButton" type="Button" parent="CenterRoot/Page/MainSplit/Scroll/FormColumn" unique_id=1012112632]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
text = "Back"
|
||||||
@@ -0,0 +1,343 @@
|
|||||||
|
[gd_scene format=3 uid="uid://tqhk0a248g5k"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://1udl42sp42sp" path="res://Scenes/Scripts/escape_capsule.gd" id="1_mfps1"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dg0yewov2bymm" path="res://kestrel_ec01_godot/kestrel.tscn" id="2_85cng"]
|
||||||
|
[ext_resource type="Script" uid="uid://ond7pwt03hgd" path="res://kestrel_driver.gd" id="3_81abi"]
|
||||||
|
|
||||||
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_j65qs"]
|
||||||
|
height = 3.795288
|
||||||
|
radius = 2.2
|
||||||
|
|
||||||
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_81abi"]
|
||||||
|
height = 2.0190659
|
||||||
|
radius = 0.10839844
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kq58d"]
|
||||||
|
albedo_color = Color(0.3529412, 0.36862746, 0.4, 1)
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="CylinderMesh_18y2q"]
|
||||||
|
material = SubResource("StandardMaterial3D_kq58d")
|
||||||
|
top_radius = 1.8
|
||||||
|
bottom_radius = 2.2
|
||||||
|
height = 3.5
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ryguw"]
|
||||||
|
albedo_color = Color(0.017732391, 0.017732391, 0.01773239, 1)
|
||||||
|
metallic = 0.56
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="CylinderMesh_3jrso"]
|
||||||
|
material = SubResource("StandardMaterial3D_ryguw")
|
||||||
|
top_radius = 2.3
|
||||||
|
bottom_radius = 2.3
|
||||||
|
height = 0.25
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_crvdt"]
|
||||||
|
radius = 3.5
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_58fjt"]
|
||||||
|
transparency = 1
|
||||||
|
cull_mode = 2
|
||||||
|
shading_mode = 0
|
||||||
|
albedo_color = Color(0.2347951, 0.2347951, 0.2347951, 0.060000002)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ijs7n"]
|
||||||
|
material = SubResource("StandardMaterial3D_58fjt")
|
||||||
|
size = Vector3(1.4949585, 0.8827637, 0.16409448)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_a6jrf"]
|
||||||
|
albedo_color = Color(0.101960786, 0.13725491, 0.19607843, 1)
|
||||||
|
emission = Color(0, 0.9704087, 1, 1)
|
||||||
|
emission_energy_multiplier = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_xuqvo"]
|
||||||
|
material = SubResource("StandardMaterial3D_a6jrf")
|
||||||
|
size = Vector3(1.2497559, 0.6052246, 0.04)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1u8w0"]
|
||||||
|
albedo_color = Color(0.37187055, 0.11207495, 0.050708726, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_d13ii"]
|
||||||
|
material = SubResource("StandardMaterial3D_1u8w0")
|
||||||
|
size = Vector3(0.65, 0.12, 0.65)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_l6148"]
|
||||||
|
albedo_color = Color(0.88857853, 0.025840001, 0, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ts8u1"]
|
||||||
|
material = SubResource("StandardMaterial3D_l6148")
|
||||||
|
size = Vector3(0.65, 0.85, 0.1)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_wqh1g"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
metallic = 0.51
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_l6148"]
|
||||||
|
material = SubResource("StandardMaterial3D_wqh1g")
|
||||||
|
size = Vector3(1, 0.7, 0.5)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kx67c"]
|
||||||
|
albedo_color = Color(0.101960786, 0.13725491, 0.19607843, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.101960786, 0.22745098, 0.36078432, 1)
|
||||||
|
emission_energy_multiplier = 2.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_wqh1g"]
|
||||||
|
material = SubResource("StandardMaterial3D_kx67c")
|
||||||
|
size = Vector3(0.35, 0.25, 0.02)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_r6cyv"]
|
||||||
|
albedo_color = Color(0.16470589, 0.16470589, 0.16470589, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_kx67c"]
|
||||||
|
material = SubResource("StandardMaterial3D_r6cyv")
|
||||||
|
size = Vector3(0.15, 0.08, 0.02)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_omqyl"]
|
||||||
|
albedo_color = Color(0.039215688, 0.0627451, 0.09411765, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.101960786, 0.22745098, 0.36078432, 1)
|
||||||
|
emission_energy_multiplier = 2.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_52c6f"]
|
||||||
|
material = SubResource("StandardMaterial3D_omqyl")
|
||||||
|
size = Vector3(0.24501038, 0.20367628, 0.01890625)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0odxb"]
|
||||||
|
albedo_color = Color(0.07058824, 0.07058824, 0.07058824, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_r6cyv"]
|
||||||
|
material = SubResource("StandardMaterial3D_0odxb")
|
||||||
|
size = Vector3(0.08, 2.1133926, 3.2745347)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_d13ii"]
|
||||||
|
albedo_color = Color(0.07058824, 0.07058824, 0.07058824, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_4yprg"]
|
||||||
|
material = SubResource("StandardMaterial3D_d13ii")
|
||||||
|
size = Vector3(2.7717957, 0.04, 3.2841797)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_52c6f"]
|
||||||
|
albedo_color = Color(0.07058824, 0.07058824, 0.07058824, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_o0dcp"]
|
||||||
|
material = SubResource("StandardMaterial3D_52c6f")
|
||||||
|
size = Vector3(1.187207, 0.06, 0.35)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p2ucw"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_omqyl"]
|
||||||
|
material = SubResource("StandardMaterial3D_p2ucw")
|
||||||
|
size = Vector3(2.9555702, 0.75, 0.08)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ucmdv"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_p2ucw"]
|
||||||
|
material = SubResource("StandardMaterial3D_ucmdv")
|
||||||
|
size = Vector3(2.9560547, 0.7133789, 0.08)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_seu75"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_81jjf"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ucmdv"]
|
||||||
|
material = SubResource("StandardMaterial3D_81jjf")
|
||||||
|
size = Vector3(0.65, 0.05, 3.2439454)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ijs7n"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_81jjf"]
|
||||||
|
material = SubResource("StandardMaterial3D_ijs7n")
|
||||||
|
size = Vector3(0.64851075, 0.05, 3.2384765)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_nei3f"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[node name="EscapeCapsule" type="CharacterBody3D" unique_id=900802887 groups=["interactable"]]
|
||||||
|
script = ExtResource("1_mfps1")
|
||||||
|
|
||||||
|
[node name="Kestrel" parent="." unique_id=193910237 instance=ExtResource("2_85cng")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.0820568, 0)
|
||||||
|
script = ExtResource("3_81abi")
|
||||||
|
|
||||||
|
[node name="CameraPivot" type="Node3D" parent="." unique_id=1263006067]
|
||||||
|
transform = Transform3D(1, 8.742278e-08, -8.7422784e-08, -8.742278e-08, -4.371139e-08, -1, -8.7422784e-08, 1, -4.371138e-08, -0.6827204, -1.8933923, 1.2853639)
|
||||||
|
|
||||||
|
[node name="CapsuleCamera" type="Camera3D" parent="CameraPivot" unique_id=1044956475]
|
||||||
|
transform = Transform3D(1, 0, -3.2840569e-15, 0, 1, 0, -3.2840569e-15, 0, 1, 0, -0.21693517, -0.4030409)
|
||||||
|
far = 1000000.0
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=640959005]
|
||||||
|
shape = SubResource("CylinderShape3D_j65qs")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D2" type="CollisionShape3D" parent="." unique_id=2080610717]
|
||||||
|
transform = Transform3D(0.81112194, -0.30945623, 0.49630463, 0.077922754, 0.89817417, 0.43267947, -0.57966334, -0.31228232, 0.75264233, 1.8034304, -2.742339, 1.8590356)
|
||||||
|
shape = SubResource("CylinderShape3D_81abi")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D5" type="CollisionShape3D" parent="." unique_id=908124294]
|
||||||
|
transform = Transform3D(-0.7822406, 0.32521898, -0.53135055, 0.012437973, 0.8609036, 0.5086148, 0.6228521, 0.39124995, -0.6774788, -1.945058, -2.6434186, -1.9002763)
|
||||||
|
shape = SubResource("CylinderShape3D_81abi")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D4" type="CollisionShape3D" parent="." unique_id=1939084631]
|
||||||
|
transform = Transform3D(0.89748794, 0.3169628, -0.30667582, -0.17042562, 0.89057636, 0.42169732, 0.4067809, -0.32620275, 0.8533001, -1.7836877, -2.70675, 1.7776158)
|
||||||
|
shape = SubResource("CylinderShape3D_81abi")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D3" type="CollisionShape3D" parent="." unique_id=1979004740]
|
||||||
|
transform = Transform3D(-0.792779, -0.34827715, -0.5002045, -0.45405236, 0.8849464, 0.10347074, 0.40661794, 0.30914834, -0.85970277, 1.929804, -2.7048826, -1.8303667)
|
||||||
|
shape = SubResource("CylinderShape3D_81abi")
|
||||||
|
|
||||||
|
[node name="Body" type="MeshInstance3D" parent="." unique_id=683390934]
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("CylinderMesh_18y2q")
|
||||||
|
|
||||||
|
[node name="ExternalView" type="SubViewport" parent="Body" unique_id=1265488610]
|
||||||
|
handle_input_locally = false
|
||||||
|
size = Vector2i(3840, 2160)
|
||||||
|
render_target_update_mode = 4
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="Body/ExternalView" unique_id=698867349]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 18.911898, 5.1233277, -0.039017588)
|
||||||
|
visible = false
|
||||||
|
fov = 72.0
|
||||||
|
far = 1000000.0
|
||||||
|
|
||||||
|
[node name="HeatShield" type="MeshInstance3D" parent="." unique_id=2080285390]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.9, 0)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("CylinderMesh_3jrso")
|
||||||
|
|
||||||
|
[node name="InteractionArea" type="Area3D" parent="." unique_id=1761123778]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="InteractionArea" unique_id=1229487990]
|
||||||
|
shape = SubResource("SphereShape3D_crvdt")
|
||||||
|
|
||||||
|
[node name="ThirdPersonCamera" type="Camera3D" parent="." unique_id=284479039]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, -9.5, 3.5)
|
||||||
|
far = 1000000.0
|
||||||
|
|
||||||
|
[node name="Cockpit" type="Node3D" parent="." unique_id=1933795690]
|
||||||
|
transform = Transform3D(-1, 8.742278e-08, 3.821371e-15, 0, -4.371139e-08, 1, 8.742278e-08, 1, 4.371139e-08, 0, -0.94330907, -0.62695575)
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
[node name="WindowGlass" type="MeshInstance3D" parent="Cockpit" unique_id=99141125]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0015087128, 1.5509896, 2.2775838)
|
||||||
|
mesh = SubResource("BoxMesh_ijs7n")
|
||||||
|
|
||||||
|
[node name="HudShape" type="MeshInstance3D" parent="Cockpit" unique_id=1572026781]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0777357, 1.8649361)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("BoxMesh_xuqvo")
|
||||||
|
|
||||||
|
[node name="CockpitLight" type="OmniLight3D" parent="Cockpit" unique_id=1492843635]
|
||||||
|
transform = Transform3D(-1, 0, 8.742278e-08, 8.742278e-08, -4.371139e-08, 1, 3.821371e-15, 1, 4.371139e-08, 0, 2.1579213, 0.00050091743)
|
||||||
|
light_color = Color(1, 0.89411765, 0.76862746, 1)
|
||||||
|
omni_range = 3.5
|
||||||
|
|
||||||
|
[node name="Seat" type="MeshInstance3D" parent="Cockpit" unique_id=123094182]
|
||||||
|
mesh = SubResource("BoxMesh_d13ii")
|
||||||
|
|
||||||
|
[node name="SeatBack" type="MeshInstance3D" parent="Cockpit" unique_id=1553533167]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.38205957, -0.36825216)
|
||||||
|
mesh = SubResource("BoxMesh_ts8u1")
|
||||||
|
|
||||||
|
[node name="MainPanel" type="MeshInstance3D" parent="Cockpit" unique_id=2127997099]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.42596802, 1.6161394)
|
||||||
|
mesh = SubResource("BoxMesh_l6148")
|
||||||
|
|
||||||
|
[node name="GlassCockpitPanel" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=56681667]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.16014825, -0.25493002)
|
||||||
|
mesh = SubResource("BoxMesh_wqh1g")
|
||||||
|
|
||||||
|
[node name="LeftInstrument" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=944149313]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.294096, 0.21341178, -0.25256205)
|
||||||
|
mesh = SubResource("BoxMesh_kx67c")
|
||||||
|
|
||||||
|
[node name="RightInstrument" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=1061352713]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.294, 0.213, -0.253)
|
||||||
|
mesh = SubResource("BoxMesh_kx67c")
|
||||||
|
|
||||||
|
[node name="ForwardDisplay" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=1977279423]
|
||||||
|
transform = Transform3D(0.9999994, -5.728489e-05, -0.0011173013, 5.5921435e-05, 0.99999917, -0.0012259485, 0.0011173704, 0.0012257855, 0.9999986, 0.32665062, 0.049695313, -0.25658345)
|
||||||
|
mesh = SubResource("BoxMesh_52c6f")
|
||||||
|
|
||||||
|
[node name="LeftWall" type="MeshInstance3D" parent="Cockpit" unique_id=1514749488]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4201202, 0.6709095, 0.801975)
|
||||||
|
mesh = SubResource("BoxMesh_r6cyv")
|
||||||
|
|
||||||
|
[node name="RightWall" type="MeshInstance3D" parent="Cockpit" unique_id=1764263004]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.4199867, 0.67109835, 0.79347587)
|
||||||
|
mesh = SubResource("BoxMesh_r6cyv")
|
||||||
|
|
||||||
|
[node name="Floor" type="MeshInstance3D" parent="Cockpit" unique_id=1998677292]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0061683655, -0.25959706, 0.80126953)
|
||||||
|
mesh = SubResource("BoxMesh_4yprg")
|
||||||
|
|
||||||
|
[node name="OverheadConsole" type="MeshInstance3D" parent="Cockpit" unique_id=976403028]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 2.2589908, 0.95627284)
|
||||||
|
mesh = SubResource("BoxMesh_o0dcp")
|
||||||
|
|
||||||
|
[node name="ForwardBulkhead" type="MeshInstance3D" parent="Cockpit" unique_id=1582033665]
|
||||||
|
transform = Transform3D(1, -6.905431e-09, -3.4056352e-08, -6.905438e-09, 0.92101103, -0.38953644, 3.4054356e-08, 0.38953644, 0.92101103, -0.0020980835, 0.10092795, 2.3168466)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("BoxMesh_omqyl")
|
||||||
|
|
||||||
|
[node name="ForwardBulkhead2" type="MeshInstance3D" parent="Cockpit/ForwardBulkhead" unique_id=1004286348]
|
||||||
|
transform = Transform3D(1, -6.9062125e-09, 3.4056193e-08, -6.905424e-09, 0.9210111, 0.38953647, -3.405436e-08, -0.38953647, 0.9210111, 0.018800735, 0.70290273, -0.13796377)
|
||||||
|
mesh = SubResource("BoxMesh_omqyl")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Cockpit/ForwardBulkhead" unique_id=411181651]
|
||||||
|
transform = Transform3D(1, -7.2910282e-09, 3.4950116e-08, -7.2894153e-09, 0.91661024, 0.39978403, -3.4950364e-08, -0.39978403, 0.91661024, 0.021972656, 1.129911, -0.3276949)
|
||||||
|
mesh = SubResource("BoxMesh_p2ucw")
|
||||||
|
|
||||||
|
[node name="FrontBulkhead" type="CSGCombiner3D" parent="Cockpit/ForwardBulkhead" unique_id=1462779310]
|
||||||
|
transform = Transform3D(1, -6.9062196e-09, 3.40562e-08, -6.905424e-09, 0.92101115, 0.3895365, -3.405436e-08, -0.3895365, 0.92101115, 0.0020980835, -0.0909484, 0.044061184)
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
[node name="BulkheadShape" type="CSGPolygon3D" parent="Cockpit/ForwardBulkhead/FrontBulkhead" unique_id=991532318]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.9277502, 0.22244406)
|
||||||
|
polygon = PackedVector2Array(-1.55, -0.345, 1.55, -0.345, 0.72924423, 0.34169006, -0.75127983, 0.3621254)
|
||||||
|
depth = 0.12
|
||||||
|
material = SubResource("StandardMaterial3D_seu75")
|
||||||
|
|
||||||
|
[node name="RoofLeft" type="MeshInstance3D" parent="Cockpit" unique_id=1535690315]
|
||||||
|
transform = Transform3D(0.7071067, 0.7071067, 0, -0.7071067, 0.7071067, 0, 0, 0, 1, 1.1796818, 1.8760827, 0.79144645)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="RoofLeft1" type="MeshInstance3D" parent="Cockpit/RoofLeft" unique_id=1785270765]
|
||||||
|
transform = Transform3D(0.8763269, -0.4817174, 9.8520925e-09, 0.4817174, 0.8763269, 7.3968387e-09, -1.2196834e-08, -1.7361046e-09, 1, -0.6168623, -0.15812302, 0.005322695)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="RoofRight" type="MeshInstance3D" parent="Cockpit" unique_id=10541876]
|
||||||
|
transform = Transform3D(0.7071067, -0.7071067, 0, 0.7071067, 0.7071067, 0, 0, 0, 1, -1.18, 1.876, 0.791)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="RoofRight1" type="MeshInstance3D" parent="Cockpit/RoofRight" unique_id=597720853]
|
||||||
|
transform = Transform3D(0.87630665, 0.4817537, 0, -0.4817537, 0.87630665, 0, 3.543832e-13, 0, 1, 0.6105108, -0.15750027, -0.0017383099)
|
||||||
|
mesh = SubResource("BoxMesh_81jjf")
|
||||||
|
|
||||||
|
[node name="RoofTop" type="MeshInstance3D" parent="Cockpit" unique_id=974546659]
|
||||||
|
transform = Transform3D(0.9999999, 0, 0, 0, 0.9999999, 0, 0, 0, 1, -0.00787735, 2.2835252, 0.79144645)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="ForwardBulkhead2" type="CSGCombiner3D" parent="Cockpit" unique_id=1803926178]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.14711916, 2.8341548)
|
||||||
|
|
||||||
|
[node name="BulkTop" type="CSGPolygon3D" parent="Cockpit/ForwardBulkhead2" unique_id=1704103664]
|
||||||
|
transform = Transform3D(1, -1.4087291e-09, 1.562843e-08, -1.4074928e-09, 0.9838952, 0.17874739, -1.5626552e-08, -0.17874739, 0.9838952, 0.0020980835, 1.7711809, -0.50199556)
|
||||||
|
polygon = PackedVector2Array(-1.55, -0.345, 1.55, -0.345, 0.72924423, 0.34169006, -0.75127983, 0.3621254)
|
||||||
|
depth = 0.12
|
||||||
|
material = SubResource("StandardMaterial3D_seu75")
|
||||||
|
|
||||||
|
[node name="BulkBottom" type="CSGBox3D" parent="Cockpit/ForwardBulkhead2" unique_id=1217332907]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0018692017, 0.49510977, -0.49700785)
|
||||||
|
size = Vector3(2.788086, 1.8628662, 0.08208008)
|
||||||
|
material = SubResource("StandardMaterial3D_nei3f")
|
||||||
|
|
||||||
|
[node name="WindowCutout" type="CSGBox3D" parent="Cockpit/ForwardBulkhead2" unique_id=1392835612]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4177693, -0.5765586)
|
||||||
|
operation = 2
|
||||||
|
size = Vector3(1.5, 0.89470214, 0.2836914)
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
[gd_scene format=3 uid="uid://dbva2yw4g016o"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://1udl42sp42sp" path="res://Scenes/Scripts/escape_capsule.gd" id="1_r50ee"]
|
||||||
|
|
||||||
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_j65qs"]
|
||||||
|
height = 3.795288
|
||||||
|
radius = 2.2
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kq58d"]
|
||||||
|
albedo_color = Color(0.3529412, 0.36862746, 0.4, 1)
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="CylinderMesh_18y2q"]
|
||||||
|
material = SubResource("StandardMaterial3D_kq58d")
|
||||||
|
top_radius = 1.8
|
||||||
|
bottom_radius = 2.2
|
||||||
|
height = 3.5
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ryguw"]
|
||||||
|
albedo_color = Color(0.017732391, 0.017732391, 0.01773239, 1)
|
||||||
|
metallic = 0.56
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="CylinderMesh_3jrso"]
|
||||||
|
material = SubResource("StandardMaterial3D_ryguw")
|
||||||
|
top_radius = 2.3
|
||||||
|
bottom_radius = 2.3
|
||||||
|
height = 0.25
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_crvdt"]
|
||||||
|
radius = 3.5
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_58fjt"]
|
||||||
|
transparency = 1
|
||||||
|
cull_mode = 2
|
||||||
|
shading_mode = 0
|
||||||
|
albedo_color = Color(0.2347951, 0.2347951, 0.2347951, 0.060000002)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ijs7n"]
|
||||||
|
material = SubResource("StandardMaterial3D_58fjt")
|
||||||
|
size = Vector3(1.4949585, 0.8827637, 0.16409448)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_a6jrf"]
|
||||||
|
albedo_color = Color(0.101960786, 0.13725491, 0.19607843, 1)
|
||||||
|
emission = Color(0, 0.9704087, 1, 1)
|
||||||
|
emission_energy_multiplier = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_xuqvo"]
|
||||||
|
material = SubResource("StandardMaterial3D_a6jrf")
|
||||||
|
size = Vector3(1.2497559, 0.6052246, 0.04)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1u8w0"]
|
||||||
|
albedo_color = Color(0.37187055, 0.11207495, 0.050708726, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_d13ii"]
|
||||||
|
material = SubResource("StandardMaterial3D_1u8w0")
|
||||||
|
size = Vector3(0.65, 0.12, 0.65)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_l6148"]
|
||||||
|
albedo_color = Color(0.88857853, 0.025840001, 0, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ts8u1"]
|
||||||
|
material = SubResource("StandardMaterial3D_l6148")
|
||||||
|
size = Vector3(0.65, 0.85, 0.1)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_wqh1g"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
metallic = 0.51
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_l6148"]
|
||||||
|
material = SubResource("StandardMaterial3D_wqh1g")
|
||||||
|
size = Vector3(1, 0.7, 0.5)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kx67c"]
|
||||||
|
albedo_color = Color(0.101960786, 0.13725491, 0.19607843, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.101960786, 0.22745098, 0.36078432, 1)
|
||||||
|
emission_energy_multiplier = 2.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_wqh1g"]
|
||||||
|
material = SubResource("StandardMaterial3D_kx67c")
|
||||||
|
size = Vector3(0.35, 0.25, 0.02)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_r6cyv"]
|
||||||
|
albedo_color = Color(0.16470589, 0.16470589, 0.16470589, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_kx67c"]
|
||||||
|
material = SubResource("StandardMaterial3D_r6cyv")
|
||||||
|
size = Vector3(0.15, 0.08, 0.02)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_omqyl"]
|
||||||
|
albedo_color = Color(0.039215688, 0.0627451, 0.09411765, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.101960786, 0.22745098, 0.36078432, 1)
|
||||||
|
emission_energy_multiplier = 2.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_52c6f"]
|
||||||
|
material = SubResource("StandardMaterial3D_omqyl")
|
||||||
|
size = Vector3(0.24501038, 0.20367628, 0.01890625)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0odxb"]
|
||||||
|
albedo_color = Color(0.07058824, 0.07058824, 0.07058824, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_r6cyv"]
|
||||||
|
material = SubResource("StandardMaterial3D_0odxb")
|
||||||
|
size = Vector3(0.08, 2.1133926, 3.2745347)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_d13ii"]
|
||||||
|
albedo_color = Color(0.07058824, 0.07058824, 0.07058824, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_4yprg"]
|
||||||
|
material = SubResource("StandardMaterial3D_d13ii")
|
||||||
|
size = Vector3(2.7717957, 0.04, 3.2841797)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_52c6f"]
|
||||||
|
albedo_color = Color(0.07058824, 0.07058824, 0.07058824, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_o0dcp"]
|
||||||
|
material = SubResource("StandardMaterial3D_52c6f")
|
||||||
|
size = Vector3(1.187207, 0.06, 0.35)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p2ucw"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_omqyl"]
|
||||||
|
material = SubResource("StandardMaterial3D_p2ucw")
|
||||||
|
size = Vector3(2.9555702, 0.75, 0.08)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ucmdv"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_p2ucw"]
|
||||||
|
material = SubResource("StandardMaterial3D_ucmdv")
|
||||||
|
size = Vector3(2.9560547, 0.7133789, 0.08)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_seu75"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_81jjf"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ucmdv"]
|
||||||
|
material = SubResource("StandardMaterial3D_81jjf")
|
||||||
|
size = Vector3(0.65, 0.05, 3.2439454)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ijs7n"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_81jjf"]
|
||||||
|
material = SubResource("StandardMaterial3D_ijs7n")
|
||||||
|
size = Vector3(0.64851075, 0.05, 3.2384765)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_nei3f"]
|
||||||
|
albedo_color = Color(0.05882353, 0.05882353, 0.05882353, 1)
|
||||||
|
|
||||||
|
[node name="EscapeCapsule" type="CharacterBody3D" unique_id=900802887 groups=["interactable"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.9409914, -1.1106515, 0.90658)
|
||||||
|
script = ExtResource("1_r50ee")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=640959005]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.12550688, 0)
|
||||||
|
shape = SubResource("CylinderShape3D_j65qs")
|
||||||
|
|
||||||
|
[node name="Body" type="MeshInstance3D" parent="." unique_id=683390934]
|
||||||
|
mesh = SubResource("CylinderMesh_18y2q")
|
||||||
|
|
||||||
|
[node name="ExternalView" type="SubViewport" parent="Body" unique_id=1265488610]
|
||||||
|
handle_input_locally = false
|
||||||
|
size = Vector2i(3840, 2160)
|
||||||
|
render_target_update_mode = 4
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="Body/ExternalView" unique_id=698867349]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 18.911898, 5.1233277, -0.039017588)
|
||||||
|
visible = false
|
||||||
|
fov = 72.0
|
||||||
|
far = 1000000.0
|
||||||
|
|
||||||
|
[node name="HeatShield" type="MeshInstance3D" parent="." unique_id=2080285390]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.9, 0)
|
||||||
|
mesh = SubResource("CylinderMesh_3jrso")
|
||||||
|
|
||||||
|
[node name="InteractionArea" type="Area3D" parent="." unique_id=1761123778]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="InteractionArea" unique_id=1229487990]
|
||||||
|
shape = SubResource("SphereShape3D_crvdt")
|
||||||
|
|
||||||
|
[node name="ThirdPersonCamera" type="Camera3D" parent="." unique_id=284479039]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, -9.5, 3.5)
|
||||||
|
far = 1000000.0
|
||||||
|
|
||||||
|
[node name="Cockpit" type="Node3D" parent="." unique_id=1933795690]
|
||||||
|
transform = Transform3D(-1, 8.742278e-08, 3.821371e-15, 0, -4.371139e-08, 1, 8.742278e-08, 1, 4.371139e-08, 0, -0.94330907, -0.62695575)
|
||||||
|
|
||||||
|
[node name="WindowGlass" type="MeshInstance3D" parent="Cockpit" unique_id=99141125]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0015087128, 1.5509896, 2.2775838)
|
||||||
|
mesh = SubResource("BoxMesh_ijs7n")
|
||||||
|
|
||||||
|
[node name="HudShape" type="MeshInstance3D" parent="Cockpit" unique_id=1572026781]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0777357, 1.8649361)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("BoxMesh_xuqvo")
|
||||||
|
|
||||||
|
[node name="CockpitLight" type="OmniLight3D" parent="Cockpit" unique_id=1492843635]
|
||||||
|
transform = Transform3D(-1, 0, 8.742278e-08, 8.742278e-08, -4.371139e-08, 1, 3.821371e-15, 1, 4.371139e-08, 0, 2.1579213, 0.00050091743)
|
||||||
|
light_color = Color(1, 0.89411765, 0.76862746, 1)
|
||||||
|
omni_range = 3.5
|
||||||
|
|
||||||
|
[node name="CameraPivot" type="Node3D" parent="Cockpit" unique_id=1263006067]
|
||||||
|
transform = Transform3D(-1, 0, 8.742278e-08, 0, 1, 0, -8.742278e-08, 0, -1, 0, 1.4656192, -0.07458353)
|
||||||
|
|
||||||
|
[node name="CapsuleCamera" type="Camera3D" parent="Cockpit/CameraPivot" unique_id=1044956475]
|
||||||
|
transform = Transform3D(1, 0, -3.2840569e-15, 0, 1, 0, -3.2840569e-15, 0, 1, 0, -0.21693517, -0.4030409)
|
||||||
|
far = 1000000.0
|
||||||
|
|
||||||
|
[node name="Seat" type="MeshInstance3D" parent="Cockpit" unique_id=123094182]
|
||||||
|
mesh = SubResource("BoxMesh_d13ii")
|
||||||
|
|
||||||
|
[node name="SeatBack" type="MeshInstance3D" parent="Cockpit" unique_id=1553533167]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.38205957, -0.36825216)
|
||||||
|
mesh = SubResource("BoxMesh_ts8u1")
|
||||||
|
|
||||||
|
[node name="MainPanel" type="MeshInstance3D" parent="Cockpit" unique_id=2127997099]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.42596802, 1.6161394)
|
||||||
|
mesh = SubResource("BoxMesh_l6148")
|
||||||
|
|
||||||
|
[node name="GlassCockpitPanel" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=56681667]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.16014825, -0.25493002)
|
||||||
|
mesh = SubResource("BoxMesh_wqh1g")
|
||||||
|
|
||||||
|
[node name="LeftInstrument" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=944149313]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.294096, 0.21341178, -0.25256205)
|
||||||
|
mesh = SubResource("BoxMesh_kx67c")
|
||||||
|
|
||||||
|
[node name="RightInstrument" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=1061352713]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.294, 0.213, -0.253)
|
||||||
|
mesh = SubResource("BoxMesh_kx67c")
|
||||||
|
|
||||||
|
[node name="ForwardDisplay" type="MeshInstance3D" parent="Cockpit/MainPanel" unique_id=1977279423]
|
||||||
|
transform = Transform3D(0.9999994, -5.728489e-05, -0.0011173013, 5.5921435e-05, 0.99999917, -0.0012259485, 0.0011173704, 0.0012257855, 0.9999986, 0.32665062, 0.049695313, -0.25658345)
|
||||||
|
mesh = SubResource("BoxMesh_52c6f")
|
||||||
|
|
||||||
|
[node name="LeftWall" type="MeshInstance3D" parent="Cockpit" unique_id=1514749488]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4201202, 0.6709095, 0.801975)
|
||||||
|
mesh = SubResource("BoxMesh_r6cyv")
|
||||||
|
|
||||||
|
[node name="RightWall" type="MeshInstance3D" parent="Cockpit" unique_id=1764263004]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.4199867, 0.67109835, 0.79347587)
|
||||||
|
mesh = SubResource("BoxMesh_r6cyv")
|
||||||
|
|
||||||
|
[node name="Floor" type="MeshInstance3D" parent="Cockpit" unique_id=1998677292]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0061683655, -0.25959706, 0.80126953)
|
||||||
|
mesh = SubResource("BoxMesh_4yprg")
|
||||||
|
|
||||||
|
[node name="OverheadConsole" type="MeshInstance3D" parent="Cockpit" unique_id=976403028]
|
||||||
|
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, 0, 2.2589908, 0.95627284)
|
||||||
|
mesh = SubResource("BoxMesh_o0dcp")
|
||||||
|
|
||||||
|
[node name="ForwardBulkhead" type="MeshInstance3D" parent="Cockpit" unique_id=1582033665]
|
||||||
|
transform = Transform3D(1, -6.905431e-09, -3.4056352e-08, -6.905438e-09, 0.92101103, -0.38953644, 3.4054356e-08, 0.38953644, 0.92101103, -0.0020980835, 0.10092795, 2.3168466)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("BoxMesh_omqyl")
|
||||||
|
|
||||||
|
[node name="ForwardBulkhead2" type="MeshInstance3D" parent="Cockpit/ForwardBulkhead" unique_id=1004286348]
|
||||||
|
transform = Transform3D(1, -6.9062125e-09, 3.4056193e-08, -6.905424e-09, 0.9210111, 0.38953647, -3.405436e-08, -0.38953647, 0.9210111, 0.018800735, 0.70290273, -0.13796377)
|
||||||
|
mesh = SubResource("BoxMesh_omqyl")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Cockpit/ForwardBulkhead" unique_id=411181651]
|
||||||
|
transform = Transform3D(1, -7.2910282e-09, 3.4950116e-08, -7.2894153e-09, 0.91661024, 0.39978403, -3.4950364e-08, -0.39978403, 0.91661024, 0.021972656, 1.129911, -0.3276949)
|
||||||
|
mesh = SubResource("BoxMesh_p2ucw")
|
||||||
|
|
||||||
|
[node name="FrontBulkhead" type="CSGCombiner3D" parent="Cockpit/ForwardBulkhead" unique_id=1462779310]
|
||||||
|
transform = Transform3D(1, -6.9062196e-09, 3.40562e-08, -6.905424e-09, 0.92101115, 0.3895365, -3.405436e-08, -0.3895365, 0.92101115, 0.0020980835, -0.0909484, 0.044061184)
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
[node name="BulkheadShape" type="CSGPolygon3D" parent="Cockpit/ForwardBulkhead/FrontBulkhead" unique_id=991532318]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.9277502, 0.22244406)
|
||||||
|
polygon = PackedVector2Array(-1.55, -0.345, 1.55, -0.345, 0.72924423, 0.34169006, -0.75127983, 0.3621254)
|
||||||
|
depth = 0.12
|
||||||
|
material = SubResource("StandardMaterial3D_seu75")
|
||||||
|
|
||||||
|
[node name="RoofLeft" type="MeshInstance3D" parent="Cockpit" unique_id=1535690315]
|
||||||
|
transform = Transform3D(0.7071067, 0.7071067, 0, -0.7071067, 0.7071067, 0, 0, 0, 1, 1.1796818, 1.8760827, 0.79144645)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="RoofLeft1" type="MeshInstance3D" parent="Cockpit/RoofLeft" unique_id=1785270765]
|
||||||
|
transform = Transform3D(0.8763269, -0.4817174, 9.8520925e-09, 0.4817174, 0.8763269, 7.3968387e-09, -1.2196834e-08, -1.7361046e-09, 1, -0.6168623, -0.15812302, 0.005322695)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="RoofRight" type="MeshInstance3D" parent="Cockpit" unique_id=10541876]
|
||||||
|
transform = Transform3D(0.7071067, -0.7071067, 0, 0.7071067, 0.7071067, 0, 0, 0, 1, -1.18, 1.876, 0.791)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="RoofRight1" type="MeshInstance3D" parent="Cockpit/RoofRight" unique_id=597720853]
|
||||||
|
transform = Transform3D(0.87630665, 0.4817537, 0, -0.4817537, 0.87630665, 0, 3.543832e-13, 0, 1, 0.6105108, -0.15750027, -0.0017383099)
|
||||||
|
mesh = SubResource("BoxMesh_81jjf")
|
||||||
|
|
||||||
|
[node name="RoofTop" type="MeshInstance3D" parent="Cockpit" unique_id=974546659]
|
||||||
|
transform = Transform3D(0.9999999, 0, 0, 0, 0.9999999, 0, 0, 0, 1, -0.00787735, 2.2835252, 0.79144645)
|
||||||
|
mesh = SubResource("BoxMesh_ucmdv")
|
||||||
|
|
||||||
|
[node name="ForwardBulkhead2" type="CSGCombiner3D" parent="Cockpit" unique_id=1803926178]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.14711916, 2.8341548)
|
||||||
|
|
||||||
|
[node name="BulkTop" type="CSGPolygon3D" parent="Cockpit/ForwardBulkhead2" unique_id=1704103664]
|
||||||
|
transform = Transform3D(1, -1.4087291e-09, 1.562843e-08, -1.4074928e-09, 0.9838952, 0.17874739, -1.5626552e-08, -0.17874739, 0.9838952, 0.0020980835, 1.7711809, -0.50199556)
|
||||||
|
polygon = PackedVector2Array(-1.55, -0.345, 1.55, -0.345, 0.72924423, 0.34169006, -0.75127983, 0.3621254)
|
||||||
|
depth = 0.12
|
||||||
|
material = SubResource("StandardMaterial3D_seu75")
|
||||||
|
|
||||||
|
[node name="BulkBottom" type="CSGBox3D" parent="Cockpit/ForwardBulkhead2" unique_id=1217332907]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0018692017, 0.49510977, -0.49700785)
|
||||||
|
size = Vector3(2.788086, 1.8628662, 0.08208008)
|
||||||
|
material = SubResource("StandardMaterial3D_nei3f")
|
||||||
|
|
||||||
|
[node name="WindowCutout" type="CSGBox3D" parent="Cockpit/ForwardBulkhead2" unique_id=1392835612]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4177693, -0.5765586)
|
||||||
|
operation = 2
|
||||||
|
size = Vector3(1.5, 0.89470214, 0.2836914)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user