added difficulty curve and themed stages from overworld to the end
- jumps start easy (2-3 blocks, rarely sideways/upwards) and get harder over the first 1000 jumps up to the previous difficulty (3-4 blocks, often sideways/upwards) - block themes follow a full playthrough: meadow, forest, underground, caves, deepslate, nether portal, nether, fortress & bastion, stronghold, portal room, the end (from 1000) - title and sound when a new stage is reached - gold/diamond checkpoint markers unchanged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8e046c8603
commit
0faff2bd0c
2 files changed
+107
-13
No files matched your search
@@ -2,21 +2,80 @@ package eu.mhsl.minecraft.endlessjumper.generator;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Block-Themen entlang des Fortschritts: einmal durch das komplette Spiel,
|
||||
* von der Wiese über Untergrund, Nether und Stronghold bis ins End (ab Sprung 1000).
|
||||
*/
|
||||
public class BlockPalette {
|
||||
public static Block getRandom(int seed) {
|
||||
Random r = new Random(seed);
|
||||
ArrayList<Block> blocks = new ArrayList<>();
|
||||
public record Stage(int from, String name, List<Block> blocks) {
|
||||
}
|
||||
|
||||
blocks.add(Block.COPPER_BLOCK);
|
||||
blocks.add(Block.CUT_COPPER);
|
||||
blocks.add(Block.WEATHERED_COPPER);
|
||||
blocks.add(Block.WEATHERED_CUT_COPPER);
|
||||
blocks.add(Block.OXIDIZED_COPPER);
|
||||
blocks.add(Block.OXIDIZED_CUT_COPPER);
|
||||
public static final List<Stage> STAGES = List.of(
|
||||
new Stage(0, "Wiese", List.of(
|
||||
Block.GRASS_BLOCK, Block.GRASS_BLOCK, Block.MOSS_BLOCK, Block.PODZOL, Block.ROOTED_DIRT
|
||||
)),
|
||||
new Stage(75, "Wald", List.of(
|
||||
Block.OAK_LOG, Block.BIRCH_LOG, Block.SPRUCE_LOG, Block.CHERRY_LOG,
|
||||
Block.OAK_LEAVES, Block.BIRCH_LEAVES, Block.SPRUCE_LEAVES, Block.CHERRY_LEAVES
|
||||
)),
|
||||
new Stage(150, "Untergrund", List.of(
|
||||
Block.DIRT, Block.COARSE_DIRT, Block.STONE, Block.STONE, Block.ANDESITE,
|
||||
Block.GRANITE, Block.DIORITE, Block.COBBLESTONE
|
||||
)),
|
||||
new Stage(250, "Höhlen", List.of(
|
||||
Block.STONE, Block.COAL_ORE, Block.IRON_ORE, Block.COPPER_ORE,
|
||||
Block.GOLD_ORE, Block.REDSTONE_ORE, Block.LAPIS_ORE
|
||||
)),
|
||||
new Stage(350, "Tiefenschiefer", List.of(
|
||||
Block.DEEPSLATE, Block.DEEPSLATE, Block.TUFF, Block.DEEPSLATE_DIAMOND_ORE,
|
||||
Block.DEEPSLATE_IRON_ORE, Block.AMETHYST_BLOCK
|
||||
)),
|
||||
new Stage(450, "Netherportal", List.of(
|
||||
Block.OBSIDIAN, Block.OBSIDIAN, Block.CRYING_OBSIDIAN
|
||||
)),
|
||||
new Stage(475, "Nether", List.of(
|
||||
Block.NETHERRACK, Block.NETHERRACK, Block.CRIMSON_NYLIUM, Block.WARPED_NYLIUM,
|
||||
Block.SOUL_SOIL, Block.GLOWSTONE, Block.NETHER_QUARTZ_ORE, Block.NETHER_GOLD_ORE
|
||||
)),
|
||||
new Stage(625, "Festung & Bastion", List.of(
|
||||
Block.NETHER_BRICKS, Block.RED_NETHER_BRICKS, Block.BLACKSTONE,
|
||||
Block.POLISHED_BLACKSTONE_BRICKS, Block.GILDED_BLACKSTONE, Block.BASALT
|
||||
)),
|
||||
new Stage(750, "Stronghold", List.of(
|
||||
Block.STONE_BRICKS, Block.MOSSY_STONE_BRICKS, Block.CRACKED_STONE_BRICKS,
|
||||
Block.CHISELED_STONE_BRICKS, Block.BOOKSHELF
|
||||
)),
|
||||
new Stage(925, "Portalraum", List.of(
|
||||
Block.END_PORTAL_FRAME, Block.END_PORTAL_FRAME.withProperty("eye", "true"),
|
||||
Block.STONE_BRICKS, Block.MOSSY_STONE_BRICKS
|
||||
)),
|
||||
new Stage(1000, "End", List.of(
|
||||
Block.END_STONE, Block.END_STONE, Block.END_STONE_BRICKS,
|
||||
Block.PURPUR_BLOCK, Block.PURPUR_PILLAR, Block.OBSIDIAN
|
||||
))
|
||||
);
|
||||
|
||||
return blocks.get(r.nextInt(0, blocks.size()));
|
||||
public static Stage stageAt(int index) {
|
||||
Stage current = STAGES.getFirst();
|
||||
for(Stage stage : STAGES) {
|
||||
if(index >= stage.from()) current = stage;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/** Liefert die Stufe, die genau bei diesem Index beginnt, sonst null. */
|
||||
public static Stage stageStartingAt(int index) {
|
||||
for(Stage stage : STAGES) {
|
||||
if(stage.from() == index) return stage;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Block getRandom(int index, Random random) {
|
||||
List<Block> blocks = stageAt(index).blocks();
|
||||
return blocks.get(random.nextInt(blocks.size()));
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ public class JumpGenerator {
|
||||
|
||||
private final int preview = 2;
|
||||
|
||||
private static final int FULL_DIFFICULTY_AT = 1000;
|
||||
|
||||
|
||||
public JumpGenerator(Pos starting, Player player, InstanceContainer world) {
|
||||
this.player = player;
|
||||
@@ -45,8 +47,9 @@ public class JumpGenerator {
|
||||
this.player.setLevel((this.blocks.size()-this.preview-1));
|
||||
|
||||
Random r = new Random();
|
||||
Pos target = blocks.get(blocks.size()-1).add(r.nextInt(-1, 2), r.nextInt(this.player.getPosition().y() < 80 ? 0 : -1, this.player.getPosition().y() > 120 ? 1 : 2), r.nextInt(3, 5));
|
||||
this.world.setBlock(target, isHundredth ? Block.DIAMOND_BLOCK : isTenth ? Block.GOLD_BLOCK : BlockPalette.getRandom((this.blocks.size() / 10)));
|
||||
int index = this.blocks.size();
|
||||
Pos target = blocks.get(blocks.size()-1).add(this.nextOffset(index, r));
|
||||
this.world.setBlock(target, isHundredth ? Block.DIAMOND_BLOCK : isTenth ? Block.GOLD_BLOCK : BlockPalette.getRandom(index, r));
|
||||
|
||||
if(standingTenth) {
|
||||
Pos current = this.blocks.get(this.blocks.size()-this.preview-1);
|
||||
@@ -55,6 +58,12 @@ public class JumpGenerator {
|
||||
this.player.showTitle(Title.title(Component.text(""), Component.text("Checkpoint", TextColor.color(0, 255, 0))));
|
||||
this.player.sendPacket(new ParticlePacket(Particle.CRIT, current, current.add(0.5), 1.5f, 50));
|
||||
}
|
||||
|
||||
BlockPalette.Stage reachedStage = BlockPalette.stageStartingAt(this.blocks.size()-this.preview-1);
|
||||
if(reachedStage != null && reachedStage.from() > 0) {
|
||||
this.player.playSound(Sound.sound(SoundEvent.UI_TOAST_CHALLENGE_COMPLETE, Sound.Source.MASTER, 0.4f, 1f));
|
||||
this.player.showTitle(Title.title(Component.text(reachedStage.name(), TextColor.color(255, 170, 0)), Component.text("")));
|
||||
}
|
||||
this.world.setBlock(target.add(0, 1 ,0), Block.LIGHT);
|
||||
this.blocks.add(target);
|
||||
this.player.sendPacket(new ParticlePacket(Particle.CRIT, target, target.add(0.5), 1, 10));
|
||||
@@ -62,6 +71,32 @@ public class JumpGenerator {
|
||||
this.combo++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstand zum nächsten Block. Die Schwierigkeit steigt über die ersten {@link #FULL_DIFFICULTY_AT}
|
||||
* Sprünge von leicht (2–3 weit, kaum seitlich/aufwärts) bis zum bisherigen Niveau (3–4 weit,
|
||||
* oft seitlich und aufwärts) und bleibt danach dort.
|
||||
*/
|
||||
private Pos nextOffset(int index, Random r) {
|
||||
double difficulty = Math.min(1.0, (double) index / FULL_DIFFICULTY_AT);
|
||||
|
||||
int dz = 2;
|
||||
if(r.nextDouble() < 0.5 + 0.5 * difficulty) dz++;
|
||||
if(r.nextDouble() < 0.5 * difficulty) dz++;
|
||||
|
||||
int dx = r.nextDouble() < 0.1 + 0.57 * difficulty ? (r.nextBoolean() ? 1 : -1) : 0;
|
||||
|
||||
double y = this.player.getPosition().y();
|
||||
double roll = r.nextDouble();
|
||||
int dy = 0;
|
||||
if(roll < 0.05 + 0.28 * difficulty && y <= 120) dy = 1;
|
||||
else if(roll > 1 - (0.2 + 0.13 * difficulty) && y >= 80) dy = -1;
|
||||
|
||||
// weite Diagonalsprünge nach oben erst gegen Ende
|
||||
if(dy == 1 && dz == 4 && dx != 0 && difficulty < 0.7) dx = 0;
|
||||
|
||||
return new Pos(dx, dy, dz);
|
||||
}
|
||||
|
||||
public Pos getNextLanding() {
|
||||
return this.blocks.get(this.blocks.size()-(preview+1));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user