enemy movement should be deterministic now

This commit is contained in:
2026-02-11 05:37:55 +11:00
parent b72b05f33b
commit a2dc8f1630
15 changed files with 75 additions and 45 deletions

View File

@@ -43,7 +43,7 @@ func process_state(_delta: float) -> void:
hero.edit_tool.interact_key_held = false hero.edit_tool.interact_key_held = false
if Input.is_action_just_pressed("Swap Weapons"): if Input.is_action_just_pressed("Swap Weapons"):
state_changed.emit(swap_state) state_changed.emit(swap_state)
if Input.is_action_pressed("Ready"): if Input.is_action_just_pressed("Ready"):
if hero.ready_state: if hero.ready_state:
hero.unready_self() hero.unready_self()
else: else:

View File

@@ -69,7 +69,7 @@ func process_state(_delta: float) -> void:
swap_to_slot(10) swap_to_slot(10)
if Input.is_action_just_pressed("Swap Weapons"): if Input.is_action_just_pressed("Swap Weapons"):
state_changed.emit(swap_state) state_changed.emit(swap_state)
if Input.is_action_pressed("Ready"): if Input.is_action_just_pressed("Ready"):
if hero.ready_state: if hero.ready_state:
hero.unready_self() hero.unready_self()
else: else:

View File

@@ -158,12 +158,12 @@ func exit_fighting_state() -> void:
func _physics_process(_delta: float) -> void: func _physics_process(_delta: float) -> void:
if !is_multiplayer_authority() or paused: if paused or !is_multiplayer_authority():
return return
func _process(delta: float) -> void: func _process(delta: float) -> void:
if !is_multiplayer_authority() or paused: if paused or !is_multiplayer_authority():
return return
if !movement.sprinting: if !movement.sprinting:
movement.zoom_factor += sprint_zoom_speed * 2.0 * delta movement.zoom_factor += sprint_zoom_speed * 2.0 * delta

View File

@@ -451,12 +451,12 @@ bones/15/rotation = Quaternion(-0.2017903, 0.015379741, -0.03813146, 0.97856534)
bones/16/rotation = Quaternion(-0.0048455074, 0.003865697, 0.59440565, 0.8041415) bones/16/rotation = Quaternion(-0.0048455074, 0.003865697, 0.59440565, 0.8041415)
bones/18/rotation = Quaternion(-0.2272016, 0.019839177, 0.4623247, 0.856879) bones/18/rotation = Quaternion(-0.2272016, 0.019839177, 0.4623247, 0.856879)
bones/23/rotation = Quaternion(-0.045133274, -0.11772486, 0.9614004, -0.24456768) bones/23/rotation = Quaternion(-0.045133274, -0.11772486, 0.9614004, -0.24456768)
bones/24/rotation = Quaternion(-0.31305715, 0.075180076, -0.21363969, 0.92233473) bones/24/rotation = Quaternion(-0.03303061, -0.005903939, -0.221179, 0.9746559)
bones/25/rotation = Quaternion(0.5710469, -0.039941728, 0.017517319, 0.819758) bones/25/rotation = Quaternion(0.049654786, 0.0001291396, 0.019066628, 0.9985845)
bones/26/rotation = Quaternion(-0.69202226, 0.0027399438, -0.003180337, 0.721864) bones/26/rotation = Quaternion(-0.68533796, 0.002092736, -0.0037087626, 0.7282128)
bones/28/rotation = Quaternion(0.056880478, 0.03165418, 0.2195195, 0.97343403) bones/28/rotation = Quaternion(-0.20499752, -0.0437259, 0.21891265, 0.9529646)
bones/29/rotation = Quaternion(0.038734946, -0.00095578696, -0.019037286, 0.9990678) bones/29/rotation = Quaternion(0.586818, 0.04117671, -0.017359266, 0.8084849)
bones/30/rotation = Quaternion(-0.67850786, -0.0014370738, 0.0042436896, 0.73457956) bones/30/rotation = Quaternion(-0.41481006, 0.02057148, 0.021915937, 0.9094114)
[node name="AnimationPlayer" parent="Model/doe_girl" parent_id_path=PackedInt32Array(1269374108, 1532649165) index="1" unique_id=126187206] [node name="AnimationPlayer" parent="Model/doe_girl" parent_id_path=PackedInt32Array(1269374108, 1532649165) index="1" unique_id=126187206]
autoplay = &"HoldGun" autoplay = &"HoldGun"

View File

@@ -4,8 +4,6 @@ class_name CardPrinter extends StaticBody3D
@export var button_collider: CollisionShape3D @export var button_collider: CollisionShape3D
@export var card_selection_menu: PackedScene @export var card_selection_menu: PackedScene
#TODO: use faction enum
var base_faction: int = 1
var cards_generated: int = 0 var cards_generated: int = 0
var reply_player: Hero var reply_player: Hero
var spawned_cards: Array[CardItem] = [] var spawned_cards: Array[CardItem] = []
@@ -41,9 +39,9 @@ func generate_rarity() -> int:
func randomize_cards(faction: Card.Faction) -> void: func randomize_cards(faction: Card.Faction) -> void:
#TODO: no magic numbers, asshole! 3 = cards to spawn var cards_to_spawn: int = 3
var pos_x: float = 0.0 var pos_x: float = 0.0
for x: int in 3: for x: int in cards_to_spawn:
var decided_rarity: int = generate_rarity() var decided_rarity: int = generate_rarity()
var card_choices: Array[Card] = get_faction_cards(faction) var card_choices: Array[Card] = get_faction_cards(faction)
var card_array: Array = [] var card_array: Array = []

View File

@@ -21,6 +21,7 @@ var blanks_available: int = 5
var blank_cost: int = 20 var blank_cost: int = 20
var buy_blank_prompt: String = "PROMPT_BUY_BLANK" var buy_blank_prompt: String = "PROMPT_BUY_BLANK"
var buy_card_prompt: String = "PROMPT_BUY_CARD" var buy_card_prompt: String = "PROMPT_BUY_CARD"
var shops_generated: int = 0
func close() -> void: func close() -> void:
@@ -34,9 +35,14 @@ func close() -> void:
func randomize_cards() -> void: func randomize_cards() -> void:
#TODO: use seeded randomness
blanks_available = 5 blanks_available = 5
var random_faction: int = randi_range(1, Card.Faction.values().size() - 1) var unlocked_classes: Array[HeroClass] = Data.save_data.get_unlocked_classes()
var faction_choices: Array[Card.Faction]
for hero: HeroClass in unlocked_classes:
if !faction_choices.has(hero.faction):
faction_choices.append(hero.faction)
var random_faction: int = NoiseRandom.randi_in_range(shops_generated, 0, faction_choices.size() - 1)
shops_generated += 1
var cheap_cards: Array[Card] = [] var cheap_cards: Array[Card] = []
var medium_cards: Array[Card] = [] var medium_cards: Array[Card] = []
var pricey_cards: Array[Card] = [] var pricey_cards: Array[Card] = []

View File

@@ -8,7 +8,6 @@ var speed: float = 0.0
func _ready() -> void: func _ready() -> void:
#TODO: make deterministic random var variance: float = NoiseRandom.randf_in_range(character.name.to_int(), -1.0, 1.0)
var variance: float = randf_range(-1.0, 1.0)
var variance_max: float = 0.03 # Enemy speed can vary by 3% from their base speed var variance_max: float = 0.03 # Enemy speed can vary by 3% from their base speed
speed = character.stats.movement_speed + (variance * variance_max) speed = character.stats.movement_speed + (variance * variance_max)

View File

@@ -1,8 +1,7 @@
class_name PathingController class_name PathingController
extends EnemyMovement extends EnemyMovement
#var path: Curve3D var random_points_generated: int
#var path_progress: float = 0.0
var flow_field: FlowField var flow_field: FlowField
var next_node: FlowNodeData : var next_node: FlowNodeData :
get(): get():
@@ -13,9 +12,12 @@ var next_node: FlowNodeData :
return return
var found_point: bool = false var found_point: bool = false
while !found_point: while !found_point:
#TODO: make deterministic random random_points_generated += 1
var x: float = randf_range(-1, 1) var sample: int = random_points_generated + character.name.to_int()
var y: float = randf_range(-1, 1) var r: float = 1.0 * sqrt(NoiseRandom.randf_in_range(sample, 0.0, 1.0))
var theta: float = NoiseRandom.randf_in_range(sample * 4, 0.0, 1.0) * 2.0 * PI
var x: float = r * cos(theta)
var y: float = r * sin(theta)
if Vector3(next_node.position.x + x, next_node.position.y, next_node.position.z + y).distance_to(next_node.position) <= 1.0: if Vector3(next_node.position.x + x, next_node.position.y, next_node.position.z + y).distance_to(next_node.position) <= 1.0:
found_point = true found_point = true
next_pos = Vector3(next_node.position.x + x, next_node.position.y, next_node.position.z + y) next_pos = Vector3(next_node.position.x + x, next_node.position.y, next_node.position.z + y)

View File

@@ -5,7 +5,7 @@ enum Faction {
GENERIC = 0, GENERIC = 0,
ENGINEER = 1, ENGINEER = 1,
MAGE = 2, MAGE = 2,
} }
@export var cost: int @export var cost: int
@export var rarity: Data.Rarity @export var rarity: Data.Rarity

View File

@@ -27,6 +27,17 @@ var mage_cards_bought: int = 0
var mage_unlocked: bool = 0 var mage_unlocked: bool = 0
func get_unlocked_classes() -> Array[HeroClass]:
var arr: Array[HeroClass] = []
for character: HeroClass in Data.characters:
if character.faction == Card.Faction.ENGINEER:
arr.append(Data.characters)
#TODO: When mage cards are good to show up in the shop, replace false with mage_unlocked
if false and character.faction == Card.Faction.MAGE:
arr.append(Data.characters)
return arr
func check_high_score(level_title: String, wave_reached: int, endless: bool) -> void: func check_high_score(level_title: String, wave_reached: int, endless: bool) -> void:
if !endless_high_scores.has(level_title): if !endless_high_scores.has(level_title):
endless_high_scores[level_title] = 0 endless_high_scores[level_title] = 0

View File

@@ -206,17 +206,12 @@ func set_wave_to_spawners(wave_thing: WaveConfig, wave_number: int) -> void:
func set_upcoming_wave() -> void: func set_upcoming_wave() -> void:
if is_multiplayer_authority():
#print(wave)
#print(level_config.waves.size())
if wave > level_config.waves.size(): if wave > level_config.waves.size():
#print("added new wave on top")
var spawn_power: int = WaveManager.calculate_spawn_power(wave, connected_players_nodes.size()) var spawn_power: int = WaveManager.calculate_spawn_power(wave, connected_players_nodes.size())
var new_wave: WaveConfig = WaveManager.generate_wave(spawn_power, level.enemy_pool, level.enemy_spawns.size()) var new_wave: WaveConfig = WaveManager.generate_wave(spawn_power, level.enemy_pool, level.enemy_spawns.size())
level_config.waves.append(new_wave) level_config.waves.append(new_wave)
var new_wave: WaveConfig = get_upcoming_waves(1)[0] var new_wave: WaveConfig = get_upcoming_waves(1)[0]
#print(new_wave)
set_wave_to_spawners(new_wave, wave) set_wave_to_spawners(new_wave, wave)
temp_set_upcoming_wave(new_wave, WaveManager.calculate_pot(wave, connected_players_nodes.size())) temp_set_upcoming_wave(new_wave, WaveManager.calculate_pot(wave, connected_players_nodes.size()))
@@ -407,15 +402,14 @@ func continue_with_game() -> void:
gamemode.endless = true gamemode.endless = true
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
connected_players_nodes[multiplayer.get_unique_id()].unpause() connected_players_nodes[multiplayer.get_unique_id()].unpause()
#TODO: This shouldn't happen. instead, the wave generator should generate level_config waves
#FIXME: this really needs to be changed because otherwise endless mode cant have shit like
#stations and shop respawns. it all needs to be part of the one system u know
set_upcoming_wave() set_upcoming_wave()
func quit_to_desktop() -> void: func quit_to_desktop() -> void:
multiplayer.multiplayer_peer.close() #for player: Hero in connected_players_nodes.values():
multiplayer.multiplayer_peer = null # player.queue_free()
#multiplayer.multiplayer_peer.close()
#multiplayer.multiplayer_peer = null
get_tree().quit() get_tree().quit()
@@ -424,8 +418,10 @@ func scene_switch_main_menu() -> void:
node.queue_free() node.queue_free()
level = null level = null
connected_players_nodes.clear() connected_players_nodes.clear()
if multiplayer.multiplayer_peer:
multiplayer.multiplayer_peer.close() multiplayer.multiplayer_peer.close()
multiplayer.multiplayer_peer = null multiplayer.multiplayer_peer = null
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
switch_to_main_menu.emit() switch_to_main_menu.emit()

