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

100% Statements 35/35
95.23% Branches 20/21
100% Functions 8/8
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 97 98 99 100 101      44x   44x   44x 44x             44x           21x   21x 21x       1x       2x 2x   2x 1x   1x 1x             9x         9x 7x 7x 7x   7x   6x 3x       3x 1x 2x 1x           9x       7x 7x   7x               3x   3x           1x 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);
        }
    }
}