M2.6: server rules (PvP, raiding, locks and friends, death penalty, difficulty, wolf grace), chat, admin commands, server console

This commit is contained in:
Paul Bailey
2026-11-04 22:54:40 +00:00
parent 47fc116839
commit 2ab79b68c6
26 changed files with 1195 additions and 57 deletions

View File

@@ -109,6 +109,7 @@ func bind(p: CharacterBody3D) -> void:
root.move_child(_hurt, 0)
player.survival.hurt.connect(_on_hurt)
Actions.notify.connect(toast)
_build_chat(root)
ItemDB.icons_ready.connect(_refresh)
_refresh()
@@ -175,6 +176,7 @@ func _build_stats(root: Control) -> void:
root.add_child(_clock)
func _process(_d: float) -> void:
_fade_chat()
var s = player.survival
for k in _bars:
_bars[k].value = s.get(k)
@@ -211,6 +213,70 @@ func fade(mid: Callable) -> void:
var _death: Control
# --- chat (online: T to talk) ----------------------------------------------------------
const CHAT_LINES := 8
const CHAT_FADE := 14.0 ## seconds a line stays up (all show while typing)
var _chat_log: VBoxContainer
var _chat_input: LineEdit
func _build_chat(root: Control) -> void:
_chat_log = VBoxContainer.new()
_chat_log.position = Vector2(16, 64)
_chat_log.custom_minimum_size = Vector2(520, 0)
_chat_log.add_theme_constant_override("separation", 2)
_chat_log.mouse_filter = Control.MOUSE_FILTER_IGNORE
root.add_child(_chat_log)
_chat_input = LineEdit.new()
_chat_input.position = Vector2(16, 64 + CHAT_LINES * 24 + 6)
_chat_input.custom_minimum_size = Vector2(520, 34)
_chat_input.placeholder_text = "Say something (Enter), or /help for commands. Esc to cancel"
_chat_input.max_length = 200
_chat_input.visible = false
_chat_input.text_submitted.connect(func(t):
Chat.say(t)
close_chat())
root.add_child(_chat_input)
Chat.message.connect(chat_line)
func chat_line(text: String, kind: String) -> void:
var col := UITheme.TEXT
if kind == "server":
col = Color(0.95, 0.82, 0.45)
elif kind == "reply":
col = UITheme.TEXT_DIM
var l := UITheme.label(text, 15, col)
l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
l.custom_minimum_size = Vector2(520, 0)
l.set_meta("t", Time.get_ticks_msec())
_chat_log.add_child(l)
while _chat_log.get_child_count() > CHAT_LINES:
var old := _chat_log.get_child(0)
_chat_log.remove_child(old)
old.queue_free()
func open_chat() -> void:
_chat_input.text = ""
_chat_input.visible = true
player.ui_open = true
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
_chat_input.grab_focus()
func close_chat() -> void:
_chat_input.visible = false
_chat_input.release_focus()
player.ui_open = false
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _fade_chat() -> void:
if _chat_log == null:
return
var typing := _chat_input.visible
var now := Time.get_ticks_msec()
for l in _chat_log.get_children():
var age := (now - int(l.get_meta("t", now))) / 1000.0
l.modulate.a = 1.0 if typing else clampf((CHAT_FADE - age) / 2.0, 0.0, 1.0)
## The death screen: the world fades to dark red, it says what killed you
## and where your things are, and after `delay` seconds Respawn (or Enter)
## calls `respawn`.
@@ -286,6 +352,16 @@ func _on_inventory_requested(container: Node) -> void:
## ESC: close the inventory if it's open, otherwise toggle the pause menu.
func _input(event: InputEvent) -> void:
if _chat_input != null and _chat_input.visible:
if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
close_chat()
get_viewport().set_input_as_handled()
return # (typing: keys go to the chat line)
if event is InputEventKey and event.pressed and not event.echo and event.physical_keycode == KEY_T \
and Net.state == "connected" and not player.ui_open and not is_dead_screen():
open_chat()
get_viewport().set_input_as_handled()
return
if event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_ESCAPE:
if is_dead_screen():
return # (respawn first)