package tc.oc.pgm.spawns.states;
import javax.inject.Inject;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import tc.oc.commons.bukkit.event.CoarsePlayerMoveEvent;
import tc.oc.commons.bukkit.freeze.PlayerFreezer;
import tc.oc.commons.core.util.Comparables;
import tc.oc.pgm.events.MatchBeginEvent;
import tc.oc.pgm.events.MatchEndEvent;
import tc.oc.pgm.events.MatchPlayerDeathEvent;
import tc.oc.pgm.events.ObserverInteractEvent;
import tc.oc.pgm.events.PlayerChangePartyEvent;
import tc.oc.pgm.match.Match;
import tc.oc.pgm.match.MatchPlayer;
import tc.oc.pgm.spawns.RespawnOptions;
import tc.oc.pgm.spawns.SpawnMatchModule;
import tc.oc.pgm.start.PreMatchCountdown;
public abstract class State {
@Inject protected static PlayerFreezer freezer; // HACK
protected final Match match;
protected final SpawnMatchModule smm;
protected final RespawnOptions options;
protected final MatchPlayer player;
protected final Player bukkit;
private boolean entered, exited;
public State(MatchPlayer player) {
this.match = player.getMatch();
this.smm = match.needMatchModule(SpawnMatchModule.class);
this.player = player;
this.bukkit = player.getBukkit();
this.options = smm.getRespawnOptions(player.playerState());
}
public boolean isCurrent() {
return entered && !exited;
}
public void enterState() {
if(exited) {
throw new IllegalStateException("Tried to enter already exited state " + this);
} else if(entered) {
throw new IllegalStateException("Tried to enter already entered state " + this);
}
entered = true;
}
/**
*/
public void leaveState() {
if(!entered) {
throw new IllegalStateException("Tried to leave state before entering " + this);
} else if(exited) {
throw new IllegalStateException("Tried to leave already exited state " + this);
}
exited = true;
}
protected void transition(State newState) {
smm.transition(player, newState);
}
protected void forceAlive() {
// Prevents the default death handling, in case a player manages to die
// while not in the Alive state, or without generating a PGMPlayerDeathEvent
// at all. This can happen from e.g. the /slay command.
//
// We also need to reset the max health to make sure we don't get an exception
// when setting the health. We can't just set health to max because max might
// be zero.
//
// TODO: Add a way to enumerate AttributeModifiers to the SportBukkit API
// and then remove them all here so we can always set max health.
bukkit.setMaxHealth(20);
final double maxHealth = bukkit.getMaxHealth();
if(maxHealth > 0) {
bukkit.setHealth(maxHealth);
} else {
smm.getMatch().getMap().getLogger().severe("Failed to set max health to a non-zero value, custom death screen will fail");
}
}
protected boolean canSpawn() {
return match.isRunning() || match.countdowns()
.countdown(PreMatchCountdown.class)
.filter(countdown -> Comparables.lessOrEqual(countdown.timeUntilMatchStart(),
smm.getRespawnOptions(player).freeze))
.isPresent();
}
public void onEvent(final PlayerDeathEvent event) {
forceAlive();
event.getDrops().clear();
}
public void tick() {}
/**
* Called only when oldParty and newParty are both non-null
*/
public void onEvent(final PlayerChangePartyEvent event) {}
public void onEvent(final MatchPlayerDeathEvent event) {}
public void onEvent(final InventoryClickEvent event) {}
public void onEvent(final ObserverInteractEvent event) {}
public void onEvent(final MatchBeginEvent event) {}
public void onEvent(final MatchEndEvent event) {}
public void onEvent(final CoarsePlayerMoveEvent event) {}
}