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:
2026-03-10 01:41:15 -04:00
parent 984567cf96
commit d128501f7c
52 changed files with 1179 additions and 929 deletions

View File

@@ -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: