package tc.oc.pgm.start; import java.time.Duration; 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.boss.BarColor; import org.bukkit.entity.Player; import tc.oc.commons.core.chat.Component; import tc.oc.commons.core.util.Comparables; import tc.oc.pgm.match.Match; import tc.oc.pgm.match.MatchState; import tc.oc.pgm.teams.Team; import tc.oc.pgm.teams.TeamMatchModule; import static com.google.common.base.Preconditions.checkNotNull; /** * Countdown to team huddle, or match start if huddle is disabled */ public class StartCountdown extends PreMatchCountdown { // At this duration before match start, broadcast a warning if teams will be auto-balanced private static final Duration BALANCE_WARNING_TIME = Duration.ofSeconds(15); // TODO: Avoid coupling to the team module, either by subclassing this countdown, // or implementing some kind of countdown listener system. private final @Nullable TeamMatchModule tmm; private final StartMatchModule smm; private final Duration huddle; private boolean autoBalanced, balanceWarningSent; protected final boolean forced; public StartCountdown(Match match, boolean forced, Duration huddle) { super(match); this.huddle = checkNotNull(huddle); this.forced = forced; this.smm = match.needMatchModule(StartMatchModule.class); this.tmm = match.getMatchModule(TeamMatchModule.class); } protected boolean willHuddle() { return Comparables.greaterThan(huddle, Duration.ZERO); } @Override public BaseComponent barText(Player viewer) { return new Component(new TranslatableComponent("countdown.matchStart.message", secondsRemaining(ChatColor.DARK_RED)), ChatColor.GREEN); } @Override public BarColor barColor(Player viewer) { return BarColor.GREEN; } @Override public @Nullable Duration timeUntilMatchStart() { return remaining == null ? null : remaining.plus(huddle); } @Override public void onStart(Duration remaining, Duration total) { super.onStart(remaining, total); match.ensureState(MatchState.Starting); this.autoBalanced = false; } @Override @SuppressWarnings("deprecation") public void onTick(Duration remaining, Duration total) { super.onTick(remaining, total); if(remaining.getSeconds() >= 1 && remaining.getSeconds() <= 3) { // Auto-balance runs at match start as well, but try to run it a few seconds in advance if(this.tmm != null && !this.autoBalanced) { this.autoBalanced = true; this.tmm.balanceTeams(); } } if(this.tmm != null && !this.autoBalanced && !this.balanceWarningSent && Comparables.lessOrEqual(remaining, BALANCE_WARNING_TIME)) { for(Team team : this.tmm.getTeams()) { if(team.isStacked()) { this.balanceWarningSent = true; this.getMatch().sendWarning(new TranslatableComponent("team.balanceWarning", team.getComponentName()), false); } } if(this.balanceWarningSent) { this.getMatch().playSound(COUNT_SOUND); } } } @Override public void onEnd(Duration total) { super.onEnd(total); if(this.tmm != null) this.tmm.balanceTeams(); if(willHuddle()) { match.countdowns().start(new HuddleCountdown(getMatch()), huddle); } else { match.transitionTo(MatchState.Running); } } @Override public void onCancel(Duration remaining, Duration total, boolean manual) { super.onCancel(remaining, total, manual); if(manual) { smm.setAutoStart(false); } match.ensureState(MatchState.Idle); } public boolean isForced() { return forced; } }