View File

@@ -87,6 +87,7 @@ func networked_ready_player(peer_id: int) -> void:
start_game = false start_game = false
if start_game: if start_game:
setup_game() setup_game()
visible = false
func ready_player(peer_id: int = multiplayer.get_unique_id()) -> void: func ready_player(peer_id: int = multiplayer.get_unique_id()) -> void:
@@ -99,11 +100,14 @@ func ready_player(peer_id: int = multiplayer.get_unique_id()) -> void:
start_game = false start_game = false
if start_game: if start_game:
setup_game() setup_game()
visible = false
@rpc("any_peer", "reliable") @rpc("any_peer", "reliable")
func networked_select_class(peer_id: int) -> void: func networked_select_class(peer_id: int) -> void:
player_character_selected_states[connected_players_profiles[peer_id]] = true player_character_selected_states[connected_players_profiles[peer_id]] = true
if chatbox:
chatbox.append_message("SERVER", Color.TOMATO, connected_players_profiles[peer_id].display_name + " has chosen a class!")
var start_game: bool = true var start_game: bool = true
for state: bool in player_character_selected_states.values(): for state: bool in player_character_selected_states.values():
if !state: if !state:
@@ -125,7 +129,6 @@ func select_class(peer_id: int = multiplayer.get_unique_id()) -> void:
func start_game() -> void: func start_game() -> void:
enet_peer.refuse_new_connections = true enet_peer.refuse_new_connections = true
visible = false
super.start_game() super.start_game()

View File

@@ -76,4 +76,5 @@ func advance_selector() -> void:
func _on_confirm_button_pressed() -> void: func _on_confirm_button_pressed() -> void:
$Controls.visible = false
hero_confirmed.emit() hero_confirmed.emit()

View File

@@ -69,6 +69,7 @@ func load_multiplayer() -> void:
multi_player_lobby.game_manager = game_manager multi_player_lobby.game_manager = game_manager
multi_player_lobby.setup_the_ui() multi_player_lobby.setup_the_ui()
multi_player_lobby.player_disconnected.connect(game_manager.remove_player) multi_player_lobby.player_disconnected.connect(game_manager.remove_player)
multi_player_lobby.disconnected_from_server.connect(game_manager.scene_switch_main_menu)
func load_scene(scene_path: String) -> void: func load_scene(scene_path: String) -> void:

View File

@@ -1,11 +1,16 @@
class_name NetworkPuppeteer extends Node class_name NetworkPuppeteer extends Node
@export var player: CharacterBody3D @export var player: Hero
@export var player_movement: PlayerMovement @export var player_movement: PlayerMovement
@export var skeleton: Skeleton3D @export var skeleton: Skeleton3D
@export var animation_tree: AnimationTree @export var animation_tree: AnimationTree
func _ready() -> void:
if is_multiplayer_authority():
player.ready_state_changed.connect(func x(state: bool) -> void: set_ready_state.rpc(state))
func _process(delta: float) -> void: func _process(delta: float) -> void:
if is_multiplayer_authority(): if is_multiplayer_authority():
set_position.rpc(player.global_position) set_position.rpc(player.global_position)
@@ -28,3 +33,11 @@ func set_rotation(x: float, y: float) -> void:
var bone: int = skeleton.find_bone("Head") var bone: int = skeleton.find_bone("Head")
var pos: Quaternion = skeleton.get_bone_pose_rotation(bone) var pos: Quaternion = skeleton.get_bone_pose_rotation(bone)
skeleton.set_bone_pose_rotation(bone, Quaternion.from_euler(Vector3(x, 0, 0))) skeleton.set_bone_pose_rotation(bone, Quaternion.from_euler(Vector3(x, 0, 0)))
@rpc("reliable", "call_remote")
func set_ready_state(state: bool) -> void:
if state:
player.ready_self()
else:
player.unready_self()