feat(expansion): implement Phase 3 (Town Restoration) and Phase 4 (Cannabis Textiles)

- Added TownSquareScene and linked it with M key transition
- Integrated TownRestorationSystem with material costs and inventory
- Added locked shop items in NPCShopSystem until buildings are restored
- Updated InteractionSystem to handle ruin restoration triggers
- Expanded Cannabis farming to yield Hemp Fiber
- Added Hemp Clothing crafting recipe and procedural icons
- Refactored StatusEffectSystem and NPCShopSystem to global classes
This commit is contained in:
2025-12-27 23:32:22 +01:00
parent 611cd35777
commit 822c586843
12 changed files with 454 additions and 40 deletions

View File

@@ -14,7 +14,7 @@
* @date 2025-12-23
*/
export default class NPCShopSystem {
class NPCShopSystem {
constructor(scene) {
this.scene = scene;
@@ -52,15 +52,16 @@ export default class NPCShopSystem {
location: { x: 200, y: 200 },
inventory: [
// Tools
{ id: 'iron_axe', name: 'Iron Axe', price: 200, stock: 5, category: 'tools' },
{ id: 'iron_pickaxe', name: 'Iron Pickaxe', price: 200, stock: 5, category: 'tools' },
{ id: 'iron_hoe', name: 'Iron Hoe', price: 150, stock: 5, category: 'tools' },
{ id: 'iron_axe', name: 'Iron Axe', price: 200, stock: 5, category: 'tools', locked: true },
{ id: 'iron_pickaxe', name: 'Iron Pickaxe', price: 200, stock: 5, category: 'tools', locked: true },
{ id: 'iron_hoe', name: 'Iron Hoe', price: 150, stock: 5, category: 'tools', locked: true },
{ id: 'watering_can', name: 'Watering Can', price: 100, stock: 10, category: 'tools' },
// Weapons
{ id: 'iron_sword', name: 'Iron Sword', price: 500, stock: 3, category: 'weapons' },
{ id: 'steel_sword', name: 'Steel Sword', price: 1000, stock: 2, category: 'weapons' },
{ id: 'crossbow', name: 'Crossbow', price: 800, stock: 2, category: 'weapons' },
{ id: 'iron_sword', name: 'Iron Sword', price: 500, stock: 3, category: 'weapons', locked: true },
{ id: 'steel_sword', name: 'Steel Sword', price: 1000, stock: 2, category: 'weapons', locked: true },
{ id: 'crossbow', name: 'Crossbow', price: 800, stock: 2, category: 'weapons', locked: true },
// Armor
{ id: 'leather_armor', name: 'Leather Armor', price: 300, stock: 5, category: 'armor' },
@@ -104,6 +105,7 @@ export default class NPCShopSystem {
{ id: 'corn_seeds', name: 'Corn Seeds', price: 8, stock: 150, category: 'seeds' },
{ id: 'tomato_seeds', name: 'Tomato Seeds', price: 10, stock: 100, category: 'seeds' },
{ id: 'strawberry_seeds', name: 'Strawberry Seeds', price: 15, stock: 80, category: 'seeds' },
{ id: 'cannabis_seeds', name: 'Cannabis Seeds', price: 20, stock: 50, category: 'seeds' },
// Materials
{ id: 'wood', name: 'Wood', price: 10, stock: 500, category: 'materials' },
@@ -138,7 +140,7 @@ export default class NPCShopSystem {
{ id: 'bandage', name: 'Bandage', price: 15, stock: 100, category: 'medical' },
{ id: 'medicine', name: 'Medicine', price: 80, stock: 30, category: 'medical' }
],
buyback: ['herbs', 'mushrooms', 'zombie_samples']
buyback: ['herbs', 'mushrooms', 'zombie_samples', 'cannabis', 'cannabis_buds']
}
];
@@ -332,13 +334,25 @@ export default class NPCShopSystem {
this.itemListContainer.add(priceText);
// Buy button
const buyBtn = this.scene.add.rectangle(350, y, 100, 35, 0x228B22);
buyBtn.setStrokeStyle(2, 0x32CD32);
const isLocked = item.locked && !this.isShopRestored(this.currentShop.id);
const buyColor = isLocked ? 0x666666 : 0x228B22;
const buyBtn = this.scene.add.rectangle(350, y, 100, 35, buyColor);
buyBtn.setStrokeStyle(2, isLocked ? 0x999999 : 0x32CD32);
buyBtn.setInteractive();
buyBtn.on('pointerdown', () => this.buyItem(item));
buyBtn.on('pointerdown', () => {
if (isLocked) {
this.showNotification({
title: 'Shop Ruined',
text: `Restore the shop to unlock this item!`,
icon: '🏚️'
});
} else {
this.buyItem(item);
}
});
this.itemListContainer.add(buyBtn);
const buyText = this.scene.add.text(350, y, 'BUY', {
const buyText = this.scene.add.text(350, y, isLocked ? 'LOCKED' : 'BUY', {
fontSize: '14px',
fontFamily: 'Arial',
color: '#ffffff',
@@ -349,6 +363,24 @@ export default class NPCShopSystem {
});
}
isShopRestored(shopId) {
if (!this.scene.townRestorationSystem) return true; // Fallback if system missing
// Map shopId to buildingId
const mapping = {
'blacksmith': 'jakob_shop', // or whichever ID correctly matches TownRestorationSystem
'baker': 'lena_bakery',
'healer': 'dr_chen_clinic'
};
const buildingId = mapping[shopId];
if (!buildingId) return true; // General trader is always open
const building = this.scene.townRestorationSystem.buildings.get(buildingId);
return building ? building.isRestored : false;
}
/**
* Filter by category
*/