240 lines
6.6 KiB
JavaScript
240 lines
6.6 KiB
JavaScript
import Component from '@/ecs/component.js';
|
|
|
|
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[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.ecs = this.Component.ecs;
|
|
this.scripts.projectionCheckInstance.context.layer = layer;
|
|
this.scripts.projectionCheckInstance.context.projected = projected;
|
|
return this.scripts.projectionCheckInstance.evaluateSync();
|
|
}
|
|
else {
|
|
return projected;
|
|
}
|
|
}
|
|
get icon() {
|
|
return this.json.icon;
|
|
}
|
|
get projection() {
|
|
return this.json.projection;
|
|
}
|
|
get qty() {
|
|
return this.instance.slots[this.slot].qty;
|
|
}
|
|
set qty(qty) {
|
|
const {instance} = this;
|
|
if (qty <= 0) {
|
|
this.Component.markChange(instance.entity, 'cleared', {[this.slot]: true});
|
|
delete instance.slots[this.slot];
|
|
delete instance.$$items[this.slot];
|
|
}
|
|
else {
|
|
instance.slots[this.slot].qty = qty;
|
|
this.Component.markChange(instance.entity, 'qtyUpdated', {[this.slot]: qty});
|
|
}
|
|
}
|
|
}
|
|
|
|
export default class Inventory extends Component {
|
|
async insertMany(entities) {
|
|
for (const [id, {cleared, given, qtyUpdated, swapped}] of entities) {
|
|
const instance = this.get(id);
|
|
const {$$items, slots} = instance;
|
|
if (cleared) {
|
|
for (const slot in cleared) {
|
|
delete slots[slot];
|
|
}
|
|
}
|
|
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];
|
|
}
|
|
}
|
|
if (qtyUpdated) {
|
|
for (const slot in qtyUpdated) {
|
|
slots[slot].qty = qtyUpdated[slot];
|
|
}
|
|
}
|
|
if (swapped) {
|
|
for (const [l, r] of swapped) {
|
|
const tmp = [$$items[l], slots[l]];
|
|
[$$items[l], slots[l]] = [$$items[r], slots[r]];
|
|
[$$items[r], slots[r]] = tmp;
|
|
if ($$items[r]) {
|
|
$$items[r].slot = r;
|
|
}
|
|
if ($$items[l]) {
|
|
$$items[l].slot = l;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
await super.insertMany(entities);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
instanceFromSchema() {
|
|
const Instance = super.instanceFromSchema();
|
|
const Component = this;
|
|
return class InventoryInstance extends Instance {
|
|
$$items = {};
|
|
item(slot) {
|
|
return this.$$items[slot];
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
swapSlots(l, r) {
|
|
const {$$items, slots} = this;
|
|
const tmp = [$$items[l], slots[l]];
|
|
[$$items[l], slots[l]] = [$$items[r], slots[r]];
|
|
[$$items[r], slots[r]] = tmp;
|
|
Component.markChange(this.entity, 'swapped', [[l, r]]);
|
|
}
|
|
}
|
|
}
|
|
async load(instance) {
|
|
for (const slot in instance.slots) {
|
|
instance.$$items[slot] = new ItemProxy(this, instance, slot);
|
|
await instance.$$items[slot].load(instance.slots[slot].source);
|
|
}
|
|
}
|
|
mergeDiff(original, update) {
|
|
const merged = {
|
|
...original,
|
|
qtyUpdated: {
|
|
...original.qtyUpdated,
|
|
...update.qtyUpdated,
|
|
},
|
|
cleared: {
|
|
...original.cleared,
|
|
...update.cleared,
|
|
},
|
|
given: {
|
|
...original.given,
|
|
...update.given,
|
|
},
|
|
swapped: [
|
|
...(original.swapped || []),
|
|
...(update.swapped || []),
|
|
],
|
|
};
|
|
return merged;
|
|
}
|
|
static properties = {
|
|
slots: {
|
|
type: 'map',
|
|
value: {
|
|
type: 'object',
|
|
properties: {
|
|
quantity: {type: 'uint16'},
|
|
source: {type: 'string'},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|