diff --git a/docs/STATUS.md b/docs/STATUS.md index c657124..d3f2449 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -1,6 +1,6 @@ # Ruf der Pilze — Projektstatus -Zuletzt aktualisiert: 2026-04-14 (Plan Schritt 6 fertig) +Zuletzt aktualisiert: 2026-04-14 (Schritt 5 abgeschlossen) --- @@ -13,14 +13,13 @@ Zuletzt aktualisiert: 2026-04-14 (Plan Schritt 6 fertig) - **Multiplayer Grundgerüst** — ENet Server/Client, NetworkManager Autoload, welcome RPC verifiziert - **Lobby + Rollen** — Join-UI, Warteraum, Spieler/DM-Rollen, Sync, Kick, Spiel-Start-Signal - **Tavern Lobby** — 3D-Taverne ersetzt die flache Lobby-UI; SceneManager Autoload eingeführt +- **Taverne + Szenen-Wechsel** — 2-stöckige In-Game-Taverne (Blockout), taproom.tscn als Sub-Scene, + game_started → Spieler in zugewiesenem Zimmer (SpawnPoint), DM in dm_view.tscn Stub ### 🔄 In Arbeit — (nichts aktiv) ### ⏳ Als nächstes -- **Taverne + Szenen-Wechsel nach Spielstart** — 2-stöckige In-Game-Taverne (Blockout), taproom als Sub-Scene, game_started → Spieler in Zimmer, DM in Stub-Szene - Spec: `docs/superpowers/specs/2026-04-14-tavern-scene-design.md` - Plan: `docs/plans/2026-04-14-tavern-scene-plan.md` - **DM Regiepult Basics** — Top-Down-Karte (EG/OG), Spieler-Positionsmarker, Live-Cam-Feeds pro Spieler, Overlay-Toggle Plan: `docs/plans/2026-04-14-dm-regiepult-basics.md` @@ -32,7 +31,7 @@ Zuletzt aktualisiert: 2026-04-14 (Plan Schritt 6 fertig) 2. ✅ Multiplayer Grundgerüst (Server, Clients verbinden, rpc testen) 3. ✅ Lobby + Rollen (Spieler registrieren sich, DM kriegt Sonderrechte) 4. ✅ Tavern Lobby — 3D-Taverne als Warteraum, SceneManager Autoload -5. ⏳ Szenen-Wechsel nach Spielstart — Chamber/DM-Szene nach game_started +5. ✅ Szenen-Wechsel nach Spielstart — taproom Sub-Scene, 2 Etagen, SpawnPoints, dm_view Stub 6. ⏳ DM Regiepult Basics — Overlay-Toggle, Top-Down pro Etage, Player-Cams Plan: `docs/plans/2026-04-14-dm-regiepult-basics.md` 7. ⏳ Refectorium — asymmetrische Wahrnehmung (erster Raum) diff --git a/ruf-der-pilze/CLAUDE.md b/ruf-der-pilze/CLAUDE.md index 8c7744a..69bc51b 100644 --- a/ruf-der-pilze/CLAUDE.md +++ b/ruf-der-pilze/CLAUDE.md @@ -233,10 +233,9 @@ Verzeichnis: `../Anna_Model/` (außerhalb von `ruf-der-pilze/`, im Repo-Root) 2. ✅ Multiplayer Grundgerüst (Server, Clients verbinden, rpc testen) 3. ✅ Lobby + Rollen (Spieler mit Name + Rolle, DM-Sonderrechte) 4. ✅ Tavern Lobby — 3D-Taverne als Warteraum, SceneManager Autoload -5. ⏳ Taverne + Szenen-Wechsel — 2-stöckige In-Game-Taverne (Blockout), taproom.tscn +5. ✅ Taverne + Szenen-Wechsel — 2-stöckige In-Game-Taverne (Blockout), taproom.tscn als Sub-Scene, game_started → Spieler in Zimmer (SpawnPoint), DM → dm_view.tscn Kein separates "chamber" — Zimmer sind Teil von tavern.tscn - Plan: ../docs/plans/2026-04-14-tavern-scene-plan.md 6. ⏳ DM Regiepult Basics — Overlay-Toggle, Top-Down pro Etage, Player-Cams Plan: `../docs/plans/2026-04-14-dm-regiepult-basics.md` 7. ⏳ Erster Raum — Refectory mit asymmetrischer Wahrnehmung diff --git a/ruf-der-pilze/scenes/dm_view.tscn b/ruf-der-pilze/scenes/dm_view.tscn index 3b2ef79..ff2337e 100644 --- a/ruf-der-pilze/scenes/dm_view.tscn +++ b/ruf-der-pilze/scenes/dm_view.tscn @@ -5,55 +5,27 @@ [node name="DmView" type="Node"] script = ExtResource("1") -[node name="RootLayout" type="VBoxContainer" parent="."] +[node name="ViewportContainer" type="SubViewportContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 -[node name="TopSection" type="HSplitContainer" parent="RootLayout"] -size_flags_vertical = 3 +[node name="SubViewport" type="SubViewport" parent="ViewportContainer"] -[node name="MapContainer" type="SubViewportContainer" parent="RootLayout/TopSection"] -custom_minimum_size = Vector2(700, 500) -size_flags_horizontal = 3 -stretch = true - -[node name="MapViewport" type="SubViewport" parent="RootLayout/TopSection/MapContainer"] -size = Vector2i(700, 500) - -[node name="MapRoot" type="Node3D" parent="RootLayout/TopSection/MapContainer/MapViewport"] - -[node name="PlayerMarkers" type="Node3D" parent="RootLayout/TopSection/MapContainer/MapViewport/MapRoot"] - -[node name="TopDownCam" type="Camera3D" parent="RootLayout/TopSection/MapContainer/MapViewport/MapRoot"] -transform = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, 2, 25, 0) +[node name="Camera3D" type="Camera3D" parent="ViewportContainer/SubViewport"] +transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 20, 0) current = true -[node name="SidePanel" type="VBoxContainer" parent="RootLayout/TopSection"] -custom_minimum_size = Vector2(220, 0) +[node name="UI" type="CanvasLayer" parent="."] -[node name="LblFloor" type="Label" parent="RootLayout/TopSection/SidePanel"] -text = "Etage" - -[node name="FloorButtons" type="HBoxContainer" parent="RootLayout/TopSection/SidePanel"] - -[node name="BtnEG" type="Button" parent="RootLayout/TopSection/SidePanel/FloorButtons"] -text = "Erdgeschoss" -toggle_mode = true -button_pressed = true - -[node name="BtnOG" type="Button" parent="RootLayout/TopSection/SidePanel/FloorButtons"] -text = "Obergeschoss" -toggle_mode = true - -[node name="HSeparator" type="HSeparator" parent="RootLayout/TopSection/SidePanel"] - -[node name="LblOverlay" type="Label" parent="RootLayout/TopSection/SidePanel"] -text = "Overlays" - -[node name="OverlayScroll" type="ScrollContainer" parent="RootLayout/TopSection/SidePanel"] -size_flags_vertical = 3 - -[node name="PlayerList" type="VBoxContainer" parent="RootLayout/TopSection/SidePanel/OverlayScroll"] - -[node name="HSeparator2" type="HSeparator" parent="RootLayout"] - -[node name="PlayerCamsRow" type="HBoxContainer" parent="RootLayout"] -custom_minimum_size = Vector2(0, 200) +[node name="StubLabel" type="Label" parent="UI"] +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -150.0 +offset_top = -30.0 +offset_right = 150.0 +offset_bottom = 30.0 +text = "DM View — Stub +(wird in Schritt 7 ausgebaut)" +horizontal_alignment = 1 diff --git a/ruf-der-pilze/scenes/taproom.tscn b/ruf-der-pilze/scenes/taproom.tscn new file mode 100644 index 0000000..3cf2816 --- /dev/null +++ b/ruf-der-pilze/scenes/taproom.tscn @@ -0,0 +1,120 @@ +[gd_scene load_steps=22 format=3] + +[sub_resource type="StandardMaterial3D" id="Material_wood"] +albedo_color = Color(0.169, 0.102, 0.051, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_floor"] +size = Vector3(12, 0.1, 8) + +[sub_resource type="BoxShape3D" id="BoxShape3D_floor"] +size = Vector3(12, 0.1, 8) + +[sub_resource type="BoxMesh" id="BoxMesh_ceiling"] +size = Vector3(12, 0.1, 8) + +[sub_resource type="BoxShape3D" id="BoxShape3D_ceiling"] +size = Vector3(12, 0.1, 8) + +[sub_resource type="BoxMesh" id="BoxMesh_wallback"] +size = Vector3(12, 4, 0.1) + +[sub_resource type="BoxShape3D" id="BoxShape3D_wallback"] +size = Vector3(12, 4, 0.1) + +[sub_resource type="BoxMesh" id="BoxMesh_wallleft"] +size = Vector3(0.1, 4, 8) + +[sub_resource type="BoxShape3D" id="BoxShape3D_wallleft"] +size = Vector3(0.1, 4, 8) + +[sub_resource type="BoxMesh" id="BoxMesh_wallright"] +size = Vector3(0.1, 4, 8) + +[sub_resource type="BoxShape3D" id="BoxShape3D_wallright"] +size = Vector3(0.1, 4, 8) + +[sub_resource type="BoxMesh" id="BoxMesh_bar"] +size = Vector3(4, 1.1, 0.3) + +[sub_resource type="BoxShape3D" id="BoxShape3D_bar"] +size = Vector3(4, 1.1, 0.3) + +[sub_resource type="Environment" id="Environment_1"] +background_mode = 1 +background_color = Color(0.102, 0.059, 0, 1) +ambient_light_color = Color(0.6, 0.35, 0.1, 1) +ambient_light_energy = 0.4 +fog_enabled = true +fog_light_color = Color(0.102, 0.059, 0, 1) +fog_density = 0.05 + +[node name="Taproom" type="Node3D"] + +[node name="Floor" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor"] +mesh = SubResource("BoxMesh_floor") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor"] +shape = SubResource("BoxShape3D_floor") + +[node name="Ceiling" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.05, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Ceiling"] +mesh = SubResource("BoxMesh_ceiling") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ceiling"] +shape = SubResource("BoxShape3D_ceiling") + +[node name="WallBack" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, -4) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="WallBack"] +mesh = SubResource("BoxMesh_wallback") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="WallBack"] +shape = SubResource("BoxShape3D_wallback") + +[node name="WallLeft" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 2, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="WallLeft"] +mesh = SubResource("BoxMesh_wallleft") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="WallLeft"] +shape = SubResource("BoxShape3D_wallleft") + +[node name="WallRight" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 2, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="WallRight"] +mesh = SubResource("BoxMesh_wallright") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="WallRight"] +shape = SubResource("BoxShape3D_wallright") + +[node name="Bar" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0.55, -3.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Bar"] +mesh = SubResource("BoxMesh_bar") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Bar"] +shape = SubResource("BoxShape3D_bar") + +[node name="Light" type="OmniLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0) +light_color = Color(0.91, 0.643, 0.29, 1) +light_energy = 1.2 +omni_range = 10.0 + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_1") diff --git a/ruf-der-pilze/scenes/tavern.tscn b/ruf-der-pilze/scenes/tavern.tscn index a559e11..7c438e3 100644 --- a/ruf-der-pilze/scenes/tavern.tscn +++ b/ruf-der-pilze/scenes/tavern.tscn @@ -1,108 +1,402 @@ -[gd_scene load_steps=8 format=3] +[gd_scene load_steps=28 format=3] [ext_resource type="Script" path="res://scripts/tavern.gd" id="1"] +[ext_resource type="PackedScene" path="res://scenes/taproom.tscn" id="2"] -[sub_resource type="Environment" id="Environment_1"] -background_mode = 1 -background_color = Color(0.102, 0.059, 0, 1) -ambient_light_color = Color(0.6, 0.35, 0.1, 1) -ambient_light_energy = 0.4 -fog_enabled = true -fog_light_color = Color(0.102, 0.059, 0, 1) -fog_density = 0.05 - -[sub_resource type="StandardMaterial3D" id="Material_1"] +[sub_resource type="StandardMaterial3D" id="Material_wood"] albedo_color = Color(0.169, 0.102, 0.051, 1) -[sub_resource type="BoxMesh" id="BoxMesh_floor"] -size = Vector3(12, 0.1, 8) +[sub_resource type="StandardMaterial3D" id="Material_myzel"] +albedo_color = Color(0.2, 0.8, 0.3, 1) +emission_enabled = true +emission = Color(0.1, 0.4, 0.1, 1) -[sub_resource type="BoxMesh" id="BoxMesh_ceiling"] -size = Vector3(12, 0.1, 8) +[sub_resource type="BoxMesh" id="BoxMesh_kitchen_back"] +size = Vector3(4, 3, 0.1) -[sub_resource type="BoxMesh" id="BoxMesh_back"] -size = Vector3(12, 4, 0.1) +[sub_resource type="BoxShape3D" id="BoxShape3D_kitchen_back"] +size = Vector3(4, 3, 0.1) -[sub_resource type="BoxMesh" id="BoxMesh_left"] -size = Vector3(0.1, 4, 8) +[sub_resource type="BoxMesh" id="BoxMesh_kitchen_side"] +size = Vector3(0.1, 3, 2.3) -[sub_resource type="BoxMesh" id="BoxMesh_right"] -size = Vector3(0.1, 4, 8) +[sub_resource type="BoxShape3D" id="BoxShape3D_kitchen_side"] +size = Vector3(0.1, 3, 2.3) + +[sub_resource type="BoxMesh" id="BoxMesh_door"] +size = Vector3(0.1, 4, 2) + +[sub_resource type="BoxShape3D" id="BoxShape3D_door"] +size = Vector3(0.1, 4, 2) + +[sub_resource type="BoxMesh" id="BoxMesh_trail_long"] +size = Vector3(0.5, 0.01, 3) + +[sub_resource type="BoxMesh" id="BoxMesh_trail_medium"] +size = Vector3(0.5, 0.01, 4) + +[sub_resource type="BoxMesh" id="BoxMesh_stairs"] +size = Vector3(1.5, 0.2, 4) + +[sub_resource type="BoxShape3D" id="BoxShape3D_stairs"] +size = Vector3(1.5, 0.2, 4) + +[sub_resource type="BoxMesh" id="BoxMesh_upper_floor"] +size = Vector3(18, 0.1, 8) + +[sub_resource type="BoxShape3D" id="BoxShape3D_upper_floor"] +size = Vector3(18, 0.1, 8) + +[sub_resource type="BoxMesh" id="BoxMesh_upper_wall_long"] +size = Vector3(18, 3, 0.1) + +[sub_resource type="BoxShape3D" id="BoxShape3D_upper_wall_long"] +size = Vector3(18, 3, 0.1) + +[sub_resource type="BoxMesh" id="BoxMesh_upper_wall_short"] +size = Vector3(0.1, 3, 8) + +[sub_resource type="BoxShape3D" id="BoxShape3D_upper_wall_short"] +size = Vector3(0.1, 3, 8) + +[sub_resource type="BoxMesh" id="BoxMesh_bed"] +size = Vector3(1.8, 0.5, 0.9) + +[sub_resource type="BoxShape3D" id="BoxShape3D_bed"] +size = Vector3(1.8, 0.5, 0.9) + +[sub_resource type="BoxMesh" id="BoxMesh_anna_door"] +size = Vector3(0.05, 2.5, 1.2) + +[sub_resource type="BoxShape3D" id="BoxShape3D_anna_door"] +size = Vector3(0.05, 2.5, 1.2) + +[sub_resource type="BoxMesh" id="BoxMesh_myzel_patch"] +size = Vector3(0.8, 0.01, 0.8) + +[sub_resource type="BoxMesh" id="BoxMesh_myzel_trail_anna"] +size = Vector3(0.4, 0.01, 1.5) [node name="Tavern" type="Node3D"] script = ExtResource("1") -[node name="Camera3D" type="Camera3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.951, 0.309, 0, -0.309, 0.951, 0, 3, 6) -fov = 70.0 -current = true +[node name="Taproom" parent="." instance=ExtResource("2")] -[node name="WorldEnvironment" type="WorldEnvironment" parent="."] -environment = SubResource("Environment_1") +[node name="GroundFloor" type="Node3D" parent="."] -[node name="OmniLight3D" type="OmniLight3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0) -light_color = Color(0.91, 0.643, 0.29, 1) -light_energy = 1.2 -omni_range = 10.0 +[node name="KitchenBack" type="StaticBody3D" parent="GroundFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 1.5, -5.9) -[node name="Floor" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0) -mesh = SubResource("BoxMesh_floor") -surface_material_override/0 = SubResource("Material_1") +[node name="MeshInstance3D" type="MeshInstance3D" parent="GroundFloor/KitchenBack"] +mesh = SubResource("BoxMesh_kitchen_back") +surface_material_override/0 = SubResource("Material_wood") -[node name="Ceiling" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.05, 0) -mesh = SubResource("BoxMesh_ceiling") -surface_material_override/0 = SubResource("Material_1") +[node name="CollisionShape3D" type="CollisionShape3D" parent="GroundFloor/KitchenBack"] +shape = SubResource("BoxShape3D_kitchen_back") -[node name="WallBack" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, -4) -mesh = SubResource("BoxMesh_back") -surface_material_override/0 = SubResource("Material_1") +[node name="KitchenLeft" type="StaticBody3D" parent="GroundFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.05, 1.5, -4.85) -[node name="WallLeft" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 2, 0) -mesh = SubResource("BoxMesh_left") -surface_material_override/0 = SubResource("Material_1") +[node name="MeshInstance3D" type="MeshInstance3D" parent="GroundFloor/KitchenLeft"] +mesh = SubResource("BoxMesh_kitchen_side") +surface_material_override/0 = SubResource("Material_wood") -[node name="WallRight" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 2, 0) -mesh = SubResource("BoxMesh_right") -surface_material_override/0 = SubResource("Material_1") +[node name="CollisionShape3D" type="CollisionShape3D" parent="GroundFloor/KitchenLeft"] +shape = SubResource("BoxShape3D_kitchen_side") -[node name="CanvasLayer" type="CanvasLayer" parent="."] +[node name="KitchenRight" type="StaticBody3D" parent="GroundFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.95, 1.5, -4.85) -[node name="JoinPanel" type="VBoxContainer" parent="CanvasLayer"] -offset_left = 300.0 -offset_top = 200.0 -offset_right = 700.0 -offset_bottom = 500.0 +[node name="MeshInstance3D" type="MeshInstance3D" parent="GroundFloor/KitchenRight"] +mesh = SubResource("BoxMesh_kitchen_side") +surface_material_override/0 = SubResource("Material_wood") -[node name="Title" type="Label" parent="CanvasLayer/JoinPanel"] -text = "Ruf der Pilze" +[node name="CollisionShape3D" type="CollisionShape3D" parent="GroundFloor/KitchenRight"] +shape = SubResource("BoxShape3D_kitchen_side") -[node name="NameInput" type="LineEdit" parent="CanvasLayer/JoinPanel"] -placeholder_text = "Dein Name" +[node name="PrivateRoomDoor" type="StaticBody3D" parent="GroundFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 2, 2) -[node name="RoleOption" type="OptionButton" parent="CanvasLayer/JoinPanel"] +[node name="MeshInstance3D" type="MeshInstance3D" parent="GroundFloor/PrivateRoomDoor"] +mesh = SubResource("BoxMesh_door") +surface_material_override/0 = SubResource("Material_wood") -[node name="JoinButton" type="Button" parent="CanvasLayer/JoinPanel"] -text = "Beitreten" +[node name="CollisionShape3D" type="CollisionShape3D" parent="GroundFloor/PrivateRoomDoor"] +shape = SubResource("BoxShape3D_door") -[node name="WaitPanel" type="VBoxContainer" parent="CanvasLayer"] -visible = false -offset_left = 300.0 -offset_top = 200.0 -offset_right = 700.0 -offset_bottom = 500.0 +[node name="ExitDoor" type="StaticBody3D" parent="GroundFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 2, 4) -[node name="WaitLabel" type="Label" parent="CanvasLayer/WaitPanel"] -text = "Warte auf Spieler..." +[node name="MeshInstance3D" type="MeshInstance3D" parent="GroundFloor/ExitDoor"] +mesh = SubResource("BoxMesh_door") +surface_material_override/0 = SubResource("Material_wood") -[node name="PlayerList" type="ItemList" parent="CanvasLayer/WaitPanel"] -custom_minimum_size = Vector2(0, 150) +[node name="CollisionShape3D" type="CollisionShape3D" parent="GroundFloor/ExitDoor"] +shape = SubResource("BoxShape3D_door") -[node name="StartButton" type="Button" parent="CanvasLayer/WaitPanel"] -text = "Spiel starten" -visible = false +[node name="MyzelTrailGround" type="Node3D" parent="GroundFloor"] + +[node name="TrailSegment1" type="MeshInstance3D" parent="GroundFloor/MyzelTrailGround"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.06, 1.5) +mesh = SubResource("BoxMesh_trail_long") +surface_material_override/0 = SubResource("Material_myzel") + +[node name="TrailSegment2" type="MeshInstance3D" parent="GroundFloor/MyzelTrailGround"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0.06, 0) +mesh = SubResource("BoxMesh_trail_medium") +surface_material_override/0 = SubResource("Material_myzel") + +[node name="Stairs" type="StaticBody3D" parent="GroundFloor"] +transform = Transform3D(1, 0, 0, 0, 0.906, -0.423, 0, 0.423, 0.906, 0, 1, 3) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="GroundFloor/Stairs"] +mesh = SubResource("BoxMesh_stairs") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="GroundFloor/Stairs"] +shape = SubResource("BoxShape3D_stairs") + +[node name="UpperFloor" type="Node3D" parent="."] + +[node name="Floor" type="StaticBody3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 4, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Floor"] +mesh = SubResource("BoxMesh_upper_floor") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Floor"] +shape = SubResource("BoxShape3D_upper_floor") + +[node name="Ceiling" type="StaticBody3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 7, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Ceiling"] +mesh = SubResource("BoxMesh_upper_floor") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Ceiling"] +shape = SubResource("BoxShape3D_upper_floor") + +[node name="WallBack" type="StaticBody3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 5.5, -4) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/WallBack"] +mesh = SubResource("BoxMesh_upper_wall_long") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/WallBack"] +shape = SubResource("BoxShape3D_upper_wall_long") + +[node name="WallFront" type="StaticBody3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 5.5, 4) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/WallFront"] +mesh = SubResource("BoxMesh_upper_wall_long") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/WallFront"] +shape = SubResource("BoxShape3D_upper_wall_long") + +[node name="WallLeft" type="StaticBody3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 5.5, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/WallLeft"] +mesh = SubResource("BoxMesh_upper_wall_short") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/WallLeft"] +shape = SubResource("BoxShape3D_upper_wall_short") + +[node name="WallRight" type="StaticBody3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 5.5, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/WallRight"] +mesh = SubResource("BoxMesh_upper_wall_short") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/WallRight"] +shape = SubResource("BoxShape3D_upper_wall_short") + +[node name="CorridorWall" type="StaticBody3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 5.5, 2) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/CorridorWall"] +mesh = SubResource("BoxMesh_upper_wall_long") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/CorridorWall"] +shape = SubResource("BoxShape3D_upper_wall_long") + +[node name="Room1" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room1"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room1/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room1/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room1"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room2" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room2"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room2/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room2/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room2"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room3" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room3"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room3/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room3/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room3"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room4" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room4"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room4/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room4/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room4"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room5" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room5"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room5/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room5/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room5"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room6" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room6"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room6/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room6/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room6"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room7" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room7"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room7/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room7/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room7"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room8" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room8"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room8/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room8/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room8"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="Room9" type="Node3D" parent="UpperFloor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 11, 4.1, 2.8) + +[node name="Bed" type="StaticBody3D" parent="UpperFloor/Room9"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, -2.5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room9/Bed"] +mesh = SubResource("BoxMesh_bed") +surface_material_override/0 = SubResource("Material_myzel") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room9/Bed"] +shape = SubResource("BoxShape3D_bed") + +[node name="SpawnPoint" type="Marker3D" parent="UpperFloor/Room9"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, -1) + +[node name="OpenDoor" type="StaticBody3D" parent="UpperFloor/Room9"] +transform = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0.6, 1.25, 0.2) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="UpperFloor/Room9/OpenDoor"] +mesh = SubResource("BoxMesh_anna_door") +surface_material_override/0 = SubResource("Material_wood") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="UpperFloor/Room9/OpenDoor"] +shape = SubResource("BoxShape3D_anna_door") + +[node name="MyzelDecor" type="Node3D" parent="UpperFloor/Room9"] + +[node name="MyzelPatch1" type="MeshInstance3D" parent="UpperFloor/Room9/MyzelDecor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.3, 0.01, -2) +mesh = SubResource("BoxMesh_myzel_patch") +surface_material_override/0 = SubResource("Material_myzel") + +[node name="MyzelPatch2" type="MeshInstance3D" parent="UpperFloor/Room9/MyzelDecor"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.8, -3.8) +mesh = SubResource("BoxMesh_myzel_patch") +surface_material_override/0 = SubResource("Material_myzel") + +[node name="MyzelTrailAnna" type="Node3D" parent="UpperFloor/Room9"] + +[node name="TrailOut" type="MeshInstance3D" parent="UpperFloor/Room9/MyzelTrailAnna"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.06, 1.2) +mesh = SubResource("BoxMesh_myzel_trail_anna") +surface_material_override/0 = SubResource("Material_myzel") diff --git a/ruf-der-pilze/scenes/tavern_lobby.tscn b/ruf-der-pilze/scenes/tavern_lobby.tscn new file mode 100644 index 0000000..e4fd68c --- /dev/null +++ b/ruf-der-pilze/scenes/tavern_lobby.tscn @@ -0,0 +1,50 @@ +[gd_scene load_steps=2 format=3] + +[ext_resource type="Script" path="res://scripts/tavern_lobby.gd" id="1"] +[ext_resource type="PackedScene" path="res://scenes/taproom.tscn" id="2"] + +[node name="TavernLobby" type="Node3D"] +script = ExtResource("1") + +[node name="Taproom" parent="." instance=ExtResource("2")] + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.951, 0.309, 0, -0.309, 0.951, 0, 3, 6) +fov = 70.0 +current = true + +[node name="CanvasLayer" type="CanvasLayer" parent="."] + +[node name="JoinPanel" type="VBoxContainer" parent="CanvasLayer"] +offset_left = 300.0 +offset_top = 200.0 +offset_right = 700.0 +offset_bottom = 500.0 + +[node name="Title" type="Label" parent="CanvasLayer/JoinPanel"] +text = "Ruf der Pilze" + +[node name="NameInput" type="LineEdit" parent="CanvasLayer/JoinPanel"] +placeholder_text = "Dein Name" + +[node name="RoleOption" type="OptionButton" parent="CanvasLayer/JoinPanel"] + +[node name="JoinButton" type="Button" parent="CanvasLayer/JoinPanel"] +text = "Beitreten" + +[node name="WaitPanel" type="VBoxContainer" parent="CanvasLayer"] +visible = false +offset_left = 300.0 +offset_top = 200.0 +offset_right = 700.0 +offset_bottom = 500.0 + +[node name="WaitLabel" type="Label" parent="CanvasLayer/WaitPanel"] +text = "Warte auf Spieler..." + +[node name="PlayerList" type="ItemList" parent="CanvasLayer/WaitPanel"] +custom_minimum_size = Vector2(0, 150) + +[node name="StartButton" type="Button" parent="CanvasLayer/WaitPanel"] +text = "Spiel starten" +visible = false diff --git a/ruf-der-pilze/scripts/dm_view.gd b/ruf-der-pilze/scripts/dm_view.gd index 576adfe..f753936 100644 --- a/ruf-der-pilze/scripts/dm_view.gd +++ b/ruf-der-pilze/scripts/dm_view.gd @@ -1,216 +1,5 @@ extends Node -const TAVERN_SCENE := "res://scenes/tavern.tscn" -const CAM_EG_Y := 25.0 -const CAM_OG_Y := 30.0 -const OVERLAY_CYCLE := ["default", "spore_active"] - -var _top_down_cam: Camera3D -var _player_markers: Node3D -var _markers_by_id: Dictionary = {} # peer_id → MeshInstance3D -var _player_cam_cams: Dictionary = {} # peer_id → Camera3D (in SubViewport) -var _showing_upper_floor: bool = false - func _ready() -> void: - $RootLayout.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) - _load_tavern_into_viewport() - _setup_floor_buttons() - _setup_player_cams() - _setup_overlay_panel() - - -func _load_tavern_into_viewport() -> void: - var packed := ResourceLoader.load(TAVERN_SCENE, "PackedScene") as PackedScene - if packed == null: - push_error("[DmView] tavern.tscn nicht gefunden — wird nach Schritt 5 verfügbar sein") - return - var map_root := $RootLayout/TopSection/MapContainer/MapViewport/MapRoot as Node3D - _top_down_cam = map_root.get_node("TopDownCam") as Camera3D - _player_markers = map_root.get_node("PlayerMarkers") as Node3D - var tavern := packed.instantiate() - tavern.name = "Tavern" - map_root.add_child(tavern) - print("[DmView] Tavern in SubViewport geladen") - - -func _setup_floor_buttons() -> void: - var btn_eg := $RootLayout/TopSection/SidePanel/FloorButtons/BtnEG as Button - var btn_og := $RootLayout/TopSection/SidePanel/FloorButtons/BtnOG as Button - btn_eg.pressed.connect(func() -> void: _switch_floor(false)) - btn_og.pressed.connect(func() -> void: _switch_floor(true)) - - -func _switch_floor(upper: bool) -> void: - _showing_upper_floor = upper - if _top_down_cam == null: - return - _top_down_cam.global_position.y = CAM_OG_Y if upper else CAM_EG_Y - print("[DmView] Etage gewechselt → %s" % ("OG" if upper else "EG")) - - -# --- Player Cam Feeds (Task 7) --- - -func _setup_player_cams() -> void: - NetworkManager.player_joined.connect(_on_player_joined_cam) - NetworkManager.player_left.connect(_on_player_left_cam) - for peer_id in NetworkManager.players.keys(): - var info: Dictionary = NetworkManager.players[peer_id] - if info.get("role", "") == "player": - _create_player_cam(peer_id, info.get("name", "???")) - - -func _on_player_joined_cam(peer_id: int, player_name: String, role: String) -> void: - if role == "player": - _create_player_cam(peer_id, player_name) - - -func _on_player_left_cam(peer_id: int) -> void: - var row := $RootLayout/PlayerCamsRow - var panel := row.get_node_or_null("CamPanel_%d" % peer_id) - if panel != null: - panel.queue_free() - _player_cam_cams.erase(peer_id) - - -func _create_player_cam(peer_id: int, player_name: String) -> void: - var packed := ResourceLoader.load(TAVERN_SCENE, "PackedScene") as PackedScene - if packed == null: - push_error("[DmView] tavern.tscn nicht gefunden für Player-Cam") - return - - var viewport := SubViewport.new() - viewport.size = Vector2i(320, 180) - - var scene_root := Node3D.new() - var tavern := packed.instantiate() - scene_root.add_child(tavern) - - var cam := Camera3D.new() - cam.name = "PlayerCam" - cam.current = true - scene_root.add_child(cam) - viewport.add_child(scene_root) - - var container := SubViewportContainer.new() - container.name = "CamPanel_%d" % peer_id - container.custom_minimum_size = Vector2(320, 180) - container.stretch = true - container.add_child(viewport) - - var wrapper := VBoxContainer.new() - var label := Label.new() - label.text = player_name - label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - wrapper.add_child(label) - wrapper.add_child(container) - - $RootLayout/PlayerCamsRow.add_child(wrapper) - _player_cam_cams[peer_id] = cam - print("[DmView] Player-Cam erstellt für %s (Peer %d)" % [player_name, peer_id]) - - -# --- Overlay Panel (Task 8) --- - -func _setup_overlay_panel() -> void: - NetworkManager.player_joined.connect(_on_player_joined) - NetworkManager.player_left.connect(_on_player_left) - for peer_id in NetworkManager.players.keys(): - var info: Dictionary = NetworkManager.players[peer_id] - if info.get("role", "") == "player": - _add_overlay_row(peer_id, info.get("name", "???")) - - -func _on_player_joined(peer_id: int, player_name: String, role: String) -> void: - if role == "player": - _add_overlay_row(peer_id, player_name) - - -func _on_player_left(peer_id: int) -> void: - var list := $RootLayout/TopSection/SidePanel/OverlayScroll/PlayerList as VBoxContainer - var row := list.get_node_or_null("Row_%d" % peer_id) - if row != null: - row.queue_free() - - -func _add_overlay_row(peer_id: int, player_name: String) -> void: - var list := $RootLayout/TopSection/SidePanel/OverlayScroll/PlayerList as VBoxContainer - var row := HBoxContainer.new() - row.name = "Row_%d" % peer_id - var label := Label.new() - label.text = player_name - label.size_flags_horizontal = Control.SIZE_EXPAND_FILL - var btn := Button.new() - btn.text = "● default" - btn.pressed.connect(func() -> void: _toggle_overlay(peer_id, btn)) - row.add_child(label) - row.add_child(btn) - list.add_child(row) - - -func _toggle_overlay(peer_id: int, btn: Button) -> void: - var current := GameState.get_overlay(peer_id) - var idx := OVERLAY_CYCLE.find(current) - var next: String = OVERLAY_CYCLE[(idx + 1) % OVERLAY_CYCLE.size()] - NetworkManager.request_set_overlay.rpc_id(1, peer_id, next) - GameState.set_overlay_local(peer_id, next) - btn.text = "● %s" % next - print("[DmView] Overlay-Toggle → Spieler %d: %s" % [peer_id, next]) - - -# --- _process: Marker + Cam updates --- - -func _process(_delta: float) -> void: - _update_player_markers() - _update_player_cams() - - -func _update_player_markers() -> void: - if _player_markers == null: - return - for peer_id in GameState.player_positions.keys(): - var data: Dictionary = GameState.player_positions[peer_id] - var pos: Vector3 = data.get("position", Vector3.ZERO) - var rot: Vector3 = data.get("rotation", Vector3.ZERO) - var marker := _get_or_create_marker(peer_id) - marker.global_position = pos + Vector3(0, 0.2, 0) - marker.rotation.y = rot.y - var is_upper := pos.y > 3.5 - marker.visible = (is_upper == _showing_upper_floor) - - -func _get_or_create_marker(peer_id: int) -> MeshInstance3D: - if peer_id in _markers_by_id: - return _markers_by_id[peer_id] - var mesh := MeshInstance3D.new() - var sphere := SphereMesh.new() - sphere.radius = 0.25 - sphere.height = 0.5 - mesh.mesh = sphere - var mat := StandardMaterial3D.new() - mat.albedo_color = _peer_color(peer_id) - mat.emission_enabled = true - mat.emission = mat.albedo_color - mat.emission_energy_multiplier = 0.5 - mesh.material_override = mat - _player_markers.add_child(mesh) - _markers_by_id[peer_id] = mesh - print("[DmView] Marker erstellt für Peer %d" % peer_id) - return mesh - - -func _peer_color(peer_id: int) -> Color: - var colors := [Color.RED, Color.CYAN, Color.YELLOW, Color.MAGENTA, Color.GREEN] - return colors[peer_id % colors.size()] - - -func _update_player_cams() -> void: - for peer_id in _player_cam_cams.keys(): - if not GameState.player_positions.has(peer_id): - continue - var data: Dictionary = GameState.player_positions[peer_id] - var pos: Vector3 = data.get("position", Vector3.ZERO) - var rot: Vector3 = data.get("rotation", Vector3.ZERO) - var cam: Camera3D = _player_cam_cams[peer_id] - cam.global_position = pos - cam.global_rotation = rot + print("[DmView] DM-Szene geladen (Stub)") diff --git a/ruf-der-pilze/scripts/network_manager.gd b/ruf-der-pilze/scripts/network_manager.gd index 310bacd..f4b7de7 100644 --- a/ruf-der-pilze/scripts/network_manager.gd +++ b/ruf-der-pilze/scripts/network_manager.gd @@ -118,14 +118,27 @@ func request_start_game() -> void: var requester_id := multiplayer.get_remote_sender_id() if players.get(requester_id, {}).get("role", "") != "dm": return - start_game.rpc() + var assignments := _build_room_assignments() + start_game.rpc(assignments) @rpc("authority", "call_local", "reliable") -func start_game() -> void: +func start_game(room_assignments: Dictionary) -> void: + if my_id in room_assignments: + SceneManager.pending_room_index = room_assignments[my_id] game_started.emit() +func _build_room_assignments() -> Dictionary: + var result := {} + var player_peers: Array = players.keys().filter( + func(id: int) -> bool: return players[id].role == "player" + ) + for i in player_peers.size(): + result[player_peers[i]] = i % 8 # 8 Gästezimmer (Index 0–7) + return result + + # call_remote: Server hat lokal bereits gelöscht; nur Clients führen aus @rpc("authority", "call_remote", "reliable") func _broadcast_player_left(peer_id: int) -> void: diff --git a/ruf-der-pilze/scripts/scene_manager.gd b/ruf-der-pilze/scripts/scene_manager.gd index 9ebc426..d16d319 100644 --- a/ruf-der-pilze/scripts/scene_manager.gd +++ b/ruf-der-pilze/scripts/scene_manager.gd @@ -1,24 +1,23 @@ extends Node const SCENES := { - "tavern": "res://scenes/tavern.tscn", - "chamber": "res://scenes/chamber.tscn", + "lobby": "res://scenes/tavern_lobby.tscn", + "tavern": "res://scenes/tavern.tscn", + "dm_view": "res://scenes/dm_view.tscn", "entrance_hall": "res://scenes/entrance_hall.tscn", - "refectory": "res://scenes/refectory.tscn", - "library": "res://scenes/library.tscn", - "chapel": "res://scenes/chapel.tscn", - "cloister": "res://scenes/cloister.tscn", - "sanctum": "res://scenes/sanctum.tscn", + "refectory": "res://scenes/refectory.tscn", + "library": "res://scenes/library.tscn", + "chapel": "res://scenes/chapel.tscn", + "cloister": "res://scenes/cloister.tscn", + "sanctum": "res://scenes/sanctum.tscn", } +var pending_room_index: int = 0 var _current_scene_node: Node = null func _ready() -> void: NetworkManager.game_started.connect(_on_game_started) - # Defer until main.tscn and its CurrentScene node are in the tree. - # call_deferred is not sufficient here — autoloads init before the main - # scene. Connect to root.ready (fires once, after main scene is ready). get_tree().root.ready.connect(_on_root_ready, CONNECT_ONE_SHOT) @@ -26,7 +25,7 @@ func _on_root_ready() -> void: var args := OS.get_cmdline_args() + OS.get_cmdline_user_args() var is_server := OS.has_feature("dedicated_server") or "--server" in args if not is_server: - transition_to("tavern") + transition_to("lobby") func transition_to(scene_name: String) -> void: @@ -51,13 +50,8 @@ func _on_game_started() -> void: var args := OS.get_cmdline_args() + OS.get_cmdline_user_args() if OS.has_feature("dedicated_server") or "--server" in args: return - # TODO next feature: call _load_for_role("chamber") here once role routing is implemented - print("[SceneManager] Spiel gestartet — chamber transition kommt im nächsten Feature") - - -func _load_for_role(scene_name: String) -> void: - # my_id is only valid after NetworkManager._on_connected_to_server fires. - # Do not call before game_started — my_id will be 0 before that. var role: String = NetworkManager.players.get(NetworkManager.my_id, {}).get("role", "player") - # TODO next feature: load dm variant when role == "dm" - print("[SceneManager] Role %s → %s (stub, not switching yet)" % [role, scene_name]) + if role == "dm": + transition_to("dm_view") + else: + transition_to("tavern") diff --git a/ruf-der-pilze/scripts/tavern.gd b/ruf-der-pilze/scripts/tavern.gd index 6c7c3c4..23583a2 100644 --- a/ruf-der-pilze/scripts/tavern.gd +++ b/ruf-der-pilze/scripts/tavern.gd @@ -1,68 +1,29 @@ extends Node3D -var _local_role: String = "" -var _pending_player_name: String = "" +const ROOM_COUNT := 8 func _ready() -> void: - $CanvasLayer/JoinPanel/RoleOption.add_item("Spieler") - $CanvasLayer/JoinPanel/RoleOption.add_item("DM") - - $CanvasLayer/JoinPanel/JoinButton.pressed.connect(_on_join_pressed) - $CanvasLayer/WaitPanel/StartButton.pressed.connect(_on_start_pressed) - - NetworkManager.connected_to_server.connect(_on_connected) - NetworkManager.connection_failed.connect(_on_connection_failed) - NetworkManager.player_joined.connect(_on_player_joined) - NetworkManager.player_left.connect(_on_player_left) - NetworkManager.player_list_synced.connect(_rebuild_player_list) - - -func _on_join_pressed() -> void: - var player_name: String = ($CanvasLayer/JoinPanel/NameInput as LineEdit).text.strip_edges() - if player_name.is_empty(): + var args := OS.get_cmdline_args() + OS.get_cmdline_user_args() + if OS.has_feature("dedicated_server") or "--server" in args: return - _local_role = "dm" if $CanvasLayer/JoinPanel/RoleOption.selected == 1 else "player" - _pending_player_name = player_name - NetworkManager.join_server("127.0.0.1", 4242) + var room_index := SceneManager.pending_room_index + _spawn_player(room_index) -func _on_connected() -> void: - NetworkManager.register.rpc_id(1, _pending_player_name, _local_role) - $CanvasLayer/JoinPanel.visible = false - $CanvasLayer/WaitPanel.visible = true - $CanvasLayer/WaitPanel/StartButton.visible = (_local_role == "dm") - - -func _exit_tree() -> void: - NetworkManager.connected_to_server.disconnect(_on_connected) - NetworkManager.connection_failed.disconnect(_on_connection_failed) - NetworkManager.player_joined.disconnect(_on_player_joined) - NetworkManager.player_left.disconnect(_on_player_left) - NetworkManager.player_list_synced.disconnect(_rebuild_player_list) - - -func _on_connection_failed() -> void: - push_error("[Tavern] Verbindung fehlgeschlagen") - _local_role = "" - _pending_player_name = "" - $CanvasLayer/JoinPanel.visible = true - $CanvasLayer/WaitPanel.visible = false - - -func _on_player_joined(_peer_id: int, _player_name: String, _role: String) -> void: - _rebuild_player_list() - - -func _on_player_left(_peer_id: int) -> void: - _rebuild_player_list() - - -func _rebuild_player_list() -> void: - $CanvasLayer/WaitPanel/PlayerList.clear() - for p in NetworkManager.players.values(): - $CanvasLayer/WaitPanel/PlayerList.add_item("%s (%s)" % [p.name, p.role]) - - -func _on_start_pressed() -> void: - NetworkManager.request_start_game.rpc_id(1) +func _spawn_player(room_index: int) -> void: + var room_num := (room_index % ROOM_COUNT) + 1 # Zimmer heißen Room1..Room8 + var spawn_path := "UpperFloor/Room%d/SpawnPoint" % room_num + var spawn := get_node_or_null(spawn_path) as Marker3D + if spawn == null: + push_error("[Tavern] SpawnPoint nicht gefunden: %s" % spawn_path) + return + var controller := Node3D.new() + controller.name = "PlayerController" + var camera := Camera3D.new() + camera.name = "Camera3D" + camera.current = true + controller.add_child(camera) + add_child(controller) + controller.global_transform = spawn.global_transform + print("[Tavern] Spieler gespawnt in %s" % spawn_path) diff --git a/ruf-der-pilze/scripts/tavern_lobby.gd b/ruf-der-pilze/scripts/tavern_lobby.gd new file mode 100644 index 0000000..6c7c3c4 --- /dev/null +++ b/ruf-der-pilze/scripts/tavern_lobby.gd @@ -0,0 +1,68 @@ +extends Node3D + +var _local_role: String = "" +var _pending_player_name: String = "" + + +func _ready() -> void: + $CanvasLayer/JoinPanel/RoleOption.add_item("Spieler") + $CanvasLayer/JoinPanel/RoleOption.add_item("DM") + + $CanvasLayer/JoinPanel/JoinButton.pressed.connect(_on_join_pressed) + $CanvasLayer/WaitPanel/StartButton.pressed.connect(_on_start_pressed) + + NetworkManager.connected_to_server.connect(_on_connected) + NetworkManager.connection_failed.connect(_on_connection_failed) + NetworkManager.player_joined.connect(_on_player_joined) + NetworkManager.player_left.connect(_on_player_left) + NetworkManager.player_list_synced.connect(_rebuild_player_list) + + +func _on_join_pressed() -> void: + var player_name: String = ($CanvasLayer/JoinPanel/NameInput as LineEdit).text.strip_edges() + if player_name.is_empty(): + return + _local_role = "dm" if $CanvasLayer/JoinPanel/RoleOption.selected == 1 else "player" + _pending_player_name = player_name + NetworkManager.join_server("127.0.0.1", 4242) + + +func _on_connected() -> void: + NetworkManager.register.rpc_id(1, _pending_player_name, _local_role) + $CanvasLayer/JoinPanel.visible = false + $CanvasLayer/WaitPanel.visible = true + $CanvasLayer/WaitPanel/StartButton.visible = (_local_role == "dm") + + +func _exit_tree() -> void: + NetworkManager.connected_to_server.disconnect(_on_connected) + NetworkManager.connection_failed.disconnect(_on_connection_failed) + NetworkManager.player_joined.disconnect(_on_player_joined) + NetworkManager.player_left.disconnect(_on_player_left) + NetworkManager.player_list_synced.disconnect(_rebuild_player_list) + + +func _on_connection_failed() -> void: + push_error("[Tavern] Verbindung fehlgeschlagen") + _local_role = "" + _pending_player_name = "" + $CanvasLayer/JoinPanel.visible = true + $CanvasLayer/WaitPanel.visible = false + + +func _on_player_joined(_peer_id: int, _player_name: String, _role: String) -> void: + _rebuild_player_list() + + +func _on_player_left(_peer_id: int) -> void: + _rebuild_player_list() + + +func _rebuild_player_list() -> void: + $CanvasLayer/WaitPanel/PlayerList.clear() + for p in NetworkManager.players.values(): + $CanvasLayer/WaitPanel/PlayerList.add_item("%s (%s)" % [p.name, p.role]) + + +func _on_start_pressed() -> void: + NetworkManager.request_start_game.rpc_id(1)