Extensive work on virtually all of the visuals and the net code
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user