Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

game_data.gno

22.49 Kb · 374 lines
  1// GnoMoji — Main Game Realm (game30)
  2// gno.land/r/g138gdmwj6heduu3st796lw6qqdwylgaxf7ty5gz/game30
  3//
  4// game29 closes the game28 audit holes (see SECURITY_GAME28.md):
  5//   - claims and achievements need an ed25519 voucher from the server's claim
  6//     signer (a dedicated key, never the treasury), with per-player nonces;
  7//   - per-rarity rate caps still apply on chain, plus per-coin vein caps;
  8//   - the Gnome Pass costs real ugnot (OriginSend), withdrawable by admin;
  9//   - PvP commit/reveal is hash-checked, casino bets settle on chain;
 10//   - player state can be imported once from game27/game28, then locked.
 11
 12package game31
 13
 14import (
 15	"gno.land/p/nt/avl/v0"
 16)
 17
 18const realmPkgPath = "gno.land/r/g138gdmwj6heduu3st796lw6qqdwylgaxf7ty5gz/game30"
 19
 20// ── State ────────────────────────────────────────────────────────────────────
 21
 22var (
 23	admin    address // deployer; can set roles, prices, veins, migrate, withdraw
 24	operator address // server hot account for casino seeds (defaults to admin)
 25
 26	// claimSignerPubKey is the ed25519 public key (32 bytes) whose signatures
 27	// authorise ClaimAndMint / achievement vouchers. Empty = claims disabled.
 28	claimSignerPubKey []byte
 29	claimNonces       avl.Tree // addr → last used voucher nonce (decimal string)
 30
 31	balances      avl.Tree // addr+":"+coinId → amount string
 32	claimBuckets  avl.Tree // addr → "m0:t0|m1:t1|m2:t2|m3:t3|m4:t4|m5:t5|m6:t6" (packed; lazy-migrated from old addr:r keys)
 33	veinMinted    avl.Tree // coinId → total ever credited by claims/rewards/migration
 34	veinMaxOverride avl.Tree // coinId → admin-set max (overrides the rarity default)
 35	veinOverrideActive bool   // true once any SetVeinMax has been called; gates the veinMaxOverride AVL read
 36	casinoRounds  avl.Tree // roundId → *casinoRound
 37	pvpLobbies    avl.Tree // lobbyId and lobbyId+":field" → string (see game_pvp.gno)
 38	pvpWagers     avl.Tree // lobbyId → "coinId:amount:creator:challenger"
 39	ownedTools    avl.Tree // addr → comma-separated tool IDs
 40	toolLife      avl.Tree // addr+":"+toolId → remaining life string
 41	lifetimeMined avl.Tree // addr+":"+coinId → total mined string (real claims only)
 42	rewarded      avl.Tree // addr+":"+coinId → total credited by rewards (medals etc.)
 43	achievements  avl.Tree // addr+":"+achId → "1"
 44	dailyCheckins avl.Tree // addr → unix seconds string
 45	skillRanks    avl.Tree // addr+":"+skillId → rank string
 46	miners        avl.Tree // addr → total mined all-time string
 47	playerXp      avl.Tree // addr → cumulative rarity-weighted XP (uint64 string)
 48	lastClaim     avl.Tree // addr → unix timestamp of last ClaimAndMint
 49	blacklist     avl.Tree // addr → "reason:timestamp"
 50	banExpiries   avl.Tree // addr → unix expiry (0 = permanent)
 51	guilds        avl.Tree // guildId → JSON{name, leader, memberCount, createdAt}
 52	guildMembers  avl.Tree // guildId+":"+addr → "1"
 53	playerGuild   avl.Tree // addr → guildId
 54	gnomePasses   avl.Tree // addr → unix expiry timestamp string
 55
 56	paused bool
 57
 58	// Gnome Pass price in ugnot per 30 days (admin-settable).
 59	passPriceUgnot = int64(5000000)
 60	passRevenueUgnot int64 // lifetime ugnot received for passes (accounting only)
 61
 62	pvpCounter   uint64 // monotonically increasing lobby number
 63	guildCounter uint64 // monotonically increasing guild number
 64
 65	// Migration (game27/game28 → game29). Batches are idempotent (set
 66	// semantics + batch registry); FinalizeMigration locks imports forever.
 67	migrationFinalized bool
 68	migrationBatches   avl.Tree // batchId → kind
 69)
 70
 71// ── Tool Tables (game29) ──────────────────────────────────────────────────────
 72// One ID scheme shared with src/lib/game/catalog.ts. Every ingredient is
 73// mineable by the previous tool (rarity ≤ prev maxRarity). Repair = ceil(30%
 74// of cost). See REPORT.md §4 for the full progression table and §5 for the
 75// claim-rate cap table.
 76
 77// toolOrder is the canonical upgrade path from hands to omega.
 78var toolOrder = []string{
 79	"hands", "starter-twig", "twig", "wood", "stone", "iron", "gold",
 80	"diamond", "cosmic", "plasma", "neutron", "quasar", "void", "genesis", "omega",
 81}
 82
 83// toolRequires: BuyTool must panic unless the caller owns the prerequisite tool.
 84var toolRequires = map[string]string{
 85	"starter-twig": "hands",
 86	"twig":         "starter-twig",
 87	"wood":         "twig",
 88	"stone":        "wood",
 89	"iron":         "stone",
 90	"gold":         "iron",
 91	"diamond":      "gold",
 92	"cosmic":       "diamond",
 93	"plasma":       "cosmic",
 94	"neutron":      "plasma",
 95	"quasar":       "neutron",
 96	"void":         "quasar",
 97	"genesis":      "void",
 98	"omega":        "genesis",
 99}
