Phase 3: Alpha guardians, one per zone, back 5 hours after a defeat
CI / build-and-smoke-test (push) Failing after 7m6s
CI / build-and-smoke-test (push) Failing after 7m6s
- Companion mod (zone/Guardians.kt): each zone's guardian stands at the zone's sample point, appears when a player is within 96 blocks, stays within 24 blocks, is uncatchable and half again as big. Beating it in a battle gives every player in the battle its drops; it returns after 5 hours of game time (Adrian: fixed spots, 5 hours). State lives in the world save; /cobblesurvival guardians lists it. - tools/zone_spawns.py writes data/cobblesurvival/guardians/<zone>.json: the strongest walking (or swimming) Pokemon of the zone at band top + 5, with the drops from world/zones.json. Boss drops follow Adrian's rule: Icy Rocks before Sunscorch, Heat Rocks before Frostpeak. - Goat Fur and Hoglin Hide recipes make 8 per rock, so one guardian's 3 rocks pay for one full insulating set. - Self-test guardian_appears_and_returns; hazard tests cleaned up; the zone generator reads Cobblemon's own entries from the field guide's hidden_spawns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
398301f0be
commit
73fe71918f
25 files changed
+607
-23
No files matched your search
+39
-1
@@ -21,6 +21,9 @@ datapacks/core/data/cobblesurvival/spawn_pool_world/<zone>.json:
|
||||
doesn't spawn there. If no stage fits, the closest one spawns across the whole band.
|
||||
3. world/zones.json → "species" pins a line to a zone by hand: {"pikachu": "southwold"}.
|
||||
4. In cave zones, sky-light minimums, "can see sky" and the "natural" ground preset are dropped.
|
||||
5. Each zone with a "guardian" gets datapacks/core/data/cobblesurvival/guardians/<zone>.json: the
|
||||
strongest Pokémon spawning in the zone (or "species"), uncatchable, half again as big, five levels
|
||||
above the band, with the zone's boss drops and world/zones.json → guardian_respawn_hours.
|
||||
|
||||
Also writes docs/zone-species.md, the list per zone for review.
|
||||
|
||||
@@ -41,6 +44,9 @@ from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
OUT = ROOT / "datapacks/core/data/cobblesurvival/spawn_pool_world"
|
||||
GUARDIANS = ROOT / "datapacks/core/data/cobblesurvival/guardians"
|
||||
GUARDIAN_SCALE = 1.5 # "Alpha": half again as big as a normal one
|
||||
GUARDIAN_LEVELS_ABOVE_BAND = 5
|
||||
REPORT = ROOT / "docs/zone-species.md"
|
||||
EXCLUDED_LABELS = {"legendary", "mythical", "ultra_beast", "paradox", "restricted"}
|
||||
MIN_CELLS = 5 # a zone "has" a biome when at least this many grid cells of it lie in the zone
|
||||
@@ -242,6 +248,29 @@ def main():
|
||||
"spawns": sorted(spawns, key=lambda s: s["id"]),
|
||||
}, indent=1) + "\n")
|
||||
|
||||
GUARDIANS.mkdir(parents=True, exist_ok=True)
|
||||
for old in GUARDIANS.glob("*.json"):
|
||||
old.unlink()
|
||||
guardians = {}
|
||||
for zid, zone in zones.items():
|
||||
config = zone.get("guardian")
|
||||
if not config:
|
||||
continue
|
||||
# A guardian stands its ground: on land a walking spawn, at sea a swimming one, never a fishing catch.
|
||||
kinds = {"submerged", "surface"} if "water" in zone.get("rule", {}) else {"grounded"}
|
||||
spawning = {s["pokemon"].split()[0].lower() for s in pools.get(zid, []) if s.get("spawnablePositionType") in kinds}
|
||||
species_name = config.get("species") or max(spawning, key=lambda n: bst.get(f"cobblemon:{n}", 0))
|
||||
level = zone["levels"][1] + GUARDIAN_LEVELS_ABOVE_BAND
|
||||
guardians[zid] = species_name
|
||||
(GUARDIANS / f"{zid}.json").write_text(json.dumps({
|
||||
"_comment": "Generated by tools/zone_spawns.py from world/zones.json; do not edit by hand.",
|
||||
"zone": zid,
|
||||
"pokemon": f"{species_name} level={level} uncatchable=yes",
|
||||
"scale": GUARDIAN_SCALE,
|
||||
"drops": [{"item": item, "count": count} for item, count in config["drops"]],
|
||||
"respawn_hours": plan["guardian_respawn_hours"],
|
||||
}, indent=1) + "\n")
|
||||
|
||||
lines_out = ["# Pokémon per zone", "",
|
||||
"Generated by `tools/zone_spawns.py` from Cobblemon's spawn data and `world/zones.json`; "
|
||||
"do not edit by hand. Each evolution line spawns in one zone; the stages listed are the ones "
|
||||
@@ -251,7 +280,16 @@ def main():
|
||||
rows = sorted(report.get(zid, []))
|
||||
lines_out += [f"## {zone['name']} (Lv {zone['levels'][0]}–{zone['levels'][1]}, {len(rows)} lines)", ""]
|
||||
lines_out += [", ".join(f"{root}" + (f" ({', '.join(n)})" if n != [root] else "") for root, n in rows) or "none", ""]
|
||||
REPORT.write_text("\n".join(lines_out))
|
||||
lines_out += ["## Alpha guardians", "",
|
||||
f"One per zone at its sample point, uncatchable, five levels above the band; it returns "
|
||||
f"{plan['guardian_respawn_hours']} hours after it is beaten. Its drops help with the next zone.", "",
|
||||
"| Zone | Guardian | Level | Drops |", "| --- | --- | --- | --- |"]
|
||||
for zid, species_name in guardians.items():
|
||||
zone = zones[zid]
|
||||
drop_text = ", ".join(f"{count}× {item.split(':')[1]}" for item, count in zone["guardian"]["drops"])
|
||||
lines_out.append(f"| {zone['name']} | {species[f'cobblemon:{species_name}']['name'] if f'cobblemon:{species_name}' in species else species_name} "
|
||||
f"| {zone['levels'][1] + GUARDIAN_LEVELS_ABOVE_BAND} | {drop_text} |")
|
||||
REPORT.write_text("\n".join(lines_out) + "\n")
|
||||
|
||||
unplaced = [r for r in lines if r not in home]
|
||||
for zid, zone in zones.items():
|
||||
|
||||
Reference in new issue
Block a user