Crafting tabs (tools, weapons, cooking, building...); panel fits at 1280x720; steadier smoothness test
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
"output": "stone_axe",
|
"output": "stone_axe",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "",
|
"station": "",
|
||||||
|
"category": "tools",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"stick": 2,
|
"stick": 2,
|
||||||
"flint": 2
|
"flint": 2
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
"output": "stone_pickaxe",
|
"output": "stone_pickaxe",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "",
|
"station": "",
|
||||||
|
"category": "tools",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"stick": 2,
|
"stick": 2,
|
||||||
"stone": 3,
|
"stone": 3,
|
||||||
@@ -26,6 +28,7 @@
|
|||||||
"output": "campfire",
|
"output": "campfire",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "",
|
"station": "",
|
||||||
|
"category": "stations",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"stone": 5,
|
"stone": 5,
|
||||||
"stick": 4
|
"stick": 4
|
||||||
@@ -36,6 +39,7 @@
|
|||||||
"output": "workbench",
|
"output": "workbench",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "",
|
"station": "",
|
||||||
|
"category": "stations",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 10,
|
"wood": 10,
|
||||||
"flint": 2
|
"flint": 2
|
||||||
@@ -46,6 +50,7 @@
|
|||||||
"output": "club",
|
"output": "club",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "",
|
"station": "",
|
||||||
|
"category": "weapons",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 4
|
"wood": 4
|
||||||
}
|
}
|
||||||
@@ -55,6 +60,7 @@
|
|||||||
"output": "chest",
|
"output": "chest",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "furniture",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 10,
|
"wood": 10,
|
||||||
"stick": 4
|
"stick": 4
|
||||||
@@ -65,6 +71,7 @@
|
|||||||
"output": "torch",
|
"output": "torch",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "",
|
"station": "",
|
||||||
|
"category": "tools",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"stick": 1,
|
"stick": 1,
|
||||||
"fiber": 2
|
"fiber": 2
|
||||||
@@ -75,6 +82,7 @@
|
|||||||
"output": "roasted_mushroom",
|
"output": "roasted_mushroom",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "campfire",
|
"station": "campfire",
|
||||||
|
"category": "cooking",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"mushroom": 1
|
"mushroom": 1
|
||||||
}
|
}
|
||||||
@@ -84,6 +92,7 @@
|
|||||||
"output": "wood_floor",
|
"output": "wood_floor",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "building",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 2
|
"wood": 2
|
||||||
}
|
}
|
||||||
@@ -93,6 +102,7 @@
|
|||||||
"output": "wood_wall",
|
"output": "wood_wall",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "building",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 2
|
"wood": 2
|
||||||
}
|
}
|
||||||
@@ -102,6 +112,7 @@
|
|||||||
"output": "wood_door",
|
"output": "wood_door",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "building",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 4
|
"wood": 4
|
||||||
}
|
}
|
||||||
@@ -111,6 +122,7 @@
|
|||||||
"output": "wood_roof",
|
"output": "wood_roof",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "building",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 2,
|
"wood": 2,
|
||||||
"fiber": 1
|
"fiber": 1
|
||||||
@@ -121,6 +133,7 @@
|
|||||||
"output": "wood_gable",
|
"output": "wood_gable",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "building",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 1
|
"wood": 1
|
||||||
}
|
}
|
||||||
@@ -130,6 +143,7 @@
|
|||||||
"output": "bed",
|
"output": "bed",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "furniture",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 8,
|
"wood": 8,
|
||||||
"fiber": 6
|
"fiber": 6
|
||||||
@@ -140,6 +154,7 @@
|
|||||||
"output": "cooked_meat",
|
"output": "cooked_meat",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "campfire",
|
"station": "campfire",
|
||||||
|
"category": "cooking",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"raw_meat": 1
|
"raw_meat": 1
|
||||||
}
|
}
|
||||||
@@ -149,6 +164,7 @@
|
|||||||
"output": "spear",
|
"output": "spear",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "weapons",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 3,
|
"wood": 3,
|
||||||
"flint": 2,
|
"flint": 2,
|
||||||
@@ -160,6 +176,7 @@
|
|||||||
"output": "bow",
|
"output": "bow",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "weapons",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wood": 4,
|
"wood": 4,
|
||||||
"fiber": 6
|
"fiber": 6
|
||||||
@@ -170,6 +187,7 @@
|
|||||||
"output": "arrow",
|
"output": "arrow",
|
||||||
"count": 5,
|
"count": 5,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "weapons",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"stick": 2,
|
"stick": 2,
|
||||||
"flint": 1,
|
"flint": 1,
|
||||||
@@ -181,6 +199,7 @@
|
|||||||
"output": "hide_cloak",
|
"output": "hide_cloak",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "clothing",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"hide": 4,
|
"hide": 4,
|
||||||
"fiber": 4
|
"fiber": 4
|
||||||
@@ -191,6 +210,7 @@
|
|||||||
"output": "wolf_cloak",
|
"output": "wolf_cloak",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "clothing",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"wolf_pelt": 3,
|
"wolf_pelt": 3,
|
||||||
"hide": 2,
|
"hide": 2,
|
||||||
@@ -202,6 +222,7 @@
|
|||||||
"output": "fishing_rod",
|
"output": "fishing_rod",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "workbench",
|
"station": "workbench",
|
||||||
|
"category": "tools",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"stick": 2,
|
"stick": 2,
|
||||||
"fiber": 3,
|
"fiber": 3,
|
||||||
@@ -213,6 +234,7 @@
|
|||||||
"output": "grilled_perch",
|
"output": "grilled_perch",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "campfire",
|
"station": "campfire",
|
||||||
|
"category": "cooking",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"perch": 1
|
"perch": 1
|
||||||
}
|
}
|
||||||
@@ -222,6 +244,7 @@
|
|||||||
"output": "grilled_trout",
|
"output": "grilled_trout",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"station": "campfire",
|
"station": "campfire",
|
||||||
|
"category": "cooking",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"trout": 1
|
"trout": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,29 @@ func define_recipe(r: Dictionary) -> void:
|
|||||||
return
|
return
|
||||||
r.count = int(r.get("count", 1))
|
r.count = int(r.get("count", 1))
|
||||||
r.station = String(r.get("station", ""))
|
r.station = String(r.get("station", ""))
|
||||||
|
r.category = String(r.get("category", guess_category(items[r.output])))
|
||||||
|
if not CATEGORIES.has(r.category):
|
||||||
|
r.category = "other"
|
||||||
recipes[r.id] = r
|
recipes[r.id] = r
|
||||||
|
|
||||||
|
## The crafting screen's tabs, in order: id -> label.
|
||||||
|
const CATEGORIES := {"tools": "Tools", "weapons": "Weapons", "cooking": "Cooking", "building": "Building",
|
||||||
|
"stations": "Stations", "furniture": "Furniture", "clothing": "Clothing", "other": "Other"}
|
||||||
|
|
||||||
|
## For recipes (an addon's, say) that don't say: worked out from what they make.
|
||||||
|
static func guess_category(item: Dictionary) -> String:
|
||||||
|
if item.has("food"):
|
||||||
|
return "cooking"
|
||||||
|
if item.has("weapon") or item.has("bow"):
|
||||||
|
return "weapons"
|
||||||
|
if item.has("tool") or item.has("fishing") or item.has("light"):
|
||||||
|
return "tools"
|
||||||
|
if item.has("wear"):
|
||||||
|
return "clothing"
|
||||||
|
if item.has("place"):
|
||||||
|
return "building" if item.place.has("kind") else "furniture"
|
||||||
|
return "other"
|
||||||
|
|
||||||
func _load_fishing(path: String) -> void:
|
func _load_fishing(path: String) -> void:
|
||||||
var data = JSON.parse_string(FileAccess.get_file_as_string(path))
|
var data = JSON.parse_string(FileAccess.get_file_as_string(path))
|
||||||
if typeof(data) != TYPE_DICTIONARY or not data.has("waters"):
|
if typeof(data) != TYPE_DICTIONARY or not data.has("waters"):
|
||||||
|
|||||||
@@ -100,8 +100,14 @@ func bind(p: CharacterBody3D) -> void:
|
|||||||
crv.add_child(UITheme.label("Crafting", 20))
|
crv.add_child(UITheme.label("Crafting", 20))
|
||||||
_station_label = UITheme.label("", 13, UITheme.TEXT_DIM)
|
_station_label = UITheme.label("", 13, UITheme.TEXT_DIM)
|
||||||
crv.add_child(_station_label)
|
crv.add_child(_station_label)
|
||||||
|
# Categories: Tools, Weapons, Cooking... (ItemDB.CATEGORIES). Two rows
|
||||||
|
# of tabs, so they all fit.
|
||||||
|
_tabs = HFlowContainer.new()
|
||||||
|
_tabs.add_theme_constant_override("h_separation", 4)
|
||||||
|
_tabs.add_theme_constant_override("v_separation", 4)
|
||||||
|
crv.add_child(_tabs)
|
||||||
var scroll := ScrollContainer.new()
|
var scroll := ScrollContainer.new()
|
||||||
scroll.custom_minimum_size = Vector2(320, 380)
|
scroll.custom_minimum_size = Vector2(320, 330)
|
||||||
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||||
_recipe_list = VBoxContainer.new()
|
_recipe_list = VBoxContainer.new()
|
||||||
_recipe_list.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
_recipe_list.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
@@ -139,6 +145,7 @@ func open(chest: Node) -> void:
|
|||||||
visible = true
|
visible = true
|
||||||
player.ui_open = true
|
player.ui_open = true
|
||||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
_pick_tab()
|
||||||
_rebuild_chest()
|
_rebuild_chest()
|
||||||
_refresh()
|
_refresh()
|
||||||
|
|
||||||
@@ -250,8 +257,59 @@ func _rebuild_recipes() -> void:
|
|||||||
if Actions.station_near(player, st):
|
if Actions.station_near(player, st):
|
||||||
stations.append(st)
|
stations.append(st)
|
||||||
_station_label.text = "Nearby: " + (", ".join(stations) if not stations.is_empty() else "nothing (hand crafting only)")
|
_station_label.text = "Nearby: " + (", ".join(stations) if not stations.is_empty() else "nothing (hand crafting only)")
|
||||||
|
_rebuild_tabs()
|
||||||
for rid in ItemDB.recipes:
|
for rid in ItemDB.recipes:
|
||||||
_recipe_list.add_child(_recipe_row(ItemDB.recipes[rid]))
|
var r: Dictionary = ItemDB.recipes[rid]
|
||||||
|
if r.category == category:
|
||||||
|
_recipe_list.add_child(_recipe_row(r))
|
||||||
|
|
||||||
|
var _tabs: HFlowContainer
|
||||||
|
var category := "tools" ## the tab showing
|
||||||
|
var _picked := false ## chose a tab since opening (don't jump about)
|
||||||
|
|
||||||
|
## Tabs for the categories that have recipes, each with how many of its
|
||||||
|
## recipes you could make right now.
|
||||||
|
func _rebuild_tabs() -> void:
|
||||||
|
for c in _tabs.get_children():
|
||||||
|
c.queue_free()
|
||||||
|
var count := {}
|
||||||
|
var ready := {}
|
||||||
|
for rid in ItemDB.recipes:
|
||||||
|
var r: Dictionary = ItemDB.recipes[rid]
|
||||||
|
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
|
||||||
|
if not count.has(category):
|
||||||
|
category = count.keys()[0] if not count.is_empty() else "tools"
|
||||||
|
for cat in ItemDB.CATEGORIES:
|
||||||
|
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.toggle_mode = true
|
||||||
|
b.button_pressed = cat == category
|
||||||
|
b.focus_mode = Control.FOCUS_NONE
|
||||||
|
b.add_theme_font_size_override("font_size", 13)
|
||||||
|
if n > 0 and cat != category:
|
||||||
|
b.add_theme_color_override("font_color", UITheme.OK)
|
||||||
|
b.pressed.connect(func():
|
||||||
|
category = cat
|
||||||
|
_picked = true
|
||||||
|
_rebuild_recipes())
|
||||||
|
_tabs.add_child(b)
|
||||||
|
|
||||||
|
## On opening: Cooking if you're at a lit fire with something to cook,
|
||||||
|
## otherwise the tab you were on last.
|
||||||
|
func _pick_tab() -> void:
|
||||||
|
_picked = false
|
||||||
|
if not Actions.station_near(player, "campfire"):
|
||||||
|
return
|
||||||
|
for rid in ItemDB.recipes:
|
||||||
|
var r: Dictionary = ItemDB.recipes[rid]
|
||||||
|
if r.category == "cooking" and Actions.can_craft(player, rid):
|
||||||
|
category = "cooking"
|
||||||
|
return
|
||||||
|
|
||||||
func _recipe_row(r: Dictionary) -> Control:
|
func _recipe_row(r: Dictionary) -> Control:
|
||||||
var ok := Actions.can_craft(player, r.id)
|
var ok := Actions.can_craft(player, r.id)
|
||||||
@@ -275,7 +333,7 @@ func _recipe_row(r: Dictionary) -> Control:
|
|||||||
req.bbcode_enabled = true
|
req.bbcode_enabled = true
|
||||||
req.fit_content = true
|
req.fit_content = true
|
||||||
req.scroll_active = false
|
req.scroll_active = false
|
||||||
req.autowrap_mode = TextServer.AUTOWRAP_OFF
|
req.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART # (long lists wrap rather than widen the panel)
|
||||||
req.add_theme_font_size_override("normal_font_size", 13)
|
req.add_theme_font_size_override("normal_font_size", 13)
|
||||||
var parts: Array[String] = []
|
var parts: Array[String] = []
|
||||||
for id in r.inputs:
|
for id in r.inputs:
|
||||||
@@ -287,7 +345,7 @@ func _recipe_row(r: Dictionary) -> Control:
|
|||||||
var col := UITheme.OK if Actions.station_near(player, r.station) else UITheme.BAD
|
var col := UITheme.OK if Actions.station_near(player, r.station) else UITheme.BAD
|
||||||
parts.append("[color=#%s]@ %s[/color]" % [col.to_html(false), r.station])
|
parts.append("[color=#%s]@ %s[/color]" % [col.to_html(false), r.station])
|
||||||
req.text = " ".join(parts)
|
req.text = " ".join(parts)
|
||||||
req.custom_minimum_size = Vector2(200, 0)
|
req.custom_minimum_size = Vector2(170, 0)
|
||||||
v.add_child(req)
|
v.add_child(req)
|
||||||
h.add_child(v)
|
h.add_child(v)
|
||||||
var b := Button.new()
|
var b := Button.new()
|
||||||
|
|||||||
@@ -107,9 +107,18 @@ func _body() -> void:
|
|||||||
var end_anim: int = av.anim if is_instance_valid(av) else -1
|
var end_anim: int = av.anim if is_instance_valid(av) else -1
|
||||||
var br := await _result(bob)
|
var br := await _result(bob)
|
||||||
var moving := samples.filter(func(s): return s[1] > 0.5)
|
var moving := samples.filter(func(s): return s[1] > 0.5)
|
||||||
|
# Top speed over 0.2 s windows (4 samples): one late frame on this machine
|
||||||
|
# reads as a burst in a single 50 ms sample, while a real jump (half a
|
||||||
|
# metre extra) still shows as over 6.5 m/s.
|
||||||
var top := 0.0
|
var top := 0.0
|
||||||
for s in samples:
|
for i in range(3, samples.size()):
|
||||||
top = maxf(top, s[1])
|
var dt_sum := 0.0
|
||||||
|
var dist := 0.0
|
||||||
|
for j in range(i - 3, i + 1):
|
||||||
|
var dtj: float = samples[j][0] - (samples[j - 1][0] if j > 0 else 0.0)
|
||||||
|
dt_sum += dtj
|
||||||
|
dist += float(samples[j][1]) * dtj
|
||||||
|
top = maxf(top, dist / maxf(dt_sum, 0.001))
|
||||||
var stalls := 0
|
var stalls := 0
|
||||||
if moving.size() > 2:
|
if moving.size() > 2:
|
||||||
# Count gaps inside the walking stretch where he froze.
|
# Count gaps inside the walking stretch where he froze.
|
||||||
|
|||||||
Reference in New Issue
Block a user