P1 iron: nuggets, ore, clay, kiln, smelter, forge, iron tools and arrows, lantern, tool wear and repair

This commit is contained in:
Paul Bailey
2026-11-05 00:31:07 +00:00
parent ab1f417c32
commit 24c280d885
24 changed files with 1334 additions and 43 deletions

View File

@@ -154,9 +154,11 @@ func close() -> void:
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)
var left: int = player.inventory.add_stack(_cursor)
if left > 0 and container != null and is_instance_valid(container):
left = container.inventory.add(_cursor.id, left)
var rest: Dictionary = _cursor.duplicate()
rest.count = left
left = container.inventory.add_stack(rest)
_cursor = null
if container != null and is_instance_valid(container) and container.inventory.changed.is_connected(_refresh):
container.inventory.changed.disconnect(_refresh)
@@ -253,16 +255,75 @@ func _rebuild_recipes() -> void:
for c in _recipe_list.get_children():
c.queue_free()
var stations: Array[String] = []
for st in ["workbench", "campfire"]:
for st in ["workbench", "campfire", "forge"]:
if Actions.station_near(player, st):
stations.append(st)
_station_label.text = "Nearby: " + (", ".join(stations) if not stations.is_empty() else "nothing (hand crafting only)")
_rebuild_tabs()
if category == "repair":
for slot in _worn_slots():
_recipe_list.add_child(_repair_row(slot))
return
for rid in ItemDB.recipes:
var r: Dictionary = ItemDB.recipes[rid]
if r.category == category:
_recipe_list.add_child(_recipe_row(r))
## Slots holding a tool or weapon that's been used.
func _worn_slots() -> Array:
var out: Array = []
for i in range(player.inventory.size()):
if not Actions.repair_cost(player, i).is_empty():
out.append(i)
return out
func _repair_row(slot: int) -> Control:
var s = player.inventory.get_slot(slot)
var cost: Dictionary = Actions.repair_cost(player, slot)
var ok := Actions.can_repair(player, slot)
var row := PanelContainer.new()
row.add_theme_stylebox_override("panel", UITheme.box(UITheme.SLOT_BG, UITheme.SELECTED if ok else UITheme.SLOT_BORDER, 1, 5, 6))
var h := HBoxContainer.new()
h.add_theme_constant_override("separation", 8)
row.add_child(h)
var icon := TextureRect.new()
icon.texture = ItemDB.icon(s.id)
icon.custom_minimum_size = Vector2(44, 44)
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
h.add_child(icon)
var v := VBoxContainer.new()
v.size_flags_horizontal = Control.SIZE_EXPAND_FILL
v.add_child(UITheme.label("%s (%d/%d)" % [ItemDB.item_name(s.id), ItemDB.durability(s), ItemDB.max_durability(s.id)], 16,
UITheme.TEXT if ok else UITheme.TEXT_DIM))
var req := RichTextLabel.new()
req.bbcode_enabled = true
req.fit_content = true
req.scroll_active = false
req.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
req.add_theme_font_size_override("normal_font_size", 13)
req.custom_minimum_size = Vector2(170, 0)
var parts: Array[String] = []
for id in cost.inputs:
var need := int(cost.inputs[id])
var have: int = player.inventory.count(id)
parts.append("[color=#%s]%s %d/%d[/color]" % [(UITheme.OK if have >= need else UITheme.BAD).to_html(false), ItemDB.item_name(id), have, need])
var st := String(cost.get("station", ""))
if not st.is_empty():
parts.append("[color=#%s]@ %s[/color]" % [(UITheme.OK if Actions.station_near(player, st) else UITheme.BAD).to_html(false), st])
req.text = " ".join(parts)
v.add_child(req)
h.add_child(v)
var b := Button.new()
b.text = "Repair"
b.disabled = not ok
b.focus_mode = Control.FOCUS_NONE
b.pressed.connect(func():
Actions.repair(player, slot)
_refresh())
h.add_child(b)
return row
var _tabs: HFlowContainer
var category := "tools" ## the tab showing
var _picked := false ## chose a tab since opening (don't jump about)
@@ -279,14 +340,19 @@ func _rebuild_tabs() -> void:
count[r.category] = int(count.get(r.category, 0)) + 1
if Actions.can_craft(player, rid):
ready[r.category] = int(ready.get(r.category, 0)) + 1
# Repair: shown once something you carry is worn.
var worn := _worn_slots()
if not worn.is_empty():
count["repair"] = worn.size()
ready["repair"] = worn.filter(func(i): return Actions.can_repair(player, i)).size()
if not count.has(category):
category = count.keys()[0] if not count.is_empty() else "tools"
for cat in ItemDB.CATEGORIES:
for cat in ItemDB.CATEGORIES.keys() + ["repair"]:
if not count.has(cat):
continue
var b := Button.new()
var n := int(ready.get(cat, 0))
b.text = ItemDB.CATEGORIES[cat] + (" (%d)" % n if n > 0 else "")
b.text = String(ItemDB.CATEGORIES.get(cat, "Repair")) + (" (%d)" % n if n > 0 else "")
b.toggle_mode = true
b.button_pressed = cat == category
b.focus_mode = Control.FOCUS_NONE

View File

@@ -13,6 +13,8 @@ var _key: Label
var _style: StyleBoxFlat
var _selected_style: StyleBoxFlat
var _stack = null
var _wear: ColorRect
var _wear_fill: ColorRect
func _init(i: int = 0, size_px: int = 64, key_label: String = "") -> void:
index = i
@@ -44,17 +46,44 @@ func _init(i: int = 0, size_px: int = 64, key_label: String = "") -> void:
_key.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(_key)
_wear = ColorRect.new()
_wear.color = Color(0, 0, 0, 0.6)
_wear.set_anchors_and_offsets_preset(Control.PRESET_BOTTOM_WIDE)
_wear.offset_left = 6
_wear.offset_right = -6
_wear.offset_top = -9
_wear.offset_bottom = -5
_wear.mouse_filter = Control.MOUSE_FILTER_IGNORE
_wear.visible = false
add_child(_wear)
_wear_fill = ColorRect.new()
_wear_fill.anchor_bottom = 1.0
_wear_fill.mouse_filter = Control.MOUSE_FILTER_IGNORE
_wear.add_child(_wear_fill)
func set_stack(stack) -> void:
_stack = stack
if stack == null:
_icon.texture = null
_count.text = ""
tooltip_text = ""
_wear.visible = false
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", "")]
# Wear: a bar along the bottom once a tool or weapon has been used.
var full := ItemDB.max_durability(stack.id)
var left := ItemDB.durability(stack)
if full > 0 and left < full:
var k := float(left) / full
_wear.visible = true
_wear_fill.anchor_right = k
_wear_fill.color = Color(0.85, 0.25, 0.2) if k < 0.2 else (Color(0.9, 0.75, 0.25) if k < 0.5 else Color(0.45, 0.8, 0.35))
tooltip_text += "\n%d of %d uses left" % [left, full]
else:
_wear.visible = false
func set_selected(on: bool) -> void:
add_theme_stylebox_override("panel", _selected_style if on else _style)