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

100% Statements 100/100
95.65% Branches 22/23
100% Functions 7/7
100% Lines 100/100

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 97 98 99 100 1011x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 21x 21x 21x 21x 21x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 2x 2x 1x 1x 9x 9x 9x 9x 9x 9x 7x 7x 7x 7x 7x 6x 6x 3x 3x 3x 3x 3x 1x 3x 1x 1x 3x 6x 7x 9x 9x 9x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 7x 1x 1x 3x 3x 3x 3x 1x 1x 1x 3x 1x 1x 1x 3x 1x  
import { GameMap, PositionInterface } from "../../maps/index";
import { TileInterface } from "../../tiles/index";
 
import { ComponentName, isPositionComponent } from "../components";
 
import { isActor, Entity, isEntity } 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, Entity>;
 
    public constructor(entities: Map<string, Entity>, position: PositionInterface, targets: Map<string, Entity>) {
        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);
 
                if (isPositionComponent(positionComponent)) {
                    positionComponent.setPosition(this.position);
                }
            }
        });
    }
 
    public canMove(world: World): MoveInterface {
        const move: MoveInterface = {
            canMove: false,
            newPosition: this.position,
        };
 
        if (this.position != null && world != null && world.getMap() !== null) {
            const map: GameMap = world.getMap();
            const tile: TileInterface = map.getTile(this.position);
            const targets: Entity[] = this.filterTargetsAtPosition();
 
            if (tile !== null) {
                // if there is a target, attack
                if (targets.length !== 0) {
                    this.attack(targets[0], world);
                } else {
                    // else move
                    // eslint-disable-next-line no-lonely-if
                    if (tile.isWalkable) {
                        move.canMove = true;
                    } else if (tile.isDiggable) {
                        map.dig(this.position);
                    }
                }
            }
        }
 
        return move;
    }
 
    private filterTargetsAtPosition(): Entity[] {
        return Array.from(this.targets.values()).filter((entity) => {
            const entityPosition = entity.getComponent(ComponentName.POSITION);
 
            return isPositionComponent(entityPosition)
                ? this.position.x === entityPosition.getPosition().x &&
                      this.position.y === entityPosition.getPosition().y
                : false;
        });
    }
 
    private attack(target: Entity, world: World): void {
        const attacker = Array.from(this.entities.values())[0];
 
        if (
            isActor(attacker) &&
            isEntity(target) &&
            attacker.hasComponent(ComponentName.ATTACK) &&
            target.hasComponent(ComponentName.DAMAGEABLE)
        ) {
            const damageSystem = new DamageSystem(attacker, target);
            damageSystem.run(world);
        }
    }
}