205 lines
6.8 KiB
Java
205 lines
6.8 KiB
Java
package tc.oc.pgm.spawns.states;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import org.bukkit.GameMode;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Sound;
|
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
|
import org.bukkit.event.player.PlayerRespawnEvent;
|
|
import org.bukkit.potion.PotionEffect;
|
|
import org.bukkit.potion.PotionEffectType;
|
|
import tc.oc.commons.bukkit.freeze.FrozenPlayer;
|
|
import tc.oc.pgm.classes.ClassMatchModule;
|
|
import tc.oc.pgm.events.MatchPlayerDeathEvent;
|
|
import tc.oc.pgm.events.PlayerChangePartyEvent;
|
|
import tc.oc.pgm.itemkeep.ItemKeepPlayerFacet;
|
|
import tc.oc.pgm.killreward.KillRewardMatchModule;
|
|
import tc.oc.pgm.kits.Kit;
|
|
import tc.oc.pgm.kits.KitPlayerFacet;
|
|
import tc.oc.pgm.match.Competitor;
|
|
import tc.oc.pgm.match.MatchPlayer;
|
|
import tc.oc.pgm.match.ParticipantState;
|
|
import tc.oc.pgm.mutation.MutationMatchModule;
|
|
import tc.oc.pgm.mutation.types.KitMutation;
|
|
import tc.oc.pgm.spawns.Spawn;
|
|
import tc.oc.pgm.spawns.events.ParticipantDespawnEvent;
|
|
import tc.oc.pgm.spawns.events.ParticipantReleaseEvent;
|
|
import tc.oc.pgm.spawns.events.ParticipantSpawnEvent;
|
|
|
|
/**
|
|
* Player is alive and participating
|
|
*/
|
|
public class Alive extends Participating {
|
|
|
|
protected final Spawn spawn;
|
|
protected final Location location;
|
|
private @Nullable FrozenPlayer frozenPlayer;
|
|
|
|
public Alive(MatchPlayer player, Spawn spawn, Location location) {
|
|
super(player);
|
|
this.spawn = spawn;
|
|
this.location = location;
|
|
}
|
|
|
|
@Override
|
|
public void enterState() {
|
|
super.enterState();
|
|
|
|
player.reset();
|
|
player.setSpawned(true);
|
|
player.refreshInteraction();
|
|
|
|
// Fire Bukkit's event
|
|
PlayerRespawnEvent respawnEvent = new PlayerRespawnEvent(player.getBukkit(), location, false);
|
|
player.getMatch().callEvent(respawnEvent);
|
|
|
|
// Fire our event
|
|
ParticipantSpawnEvent spawnEvent = new ParticipantSpawnEvent(player, respawnEvent.getRespawnLocation());
|
|
player.getMatch().callEvent(spawnEvent);
|
|
|
|
// Teleport the player
|
|
player.getBukkit().teleport(spawnEvent.getLocation());
|
|
|
|
// Return kept items
|
|
// TODO: Module should do this itself, maybe from ParticipantSpawnEvent
|
|
player.facetMaybe(ItemKeepPlayerFacet.class)
|
|
.ifPresent(ItemKeepPlayerFacet::restoreKeptInventory);
|
|
|
|
player.setVisible(true);
|
|
player.refreshVisibility();
|
|
bukkit.setGameMode(GameMode.SURVIVAL);
|
|
|
|
// Apply spawn kit
|
|
for(Kit kit : smm.getPlayerKits()) {
|
|
player.facet(KitPlayerFacet.class).applyKit(kit, false);
|
|
}
|
|
spawn.applyKit(player);
|
|
|
|
// Apply class kit(s)
|
|
// TODO: Module should do this itself, maybe from ParticipantSpawnEvent
|
|
match.module(ClassMatchModule.class).ifPresent(cmm -> cmm.giveClassKits(player));
|
|
|
|
// Give kill rewards earned while dead
|
|
// TODO: Module should do this itself, maybe from ParticipantSpawnEvent
|
|
match.module(KillRewardMatchModule.class).ifPresent(krmm -> krmm.giveDeadPlayerRewards(player));
|
|
|
|
// Apply kit injections from KitMutationModules
|
|
match.module(MutationMatchModule.class)
|
|
.ifPresent(mmm -> mmm.mutationModules().stream()
|
|
.filter(mm -> mm instanceof KitMutation)
|
|
.forEach(mm -> ((KitMutation) mm).apply(player)));
|
|
|
|
player.getBukkit().updateInventory();
|
|
|
|
if(match.hasStarted()) {
|
|
match.callEvent(new ParticipantReleaseEvent(player, false));
|
|
} else {
|
|
frozenPlayer = freezer.freeze(bukkit);
|
|
}
|
|
}
|
|
|
|
private boolean thaw() {
|
|
if(frozenPlayer != null) {
|
|
frozenPlayer.thaw();
|
|
frozenPlayer = null;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
|
|
if(match.hasStarted()) {
|
|
if(thaw()) {
|
|
match.callEvent(new ParticipantReleaseEvent(player, true));
|
|
}
|
|
} else if(!canSpawn()) {
|
|
transition(new Observing(player, true, false));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void leaveState() {
|
|
match.callEvent(new ParticipantDespawnEvent(player, player.getBukkit().getLocation()));
|
|
thaw();
|
|
super.leaveState();
|
|
}
|
|
|
|
@Override
|
|
public void onEvent(PlayerChangePartyEvent event) {
|
|
super.onEvent(event);
|
|
|
|
if(event.getNewParty() instanceof Competitor) {
|
|
transition(new Joining(player));
|
|
} else {
|
|
transition(new Observing(player, true, true));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onEvent(PlayerDeathEvent event) {
|
|
// Prevent default death, but allow item drops
|
|
forceAlive();
|
|
}
|
|
|
|
@Override
|
|
public void onEvent(MatchPlayerDeathEvent event) {
|
|
if(!event.isPredicted()) {
|
|
die(event.getKiller());
|
|
}
|
|
}
|
|
|
|
public void die(@Nullable ParticipantState killer) {
|
|
player.setDead(true);
|
|
|
|
// Setting a player's gamemode resets their fall distance.
|
|
// We need the fall distance for the death message.
|
|
// We set the fall distance back to 0 when we refresh the player.
|
|
float fallDistance = bukkit.getFallDistance();
|
|
bukkit.setGameMode(GameMode.CREATIVE);
|
|
bukkit.setFallDistance(fallDistance);
|
|
|
|
playDeathEffect(killer);
|
|
|
|
transition(new Dead(player));
|
|
}
|
|
|
|
private void playDeathEffect(@Nullable ParticipantState killer) {
|
|
playDeathSound(killer);
|
|
|
|
// negative health boost potions sometimes change max health
|
|
for(PotionEffect effect : bukkit.getActivePotionEffects()) {
|
|
// Keep speed and NV for visual continuity
|
|
if(effect.getType() != null &&
|
|
!PotionEffectType.NIGHT_VISION.equals(effect.getType()) &&
|
|
!PotionEffectType.SPEED.equals(effect.getType())) {
|
|
|
|
bukkit.removePotionEffect(effect.getType());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void playDeathSound(@Nullable ParticipantState killer) {
|
|
Location death = player.getBukkit().getLocation();
|
|
|
|
for(MatchPlayer listener : player.getMatch().getPlayers()) {
|
|
if(listener == player) {
|
|
// Own death is normal pitch, full volume
|
|
listener.playSound(Sound.ENTITY_IRONGOLEM_DEATH);
|
|
} else if(killer != null && killer.isPlayer(listener)) {
|
|
// Kill is higher pitch, quieter
|
|
listener.playSound(Sound.ENTITY_IRONGOLEM_DEATH, 0.75f, 4f / 3f);
|
|
} else if(listener.getParty() == player.getParty()) {
|
|
// Ally death is a shorter sound
|
|
listener.playSound(Sound.ENTITY_IRONGOLEM_HURT, death);
|
|
} else {
|
|
// Enemy death is higher pitch
|
|
listener.playSound(Sound.ENTITY_IRONGOLEM_HURT, death, 1, 4f / 3f);
|
|
}
|
|
}
|
|
}
|
|
}
|