This commit is contained in:
Marek Le
2026-05-09 23:37:26 +02:00
parent 6d28b04c12
commit 2d4002bd3f
263 changed files with 5250 additions and 4597 deletions

View File

@@ -1,69 +0,0 @@
extends Node
const PORTAL_SCENE: PackedScene = preload("res://scenes/portal/portal.tscn")
const GATE_SCENE: PackedScene = preload("res://scenes/portal/gate.tscn")
const RED_PORTAL_STATS: Resource = preload("res://scenes/portal/red_portal_stats.tres")
const MAX_NORMAL_PORTALS := 3
const MIN_DISTANCE := 20.0
const MAX_DISTANCE := 40.0
const RESPAWN_DELAY := 1.0
var portals: Array[Node] = []
func _ready() -> void:
EventBus.portal_defeated.connect(_on_portal_defeated)
EventBus.wave_started.connect(_on_wave_started)
if PlayerData.portal_position != Vector3.ZERO and not PlayerData.dungeon_cleared:
call_deferred("_restore_gate")
else:
if PlayerData.dungeon_cleared:
PlayerData.clear_cache()
call_deferred("_ensure_portals")
func _restore_gate() -> void:
var gate: Node3D = GATE_SCENE.instantiate()
get_parent().add_child(gate)
gate.global_position = PlayerData.portal_position
func _ensure_portals() -> void:
_cleanup_dead()
while portals.size() < MAX_NORMAL_PORTALS:
_spawn_portal()
func _on_portal_defeated(portal: Node) -> void:
if portal.is_in_group("red_portal"):
return
portals.erase(portal)
await get_tree().create_timer(RESPAWN_DELAY).timeout
_ensure_portals()
func _on_wave_started(_wave_number: int) -> void:
_spawn_red_portal()
func _spawn_red_portal() -> void:
for p in get_tree().get_nodes_in_group("red_portal"):
if is_instance_valid(p):
return
var angle: float = randf() * TAU
var distance: float = randf_range(MIN_DISTANCE, MAX_DISTANCE)
var pos := Vector3(cos(angle) * distance, 0, sin(angle) * distance)
var portal: Node3D = PORTAL_SCENE.instantiate()
portal.stats = RED_PORTAL_STATS
get_parent().add_child(portal)
portal.global_position = pos
func _spawn_portal() -> void:
var angle: float = randf() * TAU
var distance: float = randf_range(MIN_DISTANCE, MAX_DISTANCE)
var pos := Vector3(cos(angle) * distance, 0, sin(angle) * distance)
var portal: Node3D = PORTAL_SCENE.instantiate()
get_parent().add_child(portal)
portal.global_position = pos
portals.append(portal)
func _cleanup_dead() -> void:
var valid: Array[Node] = []
for p in portals:
if is_instance_valid(p):
valid.append(p)
portals = valid

View File

@@ -1 +0,0 @@
uid://cskx6o07iukwh

View File

