package dev.llan.model;
import dev.llan.events.Events.*;
import dev.llan.events.SwitchStateEvent;
import dev.llan.model.board.GameMap;
import dev.llan.model.board.Point;
import dev.llan.events.GameEvent;
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.*;
import dev.llan.model.state.combat.CombatManager.CombatPhase;
import dev.llan.model.state.combat.TurnInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static dev.llan.model.Constants.*;
public class Game {
private GameMap map;
private Player player;
private List<Enemy> enemies;
private List<Inanimate> inanimates;
private GameState state;
private int floor;
private int score;
public Game(int size) {
score = 0;
floor = 1;
map = new GameMap(this, size);
this.initGamePieces();
this.state = new Exploration(this);
map.updateGameState(State.EXPLORATION);
}
public void nextFloor() {
floor++;
score += floor * FLOOR_BONUS;
if (floor <= MAX_FLOOR) {
this.generateNextFloor();
} else {
this.win();
}
}
private void initGamePieces() {
GamePieces initialized = map.init();
player = initialized.player();
enemies = initialized.enemies();
inanimates = initialized.inanimates();
}
private void generateNextFloor() {
GamePieces nextInitialized = map.initNext(player);
enemies = nextInitialized.enemies();
inanimates = nextInitialized.inanimates();
}
public void addScore(int score) {
this.score += score;
}
public List<GameEvent> setState(State newState) {
List<GameEvent> events = new ArrayList<>();
switch (newState) {
case COMBAT -> state = new Combat(this);
case EXPLORATION -> state = new Exploration(this);
default -> throw new IllegalArgumentException("Input is not a valid game state");
}
map.updateGameState(newState);
events.addAll(state.onSwapTo());
events.add(new SwitchStateEvent(newState));
return events;
}
public State getState() {
return this.state.getState();
}
public CombatPhase getPhase() {
if (state instanceof Combat) {
return ((Combat) state).getPhase();
}
return CombatPhase.NONE;
}
public Optional<Entity> getTurn() {
if (state.getState() == State.COMBAT) {
Entity entity = ((Combat) state).getCurrentTurn();
if(entity != null) {
return Optional.of(entity);
}
}
return Optional.empty();
}
public List<TurnInfo> getTurnsList() {
if(state.getState() == State.COMBAT) {
return ((Combat) state).getTurnsList();
}
return List.of();
}
public List<GameEvent> tryMoveTo(Point position) {
return state.tryMoveTo(position);
}
public List<GameEvent> moveActivePath() {
return state.moveActivePath();
}
public List<GameEvent> endTurn() {
return state.endTurn();
}
public List<GameEvent> waitTurn() {
return state.waitTurn();
}
public List<GameEvent> useCardOn(Point position) {
return state.useCardOn(position);
}
public List<GameEvent> swapCards(int first, int second) {
return state.swapCards(first, second);
}
public List<GameEvent> selectCard(int cardIndex) {
return state.selectCard(cardIndex);
}
public List<GameEvent> removeCard(int index) {
return state.removeCard(index);
}
public List<GameEvent> equip(int index) {
return state.equip(index);
}
public List<GameEvent> swapEquipment(int first, int second) {
return state.swapEquipment(first, second);
}
public List<GameEvent> removeEquipment(int index) {
return state.removeEquipment(index);
}
public List<GameEvent> setHighlighted(Point point, boolean highlighted) {
return state.setHighlighted(point, highlighted);
}
public GameMap getMap() {
return map;
}
public Player getPlayer() {
return player;
}
public List<Enemy> getEnemies() {
return enemies;
}
public List<Inanimate> getInanimates() {
return inanimates;
}
public int getFloor() {
return floor;
}
public int getScore() {
return score;
}
public void removeEnemy(Enemy enemy) {
enemies.remove(enemy);
}
public void removeInanimate(Inanimate inanimate) {
inanimates.remove(inanimate);
}
public void end() {
state = new End(this);
}
public void win() {
state = new Win(this);
}
public GameRecord getImmutableSnapshot(EventType eventType) {
return new GameRecord(this, eventType);
}
}