initial commit
This commit is contained in:
16
Assets/Scripts/Misc/flickering_light.gd
Normal file
16
Assets/Scripts/Misc/flickering_light.gd
Normal file
@@ -0,0 +1,16 @@
|
||||
extends OmniLight3D
|
||||
@onready var light: OmniLight3D = get_node(".")
|
||||
@onready var timer: Timer = get_node('Timer')
|
||||
|
||||
var randomRange: float = 0.0
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta: float) -> void:
|
||||
light.light_energy = lerp(light.light_energy, randomRange, 0.3)
|
||||
|
||||
pass
|
||||
|
||||
func _on_timer_timeout() -> void:
|
||||
randomRange = randf_range(1.5, 4)
|
||||
timer.wait_time = randf_range(0.2, 0.5)
|
||||
pass # Replace with function body.
|
||||
1
Assets/Scripts/Misc/flickering_light.gd.uid
Normal file
1
Assets/Scripts/Misc/flickering_light.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bfsaxhnb0qpuk
|
||||
2
Assets/Scripts/Player Controls/global_settings.gd
Normal file
2
Assets/Scripts/Player Controls/global_settings.gd
Normal file
@@ -0,0 +1,2 @@
|
||||
extends Node
|
||||
@export var cameraSensitivity: float = 0.001
|
||||
1
Assets/Scripts/Player Controls/global_settings.gd.uid
Normal file
1
Assets/Scripts/Player Controls/global_settings.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ctroo2h1bbcyv
|
||||
40
Assets/Scripts/Player Controls/interact.gd
Normal file
40
Assets/Scripts/Player Controls/interact.gd
Normal file
@@ -0,0 +1,40 @@
|
||||
extends Camera3D
|
||||
|
||||
var rayRange = 2000
|
||||
|
||||
@onready var crosshair = %CrosshairCenter
|
||||
@export var terminal: TerminalControls
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
Get_Camera_Collision()
|
||||
|
||||
|
||||
func Get_Camera_Collision():
|
||||
var centre = get_viewport().get_size()/2
|
||||
|
||||
var rayOrigin = project_ray_origin(centre)
|
||||
var rayEnd = rayOrigin + project_ray_normal(centre)*rayRange
|
||||
|
||||
var newIntersection = PhysicsRayQueryParameters3D.create(rayOrigin, rayEnd)
|
||||
var intersection = get_world_3d().direct_space_state.intersect_ray(newIntersection)
|
||||
|
||||
var is_highlighted = not intersection.is_empty()
|
||||
|
||||
if crosshair and is_instance_valid(crosshair):
|
||||
crosshair.set_highlight(is_highlighted)
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventKey and event.pressed and crosshair.is_highlighted:
|
||||
if event.is_echo(): return
|
||||
|
||||
if event.keycode == KEY_BACKSPACE:
|
||||
terminal.InputDelChar()
|
||||
|
||||
if event.unicode > 31:
|
||||
var character = char(event.unicode)
|
||||
if terminal: # Check that you assigned the node in the Inspector
|
||||
terminal.InputChar(character)
|
||||
|
||||
if event.keycode == KEY_ENTER:
|
||||
terminal.EnterCommand()
|
||||
1
Assets/Scripts/Player Controls/interact.gd.uid
Normal file
1
Assets/Scripts/Player Controls/interact.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://55cgjgncpb53
|
||||
44
Assets/Scripts/Player Controls/player_movement.gd
Normal file
44
Assets/Scripts/Player Controls/player_movement.gd
Normal file
@@ -0,0 +1,44 @@
|
||||
extends Node3D
|
||||
|
||||
@onready var camera: Camera3D = $Camera3D
|
||||
@export var verticalLookLimit: float = deg_to_rad(50)
|
||||
|
||||
|
||||
@export var psxScene: PackedScene
|
||||
var psxInstance: Node = null
|
||||
var togglePsxEffect: bool = false
|
||||
#@export var horizontalLookRightLimit: float = deg_to_rad(290)
|
||||
#@export var horizontalLookLeftLimit: float = deg_to_rad(-196)
|
||||
var cameraPitch: float = 0.0
|
||||
var cameraYaw: float = 0.0
|
||||
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
var currentRot = camera.rotation
|
||||
cameraPitch = currentRot.x
|
||||
cameraYaw = currentRot.y
|
||||
camera.rotation.z = 0.0
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
cameraPitch -= event.screen_relative.y * GlobalSettings.cameraSensitivity
|
||||
cameraYaw -= event.screen_relative.x * GlobalSettings.cameraSensitivity
|
||||
#cameraPitch = clamp(cameraPitch, -verticalLookLimit, verticalLookLimit)
|
||||
#cameraYaw = clamp(cameraYaw, -horizontalLookLeftLimit, horizontalLookRightLimit)
|
||||
cameraPitch = clamp(cameraPitch, -verticalLookLimit, verticalLookLimit)
|
||||
camera.rotation = Vector3(cameraPitch, cameraYaw, 0)
|
||||
|
||||
if Input.is_action_just_released("PSX Theme toggle"):
|
||||
togglePsxEffect = !togglePsxEffect
|
||||
|
||||
if togglePsxEffect:
|
||||
psxInstance = psxScene.instantiate()
|
||||
add_child(psxInstance)
|
||||
else:
|
||||
psxInstance.queue_free()
|
||||
psxInstance = null
|
||||
|
||||
|
||||
|
||||
1
Assets/Scripts/Player Controls/player_movement.gd.uid
Normal file
1
Assets/Scripts/Player Controls/player_movement.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dmtpstry0o0a3
|
||||
89
Assets/Scripts/Shaders/psx.gdshader
Normal file
89
Assets/Scripts/Shaders/psx.gdshader
Normal file
@@ -0,0 +1,89 @@
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform sampler2D screen_texture : hint_screen_texture;
|
||||
uniform float pixel_resolution : hint_range(64.0, 512.0) = 240.0;
|
||||
uniform int color_steps : hint_range(2, 64) = 16;
|
||||
uniform float noise_strength : hint_range(0.0, 1.0) = 0.1;
|
||||
uniform bool enable_dither = true;
|
||||
uniform float dither_strength : hint_range(0.0, 1.0) = 0.3;
|
||||
|
||||
uniform bool enable_glow = true;
|
||||
uniform float glow_strength : hint_range(0.0, 1.0) = 0.4;
|
||||
uniform float glow_spread : hint_range(0.001, 0.01) = 0.005;
|
||||
|
||||
uniform bool enable_vintage = true; // Toggle
|
||||
uniform float vintage_strength : hint_range(0.0, 1.0) = 0.8;
|
||||
|
||||
float random(vec2 co) {
|
||||
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
float bayer_dither(vec2 pos) {
|
||||
int x = int(mod(pos.x, 4.0));
|
||||
int y = int(mod(pos.y, 4.0));
|
||||
int index = x + y * 4;
|
||||
|
||||
float bayer[16] = float[](
|
||||
0.0, 8.0, 2.0, 10.0,
|
||||
12.0, 4.0, 14.0, 6.0,
|
||||
3.0, 11.0, 1.0, 9.0,
|
||||
15.0, 7.0, 13.0, 5.0
|
||||
);
|
||||
|
||||
return bayer[index] / 16.0;
|
||||
}
|
||||
|
||||
vec3 get_glow(vec2 uv) {
|
||||
vec3 col = vec3(0.0);
|
||||
float total = 0.0;
|
||||
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
vec2 offset = vec2(float(x), float(y)) * glow_spread;
|
||||
col += texture(screen_texture, uv + offset).rgb;
|
||||
total += 1.0;
|
||||
}
|
||||
}
|
||||
return col / total;
|
||||
}
|
||||
|
||||
vec3 apply_black_vintage_edges(vec3 color, vec2 uv) {
|
||||
// Distance from screen center
|
||||
float dist = distance(uv, vec2(0.5));
|
||||
|
||||
// Mask: only affects edges
|
||||
float edge_mask = smoothstep(0.4, 0.8, dist);
|
||||
|
||||
// Blend edges to black
|
||||
color = mix(color, vec3(0.0), edge_mask * vintage_strength);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec2 pixel_uv = floor(UV * pixel_resolution) / pixel_resolution;
|
||||
vec3 color = texture(screen_texture, pixel_uv).rgb;
|
||||
|
||||
if (enable_glow) {
|
||||
vec3 blurred = get_glow(UV);
|
||||
color += blurred * glow_strength;
|
||||
}
|
||||
|
||||
float steps = float(color_steps);
|
||||
color = floor(color * steps + 0.5) / steps;
|
||||
|
||||
float noise = (random(UV + TIME) - 0.5) * noise_strength;
|
||||
color += noise;
|
||||
|
||||
if (enable_dither) {
|
||||
float threshold = bayer_dither(FRAGCOORD.xy);
|
||||
color += (dither_strength * (threshold - 0.5));
|
||||
}
|
||||
|
||||
// Black vintage only on edges
|
||||
if (enable_vintage) {
|
||||
color = apply_black_vintage_edges(color, UV);
|
||||
}
|
||||
|
||||
COLOR.rgb = clamp(color, 0.0, 1.0);
|
||||
}
|
||||
1
Assets/Scripts/Shaders/psx.gdshader.uid
Normal file
1
Assets/Scripts/Shaders/psx.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://uo56rpfskail
|
||||
39
Assets/Scripts/UI/crosshair.gd
Normal file
39
Assets/Scripts/UI/crosshair.gd
Normal file
@@ -0,0 +1,39 @@
|
||||
extends CenterContainer
|
||||
@export var dotRadius: float = 1
|
||||
@export var dotColor: Color = Color.WHITE
|
||||
|
||||
var current_radius: float
|
||||
var is_highlighted: bool = false
|
||||
var tween: Tween
|
||||
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
queue_redraw()
|
||||
pass # Replace with function body.
|
||||
|
||||
# This function is called by the Camera script
|
||||
func set_highlight(active: bool) -> void:
|
||||
is_highlighted = active
|
||||
_animate_radius()
|
||||
queue_redraw()
|
||||
|
||||
func _animate_radius():
|
||||
# Kill any existing tween so they don't fight each other
|
||||
if tween and tween.is_running():
|
||||
tween.kill()
|
||||
|
||||
tween = create_tween()
|
||||
|
||||
# Determine target based on state
|
||||
var target = dotRadius * 3 if is_highlighted else dotRadius
|
||||
|
||||
# Transition from current_radius to target over 0.3 seconds
|
||||
tween.tween_property(self, "current_radius", target, 0.1)\
|
||||
.set_trans(Tween.TRANS_SINE)\
|
||||
.set_ease(Tween.EASE_OUT)
|
||||
|
||||
|
||||
func _draw():
|
||||
draw_circle(Vector2(0,0),current_radius,dotColor)
|
||||
1
Assets/Scripts/UI/crosshair.gd.uid
Normal file
1
Assets/Scripts/UI/crosshair.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://chb1dyhl7cyg1
|
||||
13
Assets/Scripts/UI/fade_in.gd
Normal file
13
Assets/Scripts/UI/fade_in.gd
Normal file
@@ -0,0 +1,13 @@
|
||||
extends Node
|
||||
|
||||
@onready var colorRect = $ColorRect
|
||||
@onready var animationPlayer = $AnimationPlayer
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
colorRect.visible = true
|
||||
animationPlayer.play("fade_in")
|
||||
await get_tree().create_timer(5.0).timeout
|
||||
queue_free()
|
||||
|
||||
pass # Replace with function body.
|
||||
1
Assets/Scripts/UI/fade_in.gd.uid
Normal file
1
Assets/Scripts/UI/fade_in.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cs6mhxw52ldo1
|
||||
15
Assets/Scripts/UI/main_menu.gd
Normal file
15
Assets/Scripts/UI/main_menu.gd
Normal file
@@ -0,0 +1,15 @@
|
||||
extends Control
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
|
||||
|
||||
func _on_new_game_button_pressed() -> void:
|
||||
get_tree().change_scene_to_file("res://Scenes/Levels/office.tscn")
|
||||
print("changed")
|
||||
pass # Replace with function body.
|
||||
1
Assets/Scripts/UI/main_menu.gd.uid
Normal file
1
Assets/Scripts/UI/main_menu.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2sxp2yxkv5k2
|
||||
39
Assets/Scripts/UI/pause_menu.gd
Normal file
39
Assets/Scripts/UI/pause_menu.gd
Normal file
@@ -0,0 +1,39 @@
|
||||
extends Control
|
||||
|
||||
|
||||
var paused = false
|
||||
var showMouse = false
|
||||
|
||||
func _ready() -> void:
|
||||
|
||||
self.visible = paused
|
||||
|
||||
func _input(_event: InputEvent) -> void:
|
||||
if Input.is_action_just_pressed("Pause"):
|
||||
print("paused")
|
||||
_pause_and_unpause()
|
||||
|
||||
func _pause_and_unpause():
|
||||
paused = !paused
|
||||
showMouse = !showMouse
|
||||
get_tree().paused = paused
|
||||
self.visible = paused
|
||||
$MarginContainer/VBoxContainer/CameraSensitivityLabel/HSlider.value = GlobalSettings.cameraSensitivity
|
||||
|
||||
if showMouse:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||
else:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
func _on_resume_game_button_pressed() -> void:
|
||||
_pause_and_unpause()
|
||||
|
||||
|
||||
func _on_quit_game_button_pressed() -> void:
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func _on_h_slider_value_changed(value: float) -> void:
|
||||
GlobalSettings.cameraSensitivity = value
|
||||
print(GlobalSettings.cameraSensitivity)
|
||||
pass # Replace with function body.
|
||||
1
Assets/Scripts/UI/pause_menu.gd.uid
Normal file
1
Assets/Scripts/UI/pause_menu.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cnw8764a6hljr
|
||||
168
Assets/Scripts/UI/terminal/terminal_controls.gd
Normal file
168
Assets/Scripts/UI/terminal/terminal_controls.gd
Normal file
@@ -0,0 +1,168 @@
|
||||
extends Node
|
||||
class_name TerminalControls
|
||||
|
||||
@onready var historyContainer = $MarginContainer/ScrollContainer/VBoxContainer
|
||||
@onready var caret = $MarginContainer/ScrollContainer/VBoxContainer/Label/Caret
|
||||
@onready var blink_timer = $MarginContainer/ScrollContainer/VBoxContainer/Label/CaretTimer
|
||||
@export var terminalLine: Label
|
||||
|
||||
var command: String
|
||||
var directory: String = "~/"
|
||||
var fileSystem: Dictionary = {
|
||||
"documents": {
|
||||
"special": {
|
||||
"notes.txt": "test",
|
||||
"secrets": {
|
||||
"password.txt": 123
|
||||
}
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"sh": "binary data",
|
||||
}
|
||||
}
|
||||
|
||||
func _ready() -> void:
|
||||
terminalLine.text = "user@work "+ directory + " "
|
||||
UpdateCaretPos()
|
||||
blink_timer.start()
|
||||
|
||||
# --- Caret Blinking Logic ---
|
||||
func _on_caret_timer_timeout() -> void:
|
||||
caret.visible = !caret.visible
|
||||
|
||||
func reset_blink() -> void:
|
||||
caret.visible = true
|
||||
blink_timer.start() # Resets the countdown
|
||||
|
||||
# --- Input Handling ---
|
||||
func InputChar(input) -> void:
|
||||
if input == null:
|
||||
return
|
||||
command = input
|
||||
terminalLine.text += command
|
||||
UpdateCaretPos()
|
||||
reset_blink()
|
||||
func InputDelChar() -> void:
|
||||
if terminalLine.text.length() > ("user@work " + directory).length() + 1:
|
||||
terminalLine.text = terminalLine.text.left(-1)
|
||||
UpdateCaretPos()
|
||||
reset_blink()
|
||||
|
||||
func EnterCommand() -> void:
|
||||
var fullText = terminalLine.text
|
||||
var userInput = fullText.trim_prefix("user@work " + directory).strip_edges()
|
||||
|
||||
if historyContainer.get_child_count() <22:
|
||||
CreateHistoryEntry(fullText)
|
||||
var parts = userInput.split(" ")
|
||||
|
||||
match parts[0]:
|
||||
"ls":
|
||||
var currentDirData
|
||||
if parts.size() > 1:
|
||||
currentDirData = GetDirAtPath(directory + parts[1])
|
||||
else:
|
||||
currentDirData = GetDirAtPath(directory)
|
||||
if currentDirData is Dictionary:
|
||||
var list = ""
|
||||
for key in currentDirData.keys():
|
||||
list += key + " "
|
||||
CreateHistoryEntry(list)
|
||||
else:
|
||||
CreateHistoryEntry("error: Directory not found")
|
||||
"cd":
|
||||
if parts.size() > 1:
|
||||
var targetPath = parts[1]
|
||||
var newDir = ResolvePath(directory, targetPath)
|
||||
if GetDirAtPath(newDir) != null:
|
||||
directory = newDir
|
||||
else:
|
||||
CreateHistoryEntry("cd: no such directory: " + targetPath)
|
||||
else:
|
||||
directory = "~/"
|
||||
"cat":
|
||||
if parts.size() > 1:
|
||||
RetrieveData(parts[1])
|
||||
else:
|
||||
CreateHistoryEntry("usage: cat [filename]")
|
||||
"clear":
|
||||
for child in historyContainer.get_children():
|
||||
if child != terminalLine:
|
||||
child.queue_free()
|
||||
"":
|
||||
pass
|
||||
_:
|
||||
CreateHistoryEntry("Command not found: " + userInput)
|
||||
|
||||
terminalLine.text = "user@work "+ directory + " "
|
||||
|
||||
# Handle UI scrolling correctly
|
||||
|
||||
var scrollBox = historyContainer.get_parent() as ScrollContainer
|
||||
historyContainer.force_update_transform()
|
||||
await get_tree().process_frame
|
||||
scrollBox.scroll_vertical = int(scrollBox.get_v_scroll_bar().max_value)
|
||||
UpdateCaretPos()
|
||||
|
||||
# --- History and FileSystem Helpers ---
|
||||
func CreateHistoryEntry(content: String) -> void:
|
||||
var label = Label.new()
|
||||
label.text = content
|
||||
label.label_settings = LabelSettings.new()
|
||||
label.label_settings.font_size = 42
|
||||
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
label.custom_minimum_size = Vector2(1400, 0)
|
||||
|
||||
if terminalLine.text.length() > 200:
|
||||
for child in historyContainer.get_children():
|
||||
if child != terminalLine:
|
||||
child.queue_free()
|
||||
historyContainer.add_child(label)
|
||||
historyContainer.move_child(label, historyContainer.get_child_count() - 2)
|
||||
|
||||
# Limit history to 15 entries + 1 active line
|
||||
if historyContainer.get_child_count() > 22:
|
||||
historyContainer.get_child(0).queue_free()
|
||||
|
||||
func ResolvePath(current: String, target: String) -> String:
|
||||
if target.begins_with("~/"):
|
||||
return target if target.ends_with("/") else target + "/"
|
||||
if target == "..":
|
||||
if current == "~/": return "~/"
|
||||
var parts = current.trim_suffix("/").rsplit("/", true, 1)
|
||||
return parts[0] + "/"
|
||||
var joined = current + target
|
||||
return joined if joined.ends_with("/") else joined + "/"
|
||||
|
||||
func GetDirAtPath(path: String):
|
||||
if path == "~/": return fileSystem
|
||||
var cleanPath = path.trim_prefix("~/").trim_suffix("/")
|
||||
var folders = cleanPath.split("/")
|
||||
var current = fileSystem
|
||||
for folder in folders:
|
||||
if current is Dictionary and current.has(folder) and current[folder] is Dictionary:
|
||||
current = current[folder]
|
||||
else:
|
||||
return null
|
||||
return current if current is Dictionary else null
|
||||
|
||||
func RetrieveData(filename: String):
|
||||
var currentData = GetDirAtPath(directory)
|
||||
if currentData == null:
|
||||
CreateHistoryEntry("Error: Current directory invalid.")
|
||||
return
|
||||
if currentData.has(filename):
|
||||
var content = currentData[filename]
|
||||
if content is Dictionary:
|
||||
CreateHistoryEntry("cat: " + filename + ": is a directory")
|
||||
else:
|
||||
CreateHistoryEntry(str(content))
|
||||
else:
|
||||
CreateHistoryEntry("cat: " + filename + ": no such file")
|
||||
|
||||
func UpdateCaretPos():
|
||||
var last_char_index = terminalLine.text.length() - 1
|
||||
var char_rect = terminalLine.get_character_bounds(max(0, last_char_index))
|
||||
caret.position.x = char_rect.end.x + 1
|
||||
caret.position.y = char_rect.position.y
|
||||
1
Assets/Scripts/UI/terminal/terminal_controls.gd.uid
Normal file
1
Assets/Scripts/UI/terminal/terminal_controls.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ckagscjkf3iiu
|
||||
Reference in New Issue
Block a user