package dev.llan.model.pieces.enemies; import dev.llan.model.board.GameMap; import dev.llan.model.board.Grid; import dev.llan.model.board.Point; import dev.llan.model.board.pathfinding.Path; import dev.llan.model.cards.Card; import dev.llan.model.pieces.BaseEntity; import dev.llan.model.pieces.attributes.stats.BaseStatsBuilder; import dev.llan.model.pieces.attributes.stats.Stats; import dev.llan.model.pieces.player.Player; import dev.llan.model.state.combat.CombatManager; import dev.llan.model.state.combat.actions.Action; 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 java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; public abstract class BaseEnemy extends BaseEntity implements Enemy { private boolean inCombat; protected BaseEnemy( String name, String resourcePath, Point startingPos, Grid grid, BaseStatsBuilder builder) { super(name, resourcePath, startingPos, grid, builder); this.inCombat = false; } protected BaseEnemy( String name, String resourcePath, Point startingPos, Grid grid, Stats clonedStats) { super(name, resourcePath, startingPos, grid, clonedStats); this.inCombat = false; } @Override public void setInCombat() { inCombat = true; } @Override public boolean inCombat() { return inCombat; } @Override public void notifyNearbyEnemies(List others, Set notified) { List withinRadius = this.getNearbyEnemies(others); for (Enemy other : withinRadius) { if (!notified.contains(other) && !other.inCombat()) { notified.add(other); other.notifyNearbyEnemies(others, notified); } } } private List getNearbyEnemies(List others) { List within = new ArrayList<>(); for (Enemy other : others) { double distance = Point.getDistance(this.getPosition(), other.getPosition()); if (distance < this.getStats().getNotificationRadius()) { within.add(other); } } return within; } @Override public boolean withinRadius(Point playerPos) { double distance = Point.getDistance(playerPos, this.getPosition()); return distance < this.getStats().getScoutingRadius(); } @Override public List generateActions(GameMap map, Player player, CombatManager.CombatPhase phase) { if (phase != CombatManager.CombatPhase.WAIT) { return List.of(new Wait(this)); } List actions = new ArrayList<>(); activePath = generateActivePath(player.getPosition()); if (activePath.isPresent()) { actions.add(new Move(this, activePath.get())); } if(!hasAttacked){ actions.add(new CardUse(this, player, this.selectCard())); } return actions; } @Override public Optional generateActivePath(Point playerPos) { List points = playerPos.findClosestVacant(grid); if (points.size() > 0) { Point minPoint = points.getFirst(); double minDistance = Point.getDistance(getPosition(), minPoint); for (int i = 1; i < points.size(); i++) { Point currentPoint = points.get(i); double currentDistance = Point.getDistance(getPosition(), currentPoint); if (currentDistance < minDistance) { minDistance = currentDistance; minPoint = currentPoint; } } return pathFinder.findPath(getPosition(), minPoint); } return Optional.empty(); } protected abstract Card selectCard(); protected void cloneAttributes(BaseEnemy original) { this.activePath = original.cloneActivePath(); this.clonedEffects = original.cloneEffects(); // NOT DEEP COPIES this.collection = original.collection; this.modifiers = original.modifiers; this.effects = original.effects; } @Override public String toString() { final StringBuilder sb = new StringBuilder("BaseEnemy{"); sb.append("name=").append(this.getName()); sb.append(", position=").append(this.getPosition()); sb.append(", inCombat=").append(inCombat); sb.append(", stats=").append(stats); sb.append('}'); return sb.toString(); } }