M8: progression, items, bankarta och sparfil
All checks were successful
release / build-release (push) Successful in 1m46s

- internal/progress: katalog (skills.json 12 noder, items.json 25 items)
  med validering; XP/nivåer (150·n(n+1)/2) och skillpoäng; skillträd med
  krav och kostnad; items per plats med buffar, genvägar (JR Pass, kartor,
  powerbank) och färgton; banresultat och upplåsning (huvudbanor i ordning,
  sidospår efter föräldern); 33 %-regeln som test
- internal/save: versionerad JSON med kunskap, plånbok, debuffar,
  progression och pågående bana + seed; atomisk skrivning; migrering;
  ~/.config/metro-puzzle-jp/save.json resp. %AppData%
- sim: RunOptions får Extra/FogRadius/Landmarks/FreeGates/RevealAll/
  InfiniteBattery; luck påverkar trängselzonen; Fog.RevealAll och extra
  landmärken
- game: bankarta i spelbrädesstil ersätter menyn (⟳ återupptar med sparad
  seed), skillträd (T), garderob (I), butik i kiosken (B), XP/nivå/items/
  upplåsningar på resultatet, spelaren tonas av skins; autospar vid banstart,
  efter banan och vid köp; flaggor -save/-nosave
- level: kind/order/parent/rewards/shop; ny sidobana 002b Kabukicho som
  belönar skinnet Kimono; 001 belönar Salaryman-skinnet; butikssortiment
  på 002/003
- tools/shots: demo-sparfil (build/, aldrig den riktiga), bilder av karta,
  skills, garderob och butik; alla körningar med -nosave
- docs/README/wiki uppdaterade

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 11:29:30 +02:00
parent d466333f01
commit 915c684dc2
46 changed files with 3058 additions and 316 deletions

432
resources/data/items.json Normal file
View File

