Files
cobblemon-survival-pack/docs/design.md
T
claudeandClaude Opus 5.5 4e7b16abae Phase 7: one End boss at a time; more visible attack telegraphs
Adrian (2026-11-02): a second Eternatus appeared on his second visit
to the End; the attacks should be more visible.

- EndBoss waits until the entities around its spot are loaded before
  deciding it's missing, refuses a second copy while the recorded one
  is alive (join check, like the guardians), and removes extra copies
  near the spot (cleans up worlds that already have two).
- Telegraphs: 2.2-size dust redrawn every 2 ticks, the inside filled
  (Area.fill), rising sparks on the outline, a low bell on cast.
- Tests: no second End boss (after the End's middle is loaded), fill
  points inside their areas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 16:50:58 +01:00

65 KiB
Raw Blame History

Design notes

The roadmap (design pillars, phases, open decisions) is the source of truth for what to build. This file records how it was built and every decision taken on the way.

Decisions taken in Phase 0

Decision Why
Loader NeoForge 21.1.265 (latest 21.1 build on 2026-10-28) The roadmap's default. Not yet confirmed by Adrian
Cobblemon 1.8.4 instead of 1.8.3 1.8.4 came out 2026-10-27 (bug-fix release); every 1.8-aware addon accepts it
Companion mod builds with Cobblemon's official MDK (Architectury Loom), not the plain NeoForge MDK The roadmap says to take Cobblemon's coordinates from its official docs or addon template. That template is Loom-based and the coordinates (com.cobblemon:neoforge on artefacts.cobblemon.com) come from it
Kotlin 2.4.0 instead of the MDK's 2.2.20 Kotlin for Forge 5.12.0 ships stdlib 2.4.0, which the older compiler can't read
datapacks/core ships inside the companion mod as an always-on built-in data pack (top priority) Works in every world and on every server without copying files around. Its pack.mcmeta filter can later blank Cobblemon's base spawns (Phase 3). The data stays plain JSON in datapacks/core
Every mod .pw.toml carries both a Modrinth URL and CurseForge IDs where both exist (tools/crosslink.py) packwiz only records one source. Without the second one, an export to the other platform copies the jar into overrides/, which bundles a third-party jar
Mods hosted on one platform only are left out of the other platform's export Same rule: no bundling. See the platform split in docs/addon-status.md
Dev instance in Prism is synced with packwiz-installer from build/stage/full Gets every mod from both platforms, and re-syncing removes mods that left the pack. Prism is a Flatpak that can't read the repo folder, so the sync runs on the host
Companion mod id cobblesurvival, package dev.cobblesurvival Placeholder names, easy to rename while the mod is empty
No publishing for now (Adrian, 2026-10-28) The target is the Prism instance and a private server, which both get every mod. The platform split below only matters again for a public release (Phase 9). Mods may be chosen regardless of which platform hosts them

Decisions taken in Phase 1

Decision Why
World type cobblesurvival:island (our data pack) points WorldGen Editor at our own preset cobblesurvival_island Our preset is never confused with WorldGen Editor's bundled examples. Servers set level-type=cobblesurvival:island; the type is also listed in the singleplayer world-type button
Biome set = Adrian's list (2026-10-28): plains, forest, cherry grove, mangrove swamp, jungle, desert, badlands, "mountain edge", jagged peaks; caves: lush caves, dripstone caves, deep dark, basalt deltas Set in world/biomes.json. Ocean, deep ocean, lukewarm/warm ocean, river and beach stay, because an island needs a sea and a coast
The biome list is enforced by remapping vanilla's overworld biome table (from Minecraft's data generator) onto the list, written into the world type by tools/biome_layout.py Keeps vanilla's terrain–biome fit (peaks on peaks, swamps in lowlands) while only listed biomes can appear. Pure data. WorldGen Editor's own climate/exclusion options were rejected: they replace cave biomes with surface fallbacks such as snowy plains, and leak unlisted biomes
"Mountain edge" → windswept_hills (with snowy slopes and stony shore folded in) Mountain Edge was removed in 1.18; windswept hills is its successor. Flagged in case another biome was meant
Basalt deltas is an overworld cave biome under the hottest, driest land (where desert and badlands are), at cave depth like lush and dripstone caves Adrian's request. It keeps its own features (basalt columns, magma, lava deltas) and particles; its nether ores are removed with the rest
The Deep Dark no longer fills the deepslate layer (Adrian, 2026-10-30: "too much"; part of it should become basalt deltas). Vanilla puts it at depth 1.1 wherever erosion is low, at any temperature; world/biomes.json → split cuts it by the temperature of the land above: up to −0.1 Deep Dark, from 0.4 basalt deltas, in between ordinary caves of the land above Biome preview at y −52, share of land: Deep Dark 30 % → 14 %, basalt deltas 0 → 7 %, ordinary caves 9 %; at y −30 Deep Dark 18 % → 7 %. The deep basalt is part of the Basalt Furnace (Lv 55–70), so the deepest caves reach Lv 70 under hot land. The gaps between the pieces must be wide: Minecraft picks the nearest biome entry, and the land biome above is only 0.1 away in depth, so a narrow gap goes to the neighbouring piece
No Nether: the world type cobblesurvival:island defines only the overworld and the End Adrian's request. Portals can still be lit but lead nowhere. The smoke test checks that minecraft:the_nether is an unknown dimension
Island shaped like a Poké Ball (Adrian, 2026-10-28): a round island cut into top and bottom halves by a channel across the middle, with a ring channel around a round centre island where the spawn is. Written by tools/pokeball_preset.py (ball r 1,500, band 160, button r 280, ring 120 — placeholders) WorldGen Editor makes the round island; two flat-ended ocean entries cut the band and 36 overlapping ocean circles cut the ring. Entries have no climate or exclusions; biomes come from the remapped table
The seed is chosen by tools/seed_search.py, which scores many seeds with the op-only dev command /cobblesurvival biomepreview (samples the generator without generating chunks) With vanilla climate noise, which biomes land on a 1,500-block island depends on the seed. The search wants every listed biome at a useful share, few large patches, a gentle start area and all four cave biomes
Natural ore removed with data only, no extra mod: a NeoForge remove_features biome modifier for vanilla ores, zero-placement overrides for Cobblemon's evolution-stone ores, ore_veins_enabled: false in WorldGen Editor's noise settings Pillar 7 (data before code). Ore Generation Configuration was not needed. Cobblemon adds its ores from code as direct holders, which the biome modifier can't match, hence the overrides (found by the ore scan)
Structures and fossils place no ore either: tools/clean_structures.py appends a rule processor that turns ore into stone (raw ore blocks into tuff/terracotta, placeholders) to every processor list that places an ore-containing template or outputs ore Found by the ore scan of the first template: Cobblemon habitats/ruins have ore and raw ore blocks built into their templates, vanilla fossils have coal/diamond ore. Overriding the processor lists keeps the structures and only swaps those blocks
Nether fortresses and Nether ruined portals are kept out of the overworld: their biome tags list the Nether biomes except basalt deltas Basalt deltas is now an overworld cave biome, and these structures go wherever a Nether biome is. The first template had fortress pieces underground
Standard QOL mods (Adrian, 2026-10-28): JEI, Jade, Inventory Profiles Next, Mouse Tweaks, AppleSkin, Controlling, Xaero's Minimap + World Map; performance: Sodium, FerriteCore, ModernFix, ImmediatelyFast, Entity Culling JEI as the NEI successor, Jade as the block/mod probe, Inventory Profiles Next as the Inventory Tweaks successor. Flagged: a minimap and world map make exploring the island easier; drop them if exploration should stay harder. Xaero's radar can show mobs; restrict it in its config if that feels like cheating
The world template is generated by tools/make_world.py from world/world.json and kept out of git The world is several hundred MB. Seed + preset + mod versions reproduce it. Prism and the test server get it from build/world-template
Two test speeds (Adrian, 2026-10-28: 10 minutes was too long): tools/quick_check.py (one boot, smoke checks, /locate for removed structures, a sampled world around spawn and sample structures; about 75 s) for everyday changes, and tools/make_world.py (whole island, about 6 min) only when the island changes The template build pregenerates a circle that just covers the island instead of the whole square, and sets the border in the same server session
Chunky is used only while building the template; it is not in the pack It is a build tool. Pinned by URL and SHA-1 in world/world.json
Seed isle-26 approved (Adrian, 2026-10-28) Poké Ball, radius 1,500
No vanilla mobs, only Pokémon (Adrian, 2026-10-28): the companion mod (world/OnlyPokemon.kt) never lets a vanilla mob join a world unless it is loaded from a save (since Phase 3 any mob that isn't Cobblemon's, e.g. Cold Sweat's chameleons); exceptions go in the entity type tag cobblesurvival:allowed_vanilla_mobs (only the Ender Dragon for now). On top, every biome's vanilla spawn list is emptied (no_vanilla_spawns.json), infested stone doesn't generate (no_infested_stone.json) and the template has doMobSpawning false One rule covers mobs placed by structures during world generation (villagers, guardians, drowned, shulkers, ...), natural spawns, spawners and commands. Cobblemon spawns through its own spawner and isn't a vanilla mob, so Pokémon are unaffected. The data-pack and gamerule layers save the work of creating mobs only to block them. To undo: remove the listener, the two modifier files and the gamerule entry. A side effect: player-built golems and the Wither can't be summoned either
All structures stay, only their ore and vanilla mobs go (Adrian, 2026-10-28) Villages, ocean ruins, monuments, mineshafts, strongholds, trial chambers, ancient cities, Gimmighoul towers etc. generate as designed (igloos, witch huts and mansions can't, because their biomes are remapped away). Exception: ruined portals stay off, because Nether portals shouldn't generate at all
Mob sources in structures go when a chunk has just been generated (world/OnlyPokemon.kt): blocks in the tag cobblesurvival:removed_on_generation (spawner, trial spawner) become air, sculk shriekers can't summon the Warden, infested blocks become normal stone/bricks Stronghold, mineshaft and dungeon spawners and stronghold infested bricks are placed by game code, so data can't reach them. Chunks loaded from disk are never touched. The Deep Dark's own sculk patches can summon the Warden too, not only ancient cities. Trial chamber vaults stay but can't be opened, since trial keys come from trial spawners. tools/world_report.py fails a world that still has a spawner, trial spawner, infested block, summoning shrieker or vanilla mob
Nether portals don't form: the companion mod cancels portal creation while the server has no Nether dimension; ruined portals don't generate (their biome tags are empty) Adrian: portals formed but led nowhere. The check is on the dimension, so if the Nether ever comes back, portals work again. The smoke test lights an obsidian frame and expects no portal
Default keybinds without conflicts, shipped with Default Options (pack/config/defaultoptions/keybindings.txt) NeoForge's Controls screen flags any two keybinds on the same key, even a GUI-only one next to an in-game one. Changes: Cobblemon summary M→N and hide party O→Y; Xaero waypoints U→J, minimap settings unbound; Jade details Shift→V; JEI recipe R→G, bookmark A→K, search Ctrl+F→Ctrl+H, pause cycling Shift→Right Ctrl, search history unbound; KubeJS Kubedex unbound; FTB Quests: recenter Home, chapters ./,, search Ctrl+I, panning up/down and player prefs unbound, all quest-editor shortcuts unbound (pack authors rebind them in Controls → FTB Quests). JEI's mouse-click actions still share mouse buttons with attack/use by design. Check with tools/check_keybinds.py after adding a mod
Square vanilla world border around the land's bounding box, 96 blocks of sea margin (placeholder) The vanilla border can only be a square. On the island's shorter axis the gap to the coast is larger than 96 blocks. The border is measured from the large land masses only; icebergs, sea stacks and wrecks out at sea don't count

Decisions taken in Phase 2

Decision Why
Permadeath: CobbleHardcoreMon removes Pokémon that fainted in a battle when the battle ends; holding a Revival Charm (cobblesurvival:revival_charm, a KubeJS item) saves it once instead Roadmap pillar 2. The charm replaces the Totem of Undying (defaultconfigs/cobblehardcoremon/server.toml). Health Link off; Soul Link is opt-in per player and not used
The companion mod closes CobbleHardcoreMon's gaps (permadeath/Permadeath.kt): a Pokémon that faints outside a battle is settled at the end of the same tick; one that fainted in a battle and was revived before it ended is fainted again just before CobbleHardcoreMon looks; every second each online player's party and PC are swept for fainted Pokémon. A charm is any item in #cobblesurvival:revival_charms Found while writing the permadeath tests: CobbleHardcoreMon only looks once a second outside battles (time to heal a Pokémon or put it in the PC), waits 60 s for a Pokémon whose charm already saved it once, never looks at the PC, and skips a Pokémon that isn't fainted when the battle ends. With the companion mod's part switched off, charm_saves_once, fainted_in_pc and revived_during_battle fail (2026-10-29). Out-of-battle poison can knock a Pokémon out too (5 % HP now and then, no floor). Both mods use the same chat messages
A Revive used during a battle doesn't save a Pokémon that fainted in it (Adrian, 2026-10-29): it is gone when the battle ends Roadmap: a fainted Pokémon is deleted. Revives, Max Revives and Revival Blessing only help within that battle; Revives are mainly Revival Charm material. Adrian may later disable revive items in battles completely
No remote PC access: Cobblemon's /pc needs cheats (operator level 2) and is left as an admin tool; a PC opened at a block closes once the player is more than 10 blocks from it. No remote-PC mod is installed Roadmap Phase 2. Checked by the self-test no_remote_pc. Players on a server never have level 2; single-player worlds only with cheats on
Free movement in battle stays: nothing in the pack stops breaking, placing or walking during a battle Phase 7 boss fights need it. The self-test free_movement_in_battle checks the server side; Cobblemon's own key for leaving the battle screen is a manual check. A wild battle still ends if the player gets too far from the wild Pokémon (Cobblemon's flee distance)
In-game self-tests (/cobblesurvival selftest, tools/selftest.py, also run by tools/quick_check.py) on Minecraft's GameTest framework NeoForge only runs GameTests in a development environment, so the companion mod starts and ticks them itself on the real pack server. Fake players get a connection that accepts every mod channel. The command only exists with -Dcobblesurvival.selftest=true. Tests run in barrier-walled boxes 15×12×15 on a platform at y 200 above spawn; a wild Pokémon must have ticked once before a battle with it starts, or its side never picks a move
Cobblemon's faint timer is effectively infinite (defaultFaintTimer 1,000,000,000 s) Otherwise a fainted Pokémon wakes up on its own after 5 minutes, and staying in a battle that long would let it escape permadeath
No healing while sleeping: Cobblemon healPercent 0 Cobblemon only uses healPercent/healTimer while the player sleeps
Healing Machines are expensive (roadmap): a dearer recipe (gold, iron, a Max Revive and a diamond) and a four times slower recharge; values in docs/balance.md With loot chests handing out ingots (Adrian, 2026-10-29), Cobblemon's copper-and-iron recipe would be cheap early on. The recipe is replaced by KubeJS under the id cobblesurvival:healing_machine
Fight or Flight Reborn and TP-Pastures installed with default settings Tuning comes with the zones (Phase 3) and pastures (Phase 4)
Chest loot keeps its ore and ingots; every loot container refills with a new roll 1 hour after it was first opened (Adrian, 2026-10-29). Tiering loot by structure/biome comes later (lower priority) Done with Lootr (config/lootr-common.toml: refresh_all, refresh_value 72,000 ticks of game time). Loot is shared by all players (Adrian, 2026-10-30): every player joins the scoreboard team islanders (world/SharedLoot.kt) and Lootr's team_loot is on, so a container has one inventory for everybody. Cobblemon's gilded chests (Gimmighoul's hiding spots) aren't Lootr containers: their loot is rolled once, shared, and doesn't come back. This changes the roadmap's Phase 2 item "remove loot tables that hand out ore or ingots": chests are a second, renewable ore source next to the veins (pillar 3)
Lootr converts a vanilla loot chest once the 5×5 chunks around it are loaded, i.e. when a player is near, not during pregeneration So the template keeps vanilla loot chests until then. tools/quick_check.py force-loads the area around a sampled village and checks that its chests became Lootr chests
Matthiesen Core's usage statistics are off by default A pack shouldn't send data for its players without asking; players can switch it on in config/matthiesen_core/metrics.properties

Phase 3 zone plan (approved by Adrian, 2026-10-29)

Source of truth: world/zones.json; tools/zone_layout.py lays it onto the island and draws build/zone-map.png. The model is decided; levels, drops and guardians below are still placeholders (docs/balance.md).

A zone decides which Pokémon spawn and at what levels: Cobblemon's own spawn lists are switched off and each zone gets its own list, drawn from Cobblemon's spawn data for the zone's biomes.

Model. Zones are regions that follow the island's biome clusters. A biome with a hazard (jagged peaks, desert/badlands, mangrove swamp) or its own character (jungle) is its own zone wherever it lies, with small specks dropped. The forest and plains that fill the rest (65 % of the land) are split into regions by position. Rivers belong to the zone they run through; only the coast and the open sea are sea zones. Caves are zones by cave biome, everywhere under the island. Cold Sweat's heat and cold follow the biome anyway, so hazards and zones line up. Cobblemon spawn files can't express these shapes, so the companion mod will add a spawn condition "zone": "<id>" (Cobblemon's appendage API) that looks up a grid generated from this plan.

Zone Where Biomes Levels Hazard (gate) Signature drops (examples) Alpha guardian (example)
Button Isle the start island inside the ring channel (3.6 % of land) forest, plains, a little cherry grove and desert 2–10 none feathers, berries (Pidgey, Sentret, Bidoof) Pidgeotto, Lv 14
Southwold south half, west of the jungle and swamp (30 %) forest, plains, windswept hills 8–18 none wool (Wooloo, Mareep) for cold insulation later; bones, honey Dubwool, Lv 22
Westmarch north-west (18 %) forest, windswept hills 15–25 none raw copper (Cufant), charcoal (Vulpix) Ursaring, Lv 30
Verdant Jungle east, both sides of the band (9 %) jungle 18–30 none (warm and humid, below Cold Sweat's damage) vines, Big Root (Tangela), food (Tropius) Tangrowth, Lv 34
Mangrove Mire south-east (10 %) mangrove swamp 25–38 poison while in the swamp (companion mod area effect); Pecha berries, milk and potions help Black Sludge (Croagunk, Grimer), Pecha berries Toxicroak, Lv 42
Highland Meadows north-east around the peaks (20 %) plains, forest, cherry grove 25–35 none leather (Ponyta) for heat insulation, Hard Stone (Larvitar) Rapidash, Lv 40
Sunscorch the desert and badlands pockets: north of the ring channel, the north-east and north-west coasts (3.4 %) desert, badlands 30–45 heat (Cold Sweat): heat insulation, Fire Resistance potions armadillo scutes (Sandshrew), Soft Sand, magma cream (Numel) Hippowdon, Lv 50
Frostpeak Range the jagged peaks plus the windswept hills and cherry groves right next to them (6 %) jagged peaks 40–55 cold (Cold Sweat): wool insulation; warming food and potions Never-Melt Ice (Snover), Razor Claw (Sneasel) Abomasnow, Lv 60
Shallows coast and beaches ocean, lukewarm and warm ocean, beach 5–20 none fish, kelp none
Deep Sea ring and band channels, outer sea deep ocean 30–50 none Heart Scale-type rarities Lapras or Wailord, Lv 55
Lush Caves under the whole island lush caves 12–28 none glow berries, mushrooms (Paras) none
Dripstone Depths under the whole island dripstone caves 22–38 none Dragon Fang (Bagon, Gible) none
Deep Dark under the cold and temperate land, deep (since 2026-10-30) deep dark 45–60 darkness (vanilla sculk; no Warden) Sableye or Spiritomb, Lv 62
Basalt Furnace under the hottest land, at cave depth and (since 2026-10-30) down to the bottom basalt deltas 55–70 heat (Cold Sweat) raw iron (Durant), coal (Torkoal), blaze powder (Heatmor) Heatran-like boss later (Phase 7)

Order of play the bands suggest: Button Isle → Southwold → Westmarch or Jungle → Mire or Highlands → Sunscorch (heat) → Frostpeak (cold) → the deep caves.

What helps with a zone drops from the boss fight of the zone before it (Adrian, 2026-10-29). Wild Pokémon keep their normal drops (the "signature drops" column); the items a zone's hazard asks for come from the previous zone's Alpha guardian, so beating it is the way forward. Never a hard unlock: potions and golden apples still get a player through. Placeholder chain:

Boss of Helps with Drops (placeholder)
Button Isle Southwold Poké Balls, Potions
Southwold Westmarch, Verdant Jungle Great Balls, Exp. Candy
Westmarch, Verdant Jungle Mangrove Mire (poison) the material for wading gear that keeps the swamp's poison off, Pecha berries
Mangrove Mire, Highland Meadows Sunscorch (heat) Cold Sweat heat-insulation material
Sunscorch Frostpeak Range (cold) Cold Sweat cold-insulation material (the recipe also takes wool)
Frostpeak Range Deep Dark, Basalt Furnace Night Vision potions, more heat insulation

Decided with the plan (Adrian, 2026-10-29): the Sunscorch pocket just north of the start and the hot desert spots on Button Isle stay as an early taste of the heat; caves follow the cave biome everywhere, so the Deep Dark under the start island is Lv 45–60 too; the straight Westmarch/Highland Meadows border (x = −250) stays.

How zones are built (Phase 3, step 2):

  • tools/zone_layout.py writes the zone grid to datapacks/core/data/cobblesurvival/zones/island.json (24-block cells; caves by cave biome). The companion mod loads it (zone/Zones.kt) and adds the spawn-condition field "zone"/"zones" to every Cobblemon spawn condition. /cobblesurvival zone (operators) names the zone you stand in.
  • Cobblemon's own spawn files are switched off by a filter in datapacks/core/pack.mcmeta. tools/zone_spawns.py writes one spawn pool per zone (datapacks/core/data/cobblesurvival/spawn_pool_world/<zone>.json) from Cobblemon's spawn data: every evolution line that can spawn on the island gets one home zone (none is lost; legendaries, mythicals, Ultra Beasts and Paradox Pokémon stay out), and its levels are clamped into the zone's band, which picks the evolution stages; every stage that reaches the band spawns up to its top (Adrian, 2026-10-31; Cobblemon's own ranges stop where the next stage takes over, which left Dusclops at Lv 45–46 in the Deep Dark and the zone topping out at Lv 54). Wild Pokémon never evolve; a caught one past its evolution level evolves on its next level-up. Placement weighs how much of the zone is the line's habitat, how much of the line's range the zone covers, and the line's strength (base-stat total of its strongest form) against the zone's band. Lines that Cobblemon lets spawn nearly everywhere first fill the cave zones, which take those whose first stage's primary type fits the cave (world/zones.json → caves → types; Adrian, 2026-10-30: the deep caves' tables were too small), then are shared out over the land zones by strength. The result per zone is in docs/zone-species.md; world/zones.json → species pins a line by hand.
  • Cave zones: every entry spawns in the cave's biome, and sky-light minimums, "can see sky", time of day, excluded biomes and the "natural" ground preset are dropped; otherwise the Deep Dark (fed by Cobblemon's surface "spooky" spawns, many of them night-only) would barely spawn anything, and lush caves' moss floors would barely count.
  • Strays (Adrian, 2026-10-30: a Lv 61 from the Basalt Furnace turned up in the Lush Caves): every 5 seconds a wild Pokémon near a player that stands in a zone whose band it tops by more than 10 levels despawns, unless it is in a battle, angry at someone or a guardian (zone/Wanderers.kt, world/zones.json → wanderers). Tested: strays_despawn.
  • Basalt Furnace got Durant, Torkoal and Heatmor pinned to it: its own lines were all big (Charizard, Turtonator, Centiskorch, …) and Cobblemon only spawns a Pokémon where its body fits, so cramped basalt caves stayed empty.
  • Tested: spawn_pools_are_zoned (no Cobblemon default spawn is left; every entry has a zone and spawns within its band) and spawn_survey (a player at a point deep inside each zone is offered only that zone's spawns, and at least one), both in tools/quick_check.py.

The Mire's poison (Phase 3, step 5): while a player is in the Mangrove Mire without Mire Waders on, the companion mod gives them Poison every 5 seconds (zone/ZoneHazards.kt, data in datapacks/core/data/cobblesurvival/zone_hazards/mire.json, protection tag #cobblesurvival:mire_protection); the first time they walk in unprotected they get a warning. Vanilla Poison never kills, but it pins a player at half a heart, so a fall or a Pokémon's hit becomes deadly; milk, potions and golden apples still help. Mire Waders (leather boots, a KubeJS item) drop from the guardians of Westmarch and the Verdant Jungle, the zones before the Mire. Tested: mire_poisons_without_waders.

Soft level pressure (Phase 3, step 6; no hard level caps): a Pokémon more than 5 levels above the band of the zone its trainer is in gets 10 % less experience per extra level, down to 10 % (zone/LevelPressure.kt, values in world/zones.json → level_pressure). It counts battle experience and anything else except Exp. Candy and commands. The roadmap also offered a disobedience chance; experience alone is gentler and Cobblemon has nothing to build disobedience on. Tested: level_pressure_cuts_xp.

Flyers (Phase 3, step 7): strong flyers only spawn in high-level zones. A species you can ride through the air with a top flying speed of 60 or a top stamina of 85 (Cobblemon's ride stats) never spawns in a zone whose band starts below Lv 30; its weaker pre-evolutions still do, and a line that starts as a strong flyer is only placed in such zones (tools/zone_spawns.py, which refuses to write pools that break this). So Drampa lives in Sunscorch, Togekiss, Staraptor and Braviary in Frostpeak, Charizard in the Basalt Furnace; Salamence never spawns (Bagon and Shelgon stay in the Dripstone caves), and Aerodactyl only comes from fossils. Ride stats stay Cobblemon's for now: they can be overridden per species with a species_additions file replacing riding, best tuned after play-testing how far a flyer takes you on a 3 km island. Nothing blocks mounting.

Alpha guardians (Phase 3, step 4; Adrian, 2026-10-29: fixed spots, back 5 hours after being beaten):

  • One per zone except the Shallows, Lush Caves and Dripstone; the Basalt Furnace gets its boss in Phase 7. Each stands at its zone's sample point (deep inside the zone; a cave floor for the Deep Dark) and only appears while a player is within 96 blocks; it wanders no further than 24 blocks.
  • The guardian is the strongest Pokémon that spawns walking (or, at sea, swimming) in its zone, five levels above the band, half again as big, and uncatchable: Pachirisu (Button Isle), Sigilyph (Southwold), Carbink (Westmarch), Tangrowth (Jungle), Arcanine (Mire), Cinderace (Highlands), Delphox (Sunscorch), Tyranitar (Frostpeak), Kingdra (Deep Sea), Dusknoir (Deep Dark). world/zones.json → guardian.species overrides the pick.
  • Beating it in a battle gives every player in that battle its drops (the chain above: Icy Rocks before Sunscorch, Heat Rocks before Frostpeak, ...). It returns after 5 hours of game time, which only passes while the server runs. Cobblemon's Habitat Blocks were the roadmap's idea, but they can't wait a set time after a defeat or carry custom drops, so the companion mod runs guardians (zone/Guardians.kt; state in the world save; /cobblesurvival guardians for operators). Definitions: datapacks/core/data/cobblesurvival/guardians/<zone>.json, written by tools/zone_spawns.py.
  • Tested: guardian_appears_and_returns (appears big and uncatchable at its level, beaten in a real battle, drops arrive, stays away, returns after its time).

Hazards (Phase 3, step 5), with Cold Sweat 2.4.4:

  • Cold and heat follow the biome: Frostpeak's jagged peaks freeze an unprotected player in about a minute even at noon, Sunscorch's desert and badlands overheat one in about two minutes at noon; deserts cool off at night. Cold Sweat's insulation doesn't move the comfortable range, it slows how fast the body drifts out of it.
  • Only Cold Sweat's fur set (cold) and hide set (heat) really insulate: about 14 minutes in Frostpeak at noon and 25 in Sunscorch, longer with extra fur or hide sewn in. Their materials need boss drops (Adrian's rule): Goat Fur from wool and a Heat Rock (Sunscorch's guardian), Hoglin Hide from leather and an Icy Rock (the Mire's and the Highlands' guardians), kubejs/server_scripts/insulation.js. Leather armour no longer insulates by itself; sewn-in leather and wool only a little. Fire Resistance and Cold Sweat's own potions and warm/cold food still work.
  • So the lowlands stay livable at night, the coldest comfortable temperature is lower (0.25 instead of 0.4) and windswept hills are milder (45–72 °F instead of 24–58 °F). New players keep Cold Sweat's 5-minute grace period.
  • Cold Sweat's own animals (chameleons) can't join, like vanilla mobs: the only-Pokémon rule now lets in Cobblemon's entities only.
  • Tested on the island itself (cold_needs_fur, heat_needs_hide, lowlands_are_mild in tools/quick_check.py): players stand at real spots in each zone, their body drift is turned into minutes until it hurts, and a frozen player without the grace period takes damage.

Phase 4: resources

Adrian's answers (2026-10-30): Cobblebase's skills look fun and stay in, gated behind progression; power comes from an existing mod, also gated (Cobblemon Poke Power); evolution stones as ores are fine for now; the balance values are fine for now and stay configurable, to tweak later.

Ore nodes and veins. Ore only comes from Regenerating Ore Veins (plus chest loot): a mined ore block turns into a regenerator and grows back after its time, which counts in real time, unlike the guardians' game time. Each ore tier lives in exactly one zone, higher tiers in higher zones (table in docs/balance.md). Adrian (2026-10-30): ore shows up mainly as small nodes on the surface, the larger veins underground are harder to find, and the cave zones' ores are nodes on the cave floor, not in the walls. tools/zone_ores.py writes the vein mod's config (pack/config/regenerating_ore_veins/) and the node table from world/zones.json → ores:

  • Surface nodes (every surface tier): 1–5 ore blocks lying in natural ground (grass, dirt, sand, stone, snow, ...; tag cobblesurvival:ore_node_ground), at most one block standing out, never in water or under leaves, a given chance per chunk of the tier's zone. Evolution stones are single blocks and rarer.
  • Cave nodes (Lush Caves, Dripstone Depths, Deep Dark, Basalt Furnace): a lump on a cave floor in the tier's cave biome, at the depths where that biome lies (the Deep Dark mostly below y −24, the others between 0 and 40). Cave tiers have no veins inside the rock.
  • The companion mod places the nodes (ore/OreNodes.kt, table datapacks/core/data/cobblesurvival/ore_nodes/island.json) in every new overworld chunk, through the vein mod's own placement, so they are veins like any other and grow back.
  • Underground veins (surface tiers): larger (radius 2–4) and fewer than the nodes, generated by the vein mod inside the rock under their zone. A surface zone is a set of boxes cut from the zone grid; the mod checks every vein block against them, so no vein block lies outside its zone; cave biomes are zones of their own, which the veins keep out of (the mod checks the biome at a vein's centre, so an edge can reach a little over a cave border). Tiers with an ordinary and a deepslate ore get two veins: the ordinary ore from y 0 up, the deepslate one below.
  • Vein Locator: attuned in the crafting grid with an ore block (needs Silk Touch), it finds the nearest vein or node of exactly that block and throws a signal toward it like an Eye of Ender; 75 % chance to break per use. Attuned to the deepslate ore it only finds the deep half of the veins.
  • Cobblemon's evolution stones are tiers too (approved for now, 2026-10-30): their natural ores have been off since Phase 1, so stones had no source. Each stone lives in one zone that fits it (Leaf Stone in the jungle, Water Stone in the Mire, Ice and Dawn Stone on Frostpeak, ...).
  • Players can't break regenerators (allow_breaking false), so nobody removes a vein for good, and explosions don't hurt veins. The Vein Locator is crafted from a compass and a copper ingot instead of netherite.
  • Both mods fill a new chunk only while it is loaded, a few chunks a tick, and the vein mod forgets the rest when the server stops. Pregeneration is faster than that, so tools/make_world.py loads the island again row by row until every chunk has its veins and nodes (/cobblesurvival veins unfilled counts what's left), and the world report fails on any chunk without them. On a live server new chunks fill as players load them.
  • Checked: the world report (ore only in tracked veins and nodes inside their tier's zone, every tier with nodes and every surface tier with veins, every chunk filled) and the self-tests surface_nodes_lie_in_the_ground, cave_nodes_lie_on_the_cave_floor, vein_regrows_after_unload and vein_regrows_after_restart (a second server start in tools/selftest.py and tools/quick_check.py).

Unique drops. Only Pokémon live on the island, so a mob's drop needs another source. tools/drop_audit.py checks every item a Pokémon or a vanilla mob drops that a recipe or brewing consumes, and writes docs/pokemon-drops.md (item, wild Pokémon with zone and chance, other sources, consumers). Gaps it found, filled through Cobblemon species additions (datapacks/core/data/cobblesurvival/species_additions/, placeholders): Blaze Rod (Carkol in Westmarch, Torkoal in the Basalt Furnace; needed for brewing stands, blaze powder and Eyes of Ender), Ghast Tear (Drifloon, Dusclops), Breeze Rod (Whimsicott), Shulker Shell (Shuckle, Cloyster), Nether Star (Charizard). The tide armour trim and the wither skeleton skull stay without a source (cosmetic here). A zone spawn with its own drops overrides the species' drops, so the audit also fails if an addition targets such a spawn (Magmortar's and Centiskorch's did). Self-test: drop_additions_apply.

Base jobs and power. Cobblebase (Pokémon in a pasture work: harvesting, producing, finding, buffs, ...) and Cobblemon Poke Power (Electric-type Pokémon in a Power Block make Forge Energy; nothing in the pack uses the energy yet, Phase 6 machines). Phase 4 first gated them with flags: a skill or the Power Block opened once its owner had beaten a zone's Alpha guardian. Replaced by soft gates on 2026-10-31 (Adrian: guardians must not set flags; see "Soft gates" under Phase 5). The companion mod still puts every Cobblebase skill executor behind the gate, by reflection, when the server starts (progress/CobblebaseGate.kt); a skill missing from the table stays off, so an update can't add ungated skills. Breeder and Egg Hatcher work since Cobbreeding came in (Phase 5, "Breeding").

Catching high-level Pokémon (Adrian, 2026-10-30). Measured against the trainer's strongest party Pokémon (catching/Catching.kt, values in datapacks/core/data/cobblesurvival/catching/rules.json):

  • The catch rate falls with the level gap: full at the trainer's level, then linearly down to 2 % of the normal rate at 20 levels above and beyond ("20+ levels higher should be very improbable"). Applied to the rate Cobblemon's catch formula uses (its catch-rate event), so balls, status and HP still count.
  • A failed catch angers the Pokémon: it attacks the thrower instead of fleeing.
  • A wild Pokémon above the strongest Pokémon in a nearby player's party (16 blocks) is hostile to that player.
  • The fighting is Fight or Flight Reborn's: an angry Pokémon gets the aspect cobblesurvival_enraged, which the pack's config/fightorflight.json5 lists in always_aggro_aspects (so it fights rather than flees), and its target is set through Fight or Flight's own "caught by" mark, by reflection. While an angry Pokémon has a target, thrown balls don't catch it (Fight or Flight's aggressive_pokemon_catchable false, its default): it has to be battled. Pokémon below Lv 5 never fight back (its minimum_attack_level).
  • Self-tests: catch_rate_falls_with_level_gap, failed_catch_enrages, strong_wild_pokemon_hunt_weak_trainers, wild_pokemon_ignore_stronger_trainers.

Bee nests (found by Adrian in the Phase 4 world): a nest whose bee the island turns away kept the bee and tried to let it out every tick, with its sound each time. The companion mod now empties such a nest (world/OnlyPokemon.kt); honey still comes from Combee and shearing nests that have honey.

The field guide learned two things on the way: vanilla mobs count as absent (the companion mod lets only Cobblemon's entities join a world), and species additions replace the drops they set. The veins come in as sources from world/vein-sources.json.

Notes for Phase 5

  • Shoulder Pokémon (Adrian, 2026-10-30): Cobblemon lets a player carry a small Pokémon on their shoulder (96 species are shoulderMountable: Pidgey, Pikachu, Eevee, Zubat, Squirtle, ...). It has a shoulder-effect system with one type, potion_effect (effect, amplifier, particles, icon), but no species uses it in 1.8. Party passives can start there, as data: species additions giving shoulder Pokémon an effect while carried (e.g. Pidgey slow falling, Zubat night vision, a Fire type warmth against Frostpeak's cold), maybe gated behind progression like Cobblebase's skills. To check first: that species additions can set shoulderEffects, and how the effect behaves when the Pokémon faints or goes back in its ball.

Phase 5: existing mods checked first (2026-10-31)

The roadmap lists four mods as prior art; on Cobblemon 1.8 / NeoForge 1.21.1 today:

  • Cobblemon HMs 4.1.0 (NeoForge, Cobblemon ≥ 1.8.0, Kotlin for Forge): send out a Pokémon that knows the move, pick it on Cobblemon's interaction wheel, and your fist uses it. 39 abilities: Cut, Rock Smash, Dig, Strength, Teleport, Leafage, Growth, Flash, Dive, Rock Climb, Magnet Rise, Sweet Scent, weather moves (Rain Dance, Sunny Day, Thunder, Sandstorm, Snowscape, Blizzard), riding boosts (Surf, Tailwind, Agility, ...), Camouflage. Each ability has an on/off switch, cooldown, power, a minimum Pokémon level and a fullness/friendship cost (config/cobblemon_hms.json). Tried with the pack: loads, all self-tests pass. License "shiero's Mods License": free, also in a free modpack; anything that earns money (paid pack, paid server perks) needs an agreement with the author. Missing from the roadmap's first set: ignite (Ember/Flamethrower), freeze water (Ice Beam), extinguish and fill cauldrons (Water Gun).
  • Cobblemon Environment Interactions 3.1.0 (NeoForge, Apache-2.0, Cobblemon ≥ 1.7.3): type-based mining and utilities while riding or commanding one companion; not move-based.
  • Cobblemon Field Moves (Fabric, Cobblemon 1.6), Cobblemon Map Kit (Fabric), SceneBlocks (special blocks, custom license), CobbleStrike (real-time attacks): no fit.

Phase 5: field moves from Cobblemon HMs (Adrian, 2026-10-31)

Adrian: use Cobblemon HMs. Mining ore is the one hard requirement; the other field moves are nice to have, and Flamethrower in the roadmap was only an example. Furnaces are not lit by a field move: a Pokémon goes inside a Phase 6 multiblock instead. So the companion mod doesn't build the roadmap's own field_moves system for now; HMs replaces it.

  • Mining is HMs' Rock Smash: with a Pokémon that knows it sent out, the player's fist breaks the ore it hits and the ore connected to it, up to 32 blocks (power 32). HMs breaks each block as the player with a netherite pickaxe, through the normal break event, so Regenerating Ore Veins turns mined vein blocks into regenerators and the vein grows back. Automated: rock_smash_mines_veins (fires HMs' own Rock Smash handler at a vein).
  • Trainer Ditto. HMs sends a visiting Trainer Ditto that sells TMs; underneath it is a wild Cobblemon Ditto. The island's wild-Pokémon rules (hunting weaker trainers, strays despawning) leave it alone, like guardians (world/SpecialPokemon.kt).
  • Config: HMs' defaults for now (config/cobblemon_hms.json is written by the mod on first start; the pack ships none). Every ability can be switched off or tuned there.

Adrian's answers (2026-10-31): HMs' abilities stay open; the ones that get around zone hazards get soft gates; party passives come from shoulder Pokémon.

Soft gates (Adrian, 2026-10-31: gate behind ores/materials or a high-level Pokémon of a hard zone; materials may come from guardians, but guardians set no flags, and a gifted Pokémon or material does the same as an earned one). This is the roadmap's first rule ("soft gates only"), which the Phase 4 flags broke. One rule for everything gated (progress/Gates.kt, data datapacks/core/data/cobblesurvival/progression_gates/base.json):

  • A gate names a zone. The Pokémon doing the work passes it when its level reaches the top of that zone's band, or when it holds one of the zone's materials: its ores (raw or smelted), its evolution stone, or its guardian's drop (Heat Rock for Sunscorch, Mystic Water for the Deep Sea). A material of a zone with a higher gate counts too, so a Pokémon holding a diamond passes the Westmarch gate. Cobblemon lets a Pokémon hold any item, and Cobblebase doesn't use the held item, so holding the material costs nothing else.
  • Cobblebase skills keep their Phase 4 stages, now as zone gates on the pastured Pokémon. When one idles, its owner (if within 64 blocks) is told once what it needs.
  • The Power Block has no gate of its own: its recipe already takes four redstone blocks, the Verdant Jungle's ore.
  • HMs auras that get around hazards (progress/HmsGate.kt): Flash (Dripstone gate, for the Deep Dark), Dive and Mist (Mire; the Deep Sea, and slipping away from Pokémon that hunt you), Rock Climb (Highland Meadows; Frostpeak's cliffs), Magnet Rise (Sunscorch; flight), Lucky Chant (Frostpeak; more ore), Lava Plume (Deep Dark; the Basalt Furnace). HMs keeps a switch per player, Pokémon and aura; every 5 ticks the companion mod switches off a gated aura whose Pokémon doesn't pass and says what it needs. Dive, Mist and Rock Climb were added to Adrian's four (Flash, Lava Plume, Magnet Rise, Lucky Chant) because they get around hazards the same way.
  • The guardian record (Progress) and /cobblesurvival progress are gone; a guardian win only gives its drops.

Shoulder passives (party/ShoulderPassives.kt, data datapacks/core/data/cobblesurvival/shoulder_passives/base.json): while a Pokémon rides a player's shoulder, its type gives an effect: Flying slow falling, Electric speed, Rock/Ground/Steel haste; behind soft gates, Fire Cold Sweat's warmth (Highland Meadows gate, for Frostpeak), Ice its frigidness (Jungle gate, for Sunscorch), Water water breathing (Mire gate) and Ghost/Dark night vision (Dripstone gate). 93 species can ride a shoulder in Cobblemon 1.8, and every passive's types have at least one. Done in the companion mod rather than with Cobblemon's own shoulderEffects, which can match neither types nor gates.

Self-tests: gates_cover_every_cobblebase_skill, cobblebase_skills_need_level_or_material, power_block_gated_by_its_recipe, hazard_auras_need_level_or_material, shoulder_pokemon_give_passives.

Cobblebase Mining, from Adrian's play-test (2026-10-31):

  • Loot on the ground. Cobblebase's Mining never fills a chest: it drops what it digs at the Pokémon's feet, tagged with its pasture. A second Pokémon in the same pasture working as Item Gatherer (open from the start) picks up items tagged with its pasture and puts them into the best container within 12 blocks of it. Untouched, the loot despawns after 5 minutes like any dropped item. Left as Cobblebase designed it; direct delivery would be a change in the companion mod.
  • Gated jobs don't stick. Cobblebase lets the player assign one job per pastured Pokémon in its Skills tab, and the Buffs tab's "Active" list shows the assigned jobs. A job the Pokémon doesn't pass the gate for is now taken back the moment Cobblebase ticks it: the assignment is cleared, every client gets Cobblebase's assignment sync (so it leaves the Active list), and the owner is told what the Pokémon needs (progress/CobblebaseGate.kt). The job's button still shows in the Skills tab. Hiding it per Pokémon would need the gate tables sent to clients and a client mixin into Cobblebase's SkillsPanel (the screen already knows each pastured Pokémon's level and held item); Adrian (2026-10-31): leave it as is.
  • Ores from the pasture's zone only (Adrian: only the items of the zone the pasture is in). Mining, the Ore Finder and the Evolution-item Finder roll Cobblebase's tables mining_*, finder_ore_* and finder_evo_*. Cobblebase rolls its own built-in copy of a table (without loot conditions) and only falls back to the data pack's table when it has none, so the companion mod removes its copies of those twelve tables at server start (ore/BaseLoot.kt) and the pack ships its own versions (datapacks/core/data/cobblebase/loot_table/, written by tools/cobblebase_loot.py from Cobblebase's): every ore and evolution stone carries the loot condition cobblesurvival:in_zone (zone/InZoneCondition.kt) naming the zone of its tier in world/zones.json, checked at the Pokémon's position. Mining also gets the zone ores Cobblebase leaves out (quartz, the evolution stones) and loses the type gems, which are crafting shortcuts to gate materials (a Fire Gem makes a Heat Rock); ruins archaeology still has the gems. Cobblestone, gravel, flint, tumblestones and fossils stay everywhere. A table an operator edits in Cobblebase's own loot editor still wins.

Self-tests: gated_jobs_are_taken_back, base_jobs_dig_their_zones_ores.

Breeding (Adrian, 2026-10-31: add Cobbreeding without a gate; only Ditto should be rare, in an endgame area or gated behind something else). Cobblebase's hatchery only takes Cobbreeding's eggs, so its Breeder and Egg Hatcher did nothing before.

  • Cobbreeding 2.4.1: two compatible Pokémon (or one and a Ditto) in a Pasture Block, breeding switched on with the pasture's button, lay an egg in its nest now and then (every 8,000–14,000 ticks); an egg hatches in a player's inventory (about 10 minutes for 20 egg cycles). Defaults kept: two Dittos make no random eggs, Masuda shiny boost ×4, hoppers may pull eggs out of a pasture. Open from the start, no gate; Cobblebase's Breeder and Egg Hatcher stay behind the Deep Dark gate. Cloth Config comes along for its client config screen.
  • Ditto moved from Button Isle to the Deep Dark (Lv 45–60), with both of Cobblemon's entries: rare bucket in slime chunks, ultra-rare elsewhere. world/zones.json → species takes the long form {"zone": "deep_dark", "all_entries": true} for it, because when no stage fits a band tools/zone_spawns.py keeps one entry, which was the slime-chunk one. The Deep Dark's line target went up by one and Button Isle's down by one, so no other line moved; the Southwold and Frostpeak guardians are pinned (Pinsir, Tyranitar), since they tie on base stats with Hawlucha and Archaludon and the tool's pick between ties changed from run to run.
  • HMs' visiting Trainer Ditto is made uncatchable (world/SpecialPokemon.kt); it still trades TMs.
  • Cobbreeding lists a mixin into Cobblemon's client-only pasture screen among its common ones, so a dedicated server logs one harmless "invalid dist" error at start; allowlisted in tools/smoke_allowlist.txt. tools/check_deps.py now skips dependencies meant for the other side (Cobbreeding needs Cloth Config on clients only).

Self-tests: cobbreeding_eggs_fit_the_hatchery (Cobblebase's bridge takes Cobbreeding's eggs), trainer_ditto_cant_be_caught.

Notes for Phase 6 (researched 2026-10-31)

Adrian asked for existing mods for the multiblocks, or at least their logic. Phase 6's machines need a pattern-checked structure with a controller, a Pokémon stored inside (keeping its data, visible), safe return when the structure breaks, and state that survives unload and restart. Power is already Poke Power's (Phase 4), so the first machine is the Large Furnace. Nothing on NeoForge 1.21.1 puts a Pokémon into a multiblock; the structure part has several options:

Option What it is License, size Fit
Vanilla BlockPattern / BlockPatternBuilder Minecraft's own pattern matcher (iron golems, withers, end portals): layered aisles, block predicates, finds the structure in any rotation built in Enough for checking a fixed shape around a controller; no previews or editor. Recommended for the companion mod
Patchouli multiblock API Pattern definition and validation with rotation, plus in-world "visualize" previews from a guide book CC BY-NC-SA 3.0, very widely installed Good add-on to the above if players should see how to build a machine (e.g. a field-guide page)
Multiblocked2 Full multiblock framework: in-game 3D editor, controller, recipes, GUIs, machine effects, KubeJS; a Java API for custom traits and recipe capabilities (where a "Pokémon slot" would plug in) LGPL-3.0; needs LDLib2 and KilaGraph (MIT); the companion mod would compile against a snapshot Maven Most powerful, if many machines with recipes and GUIs are wanted; heavy, and the Pokémon part stays custom code
Custom Machinery Data-driven machines for pack makers; recipes can require a structure around the machine and entities nearby (check, hurt, kill) LGPL-3.0, KubeJS optional Poor fit: no stored Pokémon, only nearby entities
Modular Machinery Reborn JSON multiblocks with item/fluid/energy hatches LGPL-3.0; needs ExperienceLib and Athena (GPL) Poor fit: hatches and recipes, nothing for Pokémon
Tiny Multiblock Lib, CTMLib, ZeroCore bed/door-style big blocks; connected textures; an old All Rights Reserved API Not useful

For the Pokémon inside, the best prior art is already in the pack: Poke Power's Power Block (MIT, source) stores Pokémon with their owner, returns them on break, saves and syncs them, and renders the model in the block. Study it (and Cobblemon's Pasture Block, as the roadmap says); don't depend on it.

Phase 6: Pokémon machines (Adrian, 2026-10-31)

Adrian's choices: the Large Furnace has a Fire Pokémon heat real furnaces, and hoppers must work in and out; an Electric generator making Forge Energy is built too (alongside Poke Power's Power Block); machine work costs the Pokémon nothing. Then three more (Adrian, 2026-10-31): a drop synthesizer that turns a lot of energy into what the Pokémon inside would drop, faster with more energy, with a full drop roll and tiers that add looting; a sacrifice altar that trades a high-level Pokémon for hard-to-get items, rare candies only above the highest natural level, lower tiers too; and a rebirth chamber that turns a Lv 100 Pokémon into a shiny Lv 1 after a long time.

Shape. Every machine is a 3×3×3 shell with the machine's core block in the middle of one wall and air in the centre, where the Pokémon stands. The block under the core is free (a hopper can go there), and the middle of each side wall and the top centre are window spots that may be glass instead of casing, to see the Pokémon. The shell is data (datapacks/core/data/cobblesurvival/machines/<id>.json: layers bottom to top, a key per character listing the blocks allowed, the core and the chamber marked), checked in all four horizontal rotations around the core every second. Casing is a block tag per machine, so the casing is the materials gate:

Machine Core Casing Pokémon
Large Furnace Heat Core #cobblesurvival:heat_casing: bricks, mud bricks, deepslate bricks any Fire type
Generator Dynamo Core #cobblesurvival:dynamo_casing: copper blocks (any weathering, waxed or not, cut or not) any Electric type
Drop Synthesizer Synthesis Core #cobblesurvival:synthesis_casing: iron, gold, diamond or netherite blocks; the lowest metal present sets the tier any Pokémon
Sacrifice Altar Altar Core #cobblesurvival:altar_casing: obsidian, crying obsidian, blackstone, polished blackstone bricks Lv 20 or more
Rebirth Chamber Rebirth Core #cobblesurvival:rebirth_casing: amethyst, quartz and calcite blocks Lv 100

A Pokémon goes in when its owner sends it out near the core and uses the core with an empty hand: the nearest of their sent-out Pokémon that fits walks in (it leaves the party and its data is kept in the core). Using the core again takes it out, back to the party or else the PC. Sneak-use shows the machine's state. Breaking the core or any part of the shell sends the Pokémon back to its owner, online or not. The core is the only place the Pokémon exists while inside, so nothing can be duplicated by breaking and inserting at once.

What's shown is a real Cobblemon Pokémon entity, a copy, standing in the chamber: scaled to fit, no AI, invulnerable, silent, uncatchable, and it can't be battled or used. It's never kept in the world save: one loaded from disk is dropped, and the core puts a fresh one there. The cores are see-through (Adrian, 2026-11-02): a solid frame around tinted glass, rendered translucent, so the Pokémon shows through the core as well as through glass windows. When a sacrifice is made or a rebirth ends, the shown Pokémon plays Cobblemon's faint animation and its cry pitched down (Cobblemon has no separate death sounds; the games pitch the cry down when a Pokémon faints), and vanishes two seconds later; a reborn Pokémon then appears in its new form.

Large Furnace. Furnaces, blast furnaces and smokers (#cobblesurvival:machine_furnaces) standing against the outside of the shell burn without fuel while they have something to cook, and cook faster. They stay ordinary vanilla blocks, so their screens, recipes and hoppers work as always (input from above, output from below). How many are heated and how fast depend on the Pokémon's level and Special Attack (numbers in the data file and docs/balance.md).

Drop Synthesizer. Takes Forge Energy into the Synthesis Core (from a Dynamo Core or cables) and, for every so much energy, rolls the Pokémon's own drop table once, as if it had been defeated. The shell's tier adds looting: iron none, gold I, diamond II, netherite III (more of each drop, rare drops likelier). It takes energy up to a cap per tick, so more energy makes it faster. What it makes waits in the core (nine stacks; it stops when full) for a hopper under the core, or pipes from other mods on any side; breaking the core drops it.

Sacrifice Altar. Sneak-use the Altar Core with the Pokémon inside to see what it would give, sneak-use again within five seconds to sacrifice it: the Pokémon is gone for good and the rewards go to the owner. The highest level tier reached decides the reward: Exp. Candies from Lv 20, Ability Capsules from Lv 65, rare candies only from Lv 80 (above the highest natural level: Basalt Furnace Lv 70, guardians Lv 75), an Ability Patch from Lv 90, a nether star at Lv 100; a Lv 100 Dragon type also gives a dragon egg.

Rebirth Chamber. A Lv 100 Pokémon put in starts a long rebirth (placeholder: two hours of server time, also while the chunk is unloaded). Then it is the first stage of its line at Lv 1 and shiny, keeps its nickname, original trainer, held item and every move it learned, gets three of its IVs set to 31 (no IV ever goes down), and keeps its ability; an Ability Patch comes with it, so taking the hidden ability is the player's choice. Taking it out before the end cancels the rebirth.

Finding out how to build one (Adrian, 2026-11-02: there must be a way in game). Placing a core, using it while its shell is incomplete, or sneak-using it while empty shows every missing or wrong spot of the shell as a small glowing ghost block for ten seconds (vanilla block displays, so clients need nothing; never saved), in the orientation the core faces, with a chat line counting what's missing. The cores' tooltips say what each machine does and what its shell is made of. The machine test world (tools/make_machine_world.py) has every machine built.

Cores are crafted (soft gates by material): Heat Core from bricks, iron and a blast furnace; Dynamo Core from copper blocks, redstone and a thunder stone; Synthesis Core from iron and redstone blocks, hoppers and a crafter; Altar Core from obsidian, gold blocks and an echo shard; Rebirth Core from amethyst blocks, diamonds and a shiny stone. Their textures are drawn by tools/machine_assets.py.

Self-tests (MachineTests): in and out, wrong Pokémon refused, broken shell and broken core (to the PC when the party is full), chunk unload, server restart, and each machine's work (a furnace fed and emptied by hoppers without fuel, a Poke Power cable charged by a Dynamo Core, Magikarp's salmon through a hopper under a gold Synthesis Core, a confirmed sacrifice with a Lv 100 Dragonite's rewards, a rebirth from Charizard to a shiny Lv 1 Charmander with its moves and ability).

Generator. The Dynamo Core stores Forge Energy and pushes it to whatever touches the core and takes energy (cables, machines from other mods); its output per tick depends on the Pokémon's level and Special Attack, in line with Poke Power's 50 FE per level.

Phase 7: boss battles with area attacks (Adrian, 2026-11-02)

Adrian's choices: every zone guardian gets area attacks (more and harder in harder zones); the Basalt Furnace gets a boss and the End a Pokémon that replaces the Ender Dragon; dying or leaving the arena loses the fight; area attacks hit only the player (the roadmap's default).

Guardians reviewed (Adrian, 2026-11-02: the Deep Dark should have a legendary, and each guardian should fit its zone; Tyranitar in the snow looked off). Adrian's first picks, Groudon (Basalt), Giratina (End) and Meloetta (Deep Dark), have no model in Cobblemon 1.8.4 (only 17 legendaries and 2 mythicals are implemented), so implemented ones stand in until they come; changing one is a word in world/zones.json:

Zone Was Now Why
Highland Meadows Cinderace Mudsdale a draft horse of highland pastures, not a starter
Sunscorch Delphox Flygon the desert spirit of sandstorms
Frostpeak Range Tyranitar Abomasnow lives on snowy mountains; spawns there
Deep Dark Crobat Regigigas (normal size) a legendary; the ancient colossus sleeping in ruins, like the Ancient Cities
Basalt Furnace none Moltres (Lv 75) the flame bird of the volcano; stands in for Groudon
The End Ender Dragon Eternatus the cosmic final boss; stands in for Giratina

The others fit and stay: Morpeko (Button Isle), Pinsir (Southwold), Scyther (Westmarch), Tangrowth (Jungle), Swampert (Mire), Kingdra (Deep Sea).

Bosses are data, datapacks/core/data/cobblesurvival/bosses/<id>.json, written by tools/zone_bosses.py from a tier table per zone band: which fight it is (a zone's guardian, or the End boss), the arena radius, and the attack patterns. A pattern has a shape (circle, ring, line, cone) and its size, where it's aimed (at the player, or around the boss), a telegraph time, damage, an optional effect (fire: set alight; ice: slowed and freezing) and a trigger (every so many seconds, every so many turns, or once when the boss's HP falls below a share).

Runtime (companion mod). A battle between players and a boss Pokémon becomes a boss fight. While it lasts, due patterns telegraph on the ground where they'll land (made more visible after Adrian's first fight, 2026-11-02: large particles redrawn every 2 ticks over the whole area, a bright outline with rising sparks, and a low bell when an attack begins), then hit the battling players standing inside; everything stops when the battle ends. The arena is a circle around where the boss stood when the fight began: a player who leaves it, or dies, loses the fight (the battle ends, the boss stays, nothing drops). Cobblemon's own flee check only applies when a battle starts, which is why the arena is enforced here.

Moltres becomes the Basalt Furnace's guardian like the others (Lv 75, band top + 5), with placeholder drops (3 Exp. Candy XL, 2 netherite scrap).

Self-tests (BossTests): every guardian has a fight and a Cobblemon model; each attack shape hits a player standing in it and misses one ten blocks away; attacks stop when the battle ends; leaving the arena ends the battle and the boss heals; the dragon can't join the End, Eternatus appears, and beating it opens the exit portal with the egg.

Eternatus replaces the Ender Dragon: the dragon no longer spawns; Eternatus (uncatchable, Lv 80, scaled down to fit) appears on the main End island while a player is there, and beating it does what killing the dragon did (exit portal, gateways, the egg on the first win). Only one at a time: it waits until the entities around its spot have loaded before deciding it's missing, and a second copy never joins while the recorded one is alive (Adrian met a second Eternatus on his second visit, 2026-11-02); extra copies left in older worlds are removed.

Open decisions for Adrian (proceeding with the default, flagged)

Decision Default used for now
Roadmap's open decisions table (loader, island size, safety net, boss AoE, etc.) Roadmap defaults, unchanged
Platform split (deferred until a public release; not publishing for now) No platform hosts the full mod list (FTB Quests is CurseForge-only; CobbleHardcoreMon is Modrinth-only). Both mods stay; the exports keep listing what they leave out. Options for release: (a) publish one platform's pack, or both with the gaps listed; (b) ask the authors to cross-post (CobbleHardcoreMon, Matthiesen Core, Regenerating Ore Veins and Ore Generation Configuration are MIT); (c) a quest mod on both platforms; (d) permadeath in the companion mod
No CI (Adrian, 2026-10-30): no Actions runners on the Gitea server, which is too weak; a push that started the old .github/workflows/ci.yml crashed it. The workflow is removed (still in the git history) The roadmap's "CI smoke test" runs locally instead: tools/smoke_test.py, tools/selftest.py, tools/quick_check.py. Adrian accepted the Minecraft EULA for the local test server on 2026-10-28
License for the companion mod and pack content MIT for the companion mod (placeholder); nothing chosen for the rest
Pack name and mod id "Cobblemon Survival Pack" / cobblesurvival (working titles)
Basalt deltas keeps the vanilla Nether biome's mobs and features: ghasts, magma cubes and striders can spawn in those caves, glowstone generates, and Cobblemon's Nether-themed habitats appear there (found by the field guide) Settled by Phase 2: no vanilla mob can join (world/OnlyPokemon.kt), so no ghasts, magma cubes or striders; glowstone and Cobblemon's Nether-themed habitats stay
Items that need the Nether have no source: Choice Band, Choice Specs (Nether Quartz, Blaze Rod), Master Ball (Netherite) Phase 4 adds sources (veins, drops or recipe changes); listed by the field guide
End portals stay openable; the Ender Dragon will be replaced by a Pokémon boss fight (Adrian, 2026-10-28; Phase 7) Eyes of ender are obtainable: ender pearls drop from Abra, Kadabra and Alakazam (and trial chamber loot), blaze powder from Magmar, Magby, Houndour and others. The dragon is on the allowed list until its replacement exists; End city shulkers are blocked like every vanilla mob
End access depends on the seed: a stronghold must start inside the border isle-26 has two; tools/world_report.py now fails a world without one