UI work, placing traps, removing traps, disarming traps, new sound fx.

This commit is contained in:
2025-12-25 17:52:30 -05:00
parent 3b6407d6e5
commit 55eb37ca74
34 changed files with 867 additions and 72 deletions

View File

@@ -86,3 +86,18 @@ detect={
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":3,"pressure":0.0,"pressed":true,"script":null) "events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":3,"pressure":0.0,"pressed":true,"script":null)
] ]
} }
"lay trap"={
"deadzone": 0.2,
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":2,"pressure":0.0,"pressed":true,"script":null)
]
}
attack={
"deadzone": 0.2,
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":true,"script":null)
]
}
detonate={
"deadzone": 0.2,
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
]
}

View File

@@ -1,22 +1,11 @@
[gd_scene load_steps=11 format=3 uid="uid://by6suwmds7xq2"] [gd_scene load_steps=6 format=3 uid="uid://by6suwmds7xq2"]
[ext_resource type="Script" uid="uid://d3t381vws7vns" path="res://scripts/test_level.gd" id="1_qcd3b"] [ext_resource type="Script" uid="uid://d3t381vws7vns" path="res://scripts/test_level.gd" id="1_qcd3b"]
[ext_resource type="PackedScene" uid="uid://bgocskbofewsr" path="res://templates/HUD.tscn" id="1_x4b8f"] [ext_resource type="PackedScene" uid="uid://bgocskbofewsr" path="res://templates/HUD.tscn" id="1_x4b8f"]
[ext_resource type="Script" uid="uid://cymi1n4gavixy" path="res://scripts/level_camera.gd" id="3_qcd3b"] [ext_resource type="Script" uid="uid://cymi1n4gavixy" path="res://scripts/level_camera.gd" id="3_qcd3b"]
[ext_resource type="ArrayMesh" uid="uid://bih57xe642hrc" path="res://models/trap.obj" id="4_tmr53"]
[ext_resource type="Texture2D" uid="uid://dri0a20l6kpbj" path="res://visuals/images/icon.svg" id="6_ahbqi"]
[ext_resource type="MeshLibrary" uid="uid://bhpyvhf36jl0f" path="res://testing.tres" id="7_88ety"] [ext_resource type="MeshLibrary" uid="uid://bhpyvhf36jl0f" path="res://testing.tres" id="7_88ety"]
[ext_resource type="MeshLibrary" uid="uid://cvhm40o2uw5mr" path="res://testing markers.tres" id="7_ahbqi"] [ext_resource type="MeshLibrary" uid="uid://cvhm40o2uw5mr" path="res://testing markers.tres" id="7_ahbqi"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qcd3b"]
albedo_color = Color(0, 0, 1, 1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_88ety"]
albedo_color = Color(1, 0, 0, 1)
[sub_resource type="BoxShape3D" id="BoxShape3D_dw7u0"]
size = Vector3(0.8, 1, 0.8)
[node name="Node3D" type="Node3D"] [node name="Node3D" type="Node3D"]
script = ExtResource("1_qcd3b") script = ExtResource("1_qcd3b")
@@ -31,25 +20,6 @@ projection = 1
size = 5.0 size = 5.0
script = ExtResource("3_qcd3b") script = ExtResource("3_qcd3b")
[node name="Area3D" type="Area3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.496, 0, 0.479267)
[node name="Trap" type="MeshInstance3D" parent="Area3D"]
transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, 0, 0, 0)
material_overlay = SubResource("StandardMaterial3D_qcd3b")
mesh = ExtResource("4_tmr53")
skeleton = NodePath("")
surface_material_override/0 = SubResource("StandardMaterial3D_88ety")
[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
shape = SubResource("BoxShape3D_dw7u0")
[node name="Sprite3D" type="Sprite3D" parent="Area3D"]
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 0.05, 0)
visible = false
texture = ExtResource("6_ahbqi")
[node name="OmniLight3D" type="OmniLight3D" parent="."] [node name="OmniLight3D" type="OmniLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 18.508709, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 18.508709, 0)
omni_range = 25.142 omni_range = 25.142

View File

@@ -1,14 +1,8 @@
extends Node extends Node
enum TrapType{
BOMB,
MINE,
GAS,
FORCE_PANEL,
SWITCH,
PITFALL
}
const blinder_template = preload("res://templates/blinder.tscn") const blinder_template = preload("res://templates/blinder.tscn")
const one_shot_template = preload("res://templates/one_shot.tscn")
const vs_man_level = preload("res://scenes/multiplayer_test.tscn") const vs_man_level = preload("res://scenes/multiplayer_test.tscn")
@@ -41,3 +35,11 @@ func start_vs_man() -> void:
var spawner = get_tree().get_first_node_in_group("level_spawner") as MultiplayerSpawner var spawner = get_tree().get_first_node_in_group("level_spawner") as MultiplayerSpawner
spawner.add_child(level) spawner.add_child(level)
func oneshot(stream : AudioStream) -> void:
var shot = one_shot_template.instantiate()
shot.stream = stream
if level:
level.add_child(shot)
else:
add_child(shot)

View File

@@ -4,7 +4,7 @@ extends Node
const SERVER_PORT = 8080 const SERVER_PORT = 8080
const SERVER_IP = "127.0.0.1" const SERVER_IP = "127.0.0.1"
var handle : String var handle : String
var id : int var id : int = 1
var players : Dictionary = {} var players : Dictionary = {}
signal client_added(handle : String, id : int) signal client_added(handle : String, id : int)

View File

@@ -0,0 +1,103 @@
class_name DisarmTrapModal extends Control
const action_value : Dictionary[String, int] = {
"detonate" : 0,
"lay trap" : 1,
"detect" : 2,
"attack" : 3
}
const icon_textures : Array = [
{
"normal" : preload("res://visuals/images/icons/switch button.png"),
"pressed" : preload("res://visuals/images/icons/lit switch button.png")
},
{
"normal" : preload("res://visuals/images/icons/trap button.png"),
"pressed" : preload("res://visuals/images/icons/lit trap button.png")
},
{
"normal" : preload("res://visuals/images/icons/detect button.png"),
"pressed" : preload("res://visuals/images/icons/lit detect button.png")
},
{
"normal" : preload("res://visuals/images/icons/ranged attack button.png"),
"pressed" : preload("res://visuals/images/icons/lit ranged attack button.png")
},
]
const disarm_icon_template = preload("res://templates/disarm_icon.tscn")
const success_sound = preload("res://audio/sounds/menu select.wav")
const fail_sound = preload("res://audio/sounds/134688__otbtechno__bike-bell.wav")
const progress_sound = preload("res://audio/sounds/BUTTON Generic Metal Medium High Mechanics 02.wav")
@onready var confirmation_dialog : ConfirmationDialog = %ConfirmationDialog
@onready var disarm_window : PanelContainer = %DisarmWindow
@onready var disarm_button_container : HBoxContainer = %DisarmContainer
@onready var timer : Timer = %Timer
@onready var timer_label : Label = %TimerLabel
var square : Vector3i
var disarm_icons : Array[TextureButton]
var disarm_buttons : Array[int]
var progress : int
var disarming : bool
var difficulty : int = 1
func _process(delta: float) -> void:
timer_label.text = "%02d.3" % timer.time_left
func start_disarming() -> void:
disarming = true
progress = 0
disarm_icons = []
disarm_buttons = []
for i in range(difficulty):
var btn = randi_range(0,3)
var icon : TextureButton = disarm_icon_template.instantiate()
icon.texture_normal = icon_textures[btn].normal
icon.texture_pressed = icon_textures[btn].pressed
disarm_buttons.append(btn)
disarm_icons.append(icon)
disarm_button_container.add_child(icon)
confirmation_dialog.visible = false
disarm_window.visible = true
timer.start(3 + (2 * len(disarm_buttons) * randf_range(.75, 1.25) ))
func try_advance(btn : int) -> void:
if btn == disarm_buttons[progress]:
disarm_icons[progress].set_pressed_no_signal(true)
progress += 1
if progress >= len(disarm_buttons):
Game.player.close_modal()
Game.oneshot(success_sound)
Game.level.disarm_trap(square)
else:
Game.oneshot(progress_sound)
else:
Game.player.close_modal()
Game.oneshot(fail_sound)
Game.level.activate_trap(square)
func button_pressed(event : InputEventAction) -> void:
if disarming:
try_advance(action_value[event.action])
else:
match(event.action):
"detonate":
start_disarming()
"attack":
Game.player.close_modal()
_: return
func _on_timer_timeout() -> void:
Game.player.close_modal()
Game.oneshot(fail_sound)
Game.level.activate_trap(square)

View File

@@ -0,0 +1 @@
uid://5nrsscwod1xg

8
scripts/one_shot.gd Normal file
View File

@@ -0,0 +1,8 @@
extends AudioStreamPlayer
func _ready() -> void:
$Timer.start(stream.get_length())
func _on_timeout() -> void:
queue_free()

1
scripts/one_shot.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://cb72nk0ddi3c

View File

@@ -1,13 +1,24 @@
class_name Player extends CharacterBody3D class_name Player extends CharacterBody3D
const trap_template = preload("res://templates/trap.tscn")
const remove_trap_modal = preload("res://templates/remove_trap_modal.tscn")
const disarm_trap_modal = preload("res://templates/disarm_trap_modal.tscn")
@export var speed : float = 10 @export var speed : float = 10
@onready var body = $Body @onready var body = $Body
@onready var data : PlayerData = $Data @onready var data : PlayerData = $Data
@onready var trap_sound : AudioStreamPlayer3D = $TrapSound
var button_actions : Dictionary[int, String]
var current_square : Vector3i var current_square : Vector3i
var detecting : bool var detecting : bool = false
var detect_squares : Dictionary[Vector3i, bool] = {} var detect_squares : Dictionary[Vector3i, bool] = {}
var input_locked : bool = false
var action_tween : Tween = null
var modal = null
signal trap_cycled(trap_index) signal trap_cycled(trap_index)
signal trap_quantity_changed(trap_index, quantity) signal trap_quantity_changed(trap_index, quantity)
signal trap_list_changed(traps) signal trap_list_changed(traps)
@@ -16,6 +27,8 @@ signal trap_list_changed(traps)
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
var dir = Input.get_vector("west", "east", "north", "south") var dir = Input.get_vector("west", "east", "north", "south")
dir = Vector3(dir.x, 0, dir.y) dir = Vector3(dir.x, 0, dir.y)
if input_locked or modal != null:
dir = Vector3.ZERO
if dir.length_squared() > 0: if dir.length_squared() > 0:
body.look_at(body.global_position - dir) body.look_at(body.global_position - dir)
velocity = speed * dir velocity = speed * dir
@@ -24,9 +37,28 @@ func _physics_process(delta: float) -> void:
if !is_on_floor(): if !is_on_floor():
velocity += get_gravity() velocity += get_gravity()
move_and_slide() move_and_slide()
elif !is_on_floor():
velocity = get_gravity()
move_and_slide()
if detecting: if detecting:
update_detecting() update_detecting()
if !input_locked:
if modal:
var evt = InputEventAction.new()
var buttons = [
"lay trap",
"detect",
"attack",
"detonate"
]
for button in buttons:
if Input.is_action_just_pressed(button):
evt.action = button
evt.pressed = true
modal.button_pressed(evt)
else:
if Input.is_action_just_pressed("left cycle trap"): if Input.is_action_just_pressed("left cycle trap"):
cycle_active_trap(-1) cycle_active_trap(-1)
if Input.is_action_just_pressed("right cycle trap"): if Input.is_action_just_pressed("right cycle trap"):
@@ -35,7 +67,40 @@ func _physics_process(delta: float) -> void:
start_detecting() start_detecting()
elif Input.is_action_just_released("detect"): elif Input.is_action_just_released("detect"):
stop_detecting() stop_detecting()
if !detecting and Input.is_action_just_pressed("lay trap"):
try_lay_trap()
func try_lay_trap() -> void:
if !is_on_floor():
return
if data.traps[data.active_trap].quantity < 1:
return
var square : Vector3i = (global_position - Vector3.ONE * .5).round()
if !Game.level.is_valid_trap_square(square):
return
action_tween = create_tween()
input_locked = true
action_tween.tween_interval(.2)
action_tween.tween_callback(Callable(lay_trap).bind(square, data.active_trap))
action_tween.tween_interval(.25)
action_tween.tween_callback(clear_action)
func lay_trap(square : Vector3i, idx : int) -> void:
var type : Trap.Type = data.traps[idx].type
var trap = trap_template.instantiate()
trap.setup(type, Multiplayer.id)
trap.disarmed.connect(_on_trap_disarmed)
data.traps[idx].quantity -= 1
trap_quantity_changed.emit(idx, data.traps[idx].quantity)
Game.level.add_trap(trap, square)
trap_sound.play()
func clear_action() -> void:
input_locked = false
action_tween = null
func update_detecting() -> void: func update_detecting() -> void:
var new_square : Vector3i = (global_position - Vector3.ONE * .5).round() var new_square : Vector3i = (global_position - Vector3.ONE * .5).round()
@@ -68,9 +133,30 @@ func update_detecting() -> void:
for key in remove_list: for key in remove_list:
detect_squares.erase(key) detect_squares.erase(key)
var trap : Trap = Game.level.get_square_trap(current_square)
if trap != null:
if trap.trap_owner == Multiplayer.id:
show_remove_trap_modal()
else:
show_disarm_trap_modal()
func close_modal() -> void:
modal.queue_free()
modal = null
func show_remove_trap_modal() -> void:
stop_detecting()
modal = remove_trap_modal.instantiate()
modal.square = current_square
Game.level.add_child(modal)
func show_disarm_trap_modal() -> void:
stop_detecting()
modal = disarm_trap_modal.instantiate()
modal.difficulty = Game.level.difficulty
modal.square = current_square
Game.level.add_child(modal)
func start_detecting() -> void: func start_detecting() -> void:
detecting = true detecting = true
@@ -92,6 +178,10 @@ func start_detecting() -> void:
for key in remove_list: for key in remove_list:
detect_squares.erase(key) detect_squares.erase(key)
var trap : Trap = Game.level.get_square_trap(current_square)
if trap != null:
if trap.trap_owner == Multiplayer.id:
show_remove_trap_modal()
func stop_detecting() -> void: func stop_detecting() -> void:
detecting = false detecting = false
@@ -103,6 +193,17 @@ func setup(traps) -> void:
$Data.traps = traps $Data.traps = traps
Game.setup_player(self) Game.setup_player(self)
func remove_trap_at(square) -> void:
var trap : Trap = Game.level.traps[square]
for i in range(len(data.traps)):
var d = data.traps[i]
if d.type == trap.type:
d.quantity += 1
trap_quantity_changed.emit(i, d.quantity)
break
trap.queue_free()
Game.level.traps.erase(square)
func cycle_active_trap(dir) -> void: func cycle_active_trap(dir) -> void:
var prev = data.active_trap var prev = data.active_trap
data.active_trap += dir data.active_trap += dir
@@ -114,3 +215,11 @@ func cycle_active_trap(dir) -> void:
if prev != data.active_trap: if prev != data.active_trap:
trap_cycled.emit(data.active_trap) trap_cycled.emit(data.active_trap)
func _on_trap_disarmed(type : Trap.Type) -> void:
for i in range(len(data.traps)):
var d = data.traps[i]
if d.type == type:
d.max -= 1
trap_quantity_changed.emit(i, d.quantity)
break

View File

@@ -1,11 +1,11 @@
class_name PlayerData extends Node class_name PlayerData extends Node
class TrapData: class TrapData:
var type : Game.TrapType var type : Trap.Type
var quantity : int var quantity : int
var max : int var max : int
func _init(type : Game.TrapType, quantity : int, max : int) -> void: func _init(type : Trap.Type, quantity : int, max : int) -> void:
self.type = type self.type = type
self.quantity = quantity self.quantity = quantity
self.max = max self.max = max

View File

@@ -0,0 +1,12 @@
class_name RemoveTrapModal extends ConfirmationDialog
var square : Vector3i
func button_pressed(event : InputEventAction) -> void:
match(event.action):
"detonate":
Game.player.remove_trap_at(square)
Game.player.close_modal()
"attack":
Game.player.close_modal()
_: return

View File

@@ -0,0 +1 @@
uid://bj1udbw3sm73f

View File

@@ -1,26 +1,71 @@
class_name Level extends Node3D class_name Level extends Node3D
const player_controller = preload("res://templates/singleplayer_pc.tscn") const player_controller = preload("res://templates/singleplayer_pc.tscn")
const trap_template = preload("res://templates/trap.tscn")
@onready var floor_layer : GridMap = %Floor @onready var floor_layer : GridMap = %Floor
@onready var marker_layer : GridMap = %Markers @onready var marker_layer : GridMap = %Markers
@export var difficulty : int = 1
var traps : Dictionary[Vector3i, Trap] = {}
func _ready() -> void:
Game.level = self
var player = player_controller.instantiate()
var traps : Array[PlayerData.TrapData] = [
PlayerData.TrapData.new(Trap.Type.BOMB, 3, 3),
PlayerData.TrapData.new(Trap.Type.SWITCH, 3, 3),
PlayerData.TrapData.new(Trap.Type.MINE, 3, 3)
]
add_child(player)
generate_trap(Trap.Type.MINE, Vector3i(5,0,2))
player.setup(traps)
func is_square_detected(crd) -> bool:
return marker_layer.get_cell_item(crd + Vector3i(0,-1,0)) != GridMap.INVALID_CELL_ITEM
func detect_square(crd : Vector3i, mark : bool) -> bool: func detect_square(crd : Vector3i, mark : bool) -> bool:
var cell = floor_layer.get_cell_item(crd) var cell = floor_layer.get_cell_item(crd)
if cell == GridMap.INVALID_CELL_ITEM: if cell == GridMap.INVALID_CELL_ITEM:
return false return false
marker_layer.set_cell_item(crd, 0 if mark else GridMap.INVALID_CELL_ITEM) marker_layer.set_cell_item(crd, 0 if mark else GridMap.INVALID_CELL_ITEM)
if mark:
var trap_crd = crd + Vector3i(0,1,0)
if traps.has(trap_crd):
var trap : Trap = traps[trap_crd]
if trap.trap_owner != Multiplayer.id:
trap.reveal()
return true
func add_trap(trap : Trap, crd : Vector3i) -> void:
trap.square = crd
traps[crd] = trap
trap.global_position = Vector3(crd) + Vector3(.5, 0, .5)
add_child(trap)
pass
func get_square_trap(crd : Vector3i) -> Trap:
if traps.has(crd):
return traps[crd]
else:
return null
func is_valid_trap_square(crd : Vector3i) -> bool:
if floor_layer.get_cell_item(crd + Vector3i(0,-1,0)) == GridMap.INVALID_CELL_ITEM:
return false
if traps.has(crd):
return false
return true return true
func _ready() -> void: func generate_trap(type : Trap.Type, square : Vector3i):
Game.level = self var trap = trap_template.instantiate()
var player = player_controller.instantiate() trap.setup(type, -1)
var traps : Array[PlayerData.TrapData] = [ add_trap(trap, square)
PlayerData.TrapData.new(Game.TrapType.BOMB, 3, 3),
PlayerData.TrapData.new(Game.TrapType.SWITCH, 3, 3), func disarm_trap(crd : Vector3i) -> void:
PlayerData.TrapData.new(Game.TrapType.MINE, 3, 3) var trap = traps[crd]
] trap.disarm()
add_child(player) traps.erase(crd)
player.setup(traps)

54
scripts/trap.gd Normal file
View File

@@ -0,0 +1,54 @@
class_name Trap extends Area3D
enum Type{
BOMB,
MINE,
GAS,
FORCE_PANEL,
SWITCH,
PITFALL
}
const trap_icons : Dictionary = {
Trap.Type.BOMB : preload("res://visuals/images/icons/t-bomb.png"),
Trap.Type.GAS : preload("res://visuals/images/icons/t-gas.png"),
Trap.Type.PITFALL : preload("res://visuals/images/icons/t-pitfall.png"),
Trap.Type.FORCE_PANEL : preload("res://visuals/images/icons/t-force_panel.png"),
Trap.Type.SWITCH : preload("res://visuals/images/icons/t-switch.png"),
Trap.Type.MINE : preload("res://visuals/images/icons/t-mine.png"),
}
@onready var model : MeshInstance3D = %Model
@onready var icon : Sprite3D = %Icon
@onready var material : StandardMaterial3D = model.get_surface_override_material(0)
@onready var reveal_timer : Timer = %RevealTimer
var type : Type
var square : Vector3i
var trap_owner : int
signal disarmed(type : Trap.Type)
func setup(type : Type, trap_owner : int) -> void:
self.type = type
self.trap_owner = trap_owner
func disarm() -> void:
disarmed.emit(type)
queue_free()
func reveal() -> void:
model.visible = true
reveal_timer.start(5)
func _on_reveal_timeout() -> void:
if Game.level.is_square_detected(square):
reveal_timer.start(5)
else:
model.visible = false
func _ready() -> void:
var owns_trap = trap_owner == Multiplayer.id
icon.texture = trap_icons[type]
model.visible = owns_trap
icon.visible = owns_trap
material.albedo_color = Color.YELLOW if owns_trap else Color.RED

1
scripts/trap.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://yjsgte3x7jjw

View File

@@ -1,18 +1,18 @@
class_name TrapIcon extends Control class_name TrapIcon extends Control
const trap_icons : Dictionary = { const trap_icons : Dictionary = {
Game.TrapType.BOMB : preload("res://visuals/images/icons/bomb.png"), Trap.Type.BOMB : preload("res://visuals/images/icons/bomb.png"),
Game.TrapType.GAS : preload("res://visuals/images/icons/gas.png"), Trap.Type.GAS : preload("res://visuals/images/icons/gas.png"),
Game.TrapType.PITFALL : preload("res://visuals/images/icons/pitfall.png"), Trap.Type.PITFALL : preload("res://visuals/images/icons/pitfall.png"),
Game.TrapType.FORCE_PANEL : preload("res://visuals/images/icons/force_panel.png"), Trap.Type.FORCE_PANEL : preload("res://visuals/images/icons/force_panel.png"),
Game.TrapType.SWITCH : preload("res://visuals/images/icons/switch.png"), Trap.Type.SWITCH : preload("res://visuals/images/icons/switch.png"),
Game.TrapType.MINE : preload("res://visuals/images/icons/mine.png"), Trap.Type.MINE : preload("res://visuals/images/icons/mine.png"),
} }
@onready var icon_image : TextureRect = %Icon @onready var icon_image : TextureRect = %Icon
@onready var qty_label : Label = %Label @onready var qty_label : Label = %Label
func setup(type : Game.TrapType, qty : int) -> void: func setup(type : Trap.Type, qty : int) -> void:
icon_image.texture = trap_icons[type] icon_image.texture = trap_icons[type]
set_quantity(qty) set_quantity(qty)

View File

@@ -0,0 +1,11 @@
[gd_scene load_steps=3 format=3 uid="uid://c5ienwpgidanx"]
[ext_resource type="Texture2D" uid="uid://bxs0jj4y4clvv" path="res://visuals/images/icons/detect button.png" id="1_tmc0a"]
[ext_resource type="Texture2D" uid="uid://bxxm3c2lpmr4f" path="res://visuals/images/icons/lit detect button.png" id="2_75gk1"]
[node name="DisarmIcon" type="TextureButton"]
custom_minimum_size = Vector2(32, 32)
texture_normal = ExtResource("1_tmc0a")
texture_pressed = ExtResource("2_75gk1")
ignore_texture_size = true
stretch_mode = 0

View File

@@ -0,0 +1,110 @@
[gd_scene load_steps=4 format=3 uid="uid://v12wymuy2xk6"]
[ext_resource type="Script" uid="uid://5nrsscwod1xg" path="res://scripts/disarm_trap_modal.gd" id="1_eo0gq"]
[ext_resource type="Texture2D" uid="uid://barbcaa2xvgkk" path="res://visuals/images/icons/switch button.png" id="2_cgabh"]
[ext_resource type="Texture2D" uid="uid://diyks5oxgidoo" path="res://visuals/images/icons/ranged attack button.png" id="3_06srb"]
[node name="DisarmTrapModal" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_eo0gq")
[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
unique_name_in_owner = true
oversampling_override = 1.0
initial_position = 1
visible = true
transient = false
borderless = true
always_on_top = true
unfocusable = true
ok_button_text = "Disarm"
dialog_text = "Disarm Trap?"
[node name="Control" type="Control" parent="ConfirmationDialog"]
layout_mode = 3
anchors_preset = 0
offset_left = 8.0
offset_top = 8.0
offset_right = 192.0
offset_bottom = 51.0
[node name="TextureRect" type="TextureRect" parent="ConfirmationDialog/Control"]
z_index = 10
layout_mode = 0
offset_left = 36.0
offset_top = 29.0
offset_right = 68.0
offset_bottom = 61.0
texture = ExtResource("2_cgabh")
expand_mode = 1
[node name="TextureRect2" type="TextureRect" parent="ConfirmationDialog/Control"]
z_index = 10
layout_mode = 0
offset_left = 120.0
offset_top = 29.0
offset_right = 152.0
offset_bottom = 61.0
texture = ExtResource("3_06srb")
expand_mode = 1
[node name="Timer" type="Timer" parent="."]
unique_name_in_owner = true
[node name="DisarmSound" type="AudioStreamPlayer" parent="."]
[node name="SuccessSound" type="AudioStreamPlayer" parent="."]
[node name="AudioStreamPlayer3" type="AudioStreamPlayer" parent="."]
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="DisarmWindow" type="PanelContainer" parent="CanvasLayer"]
unique_name_in_owner = true
visible = false
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -96.0
offset_top = -56.0
offset_right = 96.0
offset_bottom = 56.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/DisarmWindow"]
layout_mode = 2
alignment = 1
[node name="PressToDisarmHeader" type="Label" parent="CanvasLayer/DisarmWindow/VBoxContainer"]
layout_mode = 2
text = "PRESS TO DISARM"
horizontal_alignment = 1
[node name="Panel" type="PanelContainer" parent="CanvasLayer/DisarmWindow/VBoxContainer"]
layout_mode = 2
[node name="DisarmContainer" type="HBoxContainer" parent="CanvasLayer/DisarmWindow/VBoxContainer/Panel"]
unique_name_in_owner = true
layout_mode = 2
alignment = 1
[node name="TimeRemainingLabel" type="Label" parent="CanvasLayer/DisarmWindow/VBoxContainer"]
layout_mode = 2
text = "TIME REMAINING: "
horizontal_alignment = 1
[node name="TimerLabel" type="Label" parent="CanvasLayer/DisarmWindow/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "00.000"
horizontal_alignment = 1
[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]

10
templates/one_shot.tscn Normal file
View File

@@ -0,0 +1,10 @@
[gd_scene load_steps=2 format=3 uid="uid://cmw77i7e7jxkn"]
[ext_resource type="Script" uid="uid://cb72nk0ddi3c" path="res://scripts/one_shot.gd" id="1_k1ss2"]
[node name="OneShot" type="AudioStreamPlayer"]
script = ExtResource("1_k1ss2")
[node name="Timer" type="Timer" parent="."]
[connection signal="timeout" from="Timer" to="." method="_on_timeout"]

View File

@@ -0,0 +1,51 @@
[gd_scene load_steps=4 format=3 uid="uid://bwj76wt4pab4t"]
[ext_resource type="Script" uid="uid://bj1udbw3sm73f" path="res://scripts/remove_trap_modal.gd" id="1_27jge"]
[ext_resource type="Texture2D" uid="uid://barbcaa2xvgkk" path="res://visuals/images/icons/switch button.png" id="2_dmpk7"]
[ext_resource type="Texture2D" uid="uid://diyks5oxgidoo" path="res://visuals/images/icons/ranged attack button.png" id="3_42gya"]
[node name="RemoveTrapModal" type="ConfirmationDialog"]
handle_input_locally = false
canvas_item_default_texture_filter = 2
gui_disable_input = true
oversampling_override = 1.0
title = "Remove Trap?"
initial_position = 1
visible = true
transient = false
borderless = true
always_on_top = true
unfocusable = true
content_scale_mode = 1
content_scale_aspect = 2
ok_button_text = "Remove"
dialog_text = "Remove Trap?"
script = ExtResource("1_27jge")
[node name="Control" type="Control" parent="."]
layout_mode = 3
anchors_preset = 0
offset_left = 8.0
offset_top = 8.0
offset_right = 192.0
offset_bottom = 51.0
[node name="TextureRect" type="TextureRect" parent="Control"]
z_index = 10
layout_mode = 0
offset_left = 36.0
offset_top = 29.0
offset_right = 68.0
offset_bottom = 61.0
texture = ExtResource("2_dmpk7")
expand_mode = 1
[node name="TextureRect2" type="TextureRect" parent="Control"]
z_index = 10
layout_mode = 0
offset_left = 120.0
offset_top = 29.0
offset_right = 152.0
offset_bottom = 61.0
texture = ExtResource("3_42gya")
expand_mode = 1

View File

@@ -1,7 +1,8 @@
[gd_scene load_steps=6 format=3 uid="uid://c8xf3qawk5c6u"] [gd_scene load_steps=7 format=3 uid="uid://c8xf3qawk5c6u"]
[ext_resource type="Script" uid="uid://bcs7ygh6s3l35" path="res://scripts/player.gd" id="1_a5wj7"] [ext_resource type="Script" uid="uid://bcs7ygh6s3l35" path="res://scripts/player.gd" id="1_a5wj7"]
[ext_resource type="Script" uid="uid://6w608y2grdqb" path="res://scripts/player_data.gd" id="2_sfa2f"] [ext_resource type="Script" uid="uid://6w608y2grdqb" path="res://scripts/player_data.gd" id="2_sfa2f"]
[ext_resource type="AudioStream" uid="uid://cjrlb4qiy23sj" path="res://audio/sounds/impact_deep_thud_bounce_09.wav" id="3_sfa2f"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_y646j"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_y646j"]
albedo_color = Color(0.08468992, 0.08468992, 0.08468992, 1) albedo_color = Color(0.08468992, 0.08468992, 0.08468992, 1)
@@ -38,3 +39,9 @@ shape = SubResource("CapsuleShape3D_a5wj7")
[node name="Data" type="Node" parent="."] [node name="Data" type="Node" parent="."]
script = ExtResource("2_sfa2f") script = ExtResource("2_sfa2f")
[node name="TrapSound" type="AudioStreamPlayer3D" parent="."]
stream = ExtResource("3_sfa2f")
[node name="AudioListener3D" type="AudioListener3D" parent="."]
current = true

43
templates/trap.tscn Normal file
View File

@@ -0,0 +1,43 @@
[gd_scene load_steps=7 format=3 uid="uid://bk3yqawritfnj"]
[ext_resource type="Script" uid="uid://yjsgte3x7jjw" path="res://scripts/trap.gd" id="1_6h4aj"]
[ext_resource type="ArrayMesh" uid="uid://bih57xe642hrc" path="res://models/trap.obj" id="2_oj6ox"]
[ext_resource type="Texture2D" uid="uid://cmlp8tn6mnbd" path="res://visuals/images/icons/t-bomb.png" id="3_mxvh5"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_qcd3b"]
albedo_color = Color(0, 0, 1, 1)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_88ety"]
resource_local_to_scene = true
albedo_color = Color(1, 1, 0, 1)
[sub_resource type="BoxShape3D" id="BoxShape3D_dw7u0"]
size = Vector3(0.8, 1, 0.8)
[node name="Trap" type="Area3D"]
script = ExtResource("1_6h4aj")
[node name="Model" type="MeshInstance3D" parent="."]
unique_name_in_owner = true
transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, 0, 0, 0)
material_overlay = SubResource("StandardMaterial3D_qcd3b")
mesh = ExtResource("2_oj6ox")
skeleton = NodePath("")
surface_material_override/0 = SubResource("StandardMaterial3D_88ety")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
shape = SubResource("BoxShape3D_dw7u0")
[node name="Icon" type="Sprite3D" parent="."]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
pixel_size = 0.0075
axis = 1
double_sided = false
texture = ExtResource("3_mxvh5")
[node name="RevealTimer" type="Timer" parent="."]
unique_name_in_owner = true
[connection signal="timeout" from="RevealTimer" to="." method="_on_reveal_timeout"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cmlp8tn6mnbd"
path.s3tc="res://.godot/imported/t-bomb.png-b0fba279e3e15cee1114dff95868ac2c.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://visuals/images/icons/t-bomb.png"
dest_files=["res://.godot/imported/t-bomb.png-b0fba279e3e15cee1114dff95868ac2c.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dxbdj3448tcse"
path="res://.godot/imported/t-force_panel.png-8187f2672c6b23f490483f18d6c18d70.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://visuals/images/icons/t-force_panel.png"
dest_files=["res://.godot/imported/t-force_panel.png-8187f2672c6b23f490483f18d6c18d70.ctex"]
[params]
compress/mode=0
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=false
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=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://r7grey8tumrp"
path="res://.godot/imported/t-gas.png-110c34a22ea1a82475e91c8498c0628f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://visuals/images/icons/t-gas.png"
dest_files=["res://.godot/imported/t-gas.png-110c34a22ea1a82475e91c8498c0628f.ctex"]
[params]
compress/mode=0
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=false
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=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://r1c5q74q4n12"
path="res://.godot/imported/t-mine.png-93926d001ee567f1ac6b631b1f6bea15.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://visuals/images/icons/t-mine.png"
dest_files=["res://.godot/imported/t-mine.png-93926d001ee567f1ac6b631b1f6bea15.ctex"]
[params]
compress/mode=0
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=false
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=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d3rydevalb47q"
path="res://.godot/imported/t-pitfall.png-b517735d43c995be7bbcb62b2f335337.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://visuals/images/icons/t-pitfall.png"
dest_files=["res://.godot/imported/t-pitfall.png-b517735d43c995be7bbcb62b2f335337.ctex"]
[params]
compress/mode=0
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=false
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=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bvfb6ntwfwopc"
path="res://.godot/imported/t-switch.png-e4dbb8ba88d48cbefbc08280c0c6cbe2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://visuals/images/icons/t-switch.png"
dest_files=["res://.godot/imported/t-switch.png-e4dbb8ba88d48cbefbc08280c0c6cbe2.ctex"]
[params]
compress/mode=0
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=false
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=1