Phase 6: Pokémon machines (five cores, shells as data)
Adrian (2026-10-31): a Large Furnace where a Fire Pokémon heats real furnaces (hoppers in and out), our own Electric generator, no upkeep; then a drop synthesizer (FE into full drop rolls, looting tiers), a sacrifice altar (level tiers, rare candies only from Lv 80) and a rebirth chamber (Lv 100 -> shiny Lv 1 first stage, three perfect IVs, moves kept, Ability Patch so the hidden ability is optional). - machine/: data-driven 3x3x3 shells (window spots for glass, free spot under the core), checked in four rotations; the Pokémon walks in from the party and lives in the core; breaking core or shell sends it home (party, else PC, offline too); a real Cobblemon entity copy is shown in the chamber (no AI, invulnerable, uncatchable, never saved). - Heat Core keeps vanilla furnaces lit and faster; Dynamo Core makes and pushes FE; Synthesis Core takes FE and rolls drops into a hopper- extractable buffer; Altar Core sacrifices on a confirmed sneak-use; Rebirth Core runs on server time. - Recipes, casing tags, block loot, textures (tools/machine_assets.py), models, blockstates, names. - Self-tests: in/out, refusal, shell and core breaks (PC when full), chunk unload, server restart, and each machine's work. - Docs: design, balance table, Phase 6 checklist; Phase 5 approved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5cae9252c3
commit
0877a6a179
75 files changed
+2321
-7
No files matched your search
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Writes the machine cores' textures, block models, item models and blockstates (Phase 6).
|
||||
|
||||
Each core is an "orientable" block (front, side, top) facing the player who placed it. The 16x16 textures are drawn
|
||||
here, from a palette and an emblem per machine, so they can be redrawn after a change. Our own art (pack license).
|
||||
|
||||
Usage: tools/machine_assets.py
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
ASSETS = ROOT / "mod/src/main/resources/assets/cobblesurvival"
|
||||
|
||||
# name: (dark, mid, light, accent, emblem)
|
||||
CORES = {
|
||||
"heat_core": ((92, 34, 26), (150, 62, 44), (186, 92, 66), (255, 160, 40), "flame"),
|
||||
"dynamo_core": ((112, 58, 36), (184, 104, 70), (224, 150, 108), (255, 230, 70), "bolt"),
|
||||
"synthesis_core": ((70, 74, 80), (128, 134, 142), (180, 186, 194), (90, 220, 120), "drop"),
|
||||
"altar_core": ((22, 18, 26), (52, 44, 58), (84, 72, 92), (190, 60, 220), "eye"),
|
||||
"rebirth_core": ((70, 40, 110), (130, 90, 190), (186, 150, 236), (255, 200, 245), "star"),
|
||||
}
|
||||
|
||||
EMBLEMS = {
|
||||
"flame": [
|
||||
"......#.........",
|
||||
".....##.........",
|
||||
".....###..#.....",
|
||||
"....####.##.....",
|
||||
"...#########....",
|
||||
"...##########...",
|
||||
"..###++######...",
|
||||
"..##++++#####...",
|
||||
"..##+++++####...",
|
||||
"...##+++++##....",
|
||||
"....########....",
|
||||
],
|
||||
"bolt": [
|
||||
"........####....",
|
||||
".......####.....",
|
||||
"......####......",
|
||||
".....####.......",
|
||||
"....#######.....",
|
||||
".......####.....",
|
||||
"......####......",
|
||||
".....###........",
|
||||
"....##..........",
|
||||
"...#............",
|
||||
],
|
||||
"drop": [
|
||||
".......#........",
|
||||
"......###.......",
|
||||
".....#####......",
|
||||
"....###+###.....",
|
||||
"...###+++###....",
|
||||
"...##+++++##....",
|
||||
"...###+++###....",
|
||||
"....#######.....",
|
||||
".....#####......",
|
||||
],
|
||||
"eye": [
|
||||
"................",
|
||||
".....######.....",
|
||||
"...##......##...",
|
||||
"..#...####...#..",
|
||||
".#...##++##...#.",
|
||||
"..#...####...#..",
|
||||
"...##......##...",
|
||||
".....######.....",
|
||||
],
|
||||
"star": [
|
||||
".......#........",
|
||||
".......#........",
|
||||
"......###.......",
|
||||
"..###########...",
|
||||
"....#######.....",
|
||||
".....#####......",
|
||||
"....###.###.....",
|
||||
"...##.....##....",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def frame(image, dark, light):
|
||||
for i in range(16):
|
||||
image.putpixel((i, 0), light)
|
||||
image.putpixel((0, i), light)
|
||||
image.putpixel((i, 15), dark)
|
||||
image.putpixel((15, i), dark)
|
||||
|
||||
|
||||
def side(dark, mid, light):
|
||||
image = Image.new("RGBA", (16, 16), mid + (255,))
|
||||
for y in range(16):
|
||||
for x in range(16):
|
||||
# Plates of 8x4 with a seam, offset every other row, like bricks or panels.
|
||||
if y % 4 == 0 or (x + (4 if (y // 4) % 2 else 0)) % 8 == 0:
|
||||
image.putpixel((x, y), dark + (255,))
|
||||
elif (x + y) % 7 == 0:
|
||||
image.putpixel((x, y), light + (255,))
|
||||
frame(image, dark + (255,), light + (255,))
|
||||
return image
|
||||
|
||||
|
||||
def top(dark, mid, light, accent):
|
||||
image = side(dark, mid, light)
|
||||
for y in range(5, 11):
|
||||
for x in range(5, 11):
|
||||
edge = x in (5, 10) or y in (5, 10)
|
||||
image.putpixel((x, y), (dark if edge else accent) + (255,))
|
||||
return image
|
||||
|
||||
|
||||
def front(dark, mid, light, accent, emblem):
|
||||
image = Image.new("RGBA", (16, 16), dark + (255,))
|
||||
for y in range(2, 14):
|
||||
for x in range(2, 14):
|
||||
image.putpixel((x, y), (mid if (x + y) % 2 else dark) + (255,))
|
||||
frame(image, dark + (255,), light + (255,))
|
||||
rows = EMBLEMS[emblem]
|
||||
top_row = (16 - len(rows)) // 2
|
||||
glow = tuple(min(255, c + 60) for c in accent)
|
||||
for y, row in enumerate(rows):
|
||||
for x, c in enumerate(row):
|
||||
if c == "#":
|
||||
image.putpixel((x, top_row + y), accent + (255,))
|
||||
elif c == "+":
|
||||
image.putpixel((x, top_row + y), glow + (255,))
|
||||
return image
|
||||
|
||||
|
||||
def write_json(path, data):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(data, indent=2) + "\n")
|
||||
|
||||
|
||||
def main():
|
||||
textures = ASSETS / "textures/block"
|
||||
textures.mkdir(parents=True, exist_ok=True)
|
||||
for name, (dark, mid, light, accent, emblem) in CORES.items():
|
||||
side(dark, mid, light).save(textures / f"{name}_side.png")
|
||||
top(dark, mid, light, accent).save(textures / f"{name}_top.png")
|
||||
front(dark, mid, light, accent, emblem).save(textures / f"{name}_front.png")
|
||||
write_json(ASSETS / f"models/block/{name}.json", {
|
||||
"parent": "minecraft:block/orientable",
|
||||
"textures": {"top": f"cobblesurvival:block/{name}_top", "front": f"cobblesurvival:block/{name}_front",
|
||||
"side": f"cobblesurvival:block/{name}_side"},
|
||||
})
|
||||
write_json(ASSETS / f"models/item/{name}.json", {"parent": f"cobblesurvival:block/{name}"})
|
||||
rotation = {"north": 0, "east": 90, "south": 180, "west": 270}
|
||||
write_json(ASSETS / f"blockstates/{name}.json", {
|
||||
"variants": {f"facing={facing}": {"model": f"cobblesurvival:block/{name}", **({"y": y} if y else {})}
|
||||
for facing, y in rotation.items()},
|
||||
})
|
||||
print(f"wrote {len(CORES)} cores to {ASSETS.relative_to(ROOT)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user