DungeonsXL/core/src/main/java/de/erethon/dungeonsxl/dungeon/DGame.java

402 lines
11 KiB
Java

/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.dungeon;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
import de.erethon.dungeonsxl.api.dungeon.Game;
import de.erethon.dungeonsxl.api.dungeon.GameGoal;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.player.PlayerGroup;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.api.world.ResourceWorld;
import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.global.GameSign;
import de.erethon.dungeonsxl.player.DGroup;
import de.erethon.dungeonsxl.sign.windup.MobSign;
import de.erethon.dungeonsxl.trigger.ProgressTrigger;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
/**
* @author Daniel Saukel
*/
public class DGame implements Game {
private DungeonsXL plugin;
private Dungeon dungeon;
private GameWorld world;
private List<ResourceWorld> unplayedFloors = new ArrayList<>();
private ResourceWorld nextFloor;
private int floorCount;
private List<PlayerGroup> groups = new ArrayList<>();
private boolean tutorial;
private boolean rewards = true;
private boolean started;
private int waveCount;
private Map<String, Integer> gameKills = new HashMap<>();
private Map<String, Integer> waveKills = new HashMap<>();
public DGame(DungeonsXL plugin, Dungeon dungeon) {
this.plugin = plugin;
plugin.getGameCache().add(this);
setDungeon(dungeon);
if (this.dungeon == null) {
throw new IllegalStateException("Game initialized without dungeon");
}
tutorial = false;
started = false;
}
public DGame(DungeonsXL plugin, Dungeon dungeon, PlayerGroup group) {
this(plugin, dungeon);
addGroup(group);
}
public DGame(DungeonsXL plugin, Dungeon dungeon, List<PlayerGroup> groups) {
this(plugin, dungeon);
groups.forEach(this::addGroup);
}
@Override
public boolean isTutorial() {
return tutorial;
}
@Override
public void setTutorial(boolean tutorial) {
this.tutorial = tutorial;
}
@Override
public List<PlayerGroup> getGroups() {
return new ArrayList<>(groups);
}
@Override
public void addGroup(PlayerGroup group) {
groups.add(group);
((DGroup) group).setGame(this);
group.setInitialLives(getRules().getState(GameRule.INITIAL_GROUP_LIVES));
group.setLives(getRules().getState(GameRule.INITIAL_GROUP_LIVES));
GameGoal goal = getRules().getState(GameRule.GAME_GOAL);
if (goal.getType().hasComponent(GameGoal.INITIAL_SCORE)) {
group.setScore(goal.getState(GameGoal.INITIAL_SCORE));
}
}
@Override
public void removeGroup(PlayerGroup group) {
groups.remove(group);
if (groups.isEmpty()) {
delete();
}
}
@Override
public boolean hasStarted() {
return started;
}
@Override
public void setStarted(boolean started) {
this.started = started;
}
@Override
public Dungeon getDungeon() {
return dungeon;
}
/**
* Sets up all dungeon-related fields.
*
* @param dungeon the dungeon to set
*/
public void setDungeon(Dungeon dungeon) {
this.dungeon = dungeon;
if (dungeon.isMultiFloor()) {
unplayedFloors = dungeon.getFloors();
}
}
/**
* Sets up all dungeon-related fields.
*
* @param name the name of the dungeon
* @return if the action was successful
*/
public boolean setDungeon(String name) {
dungeon = plugin.getDungeonRegistry().get(name);
if (dungeon != null) {
unplayedFloors = dungeon.getFloors();
return true;
} else {
ResourceWorld resource = plugin.getMapRegistry().get(name);
if (resource != null) {
dungeon = resource.getSingleFloorDungeon();
return true;
}
return false;
}
}
@Override
public DGameWorld getWorld() {
return (DGameWorld) world;
}
@Override
public void setWorld(GameWorld gameWorld) {
world = gameWorld;
}
@Override
public List<ResourceWorld> getUnplayedFloors() {
return unplayedFloors;
}
@Override
public boolean addUnplayedFloor(ResourceWorld unplayedFloor) {
return unplayedFloors.add(unplayedFloor);
}
@Override
public boolean removeUnplayedFloor(ResourceWorld unplayedFloor, boolean force) {
if (getDungeon().getRemoveWhenPlayed() || force) {
return unplayedFloors.remove(unplayedFloor);
}
return false;
}
@Override
public ResourceWorld getNextFloor() {
return nextFloor;
}
@Override
public void setNextFloor(ResourceWorld floor) {
nextFloor = floor;
}
@Override
public int getFloorCount() {
return floorCount;
}
@Override
public boolean hasRewards() {
return rewards;
}
@Override
public void setRewards(boolean enabled) {
rewards = enabled;
}
/**
* @return the waveCount
*/
public int getWaveCount() {
return waveCount;
}
/**
* @param waveCount the waveCount to set
*/
public void setWaveCount(int waveCount) {
this.waveCount = waveCount;
}
/**
* @return how many mobs have been killed in the game
*/
public int getGameKills() {
int count = 0;
for (String killer : gameKills.keySet()) {
count += gameKills.get(killer);
}
return count;
}
/**
* @return how many mobs have been killed in the last game
*/
public int getWaveKills() {
int count = 0;
for (String killer : waveKills.keySet()) {
count += waveKills.get(killer);
}
return count;
}
/**
* @param killer the killer; null if the killer is not a player
*/
public void addKill(String killer) {
if (killer == null) {
killer = "N/A";
}
waveKills.put(killer, waveKills.get(killer) == null ? 1 : waveKills.get(killer) + 1);
}
/**
* Adds the values of the wave kills map to the game kills map and resets the wave kills.
*/
public void resetWaveKills() {
gameKills.putAll(waveKills);
waveKills.clear();
}
@Override
public Collection<Player> getPlayers() {
Set<Player> toReturn = new HashSet<>();
for (PlayerGroup group : groups) {
toReturn.addAll(group.getMembers().getOnlinePlayers());
}
return toReturn;
}
@Override
public boolean isEmpty() {
return groups.isEmpty();
}
@Override
public GameWorld ensureWorldIsLoaded(boolean ignoreLimit) {
if (world != null) {
return world;
}
world = dungeon.getMap().instantiateGameWorld(this, ignoreLimit);
return world;
}
@Override
public boolean start() {
getWorld().setWeather(getRules());
for (PlayerGroup group : groups) {
if (group == null) {
continue;
}
if (!((DGroup) group).checkStartGame(this)) {
plugin.log("Could not start game for group " + group);
return false;
}
}
int i = 0;
for (PlayerGroup group : groups) {
if (group != null) {
((DGroup) group).startGame(this, i++);
}
}
if (getWorld() != null) {
if (!getWorld().isPlaying()) {
getWorld().startGame();
}
}
floorCount++;
nextFloor = null;
started = true;
return true;
}
@Override
public void delete() {
GameSign gameSign = GameSign.getByGame(plugin, this);
plugin.getGameCache().remove(this);
if (gameSign != null) {
gameSign.update();
}
}
/**
* @param mobCountIncreaseRate the new mob count will be increased by this rate
* @param teleport whether or not to teleport the players to the start location
*/
public void finishWave(final double mobCountIncreaseRate, final boolean teleport) {
waveCount++;
resetWaveKills();
for (Trigger uncasted : getWorld().getTriggers()) {
if (!(uncasted instanceof ProgressTrigger)) {
continue;
}
ProgressTrigger trigger = (ProgressTrigger) uncasted;
if (getWaveCount() >= trigger.getWaveCount() & getFloorCount() >= trigger.getFloorCount() - 1
|| !getUnplayedFloors().contains(trigger.getFloor()) & trigger.getFloor() != null) {
trigger.trigger(true, null);
}
}
int delay = getRules().getState(GameRule.TIME_TO_NEXT_WAVE);
sendMessage(DMessage.GROUP_WAVE_FINISHED.getMessage(String.valueOf(waveCount), String.valueOf(delay)));
new BukkitRunnable() {
@Override
public void run() {
if (teleport) {
groups.forEach(g -> g.getMembers().getOnlinePlayers().forEach(p -> p.teleport(world.getStartLocation(plugin.getPlayerGroup(p)))));
}
for (DungeonSign dSign : world.getDungeonSigns()) {
if (!(dSign instanceof MobSign)) {
continue;
}
MobSign mobSign = (MobSign) dSign;
int newAmount = (int) Math.ceil(mobSign.getInitialAmount() * mobCountIncreaseRate);
mobSign.setN(newAmount);
mobSign.startTask();
}
}
}.runTaskLater(plugin, delay * 20);
}
@Override
public boolean isFinished() {
return groups.stream().allMatch(PlayerGroup::isFinished);
}
@Override
public String toString() {
return getClass().getSimpleName() + "{dungeon=" + getDungeon() + "}";
}
}