package tc.oc.pgm.tracker.damage; import javax.annotation.Nullable; import org.bukkit.Location; import tc.oc.commons.core.inspect.Inspectable; import tc.oc.pgm.match.MatchPlayer; import tc.oc.pgm.match.ParticipantState; import tc.oc.pgm.time.TickTime; public class FallState extends Inspectable.Impl implements FallInfo { // A player must leave the ground within this many ticks of being attacked for // the fall to be caused by knockback from that attack public static final long MAX_KNOCKBACK_TICKS = 20; // A player's fall is cancelled if they are on the ground continuously for more than this many ticks public static final long MAX_ON_GROUND_TICKS = 10; // A player's fall is cancelled if they touch the ground more than this many times public static final long MAX_GROUND_TOUCHES = 2; // A player's fall is cancelled if they are in water for more than this many ticks public static final long MAX_SWIMMING_TICKS = 20; // A player's fall is cancelled if they are climbing something for more than this many ticks public static final long MAX_CLIMBING_TICKS = 10; @Inspect final public MatchPlayer victim; @Inspect final public Location origin; // The kind of attack that initiated the fall @Inspect final public From from; @Inspect final public TrackerInfo cause; @Inspect final public TickTime startTime; // Where they land.. this is set when the fall ends @Inspect public To to; // If the player is on the ground when attacked, this is initially set false and later set true when they leave // the ground within the allowed time window. If the player is already in the air when attacked, this is set true. // This is used to distinguish the initial knockback/spleef from ground touches that occur during the fall. @Inspect public boolean isStarted; // Set true when the fall is over and no further processing should be done @Inspect public boolean isEnded; // Time the player last transitioned from off-ground to on-ground @Inspect public long onGroundTick; // The player's most recent swimming state and the time it was last set true @Inspect public boolean isSwimming; @Inspect public long swimmingTick; // The player's most recent climbing state and the time it was last set true @Inspect public boolean isClimbing; @Inspect public long climbingTick; // The player's most recent in-lava state and the time it was last set true @Inspect public boolean isInLava; @Inspect public long inLavaTick; // The number of times the player has touched the ground during since isFalling was set true @Inspect public int groundTouchCount; public FallState(MatchPlayer victim, From from, TrackerInfo cause) { this.victim = victim; this.from = from; this.cause = cause; this.startTime = victim.getMatch().getClock().now(); this.origin = victim.getBukkit().getLocation(); } @Override public @Nullable ParticipantState getAttacker() { if(cause instanceof OwnerInfo) { return ((OwnerInfo) cause).getOwner(); } else if(cause instanceof DamageInfo) { return ((DamageInfo) cause).getAttacker(); } else { return null; } } @Override public Location getOrigin() { return origin; } @Override public From getFrom() { return from; } @Override public To getTo() { return to; } @Override public TrackerInfo getCause() { return cause; } /** * Check if the victim of this fall is current supported by any solid blocks, water, or ladders */ public boolean isSupported() { return this.isClimbing || this.isSwimming || victim.getBukkit().isOnGround(); } /** * Check if the victim has failed to become unsupported quickly enough after the fall began */ public boolean isExpired(TickTime now) { return this.isSupported() && now.tick - startTime.tick > MAX_KNOCKBACK_TICKS; } /** * Check if this fall has ended safely, which is true if the victim is not in lava and any of the following are true: * * - victim has been on the ground for MAX_ON_GROUND_TICKS * - victim has touched the ground MAX_GROUND_TOUCHES times * - victim has been in water for MAX_SWIMMING_TICKS * - victim has been on a ladder for MAX_CLIMBING_TICKS */ public boolean isEndedSafely(TickTime now) { return !this.isInLava && ((victim.getBukkit().isOnGround() && (now.tick - onGroundTick > MAX_ON_GROUND_TICKS || groundTouchCount > MAX_GROUND_TOUCHES)) || (isSwimming && now.tick - swimmingTick > MAX_SWIMMING_TICKS) || (isClimbing && now.tick - climbingTick > MAX_CLIMBING_TICKS)); } }