package dev.llan.model.board; import dev.llan.events.DisplayUpdatedEvent; import dev.llan.model.Game; import dev.llan.model.board.generation.MapInitialization; import dev.llan.model.board.pathfinding.Path; import dev.llan.model.board.Tile.TileType; import dev.llan.events.GameEvent; import dev.llan.events.GridUpdatedEvent; import dev.llan.model.pieces.Entity; import dev.llan.model.pieces.GamePieces; import dev.llan.model.pieces.inanimates.Inanimate; import dev.llan.model.pieces.enemies.Enemy; import dev.llan.model.pieces.player.Player; import dev.llan.model.state.State; import java.util.*; public class GameMap implements Board { private final Game game; private final Grid grid; private EntityPosition playerPos; private final Map enemyPosMap; private State gameState; private final List highlightedPoints; private final MapInitialization initializer; public GameMap(Game game, int size) { this.game = game; grid = new Grid(size); enemyPosMap = new HashMap<>(); highlightedPoints = new ArrayList<>(); initializer = new MapInitialization(game, this); } @Override public GamePieces init() { GamePieces pieces = initializer.generateMap(Optional.empty()); Player player = pieces.player(); playerPos = new EntityPosition(pieces.player(), pieces.player().getPosition()); for (Enemy enemy : pieces.enemies()) { enemyPosMap.put(enemy, new EntityPosition(enemy, enemy.getPosition())); } grid.updateVisibilities(player.getPosition(), player.getStats().getScoutingRadius()); return pieces; } public GamePieces initNext(Player player) { GamePieces pieces = initializer.generateMap(Optional.of(player)); playerPos = new EntityPosition(player, player.getPosition()); enemyPosMap.clear(); for (Enemy enemy : pieces.enemies()) { enemyPosMap.put(enemy, new EntityPosition(enemy, enemy.getPosition())); } grid.updateVisibilities(player.getPosition(), player.getStats().getScoutingRadius()); return pieces; } public void updateGameState(State gameState) { this.gameState = gameState; } public Grid getGrid() { return grid; } @Override public int getWidth() { return grid.getColSize(); } @Override public int getHeight() { return grid.getRowSize(); } public List setTileHighlight(Point point, boolean highlighted){ grid.tileAt(point).setHighlighted(highlighted); highlightedPoints.add(point); return List.of(new DisplayUpdatedEvent()); } public List clearAllHighlightedTiles() { for(Point point : highlightedPoints) { grid.tileAt(point).setHighlighted(false); } highlightedPoints.clear(); return List.of(new DisplayUpdatedEvent()); } public List moveEntity(Entity entity, Path path) { List events = new ArrayList<>(); State startingState = gameState; while (!path.isEmpty()) { if (startingState != gameState) { break; } Point point = path.getFirst(); double movementCost = grid.getMovementCost(point, entity.getPosition()); if (entity.canMove(movementCost)) { path.removeFirst(); if (entity instanceof Player) { if (path.isEmpty()) { ((Player) entity).removeActivePath(); } } switch (gameState) { case EXPLORATION -> events.addAll(moveExploration((Player) entity, point)); case COMBAT -> events.addAll(moveCombat(entity, point, movementCost)); } } else { break; } } return events; } private List moveExploration(Player player, Point newPos) { Tile tile = grid.tileAt(newPos); if (tile.getType() == TileType.VACANT) { return movePlayerTo(player, newPos); } else if (tile.getType() == TileType.INTERACTABLE) { Inanimate inanimate = grid.tileAt(newPos).getInanimate().get(); return inanimate.interact(); } return List.of(); } private List moveCombat(Entity entity, Point newPos, double movementCost) { Tile tile = grid.tileAt(newPos); entity.reduceMovement(movementCost); if (tile.getType() == TileType.VACANT) { if (entity instanceof Player) { return movePlayerTo((Player) entity, newPos); } else { return moveEnemyTo((Enemy) entity, newPos); } } else if (tile.getType() == TileType.INTERACTABLE) { Inanimate inanimate = grid.tileAt(newPos).getInanimate().get(); return inanimate.interact(); } return List.of(); } private List movePlayerTo(Player player, Point newPos) { Tile prev = grid.tileAt(player.getPosition()); prev.removeEntity(); Tile current = grid.tileAt(newPos); current.addEntity(player); player.setPosition(newPos); playerPos.setPoint(newPos); grid.updateVisibilities(newPos, player.getStats().getScoutingRadius()); return generateMovementEvent(); } private List moveEnemyTo(Enemy enemy, Point newPos) { Tile prev = grid.tileAt(enemy.getPosition()); prev.removeEntity(); Tile current = grid.tileAt(newPos); current.addEntity(enemy); enemy.setPosition(newPos); EntityPosition enemyPos = enemyPosMap.get(enemy); enemyPos.setPoint(newPos); return generateMovementEvent(); } private List generateMovementEvent() { List events = new ArrayList<>(); if (gameState == State.EXPLORATION) { for (EntityPosition positions : enemyPosMap.values()) { Enemy enemy = (Enemy) positions.getEntity(); if (enemy.withinRadius(playerPos.getPoint())) { enemy.setInCombat(); events.add(new GridUpdatedEvent()); events.addAll(game.setState(State.COMBAT)); return events; } } } events.add(new GridUpdatedEvent()); return events; } public void removeEnemy(Enemy enemy) { Point enemyPos = enemy.getPosition(); grid.tileAt(enemyPos).removeEntity(); enemyPosMap.remove(enemy); game.removeEnemy(enemy); } public Grid cloneGrid() { return this.grid.clone(); } }