Phase 9: safe start island, better quest book, every useful item obtainable
- Button Isle is peaceful: wild Pokémon only fight a player who hit them first (tuning/server.json peaceful_zones); its apricorns and coal make Poké Balls (4 apricorns + coal or charcoal), and the world report checks it has enough. - Quest book: no boilerplate; each zone page says what is particular to it, and every zone that needs gear or a field move to be safe has its own quest. New page on the bigger mods (Cold Sweat, Fight or Flight, Cobblebase, breeding, veins, shared loot, maps and info). - The Mire's poison stops 10 blocks below the surface. - Player battles never cost a Pokémon (CobbleHardcoreMon config, mixins, and the companion mod's own permadeath). - tools/item_audit.py: every item with a use has a source on the island; new sources for the gaps it found (species additions, three recipes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6ace26e012
commit
d29e177f9d
65 files changed
+1920
-364
No files matched your search
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"mod/gradle.properties": "981e881361121f4109d87b3292eadec054fd73945e24249a29134dcc174045c1",
|
||||
"mod/src/main/java/dev/cobblesurvival/mixin/HardcorePartyMixin.java": "7dc3158882fa6baf04409493505d5e91f56c6e112f69bd9f095772a72b31e6e4",
|
||||
"mod/src/main/java/dev/cobblesurvival/mixin/HardcoreBattlesMixin.java": "0d82820f331f6e8e97045287f27f2d2b1860139fabc5661831cb4e2ef126120f",
|
||||
"mod/src/main/java/dev/cobblesurvival/mixin/HardcorePartyMixin.java": "d04c1ef392a98f903b981635fcd13e121b67cce4358a0e256769fbd1b7909e7a",
|
||||
"mod/src/main/java/dev/cobblesurvival/mixin/RegeneratorBlockMixin.java": "84706a42b2a6d5359993831e17f886680decb76e027c451c64463d009e36acae",
|
||||
"mod/src/main/kotlin/dev/cobblesurvival/jei/DropSources.kt": "9437c1dac38c1c236067d661379b02b04657cee231ccdf4035183c6639c2e0f9",
|
||||
"mod/src/main/kotlin/dev/cobblesurvival/jei/DropSourcesJei.kt": "89e7e6dc3b8ef4aac3e095887c63ceb95f3214270e2d91e0322074c09f41ac55",
|
||||
@@ -57,7 +58,7 @@
|
||||
"mod/src/main/resources/assets/cobblesurvival/textures/block/synthesis_core_side.png": "b7d289800824b16a0e1a961c042b40d688ae33d64bc5c7081d16d3d2d3a0825f",
|
||||
"mod/src/main/resources/assets/cobblesurvival/textures/block/synthesis_core_top.png": "fd1ee6c550f0a7fe7ea97022b32a046ad69563727dc05e31aa339c9b8647aa64",
|
||||
"mod/src/main/resources/assets/cobblesurvival/textures/item/summon_sigil.png": "8b7e9bea51f529c250f03fcd8816aadf1e6b9cf4a53a439c16650b6767c71f56",
|
||||
"mod/src/main/resources/cobblesurvival.mixins.json": "aae2a4db2673be681e3b8389682a89b79a60462a3e157ab11e1dd70b48e79f95",
|
||||
"mod/src/main/resources/cobblesurvival.mixins.json": "8a35ca950a03a393f7aa17cdba7352da14bc023ce16c3f0841efd6fb571db06c",
|
||||
"pack/config/defaultoptions/extra/config/iris.properties": "3866233ba2035bd6ffe6e06cf74c7b1f16869184c274276ca0bd546f1e8bf003",
|
||||
"pack/config/defaultoptions/keybindings.txt": "515362c7a71b203b8ba3ea9d125c6b8cafc2abdb480df5936b9af6a3632d865b",
|
||||
"pack/config/xaero/minimap/default_radar_categories_client.json": "e0a234797b1063dd91a6fec8ebdd3828b93dc39ee4c134d11175aa6d1f26fc20",
|
||||
|
||||
@@ -45,7 +45,6 @@ BREWING = {
|
||||
}
|
||||
# Audited items that may stay without a source, and why.
|
||||
NO_SOURCE_OK = {
|
||||
"cold_sweat:chameleon_molt": "Cold Sweat's chameleon armour and Thermolith are not part of the pack's progression",
|
||||
"minecraft:dragon_breath": "the End's dragon is the only source by design (the End is reachable)",
|
||||
"minecraft:tide_armor_trim_smithing_template": "cosmetic (an armour trim); elder guardians don't live on the island",
|
||||
"minecraft:wither_skeleton_skull": "cosmetic here (the skull banner pattern); the Wither can't be built",
|
||||
|
||||
@@ -1,21 +1,411 @@
|
||||
{
|
||||
"_comment": "Item sources that Minecraft decides in code, so no data file shows them. Each entry: item, how (shown in the guide), needs (list of groups; each group is satisfied by any one of its keys: item:<id>, mob:<id>, block:<id>). Keep this list short and add only well-known mechanics; Phase 4 sources (ore veins, KubeJS recipes) go in an --extra file instead (see docs/field-guide.md).",
|
||||
"_comment": "Item sources that Minecraft decides in code, so no data file shows them. Each entry: item, how (shown in the guide), needs (list of groups; each group is satisfied by any one of its keys: item:<id>, mob:<id>, block:<id>). Keep this list short and add only well-known mechanics; Phase 4 sources (ore veins, KubeJS recipes) go in an --extra file instead (see docs/field-guide.md). 'pattern' instead of 'item' matches several items (fnmatch). Below the vanilla ones: what the pack's own rules give (Adrian, 2026-11-10: every item with a use is obtainable; tools/item_audit.py).",
|
||||
"sources": [
|
||||
{"item": "minecraft:emerald", "how": "Trade with villagers", "needs": [["mob:minecraft:villager"]]},
|
||||
{"item": "minecraft:milk_bucket", "how": "Milk a cow or goat with a bucket", "needs": [["mob:minecraft:cow", "mob:minecraft:goat", "mob:minecraft:mooshroom"], ["item:minecraft:bucket"]]},
|
||||
{"item": "minecraft:egg", "how": "Laid by chickens", "needs": [["mob:minecraft:chicken"]]},
|
||||
{"item": "minecraft:white_wool", "how": "Shear a sheep", "needs": [["mob:minecraft:sheep"], ["item:minecraft:shears"]]},
|
||||
{"item": "minecraft:honeycomb", "how": "Shear a full bee nest", "needs": [["block:minecraft:bee_nest", "block:minecraft:beehive"], ["item:minecraft:shears"]]},
|
||||
{"item": "minecraft:honey_bottle", "how": "Use a glass bottle on a full bee nest", "needs": [["block:minecraft:bee_nest", "block:minecraft:beehive"], ["item:minecraft:glass_bottle"]]},
|
||||
{"item": "minecraft:turtle_scute", "how": "Dropped when a baby turtle grows up", "needs": [["mob:minecraft:turtle"]]},
|
||||
{"item": "minecraft:water_bucket", "how": "Fill a bucket with water", "needs": [["item:minecraft:bucket"]]},
|
||||
{"item": "minecraft:lava_bucket", "how": "Fill a bucket with lava", "needs": [["item:minecraft:bucket"], ["block:minecraft:lava"]]},
|
||||
{"item": "minecraft:obsidian", "how": "Pour water on a lava source", "needs": [["item:minecraft:water_bucket"], ["block:minecraft:lava"]]},
|
||||
{"item": "minecraft:dragon_breath", "how": "Collect the Ender Dragon's breath with a glass bottle", "needs": [["mob:minecraft:ender_dragon"], ["item:minecraft:glass_bottle"]]},
|
||||
{"item": "minecraft:dragon_egg", "how": "Left by the first Ender Dragon", "needs": [["mob:minecraft:ender_dragon"]]},
|
||||
{"item": "minecraft:pumpkin_seeds", "how": "Craft from a pumpkin", "needs": [["item:minecraft:pumpkin"]]},
|
||||
{"item": "minecraft:mud", "how": "Use a water bottle on dirt", "needs": [["item:minecraft:glass_bottle"]]},
|
||||
{"item": "minecraft:ominous_bottle", "how": "Dropped by raid captains", "needs": [["mob:minecraft:pillager"]]}
|
||||
{
|
||||
"item": "minecraft:emerald",
|
||||
"how": "Trade with villagers",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:villager"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:milk_bucket",
|
||||
"how": "Milk a cow or goat with a bucket",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:cow",
|
||||
"mob:minecraft:goat",
|
||||
"mob:minecraft:mooshroom"
|
||||
],
|
||||
[
|
||||
"item:minecraft:bucket"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:egg",
|
||||
"how": "Laid by chickens",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:chicken"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:white_wool",
|
||||
"how": "Shear a sheep",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:sheep"
|
||||
],
|
||||
[
|
||||
"item:minecraft:shears"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:honeycomb",
|
||||
"how": "Shear a full bee nest",
|
||||
"needs": [
|
||||
[
|
||||
"block:minecraft:bee_nest",
|
||||
"block:minecraft:beehive"
|
||||
],
|
||||
[
|
||||
"item:minecraft:shears"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:honey_bottle",
|
||||
"how": "Use a glass bottle on a full bee nest",
|
||||
"needs": [
|
||||
[
|
||||
"block:minecraft:bee_nest",
|
||||
"block:minecraft:beehive"
|
||||
],
|
||||
[
|
||||
"item:minecraft:glass_bottle"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:turtle_scute",
|
||||
"how": "Dropped when a baby turtle grows up",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:turtle"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:water_bucket",
|
||||
"how": "Fill a bucket with water",
|
||||
"needs": [
|
||||
[
|
||||
"item:minecraft:bucket"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:lava_bucket",
|
||||
"how": "Fill a bucket with lava",
|
||||
"needs": [
|
||||
[
|
||||
"item:minecraft:bucket"
|
||||
],
|
||||
[
|
||||
"block:minecraft:lava"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:obsidian",
|
||||
"how": "Pour water on a lava source",
|
||||
"needs": [
|
||||
[
|
||||
"item:minecraft:water_bucket"
|
||||
],
|
||||
[
|
||||
"block:minecraft:lava"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:dragon_breath",
|
||||
"how": "Collect the Ender Dragon's breath with a glass bottle",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:ender_dragon"
|
||||
],
|
||||
[
|
||||
"item:minecraft:glass_bottle"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:dragon_egg",
|
||||
"how": "Left by the first Ender Dragon",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:ender_dragon"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:pumpkin_seeds",
|
||||
"how": "Craft from a pumpkin",
|
||||
"needs": [
|
||||
[
|
||||
"item:minecraft:pumpkin"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:mud",
|
||||
"how": "Use a water bottle on dirt",
|
||||
"needs": [
|
||||
[
|
||||
"item:minecraft:glass_bottle"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "minecraft:ominous_bottle",
|
||||
"how": "Dropped by raid captains",
|
||||
"needs": [
|
||||
[
|
||||
"mob:minecraft:pillager"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"pattern": "cobbreeding:*_egg",
|
||||
"how": "Laid in a Pasture Block by two compatible Pokémon (Cobbreeding)",
|
||||
"needs": [
|
||||
[
|
||||
"item:cobblemon:pasture"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "cobblesurvival:mire_waders",
|
||||
"how": "Dropped by the guardians of Westmarch and the Verdant Jungle",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:ability_patch",
|
||||
"how": "The Sacrifice Altar (Lv 90 or more) and the Rebirth Chamber",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon_hms:hm_case",
|
||||
"how": "A Trainer Ditto's gift the first time you meet one",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "regenerating_ore_veins:vein_locator",
|
||||
"how": "Crafted from a compass and a copper ingot (Regenerating Ore Veins' config)",
|
||||
"needs": [
|
||||
[
|
||||
"item:minecraft:compass"
|
||||
],
|
||||
[
|
||||
"item:minecraft:copper_ingot"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "cold_sweat:filled_waterskin",
|
||||
"how": "Use an empty Waterskin on water",
|
||||
"needs": [
|
||||
[
|
||||
"item:cold_sweat:waterskin"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:dawn_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_dawn_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_dusk_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_fire_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_ice_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_leaf_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_moon_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_shiny_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_sun_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_thunder_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:deepslate_water_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:dripstone_moon_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:fire_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:ice_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:leaf_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:moon_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:shiny_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:sun_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:thunder_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "cobblemon:water_stone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:amethyst_block",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:ancient_debris",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:budding_amethyst",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:coal_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:copper_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_coal_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_copper_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_diamond_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_emerald_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_gold_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_iron_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_lapis_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:deepslate_redstone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:emerald_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:gold_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:iron_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:lapis_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:nether_quartz_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:redstone_ore",
|
||||
"how": "Mine its regenerating vein with Silk Touch",
|
||||
"needs": []
|
||||
},
|
||||
{
|
||||
"item": "minecraft:chorus_fruit",
|
||||
"how": "Break chorus plants on the End's outer islands (vanilla End generation)",
|
||||
"needs": []
|
||||
}
|
||||
],
|
||||
"concrete_from_powder": true
|
||||
}
|
||||
@@ -531,9 +531,12 @@ class Model:
|
||||
|
||||
def _manual(self):
|
||||
from pathlib import Path
|
||||
import fnmatch
|
||||
cfg = json.loads((Path(__file__).parent / "manual_sources.json").read_text())
|
||||
known = self.vanilla_items | set(self.stack.ids("models/item", root="assets"))
|
||||
for s in cfg["sources"]:
|
||||
self.add(f"item:{s['item']}", "manual", s["how"], needs=s.get("needs", []))
|
||||
for item in sorted(fnmatch.filter(known, s["pattern"])) if "pattern" in s else [s["item"]]:
|
||||
self.add(f"item:{item}", "manual", s["how"], needs=s.get("needs", []))
|
||||
axes = [f"item:{i}" for i in self.itags.resolve("#minecraft:axes")]
|
||||
for item in sorted(self.vanilla_items | {k for k in self.stack.ids("models/item", root="assets")}):
|
||||
ns, path = split_id(item)
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Every item in the pack that has a use can be had on the island (Adrian, 2026-11-10).
|
||||
|
||||
Reads the field guide (build/field-guide/fieldguide.json; run tools/fieldguide/build.py first), which works out what
|
||||
the island can provide from the pack's data: worldgen, loot, recipes, Pokémon drops, and what Minecraft and the
|
||||
pack's own rules give in code (tools/fieldguide/manual_sources.json). Every item still without a source must be listed
|
||||
in NO_USE below, with the reason it needs none; anything else fails.
|
||||
|
||||
Usage: tools/item_audit.py
|
||||
"""
|
||||
import fnmatch
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
GUIDE = ROOT / "build/field-guide/fieldguide.json"
|
||||
|
||||
# Items that may stay without a source, and why (fnmatch patterns).
|
||||
NO_USE = {
|
||||
"cobblemon_hms:hm_*": "left over from Cobblemon HMs before 4.0: the items do nothing now (the HM Case has a source)",
|
||||
"lootr:*": "Lootr's own containers: structures place them, nobody uses them as items",
|
||||
"regenerating_ore_veins:regenerator_block": "the block a mined vein turns into; it can't be broken",
|
||||
"cold_sweat:chameleon_spawn_egg": "a creative-mode spawn egg",
|
||||
"minecraft:infested_*": "silverfish blocks; the island has no silverfish",
|
||||
"minecraft:crimson_*": "Nether wood for decoration; the island has no Nether",
|
||||
"cobblemon:*tumblestone_cluster": "tumblestone itself comes from the ruins; clusters are decoration",
|
||||
"cobblemon:*_budding_*tumblestone": "tumblestone itself comes from the ruins; buds are decoration",
|
||||
"cobblemon:damaged_monitor": "a decoration block in Cobblemon's ruins",
|
||||
"cobblemon:gimmighoul_chest": "the chest Gimmighoul hides in",
|
||||
"cobblemon:lectern": "Cobblemon's decorative lectern, with no recipe in Cobblemon",
|
||||
"cobblemon:bugwort": "a decoration plant with no recipe, seasoning or other use in Cobblemon",
|
||||
"cobblemon:poke_puff": "Cobblemon 1.8.4 has no way to make Poké Puffs yet",
|
||||
"cobblemon:shalour_sable": "Cobblemon 1.8.4 has no way to make it yet",
|
||||
"cobblemon:scroll_of_*": "they evolve Kubfu, which Cobblemon 1.8.4 doesn't have",
|
||||
"cobblemon:saccharine_log_slathered": "only gives planks and charcoal, which other logs give too",
|
||||
"cobblemon:nether_fire_stone_ore": "an ore the island's veins don't use; Fire Stones come from Sunscorch's veins",
|
||||
"cobblemon:terracotta_sun_stone_ore": "an ore the island's veins don't use; Sun Stones come from the Highlands' veins",
|
||||
"cobblemon:dusk_stone_ore": "an ore the island's veins don't use; Dusk Stones come from the Deep Dark's veins",
|
||||
"cold_sweat:slush_bucket": "slush is a cold fuel for the Hearth and Icebox; ice and snow do the same",
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
if not GUIDE.exists():
|
||||
sys.exit(f"{GUIDE} is missing: run tools/fieldguide/build.py first")
|
||||
guide = json.loads(GUIDE.read_text())
|
||||
entries = {**guide["vanilla"], **guide["items"]}
|
||||
missing = sorted(k for k, v in entries.items() if v.get("status") != "available" and not v.get("technical"))
|
||||
unexplained = [k for k in missing if not any(fnmatch.fnmatch(k, pattern) for pattern in NO_USE)]
|
||||
stale = [p for p in NO_USE if not any(fnmatch.fnmatch(k, p) for k in missing)]
|
||||
print(f"{len(entries)} items, {len(missing)} without a source on the island, {len(missing) - len(unexplained)} of them with no use")
|
||||
for pattern in stale:
|
||||
print(f" note: nothing matches NO_USE {pattern!r} any more; remove it")
|
||||
if unexplained:
|
||||
for k in unexplained:
|
||||
uses = ", ".join(u.get("text", "") for u in entries[k].get("uses", [])[:3]) or "no recipe uses"
|
||||
print(f" - {k}: {entries[k].get('reason', '')} (uses: {uses})")
|
||||
sys.exit("ITEM AUDIT FAILED: give these a source, or list them in NO_USE with the reason they need none")
|
||||
print("ITEM AUDIT PASSED")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+8
-1
@@ -194,11 +194,18 @@ def title_case(item):
|
||||
|
||||
|
||||
def zone_fields(zone, chapter, book):
|
||||
"""What the zone template fills in. A zone chapter says what is particular about it (Adrian, 2026-11-10: no
|
||||
boilerplate): `about`, the `locals` named as examples (they must spawn there), and a `guardian_note`."""
|
||||
g = zone["guardian_data"]
|
||||
ores = zone["ore_items"]
|
||||
if not chapter.get("about"):
|
||||
sys.exit(f"zone chapter {chapter['id']} has no 'about'")
|
||||
for name in re.split(r", | and ", chapter.get("locals", "")):
|
||||
if name and f"cobblemon:{re.sub(r'[^a-z0-9]', '', name.lower())}" not in zone["species"]:
|
||||
sys.exit(f"{chapter['id']}: {name} is named as a local but doesn't spawn in {zone['name']}")
|
||||
return {
|
||||
"zone": zone["name"], "zone_id": zone["id"], "low": zone["levels"][0], "high": zone["levels"][1],
|
||||
"hazard_text": chapter.get("hazard_text", ""),
|
||||
"about": chapter["about"].strip(), "locals": chapter.get("locals", ""), "guardian_note": chapter.get("guardian_note", ""),
|
||||
"guardian": g["pokemon"].split()[0].title() if g else "",
|
||||
"guardian_level": re.search(r"level=(\d+)", g["pokemon"])[1] if g else "",
|
||||
"drops": ", ".join(f"{d['count']} {title_case(d['item'])}" for d in g["drops"]) if g else "",
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
the check, and so (except with --sample) do an ore tier without nodes, a
|
||||
surface tier without underground veins, and a chunk that never got its
|
||||
veins and nodes.
|
||||
* Start island: Button Isle has enough apricorns and coal ore for Poké Balls
|
||||
(four apricorns and coal or charcoal make one; Adrian, 2026-11-10).
|
||||
* Biome set: every biome stored in any chunk section (surface and caves)
|
||||
must be listed in world/biomes.json ("allowed" or "water").
|
||||
* End access: at least one stronghold must start inside the world border.
|
||||
@@ -42,6 +44,7 @@ import math
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from concurrent.futures import ProcessPoolExecutor
|
||||
from pathlib import Path
|
||||
|
||||
@@ -331,6 +334,38 @@ def island_mask(data, cell=16, min_share=0.01):
|
||||
return out
|
||||
|
||||
|
||||
# Adrian, 2026-11-10: the start island alone makes Poké Balls (four apricorns and coal or charcoal, the pack's
|
||||
# poke_ball_from_coal recipe), with some exploring. Coal grows back in its veins; apricorns grow back on their trees.
|
||||
START_MINIMUM = {"apricorns": 100, "coal ore": 500}
|
||||
|
||||
|
||||
def check_start_isle(world):
|
||||
"""Apricorns and coal ore on Button Isle (the zone within world/zones.json's radius of 0,0), from its stored chunks."""
|
||||
plan = json.loads((ROOT / "world/zones.json").read_text())
|
||||
radius = next(z for z in plan["zones"] if z["id"] == "button_isle")["rule"]["within"]
|
||||
found = defaultdict(int)
|
||||
span = range(-((radius + 511) // 512), (radius + 511) // 512)
|
||||
for rx in span:
|
||||
for rz in span:
|
||||
path = world / "region" / f"r.{rx}.{rz}.mca"
|
||||
if not path.exists():
|
||||
continue
|
||||
for cx, cz, chunk in anvil.region_chunks(path):
|
||||
x0, z0 = cx * 16, cz * 16
|
||||
if math.hypot(x0 + 8, z0 + 8) > radius + 12:
|
||||
continue
|
||||
inside = np.hypot(np.arange(16)[None, :] + x0 + .5, np.arange(16)[:, None] + z0 + .5) <= radius
|
||||
for section in chunk.get("sections", []):
|
||||
palette, indices = anvil.section_blocks(section)
|
||||
wanted = [i for i, name in enumerate(palette) if name.endswith("_apricorn") or name.endswith("coal_ore")]
|
||||
cube = indices.reshape(16, 16, 16)
|
||||
for i in wanted:
|
||||
kind = "apricorns" if palette[i].endswith("_apricorn") else "coal ore"
|
||||
found[kind] += int(((cube == i) & inside[None, :, :]).sum())
|
||||
problems = [f"Button Isle has {found[k]} {k}, fewer than {n}" for k, n in START_MINIMUM.items() if found[k] < n]
|
||||
return dict(found), problems
|
||||
|
||||
|
||||
def check_border(data, level, margin):
|
||||
zs, xs = np.nonzero(island_mask(data))
|
||||
ox, oz = data["origin"]
|
||||
@@ -479,10 +514,12 @@ def main():
|
||||
listed = set(biomes["allowed"]) | set(biomes["water"])
|
||||
unlisted = {b: n for b, n in data["sections_per_biome"].items() if b not in listed}
|
||||
vein_counts, vein_problems = check_veins(args.world, data["ore_at"], data["full_chunks"], args.sample)
|
||||
start_isle, start_problems = check_start_isle(args.world)
|
||||
report = {
|
||||
"chunks_scanned": data["chunks"],
|
||||
"ore_blocks": {k: v for k, v in data["ores"].items() if ORE.search(k) or k in VEIN_BLOCKS},
|
||||
"vein_blocks_per_tier_and_zone": vein_counts,
|
||||
"start_isle_ball_materials": start_isle,
|
||||
"mob_source_blocks": {k: v for k, v in data["ores"].items() if MOB_BLOCK.search(k) or "shrieker" in k},
|
||||
"unlisted_biomes": unlisted,
|
||||
"gamerules_not_as_recipe": wrong_rules,
|
||||
@@ -502,6 +539,7 @@ def main():
|
||||
|
||||
failures = ([f"{n} {name}" for name, n in data["ores"].items() if MOB_BLOCK.search(name) or "shrieker" in name]
|
||||
+ vein_problems
|
||||
+ ([] if args.sample else start_problems)
|
||||
+ border["problems"]
|
||||
+ [f"unlisted biome {b} in {n} chunk sections" for b, n in unlisted.items()]
|
||||
+ [f"gamerule {r} is {v}, recipe says {recipe['gamerules'][r]}" for r, v in wrong_rules.items()]
|
||||
|
||||
Reference in new issue
Block a user