LoParkour/src/main/java/dev/loki/loparkour/duels/SingleDuelsGenerator.java
loki5512344 5707cf2d24
feat: duels player colors + elytra sub-modes (M-level)
- Add ParkourGenerator.selectBlockData() hook (forced course material);
  BlockSelector checks it first; SingleDuelsGenerator overrides to use the
  player's color (16 concrete colors) and forces only DEFAULT block type
- Elytra sub-modes: SpeedDemonGenerator (max-speed score), MinSpeedGenerator
  (min-speed check, reset on 6 slow ticks), TimeTrialGenerator (score cap),
  CloseGenerator (FLAT rings); + SpeedDemon/MinSpeed/TimeTrial/Close modes,
  registration, locales play.elytra.*, config mode-settings.*
- Config.getDouble(path, default) + ConfigAccessor overload
- checkstyle 0/0, PMD 0, build green
2026-08-05 21:32:54 +02:00

108 lines
3.2 KiB
Java

package dev.loki.loparkour.duels;
import dev.loki.loparkour.generator.core.coordinator.ParkourGenerator;
import dev.loki.loparkour.mode.base.Mode;
import dev.loki.loparkour.mode.base.Modes;
import dev.loki.loparkour.player.core.ParkourPlayer;
import dev.loki.loparkour.session.core.Session;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* One parkour course per duels player, isolated from everyone else.
*
* <p>Scoring only looks at the owned player: {@link #getPlayers()} returns just
* the owned player, so {@code state.history}/{@code state.score} belong to that
* single course. The owning {@link DuelsGenerator} ticks every instance.</p>
*/
public class SingleDuelsGenerator extends ParkourGenerator {
private static final List<Material> COLORS = List.of(
Material.LIGHT_BLUE_CONCRETE, Material.RED_CONCRETE, Material.LIME_CONCRETE, Material.YELLOW_CONCRETE,
Material.ORANGE_CONCRETE, Material.BLUE_CONCRETE, Material.MAGENTA_CONCRETE, Material.WHITE_CONCRETE,
Material.LIGHT_GRAY_CONCRETE, Material.BLACK_CONCRETE, Material.GREEN_CONCRETE, Material.BROWN_CONCRETE,
Material.CYAN_CONCRETE, Material.PURPLE_CONCRETE, Material.GRAY_CONCRETE, Material.PINK_CONCRETE);
public DuelsGenerator owningGenerator;
private ParkourPlayer ownedPlayer;
private BlockData blockData;
private boolean won;
public SingleDuelsGenerator(@NotNull Session session) {
super(session);
forceDefaultBlocks();
}
@Override
public void reset(boolean regenerate) {
super.reset(regenerate);
forceDefaultBlocks();
}
/**
* Duels courses use only plain (non-special, non-schematic) blocks so the
* player's color is the only material on the course.
*/
private void forceDefaultBlocks() {
state.defaultChances.clear();
state.defaultChances.put(BlockGenerationType.DEFAULT, 1.0);
state.specialChances.clear();
}
public void setOwnedPlayer(@NotNull ParkourPlayer pp) {
this.ownedPlayer = pp;
}
public void setPlayerIndex(int index) {
this.blockData = COLORS.get(index % COLORS.size()).createBlockData();
}
@Override
public @NotNull BlockData selectBlockData() {
return blockData == null ? Material.STONE.createBlockData() : blockData;
}
@Override
@NotNull
public List<ParkourPlayer> getPlayers() {
return ownedPlayer == null ? List.of() : List.of(ownedPlayer);
}
@Override
public void startTick() {
}
@Override
public void tick() {
super.tick();
checkWin();
}
@Override
protected void score() {
super.score();
checkWin();
}
/**
* Duels has no persistent leaderboard; falling must not register anything.
*/
@Override
public void registerScore(String time, String difficulty, int score) {
}
private void checkWin() {
if (!won && owningGenerator != null && state.score >= owningGenerator.goal) {
won = true;
owningGenerator.win(ownedPlayer);
}
}
@Override
public Mode getMode() {
return Modes.DUELS;
}
}