silphius/app/ecs-components/inventory.js
2024-06-28 13:10:27 -05:00

190 lines
5.3 KiB
JavaScript

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 {slots} = instance;
class ItemProxy {
constructor(slot, json, scripts) {
this.json = json;
this.scripts = scripts;
this.slot = slot;
}
project(position, direction) {
const {TileLayers} = Component.ecs.get(1);
const layer = TileLayers.layer(0);
const {projection} = this.json;
if (!projection) {
return undefined;
}
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});
}
}
}
if (this.scripts.projectionCheckInstance) {
this.scripts.projectionCheckInstance.context.layer = layer;
this.scripts.projectionCheckInstance.context.projected = projected;
return this.scripts.projectionCheckInstance.evaluateSync();
}
else {
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 json = await this.ecs.readJson(slots[slot].source);
const scripts = {};
if (json.projectionCheck) {
scripts.projectionCheckInstance = await this.ecs.readScript(json.projectionCheck);
}
if (json.start) {
scripts.startInstance = await this.ecs.readScript(json.start);
}
if (json.stop) {
scripts.stopInstance = await this.ecs.readScript(json.stop);
}
instance.$$items[slot] = new ItemProxy(slots, json, scripts);
}
}
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'},
},
},
},
};
}