M1a: survival core, pause menu, title screen and save/load
Design: docs/SURVIVAL_DESIGN.md (core loop, systems, architecture, phases). Survival core (M1a): - Items/recipes as data (data/*.json) in the addon SDK's define_item / define_recipe shape; procedural item meshes and offscreen-rendered icons - Inventory class (40 slots, hotbar = row 1) shared by player and chests; click / right-click split / shift-click quick-move - Actions autoload: the intent layer (craft, pickup, harvest_hit, place, transfer) that validates every change; becomes the RPC surface in M2 - Gathering: ground pickups (sticks, stones, flint); trees chopped with an axe fall and leave stumps; boulders mined with a pickaxe shrink per hit - Crafting screen with station checks (workbench); placement mode with green/red ghost, rotation and overlap/slope validation - Pieces: campfire (light, flames, embers), workbench, chest (16 slots) - HUD: hotbar, held tool view model with swing, prompts, toasts Menus and saving: - ESC pause menu: resume, controls, fullscreen, mouse sensitivity, quit - Title screen over a flyover of the island: Continue / New World (name + seed) / Load World (with delete) / Quit - Saves autoload: one folder per world under user://worlds, atomic writes with a .bak; stores only player changes (player, pieces, chest contents, harvested resources, taken pickups) and regenerates the rest from the seed - Autosave every 2 min, Save & Quit to title/desktop, save on window close Fixes: UI screens now fill the viewport (were pinned top-left); title backdrop no longer captures the mouse. Tests: test_survival_core (31 checks), test_save_load (round trip + slots), test_terrain_edges now checks 8 seeds for deep pits / unbanked water.
This commit is contained in:
66
scripts/ui/slot.gd
Normal file
66
scripts/ui/slot.gd
Normal file
@@ -0,0 +1,66 @@
|
||||
extends Panel
|
||||
## One inventory slot: icon, stack count, optional hotbar number. Renders a
|
||||
## stack and reports clicks; it never changes the inventory itself.
|
||||
|
||||
signal clicked(index: int, right: bool, shift: bool)
|
||||
|
||||
const UITheme = preload("res://scripts/ui/theme.gd")
|
||||
|
||||
var index := 0
|
||||
var _icon: TextureRect
|
||||
var _count: Label
|
||||
var _key: Label
|
||||
var _style: StyleBoxFlat
|
||||
var _selected_style: StyleBoxFlat
|
||||
var _stack = null
|
||||
|
||||
func _init(i: int = 0, size_px: int = 64, key_label: String = "") -> void:
|
||||
index = i
|
||||
custom_minimum_size = Vector2(size_px, size_px)
|
||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
_style = UITheme.box(UITheme.SLOT_BG, UITheme.SLOT_BORDER, 2, 5, 0)
|
||||
_selected_style = UITheme.box(UITheme.SLOT_BG.lightened(0.15), UITheme.SELECTED, 3, 5, 0)
|
||||
add_theme_stylebox_override("panel", _style)
|
||||
|
||||
_icon = TextureRect.new()
|
||||
_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
_icon.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
_icon.offset_left = 5; _icon.offset_top = 5; _icon.offset_right = -5; _icon.offset_bottom = -5
|
||||
_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(_icon)
|
||||
|
||||
_count = UITheme.label("", 15)
|
||||
_count.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_RIGHT)
|
||||
_count.grow_horizontal = Control.GROW_DIRECTION_BEGIN
|
||||
_count.grow_vertical = Control.GROW_DIRECTION_BEGIN
|
||||
_count.offset_right = -5
|
||||
_count.offset_bottom = -2
|
||||
_count.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(_count)
|
||||
|
||||
_key = UITheme.label(key_label, 12, UITheme.TEXT_DIM)
|
||||
_key.position = Vector2(5, 2)
|
||||
_key.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(_key)
|
||||
|
||||
func set_stack(stack) -> void:
|
||||
_stack = stack
|
||||
if stack == null:
|
||||
_icon.texture = null
|
||||
_count.text = ""
|
||||
tooltip_text = ""
|
||||
return
|
||||
_icon.texture = ItemDB.icon(stack.id)
|
||||
_count.text = str(stack.count) if stack.count > 1 else ""
|
||||
var def := ItemDB.get_item(stack.id)
|
||||
tooltip_text = "%s\n%s" % [def.get("name", stack.id), def.get("description", "")]
|
||||
|
||||
func set_selected(on: bool) -> void:
|
||||
add_theme_stylebox_override("panel", _selected_style if on else _style)
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton and event.pressed:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT:
|
||||
clicked.emit(index, event.button_index == MOUSE_BUTTON_RIGHT, event.shift_pressed)
|
||||
accept_event()
|
||||
Reference in New Issue
Block a user