feat(gameplay): add crazy dave casino and bank, and zombie mutation lab
This commit is contained in:
1 parent
d8be8f4366
commit
b8db5a123d
16 files changed
+2365
-135
No files matched your search
@@ -0,0 +1,189 @@
|
||||
// Zombie Lab & Mutation System for "I, Zombie" mode
|
||||
window.ZombieLabSystem = class ZombieLabSystem {
|
||||
constructor(economy, workshop) {
|
||||
this.economy = economy;
|
||||
this.workshop = workshop;
|
||||
|
||||
// Upgradable zombie definitions
|
||||
this.zombies = {
|
||||
normal: {
|
||||
id: 'normal',
|
||||
name: 'Обычный зомби',
|
||||
icon: '🧟',
|
||||
tiers: {
|
||||
1: { title: 'Базовый ходок', desc: 'HP 200, стандартная скорость' },
|
||||
2: { title: 'Спринтер', desc: 'Скорость бега +35%', cost: { coins: 150, scrapMetal: 8 } },
|
||||
3: { title: 'Зомби-Вампир', desc: 'Лечит +45 HP за каждый укус растения', cost: { coins: 350, scrapMetal: 15, bioHumus: 10 } }
|
||||
}
|
||||
},
|
||||
conehead: {
|
||||
id: 'conehead',
|
||||
name: 'Зомби с конусом',
|
||||
icon: '⚠️',
|
||||
tiers: {
|
||||
1: { title: 'Дорожный конус', desc: 'HP 560 (конус поглощает урон)' },
|
||||
2: { title: 'Титановый конус', desc: 'HP 800 + устойчивость к критам', cost: { coins: 200, scrapMetal: 15 } },
|
||||
3: { title: 'Шипованный шлем', desc: 'HP 1050 + отражает 25% урона стрелкам', cost: { coins: 450, scrapMetal: 30, crystals: 1 } }
|
||||
}
|
||||
},
|
||||
polevaulter: {
|
||||
id: 'polevaulter',
|
||||
name: 'Зомби с шестом',
|
||||
icon: '🏃',
|
||||
tiers: {
|
||||
1: { title: 'Легкоатлет', desc: 'Быстрый разбег, 1 прыжок через растение' },
|
||||
2: { title: 'Двойной шест', desc: 'Может перепрыгнуть 2 растения подряд!', cost: { coins: 250, scrapMetal: 20, bioHumus: 10 } },
|
||||
3: { title: 'Турбо-спринтер', desc: 'Спринт +50% скорости даже после приземления', cost: { coins: 500, scrapMetal: 35, crystals: 1 } }
|
||||
}
|
||||
},
|
||||
buckethead: {
|
||||
id: 'buckethead',
|
||||
name: 'Зомби с ведром',
|
||||
icon: '🪣',
|
||||
tiers: {
|
||||
1: { title: 'Стальное ведро', desc: 'HP 1300 тяжелая броня' },
|
||||
2: { title: 'Тяжелый сплав', desc: 'HP 1800 колоссальная прочность', cost: { coins: 300, scrapMetal: 25 } },
|
||||
3: { title: 'Крио-изоляция', desc: 'HP 2300 + полный иммунитет к замедлению льдом!', cost: { coins: 650, scrapMetal: 45, crystals: 2 } }
|
||||
}
|
||||
},
|
||||
football: {
|
||||
id: 'football',
|
||||
name: 'Зомби-футболист',
|
||||
icon: '🏈',
|
||||
tiers: {
|
||||
1: { title: 'Квотербек', desc: 'HP 1600 суперскорость и шлем' },
|
||||
2: { title: 'Тяжелый лайнмен', desc: 'HP 2200 + поглощает 20% урона', cost: { coins: 400, scrapMetal: 35 } },
|
||||
3: { title: 'Безумный таран', desc: 'HP 2800 + сминает картофельную мину без взрыва!', cost: { coins: 800, scrapMetal: 60, crystals: 2 } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// User levels (1..3)
|
||||
this.levels = {
|
||||
normal: 1,
|
||||
conehead: 1,
|
||||
polevaulter: 1,
|
||||
buckethead: 1,
|
||||
football: 1
|
||||
};
|
||||
|
||||
// Unlocked stage in I, Zombie campaign (1..5)
|
||||
this.unlockedStage = 1;
|
||||
this.selectedStage = 1;
|
||||
|
||||
this.stages = [
|
||||
{ id: 1, title: '1. Зелёный Двор', desc: 'Базовый газон Дэйва. Съешьте все подсолнухи!', reward: 100 },
|
||||
{ id: 2, title: '2. Ночной Дозор', desc: 'Тёмный двор с Дымогрибами и Могилами', reward: 150 },
|
||||
{ id: 3, title: '3. Водный Штурм', desc: '6 дорожек, Кувшинки и тройные Горохострелы', reward: 220 },
|
||||
{ id: 4, title: '4. Ореховый Бастион', desc: 'Мощный частокол Стеноорехов и Картофельных Мин', reward: 300 },
|
||||
{ id: 5, title: '5. РЕЙД-БОСС: Золотой Подсолнух', desc: 'Эпический бой против гигантского Подсолнуха-Босса 5000 HP!', reward: 600, crystals: 2, isBoss: true }
|
||||
];
|
||||
|
||||
this.loadFromAuth();
|
||||
}
|
||||
|
||||
loadFromAuth() {
|
||||
if (window.PvZAuth) {
|
||||
const uData = window.PvZAuth.getUserData();
|
||||
if (uData.zombieLab) {
|
||||
const zl = uData.zombieLab;
|
||||
if (zl.levels) {
|
||||
for (const k in this.levels) {
|
||||
if (zl.levels[k]) this.levels[k] = Math.min(3, Math.max(1, Number(zl.levels[k])));
|
||||
}
|
||||
}
|
||||
if (zl.unlockedStage) {
|
||||
this.unlockedStage = Math.max(1, Math.min(5, Number(zl.unlockedStage)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveToAuth() {
|
||||
if (window.PvZAuth && !window.PvZAuth.isGuest()) {
|
||||
window.PvZAuth.saveUserData({
|
||||
zombieLab: {
|
||||
levels: { ...this.levels },
|
||||
unlockedStage: this.unlockedStage
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getZombieLevel(type) {
|
||||
return this.levels[type] || 1;
|
||||
}
|
||||
|
||||
canUpgrade(type) {
|
||||
const curLevel = this.getZombieLevel(type);
|
||||
if (curLevel >= 3) return false;
|
||||
const def = this.zombies[type];
|
||||
if (!def) return false;
|
||||
const nextTier = def.tiers[curLevel + 1];
|
||||
if (!nextTier) return false;
|
||||
|
||||
const cost = nextTier.cost;
|
||||
if (cost.coins && (!this.economy || this.economy.totalCoins < cost.coins)) return false;
|
||||
if (this.workshop) {
|
||||
if (cost.scrapMetal && (this.workshop.materials.scrapMetal || 0) < cost.scrapMetal) return false;
|
||||
if (cost.bioHumus && (this.workshop.materials.bioHumus || 0) < cost.bioHumus) return false;
|
||||
if (cost.crystals && (this.workshop.materials.crystals || 0) < cost.crystals) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
upgradeZombie(type) {
|
||||
const curLevel = this.getZombieLevel(type);
|
||||
if (curLevel >= 3) return { success: false, message: 'Максимальный уровень мутации!' };
|
||||
const def = this.zombies[type];
|
||||
if (!def) return { success: false, message: 'Неизвестный зомби' };
|
||||
const nextTier = def.tiers[curLevel + 1];
|
||||
if (!nextTier) return { success: false, message: 'Нет следующего уровня' };
|
||||
|
||||
const cost = nextTier.cost;
|
||||
if (cost.coins && (!this.economy || this.economy.totalCoins < cost.coins)) {
|
||||
return { success: false, message: 'Недостаточно монет' };
|
||||
}
|
||||
|
||||
if (this.workshop) {
|
||||
if (cost.scrapMetal && (this.workshop.materials.scrapMetal || 0) < cost.scrapMetal) {
|
||||
return { success: false, message: 'Недостаточно металлолома ⚙️' };
|
||||
}
|
||||
if (cost.bioHumus && (this.workshop.materials.bioHumus || 0) < cost.bioHumus) {
|
||||
return { success: false, message: 'Недостаточно био-гумуса 🧪' };
|
||||
}
|
||||
if (cost.crystals && (this.workshop.materials.crystals || 0) < cost.crystals) {
|
||||
return { success: false, message: 'Недостаточно кристаллов 💎' };
|
||||
}
|
||||
// Deduct materials
|
||||
if (cost.scrapMetal) this.workshop.materials.scrapMetal -= cost.scrapMetal;
|
||||
if (cost.bioHumus) this.workshop.materials.bioHumus -= cost.bioHumus;
|
||||
if (cost.crystals) this.workshop.materials.crystals -= cost.crystals;
|
||||
this.workshop.saveToAuth();
|
||||
}
|
||||
|
||||
if (cost.coins) {
|
||||
this.economy.totalCoins -= cost.coins;
|
||||
this.economy.saveProfileData();
|
||||
}
|
||||
|
||||
this.levels[type] = curLevel + 1;
|
||||
this.saveToAuth();
|
||||
|
||||
if (window.PvZAudio) window.PvZAudio.playWin();
|
||||
return {
|
||||
success: true,
|
||||
newLevel: this.levels[type],
|
||||
message: `🎉 ${def.name} мутировал до Ур. ${this.levels[type]} («${nextTier.title}»)!`
|
||||
};
|
||||
}
|
||||
|
||||
unlockNextStage(completedStage) {
|
||||
if (completedStage >= this.unlockedStage && this.unlockedStage < 5) {
|
||||
this.unlockedStage = completedStage + 1;
|
||||
this.saveToAuth();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user