package dev.llan.model.state.combat; import dev.llan.events.*; import dev.llan.model.state.combat.actions.CardUse; import dev.llan.model.state.combat.actions.Move; import dev.llan.model.state.combat.actions.Wait; import dev.llan.events.Events.*; import dev.llan.model.Game; import dev.llan.model.board.GameMap; import dev.llan.model.pieces.Entity; import dev.llan.model.pieces.enemies.Enemy; import dev.llan.model.pieces.player.Player; import dev.llan.model.state.State; import dev.llan.model.state.combat.actions.Action; import java.util.*; public class CombatManager { public enum CombatPhase { TURN, WAIT, NONE } private static final Comparator turnComparator = (o1, o2) -> Double.compare(o2.getStats().getSpeed(), o1.getStats().getSpeed()); private static final Comparator waitComparator = Comparator.comparingDouble(o -> o.getStats().getSpeed()); private final Game game; private final List entities; private final Player player; private final GameMap map; private final PriorityQueue turnQueue; private final PriorityQueue waitQueue; private Entity currentTurn; private CombatPhase phase; public CombatManager(Player player, List enemies, GameMap map, Game game) { this.game = game; this.player = player; entities = new ArrayList<>(); entities.add(player); addCombatEnemies(enemies); this.map = map; turnQueue = new PriorityQueue<>(entities.size(), turnComparator); waitQueue = new PriorityQueue<>(entities.size(), waitComparator); phase = CombatPhase.NONE; } private void addCombatEnemies(List enemies) { Set notified = new HashSet<>(); for (Enemy enemy : enemies) { if (enemy.inCombat()) { notified.add(enemy); enemy.notifyNearbyEnemies(enemies, notified); } } this.addAllEntities(notified); } public void addAllEntities(Set entities) { for (Enemy enemy : entities) { if (!enemy.inCombat()) { enemy.setInCombat(); } } this.entities.addAll(entities); } public List initCombat() { List events = new ArrayList<>(); events.addAll(startRound()); events.addAll(nextTurn()); events.addAll(processUntilPlayer()); return events; } private List startRound() { List events = new ArrayList<>(); for (Entity entity : entities) { entity.onNextCombatRound(); } events.add(new PlayerUpdatedEvent(PlayerUpdateType.ATTRIBUTES)); events.addAll(checkEliminations()); turnQueue.addAll(entities); return events; } public List nextTurn() { List events = new ArrayList<>(); if (turnQueue.isEmpty() && waitQueue.isEmpty() && entities.size() > 1) { events.addAll(startRound()); nextTurn(); } else if (turnQueue.isEmpty()) { currentTurn = waitQueue.poll(); phase = CombatPhase.WAIT; } else { currentTurn = turnQueue.poll(); phase = CombatPhase.TURN; } if(currentTurn instanceof Player) { events.add(new PlayerUpdatedEvent(PlayerUpdateType.ATTRIBUTES)); } return events; } public List processUntilPlayer() { List events = new ArrayList<>(); while (currentTurn instanceof Enemy) { events.addAll(processEnemyTurn()); events.addAll(nextTurn()); } return events; } private List processEnemyTurn() { List actions = ((Enemy) currentTurn).generateActions(map, player, phase); return processActions(actions); } private List processActions(List actions) { List events = new ArrayList<>(); for (Action action : actions) { switch (action.getActionType()) { case MOVE -> events.addAll(processMove((Move) action)); case WAIT -> events.addAll(processWait((Wait) action)); case CARD_USE -> events.addAll(processCardUse((CardUse) action)); } } return events; } public List processAction(Action action) { return switch (action.getActionType()) { case MOVE -> processMove((Move) action); case WAIT -> processWait((Wait) action); case CARD_USE -> processCardUse((CardUse) action); }; } private List processMove(Move move) { return map.moveEntity(move.getActor(), move.getPath()); } private List processWait(Wait wait) { waitQueue.add(wait.getActor()); return List.of(new WaitedEvent()); } private List processCardUse(CardUse cardUse) { List events = new ArrayList<>(); events.addAll(cardUse.process(map)); events.addAll(checkEliminations()); return events; } private List checkEliminations() { List elimEvents = new ArrayList<>(); List toRemove = new ArrayList<>(); for (Entity entity : entities) { if (entity.getStats().getHealth() == 0.0) { if (entity instanceof Enemy) { map.removeEnemy((Enemy) entity); turnQueue.remove(entity); waitQueue.remove(entity); toRemove.add(entity); elimEvents.addAll(player.onEliminationOf(entity)); elimEvents.add(new GridUpdatedEvent()); } else { elimEvents.add(new GameOverEvent()); game.end(); } } } entities.removeAll(toRemove); List enemiesLeft = entities.stream().filter(entity -> (entity instanceof Enemy)).toList(); if (enemiesLeft.isEmpty()) { elimEvents.addAll(game.setState(State.EXPLORATION)); } return elimEvents; } public CombatPhase getPhase() { return this.phase; } public Entity getTurn() { return this.currentTurn; } public List getTurnList() { List turnEntities = new ArrayList<>(turnQueue); turnEntities.sort(turnComparator); List waitEntities = new ArrayList<>(waitQueue); waitEntities.sort(waitComparator); List turnList = new ArrayList<>(); if(currentTurn != null) { turnList.add(currentTurn.getTurnInfo()); } for(Entity entity : turnEntities) { turnList.add(entity.getTurnInfo()); } for(Entity entity : waitEntities) { turnList.add(entity.getTurnInfo()); } return turnList; } }