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<Point> 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<Path> activePath) {
this.activePath = activePath;
return new PlayerUpdatedEvent(PlayerUpdateType.PATH);
}
@Override
public Inventory getInventory() {
return inventory;
}
@Override
public Optional<GameEvent> selectCardInHand(int cardIndex) {
if (cardIndex != collection.getSelectedIndex()) {
if ((cardIndex == -1 || !hasAttacked)) {
collection.selectCard(cardIndex);
Optional<Card> 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<Card> getSelectedCard() {
return collection.getSelectedCard();
}
@Override
public Optional<Path> 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<GameEvent> recalculateActivePath() {
if (activePath.isPresent()) {
Point endpoint = activePath.get().getEndpoint();
Optional<Path> 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<Point> getPointsInRange() {
return inRange;
}
@Override
public boolean isInRange(Point point) {
return inRange.contains(point);
}
@Override
public List<GameEvent> 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();
}
}