add demolish mode for buildings (Issue #50)

- New 💥 Demolish button in the action bar
- Red ghost highlights building footprint on hover
- Refund: 100% within 3 min, decays linearly to 0%
- Mine teardown unblocks passability tiles and removes status label
- Nisse inside demolished mine are rescued and reset to idle
- Floor/wall/chest tiles restored to GRASS on demolish
- Build error now shows missing resources instead of generic message
- BuildingState gains builtAt field; old saves default to 0 (no refund)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 20:18:49 +00:00
parent 6eeb47c720
commit fc10201469
8 changed files with 302 additions and 30 deletions

View File

@@ -767,6 +767,33 @@ export class VillagerSystem {
* Destroys all Nisse sprites and clears the runtime map.
* Should be called when the scene shuts down.
*/
/**
* Rescues all Nisse that were working inside a demolished building.
* Makes hidden sprites visible again, clears their jobs, and resets AI to idle.
* Also releases any mine-capacity claims for that building.
* @param buildingId - ID of the building that was demolished
*/
rescueNisseFromBuilding(buildingId: string): void {
this.mineClaimsMap.delete(buildingId)
const state = stateManager.getState()
for (const v of Object.values(state.world.villagers)) {
if (v.job?.targetId !== buildingId) continue
const rt = this.runtime.get(v.id)
if (!rt) continue
// Make sprite visible in case the Nisse was hidden inside the mine
rt.sprite.setVisible(true)
rt.nameLabel.setVisible(true)
rt.energyBar.setVisible(true)
rt.jobIcon.setVisible(true)
rt.workTimer = 0
rt.idleScanTimer = 0
this.claimed.delete(buildingId)
this.adapter.send({ type: 'VILLAGER_SET_JOB', villagerId: v.id, job: null })
this.adapter.send({ type: 'VILLAGER_SET_AI', villagerId: v.id, aiState: 'idle' })
this.addLog(v.id, '! Building demolished — resuming')
}
}
/**
* Destroys all Nisse sprites and clears the runtime map.
* Should be called when the scene shuts down.