diff options
Diffstat (limited to 'resources')
-rw-r--r-- | resources/css/menu.css | 53 | ||||
-rw-r--r-- | resources/js/classes/InventoryItem.js | 40 | ||||
-rw-r--r-- | resources/js/classes/Item.js | 22 | ||||
-rw-r--r-- | resources/js/classes/State.js | 2 | ||||
-rw-r--r-- | resources/js/db.js | 16 | ||||
-rw-r--r-- | resources/js/game.js | 17 | ||||
-rw-r--r-- | resources/js/helpers.js | 7 | ||||
-rw-r--r-- | resources/js/ui.js | 148 |
8 files changed, 299 insertions, 6 deletions
diff --git a/resources/css/menu.css b/resources/css/menu.css index 72c225a..de8d8ce 100644 --- a/resources/css/menu.css +++ b/resources/css/menu.css @@ -42,6 +42,43 @@ } +.tabs { + display: grid; +} + +.tabs > input { + display: none; +} + +.tabs > input:checked + .tabs__tab-heading { + background-color: rgba(255, 255, 255, 0.75); +} +.tabs__tab-heading { + cursor: pointer; + background-color: rgba(0, 0, 0, 0.1); + text-align: center; +} + +.tabs__panels { + grid-column: 1 / -1; +} + +.tabs__tab-panel { + display: none; +} + +.tabs > input:nth-child(1):checked ~ .tabs__panels > .tabs__tab-panel:nth-child(1), +.tabs > input:nth-child(3):checked ~ .tabs__panels > .tabs__tab-panel:nth-child(2), +.tabs > input:nth-child(5):checked ~ .tabs__panels > .tabs__tab-panel:nth-child(3), +.tabs > input:nth-child(7):checked ~ .tabs__panels > .tabs__tab-panel:nth-child(4), +.tabs > input:nth-child(9):checked ~ .tabs__panels > .tabs__tab-panel:nth-child(5), +.tabs > input:nth-child(11):checked ~ .tabs__panels > .tabs__tab-panel:nth-child(6) { + display: block; +} + + + + .gender-icon { line-height: 1em; } @@ -72,6 +109,22 @@ } + +.inventory {} + +.inventory__popup { + align-items: start; +} +.inventory__popup .popup { + margin-top: 10vh; +} + +.inventory .tabs__tab-heading { + font-size: 1.25rem; +} + + + .menu__journal { display: flex; flex-direction: column; diff --git a/resources/js/classes/InventoryItem.js b/resources/js/classes/InventoryItem.js new file mode 100644 index 0000000..9dfdbcc --- /dev/null +++ b/resources/js/classes/InventoryItem.js @@ -0,0 +1,40 @@ +class InventoryItem { + /** + * @type {Item} + */ + item = null; + + /** + * @type {number} + */ + quantity = 1; + + /** + * @param {Item} item + */ + constructor (item) { + this.item = item; + } + + /* Item */ + + get slug () { + return this.item.slug; + } + + get name () { + return this.item.name; + } + + get category () { + return this.item.category; + } + + get type () { + return this.item.type; + } + + get sprite () { + return this.item.sprite; + } +} diff --git a/resources/js/classes/Item.js b/resources/js/classes/Item.js index e274a20..6207cc2 100644 --- a/resources/js/classes/Item.js +++ b/resources/js/classes/Item.js @@ -1 +1,21 @@ -class Item {} +class Item { + constructor (slug) { + this.slug = slug; + } + + get name () { + return slugToName(this.slug); + } + + get category () { + return DB.items[this.slug].category; + } + + get type () { + return DB.items[this.slug].type; + } + + get sprite () { + return DB.items[this.slug].sprite; + } +} diff --git a/resources/js/classes/State.js b/resources/js/classes/State.js index 2384a85..c0065d1 100644 --- a/resources/js/classes/State.js +++ b/resources/js/classes/State.js @@ -10,7 +10,7 @@ class State { monsters = []; /** - * @type {Item[]} + * @type {InventoryItem[]} */ inventory = []; diff --git a/resources/js/db.js b/resources/js/db.js index 96b971a..64b2e9b 100644 --- a/resources/js/db.js +++ b/resources/js/db.js @@ -1,16 +1,19 @@ const DB = { allMonsters: [], allAnimations: {}, + allItems: [], monsters: {}, shapes: {}, elements: {}, techniques: {}, statusEffects: {}, + items: {}, }; async function initializeDB () { DB.allMonsters = await fetch('/db/all-monsters.json').then((response) => response.json()); DB.allAnimations = await fetch('/db/animations.json').then((response) => response.json()); + DB.allItems = await fetch('/db/all-items.json').then((response) => response.json()); DB.shapes = await fetch('/modules/tuxemon/mods/tuxemon/db/shape/shapes.json').then((response) => response.json()); @@ -60,3 +63,16 @@ async function fetchStatusEffect (slug) { return new StatusEffect(slug); } + +/** + * @param {string} slug + * + * @returns {Promise<StatusEffect>} + */ +async function fetchItem (slug) { + if (! DB.items[slug]) { + DB.items[slug] = await fetch(`/modules/tuxemon/mods/tuxemon/db/item/${slug}.json`).then((response) => response.json()); + } + + return new Item(slug); +} diff --git a/resources/js/game.js b/resources/js/game.js index 140f9d5..e383677 100644 --- a/resources/js/game.js +++ b/resources/js/game.js @@ -462,6 +462,7 @@ UI.elements.menuCatch.addEventListener('click', Game.catchMonster); state.enemy.monster = await fetchMonster(possibleStarterMonsters[Math.round(Math.random() * (possibleStarterMonsters.length - 1))]); state.partyMonsters = [ + await fetchMonster('dollfin'), await fetchMonster(possibleStarterMonsters[Math.round(Math.random() * (possibleStarterMonsters.length - 1))]), await fetchMonster('corvix'), await fetchMonster('lunight'), @@ -477,6 +478,22 @@ UI.elements.menuCatch.addEventListener('click', Game.catchMonster); state.activeMonster = state.partyMonsters[0]; state.activeTechnique = state.activeMonster.activeTechniques[0]; + state.inventory = [ + new InventoryItem(await fetchItem('tuxeball')), + new InventoryItem(await fetchItem('ancient_egg')), + new InventoryItem(await fetchItem('sweet_sand')), + new InventoryItem(await fetchItem('tectonic_drill')), + new InventoryItem(await fetchItem('surfboard')), + new InventoryItem(await fetchItem('sledgehammer')), + new InventoryItem(await fetchItem('raise_melee')), + new InventoryItem(await fetchItem('raise_speed')), + new InventoryItem(await fetchItem('mm_fire')), + new InventoryItem(await fetchItem('mm_water')), + new InventoryItem(await fetchItem('cureall')), + new InventoryItem(await fetchItem('potion')), + new InventoryItem(await fetchItem('super_potion')), + ]; + UI.drawEnemyMonster(); UI.drawActiveMonster(); UI.drawActiveTechniques(); diff --git a/resources/js/helpers.js b/resources/js/helpers.js index 019f822..1622eb2 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -43,3 +43,10 @@ function mixColors(...colors) { return `rgb(${r}, ${g}, ${b})`; } + +/** + * @returns {string} + */ +function randomString () { + return (Math.random() + 1).toString(36).substring(2); +} diff --git a/resources/js/ui.js b/resources/js/ui.js index 3739ce6..455e785 100644 --- a/resources/js/ui.js +++ b/resources/js/ui.js @@ -1,6 +1,11 @@ const Template = { popup: document.querySelector('#tpl___popup'), + tabs: document.querySelector('#tpl___tabs'), + tabHeading: document.querySelector('#tpl___tabs__tab-heading'), + tabPanels: document.querySelector('#tpl___tabs__panels'), + tabPanel: document.querySelector('#tpl___tabs__tab-panel'), + battleMonster: document.querySelector('#tpl___battle__monster'), battleHpBar: document.querySelector('#tpl___battle__hp-bar'), battleExpBar: document.querySelector('#tpl___battle__exp-bar'), @@ -17,6 +22,9 @@ const Template = { movesetList: document.querySelector('#tpl___moveset__list'), movesetItem: document.querySelector('#tpl___moveset__item'), + inventory: document.querySelector('#tpl___inventory'), + inventoryItem: document.querySelector('#tpl___inventory__item'), + menuJournal: document.querySelector('#tpl___menu__journal'), dialogSave: document.querySelector('#tpl___dialog__save'), dialogLoad: document.querySelector('#tpl___dialog__load'), @@ -49,7 +57,22 @@ const UI = { const templateBase = document.createElement('div'); templateBase.innerHTML = template.innerHTML.trim(); - return templateBase.firstChild; + const templateNode = templateBase.firstChild; + + /** + * @param {HTMLElement} targetElement + */ + templateNode.appendTo = function (targetElement) { + if (templateNode.dataset.templateType && templateNode.dataset.templateType === 'multiple') { + for (const child of [...this.children]) { + targetElement.appendChild(child); + } + } else { + targetElement.appendChild(this); + } + }; + + return templateNode; }, /** @@ -69,6 +92,56 @@ const UI = { }, /** + * @typedef {Object} Tab + * @property {HTMLElement} heading + * @property {HTMLElement} content + * @inner + * + * @param {Tab[]} tabs + * + * @returns {HTMLElement} + */ + createTabs (tabs) { + const wrap = UI.createTemplate(Template.tabs); + const panelsNode = UI.createTemplate(Template.tabPanels); + + wrap.style.gridTemplateColumns = '1fr '.repeat(tabs.length); + + const name = randomString(); + + for (const idx in tabs) { + const tab = tabs[idx]; + const tabHeading = UI.createTemplate(Template.tabHeading); + const tabPanel = UI.createTemplate(Template.tabPanel); + + const inputId = `${name}_${idx}`; + const panelId = randomString(); + + const tabHeadingInput = tabHeading.querySelector('[data-template-slot="input"]'); + tabHeadingInput.name = name; + tabHeadingInput.id = inputId; + tabHeadingInput.setAttribute('aria-controls', panelId); + if (idx == 0) { + tabHeadingInput.checked = true; + } + + const tabHeadingLabel = tabHeading.querySelector('[data-template-slot="label"]'); + tabHeadingLabel.setAttribute('for', inputId); + tabHeadingLabel.appendChild(tab.heading); + + tabPanel.id = panelId; + tabPanel.appendChild(tab.content); + + tabHeading.appendTo(wrap); + panelsNode.appendChild(tabPanel); + } + + wrap.appendChild(panelsNode); + + return wrap; + }, + + /** * @param {HTMLElement} slotNode * @param {HTMLElement} replacingNode * @@ -527,15 +600,82 @@ const UI = { UI.drawPopup(popup); }, - openInventoryMenu () { // TODO + openInventoryMenu () { const popup = UI.createPopup(); + const inventory = UI.createTemplate(Template.inventory); + + const tabs = { + heal: { + heading: 'Heal', + items: [], + }, + stats: { + heading: 'Stats', + items: [], + }, + balls: { + heading: 'Balls', + items: [], + }, + techniques: { + heading: 'Techniques', + items: [], + }, + other: { + heading: 'Other', + items: [], + }, + keyItems: { + heading: 'Key Items', + items: [], + }, + }; - const inventory = document.createElement('div'); - inventory.id = 'inventory'; for (const item of state.inventory) { + const inventoryItemNode = UI.createTemplate(Template.inventoryItem); + + inventoryItemNode.querySelector('[data-template-slot="sprite"]').src = `/modules/tuxemon/mods/tuxemon/${item.sprite}`; + inventoryItemNode.querySelector('[data-template-slot="name"]').textContent = item.name; + inventoryItemNode.querySelector('[data-template-slot="quantity"]').textContent = item.quantity; + + if (['potion', 'revive'].includes(item.category)) { + tabs['heal'].items.push(inventoryItemNode); + } + else if (['stats'].includes(item.category)) { + tabs['stats'].items.push(inventoryItemNode); + } + else if (['capture'].includes(item.category)) { + tabs['balls'].items.push(inventoryItemNode); + } + else if (['technique'].includes(item.category)) { + tabs['techniques'].items.push(inventoryItemNode); + } + else if (['KeyItem'].includes(item.type)) { + tabs['keyItems'].items.push(inventoryItemNode); + } + else { + tabs['other'].items.push(inventoryItemNode); + } } + const tabsNode = UI.createTabs(Object.values(tabs).map((tab) => { + const content = document.createElement('div'); + for (const item of tab.items) { + content.appendChild(item); + } + + return { + heading: document.createTextNode(tab.heading), + content: content, + }; + })); + + tabsNode.style.gridTemplateColumns = '1fr 1fr 1fr'; + inventory.appendChild(tabsNode); + popup.querySelector('.popup').appendChild(inventory); + popup.classList.add('inventory__popup'); + UI.drawPopup(popup); }, |