100
101// toolMaxRarity: highest coin rarity each tool can mine (used by the claim rate cap).
102var toolMaxRarity = map[string]int{
103	"hands":        0,
104	"starter-twig": 0,
105	"twig":         0,
106	"wood":         1,
107	"stone":        2,
108	"iron":         3,
109	"gold":         4,
110	"diamond":      5,
111	"cosmic":       6,
112	"plasma":       6,
113	"neutron":      6,
114	"quasar":       6,
115	"void":         6,
116	"genesis":      6,
117	"omega":        6,
118}
119
120// toolCosts maps toolId → slice of [coinId, amount] pairs.
121// Matches catalog.ts TOOLS array exactly. Amounts are for qty=1.
122var toolCosts = map[string][][2]string{
123	"starter-twig": {
124		{"grin", "13"},
125	},
126	"twig": {
127		{"grin", "14"}, {"joy", "9"}, {"cool", "7"},
128	},
129	"wood": {
130		{"seedling", "19"}, {"leaves", "16"}, {"fallen", "13"}, {"think", "11"}, {"sleep", "10"}, {"party", "8"},
131	},
132	"stone": {
133		{"rock", "50"}, {"log", "45"}, {"evergreen", "40"}, {"brick", "35"}, {"mushroom", "30"}, {"heart", "25"},
134		{"deciduous", "20"}, {"cactus", "15"},
135	},
136	"iron": {
137		{"gear", "42"}, {"chains", "42"}, {"wrench", "38"}, {"hammer", "34"}, {"anchor", "34"}, {"pick", "29"},
138		{"nut", "21"}, {"saw", "8"}, {"hammer-wrench", "17"}, {"magnet", "4"},
139	},
140	"gold": {
141		{"gold-medal", "150"}, {"crown", "140"}, {"trophy", "130"}, {"money-bag", "120"}, {"bolt", "120"}, {"sword", "110"},
142		{"dagger", "10"}, {"bow", "10"}, {"bullseye", "30"}, {"mahjong", "10"}, {"hanafuda", "10"}, {"fireworks", "10"},
143	},
144	"diamond": {
145		{"gem", "220"}, {"coin", "200"}, {"ring", "190"}, {"disco", "180"}, {"kite", "180"}, {"dodo", "160"},
146		{"scope", "10"}, {"xray", "10"}, {"tube", "10"}, {"dish", "10"}, {"lock", "40"}, {"key-lock", "30"},
147		{"eight", "20"}, {"puzzle", "30"},
148	},
149	"cosmic": {
150		{"galaxy", "336"}, {"moai", "320"}, {"hamsa", "320"}, {"mirror", "304"}, {"atom", "288"}, {"ufo", "256"},
151		{"whale-spout", "16"}, {"whale", "16"}, {"sun", "16"}, {"radioactive", "16"}, {"cyclone", "16"}, {"tornado", "16"},
152		{"sat", "16"}, {"castle", "16"}, {"liberty", "16"}, {"castle-jp", "16"},
153	},
154	"plasma": {
155		{"galaxy", "1003"}, {"atom", "935"}, {"moai", "935"}, {"comet", "867"}, {"jelly", "799"}, {"peacock", "799"},
156		{"om", "17"}, {"yin", "17"}, {"ophiuchus", "17"}, {"fleur", "17"}, {"trident", "17"}, {"radioactive", "17"},
157		{"biohazard", "17"}, {"castle-jp", "34"}, {"sun-face", "17"}, {"dragon-face", "17"}, {"sauropod", "17"}, {"moon-word", "34"},
158	},
159	"neutron": {
160		{"jelly", "2040"}, {"peacock", "1870"}, {"unicorn", "1870"}, {"galaxy", "1700"}, {"hamsa", "1700"}, {"dna", "1496"},
161		{"genie", "17"}, {"heart-organ", "34"}, {"mage", "34"}, {"monarch", "51"}, {"ninja", "34"}, {"brain", "17"},
162		{"lotus-sit", "34"}, {"lion", "51"}, {"tiger", "51"}, {"eagle", "51"}, {"wolf", "68"}, {"shark", "85"},
163	},
164	"quasar": {
165		{"unicorn", "4590"}, {"peacock", "4590"}, {"jelly", "4590"}, {"lotus", "3510"}, {"galaxy", "3780"}, {"dragon", "3510"},
166		{"fireworks", "54"}, {"medal", "27"}, {"sports-medal", "54"}, {"silver-medal", "81"}, {"bronze-medal", "81"}, {"tower", "108"},
167		{"hot-spring", "135"}, {"pirate", "81"}, {"fairy", "108"}, {"vampire", "108"}, {"heli", "54"}, {"bullet", "81"},
168		{"race", "108"},
169	},
170	"void": {
171		{"lotus", "8990"}, {"unicorn", "10850"}, {"dragon", "10540"}, {"peacock", "10850"}, {"jelly", "11470"}, {"galaxy", "3720"},
172		{"om", "31"}, {"yin", "31"}, {"trident", "62"}, {"fleur", "62"}, {"ophiuchus", "31"}, {"shooting", "62"},
173		{"sun-face", "62"}, {"dragon-face", "93"}, {"rex", "93"}, {"sauropod", "93"}, {"mammoth", "124"}, {"new-face", "93"},
174		{"kaaba", "31"}, {"witness", "31"}, {"genie", "31"},
175	},
176	"genesis": {
177		{"lotus", "18000"}, {"dragon", "18000"}, {"unicorn", "17520"}, {"peacock", "16560"}, {"jelly", "16080"}, {"infinity", "14160"},
178		{"genie", "48"}, {"witness", "48"}, {"sun-face", "144"}, {"shooting", "96"}, {"dragon-face", "168"}, {"om", "72"},
179		{"yin", "72"}, {"trident", "72"}, {"fleur", "72"}, {"kaaba", "72"}, {"rex", "144"}, {"sauropod", "144"},
180		{"mammoth", "168"}, {"new-face", "144"}, {"lion", "264"}, {"shark", "504"},
181	},
182	"omega": {
183		{"lotus", "26970"}, {"dragon", "25110"}, {"unicorn", "24180"}, {"peacock", "23250"}, {"jelly", "23250"}, {"infinity", "22320"},
184		{"genie", "65"}, {"witness", "74"}, {"sun-face", "195"}, {"shooting", "158"}, {"dragon-face", "233"}, {"om", "93"},
185		{"yin", "93"}, {"trident", "112"}, {"fleur", "112"}, {"ophiuchus", "93"}, {"kaaba", "93"}, {"rex", "195"},
186		{"sauropod", "214"}, {"mammoth", "233"}, {"new-face", "195"}, {"mage", "307"}, {"heart-organ", "233"}, {"sat", "381"},
187	},
188}
189
190// skillBaseCosts maps skillId → base cost at rank 0.
191// Actual cost at rank N = base × 2^N (doubles per rank).
192var skillBaseCosts = map[string][][2]string{
193	// STRIKE branch
194	"wrist":               {{"grin", "80"}, {"joy", "20"}},
195	"palm_strike":         {{"cool", "60"}, {"think", "40"}},
196	"follow":              {{"fire", "40"}, {"up", "40"}},
197	"knuckle_wrap":        {{"rock", "45"}, {"log", "40"}},
198	"heavy_swing":         {{"brick", "35"}, {"evergreen", "30"}},
199	"stone_breaker":       {{"rock", "70"}, {"hammer", "25"}, {"gear", "20"}},
200	"anvil_force":         {{"chains", "35"}, {"wrench", "30"}, {"brick", "60"}},
201	"point_drive":         {{"pick", "35"}, {"gear", "40"}, {"log", "90"}},
202	"kinetic_thrust":      {{"rocket", "20"}, {"bolt", "12"}, {"fire", "70"}},
203	"crushing_blow":       {{"crown", "10"}, {"trophy", "12"}, {"hammer", "45"}, {"bolt", "15"}},
204	"shatter_spike":       {{"sword", "18"}, {"pick", "45"}, {"chains", "45"}, {"gold-medal", "12"}},
205	"ironclad_cleave":     {{"anchor", "40"}, {"gear", "60"}, {"wrench", "50"}, {"money-bag", "15"}},
206	"thunder_jab":         {{"bolt", "25"}, {"rocket", "30"}, {"fire", "120"}, {"wand", "15"}},
207	"titan_hammer":        {{"gem", "14"}, {"coin", "18"}, {"crown", "22"}, {"trophy", "22"}, {"sword", "28"}},
208	"diamond_cleave":      {{"gem", "20"}, {"ring", "12"}, {"disco", "15"}, {"pick", "70"}, {"gold-medal", "24"}},
209	"hyper_drive":         {{"kite", "15"}, {"dodo", "12"}, {"bolt", "35"}, {"rocket", "45"}, {"gear", "70"}},
210	"quasar_impact":       {{"galaxy", "18"}, {"moai", "18"}, {"atom", "20"}, {"ufo", "16"}, {"comet", "18"}},
211	"black_hole_crush":    {{"galaxy", "30"}, {"atom", "28"}, {"moai", "24"}, {"gem", "35"}, {"ring", "28"}, {"comet", "22"}},
212	"mythic_annihilation": {{"dragon", "8"}, {"unicorn", "10"}, {"jelly", "12"}, {"peacock", "12"}, {"galaxy", "35"}, {"moai", "30"}},
213	"singularity_fist":    {{"infinity", "6"}, {"lotus", "8"}, {"dragon", "10"}, {"unicorn", "12"}, {"jelly", "14"}, {"galaxy", "40"}},
214	// FORTUNE branch
215	"fortune":             {{"clover", "16"}, {"heart", "40"}},
216	"four_leaf":           {{"seedling", "60"}, {"leaves", "50"}},
217	"edge":                {{"pizza", "20"}, {"spark", "30"}},
218	"glint":               {{"spark", "50"}, {"star", "12"}},
219	"spark_chaser":        {{"fire", "45"}, {"tada", "25"}},
220	"razor_focus":         {{"coffee", "25"}, {"game", "25"}, {"hundred", "30"}},
221	"precision_cut":       {{"eyes", "40"}, {"skull", "35"}, {"flutter", "18"}},
222	"aurora_gaze":         {{"rainbow", "15"}, {"spark", "60"}, {"moon", "20"}},
223	"starlight_gleam":     {{"star", "25"}, {"clover", "20"}, {"heart", "80"}},
224	"double_haul":         {{"gear", "30"}, {"anchor", "20"}, {"up", "70"}},
225	"twin_strike":         {{"chains", "25"}, {"wrench", "25"}, {"pick", "20"}},
226	"executioner":         {{"skull", "60"}, {"sword", "18"}, {"crown", "10"}, {"orb", "8"}},
227	"celestial_sight":     {{"planet", "10"}, {"moon", "30"}, {"star", "30"}, {"bead", "8"}},
228	"helix_harmony":       {{"dna", "12"}, {"spark", "80"}, {"rainbow", "25"}, {"orb", "10"}},
229	"fortune_split":       {{"money-bag", "15"}, {"gold-medal", "12"}, {"clover", "35"}, {"chains", "40"}},
230	"critical_surge":      {{"gem", "15"}, {"disco", "14"}, {"ring", "12"}, {"orb", "20"}, {"planet", "18"}},
231	"astral_scintillation": {{"ring", "14"}, {"gem", "16"}, {"dna", "20"}, {"star", "60"}, {"moon", "50"}},
232	"plunder_frenzy":      {{"coin", "25"}, {"money-bag", "30"}, {"gem", "12"}, {"crown", "25"}, {"trophy", "25"}},
233	"singularity_edge":    {{"lotus", "6"}, {"dragon", "8"}, {"galaxy", "25"}, {"hamsa", "20"}, {"atom", "22"}, {"mirror", "20"}},
234	"cosmic_fortune":      {{"peacock", "10"}, {"unicorn", "8"}, {"comet", "25"}, {"disco", "30"}, {"galaxy", "30"}, {"gem", "35"}},
235	// POCKET branch
236	"dustbag":             {{"grin", "200"}, {"sleep", "40"}},
237	"rhythm":              {{"music", "16"}, {"clap", "30"}},
238	"pocket_expansion":    {{"fallen", "45"}, {"herb", "35"}},
239	"steady_tempo":        {{"party", "40"}, {"wow", "30"}},
240	"cadence":             {{"music", "30"}, {"coffee", "20"}, {"clap", "50"}},
241	"deep_pouch":          {{"log", "70"}, {"rock", "60"}, {"mushroom", "35"}},
242	"vein_resonator":      {{"flutter", "20"}, {"rainbow", "15"}, {"tada", "40"}},
243	"cart_bed":            {{"log", "120"}, {"rock", "100"}, {"brick", "80"}, {"money-bag", "10"}},
244	"bounty_overflow":     {{"trophy", "15"}, {"crown", "12"}, {"pick", "45"}, {"game", "35"}},
245	"fracture_pulse":      {{"bolt", "25"}, {"wand", "15"}, {"hammer", "50"}, {"rocket", "25"}},
246	"metro_pulse":         {{"music", "45"}, {"coffee", "35"}, {"raise", "30"}, {"bolt", "15"}},
247	"hoarders_tote":       {{"coin", "22"}, {"gem", "10"}, {"money-bag", "35"}, {"rock", "150"}, {"log", "150"}},
248	"shatter_strike":      {{"gem", "14"}, {"bolt", "35"}, {"wand", "25"}, {"sword", "30"}, {"hammer", "60"}},
249	"super_conductor":     {{"coin", "20"}, {"ring", "12"}, {"music", "60"}, {"bolt", "30"}, {"coffee", "50"}},
250	"dodo_instinct":       {{"dodo", "14"}, {"kite", "14"}, {"crown", "22"}, {"trophy", "22"}, {"eyes", "80"}},
251	"void_rend":           {{"infinity", "6"}, {"jelly", "12"}, {"dragon", "8"}, {"atom", "30"}, {"comet", "25"}, {"bolt", "60"}},
252	"celestial_duplication": {{"infinity", "5"}, {"lotus", "6"}, {"dragon", "8"}, {"peacock", "10"}, {"coin", "40"}, {"gem", "35"}},
253	"eternity_flow":       {{"infinity", "5"}, {"lotus", "6"}, {"peacock", "8"}, {"hamsa", "25"}, {"mirror", "25"}, {"music", "100"}},
254	"abyssal_reserve":     {{"unicorn", "6"}, {"jelly", "10"}, {"moai", "25"}, {"ufo", "25"}, {"money-bag", "50"}, {"rock", "300"}},
255	"singularity_snap":    {{"infinity", "8"}, {"lotus", "8"}, {"dragon", "10"}, {"galaxy", "40"}, {"moai", "30"}, {"bolt", "80"}},
256
257	// ── Phase 5: Nature branch (level 20) ────────────────────────────────────
258	"deep_root":       {{"bear", "60"}, {"fox", "40"}},
259	"stone_sense":     {{"turtle", "30"}, {"coral", "15"}},
260	"bloom_tide":      {{"sakura", "20"}, {"bee", "50"}, {"deciduous", "80"}},
261	"thorn_hide":      {{"boar", "40"}, {"snake", "30"}, {"scorpion", "20"}},
262	"old_growth":      {{"elephant", "25"}, {"gorilla", "20"}, {"whale-spout", "15"}},
263	"storm_surge":     {{"storm", "25"}, {"lightning-cloud", "20"}, {"tornado", "15"}},
264	"predator_sense":  {{"tiger", "20"}, {"lion", "20"}, {"wolf", "20"}, {"eagle", "15"}},
265	"world_tree":      {{"rex", "12"}, {"mammoth", "10"}, {"dragon-face", "8"}, {"shooting", "8"}},
266
267	// ── Phase 5: Food branch (level 30) ──────────────────────────────────────
268	"hot_meal":     {{"ramen", "50"}, {"stew", "40"}},
269	"sugar_rush":   {{"candy", "60"}, {"cupcake", "40"}, {"donut", "30"}},
270	"second_wind":  {{"burger", "50"}, {"bacon", "40"}, {"cheese", "30"}},
271	"caffeinated":  {{"boba", "40"}, {"tea", "30"}, {"sake", "25"}},
272	"feast_mode":   {{"sushi", "30"}, {"curry", "40"}, {"pasta", "40"}, {"paella", "25"}},
273	"night_shift":  {{"honey", "30"}, {"pie", "25"}, {"cake", "20"}},
274	"brew_mastery": {{"beer", "40"}, {"wine", "30"}, {"cocktail", "20"}, {"champagne", "15"}},
275	"mythic_feast": {{"tropical-drink", "20"}, {"cheers", "15"}, {"toast", "12"}, {"mate", "12"}},
276
277	// ── Phase 5: People branch (level 40) ────────────────────────────────────
278	"mentor":        {{"baby", "60"}, {"child", "50"}},
279	"crowd_favor":   {{"clap", "80"}, {"heart-hands", "60"}},
280	"team_spirit":   {{"shake", "40"}, {"pray", "30"}, {"hug-pair", "30"}},
281	"athlete_heart": {{"surf", "30"}, {"swim", "30"}, {"run", "40"}, {"lift", "25"}},
282	"warrior_code":  {{"ninja", "20"}, {"fencer", "15"}, {"juggle", "15"}},
283	"elder_wisdom":  {{"monarch", "15"}, {"mage", "15"}, {"fairy", "12"}},
284	"hero_legend":   {{"hero", "12"}, {"vampire", "10"}, {"merfolk", "10"}},
285	"genie_wish":    {{"genie", "8"}, {"heart-organ", "12"}},
286
287	// ── Phase 5: Things branch (level 50) ────────────────────────────────────
288	"tempered_grip":   {{"gloves", "80"}, {"hammer", "60"}},
289	"field_repair":    {{"hammer-wrench", "40"}, {"saw", "30"}, {"nut", "50"}},
290	"master_craft":    {{"wrench", "60"}, {"driver", "50"}, {"clamp", "30"}},
291	"workshop_lore":   {{"toolbox", "30"}, {"abacus", "25"}, {"scroll", "20"}},
292	"iron_discipline": {{"axe", "30"}, {"dagger", "20"}, {"bow", "15"}},
293	"vault_keeper":    {{"lock", "40"}, {"key-lock", "30"}, {"old-key", "15"}},
294	"precision_forge": {{"scope", "20"}, {"telescope", "15"}, {"tube", "18"}, {"dish", "15"}},
295	"deep_science":    {{"alembic", "12"}, {"shield", "15"}, {"hammer-pick", "15"}, {"scale", "12"}},
296
297	// ── Phase 5: Travel branch (level 65) ────────────────────────────────────
298	"long_haul":      {{"car", "80"}, {"bus", "60"}},
299	"vein_compass":   {{"plane", "50"}, {"sail", "30"}},
300	"nomad_pace":     {{"moto", "40"}, {"cycle", "50"}, {"scooter", "40"}},
301	"deep_sea":       {{"ship", "30"}, {"whale-spout", "15"}, {"dolphin", "25"}},
302	"sky_route":      {{"rocket", "30"}, {"heli", "20"}, {"depart", "20"}},
303	"monument_seal":  {{"tower", "20"}, {"castle", "15"}, {"liberty", "12"}},
304	"orbital_drift":  {{"sat", "15"}, {"castle-jp", "12"}},
305	"sacred_ground":  {{"kaaba", "8"}, {"shrine", "10"}, {"temple", "10"}, {"mosque", "10"}},
306
307	// ── Phase 5: Signs branch (level 80) ─────────────────────────────────────
308	"amplify":       {{"sparkle", "80"}, {"eight-star", "60"}},
309	"resonance":     {{"recycle", "60"}, {"medical", "50"}},
310	"sigil_power":   {{"worship", "40"}, {"peace-sign", "30"}},
311	"zodiac_edge":   {{"aries", "20"}, {"taurus", "20"}, {"gemini", "20"}, {"cancer", "15"}},
312	"star_david":    {{"star-david", "15"}, {"dharma", "15"}, {"cross", "15"}, {"menorah", "12"}},
313	"hazard_forge":  {{"radioactive", "12"}, {"biohazard", "12"}},
314	"cosmic_sigil":  {{"trident", "10"}, {"fleur", "10"}, {"ophiuchus", "8"}},
315	"infinite_mark": {{"om", "8"}, {"yin", "8"}, {"witness", "6"}},
316}
317
318// skillMaxRanks maps skillId → maximum rank allowed.
319// Most skills cap at 3 or 4 — see catalog.ts SKILLS[*].max.
320var skillMaxRanks = map[string]uint64{
321	// Strike branch
322	"wrist": 5, "palm_strike": 4, "follow": 3, "knuckle_wrap": 4, "heavy_swing": 4,
323	"stone_breaker": 4, "anvil_force": 4, "point_drive": 4, "kinetic_thrust": 4,
324	"crushing_blow": 4, "shatter_spike": 4, "ironclad_cleave": 3, "thunder_jab": 3,
325	"titan_hammer": 3, "diamond_cleave": 3, "hyper_drive": 3, "quasar_impact": 3,
326	"black_hole_crush": 3, "mythic_annihilation": 3, "singularity_fist": 3,
327	// Fortune branch
328	"fortune": 4, "four_leaf": 3, "edge": 3, "glint": 3, "spark_chaser": 3,
329	"razor_focus": 3, "precision_cut": 3, "aurora_gaze": 3, "starlight_gleam": 3,
330	"double_haul": 3, "twin_strike": 3, "executioner": 3, "celestial_sight": 3,
331	"helix_harmony": 3, "fortune_split": 3, "critical_surge": 3,
332	"astral_scintillation": 3, "plunder_frenzy": 3, "singularity_edge": 3, "cosmic_fortune": 3,
333	// Pocket branch
334	"dustbag": 3, "rhythm": 3, "pocket_expansion": 3, "steady_tempo": 3, "cadence": 3,
335	"deep_pouch": 3, "vein_resonator": 3, "cart_bed": 3, "bounty_overflow": 3,
336	"fracture_pulse": 3, "metro_pulse": 3, "hoarders_tote": 3, "shatter_strike": 3,
337	"super_conductor": 3, "dodo_instinct": 3, "void_rend": 3, "celestial_duplication": 3,
338	"eternity_flow": 3, "abyssal_reserve": 3, "singularity_snap": 3,
339	// Phase 5 — Nature branch (unlocks level 20)
340	"deep_root": 3, "stone_sense": 3, "bloom_tide": 3, "thorn_hide": 3,
341	"old_growth": 3, "storm_surge": 3, "predator_sense": 3, "world_tree": 3,
342	// Phase 5 — Food branch (unlocks level 30)
343	"hot_meal": 3, "sugar_rush": 3, "second_wind": 3, "caffeinated": 3,
344	"feast_mode": 3, "night_shift": 3, "brew_mastery": 3, "mythic_feast": 3,
345	// Phase 5 — People branch (unlocks level 40)
346	"mentor": 3, "crowd_favor": 3, "team_spirit": 3, "athlete_heart": 3,
347	"warrior_code": 3, "elder_wisdom": 3, "hero_legend": 3, "genie_wish": 3,
348	// Phase 5 — Things branch (unlocks level 50)
349	"tempered_grip": 3, "field_repair": 3, "master_craft": 3, "workshop_lore": 3,
350	"iron_discipline": 3, "vault_keeper": 3, "precision_forge": 3, "deep_science": 3,
351	// Phase 5 — Travel branch (unlocks level 65)
352	"long_haul": 3, "vein_compass": 3, "nomad_pace": 3, "deep_sea": 3,
353	"sky_route": 3, "monument_seal": 3, "orbital_drift": 3, "sacred_ground": 3,
354	// Phase 5 — Signs branch (unlocks level 80)
355	"amplify": 3, "resonance": 3, "sigil_power": 3, "zodiac_edge": 3,
356	"star_david": 3, "hazard_forge": 3, "cosmic_sigil": 3, "infinite_mark": 3,
357}
358
359// toolMaxLife maps toolId → maximum durability in blocks broken.
360// 0 = indestructible (hands, starter-twig, twig). Matches catalog.ts tool.life.
361var toolMaxLife = map[string]uint64{
362	"hands": 0, "starter-twig": 0, "twig": 0,
363	"wood": 300, "stone": 900, "iron": 940, "gold": 4900, "diamond": 5300, "cosmic": 4500,
364	"plasma": 15000, "neutron": 15000, "quasar": 23000, "void": 30000, "genesis": 36000, "omega": 54000,
365}
366
367// ── Coin allowlist and rarity lookup ─────────────────────────────────────────
368// coinRarity maps every valid coin id → its rarity (0=dust .. 6=mythic).
369// ClaimMine and ClaimAndMint panic on any id not present here.
370// Generated from src/lib/game/catalog.ts COINS (1262 entries).
371// Populated across two init() functions in game_data_coins.gno and game_data_coins2.gno
372// to keep each file under the 594-line Onyx parser limit.
373
374var coinRarity map[string]int