package dev.llan.model.pieces.player; import dev.llan.model.board.Grid; import dev.llan.model.board.Point; import dev.llan.model.board.Tile.TileType; import dev.llan.model.board.pathfinding.Path; import dev.llan.model.cards.Card; import dev.llan.model.pieces.BaseEntity; import dev.llan.model.pieces.Displays; import dev.llan.model.pieces.Entity; import dev.llan.model.pieces.attributes.stats.BaseStatsBuilder; import dev.llan.model.pieces.attributes.inventory.Inventory; import dev.llan.events.GameEvent; import dev.llan.events.PlayerUpdatedEvent; import dev.llan.events.Events.*; import javafx.scene.image.Image; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class MainCharacter extends BaseEntity implements Player { private Inventory inventory; private List inRange; public MainCharacter(Point startingPos, Grid grid) { super( Constants.MAIN_CHARACTER_NAME, Constants.RESOURCE_PATH, startingPos, grid, new BaseStatsBuilder().maxHealth(15.0).healthRegen(0.2).scoutingRadius(8.7)); inventory = new Inventory(this); inRange = List.of(); collection.initCollection(Constants.getInitialDeck(this)); } @Override public GameEvent setActivePath(Optional activePath) { this.activePath = activePath; return new PlayerUpdatedEvent(PlayerUpdateType.PATH); } @Override public Inventory getInventory() { return inventory; } @Override public Optional selectCardInHand(int cardIndex) { if (cardIndex != collection.getSelectedIndex()) { if ((cardIndex == -1 || !hasAttacked)) { collection.selectCard(cardIndex); Optional selected = collection.getSelectedCard(); if (selected.isPresent()) { double range = selected.get().getRange(); if(range == 0.0) { inRange = new ArrayList<>(); inRange.add(getPosition().clone()); } else { inRange = getPosition().findWithin(grid, selected.get().getRange(), true); } } else { inRange = List.of(); } return Optional.of(new PlayerUpdatedEvent(PlayerUpdateType.CARDS)); } } return Optional.empty(); } @Override public Optional getSelectedCard() { return collection.getSelectedCard(); } @Override public Optional generateActivePath(Point to) { TileType type = grid.tileAt(to).getType(); if (type == TileType.INTERACTABLE || type == TileType.VACANT) { return pathFinder.findPath(this.getPosition(), to); } return Optional.empty(); } @Override public Optional recalculateActivePath() { if (activePath.isPresent()) { Point endpoint = activePath.get().getEndpoint(); Optional newPath = pathFinder.findPath(this.getPosition(), endpoint); return Optional.of(this.setActivePath(newPath)); } return Optional.empty(); } @Override public void removeActivePath() { activePath = Optional.empty(); } @Override public List getPointsInRange() { return inRange; } @Override public boolean isInRange(Point point) { return inRange.contains(point); } @Override public List onEliminationOf(Entity other) { getStats().addExperience(other.getStats().getExperienceOnDeath()); return List.of(new PlayerUpdatedEvent(PlayerUpdateType.ATTRIBUTES)); } @Override public Image getImage() { return Displays.PLAYER_RAW; } @Override public Image getIcon() { return Displays.PLAYER; } @Override public String[] getNotes() { return Constants.NOTES; } @Override public Player clone(Grid grid) { MainCharacter clone = new MainCharacter(this.getPosition().clone(), grid); clone.setStats(new BaseStatsBuilder().copyAll(this.stats).buildClone()); clone.activePath = this.cloneActivePath(); clone.clonedEffects = this.cloneEffects(); clone.inventory = this.getInventory().clone(clone); // NOT DEEP COPIES clone.modifiers = this.modifiers; clone.effects = this.effects; clone.collection = this.collection; clone.inRange = this.inRange; return clone; } @Override public String toString() { final StringBuilder sb = new StringBuilder("MainCharacter{"); sb.append("stats=").append(stats); sb.append(", inventory=").append(inventory); sb.append(", position=").append(this.getPosition()); sb.append('}'); return sb.toString(); } }