silphius/app/ecs/components/inventory.js

258 lines
7.3 KiB
JavaScript
Raw Normal View History

2024-06-26 21:08:09 -05:00
import Component from '@/ecs/component.js';
2024-07-01 21:50:43 -05:00
class ItemProxy {
constructor(Component, instance, slot) {
this.Component = Component;
this.instance = instance;
this.slot = slot;
}
async load(source) {
const {ecs} = this.Component;
const json = await ecs.readJson(source);
const scripts = {};
if (json.projectionCheck) {
scripts.projectionCheckInstance = await ecs.readScript(json.projectionCheck);
}
if (json.start) {
scripts.startInstance = await ecs.readScript(json.start);
}
if (json.stop) {
scripts.stopInstance = await ecs.readScript(json.stop);
}
this.json = json;
this.scripts = scripts;
}
project(position, direction) {
const {TileLayers} = this.Component.ecs.get(1);
const layer = TileLayers.layer(0);
const {projection} = this;
if (!projection) {
return undefined;
}
let startX = position.x;
let startY = position.y;
switch (direction) {
case 0:
startX += projection.distance[0];
startY += projection.distance[1];
break;
2024-07-24 09:28:35 -05:00
case 1:
2024-07-01 21:50:43 -05:00
startX -= projection.distance[1];
startY += projection.distance[0];
break;
2024-07-24 09:28:35 -05:00
case 2:
2024-07-01 21:50:43 -05:00
startX -= projection.distance[0];
startY -= projection.distance[1];
break;
2024-07-24 09:28:35 -05:00
case 3:
startX += projection.distance[1];
startY -= projection.distance[0];
break;
2024-07-01 21:50:43 -05:00
}
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:
2024-07-24 09:28:35 -05:00
axe = [-row, column];
2024-07-01 21:50:43 -05:00
break;
case 1:
2024-07-24 09:28:35 -05:00
axe = [-column, -row];
2024-07-01 21:50:43 -05:00
break;
case 2:
2024-07-24 09:28:35 -05:00
axe = [row, -column];
2024-07-01 21:50:43 -05:00
break;
case 3:
2024-07-24 09:28:35 -05:00
axe = [column, row];
2024-07-01 21:50:43 -05:00
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.ecs = this.Component.ecs;
this.scripts.projectionCheckInstance.context.projected = projected;
2024-07-11 15:43:08 -05:00
return this.scripts.projectionCheckInstance.evaluate();
2024-07-01 21:50:43 -05:00
}
else {
return projected;
}
}
get icon() {
return this.json.icon;
}
2024-07-23 23:27:08 -05:00
get label() {
return this.json.label;
}
2024-07-01 21:50:43 -05:00
get projection() {
return this.json.projection;
}
get qty() {
return this.instance.slots[this.slot].qty;
}
set qty(qty) {
const {instance} = this;
if (qty <= 0) {
2024-07-02 20:43:47 -05:00
this.Component.markChange(instance.entity, 'cleared', {[this.slot]: true});
2024-07-01 21:50:43 -05:00
delete instance.slots[this.slot];
delete instance.$$items[this.slot];
}
else {
instance.slots[this.slot].qty = qty;
2024-07-02 20:43:47 -05:00
this.Component.markChange(instance.entity, 'qtyUpdated', {[this.slot]: qty});
2024-07-01 21:50:43 -05:00
}
}
}
2024-06-26 21:08:09 -05:00
export default class Inventory extends Component {
2024-07-30 11:46:04 -05:00
async updateMany(entities) {
2024-07-01 21:50:43 -05:00
for (const [id, {cleared, given, qtyUpdated, swapped}] of entities) {
const instance = this.get(id);
const {$$items, slots} = instance;
2024-06-28 14:10:44 -05:00
if (cleared) {
for (const slot in cleared) {
delete slots[slot];
}
}
2024-07-01 21:50:43 -05:00
if (given) {
for (const slot in given) {
$$items[slot] = new ItemProxy(this, instance, slot);
await $$items[slot].load(given[slot].source);
slots[slot] = given[slot];
}
}
2024-06-28 14:10:44 -05:00
if (qtyUpdated) {
for (const slot in qtyUpdated) {
slots[slot].qty = qtyUpdated[slot];
}
}
if (swapped) {
2024-07-28 18:42:28 -05:00
for (const [l, otherEntityId, r] of swapped) {
const otherInstance = this.get(otherEntityId);
const {$$items: $$otherItems, slots: otherSlots} = otherInstance;
2024-06-28 14:10:44 -05:00
const tmp = [$$items[l], slots[l]];
2024-07-28 18:42:28 -05:00
[$$items[l], slots[l]] = [$$otherItems[r], otherSlots[r]];
[$$otherItems[r], otherSlots[r]] = tmp;
if ($$otherItems[r]) {
$$otherItems[r].slot = r;
2024-07-01 21:50:43 -05:00
}
if ($$items[l]) {
$$items[l].slot = l;
}
2024-06-22 22:04:24 -05:00
}
}
}
2024-07-30 11:46:04 -05:00
await super.updateMany(entities);
2024-07-02 20:43:47 -05:00
for (const [id, {slots}] of entities) {
if (slots) {
const instance = this.get(id);
instance.$$items = {};
for (const slot in slots) {
instance.$$items[slot] = new ItemProxy(this, instance, slot);
await instance.$$items[slot].load(instance.slots[slot].source);
}
}
}
2024-06-26 21:08:09 -05:00
}
instanceFromSchema() {
const Instance = super.instanceFromSchema();
const Component = this;
2024-06-27 13:56:43 -05:00
return class InventoryInstance extends Instance {
2024-06-28 08:53:20 -05:00
$$items = {};
item(slot) {
return this.$$items[slot];
2024-06-26 21:08:09 -05:00
}
2024-07-01 21:50:43 -05:00
async give(stack) {
const {slots} = this;
for (let slot = 1; slot < 11; ++slot) {
if (slots[slot]?.source === stack.source) {
slots[slot].qty += stack.qty;
Component.markChange(this.entity, 'qtyUpdated', {[slot]: slots[slot].qty});
return;
}
}
for (let slot = 1; slot < 11; ++slot) {
if (!slots[slot]) {
slots[slot] = stack;
this.$$items[slot] = new ItemProxy(Component, this, slot);
await this.$$items[slot].load();
Component.markChange(this.entity, 'given', {[slot]: slots[slot]});
return;
}
}
}
2024-07-28 18:42:28 -05:00
swapSlots(l, OtherInventory, r) {
2024-06-28 14:10:44 -05:00
const {$$items, slots} = this;
2024-07-28 18:42:28 -05:00
const {$$items: $$otherItems, slots: otherSlots} = OtherInventory;
2024-06-28 14:10:44 -05:00
const tmp = [$$items[l], slots[l]];
2024-07-28 18:42:28 -05:00
[$$items[l], slots[l]] = [$$otherItems[r], otherSlots[r]];
[$$otherItems[r], otherSlots[r]] = tmp;
2024-07-24 02:39:25 -05:00
if (undefined === slots[l]) {
delete slots[l];
}
2024-07-28 18:42:28 -05:00
if (undefined === otherSlots[r]) {
delete otherSlots[r];
2024-07-24 02:39:25 -05:00
}
2024-07-28 18:42:28 -05:00
Component.markChange(this.entity, 'swapped', [[l, OtherInventory.entity, r]]);
Component.markChange(OtherInventory.entity, 'swapped', [[r, this.entity, l]]);
}
toNet(recipient, data) {
if (recipient.id !== this.entity && this !== recipient.Player.openInventory) {
return {};
}
return super.toNet(data);
2024-06-26 21:08:09 -05:00
}
2024-06-27 13:56:43 -05:00
}
}
2024-06-28 08:53:20 -05:00
async load(instance) {
2024-07-01 21:50:43 -05:00
for (const slot in instance.slots) {
instance.$$items[slot] = new ItemProxy(this, instance, slot);
await instance.$$items[slot].load(instance.slots[slot].source);
2024-06-28 08:53:20 -05:00
}
}
mergeDiff(original, update) {
2024-06-28 14:10:44 -05:00
const merged = {
...original,
qtyUpdated: {
...original.qtyUpdated,
...update.qtyUpdated,
},
cleared: {
2024-07-01 17:48:34 -05:00
...original.cleared,
...update.cleared,
2024-06-28 14:10:44 -05:00
},
2024-07-01 21:50:43 -05:00
given: {
...original.given,
...update.given,
},
2024-07-01 21:46:08 -05:00
swapped: [
2024-06-28 14:10:44 -05:00
...(original.swapped || []),
...(update.swapped || []),
2024-07-01 21:46:08 -05:00
],
2024-06-28 08:53:20 -05:00
};
2024-06-28 14:10:44 -05:00
return merged;
2024-06-28 08:53:20 -05:00
}
2024-06-26 21:08:09 -05:00
static properties = {
slots: {
type: 'map',
value: {
type: 'object',
properties: {
quantity: {type: 'uint16'},
source: {type: 'string'},
},
},
},
};
}