From b8a14fcffca639bf1a88666cce044b0b7984f3fe Mon Sep 17 00:00:00 2001 From: M_Viper Date: Fri, 27 Feb 2026 17:45:25 +0100 Subject: [PATCH] Update from Git Manager GUI --- .../java/de/fussball/plugin/game/Ball.java | 2 +- .../java/de/fussball/plugin/game/Game.java | 51 +++++++++---- .../placeholders/FussballPlaceholders.java | 72 +++++++++++-------- .../plugin/scoreboard/FussballScoreboard.java | 18 +++-- src/main/resources/plugin.yml | 2 +- 5 files changed, 95 insertions(+), 50 deletions(-) diff --git a/src/main/java/de/fussball/plugin/game/Ball.java b/src/main/java/de/fussball/plugin/game/Ball.java index e85f6fe..afd2f8b 100644 --- a/src/main/java/de/fussball/plugin/game/Ball.java +++ b/src/main/java/de/fussball/plugin/game/Ball.java @@ -129,7 +129,7 @@ public class Ball { if (entity == null || entity.isDead() || !active) return; Location ballLoc = entity.getLocation(); Vector dir = blendDirection(player, 0.65); - double power = cfg("ball.header-power", 1.3); + double power = cfg("gameplay.header-power", 1.3); dir.setY(Math.max(dir.getY(), -0.05)); dir.multiply(power); applyKick(dir, ballLoc, 0.85f); diff --git a/src/main/java/de/fussball/plugin/game/Game.java b/src/main/java/de/fussball/plugin/game/Game.java index b89117d..6009daf 100644 --- a/src/main/java/de/fussball/plugin/game/Game.java +++ b/src/main/java/de/fussball/plugin/game/Game.java @@ -352,6 +352,9 @@ public class Game { state = GameState.RUNNING; secondHalf = true; timeLeft = arena.getGameDuration() / 2; + // Nachspielzeit der 1. Halbzeit zurücksetzen + injuryTimeBuffer = 0; + inInjuryTime = false; // Seitenwechsel: Rotes Team → BlueSpawn, Blaues Team → RedSpawn for (UUID uuid : redTeam) { Player p = Bukkit.getPlayer(uuid); if (p != null) p.teleport(arena.getBlueSpawn()); } @@ -572,6 +575,7 @@ public class Game { // ════════════════════════════════════════════════════════════════════════ private void startGameLoop() { + if (gameTask != null) { gameTask.cancel(); gameTask = null; } gameTask = new BukkitRunnable() { public void run() { if (state != GameState.RUNNING && state != GameState.OVERTIME) return; @@ -841,18 +845,29 @@ public class Game { } private void checkPlayerBallInteraction() { - if (ball == null || !ball.isActive()) return; + if (ball == null || !ball.isActive() || ball.isHeld()) return; for (UUID uuid : allPlayers) { Player p = Bukkit.getPlayer(uuid); if (p == null) continue; - if (ball.getDistanceTo(p) < 1.5) { - if (throwInTeam != null && getTeam(p) != throwInTeam) continue; - lastKicker = p.getUniqueId(); - lastTouchTeam = getTeam(p); - kicks.merge(p.getUniqueId(), 1, Integer::sum); - throwInTeam = null; - ball.kick(p); + if (ball.getDistanceTo(p) >= 1.5) continue; + if (throwInTeam != null && getTeam(p) != throwInTeam) continue; + + // ── Rückpass-Regel für Torwarte ────────────────────────────────── + // Torwart im Auto-Kick: falls Ball vom Mitspieler per Fuß zugespielt → überspringen + if (isGoalkeeper(p) && isInOwnHalf(p)) { + UUID prev = lastKicker; + if (prev != null && !prev.equals(uuid)) { + Player prevPlayer = Bukkit.getPlayer(prev); + if (prevPlayer != null && getTeam(prevPlayer) == getTeam(p) && !lastKickWasHeader) { + continue; // Rückpass – auto-kick nicht ausführen + } + } } + + throwInTeam = null; + setLastKicker(uuid); // korrekt: nutzt setLastKicker statt direktem Feldzugriff + ball.kick(p); + break; // pro Tick max. 1 Auto-Kick } } @@ -1452,12 +1467,20 @@ public class Game { if (ball != null) ball.remove(); if (bossBar != null) { bossBar.removeAll(); bossBar = null; } outOfBoundsCountdown.clear(); - freekickLocation = null; - freekickTicks = 0; - throwInTeam = null; + headerCooldowns.clear(); + freekickLocation = null; + freekickTicks = 0; + throwInTeam = null; + injuryTimeBuffer = 0; + inInjuryTime = false; + lastKicker = null; + secondLastKicker = null; + lastKickWasHeader = false; // Persistente Statistiken speichern - boolean draw = winner == null || redScore == blueScore; + // BUG FIX: nach Elfmeter kann redScore == blueScore true sein obwohl ein Gewinner existiert. + // Einzig korrekte Quelle der Wahrheit ist das übergebene winner-Argument. + boolean draw = (winner == null); Map names = new HashMap<>(); for (UUID uuid : allPlayers) { Player p = Bukkit.getPlayer(uuid); if (p != null) names.put(uuid, p.getName()); } plugin.getStatsManager().flushKicks(kicks, names); @@ -1693,7 +1716,9 @@ public class Game { public Map getGoals() { return goals; } public Map getKicks() { return kicks; } public boolean isSecondHalf() { return secondHalf; } - public int getPenaltyRedGoals() { return penaltyRedGoals; } + public boolean isInInjuryTime() { return inInjuryTime; } + public int getInjuryTimeBuffer() { return injuryTimeBuffer; } + public int getPenaltyRedGoals() { return penaltyRedGoals; } public int getPenaltyBlueGoals() { return penaltyBlueGoals; } /** Gibt zurück welches Team gerade Einwurf/Ecke/Abstoß hat (null = jeder darf) */ public Team getThrowInTeam() { return throwInTeam; } diff --git a/src/main/java/de/fussball/plugin/placeholders/FussballPlaceholders.java b/src/main/java/de/fussball/plugin/placeholders/FussballPlaceholders.java index 6b9d260..64a928f 100644 --- a/src/main/java/de/fussball/plugin/placeholders/FussballPlaceholders.java +++ b/src/main/java/de/fussball/plugin/placeholders/FussballPlaceholders.java @@ -9,16 +9,20 @@ import org.bukkit.entity.Player; * PlaceholderAPI-Erweiterung für das Fußball-Plugin. * * Verfügbare Platzhalter: - * %fussball_goals% - Tore des Spielers (gesamt) - * %fussball_kicks% - Schüsse des Spielers (gesamt) - * %fussball_wins% - Siege des Spielers - * %fussball_losses% - Niederlagen des Spielers - * %fussball_draws% - Unentschieden des Spielers - * %fussball_games% - Gespielte Spiele des Spielers - * %fussball_winrate% - Siegquote in Prozent (z.B. "67.5") - * %fussball_ingame% - "true" / "false" – ob Spieler gerade im Spiel ist - * %fussball_arena% - Name der aktuellen Arena (oder "–") - * %fussball_score% - Aktueller Spielstand (z.B. "2 : 1") oder "–" + * %fussball_goals% - Tore des Spielers (gesamt) + * %fussball_owngoals% - Eigentore des Spielers + * %fussball_assists% - Vorlagen des Spielers + * %fussball_kicks% - Schüsse des Spielers (gesamt) + * %fussball_wins% - Siege des Spielers + * %fussball_losses% - Niederlagen des Spielers + * %fussball_draws% - Unentschieden des Spielers + * %fussball_games% - Gespielte Spiele des Spielers + * %fussball_winrate% - Siegquote in Prozent (z.B. "67.5") + * %fussball_ingame% - "true" / "false" – ob Spieler gerade im Spiel ist + * %fussball_arena% - Name der aktuellen Arena (oder "–") + * %fussball_score% - Aktueller Spielstand (z.B. "2 : 1") oder "–" + * %fussball_team% - Team des Spielers im aktuellen Spiel ("Rot"/"Blau"/"–") + * %fussball_injurytime% - Aktuelle Nachspielzeit in Sekunden (0 wenn keine) */ public class FussballPlaceholders extends PlaceholderExpansion { @@ -28,17 +32,10 @@ public class FussballPlaceholders extends PlaceholderExpansion { this.plugin = plugin; } - @Override - public String getIdentifier() { return "fussball"; } - - @Override - public String getAuthor() { return "M_Viper"; } - - @Override - public String getVersion() { return plugin.getDescription().getVersion(); } - - @Override - public boolean persist() { return true; } + @Override public String getIdentifier() { return "fussball"; } + @Override public String getAuthor() { return "M_Viper"; } + @Override public String getVersion() { return plugin.getDescription().getVersion(); } + @Override public boolean persist() { return true; } @Override public String onPlaceholderRequest(Player player, String identifier) { @@ -47,22 +44,35 @@ public class FussballPlaceholders extends PlaceholderExpansion { StatsManager.PlayerStats s = stats.getStats(player.getUniqueId()); return switch (identifier.toLowerCase()) { - case "goals" -> String.valueOf(s.goals); - case "kicks" -> String.valueOf(s.kicks); - case "wins" -> String.valueOf(s.wins); - case "losses" -> String.valueOf(s.losses); - case "draws" -> String.valueOf(s.draws); - case "games" -> String.valueOf(s.games); - case "winrate" -> String.format("%.1f", s.getWinRate()); - case "ingame" -> String.valueOf(plugin.getGameManager().isInGame(player)); - case "arena" -> { + case "goals" -> String.valueOf(s.goals); + case "owngoals" -> String.valueOf(s.ownGoals); + case "assists" -> String.valueOf(s.assists); + case "kicks" -> String.valueOf(s.kicks); + case "wins" -> String.valueOf(s.wins); + case "losses" -> String.valueOf(s.losses); + case "draws" -> String.valueOf(s.draws); + case "games" -> String.valueOf(s.games); + case "winrate" -> String.format("%.1f", s.getWinRate()); + case "ingame" -> String.valueOf(plugin.getGameManager().isInGame(player)); + case "arena" -> { var game = plugin.getGameManager().getPlayerGame(player); yield game != null ? game.getArena().getName() : "–"; } - case "score" -> { + case "score" -> { var game = plugin.getGameManager().getPlayerGame(player); yield game != null ? game.getRedScore() + " : " + game.getBlueScore() : "–"; } + case "team" -> { + var game = plugin.getGameManager().getPlayerGame(player); + if (game == null) yield "–"; + de.fussball.plugin.game.Team t = game.getTeam(player); + yield t != null ? t.getDisplayName() : "–"; + } + case "injurytime" -> { + var game = plugin.getGameManager().getPlayerGame(player); + yield (game != null && game.isInInjuryTime()) + ? String.valueOf(game.getInjuryTimeBuffer()) : "0"; + } default -> null; }; } diff --git a/src/main/java/de/fussball/plugin/scoreboard/FussballScoreboard.java b/src/main/java/de/fussball/plugin/scoreboard/FussballScoreboard.java index bdf1aa1..598eb59 100644 --- a/src/main/java/de/fussball/plugin/scoreboard/FussballScoreboard.java +++ b/src/main/java/de/fussball/plugin/scoreboard/FussballScoreboard.java @@ -64,14 +64,24 @@ public class FussballScoreboard { // Zeit / Status-Zeile switch (game.getState()) { case RUNNING, GOAL -> { - int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60; String half = game.isSecondHalf() ? "§72. HZ" : "§71. HZ"; - set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " " + half, l--); + if (game.isInInjuryTime()) { + int injMins = (int) Math.ceil(game.getInjuryTimeBuffer() / 60.0); + set(obj, "§c⏱ +" + injMins + "' §7Nachsp. " + half, l--); + } else { + int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60; + set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " " + half, l--); + } } case HALFTIME -> set(obj, "§6⏸ HALBZEIT", l--); case OVERTIME -> { - int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60; - set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " §6VL", l--); + if (game.isInInjuryTime()) { + int injMins = (int) Math.ceil(game.getInjuryTimeBuffer() / 60.0); + set(obj, "§c⏱ +" + injMins + "' §6VL Nachsp.", l--); + } else { + int m = game.getTimeLeft() / 60, s = game.getTimeLeft() % 60; + set(obj, "§e⏱ " + String.format("%02d:%02d", m, s) + " §6VL", l--); + } } case PENALTY -> set(obj, "§c⚽ ELFMETER R" + game.getPenaltyRedGoals() + ":B" + game.getPenaltyBlueGoals(), l--); case STARTING -> set(obj, "§e⏱ §6Startet gleich...", l--); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e03c412..fc02b88 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Fussball -version: 2.0.0 +version: 1.0.0 main: de.fussball.plugin.Fussball api-version: 1.21 author: M_Viper