import Component from '@/ecs/component.js'; export default class Inventory extends Component { insertMany(entities) { for (const [id, {slotChange}] of entities) { if (slotChange) { const {slots} = this.get(id); for (const slotIndex in slotChange) { if (false === slotChange[slotIndex]) { delete slots[slotIndex]; } else { slots[slotIndex] = { ...slots[slotIndex], ...slotChange[slotIndex], }; } } } } return super.insertMany(entities); } instanceFromSchema() { const Instance = super.instanceFromSchema(); const Component = this; return class InventoryInstance extends Instance { $$items = {}; item(slot) { return this.$$items[slot]; } swapSlots(l, r) { const {slots} = this; const tmp = slots[l]; const change = {}; if (slots[r]) { change[l] = slots[l] = slots[r]; } else { change[l] = false; delete slots[l]; } if (tmp) { change[r] = slots[r] = tmp; } else { change[r] = false; delete slots[r]; } Component.markChange(this.entity, 'slotChange', change); } } } async load(instance) { const Component = this; const {readAsset} = this.ecs; const {slots} = instance; class ItemProxy { constructor(slot, json) { this.json = json; this.slot = slot; } project(position, direction) { const {TileLayers: {layers: [layer]}} = Component.ecs.get(1); const {projection} = this.json; let startX = position.x; let startY = position.y; switch (direction) { case 0: startX += projection.distance[1]; startY -= projection.distance[0]; break; case 1: startX += projection.distance[0]; startY += projection.distance[1]; break; case 2: startX -= projection.distance[1]; startY += projection.distance[0]; break; case 3: startX -= projection.distance[0]; startY -= projection.distance[1]; break; } const projected = []; for (const row in projection.grid) { const columns = projection.grid[row]; for (const column in columns) { const targeted = projection.grid[row][column]; if (targeted) { let axe; switch (direction) { case 0: axe = [column, row]; break; case 1: axe = [-row, column]; break; case 2: axe = [-column, -row]; break; case 3: axe = [row, -column]; break; } const x = startX + parseInt(axe[0]); const y = startY + parseInt(axe[1]); if (x < 0 || y < 0 || x >= layer.area.x || y >= layer.area.y) { continue; } projected.push({x, y}); } } } return projected; } get qty() { return slots[this.slot].qty; } set qty(qty) { if (qty <= 0) { Component.markChange(instance.entity, 'slotChange', {[this.slot]: false}); delete slots[this.slot]; } else { slots[this.slot].qty = qty; Component.markChange(instance.entity, 'slotChange', {[this.slot]: {qty}}); } } } for (const slot in slots) { const chars = await readAsset([slots[slot].source, 'item.json'].join('/')) const json = chars.byteLength > 0 ? JSON.parse( (new TextDecoder()).decode(chars), ) : {}; instance.$$items[slot] = new ItemProxy(slots, json); } } mergeDiff(original, update) { if (!update.slotChange) { return super.mergeDiff(original, update); } const slotChange = { ...original.slotChange, }; for (const index in update.slotChange) { if (false === update.slotChange[index]) { slotChange[index] = false; } else { slotChange[index] = { ...slotChange[index], ...update.slotChange[index], }; } } return {slotChange}; } static properties = { slots: { type: 'map', value: { type: 'object', properties: { quantity: {type: 'uint16'}, source: {type: 'string'}, }, }, }, }; }