All files / games/engine/src/systems movement.ts

100% Statements 35/35
100% Branches 21/21
100% Functions 7/7
100% Lines 35/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96  16x 16x 16x 16x 16x         13x 13x 13x     1x     2x 2x 2x 1x 1x         9x       9x 7x 7x 7x 7x 7x     7x   6x 3x 3x 3x       3x 1x   2x 1x         9x     3x 1x 1x       16x                                                          
import { GameMap, PositionInterface } from "jga-games-maps";
 
import { TileInterface } from "jga-games-tiles";
 
import { EntityInterface } from "jga-patterns-ecs";
 
import { ComponentName, PositionComponent } from "../components";
 
import { Actor, Entity } from "../entities";
import { World } from "../world";
import { DamageSystem } from "./damage";
import { System } from "./system";
 
export interface MoveInterface {
    canMove: boolean;
    newPosition: PositionInterface | null;
}
 
export class MovementSystem extends System {
    protected position: PositionInterface;
    protected targets: Map<string, EntityInterface>;
 
    public constructor(
        entities: Map<string, Entity>,
        position: PositionInterface,
        targets: Map<string, EntityInterface>,
    ) {
        super(entities, [ComponentName.MOVEABLE, ComponentName.POSITION]);
 
        this.position = position;
        this.targets = this.filterEntities(targets, [ComponentName.POSITION]);
    }
 
    public getPosition(): PositionInterface {
        return this.position;
    }
 
    public run(world: World): void {
        return this.entities.forEach((entity): void => {
            const move = this.canMove(world);
 
            if (move.canMove) {
                const positionComponent = entity.getComponent(ComponentName.POSITION) as PositionComponent;
 
                positionComponent.setPosition(this.position);
            }
        });
    }
 
    public canMove(world: World): MoveInterface {
        const move: MoveInterface = {
            canMove: false,
            newPosition: this.position,
        };
 
        if (null != this.position && null != world && null !== world.getMap()) {
            const map: GameMap = world.getMap();
            const tile: TileInterface = map.getTile(this.position);
            const targets: EntityInterface[] = Array.from(this.targets.values()).filter((entity) => {
                const entityPosition = entity.getComponent(ComponentName.POSITION) as PositionComponent;
 
                return (
                    this.position.x === entityPosition.getPosition().x &&
                    this.position.y === entityPosition.getPosition().y
                );
            });
 
            if (null !== tile) {
                // if there is a target, attack
                if (0 !== targets.length) {
                    const attacker: Actor = Array.from(this.entities.values())[0] as Actor;
                    const target: Entity = targets[0] as Entity;
 
                    this.attack(attacker, target, world);
                } else {
                    // else move
                    if (tile.isWalkable) {
                        move.canMove = true;
                    } else if (tile.isDiggable) {
                        map.dig(this.position);
                    }
                }
            }
        }
 
        return move;
    }
 
    private attack(attacker: Actor, target: Entity, world: World): void {
        if (attacker.hasComponent(ComponentName.ATTACK) && target.hasComponent(ComponentName.DAMAGEABLE)) {
            const damageSystem = new DamageSystem(attacker, target);
            damageSystem.run(world);
        }
    }
}