feat: merge Schritt 8 — dice roller
This commit is contained in:
@@ -56,6 +56,28 @@ size_flags_vertical = 3
|
||||
|
||||
[node name="PlayerList" type="VBoxContainer" parent="RootLayout/TopSection/SidePanel/OverlayScroll"]
|
||||
|
||||
[node name="SepDice" type="HSeparator" parent="RootLayout/TopSection/SidePanel"]
|
||||
|
||||
[node name="LblDice" type="Label" parent="RootLayout/TopSection/SidePanel"]
|
||||
text = "Würfelwürfe"
|
||||
|
||||
[node name="DCRow" type="HBoxContainer" parent="RootLayout/TopSection/SidePanel"]
|
||||
|
||||
[node name="LblDC" type="Label" parent="RootLayout/TopSection/SidePanel/DCRow"]
|
||||
text = "DC:"
|
||||
|
||||
[node name="DCSpinBox" type="SpinBox" parent="RootLayout/TopSection/SidePanel/DCRow"]
|
||||
min_value = 1.0
|
||||
max_value = 30.0
|
||||
value = 12.0
|
||||
|
||||
[node name="RollLogScroll" type="ScrollContainer" parent="RootLayout/TopSection/SidePanel"]
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="RollLog" type="RichTextLabel" parent="RootLayout/TopSection/SidePanel/RollLogScroll"]
|
||||
bbcode_enabled = true
|
||||
fit_content = true
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="RootLayout"]
|
||||
|
||||
[node name="PlayerCamsRow" type="HBoxContainer" parent="RootLayout"]
|
||||
|
||||
@@ -4,6 +4,8 @@ const TAVERN_SCENE := "res://scenes/tavern.tscn"
|
||||
const FLOOR_THRESHOLD := 3.5 # y < threshold → EG, y >= threshold → OG
|
||||
const OVERLAY_CYCLE := ["default", "spore_active"]
|
||||
|
||||
var _dm_roll_log: RichTextLabel
|
||||
|
||||
var _eg_markers: Node3D
|
||||
var _og_markers: Node3D
|
||||
var _eg_markers_by_id: Dictionary = {} # peer_id → MeshInstance3D
|
||||
@@ -16,6 +18,7 @@ func _ready() -> void:
|
||||
_load_tavern_into_viewports()
|
||||
_setup_player_cams()
|
||||
_setup_overlay_panel()
|
||||
_setup_dc_section()
|
||||
|
||||
|
||||
func _load_tavern_into_viewports() -> void:
|
||||
@@ -196,6 +199,24 @@ func _peer_color(peer_id: int) -> Color:
|
||||
return colors[peer_id % colors.size()]
|
||||
|
||||
|
||||
func _setup_dc_section() -> void:
|
||||
_dm_roll_log = $RootLayout/TopSection/SidePanel/RollLogScroll/RollLog as RichTextLabel
|
||||
NetworkManager.roll_received.connect(_on_roll_received_dm)
|
||||
|
||||
|
||||
func _on_roll_received_dm(roller_peer_id: int, player_name: String, d20_result: int, modifier: int, total: int) -> void:
|
||||
var dc: int = ($RootLayout/TopSection/SidePanel/DCRow/DCSpinBox as SpinBox).value as int
|
||||
var mod_str := " %+d" % modifier if modifier != 0 else ""
|
||||
var success := total >= dc
|
||||
var result_str := "[color=green]Erfolg[/color]" if success else "[color=red]Fehlschlag[/color]"
|
||||
var line := "[b]%s[/b]: %d%s = [b]%d[/b] vs DC%d → %s" % [player_name, d20_result, mod_str, total, dc, result_str]
|
||||
if d20_result == 20:
|
||||
line += " [color=gold]★[/color]"
|
||||
elif d20_result == 1:
|
||||
line += " [color=red]☠[/color]"
|
||||
_dm_roll_log.append_text(line + "\n")
|
||||
|
||||
|
||||
func _update_player_cams() -> void:
|
||||
for peer_id in _player_cam_cams.keys():
|
||||
if not GameState.player_positions.has(peer_id):
|
||||
|
||||
@@ -14,6 +14,7 @@ signal player_joined(peer_id: int, player_name: String, role: String)
|
||||
signal player_left(peer_id: int)
|
||||
signal player_list_synced()
|
||||
signal game_started()
|
||||
signal roll_received(roller_peer_id: int, player_name: String, d20_result: int, modifier: int, total: int)
|
||||
|
||||
|
||||
func start_server(port: int, max_clients: int) -> void:
|
||||
@@ -164,3 +165,18 @@ func set_overlay(overlay_name: String) -> void:
|
||||
@rpc("any_peer", "call_remote", "unreliable")
|
||||
func sync_player_position(player_id: int, position: Vector3, rotation: Vector3) -> void:
|
||||
GameState.update_player_transform(player_id, position, rotation)
|
||||
|
||||
|
||||
# Client calls this on server only (rpc_id(1, ...))
|
||||
@rpc("any_peer", "call_remote", "reliable")
|
||||
func broadcast_roll(roller_peer_id: int, d20_result: int, modifier: int) -> void:
|
||||
if not multiplayer.is_server(): return
|
||||
_relay_roll.rpc(roller_peer_id, d20_result, modifier)
|
||||
|
||||
|
||||
# Server broadcasts to all (including itself via call_local)
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
func _relay_roll(roller_peer_id: int, d20_result: int, modifier: int) -> void:
|
||||
var player_name: String = players.get(roller_peer_id, {}).get("name", "???")
|
||||
var total := d20_result + modifier
|
||||
roll_received.emit(roller_peer_id, player_name, d20_result, modifier, total)
|
||||
|
||||
@@ -2,6 +2,9 @@ extends Node3D
|
||||
|
||||
const ROOM_COUNT := 8
|
||||
|
||||
var _modifier: int = 0
|
||||
var _roll_log: RichTextLabel
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var args := OS.get_cmdline_args() + OS.get_cmdline_user_args()
|
||||
@@ -18,6 +21,7 @@ func _ready() -> void:
|
||||
timer.autostart = true
|
||||
timer.timeout.connect(_broadcast_camera_transform)
|
||||
add_child(timer)
|
||||
_setup_dice_ui()
|
||||
|
||||
|
||||
func _get_dm_peer_id() -> int:
|
||||
@@ -56,3 +60,73 @@ func _spawn_player(room_index: int) -> void:
|
||||
add_child(controller)
|
||||
controller.global_transform = spawn.global_transform
|
||||
print("[Tavern] Spieler gespawnt in %s" % spawn_path)
|
||||
|
||||
|
||||
func _setup_dice_ui() -> void:
|
||||
var canvas := CanvasLayer.new()
|
||||
canvas.name = "DiceUI"
|
||||
add_child(canvas)
|
||||
|
||||
var panel := PanelContainer.new()
|
||||
panel.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_LEFT)
|
||||
panel.offset_top = -120
|
||||
panel.offset_right = 400
|
||||
canvas.add_child(panel)
|
||||
|
||||
var vbox := VBoxContainer.new()
|
||||
panel.add_child(vbox)
|
||||
|
||||
_roll_log = RichTextLabel.new()
|
||||
_roll_log.custom_minimum_size = Vector2(380, 60)
|
||||
_roll_log.bbcode_enabled = true
|
||||
vbox.add_child(_roll_log)
|
||||
|
||||
var hbox := HBoxContainer.new()
|
||||
vbox.add_child(hbox)
|
||||
|
||||
var roll_btn := Button.new()
|
||||
roll_btn.text = "d20 Würfeln"
|
||||
roll_btn.pressed.connect(_on_roll_pressed)
|
||||
hbox.add_child(roll_btn)
|
||||
|
||||
var mod_label := Label.new()
|
||||
mod_label.text = " Mod:"
|
||||
hbox.add_child(mod_label)
|
||||
|
||||
var mod_display := Label.new()
|
||||
mod_display.text = "0"
|
||||
mod_display.custom_minimum_size = Vector2(30, 0)
|
||||
mod_display.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
|
||||
var mod_minus := Button.new()
|
||||
mod_minus.text = "-"
|
||||
mod_minus.pressed.connect(func() -> void: _modifier -= 1; _update_mod_display(mod_display))
|
||||
hbox.add_child(mod_minus)
|
||||
|
||||
hbox.add_child(mod_display)
|
||||
|
||||
var mod_plus := Button.new()
|
||||
mod_plus.text = "+"
|
||||
mod_plus.pressed.connect(func() -> void: _modifier += 1; _update_mod_display(mod_display))
|
||||
hbox.add_child(mod_plus)
|
||||
|
||||
NetworkManager.roll_received.connect(_on_roll_received)
|
||||
|
||||
|
||||
func _update_mod_display(label: Label) -> void:
|
||||
label.text = "%+d" % _modifier if _modifier != 0 else "0"
|
||||
|
||||
|
||||
func _on_roll_pressed() -> void:
|
||||
var d20 := randi() % 20 + 1
|
||||
NetworkManager.broadcast_roll.rpc_id(1, NetworkManager.my_id, d20, _modifier)
|
||||
|
||||
|
||||
func _on_roll_received(roller_peer_id: int, player_name: String, d20_result: int, modifier: int, total: int) -> void:
|
||||
var mod_str := " %+d" % modifier if modifier != 0 else ""
|
||||
var line := "[b]%s[/b] würfelt %d%s = [b]%d[/b]" % [player_name, d20_result, mod_str, total]
|
||||
if d20_result == 20:
|
||||
line = "[color=gold]" + line + " ★ NAT 20![/color]"
|
||||
elif d20_result == 1:
|
||||
line = "[color=red]" + line + " ☠ NAT 1[/color]"
|
||||
_roll_log.append_text(line + "\n")
|
||||
|
||||
Reference in New Issue
Block a user