diff --git a/common/traits/plant.trait.js b/common/traits/plant.trait.js new file mode 100644 index 0000000..bf56d42 --- /dev/null +++ b/common/traits/plant.trait.js @@ -0,0 +1,90 @@ +import {behaviorItemFromJSON, createContext} from '@avocado/behavior'; +import {compose, Property} from '@avocado/core'; +import {StateProperty, Trait} from '@avocado/entity'; + +import {TraitPlantPacket} from './trait-plant.packet'; + +const decorate = compose( + StateProperty('growthStage', { + track: true, + }), +); + +export class Plant extends decorate(Trait) { + + static defaultParams() { + return { + growthCondition: { + type: 'condition', + operator: 'or', + operands: [], + }, + stageSpecs: {}, + }; + } + + static defaultState() { + return { + growthStage: 0, + }; + } + + static type() { + return 'plant'; + } + + constructor(entity, params, state) { + super(entity, params, state); + this.growthCondition = behaviorItemFromJSON(this.params.growthCondition); + this.growthConditionContext = createContext(); + this.growthConditionContext.set('entity', this.entity); + this.growthElapsed = 0; + } + + acceptPacket(packet) { + if (packet instanceof TraitPlantPacket) { + this.entity.growthStage = packet.data.growthStage; + } + } + + packetsForUpdate() { + return this.createTraitPacketUpdates(TraitPlantPacket); + } + + listeners() { + return { + + growthStageChanged: (oldStage, newStage) => { + const stageSpec = this.params.stageSpecs[newStage]; + this.entity.currentImage = stageSpec.image; + }, + + }; + } + + methods() { + return { + + growToNextStage: () => { + const growthStage = this.entity.growthStage; + const stageSpec = this.params.stageSpecs[growthStage]; + this.growthElapsed = stageSpec.growAt; + this.entity.growthStage = growthStage + 1; + }, + + }; + } + + tick(elapsed) { + if (this.growthCondition.get(this.growthConditionContext)) { + const growthStage = this.entity.growthStage; + const stageSpec = this.params.stageSpecs[growthStage]; + // TODO variance + this.growthElapsed += elapsed; + if (this.growthElapsed >= stageSpec.growAt) { + this.entity.growthStage = growthStage + 1; + } + } + } + +} diff --git a/common/traits/trait-plant.packet.js b/common/traits/trait-plant.packet.js new file mode 100644 index 0000000..e539c6a --- /dev/null +++ b/common/traits/trait-plant.packet.js @@ -0,0 +1,11 @@ +import {EntityPacket} from '@avocado/entity'; + +export class TraitPlantPacket extends EntityPacket { + + static get schema() { + const schema = super.schema; + schema.data.growthStage = 'uint8'; + return schema; + } + +} diff --git a/resource/seeds.png b/resource/seeds.png new file mode 100644 index 0000000..45ba9d9 Binary files /dev/null and b/resource/seeds.png differ diff --git a/resource/tomato-stage-0.png b/resource/tomato-stage-0.png new file mode 100644 index 0000000..aa565d8 Binary files /dev/null and b/resource/tomato-stage-0.png differ diff --git a/resource/tomato-stage-1.png b/resource/tomato-stage-1.png new file mode 100644 index 0000000..68fae6e Binary files /dev/null and b/resource/tomato-stage-1.png differ diff --git a/resource/tomato-stage-2.png b/resource/tomato-stage-2.png new file mode 100644 index 0000000..f3fcc5b Binary files /dev/null and b/resource/tomato-stage-2.png differ diff --git a/resource/tomato-stage-3.png b/resource/tomato-stage-3.png new file mode 100644 index 0000000..c05ac6e Binary files /dev/null and b/resource/tomato-stage-3.png differ diff --git a/resource/tomato-stage-4.png b/resource/tomato-stage-4.png new file mode 100644 index 0000000..78a7113 Binary files /dev/null and b/resource/tomato-stage-4.png differ diff --git a/server/create-entity-for-connection.js b/server/create-entity-for-connection.js index 53427ed..c52b458 100644 --- a/server/create-entity-for-connection.js +++ b/server/create-entity-for-connection.js @@ -78,6 +78,10 @@ export function createEntityForConnection(socket) { qty: 1, uri: '/watering-can.entity.json', }, + 4: { + qty: 1, + uri: '/tomato-seeds.entity.json', + }, }, }, }, diff --git a/server/create-fixtures.js b/server/create-fixtures.js index 0b93ec6..378625e 100644 --- a/server/create-fixtures.js +++ b/server/create-fixtures.js @@ -25,6 +25,8 @@ import {mamaKittySpawnerJSON} from './fixtures/mama-kitty-spawner.entity'; writeFixture('mama-kitty-spawner.entity.json', mamaKittySpawnerJSON()); import {mamaKittyJSON} from './fixtures/mama-kitty.entity'; writeFixture('mama-kitty.entity.json', mamaKittyJSON()); +import {tomatoPlantJSON} from './fixtures/tomato-plant.entity'; +writeFixture('tomato-plant.entity.json', tomatoPlantJSON()); // Write items. import {potionJSON} from './fixtures/potion.entity'; writeFixture('potion.entity.json', potionJSON()); @@ -34,6 +36,8 @@ import {hoeJSON} from './fixtures/hoe.entity'; writeFixture('hoe.entity.json', hoeJSON()); 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()); // Write rooms. import {kittyFireJSON} from './fixtures/kitty-fire.room'; writeFixture('kitty-fire.room.json', kittyFireJSON()); diff --git a/server/fixtures/tomato-plant.entity.js b/server/fixtures/tomato-plant.entity.js new file mode 100644 index 0000000..47f21b5 --- /dev/null +++ b/server/fixtures/tomato-plant.entity.js @@ -0,0 +1,76 @@ +import {buildInvoke, buildTraversal} from '@avocado/behavior'; + +// A tomato plant. +export function tomatoPlantJSON() { + return { + traits: { + existent: { + state: { + name: 'Tomato plant', + }, + }, + layered: {}, + listed: {}, + pictured: { + params: { + images: { + 'initial': { + offset: [0, 0], + size: [16, 16], + uri: '/tomato-stage-0.png', + }, + 'stage-1': { + offset: [0, 0], + size: [16, 16], + uri: '/tomato-stage-1.png', + }, + 'stage-2': { + offset: [0, 0], + size: [16, 16], + uri: '/tomato-stage-2.png', + }, + 'stage-3': { + offset: [0, 0], + size: [16, 16], + uri: '/tomato-stage-3.png', + }, + 'stage-4': { + offset: [0, 0], + size: [16, 16], + uri: '/tomato-stage-4.png', + }, + } + }, + }, + plant: { + params: { + stageSpecs: { + 0: { + growAt: 20, + image: 'initial', + }, + 1: { + growAt: 40, + image: 'stage-1', + }, + 2: { + growAt: 60, + image: 'stage-2', + }, + 3: { + growAt: 80, + image: 'stage-3', + }, + 4: { + growAt: 99999999, + image: 'stage-4', + }, + } + } + }, + positioned: {}, + roomed: {}, + visible: {}, + }, + }; +} diff --git a/server/fixtures/tomato-seeds.entity.js b/server/fixtures/tomato-seeds.entity.js new file mode 100644 index 0000000..e8b53a4 --- /dev/null +++ b/server/fixtures/tomato-seeds.entity.js @@ -0,0 +1,82 @@ +import {buildInvoke, buildTraversal, buildCondition} from '@avocado/behavior'; + +// Tomato seeds. +export function tomatoSeedsJSON() { + return { + traits: { + existent: {}, + item: { + params: { + itemActions: { + type: 'actions', + traversals: [ + buildInvoke(['item', 'useTool']), + ], + }, + slotImages: { + default: '/seeds.png', + }, + }, + }, + spawner: { + params: { + spawns: { + 'tomato-plant': { + uri: '/tomato-plant.entity.json', + }, + }, + }, + }, + tool: { + params: { + // Has to be wet dirt. + condition: buildCondition('is', [ + 7, + buildInvoke( + ['user', 'layer', 'tileAt'], + [ + buildTraversal(['target']), + ], + ), + ]), + actions: { + type: 'actions', + traversals: [ + buildInvoke( + ['item', 'spawnAt'], + [ + 'tomato-plant', + buildInvoke( + ['Vector', 'add'], + [ + buildInvoke( + ['Vector', 'mul'], + [ + buildTraversal(['target']), + buildTraversal(['user', 'layer', 'tileset', 'tileSize']), + ], + ), + buildInvoke( + ['Vector', 'scale'], + [ + buildTraversal(['user', 'layer', 'tileset', 'tileSize']), + 0.5, + ] + ), + ] + ), + ], + ), + ], + }, + target: { + type: 'projection', + distance: -1, + length: 3, + width: 3, + }, + }, + }, + }, + }; +}