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 {
|
||||
TraitUpdateReceptacleItemSwapPacket,
|
||||
} from '../packets/trait-update-receptacle-item-swap.packet';
|
||||
import {
|
||||
TraitUpdateReceptacleItemFullPacket,
|
||||
} from '../packets/trait-update-receptacle-item-full.packet';
|
||||
|
||||
const decorate = compose(
|
||||
StateProperty('slotCount', {
|
||||
|
@ -79,6 +82,14 @@ export class Receptacle extends decorate(Trait) {
|
|||
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.
|
||||
if (packet instanceof TraitUpdateReceptacleItemSwapPacket) {
|
||||
// NULL destination slot === remove.
|
||||
|
@ -105,7 +116,7 @@ export class Receptacle extends decorate(Trait) {
|
|||
this.packetUpdates.push(new TraitUpdateReceptacleItemQtyPacket({
|
||||
slotIndex,
|
||||
qty: item.qty,
|
||||
}, this.entity));
|
||||
}));
|
||||
}
|
||||
// Item was used up.
|
||||
else {
|
||||
|
@ -197,6 +208,10 @@ export class Receptacle extends decorate(Trait) {
|
|||
listeners.collisionStart = (other) => {
|
||||
if (other.is('item')) {
|
||||
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 {
|
||||
|
||||
addItemToSlot: (item, slotIndex = AUTO_SLOT) => {
|
||||
slotIndex = slotIndex >> 0;
|
||||
if (AUTO_SLOT === slotIndex) {
|
||||
return this.mergeItem(item);
|
||||
}
|
||||
else {
|
||||
this.addListenersForItem(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');
|
||||
},
|
||||
|
@ -228,7 +251,7 @@ export class Receptacle extends decorate(Trait) {
|
|||
this.packetUpdates.push(new TraitUpdateReceptacleItemSwapPacket({
|
||||
firstSlotIndex: slotIndex,
|
||||
secondSlotIndex: NULL_SLOT,
|
||||
}, this.entity));
|
||||
}));
|
||||
}
|
||||
this.entity.emit('inventoryChanged');
|
||||
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());
|
||||
import {tomatoSeedsJSON} from './fixtures/tomato-seeds.entity';
|
||||
writeFixture('tomato-seeds.entity.json', tomatoSeedsJSON());
|
||||
import {yarnBallJSON} from './fixtures/yarn-ball.entity';
|
||||
writeFixture('yarn-ball.entity.json', yarnBallJSON());
|
||||
// Write rooms.
|
||||
import {kittyFireJSON} from './fixtures/kitty-fire.room';
|
||||
writeFixture('kitty-fire.room.json', kittyFireJSON());
|
||||
|
|
|
@ -64,15 +64,15 @@ export function kittyFireJSON() {
|
|||
// for (let i = 0; i < 20; ++i) {
|
||||
// addEntityWithRandomPosition('/rock.entity.json');
|
||||
// }
|
||||
for (let i = 0; i < 30; ++i) {
|
||||
addEntityWithRandomPosition('/flower-barrel.entity.json');
|
||||
}
|
||||
// for (let i = 0; i < 30; ++i) {
|
||||
// addEntityWithRandomPosition('/flower-barrel.entity.json');
|
||||
// }
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
addEntityWithRandomPosition('/mama-kitty-spawner.entity.json');
|
||||
}
|
||||
for (let i = 0; i < 50; ++i) {
|
||||
addEntityWithRandomPosition('/fire.entity.json');
|
||||
}
|
||||
// for (let i = 0; i < 50; ++i) {
|
||||
// addEntityWithRandomPosition('/fire.entity.json');
|
||||
// }
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
addEntityWithRandomPosition('/blue-fire.entity.json');
|
||||
}
|
||||
|
|
|
@ -111,6 +111,24 @@ export function kittyJSON() {
|
|||
},
|
||||
layered: {},
|
||||
listed: {},
|
||||
lootable: {
|
||||
params: {
|
||||
table: [
|
||||
{
|
||||
perc: 20,
|
||||
json: {
|
||||
uri: '/rock.entity.json',
|
||||
},
|
||||
},
|
||||
{
|
||||
perc: 70,
|
||||
json: {
|
||||
uri: '/yarn-ball.entity.json',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
state: {
|
||||
speed: 40,
|
||||
|
@ -128,6 +146,7 @@ export function kittyJSON() {
|
|||
},
|
||||
},
|
||||
},
|
||||
spawner: {},
|
||||
vulnerable: {},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import {buildInvoke, buildTraversal} from '@avocado/behavior';
|
||||
|
||||
import {AFFINITY_NONE} from '../../common/combat/constants';
|
||||
|
||||
// Rock.
|
||||
export function rockJSON() {
|
||||
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