// ======================================== // RPG.JS - Полная RPG система // ======================================== const RPG = { // Типы предметов ItemType: { WEAPON: 'weapon', ARMOR: 'armor', POTION: 'potion', SCROLL: 'scroll', QUEST: 'quest', MATERIAL: 'material', GOLD: 'gold', FOOD: 'food', GEM: 'gem', KEY: 'key' }, // Слоты экипировки EquipmentSlot: { HEAD: 'head', CHEST: 'chest', LEGS: 'legs', FEET: 'feet', HANDS: 'hands', MAIN_HAND: 'main_hand', OFF_HAND: 'off_hand', ACCESSORY1: 'accessory1', ACCESSORY2: 'accessory2' }, // Типы оружия WeaponType: { SWORD: 'sword', AXE: 'axe', MACE: 'mace', DAGGER: 'dagger', BOW: 'bow', STAFF: 'staff', WAND: 'wand' }, // Типы брони ArmorType: { HELMET: 'helmet', CHESTPLATE: 'chestplate', LEGGINGS: 'leggings', BOOTS: 'boots', SHIELD: 'shield', CLOAK: 'cloak' }, // Редкость предметов Rarity: { COMMON: 'common', UNCOMMON: 'uncommon', RARE: 'rare', EPIC: 'epic', LEGENDARY: 'legendary', MYTHIC: 'mythic' }, // Цвета редкости RarityColors: { common: '#b0b0b0', uncommon: '#44ff44', rare: '#4444ff', epic: '#aa44ff', legendary: '#ffaa00', mythic: '#ff44ff' }, // ======================================== // СОЗДАНИЕ ПЕРСОНАЖА // ======================================== createCharacter(name, gender = 'male', classType = 'warrior') { const classStats = { warrior: { hp: 120, mp: 30, str: 12, def: 10, mag: 5, spd: 8, description: 'Сильный воин с высокой защитой' }, mage: { hp: 70, mp: 100, str: 4, def: 4, mag: 15, spd: 6, description: 'Мастер магии с мощными заклинаниями' }, archer: { hp: 90, mp: 50, str: 10, def: 6, mag: 6, spd: 12, description: 'Быстрый стрелок с высокой ловкостью' }, thief: { hp: 85, mp: 45, str: 8, def: 5, mag: 8, spd: 14, description: 'Ловкий плут, мастер скрытности' }, paladin: { hp: 110, mp: 60, str: 10, def: 12, mag: 8, spd: 6, description: 'Святой воин с лечащей магией' }, necromancer: { hp: 80, mp: 90, str: 6, def: 6, mag: 14, spd: 7, description: 'Мастер темной магии и призыва' } }; const stats = classStats[classType] || classStats.warrior; return { id: 'player_' + Date.now(), name: name, gender: gender, class: classType, description: classStats[classType].description, level: 1, exp: 0, expToNextLevel: 100, hp: stats.hp, maxHp: stats.hp, mp: stats.mp, maxMp: stats.mp, baseStr: stats.str, baseDef: stats.def, baseMag: stats.mag, baseSpd: stats.spd, str: stats.str, def: stats.def, mag: stats.mag, spd: stats.spd, gold: 50, hairColor: '#4a3520', // Позиция x: 5, y: 5, targetX: 5, targetY: 5, isMoving: false, moveProgress: 0, // Инвентарь и экипировка inventory: [], equipment: { head: null, chest: null, legs: null, feet: null, main_hand: null, off_hand: null, accessory1: null, accessory2: null }, // Навыки и заклинания skills: [], spells: [], learnedSpells: [], // Квесты quests: [], completedQuests: [], // Достижения achievements: [], // Боевые флаги inCombat: false, currentEnemy: null, combatStats: { attacks: 0, damageDealt: 0, damageTaken: 0, enemiesKilled: 0 } }; }, // ======================================== // СОЗДАНИЕ ПРЕДМЕТОВ // ======================================== createItem(id, type, name, options = {}) { return { id: id || 'item_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9), type: type, name: name, description: options.description || '', value: options.value || 0, rarity: options.rarity || 'common', // Для оружия damage: options.damage || 0, damageType: options.damageType || 'physical', // physical, magic, fire, ice, lightning weaponType: options.weaponType || null, // Для брони defense: options.defense || 0, armorType: options.armorType || null, // Для зелий healAmount: options.healAmount || 0, restoreMp: options.restoreMp || 0, // Для еды hungerRestore: options.hungerRestore || 0, // Для свитков/книг spell: options.spell || null, spellLevel: options.spellLevel || 1, // Требования requiredLevel: options.requiredLevel || 1, requiredClass: options.requiredClass || null, // Особые свойства special: options.special || null, // { name: 'something', value: x } // Визуал icon: options.icon || '?', color: options.color || null, // Остальное stackable: options.stackable || false, quantity: options.quantity || 1, subtype: options.subtype || type, // Статы bonusStr: options.bonusStr || 0, bonusDef: options.bonusDef || 0, bonusMag: options.bonusMag || 0, bonusSpd: options.bonusSpd || 0, bonusHp: options.bonusHp || 0, bonusMp: options.bonusMp || 0 }; }, // ======================================== // СОЗДАНИЕ ВРАГОВ // ======================================== createEnemy(type, level, x, y) { const enemyTemplates = { // Обычные враги goblin: { name: 'Гоблин', baseHp: 30, baseDmg: 8, baseDef: 2, exp: 20, gold: 10, lootTable: ['goblin_ear', 'herb'], behavior: 'aggressive' }, orc: { name: 'Орк', baseHp: 50, baseDmg: 12, baseDef: 4, exp: 40, gold: 25, lootTable: ['orc_tusk', 'meat'], behavior: 'aggressive' }, skeleton: { name: 'Скелет', baseHp: 40, baseDmg: 10, baseDef: 6, exp: 30, gold: 15, lootTable: ['bone', 'bone_dagger'], behavior: 'aggressive' }, slime: { name: 'Слизень', baseHp: 20, baseDmg: 5, baseDef: 0, exp: 10, gold: 5, lootTable: ['slime_gel'], behavior: 'passive' }, bandit: { name: 'Разбойник', baseHp: 35, baseDmg: 9, baseDef: 3, exp: 25, gold: 20, lootTable: ['money_pouch', 'dagger'], behavior: 'aggressive' }, // Маги mage: { name: 'Маг', baseHp: 25, baseDmg: 20, baseDef: 2, baseMp: 50, exp: 50, gold: 30, lootTable: ['mana_potion', 'scroll'], behavior: 'ranged' }, // Элитные troll: { name: 'Тролль', baseHp: 100, baseDmg: 18, baseDef: 8, exp: 80, gold: 60, lootTable: ['troll_heart', 'club'], behavior: 'aggressive' }, // Боссы dragon: { name: 'Дракон', baseHp: 200, baseDmg: 30, baseDef: 15, exp: 200, gold: 200, lootTable: ['dragon_scale', 'dragon_heart', 'dragon_egg'], behavior: 'boss', isBoss: true }, demon: { name: 'Демон', baseHp: 150, baseDmg: 25, baseDef: 10, exp: 150, gold: 150, lootTable: ['demon_heart', 'infernal_orb'], behavior: 'boss', isBoss: true }, lich: { name: 'Лич', baseHp: 100, baseDmg: 35, baseDef: 8, baseMp: 100, exp: 180, gold: 120, lootTable: ['necronomicon', 'skull_staff'], behavior: 'boss', isBoss: true } }; const template = enemyTemplates[type] || enemyTemplates.goblin; const levelMultiplier = 1 + (level - 1) * 0.2; return { id: 'enemy_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9), type: type, name: template.name, level: level, hp: Math.floor(template.baseHp * levelMultiplier), maxHp: Math.floor(template.baseHp * levelMultiplier), mp: (template.baseMp || 0) * levelMultiplier, maxMp: (template.baseMp || 0) * levelMultiplier, damage: Math.floor(template.baseDmg * levelMultiplier), defense: Math.floor((template.baseDef || 0) * levelMultiplier), exp: Math.floor(template.exp * levelMultiplier), gold: Math.floor(template.gold * levelMultiplier), lootTable: template.lootTable, behavior: template.behavior, isBoss: template.isBoss || false, x: x, y: y, height: type === 'slime' ? 25 : 45, isAttacking: false, attackCooldown: 0 }; }, // ======================================== // СОЗДАНИЕ NPC // ======================================== createNPC(name, x, y, options = {}) { return { id: 'npc_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9), name: name, x: x, y: y, color: options.color || '#8b6914', // Диалоги dialog: options.dialog || 'Приветствую, путник!', dialogOptions: options.dialogOptions || [], // Торговля shop: options.shop || null, shopName: options.shopName || 'Магазин', // Квесты quests: options.quests || [], // Услуги services: options.services || [], // heal, teleport, identify // Внешность sprite: options.sprite || 'villager', // Отношения faction: options.faction || 'neutral', attitude: options.attitude || 0 }; }, // ======================================== // КВЕСТОВАЯ СИСТЕМА // ======================================== QuestStatus: { NOT_STARTED: 'not_started', ACTIVE: 'active', COMPLETED: 'completed', FAILED: 'failed' }, createQuest(id, name, description, options = {}) { return { id: id, name: name, description: description, // Тип квеста type: options.type || 'kill', // kill, collect, talk, explore, deliver // Цели objectives: options.objectives || [], // Награды rewards: options.rewards || { exp: 0, gold: 0, items: [] }, // Требования requiredLevel: options.requiredLevel || 1, requiredQuest: options.requiredQuest || null, // Класс requiredClass: options.requiredClass || null, // Цепочка nextQuest: options.nextQuest || null, // Отслеживание progress: {}, status: 'not_started' }; }, // Добавить квест персонажу addQuest(character, quest) { if (character.completedQuests.includes(quest.id)) return false; if (character.quests.find(q => q.id === quest.id)) return false; const newQuest = JSON.parse(JSON.stringify(quest)); newQuest.status = 'active'; // Инициализация прогресса newQuest.objectives.forEach(obj => { newQuest.progress[obj.id] = { current: 0, target: obj.target, completed: false }; }); character.quests.push(newQuest); return true; }, // Обновить прогресс квеста updateQuestProgress(character, objectiveType, targetId, amount = 1) { character.quests.forEach(quest => { if (quest.status !== 'active') return; quest.objectives.forEach(obj => { if (obj.type === objectiveType && obj.target === targetId) { quest.progress[obj.id].current += amount; if (quest.progress[obj.id].current >= obj.target) { quest.progress[obj.id].completed = true; } } }); }); }, // Проверить завершение квеста checkQuestCompletion(character, questId) { const quest = character.quests.find(q => q.id === questId); if (!quest || quest.status !== 'active') return false; const allCompleted = quest.objectives.every(obj => quest.progress[obj.id].completed); if (allCompleted) { quest.status = 'completed'; return true; } return false; }, // Получить награду квеста completeQuest(character, questId) { const questIndex = character.quests.findIndex(q => q.id === questId); if (questIndex === -1) return null; const quest = character.quests[questIndex]; if (quest.status !== 'completed') return null; // Удаляем из активных и добавляем в завершённые character.quests.splice(questIndex, 1); character.completedQuests.push(questId); // Выдаём награды character.exp += quest.rewards.exp; character.gold += quest.rewards.gold; const items = []; if (quest.rewards.items) { quest.rewards.items.forEach(itemTemplate => { const item = this.createItem(itemTemplate.id, itemTemplate.type, itemTemplate.name, itemTemplate); this.addItemToInventory(character, item); items.push(item); }); } return { quest, items }; }, // ======================================== // МАГИЧЕСКАЯ СИСТЕМА // ======================================== SpellType: { FIRE: 'fire', ICE: 'ice', LIGHTNING: 'lightning', HEALING: 'healing', BUFF: 'buff', DEBUFF: 'debuff', SUMMON: 'summon', DARK: 'dark', HOLY: 'holy' }, SpellSchool: { ELEMENTAL: 'elemental', MYSTIC: 'mystic', DARK: 'dark', HOLY: 'holy' }, // База заклинаний SpellDatabase: { // Огненная магия fireball: { name: 'Огненный шар', type: 'fire', school: 'elemental', mpCost: 15, damage: 25, damageType: 'fire', range: 5, cooldown: 3000, description: 'Наносит урон огнём' }, fireblast: { name: 'Огненный взрыв', type: 'fire', school: 'elemental', mpCost: 25, damage: 40, damageType: 'fire', range: 3, cooldown: 5000, description: 'Мощный взрыв огня вокруг' }, // Ледяная магия frostbolt: { name: 'Ледяная стрела', type: 'ice', school: 'elemental', mpCost: 12, damage: 20, damageType: 'ice', range: 6, cooldown: 2000, description: 'Наносит урон льдом и замедляет' }, blizzard: { name: 'Метель', type: 'ice', school: 'elemental', mpCost: 35, damage: 50, damageType: 'ice', range: 4, cooldown: 8000, description: 'Атакует всех врагов вокруг' }, // Молния lightning: { name: 'Молния', type: 'lightning', school: 'elemental', mpCost: 20, damage: 35, damageType: 'lightning', range: 6, cooldown: 3000, description: 'Быстрая атака молнией' }, // Лечение heal: { name: 'Исцеление', type: 'healing', school: 'mystic', mpCost: 10, heal: 30, range: 4, cooldown: 4000, description: 'Восстанавливает здоровье' }, greater_heal: { name: 'Greater Heal', type: 'healing', school: 'mystic', mpCost: 25, heal: 70, range: 4, cooldown: 6000, description: 'Мощное исцеление' }, // Баффы power: { name: 'Усиление', type: 'buff', school: 'mystic', mpCost: 15, buff: { stat: 'damage', value: 1.5, duration: 10000 }, cooldown: 15000, description: 'Увеличивает урон на 50%' }, shield: { name: 'Щит', type: 'buff', school: 'mystic', mpCost: 20, buff: { stat: 'defense', value: 2, duration: 15000 }, cooldown: 20000, description: 'Удваивает защиту' }, // Тёмная магия life_drain: { name: 'Похищение жизни', type: 'dark', school: 'dark', mpCost: 18, damage: 15, heal: 10, range: 4, cooldown: 5000, description: 'Наносит урон и восстанавливает HP' }, curse: { name: 'Проклятие', type: 'debuff', school: 'dark', mpCost: 15, debuff: { stat: 'damage', value: 0.7, duration: 8000 }, range: 5, cooldown: 10000, description: 'Снижает урон врага на 30%' }, // Святая магия holy_fire: { name: 'Священный огонь', type: 'holy', school: 'holy', mpCost: 22, damage: 30, damageType: 'holy', range: 5, cooldown: 4000, description: 'Атакует нечисть' }, resurrect: { name: 'Воскрешение', type: 'holy', school: 'holy', mpCost: 50, resurrect: true, cooldown: 60000, description: 'Воскрешает союзника в бою' } }, // Изучить заклинание learnSpell(character, spellId) { const spell = this.SpellDatabase[spellId]; if (!spell) return false; if (character.learnedSpells.includes(spellId)) return false; // Проверка требований (уровень, класс) if (spell.requiredLevel && character.level < spell.requiredLevel) return false; if (spell.requiredClass && character.class !== spell.requiredClass) return false; character.learnedSpells.push(spellId); return true; }, // Использовать заклинание castSpell(character, spellId, target = null) { const spell = this.SpellDatabase[spellId]; if (!spell) return { success: false, message: 'Заклинание не найдено!' }; if (!character.learnedSpells.includes(spellId)) return { success: false, message: 'Вы не изучили это заклинание!' }; // Проверка MP if (character.mp < spell.mpCost) return { success: false, message: 'Недостаточно маны!' }; // Проверка кулдауна const lastCast = character.combatStats.lastSpellCast || {}; const now = Date.now(); if (lastCast[spellId] && now - lastCast[spellId] < spell.cooldown) { return { success: false, message: 'Заклинание на перезарядке!' }; } // Списываем ману character.mp -= spell.mpCost; // Записываем кулдаун character.combatStats.lastSpellCast = character.combatStats.lastSpellCast || {}; character.combatStats.lastSpellCast[spellId] = now; return { success: true, spell: spell, target: target, message: `Прочитано: ${spell.name}!` }; }, // ======================================== // ИНВЕНТАРЬ И ЭКИПИРОВКА // ======================================== addItemToInventory(character, item) { // Проверка стекируемости if (item.stackable) { const existing = character.inventory.find(i => i.id === item.id && i.stackable ); if (existing) { existing.quantity += item.quantity; return true; } } // Проверка лимита инвентаря if (character.inventory.length >= 25) { return false; } character.inventory.push(item); return true; }, removeItemFromInventory(character, itemId, quantity = 1) { const index = character.inventory.findIndex(i => i.id === itemId); if (index === -1) return false; const item = character.inventory[index]; if (item.stackable) { if (item.quantity >= quantity) { item.quantity -= quantity; if (item.quantity <= 0) { character.inventory.splice(index, 1); } return true; } } else { character.inventory.splice(index, 1); return true; } return false; }, equipItem(character, item) { if (item.type !== this.ItemType.WEAPON && item.type !== this.ItemType.ARMOR) { return { success: false, message: 'Этот предмет нельзя экипировать!' }; } // Проверка требований if (item.requiredLevel && character.level < item.requiredLevel) { return { success: false, message: `Требуется уровень ${item.requiredLevel}!` }; } if (item.requiredClass && character.class !== item.requiredClass) { return { success: false, message: `Только для класса ${item.requiredClass}!` }; } let slot; if (item.type === this.ItemType.WEAPON) { slot = this.EquipmentSlot.MAIN_HAND; } else if (item.type === this.ItemType.ARMOR) { switch(item.armorType) { case this.ArmorType.HELMET: slot = this.EquipmentSlot.HEAD; break; case this.ArmorType.CHESTPLATE: slot = this.EquipmentSlot.CHEST; break; case this.ArmorType.LEGGINGS: slot = this.EquipmentSlot.LEGS; break; case this.ArmorType.BOOTS: slot = this.EquipmentSlot.FEET; break; case this.ArmorType.SHIELD: slot = this.EquipmentSlot.OFF_HAND; break; case this.ArmorType.CLOAK: slot = this.EquipmentSlot.CHEST; break; default: slot = this.EquipmentSlot.CHEST; } } // Снятие текущего предмета if (character.equipment[slot]) { this.unequipItem(character, slot); } // Экипировка character.equipment[slot] = item; // Удаляем из инвентаря const invIndex = character.inventory.findIndex(i => i.id === item.id); if (invIndex >= 0) { character.inventory.splice(invIndex, 1); } return { success: true, message: `Экипировано: ${item.name}` }; }, unequipItem(character, slot) { const item = character.equipment[slot]; if (!item) return false; this.addItemToInventory(character, item); character.equipment[slot] = null; return true; }, // Получение бонусов от экипировки getEquipmentBonuses(character) { const bonuses = { damage: 0, defense: 0, hp: 0, mp: 0, str: 0, def: 0, mag: 0, spd: 0 }; Object.values(character.equipment).forEach(item => { if (!item) return; bonuses.damage += item.damage || 0; bonuses.defense += item.defense || 0; bonuses.hp += item.bonusHp || 0; bonuses.mp += item.bonusMp || 0; bonuses.str += item.bonusStr || 0; bonuses.def += item.bonusDef || 0; bonuses.mag += item.bonusMag || 0; bonuses.spd += item.bonusSpd || 0; }); return bonuses; }, // Полный расчет статов getTotalStats(character) { const bonuses = this.getEquipmentBonuses(character); return { hp: (character.maxHp || 100) + bonuses.hp, mp: (character.maxMp || 50) + bonuses.mp, damage: (character.str || 10) + bonuses.damage, defense: (character.def || 5) + bonuses.defense, magic: (character.mag || 5) + bonuses.mag, speed: (character.spd || 5) + bonuses.spd }; }, // Использование предмета useItem(character, item) { if (item.type === this.ItemType.POTION) { const oldHp = character.hp; const oldMp = character.mp; character.hp = Math.min(character.hp + (item.healAmount || 0), character.maxHp); character.mp = Math.min(character.mp + (item.restoreMp || 0), character.maxMp); const healed = character.hp - oldHp; const restored = character.mp - oldMp; if (item.stackable) { this.removeItemFromInventory(character, item.id, 1); } else { this.removeItemFromInventory(character, item.id); } return { success: true, message: healed > 0 ? `HP: +${healed}` : `MP: +${restored}`, used: true }; } if (item.type === this.ItemType.FOOD) { character.hp = Math.min(character.hp + (item.healAmount || 20), character.maxHp); if (item.stackable) { this.removeItemFromInventory(character, item.id, 1); } else { this.removeItemFromInventory(character, item.id); } return { success: true, message: `Съедено: ${item.name}` }; } if (item.type === this.ItemType.SCROLL && item.spell) { return { success: true, message: `Вы изучили заклинание: ${item.spell}!`, scrollUsed: true, spellLearned: item.spell }; } return { success: false, message: 'Этот предмет нельзя использовать!' }; }, // ======================================== // БОЕВАЯ СИСТЕМА // ======================================== attack(attacker, defender) { const attackerStats = attacker.isPlayer ? this.getTotalStats(attacker) : { damage: attacker.damage, defense: attacker.defense || 0, speed: attacker.level * 2 }; const defenderStats = defender.isPlayer ? this.getTotalStats(defender) : { damage: defender.damage || 0, defense: defender.defense || 0, speed: defender.level * 2 }; // Базовый урон let damage = Math.max(1, attackerStats.damage - defenderStats.defense); // Критический удар (10% базовый + бонус от скорости) const critChance = 0.1 + (attackerStats.speed || 0) * 0.01; const isCrit = Math.random() < critChance; if (isCrit) { damage *= 1.5 + (Math.random() * 0.5); } // Элементальная уязвимость if (attacker.damageType && defender.weakness === attacker.damageType) { damage *= 1.5; } // Случайное отклонение (±15%) const variance = 0.85 + Math.random() * 0.3; damage = Math.floor(damage * variance); defender.hp = Math.max(0, defender.hp - damage); // Статистика if (attacker.isPlayer) { attacker.combatStats.damageDealt += damage; attacker.combatStats.attacks++; } if (defender.isPlayer) { defender.combatStats.damageTaken += damage; } return { damage: damage, isCrit: isCrit, killed: defender.hp <= 0 }; }, // Атака врага (AI) enemyAttack(enemy, player) { const stats = RPG.getTotalStats(player); let damage = Math.max(1, enemy.damage - stats.defense); const isCrit = Math.random() < 0.1; if (isCrit) damage *= 1.5; damage = Math.floor(damage * (0.9 + Math.random() * 0.2)); player.hp = Math.max(0, player.hp - damage); player.combatStats.damageTaken += damage; return { damage, isCrit, killed: player.hp <= 0 }; }, // ======================================== // СИСТЕМА УРОВНЕЙ // ======================================== checkLevelUp(character) { let leveledUp = false; while (character.exp >= character.expToNextLevel) { character.exp -= character.expToNextLevel; character.level++; character.expToNextLevel = Math.floor(100 * Math.pow(1.5, character.level - 1)); // Бонус к статам по классу const classBonuses = { warrior: { hp: 15, mp: 3, str: 3, def: 2, mag: 1, spd: 1 }, mage: { hp: 5, mp: 15, str: 1, def: 1, mag: 3, spd: 1 }, archer: { hp: 8, mp: 5, str: 2, def: 1, mag: 1, spd: 2 }, thief: { hp: 7, mp: 4, str: 2, def: 1, mag: 2, spd: 3 }, paladin: { hp: 12, mp: 8, str: 2, def: 3, mag: 2, spd: 1 }, necromancer: { hp: 6, mp: 12, str: 1, def: 1, mag: 4, spd: 1 } }; const bonus = classBonuses[character.class] || classBonuses.warrior; character.maxHp += bonus.hp; character.maxMp += bonus.mp; character.baseStr += bonus.str; character.baseDef += bonus.def; character.baseMag += bonus.mag; character.baseSpd += bonus.spd; // Пересчитываем текущие статы character.str = character.baseStr; character.def = character.baseDef; character.mag = character.baseMag; character.spd = character.baseSpd; // Восстановление при левелапе character.hp = character.maxHp; character.mp = character.maxMp; leveledUp = true; } return leveledUp; }, // ======================================== // ГЕНЕРАЦИЯ ЛУТА // ======================================== generateLoot(enemy) { const loot = []; // Всегда даёт золото loot.push(this.createItem( 'gold', this.ItemType.GOLD, 'Золото', { value: enemy.gold, stackable: true, quantity: enemy.gold, rarity: 'common' } )); // Шанс выпадения из таблицы if (enemy.lootTable) { enemy.lootTable.forEach(lootId => { if (Math.random() < 0.2) { // 20% шанс на каждый предмет loot.push(this.createLootItem(lootId, enemy.level)); } }); } // Шанс случайного предмета (30%) if (Math.random() < 0.3) { const randomItems = [ { type: 'potion', healAmount: 30 }, { type: 'potion', healAmount: 50 }, { type: 'potion', restoreMp: 20 }, { type: 'food', healAmount: 15 }, { type: 'gold', value: Math.floor(enemy.gold * 0.5) } ]; const template = randomItems[Math.floor(Math.random() * randomItems.length)]; loot.push(this.createItem( 'loot_' + Date.now(), template.type, template.type === 'gold' ? 'Золото' : 'Зелье', template )); } return loot; }, createLootItem(lootId, level) { const lootDatabase = { // Материалы goblin_ear: { name: 'Ухо гоблина', value: 5, type: 'material' }, orc_tusk: { name: 'Клык орка', value: 10, type: 'material' }, bone: { name: 'Кость', value: 3, type: 'material' }, herb: { name: 'Трава', value: 8, type: 'material' }, slime_gel: { name: 'Слизь', value: 5, type: 'material' }, troll_heart: { name: 'Сердце тролля', value: 50, type: 'material', rarity: 'rare' }, dragon_scale: { name: 'Чешуя дракона', value: 100, type: 'material', rarity: 'epic' }, demon_heart: { name: 'Сердце демона', value: 80, type: 'material', rarity: 'epic' }, // Оружие bone_dagger: { name: 'Костяной кинжал', value: 25, type: 'weapon', damage: 8, rarity: 'uncommon' }, club: { name: 'Дубина', value: 15, type: 'weapon', damage: 6 }, skull_staff: { name: 'Посох черепа', value: 80, type: 'weapon', damage: 15, rarity: 'rare' }, // Щиты shield_wood: { name: 'Деревянный щит', value: 20, type: 'armor', defense: 3 }, // Зелья health_potion: { name: 'Зелье HP', value: 25, type: 'potion', healAmount: 40, rarity: 'uncommon' }, mana_potion: { name: 'Зелье MP', value: 30, type: 'potion', restoreMp: 30, rarity: 'uncommon' }, // Еда meat: { name: 'Мясо', value: 10, type: 'food', healAmount: 20 }, // Книги scroll: { name: 'Свиток', value: 50, type: 'scroll', spell: 'fireball' }, necronomicon: { name: 'Некрономикон', value: 200, type: 'scroll', spell: 'life_drain', rarity: 'rare' }, // Разное money_pouch: { name: 'Кошелёк', value: 15, type: 'gold' }, dragon_heart: { name: 'Сердце дракона', value: 300, type: 'material', rarity: 'legendary' }, dragon_egg: { name: 'Яйцо дракона', value: 500, type: 'quest', rarity: 'legendary' }, infernal_orb: { name: 'Инфернальная сфера', value: 150, type: 'material', rarity: 'epic' } }; const template = lootDatabase[lootId] || { name: 'Предмет', value: 10, type: 'material' }; return this.createItem( lootId + '_' + Date.now(), template.type, template.name, { value: template.value, damage: template.damage, defense: template.defense, healAmount: template.healAmount, restoreMp: template.restoreMp, spell: template.spell, rarity: template.rarity || 'common' } ); }, // ======================================== // ПРОВЕРКА ПРОХОДИМОСТИ // ======================================== isTilePassable(map, x, y) { if (x < 0 || y < 0 || x >= map[0].length || y >= map.length) { return false; } const tile = map[y][x]; return tile !== 1 && tile !== 4 && tile !== 6; // вода, стена, лава }, getAdjacentTiles(x, y, map) { const directions = [ { dx: 0, dy: -1 }, { dx: 1, dy: 0 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 } ]; return directions .map(d => ({ x: x + d.dx, y: y + d.dy })) .filter(pos => this.isTilePassable(map, pos.x, pos.y)); }, // ======================================== // КОЛЛИЗИИ // ======================================== checkEnemyCollision(character, enemies) { const charX = Math.round(character.x); const charY = Math.round(character.y); for (let enemy of enemies) { const enemyX = Math.round(enemy.x); const enemyY = Math.round(enemy.y); if (charX === enemyX && charY === enemyY) { return enemy; } } return null; }, checkItemCollision(character, items) { const charX = Math.round(character.x); const charY = Math.round(character.y); for (let i = 0; i < items.length; i++) { const item = items[i]; if (!item.collected && item.x === charX && item.y === charY) { return i; } } return -1; }, checkNPCCollision(character, npcs) { const charX = Math.round(character.x); const charY = Math.round(character.y); for (let npc of npcs) { if (npc.x === charX && npc.y === charY) { return npc; } } return null; }, // ======================================== // СОХРАНЕНИЕ И ЗАГРУЗКА // ======================================== saveGame(character, filename = 'rpg_save') { const saveData = { version: '1.0', timestamp: Date.now(), character: character }; try { localStorage.setItem(filename, JSON.stringify(saveData)); return { success: true, message: 'Игра сохранена!' }; } catch (e) { return { success: false, message: 'Ошибка сохранения!' }; } }, loadGame(filename = 'rpg_save') { try { const saveData = localStorage.getItem(filename); if (!saveData) { return { success: false, message: 'Нет сохранённой игры!' }; } const data = JSON.parse(saveData); return { success: true, character: data.character, message: 'Игра загружена!' }; } catch (e) { return { success: false, message: 'Ошибка загрузки!' }; } }, deleteSave(filename = 'rpg_save') { try { localStorage.removeItem(filename); return { success: true, message: 'Сохранение удалено!' }; } catch (e) { return { success: false, message: 'Ошибка удаления!' }; } }, hasSave(filename = 'rpg_save') { return localStorage.getItem(filename) !== null; }, // ======================================== // БАЗЫ ДАННЫХ // ======================================== ItemDatabase: { weapons: [ { id: 'sword_1', name: 'Железный меч', damage: 5, value: 50 }, { id: 'sword_2', name: 'Стальной меч', damage: 10, value: 150 }, { id: 'sword_3', name: 'Меч рыцаря', damage: 18, value: 400 }, { id: 'sword_legend', name: 'Экскалибур', damage: 35, value: 2000, rarity: 'legendary' }, { id: 'axe_1', name: 'Боевой топор', damage: 8, value: 80 }, { id: 'axe_2', name: 'Секира варвара', damage: 15, value: 300 }, { id: 'staff_1', name: 'Посох ученика', damage: 3, magic: 8, value: 60 }, { id: 'staff_2', name: 'Посох мага', damage: 5, magic: 15, value: 200 }, { id: 'dagger_1', name: 'Кинжал', damage: 4, value: 30 }, { id: 'bow_1', name: 'Лук', damage: 7, value: 70 } ], armor: [ { id: 'helmet_1', name: 'Кожаный шлем', defense: 2, value: 40 }, { id: 'helmet_2', name: 'Железный шлем', defense: 5, value: 120 }, { id: 'chest_1', name: 'Кожаная куртка', defense: 3, value: 50 }, { id: 'chest_2', name: 'Кольчуга', defense: 8, value: 200 }, { id: 'chest_3', name: 'Латы рыцаря', defense: 15, value: 500 }, { id: 'chest_epic', name: 'Доспех дракона', defense: 25, value: 1500, rarity: 'epic' }, { id: 'legs_1', name: 'Кожаные поножи', defense: 2, value: 35 }, { id: 'boots_1', name: 'Кожаные сапоги', defense: 1, value: 25 }, { id: 'boots_2', name: 'Железные сапоги', defense: 3, value: 80 }, { id: 'shield_1', name: 'Деревянный щит', defense: 3, value: 40 }, { id: 'shield_2', name: 'Железный щит', defense: 6, value: 150 }, { id: 'shield_epic', name: 'Щит небожителя', defense: 12, value: 800, rarity: 'epic' } ], potions: [ { id: 'health_potion_1', name: 'Малое зелье HP', healAmount: 30, value: 20 }, { id: 'health_potion_2', name: 'Среднее зелье HP', healAmount: 60, value: 50 }, { id: 'health_potion_3', name: 'Большое зелье HP', healAmount: 100, value: 100 }, { id: 'mana_potion_1', name: 'Малое зелье MP', restoreMp: 20, value: 25 }, { id: 'mana_potion_2', name: 'Среднее зелье MP', restoreMp: 40, value: 60 }, { id: 'mana_potion_3', name: 'Большое зелье MP', restoreMp: 70, value: 120 }, { id: 'elixir_1', name: 'Эликсир жизни', healAmount: 200, value: 300, rarity: 'rare' } ] } }; // Экспорт if (typeof module !== 'undefined' && module.exports) { module.exports = RPG; }