182 lines
5.9 KiB
Java
182 lines
5.9 KiB
Java
package tc.oc.pgm.spawns.states;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import net.md_5.bungee.api.ChatColor;
|
|
import net.md_5.bungee.api.chat.BaseComponent;
|
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
|
import tc.oc.api.docs.User;
|
|
import tc.oc.commons.bukkit.freeze.FrozenPlayer;
|
|
import tc.oc.commons.bukkit.nick.IdentityProvider;
|
|
import tc.oc.commons.bukkit.util.NMSHacks;
|
|
import tc.oc.commons.core.chat.Component;
|
|
import tc.oc.pgm.PGM;
|
|
import tc.oc.pgm.events.PlayerChangePartyEvent;
|
|
import tc.oc.pgm.match.Competitor;
|
|
import tc.oc.pgm.match.MatchPlayer;
|
|
import tc.oc.pgm.match.MatchScope;
|
|
import tc.oc.pgm.match.ParticipantState;
|
|
import tc.oc.pgm.spawns.Spawn;
|
|
import tc.oc.pgm.spawns.SpawnModule;
|
|
import tc.oc.pgm.spawns.events.DeathKitApplyEvent;
|
|
|
|
/**
|
|
* Player is waiting to respawn after dying in-game
|
|
*/
|
|
public class Dead extends Spawning {
|
|
private static final long CORPSE_ROT_TICKS = 15;
|
|
|
|
private final long deathTick;
|
|
private final @Nullable ParticipantState killer;
|
|
private boolean kitted, rotted;
|
|
private @Nullable FrozenPlayer frozenPlayer;
|
|
private BaseComponent title;
|
|
private final IdentityProvider identityProvider;
|
|
|
|
public Dead(MatchPlayer player, @Nullable ParticipantState killer) {
|
|
this(player, killer, player.getMatch().getClock().now().tick);
|
|
}
|
|
|
|
public Dead(MatchPlayer player, @Nullable ParticipantState killer, long deathTick) {
|
|
super(player);
|
|
this.deathTick = deathTick;
|
|
this.killer = killer;
|
|
// TODO: This is really bad, but I'm not going to rewrite the entire state system to fix a single issue.
|
|
this.identityProvider = PGM.get().injector().getInstance(IdentityProvider.class);
|
|
}
|
|
|
|
@Override
|
|
public void enterState() {
|
|
super.enterState();
|
|
|
|
player.clearInventory();
|
|
bukkit.setGravity(true);
|
|
|
|
if(player.isVisible()) NMSHacks.playDeathAnimation(player.getBukkit());
|
|
|
|
if(!options.spectate) {
|
|
frozenPlayer = freezer.freeze(bukkit);
|
|
}
|
|
|
|
// Show red vignette
|
|
NMSHacks.showBorderWarning(player.getBukkit(), true);
|
|
|
|
// Flash/wobble the screen. If we don't delay this then the client glitches out
|
|
// when the player dies from a potion effect. I have no idea why it happens,
|
|
// but this fixes it. We could investigate a better fix at some point.
|
|
smm.getMatch().getScheduler(MatchScope.LOADED).createTask(() -> {
|
|
if(isCurrent() && bukkit.isOnline()) {
|
|
NMSHacks.sendDeathEffects(bukkit, options.blackout);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void leaveState() {
|
|
if(frozenPlayer != null) {
|
|
frozenPlayer.thaw();
|
|
frozenPlayer = null;
|
|
}
|
|
player.setDead(false);
|
|
NMSHacks.showBorderWarning(bukkit, false);
|
|
NMSHacks.clearDeathEffects(bukkit);
|
|
|
|
super.leaveState();
|
|
}
|
|
|
|
protected long age() {
|
|
return player.getMatch().getClock().now().tick - deathTick;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
long age = age();
|
|
|
|
if(!kitted && ticksUntilRespawn() <= 0) {
|
|
this.kitted = true;
|
|
// Give the player the team/class picker, after death has cleared their inventory
|
|
player.getMatch().callEvent(new DeathKitApplyEvent(player));
|
|
bukkit.updateInventory();
|
|
}
|
|
|
|
if(!rotted && age >= CORPSE_ROT_TICKS) {
|
|
this.rotted = true;
|
|
// Make player invisible after the death animation is complete
|
|
player.setVisible(false);
|
|
player.refreshVisibility();
|
|
}
|
|
|
|
super.tick(); // May transition to a different state, so call last
|
|
}
|
|
|
|
@Override
|
|
public void onEvent(PlayerChangePartyEvent event) {
|
|
super.onEvent(event);
|
|
if(!(event.getNewParty() instanceof Competitor)) {
|
|
transition(new Observing(player, true, false));
|
|
}
|
|
}
|
|
|
|
protected long ticksUntilRespawn() {
|
|
return Math.max(0, options.delayTicks - age());
|
|
}
|
|
|
|
@Override
|
|
public @Nullable Spawn chooseSpawn() {
|
|
if(ticksUntilRespawn() > 0) {
|
|
return null;
|
|
} else {
|
|
return super.chooseSpawn();
|
|
}
|
|
}
|
|
|
|
public void requestSpawn() {
|
|
if(player.getMatch().getClock().now().tick - deathTick >= SpawnModule.IGNORE_CLICKS_DELAY.toMillis() / 50) {
|
|
super.requestSpawn();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected BaseComponent getTitle() {
|
|
if(title == null) {
|
|
title = computeTitle();
|
|
}
|
|
return title;
|
|
}
|
|
|
|
protected BaseComponent computeTitle() {
|
|
String screen = "deathScreen.title";
|
|
if(killer != null) {
|
|
User killerUser = userStore.user(killer.getPlayerId()).orElse(null);
|
|
if (killerUser != null && identityProvider.currentIdentity(killerUser).isRevealed(this.player.getBukkit())) {
|
|
String key = killerUser.death_screen();
|
|
if(key != null && !key.equals("default")) {
|
|
screen = "death.screen." + key;
|
|
}
|
|
}
|
|
}
|
|
BaseComponent title = new TranslatableComponent(screen);
|
|
title.setColor(ChatColor.RED);
|
|
return title;
|
|
}
|
|
|
|
@Override
|
|
protected BaseComponent getSubtitle() {
|
|
long ticks = ticksUntilRespawn();
|
|
if(ticks > 0) {
|
|
return new TranslatableComponent(spawnRequested ? "death.respawn.confirmed.time"
|
|
: "death.respawn.unconfirmed.time",
|
|
new Component(String.format("%.1f", (ticks / (float) 20))).color(ChatColor.AQUA));
|
|
} else {
|
|
return super.getSubtitle();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onEvent(InventoryClickEvent event) {
|
|
super.onEvent(event);
|
|
event.setCancelled(true); // don't allow inventory changes when dead
|
|
}
|
|
}
|