mirror of
https://github.com/DRE2N/DungeonsXL.git
synced 2024-11-14 22:56:10 +01:00
Rewrite game goals; resolves #1057
This commit is contained in:
parent
b61e1267d0
commit
50a8374b1c
@ -14,36 +14,126 @@
|
||||
*/
|
||||
package de.erethon.dungeonsxl.api.dungeon;
|
||||
|
||||
import de.erethon.commons.misc.EnumUtil;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
/**
|
||||
* A game goal defines what the players have to do in order to finish the game.
|
||||
*
|
||||
* @author Daniel Saukel
|
||||
*/
|
||||
public enum GameGoal {
|
||||
public class GameGoal extends GameRuleContainer {
|
||||
|
||||
/**
|
||||
* The default goal. The game ends when the end is reached.
|
||||
* Score used for capture the flag and similar game types.
|
||||
*/
|
||||
END,
|
||||
public static final GameRule<Integer> INITIAL_SCORE = new GameRule<>(Integer.class, "initialScore", 3);
|
||||
/**
|
||||
* The game does not end. Instead, the goal is to survive as long as possible to beat a highscore.
|
||||
* The amount of goals to score before the game ends. -1 = not used.
|
||||
*/
|
||||
HIGHSCORE,
|
||||
public static final GameRule<Integer> SCORE_GOAL = new GameRule<>(Integer.class, "scoreGoal", -1);
|
||||
/**
|
||||
* The game ends when a player dies and only one group is left.
|
||||
* The time left to finish the game; -1 if no timer is used.
|
||||
*/
|
||||
LAST_MAN_STANDING,
|
||||
public static final GameRule<Integer> TIME_TO_FINISH = new GameRule<>(Integer.class, "timeToFinish", -1);
|
||||
|
||||
/**
|
||||
* The game ends when a group reachs a specific score.
|
||||
* The default game goal: {@link Type#END} without TIME_TO_FINISH
|
||||
*/
|
||||
REACH_SCORE,
|
||||
public static final GameGoal DEFAULT = new GameGoal(Type.END);
|
||||
|
||||
static {
|
||||
DEFAULT.setState(TIME_TO_FINISH, TIME_TO_FINISH.getDefaultValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* The game ends after a specific time. The goal is to get the highest score until then.
|
||||
* The reader to deserialize a game goal from a configuration.
|
||||
*/
|
||||
TIME_SCORE,
|
||||
public static final ConfigReader<GameGoal> READER = (api, value) -> {
|
||||
if (!(value instanceof ConfigurationSection)) {
|
||||
return DEFAULT;
|
||||
}
|
||||
ConfigurationSection config = (ConfigurationSection) value;
|
||||
Type type = EnumUtil.getEnumIgnoreCase(Type.class, config.getString("type", "END"));
|
||||
GameGoal goal = new GameGoal(type);
|
||||
for (GameRule rule : type.getComponents()) {
|
||||
rule.fromConfig(api, goal, config);
|
||||
if (!goal.rules.containsKey(rule)) {
|
||||
goal.setState(rule, rule.getDefaultValue());
|
||||
}
|
||||
}
|
||||
return goal;
|
||||
};
|
||||
|
||||
private Type type;
|
||||
|
||||
public GameGoal(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The game ends after a specific time. The goal is to survive until then.
|
||||
* Returns the type of the game goal.
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
TIME_SURVIVAL;
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the behavior of the game goal and which settings apply to it.
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* The default goal. The game ends when the end is reached.
|
||||
*/
|
||||
END(TIME_TO_FINISH),
|
||||
/**
|
||||
* The game ends when a player dies and only one group is left.
|
||||
*/
|
||||
LAST_MAN_STANDING,
|
||||
/**
|
||||
* SCORE_GOAL = -1: The game does not end. Instead, the goal is to survive as long as possible to beat a highscore.
|
||||
* <p>
|
||||
* SCORE_GOAL > 0: The game ends when a group reachs a specific score.
|
||||
* <p>
|
||||
* TIME_TO_FINISH != -1: The game ends after a specific time. The goal is to get the highest score until then.
|
||||
*/
|
||||
SCORE(INITIAL_SCORE, SCORE_GOAL, TIME_TO_FINISH),
|
||||
/**
|
||||
* The game ends after a specific time. The goal is to survive until then.
|
||||
*/
|
||||
TIME_SURVIVAL;
|
||||
|
||||
private GameRule[] components;
|
||||
|
||||
Type(GameRule... components) {
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the game rules that apply to game goals of this type.
|
||||
*
|
||||
* @return an array of the game rules that apply to game goals of this type
|
||||
*/
|
||||
public GameRule[] getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given game rule applies to game goals of this type.
|
||||
*
|
||||
* @param component the game rule
|
||||
* @return whether the given game rule applies to game goals of this type
|
||||
*/
|
||||
public boolean hasComponent(GameRule component) {
|
||||
for (GameRule c : components) {
|
||||
if (c == component) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,9 +14,7 @@
|
||||
*/
|
||||
package de.erethon.dungeonsxl.api.dungeon;
|
||||
|
||||
import de.erethon.caliburn.CaliburnAPI;
|
||||
import de.erethon.caliburn.item.ExItem;
|
||||
import de.erethon.caliburn.item.VanillaItem;
|
||||
import de.erethon.caliburn.mob.ExMob;
|
||||
import de.erethon.commons.chat.MessageUtil;
|
||||
import de.erethon.commons.misc.EnumUtil;
|
||||
@ -24,7 +22,6 @@ import de.erethon.commons.misc.NumberUtil;
|
||||
import de.erethon.dungeonsxl.api.DungeonsAPI;
|
||||
import de.erethon.dungeonsxl.api.Requirement;
|
||||
import de.erethon.dungeonsxl.api.Reward;
|
||||
import de.erethon.dungeonsxl.api.world.GameWorld;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -36,9 +33,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* Represents a game rule for a {@link Game}.
|
||||
@ -79,7 +74,7 @@ public class GameRule<V> {
|
||||
/**
|
||||
* The goal of the game that defines what makes it end.
|
||||
*/
|
||||
public static final GameRule<GameGoal> GAME_GOAL = new GameRule<>(GameGoal.class, "gameGoal", GameGoal.END);
|
||||
public static final GameRule<GameGoal> GAME_GOAL = new GameRule<>(GameGoal.class, "gameGoal", GameGoal.DEFAULT, GameGoal.READER);
|
||||
/**
|
||||
* The Vanilla game mode.
|
||||
*/
|
||||
@ -164,14 +159,6 @@ public class GameRule<V> {
|
||||
* Alternatively to {@link #INITIAL_LIVES player lives}, you can use group lives.
|
||||
*/
|
||||
public static final GameRule<Integer> INITIAL_GROUP_LIVES = new GameRule<>(Integer.class, "initialGroupLives", -1);
|
||||
/**
|
||||
* Score used for capture the flag and similar game types.
|
||||
*/
|
||||
public static final GameRule<Integer> INITIAL_SCORE = new GameRule<>(Integer.class, "initialScore", 3);
|
||||
/**
|
||||
* The amount of goals to score before the game ends. -1 = not used.
|
||||
*/
|
||||
public static final GameRule<Integer> SCORE_GOAL = new GameRule<>(Integer.class, "scoreGoal", -1);
|
||||
/**
|
||||
* When loot may be taken away out of the dungeon again.
|
||||
*/
|
||||
@ -180,10 +167,6 @@ public class GameRule<V> {
|
||||
* The cooldown between two mob waves.
|
||||
*/
|
||||
public static final GameRule<Integer> TIME_TO_NEXT_WAVE = new GameRule<>(Integer.class, "timeToNextWave", 10);
|
||||
/**
|
||||
* The time left to finish the game; -1 if no timer is used.
|
||||
*/
|
||||
public static final GameRule<Integer> TIME_TO_FINISH = new GameRule<>(Integer.class, "timeToFinish", -1);
|
||||
/**
|
||||
* Time until a player is kicked out of a group after he leaves the server.
|
||||
*/
|
||||
@ -337,10 +320,20 @@ public class GameRule<V> {
|
||||
* An array of all game rules that exist natively in DungeonsXL.
|
||||
*/
|
||||
public static final GameRule[] VALUES = values();
|
||||
/**
|
||||
* A container of all rules with their default value. This is used internally as the most subsidiary container that fills missing rules if they are not set.
|
||||
*/
|
||||
public static final GameRuleContainer DEFAULT_VALUES = new GameRuleContainer();
|
||||
|
||||
static {
|
||||
for (GameRule rule : VALUES) {
|
||||
DEFAULT_VALUES.setState(rule, rule.getDefaultValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static GameRule[] values() {
|
||||
Field[] fields = GameRule.class.getFields();
|
||||
GameRule[] values = new GameRule[fields.length - 1];
|
||||
GameRule[] values = new GameRule[fields.length - 2];
|
||||
int i = 0;
|
||||
for (Field field : fields) {
|
||||
try {
|
||||
|
@ -24,18 +24,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class GameRuleContainer {
|
||||
|
||||
/**
|
||||
* A container of all rules with their default value. This is used internally as the most subsidiary container that fills missing rules if they are not set.
|
||||
*/
|
||||
public static final GameRuleContainer DEFAULT_VALUES = new GameRuleContainer();
|
||||
|
||||
static {
|
||||
for (GameRule rule : GameRule.VALUES) {
|
||||
DEFAULT_VALUES.setState(rule, rule.getDefaultValue());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<GameRule<?>, Object> rules;
|
||||
protected Map<GameRule<?>, Object> rules;
|
||||
|
||||
/**
|
||||
* Initializes an emtpy GameRuleContainer.
|
||||
|
@ -28,7 +28,6 @@ import de.erethon.dungeonsxl.api.Reward;
|
||||
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
|
||||
import de.erethon.dungeonsxl.api.dungeon.Game;
|
||||
import de.erethon.dungeonsxl.api.dungeon.GameRule;
|
||||
import de.erethon.dungeonsxl.api.dungeon.GameRuleContainer;
|
||||
import de.erethon.dungeonsxl.api.event.group.GroupCreateEvent;
|
||||
import de.erethon.dungeonsxl.api.mob.DungeonMob;
|
||||
import de.erethon.dungeonsxl.api.mob.ExternalMobProvider;
|
||||
@ -172,7 +171,7 @@ public class DungeonsXL extends DREPlugin implements DungeonsAPI {
|
||||
public void add(String key, GameRule rule) {
|
||||
super.add(key, rule);
|
||||
if (loaded) {
|
||||
GameRuleContainer.DEFAULT_VALUES.setState(rule, rule.getDefaultValue());
|
||||
GameRule.DEFAULT_VALUES.setState(rule, rule.getDefaultValue());
|
||||
mainConfig.getDefaultWorldConfig().updateGameRule(rule);
|
||||
for (Dungeon apiDungeon : dungeonRegistry) {
|
||||
DDungeon dungeon = ((DDungeon) apiDungeon);
|
||||
|
@ -18,6 +18,7 @@ package de.erethon.dungeonsxl.dungeon;
|
||||
|
||||
import de.erethon.dungeonsxl.DungeonsXL;
|
||||
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
|
||||
import de.erethon.dungeonsxl.api.dungeon.GameRule;
|
||||
import de.erethon.dungeonsxl.api.dungeon.GameRuleContainer;
|
||||
import de.erethon.dungeonsxl.api.world.ResourceWorld;
|
||||
import java.io.File;
|
||||
@ -198,7 +199,7 @@ public class DDungeon implements Dungeon {
|
||||
rules = new GameRuleContainer();
|
||||
}
|
||||
rules.merge(plugin.getMainConfig().getDefaultWorldConfig());
|
||||
rules.merge(GameRuleContainer.DEFAULT_VALUES);
|
||||
rules.merge(GameRule.DEFAULT_VALUES);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@ 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;
|
||||
@ -105,7 +106,10 @@ public class DGame implements Game {
|
||||
((DGroup) group).setGame(this);
|
||||
group.setInitialLives(getRules().getState(GameRule.INITIAL_GROUP_LIVES));
|
||||
group.setLives(getRules().getState(GameRule.INITIAL_GROUP_LIVES));
|
||||
group.setScore(getRules().getState(GameRule.INITIAL_SCORE));
|
||||
GameGoal goal = getRules().getState(GameRule.GAME_GOAL);
|
||||
if (goal.getType().hasComponent(GameGoal.INITIAL_SCORE)) {
|
||||
group.setScore(goal.getState(GameGoal.INITIAL_SCORE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -345,7 +345,7 @@ public class DGamePlayer extends DInstancePlayer implements GamePlayer {
|
||||
|
||||
getGroup().setScore(getGroup().getScore() + 1);
|
||||
GameGoal goal = rules.getState(GameRule.GAME_GOAL);
|
||||
if ((goal == GameGoal.REACH_SCORE || goal == GameGoal.TIME_SCORE) && rules.getState(GameRule.SCORE_GOAL) == getGroup().getScore()) {
|
||||
if (goal.getType().hasComponent(GameGoal.SCORE_GOAL) && goal.getState(GameGoal.SCORE_GOAL) == getGroup().getScore()) {
|
||||
getGroup().winGame();
|
||||
}
|
||||
|
||||
@ -759,7 +759,7 @@ public class DGamePlayer extends DInstancePlayer implements GamePlayer {
|
||||
}.runTaskLater(plugin, 1L);
|
||||
}
|
||||
|
||||
if (rules.getState(GameRule.GAME_GOAL) == GameGoal.LAST_MAN_STANDING) {
|
||||
if (rules.getState(GameRule.GAME_GOAL).getType() == GameGoal.Type.LAST_MAN_STANDING) {
|
||||
if (game.getGroups().size() == 1) {
|
||||
((DGroup) game.getGroups().get(0)).winGame();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import de.erethon.dungeonsxl.DungeonsXL;
|
||||
import de.erethon.dungeonsxl.api.Reward;
|
||||
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.dungeon.GameRuleContainer;
|
||||
import de.erethon.dungeonsxl.api.event.group.GroupCollectRewardEvent;
|
||||
@ -576,8 +577,9 @@ public class DGroup implements PlayerGroup {
|
||||
GameRuleContainer rules = getDungeon().getRules();
|
||||
initialLives = rules.getState(GameRule.INITIAL_GROUP_LIVES);
|
||||
lives = initialLives;
|
||||
if (rules.getState(GameRule.TIME_TO_FINISH) != -1) {
|
||||
timeIsRunningTask = new TimeIsRunningTask(plugin, this, rules.getState(GameRule.TIME_TO_FINISH)).runTaskTimer(plugin, 20, 20);
|
||||
GameGoal goal = rules.getState(GameRule.GAME_GOAL);
|
||||
if (goal.getType().hasComponent(GameGoal.TIME_TO_FINISH) && goal.getState(GameGoal.TIME_TO_FINISH) != -1) {
|
||||
timeIsRunningTask = new TimeIsRunningTask(plugin, this, goal.getState(GameGoal.TIME_TO_FINISH)).runTaskTimer(plugin, 20, 20);
|
||||
}
|
||||
|
||||
for (UUID playerId : getMembers()) {
|
||||
|
@ -17,8 +17,6 @@
|
||||
package de.erethon.dungeonsxl.player;
|
||||
|
||||
import de.erethon.dungeonsxl.DungeonsXL;
|
||||
import de.erethon.dungeonsxl.api.dungeon.GameGoal;
|
||||
import de.erethon.dungeonsxl.api.dungeon.GameRule;
|
||||
import de.erethon.dungeonsxl.api.event.group.GroupPlayerKickEvent;
|
||||
import de.erethon.dungeonsxl.api.player.GamePlayer;
|
||||
import de.erethon.dungeonsxl.api.player.PlayerGroup;
|
||||
@ -39,14 +37,12 @@ public class TimeIsRunningTask extends BukkitRunnable {
|
||||
private PlayerGroup group;
|
||||
private int time;
|
||||
private int timeLeft;
|
||||
private GameGoal goal;
|
||||
|
||||
public TimeIsRunningTask(DungeonsXL plugin, PlayerGroup group, int time) {
|
||||
this.plugin = plugin;
|
||||
this.group = group;
|
||||
this.time = time;
|
||||
this.timeLeft = time;
|
||||
goal = group.getDungeon().getRules().getState(GameRule.GAME_GOAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -70,10 +66,6 @@ public class TimeIsRunningTask extends BukkitRunnable {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fire trigger
|
||||
if (goal != GameGoal.TIME_SCORE && goal != GameGoal.TIME_SURVIVAL) {
|
||||
return;
|
||||
}
|
||||
GroupPlayerKickEvent groupPlayerKickEvent = new GroupPlayerKickEvent(group, dPlayer, GroupPlayerKickEvent.Cause.TIME_EXPIRED);
|
||||
Bukkit.getServer().getPluginManager().callEvent(groupPlayerKickEvent);
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class EndSign extends Button {
|
||||
@Override
|
||||
public void initialize() {
|
||||
GameGoal goal = getGame().getRules().getState(GameRule.GAME_GOAL);
|
||||
if (goal != GameGoal.END) {
|
||||
if (goal.getType() != GameGoal.Type.END) {
|
||||
setToAir();
|
||||
MessageUtil.log(api, "&4An end sign in the dungeon " + getGame().getDungeon().getName() + " is ignored because the game goal is " + goal.toString());
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user