diff --git a/app/ecs-components/water.js b/app/ecs-components/water.js
new file mode 100644
index 0000000..d289048
--- /dev/null
+++ b/app/ecs-components/water.js
@@ -0,0 +1,10 @@
+import Component from '@/ecs/component.js';
+
+export default class Water extends Component {
+ static properties = {
+ water: {
+ type: 'map',
+ value: {type: 'uint8'},
+ },
+ };
+}
diff --git a/app/ecs-systems/water.js b/app/ecs-systems/water.js
new file mode 100644
index 0000000..20ba83e
--- /dev/null
+++ b/app/ecs-systems/water.js
@@ -0,0 +1,13 @@
+import {System} from '@/ecs/index.js';
+
+export default class Water extends System {
+
+ tick(elapsed) {
+ const {Water} = this.ecs.get(1);
+ for (const tile in Water.water) {
+ Water.water[tile] = Math.max(0, Water.water[tile] - elapsed);
+ }
+ Water.water = {...Water.water};
+ }
+
+}
diff --git a/app/engine.js b/app/engine.js
index debe448..980af9e 100644
--- a/app/engine.js
+++ b/app/engine.js
@@ -128,6 +128,7 @@ export default class Engine {
}
],
},
+ Water: {water: {}},
});
const defaultSystems = [
'ResetForces',
@@ -142,6 +143,7 @@ export default class Engine {
'SpriteDirection',
'RunAnimations',
'RunTickingPromises',
+ 'Water',
];
defaultSystems.forEach((defaultSystem) => {
const System = ecs.system(defaultSystem);
@@ -162,9 +164,13 @@ export default class Engine {
Forces: {},
Inventory: {
slots: {
- 1: {
- qty: 10,
- source: '/assets/potion/potion.json',
+ // 1: {
+ // qty: 10,
+ // source: '/assets/potion/potion.json',
+ // },
+ 2: {
+ qty: 1,
+ source: '/assets/watering-can/watering-can.json',
},
3: {
qty: 1,
diff --git a/app/react-components/ecs.jsx b/app/react-components/ecs.jsx
index 789d5e8..24a28df 100644
--- a/app/react-components/ecs.jsx
+++ b/app/react-components/ecs.jsx
@@ -9,6 +9,7 @@ import Entities from './entities.jsx';
import TargetingGhost from './targeting-ghost.jsx';
import TargetingGrid from './targeting-grid.jsx';
import TileLayer from './tile-layer.jsx';
+import Water from './water.jsx';
export default function EcsComponent() {
const [ecs] = useEcs();
@@ -40,7 +41,7 @@ export default function EcsComponent() {
const {Direction, Position, Wielder} = entity;
const projected = Wielder.activeItem()?.project(Position.tile, Direction.direction)
const {Camera} = entity;
- const {TileLayers: {layers: [layer]}} = ecs.get(1);
+ const {TileLayers: {layers: [layer]}, Water: {water}} = ecs.get(1);
const [cx, cy] = [
Math.round(Camera.x - RESOLUTION.x / 2),
Math.round(Camera.y - RESOLUTION.y / 2),
@@ -51,6 +52,7 @@ export default function EcsComponent() {
y={-cy}
>
+
{projected && (
{
+ g.clear();
+ g.beginFill(0x000000);
+ g.drawRect(
+ 0,
+ 0,
+ width,
+ height
+ );
+ }, [height, width]);
+ return
+});
+
+export default function Water({tileLayer, water}) {
+ const [mounted, setMounted] = useState(false);
+ useEffect(() => {
+ setMounted(true);
+ }, []);
+ const waterTile = useRef();
+ const waterTiles = [];
+ if (mounted) {
+ for (const tileIndex in water) {
+ const tileIndexNumber = parseInt(tileIndex);
+ const tx = tileIndexNumber % tileLayer.area.x;
+ const ty = (tileIndexNumber - tx) / tileLayer.area.x;
+ waterTiles.push(
+
+ );
+ }
+ }
+ return (
+ <>
+
+ {waterTiles}
+ >
+ );
+}
diff --git a/public/assets/tomato-plant/may-grow.js b/public/assets/tomato-plant/may-grow.js
index 3295946..33bdcee 100644
--- a/public/assets/tomato-plant/may-grow.js
+++ b/public/assets/tomato-plant/may-grow.js
@@ -1 +1,20 @@
-return 3 !== plant.stage
+if (3 === plant.stage) {
+ return false
+}
+
+const {TileLayers, Water} = ecs.get(1);
+const layer = TileLayers.layer(0)
+const {Position} = ecs.get(plant.entity);
+const x = (Position.x - layer.tileSize.x * 0.5) / layer.tileSize.x
+const y = (Position.y - layer.tileSize.y * 0.5) / layer.tileSize.y
+const tileIndex = layer.area.x * y + x
+if (!Water.water[tileIndex]) {
+ return false
+}
+if (Water.water[tileIndex] < 32) {
+ return false
+}
+if (Water.water[tileIndex] > 224) {
+ return false
+}
+return true
diff --git a/public/assets/watering-can/icon.png b/public/assets/watering-can/icon.png
new file mode 100644
index 0000000..879b705
Binary files /dev/null and b/public/assets/watering-can/icon.png differ
diff --git a/public/assets/watering-can/projection-check.js b/public/assets/watering-can/projection-check.js
new file mode 100644
index 0000000..69da2b4
--- /dev/null
+++ b/public/assets/watering-can/projection-check.js
@@ -0,0 +1,10 @@
+const filtered = []
+
+for (let i = 0; i < projected.length; ++i) {
+ const tile = layer.tile(projected[i])
+ if ([7].includes(tile)) {
+ filtered.push(projected[i])
+ }
+}
+
+return filtered
diff --git a/public/assets/watering-can/start.js b/public/assets/watering-can/start.js
new file mode 100644
index 0000000..e285eb0
--- /dev/null
+++ b/public/assets/watering-can/start.js
@@ -0,0 +1,120 @@
+const {Direction, Position, Wielder} = wielder
+const projected = Wielder.activeItem()?.project(Position.tile, Direction.direction)
+if (projected?.length > 0) {
+
+ const {Controlled, Emitter, Sound, Sprite} = wielder
+ const {TileLayers, Water} = ecs.get(1)
+ const layer = TileLayers.layer(0)
+
+ Controlled.locked = 1
+ const [, direction] = Sprite.animation.split(':')
+ Sprite.animation = ['idle', direction].join(':');
+
+ const waterParticles = {
+ behaviors: [
+ {
+ type: 'moveAcceleration',
+ config: {
+ accel: {
+ x: 0,
+ y: 1500,
+ },
+ minStart: 0,
+ maxStart: 0,
+ rotate: false,
+ }
+ },
+ {
+ type: 'moveSpeed',
+ config: {
+ speed: {
+ list: [
+ {
+ time: 0,
+ value: 30
+ },
+ {
+ time: 1,
+ value: 0
+ }
+ ]
+ }
+ }
+ },
+ {
+ type: 'scale',
+ config: {
+ scale: {
+ list: [
+ {
+ value: 0.25,
+ time: 0,
+ },
+ {
+ value: 0.125,
+ time: 1,
+ },
+ ]
+ }
+ }
+ },
+ {
+ type: 'textureSingle',
+ config: {
+ texture: 'tileset/38',
+ }
+ },
+ ],
+ lifetime: {
+ min: 0.25,
+ max: 0.25,
+ },
+ frequency: 0.01,
+ emitterLifetime: 0.25,
+ pos: {
+ x: 0,
+ y: 0
+ },
+ rotation: 0,
+ };
+
+ Sound.play('/assets/watering-can/water.wav');
+ for (let i = 0; i < 2; ++i) {
+ for (let i = 0; i < projected.length; ++i) {
+ Emitter.emit({
+ ...waterParticles,
+ behaviors: [
+ ...waterParticles.behaviors,
+ {
+ type: 'spawnShape',
+ config: {
+ type: 'rect',
+ data: {
+ x: projected[i].x * layer.tileSize.x,
+ y: projected[i].y * layer.tileSize.y - (layer.tileSize.y * 0.5),
+ w: layer.tileSize.x,
+ h: layer.tileSize.y,
+ }
+ }
+ }
+ ]
+ })
+ }
+ await wait(0.25);
+ }
+
+ for (let i = 0; i < projected.length; ++i) {
+ const tileIndex = layer.area.x * projected[i].y + projected[i].x
+ let w;
+ if (Water.water[tileIndex]) {
+ w = Water.water[tileIndex]
+ }
+ else {
+ w = 0
+ }
+ Water.water[tileIndex] = Math.min(255, 64 + w);
+ }
+
+ Controlled.locked = 0;
+
+}
diff --git a/public/assets/watering-can/water.wav b/public/assets/watering-can/water.wav
new file mode 100644
index 0000000..a774d4c
Binary files /dev/null and b/public/assets/watering-can/water.wav differ
diff --git a/public/assets/watering-can/watering-can.json b/public/assets/watering-can/watering-can.json
new file mode 100644
index 0000000..b6c13ea
--- /dev/null
+++ b/public/assets/watering-can/watering-can.json
@@ -0,0 +1,11 @@
+{
+ "icon": "/assets/watering-can/icon.png",
+ "projectionCheck": "/assets/watering-can/projection-check.js",
+ "projection": {
+ "distance": [1, 0],
+ "grid": [
+ [1]
+ ]
+ },
+ "start": "/assets/watering-can/start.js"
+}