Phase 9: crafted summons for the legendaries

Adrian, 2026-11-09: legendaries, mythicals, Ultra Beasts and Paradox Pokemon
come from crafted summons. 22 Sigils (Naganadel evolves from Poipole), one
item told apart by custom data, from world/summons.json through
tools/summons.py: late-game recipes in three tiers (Lv 70, 80, 90), each used
in a fitting zone. A summoned legend fights as a boss (area attacks by level
and type, arena 32, the Guardian's Ward) but can be caught; on capture it
loses every boss mark. One at a time within 96 blocks.

Quest book: a Legends chapter, one quest per Sigil (97 quests). JEI lists each
Sigil as its own item, and Island Drops says where a legend is summoned; drops
Cobblemon names but doesn't have (Ho-Oh's Sacred Ash) get no slot.

Self-tests every_implemented_pokemon_is_obtainable (spawn, fossil or Sigil for
every implemented species) and sigil_summons_a_catchable_legend. Self-tests
and the island check pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
claudeandClaude Opus 5.5 committed 2026-11-09 13:03:50 +01:00
1 parent e206664b3d
commit f7ea371862
92 files changed
+4081 -21

No files matched your search

+7
View File
@@ -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 <FTB Quests folder>` 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. 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 <FTB Quests folder>` 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 ## JEI drop sources
```bash ```bash
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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
}
}
]
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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}"
]
}
}
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -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"
}
+1
View File
@@ -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 | | 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 | | 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` | | 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 | | 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`) | | 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") | | 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") |
+3
View File
@@ -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. - **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`. - **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`. - **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 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. - [ ] 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. - [ ] 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. - [ ] 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 ## Ask Adrian
+5 -1
View File
@@ -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): **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. - 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. - 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_<species>.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. **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.
+20 -1
View File
@@ -15,7 +15,8 @@
# checkmark: true the player ticks it # checkmark: true the player ticks it
# A task may also have a title. A chapter with `zone: <id>` starts with the quests of `zone_chapter`, where # A task may also have a title. A chapter with `zone: <id>` starts with the quests of `zone_chapter`, where
# {zone}, {low}, {high}, {hazard_text}, {guardian}, {guardian_level}, {drops} and {ore_names} come from the # {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: <n>` lays those out in a grid.
book: book:
title: Cobblemon Survival title: Cobblemon Survival
@@ -260,6 +261,24 @@ chapters:
- event: end_boss - event: end_boss
title: Beat Eternatus 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 - id: machines
title: Pokémon Machines title: Pokémon Machines
subtitle: Five machines, each powered by a Pokémon inside it subtitle: Five machines, each powered by a Pokémon inside it
@@ -22,6 +22,7 @@ import dev.cobblesurvival.world.OnlyPokemon
import dev.cobblesurvival.world.SharedLoot import dev.cobblesurvival.world.SharedLoot
import dev.cobblesurvival.world.SpecialPokemon import dev.cobblesurvival.world.SpecialPokemon
import dev.cobblesurvival.progress.QuestEvents import dev.cobblesurvival.progress.QuestEvents
import dev.cobblesurvival.summon.Summons
import dev.cobblesurvival.zone.GuardianBars import dev.cobblesurvival.zone.GuardianBars
import dev.cobblesurvival.zone.Guardians import dev.cobblesurvival.zone.Guardians
import dev.cobblesurvival.zone.InZoneCondition import dev.cobblesurvival.zone.InZoneCondition
@@ -70,6 +71,7 @@ class CobbleSurvival {
MOD_BUS.addListener(::onAddPackFinders) MOD_BUS.addListener(::onAddPackFinders)
InZoneCondition.register(MOD_BUS) InZoneCondition.register(MOD_BUS)
Machines.register(MOD_BUS) Machines.register(MOD_BUS)
Summons.register(MOD_BUS)
NeoForge.EVENT_BUS.addListener(::onRegisterCommands) NeoForge.EVENT_BUS.addListener(::onRegisterCommands)
NeoForge.EVENT_BUS.addListener(::onServerStarted) NeoForge.EVENT_BUS.addListener(::onServerStarted)
NeoForge.EVENT_BUS.addListener(::onPortalSpawn) NeoForge.EVENT_BUS.addListener(::onPortalSpawn)
@@ -17,7 +17,9 @@ object DropSources {
class Reward(val item: String, val count: Int) class Reward(val item: String, val count: Int)
class Spawned(val zone: String, val levels: String) class Spawned(val zone: String, val levels: String)
class LineMember(val zone: String, val species: String) class LineMember(val zone: String, val species: String)
class Pokemon(val species: String, val drops: List<Drop>, val zones: List<Spawned>, val line: List<LineMember>?) 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<Drop>, val zones: List<Spawned>, val line: List<LineMember>?, val summon: SummonedAt?)
class SpawnDrops(val species: String, val zone: String, val drops: List<Drop>) class SpawnDrops(val species: String, val zone: String, val drops: List<Drop>)
class Guardian(val zone: String, val species: String, val level: Int, val drops: List<Reward>, val respawn_hours: Double) class Guardian(val zone: String, val species: String, val level: Int, val drops: List<Reward>, 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<Reward>) class EndBoss(val species: String, val level: Int, val xp_first_win: Int, val xp: Int, val respawn_hours: Double, val first_win: List<Reward>)
@@ -33,6 +35,7 @@ object DropSources {
class Data( class Data(
val zones: Map<String, Zone>, val zones: Map<String, Zone>,
val pokemon: List<Pokemon>, val pokemon: List<Pokemon>,
val summons: List<Summon>,
val spawn_drops: List<SpawnDrops>, val spawn_drops: List<SpawnDrops>,
val guardians: List<Guardian>, val guardians: List<Guardian>,
val end_boss: EndBoss, val end_boss: EndBoss,
@@ -56,6 +59,9 @@ object DropSources {
return ItemStack(found, count.coerceIn(1, 99)) 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. */ /** The most a drop gives: "0-2" → 2. */
fun most(count: String?): Int = count?.substringAfter('-')?.toIntOrNull() ?: 1 fun most(count: String?): Int = count?.substringAfter('-')?.toIntOrNull() ?: 1
} }
@@ -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.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.item.PokemonItem import com.cobblemon.mod.common.item.PokemonItem
import dev.cobblesurvival.CobbleSurvival import dev.cobblesurvival.CobbleSurvival
import dev.cobblesurvival.summon.Summons
import mezz.jei.api.IModPlugin import mezz.jei.api.IModPlugin
import mezz.jei.api.JeiPlugin import mezz.jei.api.JeiPlugin
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder import mezz.jei.api.gui.builder.IRecipeLayoutBuilder
import mezz.jei.api.gui.drawable.IDrawable import mezz.jei.api.gui.drawable.IDrawable
import mezz.jei.api.gui.ingredient.IRecipeSlotsView 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.IFocusGroup
import mezz.jei.api.recipe.RecipeIngredientRole import mezz.jei.api.recipe.RecipeIngredientRole
import mezz.jei.api.recipe.RecipeType import mezz.jei.api.recipe.RecipeType
import mezz.jei.api.recipe.category.IRecipeCategory import mezz.jei.api.recipe.category.IRecipeCategory
import mezz.jei.api.registration.IRecipeCatalystRegistration import mezz.jei.api.registration.IRecipeCatalystRegistration
import mezz.jei.api.registration.IRecipeCategoryRegistration import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IExtraIngredientRegistration
import mezz.jei.api.registration.IRecipeRegistration import mezz.jei.api.registration.IRecipeRegistration
import mezz.jei.api.registration.ISubtypeRegistration
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Font import net.minecraft.client.gui.Font
import net.minecraft.client.gui.GuiGraphics 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.network.chat.Component
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack 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 * 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") 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<ItemStack> {
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) { override fun registerCategories(registration: IRecipeCategoryRegistration) {
val gui = registration.jeiHelpers.guiHelper val gui = registration.jeiHelpers.guiHelper
registration.addRecipeCategories(*kinds.map { kind -> 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("-", "–")}")) 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<ItemStack> = 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<Page> { fun pokemonPages(): List<Page> {
val data = DropSources.data val data = DropSources.data
val wild = data.pokemon.map { p -> val wild = data.pokemon.map { p ->
val rows = if (p.zones.isNotEmpty()) { val rows = if (p.zones.isNotEmpty()) {
p.zones.map { zoneRow(it.zone, it.levels) } 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 { } else {
listOf(Row(muted("Not wild. Its line lives in:"))) + p.line.orEmpty().map { Row(text(DropSources.zoneName(it.zone)), speciesName(it.species)) } 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 -> 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 return wild + special
} }
@@ -2,14 +2,22 @@ package dev.cobblesurvival.selftest
import com.cobblemon.mod.common.api.drop.DropTable import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.drop.ItemDropEntry 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.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail 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.BossDefs
import dev.cobblesurvival.boss.BossFights
import dev.cobblesurvival.boss.BossToughness
import dev.cobblesurvival.jei.DropSources import dev.cobblesurvival.jei.DropSources
import dev.cobblesurvival.jei.DropSourcesJei import dev.cobblesurvival.jei.DropSourcesJei
import dev.cobblesurvival.machine.MachineDefs import dev.cobblesurvival.machine.MachineDefs
import dev.cobblesurvival.progress.QuestEvents import dev.cobblesurvival.progress.QuestEvents
import dev.cobblesurvival.summon.Summons
import dev.cobblesurvival.world.SpecialPokemon
import dev.cobblesurvival.zone.Guardians import dev.cobblesurvival.zone.Guardians
import dev.cobblesurvival.zone.Zones import dev.cobblesurvival.zone.Zones
import java.util.function.Consumer import java.util.function.Consumer
@@ -32,8 +40,75 @@ object QuestTests {
SelfTestCase("quest_events_mark_zones", 200, ::zoneEvent), SelfTestCase("quest_events_mark_zones", 200, ::zoneEvent),
SelfTestCase("drop_sources_match_the_server", 20, ::dropSources), SelfTestCase("drop_sources_match_the_server", 20, ::dropSources),
SelfTestCase("jei_pages_build", 20, ::jeiPages), 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<Species>()
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<PokemonSpawnDetail>().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 * 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). * and pasture list, and every item on them exists (an unknown id would show as a barrier).
@@ -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/<species>.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<String, Def> = emptyMap()
private set
private val ITEMS = DeferredRegister.createItems(CobbleSurvival.MOD_ID)
val SIGIL: DeferredHolder<Item, SummonSigil> = ITEMS.register("summon_sigil", Supplier { SummonSigil(Item.Properties().stacksTo(1).rarity(Rarity.EPIC)) })
fun register(bus: IEventBus) {
ITEMS.register(bus)
NeoForge.EVENT_BUS.addListener<AddReloadListenerEvent> { it.addListener(this) }
CobblemonEvents.POKEMON_CAPTURED.subscribe(Priority.NORMAL) { released(it.pokemon) }
}
override fun apply(files: Map<ResourceLocation, JsonElement>, 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<ItemStack> {
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)
}
}
@@ -3,6 +3,7 @@ package dev.cobblesurvival.world
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import dev.cobblesurvival.boss.BossFights
import dev.cobblesurvival.zone.Guardians import dev.cobblesurvival.zone.Guardians
import net.minecraft.server.TickTask import net.minecraft.server.TickTask
import net.minecraft.server.level.ServerLevel 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: * 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. * 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 * 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 = 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) fun isTrainerDitto(pokemon: Pokemon): Boolean = pokemon.persistentData.contains(HMS_TRAINER)
@@ -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", "species": "cobblemon:audino",
"drops": [ "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", "species": "cobblemon:hoothoot",
"drops": [ "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", "species": "cobblemon:leafeon",
"drops": [ "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", "species": "cobblemon:lumineon",
"drops": [ "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", "species": "cobblemon:mienfoo",
"drops": [ "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", "species": "cobblemon:monferno",
"drops": [ "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", "species": "cobblemon:natu",
"drops": [ "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", "species": "cobblemon:politoed",
"drops": [ "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", "species": "cobblemon:relicanth",
"drops": [ "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", "species": "cobblemon:zebstrika",
"drops": [ "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": [ "spawn_drops": [
{ {
"species": "cobblemon:beheeyem", "species": "cobblemon:beheeyem",
@@ -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": "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.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": "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"
} }
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblesurvival:item/summon_sigil"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

@@ -7,7 +7,7 @@
id: "cobblemon:pasture" id: "cobblemon:pasture"
} }
id: "5B1F192C5A22F0B9" id: "5B1F192C5A22F0B9"
order_index: 17 order_index: 18
quest_links: [ ] quest_links: [ ]
quests: [ quests: [
{ {
@@ -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
}
]
}
@@ -7,7 +7,7 @@
id: "cobblesurvival:heat_core" id: "cobblesurvival:heat_core"
} }
id: "5170190C30A58C4C" id: "5170190C30A58C4C"
order_index: 16 order_index: 17
quest_links: [ ] quest_links: [ ]
quests: [ quests: [
{ {
@@ -1,4 +1,6 @@
{ {
"chapter.0217ED8D82F11BE4.chapter_subtitle": ["What never spawns on its own"]
"chapter.0217ED8D82F11BE4.title": "Legends"
"chapter.0F763138AA0551CF.title": "Verdant Jungle" "chapter.0F763138AA0551CF.title": "Verdant Jungle"
"chapter.1AB2113B8D294817.title": "Basalt Furnace" "chapter.1AB2113B8D294817.title": "Basalt Furnace"
"chapter.1B23BCD483E3F9CE.title": "Shallows" "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." "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.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": [ "quest.0644BAB8C69CE8D0.quest_desc": [
"Wild Pokémon in Westmarch are level 15 to 25. Bring a team that can hold its own there." "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." "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.quest_subtitle": "Lv 15–25"
"quest.0644BAB8C69CE8D0.title": "Westmarch" "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": [ "quest.0830DA072B96D6A8.quest_desc": [
"Southwold, north of Button Isle, is the next step: Pokémon up to level 18 and the island's copper." "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.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": [ "quest.0CA0C724D201B8A0.quest_desc": [
"There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "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." "Basalt Furnace has Ancient Debris, Quartz."
@@ -74,6 +92,10 @@
"Southwold has Raw Copper." "Southwold has Raw Copper."
] ]
"quest.1154E278D871A8CA.title": "Ores of Southwold" "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": [ "quest.1391BDC3E21A671E.quest_desc": [
"Each kind of Pokémon lives in one zone of the island. Catch three that call Basalt Furnace home." "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." "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." "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.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": [ "quest.20F77357783CD1BD.quest_desc": [
"Flygon, Lv 50, guards Sunscorch: a giant that takes at most a quarter of its health from any one attack." "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." "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.quest_subtitle": "Lv 12–28"
"quest.23A088BCF63BF446.title": "Lush Caves" "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": [ "quest.28873C8A3FDC26C6.quest_desc": [
"There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "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." "Dripstone Depths has Amethyst Shard, Moon Stone."
] ]
"quest.28873C8A3FDC26C6.title": "Ores of Dripstone Depths" "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": [ "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." "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." "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.quest_subtitle": "Lv 5–20"
"quest.2F51067D3773786B.title": "Shallows" "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": [ "quest.33052810B8325006.quest_desc": [
"There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "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." "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." "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.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": [ "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." "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." "Beat it for 3 Icy Rock, 2 Exp Candy L. It returns 5 hours later."
] ]
"quest.3F61AFD873C3F8EE.title": "Guardian of Frostpeak Range" "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": [ "quest.4508548D257AA751.quest_desc": [
"Each kind of Pokémon lives in one zone of the island. Catch three that call Dripstone Depths home." "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." "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.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": [ "quest.496174D8AF114AE5.quest_desc": [
"There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "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." "Lush Caves has Shiny Stone."
@@ -221,12 +279,20 @@
] ]
"quest.498A85F2039AF3BB.quest_subtitle": "Lv 25–35" "quest.498A85F2039AF3BB.quest_subtitle": "Lv 25–35"
"quest.498A85F2039AF3BB.title": "Highland Meadows" "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": [ "quest.4C0B4F1365903D23.quest_desc": [
"Wild Pokémon in Southwold are level 8 to 18. Bring a team that can hold its own there." "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." "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.quest_subtitle": "Lv 8–18"
"quest.4C0B4F1365903D23.title": "Southwold" "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": [ "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." "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." "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.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": [ "quest.55E9777C26CA6D8B.quest_desc": [
"There is no ore anywhere except in each zone's own veins, and they grow back after you mine them." "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." "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." "Beat it for 3 Exp Candy Xl, 2 Netherite Scrap. It returns 5 hours later."
] ]
"quest.64893157D81592CD.title": "Guardian of Basalt Furnace" "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": [ "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 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." "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." "Beat it for 3 Icy Rock, 4 Super Potion. It returns 5 hours later."
] ]
"quest.673147FA87104942.title": "Guardian of Highland Meadows" "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": [ "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." "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." "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." "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.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": [ "quest.6B424DADFF959A58.quest_desc": [
"An Electric-type Pokémon in a Dynamo Core shell of copper makes Forge Energy for cables and other machines." "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." "Beating it opens the way home and leaves the dragon egg the first time."
] ]
"quest.6EB4CFA7061556F9.title": "Eternatus" "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": [ "quest.6F4F5AFD500EF638.quest_desc": [
"Each kind of Pokémon lives in one zone of the island. Catch three that call Mangrove Mire home." "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." "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." "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.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": [ "quest.731852EDB1EE12B7.quest_desc": [
"Wild Pokémon in Deep Sea are level 30 to 50. Bring a team that can hold its own there." "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." "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." "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.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": [ "quest.74149A0BF939C15E.quest_desc": [
"Wild Pokémon in Button Isle are level 2 to 10. Bring a team that can hold its own there." "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." "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.58EAEDE25DA7FDA3.title": "Reach Southwold"
"task.601AABB55A476514.title": "Beat Morpeko" "task.601AABB55A476514.title": "Beat Morpeko"
"task.60EA09356932EC73.title": "Reach Mangrove Mire" "task.60EA09356932EC73.title": "Reach Mangrove Mire"
"task.6120ECDE48C04063.title": "Read this"
"task.63B77EE998527582.title": "Beat Flygon" "task.63B77EE998527582.title": "Beat Flygon"
"task.643C68559D41888A.title": "Beat Pinsir" "task.643C68559D41888A.title": "Beat Pinsir"
"task.6D2ED8A178EE3B43.title": "Reach Verdant Jungle" "task.6D2ED8A178EE3B43.title": "Reach Verdant Jungle"
+7 -3
View File
@@ -38,7 +38,7 @@ hash = "8a7eab2ca30f47109add6cfbf4eeb4717e3704bc85902ee8f4c5307b2b2eeb3c"
[[files]] [[files]]
file = "config/ftbquests/quests/chapters/base.snbt" file = "config/ftbquests/quests/chapters/base.snbt"
hash = "46710212af0c6bf3f39e97b95d2a5e0dfdfb312470fbfab5f24b6d95764032c9" hash = "555564da7dd44e375664b94a51b2334c636d7c5d72db164b03c6fe9196d06de0"
[[files]] [[files]]
file = "config/ftbquests/quests/chapters/button_isle.snbt" file = "config/ftbquests/quests/chapters/button_isle.snbt"
@@ -72,13 +72,17 @@ hash = "3724fa8a038561cc8965e6dfe5bc62718872d04f385bb636e984988762046670"
file = "config/ftbquests/quests/chapters/jungle.snbt" file = "config/ftbquests/quests/chapters/jungle.snbt"
hash = "5afa0885dbd853ea973fb61881a14b97a98af4d0dd26b66d837541ba1b09c8c8" hash = "5afa0885dbd853ea973fb61881a14b97a98af4d0dd26b66d837541ba1b09c8c8"
[[files]]
file = "config/ftbquests/quests/chapters/legends.snbt"
hash = "faed84fa13b7ea26305e2c07e23d6be0d4198cbee177042279776864387c4d97"
[[files]] [[files]]
file = "config/ftbquests/quests/chapters/lush_caves.snbt" file = "config/ftbquests/quests/chapters/lush_caves.snbt"
hash = "bd5734f9df4e1dc1caa989c32b5dac797f5104a4c6c0987801d3650e12d1e491" hash = "bd5734f9df4e1dc1caa989c32b5dac797f5104a4c6c0987801d3650e12d1e491"
[[files]] [[files]]
file = "config/ftbquests/quests/chapters/machines.snbt" file = "config/ftbquests/quests/chapters/machines.snbt"
hash = "dbeb43e993d27656f75e7a64a118e3592c40b5cbfc089bdf6a02069edae57011" hash = "f747805848fc39fa30293baebc3bce75742663c5f30a6439b0318ac4cf9657f0"
[[files]] [[files]]
file = "config/ftbquests/quests/chapters/mire.snbt" file = "config/ftbquests/quests/chapters/mire.snbt"
@@ -110,7 +114,7 @@ hash = "35b6760d4c56b02f2ff77dd5ba2f0e634c7f68238ce2809cddb22d9c61c6f943"
[[files]] [[files]]
file = "config/ftbquests/quests/lang/en_us.snbt" file = "config/ftbquests/quests/lang/en_us.snbt"
hash = "bce591f1d3b03bd1b4fe5a49a6153e06b825b41c3fc17fba23ac6b262afb0d50" hash = "f06c0b3fd853aed231d9d72b0634da737b930f4a51db3eb17bf29c14ef548a35"
[[files]] [[files]]
file = "config/lootr-common.toml" file = "config/lootr-common.toml"
+1 -1
View File
@@ -6,7 +6,7 @@ pack-format = "packwiz:1.1.0"
[index] [index]
file = "index.toml" file = "index.toml"
hash-format = "sha256" hash-format = "sha256"
hash = "b5cad59e6cdca6b6c84dcdad5237f284d5a4626f63ffe20f64b814ac462f7ef5" hash = "b2c6b7b6b2cb01942dc1c17c6526bc83ee1cbe7f4857e8af4557c2c9b4b4117a"
[versions] [versions]
minecraft = "1.21.1" minecraft = "1.21.1"
+11 -3
View File
@@ -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) 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 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) 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 guardians each zone guardian: species, level, drops, return time
end_boss the End boss and what beating it gives end_boss the End boss and what beating it gives
@@ -104,15 +106,21 @@ def main():
for zid, levels in zs.items(): for zid, levels in zs.items():
line_zones[root_of(sid, species)].setdefault(zid, sid) 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 = [] pokemon = []
for sid, s in sorted(species.items()): for sid, s in sorted(species.items()):
drops = drop_entries(s["drops"]) drops = drop_entries(s["drops"])
root = root_of(sid, species) 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 continue
entry = {"species": sid, "drops": drops, entry = {"species": sid, "drops": drops,
"zones": [{"zone": z, "levels": f"{lo}-{hi}"} for z, (lo, hi) in sorted(where.get(sid, {}).items())]} "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())] entry["line"] = [{"zone": z, "species": member} for z, member in sorted(line_zones[root].items())]
pokemon.append(entry) 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 " "mod's JEI plugin (jei/DropSourcesJei.kt); checked against the live server by the self-test "
"drop_sources_match_the_server.", "drop_sources_match_the_server.",
"zones": {zid: {"name": z["name"], "levels": z["levels"]} for zid, z in zones.items()}, "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", []), "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())], "ore_veins": [{"zone": z, "items": items} for z, items in sorted(ore_veins.items())],
"pasture_finds": pasture_finds, "pasture_finds": pasture_finds,
+18 -4
View File
@@ -230,6 +230,15 @@ def chapter_quests(chapter, book, zones):
for t in q.get("tasks", []): for t in q.get("tasks", []):
tasks += [{**t, "item": o, "each": None} for o in fields["ores"]] if t.get("each") == "ores" else [t] 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] 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). # "Catch Pokémon of a zone": its spawn pool's species (Cobblemon Quests' own biome filter knows no zones).
for q in quests: for q in quests:
for t in q.get("tasks", []): for t in q.get("tasks", []):
@@ -264,8 +273,9 @@ def task_nbt(task, name, events):
raise ValueError(f"{name}: unknown task {task}") raise ValueError(f"{name}: unknown task {task}")
def auto_layout(quests, chapter_id): def auto_layout(quests, chapter_id, grid=None):
"""Left to right by dependency depth inside the chapter, stacked within a column.""" """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} local = {q["id"] for q in quests}
depth = {} depth = {}
@@ -279,6 +289,10 @@ def auto_layout(quests, chapter_id):
for q in quests: for q in quests:
columns.setdefault(d(q), []).append(q["id"]) columns.setdefault(d(q), []).append(q["id"])
pos = {} 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 col, ids in columns.items():
for row, qid in enumerate(ids): for row, qid in enumerate(ids):
pos[f"{chapter_id}/{qid}"] = [col * 2.0, (row - (len(ids) - 1) / 2) * 1.5] 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"]): for index, chapter in enumerate(book["chapters"]):
cid = chapter["id"] cid = chapter["id"]
quests = expanded[cid] quests = expanded[cid]
auto = auto_layout(quests, cid) auto = auto_layout(quests, cid, chapter.get("columns"))
chapter_id = object_id(f"chapter:{cid}") chapter_id = object_id(f"chapter:{cid}")
lang[f"chapter.{chapter_id}.title"] = chapter["title"] lang[f"chapter.{chapter_id}.title"] = chapter["title"]
if chapter.get("subtitle"): if chapter.get("subtitle"):
@@ -369,7 +383,7 @@ def pull(book, folder):
auto, by_id = {}, {} auto, by_id = {}, {}
for c in book["chapters"]: for c in book["chapters"]:
quests = chapter_quests(c, book, zones) 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} 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 {}) layout = dict(book.get("layout") or {})
for path in sorted((folder / "chapters").glob("*.snbt")): for path in sorted((folder / "chapters").glob("*.snbt")):
+104
View File
@@ -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/<species>.json species, level, zone, read by the companion mod (summon/Summons.kt)
recipe/summon_<species>.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()
+8
View File
@@ -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. # Adrian, 2026-11-02: Eternatus was too small (0.2x, about a block). Scaled to stand this many blocks tall.
END_HEIGHT = 15 END_HEIGHT = 15
END_ARENA = 40 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. # Up to this level: these patterns.
TIERS = [ TIERS = [
@@ -71,6 +73,7 @@ def species_data(jar):
if name.startswith("data/cobblemon/species/") and name.endswith(".json"): if name.startswith("data/cobblemon/species/") and name.endswith(".json"):
d = json.loads(z.read(name)) d = json.loads(z.read(name))
types[d["name"].lower()] = {t for t in (d.get("primaryType"), d.get("secondaryType")) if t} 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) heights[d["name"].lower()] = (d.get("hitbox") or {}).get("height", 1) * d.get("baseScale", 1)
return types, heights return types, heights
@@ -94,6 +97,11 @@ def main():
end = boss(END["level"], types.get(END["species"], set()), END_ARENA, end=end_def) 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") (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") 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__": if __name__ == "__main__":
+32
View File
@@ -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"}
}
}