feat(plants): Plant purchase system in Dave's Shop & pre-battle deck selection screen
This commit is contained in:
+270
-4
@@ -422,7 +422,14 @@ window.GameEngine = class GameEngine {
|
||||
} else if (this.currentMode === 'roguelike') {
|
||||
startLvl = this.roguelike ? this.roguelike.currentFloor : 1;
|
||||
}
|
||||
this.startLevel(startLvl, this.currentMode);
|
||||
|
||||
// Fixed-conveyor mini-games launch immediately, standard modes open deck builder
|
||||
if (this.currentMode === 'bowling' || this.currentMode === 'izombie' || this.currentMode === 'boss' || this.currentMode === 'bossrush') {
|
||||
this.startLevel(startLvl, this.currentMode);
|
||||
} else {
|
||||
this.openSeedSelectionModal(startLvl, this.currentMode);
|
||||
}
|
||||
|
||||
if (!this.loopStarted) {
|
||||
this.loopStarted = true;
|
||||
requestAnimationFrame(this.loop.bind(this));
|
||||
@@ -1102,10 +1109,32 @@ window.GameEngine = class GameEngine {
|
||||
}
|
||||
|
||||
|
||||
// Shop Button
|
||||
// Inventory / Deck Builder Buttons
|
||||
const btnInvStart = document.getElementById('btn-inventory-start');
|
||||
const btnDrawerInv = document.getElementById('btn-drawer-inventory');
|
||||
if (btnInvStart) {
|
||||
btnInvStart.addEventListener('click', () => {
|
||||
this.openSeedSelectionModal(this.currentLevel || 1, this.currentMode || 'adventure');
|
||||
});
|
||||
}
|
||||
if (btnDrawerInv) {
|
||||
btnDrawerInv.addEventListener('click', () => {
|
||||
const drawer = document.getElementById('mobile-drawer');
|
||||
const backdrop = document.getElementById('drawer-backdrop');
|
||||
if (drawer) drawer.classList.add('hidden');
|
||||
if (backdrop) backdrop.classList.add('hidden');
|
||||
this.openSeedSelectionModal(this.currentLevel || 1, this.currentMode || 'adventure');
|
||||
});
|
||||
}
|
||||
|
||||
// Shop Button & Tabs
|
||||
const btnShop = document.getElementById('btn-shop');
|
||||
const shopModal = document.getElementById('shop-modal');
|
||||
const btnCloseShop = document.getElementById('btn-close-shop');
|
||||
const tabShopPlants = document.getElementById('tab-shop-plants');
|
||||
const tabShopUpgrades = document.getElementById('tab-shop-upgrades');
|
||||
const panelShopPlants = document.getElementById('shop-plants-panel');
|
||||
const panelShopUpgrades = document.getElementById('shop-upgrades-panel');
|
||||
|
||||
if (btnShop && shopModal) {
|
||||
btnShop.addEventListener('click', () => {
|
||||
@@ -1120,6 +1149,73 @@ window.GameEngine = class GameEngine {
|
||||
});
|
||||
}
|
||||
|
||||
if (tabShopPlants && tabShopUpgrades && panelShopPlants && panelShopUpgrades) {
|
||||
tabShopPlants.addEventListener('click', () => {
|
||||
tabShopPlants.classList.add('active');
|
||||
tabShopUpgrades.classList.remove('active');
|
||||
panelShopPlants.classList.remove('hidden');
|
||||
panelShopUpgrades.classList.add('hidden');
|
||||
});
|
||||
tabShopUpgrades.addEventListener('click', () => {
|
||||
tabShopUpgrades.classList.add('active');
|
||||
tabShopPlants.classList.remove('active');
|
||||
panelShopUpgrades.classList.remove('hidden');
|
||||
panelShopPlants.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
// Pre-Battle Seed Selection & Inventory Modal Handlers
|
||||
const seedSelectModal = document.getElementById('seed-select-modal');
|
||||
const btnSeedStart = document.getElementById('btn-seed-start-battle');
|
||||
const btnSeedAuto = document.getElementById('btn-seed-auto-fill');
|
||||
const btnSeedShop = document.getElementById('btn-seed-open-shop');
|
||||
const btnSeedCancel = document.getElementById('btn-seed-cancel');
|
||||
|
||||
if (btnSeedStart) {
|
||||
btnSeedStart.addEventListener('click', () => {
|
||||
if (!this.economy.selectedDeck || this.economy.selectedDeck.length === 0) {
|
||||
this.economy.autoFillDeck();
|
||||
}
|
||||
if (seedSelectModal) seedSelectModal.classList.add('hidden');
|
||||
const startModal = document.getElementById('start-modal');
|
||||
if (startModal) startModal.classList.add('hidden');
|
||||
|
||||
if (window.PvZAudio) window.PvZAudio.init();
|
||||
const lvl = this.pendingLevel || this.currentLevel || 1;
|
||||
const mode = this.pendingMode || this.currentMode || 'adventure';
|
||||
|
||||
this.startLevel(lvl, mode);
|
||||
if (!this.loopStarted) {
|
||||
this.loopStarted = true;
|
||||
requestAnimationFrame(this.loop.bind(this));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (btnSeedAuto) {
|
||||
btnSeedAuto.addEventListener('click', () => {
|
||||
this.economy.autoFillDeck();
|
||||
this.renderSeedSelectionUI();
|
||||
if (window.PvZAudio) window.PvZAudio.playButtonClick();
|
||||
});
|
||||
}
|
||||
|
||||
if (btnSeedShop) {
|
||||
btnSeedShop.addEventListener('click', () => {
|
||||
if (seedSelectModal) seedSelectModal.classList.add('hidden');
|
||||
this.updateShopUI();
|
||||
if (shopModal) shopModal.classList.remove('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
if (btnSeedCancel) {
|
||||
btnSeedCancel.addEventListener('click', () => {
|
||||
if (seedSelectModal) seedSelectModal.classList.add('hidden');
|
||||
const startModal = document.getElementById('start-modal');
|
||||
if (startModal) startModal.classList.remove('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
// Shop Item Purchases
|
||||
const btnBuySlot = document.getElementById('btn-buy-slot');
|
||||
if (btnBuySlot) {
|
||||
@@ -1128,6 +1224,7 @@ window.GameEngine = class GameEngine {
|
||||
if (window.PvZAudio) window.PvZAudio.playWin();
|
||||
this.saveUserData();
|
||||
this.updateShopUI();
|
||||
this.renderSeedSelectionUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1544,7 +1641,11 @@ window.GameEngine = class GameEngine {
|
||||
if (startModal) startModal.classList.add('hidden');
|
||||
|
||||
if (window.PvZAudio) window.PvZAudio.init();
|
||||
this.startLevel(targetLevel, 'adventure');
|
||||
if (targetLevel === 25) {
|
||||
this.startLevel(targetLevel, 'adventure');
|
||||
} else {
|
||||
this.openSeedSelectionModal(targetLevel, 'adventure');
|
||||
}
|
||||
if (!this.loopStarted) {
|
||||
this.loopStarted = true;
|
||||
requestAnimationFrame(this.loop.bind(this));
|
||||
@@ -1566,9 +1667,126 @@ window.GameEngine = class GameEngine {
|
||||
});
|
||||
}
|
||||
|
||||
openSeedSelectionModal(targetLevel = null, targetMode = null) {
|
||||
this.pendingLevel = targetLevel !== null ? targetLevel : (this.currentLevel || 1);
|
||||
this.pendingMode = targetMode !== null ? targetMode : (this.currentMode || 'adventure');
|
||||
|
||||
this.renderSeedSelectionUI();
|
||||
|
||||
const modal = document.getElementById('seed-select-modal');
|
||||
if (modal) modal.classList.remove('hidden');
|
||||
|
||||
const startModal = document.getElementById('start-modal');
|
||||
if (startModal) startModal.classList.add('hidden');
|
||||
const campaignModal = document.getElementById('campaign-modal');
|
||||
if (campaignModal) campaignModal.classList.add('hidden');
|
||||
}
|
||||
|
||||
renderSeedSelectionUI() {
|
||||
const activeDeckContainer = document.getElementById('seed-active-deck');
|
||||
const inventoryContainer = document.getElementById('seed-inventory-grid');
|
||||
const deckCountEl = document.getElementById('seed-deck-count');
|
||||
const deckMaxEl = document.getElementById('seed-deck-max');
|
||||
|
||||
const maxSlots = this.economy.getMaxSlots();
|
||||
const selectedDeck = this.economy.selectedDeck || [];
|
||||
|
||||
if (deckCountEl) deckCountEl.textContent = selectedDeck.length;
|
||||
if (deckMaxEl) deckMaxEl.textContent = maxSlots;
|
||||
|
||||
// 1. Render Active Deck Slots
|
||||
if (activeDeckContainer) {
|
||||
activeDeckContainer.innerHTML = '';
|
||||
selectedDeck.forEach(plantId => {
|
||||
const p = window.PLANT_CATALOGUE.find(item => item.id === plantId);
|
||||
if (!p) return;
|
||||
|
||||
const slot = document.createElement('div');
|
||||
slot.className = 'seed-slot-card';
|
||||
slot.title = `Нажмите, чтобы убрать ${p.name} из колоды`;
|
||||
slot.innerHTML = `
|
||||
<div class="slot-remove-badge">✕</div>
|
||||
<div class="slot-icon">${p.icon}</div>
|
||||
<div class="slot-cost">☀️ ${p.cost}</div>
|
||||
`;
|
||||
slot.addEventListener('click', () => {
|
||||
this.economy.removeFromDeck(plantId);
|
||||
this.renderSeedSelectionUI();
|
||||
if (window.PvZAudio) window.PvZAudio.playButtonClick();
|
||||
});
|
||||
activeDeckContainer.appendChild(slot);
|
||||
});
|
||||
|
||||
// Render Empty Slots up to maxSlots
|
||||
for (let i = selectedDeck.length; i < maxSlots; i++) {
|
||||
const emptySlot = document.createElement('div');
|
||||
emptySlot.className = 'seed-slot-empty';
|
||||
emptySlot.textContent = `+ Слот ${i + 1}`;
|
||||
activeDeckContainer.appendChild(emptySlot);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Render Inventory Grid
|
||||
if (inventoryContainer && window.PLANT_CATALOGUE) {
|
||||
inventoryContainer.innerHTML = '';
|
||||
window.PLANT_CATALOGUE.forEach(p => {
|
||||
const isUnlocked = this.economy.isPlantUnlocked(p.id);
|
||||
const isInDeck = selectedDeck.includes(p.id);
|
||||
const canAfford = this.economy.totalCoins >= (p.price || 0);
|
||||
|
||||
const item = document.createElement('div');
|
||||
item.className = `seed-inv-item ${isUnlocked ? (isInDeck ? 'in-deck' : 'unlocked') : 'locked'}`;
|
||||
|
||||
let statusBadge = '';
|
||||
if (isInDeck) {
|
||||
statusBadge = '<span class="seed-inv-status status-deck">✓ В колоде</span>';
|
||||
} else if (isUnlocked) {
|
||||
statusBadge = '<span class="seed-inv-status status-ready">+ Выбрать</span>';
|
||||
} else {
|
||||
statusBadge = `<button type="button" class="btn btn-sm btn-shop" style="font-size: 10px; padding: 2px 6px; margin-top: 3px;" ${canAfford ? '' : 'disabled'}>🔒 ${p.price} 💰</button>`;
|
||||
}
|
||||
|
||||
item.innerHTML = `
|
||||
<div class="seed-inv-icon">${p.icon}</div>
|
||||
<div class="seed-inv-name" title="${p.name}">${p.name}</div>
|
||||
<div class="seed-inv-sun">☀️ ${p.cost}</div>
|
||||
${statusBadge}
|
||||
`;
|
||||
|
||||
if (isUnlocked) {
|
||||
item.addEventListener('click', () => {
|
||||
if (isInDeck) {
|
||||
this.economy.removeFromDeck(p.id);
|
||||
} else {
|
||||
this.economy.addToDeck(p.id);
|
||||
}
|
||||
this.renderSeedSelectionUI();
|
||||
if (window.PvZAudio) window.PvZAudio.playButtonClick();
|
||||
});
|
||||
} else {
|
||||
const buyBtn = item.querySelector('button');
|
||||
if (buyBtn) {
|
||||
buyBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const res = this.economy.buyPlant(p.id);
|
||||
if (res.success) {
|
||||
if (window.PvZAudio) window.PvZAudio.playCoin();
|
||||
this.saveUserData();
|
||||
this.updateShopUI();
|
||||
this.renderSeedSelectionUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
inventoryContainer.appendChild(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateShopUI() {
|
||||
const elCoins = document.getElementById('shop-coins');
|
||||
if (elCoins) elCoins.textContent = `💰 Монеты: ${this.economy.totalCoins}`;
|
||||
if (elCoins) elCoins.textContent = `💰 Монеты: ${this.economy.totalCoins.toLocaleString('ru-RU')}`;
|
||||
|
||||
const btnBuySlot = document.getElementById('btn-buy-slot');
|
||||
if (btnBuySlot) {
|
||||
@@ -1581,6 +1799,54 @@ window.GameEngine = class GameEngine {
|
||||
btnBuyRake.textContent = this.economy.upgrades.hasRake ? 'Куплено ✔️' : 'Купить (150 💰)';
|
||||
btnBuyRake.disabled = this.economy.upgrades.hasRake || this.economy.totalCoins < 150;
|
||||
}
|
||||
|
||||
// Populate Shop Plants Grid
|
||||
const shopPlantsGrid = document.getElementById('shop-plants-grid');
|
||||
if (shopPlantsGrid && window.PLANT_CATALOGUE) {
|
||||
shopPlantsGrid.innerHTML = '';
|
||||
window.PLANT_CATALOGUE.forEach(p => {
|
||||
const isBasic = this.economy.defaultUnlocked.includes(p.id);
|
||||
const isUnlocked = this.economy.isPlantUnlocked(p.id);
|
||||
const canAfford = this.economy.totalCoins >= (p.price || 0);
|
||||
|
||||
const card = document.createElement('div');
|
||||
card.className = 'shop-plant-card';
|
||||
|
||||
let actionHtml = '';
|
||||
if (isBasic) {
|
||||
actionHtml = '<span class="badge-purchased" style="background: rgba(33, 150, 243, 0.25); border-color: #64b5f6; color: #90caf9;">Базовое ✅</span>';
|
||||
} else if (isUnlocked) {
|
||||
actionHtml = '<span class="badge-purchased">Куплено ✅</span>';
|
||||
} else {
|
||||
actionHtml = `<button type="button" class="btn-buy" data-plant-id="${p.id}" ${canAfford ? '' : 'disabled'}>Купить (${p.price} 💰)</button>`;
|
||||
}
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="shop-plant-icon">${p.icon}</div>
|
||||
<div class="shop-plant-info">
|
||||
<h4>${p.name}</h4>
|
||||
<div class="shop-plant-cost">☀️ ${p.cost} солнца</div>
|
||||
<p>${p.desc}</p>
|
||||
</div>
|
||||
<div>${actionHtml}</div>
|
||||
`;
|
||||
|
||||
const buyBtn = card.querySelector('button.btn-buy');
|
||||
if (buyBtn) {
|
||||
buyBtn.addEventListener('click', () => {
|
||||
const res = this.economy.buyPlant(p.id);
|
||||
if (res.success) {
|
||||
if (window.PvZAudio) window.PvZAudio.playCoin();
|
||||
this.saveUserData();
|
||||
this.updateShopUI();
|
||||
this.renderSeedSelectionUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
shopPlantsGrid.appendChild(card);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateWorkshopUI() {
|
||||
|
||||
Reference in New Issue
Block a user