@@ -0,0 +1,432 @@
{
"_comment": "Items: kläder, masker, hattar, prylar. slot = head/face/body/feet/bag (ett per plats bärs). price = kontantpris i kiosken (0 = bara belöning). effect som skills + freeGates (spärrar gratis), revealLevel (minikartan avslöjad på en bana), battery (telefonen laddar inte ur). tint = färgton på spelaren när det bärs.",
"items": [
{
"id": "cap_red",
"kind": "hat",
"slot": "head",
"name": {
"sv": "Röd keps",
"en": "Red cap"
},
"price": 800,
"effect": {
"stats": {
"focus": 1.05
}
}
},
{
"id": "sun_hat",
"kind": "hat",
"slot": "head",
"name": {
"sv": "Solhatt",
"en": "Sun hat"
},
"price": 1200,
"effect": {
"stats": {
"thirst": 0.9
}
},
"tint": [
1,
0.95,
0.7
]
},
{
"id": "beanie",
"kind": "hat",
"slot": "head",
"name": {
"sv": "Mössa",
"en": "Beanie"
},
"price": 900,
"effect": {
"stats": {
"toilet": 1.1,
"focus": 1.1
}
}
},
{
"id": "conductor_cap",
"kind": "hat",
"slot": "head",
"name": {
"sv": "Konduktörsmössa",
"en": "Conductor cap"
},
"price": 3000,
"effect": {
"stats": {
"luck": 1.15
}
},
"tint": [
0.8,
0.85,
1
]
},
{
"id": "mask_surgical",
"kind": "mask",
"slot": "face",
"name": {
"sv": "Munskydd",
"en": "Surgical mask"
},
"price": 300,
"effect": {
"stats": {
"toilet": 0.95
}
}
},
{
"id": "mask_fox",
"kind": "mask",
"slot": "face",
"name": {
"sv": "Rävmask",
"en": "Fox mask"
},
"price": 1500,
"effect": {
"stats": {
"luck": 1.1
}
},
"tint": [
1,
0.85,
0.7
]
},
{
"id": "mask_tengu",
"kind": "mask",
"slot": "face",
"name": {
"sv": "Tengumask",
"en": "Tengu mask"
},
"price": 2200,
"effect": {
"stats": {
"focus": 0.9,
"speed": 1.08
}
},
"tint": [
1,
0.7,
0.7
]
},
{
"id": "sunglasses",
"kind": "mask",
"slot": "face",
"name": {
"sv": "Solglasögon",
"en": "Sunglasses"
},
"price": 1100,
"effect": {
"stats": {
"focus": 0.95,
"luck": 1.05
}
}
},
{
"id": "happi",
"kind": "clothes",
"slot": "body",
"name": {
"sv": "Happi-jacka",
"en": "Happi coat"
},
"price": 2500,
"effect": {
"stats": {
"speed": 1.05
}
},
"tint": [
0.7,
0.8,
1
]
},
{
"id": "yukata",
"kind": "clothes",
"slot": "body",
"name": {
"sv": "Yukata",
"en": "Yukata"
},
"price": 4000,
"effect": {
"stats": {
"speed": 0.95,
"focus": 1.15
}
},
"tint": [
0.8,
0.9,
1
]
},
{
"id": "rain_poncho",
"kind": "clothes",
"slot": "body",
"name": {
"sv": "Regnponcho",
"en": "Rain poncho"
},
"price": 700,
"effect": {
"stats": {
"thirst": 1.05,
"toilet": 0.95
}
},
"tint": [
0.8,
1,
0.8
]
},
{
"id": "suit",
"kind": "clothes",
"slot": "body",
"name": {
"sv": "Kostym",
"en": "Suit"
},
"price": 5500,
"effect": {
"stats": {
"luck": 1.2,
"thirst": 1.1
}
},
"tint": [
0.75,
0.75,
0.8
]
},
{
"id": "sneakers",
"kind": "shoes",
"slot": "feet",
"name": {
"sv": "Sneakers",
"en": "Sneakers"
},
"price": 3500,
"effect": {
"stats": {
"speed": 1.1
}
}
},
{
"id": "geta",
"kind": "shoes",
"slot": "feet",
"name": {
"sv": "Geta",
"en": "Geta"
},
"price": 1800,
"effect": {
"stats": {
"speed": 0.9,
"luck": 1.2
}
}
},
{
"id": "hiking_boots",
"kind": "shoes",
"slot": "feet",
"name": {
"sv": "Vandringskängor",
"en": "Hiking boots"
},
"price": 4200,
"effect": {
"stats": {
"speed": 1.05,
"toilet": 0.9
}
}
},
{
"id": "flipflops",
"kind": "shoes",
"slot": "feet",
"name": {
"sv": "Badtofflor",
"en": "Flip-flops"
},
"price": 400,
"effect": {
"stats": {
"speed": 0.92,
"thirst": 0.9
}
}
},
{
"id": "powerbank",
"kind": "gadget",
"slot": "bag",
"name": {
"sv": "Powerbank",
"en": "Power bank"
},
"price": 2000,
"effect": {
"battery": true
}
},
{
"id": "water_bottle",
"kind": "gadget",
"slot": "bag",
"name": {
"sv": "Vattenflaska",
"en": "Water bottle"
},
"price": 600,
"effect": {
"stats": {
"thirst": 0.8
}
}
},
{
"id": "onigiri_box",
"kind": "gadget",
"slot": "bag",
"name": {
"sv": "Onigiri-låda",
"en": "Onigiri box"
},
"price": 900,
"effect": {
"stats": {
"focus": 1.05,
"toilet": 1.05
}
}
},
{
"id": "map_shinjuku",
"kind": "map",
"slot": "bag",
"name": {
"sv": "Karta: Shinjuku",
"en": "Map: Shinjuku"
},
"price": 600,
"effect": {
"revealLevel": "002-shinjuku"
}
},
{
"id": "map_shibuya",
"kind": "map",
"slot": "bag",
"name": {
"sv": "Karta: Shibuya",
"en": "Map: Shibuya"
},
"price": 800,
"effect": {
"revealLevel": "003-shibuya"
}
},
{
"id": "rail_pass",
"kind": "pass",
"slot": "bag",
"name": {
"sv": "JR Pass",
"en": "JR Pass"
},
"price": 8000,
"effect": {
"freeGates": true
}
},
{
"id": "omamori",
"kind": "charm",
"slot": "bag",
"name": {
"sv": "Omamori",
"en": "Omamori"
},
"price": 1300,
"effect": {
"stats": {
"luck": 1.15
}
}
},
{
"id": "skin_kimono",
"kind": "skin",
"slot": "body",
"name": {
"sv": "Kimono (skin)",
"en": "Kimono (skin)"
},
"price": 0,
"effect": {
"stats": {
"luck": 1.05
}
},
"tint": [
1,
0.75,
0.85
]
},
{
"id": "skin_salaryman",
"kind": "skin",
"slot": "body",
"name": {
"sv": "Salaryman (skin)",
"en": "Salaryman (skin)"
},
"price": 0,
"effect": {
"stats": {
"speed": 1.03
}
},
"tint": [
0.7,
0.7,
0.75
]
}
]
}