From cc685bfe02b42b592987117fa008a4461785f53c Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Thu, 17 Aug 2023 02:53:14 +0200 Subject: refactor --- script.js | 1152 ------------------------------------------------------------- 1 file changed, 1152 deletions(-) delete mode 100644 script.js (limited to 'script.js') diff --git a/script.js b/script.js deleted file mode 100644 index 2fab2fc..0000000 --- a/script.js +++ /dev/null @@ -1,1152 +0,0 @@ -const DB = { - allMonsters: [], - allAnimations: {}, - monsters: {}, - shapes: {}, - elements: {}, - techniques: {}, - statusEffects: {}, -}; - -const ElementType = { - aether: 'aether', - wood: 'wood', - fire: 'fire', - earth: 'earth', - metal: 'metal', - water: 'water', - - /* lightning: 'lightning', - frost: 'frost', - venom: 'venom', - //vermin: 'vermin', - cosmic: 'cosmic', - battle: 'battle', - psionic: 'psionic', - darkness: 'darkness', - heaven: 'heaven', - - combineTypes(typeA, typeB) { - if (typeA === ElementType.earth & typeB === ElementType.fire) { - return ElementType.lightning; - } - if (typeA === ElementType.earth & typeB === ElementType.water) { - return ElementType.frost; - } - if (typeA === ElementType.earth & typeB === ElementType.wood) { - return ElementType.venom; - } - // if (typeA === ElementType.earth & typeB === ElementType.metal) { - // return ElementType.vermin; - // } - if (typeA === ElementType.fire && typeB === ElementType.water) { - return ElementType.cosmic; - } - } */ -}; -const ElementTypeColor = { - [ElementType.aether]: 'rgba(255, 255, 255, 1)', - [ElementType.wood]: '#3ca6a6', - [ElementType.fire]: '#ca3c3c', - [ElementType.earth]: '#eac93c', - [ElementType.metal]: '#e4e4e4', - [ElementType.water]: '#3c3c3c', -}; -const TasteWarm = { - tasteless: 'tasteless', - peppy: 'peppy', - salty: 'salty', - hearty: 'hearty', - zesty: 'zesty', - refined: 'refined', -}; -const TasteCold = { - tasteless: 'tasteless', - mild: 'mild', - sweet: 'sweet', - soft: 'soft', - flakey: 'flakey', - dry: 'dry', -}; -const TechniqueRange = { - melee: 'melee', - touch: 'touch', - ranged: 'ranged', - reach: 'reach', - reliable: 'reliable', -}; -const StatusType = { - melee: 'melee', - armour: 'armour', - ranged: 'ranged', - dodge: 'dodge', - speed: 'speed', -}; -const StatusEffectType = { - blinded: 'blinded', - burn: 'burn', - chargedup: 'chargedup', - charging: 'charging', - confused: 'confused', - diehard: 'diehard', - dozing: 'dozing', - elementalshield: 'elementalshield', - eliminated: 'eliminated', - enraged: 'enraged', - exhausted: 'exhausted', - faint: 'faint', - feedback: 'feedback', - festering: 'festering', - flinching: 'flinching', - focused: 'focused', - grabbed: 'grabbed', - hardshell: 'hardshell', - harpooned: 'harpooned', - lifeleech: 'lifeleech', - lockdown: 'lockdown', - noddingoff: 'noddingoff', - poison: 'poison', - prickly: 'prickly', - recover: 'recover', - slow: 'slow', - sniping: 'sniping', - softened: 'softened', - stuck: 'stuck', - tired: 'tired', - wasting: 'wasting', - wild: 'wild', -}; - -class State { - money = 0; - monsters = []; - - inventory = []; - - partyMonsters = []; - - activeMonster = null; - activeTechnique = null; - - turn = 0; - currentArea = null; - - enemy = { - monster: null, - }; -}; - -class Monster { - #level = 1; - #hp = 0; - - exp = 1; - - tasteWarm = TasteWarm.tasteless; - tasteCold = TasteCold.tasteless; - - gender = ''; - - heldItem = null; - statusEffect = ''; - - statusModifier = { - hp: 0, - melee: 0, - armour: 0, - ranged: 0, - dodge: 0, - speed: 0, - }; - - experienceModifier = 1; - moneyModifier = 1; - - activeTechniques = []; - - constructor (slug) { - this.slug = slug; - - const tasteWarm = Object.keys(TasteWarm).slice(1); - this.tasteWarm = tasteWarm[Math.floor(Math.random() * tasteWarm.length)]; - const tasteCold = Object.keys(TasteCold).slice(1); - this.tasteCold = tasteCold[Math.floor(Math.random() * tasteCold.length)]; - - this.hp = this.status.hp; - - const possibleGenders = DB.monsters[this.slug].possible_genders; - this.gender = possibleGenders[Math.floor(Math.random() * possibleGenders.length)] - } - - get shape () { - for (const shapeData of DB.shapes) { - if (shapeData.slug === DB.monsters[this.slug].shape) { - return shapeData; - } - } - } - - get types () { - return DB.monsters[this.slug].types; - } - - get moveset () { - return DB.monsters[this.slug].moveset; - } - - get evolutions () { - return DB.monsters[this.slug].evolutions; - } - - get level () { - return this.#level; - } - - set level (level) { - const statusPreLevelUp = this.status; - const hpPreLevelUp = this.hp; - - this.#level = level; - - const statusPostLevelUp = this.status; - - this.hp = statusPostLevelUp.hp - (statusPreLevelUp.hp - hpPreLevelUp); - - if (this.exp < this.getExperienceRequired(-1)) { - this.exp = this.getExperienceRequired(-1); - } - } - - get hp () { - return this.#hp; - } - - set hp (hp) { - this.#hp = Math.max(0, Math.min(hp, this.status.hp)); - } - - get name () { - return slugToName(this.slug); - } - - getLearnableTechniques () { - return this.moveset.filter((move) => this.level >= move.learned_at); - } - - canLevelUp () { - return this.exp >= this.getExperienceRequired(); - } - - levelUp () { - while (this.canLevelUp()) { - this.level++; - } - } - - getExperienceRequired (levelOffset = 0) { - return Math.max( - Math.pow(this.level + levelOffset, 3), - 1 - ); - } - - getPossibleEvolutions () { - // return this.evolutions.filter((evolution) => this.level >= evolution.at_level && (!evolution.item || this.heldItem === evolution.item)); - return this.evolutions.filter((evolution) => evolution.path === 'standard' && this.level >= evolution.at_level); - } - - canEvolve () { - return this.getPossibleEvolutions().length > 0; - } - - evolve () { - const evolution = this.getPossibleEvolutions()[0]; - - const statusPreEvolve = this.status; - const hpPreEvolve = this.hp; - - this.slug = evolution.monster_slug; - - const statusPostEvolve = this.status; - - this.hp = statusPostEvolve.hp - (statusPreEvolve.hp - hpPreEvolve); - } - - getTasteStatusModifier (statusName, baseStatus) { - let positive = 0; - let negative = 0; - - let isPositive = false; - let isNegative = false; - if (statusName === 'melee') { - isPositive = this.tasteWarm === TasteWarm.salty; - isNegative = this.tasteCold === TasteCold.sweet; - } - else if (statusName === 'armour') { - isPositive = this.tasteWarm === TasteWarm.hearty; - isNegative = this.tasteCold === TasteCold.soft; - } - else if (statusName === 'ranged') { - isPositive = this.tasteWarm === TasteWarm.zesty; - isNegative = this.tasteCold === TasteCold.flakey; - } - else if (statusName === 'dodge') { - isPositive = this.tasteWarm === TasteWarm.refined; - isNegative = this.tasteCold === TasteCold.dry; - } - else if (statusName === 'speed') { - isPositive = this.tasteWarm === TasteWarm.peppy; - isNegative = this.tasteCold === TasteCold.mild; - } - - if (isPositive) { - positive = baseStatus * 10 / 100; - } - if (isNegative) { - negative = baseStatus * 10 / 100; - } - - return Math.floor(positive) - Math.floor(negative); - } - - get status () { - const multiplier = this.level + 7; - let hp = (this.shape.hp * multiplier) + this.statusModifier.hp; - let melee = (this.shape.melee * multiplier) + this.statusModifier.melee; - let armour = (this.shape.armour * multiplier) + this.statusModifier.armour; - let ranged = (this.shape.ranged * multiplier) + this.statusModifier.ranged; - let dodge = (this.shape.dodge * multiplier) + this.statusModifier.dodge; - let speed = (this.shape.speed * multiplier) + this.statusModifier.speed; - - // Tastes - melee += this.getTasteStatusModifier('melee', melee); - armour += this.getTasteStatusModifier('armour', melee); - ranged += this.getTasteStatusModifier('ranged', melee); - dodge += this.getTasteStatusModifier('dodge', melee); - speed += this.getTasteStatusModifier('speed', melee); - - return { - hp, - melee, - armour, - ranged, - dodge, - speed, - }; - } - - setStatusModifier (statusType, newAbsoluteValue) { - this.statusModifier[statusType] = newAbsoluteValue - this.status[statusType]; - } - resetStatusModifier () { - for (const m in this.statusModifier) { - this.statusModifier[m] = 0; - } - } -}; - -class Technique { - #accuracy = 0; - #potency = 0; - #power = 0; - - combatEffects = []; - - constructor (slug) { - this.slug = slug; - - this.resetToBase(); - } - - get name () { - return slugToName(this.slug); - } - - get types () { - return DB.techniques[this.slug].types; - } - - get range () { - return DB.techniques[this.slug].range; - } - - get animation () { - return DB.techniques[this.slug].animation; - } - - get sfx () { - return DB.techniques[this.slug].sfx; - } - - get effects () { - return DB.techniques[this.slug].effects; - } - - get accuracy () { - return this.#accuracy; - } - set accuracy (accuracy) { - this.#accuracy = accuracy; - } - - get potency () { - return this.#potency; - } - set potency (potency) { - this.#potency = potency; - } - - get power () { - return this.#power; - } - set power (power) { - this.#power = power; - } - - get base () { - const accuracy = DB.techniques[this.slug].accuracy; - const potency = DB.techniques[this.slug].potency; - const power = DB.techniques[this.slug].power; - - return { - accuracy, - potency, - power, - }; - } - - resetToBase () { - this.accuracy = this.base.accuracy; - this.potency = this.base.potency; - this.power = this.base.power; - } -} - -class Item {} - -class TechniqueEffect { - constructor (str) { - this.recipient = str.split(',')[1]; - this.application = str.split(' ')[0]; - this.type = str.split(',')[0].split(' ')[1].split('_')[0]; - this.effect = str.split(',')[0].split(' ')[1].split('_')[1]; - } -} - -class StatusEffect { - turnsLeft = 0; - - constructor (slug) { - this.slug = slug; - - if (['recover', 'lifeleech'].includes(this.slug)) { - this.turnsLeft = 1; - } - else if (['charging'].includes(this.slug)) { - this.turnsLeft = 2; - } - else if (this.category === 'positive') { - this.turnsLeft = Math.ceil(Math.random() * 6) + 4; - } - else if (this.category === 'negative') { - this.turnsLeft = Math.ceil(Math.random() * 3) + 2; - } - else { - this.turnsLeft = Math.ceil(Math.random() * 3) + 2; - } - } - - get effects () { - return DB.statusEffects[this.slug].effects; - } - - get category () { - return DB.statusEffects[this.slug].category; - } - - get name () { - return slugToName(this.slug); - } - - get status () { - const status = {}; - - const statusChangeKeys = Object.keys(DB.statusEffects[this.slug]).filter((key) => key.startsWith('stat')); - for (const key of statusChangeKeys) { - status[key.replace('stat', '')] = DB.statusEffects[this.slug][key]; - } - - return status; - } -} - -function simpleDamageMultiplier (techniqueTypes, targetTypes) { - let multiplier = 1; - - for (const techniqueType of techniqueTypes) { - if (techniqueType === ElementType.aether) { - continue; - } - - for (const targetType of targetTypes) { - if (targetType === ElementType.aether) { - continue; - } - - multiplier *= DB.elements[techniqueType].types.find((type) => type.against === targetType).multiplier; - } - } - - return Math.max(0.25, Math.min(multiplier, 4)); -} -function simpleDamageCalculation (technique, user, target) { - if (technique.power === 0) { - return 0; - } - - let userBaseStrength = user.level + 7; - let userStrength = 1; - let targetResist = 1; - - if (technique.range === TechniqueRange.melee) { - userStrength = userBaseStrength * user.status.melee; - targetResist = target.status.armour; - } - else if (technique.range === TechniqueRange.touch) { - userStrength = userBaseStrength * user.status.melee; - targetResist = target.status.dodge; - } - else if (technique.range === TechniqueRange.ranged) { - userStrength = userBaseStrength * user.status.ranged; - targetResist = target.status.dodge; - } - else if (technique.range === TechniqueRange.reach) { - userStrength = userBaseStrength * user.status.ranged; - targetResist = target.status.armour; - } - else if (technique.range === TechniqueRange.reliable) { - userStrength = userBaseStrength; - targetResist = 1; - } - - const multiplier = simpleDamageMultiplier(technique.types, target.types); - const moveStrength = technique.power * multiplier; - const damage = Math.floor((userStrength * moveStrength) / targetResist); - - return Math.max(damage, 1); -} - -function calculateAwardedExperience (playerMonster, enemyMonster) { - return Math.max( - Math.floor( - enemyMonster.getExperienceRequired(-1) / enemyMonster.level * enemyMonster.experienceModifier / playerMonster.level - ), - 1 - ); -} - -async function fetchMonster (slug) { - if (! DB.monsters[slug]) { - DB.monsters[slug] = await fetch(`/modules/tuxemon/mods/tuxemon/db/monster/${slug}.json`).then((response) => response.json()); - } - - return new Monster(slug); -} -async function fetchTechnique (slug) { - if (! DB.techniques[slug]) { - DB.techniques[slug] = await fetch(`/modules/tuxemon/mods/tuxemon/db/technique/${slug}.json`).then((response) => response.json()); - } - - return new Technique(slug); -} -async function fetchStatusEffect (slug) { - if (! DB.statusEffects[slug]) { - DB.statusEffects[slug] = await fetch(`/modules/tuxemon/mods/tuxemon/db/technique/status_${slug}.json`).then((response) => response.json()); - } - - return new StatusEffect(slug); -} - -function standardizeColor (color) { - var ctx = document.createElement('canvas').getContext('2d'); - ctx.fillStyle = color; - - return ctx.fillStyle; -} -function mixColors(...colors) { - let r = 0; - let g = 0; - let b = 0; - - for (const color of colors) { - const [cr, cg, cb] = color.match(/\w\w/g).map((c) => parseInt(c, 16)); - - r += cr; - g += cg; - b += cb; - } - - r = r / colors.length; - g = g / colors.length; - b = b / colors.length; - - return `rgb(${r}, ${g}, ${b})`; -} - -function slugToName (slug) { - return slug.split('_').map((item) => item.charAt(0).toUpperCase() + item.slice(1)).join(' '); -} - -(async function () { - DB.allMonsters = await fetch('/db/all-monsters.json').then((response) => response.json()); - DB.allAnimations = await fetch('/db/animations.json').then((response) => response.json()); - DB.shapes = await fetch('/modules/tuxemon/mods/tuxemon/db/shape/shapes.json').then((response) => response.json()); - for (const element of Object.keys(ElementType)) { - DB.elements[element] = await fetch(`/modules/tuxemon/mods/tuxemon/db/element/${element}.json`).then((response) => response.json()); - } - - const state = new State(); - state.enemy.monster = await fetchMonster('grintot'); - - state.partyMonsters = [ - await fetchMonster('corvix'), - await fetchMonster('lunight'), - await fetchMonster('prophetoise'), - await fetchMonster('drashimi'), - await fetchMonster('glombroc'), - await fetchMonster('uneye'), - await fetchMonster('nostray'), - await fetchMonster('dragarbor'), - ]; - state.activeMonster = state.partyMonsters[0]; - state.activeTechnique = await fetchTechnique(state.activeMonster.moveset[0].technique); - - const templatePartyMonster = document.querySelector('#tpl___party__monster').innerHTML; - const templateBattleMonster = document.querySelector('#tpl___battle__monster').innerHTML; - const templatePopup = document.querySelector('#tpl___popup').innerHTML; - const templateMovesetList = document.querySelector('#tpl___moveset__list').innerHTML; - const templateMovesetItem = document.querySelector('#tpl___moveset__item').innerHTML; - const templateTechnique = document.querySelector('#tpl___technique').innerHTML; - - const party = document.querySelector('#party'); - const money = document.querySelector('#money'); - - const battle = document.querySelector('#battle'); - const battleEnemy = document.querySelector('#battle__enemy'); - const battlePlayer = document.querySelector('#battle__player'); - - const UI = { - activeMonster: null, - - enemyImg: null, - damageHighlightClickDuration: 0.1, - damageHighlightClickTimeout: null, - imgClickDuration: 0.1, - damageClickTimeout: null, - - damageAnimationIsRunning: false, - damageAnimationNumber: 0, - - getTemplate (template) { - var tpl = document.createElement('div'); - tpl.innerHTML = template.trim(); - - return tpl.firstChild; - }, - - setExp (monster, parentNode) { - const expBar = parentNode.querySelector('.exp-bar'); - const expText = parentNode.querySelector('.exp-text'); - - const expToNextLevel = monster.getExperienceRequired() - monster.getExperienceRequired(-1); - const currentExp = monster.exp - monster.getExperienceRequired(-1); - expBar.style.width = (currentExp / expToNextLevel) * 100 + '%'; - expText.textContent = monster.exp + ' / ' + monster.getExperienceRequired(); - }, - - setHp (monster, parentNode) { - const hpBar = parentNode.querySelector('.hp-bar'); - const hpText = parentNode.querySelector('.hp-text'); - - const percentHp = (monster.hp / monster.status.hp) * 100; - if (percentHp > 60) { - hpBar.style.backgroundColor = 'green'; - } else if (percentHp > 15) { - hpBar.style.backgroundColor = 'rgb(240, 240, 100)'; - } else { - hpBar.style.backgroundColor = 'red'; - } - - hpBar.style.width = percentHp + '%'; - hpText.textContent = monster.hp + ' / ' + monster.status.hp; - }, - - async createDamage (event, damage) { - const damageNode = document.createElement('div'); - damageNode.classList.add('damage'); - damageNode.textContent = damage; - - const damageMultiplier = simpleDamageMultiplier(state.activeTechnique.types, state.enemy.monster.types); - damageNode.style.fontSize = damageMultiplier*2 + 'rem'; - - damageNode.style.top = event.pageY - battleEnemy.offsetTop + (Math.random() * 40 - 20); - damageNode.style.left = event.pageX - battleEnemy.offsetLeft + (Math.random() * 40 - 20); - - damageNode.style.color = mixColors(...state.activeTechnique.types.map((type) => standardizeColor(ElementTypeColor[type]))); - - const damageNodeDuration = 2; - damageNode.style.animationDuration = damageNodeDuration + 's'; - - battleEnemy.appendChild(damageNode); - setTimeout(() => damageNode.remove(), (damageNodeDuration * 1000) - 500); - - this.enemyImg.classList.add('damaged'); - clearTimeout(this.damageHighlightClickTimeout); - this.damageHighlightClickTimeout = setTimeout(() => this.enemyImg.classList.remove('damaged'), this.damageHighlightClickDuration * 1000); - - var enemyAnimation = battleEnemy.querySelector('.battle__monster-sprite__animation'); - if (!this.damageAnimationIsRunning && state.activeTechnique.animation && DB.allAnimations[state.activeTechnique.animation]) { - this.damageAnimationIsRunning = true; - - const damageAnimationLoop = () => { - enemyAnimation.src = `/modules/tuxemon/mods/tuxemon/animations/technique/${state.activeTechnique.animation}_${("00" + this.damageAnimationNumber).slice(-2)}.png`; - enemyAnimation.style.top = event.clientY - (enemyAnimation.clientHeight / 2); - enemyAnimation.style.left = event.clientX - (enemyAnimation.clientWidth / 2); - // console.log(enemyAnimation.src); - - this.damageAnimationNumber++; - - if (this.damageAnimationNumber >= DB.allAnimations[state.activeTechnique.animation].length) { - this.damageAnimationIsRunning = false; - this.damageAnimationNumber = 0; - enemyAnimation.src = ''; - return; - } - - setTimeout(() => requestAnimationFrame(damageAnimationLoop), 50); - }; - - requestAnimationFrame(damageAnimationLoop); - - // sfx - /* let sfx = state.activeTechnique.sfx.substr(4); - const audio = new Audio(`/modules/tuxemon/mods/tuxemon/sounds/technique/${sfx}.ogg`); - audio.play(); */ - } - }, - - setBattleMonster (monster, where) { - let battleMonster = document.createElement('div'); - battleMonster.innerHTML = templateBattleMonster.trim(); - battleMonster = battleMonster.firstChild; - - battleMonster.querySelector('.battle__monster-info__name').textContent = monster.name; - battleMonster.querySelector('.battle__monster-info__gender').textContent = monster.gender === 'male' ? '♂' : monster.gender === 'female' ? '♀' : '⚲'; - battleMonster.querySelector('.battle__monster-info__level').textContent = monster.level; - battleMonster.querySelector('.battle__monster-info__status').innerHTML = UI.createStatusEffectIcon(monster.statusEffect); - battleMonster.querySelector('.battle__monster-img').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`; - - UI.setHp(monster, battleMonster.querySelector('.hp')); - - if (where === 'player') { - UI.setExp(monster, battleMonster.querySelector('.exp')); - battleMonster.querySelector('.battle__monster-technique').addEventListener('click', UI.openMovesetSelection); - - battleMonster.classList.add('battle__monster--player'); - battlePlayer.querySelector('.battle__monster') && battlePlayer.removeChild(battlePlayer.querySelector('.battle__monster')); - battlePlayer.appendChild(battleMonster); - - UI.setActiveTechnique(); - - UI.setActiveTechniques(); - } else { - battleMonster.classList.add('battle__monster--enemy'); - - this.enemyImg = battleMonster.querySelector('.battle__monster-img'); - this.enemyImg.style.transitionDuration = this.damageHighlightClickDuration + 's'; - - const previousBattleMonster = battleEnemy.querySelector('.battle__monster'); - if (previousBattleMonster) { - this.enemyImg.classList = previousBattleMonster.querySelector('.battle__monster-img').classList; - - battleEnemy.removeChild(previousBattleMonster); - } - - battleEnemy.appendChild(battleMonster); - } - }, - - setEnemyMonster () { - UI.setBattleMonster(state.enemy.monster, 'enemy'); - }, - - setActiveMonster () { - UI.setBattleMonster(state.activeMonster, 'player'); - }, - - setActiveTechnique () { - battlePlayer.querySelector('.battle__monster-technique').innerHTML = - slugToName(state.activeTechnique.slug) + '   ' - + state.activeTechnique.types.map((type) => UI.createElementTypeIcon(type)).join(''); - }, - - setActiveTechniques () { - const techniquesNode = document.querySelector('#techniques'); - techniquesNode.replaceChildren(); - - for (const technique of state.activeMonster.activeTechniques) { - const techniqueNode = UI.getTemplate(templateTechnique); - techniqueNode.querySelector('.techniques__technique__name').innerHTML = technique.name; - techniquesNode.appendChild(techniqueNode); - } - }, - - async chooseActiveTechnique () { - let activeMoveIndex = 0; - while ((await fetchTechnique(state.activeMonster.moveset[activeMoveIndex].technique)).power === 0) { - activeMoveIndex++; - } - state.activeTechnique = await fetchTechnique(state.activeMonster.moveset[activeMoveIndex].technique); - - UI.setActiveTechnique(); - }, - - async openMovesetSelection () { - const popup = UI.createPopup(); - - const movesetList = UI.getTemplate(templateMovesetList); - for (const move of state.activeMonster.moveset) { - const technique = await fetchTechnique(move.technique); - const movesetItem = UI.getTemplate(templateMovesetItem); - - movesetItem.querySelector('.moveset__item__name').textContent = slugToName(technique.slug); - movesetItem.querySelector('.moveset__item__type').innerHTML = technique.types.map((type) => UI.createElementTypeIcon(type)).join(''); - movesetItem.querySelector('.moveset__item__power').innerHTML = technique.power; - movesetItem.querySelector('.moveset__item__level').innerHTML = move.level_learned; - - if (state.activeMonster.activeTechniques.find((item) => item.slug === technique.slug)) { - movesetItem.setAttribute('selected', true); - } - - movesetItem.addEventListener('click', () => { - if (movesetItem.getAttribute('disabled')) { - return false; - } - - state.activeTechnique = technique; - UI.setActiveTechnique(); - - if (movesetItem.getAttribute('selected')) { - movesetItem.removeAttribute('selected'); - state.activeMonster.activeTechniques.splice(state.activeMonster.activeTechniques.findIndex((item) => item.slug === technique.slug), 1); - } else { - movesetItem.setAttribute('selected', true); - state.activeMonster.activeTechniques.push(technique); - } - UI.setActiveTechniques(); - }); - - if (state.activeMonster.level < move.level_learned) { - movesetItem.setAttribute('disabled', true); - } - - movesetList.appendChild(movesetItem); - } - - popup.querySelector('.popup').appendChild(movesetList); - document.body.appendChild(popup); - }, - - async createNewEnemyMonster () { - state.enemy.monster = await fetchMonster(DB.allMonsters[Math.floor(Math.random() * DB.allMonsters.length)]); - state.enemy.monster.level = Math.ceil(Math.random() * state.activeMonster.level); - // state.enemy.monster.experienceModifier = state.enemy.monster.level; - state.enemy.monster.moneyModifier = state.enemy.monster.level; - UI.setEnemyMonster(); - }, - - createElementTypeIcon (type) { - var img = document.createElement('img'); - img.src = `/modules/tuxemon/mods/tuxemon/gfx/ui/icons/element/${type}_type.png`; - img.title = slugToName(type); - - return img.outerHTML; - }, - - createStatusEffectIcon (statusEffect) { - if (!statusEffect) return ''; - - var img = document.createElement('img'); - img.src = `/modules/tuxemon/mods/tuxemon/gfx/ui/icons/status/icon_${statusEffect.slug}.png`; - img.title = statusEffect.name; - - return img.outerHTML; - }, - - createPopup () { - const popup = UI.getTemplate(templatePopup); - popup.addEventListener('click', ({ target }) => target === popup && popup.remove()); - - return popup; - }, - - openPartyMenu () { - const popup = UI.createPopup(); - - const party = document.createElement('div'); - party.id = 'party'; - for (const monster of state.partyMonsters) { - const partyMonster = UI.getTemplate(templatePartyMonster); - - partyMonster.dataset.slug = monster.slug; - partyMonster.querySelector('img').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`; - - partyMonster.addEventListener('click', async (event) => { - let target = event.target; - while (target.parentNode.id !== 'party') { - target = target.parentNode; - } - - state.activeMonster = state.partyMonsters[Array.prototype.indexOf.call(document.querySelector('#party').children, target)]; - await UI.chooseActiveTechnique(); - UI.setActiveMonster(); - - popup.remove(); - }); - - party.appendChild(partyMonster); - } - - popup.querySelector('.popup').appendChild(party); - document.body.appendChild(popup); - }, - - openInventoryMenu () { - const popup = UI.createPopup(); - - const inventory = document.createElement('div'); - inventory.id = 'inventory'; - for (const item of state.inventory) { - } - - popup.querySelector('.popup').appendChild(inventory); - document.body.appendChild(popup); - }, - }; - - const Game = { - async useTechnique(technique, user, target) { - let statusEffects = []; - let combatEffects = []; - - for (const effect of technique.effects) { - if (effect.includes('status_')) { - statusEffects.push(new TechniqueEffect(effect)); - } - else if (!['damage', 'splash', 'area'].includes(effect)) { - combatEffects.push(effect); - } - } - - for (const effect of statusEffects) { - let recipient; - - if (effect.recipient === 'user') { - recipient = user; - } else { - recipient = target; - } - - if (effect.type === 'status') { - if (effect.application === 'give') { - if (recipient.statusEffect) { - continue; - } - - const potency = Math.random(); - const success = technique.potency >= potency; - if (success) { - recipient.statusEffect = await fetchStatusEffect(effect.effect); - } - } - else if (effect.application === 'remove') { - if (recipient.statusEffect.slug === effect.effect) { - recipient.statusEffect = ''; - } - } - } - } - - technique.combatEffects = combatEffects; - }, - - async applyStatusEffect (affectedMonster, opposingMonster) { - if (!affectedMonster.statusEffect) { - return; - } - - if (! (affectedMonster.statusEffect instanceof StatusEffect)) { - return; - } - - if (affectedMonster.statusEffect.slug === 'poison' || affectedMonster.statusEffect.slug === 'burn') { - const statusEffectDamage = Math.floor(affectedMonster.status.hp / 8); - affectedMonster.hp -= statusEffectDamage; - - UI.createDamage(clickEvent, statusEffectDamage); - } - - else if (affectedMonster.statusEffect.slug === 'recover') { - const statusEffectHeal = Math.floor(affectedMonster.status.hp / 16); - affectedMonster.hp += statusEffectHeal; - } - - else if (affectedMonster.statusEffect.slug === 'lifeleech') { - const statusEffectLeech = Math.floor(affectedMonster.status.hp / 16); - affectedMonster.hp -= statusEffectLeech; - opposingMonster.hp += statusEffectLeech; - - UI.createDamage(clickEvent, statusEffectLeech); - } - - else if (affectedMonster.statusEffect.slug === 'charging') { - turnEndPhaseEvents.push(async () => { - if (affectedMonster.statusEffect.turnsLeft === 0) { - affectedMonster.statusEffect = await fetchStatusEffect('chargedup'); - } - }); - } - - else if (affectedMonster.statusEffect.effects.includes('statchange')) { - affectedMonster.resetStatusModifier(); - - for (const statusType in affectedMonster.statusEffect.status) { - const statusChange = affectedMonster.statusEffect.status[statusType]; - - const modifiedValue = Math.floor(eval(`${affectedMonster.status[statusType]} ${statusChange.operation} ${statusChange.value}`)); - affectedMonster.setStatusModifier(statusType, modifiedValue); - } - } - - affectedMonster.statusEffect.turnsLeft--; - turnEndPhaseEvents.push(() => { - if (affectedMonster.statusEffect.turnsLeft === 0) { - affectedMonster.statusEffect = null; - affectedMonster.resetStatusModifier(); - } - }); - }, - - applyTechniqueEffect (technique, user, target) { - for (const effect of technique.combatEffects) { - if (effect === 'money') { - if (!techniqueHit) { - state.money += Math.floor(Math.random() * target.level); - } - } - } - - // modify technique stats - if (user.statusEffect) { - if (user.statusEffect.slug === 'grabbed') { - if ([TechniqueRange.ranged, TechniqueRange.reach].includes(technique.range)) { - technique.potency = technique.base.potency * 0.5; - technique.power = technique.base.power * 0.5; - } - } - - else if (user.statusEffect.slug === 'stuck') { - if ([TechniqueRange.melee, TechniqueRange.touch].includes(technique.range)) { - technique.potency = technique.base.potency * 0.5; - technique.power = technique.base.power * 0.5; - } - } - - // remove effect - if (user.statusEffect.turnsLeft === 0) { - turnEndPhaseEvents.push(() => { - technique.resetToBase(); - }); - } - } - }, - - damage () { - const damage = simpleDamageCalculation(state.activeTechnique, state.activeMonster, state.enemy.monster); - UI.createDamage(clickEvent, damage); - - state.enemy.monster.hp -= damage; - }, - }; - - UI.setActiveMonster(); - UI.setEnemyMonster(); - - let techniqueHit; - let clickEvent; - let turnEndPhaseEvents = []; - document.querySelector('#battle__enemy').addEventListener('click', async (event) => { - clickEvent = event; - - const accuracy = Math.random(); - techniqueHit = state.activeTechnique.accuracy >= accuracy; - - if (techniqueHit) { - await Game.useTechnique(state.activeTechnique, state.activeMonster, state.enemy.monster); - } - - await Game.applyStatusEffect(state.activeMonster, state.enemy.monster); - await Game.applyStatusEffect(state.enemy.monster, state.activeMonster); - - Game.applyTechniqueEffect(state.activeTechnique, state.activeMonster, state.enemy.monster); - - if (techniqueHit) { - Game.damage(); - - if (state.enemy.monster.hp <= 0) { - const faintedMonster = state.enemy.monster; - - await UI.createNewEnemyMonster(); - - state.money += faintedMonster.level * faintedMonster.moneyModifier; - - state.activeMonster.exp += calculateAwardedExperience(state.activeMonster, faintedMonster); - state.activeMonster.levelUp(); - if (state.activeMonster.canEvolve()) { - await fetchMonster(state.activeMonster.evolutions[0].monster_slug); - state.activeMonster.evolve(); - } - } - } else { - UI.createDamage(event, 'MISS!'); - } - - UI.setActiveMonster(); - UI.setEnemyMonster(); - - UI.setHp(state.enemy.monster, battleEnemy); - - money.textContent = state.money; - - for (const turnEndPhaseEvent of turnEndPhaseEvents) { - const returnValue = turnEndPhaseEvent(); - if (returnValue instanceof Promise) { - await returnValue; - } - } - turnEndPhaseEvents = []; - }); - - document.querySelector('#menu__party').addEventListener('click', UI.openPartyMenu); - - document.querySelector('#menu__catch').addEventListener('click', async () => { - const caughtMonster = new Monster(state.enemy.monster.slug); - caughtMonster.level = state.enemy.monster.level; - - state.partyMonsters.push(caughtMonster); - - UI.createNewEnemyMonster(); - }); - - document.querySelector('#menu__inventory').addEventListener('click', UI.openInventoryMenu); -})(); -- cgit v1.2.3