@@ -1,193 +1,200 @@
[gd_scene format=3 uid="uid://dy1icabu2ssbw"]
[gd_scene load_steps=10 format=3 uid="uid://b0world00001"]
[ext_resource type="Script" path="res://systems/ability_system.gd" id="ability_system"]
[ext_resource type="Script" path="res://systems/aggro/aggro_decay.gd" id="aggro_decay"]
[ext_resource type="Script" path="res://systems/aggro/aggro_events.gd" id="aggro_events"]
[ext_resource type="Script" path="res://systems/aggro/aggro_system.gd" id="aggro_system"]
[ext_resource type="Script" path="res://systems/aggro/aggro_tracker.gd" id="aggro_tracker"]
[ext_resource type="Script" path="res://systems/attack_system.gd" id="attack_system"]
[ext_resource type="Script" path="res://systems/cooldown_system.gd" id="cooldown_system"]
[ext_resource type="Script" path="res://systems/damage_system.gd" id="damage_system"]
[ext_resource type="Script" path="res://systems/health_system.gd" id="health_system"]
[ext_resource type="Script" path="res://systems/heal_system.gd" id="heal_system"]
[ext_resource type="Script" path="res://systems/role_system.gd" id="role_system"]
[ext_resource type="Script" path="res://systems/targeting_system.gd" id="targeting_system"]
[ext_resource type="Script" path="res://systems/portal_system.gd" id="portal_system"]
[ext_resource type="Script" path="res://systems/aura_system.gd" id="aura_system"]
[ext_resource type="Script" path="res://systems/buff_system.gd" id="buff_system"]
[ext_resource type="Script" path="res://systems/debuff_system.gd" id="debuff_system"]
[ext_resource type="Script" path="res://systems/element_system.gd" id="element_system"]
[ext_resource type="Script" path="res://systems/hud_system.gd" id="hud_system"]
[ext_resource type="Script" path="res://systems/nameplate_system.gd" id="nameplate_system"]
[ext_resource type="Script" path="res://systems/ai_system.gd" id="ai_system"]
[ext_resource type="Script" path="res://systems/respawn_system.gd" id="respawn_system"]
[ext_resource type="Script" path="res://systems/shield_system.gd" id="shield_system"]
[ext_resource type="Script" path="res://systems/spawn_system.gd" id="spawn_system"]
[ext_resource type="Script" path="res://systems/wave_system.gd" id="wave_system"]
[ext_resource type="Script" path="res://systems/xp_system.gd" id="xp_system"]
[ext_resource type="Script" path="res://systems/invasion_system.gd" id="invasion_system"]
[ext_resource type="Script" path="res://systems/audio_system.gd" id="audio_system"]
[ext_resource type="Script" path="res://scenes/world/world_manager.gd" id="world_manager"]
[ext_resource type="PackedScene" path="res://scenes/menu/game_over_overlay.tscn" id="game_over_overlay"]
[ext_resource type="PackedScene" path="res://scenes/hud/hud.tscn" id="hud"]
[ext_resource type="PackedScene" path="res://scenes/tavern/tavern.tscn" id="tavern"]
[ext_resource type="PackedScene" uid="uid://cdnkbt1f0db7e" path="res://scenes/player/player.tscn" id="player"]
[ext_resource type="Script" path="res://scenes/world/portal_spawner.gd" id="portal_spawner"]
[ext_resource type="Resource" uid="uid://cgxtn7dfs40bh" path="res://scenes/player/role/tank/set.tres" id="tank_set"]
[ext_resource type="Resource" uid="uid://beodknb6i1pm4" path="res://scenes/player/role/damage/set.tres" id="damage_set"]
[ext_resource type="Resource" uid="uid://kcwuhnqy34mj" path="res://scenes/player/role/healer/set.tres" id="healer_set"]
[ext_resource type="Script" path="res://scenes/world/world_manager.gd" id="1"]
[ext_resource type="PackedScene" uid="uid://b0player00001" path="res://scenes/entities/player/player.tscn" id="2"]
[ext_resource type="PackedScene" uid="uid://b0village001" path="res://scenes/entities/village/village.tscn" id="3"]
[ext_resource type="Script" path="res://systems/health_system.gd" id="4"]
[ext_resource type="Script" path="res://systems/shield_system.gd" id="5"]
[ext_resource type="Script" path="res://systems/respawn_system.gd" id="6"]
[ext_resource type="Script" path="res://systems/cooldown_system.gd" id="7"]
[ext_resource type="Script" path="res://systems/role_system.gd" id="8"]
[ext_resource type="Script" path="res://systems/effect_system.gd" id="9"]
[ext_resource type="Script" path="res://systems/element_system.gd" id="10"]
[ext_resource type="Script" path="res://systems/aggro_system.gd" id="11"]
[ext_resource type="Script" path="res://systems/combat/ability_system.gd" id="12"]
[ext_resource type="Script" path="res://systems/combat/auto_attack_system.gd" id="13"]
[ext_resource type="Script" path="res://systems/spawn_system.gd" id="14"]
[ext_resource type="Script" path="res://systems/wave_system.gd" id="15"]
[ext_resource type="Script" path="res://systems/invasion_system.gd" id="16"]
[ext_resource type="Script" path="res://systems/xp_system.gd" id="17"]
[ext_resource type="Script" path="res://systems/loot_system.gd" id="18"]
[ext_resource type="Script" path="res://systems/inventory_system.gd" id="19"]
[ext_resource type="Script" path="res://systems/crafting_system.gd" id="20"]
[ext_resource type="Script" path="res://systems/building_system.gd" id="21"]
[ext_resource type="Script" path="res://systems/npc_system.gd" id="22"]
[ext_resource type="Script" path="res://systems/dialog_system.gd" id="23"]
[ext_resource type="Script" path="res://systems/chat_system.gd" id="24"]
[ext_resource type="Script" path="res://systems/map_system.gd" id="25"]
[ext_resource type="PackedScene" uid="uid://b0hud00001" path="res://scenes/hud/hud.tscn" id="26"]
[ext_resource type="Script" path="res://systems/audio_system.gd" id="27"]
[sub_resource type="NavigationMesh" id="NavigationMesh_1"]
vertices = PackedVector3Array(-49.5, 0.5, -49.5, -49.5, 0.5, 49.5, 49.5, 0.5, 49.5, 49.5, 0.5, -49.5)
polygons = [PackedInt32Array(3, 2, 0), PackedInt32Array(0, 2, 1)]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_1"]
sky_top_color = Color(0.4, 0.55, 0.8, 1)
sky_horizon_color = Color(0.7, 0.7, 0.6, 1)
ground_horizon_color = Color(0.65, 0.55, 0.4, 1)
ground_bottom_color = Color(0.2, 0.2, 0.2, 1)
[sub_resource type="Gradient" id="Gradient_1"]
colors = PackedColorArray(0.15, 0.35, 0.05, 1, 0.3, 0.55, 0.1, 1)
[sub_resource type="Sky" id="Sky_1"]
sky_material = SubResource("ProceduralSkyMaterial_1")
[sub_resource type="FastNoiseLite" id="FastNoiseLite_1"]
frequency = 0.05
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_1"]
noise = SubResource("FastNoiseLite_1")
color_ramp = SubResource("Gradient_1")
seamless = true
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ground"]
albedo_texture = SubResource("NoiseTexture2D_1")
uv1_scale = Vector3(15, 15, 1)
[sub_resource type="Environment" id="Environment_1"]
background_mode = 2
sky = SubResource("Sky_1")
ambient_light_source = 3
ambient_light_color = Color(0.6, 0.6, 0.7, 1)
ambient_light_energy = 0.5
tonemap_mode = 2
[sub_resource type="PlaneMesh" id="PlaneMesh_1"]
material = SubResource("StandardMaterial3D_ground")
size = Vector2(100, 100)
size = Vector2(200, 200)
subdivide_width = 4
subdivide_depth = 4
[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_1"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_tavern"]
albedo_color = Color(0.45, 0.3, 0.15, 1)
[sub_resource type="BoxMesh" id="BoxMesh_tavern"]
material = SubResource("StandardMaterial3D_tavern")
size = Vector3(5, 3, 5)
[sub_resource type="BoxShape3D" id="BoxShape3D_tavern"]
size = Vector3(5, 3, 5)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_Ground"]
albedo_color = Color(0.35, 0.55, 0.3, 1)
[node name="World" type="Node3D"]
script = ExtResource("1")
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_1")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.866, -0.354, 0.354, 0, 0.707, 0.707, -0.5, -0.612, 0.612, 0, 30, 0)
light_energy = 1.2
shadow_enabled = true
[node name="Ground" type="StaticBody3D" parent="."]
collision_layer = 1
collision_mask = 0
[node name="GroundMesh" type="MeshInstance3D" parent="Ground"]
mesh = SubResource("PlaneMesh_1")
surface_material_override/0 = SubResource("StandardMaterial3D_Ground")
[node name="GroundShape" type="CollisionShape3D" parent="Ground"]
[node name="NavigationRegion" type="NavigationRegion3D" parent="."]
[node name="Systems" type="Node" parent="."]
[node name="HealthSystem" type="Node" parent="Systems"]
script = ExtResource("health_system")
[node name="DamageSystem" type="Node" parent="Systems"]
script = ExtResource("damage_system")
[node name="HealSystem" type="Node" parent="Systems"]
script = ExtResource("heal_system")
script = ExtResource("4")
[node name="ShieldSystem" type="Node" parent="Systems"]
script = ExtResource("shield_system")
[node name="RoleSystem" type="Node" parent="Systems"]
script = ExtResource("role_system")
tank_set = ExtResource("tank_set")
damage_set = ExtResource("damage_set")
healer_set = ExtResource("healer_set")
[node name="AbilitySystem" type="Node" parent="Systems"]
script = ExtResource("ability_system")
[node name="AttackSystem" type="Node" parent="Systems"]
script = ExtResource("attack_system")
[node name="CooldownSystem" type="Node" parent="Systems"]
script = ExtResource("cooldown_system")
[node name="TargetingSystem" type="Node" parent="Systems"]
script = ExtResource("targeting_system")
[node name="AggroSystem" type="Node" parent="Systems"]
script = ExtResource("aggro_system")
[node name="AggroTracker" type="Node" parent="Systems/AggroSystem"]
script = ExtResource("aggro_tracker")
[node name="AggroDecay" type="Node" parent="Systems/AggroSystem"]
script = ExtResource("aggro_decay")
[node name="AggroEvents" type="Node" parent="Systems/AggroSystem"]
script = ExtResource("aggro_events")
[node name="AISystem" type="Node" parent="Systems"]
script = ExtResource("ai_system")
script = ExtResource("5")
[node name="RespawnSystem" type="Node" parent="Systems"]
script = ExtResource("respawn_system")
script = ExtResource("6")
[node name="SpawnSystem" type="Node" parent="Systems"]
script = ExtResource("spawn_system")
[node name="CooldownSystem" type="Node" parent="Systems"]
script = ExtResource("7")
[node name="PortalSystem" type="Node" parent="Systems"]
script = ExtResource("portal_system")
[node name="RoleSystem" type="Node" parent="Systems"]
script = ExtResource("8")
[node name="AuraSystem" type="Node" parent="Systems"]
script = ExtResource("aura_system")
[node name="BuffSystem" type="Node" parent="Systems"]
script = ExtResource("buff_system")
[node name="DebuffSystem" type="Node" parent="Systems"]
script = ExtResource("debuff_system")
[node name="EffectSystem" type="Node" parent="Systems"]
script = ExtResource("9")
[node name="ElementSystem" type="Node" parent="Systems"]
script = ExtResource("element_system")
script = ExtResource("10")
[node name="HudSystem" type="Node" parent="Systems"]
script = ExtResource("hud_system")
[node name="AggroSystem" type="Node" parent="Systems"]
script = ExtResource("11")
[node name="NameplateSystem" type="Node" parent="Systems"]
script = ExtResource("nameplate_system")
[node name="AbilitySystem" type="Node" parent="Systems"]
script = ExtResource("12")
[node name="WaveSystem" type="Node" parent="Systems"]
script = ExtResource("wave_system")
[node name="AutoAttackSystem" type="Node" parent="Systems"]
script = ExtResource("13")
[node name="SpawnSystem" type="Node" parent="Systems"]
script = ExtResource("14")
[node name="LootSystem" type="Node" parent="Systems"]
script = ExtResource("18")
[node name="XpSystem" type="Node" parent="Systems"]
script = ExtResource("xp_system")
script = ExtResource("17")
[node name="InvasionSystem" type="Node" parent="Systems"]
script = ExtResource("invasion_system")
[node name="InventorySystem" type="Node" parent="Systems"]
script = ExtResource("19")
[node name="CraftingSystem" type="Node" parent="Systems"]
script = ExtResource("20")
[node name="BuildingSystem" type="Node" parent="Systems"]
script = ExtResource("21")
[node name="NpcSystem" type="Node" parent="Systems"]
script = ExtResource("22")
[node name="DialogSystem" type="Node" parent="Systems"]
script = ExtResource("23")
[node name="ChatSystem" type="Node" parent="Systems"]
script = ExtResource("24")
[node name="MapSystem" type="Node" parent="Systems"]
script = ExtResource("25")
[node name="AudioSystem" type="Node" parent="Systems"]
script = ExtResource("audio_system")
script = ExtResource("27")
[node name="NavigationRegion3D" type="NavigationRegion3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0027503967, 0.014227867, 0.023231506)
navigation_mesh = SubResource("NavigationMesh_1")
[node name="WaveSystem" type="Node" parent="Systems"]
script = ExtResource("15")
[node name="Boden" type="MeshInstance3D" parent="NavigationRegion3D"]
mesh = SubResource("PlaneMesh_1")
[node name="InvasionSystem" type="Node" parent="Systems"]
script = ExtResource("16")
[node name="BodenCollision" type="StaticBody3D" parent="."]
[node name="VillageRoot" type="Node3D" parent="."]
[node name="CollisionShape3D" type="CollisionShape3D" parent="BodenCollision"]
shape = SubResource("WorldBoundaryShape3D_1")
[node name="Village" parent="VillageRoot" instance=ExtResource("3")]
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.707, 0.707, 0, -0.707, 0.707, 0, 10, 0)
shadow_enabled = true
[node name="EntityRoot" type="Node3D" parent="."]
[node name="Tavern" parent="." instance=ExtResource("tavern")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
[node name="Players" type="Node3D" parent="EntityRoot"]
[node name="Player" parent="." instance=ExtResource("player")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, -5)
[node name="Enemies" type="Node3D" parent="EntityRoot"]
[node name="HUD" parent="." instance=ExtResource("hud")]
[node name="Bosses" type="Node3D" parent="EntityRoot"]
[node name="PortalSpawner" type="Node" parent="."]
script = ExtResource("portal_spawner")
[node name="Gates" type="Node3D" parent="EntityRoot"]
[node name="WorldManager" type="Node" parent="."]
script = ExtResource("world_manager")
[node name="Portals" type="Node3D" parent="EntityRoot"]
[node name="GameOverOverlay" parent="." instance=ExtResource("game_over_overlay")]
[node name="Buildings" type="Node3D" parent="EntityRoot"]
[node name="Loot" type="Node3D" parent="EntityRoot"]
[node name="Npcs" type="Node3D" parent="EntityRoot"]
[node name="PlayerSpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("res://scenes/entities/player/player.tscn")
spawn_path = NodePath("../EntityRoot/Players")
[node name="EnemySpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("res://scenes/entities/enemy/enemy.tscn")
spawn_path = NodePath("../EntityRoot/Enemies")
[node name="GateSpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("res://scenes/entities/gate/gate.tscn")
spawn_path = NodePath("../EntityRoot/Gates")
[node name="PortalSpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("res://scenes/entities/portal/portal.tscn")
spawn_path = NodePath("../EntityRoot/Portals")
[node name="BuildingSpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("res://scenes/entities/building/building.tscn")
spawn_path = NodePath("../EntityRoot/Buildings")
[node name="LootSpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("res://scenes/entities/loot/loot_drop.tscn")
spawn_path = NodePath("../EntityRoot/Loot")
[node name="NpcSpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("res://scenes/entities/npc/npc.tscn")
spawn_path = NodePath("../EntityRoot/Npcs")
[node name="HUD" parent="." instance=ExtResource("26")]

View File

@@ -1,21 +1,74 @@
extends Node
extends Node3D
const PLAYER_SCENE: PackedScene = preload("res://scenes/entities/player/player.tscn")
@onready var players_root: Node3D = $EntityRoot/Players
@onready var ground_shape: CollisionShape3D = $Ground/GroundShape
@onready var npc_system: Node = $Systems/NpcSystem
@onready var wave_system: Node = $Systems/WaveSystem
func _ready() -> void:
EventBus.game_over.connect(_on_game_over)
if GameState.force_return_to_world:
call_deferred("_handle_force_return")
add_to_group("world")
_setup_ground_collision()
Net.world_ready.connect(_on_world_ready)
Net.peer_world_loaded.connect(_on_peer_world_loaded)
if Net.is_host():
multiplayer.peer_connected.connect(_on_peer_connected)
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
Net.reset_world_ready()
Net.mark_world_loaded()
func _handle_force_return() -> void:
GameState.force_return_to_world = false
var player: Node3D = get_tree().get_first_node_in_group("player")
var tavern: Node3D = get_tree().get_first_node_in_group("tavern")
if player and tavern:
player.global_position = tavern.global_position + Vector3(0, 1, -6)
var invasion: Node = get_node_or_null("../Systems/InvasionSystem")
if invasion:
invasion.trigger()
func _exit_tree() -> void:
if Net.is_host():
if multiplayer.peer_connected.is_connected(_on_peer_connected):
multiplayer.peer_connected.disconnect(_on_peer_connected)
if multiplayer.peer_disconnected.is_connected(_on_peer_disconnected):
multiplayer.peer_disconnected.disconnect(_on_peer_disconnected)
if Net.world_ready.is_connected(_on_world_ready):
Net.world_ready.disconnect(_on_world_ready)
if Net.peer_world_loaded.is_connected(_on_peer_world_loaded):
Net.peer_world_loaded.disconnect(_on_peer_world_loaded)
func _on_game_over() -> void:
var overlay: CanvasLayer = get_node_or_null("../GameOverOverlay")
if overlay and overlay.has_method("show_overlay"):
overlay.show_overlay(GameState.current_wave)
func _setup_ground_collision() -> void:
var shape := WorldBoundaryShape3D.new()
shape.plane = Plane(Vector3.UP, 0.0)
ground_shape.shape = shape
func _on_world_ready() -> void:
if not Net.is_host():
return
_spawn_player(1)
for id in multiplayer.get_peers():
_spawn_player(id)
npc_system.spawn_default_npcs()
if wave_system and wave_system.has_method("start_wave"):
wave_system.start_wave(GameState.current_wave)
func _on_peer_connected(id: int) -> void:
Net.tell_peer_to_load_scene(id, GameState.SCENE_WORLD)
func _on_peer_world_loaded(peer_id: int) -> void:
if not Net.is_host():
return
_spawn_player(peer_id)
func _on_peer_disconnected(id: int) -> void:
var node := players_root.get_node_or_null(str(id))
if node:
node.queue_free()
func _spawn_player(peer_id: int) -> void:
if players_root.get_node_or_null(str(peer_id)) != null:
return
var p: CharacterBody3D = PLAYER_SCENE.instantiate()
p.name = str(peer_id)
var spawn := _spawn_position_for(peer_id)
players_root.add_child(p, true)
p.global_position = spawn
func _spawn_position_for(peer_id: int) -> Vector3:
if GameState.portal_return_position != Vector3.ZERO:
var off: float = float(peer_id) * 0.7
return GameState.portal_return_position + Vector3(cos(off) * 1.2, 1.5, sin(off) * 1.2)
var angle: float = wrapf(float(peer_id) * 1.7, 0.0, TAU)
return Vector3(cos(angle) * 5.0, 1.5, sin(angle) * 5.0)

View File

@@ -1 +1 @@
uid://cejlqodm01ob3
uid://c88xbvl82lrtx