Inspect tooltip: add crops, bed sprite-canopy, layer audit
Player report: hovering trees works after the canopy fix, but crops show
nothing and beds still report "Wood floor" sometimes.
* Crops are added to the lookup, showing kind + growth stage + percent
("Wheat | sown · 98%", "Wheat | ready to harvest", "tilled — not sown").
* Bed sprite is 16×32 (two tiles tall, anchor at the foot). Hovering on
the headboard (one tile above the anchor) used to miss. Added a sprite-
canopy pass for beds mirroring the existing 4-tile tree canopy logic.
* Full layer audit and reordering. Final priority top-down:
1. Pawn / Wolf / Corpse / Grave marker — entities the player cares
about first.
2. Crop — small sprite, exact tile only.
3. Tree — trunk tile + 4-tile canopy.
4. Big rock (2×2 footprint) / Rock — exact tile / footprint.
5. Furniture at exact tile (wall / door / bed / crate / workbench /
torch).
6. Furniture sprite-canopy (currently only bed; future tall furniture
slots in here).
7. Item on the ground (loose stack).
8. Stockpile / zone region overlay.
9. Floor — only when nothing physical is on the tile.
Confirmed at runtime: bed foot → Bed; bed headboard → Bed (via canopy);
two-tiles-above-bed → empty; crop at growing stage shows percent; bare
floor still says Wood floor; furniture on wood floor wins over floor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
00f38ffd95
commit
531b907012
1 changed files with 93 additions and 37 deletions
|
|
@ -120,21 +120,54 @@ func _position_near(mouse_screen: Vector2) -> void:
|
|||
|
||||
# ── tile → description ──────────────────────────────────────────────────────
|
||||
|
||||
## Priority order matches what the player visually expects on top of a tile:
|
||||
## pawn > wolf > corpse > grave > crop > tree (4-tile canopy) > big rock /
|
||||
## rock > furniture (bed/wall/door/crate/workbench/torch with 1-tile sprite
|
||||
## canopy for tall bottom-anchored entities) > item > stockpile region > floor.
|
||||
##
|
||||
## Floor + terrain are the bottom layer — only shown when nothing else covers
|
||||
## the tile. "Wood floor" tooltip means the tile is genuinely empty.
|
||||
##
|
||||
## "Sprite canopy" handles entities whose visual extends above their anchor
|
||||
## tile (trees: trunk + 4 tiles up; beds: 16×32 sprite covering tile.y - 1
|
||||
## as well as tile.y). Walls / torches / crates / doors are 16×16 — anchor
|
||||
## tile only, no canopy.
|
||||
func _describe_tile(tile: Vector2i) -> String:
|
||||
# Priority order: pawn > corpse > wolf > big_rock > tree > rock > furniture
|
||||
# (wall/door/bed/crate/workbench/torch/floor) > item > stockpile zone > terrain.
|
||||
# 1. Pawn
|
||||
var p = World.pawn_at_tile(tile) if World.has_method("pawn_at_tile") else null
|
||||
if p != null and is_instance_valid(p):
|
||||
return _describe_pawn(p)
|
||||
|
||||
for c in World.corpses:
|
||||
if is_instance_valid(c) and c.get("tile") == tile:
|
||||
return _describe_corpse(c)
|
||||
|
||||
# 2. Wolf
|
||||
for w in World.wolves:
|
||||
if is_instance_valid(w) and w.get("tile") == tile:
|
||||
return _describe_wolf(w)
|
||||
|
||||
# 3. Corpse
|
||||
for c in World.corpses:
|
||||
if is_instance_valid(c) and c.get("tile") == tile:
|
||||
return _describe_corpse(c)
|
||||
|
||||
# 4. Grave marker (permanent burial, dedicated structure)
|
||||
for gm in World.grave_markers:
|
||||
if is_instance_valid(gm) and gm.get("tile") == tile:
|
||||
return _describe_grave(gm)
|
||||
|
||||
# 5. Crop (farm plant — small sprite, exact tile only)
|
||||
for cp in World.crops:
|
||||
if is_instance_valid(cp) and cp.get("tile") == tile:
|
||||
return _describe_crop(cp)
|
||||
|
||||
# 6. Tree — trunk tile + 4 tiles of canopy above (sprite is 64×80 px,
|
||||
# anchored at trunk bottom; covers tile.y - 4..tile.y vertically).
|
||||
for t in World.trees:
|
||||
if not is_instance_valid(t):
|
||||
continue
|
||||
var tt: Vector2i = t.get("tile")
|
||||
if tile.x == tt.x and tile.y >= tt.y - 4 and tile.y <= tt.y:
|
||||
return _describe_tree(t)
|
||||
|
||||
# 7. Rock (big rock = 2×2 footprint match; single rock = exact tile).
|
||||
for r in World.rocks:
|
||||
if not is_instance_valid(r):
|
||||
continue
|
||||
|
|
@ -144,46 +177,43 @@ func _describe_tile(tile: Vector2i) -> String:
|
|||
elif r.get("tile") == tile:
|
||||
return _describe_rock(r)
|
||||
|
||||
# Trees anchor to the trunk tile (bottom) but visually rise up to 4 tiles
|
||||
# above (canopy). Treat any hover within that vertical band as the tree.
|
||||
for t in World.trees:
|
||||
if not is_instance_valid(t):
|
||||
continue
|
||||
var tt: Vector2i = t.get("tile")
|
||||
if tile.x == tt.x and tile.y >= tt.y - 4 and tile.y <= tt.y:
|
||||
return _describe_tree(t)
|
||||
|
||||
# Furniture / build sites at this tile (Wall, Floor, Door, Bed, Crate,
|
||||
# Workbench, Torch, GraveSlot all live in World.build_queue via _ready).
|
||||
# Two-pass: above-ground furniture wins over floor, so hovering on a bed
|
||||
# placed on a wood floor reports the bed, not the floor underneath.
|
||||
# 8. Furniture (build_queue) — three-pass priority:
|
||||
# (a) exact tile, non-floor: walls/doors/beds/crates/workbenches/torches.
|
||||
# (b) canopy match for tall sprites (bed = 16×32 covers tile.y - 1 too).
|
||||
# (c) floor + zone overlays + items below (lower layers).
|
||||
var floor_hit = null
|
||||
for s in World.build_queue:
|
||||
if not is_instance_valid(s):
|
||||
continue
|
||||
if s.get("tile") != tile:
|
||||
continue
|
||||
var s_tile: Vector2i = s.get("tile")
|
||||
var path: String = s.get_script().resource_path if s.get_script() else ""
|
||||
if "floor.gd" in path:
|
||||
floor_hit = s
|
||||
continue # remember it, but keep scanning for furniture on top
|
||||
var d := _describe_build_site(s)
|
||||
if d != "":
|
||||
return d
|
||||
# Items take priority over the bare floor too — a wood stack should show
|
||||
# as "wood ×N", not as the floor it sits on.
|
||||
if s_tile == tile:
|
||||
if "floor.gd" in path:
|
||||
floor_hit = s
|
||||
continue
|
||||
var d := _describe_build_site(s)
|
||||
if d != "":
|
||||
return d
|
||||
# Sprite canopy pass: beds (16×32) cover the tile above their anchor.
|
||||
# Any other furniture taller than 16 px should be added here.
|
||||
for s in World.build_queue:
|
||||
if not is_instance_valid(s):
|
||||
continue
|
||||
var path2: String = s.get_script().resource_path if s.get_script() else ""
|
||||
if "bed.gd" not in path2:
|
||||
continue
|
||||
var s_tile2: Vector2i = s.get("tile")
|
||||
if tile.x == s_tile2.x and tile.y == s_tile2.y - 1:
|
||||
return _describe_build_site(s)
|
||||
|
||||
# 9. Loose items on the ground (wood stacks, food, ingots).
|
||||
for it in World.items:
|
||||
if is_instance_valid(it) and it.get("tile") == tile:
|
||||
return _describe_item(it)
|
||||
if floor_hit != null:
|
||||
return _describe_build_site(floor_hit)
|
||||
|
||||
# Grave markers (permanent, not in build_queue once converted).
|
||||
for gm in World.grave_markers:
|
||||
if is_instance_valid(gm) and gm.get("tile") == tile:
|
||||
return _describe_grave(gm)
|
||||
|
||||
# Stockpile / graveyard / cremation zones (region-based, may be multi-cell).
|
||||
# 10. Stockpile / graveyard / cremation zones — region overlay shown
|
||||
# only when nothing physical occupies the tile (items above already
|
||||
# win, which is what the player expects).
|
||||
for sp in World.stockpiles:
|
||||
if not is_instance_valid(sp):
|
||||
continue
|
||||
|
|
@ -191,6 +221,10 @@ func _describe_tile(tile: Vector2i) -> String:
|
|||
if region != null and region.has_point(tile):
|
||||
return _describe_stockpile(sp)
|
||||
|
||||
# 11. Floor fallback (the genuinely-bare-floor case).
|
||||
if floor_hit != null:
|
||||
return _describe_build_site(floor_hit)
|
||||
|
||||
return "" # nothing to show
|
||||
|
||||
|
||||
|
|
@ -344,6 +378,28 @@ func _describe_build_site(s) -> String:
|
|||
return "[b]%s[/b]" % label
|
||||
|
||||
|
||||
func _describe_crop(cp) -> String:
|
||||
var kind: String = String(cp.crop_kind).capitalize() if "crop_kind" in cp else "Crop"
|
||||
var stage_name: String = "?"
|
||||
if "stage" in cp and "Stage" in cp:
|
||||
var keys: Array = cp.Stage.keys()
|
||||
var idx: int = int(cp.stage)
|
||||
if idx >= 0 and idx < keys.size():
|
||||
stage_name = String(keys[idx]).to_lower().replace("_", " ")
|
||||
var pct: int = -1
|
||||
if "stage_progress" in cp and "STAGE_TICKS" in cp:
|
||||
var st: int = int(cp.STAGE_TICKS) if cp.STAGE_TICKS != 0 else 1
|
||||
pct = int(100.0 * float(cp.stage_progress) / float(st))
|
||||
var head := "[b]%s[/b]" % kind
|
||||
if stage_name == "ready":
|
||||
return "%s\n[color=#fc6]ready to harvest[/color]" % head
|
||||
if stage_name == "tilled":
|
||||
return "%s\n[color=#888]tilled (not sown)[/color]" % head
|
||||
if pct >= 0:
|
||||
return "%s\n%s · %d%%" % [head, stage_name, pct]
|
||||
return "%s\n%s" % [head, stage_name]
|
||||
|
||||
|
||||
func _describe_item(it) -> String:
|
||||
return "[b]%s[/b] ×%d" % [String(it.item_type).capitalize(), int(it.stack_size)]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue