rimlike/scenes/ai/mine_provider.gd
megaproxy 938e871bf1 Add BigRock: 2×2 mineable boulder with full mining/path/save support
A new entity for multi-tile rock formations. Same duck-typed contract as
single-tile Rock so MineProvider scans both transparently via World.rocks.

Differences from Rock:
  • Occupies a 2×2 footprint anchored at origin_tile (top-left).
  • Renders a single 32×32 Sprite2D drawn from the FG_Grasslands_Spring 2×2
    cluster sprites at (22, 3) brown and (30, 3) gray.
  • Blocks pathfinding on all four footprint tiles — pawns route around it.
  • MineProvider asks `rock.approach_tile_for(pawn.tile)` for the walk
    destination, so the pawn stands beside the boulder instead of trying to
    path into the blocked footprint. Rock returns its own tile (walkable);
    BigRock picks the nearest walkable perimeter neighbour.
  • Mining takes 480 ticks (4× Rock) and drops 4 stone, one per footprint tile.

All init work happens in setup() rather than _ready(): the calling pattern is
`add_child(big); big.setup(origin)`, and _ready fires inside add_child with
origin_tile still at its zero default — anything reading origin_tile from
_ready would stamp the pathfinder at the wrong tile.

Wired through SaveSystem: factory preload, spawn-priority tier 0 (same as
Rock — static structures spawn before pawns), and a `&"big_rock"` factory.

World seed adds two demo boulders near the small-rock cluster
(65, 58) + (56, 64) so the visual contrast is on-screen from boot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:34:24 +01:00

61 lines
2.3 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class_name MineProvider extends WorkProvider
## WorkProvider for the "mine" work category.
##
## Scans World.rocks for the nearest mineable Rock (Manhattan distance from
## the requesting pawn) and returns a two-toil Job:
## walk_to(rock.tile) → interact(rock.get_path(), "on_mine_tick")
##
## The INTERACT toil calls Rock.on_mine_tick() once per sim tick; the Rock
## internally tracks mine_progress and handles removal when MINE_TICKS is
## reached. The toil finishes automatically when is_mineable() returns
## false (exhausted) or when the node is freed.
##
## Phase 4 simplification: rocks are assumed walkable during mining approach
## (they may block movement in a later phase once obstruction is added to the
## pathfinder).
##
## Duck-typing note: Rock is referenced without class_name (class may not be
## registered yet when this provider loads). World.rocks may also hold BigRock
## instances; both expose the same interface so we just iterate the array:
## rock.tile: Vector2i — for distance scoring
## rock.is_mineable() -> bool
## rock.approach_tile_for(pawn_tile) -> Vector2i — walk destination
## rock.get_path() -> NodePath
func _init() -> void:
category = &"mine"
priority = 4 # Slightly lower than chop (5); both higher than rest (0).
## Returns a Job targeting the nearest mineable Rock, or null if none exists.
## `pawn` is duck-typed: must expose .tile (Vector2i).
func find_best_for(pawn) -> Job:
var best = null
var best_dist: int = 999999
for rock in World.rocks:
if not rock.is_mineable():
continue
if Job.is_target_taken_by_other(rock, pawn):
continue
var d: int = abs(rock.tile.x - pawn.tile.x) + abs(rock.tile.y - pawn.tile.y)
if d < best_dist:
best_dist = d
best = rock
if best == null:
return null
var j := Job.new()
j.label = "Mine rock at %s" % best.tile
j.target_node = best
# Ask the entity where the pawn should stand. Single rocks return their own
# tile (walkable). BigRocks return a perimeter tile so the pawn doesn't try
# to pathfind into the blocked 2×2 footprint.
var walk_tile: Vector2i = (
best.approach_tile_for(pawn.tile) if best.has_method("approach_tile_for") else best.tile
)
j.toils.append(Toil.walk_to(walk_tile))
j.toils.append(Toil.interact(best.get_path(), &"on_mine_tick"))
return j