WIP: ore nodes, catching rules, bee nest fix, smaller Deep Dark

Done and checked: surface and cave-floor ore nodes (companion mod
ore/OreNodes.kt), bigger and rarer underground veins; template with nodes
passed the world check and the island quick check (node self-tests).

Built, not yet tested: catching rules (catch rate falls with the level
gap to the trainer's strongest Pokemon, failed catch enrages, strong wild
Pokemon hunt weaker trainers; catching/, Fight or Flight config), bee
nests emptied when their bee is turned away.

In progress: the Deep Dark no longer fills the deepslate layer (split by
temperature: cold = Deep Dark, hot = basalt deltas, warm = ordinary caves;
world/biomes.json), zone layout regenerated; cave zone types added to
world/zones.json but tools/zone_spawns.py doesn't use them yet; template
not rebuilt for the new caves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
claudeandClaude Opus 5.5 committed 2026-10-30 15:44:17 +01:00
1 parent 362d06aa4b
commit 6361636da7
29 files changed
+1733 -357

No files matched your search

@@ -0,0 +1,54 @@
package dev.cobblesurvival.selftest
import dev.cobblesurvival.dev.OreVeins
import dev.cobblesurvival.ore.OreNodes
import dev.cobblesurvival.zone.Zones
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.gametest.framework.GameTestAssertException
import net.minecraft.world.level.ChunkPos
/**
* Ore nodes on the island (Adrian, 2026-10-30): a surface node is a small lump of ore in the ground of its zone with
* open air above it; a cave node lies on the floor of its cave biome, touching the cave's air, not buried in a wall.
* Each test places one node on purpose near its zone's sample point and checks it as Regenerating Ore Veins tracks it.
*/
object OreNodeTests {
fun all() = listOf(
SelfTestCase("surface_nodes_lie_in_the_ground", 20, { s -> nodeTest(s, "button_isle", cave = false) }, islandOnly = true),
SelfTestCase("cave_nodes_lie_on_the_cave_floor", 20, { s -> nodeTest(s, "deep_dark", cave = true) }, islandOnly = true),
)
private fun nodeTest(s: Scenario, zone: String, cave: Boolean) {
val level = s.level
val node = OreNodes.nodes.firstOrNull { it.zone == zone && it.cave == cave }
?: throw GameTestAssertException("no ${if (cave) "cave" else "surface"} node kind in $zone")
val sample = Zones.samples[zone] ?: throw GameTestAssertException("no sample point for $zone")
val home = ChunkPos(BlockPos(sample.x, 0, sample.z))
// Next to the sample chunk first (the guardian stands on the sample point), then around it.
val chunks = listOf(ChunkPos(home.x + 2, home.z)) + (-1..1).flatMap { dx -> (-1..1).map { dz -> ChunkPos(home.x + dx, home.z + dz) } }
val grounds = chunks.asSequence()
.onEach { level.getChunk(it.x, it.z) }
.map { OreNodes.fill(level, it, only = node, force = true) }
.firstOrNull { it.isNotEmpty() }
?: throw GameTestAssertException("no spot for a ${node.vein} near $zone's sample point")
for (ground in grounds) {
val blocks = BlockPos.betweenClosed(ground.offset(-node.radius - 1, -node.radius - 1, -node.radius - 1),
ground.offset(node.radius + 1, node.radius + 1, node.radius + 1))
.map { it.immutable() }
.filter { OreVeins.veinAt(level, it) == node.vein }
s.check(blocks.isNotEmpty()) { "the ${node.vein} at ${ground.toShortString()} isn't tracked by Regenerating Ore Veins" }
val exposed = blocks.any { block -> Direction.entries.any { level.getBlockState(block.relative(it)).isAir } }
s.check(exposed) { "the ${node.vein} at ${ground.toShortString()} touches no air: it's buried" }
if (cave) {
s.check(level.getBiome(ground.above()).`is`(node.biome!!)) { "the ${node.vein} at ${ground.toShortString()} isn't in ${node.biome}" }
} else {
val top = blocks.maxBy { it.y }
s.check(level.canSeeSky(top.above())) { "the ${node.vein} at ${ground.toShortString()} is under cover" }
s.check(blocks.all { Zones.at(level, it)?.id == zone }) { "the ${node.vein} at ${ground.toShortString()} reaches out of $zone" }
}
}
s.helper.succeed()
}
}