M2.4: the server decides online (characters, inventory, stats, death, owned graves, per-player saves); death screen with Respawn after 3 s
This commit is contained in:
@@ -209,6 +209,72 @@ func fade(mid: Callable) -> void:
|
||||
player.ui_open = false
|
||||
black.queue_free())
|
||||
|
||||
var _death: Control
|
||||
|
||||
## 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`.
|
||||
func show_death(cause: String, note: String, delay: float, respawn: Callable) -> void:
|
||||
hide_death()
|
||||
player.ui_open = true
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
var bg := ColorRect.new()
|
||||
bg.color = Color(0.22, 0.02, 0.02, 0.0)
|
||||
bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
bg.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
add_child(bg)
|
||||
_death = bg
|
||||
var col := VBoxContainer.new()
|
||||
col.set_anchors_and_offsets_preset(Control.PRESET_CENTER)
|
||||
col.grow_horizontal = Control.GROW_DIRECTION_BOTH
|
||||
col.grow_vertical = Control.GROW_DIRECTION_BOTH
|
||||
col.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
col.add_theme_constant_override("separation", 14)
|
||||
col.modulate.a = 0.0
|
||||
bg.add_child(col)
|
||||
var title := UITheme.label("You died", 56)
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
col.add_child(title)
|
||||
var why := UITheme.label(cause if not cause.is_empty() else "You died", 22)
|
||||
why.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
col.add_child(why)
|
||||
var where := UITheme.label(note, 16, UITheme.TEXT_DIM)
|
||||
where.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
col.add_child(where)
|
||||
var btn := Button.new()
|
||||
btn.custom_minimum_size = Vector2(220, 46)
|
||||
btn.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
btn.disabled = true
|
||||
btn.text = "Respawn (%d)" % ceili(delay)
|
||||
col.add_child(btn)
|
||||
btn.pressed.connect(func():
|
||||
hide_death()
|
||||
respawn.call())
|
||||
var tw := bg.create_tween()
|
||||
tw.tween_property(bg, "color:a", 0.72, 0.9)
|
||||
tw.parallel().tween_property(col, "modulate:a", 1.0, 0.9)
|
||||
# Count down, then let them go.
|
||||
for k in range(1, ceili(delay)):
|
||||
var left := ceili(delay) - k
|
||||
get_tree().create_timer(float(k)).timeout.connect(func():
|
||||
if is_instance_valid(btn) and btn.disabled:
|
||||
btn.text = "Respawn (%d)" % left)
|
||||
get_tree().create_timer(delay).timeout.connect(func():
|
||||
if is_instance_valid(btn):
|
||||
btn.disabled = false
|
||||
btn.text = "Respawn"
|
||||
btn.grab_focus())
|
||||
|
||||
func is_dead_screen() -> bool:
|
||||
return _death != null and is_instance_valid(_death)
|
||||
|
||||
func hide_death() -> void:
|
||||
if is_dead_screen():
|
||||
_death.queue_free()
|
||||
_death = null
|
||||
player.ui_open = false
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
## Closes the inventory / menu (e.g. on death).
|
||||
func close_screens() -> void:
|
||||
if _screen.is_open():
|
||||
@@ -221,6 +287,8 @@ 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 event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_ESCAPE:
|
||||
if is_dead_screen():
|
||||
return # (respawn first)
|
||||
if _screen.is_open():
|
||||
_screen.close()
|
||||
elif _menu.is_open():
|
||||
|
||||
@@ -88,6 +88,7 @@ func bind(p: CharacterBody3D) -> void:
|
||||
wr.add_child(_worn_btn)
|
||||
pv.add_child(wr)
|
||||
player.worn_changed.connect(_refresh)
|
||||
PlayerNet.cursor_changed.connect(_on_server_cursor)
|
||||
pp.add_child(pv)
|
||||
row.add_child(pp)
|
||||
|
||||
@@ -142,14 +143,13 @@ func open(chest: Node) -> void:
|
||||
_refresh()
|
||||
|
||||
func close() -> void:
|
||||
if _cursor != null:
|
||||
if WorldNet.is_client():
|
||||
PlayerNet.ask("close") # the server puts the cursor back in our bag
|
||||
_cursor = null
|
||||
elif _cursor != null:
|
||||
var left: int = player.inventory.add(_cursor.id, _cursor.count)
|
||||
if left > 0 and container != null and is_instance_valid(container):
|
||||
if WorldNet.is_client():
|
||||
WorldNet.chest_put(container, {"id": _cursor.id, "count": left})
|
||||
left = 0
|
||||
else:
|
||||
left = container.inventory.add(_cursor.id, left)
|
||||
left = container.inventory.add(_cursor.id, left)
|
||||
_cursor = null
|
||||
if container != null and is_instance_valid(container) and container.inventory.changed.is_connected(_refresh):
|
||||
container.inventory.changed.disconnect(_refresh)
|
||||
@@ -193,11 +193,16 @@ func _rebuild_chest() -> void:
|
||||
_chest_grid.add_child(s)
|
||||
_chest_slots.append(s)
|
||||
|
||||
## Online the server does every click (player_net.gd). Clicks in our own
|
||||
## bag also happen here straight away, so dragging doesn't wait on the
|
||||
## network; the server's copy replaces ours once it's caught up.
|
||||
func _on_player_slot(i: int, right: bool, shift: bool) -> void:
|
||||
if shift and container != null:
|
||||
Actions.transfer(player, player.inventory, i, container.inventory, container)
|
||||
else:
|
||||
_cursor = player.inventory.click(i, _cursor, right)
|
||||
if WorldNet.is_client():
|
||||
PlayerNet.ask("inv_click", [0, i, right])
|
||||
_refresh()
|
||||
|
||||
func _on_chest_slot(i: int, right: bool, shift: bool) -> void:
|
||||
@@ -206,26 +211,17 @@ func _on_chest_slot(i: int, right: bool, shift: bool) -> void:
|
||||
if shift:
|
||||
Actions.transfer(player, container.inventory, i, player.inventory, container)
|
||||
elif WorldNet.is_client():
|
||||
# A shared chest: the server does the click (someone else may be in
|
||||
# it too) and hands back what we're holding.
|
||||
if WorldNet.chest_busy:
|
||||
return
|
||||
var held = _cursor
|
||||
_cursor = null
|
||||
WorldNet.chest_click(container, i, held, right, _on_chest_cursor)
|
||||
# A shared chest (someone else may be in it too): only the server's
|
||||
# answer counts.
|
||||
PlayerNet.ask("inv_click", [WorldNet.nid(container), i, right])
|
||||
else:
|
||||
_cursor = container.inventory.click(i, _cursor, right)
|
||||
_refresh()
|
||||
|
||||
func _on_chest_cursor(stack) -> void:
|
||||
if visible:
|
||||
_cursor = stack
|
||||
_refresh()
|
||||
elif stack != null:
|
||||
# Closed in the meantime: into our bag (or the ground).
|
||||
var left: int = player.inventory.add(stack.id, stack.count)
|
||||
if left > 0:
|
||||
player.get_parent().drop_item(stack.id, left, Transform3D(Basis(), player.global_position + Vector3(0, 0.1, 0)))
|
||||
## Online: what the server says we're holding.
|
||||
func _on_server_cursor(stack) -> void:
|
||||
_cursor = stack if visible else null
|
||||
_refresh()
|
||||
|
||||
func _refresh() -> void:
|
||||
if player == null:
|
||||
|
||||
Reference in New Issue
Block a user