226 lines
5.8 KiB
GDScript
226 lines
5.8 KiB
GDScript
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
|
|
@onready var body = $Body
|
|
@onready var data : PlayerData = $Data
|
|
@onready var trap_sound : AudioStreamPlayer3D = $TrapSound
|
|
|
|
var button_actions : Dictionary[int, String]
|
|
var current_square : Vector3i
|
|
var detecting : bool = false
|
|
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_quantity_changed(trap_index, quantity)
|
|
signal trap_list_changed(traps)
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
var dir = Input.get_vector("west", "east", "north", "south")
|
|
dir = Vector3(dir.x, 0, dir.y)
|
|
if input_locked or modal != null:
|
|
dir = Vector3.ZERO
|
|
if dir.length_squared() > 0:
|
|
body.look_at(body.global_position - dir)
|
|
velocity = speed * dir
|
|
if detecting:
|
|
velocity /= 3
|
|
if !is_on_floor():
|
|
velocity += get_gravity()
|
|
move_and_slide()
|
|
elif !is_on_floor():
|
|
velocity = get_gravity()
|
|
move_and_slide()
|
|
|
|
if 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"):
|
|
cycle_active_trap(-1)
|
|
if Input.is_action_just_pressed("right cycle trap"):
|
|
cycle_active_trap(1)
|
|
if Input.is_action_just_pressed("detect"):
|
|
start_detecting()
|
|
elif Input.is_action_just_released("detect"):
|
|
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:
|
|
var new_square : Vector3i = (global_position - Vector3.ONE * .5).round()
|
|
if new_square == current_square:
|
|
return
|
|
current_square = new_square
|
|
var new_squares : Dictionary[Vector3i, bool] = {}
|
|
for i in range(-2, 3):
|
|
for j in range(-2, 3):
|
|
for k in range(-2, 2):
|
|
if abs(i) + abs(j) < 3:
|
|
var sq = current_square + Vector3i(i, k, j)
|
|
new_squares[sq] = true
|
|
|
|
|
|
for sq in detect_squares.keys():
|
|
if !new_squares.has(sq):
|
|
Game.level.detect_square(sq, false)
|
|
|
|
|
|
|
|
var remove_list = []
|
|
for sq in new_squares.keys():
|
|
if detect_squares.has(sq):
|
|
continue
|
|
if !Game.level.detect_square(sq, true):
|
|
remove_list.append(sq)
|
|
|
|
detect_squares = new_squares
|
|
for key in remove_list:
|
|
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:
|
|
detecting = true
|
|
current_square = (global_position - Vector3.ONE * .5).round()
|
|
detect_squares = {}
|
|
for i in range(-2, 3):
|
|
for j in range(-2, 3):
|
|
for k in range(-2, 2):
|
|
if abs(i) + abs(j) < 3:
|
|
var sq = current_square + Vector3i(i, k, j)
|
|
detect_squares[sq] = true
|
|
|
|
var remove_list = []
|
|
|
|
for sq in detect_squares.keys():
|
|
if !Game.level.detect_square(sq, true):
|
|
remove_list.append(sq)
|
|
|
|
for key in remove_list:
|
|
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:
|
|
detecting = false
|
|
for sq in detect_squares.keys():
|
|
Game.level.detect_square(sq, false)
|
|
detect_squares = {}
|
|
|
|
func setup(traps) -> void:
|
|
$Data.traps = traps
|
|
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:
|
|
var prev = data.active_trap
|
|
data.active_trap += dir
|
|
if data.active_trap < 0:
|
|
data.active_trap = 0
|
|
|
|
if data.active_trap >= len(data.traps):
|
|
data.active_trap = len(data.traps) - 1
|
|
|
|
if prev != 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
|