Pawn bodies split out, character select redesigned, and started the dreaded process of correcting the netcode. Players can connect to a shared room, character select, and start a match. They appear correctly differentiated with cameras and map icons that follow them independently. Jankiness with trap ownership is present as is stuff connected to animation. Unit tests for all network functionality required.
This commit is contained in:
@@ -7,6 +7,16 @@ enum Modes{
|
||||
VS_MAN
|
||||
}
|
||||
|
||||
|
||||
var pawns : Dictionary = {
|
||||
"A" : load("res://data/pawns/a.tres"),
|
||||
"B" : load("res://data/pawns/b.tres"),
|
||||
"C" : load("res://data/pawns/c.tres"),
|
||||
"D" : load("res://data/pawns/d.tres"),
|
||||
"E" : load("res://data/pawns/e.tres"),
|
||||
"F" : load("res://data/pawns/f.tres")
|
||||
}
|
||||
|
||||
const blinder_template = preload("res://templates/blinder.tscn")
|
||||
const one_shot_template = preload("res://templates/one_shot.tscn")
|
||||
|
||||
@@ -15,13 +25,14 @@ const vs_com_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 cmd_args : Dictionary = {}
|
||||
var player : PawnController
|
||||
var hud : HUD
|
||||
var level : Level
|
||||
var mode : Modes = Modes.STORY
|
||||
var multiplayer_game : bool = false
|
||||
var num_players : int = 1
|
||||
var pawns_selected : Dictionary[int, PawnBaseData] = {}
|
||||
var pawns_selected : Dictionary[int, StringName] = {}
|
||||
var level_synced : Dictionary[int, bool] = {}
|
||||
var net_test : bool #TODO: Remove later
|
||||
|
||||
@@ -30,16 +41,21 @@ func _ready() -> void:
|
||||
for arg in OS.get_cmdline_args():
|
||||
if arg.begins_with("--"):
|
||||
var flag = arg.lstrip("--")
|
||||
if flag.contains("="):
|
||||
var key_val = flag.split("=")
|
||||
args[key_val[0]]=key_val[1]
|
||||
args[flag]=true
|
||||
if args.has("net_test"):
|
||||
net_test = true
|
||||
|
||||
if args.has("instance_id"):
|
||||
get_tree().root.title = "Net Gunner (Instance: %s)" % args.instance_id
|
||||
cmd_args = args
|
||||
|
||||
func setup_player(pc : PawnController) -> void:
|
||||
var is_local = false
|
||||
Game.level.pawns[pc.id] = pc
|
||||
if pc.id == Multiplayer.id:
|
||||
is_local = true
|
||||
level.pawns[pc.id] = pc
|
||||
if is_local:
|
||||
player = pc
|
||||
if hud:
|
||||
@@ -49,10 +65,11 @@ func is_multiplayer() -> bool:
|
||||
return multiplayer_game
|
||||
|
||||
|
||||
func start_level(pawns : Dictionary[int, PawnBaseData]) -> void:
|
||||
func start_level(pawns : Dictionary[int, StringName]) -> void:
|
||||
pawns_selected = pawns
|
||||
if !Multiplayer.is_host():
|
||||
return
|
||||
pawns_selected = pawns
|
||||
|
||||
for i in Multiplayer.players.values():
|
||||
level_synced[i] = false
|
||||
level_synced[1] = true
|
||||
@@ -117,7 +134,6 @@ func level_spawned(peer_id : int) -> void:
|
||||
level_synced[peer_id] = true
|
||||
check_level_ready()
|
||||
|
||||
|
||||
func check_level_ready() -> void:
|
||||
var ready : bool = true
|
||||
for id in level_synced:
|
||||
|
||||
@@ -34,11 +34,11 @@ func become_host() -> void:
|
||||
print("Hosting Room...")
|
||||
var room_id = await server_peer.room_connected
|
||||
print("Connected to room: ", server_peer.room_id)
|
||||
server_peer.get_rooms()
|
||||
#server_peer.get_rooms()
|
||||
print("GETTING ROOMS!")
|
||||
var rooms = await server_peer.rooms_received
|
||||
#var rooms = await server_peer.rooms_received
|
||||
print("GOT ROOMS!")
|
||||
print(rooms)
|
||||
#print(rooms)
|
||||
players[handle] = 1
|
||||
player_readiness[1] = false
|
||||
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
extends Control
|
||||
class_name CharacterSelect extends Control
|
||||
|
||||
|
||||
const pawns : Array[PawnBaseData] = [
|
||||
preload("res://data/pawns/van_reily.tres"),
|
||||
preload("res://data/pawns/lou_riche.tres"),
|
||||
preload("res://data/pawns/tico.tres"),
|
||||
preload("res://data/pawns/john_bishous.tres"),
|
||||
preload("res://data/pawns/abdoll_relin.tres"),
|
||||
preload("res://data/pawns/tenrou_ugetsu.tres")
|
||||
]
|
||||
|
||||
const p_colors : Array[Color] = [
|
||||
Color.ROYAL_BLUE,
|
||||
@@ -16,34 +9,53 @@ const p_colors : Array[Color] = [
|
||||
|
||||
|
||||
const selector_template = preload("res://templates/pawn_selector.tscn")
|
||||
|
||||
@onready var pawn_displays : Array[PawnDisplay] = [
|
||||
%P1PawnDisplay,
|
||||
%P2PawnDisplay
|
||||
]
|
||||
const pawn_pick_portrait_template = preload("res://templates/pawn_pick_portrait.tscn")
|
||||
|
||||
var selector_wait : float = 0
|
||||
var selected : int = -1
|
||||
var selectors : Dictionary[int,PawnSelector] = {}
|
||||
var displays : Dictionary[int, PawnDisplay] = {}
|
||||
var portraits : Dictionary[Vector2i, PawnPickPortrait] = {}
|
||||
|
||||
var announce_tween : Tween = null
|
||||
@onready var announcer : AudioStreamPlayer = %Announcer
|
||||
@onready var selector_start : Control = %SelectorStart
|
||||
@onready var switch_sound : AudioStreamPlayer = %SwitchSound
|
||||
@onready var select_sound : AudioStreamPlayer = %SelectSound
|
||||
@onready var portrait_grid : GridContainer = %PawnPickPortraits
|
||||
@onready var pawn_displays : Control = %PawnDisplays
|
||||
|
||||
func _ready() -> void:
|
||||
var i : int = 0
|
||||
var idx : Vector2i = Vector2i.ZERO
|
||||
for pawn in Game.pawns.values():
|
||||
var pp : PawnPickPortrait = pawn_pick_portrait_template.instantiate()
|
||||
portrait_grid.add_child(pp)
|
||||
pp.setup(pawn, i)
|
||||
portraits[idx] = pp
|
||||
|
||||
i+=1
|
||||
idx.x += 1
|
||||
if idx.x >= portrait_grid.columns:
|
||||
idx.y += 1
|
||||
idx.x -= portrait_grid.columns
|
||||
|
||||
Multiplayer.waiting = true
|
||||
var plist
|
||||
if Game.is_multiplayer():
|
||||
plist = Multiplayer.players.values()
|
||||
for i in range(Game.num_players):
|
||||
displays[plist[i]] = pawn_displays[i]
|
||||
change_display(plist[i], 0)
|
||||
for id in range(Game.num_players):
|
||||
var display : PawnDisplay = pawn_displays.get_child(id)
|
||||
displays[plist[id]] = display
|
||||
display.visible = true
|
||||
portraits[Vector2i.ZERO].num_players += 1
|
||||
change_display(plist[id], 0)
|
||||
else:
|
||||
displays[1] = pawn_displays[0]
|
||||
displays[1] = pawn_displays.get_child(0)
|
||||
displays[1].visible = true
|
||||
change_display(1, 0)
|
||||
portraits[Vector2i.ZERO].num_players += 1
|
||||
|
||||
Multiplayer.all_ready.connect(add_selector, CONNECT_ONE_SHOT)
|
||||
Multiplayer.set_player_ready.rpc(Multiplayer.id)
|
||||
#Set up each pawn on bottom
|
||||
@@ -67,12 +79,12 @@ func _process(delta : float) -> void:
|
||||
if !selectors.has(Multiplayer.id):
|
||||
return
|
||||
var locked = true
|
||||
var pawns_selected : Dictionary[int, PawnBaseData] = {}
|
||||
var pawns_selected : Dictionary[int, StringName] = {}
|
||||
for selector : PawnSelector in selectors.values():
|
||||
if !selector.selected:
|
||||
locked = false
|
||||
else:
|
||||
pawns_selected[selector.player_id] = pawns[selector.selection]
|
||||
pawns_selected[selector.player_id] = portraits[selector.selection].pawn.name
|
||||
if locked:
|
||||
Game.start_level(pawns_selected)
|
||||
|
||||
@@ -88,25 +100,25 @@ func _process(delta : float) -> void:
|
||||
|
||||
input_vector = Input.get_vector("west","east","north","south")
|
||||
|
||||
var move_dir : Vector2 = Vector2.ZERO
|
||||
var move_dir : Vector2i = Vector2.ZERO
|
||||
|
||||
if input_vector.x < 0:
|
||||
move_dir.x -= 1
|
||||
|
||||
if input_vector.x > 0:
|
||||
move_dir.x += 1
|
||||
|
||||
if move_dir.x != 0:
|
||||
move_selector.rpc(selector.player_id, wrapi(selector.selection + sign(move_dir.x),0, len(pawns)))
|
||||
move_dir = Vector2i((input_vector + .499 * sign(input_vector)).round())
|
||||
if move_dir.length_squared() != 0:
|
||||
var selection : Vector2i = selector.selection + move_dir
|
||||
selection.x = wrapi(selection.x, 0, portrait_grid.columns)
|
||||
selection.y = wrapi(selection.y, 0, ceili(float(portrait_grid.get_child_count()) / portrait_grid.columns))
|
||||
move_selector.rpc(selector.player_id, selection)
|
||||
selector_wait = 0.25
|
||||
|
||||
@rpc("any_peer","call_local","reliable")
|
||||
func move_selector(peer_id : int, selection : int) -> void:
|
||||
func move_selector(peer_id : int, selection : Vector2i) -> void:
|
||||
var selector : PawnSelector = selectors[peer_id]
|
||||
selector.selection = selection
|
||||
change_display(peer_id, selector.selection)
|
||||
var v = Vector2(175 * selector.selection, 0)
|
||||
selector.position = Vector2(175 * selector.selection, 0)
|
||||
portraits[selector.selection].num_players -= 1
|
||||
selector.selection = selection
|
||||
portraits[selector.selection].num_players += 1
|
||||
change_display(peer_id, portraits[selector.selection].pawn_idx)
|
||||
var v = Vector2(154 * selector.selection.x, 154 * selector.selection.y)
|
||||
selector.position = v
|
||||
switch_sound.play()
|
||||
if announce_tween != null and announce_tween.is_running():
|
||||
announce_tween.stop()
|
||||
@@ -114,7 +126,7 @@ func move_selector(peer_id : int, selection : int) -> void:
|
||||
announcer.stop()
|
||||
announce_tween = create_tween()
|
||||
announce_tween.tween_interval(.25)
|
||||
announcer.stream = pawns[selection].name_audio
|
||||
announcer.stream = portraits[selection].pawn.name_audio
|
||||
announce_tween.tween_callback(announcer.play)
|
||||
|
||||
@rpc("any_peer","call_local","reliable")
|
||||
@@ -126,9 +138,10 @@ func lock_selector(peer_id : int) -> void:
|
||||
|
||||
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_hacks(pawns[selection].starting_hacks)
|
||||
var pawn : PawnBaseData = Game.pawns.values()[selection]
|
||||
pd.set_pawn_name(pawn.name)
|
||||
pd.set_portrait(pawn.portrait)
|
||||
pd.set_hacks(pawn.starting_hacks)
|
||||
|
||||
|
||||
func _on_selector_start_child_entered_tree(node: Node) -> void:
|
||||
|
||||
@@ -108,7 +108,6 @@ func _on_reveal_timeout() -> void:
|
||||
|
||||
func _ready() -> void:
|
||||
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
|
||||
|
||||
@@ -24,7 +24,7 @@ const camera_offset = Vector3(0, 10, 5.25)
|
||||
@onready var cameras_node : Node3D = %Cameras
|
||||
@onready var map_markers_node : Node3D = %MapMarkers
|
||||
@onready var spawn_points : Array[Node] = $PawnSpawner.get_children()
|
||||
|
||||
@onready var multiplayer_level_setup : MultiplayerLevelSetup = %MultiplayerLevelSetup
|
||||
@export var difficulty : int = 1
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ var cameras : Dictionary[int, PawnCamera] = {}
|
||||
var map_markers : Dictionary[Object, MapMarker] = {}
|
||||
|
||||
func _ready() -> void:
|
||||
process_mode=Node.PROCESS_MODE_DISABLED
|
||||
Game.level = self
|
||||
if Game.mode == Game.Modes.STORY:
|
||||
setup()
|
||||
@@ -43,20 +44,45 @@ func setup() -> void:
|
||||
if Multiplayer.is_host():
|
||||
spawn_players()
|
||||
|
||||
|
||||
@rpc("authority")
|
||||
func spawn_players() -> void:
|
||||
if Game.is_multiplayer():
|
||||
spawn_players_multiplayer()
|
||||
else:
|
||||
spawn_players_singleplayer()
|
||||
|
||||
func spawn_players_singleplayer() -> void:
|
||||
var pc : PawnController = pawn_controller.instantiate()
|
||||
pawns[1] = pc
|
||||
pawns_node.add_child(pc,true)
|
||||
var position : Vector3
|
||||
if(spawn_points == null
|
||||
or len(spawn_points) <= 1):
|
||||
position = Vector3(0,0,0)
|
||||
else:
|
||||
position = spawn_points[0].global_position
|
||||
pc.global_position = position
|
||||
pc.setup(1, Game.pawns_selected[1])
|
||||
add_pawn_camera(pc)
|
||||
cameras[1].register_pawn(1)
|
||||
process_mode=Node.PROCESS_MODE_INHERIT
|
||||
|
||||
func spawn_players_multiplayer() -> void:
|
||||
var count = 0
|
||||
|
||||
multiplayer_level_setup.set_players_unready(Multiplayer.players.values())
|
||||
multiplayer_level_setup.set_pawns_expected.rpc(Game.pawns_selected.size())
|
||||
|
||||
for key in Game.pawns_selected:
|
||||
var pc : PawnController = pawn_controller.instantiate()
|
||||
var pd = Game.pawns_selected[key]
|
||||
pawns[key] = pc
|
||||
pawns_node.add_child(pc,true)
|
||||
var hacks : Array = []
|
||||
for hack : HackSet in pd.starting_hacks:
|
||||
var dict = {
|
||||
"type":hack.type,
|
||||
"qty":hack.qty
|
||||
}
|
||||
hacks.append(dict)
|
||||
|
||||
|
||||
await multiplayer_level_setup.all_players_ready
|
||||
|
||||
for key in pawns:
|
||||
var pc = pawns[key]
|
||||
var position : Vector3
|
||||
if(spawn_points == null
|
||||
or len(spawn_points) <= count):
|
||||
@@ -66,10 +92,23 @@ func spawn_players() -> void:
|
||||
position = Vector3(3,0,0)
|
||||
else:
|
||||
position = spawn_points[count].global_position
|
||||
pc.setup.rpc(key,hacks,position)
|
||||
add_pawn_camera(pc)
|
||||
count += 1
|
||||
|
||||
pc.global_position = position
|
||||
pc.setup.rpc(key, Game.pawns_selected[key])
|
||||
|
||||
multiplayer_level_setup.set_players_unready(Multiplayer.players.values())
|
||||
multiplayer_level_setup.set_cameras_expected.rpc(Game.pawns_selected.size())
|
||||
for pc in pawns.values():
|
||||
add_pawn_camera(pc)
|
||||
|
||||
await multiplayer_level_setup.all_players_ready
|
||||
setup_cameras()
|
||||
start_level.rpc()
|
||||
|
||||
@rpc("authority", "call_local")
|
||||
func start_level() -> void:
|
||||
process_mode=Node.PROCESS_MODE_INHERIT
|
||||
|
||||
|
||||
func is_square_detected(crd) -> bool:
|
||||
return marker_layer.get_cell_item(crd + Vector3i(0,-1,0)) != GridMap.INVALID_CELL_ITEM
|
||||
@@ -88,15 +127,21 @@ func detect_square(crd : Vector3i, mark : bool) -> bool:
|
||||
hack.reveal()
|
||||
return true
|
||||
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func add_pawn_camera(pawn : PawnController) -> void:
|
||||
if Multiplayer.is_host():
|
||||
var camera : PawnCamera = camera_template.instantiate()
|
||||
camera.position = pawn.global_position + camera_offset
|
||||
cameras_node.add_child(camera,true)
|
||||
camera.register_pawn.rpc(pawn.id)
|
||||
cameras[pawn.id] = camera
|
||||
|
||||
|
||||
|
||||
func setup_cameras() -> void:
|
||||
var camera_list = cameras_node.get_children()
|
||||
var idx = 0
|
||||
for pawn_id in pawns:
|
||||
camera_list[idx].register_pawn.rpc(pawn_id)
|
||||
cameras[pawn_id] = camera_list[idx]
|
||||
idx += 1
|
||||
|
||||
func add_hack(hack : Hack, crd : Vector3i) -> void:
|
||||
hack.square = crd
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
extends Level
|
||||
|
||||
#const pawn_controller_template = preload("res://templates/pawn_controller.tscn")
|
||||
#
|
||||
#@onready var player_spawner = %Spawner
|
||||
#func _ready() -> void:
|
||||
#print("LEVEL LOADING, ID: " + str(Multiplayer.id) + " with " + str(Multiplayer.players.size()) + " keys recognized")
|
||||
#Game.level = self
|
||||
#
|
||||
#func setup() -> void:
|
||||
#if Multiplayer.is_host():
|
||||
#spawn_players()
|
||||
#
|
||||
#func spawn_players() -> void:
|
||||
#for key in Game.pawns_selected:
|
||||
#var pc : PawnController = pawn_controller_template.instantiate()
|
||||
#var pd = Game.pawns_selected[key]
|
||||
#player_spawner.add_pawn(pc, key)
|
||||
#pc.setup(key,pd.starting_hacks)
|
||||
62
scripts/multiplayer_level_setup.gd
Normal file
62
scripts/multiplayer_level_setup.gd
Normal file
@@ -0,0 +1,62 @@
|
||||
class_name MultiplayerLevelSetup extends Node
|
||||
|
||||
|
||||
var players_ready : Dictionary[int, bool] = {}
|
||||
var pawns_expected : int = 1
|
||||
var cameras_expected : int = 1
|
||||
|
||||
signal all_pawns_spawned()
|
||||
signal all_cameras_spawned()
|
||||
signal all_players_ready()
|
||||
|
||||
@rpc("authority", "reliable")
|
||||
func set_pawns_expected(num : int) -> void:
|
||||
all_pawns_spawned.connect(_on_all_pawns_spawned, CONNECT_ONE_SHOT)
|
||||
print("(Instance %s) Expecting %d Pawns" % [Game.cmd_args.instance_id, num])
|
||||
pawns_expected = num
|
||||
|
||||
func set_players_unready(list : Array) -> void:
|
||||
players_ready = {}
|
||||
for id in list:
|
||||
players_ready[id] = false
|
||||
players_ready[1] = true
|
||||
|
||||
func check_all_ready() -> bool:
|
||||
for id in players_ready:
|
||||
if !players_ready[id]:
|
||||
return false
|
||||
return true
|
||||
|
||||
func _on_all_pawns_spawned() -> void:
|
||||
player_ready.rpc_id(1,Multiplayer.id)
|
||||
|
||||
func _on_all_cameras_spawned() -> void:
|
||||
player_ready.rpc_id(1,Multiplayer.id)
|
||||
|
||||
@rpc("any_peer", "reliable")
|
||||
func player_ready(id : int) -> void:
|
||||
print("(Instance %s) Player %d notified ready" % [Game.cmd_args.instance_id, id])
|
||||
players_ready[id] = true
|
||||
if(check_all_ready()):
|
||||
print("(Instance %s) ALL PLAYERS READY!!" % [Game.cmd_args.instance_id])
|
||||
all_players_ready.emit()
|
||||
|
||||
@rpc("authority", "reliable")
|
||||
func set_cameras_expected(num : int) -> void:
|
||||
all_cameras_spawned.connect(_on_all_cameras_spawned, CONNECT_ONE_SHOT)
|
||||
cameras_expected = num
|
||||
|
||||
|
||||
func _on_pawn_spawner_spawned(node: Node) -> void:
|
||||
print("(Instance %s) Spawned %d Pawn" % [Game.cmd_args.instance_id, node.id])
|
||||
pawns_expected -= 1
|
||||
if pawns_expected == 0:
|
||||
print("(Instance %s) ALL PAWNS SPAWNED!" % [Game.cmd_args.instance_id])
|
||||
all_pawns_spawned.emit()
|
||||
|
||||
|
||||
|
||||
func _on_camera_spawner_spawned(node: Node) -> void:
|
||||
cameras_expected -= 1
|
||||
if cameras_expected == 0:
|
||||
all_cameras_spawned.emit()
|
||||
1
scripts/multiplayer_level_setup.gd.uid
Normal file
1
scripts/multiplayer_level_setup.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b5npi1ys4lnf4
|
||||
18
scripts/multiplayer_test_level.gd
Normal file
18
scripts/multiplayer_test_level.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
extends Node3D
|
||||
|
||||
func _enter_tree() -> void:
|
||||
|
||||
Game.pawns_selected[1] = Game.pawns.keys()[0]
|
||||
Multiplayer.client_added.connect(_on_client_added)
|
||||
|
||||
#SETUP HOST:
|
||||
if !Game.net_test:
|
||||
var handle = "Host - P1"
|
||||
Multiplayer.handle = handle
|
||||
#Validate entries
|
||||
Multiplayer.become_host()
|
||||
|
||||
|
||||
func _on_client_added(handle : String, id : int) -> void:
|
||||
pass
|
||||
|
||||
@@ -13,6 +13,9 @@ class_name PawnBody extends Node3D
|
||||
@onready var walk_sound : AudioStreamPlayer3D = $WalkSound
|
||||
@onready var footstep_timer : Timer = $FootstepTimer
|
||||
|
||||
signal shooting()
|
||||
signal reloading()
|
||||
|
||||
@rpc("call_local")
|
||||
func play_animation(anim_name : String) -> void:
|
||||
anim_player.play(anim_name)
|
||||
|
||||
@@ -4,6 +4,7 @@ class_name PawnCamera extends Camera3D
|
||||
var target
|
||||
var player_offset : Vector3
|
||||
|
||||
@export var player_id = 1
|
||||
@export var decay = 0.9 # How quickly the shaking stops [0, 1].
|
||||
@export var max_offset = Vector2(2, 1.5) # Maximum hor/ver shake in pixels.
|
||||
|
||||
|
||||
@@ -15,9 +15,10 @@ 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 pawn_name : StringName
|
||||
@export var speed : float = 10
|
||||
|
||||
@onready var body : PawnBody = $PawnBody
|
||||
@onready var body : PawnBody
|
||||
@onready var input : PawnInput = $PawnInput
|
||||
@onready var data : PawnLevelData = $Data
|
||||
@onready var hack_sound : AudioStreamPlayer3D = $HackSound
|
||||
@@ -28,7 +29,7 @@ const range_sphere_template = preload("res://templates/range_sphere.tscn")
|
||||
@onready var reload_sound : AudioStreamPlayer3D = $PawnBody/ReloadSound
|
||||
@onready var detect_icon : Sprite3D = $DetectIcon
|
||||
|
||||
var id : int = 1
|
||||
@export var id : int = 1
|
||||
|
||||
@export var state : State
|
||||
var button_actions : Dictionary[int, String]
|
||||
@@ -62,6 +63,8 @@ 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
|
||||
|
||||
|
||||
@@ -95,6 +98,8 @@ func _exit_tree() -> void:
|
||||
#Game.level.evaluate_outcome()
|
||||
#Game.evaluate
|
||||
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if attack_timer > 0:
|
||||
attack_timer -= delta
|
||||
@@ -155,10 +160,11 @@ func _physics_process(delta: float) -> void:
|
||||
body.play_footsteps(lerp(.78, .33, dir.length()))
|
||||
else:
|
||||
body.stop_footsteps()
|
||||
else:
|
||||
elif body != null:
|
||||
body.stop_footsteps()
|
||||
body.set_animation_parameter("parameters/Motion/blend_position", dir.length())
|
||||
body.set_animation_parameter("parameters/Crouch/blend_position", dir.length())
|
||||
if body != null:
|
||||
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)
|
||||
@@ -197,6 +203,20 @@ func _physics_process(delta: float) -> void:
|
||||
elif state == State.NORMAL:
|
||||
update_actions()
|
||||
|
||||
@rpc("call_local", "reliable")
|
||||
func setup_pawn_body(pd : PawnBaseData) -> void:
|
||||
set_pawn_body(pd.pawn_body.instantiate())
|
||||
|
||||
func set_pawn_body(pb : PawnBody) -> void:
|
||||
if body != null:
|
||||
body.queue_free()
|
||||
body = pb
|
||||
pb.reloading.connect(reload_ranged)
|
||||
pb.shooting.connect(fire_ranged)
|
||||
add_child(body)
|
||||
struggling.connect(body._on_struggle_changed)
|
||||
|
||||
|
||||
func attack() -> void:
|
||||
if attack_timer > 0:
|
||||
return
|
||||
@@ -205,22 +225,25 @@ func attack() -> void:
|
||||
attack_timer = melee_recovery_time
|
||||
else:
|
||||
if ammo <= 0:
|
||||
reload_sound.play()
|
||||
ammo = max_ammo
|
||||
attack_timer = ranged_reload_time
|
||||
ammo_changed.emit(ammo, max_ammo)
|
||||
reloading = true
|
||||
return
|
||||
|
||||
ammo-=1
|
||||
ammo_changed.emit(ammo, max_ammo)
|
||||
attack_timer = ranged_recovery_time
|
||||
shooting == true
|
||||
shooting = true
|
||||
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()
|
||||
ammo = max_ammo
|
||||
attack_timer = ranged_reload_time
|
||||
ammo_changed.emit(ammo, max_ammo)
|
||||
|
||||
func update_actions() -> void:
|
||||
if attack_timer <= 0 and shooting and !input.is_action_pressed("attack"):
|
||||
shooting = false
|
||||
@@ -297,6 +320,9 @@ func update_poison(delta : float) -> void:
|
||||
func fire_ranged() -> void:
|
||||
var shot = body.projectile_template.instantiate()
|
||||
var tdir : Vector3 = Vector3.ZERO
|
||||
take_shot = false
|
||||
ammo-=1
|
||||
ammo_changed.emit(ammo, max_ammo)
|
||||
shot.speed = projectile_speed
|
||||
tdir = body.ranged_point.global_position.direction_to(combat_target.global_position) if combat_target else facing
|
||||
shot.direction = tdir
|
||||
@@ -490,15 +516,15 @@ func clear_detect_region() -> void:
|
||||
detect_squares = {}
|
||||
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
func setup(id : int, hacks : Array, pos : Vector3) -> void:
|
||||
func setup(id : int, pawn : StringName) -> void:
|
||||
self.id = id
|
||||
self.global_position = pos
|
||||
var base_data : PawnBaseData = Game.pawns[pawn]
|
||||
var hacklist : Array[PawnLevelData.HackData] = []
|
||||
for hack in hacks:
|
||||
for hack in base_data.starting_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)
|
||||
setup_pawn_body(base_data)
|
||||
Game.setup_player(self)
|
||||
|
||||
func uninstall_hack_at(square) -> void:
|
||||
|
||||
25
scripts/pawn_pick_portrait.gd
Normal file
25
scripts/pawn_pick_portrait.gd
Normal file
@@ -0,0 +1,25 @@
|
||||
class_name PawnPickPortrait extends Panel
|
||||
|
||||
@onready var portrait : TextureRect = %Portrait
|
||||
@onready var cover : Control = %Cover
|
||||
var pawn : PawnBaseData
|
||||
var pawn_idx : int
|
||||
var _players : int = 0
|
||||
|
||||
var num_players : int :
|
||||
get:
|
||||
return _players
|
||||
set(value):
|
||||
_players = value
|
||||
if cover != null:
|
||||
cover.visible = (_players == 0)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
pass
|
||||
|
||||
func setup(data : PawnBaseData, idx : int) -> void:
|
||||
pawn = data
|
||||
pawn_idx = idx
|
||||
if portrait != null:
|
||||
portrait.texture = data.portrait
|
||||
1
scripts/pawn_pick_portrait.gd.uid
Normal file
1
scripts/pawn_pick_portrait.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dqpoa5x8u3r3h
|
||||
@@ -2,7 +2,7 @@ class_name PawnSelector extends TextureRect
|
||||
|
||||
@onready var anim_player : AnimationPlayer = $AnimationPlayer
|
||||
@export var player_id : int
|
||||
@export var selection : int = 0
|
||||
@export var selection : Vector2i = Vector2.ZERO
|
||||
@export var selected : bool
|
||||
|
||||
func setup(id : int, color : Color) -> void:
|
||||
|
||||
@@ -3,6 +3,6 @@ extends Node3D
|
||||
@onready var level : Level = $Level
|
||||
|
||||
func _ready() -> void:
|
||||
Game.pawns_selected[1] = load("res://data/pawns/van_reily.tres")
|
||||
Game.pawns_selected[1] = "a"
|
||||
level.setup()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user