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

99.01% Statements 101/102
95.83% Branches 23/24
100% Functions 7/7
99.01% Lines 101/102

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 101 102 1031x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 1x 1x 25x 25x 6x 6x 6x 6x 1x 1x 1x 1x 1x 1x 6x 6x 25x 25x 13x 13x 13x 13x 13x 13x 11x 11x 11x 11x 11x 10x 10x 7x 7x 3x 3x 3x 1x 3x 1x 1x 3x 10x 11x 13x 13x 13x 25x 25x 11x 11x 11x 11x 11x 11x 11x   11x 11x 25x 25x 7x 7x 7x 7x 7x 5x 5x 5x 7x 5x 5x 5x 7x 25x  
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[] {
        // eslint-disable-next-line compat/compat
        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 {
        // eslint-disable-next-line compat/compat
        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);
        }
    }
}