Work on pickups and multiplayer
This commit is contained in:
@@ -2,6 +2,11 @@ class_name PawnController extends CharacterBody3D
|
||||
|
||||
enum State {
|
||||
NORMAL,
|
||||
DETECTING,
|
||||
INSTALLING,
|
||||
UNINSTALLING,
|
||||
MELEE_ATTACKING,
|
||||
RANGED_ATTACKING,
|
||||
KNOCKDOWN,
|
||||
KNOCKUP,
|
||||
FLUNG,
|
||||
@@ -26,7 +31,7 @@ const range_sphere_template = preload("res://templates/range_sphere.tscn")
|
||||
@onready var detect_sound : AudioStreamPlayer3D = $DetectSound
|
||||
@onready var fling_sound : AudioStreamPlayer3D = $FlingSound
|
||||
@onready var crash_sound : AudioStreamPlayer3D = $CrashSound
|
||||
@onready var reload_sound : AudioStreamPlayer3D = $PawnBody/ReloadSound
|
||||
@onready var reload_sound : AudioStreamPlayer3D
|
||||
@onready var detect_icon : Sprite3D = $DetectIcon
|
||||
|
||||
@export var id : int = 1
|
||||
@@ -35,9 +40,6 @@ const range_sphere_template = preload("res://templates/range_sphere.tscn")
|
||||
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
|
||||
@@ -51,18 +53,17 @@ var poison_time_remaining : float = 0
|
||||
var poison_pulse_timer : float
|
||||
|
||||
var melee_range : float = 3.0
|
||||
var can_melee : bool = false
|
||||
var ranged_range : float = 6
|
||||
var attack_timer : float = 0
|
||||
var melee_recovery_time : float = .75
|
||||
var ranged_recovery_time : float = .2
|
||||
var ranged_recovery_time : float = 0.25
|
||||
var ranged_reload_time : float = 1
|
||||
var projectile_speed : float = 10.0
|
||||
var projectile_damage : int = 4
|
||||
var ammo = 5
|
||||
var max_ammo = 5
|
||||
var combat_target
|
||||
var meleeing : bool = false
|
||||
var shooting : bool = false
|
||||
var reloading : bool = false
|
||||
var take_shot : bool = false
|
||||
var flinch : float = 0
|
||||
@@ -98,7 +99,22 @@ func _exit_tree() -> void:
|
||||
#Game.level.evaluate_outcome()
|
||||
#Game.evaluate
|
||||
|
||||
func calculate_pawn_velocity(dir : Vector3) -> Vector3:
|
||||
var y = velocity.y
|
||||
var result = speed * dir
|
||||
if is_poisoned():
|
||||
result *= 0.5
|
||||
if is_crouching():
|
||||
result *= .33
|
||||
result.y = y
|
||||
return result
|
||||
|
||||
func play_footsteps(spd : float, loud : bool) -> void:
|
||||
if loud:
|
||||
body.play_footsteps(spd)
|
||||
|
||||
func stop_footsteps() -> void:
|
||||
body.stop_footsteps()
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if attack_timer > 0:
|
||||
@@ -142,26 +158,16 @@ func _physics_process(delta: float) -> void:
|
||||
knockdown(-fling_direction)
|
||||
hurt(10)
|
||||
moving = false
|
||||
State.NORMAL:
|
||||
State.NORMAL, State.DETECTING, State.INSTALLING:
|
||||
can_fall = true
|
||||
|
||||
if dir.length_squared() > 0:
|
||||
moving = true
|
||||
velocity = calculate_pawn_velocity(dir)
|
||||
facing = dir.normalized()
|
||||
body.look_at(body.global_position - dir)
|
||||
var y = velocity.y
|
||||
velocity = speed * dir
|
||||
if is_poisoned():
|
||||
velocity *= 0.5
|
||||
if is_crouching():
|
||||
velocity *= .33
|
||||
velocity.y = y
|
||||
if !detecting:
|
||||
body.play_footsteps(lerp(.78, .33, dir.length()))
|
||||
else:
|
||||
body.stop_footsteps()
|
||||
elif body != null:
|
||||
body.stop_footsteps()
|
||||
play_footsteps(lerp(.78, .33, dir.length()), true)
|
||||
else:
|
||||
stop_footsteps()
|
||||
if body != null:
|
||||
body.set_animation_parameter("parameters/Motion/blend_position", dir.length())
|
||||
body.set_animation_parameter("parameters/Crouch/blend_position", dir.length())
|
||||
@@ -171,12 +177,9 @@ func _physics_process(delta: float) -> void:
|
||||
else:
|
||||
moving = true
|
||||
can_fall = true
|
||||
State.KNOCKDOWN,State.BOUND,State.DEAD:
|
||||
return
|
||||
|
||||
|
||||
if can_fall:
|
||||
var down = 0
|
||||
if !is_on_floor():
|
||||
velocity.y = velocity.y + get_gravity().y * delta
|
||||
moving = true
|
||||
@@ -184,8 +187,9 @@ func _physics_process(delta: float) -> void:
|
||||
if moving:
|
||||
move_and_slide()
|
||||
|
||||
if detecting:
|
||||
if is_detecting():
|
||||
update_detect_region.rpc(true)
|
||||
|
||||
if range_sphere:
|
||||
update_range_sphere()
|
||||
#Deal with the rest of the buttons
|
||||
@@ -200,7 +204,7 @@ func _physics_process(delta: float) -> void:
|
||||
for button in buttons:
|
||||
if input.is_action_just_pressed(button):
|
||||
modal.button_pressed(button)
|
||||
elif state == State.NORMAL:
|
||||
else:
|
||||
update_actions()
|
||||
|
||||
@rpc("call_local", "reliable")
|
||||
@@ -213,15 +217,17 @@ func set_pawn_body(pb : PawnBody) -> void:
|
||||
body = pb
|
||||
pb.reloading.connect(reload_ranged)
|
||||
pb.shooting.connect(fire_ranged)
|
||||
reload_sound = body.find_child("ReloadSound")
|
||||
add_child(body)
|
||||
body.set_animation_length("Ranged Fire", ranged_recovery_time)
|
||||
struggling.connect(body._on_struggle_changed)
|
||||
|
||||
|
||||
func attack() -> void:
|
||||
if attack_timer > 0:
|
||||
return
|
||||
if meleeing:
|
||||
body.play_animation.rpc("melee")
|
||||
if can_melee:
|
||||
state = State.MELEE_ATTACKING
|
||||
attack_timer = melee_recovery_time
|
||||
else:
|
||||
if ammo <= 0:
|
||||
@@ -229,14 +235,14 @@ func attack() -> void:
|
||||
return
|
||||
|
||||
attack_timer = ranged_recovery_time
|
||||
shooting = true
|
||||
state = State.RANGED_ATTACKING
|
||||
take_shot = true
|
||||
if combat_target != null:
|
||||
var v = body.global_position.direction_to(combat_target.global_position)
|
||||
v.y = 0
|
||||
body.look_at(body.global_position - v)
|
||||
|
||||
|
||||
|
||||
func reload_ranged() -> void:
|
||||
reloading = false
|
||||
reload_sound.play()
|
||||
@@ -245,41 +251,44 @@ func reload_ranged() -> void:
|
||||
ammo_changed.emit(ammo, max_ammo)
|
||||
|
||||
func update_actions() -> void:
|
||||
if attack_timer <= 0 and shooting and !input.is_action_pressed("attack"):
|
||||
shooting = false
|
||||
|
||||
if state == State.DEAD:
|
||||
return
|
||||
|
||||
if attack_timer <= 0 and is_attacking():
|
||||
if !input.is_action_pressed("attack"):
|
||||
state = State.NORMAL
|
||||
elif is_shooting():
|
||||
if ammo <= 0:
|
||||
reloading = true
|
||||
else:
|
||||
take_shot = true
|
||||
|
||||
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 !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()
|
||||
Game.level.add_child(range_sphere)
|
||||
#Set the range sphere size based upon the current hack
|
||||
update_range_sphere()
|
||||
if input.is_action_just_released("install"):
|
||||
installing = false
|
||||
range_sphere.queue_free()
|
||||
range_sphere = null
|
||||
try_install_hack()
|
||||
match(state):
|
||||
State.NORMAL:
|
||||
if input.is_action_just_pressed("detonate"):
|
||||
detonate()
|
||||
if(input.is_action_just_pressed("detect")
|
||||
and input.is_action_pressed("detect")):
|
||||
start_detecting()
|
||||
return
|
||||
if(input.is_action_just_pressed("install")
|
||||
and input.is_action_pressed("install")):
|
||||
start_installing()
|
||||
return
|
||||
elif input.is_action_pressed("attack"):
|
||||
attack()
|
||||
elif input.is_action_just_released("install"):
|
||||
installing = false
|
||||
range_sphere.queue_free()
|
||||
range_sphere = null
|
||||
try_install_hack()
|
||||
State.DETECTING:
|
||||
if !input.is_action_pressed("detect"):
|
||||
stop_detecting()
|
||||
State.INSTALLING:
|
||||
if !input.is_action_pressed("install"):
|
||||
stop_installing()
|
||||
try_install_hack()
|
||||
|
||||
func update_range_sphere() -> void:
|
||||
var new_pos = (global_position - Vector3.ONE * .5).round() + Vector3(0.5, 0, 0.5)
|
||||
@@ -324,6 +333,7 @@ func fire_ranged() -> void:
|
||||
ammo-=1
|
||||
ammo_changed.emit(ammo, max_ammo)
|
||||
shot.speed = projectile_speed
|
||||
shot.id = id
|
||||
tdir = body.ranged_point.global_position.direction_to(combat_target.global_position) if combat_target else facing
|
||||
shot.direction = tdir
|
||||
shot.damage = projectile_damage
|
||||
@@ -368,10 +378,10 @@ func check_attack_target() -> void:
|
||||
ranged_closest = target
|
||||
ranged_d_sq = d_sq
|
||||
if melee_closest != null:
|
||||
meleeing = true
|
||||
can_melee = true
|
||||
combat_target = melee_closest
|
||||
else:
|
||||
meleeing = false
|
||||
can_melee = false
|
||||
if ranged_closest != null:
|
||||
combat_target = ranged_closest
|
||||
combat_target_changed.emit(melee_closest != null)
|
||||
@@ -423,21 +433,21 @@ func detect_alert() -> void:
|
||||
detect_tween.tween_callback(func(): detect_tween = null)
|
||||
|
||||
func close_modal() -> void:
|
||||
uninstalling = false
|
||||
state = State.NORMAL
|
||||
if modal != null:
|
||||
modal.queue_free()
|
||||
modal = null
|
||||
|
||||
func show_uninstall_hack_modal() -> void:
|
||||
stop_detecting()
|
||||
uninstalling = true
|
||||
state = State.UNINSTALLING
|
||||
modal = uninstall_hack_modal.instantiate()
|
||||
modal.square = current_square
|
||||
Game.level.add_child(modal)
|
||||
|
||||
func show_decompile_hack_modal() -> void:
|
||||
stop_detecting()
|
||||
uninstalling = true
|
||||
state = State.UNINSTALLING
|
||||
modal = decompile_hack_modal.instantiate()
|
||||
modal.difficulty = Game.level.difficulty
|
||||
modal.square = current_square
|
||||
@@ -451,8 +461,23 @@ func show_decompile_hack_modal() -> void:
|
||||
Game.level.add_child(modal)
|
||||
|
||||
func start_detecting() -> void:
|
||||
detecting = true
|
||||
update_detect_region.rpc(false)
|
||||
state = State.DETECTING
|
||||
update_detect_region(false)
|
||||
|
||||
func start_installing() -> void:
|
||||
state = State.INSTALLING
|
||||
if id == Multiplayer.id:
|
||||
if range_sphere != null:
|
||||
range_sphere.queue_free()
|
||||
range_sphere = range_sphere_template.instantiate()
|
||||
Game.level.add_child(range_sphere)
|
||||
#Set the range sphere size based upon the current hack
|
||||
update_range_sphere()
|
||||
|
||||
func stop_installing() -> void:
|
||||
state = State.NORMAL
|
||||
range_sphere.queue_free()
|
||||
range_sphere = null
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
func update_detect_region(update : bool) -> void:
|
||||
@@ -477,13 +502,14 @@ func update_detect_region(update : bool) -> void:
|
||||
|
||||
var remove_list = []
|
||||
var hack_detected : bool = false
|
||||
var hack : Hack
|
||||
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 hack = Game.level.get_square_hack(sq + Vector3i(0,1,0))
|
||||
hack = Game.level.get_square_hack(sq + Vector3i(0,1,0))
|
||||
if hack and hack.is_just_revealed():
|
||||
hack_detected = true
|
||||
|
||||
@@ -495,7 +521,7 @@ func update_detect_region(update : bool) -> void:
|
||||
for key in remove_list:
|
||||
detect_squares.erase(key)
|
||||
|
||||
var hack : Hack = Game.level.get_square_hack(current_square)
|
||||
hack = Game.level.get_square_hack(current_square)
|
||||
if hack != null:
|
||||
if hack.hack_owner == Multiplayer.id:
|
||||
show_uninstall_hack_modal()
|
||||
@@ -504,7 +530,7 @@ func update_detect_region(update : bool) -> void:
|
||||
show_decompile_hack_modal()
|
||||
|
||||
func stop_detecting() -> void:
|
||||
detecting = false
|
||||
state = State.NORMAL
|
||||
clear_detect_region.rpc()
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
@@ -516,8 +542,8 @@ func clear_detect_region() -> void:
|
||||
detect_squares = {}
|
||||
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
func setup(id : int, pawn : StringName) -> void:
|
||||
self.id = id
|
||||
func setup(p_id : int, pawn : StringName) -> void:
|
||||
id = p_id
|
||||
var base_data : PawnBaseData = Game.pawns[pawn]
|
||||
var hacklist : Array[PawnLevelData.HackData] = []
|
||||
for hack in base_data.starting_hacks:
|
||||
@@ -564,9 +590,11 @@ func hurt(damage : int) -> void:
|
||||
health_changed.emit(data.life, data.max_life)
|
||||
if data.life == 0:
|
||||
die.rpc()
|
||||
@rpc("any_peer", "call_local")
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
func die() -> void:
|
||||
state = State.DEAD
|
||||
body.travel_animation("Death")
|
||||
input_locked = true
|
||||
if id == Multiplayer.id:
|
||||
var death_tween = create_tween()
|
||||
@@ -578,21 +606,15 @@ 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
|
||||
d.max_quantity -= 1
|
||||
hack_quantity_changed.emit(i, d.quantity)
|
||||
break
|
||||
#hurt
|
||||
#blast
|
||||
#blast_players
|
||||
#activate
|
||||
#activate_hack
|
||||
#fail
|
||||
#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)
|
||||
d.quantity = min(d.max_quantity, d.quantity+ 1)
|
||||
hack_quantity_changed.emit(i, d.quantity)
|
||||
break
|
||||
|
||||
@@ -623,10 +645,10 @@ func poison(damage : int, length : float) -> void:
|
||||
pshader.set_shader_parameter("strength", 0.5)
|
||||
poison_status_changed.emit(true)
|
||||
|
||||
func fling(direction : Vector3, speed : float) -> void:
|
||||
func fling(direction : Vector3, spd : float) -> void:
|
||||
state = State.FLUNG
|
||||
fling_direction = direction
|
||||
fling_speed = speed
|
||||
fling_speed = spd
|
||||
fling_sound.play()
|
||||
|
||||
func knockdown(direction : Vector3) -> void:
|
||||
@@ -641,14 +663,14 @@ func knockdown(direction : Vector3) -> void:
|
||||
knockdown_tween.tween_property(self, "input_locked", false, 0)
|
||||
knockdown_tween.tween_callback(Callable(body.look_at).bind(facing, Vector3(0,1,0)))
|
||||
|
||||
func knockup(velocity : Vector3) -> void:
|
||||
func knockup(vel : Vector3) -> void:
|
||||
if state != State.KNOCKUP:
|
||||
state = State.KNOCKUP
|
||||
input_locked = true
|
||||
if is_on_floor():
|
||||
self.velocity = Vector3.UP * .1
|
||||
velocity = Vector3.UP * .1
|
||||
move_and_slide()
|
||||
self.velocity = velocity
|
||||
velocity = vel
|
||||
|
||||
func knockback(direction : Vector3, impact : float) -> void:
|
||||
if state != State.NORMAL:
|
||||
@@ -672,14 +694,46 @@ func start_pitfall(square : Vector3, duration : float) -> void:
|
||||
tween.tween_property(self, "input_locked", false, 0)
|
||||
tween.tween_callback(pitfall.bind(duration))
|
||||
|
||||
func _on_melee_hit(body : Node3D) -> void:
|
||||
func _on_melee_hit(_body : Node3D) -> void:
|
||||
#TODO: WRITE THE MELEE DAMAGE CODE
|
||||
pass
|
||||
|
||||
|
||||
func is_attacking() -> bool:
|
||||
return state == State.RANGED_ATTACKING or state == State.MELEE_ATTACKING
|
||||
|
||||
func is_meleeing() -> bool:
|
||||
return state == State.MELEE_ATTACKING
|
||||
func is_shooting() -> bool:
|
||||
return state == State.RANGED_ATTACKING
|
||||
|
||||
func is_dead() -> bool:
|
||||
return state == State.DEAD
|
||||
|
||||
func is_detecting() -> bool:
|
||||
return detecting
|
||||
return state == State.DETECTING
|
||||
|
||||
func is_installing() -> bool:
|
||||
return state == State.INSTALLING
|
||||
|
||||
func is_uninstalling() -> bool:
|
||||
return state == State.UNINSTALLING
|
||||
|
||||
func is_crouching() -> bool:
|
||||
return detecting or installing or uninstalling
|
||||
var result : bool = false
|
||||
match(state):
|
||||
State.DETECTING: result = true
|
||||
State.INSTALLING: result = true
|
||||
State.UNINSTALLING: result = true
|
||||
return result
|
||||
|
||||
func add_random_hack(advanced : bool) -> void:
|
||||
#TODO: Add random hack spawning using RPCs
|
||||
pass
|
||||
|
||||
func pickup(type : Pickup.Type) -> void:
|
||||
if id != Multiplayer.id:
|
||||
return
|
||||
match(type):
|
||||
Pickup.Type.DATABLOCK: print("Datablock picked up!")
|
||||
Pickup.Type.BASIC_HACK: add_random_hack(false)
|
||||
|
||||
Reference in New Issue
Block a user