Extensive work on virtually all of the visuals and the net code
This commit is contained in:
@@ -10,9 +10,9 @@ enum Modes{
|
||||
const blinder_template = preload("res://templates/blinder.tscn")
|
||||
const one_shot_template = preload("res://templates/one_shot.tscn")
|
||||
|
||||
const story_level = preload("res://scenes/test_level.tscn")
|
||||
const story_level = preload("res://scenes/manufactory.tscn")
|
||||
const vs_com_level = preload("res://scenes/test_level.tscn")
|
||||
const vs_man_level = preload("res://scenes/test_level.tscn")
|
||||
const vs_man_level = preload("res://scenes/manufactory.tscn")
|
||||
const pawn_select_scene = preload("res://scenes/character_select.tscn")
|
||||
|
||||
var player : PawnController
|
||||
|
||||
@@ -19,7 +19,7 @@ func become_host() -> void:
|
||||
func(error_msg):
|
||||
push_error("NodeTunnel Error: ", error_msg)
|
||||
)
|
||||
server_peer.connect_to_relay("us_east.nodetunnel.io:8080", "1dl00j5zgo2uxk0")
|
||||
server_peer.connect_to_relay("74.208.202.81:8080", "net-gunner")
|
||||
multiplayer.multiplayer_peer = server_peer
|
||||
print("Authenticating")
|
||||
await server_peer.authenticated
|
||||
@@ -35,10 +35,10 @@ func become_host() -> void:
|
||||
var room_id = await server_peer.room_connected
|
||||
print("Connected to room: ", server_peer.room_id)
|
||||
server_peer.get_rooms()
|
||||
print("GETTING ROOMS!")
|
||||
var rooms = await server_peer.rooms_received
|
||||
for r in rooms:
|
||||
var meta = JSON.parse_string(r.metadata)
|
||||
#can now use meta.players, meta.name, meta.password_req, etc.
|
||||
print("GOT ROOMS!")
|
||||
print(rooms)
|
||||
players[handle] = 1
|
||||
player_readiness[1] = false
|
||||
|
||||
@@ -48,13 +48,23 @@ func become_host() -> void:
|
||||
multiplayer.peer_disconnected.connect(_remove_player_from_game)
|
||||
|
||||
|
||||
func join_game(new_handle : String, ip : String = "") -> Error:
|
||||
print("Player 2 joining.")
|
||||
if ip == "":
|
||||
ip = SERVER_IP
|
||||
var client_peer = ENetMultiplayerPeer.new()
|
||||
var error = client_peer.create_client(ip, SERVER_PORT)
|
||||
func join_game(new_handle : String, room : String = "") -> Error:
|
||||
var client_peer = NodeTunnelPeer.new()
|
||||
client_peer.error.connect(
|
||||
func(error_msg):
|
||||
push_error("NodeTunnel Error: ", error_msg)
|
||||
)
|
||||
client_peer.connect_to_relay("74.208.202.81:8080", "net-gunner")
|
||||
multiplayer.multiplayer_peer = client_peer
|
||||
print("Authenticating")
|
||||
await client_peer.authenticated
|
||||
print("Authenticated")
|
||||
|
||||
|
||||
var error = client_peer.join_room(room)
|
||||
print("Player 2 joining room :", room)
|
||||
await client_peer.room_connected
|
||||
print("Player 2 joined.")
|
||||
handle = new_handle
|
||||
id = multiplayer.get_unique_id()
|
||||
players[handle] = id
|
||||
|
||||
@@ -117,7 +117,7 @@ func change_display(player : int, selection: int) -> void:
|
||||
var pd : PawnDisplay = displays[player]
|
||||
pd.set_pawn_name(pawns[selection].name)
|
||||
pd.set_portrait(pawns[selection].portrait)
|
||||
pd.set_traps(pawns[selection].starting_traps)
|
||||
pd.set_hacks(pawns[selection].starting_hacks)
|
||||
|
||||
|
||||
func _on_selector_start_child_entered_tree(node: Node) -> void:
|
||||
|
||||
@@ -2,7 +2,7 @@ class_name ControlDisplay extends Control
|
||||
|
||||
@onready var range_attack_button : TextureButton = $RangedAttack
|
||||
@onready var melee_attack_button : TextureButton = $MeleeAttack
|
||||
@onready var trap_button : TextureButton = $Trap
|
||||
@onready var hack_button : TextureButton = $Hack
|
||||
@onready var detect_button : TextureButton = $Detect
|
||||
@onready var switch_button : TextureButton = $Switch
|
||||
|
||||
@@ -11,7 +11,7 @@ func _on_melee_range_changed(melee : bool) -> void:
|
||||
melee_attack_button.visible = melee
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
trap_button.set_pressed_no_signal(Input.is_action_pressed("lay trap"))
|
||||
hack_button.set_pressed_no_signal(Input.is_action_pressed("install"))
|
||||
detect_button.set_pressed_no_signal(Input.is_action_pressed("detect"))
|
||||
switch_button.set_pressed_no_signal(Input.is_action_pressed("detonate"))
|
||||
melee_attack_button.set_pressed_no_signal(Input.is_action_pressed("attack"))
|
||||
|
||||
@@ -2,6 +2,6 @@ extends TextureRect
|
||||
|
||||
@onready var qty_label : Label = $Label
|
||||
|
||||
func setup(type : Trap.Type, qty : int) -> void:
|
||||
texture = Trap.trap_icons[type]
|
||||
func setup(type : Hack.Type, qty : int) -> void:
|
||||
texture = Hack.hack_icons[type]
|
||||
qty_label.text = str(qty)
|
||||
@@ -1,9 +1,9 @@
|
||||
class_name DisarmTrapModal extends Control
|
||||
class_name DecompileHackModal extends Control
|
||||
|
||||
|
||||
const action_value : Dictionary[String, int] = {
|
||||
"detonate" : 0,
|
||||
"lay trap" : 1,
|
||||
"install" : 1,
|
||||
"detect" : 2,
|
||||
"attack" : 3
|
||||
}
|
||||
@@ -14,8 +14,8 @@ const icon_textures : Array = [
|
||||
"pressed" : preload("res://visuals/images/icons/button-detonate-hit.png")
|
||||
},
|
||||
{
|
||||
"normal" : preload("res://visuals/images/icons/button-trap.png"),
|
||||
"pressed" : preload("res://visuals/images/icons/button-trap-hit.png")
|
||||
"normal" : preload("res://visuals/images/icons/button-hack.png"),
|
||||
"pressed" : preload("res://visuals/images/icons/button-hack-hit.png")
|
||||
},
|
||||
{
|
||||
"normal" : preload("res://visuals/images/icons/button-detect.png"),
|
||||
@@ -27,52 +27,52 @@ const icon_textures : Array = [
|
||||
},
|
||||
]
|
||||
|
||||
const disarm_icon_template = preload("res://templates/disarm_icon.tscn")
|
||||
const decompile_icon_template = preload("res://templates/decompile_icon.tscn")
|
||||
const success_sound = preload("res://audio/sounds/TomWinandySFX_UI_ScifiTech_Notification_13.wav")
|
||||
const fail_sound = preload("res://audio/sounds/TomWinandySFX_UI_ScifiTech_Cancel_05.wav")
|
||||
const progress_sound = preload("res://audio/sounds/metal_tiny_hit_impact_01.wav")
|
||||
|
||||
@onready var confirmation_dialog : ConfirmationDialog = %ConfirmationDialog
|
||||
@onready var disarm_window : PanelContainer = %DisarmWindow
|
||||
@onready var disarm_button_container : HBoxContainer = %DisarmContainer
|
||||
@onready var decompile_window : PanelContainer = %DecompileWindow
|
||||
@onready var decompile_button_container : HBoxContainer = %DecompileContainer
|
||||
@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 decompile_icons : Array[TextureButton]
|
||||
var decompile_buttons : Array[int]
|
||||
var progress : int
|
||||
var disarming : bool
|
||||
var decompiling : bool
|
||||
var failed : bool
|
||||
var difficulty : int = 1
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
timer_label.text = "%02f.3" % timer.time_left
|
||||
|
||||
func start_disarming() -> void:
|
||||
disarming = true
|
||||
func start_decompiling() -> void:
|
||||
decompiling = true
|
||||
progress = 0
|
||||
disarm_icons = []
|
||||
disarm_buttons = []
|
||||
decompile_icons = []
|
||||
decompile_buttons = []
|
||||
for i in range(Game.level.difficulty):
|
||||
var btn = randi_range(0,3)
|
||||
var icon : TextureButton = disarm_icon_template.instantiate()
|
||||
var icon : TextureButton = decompile_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)
|
||||
decompile_buttons.append(btn)
|
||||
decompile_icons.append(icon)
|
||||
decompile_button_container.add_child(icon)
|
||||
confirmation_dialog.visible = false
|
||||
disarm_window.visible = true
|
||||
timer.start(2 + (len(disarm_buttons) * randf_range(.75, 1.25) ))
|
||||
decompile_window.visible = true
|
||||
timer.start(2 + (len(decompile_buttons) * randf_range(.75, 1.25) ))
|
||||
|
||||
func try_advance(btn : int) -> void:
|
||||
|
||||
if btn == disarm_buttons[progress]:
|
||||
disarm_icons[progress].button_pressed = true
|
||||
if btn == decompile_buttons[progress]:
|
||||
decompile_icons[progress].button_pressed = true
|
||||
progress += 1
|
||||
if progress >= len(disarm_buttons):
|
||||
if progress >= len(decompile_buttons):
|
||||
succeed()
|
||||
else:
|
||||
Game.oneshot(progress_sound)
|
||||
@@ -80,16 +80,16 @@ func try_advance(btn : int) -> void:
|
||||
fail()
|
||||
|
||||
|
||||
func button_pressed(event : InputEventAction) -> void:
|
||||
if disarming:
|
||||
try_advance(action_value[event.action])
|
||||
func button_pressed(event : String) -> void:
|
||||
if decompiling:
|
||||
try_advance(action_value[event])
|
||||
else:
|
||||
match(event.action):
|
||||
match(event):
|
||||
"detonate":
|
||||
start_disarming()
|
||||
start_decompiling()
|
||||
"attack":
|
||||
var trap = Game.level.get_square_trap(square)
|
||||
trap.disarming = false
|
||||
var hack = Game.level.get_square_hack(square)
|
||||
hack.decompiling = false
|
||||
Game.player.close_modal()
|
||||
_: return
|
||||
|
||||
@@ -99,15 +99,15 @@ func fail() -> void:
|
||||
failed = true
|
||||
Game.player.close_modal()
|
||||
Game.oneshot(fail_sound)
|
||||
Game.level.activate_trap(square)
|
||||
Game.level.activate_hack(square)
|
||||
|
||||
func succeed() -> void:
|
||||
Game.player.close_modal()
|
||||
Game.oneshot(success_sound)
|
||||
Game.level.disarm_trap(square)
|
||||
Game.level.decompile_hack(square)
|
||||
|
||||
func _on_trap_failed() -> void:
|
||||
func _on_hack_failed() -> void:
|
||||
fail()
|
||||
|
||||
func _on_trap_removed(type : Trap.Type) -> void:
|
||||
func _on_hack_removed(type : Hack.Type) -> void:
|
||||
Game.player.close_modal()
|
||||
@@ -5,7 +5,7 @@ var cycles : int = 3
|
||||
var square : Vector3i = Vector3i(2,0,0)
|
||||
var squares : Dictionary[Vector3i, bool] = {}
|
||||
var last_spread : Array[Vector3i]
|
||||
var trap_owner : int
|
||||
var hack_owner : int
|
||||
var damage : int = 4
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -42,5 +42,5 @@ func spread() -> void:
|
||||
|
||||
func emit_gas(square) -> void:
|
||||
var gas = gas_square_template.instantiate()
|
||||
gas.setup(trap_owner, damage)
|
||||
gas.setup(hack_owner, damage)
|
||||
Game.level.add_vfx(gas, square)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
extends Area3D
|
||||
|
||||
@onready var particles : GPUParticles3D = %ParticleFX
|
||||
var trap_owner : int
|
||||
var hack_owner : int
|
||||
var damage : int
|
||||
var time_remaining : float
|
||||
|
||||
@@ -17,7 +17,7 @@ func _physics_process(delta: float) -> void:
|
||||
queue_free()
|
||||
|
||||
func setup(owner, damage) -> void:
|
||||
self.trap_owner = trap_owner
|
||||
self.hack_owner = hack_owner
|
||||
self.damage = damage
|
||||
time_remaining = 2.0
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class_name Trap extends Area3D
|
||||
class_name Hack extends Area3D
|
||||
|
||||
enum Type{
|
||||
BOMB,
|
||||
@@ -10,20 +10,20 @@ enum Type{
|
||||
}
|
||||
|
||||
const range_shapes : Dictionary = {
|
||||
Trap.Type.BOMB : Vector3(5,1,5),
|
||||
Trap.Type.GAS : Vector3(1,1,1),
|
||||
Trap.Type.PITFALL : Vector3(1,1,1),
|
||||
Trap.Type.FORCE_PANEL : Vector3(1,1,1),
|
||||
Trap.Type.SWITCH : Vector3(3,1,3),
|
||||
Trap.Type.MINE : Vector3(5,1,5),
|
||||
Hack.Type.BOMB : Vector3(4.25,3,4.25),
|
||||
Hack.Type.GAS : Vector3(1,1,1),
|
||||
Hack.Type.PITFALL : Vector3(1,1,1),
|
||||
Hack.Type.FORCE_PANEL : Vector3(1,1,1),
|
||||
Hack.Type.SWITCH : Vector3(3,1,3),
|
||||
Hack.Type.MINE : Vector3(4.25,3,4.25),
|
||||
}
|
||||
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"),
|
||||
const hack_icons : Dictionary = {
|
||||
Hack.Type.BOMB : preload("res://visuals/images/icons/t-bomb.png"),
|
||||
Hack.Type.GAS : preload("res://visuals/images/icons/t-gas.png"),
|
||||
Hack.Type.PITFALL : preload("res://visuals/images/icons/t-pitfall.png"),
|
||||
Hack.Type.FORCE_PANEL : preload("res://visuals/images/icons/t-force_panel.png"),
|
||||
Hack.Type.SWITCH : preload("res://visuals/images/icons/t-switch.png"),
|
||||
Hack.Type.MINE : preload("res://visuals/images/icons/t-mine.png"),
|
||||
}
|
||||
|
||||
const bomb_explosion_template = preload("res://templates/explosion.tscn")
|
||||
@@ -38,18 +38,18 @@ const force_activate_sound = preload("res://audio/sounds/TomWinandySFX_UI_ScifiT
|
||||
@onready var model : MeshInstance3D = %Model
|
||||
@onready var icon : Sprite3D = %Icon
|
||||
@onready var force_strip : Sprite3D = %ForceStrip
|
||||
@onready var material : StandardMaterial3D = model.get_surface_override_material(0)
|
||||
@onready var material : ShaderMaterial = model.get_active_material(0)
|
||||
@onready var reveal_timer : Timer = %RevealTimer
|
||||
@onready var activation_timer : Timer = %ActivationTimer
|
||||
|
||||
var type : Type
|
||||
var square : Vector3i
|
||||
var trap_owner : int
|
||||
var hack_owner : int
|
||||
var direction : Vector3
|
||||
|
||||
var expended : bool = false
|
||||
var disarming : bool
|
||||
var disarm_id : int
|
||||
var decompiling : bool
|
||||
var decompile_id : int
|
||||
|
||||
var delayed_trigger_tween : Tween = null
|
||||
|
||||
@@ -58,9 +58,9 @@ var damage : int = 10
|
||||
var just_revealed : bool = false
|
||||
|
||||
|
||||
signal removed(type : Trap.Type)
|
||||
signal disarmed(type : Trap.Type)
|
||||
signal activated(type : Trap.Type)
|
||||
signal removed(type : Hack.Type)
|
||||
signal decompiled(type : Hack.Type)
|
||||
signal activated(type : Hack.Type)
|
||||
signal revealed(is_visible : bool)
|
||||
|
||||
func _enter_tree() -> void:
|
||||
@@ -69,9 +69,9 @@ func _enter_tree() -> void:
|
||||
func _exit_tree() -> void:
|
||||
Game.level.remove_map_marker(self)
|
||||
|
||||
func setup(type : Type, direction : Vector3, trap_owner : int) -> void:
|
||||
func setup(type : Type, direction : Vector3, hack_owner : int) -> void:
|
||||
self.type = type
|
||||
self.trap_owner = trap_owner
|
||||
self.hack_owner = hack_owner
|
||||
if type == Type.FORCE_PANEL:
|
||||
var r : float = atan2(direction.z, direction.x)
|
||||
var cardinal : float = roundi(r * 2 / PI) * PI / 2
|
||||
@@ -81,8 +81,8 @@ func remove() -> void:
|
||||
removed.emit(type)
|
||||
queue_free()
|
||||
|
||||
func disarm() -> void:
|
||||
disarmed.emit(type)
|
||||
func decompile() -> void:
|
||||
decompiled.emit(type)
|
||||
queue_free()
|
||||
|
||||
func reveal() -> void:
|
||||
@@ -100,19 +100,20 @@ func is_revealed() -> bool:
|
||||
return model.visible
|
||||
|
||||
func _on_reveal_timeout() -> void:
|
||||
if Game.level.is_square_detected(square) or disarming:
|
||||
if Game.level.is_square_detected(square) or decompiling:
|
||||
reveal_timer.start(5)
|
||||
else:
|
||||
model.visible = false
|
||||
revealed.emit(false)
|
||||
|
||||
func _ready() -> void:
|
||||
var owns_trap = trap_owner == Multiplayer.id
|
||||
icon.texture = trap_icons[type]
|
||||
model.visible = owns_trap
|
||||
icon.visible = owns_trap
|
||||
var owns_hack = hack_owner == Multiplayer.id
|
||||
print("Setup Hack " + name)
|
||||
material.set_shader_parameter("glow_color", Color.YELLOW if owns_hack else Color.RED)
|
||||
icon.texture = hack_icons[type]
|
||||
model.visible = owns_hack
|
||||
icon.visible = owns_hack
|
||||
range_shape.size = range_shapes[type]
|
||||
material.albedo_color = Color.YELLOW if owns_trap else Color.RED
|
||||
match(type):
|
||||
Type.BOMB:
|
||||
damage = 15
|
||||
@@ -125,7 +126,7 @@ func _ready() -> void:
|
||||
Type.FORCE_PANEL:
|
||||
var r : float = atan2(direction.z, -direction.x) + PI/2
|
||||
force_strip.rotate_y(r)
|
||||
force_strip.visible = owns_trap
|
||||
force_strip.visible = owns_hack
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
just_revealed = false
|
||||
@@ -162,7 +163,7 @@ func activate() -> void:
|
||||
explode = true
|
||||
Type.GAS:
|
||||
var emitter = gas_emitter_template.instantiate()
|
||||
emitter.trap_owner = trap_owner
|
||||
emitter.hack_owner = hack_owner
|
||||
emitter.square = square
|
||||
emitter.damage = 4
|
||||
Game.level.add_vfx(emitter, square)
|
||||
@@ -172,14 +173,14 @@ func activate() -> void:
|
||||
blast_players()
|
||||
|
||||
expended = true
|
||||
Game.level.remove_trap_square(square)
|
||||
Game.level.uninstall_hack_square(square)
|
||||
activated.emit(type)
|
||||
queue_free()
|
||||
|
||||
func trigger_adjacent_bombs() -> void:
|
||||
for trap : Trap in range_area.get_overlapping_areas():
|
||||
if trap.type == Type.BOMB and trap != self:
|
||||
trap.delay_trigger()
|
||||
for hack : Hack in range_area.get_overlapping_areas():
|
||||
if hack.type == Type.BOMB and hack != self:
|
||||
hack.delay_trigger()
|
||||
|
||||
func generate_pitfall(suqare : Vector3i) -> void:
|
||||
var pitfall = pitfall_template.instantiate()
|
||||
@@ -202,10 +203,10 @@ func _on_body_entered(body: Node3D) -> void:
|
||||
if type == Type.GAS or type == Type.BOMB:
|
||||
return
|
||||
|
||||
if body.id == trap_owner:
|
||||
if body.id == hack_owner:
|
||||
return
|
||||
|
||||
if !disarming or body.id != disarm_id:
|
||||
if !decompiling or body.id != decompile_id:
|
||||
if !body.detecting:
|
||||
activate()
|
||||
|
||||
28
scripts/hack_display.gd
Normal file
28
scripts/hack_display.gd
Normal file
@@ -0,0 +1,28 @@
|
||||
class_name HackDisplay extends PanelContainer
|
||||
|
||||
|
||||
const hack_hud_icon = preload("res://templates/hack_icon.tscn")
|
||||
@onready var hack_container : HBoxContainer = %HacksContainer
|
||||
@onready var cycle_sound : AudioStreamPlayer = %CycleSound
|
||||
func clear_hacks() -> void:
|
||||
for child in hack_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
func _on_hack_list_changed(hacks, hack_index) -> void:
|
||||
clear_hacks()
|
||||
for hack in hacks:
|
||||
var ticon = hack_hud_icon.instantiate()
|
||||
hack_container.add_child(ticon)
|
||||
ticon.setup(hack.type, hack.quantity)
|
||||
%LeftArrow.visible = (hack_index != 0)
|
||||
%RightArrow.visible = (hack_index != hack_container.get_children().size() - 1)
|
||||
|
||||
func _on_hack_quantity_changed(hack_index, qty) -> void:
|
||||
var hicon = hack_container.get_child(hack_index) as HackIcon
|
||||
hicon.set_quantity(qty)
|
||||
|
||||
func _on_hack_cycled(hack_index) -> void:
|
||||
hack_container.position.x = -hack_index * 150
|
||||
%LeftArrow.visible = (hack_index != 0)
|
||||
%RightArrow.visible = (hack_index != hack_container.get_children().size() - 1)
|
||||
cycle_sound.play()
|
||||
24
scripts/hack_icon.gd
Normal file
24
scripts/hack_icon.gd
Normal file
@@ -0,0 +1,24 @@
|
||||
class_name HackIcon extends Control
|
||||
|
||||
const hack_icons : Dictionary = {
|
||||
Hack.Type.BOMB : preload("res://visuals/images/icons/bomb.png"),
|
||||
Hack.Type.GAS : preload("res://visuals/images/icons/gas.png"),
|
||||
Hack.Type.PITFALL : preload("res://visuals/images/icons/pitfall.png"),
|
||||
Hack.Type.FORCE_PANEL : preload("res://visuals/images/icons/force_panel.png"),
|
||||
Hack.Type.SWITCH : preload("res://visuals/images/icons/switch.png"),
|
||||
Hack.Type.MINE : preload("res://visuals/images/icons/mine.png"),
|
||||
}
|
||||
|
||||
@onready var icon_image : TextureRect = %Icon
|
||||
@onready var qty_label : Label = %Label
|
||||
|
||||
func setup(type : Hack.Type, qty : int) -> void:
|
||||
icon_image.texture = hack_icons[type]
|
||||
set_quantity(qty)
|
||||
|
||||
func set_quantity(qty : int) -> void:
|
||||
qty_label.text = str(qty)
|
||||
if qty < 1:
|
||||
icon_image.modulate = Color.DIM_GRAY
|
||||
else:
|
||||
icon_image.modulate = Color.WHITE
|
||||
@@ -1,6 +1,6 @@
|
||||
class_name HUD extends Control
|
||||
|
||||
@onready var trap_display : TrapDisplay = %TrapDisplay
|
||||
@onready var hack_display : HackDisplay = %HackDisplay
|
||||
@onready var p1_healthbar : HealthBar = %P1HealthBar
|
||||
@onready var p2_healthbar : HealthBar = %P2HealthBar
|
||||
@onready var control_display : ControlDisplay = %ControlDisplay
|
||||
@@ -13,10 +13,10 @@ func register_pawn(player : PawnController, is_local : bool) -> void:
|
||||
player.health_changed.connect(p1_healthbar._on_health_changed if is_local else p2_healthbar._on_health_changed)
|
||||
player.poison_status_changed.connect(p1_healthbar._on_poison_status_changed if is_local else p2_healthbar._on_poison_status_changed)
|
||||
if is_local:
|
||||
trap_display._on_trap_list_changed(player.data.traps, player.data.active_trap)
|
||||
player.trap_cycled.connect(trap_display._on_trap_cycled)
|
||||
player.trap_quantity_changed.connect(trap_display._on_trap_quantity_changed)
|
||||
player.trap_list_changed.connect(trap_display._on_trap_list_changed)
|
||||
hack_display._on_hack_list_changed(player.data.hacks, player.data.active_hack)
|
||||
player.hack_cycled.connect(hack_display._on_hack_cycled)
|
||||
player.hack_quantity_changed.connect(hack_display._on_hack_quantity_changed)
|
||||
player.hack_list_changed.connect(hack_display._on_hack_list_changed)
|
||||
player.combat_target_changed.connect(control_display._on_melee_range_changed)
|
||||
player.ammo_changed.connect(_on_ammo_changed)
|
||||
set_ammo(player.ammo)
|
||||
|
||||
114
scripts/level.gd
114
scripts/level.gd
@@ -3,14 +3,14 @@ class_name Level extends Node3D
|
||||
|
||||
const map_marker_templates : Dictionary[String, PackedScene] = {
|
||||
"pawn" : preload("res://templates/markers/pawn_marker.tscn"),
|
||||
"friendly_trap":preload("res://templates/markers/friendly_trap_marker.tscn"),
|
||||
"enemy_trap": preload("res://templates/markers/enemy_trap_marker.tscn"),
|
||||
"friendly_hack":preload("res://templates/markers/friendly_hack_marker.tscn"),
|
||||
"enemy_hack": preload("res://templates/markers/enemy_hack_marker.tscn"),
|
||||
"item": preload("res://templates/markers/item_marker.tscn")
|
||||
}
|
||||
|
||||
|
||||
const pawn_controller = preload("res://templates/pawn_controller.tscn")
|
||||
const trap_template = preload("res://templates/trap.tscn")
|
||||
const hack_template = preload("res://templates/hack.tscn")
|
||||
const camera_template = preload("res://templates/pawn_camera.tscn")
|
||||
|
||||
const camera_offset = Vector3(0, 10, 5.25)
|
||||
@@ -20,12 +20,15 @@ const camera_offset = Vector3(0, 10, 5.25)
|
||||
@onready var ramp_layer : GridMap = %Ramps
|
||||
@onready var marker_layer : GridMap = %Markers
|
||||
@onready var pawns_node : Node3D = %Pawns
|
||||
@onready var traps_node : Node3D = %Traps
|
||||
@onready var hacks_node : Node3D = %Hacks
|
||||
@onready var cameras_node : Node3D = %Cameras
|
||||
@onready var map_markers_node : Node3D = %MapMarkers
|
||||
@onready var spawn_points : Array[Node] = $PawnSpawner.get_children()
|
||||
|
||||
@export var difficulty : int = 1
|
||||
|
||||
var traps : Dictionary[Vector3i, Trap] = {}
|
||||
|
||||
var hacks : Dictionary[Vector3i, Hack] = {}
|
||||
var pawns : Dictionary[int, PawnController] = {}
|
||||
var cameras : Dictionary[int, PawnCamera] = {}
|
||||
var map_markers : Dictionary[Object, MapMarker] = {}
|
||||
@@ -34,33 +37,38 @@ func _ready() -> void:
|
||||
Game.level = self
|
||||
if Game.mode == Game.Modes.STORY:
|
||||
setup()
|
||||
add_level_trap.call_deferred(Trap.Type.MINE, Vector3.ZERO, Vector3i(5,0,3))
|
||||
add_level_hack.call_deferred(Hack.Type.MINE, Vector3.ZERO, Vector3i(-2,2,0))
|
||||
|
||||
func setup() -> void:
|
||||
if Multiplayer.is_host():
|
||||
spawn_players()
|
||||
|
||||
func spawn_players() -> void:
|
||||
var count = 0
|
||||
for key in Game.pawns_selected:
|
||||
var pc : PawnController = pawn_controller.instantiate()
|
||||
var pd = Game.pawns_selected[key]
|
||||
pawns_node.add_child(pc,true)
|
||||
var traps : Array = []
|
||||
for trap : TrapSet in pd.starting_traps:
|
||||
var hacks : Array = []
|
||||
for hack : HackSet in pd.starting_hacks:
|
||||
var dict = {
|
||||
"type":trap.type,
|
||||
"qty":trap.qty
|
||||
"type":hack.type,
|
||||
"qty":hack.qty
|
||||
}
|
||||
traps.append(dict)
|
||||
hacks.append(dict)
|
||||
|
||||
var position : Vector3
|
||||
if key == Multiplayer.id:
|
||||
position = Vector3(0,0,0)
|
||||
if(spawn_points == null
|
||||
or len(spawn_points) <= count):
|
||||
if key == Multiplayer.id:
|
||||
position = Vector3(0,0,0)
|
||||
else:
|
||||
position = Vector3(3,0,0)
|
||||
else:
|
||||
position = Vector3(3,0,0)
|
||||
|
||||
pc.setup.rpc(key,traps,position)
|
||||
position = spawn_points[count].global_position
|
||||
pc.setup.rpc(key,hacks,position)
|
||||
add_pawn_camera(pc)
|
||||
count += 1
|
||||
|
||||
|
||||
func is_square_detected(crd) -> bool:
|
||||
@@ -73,11 +81,11 @@ func detect_square(crd : Vector3i, mark : bool) -> bool:
|
||||
|
||||
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()
|
||||
var hack_crd = crd + Vector3i(0,1,0)
|
||||
if hacks.has(hack_crd):
|
||||
var hack : Hack = hacks[hack_crd]
|
||||
if hack.hack_owner != Multiplayer.id:
|
||||
hack.reveal()
|
||||
return true
|
||||
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
@@ -90,30 +98,30 @@ func add_pawn_camera(pawn : PawnController) -> void:
|
||||
|
||||
|
||||
|
||||
func add_trap(trap : Trap, crd : Vector3i) -> void:
|
||||
trap.square = crd
|
||||
traps[crd] = trap
|
||||
trap.position = Vector3(crd) + Vector3(.5, 0, .5)
|
||||
add_child(trap, true)
|
||||
func add_hack(hack : Hack, crd : Vector3i) -> void:
|
||||
hack.square = crd
|
||||
hacks[crd] = hack
|
||||
hack.position = Vector3(crd) + Vector3(.5, 0, .5)
|
||||
add_child(hack, true)
|
||||
|
||||
func add_projectile(shot : Projectile) -> void:
|
||||
add_child(shot, true)
|
||||
|
||||
func remove_trap_square(crd : Vector3i) -> void:
|
||||
traps.erase(crd)
|
||||
func uninstall_hack_square(crd : Vector3i) -> void:
|
||||
hacks.erase(crd)
|
||||
|
||||
func get_square_trap(crd : Vector3i) -> Trap:
|
||||
if traps.has(crd):
|
||||
return traps[crd]
|
||||
func get_square_hack(crd : Vector3i) -> Hack:
|
||||
if hacks.has(crd):
|
||||
return hacks[crd]
|
||||
else:
|
||||
return null
|
||||
|
||||
|
||||
|
||||
func is_valid_trap_square(crd : Vector3i) -> bool:
|
||||
func is_valid_hack_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):
|
||||
if hacks.has(crd):
|
||||
return false
|
||||
return true
|
||||
|
||||
@@ -121,20 +129,20 @@ func add_vfx(vfx, crd : Vector3i) -> void:
|
||||
vfx.position = Vector3(crd) #+ Vector3(0.5, 0, 0.5)
|
||||
add_child(vfx, true)
|
||||
|
||||
func activate_trap(crd : Vector3i) -> void:
|
||||
if traps.has(crd):
|
||||
traps[crd].activate()
|
||||
func activate_hack(crd : Vector3i) -> void:
|
||||
if hacks.has(crd):
|
||||
hacks[crd].activate()
|
||||
|
||||
|
||||
func generate_trap(type : Trap.Type, dir : Vector3, square : Vector3i):
|
||||
var trap = trap_template.instantiate()
|
||||
trap.setup(type, dir, -1)
|
||||
add_trap(trap, square)
|
||||
func generate_hack(type : Hack.Type, dir : Vector3, square : Vector3i):
|
||||
var hack = hack_template.instantiate()
|
||||
hack.setup(type, dir, -1)
|
||||
add_hack(hack, square)
|
||||
|
||||
func disarm_trap(crd : Vector3i) -> void:
|
||||
var trap = traps[crd]
|
||||
trap.disarm()
|
||||
traps.erase(crd)
|
||||
func decompile_hack(crd : Vector3i) -> void:
|
||||
var hack = hacks[crd]
|
||||
hack.decompile()
|
||||
hacks.erase(crd)
|
||||
|
||||
func remove_map_marker(target) -> void:
|
||||
if !map_markers.has(target):
|
||||
@@ -149,13 +157,13 @@ func add_map_marker(target) -> void:
|
||||
if target is PawnController:
|
||||
marker = map_marker_templates.pawn.instantiate()
|
||||
height += 40
|
||||
elif target is Trap:
|
||||
if target.trap_owner == Multiplayer.id:
|
||||
marker = map_marker_templates.friendly_trap.instantiate()
|
||||
elif target is Hack:
|
||||
if target.hack_owner == Multiplayer.id:
|
||||
marker = map_marker_templates.friendly_hack.instantiate()
|
||||
else:
|
||||
marker = map_marker_templates.enemy_trap.instantiate()
|
||||
marker = map_marker_templates.enemy_hack.instantiate()
|
||||
marker.visible = false
|
||||
target.revealed.connect(marker._on_trap_revealed)
|
||||
target.revealed.connect(marker._on_hack_revealed)
|
||||
height += 30
|
||||
elif target is Item:
|
||||
marker = map_marker_templates.item.instantiate()
|
||||
@@ -165,7 +173,7 @@ func add_map_marker(target) -> void:
|
||||
map_markers_node.add_child(marker)
|
||||
marker.position += Vector3(0, height,0)
|
||||
|
||||
func add_level_trap(type : Trap.Type, facing : Vector3, crd : Vector3i) -> void:
|
||||
var trap = trap_template.instantiate()
|
||||
trap.setup(type, facing, -1)
|
||||
add_trap(trap, crd)
|
||||
func add_level_hack(type : Hack.Type, facing : Vector3, crd : Vector3i) -> void:
|
||||
var hack = hack_template.instantiate()
|
||||
hack.setup(type, facing, -1)
|
||||
add_hack(hack, crd)
|
||||
|
||||
@@ -14,5 +14,5 @@ func _process(delta: float) -> void:
|
||||
if target:
|
||||
reposition()
|
||||
|
||||
func _on_trap_revealed(is_visible : bool) -> void:
|
||||
func _on_hack_revealed(is_visible : bool) -> void:
|
||||
visible = is_visible
|
||||
|
||||
@@ -16,4 +16,4 @@ extends Level
|
||||
#var pc : PawnController = pawn_controller_template.instantiate()
|
||||
#var pd = Game.pawns_selected[key]
|
||||
#player_spawner.add_pawn(pc, key)
|
||||
#pc.setup(key,pd.starting_traps)
|
||||
#pc.setup(key,pd.starting_hacks)
|
||||
|
||||
@@ -4,20 +4,47 @@ class_name PawnBody extends Node3D
|
||||
|
||||
@onready var anim_player : AnimationPlayer = %AnimationPlayer
|
||||
@onready var ranged_point : Node3D = %RangedPoint
|
||||
@onready var material : StandardMaterial3D = $Mesh.material
|
||||
#@onready var material : StandardMaterial3D = $Mesh.material
|
||||
@onready var struggle_ui : Sprite3D = %StruggleUI
|
||||
@onready var struggle_bar : ProgressBar = %StruggleBar
|
||||
@onready var anim_tree : AnimationTree = %AnimationTree
|
||||
@onready var anim_machine : AnimationNodeStateMachinePlayback = %AnimationTree.get("parameters/playback")
|
||||
|
||||
@onready var walk_sound : AudioStreamPlayer3D = $WalkSound
|
||||
@onready var footstep_timer : Timer = $FootstepTimer
|
||||
|
||||
@rpc("call_local")
|
||||
func play_animation(anim_name : String) -> void:
|
||||
anim_player.play(anim_name)
|
||||
|
||||
@rpc("call_local")
|
||||
func travel_animation(node_name : String) -> void:
|
||||
anim_machine.travel(node_name)
|
||||
|
||||
|
||||
@rpc("call_local")
|
||||
func show_struggle() -> void:
|
||||
struggle_ui.visible = true
|
||||
|
||||
func set_animation_parameter(parameter : String, value : Variant) -> void:
|
||||
anim_tree.set(parameter, value)
|
||||
|
||||
func stop_footsteps() -> void:
|
||||
footstep_timer.stop()
|
||||
|
||||
func play_footsteps(step_time : float = 1) -> void:
|
||||
if footstep_timer.is_stopped():
|
||||
walk_sound.play()
|
||||
footstep_timer.start(step_time)
|
||||
elif footstep_timer.wait_time != step_time:
|
||||
footstep_timer.wait_time = step_time
|
||||
|
||||
func _on_struggle_changed(value : float) -> void:
|
||||
if value <= 0:
|
||||
struggle_ui.visible = false
|
||||
else:
|
||||
struggle_bar.value = value
|
||||
|
||||
|
||||
func _on_footstep_timer_timeout() -> void:
|
||||
walk_sound.play()
|
||||
|
||||
@@ -10,16 +10,17 @@ enum State {
|
||||
}
|
||||
|
||||
|
||||
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")
|
||||
const hack_template = preload("res://templates/hack.tscn")
|
||||
|
||||
const uninstall_hack_modal = preload("res://templates/uninstall_hack_modal.tscn")
|
||||
const decompile_hack_modal = preload("res://templates/decompile_hack_modal.tscn")
|
||||
const range_sphere_template = preload("res://templates/range_sphere.tscn")
|
||||
@export var speed : float = 10
|
||||
|
||||
@onready var body : PawnBody = $PawnBody
|
||||
@onready var input : PawnInput = $PawnInput
|
||||
@onready var data : PawnLevelData = $Data
|
||||
@onready var trap_sound : AudioStreamPlayer3D = $TrapSound
|
||||
@onready var hack_sound : AudioStreamPlayer3D = $HackSound
|
||||
@onready var detonate_sound : AudioStreamPlayer3D = $DetonateSound
|
||||
@onready var detect_sound : AudioStreamPlayer3D = $DetectSound
|
||||
@onready var fling_sound : AudioStreamPlayer3D = $FlingSound
|
||||
@@ -34,6 +35,9 @@ var button_actions : Dictionary[int, String]
|
||||
var current_square : Vector3i
|
||||
var facing : Vector3
|
||||
@export var detecting : bool = false
|
||||
var installing : bool = false
|
||||
var uninstalling : bool = false
|
||||
var range_sphere : RangeSphere
|
||||
var detect_squares : Dictionary[Vector3i, bool] = {}
|
||||
var detect_tween : Tween = null
|
||||
var fling_direction : Vector3
|
||||
@@ -57,6 +61,9 @@ var ammo = 5
|
||||
var max_ammo = 5
|
||||
var combat_target
|
||||
var meleeing : bool = false
|
||||
var shooting : bool = false
|
||||
var flinch : float = 0
|
||||
|
||||
|
||||
var input_locked : bool = false
|
||||
var action_tween : Tween = null
|
||||
@@ -66,9 +73,9 @@ var camera : PawnCamera = null
|
||||
|
||||
var modal = null
|
||||
|
||||
signal trap_cycled(trap_index : int)
|
||||
signal trap_quantity_changed(trap_index : int, quantity : int)
|
||||
signal trap_list_changed(traps)
|
||||
signal hack_cycled(hack_index : int)
|
||||
signal hack_quantity_changed(hack_index : int, quantity : int)
|
||||
signal hack_list_changed(hacks)
|
||||
signal health_changed(current : int, max : int)
|
||||
signal harmed()
|
||||
signal poison_status_changed(poisoned : bool)
|
||||
@@ -82,6 +89,11 @@ func _enter_tree() -> void:
|
||||
|
||||
func _exit_tree() -> void:
|
||||
Game.level.remove_map_marker(self)
|
||||
#if id == Multiplayer.id:
|
||||
#Game.level.show_loss_screen()
|
||||
#else:
|
||||
#Game.level.evaluate_outcome()
|
||||
#Game.evaluate
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if attack_timer > 0:
|
||||
@@ -102,6 +114,7 @@ func _physics_process(delta: float) -> void:
|
||||
var moving : bool = false
|
||||
match(state):
|
||||
State.FLUNG:
|
||||
body.stop_footsteps()
|
||||
can_fall = true
|
||||
moving = true
|
||||
dir = fling_direction
|
||||
@@ -126,15 +139,26 @@ func _physics_process(delta: float) -> void:
|
||||
moving = false
|
||||
State.NORMAL:
|
||||
can_fall = true
|
||||
|
||||
if dir.length_squared() > 0:
|
||||
moving = true
|
||||
facing = dir.normalized()
|
||||
body.look_at(body.global_position - dir)
|
||||
var y = velocity.y
|
||||
velocity = speed * dir
|
||||
if is_poisoned():
|
||||
velocity *= 0.5
|
||||
if detecting:
|
||||
velocity *= .33
|
||||
velocity.y = y
|
||||
if !detecting:
|
||||
body.play_footsteps(lerp(.78, .33, dir.length()))
|
||||
else:
|
||||
body.stop_footsteps()
|
||||
else:
|
||||
body.stop_footsteps()
|
||||
body.set_animation_parameter("parameters/Motion/blend_position", dir.length())
|
||||
body.set_animation_parameter("parameters/Crouch/blend_position", dir.length())
|
||||
State.KNOCKUP:
|
||||
if is_on_floor():
|
||||
knockdown(facing)
|
||||
@@ -161,7 +185,7 @@ func _physics_process(delta: float) -> void:
|
||||
if !input_locked:
|
||||
if modal:
|
||||
var buttons = [
|
||||
"lay trap",
|
||||
"install",
|
||||
"detect",
|
||||
"attack",
|
||||
"detonate"
|
||||
@@ -189,7 +213,7 @@ func attack() -> void:
|
||||
ammo-=1
|
||||
ammo_changed.emit(ammo, max_ammo)
|
||||
attack_timer = ranged_recovery_time
|
||||
body.play_animation("shoot")
|
||||
shooting == true
|
||||
if combat_target != null:
|
||||
var v = body.global_position.direction_to(combat_target.global_position)
|
||||
v.y = 0
|
||||
@@ -197,20 +221,39 @@ func attack() -> void:
|
||||
|
||||
|
||||
func update_actions() -> void:
|
||||
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 attack_timer <= 0 and shooting and !input.is_action_pressed("attack"):
|
||||
shooting = false
|
||||
|
||||
if input.is_action_just_pressed("left cycle hack"):
|
||||
cycle_active_hack(-1)
|
||||
if input.is_action_just_pressed("right cycle hack"):
|
||||
cycle_active_hack(1)
|
||||
if input.is_action_just_pressed("detonate"):
|
||||
detonate()
|
||||
elif input.is_action_just_pressed("detect"):
|
||||
start_detecting()
|
||||
elif input.is_action_just_released("detect"):
|
||||
stop_detecting()
|
||||
elif !detecting and input.is_action_just_pressed("lay trap"):
|
||||
try_lay_trap()
|
||||
elif input.is_action_pressed("attack"):
|
||||
attack()
|
||||
elif !installing:
|
||||
if input.is_action_just_pressed("detect"):
|
||||
start_detecting()
|
||||
elif input.is_action_just_released("detect"):
|
||||
stop_detecting()
|
||||
if!detecting:
|
||||
if input.is_action_just_pressed("install"):
|
||||
installing = true
|
||||
if range_sphere != null:
|
||||
range_sphere.queue_free()
|
||||
range_sphere = range_sphere_template.instantiate()
|
||||
#Set the range sphere size based upon the current hack
|
||||
update_range_sphere()
|
||||
if input.is_action_just_released("install"):
|
||||
installing = false
|
||||
try_install_hack()
|
||||
elif input.is_action_pressed("attack"):
|
||||
attack()
|
||||
elif input.is_action_just_released("install"):
|
||||
installing = false
|
||||
try_install_hack()
|
||||
|
||||
func update_range_sphere() -> void:
|
||||
pass
|
||||
|
||||
func update_struggle(delta : float) -> bool:
|
||||
if struggle_timer > 0:
|
||||
@@ -295,34 +338,35 @@ func check_attack_target() -> void:
|
||||
combat_target = ranged_closest
|
||||
combat_target_changed.emit(melee_closest != null)
|
||||
|
||||
func try_lay_trap() -> void:
|
||||
func try_install_hack() -> void:
|
||||
if !is_on_floor():
|
||||
return
|
||||
|
||||
if data.traps[data.active_trap].quantity < 1:
|
||||
if data.hacks[data.active_hack].quantity < 1:
|
||||
return
|
||||
|
||||
var square : Vector3i = (global_position - Vector3.ONE * .5).round()
|
||||
if !Game.level.is_valid_trap_square(square):
|
||||
if !Game.level.is_valid_hack_square(square):
|
||||
return
|
||||
|
||||
action_tween = create_tween()
|
||||
input_locked = true
|
||||
body.travel_animation("Install")
|
||||
action_tween.tween_interval(.2)
|
||||
action_tween.tween_callback(Callable(lay_trap).bind(square, data.active_trap))
|
||||
action_tween.tween_callback(Callable(install_hack).bind(square, data.active_hack))
|
||||
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, facing, id)
|
||||
trap.disarmed.connect(_on_trap_disarmed)
|
||||
trap.activated.connect(_on_trap_activated)
|
||||
data.traps[idx].quantity -= 1
|
||||
trap_quantity_changed.emit(idx, data.traps[idx].quantity)
|
||||
Game.level.add_trap(trap, square)
|
||||
trap_sound.play()
|
||||
func install_hack(square : Vector3i, idx : int) -> void:
|
||||
var type : Hack.Type = data.hacks[idx].type
|
||||
var hack = hack_template.instantiate()
|
||||
hack.setup(type, facing, id)
|
||||
hack.decompiled.connect(_on_hack_decompiled)
|
||||
hack.activated.connect(_on_hack_activated)
|
||||
data.hacks[idx].quantity -= 1
|
||||
hack_quantity_changed.emit(idx, data.hacks[idx].quantity)
|
||||
Game.level.add_hack(hack, square)
|
||||
hack_sound.play()
|
||||
|
||||
func clear_action() -> void:
|
||||
input_locked = false
|
||||
@@ -340,28 +384,31 @@ func detect_alert() -> void:
|
||||
detect_tween.tween_callback(func(): detect_tween = null)
|
||||
|
||||
func close_modal() -> void:
|
||||
uninstalling = false
|
||||
if modal != null:
|
||||
modal.queue_free()
|
||||
modal = null
|
||||
|
||||
func show_remove_trap_modal() -> void:
|
||||
func show_uninstall_hack_modal() -> void:
|
||||
stop_detecting()
|
||||
modal = remove_trap_modal.instantiate()
|
||||
uninstalling = true
|
||||
modal = uninstall_hack_modal.instantiate()
|
||||
modal.square = current_square
|
||||
Game.level.add_child(modal)
|
||||
|
||||
func show_disarm_trap_modal() -> void:
|
||||
func show_decompile_hack_modal() -> void:
|
||||
stop_detecting()
|
||||
modal = disarm_trap_modal.instantiate()
|
||||
uninstalling = true
|
||||
modal = decompile_hack_modal.instantiate()
|
||||
modal.difficulty = Game.level.difficulty
|
||||
modal.square = current_square
|
||||
|
||||
var trap = Game.level.traps[current_square]
|
||||
trap.disarming = true
|
||||
trap.disarm_id = Multiplayer.id
|
||||
trap.removed.connect(modal._on_trap_removed)
|
||||
trap.activated.connect(modal._on_trap_failed)
|
||||
harmed.connect(modal._on_trap_failed)
|
||||
var hack = Game.level.hacks[current_square]
|
||||
hack.decompiling = true
|
||||
hack.decompile_id = Multiplayer.id
|
||||
hack.removed.connect(modal._on_hack_removed)
|
||||
hack.activated.connect(modal._on_hack_failed)
|
||||
harmed.connect(modal._on_hack_failed)
|
||||
Game.level.add_child(modal)
|
||||
|
||||
func start_detecting() -> void:
|
||||
@@ -390,18 +437,18 @@ func update_detect_region(update : bool) -> void:
|
||||
Game.level.detect_square(sq, false)
|
||||
|
||||
var remove_list = []
|
||||
var trap_detected : bool = false
|
||||
var hack_detected : bool = false
|
||||
for sq in new_squares.keys():
|
||||
if update and detect_squares.has(sq):
|
||||
continue
|
||||
if !Game.level.detect_square(sq, true):
|
||||
remove_list.append(sq)
|
||||
else:
|
||||
var trap = Game.level.get_square_trap(sq + Vector3i(0,1,0))
|
||||
if trap and trap.is_just_revealed():
|
||||
trap_detected = true
|
||||
var hack = Game.level.get_square_hack(sq + Vector3i(0,1,0))
|
||||
if hack and hack.is_just_revealed():
|
||||
hack_detected = true
|
||||
|
||||
if trap_detected:
|
||||
if hack_detected:
|
||||
detect_alert()
|
||||
|
||||
detect_squares = new_squares
|
||||
@@ -409,13 +456,13 @@ func update_detect_region(update : bool) -> void:
|
||||
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()
|
||||
var hack : Hack = Game.level.get_square_hack(current_square)
|
||||
if hack != null:
|
||||
if hack.hack_owner == Multiplayer.id:
|
||||
show_uninstall_hack_modal()
|
||||
else:
|
||||
trap.disarming = true
|
||||
show_disarm_trap_modal()
|
||||
hack.decompiling = true
|
||||
show_decompile_hack_modal()
|
||||
|
||||
func stop_detecting() -> void:
|
||||
detecting = false
|
||||
@@ -430,39 +477,39 @@ func clear_detect_region() -> void:
|
||||
detect_squares = {}
|
||||
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
func setup(id : int, traps : Array, pos : Vector3) -> void:
|
||||
func setup(id : int, hacks : Array, pos : Vector3) -> void:
|
||||
self.id = id
|
||||
self.global_position = pos
|
||||
var traplist : Array[PawnLevelData.TrapData] = []
|
||||
for trap in traps:
|
||||
traplist.append(PawnLevelData.TrapData.new(trap.type, trap.qty, trap.qty))
|
||||
$Data.traps = traplist
|
||||
var hacklist : Array[PawnLevelData.HackData] = []
|
||||
for hack in hacks:
|
||||
hacklist.append(PawnLevelData.HackData.new(hack.type, hack.qty, hack.qty))
|
||||
$Data.hacks = hacklist
|
||||
input.set_multiplayer_authority(id)
|
||||
struggling.connect(body._on_struggle_changed)
|
||||
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:
|
||||
func uninstall_hack_at(square) -> void:
|
||||
var hack : Hack = Game.level.hacks[square]
|
||||
for i in range(len(data.hacks)):
|
||||
var d = data.hacks[i]
|
||||
if d.type == hack.type:
|
||||
d.quantity += 1
|
||||
trap_quantity_changed.emit(i, d.quantity)
|
||||
hack_quantity_changed.emit(i, d.quantity)
|
||||
break
|
||||
trap.remove()
|
||||
Game.level.traps.erase(square)
|
||||
hack.remove()
|
||||
Game.level.hacks.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
|
||||
func cycle_active_hack(dir) -> void:
|
||||
var prev = data.active_hack
|
||||
data.active_hack += dir
|
||||
if data.active_hack < 0:
|
||||
data.active_hack = 0
|
||||
|
||||
if data.active_trap >= len(data.traps):
|
||||
data.active_trap = len(data.traps) - 1
|
||||
if data.active_hack >= len(data.hacks):
|
||||
data.active_hack = len(data.hacks) - 1
|
||||
|
||||
if prev != data.active_trap:
|
||||
trap_cycled.emit(data.active_trap)
|
||||
if prev != data.active_hack:
|
||||
hack_cycled.emit(data.active_hack)
|
||||
|
||||
func can_hurt() -> bool:
|
||||
return true
|
||||
@@ -476,38 +523,49 @@ func hurt(damage : int) -> void:
|
||||
struggling.emit(struggle_timer)
|
||||
knockdown(Vector3(0,0,-1))
|
||||
health_changed.emit(data.life, data.max_life)
|
||||
if data.life == 0:
|
||||
die.rpc()
|
||||
@rpc("any_peer", "call_local")
|
||||
func die() -> void:
|
||||
state = State.DEAD
|
||||
input_locked = true
|
||||
if id == Multiplayer.id:
|
||||
var death_tween = create_tween()
|
||||
death_tween.tween_interval(3)
|
||||
death_tween.tween_callback(queue_free)
|
||||
pass
|
||||
|
||||
func _on_trap_disarmed(type : Trap.Type) -> void:
|
||||
for i in range(len(data.traps)):
|
||||
var d = data.traps[i]
|
||||
func _on_hack_decompiled(type : Hack.Type) -> void:
|
||||
for i in range(len(data.hacks)):
|
||||
var d = data.hacks[i]
|
||||
if d.type == type:
|
||||
d.max -= 1
|
||||
trap_quantity_changed.emit(i, d.quantity)
|
||||
hack_quantity_changed.emit(i, d.quantity)
|
||||
break
|
||||
#hurt
|
||||
#blast
|
||||
#blast_players
|
||||
#activate
|
||||
#activate_trap
|
||||
#activate_hack
|
||||
#fail
|
||||
#on_trap_failed
|
||||
func _on_trap_activated(type : Trap.Type) -> void:
|
||||
for i in range(len(data.traps)):
|
||||
var d = data.traps[i]
|
||||
#on_hack_failed
|
||||
func _on_hack_activated(type : Hack.Type) -> void:
|
||||
for i in range(len(data.hacks)):
|
||||
var d = data.hacks[i]
|
||||
if d.type == type:
|
||||
d.quantity = min(d.max, d.quantity+ 1)
|
||||
trap_quantity_changed.emit(i, d.quantity)
|
||||
hack_quantity_changed.emit(i, d.quantity)
|
||||
break
|
||||
|
||||
func detonate() -> void:
|
||||
var switch_list = []
|
||||
for trap : Trap in Game.level.traps.values():
|
||||
if trap.type == Trap.Type.SWITCH and trap.trap_owner == id:
|
||||
switch_list.append(trap)
|
||||
for hack : Hack in Game.level.hacks.values():
|
||||
if hack.type == Hack.Type.SWITCH and hack.hack_owner == id:
|
||||
switch_list.append(hack)
|
||||
detonate_sound.play()
|
||||
|
||||
for trap : Trap in switch_list:
|
||||
trap.activate()
|
||||
for hack : Hack in switch_list:
|
||||
hack.activate()
|
||||
|
||||
func is_poisoned() -> bool:
|
||||
return poison_time_remaining > 0
|
||||
@@ -553,7 +611,13 @@ func knockup(velocity : Vector3) -> void:
|
||||
move_and_slide()
|
||||
self.velocity = velocity
|
||||
|
||||
|
||||
func knockback(direction : Vector3, impact : float) -> void:
|
||||
if state != State.NORMAL:
|
||||
return
|
||||
flinch += impact
|
||||
if flinch > 0:
|
||||
knockdown(direction)
|
||||
#ELSE DO A KNOCKBACK ANIMATION
|
||||
|
||||
func pitfall(duration : float) -> void:
|
||||
struggle_timer = duration
|
||||
@@ -568,3 +632,15 @@ func start_pitfall(square : Vector3, duration : float) -> void:
|
||||
tween.tween_property(self, "position", square + Vector3(.5,0,.5), 0.25)
|
||||
tween.tween_property(self, "input_locked", false, 0)
|
||||
tween.tween_callback(pitfall.bind(duration))
|
||||
|
||||
func _on_melee_hit(body : Node3D) -> void:
|
||||
pass
|
||||
|
||||
func is_dead() -> bool:
|
||||
return state == State.DEAD
|
||||
|
||||
func is_detecting() -> bool:
|
||||
return detecting
|
||||
|
||||
func is_crouching() -> bool:
|
||||
return detecting or installing or uninstalling
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
class_name PawnDisplay extends Panel
|
||||
|
||||
@onready var pawn_name : Label = %PawnName
|
||||
@onready var trap_container : HBoxContainer = %TrapContainer
|
||||
@onready var hack_container : HBoxContainer = %HackContainer
|
||||
@onready var portrait : TextureRect = $Portrait
|
||||
@onready var portrait_blinder : TextureRect = $PortraitBlinder
|
||||
var traps : Array = []
|
||||
var hacks : Array = []
|
||||
var swap_portrait_tween : Tween = null
|
||||
|
||||
func _ready() -> void:
|
||||
for child in trap_container.get_children():
|
||||
traps.append(child)
|
||||
for child in hack_container.get_children():
|
||||
hacks.append(child)
|
||||
|
||||
func set_traps(trap_list : Array[TrapSet]) -> void:
|
||||
var tcount = 0
|
||||
if len(trap_list) != 3:
|
||||
func set_hacks(hack_list : Array[HackSet]) -> void:
|
||||
var hcount = 0
|
||||
if len(hack_list) != 3:
|
||||
return
|
||||
for trap in traps:
|
||||
trap.setup(trap_list[tcount].type, trap_list[tcount].qty)
|
||||
tcount+=1
|
||||
for hack in hacks:
|
||||
hack.setup(hack_list[hcount].type, hack_list[hcount].qty)
|
||||
hcount+=1
|
||||
|
||||
func set_portrait(picture : Texture2D) -> void:
|
||||
if swap_portrait_tween != null and swap_portrait_tween.is_running():
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class_name PawnInput extends Node
|
||||
class_name PawnInput extends MultiplayerSynchronizer
|
||||
|
||||
|
||||
@export var dir : Vector3
|
||||
@@ -8,31 +8,33 @@ class_name PawnInput extends Node
|
||||
|
||||
func _ready() -> void:
|
||||
pressed = {
|
||||
"left cycle trap":false,
|
||||
"right cycle trap":false,
|
||||
"left cycle hack":false,
|
||||
"right cycle hack":false,
|
||||
"detonate":false,
|
||||
"detect":false,
|
||||
"lay trap":false,
|
||||
"install":false,
|
||||
"attack":false
|
||||
}
|
||||
just_pressed = {
|
||||
"left cycle trap":false,
|
||||
"right cycle trap":false,
|
||||
"left cycle hack":false,
|
||||
"right cycle hack":false,
|
||||
"detonate":false,
|
||||
"detect":false,
|
||||
"lay trap":false,
|
||||
"install":false,
|
||||
"attack":false
|
||||
}
|
||||
just_released = {
|
||||
"left cycle trap":false,
|
||||
"right cycle trap":false,
|
||||
"left cycle hack":false,
|
||||
"right cycle hack":false,
|
||||
"detonate":false,
|
||||
"detect":false,
|
||||
"lay trap":false,
|
||||
"install":false,
|
||||
"attack":false
|
||||
}
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if get_multiplayer_authority() != Multiplayer.id:
|
||||
return
|
||||
var d = Input.get_vector("west", "east", "north", "south")
|
||||
dir = Vector3(d.x, 0, d.y)
|
||||
for key : String in pressed:
|
||||
@@ -45,6 +47,8 @@ func _physics_process(delta: float) -> void:
|
||||
just_pressed[key] = false
|
||||
pressed[key] = false
|
||||
|
||||
|
||||
|
||||
func is_action_pressed(action : String) -> bool:
|
||||
return pressed.has(action) && pressed[action]
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
class_name PawnLevelData extends Node
|
||||
|
||||
class TrapData:
|
||||
var type : Trap.Type
|
||||
class HackData:
|
||||
var type : Hack.Type
|
||||
var quantity : int
|
||||
var max : int
|
||||
|
||||
func _init(type : Trap.Type, quantity : int, max : int) -> void:
|
||||
func _init(type : Hack.Type, quantity : int, max : int) -> void:
|
||||
self.type = type
|
||||
self.quantity = quantity
|
||||
self.max = max
|
||||
|
||||
var traps : Array[TrapData] = []
|
||||
var active_trap : int = 0
|
||||
var hacks : Array[HackData] = []
|
||||
var active_hack : int = 0
|
||||
|
||||
var life : int = 100
|
||||
var max_life : int = 100
|
||||
|
||||
5
scripts/range_sphere.gd
Normal file
5
scripts/range_sphere.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
class_name RangeSphere extends CSGSphere3D
|
||||
|
||||
|
||||
func set_range(range : int) -> void:
|
||||
radius = range
|
||||
1
scripts/range_sphere.gd.uid
Normal file
1
scripts/range_sphere.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://w801e8ko5s5d
|
||||
@@ -1,12 +0,0 @@
|
||||
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
|
||||
@@ -1,28 +0,0 @@
|
||||
class_name TrapDisplay extends PanelContainer
|
||||
|
||||
|
||||
const trap_hud_icon = preload("res://templates/trap_icon.tscn")
|
||||
@onready var trap_container : HBoxContainer = %TrapsContainer
|
||||
@onready var cycle_sound : AudioStreamPlayer = %CycleSound
|
||||
func clear_traps() -> void:
|
||||
for child in trap_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
func _on_trap_list_changed(traps, trap_index) -> void:
|
||||
clear_traps()
|
||||
for trap in traps:
|
||||
var ticon = trap_hud_icon.instantiate()
|
||||
trap_container.add_child(ticon)
|
||||
ticon.setup(trap.type, trap.quantity)
|
||||
%LeftArrow.visible = (trap_index != 0)
|
||||
%RightArrow.visible = (trap_index != trap_container.get_children().size() - 1)
|
||||
|
||||
func _on_trap_quantity_changed(trap_index, qty) -> void:
|
||||
var ticon = trap_container.get_child(trap_index) as TrapIcon
|
||||
ticon.set_quantity(qty)
|
||||
|
||||
func _on_trap_cycled(trap_index) -> void:
|
||||
trap_container.position.x = -trap_index * 150
|
||||
%LeftArrow.visible = (trap_index != 0)
|
||||
%RightArrow.visible = (trap_index != trap_container.get_children().size() - 1)
|
||||
cycle_sound.play()
|
||||
@@ -1,24 +0,0 @@
|
||||
class_name TrapIcon extends Control
|
||||
|
||||
const trap_icons : Dictionary = {
|
||||
Trap.Type.BOMB : preload("res://visuals/images/icons/bomb.png"),
|
||||
Trap.Type.GAS : preload("res://visuals/images/icons/gas.png"),
|
||||
Trap.Type.PITFALL : preload("res://visuals/images/icons/pitfall.png"),
|
||||
Trap.Type.FORCE_PANEL : preload("res://visuals/images/icons/force_panel.png"),
|
||||
Trap.Type.SWITCH : preload("res://visuals/images/icons/switch.png"),
|
||||
Trap.Type.MINE : preload("res://visuals/images/icons/mine.png"),
|
||||
}
|
||||
|
||||
@onready var icon_image : TextureRect = %Icon
|
||||
@onready var qty_label : Label = %Label
|
||||
|
||||
func setup(type : Trap.Type, qty : int) -> void:
|
||||
icon_image.texture = trap_icons[type]
|
||||
set_quantity(qty)
|
||||
|
||||
func set_quantity(qty : int) -> void:
|
||||
qty_label.text = str(qty)
|
||||
if qty < 1:
|
||||
icon_image.modulate = Color.DIM_GRAY
|
||||
else:
|
||||
icon_image.modulate = Color.WHITE
|
||||
12
scripts/uninstall_hack_modal.gd
Normal file
12
scripts/uninstall_hack_modal.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
class_name UninstallHackModal extends ConfirmationDialog
|
||||
|
||||
var square : Vector3i
|
||||
|
||||
func button_pressed(button : String) -> void:
|
||||
match(button):
|
||||
"detonate":
|
||||
Game.player.uninstall_hack_at(square)
|
||||
Game.player.close_modal()
|
||||
"attack":
|
||||
Game.player.close_modal()
|
||||
_: return
|
||||
Reference in New Issue
Block a user