fun: lootz!
This commit is contained in:
parent
7a8c787261
commit
4b8c062b0f
29
common/packets/trait-update-receptacle-item-full.packet.js
Normal file
29
common/packets/trait-update-receptacle-item-full.packet.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import msgpack from 'msgpack-lite';
|
||||||
|
|
||||||
|
import {Packet} from '@avocado/net';
|
||||||
|
|
||||||
|
export class TraitUpdateReceptacleItemFullPacket extends Packet {
|
||||||
|
|
||||||
|
static pack(packet) {
|
||||||
|
const data = packet.data[1];
|
||||||
|
data.json = msgpack.encode(data.json);
|
||||||
|
return super.pack(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get schema() {
|
||||||
|
return {
|
||||||
|
...super.schema,
|
||||||
|
data: {
|
||||||
|
slotIndex: 'uint16',
|
||||||
|
json: 'buffer',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static unpack(packet) {
|
||||||
|
const data = super.unpack(packet);
|
||||||
|
data.json = msgpack.decode(data.json);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
68
common/traits/lootable.trait.js
Normal file
68
common/traits/lootable.trait.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import {compose, Property} from '@avocado/core';
|
||||||
|
import {StateProperty, Trait, Entity} from '@avocado/entity';
|
||||||
|
import {Rectangle, Vector} from '@avocado/math';
|
||||||
|
|
||||||
|
const decorate = compose(
|
||||||
|
StateProperty('lootable', {
|
||||||
|
track: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export class Lootable extends decorate(Trait) {
|
||||||
|
|
||||||
|
static defaultParams() {
|
||||||
|
return {
|
||||||
|
table: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultState() {
|
||||||
|
return {
|
||||||
|
lootable: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static type() {
|
||||||
|
return 'lootable';
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(entity, params, state) {
|
||||||
|
super(entity, params, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateLoot() {
|
||||||
|
const jsons = [];
|
||||||
|
const roll = Math.random() * 100;
|
||||||
|
for (const {perc, json} of this.params.table) {
|
||||||
|
if (perc > roll) {
|
||||||
|
jsons.push(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jsons;
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners() {
|
||||||
|
const listeners = {};
|
||||||
|
if (AVOCADO_SERVER) {
|
||||||
|
listeners['died'] = () => {
|
||||||
|
const jsons = this.calculateLoot();
|
||||||
|
const position = this.entity.position;
|
||||||
|
for (let i = 0; i < jsons.length; i++) {
|
||||||
|
const offset = Vector.sub(
|
||||||
|
[
|
||||||
|
Math.floor(Math.random() * 16),
|
||||||
|
Math.floor(Math.random() * 16)
|
||||||
|
],
|
||||||
|
[8, 8]
|
||||||
|
);
|
||||||
|
this.entity.spawnRawAt(
|
||||||
|
Vector.add(position, offset),
|
||||||
|
jsons[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return listeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,9 @@ import {
|
||||||
import {
|
import {
|
||||||
TraitUpdateReceptacleItemSwapPacket,
|
TraitUpdateReceptacleItemSwapPacket,
|
||||||
} from '../packets/trait-update-receptacle-item-swap.packet';
|
} from '../packets/trait-update-receptacle-item-swap.packet';
|
||||||
|
import {
|
||||||
|
TraitUpdateReceptacleItemFullPacket,
|
||||||
|
} from '../packets/trait-update-receptacle-item-full.packet';
|
||||||
|
|
||||||
const decorate = compose(
|
const decorate = compose(
|
||||||
StateProperty('slotCount', {
|
StateProperty('slotCount', {
|
||||||
|
@ -79,6 +82,14 @@ export class Receptacle extends decorate(Trait) {
|
||||||
item.qty = packet.data.qty;
|
item.qty = packet.data.qty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Full item.
|
||||||
|
if (packet instanceof TraitUpdateReceptacleItemFullPacket) {
|
||||||
|
Entity.loadOrInstance(packet.data.json).then((item) => {
|
||||||
|
item.hydrate().then(() => {
|
||||||
|
this.entity.addItemToSlot(item, packet.data.slotIndex);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
// Slot swap.
|
// Slot swap.
|
||||||
if (packet instanceof TraitUpdateReceptacleItemSwapPacket) {
|
if (packet instanceof TraitUpdateReceptacleItemSwapPacket) {
|
||||||
// NULL destination slot === remove.
|
// NULL destination slot === remove.
|
||||||
|
@ -105,7 +116,7 @@ export class Receptacle extends decorate(Trait) {
|
||||||
this.packetUpdates.push(new TraitUpdateReceptacleItemQtyPacket({
|
this.packetUpdates.push(new TraitUpdateReceptacleItemQtyPacket({
|
||||||
slotIndex,
|
slotIndex,
|
||||||
qty: item.qty,
|
qty: item.qty,
|
||||||
}, this.entity));
|
}));
|
||||||
}
|
}
|
||||||
// Item was used up.
|
// Item was used up.
|
||||||
else {
|
else {
|
||||||
|
@ -197,6 +208,10 @@ export class Receptacle extends decorate(Trait) {
|
||||||
listeners.collisionStart = (other) => {
|
listeners.collisionStart = (other) => {
|
||||||
if (other.is('item')) {
|
if (other.is('item')) {
|
||||||
this.entity.addItemToSlot(other);
|
this.entity.addItemToSlot(other);
|
||||||
|
const slotIndex = this.itemSlotIndex(other);
|
||||||
|
if (other.is('listed')) {
|
||||||
|
other.list.removeEntity(other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -207,12 +222,20 @@ export class Receptacle extends decorate(Trait) {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
addItemToSlot: (item, slotIndex = AUTO_SLOT) => {
|
addItemToSlot: (item, slotIndex = AUTO_SLOT) => {
|
||||||
|
slotIndex = slotIndex >> 0;
|
||||||
if (AUTO_SLOT === slotIndex) {
|
if (AUTO_SLOT === slotIndex) {
|
||||||
return this.mergeItem(item);
|
return this.mergeItem(item);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.addListenersForItem(item);
|
this.addListenersForItem(item);
|
||||||
this.slotItems[slotIndex] = item;
|
this.slotItems[slotIndex] = item;
|
||||||
|
if (AVOCADO_SERVER) {
|
||||||
|
this.packetUpdates.push(new TraitUpdateReceptacleItemFullPacket({
|
||||||
|
slotIndex,
|
||||||
|
// CHEATING: assuming this entity is the informed
|
||||||
|
json: item.toNetwork(this.entity),
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.entity.emit('inventoryChanged');
|
this.entity.emit('inventoryChanged');
|
||||||
},
|
},
|
||||||
|
@ -228,7 +251,7 @@ export class Receptacle extends decorate(Trait) {
|
||||||
this.packetUpdates.push(new TraitUpdateReceptacleItemSwapPacket({
|
this.packetUpdates.push(new TraitUpdateReceptacleItemSwapPacket({
|
||||||
firstSlotIndex: slotIndex,
|
firstSlotIndex: slotIndex,
|
||||||
secondSlotIndex: NULL_SLOT,
|
secondSlotIndex: NULL_SLOT,
|
||||||
}, this.entity));
|
}));
|
||||||
}
|
}
|
||||||
this.entity.emit('inventoryChanged');
|
this.entity.emit('inventoryChanged');
|
||||||
return item;
|
return item;
|
||||||
|
|
BIN
resource/yarn-ball.png
Normal file
BIN
resource/yarn-ball.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 355 B |
|
@ -40,6 +40,8 @@ import {wateringCanJSON} from './fixtures/watering-can.entity';
|
||||||
writeFixture('watering-can.entity.json', wateringCanJSON());
|
writeFixture('watering-can.entity.json', wateringCanJSON());
|
||||||
import {tomatoSeedsJSON} from './fixtures/tomato-seeds.entity';
|
import {tomatoSeedsJSON} from './fixtures/tomato-seeds.entity';
|
||||||
writeFixture('tomato-seeds.entity.json', tomatoSeedsJSON());
|
writeFixture('tomato-seeds.entity.json', tomatoSeedsJSON());
|
||||||
|
import {yarnBallJSON} from './fixtures/yarn-ball.entity';
|
||||||
|
writeFixture('yarn-ball.entity.json', yarnBallJSON());
|
||||||
// Write rooms.
|
// Write rooms.
|
||||||
import {kittyFireJSON} from './fixtures/kitty-fire.room';
|
import {kittyFireJSON} from './fixtures/kitty-fire.room';
|
||||||
writeFixture('kitty-fire.room.json', kittyFireJSON());
|
writeFixture('kitty-fire.room.json', kittyFireJSON());
|
||||||
|
|
|
@ -64,15 +64,15 @@ export function kittyFireJSON() {
|
||||||
// for (let i = 0; i < 20; ++i) {
|
// for (let i = 0; i < 20; ++i) {
|
||||||
// addEntityWithRandomPosition('/rock.entity.json');
|
// addEntityWithRandomPosition('/rock.entity.json');
|
||||||
// }
|
// }
|
||||||
for (let i = 0; i < 30; ++i) {
|
// for (let i = 0; i < 30; ++i) {
|
||||||
addEntityWithRandomPosition('/flower-barrel.entity.json');
|
// addEntityWithRandomPosition('/flower-barrel.entity.json');
|
||||||
}
|
// }
|
||||||
for (let i = 0; i < 5; ++i) {
|
for (let i = 0; i < 5; ++i) {
|
||||||
addEntityWithRandomPosition('/mama-kitty-spawner.entity.json');
|
addEntityWithRandomPosition('/mama-kitty-spawner.entity.json');
|
||||||
}
|
}
|
||||||
for (let i = 0; i < 50; ++i) {
|
// for (let i = 0; i < 50; ++i) {
|
||||||
addEntityWithRandomPosition('/fire.entity.json');
|
// addEntityWithRandomPosition('/fire.entity.json');
|
||||||
}
|
// }
|
||||||
for (let i = 0; i < 5; ++i) {
|
for (let i = 0; i < 5; ++i) {
|
||||||
addEntityWithRandomPosition('/blue-fire.entity.json');
|
addEntityWithRandomPosition('/blue-fire.entity.json');
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,24 @@ export function kittyJSON() {
|
||||||
},
|
},
|
||||||
layered: {},
|
layered: {},
|
||||||
listed: {},
|
listed: {},
|
||||||
|
lootable: {
|
||||||
|
params: {
|
||||||
|
table: [
|
||||||
|
{
|
||||||
|
perc: 20,
|
||||||
|
json: {
|
||||||
|
uri: '/rock.entity.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
perc: 70,
|
||||||
|
json: {
|
||||||
|
uri: '/yarn-ball.entity.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
mobile: {
|
mobile: {
|
||||||
state: {
|
state: {
|
||||||
speed: 40,
|
speed: 40,
|
||||||
|
@ -128,6 +146,7 @@ export function kittyJSON() {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
spawner: {},
|
||||||
vulnerable: {},
|
vulnerable: {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import {buildInvoke, buildTraversal} from '@avocado/behavior';
|
import {buildInvoke, buildTraversal} from '@avocado/behavior';
|
||||||
|
|
||||||
import {AFFINITY_NONE} from '../../common/combat/constants';
|
|
||||||
|
|
||||||
// Rock.
|
// Rock.
|
||||||
export function rockJSON() {
|
export function rockJSON() {
|
||||||
const spawnProjectile = buildInvoke(
|
const spawnProjectile = buildInvoke(
|
||||||
|
|
54
server/fixtures/yarn-ball.entity.js
Normal file
54
server/fixtures/yarn-ball.entity.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import {buildInvoke, buildTraversal} from '@avocado/behavior';
|
||||||
|
|
||||||
|
// Yarn ball.
|
||||||
|
export function yarnBallJSON() {
|
||||||
|
return {
|
||||||
|
traits: {
|
||||||
|
collider: {
|
||||||
|
params: {
|
||||||
|
isSensor: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
existent: {
|
||||||
|
state: {
|
||||||
|
name: 'Yarn Ball',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
params: {
|
||||||
|
slotImageUris: {
|
||||||
|
default: '/yarn-ball.png',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
layered: {},
|
||||||
|
listed: {},
|
||||||
|
magnetic: {},
|
||||||
|
mobile: {},
|
||||||
|
physical: {},
|
||||||
|
pictured: {
|
||||||
|
params: {
|
||||||
|
images: {
|
||||||
|
initial: {
|
||||||
|
offset: [0, 0],
|
||||||
|
size: [8, 8], // Derive?
|
||||||
|
uri: '/yarn-ball.png',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
positioned: {},
|
||||||
|
roomed: {},
|
||||||
|
shaped: {
|
||||||
|
params: {
|
||||||
|
shape: {
|
||||||
|
type: 'rectangle',
|
||||||
|
position: [0, 0],
|
||||||
|
size: [16, 16],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visible: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user