Initial commit: 3D Hommie RPG game

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-02-25 01:04:09 +03:00
commit fb5f09212b
34 changed files with 14550 additions and 0 deletions

201
js/game/Inventory.js Normal file
View File

@@ -0,0 +1,201 @@
export class Inventory {
constructor(game) {
this.game = game;
this.items = {};
this.maxSlots = 20;
this.itemData = {
bottle: { name: 'Бутылка', icon: '🍾', usable: false, desc: 'Пустая бутылка. Можно сдать в магазине за 5₽.' },
bread: { name: 'Хлеб', icon: '🍞', usable: true, desc: 'Кусок хлеба. +20 Сытость.' },
can: { name: 'Консервы', icon: '🥫', usable: true, desc: '+35 Сытость.' },
tea: { name: 'Чай', icon: '🍵', usable: true, desc: '+20 Тепло, +5 Настроение.' },
bandage: { name: 'Бинт', icon: '🩹', usable: true, desc: '+25 Здоровье.' },
clothing: { name: 'Одежда', icon: '🧥', usable: true, desc: '+30 Тепло.' },
newspaper: { name: 'Газета', icon: '📰', usable: true, desc: '+5 Настроение.' },
scrap: { name: 'Хлам', icon: '🔩', usable: false, desc: 'Для крафта и строительства.' },
rope: { name: 'Верёвка', icon: '🪢', usable: false, desc: 'Для крафта и строительства.' },
medkit: { name: 'Аптечка', icon: '💊', usable: true, desc: '+50 Здоровье.' },
stew: { name: 'Похлёбка', icon: '🍲', usable: true, desc: '+50 Сытость, +15 Тепло.' },
blanket: { name: 'Одеяло', icon: '🛏️', usable: true, desc: '+50 Тепло, +10 Настроение.' },
harmonica: { name: 'Губная гармошка', icon: '🎵', usable: true, desc: '+20 Настроение (многоразовое).' },
candle: { name: 'Свеча', icon: '🕯️', usable: false, desc: 'Для крафта.' },
// Новые предметы
fish: { name: 'Рыба', icon: '🐟', usable: true, desc: '+25 Сытость. Свежая рыба.' },
apple: { name: 'Яблоко', icon: '🍎', usable: true, desc: '+10 Сытость, +5 Здоровье.' },
vodka: { name: 'Водка', icon: '🍺', usable: true, desc: '+30 Тепло, -10 Здоровье, +15 Настроение.' },
vitamins: { name: 'Витамины', icon: '💊', usable: true, desc: '+15 Здоровье, +10 Настроение.' },
torch: { name: 'Факел', icon: '🔦', usable: true, desc: '+20 Тепло, +10 Настроение ночью.' },
soap: { name: 'Мыло', icon: '🧼', usable: true, desc: '+30 Гигиена.' },
// Экипировка (в инвентаре до экипировки)
eq_old_hat: { name: 'Старая шапка', icon: '🧢', usable: false, equippable: true, eqKey: 'old_hat', desc: 'Экипировка: +5 Тепло' },
eq_hood: { name: 'Капюшон', icon: '🪖', usable: false, equippable: true, eqKey: 'hood', desc: 'Экипировка: +8 Тепло, +2 Защита' },
eq_warm_hat: { name: 'Тёплая шапка', icon: '🎩', usable: false, equippable: true, eqKey: 'warm_hat', desc: 'Экипировка: +15 Тепло, +3 Настроение' },
eq_helmet: { name: 'Каска', icon: '⛑️', usable: false, equippable: true, eqKey: 'helmet', desc: 'Экипировка: +8 Защита' },
eq_old_jacket: { name: 'Драная куртка', icon: '🧥', usable: false, equippable: true, eqKey: 'old_jacket', desc: 'Экипировка: +10 Тепло' },
eq_coat: { name: 'Пальто', icon: '🧥', usable: false, equippable: true, eqKey: 'coat', desc: 'Экипировка: +18 Тепло, +3 Защита' },
eq_warm_jacket: { name: 'Тёплая куртка', icon: '🧥', usable: false, equippable: true, eqKey: 'warm_jacket', desc: 'Экипировка: +25 Тепло, +5 Защита' },
eq_vest: { name: 'Жилетка', icon: '🦺', usable: false, equippable: true, eqKey: 'vest', desc: 'Экипировка: +10 Защита' },
eq_old_boots: { name: 'Рваные ботинки', icon: '👞', usable: false, equippable: true, eqKey: 'old_boots', desc: 'Экипировка: +5 Тепло' },
eq_boots: { name: 'Ботинки', icon: '🥾', usable: false, equippable: true, eqKey: 'boots', desc: 'Экипировка: +10 Тепло, +3 Защита' },
eq_warm_boots: { name: 'Тёплые сапоги', icon: '🥾', usable: false, equippable: true, eqKey: 'warm_boots', desc: 'Экипировка: +18 Тепло' },
eq_old_gloves: { name: 'Дырявые перчатки', icon: '🧤', usable: false, equippable: true, eqKey: 'old_gloves', desc: 'Экипировка: +3 Тепло' },
eq_gloves: { name: 'Перчатки', icon: '🧤', usable: false, equippable: true, eqKey: 'gloves', desc: 'Экипировка: +8 Тепло, +2 Защита' },
eq_warm_gloves: { name: 'Тёплые перчатки', icon: '🧤', usable: false, equippable: true, eqKey: 'warm_gloves', desc: 'Экипировка: +14 Тепло' },
// Оружие
eq_stick: { name: 'Палка', icon: '🏑', usable: false, equippable: false, desc: 'Оружие: +15% шанс отбиться.' },
eq_pipe: { name: 'Труба', icon: '🔧', usable: false, equippable: false, desc: 'Оружие: +25% шанс отбиться.' },
};
// Рецепты крафта
this.recipes = [
{
name: 'Аптечка',
result: 'medkit',
ingredients: { bandage: 2, bottle: 1 },
desc: '2x Бинт + 1x Бутылка'
},
{
name: 'Похлёбка',
result: 'stew',
ingredients: { can: 1, bread: 1 },
desc: '1x Консервы + 1x Хлеб'
},
{
name: 'Одеяло',
result: 'blanket',
ingredients: { clothing: 2, newspaper: 2 },
desc: '2x Одежда + 2x Газета'
},
{
name: 'Губная гармошка',
result: 'harmonica',
ingredients: { scrap: 3 },
desc: '3x Хлам'
},
{
name: 'Факел',
result: 'torch',
ingredients: { scrap: 1, rope: 1, candle: 1 },
desc: '1x Хлам + 1x Верёвка + 1x Свеча'
},
{
name: 'Витамины',
result: 'vitamins',
ingredients: { apple: 2, tea: 1 },
desc: '2x Яблоко + 1x Чай'
},
{
name: 'Мыло',
result: 'soap',
ingredients: { bottle: 1, scrap: 1 },
desc: '1x Бутылка + 1x Хлам'
},
// Экипировка
{
name: 'Капюшон',
result: 'eq_hood',
ingredients: { clothing: 2, rope: 1 },
desc: '2x Одежда + 1x Верёвка'
},
{
name: 'Тёплая шапка',
result: 'eq_warm_hat',
ingredients: { clothing: 3, rope: 1 },
desc: '3x Одежда + 1x Верёвка'
},
{
name: 'Тёплая куртка',
result: 'eq_warm_jacket',
ingredients: { clothing: 4, rope: 2 },
desc: '4x Одежда + 2x Верёвка'
},
{
name: 'Тёплые перчатки',
result: 'eq_warm_gloves',
ingredients: { clothing: 2 },
desc: '2x Одежда'
},
{
name: 'Палка',
result: 'eq_stick',
ingredients: { scrap: 2, rope: 1 },
desc: '2x Хлам + 1x Верёвка'
},
{
name: 'Труба',
result: 'eq_pipe',
ingredients: { scrap: 4, rope: 1 },
desc: '4x Хлам + 1x Верёвка'
},
];
}
addItem(key, count = 1) {
if (!this.items[key]) this.items[key] = 0;
this.items[key] += count;
}
removeItem(key, count = 1) {
if (!this.items[key]) return;
this.items[key] -= count;
if (this.items[key] <= 0) delete this.items[key];
}
getCount(key) {
return this.items[key] || 0;
}
getAll() {
return Object.entries(this.items).map(([key, count]) => ({
key,
count,
...this.itemData[key]
}));
}
useItem(key) {
const data = this.itemData[key];
if (!data) return false;
// Экипировка
if (data.equippable) {
this.removeItem(key, 1);
this.game.equipment.equip(data.eqKey);
return true;
}
if (!data.usable) return false;
if (this.getCount(key) <= 0) return false;
return this.game.player.useItem(key);
}
canCraft(recipe) {
for (const [key, needed] of Object.entries(recipe.ingredients)) {
if (this.getCount(key) < needed) return false;
}
return true;
}
craft(recipe) {
if (!this.canCraft(recipe)) return false;
for (const [key, needed] of Object.entries(recipe.ingredients)) {
this.removeItem(key, needed);
}
this.addItem(recipe.result, 1);
this.game.sound.playPickup();
this.game.notify(`Создано: ${recipe.name}`, 'good');
this.game.skills.addXP('scavenging', 3);
this.game.questSystem.onEvent('craft_item');
this.game.totalCrafted++;
if (this.game.totalCrafted >= 5) {
this.game.achievements.check('crafter');
}
return true;
}
reset() {
this.items = {};
this.maxSlots = 20;
}
}