package de.towerdefence.server.game; import java.lang.reflect.Constructor; import java.time.Instant; import java.util.ArrayList; import java.util.List; import de.towerdefence.server.game.callbacks.EnemiesChangedCallback; import de.towerdefence.server.game.callbacks.PlayerMoneyCallback; import de.towerdefence.server.game.callbacks.PlayerHitpointsCallback; import de.towerdefence.server.game.exeptions.InvalidPlacementException; import de.towerdefence.server.game.exeptions.InvalidPlacementReason; import de.towerdefence.server.game.exeptions.WaveInProgressException; import de.towerdefence.server.player.Player; import lombok.Getter; import org.joml.Vector2i; public class GameSession { final static int START_HITPOINTS = 100; final static int START_MONEY = 50; final static Vector2i MAP_SIZE = new Vector2i(10, 20); final static int WAVE_SPAWN_DELAY = 200; // ms final static Vector2i WAVE_SPAWN = new Vector2i(5, 0); final static Vector2i WAVE_TARGET = new Vector2i(5, 19); private final Player player; @Getter private int money; @Getter private int playerHitpoints; private final PlayerMoneyCallback moneyCallback; private final PlayerHitpointsCallback hitpointsCallback; private final EnemiesChangedCallback enemyCallback; private final Tower[][] towers = new Tower[MAP_SIZE.x][MAP_SIZE.y]; private final Enemy[][] enemies = new Enemy[MAP_SIZE.x][MAP_SIZE.y]; private List<Enemy> wave = new ArrayList<>(); private long lastSpawn = Instant.now().toEpochMilli(); public GameSession( Player player, PlayerMoneyCallback moneyCallback, PlayerHitpointsCallback hitpointsCallback, EnemiesChangedCallback enemyCallback) { this.player = player; this.moneyCallback = moneyCallback; this.hitpointsCallback = hitpointsCallback; this.enemyCallback = enemyCallback; this.money = START_MONEY; this.playerHitpoints = START_HITPOINTS; } public void startWave(List<Enemy> enemies) throws WaveInProgressException { if (wave.size() > 0) { throw new WaveInProgressException(); } wave = enemies; } public void update() { List<Enemy> newEnemies = new ArrayList<>(); List<Enemy> changedEnemies = moveEnemies(); if (wave.size() > 0 && shouldSpawn()) { enemies[WAVE_SPAWN.x][WAVE_SPAWN.y] = wave.removeFirst(); newEnemies.add(enemies[WAVE_SPAWN.x][WAVE_SPAWN.y]); } if (newEnemies.size() > 0 || changedEnemies.size() > 0) { enemyCallback.call( player, newEnemies.toArray(new Enemy[newEnemies.size()]), changedEnemies.toArray(new Enemy[changedEnemies.size()])); } } private boolean shouldSpawn() { return lastSpawn + WAVE_SPAWN_DELAY < Instant.now().toEpochMilli() && enemies[WAVE_SPAWN.x][WAVE_SPAWN.y] == null; } private List<Enemy> moveEnemies() { // List<Enemy> changedEnemies = moveEnemies(); // TODO: Implement Moving of Enemies (possibly through A*) throw new RuntimeException("NOT IMPLEMENTED"); // return changedEnemies; } /** * @return the next position to go to */ private Vector2i pathfinding(Vector2i start, Vector2i target) { } public void placeTower(Tower tower, int x, int y) throws InvalidPlacementException { if (x < 0 || y < 0 || x + 1 > MAP_SIZE.x || y + 1 > MAP_SIZE.y) { throw new InvalidPlacementException(InvalidPlacementReason.OUT_OF_BOUNDS); } if (towers[x][y] != null) { throw new InvalidPlacementException(InvalidPlacementReason.LOCATION_USED); } if (money < Tower.COST) { throw new InvalidPlacementException(InvalidPlacementReason.NOT_ENOUGH_MONEY); } // TODO: Do Pathfinding check for the placement money -= Tower.COST; moneyCallback.call(player, money); tower.x = x; tower.y = y; towers[x][y] = tower; } public void addMoney(int amount) { money += amount; moneyCallback.call(player, money); } }