diff --git a/README.md b/README.md index 3c10f0b..97419b7 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,13 @@ python3 tools/quests.py ``` Generates the quest book (Phase 8) from `docs/quests.yaml` into `pack/config/ftbquests/quests/`, and the hidden advancements quests check. `tools/build.py` runs it. `--pull ` first copies node positions moved in the in-game editor back into `docs/quests.yaml` (`tools/prism_instance.py` does it from the instance before each sync); `--check` fails if the generated files are out of date. +## Legend summons + +```bash +python3 tools/summons.py && python3 tools/zone_bosses.py +``` +Writes the Sigils' recipes and data and their fights (Phase 9) from `world/summons.json`. Then run `tools/jei_sources.py` and rebuild. + ## JEI drop sources ```bash diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_articuno.json b/datapacks/core/data/cobblesurvival/bosses/summon_articuno.json new file mode 100644 index 0000000..34bbed7 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_articuno.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "articuno", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_eternatus.json b/datapacks/core/data/cobblesurvival/bosses/summon_eternatus.json new file mode 100644 index 0000000..b94ec07 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_eternatus.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "eternatus", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "poison", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "poison", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "poison", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 15, + "effect": "poison", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 15, + "effect": "poison", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_hooh.json b/datapacks/core/data/cobblesurvival/bosses/summon_hooh.json new file mode 100644 index 0000000..30bdb5a --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_hooh.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "hooh", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "fire", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "fire", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "fire", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "fire", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "fire", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_ironleaves.json b/datapacks/core/data/cobblesurvival/bosses/summon_ironleaves.json new file mode 100644 index 0000000..afae2f9 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_ironleaves.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "ironleaves", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_latias.json b/datapacks/core/data/cobblesurvival/bosses/summon_latias.json new file mode 100644 index 0000000..4f1c57d --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_latias.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "latias", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_latios.json b/datapacks/core/data/cobblesurvival/bosses/summon_latios.json new file mode 100644 index 0000000..bf4cdf2 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_latios.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "latios", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_lugia.json b/datapacks/core/data/cobblesurvival/bosses/summon_lugia.json new file mode 100644 index 0000000..9ccf0cb --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_lugia.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "lugia", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_mew.json b/datapacks/core/data/cobblesurvival/bosses/summon_mew.json new file mode 100644 index 0000000..2b4e1d8 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_mew.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "mew", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_mewtwo.json b/datapacks/core/data/cobblesurvival/bosses/summon_mewtwo.json new file mode 100644 index 0000000..3b4140c --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_mewtwo.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "mewtwo", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_moltres.json b/datapacks/core/data/cobblesurvival/bosses/summon_moltres.json new file mode 100644 index 0000000..93af569 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_moltres.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "moltres", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "fire", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "fire", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "fire", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "fire", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "fire", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_poipole.json b/datapacks/core/data/cobblesurvival/bosses/summon_poipole.json new file mode 100644 index 0000000..a3ae294 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_poipole.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "poipole", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "poison", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "poison", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "poison", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "poison", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "poison", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_rayquaza.json b/datapacks/core/data/cobblesurvival/bosses/summon_rayquaza.json new file mode 100644 index 0000000..5b0d3f9 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_rayquaza.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "rayquaza", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 15, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_regice.json b/datapacks/core/data/cobblesurvival/bosses/summon_regice.json new file mode 100644 index 0000000..c5b753e --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_regice.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "regice", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "ice", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_regidrago.json b/datapacks/core/data/cobblesurvival/bosses/summon_regidrago.json new file mode 100644 index 0000000..c19e501 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_regidrago.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "regidrago", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_regieleki.json b/datapacks/core/data/cobblesurvival/bosses/summon_regieleki.json new file mode 100644 index 0000000..e6fe563 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_regieleki.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "regieleki", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_regigigas.json b/datapacks/core/data/cobblesurvival/bosses/summon_regigigas.json new file mode 100644 index 0000000..8a4fa12 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_regigigas.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "regigigas", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_regirock.json b/datapacks/core/data/cobblesurvival/bosses/summon_regirock.json new file mode 100644 index 0000000..9f6e1dc --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_regirock.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "regirock", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_registeel.json b/datapacks/core/data/cobblesurvival/bosses/summon_registeel.json new file mode 100644 index 0000000..e30dabb --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_registeel.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "registeel", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_walkingwake.json b/datapacks/core/data/cobblesurvival/bosses/summon_walkingwake.json new file mode 100644 index 0000000..cb12b85 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_walkingwake.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "walkingwake", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_xerneas.json b/datapacks/core/data/cobblesurvival/bosses/summon_xerneas.json new file mode 100644 index 0000000..e5c1bba --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_xerneas.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "xerneas", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_zapdos.json b/datapacks/core/data/cobblesurvival/bosses/summon_zapdos.json new file mode 100644 index 0000000..883ec03 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_zapdos.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "zapdos", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 12, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/bosses/summon_zarude.json b/datapacks/core/data/cobblesurvival/bosses/summon_zarude.json new file mode 100644 index 0000000..a5e2aa0 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/bosses/summon_zarude.json @@ -0,0 +1,69 @@ +{ + "_comment": "Generated by tools/zone_bosses.py; do not edit by hand. See docs/design.md (Phase 7) for the format.", + "summon": "zarude", + "arena": 32, + "patterns": [ + { + "shape": "circle", + "radius": 3.5, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 112, + "offset": 40 + } + }, + { + "shape": "line", + "length": 14, + "width": 2, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 160, + "offset": 100 + } + }, + { + "shape": "cone", + "length": 10, + "angle": 70, + "aim": "player", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "every_ticks": 200, + "offset": 160 + } + }, + { + "shape": "ring", + "inner": 3, + "outer": 9, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.5 + } + }, + { + "shape": "ring", + "inner": 2, + "outer": 12, + "aim": "boss", + "telegraph_ticks": 30, + "damage": 13, + "effect": "none", + "trigger": { + "below_health": 0.25 + } + } + ] +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_articuno.json b/datapacks/core/data/cobblesurvival/recipe/summon_articuno.json new file mode 100644 index 0000000..06acdb9 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_articuno.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:ice_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "articuno" + }, + "minecraft:item_name": "\"Articuno Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Frostpeak Range to summon a Lv 70 Articuno\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_eternatus.json b/datapacks/core/data/cobblesurvival/recipe/summon_eternatus.json new file mode 100644 index 0000000..e28af89 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_eternatus.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:ender_eye" + }, + "R": { + "item": "minecraft:netherite_ingot" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "eternatus" + }, + "minecraft:item_name": "\"Eternatus Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in The End to summon a Lv 90 Eternatus\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_hooh.json b/datapacks/core/data/cobblesurvival/recipe/summon_hooh.json new file mode 100644 index 0000000..91465dd --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_hooh.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:sun_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "hooh" + }, + "minecraft:item_name": "\"Ho-Oh Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Highland Meadows to summon a Lv 80 Ho-Oh\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_ironleaves.json b/datapacks/core/data/cobblesurvival/recipe/summon_ironleaves.json new file mode 100644 index 0000000..0c01645 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_ironleaves.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:leaf_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "ironleaves" + }, + "minecraft:item_name": "\"Iron Leaves Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Verdant Jungle to summon a Lv 70 Iron Leaves\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_latias.json b/datapacks/core/data/cobblesurvival/recipe/summon_latias.json new file mode 100644 index 0000000..1fd5155 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_latias.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:sun_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "latias" + }, + "minecraft:item_name": "\"Latias Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Highland Meadows to summon a Lv 70 Latias\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_latios.json b/datapacks/core/data/cobblesurvival/recipe/summon_latios.json new file mode 100644 index 0000000..9041358 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_latios.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:moon_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "latios" + }, + "minecraft:item_name": "\"Latios Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Highland Meadows to summon a Lv 70 Latios\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_lugia.json b/datapacks/core/data/cobblesurvival/recipe/summon_lugia.json new file mode 100644 index 0000000..fc1ce42 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_lugia.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:water_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "lugia" + }, + "minecraft:item_name": "\"Lugia Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Deep Sea to summon a Lv 80 Lugia\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_mew.json b/datapacks/core/data/cobblesurvival/recipe/summon_mew.json new file mode 100644 index 0000000..643a757 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_mew.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:shiny_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "mew" + }, + "minecraft:item_name": "\"Mew Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Verdant Jungle to summon a Lv 80 Mew\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_mewtwo.json b/datapacks/core/data/cobblesurvival/recipe/summon_mewtwo.json new file mode 100644 index 0000000..7f1c26a --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_mewtwo.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:dusk_stone" + }, + "R": { + "item": "minecraft:netherite_ingot" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "mewtwo" + }, + "minecraft:item_name": "\"Mewtwo Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Deep Dark to summon a Lv 90 Mewtwo\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_moltres.json b/datapacks/core/data/cobblesurvival/recipe/summon_moltres.json new file mode 100644 index 0000000..1bc0ecf --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_moltres.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:fire_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "moltres" + }, + "minecraft:item_name": "\"Moltres Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Basalt Furnace to summon a Lv 70 Moltres\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_poipole.json b/datapacks/core/data/cobblesurvival/recipe/summon_poipole.json new file mode 100644 index 0000000..bbb899e --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_poipole.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:ender_pearl" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "poipole" + }, + "minecraft:item_name": "\"Poipole Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in The End to summon a Lv 70 Poipole\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_rayquaza.json b/datapacks/core/data/cobblesurvival/recipe/summon_rayquaza.json new file mode 100644 index 0000000..6022378 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_rayquaza.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:emerald_block" + }, + "R": { + "item": "minecraft:netherite_ingot" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "rayquaza" + }, + "minecraft:item_name": "\"Rayquaza Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Frostpeak Range to summon a Lv 90 Rayquaza\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_regice.json b/datapacks/core/data/cobblesurvival/recipe/summon_regice.json new file mode 100644 index 0000000..4e5f16f --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_regice.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:icy_rock" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "regice" + }, + "minecraft:item_name": "\"Regice Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Frostpeak Range to summon a Lv 70 Regice\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_regidrago.json b/datapacks/core/data/cobblesurvival/recipe/summon_regidrago.json new file mode 100644 index 0000000..02c7f96 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_regidrago.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:gold_block" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "regidrago" + }, + "minecraft:item_name": "\"Regidrago Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Sunscorch to summon a Lv 70 Regidrago\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_regieleki.json b/datapacks/core/data/cobblesurvival/recipe/summon_regieleki.json new file mode 100644 index 0000000..c48fca4 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_regieleki.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:redstone_block" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "regieleki" + }, + "minecraft:item_name": "\"Regieleki Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Westmarch to summon a Lv 70 Regieleki\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_regigigas.json b/datapacks/core/data/cobblesurvival/recipe/summon_regigigas.json new file mode 100644 index 0000000..62a3a4a --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_regigigas.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:echo_shard" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "regigigas" + }, + "minecraft:item_name": "\"Regigigas Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Deep Dark to summon a Lv 80 Regigigas\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_regirock.json b/datapacks/core/data/cobblesurvival/recipe/summon_regirock.json new file mode 100644 index 0000000..d9646ff --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_regirock.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:amethyst_shard" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "regirock" + }, + "minecraft:item_name": "\"Regirock Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Dripstone Depths to summon a Lv 70 Regirock\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_registeel.json b/datapacks/core/data/cobblesurvival/recipe/summon_registeel.json new file mode 100644 index 0000000..aa1063b --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_registeel.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:iron_block" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "registeel" + }, + "minecraft:item_name": "\"Registeel Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Deep Dark to summon a Lv 70 Registeel\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_walkingwake.json b/datapacks/core/data/cobblesurvival/recipe/summon_walkingwake.json new file mode 100644 index 0000000..644650e --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_walkingwake.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:water_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "walkingwake" + }, + "minecraft:item_name": "\"Walking Wake Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Mangrove Mire to summon a Lv 70 Walking Wake\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_xerneas.json b/datapacks/core/data/cobblesurvival/recipe/summon_xerneas.json new file mode 100644 index 0000000..3fd810a --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_xerneas.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:leaf_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "xerneas" + }, + "minecraft:item_name": "\"Xerneas Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Verdant Jungle to summon a Lv 80 Xerneas\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_zapdos.json b/datapacks/core/data/cobblesurvival/recipe/summon_zapdos.json new file mode 100644 index 0000000..0d58bce --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_zapdos.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "cobblemon:thunder_stone" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:netherite_ingot" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "zapdos" + }, + "minecraft:item_name": "\"Zapdos Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Westmarch to summon a Lv 70 Zapdos\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/recipe/summon_zarude.json b/datapacks/core/data/cobblesurvival/recipe/summon_zarude.json new file mode 100644 index 0000000..2e05410 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/recipe/summon_zarude.json @@ -0,0 +1,34 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "type": "minecraft:crafting_shaped", + "category": "misc", + "pattern": [ + "MRM", + "RCR", + "MRM" + ], + "key": { + "M": { + "item": "minecraft:redstone_block" + }, + "R": { + "item": "minecraft:diamond" + }, + "C": { + "item": "minecraft:nether_star" + } + }, + "result": { + "id": "cobblesurvival:summon_sigil", + "count": 1, + "components": { + "minecraft:custom_data": { + "cobblesurvival_summon": "zarude" + }, + "minecraft:item_name": "\"Zarude Sigil\"", + "minecraft:lore": [ + "{\"text\": \"Use in Verdant Jungle to summon a Lv 80 Zarude\", \"color\": \"gray\", \"italic\": false}" + ] + } + } +} diff --git a/datapacks/core/data/cobblesurvival/summons/articuno.json b/datapacks/core/data/cobblesurvival/summons/articuno.json new file mode 100644 index 0000000..b942284 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/articuno.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "articuno", + "level": 70, + "zone": "frostpeak" +} diff --git a/datapacks/core/data/cobblesurvival/summons/eternatus.json b/datapacks/core/data/cobblesurvival/summons/eternatus.json new file mode 100644 index 0000000..65da57d --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/eternatus.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "eternatus", + "level": 90, + "zone": "the_end" +} diff --git a/datapacks/core/data/cobblesurvival/summons/hooh.json b/datapacks/core/data/cobblesurvival/summons/hooh.json new file mode 100644 index 0000000..3a4a95d --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/hooh.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "hooh", + "level": 80, + "zone": "highlands" +} diff --git a/datapacks/core/data/cobblesurvival/summons/ironleaves.json b/datapacks/core/data/cobblesurvival/summons/ironleaves.json new file mode 100644 index 0000000..d11dceb --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/ironleaves.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "ironleaves", + "level": 70, + "zone": "jungle" +} diff --git a/datapacks/core/data/cobblesurvival/summons/latias.json b/datapacks/core/data/cobblesurvival/summons/latias.json new file mode 100644 index 0000000..53a889d --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/latias.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "latias", + "level": 70, + "zone": "highlands" +} diff --git a/datapacks/core/data/cobblesurvival/summons/latios.json b/datapacks/core/data/cobblesurvival/summons/latios.json new file mode 100644 index 0000000..bf92c22 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/latios.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "latios", + "level": 70, + "zone": "highlands" +} diff --git a/datapacks/core/data/cobblesurvival/summons/lugia.json b/datapacks/core/data/cobblesurvival/summons/lugia.json new file mode 100644 index 0000000..38ad4f6 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/lugia.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "lugia", + "level": 80, + "zone": "deep_sea" +} diff --git a/datapacks/core/data/cobblesurvival/summons/mew.json b/datapacks/core/data/cobblesurvival/summons/mew.json new file mode 100644 index 0000000..5ab4a77 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/mew.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "mew", + "level": 80, + "zone": "jungle" +} diff --git a/datapacks/core/data/cobblesurvival/summons/mewtwo.json b/datapacks/core/data/cobblesurvival/summons/mewtwo.json new file mode 100644 index 0000000..215d568 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/mewtwo.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "mewtwo", + "level": 90, + "zone": "deep_dark" +} diff --git a/datapacks/core/data/cobblesurvival/summons/moltres.json b/datapacks/core/data/cobblesurvival/summons/moltres.json new file mode 100644 index 0000000..21f5de9 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/moltres.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "moltres", + "level": 70, + "zone": "basalt" +} diff --git a/datapacks/core/data/cobblesurvival/summons/poipole.json b/datapacks/core/data/cobblesurvival/summons/poipole.json new file mode 100644 index 0000000..759ed82 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/poipole.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "poipole", + "level": 70, + "zone": "the_end" +} diff --git a/datapacks/core/data/cobblesurvival/summons/rayquaza.json b/datapacks/core/data/cobblesurvival/summons/rayquaza.json new file mode 100644 index 0000000..48e807b --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/rayquaza.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "rayquaza", + "level": 90, + "zone": "frostpeak" +} diff --git a/datapacks/core/data/cobblesurvival/summons/regice.json b/datapacks/core/data/cobblesurvival/summons/regice.json new file mode 100644 index 0000000..03af569 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/regice.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "regice", + "level": 70, + "zone": "frostpeak" +} diff --git a/datapacks/core/data/cobblesurvival/summons/regidrago.json b/datapacks/core/data/cobblesurvival/summons/regidrago.json new file mode 100644 index 0000000..a27c7c3 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/regidrago.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "regidrago", + "level": 70, + "zone": "sunscorch" +} diff --git a/datapacks/core/data/cobblesurvival/summons/regieleki.json b/datapacks/core/data/cobblesurvival/summons/regieleki.json new file mode 100644 index 0000000..8465e66 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/regieleki.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "regieleki", + "level": 70, + "zone": "westmarch" +} diff --git a/datapacks/core/data/cobblesurvival/summons/regigigas.json b/datapacks/core/data/cobblesurvival/summons/regigigas.json new file mode 100644 index 0000000..b784ec3 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/regigigas.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "regigigas", + "level": 80, + "zone": "deep_dark" +} diff --git a/datapacks/core/data/cobblesurvival/summons/regirock.json b/datapacks/core/data/cobblesurvival/summons/regirock.json new file mode 100644 index 0000000..602af1b --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/regirock.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "regirock", + "level": 70, + "zone": "dripstone" +} diff --git a/datapacks/core/data/cobblesurvival/summons/registeel.json b/datapacks/core/data/cobblesurvival/summons/registeel.json new file mode 100644 index 0000000..091ddd4 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/registeel.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "registeel", + "level": 70, + "zone": "deep_dark" +} diff --git a/datapacks/core/data/cobblesurvival/summons/walkingwake.json b/datapacks/core/data/cobblesurvival/summons/walkingwake.json new file mode 100644 index 0000000..412249b --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/walkingwake.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "walkingwake", + "level": 70, + "zone": "mire" +} diff --git a/datapacks/core/data/cobblesurvival/summons/xerneas.json b/datapacks/core/data/cobblesurvival/summons/xerneas.json new file mode 100644 index 0000000..be848d6 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/xerneas.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "xerneas", + "level": 80, + "zone": "jungle" +} diff --git a/datapacks/core/data/cobblesurvival/summons/zapdos.json b/datapacks/core/data/cobblesurvival/summons/zapdos.json new file mode 100644 index 0000000..9673f99 --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/zapdos.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "zapdos", + "level": 70, + "zone": "westmarch" +} diff --git a/datapacks/core/data/cobblesurvival/summons/zarude.json b/datapacks/core/data/cobblesurvival/summons/zarude.json new file mode 100644 index 0000000..53f3a3f --- /dev/null +++ b/datapacks/core/data/cobblesurvival/summons/zarude.json @@ -0,0 +1,6 @@ +{ + "_comment": "Generated by tools/summons.py from world/summons.json; do not edit by hand.", + "species": "zarude", + "level": 80, + "zone": "jungle" +} diff --git a/docs/balance.md b/docs/balance.md index 9be4fbe..2c5820f 100644 --- a/docs/balance.md +++ b/docs/balance.md @@ -54,6 +54,7 @@ Every tunable lives in a config file or in this table. **Placeholder** means gue | Regenerators breakable by players | no; explosions don't hurt veins | Fine for now (Adrian, 2026-10-30) | `tools/zone_ores.py` → `global.json` | Otherwise a player could remove a vein for good | | Respawn block (regenerator) | the player's aim passes through it unless sneaking, so ore behind it can be mined; no collision (the mod's own); glass about 9 % opaque with a 27 % edge (was stained glass, about 50 %) | Adrian, 2026-11-09 | `mod/src/main/java/.../RegeneratorBlockMixin.java`; `pack/kubejs/assets/regenerating_ore_veins/` | Sneak-use still shows its info | | Homeless lines | 31 lines with no matching biome on the island: rare bucket, weight 10, at the zone's levels, anywhere in the zone | Placeholder (Adrian, 2026-11-09: rare, in fitting zones) | `world/zones.json` → `homeless` → `tools/zone_spawns.py` | Which zone each lives in is listed there and in `docs/zone-species.md` | +| Legend summons | 22 Sigils; tier 1 Lv 70: 4 zone material, 4 diamonds, netherite ingot; tier 2 Lv 80: 4 material, 4 diamonds, nether star; tier 3 Lv 90 (Rayquaza, Mewtwo, Eternatus): 4 material, 4 netherite ingots, nether star; one at a time within 96 blocks; fight as a boss with the Guardian's Ward, arena 32 | Placeholder (Adrian, 2026-11-09: crafted summons) | `world/summons.json` → `tools/summons.py`, `tools/zone_bosses.py` (`SUMMON_ARENA`) | Nether stars come from the Sacrifice Altar at Lv 100 | | Vein Locator | compass + copper ingot; 75 % chance to break per use (the mod's default) | Fine for now (Adrian, 2026-10-30) | `tools/zone_ores.py` → `vein_locator.json` | The mod's default recipe needs netherite | | Drops for mobs the island lacks | Blaze Rod: Carkol 10 %, Torkoal 25 % ×1–2; Ghast Tear: Drifloon 5 %, Dusclops 10 %; Breeze Rod: Whimsicott 10 %; Shulker Shell: Shuckle 10 %, Cloyster 10 %; Nether Star: Charizard 5 % | Fine for now (Adrian, 2026-10-30) | `datapacks/core/data/cobblesurvival/species_additions/` | Every drop and what consumes it: `docs/pokemon-drops.md` (`tools/drop_audit.py`) | | Cobblebase skill gates | start: gatherer, harvester, irrigator, producer, furnace fuel, water fill, extinguisher, scout, guard; Button Isle: fishing, forager, botanist, collector, snow fill, brewing fuel, craftsman; Southwold: pharmacist, scholar, mentor (passive XP), lava fill; Westmarch: mining, excavator, architect, armorer, diving; Verdant Jungle: alchemist, trainer, smith, prospector, growth aura; Highland Meadows: speed, jump, haste, night vision, water breathing, saturation buffs; Mangrove Mire: resistance, strength buffs; Sunscorch: friend recruiter, aura boost; Frostpeak: healer, lucky charm; Deep Dark: breeder, egg hatcher | Placeholder | `datapacks/core/data/cobblesurvival/progression_gates/base.json` → `cobblebase_skills` | A zone means its soft gate, checked on the pastured Pokémon (see "Soft gate levels and materials") | diff --git a/docs/checklists/phase-9.md b/docs/checklists/phase-9.md index 425aa72..ec4b381 100644 --- a/docs/checklists/phase-9.md +++ b/docs/checklists/phase-9.md @@ -8,12 +8,15 @@ - **Ore veins:** rarer nodes and wider vein spacing, one block larger in radius. Needs a new island: the save "Cobblemon Survival Island (new veins)" has it. Your other saves keep their old veins. - **Respawn block:** much fainter glass; you aim through it unless sneaking. Automated: `regenerator_lets_the_aim_through`. +- **Legend summons:** 22 Sigils, crafted from late-game materials (search "Sigil" in JEI). Used in the zone written on one, it summons a catchable legend that fights like a boss. Automated: `every_implemented_pokemon_is_obtainable`, `sigil_summons_a_catchable_legend`. The Legends chapter in the quest book lists them. - **Left-out Pokémon:** 31 lines (67 species) spawn rarely in fitting zones (`docs/zone-species.md`). Automated: `spawn_pools_are_zoned`, `drop_sources_match_the_server`. ## In game (Prism instance) - [ ] In the new save, mine into an ore node or vein: the mined blocks turn into faint glass, and you can keep aiming and mining the ore behind them. Sneak and use one: its info still shows. - [ ] Do nodes and veins feel right: fewer, bigger? The island has 1.5–3× the old ore; tell me if that's too much. +- [ ] Give yourself a Sigil from JEI (creative) and use it outside its zone: it refuses and says where it works. Use it in its zone: the legend appears with a sound and particles. Fight it: area attacks, at most a quarter of its HP per attack. Weaken it and catch it; afterwards it's an ordinary Pokémon in your party (no quarter-HP limit in later battles). +- [ ] Is a Sigil the right cost, and the fight the right difficulty? - [ ] Spend time in Frostpeak or the Deep Sea: now and then a Beartic, Mamoswine, Empoleon or Walrein turns up. JEI's Island Drops page names the zone. ## Ask Adrian diff --git a/docs/design.md b/docs/design.md index e6c642e..9d8ce5d 100644 --- a/docs/design.md +++ b/docs/design.md @@ -329,7 +329,11 @@ Adrian's choices: Pokémon with no biome on the island become rare spawns in fit **Every implemented Pokémon is obtainable** (roadmap). Of 905 implemented species, 95 were out of reach by wild spawn or by evolving a wild line (2026-11-09): - 5 fossils (Aerodactyl, Arctovish, Arctozolt, Dracovish, Dracozolt): already obtainable. The field guide lists their fossils as found on the island, and the fossil machines are craftable. - 67 species in 31 lines that spawn only in biomes the island lacks, or not at all (Rotom): each line gets a home in the closest-fitting zone (`world/zones.json` → `homeless`), as a rare spawn anywhere in that zone at its levels. Conditions tied to the missing biomes are dropped. Existing spawns and homes don't move. They show in `docs/zone-species.md` and in JEI. -- 23 legendaries, mythicals, Ultra Beasts and Paradox Pokémon, with no spawn data: crafted summons (to do). +- 23 legendaries, mythicals, Ultra Beasts and Paradox Pokémon, with no spawn data: crafted summons (below). Naganadel comes from evolving Poipole, so 22 Sigils. + +**Crafted summons** (Adrian, 2026-11-09). Each legend has a Sigil (`cobblesurvival:summon_sigil`, one item told apart by its custom data), crafted from four of a zone material, four of a ring item and a core: tier 1 (Lv 70) diamond and netherite ingot, tier 2 (Lv 80) diamond and nether star, tier 3 (Lv 90: Rayquaza, Mewtwo, Eternatus) netherite ingots and nether star. Used in the zone written on it, it summons a wild one six blocks ahead, one at a time within 96 blocks. It fights like a boss (`bosses/summon_.json`: area attacks by level and type, a 32-block arena, the Guardian's Ward, so at most a quarter of its HP per attack), except it can be caught: the pack's usual catching rules apply. On capture it loses every boss mark and is an ordinary Pokémon. If it's knocked out, the Sigil is spent; if the fight is lost it heals and stays. Which zone, tier and material: `world/summons.json` → `tools/summons.py` (recipes and data, with the name and "use in" text on the recipe's result so the client needs no server data). The quest book has a Legends chapter with a quest per Sigil; JEI lists each Sigil as its own item, and the Island Drops pages say where a legend is summoned. Moltres, Regigigas and Eternatus are guardians too: those stay uncatchable, the summoned ones are separate. + +Self-tests: `every_implemented_pokemon_is_obtainable` (every implemented species' line spawns, comes from a fossil or has a Sigil; a new Cobblemon version adding species fails it until they have a home), `sigil_summons_a_catchable_legend`. **Ore veins** (Adrian, 2026-11-09: more sporadic but bigger). Nodes are about 40 % rarer and veins about 30 % further apart, each one block larger in radius; the bigger size outweighs the spacing, so the island holds 1.5–3× the ore. Veins are laid down when chunks generate, so this needs a newly generated island. diff --git a/docs/quests.yaml b/docs/quests.yaml index 144280f..b0a42c5 100644 --- a/docs/quests.yaml +++ b/docs/quests.yaml @@ -15,7 +15,8 @@ # checkmark: true the player ticks it # A task may also have a title. A chapter with `zone: ` starts with the quests of `zone_chapter`, where # {zone}, {low}, {high}, {hazard_text}, {guardian}, {guardian_level}, {drops} and {ore_names} come from the -# zone's data; a template quest with `when:` is left out of zones that lack the thing named. +# zone's data; a template quest with `when:` is left out of zones that lack the thing named. A chapter with +# `summons: true` adds a quest per Sigil (world/summons.json), `columns: ` lays those out in a grid. book: title: Cobblemon Survival @@ -260,6 +261,24 @@ chapters: - event: end_boss title: Beat Eternatus + - id: legends + title: Legends + subtitle: What never spawns on its own + icon: cobblesurvival:summon_sigil + summons: true + columns: 6 + quests: + - id: about + title: Calling a Legend + icon: cobblesurvival:summon_sigil + size: 1.5 + text: | + Legendary Pokémon don't spawn on their own. Each has a Sigil you can craft from late-game materials: look "Sigil" up in JEI. Using one in the zone written on it summons the Pokémon. + It fights like a guardian, area attacks and all, but this one can be caught. If it's knocked out, the Sigil is lost. + tasks: + - checkmark: true + title: Read this + - id: machines title: Pokémon Machines subtitle: Five machines, each powered by a Pokémon inside it diff --git a/mod/src/main/kotlin/dev/cobblesurvival/CobbleSurvival.kt b/mod/src/main/kotlin/dev/cobblesurvival/CobbleSurvival.kt index 3a10077..314e7a3 100644 --- a/mod/src/main/kotlin/dev/cobblesurvival/CobbleSurvival.kt +++ b/mod/src/main/kotlin/dev/cobblesurvival/CobbleSurvival.kt @@ -22,6 +22,7 @@ import dev.cobblesurvival.world.OnlyPokemon import dev.cobblesurvival.world.SharedLoot import dev.cobblesurvival.world.SpecialPokemon import dev.cobblesurvival.progress.QuestEvents +import dev.cobblesurvival.summon.Summons import dev.cobblesurvival.zone.GuardianBars import dev.cobblesurvival.zone.Guardians import dev.cobblesurvival.zone.InZoneCondition @@ -70,6 +71,7 @@ class CobbleSurvival { MOD_BUS.addListener(::onAddPackFinders) InZoneCondition.register(MOD_BUS) Machines.register(MOD_BUS) + Summons.register(MOD_BUS) NeoForge.EVENT_BUS.addListener(::onRegisterCommands) NeoForge.EVENT_BUS.addListener(::onServerStarted) NeoForge.EVENT_BUS.addListener(::onPortalSpawn) diff --git a/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSources.kt b/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSources.kt index d47262b..e33e30b 100644 --- a/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSources.kt +++ b/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSources.kt @@ -17,7 +17,9 @@ object DropSources { class Reward(val item: String, val count: Int) class Spawned(val zone: String, val levels: String) class LineMember(val zone: String, val species: String) - class Pokemon(val species: String, val drops: List, val zones: List, val line: List?) + class SummonedAt(val zone: String, val level: Int) + class Summon(val species: String, val name: String, val zone: String, val level: Int) + class Pokemon(val species: String, val drops: List, val zones: List, val line: List?, val summon: SummonedAt?) class SpawnDrops(val species: String, val zone: String, val drops: List) class Guardian(val zone: String, val species: String, val level: Int, val drops: List, val respawn_hours: Double) class EndBoss(val species: String, val level: Int, val xp_first_win: Int, val xp: Int, val respawn_hours: Double, val first_win: List) @@ -33,6 +35,7 @@ object DropSources { class Data( val zones: Map, val pokemon: List, + val summons: List, val spawn_drops: List, val guardians: List, val end_boss: EndBoss, @@ -56,6 +59,9 @@ object DropSources { return ItemStack(found, count.coerceIn(1, 99)) } + /** Cobblemon's own tables can name an item it doesn't have (Ho-Oh's Sacred Ash in 1.8.4): it never drops, so it gets no slot. */ + fun exists(item: String): Boolean = BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(item)) + /** The most a drop gives: "0-2" → 2. */ fun most(count: String?): Int = count?.substringAfter('-')?.toIntOrNull() ?: 1 } diff --git a/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSourcesJei.kt b/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSourcesJei.kt index 3ce2c1e..6c239a7 100644 --- a/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSourcesJei.kt +++ b/mod/src/main/kotlin/dev/cobblesurvival/jei/DropSourcesJei.kt @@ -4,25 +4,34 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties import com.cobblemon.mod.common.api.pokemon.PokemonSpecies import com.cobblemon.mod.common.item.PokemonItem import dev.cobblesurvival.CobbleSurvival +import dev.cobblesurvival.summon.Summons import mezz.jei.api.IModPlugin import mezz.jei.api.JeiPlugin import mezz.jei.api.gui.builder.IRecipeLayoutBuilder import mezz.jei.api.gui.drawable.IDrawable import mezz.jei.api.gui.ingredient.IRecipeSlotsView +import mezz.jei.api.ingredients.subtypes.ISubtypeInterpreter +import mezz.jei.api.ingredients.subtypes.UidContext import mezz.jei.api.recipe.IFocusGroup import mezz.jei.api.recipe.RecipeIngredientRole import mezz.jei.api.recipe.RecipeType import mezz.jei.api.recipe.category.IRecipeCategory import mezz.jei.api.registration.IRecipeCatalystRegistration import mezz.jei.api.registration.IRecipeCategoryRegistration +import mezz.jei.api.registration.IExtraIngredientRegistration import mezz.jei.api.registration.IRecipeRegistration +import mezz.jei.api.registration.ISubtypeRegistration import net.minecraft.ChatFormatting import net.minecraft.client.Minecraft import net.minecraft.client.gui.Font import net.minecraft.client.gui.GuiGraphics +import net.minecraft.core.component.DataComponents +import net.minecraft.nbt.CompoundTag import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.component.CustomData +import net.minecraft.world.item.component.ItemLore /** * The pack's own JEI pages (roadmap Phase 8; Adrian, 2026-11-02: every item that can drop gets a page naming where it @@ -58,6 +67,19 @@ class DropSourcesJei : IModPlugin { override fun getPluginUid(): ResourceLocation = ResourceLocation.fromNamespaceAndPath(CobbleSurvival.MOD_ID, "drop_sources") + /** Each Sigil counts as an item of its own, by the species in its custom data. */ + override fun registerItemSubtypes(registration: ISubtypeRegistration) { + registration.registerSubtypeInterpreter(Summons.SIGIL.get(), object : ISubtypeInterpreter { + override fun getSubtypeData(stack: ItemStack, context: UidContext): Any? = Summons.speciesOf(stack) + override fun getLegacyStringSubtypeInfo(stack: ItemStack, context: UidContext): String = Summons.speciesOf(stack).orEmpty() + }) + } + + /** The Sigils aren't in a creative tab (they need a species), so JEI wouldn't list them otherwise. */ + override fun registerExtraIngredients(registration: IExtraIngredientRegistration) { + registration.addExtraItemStacks(sigils()) + } + override fun registerCategories(registration: IRecipeCategoryRegistration) { val gui = registration.jeiHelpers.guiHelper registration.addRecipeCategories(*kinds.map { kind -> @@ -177,18 +199,31 @@ class DropSourcesJei : IModPlugin { private fun zoneRow(zone: String, levels: String) = Row(text(DropSources.zoneName(zone)), text("Lv ${levels.replace("-", "–")}")) + /** Each Sigil as its recipe makes it: the species, its name and where to use it. */ + fun sigils(): List = DropSources.data.summons.map { s -> + ItemStack(Summons.SIGIL.get()).apply { + val data = CompoundTag().apply { putString(Summons.KEY, s.species.substringAfter(':')) } + set(DataComponents.CUSTOM_DATA, CustomData.of(data)) + set(DataComponents.ITEM_NAME, Component.literal("${s.name} Sigil")) + set(DataComponents.LORE, ItemLore(listOf(Component.literal("Use in ${DropSources.zoneName(s.zone)} to summon a Lv ${s.level} ${s.name}") + .withStyle { it.withColor(ChatFormatting.GRAY).withItalic(false) }))) + } + } + fun pokemonPages(): List { val data = DropSources.data val wild = data.pokemon.map { p -> val rows = if (p.zones.isNotEmpty()) { p.zones.map { zoneRow(it.zone, it.levels) } + } else if (p.summon != null) { + listOf(Row(muted("Not wild. A Sigil summons it in:")), Row(text(DropSources.zoneName(p.summon.zone)), text("Lv ${p.summon.level}"))) } else { listOf(Row(muted("Not wild. Its line lives in:"))) + p.line.orEmpty().map { Row(text(DropSources.zoneName(it.zone)), speciesName(it.species)) } } - Page(picture(p.species), speciesName(p.species), "Drops", rows, p.drops.map(::dropOutput)) + Page(picture(p.species), speciesName(p.species), "Drops", rows, p.drops.filter { DropSources.exists(it.item) }.map(::dropOutput)) } val special = data.spawn_drops.map { s -> - Page(picture(s.species), speciesName(s.species), "Drops here", listOf(Row(text(DropSources.zoneName(s.zone)), text("instead"))), s.drops.map(::dropOutput)) + Page(picture(s.species), speciesName(s.species), "Drops here", listOf(Row(text(DropSources.zoneName(s.zone)), text("instead"))), s.drops.filter { DropSources.exists(it.item) }.map(::dropOutput)) } return wild + special } diff --git a/mod/src/main/kotlin/dev/cobblesurvival/selftest/QuestTests.kt b/mod/src/main/kotlin/dev/cobblesurvival/selftest/QuestTests.kt index b9bc485..7685f9d 100644 --- a/mod/src/main/kotlin/dev/cobblesurvival/selftest/QuestTests.kt +++ b/mod/src/main/kotlin/dev/cobblesurvival/selftest/QuestTests.kt @@ -2,14 +2,22 @@ package dev.cobblesurvival.selftest import com.cobblemon.mod.common.api.drop.DropTable import com.cobblemon.mod.common.api.drop.ItemDropEntry +import com.cobblemon.mod.common.api.fossil.Fossils import com.cobblemon.mod.common.api.pokemon.PokemonSpecies import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail +import com.cobblemon.mod.common.entity.pokemon.PokemonEntity +import com.cobblemon.mod.common.pokemon.Species +import dev.cobblesurvival.CobbleSurvival import dev.cobblesurvival.boss.BossDefs +import dev.cobblesurvival.boss.BossFights +import dev.cobblesurvival.boss.BossToughness import dev.cobblesurvival.jei.DropSources import dev.cobblesurvival.jei.DropSourcesJei import dev.cobblesurvival.machine.MachineDefs import dev.cobblesurvival.progress.QuestEvents +import dev.cobblesurvival.summon.Summons +import dev.cobblesurvival.world.SpecialPokemon import dev.cobblesurvival.zone.Guardians import dev.cobblesurvival.zone.Zones import java.util.function.Consumer @@ -32,8 +40,75 @@ object QuestTests { SelfTestCase("quest_events_mark_zones", 200, ::zoneEvent), SelfTestCase("drop_sources_match_the_server", 20, ::dropSources), SelfTestCase("jei_pages_build", 20, ::jeiPages), + SelfTestCase("every_implemented_pokemon_is_obtainable", 20, ::obtainable), + SelfTestCase("sigil_summons_a_catchable_legend", 200, ::summon), ) + private fun rootOf(species: Species): Species { + var current = species + val seen = HashSet() + while (seen.add(current)) current = current.preEvolution?.species ?: return current + return current + } + + /** + * Roadmap Phase 9 (Adrian, 2026-11-09): every species Cobblemon has a model for can be had without commands: its line + * spawns somewhere, comes from a fossil, or has a Sigil. A new Cobblemon version adding species fails this until + * they have a home. + */ + private fun obtainable(s: Scenario) { + val wild = CobblemonSpawnPools.WORLD_SPAWN_POOL.details.filterIsInstance().mapNotNull { it.pokemon.species } + val fossils = Fossils.all().mapNotNull { it.result.species } + val summons = Summons.defs.keys + val reachable = (wild + fossils + summons).mapNotNull { PokemonSpecies.getByName(it.substringAfter(':')) }.map(::rootOf).toSet() + val missing = PokemonSpecies.implemented.filter { rootOf(it) !in reachable } + s.check(missing.isEmpty()) { "${missing.size} implemented Pokémon can't be obtained: ${missing.take(12).joinToString { it.name }}" } + s.helper.succeed() + } + + /** A Sigil works only in its zone, summons a catchable legend that fights as a boss, and once caught it's ordinary. */ + private fun summon(s: Scenario) { + val level = s.level + val player = s.player() + val sigil = DropSourcesJei.sigils().first { Summons.speciesOf(it) == "zapdos" } + val recipe = level.server.recipeManager.byKey(ResourceLocation.fromNamespaceAndPath(CobbleSurvival.MOD_ID, "summon_zapdos")).orElse(null) + ?: throw GameTestAssertException("the Zapdos Sigil has no recipe") + val made = recipe.value.getResultItem(level.registryAccess()) + s.check(Summons.speciesOf(made) == "zapdos" && made.hoverName.string == "Zapdos Sigil") { "the recipe makes '${made.hoverName.string}' for ${Summons.speciesOf(made)}" } + val missingRecipes = Summons.defs.keys.filter { level.server.recipeManager.byKey(ResourceLocation.fromNamespaceAndPath(CobbleSurvival.MOD_ID, "summon_$it")).isEmpty } + s.check(missingRecipes.isEmpty()) { "no recipe for the Sigils of $missingRecipes" } + val elsewhere = Zones.samples["button_isle"] ?: throw GameTestAssertException("no sample point for Button Isle") + val home = Zones.samples["westmarch"] ?: throw GameTestAssertException("no sample point for Westmarch") + fun ground(x: Int, z: Int) = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z).toDouble() + fun summoned() = level.getEntitiesOfClass(PokemonEntity::class.java, player.boundingBox.inflate(32.0)) { it.pokemon.persistentData.contains(Summons.TAG) } + s.afterTest { summoned().forEach { it.discard() } } + s.helper.startSequence() + .thenExecute { + level.getChunk(elsewhere.x shr 4, elsewhere.z shr 4) + s.moveTo(player, elsewhere.x + 0.5, ground(elsewhere.x, elsewhere.z), elsewhere.z + 0.5) + } + .thenWaitUntil { s.check(level.isPositionEntityTicking(player.blockPosition())) { "Button Isle isn't loaded yet" } } + .thenExecute { + s.check(!Summons.summon(level, player, sigil) && summoned().isEmpty()) { "the Sigil worked outside its zone" } + level.getChunk(home.x shr 4, home.z shr 4) + s.moveTo(player, home.x + 0.5, ground(home.x, home.z), home.z + 0.5) + } + .thenWaitUntil { s.check(level.isPositionEntityTicking(player.blockPosition())) { "Westmarch isn't loaded yet" } } + .thenExecute { + s.check(Summons.summon(level, player, sigil)) { "the Sigil didn't work in its zone" } + val legend = summoned().singleOrNull() ?: throw GameTestAssertException("${summoned().size} legends appeared") + val pokemon = legend.pokemon + s.check(pokemon.species.name == "Zapdos" && pokemon.level == Summons.defs.getValue("zapdos").level) { "summoned ${pokemon.species.name} Lv ${pokemon.level}" } + s.check(!pokemon.isUncatchable() && BossFights.defOf(legend) != null && BossToughness.isBoss(pokemon)) { "the legend isn't a catchable boss" } + s.check(SpecialPokemon.isExempt(pokemon)) { "the wild-Pokémon rules would remove the legend" } + s.check(!Summons.summon(level, player, sigil)) { "a second legend came while the first was here" } + Summons.released(pokemon) + s.check(!BossToughness.isBoss(pokemon) && !SpecialPokemon.isExempt(pokemon)) { "a caught legend still counts as a boss" } + legend.discard() + } + .thenSucceed() + } + /** * Every JEI page builds (the same code JEI calls on the client), one per Pokémon, guardian, altar tier, vein zone * and pasture list, and every item on them exists (an unknown id would show as a barrier). diff --git a/mod/src/main/kotlin/dev/cobblesurvival/summon/Summons.kt b/mod/src/main/kotlin/dev/cobblesurvival/summon/Summons.kt new file mode 100644 index 0000000..3b5642e --- /dev/null +++ b/mod/src/main/kotlin/dev/cobblesurvival/summon/Summons.kt @@ -0,0 +1,145 @@ +package dev.cobblesurvival.summon + +import com.cobblemon.mod.common.api.Priority +import com.cobblemon.mod.common.api.events.CobblemonEvents +import com.cobblemon.mod.common.api.pokemon.PokemonProperties +import com.cobblemon.mod.common.entity.pokemon.PokemonEntity +import com.cobblemon.mod.common.pokemon.Pokemon +import com.google.gson.Gson +import com.google.gson.JsonElement +import dev.cobblesurvival.CobbleSurvival +import dev.cobblesurvival.boss.BossFights +import dev.cobblesurvival.zone.Zones +import net.minecraft.ChatFormatting +import net.minecraft.core.BlockPos +import net.minecraft.core.component.DataComponents +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerLevel +import net.minecraft.server.level.ServerPlayer +import net.minecraft.server.packs.resources.ResourceManager +import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener +import net.minecraft.sounds.SoundEvents +import net.minecraft.sounds.SoundSource +import net.minecraft.util.Mth +import net.minecraft.util.profiling.ProfilerFiller +import net.minecraft.world.InteractionHand +import net.minecraft.world.InteractionResultHolder +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Rarity +import net.minecraft.world.level.Level +import net.minecraft.world.phys.Vec3 +import net.neoforged.bus.api.IEventBus +import net.neoforged.neoforge.common.NeoForge +import net.neoforged.neoforge.event.AddReloadListenerEvent +import net.neoforged.neoforge.registries.DeferredHolder +import net.neoforged.neoforge.registries.DeferredRegister +import java.util.function.Supplier + +/** + * Crafted summons (Adrian, 2026-11-09): legendaries, mythicals, Ultra Beasts and Paradox Pokémon have no spawn data, so + * each has a Sigil, used in a fitting zone, that summons a catchable wild one. It fights as a boss would (area attacks + * and the Guardian's Ward, [BossFights]) until it's caught, when it becomes an ordinary Pokémon ([released]). One item, + * told apart by its custom data; the recipe's result also carries its name and where to use it, so the client needs + * none of this. Definitions: `data/cobblesurvival/summons/.json`, written by tools/summons.py. + */ +object Summons : SimpleJsonResourceReloadListener(Gson(), "summons") { + /** Key in the sigil's custom data; its value is the species. */ + const val KEY = "cobblesurvival_summon" + /** Key in a summoned Pokémon's persistent data, for as long as it's wild. */ + const val TAG = "cobblesurvival_summoned" + /** How far ahead of the player it appears. */ + private const val DISTANCE = 6.0 + /** Only one at a time within this many blocks, so sigils can't be stacked into one place. */ + private const val NEARBY = 96.0 + private const val FLOOR_ABOVE = 4 + private const val FLOOR_BELOW = 8 + + class Def(val species: String, val level: Int, val zone: String) + + var defs: Map = emptyMap() + private set + + private val ITEMS = DeferredRegister.createItems(CobbleSurvival.MOD_ID) + val SIGIL: DeferredHolder = ITEMS.register("summon_sigil", Supplier { SummonSigil(Item.Properties().stacksTo(1).rarity(Rarity.EPIC)) }) + + fun register(bus: IEventBus) { + ITEMS.register(bus) + NeoForge.EVENT_BUS.addListener { it.addListener(this) } + CobblemonEvents.POKEMON_CAPTURED.subscribe(Priority.NORMAL) { released(it.pokemon) } + } + + override fun apply(files: Map, resources: ResourceManager, profiler: ProfilerFiller) { + defs = files.values.map { it.asJsonObject }.associate { + it.get("species").asString to Def(it.get("species").asString, it.get("level").asInt, it.get("zone").asString) + } + CobbleSurvival.LOGGER.info("Loaded {} summons", defs.size) + } + + /** Caught: from here on it's an ordinary Pokémon, without the boss rules. */ + fun released(pokemon: Pokemon) { + pokemon.persistentData.remove(TAG) + pokemon.persistentData.remove(BossFights.TAG) + } + + fun speciesOf(stack: ItemStack): String? = + stack.get(DataComponents.CUSTOM_DATA)?.copyTag()?.getString(KEY)?.takeIf { it.isNotEmpty() } + + private fun tell(player: ServerPlayer, message: Component) = player.displayClientMessage(message, true) + + /** Where it appears: on the floor a little ahead of the player, or level with them when there's none (at sea). */ + private fun spot(level: ServerLevel, player: ServerPlayer): Vec3 { + val look = player.lookAngle + val ahead = player.position().add(Vec3(look.x, 0.0, look.z).normalize().scale(DISTANCE)) + val x = Mth.floor(ahead.x) + val z = Mth.floor(ahead.z) + for (y in player.blockY + FLOOR_ABOVE downTo player.blockY - FLOOR_BELOW) { + val pos = BlockPos(x, y, z) + if (level.getBlockState(pos).isAir && level.getBlockState(pos.below()).isSolid) return Vec3.atBottomCenterOf(pos) + } + return ahead + } + + /** Summons what [stack] calls for, if this is the place; true when it appeared and the sigil is spent. */ + fun summon(level: ServerLevel, player: ServerPlayer, stack: ItemStack): Boolean { + val def = speciesOf(stack)?.let { defs[it] } ?: run { + tell(player, Component.translatableWithFallback("message.cobblesurvival.summon.blank", "This sigil is blank.").withStyle(ChatFormatting.RED)) + return false + } + if (Zones.at(level, player.blockPosition())?.id != def.zone) { + tell(player, Component.translatableWithFallback("message.cobblesurvival.summon.wrong_zone", "This sigil only answers in %s.", + Zones.byId[def.zone]?.name ?: def.zone).withStyle(ChatFormatting.RED)) + return false + } + if (level.getEntitiesOfClass(PokemonEntity::class.java, player.boundingBox.inflate(NEARBY)) { it.pokemon.persistentData.contains(TAG) }.isNotEmpty()) { + tell(player, Component.translatableWithFallback("message.cobblesurvival.summon.busy", "Another legend is already here.").withStyle(ChatFormatting.RED)) + return false + } + val pokemon = PokemonProperties.parse("${def.species} level=${def.level}").create() + pokemon.persistentData.putBoolean(TAG, true) + pokemon.persistentData.putString(BossFights.TAG, "${CobbleSurvival.MOD_ID}:summon_${def.species}") + val entity = PokemonEntity(level, pokemon) + val at = spot(level, player) + entity.moveTo(at.x, at.y, at.z, player.yRot + 180f, 0f) + entity.setPersistenceRequired() + if (!level.addFreshEntity(entity)) return false + level.playSound(null, at.x, at.y, at.z, SoundEvents.WITHER_SPAWN, SoundSource.HOSTILE, 0.8f, 1.1f) + level.sendParticles(ParticleTypes.END_ROD, at.x, at.y + 1.0, at.z, 60, 1.2, 1.5, 1.2, 0.08) + player.sendSystemMessage(Component.translatableWithFallback("message.cobblesurvival.summon.answered", + "%s answers the sigil. Battle it and catch it: if it's knocked out, the sigil is lost.", pokemon.getDisplayName()).withStyle(ChatFormatting.GOLD)) + CobbleSurvival.LOGGER.info("{} summoned {} at {}", player.gameProfile.name, def.species, BlockPos.containing(at).toShortString()) + return true + } +} + +/** A Sigil: use it in its zone (written on it) to summon its legendary. */ +class SummonSigil(properties: Properties) : Item(properties) { + override fun use(level: Level, player: Player, hand: InteractionHand): InteractionResultHolder { + val stack = player.getItemInHand(hand) + if (level is ServerLevel && player is ServerPlayer && Summons.summon(level, player, stack) && !player.isCreative) stack.shrink(1) + return InteractionResultHolder.sidedSuccess(stack, level.isClientSide) + } +} diff --git a/mod/src/main/kotlin/dev/cobblesurvival/world/SpecialPokemon.kt b/mod/src/main/kotlin/dev/cobblesurvival/world/SpecialPokemon.kt index 04d2ca4..efe35a4 100644 --- a/mod/src/main/kotlin/dev/cobblesurvival/world/SpecialPokemon.kt +++ b/mod/src/main/kotlin/dev/cobblesurvival/world/SpecialPokemon.kt @@ -3,6 +3,7 @@ package dev.cobblesurvival.world import com.cobblemon.mod.common.entity.pokemon.PokemonEntity import com.cobblemon.mod.common.pokemon.Pokemon import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty +import dev.cobblesurvival.boss.BossFights import dev.cobblesurvival.zone.Guardians import net.minecraft.server.TickTask import net.minecraft.server.level.ServerLevel @@ -11,7 +12,7 @@ import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent /** * Wild Pokémon that the island's rules for wild Pokémon (strays despawning, hunting weaker trainers) leave alone: - * guardians, anything uncatchable, and other mods' characters that are Pokémon underneath, such as Cobblemon HMs' + * guardians, summoned legendaries while they're wild, anything uncatchable, and other mods' characters that are Pokémon underneath, such as Cobblemon HMs' * visiting Trainer Ditto, which sells TMs. * * The Trainer Ditto is also made uncatchable (Adrian, 2026-10-31: Ditto, which breeds with anything, is a rare find in @@ -26,7 +27,7 @@ object SpecialPokemon { } fun isExempt(pokemon: Pokemon): Boolean = - pokemon.isUncatchable() || pokemon.persistentData.contains(Guardians.TAG) || isTrainerDitto(pokemon) + pokemon.isUncatchable() || pokemon.persistentData.contains(Guardians.TAG) || pokemon.persistentData.contains(BossFights.TAG) || isTrainerDitto(pokemon) fun isTrainerDitto(pokemon: Pokemon): Boolean = pokemon.persistentData.contains(HMS_TRAINER) diff --git a/mod/src/main/resources/assets/cobblesurvival/jei/drop_sources.json b/mod/src/main/resources/assets/cobblesurvival/jei/drop_sources.json index c79fcae..217764a 100644 --- a/mod/src/main/resources/assets/cobblesurvival/jei/drop_sources.json +++ b/mod/src/main/resources/assets/cobblesurvival/jei/drop_sources.json @@ -774,6 +774,28 @@ } ] }, + { + "species": "cobblemon:articuno", + "drops": [ + { + "item": "minecraft:feather", + "count": "2-4" + }, + { + "item": "minecraft:chicken", + "count": "1" + }, + { + "item": "cobblemon:never_melt_ice", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "frostpeak", + "level": 70 + } + }, { "species": "cobblemon:audino", "drops": [ @@ -7994,6 +8016,24 @@ } ] }, + { + "species": "cobblemon:hooh", + "drops": [ + { + "item": "minecraft:feather", + "count": "2-4" + }, + { + "item": "cobblemon:sacred_ash", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "highlands", + "level": 80 + } + }, { "species": "cobblemon:hoothoot", "drops": [ @@ -9231,6 +9271,34 @@ } ] }, + { + "species": "cobblemon:latias", + "drops": [ + { + "item": "minecraft:feather", + "count": "2-4" + } + ], + "zones": [], + "summon": { + "zone": "highlands", + "level": 70 + } + }, + { + "species": "cobblemon:latios", + "drops": [ + { + "item": "minecraft:feather", + "count": "2-4" + } + ], + "zones": [], + "summon": { + "zone": "highlands", + "level": 70 + } + }, { "species": "cobblemon:leafeon", "drops": [ @@ -9732,6 +9800,20 @@ } ] }, + { + "species": "cobblemon:lugia", + "drops": [ + { + "item": "minecraft:feather", + "count": "2-4" + } + ], + "zones": [], + "summon": { + "zone": "deep_sea", + "level": 80 + } + }, { "species": "cobblemon:lumineon", "drops": [ @@ -10792,6 +10874,20 @@ } ] }, + { + "species": "cobblemon:mewtwo", + "drops": [ + { + "item": "cobblemon:twisted_spoon", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "deep_dark", + "level": 90 + } + }, { "species": "cobblemon:mienfoo", "drops": [ @@ -11078,6 +11174,28 @@ } ] }, + { + "species": "cobblemon:moltres", + "drops": [ + { + "item": "minecraft:feather", + "count": "2-4" + }, + { + "item": "minecraft:cooked_chicken", + "count": "1" + }, + { + "item": "cobblemon:charcoal_stick", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "basalt", + "level": 70 + } + }, { "species": "cobblemon:monferno", "drops": [ @@ -11443,6 +11561,20 @@ } ] }, + { + "species": "cobblemon:naganadel", + "drops": [ + { + "item": "minecraft:echo_shard", + "count": "1-3" + } + ], + "zones": [], + "summon": { + "zone": "the_end", + "level": 70 + } + }, { "species": "cobblemon:natu", "drops": [ @@ -12807,6 +12939,20 @@ } ] }, + { + "species": "cobblemon:poipole", + "drops": [ + { + "item": "minecraft:echo_shard", + "count": "1-2" + } + ], + "zones": [], + "summon": { + "zone": "the_end", + "level": 70 + } + }, { "species": "cobblemon:politoed", "drops": [ @@ -13587,6 +13733,62 @@ } ] }, + { + "species": "cobblemon:rayquaza", + "drops": [ + { + "item": "minecraft:dragon_breath", + "count": "3-5" + } + ], + "zones": [], + "summon": { + "zone": "frostpeak", + "level": 90 + } + }, + { + "species": "cobblemon:regice", + "drops": [ + { + "item": "cobblemon:never_melt_ice", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "frostpeak", + "level": 70 + } + }, + { + "species": "cobblemon:regirock", + "drops": [ + { + "item": "cobblemon:hard_stone", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "dripstone", + "level": 70 + } + }, + { + "species": "cobblemon:registeel", + "drops": [ + { + "item": "cobblemon:metal_coat", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "deep_dark", + "level": 70 + } + }, { "species": "cobblemon:relicanth", "drops": [ @@ -19349,6 +19551,28 @@ } ] }, + { + "species": "cobblemon:zapdos", + "drops": [ + { + "item": "minecraft:feather", + "count": "2-4" + }, + { + "item": "minecraft:chicken", + "count": "1" + }, + { + "item": "cobblemon:magnet", + "count": "1" + } + ], + "zones": [], + "summon": { + "zone": "westmarch", + "level": 70 + } + }, { "species": "cobblemon:zebstrika", "drops": [ @@ -19473,6 +19697,140 @@ ] } ], + "summons": [ + { + "species": "cobblemon:zapdos", + "name": "Zapdos", + "zone": "westmarch", + "level": 70 + }, + { + "species": "cobblemon:regieleki", + "name": "Regieleki", + "zone": "westmarch", + "level": 70 + }, + { + "species": "cobblemon:ironleaves", + "name": "Iron Leaves", + "zone": "jungle", + "level": 70 + }, + { + "species": "cobblemon:regirock", + "name": "Regirock", + "zone": "dripstone", + "level": 70 + }, + { + "species": "cobblemon:latias", + "name": "Latias", + "zone": "highlands", + "level": 70 + }, + { + "species": "cobblemon:latios", + "name": "Latios", + "zone": "highlands", + "level": 70 + }, + { + "species": "cobblemon:walkingwake", + "name": "Walking Wake", + "zone": "mire", + "level": 70 + }, + { + "species": "cobblemon:regidrago", + "name": "Regidrago", + "zone": "sunscorch", + "level": 70 + }, + { + "species": "cobblemon:articuno", + "name": "Articuno", + "zone": "frostpeak", + "level": 70 + }, + { + "species": "cobblemon:regice", + "name": "Regice", + "zone": "frostpeak", + "level": 70 + }, + { + "species": "cobblemon:registeel", + "name": "Registeel", + "zone": "deep_dark", + "level": 70 + }, + { + "species": "cobblemon:moltres", + "name": "Moltres", + "zone": "basalt", + "level": 70 + }, + { + "species": "cobblemon:poipole", + "name": "Poipole", + "zone": "the_end", + "level": 70 + }, + { + "species": "cobblemon:xerneas", + "name": "Xerneas", + "zone": "jungle", + "level": 80 + }, + { + "species": "cobblemon:zarude", + "name": "Zarude", + "zone": "jungle", + "level": 80 + }, + { + "species": "cobblemon:mew", + "name": "Mew", + "zone": "jungle", + "level": 80 + }, + { + "species": "cobblemon:hooh", + "name": "Ho-Oh", + "zone": "highlands", + "level": 80 + }, + { + "species": "cobblemon:lugia", + "name": "Lugia", + "zone": "deep_sea", + "level": 80 + }, + { + "species": "cobblemon:regigigas", + "name": "Regigigas", + "zone": "deep_dark", + "level": 80 + }, + { + "species": "cobblemon:rayquaza", + "name": "Rayquaza", + "zone": "frostpeak", + "level": 90 + }, + { + "species": "cobblemon:mewtwo", + "name": "Mewtwo", + "zone": "deep_dark", + "level": 90 + }, + { + "species": "cobblemon:eternatus", + "name": "Eternatus", + "zone": "the_end", + "level": 90 + } + ], "spawn_drops": [ { "species": "cobblemon:beheeyem", diff --git a/mod/src/main/resources/assets/cobblesurvival/lang/en_us.json b/mod/src/main/resources/assets/cobblesurvival/lang/en_us.json index 875b15d..f06c576 100644 --- a/mod/src/main/resources/assets/cobblesurvival/lang/en_us.json +++ b/mod/src/main/resources/assets/cobblesurvival/lang/en_us.json @@ -35,5 +35,6 @@ "tooltip.cobblesurvival.altar_core": "Sacrifice Altar: trades a Pokémon of Lv 20 or more for items; sneak-use twice. It's gone for good.", "tooltip.cobblesurvival.altar_core.shell": "Shell: obsidian, crying obsidian, blackstone or polished blackstone bricks.", "tooltip.cobblesurvival.rebirth_core": "Rebirth Chamber: a Lv 100 Pokémon becomes a shiny Lv 1 of its first stage after a long time.", - "tooltip.cobblesurvival.rebirth_core.shell": "Shell: amethyst, quartz or calcite blocks." + "tooltip.cobblesurvival.rebirth_core.shell": "Shell: amethyst, quartz or calcite blocks.", + "item.cobblesurvival.summon_sigil": "Blank Sigil" } diff --git a/mod/src/main/resources/assets/cobblesurvival/models/item/summon_sigil.json b/mod/src/main/resources/assets/cobblesurvival/models/item/summon_sigil.json new file mode 100644 index 0000000..05549c0 --- /dev/null +++ b/mod/src/main/resources/assets/cobblesurvival/models/item/summon_sigil.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "cobblesurvival:item/summon_sigil" + } +} diff --git a/mod/src/main/resources/assets/cobblesurvival/textures/item/summon_sigil.png b/mod/src/main/resources/assets/cobblesurvival/textures/item/summon_sigil.png new file mode 100644 index 0000000..f37a223 Binary files /dev/null and b/mod/src/main/resources/assets/cobblesurvival/textures/item/summon_sigil.png differ diff --git a/pack/config/ftbquests/quests/chapters/base.snbt b/pack/config/ftbquests/quests/chapters/base.snbt index 6eb5685..c692d62 100644 --- a/pack/config/ftbquests/quests/chapters/base.snbt +++ b/pack/config/ftbquests/quests/chapters/base.snbt @@ -7,7 +7,7 @@ id: "cobblemon:pasture" } id: "5B1F192C5A22F0B9" - order_index: 17 + order_index: 18 quest_links: [ ] quests: [ { diff --git a/pack/config/ftbquests/quests/chapters/legends.snbt b/pack/config/ftbquests/quests/chapters/legends.snbt new file mode 100644 index 0000000..6477dd1 --- /dev/null +++ b/pack/config/ftbquests/quests/chapters/legends.snbt @@ -0,0 +1,733 @@ +{ + default_hide_dependency_lines: false + default_quest_shape: "" + filename: "legends" + group: "" + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "0217ED8D82F11BE4" + order_index: 16 + quest_links: [ ] + quests: [ + { + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "73A150C1A7221BD0" + size: 1.5d + tasks: [ + { + id: "6120ECDE48C04063" + type: "checkmark" + } + ] + x: 0.0d + y: 0.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "1334D8BDB02D0027" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "4D7EBD1D4EC8F582" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:zapdos" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 2.0d + y: 0.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "32265A879257CF62" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "7065C0FCA23D43C9" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:regieleki" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 3.5d + y: 0.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "683AFA47A4D71DAD" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "3775C57598442334" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:ironleaves" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 5.0d + y: 0.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "25687CFA78E8BE5E" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "151B4ADB993F3C19" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:regirock" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 6.5d + y: 0.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "65A44ABB757D8EC9" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "31A75B48DEC93541" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:latias" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 8.0d + y: 0.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "0BCD6F1DF120EEF0" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "50D5C5BB7872F734" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:latios" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 9.5d + y: 0.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "492E2A0DB2875211" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "73A0CBBB99E04DD5" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:walkingwake" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 2.0d + y: 1.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "47CC5F3E473D3ADA" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "31AAB717DA533470" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:regidrago" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 3.5d + y: 1.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "28B36D465013F4FC" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "00D2DC946D0C559D" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:articuno" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 5.0d + y: 1.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "2732EB3DCE5B837B" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "64E08548F1BB6B6E" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:regice" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 6.5d + y: 1.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "4CA0BE77C607EFF4" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "597B64D4E7AC01A0" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:registeel" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 8.0d + y: 1.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "3A7416794209F29E" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "69B2D884307B8F22" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:moltres" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 9.5d + y: 1.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "69D61BD349921400" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "79191F2DCD42DFA3" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:poipole" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 2.0d + y: 3.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "44BC987FF615F811" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "7699A61FCF9AD7D4" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:xerneas" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 3.5d + y: 3.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "0804892E5BD15447" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "1721B8E9F78B03AB" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:zarude" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 5.0d + y: 3.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "4AC2A700F404BD2F" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "5681CA1A8AA79725" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:mew" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 6.5d + y: 3.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "55A04905BAB11C0B" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "1AB5DA1326D2AF75" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:hooh" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 8.0d + y: 3.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "7286E3D8F9A6BC2A" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "0F351D73280AA460" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:lugia" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 9.5d + y: 3.0d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "6F2260E7AF1E93B6" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "56542F196CB24CF3" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:regigigas" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 2.0d + y: 4.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "06D5D9F10AAA81ED" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "30B074353AB674A7" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:rayquaza" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 3.5d + y: 4.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "05C2A740412D6FC6" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "378C79FBBBAE02A3" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:mewtwo" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 5.0d + y: 4.5d + } + { + dependencies: ["73A150C1A7221BD0"] + icon: { + id: "cobblesurvival:summon_sigil" + } + id: "1F0FBB6BF2F87AA2" + tasks: [ + { + action: "catch" + amount: 1L + biome: "" + dex_progress: "" + dimension: "" + form: "" + gender: "" + id: "53A3A2FE39371F4C" + max_level: 0 + min_level: 0 + natures: "" + poke_ball_used: "" + pokemon: "cobblemon:eternatus" + pokemon_type: "" + region: "" + shiny: false + time_max: 0L + time_min: 0L + type: "cobblemon_tasks:cobblemon_task" + } + ] + x: 6.5d + y: 4.5d + } + ] +} diff --git a/pack/config/ftbquests/quests/chapters/machines.snbt b/pack/config/ftbquests/quests/chapters/machines.snbt index 5996173..3bffc77 100644 --- a/pack/config/ftbquests/quests/chapters/machines.snbt +++ b/pack/config/ftbquests/quests/chapters/machines.snbt @@ -7,7 +7,7 @@ id: "cobblesurvival:heat_core" } id: "5170190C30A58C4C" - order_index: 16 + order_index: 17 quest_links: [ ] quests: [ { diff --git a/pack/config/ftbquests/quests/lang/en_us.snbt b/pack/config/ftbquests/quests/lang/en_us.snbt index 63f5aa3..da44c5e 100644 --- a/pack/config/ftbquests/quests/lang/en_us.snbt +++ b/pack/config/ftbquests/quests/lang/en_us.snbt @@ -1,4 +1,6 @@ { + "chapter.0217ED8D82F11BE4.chapter_subtitle": ["What never spawns on its own"] + "chapter.0217ED8D82F11BE4.title": "Legends" "chapter.0F763138AA0551CF.title": "Verdant Jungle" "chapter.1AB2113B8D294817.title": "Basalt Furnace" "chapter.1B23BCD483E3F9CE.title": "Shallows" @@ -43,16 +45,32 @@ "Poké Balls are crafted from apricorns, which grow on apricorn trees around the island. Look the recipe up in JEI." ] "quest.05B922BE6CEBAAC2.title": "Poké Balls" + "quest.05C2A740412D6FC6.quest_desc": [ + "Craft the Mewtwo Sigil and use it in Deep Dark. Catch the Lv 90 Mewtwo that answers." + ] + "quest.05C2A740412D6FC6.title": "Mewtwo" "quest.0644BAB8C69CE8D0.quest_desc": [ "Wild Pokémon in Westmarch are level 15 to 25. Bring a team that can hold its own there." "A Pokémon far above a zone's levels learns less from battles there; Exp. Candy always works in full." ] "quest.0644BAB8C69CE8D0.quest_subtitle": "Lv 15–25" "quest.0644BAB8C69CE8D0.title": "Westmarch" + "quest.06D5D9F10AAA81ED.quest_desc": [ + "Craft the Rayquaza Sigil and use it in Frostpeak Range. Catch the Lv 90 Rayquaza that answers." + ] + "quest.06D5D9F10AAA81ED.title": "Rayquaza" + "quest.0804892E5BD15447.quest_desc": [ + "Craft the Zarude Sigil and use it in Verdant Jungle. Catch the Lv 80 Zarude that answers." + ] + "quest.0804892E5BD15447.title": "Zarude" "quest.0830DA072B96D6A8.quest_desc": [ "Southwold, north of Button Isle, is the next step: Pokémon up to level 18 and the island's copper." ] "quest.0830DA072B96D6A8.title": "Beyond Button Isle" + "quest.0BCD6F1DF120EEF0.quest_desc": [ + "Craft the Latios Sigil and use it in Highland Meadows. Catch the Lv 70 Latios that answers." + ] + "quest.0BCD6F1DF120EEF0.title": "Latios" "quest.0CA0C724D201B8A0.quest_desc": [ "There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "Basalt Furnace has Ancient Debris, Quartz." @@ -74,6 +92,10 @@ "Southwold has Raw Copper." ] "quest.1154E278D871A8CA.title": "Ores of Southwold" + "quest.1334D8BDB02D0027.quest_desc": [ + "Craft the Zapdos Sigil and use it in Westmarch. Catch the Lv 70 Zapdos that answers." + ] + "quest.1334D8BDB02D0027.title": "Zapdos" "quest.1391BDC3E21A671E.quest_desc": [ "Each kind of Pokémon lives in one zone of the island. Catch three that call Basalt Furnace home." "Their drops are what this zone adds to your crafting: look an item up in JEI to see who drops it." @@ -119,6 +141,10 @@ "A level 100 Pokémon in a Rebirth Core shell of amethyst is reborn after two hours as a shiny level 1 of its first stage, with better IVs and every move it knew." ] "quest.1DE944B24F006EB2.title": "Rebirth Chamber" + "quest.1F0FBB6BF2F87AA2.quest_desc": [ + "Craft the Eternatus Sigil and use it in The End. Catch the Lv 90 Eternatus that answers." + ] + "quest.1F0FBB6BF2F87AA2.title": "Eternatus" "quest.20F77357783CD1BD.quest_desc": [ "Flygon, Lv 50, guards Sunscorch: a giant that takes at most a quarter of its health from any one attack." "Within 128 blocks its bar shows how far away it is. In the fight, watch the ground and step out of its area attacks; leaving the arena or dying loses the fight." @@ -137,11 +163,23 @@ ] "quest.23A088BCF63BF446.quest_subtitle": "Lv 12–28" "quest.23A088BCF63BF446.title": "Lush Caves" + "quest.25687CFA78E8BE5E.quest_desc": [ + "Craft the Regirock Sigil and use it in Dripstone Depths. Catch the Lv 70 Regirock that answers." + ] + "quest.25687CFA78E8BE5E.title": "Regirock" + "quest.2732EB3DCE5B837B.quest_desc": [ + "Craft the Regice Sigil and use it in Frostpeak Range. Catch the Lv 70 Regice that answers." + ] + "quest.2732EB3DCE5B837B.title": "Regice" "quest.28873C8A3FDC26C6.quest_desc": [ "There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "Dripstone Depths has Amethyst Shard, Moon Stone." ] "quest.28873C8A3FDC26C6.title": "Ores of Dripstone Depths" + "quest.28B36D465013F4FC.quest_desc": [ + "Craft the Articuno Sigil and use it in Frostpeak Range. Catch the Lv 70 Articuno that answers." + ] + "quest.28B36D465013F4FC.title": "Articuno" "quest.2AAB6A47FDDD9D21.quest_desc": [ "Regigigas, Lv 65, guards Deep Dark: a giant that takes at most a quarter of its health from any one attack." "Within 128 blocks its bar shows how far away it is. In the fight, watch the ground and step out of its area attacks; leaving the arena or dying loses the fight." @@ -159,6 +197,10 @@ ] "quest.2F51067D3773786B.quest_subtitle": "Lv 5–20" "quest.2F51067D3773786B.title": "Shallows" + "quest.32265A879257CF62.quest_desc": [ + "Craft the Regieleki Sigil and use it in Westmarch. Catch the Lv 70 Regieleki that answers." + ] + "quest.32265A879257CF62.title": "Regieleki" "quest.33052810B8325006.quest_desc": [ "There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "Frostpeak Range has Dawn Stone, Emerald, Ice Stone." @@ -184,6 +226,10 @@ "Their drops are what this zone adds to your crafting: look an item up in JEI to see who drops it." ] "quest.38D974F9298EC54A.title": "Locals of Deep Sea" + "quest.3A7416794209F29E.quest_desc": [ + "Craft the Moltres Sigil and use it in Basalt Furnace. Catch the Lv 70 Moltres that answers." + ] + "quest.3A7416794209F29E.title": "Moltres" "quest.3B64655619EB4CD4.quest_desc": [ "A Pokémon of level 20 or more in an Altar Core shell of obsidian can be given up for rare rewards: rare candies, ability items, even a nether star. It is gone for good." ] @@ -205,11 +251,23 @@ "Beat it for 3 Icy Rock, 2 Exp Candy L. It returns 5 hours later." ] "quest.3F61AFD873C3F8EE.title": "Guardian of Frostpeak Range" + "quest.44BC987FF615F811.quest_desc": [ + "Craft the Xerneas Sigil and use it in Verdant Jungle. Catch the Lv 80 Xerneas that answers." + ] + "quest.44BC987FF615F811.title": "Xerneas" "quest.4508548D257AA751.quest_desc": [ "Each kind of Pokémon lives in one zone of the island. Catch three that call Dripstone Depths home." "Their drops are what this zone adds to your crafting: look an item up in JEI to see who drops it." ] "quest.4508548D257AA751.title": "Locals of Dripstone Depths" + "quest.47CC5F3E473D3ADA.quest_desc": [ + "Craft the Regidrago Sigil and use it in Sunscorch. Catch the Lv 70 Regidrago that answers." + ] + "quest.47CC5F3E473D3ADA.title": "Regidrago" + "quest.492E2A0DB2875211.quest_desc": [ + "Craft the Walking Wake Sigil and use it in Mangrove Mire. Catch the Lv 70 Walking Wake that answers." + ] + "quest.492E2A0DB2875211.title": "Walking Wake" "quest.496174D8AF114AE5.quest_desc": [ "There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "Lush Caves has Shiny Stone." @@ -221,12 +279,20 @@ ] "quest.498A85F2039AF3BB.quest_subtitle": "Lv 25–35" "quest.498A85F2039AF3BB.title": "Highland Meadows" + "quest.4AC2A700F404BD2F.quest_desc": [ + "Craft the Mew Sigil and use it in Verdant Jungle. Catch the Lv 80 Mew that answers." + ] + "quest.4AC2A700F404BD2F.title": "Mew" "quest.4C0B4F1365903D23.quest_desc": [ "Wild Pokémon in Southwold are level 8 to 18. Bring a team that can hold its own there." "A Pokémon far above a zone's levels learns less from battles there; Exp. Candy always works in full." ] "quest.4C0B4F1365903D23.quest_subtitle": "Lv 8–18" "quest.4C0B4F1365903D23.title": "Southwold" + "quest.4CA0BE77C607EFF4.quest_desc": [ + "Craft the Registeel Sigil and use it in Deep Dark. Catch the Lv 70 Registeel that answers." + ] + "quest.4CA0BE77C607EFF4.title": "Registeel" "quest.4CCE497681B71AB5.quest_desc": [ "Sleeping doesn't heal your Pokémon. A Healing Machine does, but it is expensive and recharges slowly; potions and berries help in between." ] @@ -248,6 +314,10 @@ "Beat it for 1 Mire Waders, 4 Pecha Berry, 2 Exp Candy M. It returns 5 hours later." ] "quest.51F4867542A2849E.title": "Guardian of Westmarch" + "quest.55A04905BAB11C0B.quest_desc": [ + "Craft the Ho-Oh Sigil and use it in Highland Meadows. Catch the Lv 80 Ho-Oh that answers." + ] + "quest.55A04905BAB11C0B.title": "Ho-Oh" "quest.55E9777C26CA6D8B.quest_desc": [ "There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "Deep Dark has Diamond, Dusk Stone." @@ -298,6 +368,10 @@ "Beat it for 3 Exp Candy Xl, 2 Netherite Scrap. It returns 5 hours later." ] "quest.64893157D81592CD.title": "Guardian of Basalt Furnace" + "quest.65A44ABB757D8EC9.quest_desc": [ + "Craft the Latias Sigil and use it in Highland Meadows. Catch the Lv 70 Latias that answers." + ] + "quest.65A44ABB757D8EC9.title": "Latias" "quest.6603239BE6012B1F.quest_desc": [ "A Pokémon that faints is gone for good once the battle ends. Revives only help within that battle." "A Pokémon holding a Revival Charm is saved once instead: the charm is used up and the Pokémon is healed. Give one to your most valuable partner." @@ -316,6 +390,10 @@ "Beat it for 3 Icy Rock, 4 Super Potion. It returns 5 hours later." ] "quest.673147FA87104942.title": "Guardian of Highland Meadows" + "quest.683AFA47A4D71DAD.quest_desc": [ + "Craft the Iron Leaves Sigil and use it in Verdant Jungle. Catch the Lv 70 Iron Leaves that answers." + ] + "quest.683AFA47A4D71DAD.title": "Iron Leaves" "quest.692C224D099307BA.quest_desc": [ "This island has no zombies, no creepers and no cows: only Pokémon. Their drops are your food, string, leather and much more." "The island is split into zones, each with its own Pokémon, levels, ores and a guardian. You start on Button Isle; the further out you go, the stronger everything gets." @@ -328,6 +406,10 @@ "Their drops are what this zone adds to your crafting: look an item up in JEI to see who drops it." ] "quest.69D3A6622A0EE729.title": "Locals of Frostpeak Range" + "quest.69D61BD349921400.quest_desc": [ + "Craft the Poipole Sigil and use it in The End. Catch the Lv 70 Poipole that answers." + ] + "quest.69D61BD349921400.title": "Poipole" "quest.6B424DADFF959A58.quest_desc": [ "An Electric-type Pokémon in a Dynamo Core shell of copper makes Forge Energy for cables and other machines." ] @@ -346,6 +428,10 @@ "Beating it opens the way home and leaves the dragon egg the first time." ] "quest.6EB4CFA7061556F9.title": "Eternatus" + "quest.6F2260E7AF1E93B6.quest_desc": [ + "Craft the Regigigas Sigil and use it in Deep Dark. Catch the Lv 80 Regigigas that answers." + ] + "quest.6F2260E7AF1E93B6.title": "Regigigas" "quest.6F4F5AFD500EF638.quest_desc": [ "Each kind of Pokémon lives in one zone of the island. Catch three that call Mangrove Mire home." "Their drops are what this zone adds to your crafting: look an item up in JEI to see who drops it." @@ -356,6 +442,10 @@ "Their drops are what this zone adds to your crafting: look an item up in JEI to see who drops it." ] "quest.70FDBAB56079AA17.title": "Locals of Lush Caves" + "quest.7286E3D8F9A6BC2A.quest_desc": [ + "Craft the Lugia Sigil and use it in Deep Sea. Catch the Lv 80 Lugia that answers." + ] + "quest.7286E3D8F9A6BC2A.title": "Lugia" "quest.731852EDB1EE12B7.quest_desc": [ "Wild Pokémon in Deep Sea are level 30 to 50. Bring a team that can hold its own there." "A Pokémon far above a zone's levels learns less from battles there; Exp. Candy always works in full." @@ -366,6 +456,11 @@ "Raise a Pokémon to level 10 by battling. Wild Pokémon stronger than your team may come after you; weaker ones keep their distance." ] "quest.734F4C633D8946E3.title": "Growing Up" + "quest.73A150C1A7221BD0.quest_desc": [ + "Legendary Pokémon don't spawn on their own. Each has a Sigil you can craft from late-game materials: look \"Sigil\" up in JEI. Using one in the zone written on it summons the Pokémon." + "It fights like a guardian, area attacks and all, but this one can be caught. If it's knocked out, the Sigil is lost." + ] + "quest.73A150C1A7221BD0.title": "Calling a Legend" "quest.74149A0BF939C15E.quest_desc": [ "Wild Pokémon in Button Isle are level 2 to 10. Bring a team that can hold its own there." "A Pokémon far above a zone's levels learns less from battles there; Exp. Candy always works in full." @@ -428,6 +523,7 @@ "task.58EAEDE25DA7FDA3.title": "Reach Southwold" "task.601AABB55A476514.title": "Beat Morpeko" "task.60EA09356932EC73.title": "Reach Mangrove Mire" + "task.6120ECDE48C04063.title": "Read this" "task.63B77EE998527582.title": "Beat Flygon" "task.643C68559D41888A.title": "Beat Pinsir" "task.6D2ED8A178EE3B43.title": "Reach Verdant Jungle" diff --git a/pack/index.toml b/pack/index.toml index 89cc939..af6173d 100644 --- a/pack/index.toml +++ b/pack/index.toml @@ -38,7 +38,7 @@ hash = "8a7eab2ca30f47109add6cfbf4eeb4717e3704bc85902ee8f4c5307b2b2eeb3c" [[files]] file = "config/ftbquests/quests/chapters/base.snbt" -hash = "46710212af0c6bf3f39e97b95d2a5e0dfdfb312470fbfab5f24b6d95764032c9" +hash = "555564da7dd44e375664b94a51b2334c636d7c5d72db164b03c6fe9196d06de0" [[files]] file = "config/ftbquests/quests/chapters/button_isle.snbt" @@ -72,13 +72,17 @@ hash = "3724fa8a038561cc8965e6dfe5bc62718872d04f385bb636e984988762046670" file = "config/ftbquests/quests/chapters/jungle.snbt" hash = "5afa0885dbd853ea973fb61881a14b97a98af4d0dd26b66d837541ba1b09c8c8" +[[files]] +file = "config/ftbquests/quests/chapters/legends.snbt" +hash = "faed84fa13b7ea26305e2c07e23d6be0d4198cbee177042279776864387c4d97" + [[files]] file = "config/ftbquests/quests/chapters/lush_caves.snbt" hash = "bd5734f9df4e1dc1caa989c32b5dac797f5104a4c6c0987801d3650e12d1e491" [[files]] file = "config/ftbquests/quests/chapters/machines.snbt" -hash = "dbeb43e993d27656f75e7a64a118e3592c40b5cbfc089bdf6a02069edae57011" +hash = "f747805848fc39fa30293baebc3bce75742663c5f30a6439b0318ac4cf9657f0" [[files]] file = "config/ftbquests/quests/chapters/mire.snbt" @@ -110,7 +114,7 @@ hash = "35b6760d4c56b02f2ff77dd5ba2f0e634c7f68238ce2809cddb22d9c61c6f943" [[files]] file = "config/ftbquests/quests/lang/en_us.snbt" -hash = "bce591f1d3b03bd1b4fe5a49a6153e06b825b41c3fc17fba23ac6b262afb0d50" +hash = "f06c0b3fd853aed231d9d72b0634da737b930f4a51db3eb17bf29c14ef548a35" [[files]] file = "config/lootr-common.toml" diff --git a/pack/pack.toml b/pack/pack.toml index 32bc577..c31ac27 100644 --- a/pack/pack.toml +++ b/pack/pack.toml @@ -6,7 +6,7 @@ pack-format = "packwiz:1.1.0" [index] file = "index.toml" hash-format = "sha256" -hash = "b5cad59e6cdca6b6c84dcdad5237f284d5a4626f63ffe20f64b814ac462f7ef5" +hash = "b2c6b7b6b2cb01942dc1c17c6526bc83ee1cbe7f4857e8af4557c2c9b4b4117a" [versions] minecraft = "1.21.1" diff --git a/tools/jei_sources.py b/tools/jei_sources.py index b9fe081..c092f1c 100644 --- a/tools/jei_sources.py +++ b/tools/jei_sources.py @@ -8,6 +8,8 @@ this file inside the companion mod: mod/src/main/resources/assets/cobblesurvival pokemon every species of a line that lives on the island: its drops (as the Drop Synthesizer rolls them) and the zones it spawns in, or the zones where its line lives + (legendaries: where a Sigil summons them, world/summons.json; that line's evolutions too) + summons each Sigil: species, name, zone, level, so JEI can list it as an item of its own spawn_drops zone spawns that drop something else than their species (e.g. Beheeyem in the End) guardians each zone guardian: species, level, drops, return time end_boss the End boss and what beating it gives @@ -104,15 +106,21 @@ def main(): for zid, levels in zs.items(): line_zones[root_of(sid, species)].setdefault(zid, sid) + table = json.loads((ROOT / "world/summons.json").read_text()) + summoned = {f"cobblemon:{k}": {"zone": v["zone"], "level": table["tiers"][str(v["tier"])]["level"]} for k, v in table["summons"].items()} + summons = [{"species": sid, "name": species[sid]["name"], **s} for sid, s in summoned.items()] + pokemon = [] for sid, s in sorted(species.items()): drops = drop_entries(s["drops"]) root = root_of(sid, species) - if not drops or not s["implemented"] or not (where.get(sid) or line_zones.get(root)): + if not drops or not s["implemented"] or not (where.get(sid) or line_zones.get(root) or root in summoned): continue entry = {"species": sid, "drops": drops, "zones": [{"zone": z, "levels": f"{lo}-{hi}"} for z, (lo, hi) in sorted(where.get(sid, {}).items())]} - if not entry["zones"]: + if root in summoned: + entry["summon"] = summoned[root] + elif not entry["zones"]: entry["line"] = [{"zone": z, "species": member} for z, member in sorted(line_zones[root].items())] pokemon.append(entry) @@ -159,7 +167,7 @@ def main(): "mod's JEI plugin (jei/DropSourcesJei.kt); checked against the live server by the self-test " "drop_sources_match_the_server.", "zones": {zid: {"name": z["name"], "levels": z["levels"]} for zid, z in zones.items()}, - "pokemon": pokemon, "spawn_drops": spawn_drops, "guardians": guardians, "end_boss": end_boss, + "pokemon": pokemon, "summons": summons, "spawn_drops": spawn_drops, "guardians": guardians, "end_boss": end_boss, "altar": {"tiers": altar["tiers"], "specials": altar.get("specials", [])}, "rebirth": rebirth.get("extra", []), "ore_veins": [{"zone": z, "items": items} for z, items in sorted(ore_veins.items())], "pasture_finds": pasture_finds, diff --git a/tools/quests.py b/tools/quests.py index 004de5b..2b80b47 100644 --- a/tools/quests.py +++ b/tools/quests.py @@ -230,6 +230,15 @@ def chapter_quests(chapter, book, zones): for t in q.get("tasks", []): tasks += [{**t, "item": o, "each": None} for o in fields["ores"]] if t.get("each") == "ores" else [t] q["tasks"] = [{k: v for k, v in t.items() if k != "each"} for t in tasks] + # One quest per Sigil: craft it, use it, catch what comes (world/summons.json; names from the JEI data). + if chapter.get("summons"): + sigils = json.loads((ROOT / "mod/src/main/resources/assets/cobblesurvival/jei/drop_sources.json").read_text())["summons"] + for s in sigils: + quests.append({ + "id": s["species"].split(":")[1], "title": s["name"], "icon": "cobblesurvival:summon_sigil", "after": ["about"], + "text": f"Craft the {s['name']} Sigil and use it in {zones[s['zone']]['name']}. Catch the Lv {s['level']} {s['name']} that answers.", + "tasks": [{"cobblemon": "catch", "pokemon": [s["species"]]}], + }) # "Catch Pokémon of a zone": its spawn pool's species (Cobblemon Quests' own biome filter knows no zones). for q in quests: for t in q.get("tasks", []): @@ -264,8 +273,9 @@ def task_nbt(task, name, events): raise ValueError(f"{name}: unknown task {task}") -def auto_layout(quests, chapter_id): - """Left to right by dependency depth inside the chapter, stacked within a column.""" +def auto_layout(quests, chapter_id, grid=None): + """Left to right by dependency depth inside the chapter, stacked within a column; with `grid` columns, what depends + on something goes into a grid to the right instead of one tall column.""" local = {q["id"] for q in quests} depth = {} @@ -279,6 +289,10 @@ def auto_layout(quests, chapter_id): for q in quests: columns.setdefault(d(q), []).append(q["id"]) pos = {} + if grid: + for i, qid in enumerate(q["id"] for q in quests if depth[q["id"]] > 0): + pos[f"{chapter_id}/{qid}"] = [2.0 + (i % grid) * 1.5, (i // grid) * 1.5] + columns = {c: ids for c, ids in columns.items() if c == 0} for col, ids in columns.items(): for row, qid in enumerate(ids): pos[f"{chapter_id}/{qid}"] = [col * 2.0, (row - (len(ids) - 1) / 2) * 1.5] @@ -296,7 +310,7 @@ def build(book): for index, chapter in enumerate(book["chapters"]): cid = chapter["id"] quests = expanded[cid] - auto = auto_layout(quests, cid) + auto = auto_layout(quests, cid, chapter.get("columns")) chapter_id = object_id(f"chapter:{cid}") lang[f"chapter.{chapter_id}.title"] = chapter["title"] if chapter.get("subtitle"): @@ -369,7 +383,7 @@ def pull(book, folder): auto, by_id = {}, {} for c in book["chapters"]: quests = chapter_quests(c, book, zones) - auto |= auto_layout(quests, c["id"]) + auto |= auto_layout(quests, c["id"], c.get("columns")) by_id |= {object_id(f"quest:{c['id']}/{q['id']}"): f"{c['id']}/{q['id']}" for q in quests} layout = dict(book.get("layout") or {}) for path in sorted((folder / "chapters").glob("*.snbt")): diff --git a/tools/summons.py b/tools/summons.py new file mode 100644 index 0000000..6edbb29 --- /dev/null +++ b/tools/summons.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +"""Write the crafted summons (Phase 9; Adrian, 2026-11-09) from world/summons.json. + +Legendaries, mythicals, Ultra Beasts and Paradox Pokémon have no spawn data, so each gets a Sigil (one item, +cobblesurvival:summon_sigil, told apart by its custom data), used in a fitting zone to summon a catchable wild one. This +writes, under datapacks/core/data/cobblesurvival/: + + summons/.json species, level, zone, read by the companion mod (summon/Summons.kt) + recipe/summon_.json material in the corners, ring on the sides, core in the middle; the result carries + the species, its name and where to use it, so the client needs no server data + +and the sigil's texture and item model in the companion mod. The fights are written by tools/zone_bosses.py, so run that +afterwards, and tools/jei_sources.py and tools/quests.py after it. + +Needs the Cobblemon jar in build/server/mods (any test-server run), for the names. + +Usage: tools/summons.py +""" +import json +import re +import zipfile +from pathlib import Path + +from PIL import Image + +ROOT = Path(__file__).resolve().parent.parent +DATA = ROOT / "datapacks/core/data/cobblesurvival" +ASSETS = ROOT / "mod/src/main/resources/assets/cobblesurvival" +SIGIL = "cobblesurvival:summon_sigil" + +# The sigil: a dark disc with a gold ring and a violet eye. +TEXTURE = [ + "................", + ".....######.....", + "...##gggggg##...", + "..#gg......gg#..", + "..#g..vvvv..g#..", + ".#g..vv++vv..g#.", + ".#g.vv++++vv.g#.", + ".#g.vv+WW+vv.g#.", + ".#g.vv+WW+vv.g#.", + ".#g.vv++++vv.g#.", + ".#g..vv++vv..g#.", + "..#g..vvvv..g#..", + "..#gg......gg#..", + "...##gggggg##...", + ".....######.....", + "................", +] +COLORS = {"#": (40, 30, 60, 255), "g": (230, 185, 70, 255), ".": (0, 0, 0, 0), "v": (130, 60, 200, 255), + "+": (190, 120, 245, 255), "W": (250, 235, 255, 255)} + + +def names(jar): + found = {} + with zipfile.ZipFile(jar) as z: + for name in z.namelist(): + m = re.fullmatch(r"data/cobblemon/species/[^/]+/([^/]+)\.json", name) + if m: + found[m[1]] = json.loads(z.read(name))["name"] + return found + + +def main(): + table = json.loads((ROOT / "world/summons.json").read_text()) + plan = json.loads((ROOT / "world/zones.json").read_text()) + zones = {z["id"]: z["name"] for z in plan["zones"] + plan["caves"] + plan.get("dimensions", [])} + species_names = names(next((ROOT / "build/server/mods").glob("Cobblemon-*.jar"))) + + summons, recipes = DATA / "summons", DATA / "recipe" + summons.mkdir(parents=True, exist_ok=True) + for old in list(summons.glob("*.json")) + list(recipes.glob("summon_*.json")): + old.unlink() + comment = "Generated by tools/summons.py from world/summons.json; do not edit by hand." + for species, s in table["summons"].items(): + tier = table["tiers"][str(s["tier"])] + name = species_names[species] + (summons / f"{species}.json").write_text(json.dumps( + {"_comment": comment, "species": species, "level": tier["level"], "zone": s["zone"]}, indent=1) + "\n") + lore = f"Use in {zones[s['zone']]} to summon a Lv {tier['level']} {name}" + (recipes / f"summon_{species}.json").write_text(json.dumps({ + "_comment": comment, "type": "minecraft:crafting_shaped", "category": "misc", + "pattern": ["MRM", "RCR", "MRM"], + "key": {"M": {"item": s["material"]}, "R": {"item": tier["ring"]}, "C": {"item": tier["core"]}}, + "result": {"id": SIGIL, "count": 1, "components": { + "minecraft:custom_data": {"cobblesurvival_summon": species}, + "minecraft:item_name": json.dumps(f"{name} Sigil"), + "minecraft:lore": [json.dumps({"text": lore, "color": "gray", "italic": False})], + }}, + }, indent=1) + "\n") + + image = Image.new("RGBA", (16, 16)) + for y, row in enumerate(TEXTURE): + for x, c in enumerate(row): + image.putpixel((x, y), COLORS[c]) + (ASSETS / "textures/item").mkdir(parents=True, exist_ok=True) + image.save(ASSETS / "textures/item/summon_sigil.png") + (ASSETS / "models/item/summon_sigil.json").write_text(json.dumps( + {"parent": "minecraft:item/generated", "textures": {"layer0": "cobblesurvival:item/summon_sigil"}}, indent=2) + "\n") + print(f"wrote {len(table['summons'])} summons") + + +if __name__ == "__main__": + main() diff --git a/tools/zone_bosses.py b/tools/zone_bosses.py index 5662b8e..bff8d21 100644 --- a/tools/zone_bosses.py +++ b/tools/zone_bosses.py @@ -26,6 +26,8 @@ END = {"species": "eternatus", "level": 80, "respawn_hours": 5, "xp_first_win": # Adrian, 2026-11-02: Eternatus was too small (0.2x, about a block). Scaled to stand this many blocks tall. END_HEIGHT = 15 END_ARENA = 40 +# A summoned legendary's fight (world/summons.json; Adrian, 2026-11-09): catchable, same rules as a boss. +SUMMON_ARENA = 32 # Up to this level: these patterns. TIERS = [ @@ -71,6 +73,7 @@ def species_data(jar): if name.startswith("data/cobblemon/species/") and name.endswith(".json"): d = json.loads(z.read(name)) types[d["name"].lower()] = {t for t in (d.get("primaryType"), d.get("secondaryType")) if t} + types[Path(name).stem] = types[d["name"].lower()] heights[d["name"].lower()] = (d.get("hitbox") or {}).get("height", 1) * d.get("baseScale", 1) return types, heights @@ -94,6 +97,11 @@ def main(): end = boss(END["level"], types.get(END["species"], set()), END_ARENA, end=end_def) (OUT / "end.json").write_text(json.dumps({"_comment": comment, **end}, indent=1) + "\n") print(f"end: {END['species']} Lv {END['level']}, {len(end['patterns'])} patterns") + table = json.loads((ROOT / "world/summons.json").read_text()) + for species, s in table["summons"].items(): + fight = boss(table["tiers"][str(s["tier"])]["level"], types.get(species, set()), SUMMON_ARENA, summon=species) + (OUT / f"summon_{species}.json").write_text(json.dumps({"_comment": comment, **fight}, indent=1) + "\n") + print(f"{len(table['summons'])} summoned legendaries") if __name__ == "__main__": diff --git a/world/summons.json b/world/summons.json new file mode 100644 index 0000000..129989f --- /dev/null +++ b/world/summons.json @@ -0,0 +1,32 @@ +{ + "_comment": "Crafted summons (Adrian, 2026-11-09): legendaries, mythicals, Ultra Beasts and Paradox Pokemon have no spawn data, so each gets a sigil, used in a fitting zone, that summons a catchable wild one for a hard fight. Levels and recipes are placeholders; see docs/balance.md. tools/summons.py writes the recipes and data; tools/zone_bosses.py their fights. Recipe: material in the corners, ring on the sides, core in the middle.", + "tiers": { + "1": {"level": 70, "core": "minecraft:netherite_ingot", "ring": "minecraft:diamond"}, + "2": {"level": 80, "core": "minecraft:nether_star", "ring": "minecraft:diamond"}, + "3": {"level": 90, "core": "minecraft:nether_star", "ring": "minecraft:netherite_ingot"} + }, + "summons": { + "zapdos": {"zone": "westmarch", "tier": 1, "material": "cobblemon:thunder_stone"}, + "regieleki": {"zone": "westmarch", "tier": 1, "material": "minecraft:redstone_block"}, + "ironleaves": {"zone": "jungle", "tier": 1, "material": "cobblemon:leaf_stone"}, + "regirock": {"zone": "dripstone", "tier": 1, "material": "minecraft:amethyst_shard"}, + "latias": {"zone": "highlands", "tier": 1, "material": "cobblemon:sun_stone"}, + "latios": {"zone": "highlands", "tier": 1, "material": "cobblemon:moon_stone"}, + "walkingwake": {"zone": "mire", "tier": 1, "material": "cobblemon:water_stone"}, + "regidrago": {"zone": "sunscorch", "tier": 1, "material": "minecraft:gold_block"}, + "articuno": {"zone": "frostpeak", "tier": 1, "material": "cobblemon:ice_stone"}, + "regice": {"zone": "frostpeak", "tier": 1, "material": "cobblemon:icy_rock"}, + "registeel": {"zone": "deep_dark", "tier": 1, "material": "minecraft:iron_block"}, + "moltres": {"zone": "basalt", "tier": 1, "material": "cobblemon:fire_stone"}, + "poipole": {"zone": "the_end", "tier": 1, "material": "minecraft:ender_pearl"}, + "xerneas": {"zone": "jungle", "tier": 2, "material": "cobblemon:leaf_stone"}, + "zarude": {"zone": "jungle", "tier": 2, "material": "minecraft:redstone_block"}, + "mew": {"zone": "jungle", "tier": 2, "material": "cobblemon:shiny_stone"}, + "hooh": {"zone": "highlands", "tier": 2, "material": "cobblemon:sun_stone"}, + "lugia": {"zone": "deep_sea", "tier": 2, "material": "cobblemon:water_stone"}, + "regigigas": {"zone": "deep_dark", "tier": 2, "material": "minecraft:echo_shard"}, + "rayquaza": {"zone": "frostpeak", "tier": 3, "material": "minecraft:emerald_block"}, + "mewtwo": {"zone": "deep_dark", "tier": 3, "material": "cobblemon:dusk_stone"}, + "eternatus": {"zone": "the_end", "tier": 3, "material": "minecraft:ender_eye"} + } +}