summaryrefslogtreecommitdiff
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/css/menu.css53
-rw-r--r--resources/js/classes/InventoryItem.js40
-rw-r--r--resources/js/classes/Item.js22
-rw-r--r--resources/js/classes/State.js2
-rw-r--r--resources/js/db.js16
-rw-r--r--resources/js/game.js17
-rw-r--r--resources/js/helpers.js7
-rw-r--r--resources/js/ui.js148
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);
},