code wiki / _hdl_build / nx_game_companion.nx

nx_game_companion.nx source

↩ module page · 137 lines · 5319 B

1// nx_game_companion.nx -- the OWNERSHIP core of the beat-Veloren companion-collector. The research (SDT + 2// operator's pillars, gamebench round 14) says Veloren wins on AUTONOMY but has no OWNERSHIP; the 3// endowment effect (Pokemon) is the pillar we can build because our certified parts already hold its 4// substrate. This part composes them into a companion whose OWNERSHIP is STRUCTURALLY REAL and MEASURABLE: 5// - UNIQUE by construction (a per-companion rolled trait vector; no two alike -- the IV/nature equiv), 6// - PERSISTENT (rides nx_gamesave bit-exact -- what you own does not evaporate), 7// - INVESTMENT-DIVERGENT (nx_rpgstats: what you pour XP into grows distinct -- the IKEA effect), 8// - individually addressed (nx_entity_store handle=index+generation; a companion is a THING, not a row). 9// ⚠HONEST SCOPE: these are the measurable PREREQUISITES for the endowment effect, NOT the psychological 10// bond itself (unmeasurable). A game can have all three and still feel hollow; but a game LACKING them 11// cannot produce ownership at all -- so they are necessary, gate-able, and red-teamable. 12// LIB, no main. license_tier: ORIGINAL 13import "nx_syscalls.nx" 14import "nx_entity_store.nx" 15import "nx_rpgstats.nx" 16import "nx_gamesave.nx" 17const COMP_MAGIC_2654435761: i64 = 2654435761 18const COMP_MAGIC_40503: i64 = 40503 19 20const COMP_NC: i64 = 8 // components 21const C_SPEC: i64 = 0 22const C_IV0: i64 = 1 23const C_IV1: i64 = 2 24const C_IV2: i64 = 3 25const C_IV3: i64 = 4 26const C_XP: i64 = 5 27const C_LVL: i64 = 6 28const C_NICK: i64 = 7 29const COMP_NSPEC: i64 = 6 30const COMP_XB: i64 = 20 31const COMP_XQ: i64 = 10 32const COMP_HPB: i64 = 10 33const COMP_HPC: i64 = 2 34const COMP_HPL: i64 = 4 35 36func comp_rng(s: i64) -> i64 { 37 var x: i64 = s 38 x = x ^ (x << 13); x = x ^ (x >> 7); x = x ^ (x << 17) 39 if x < 0 { return 0 - x } 40 return x 41} 42 43// roll a roster of n UNIQUE companions from a world seed. `variety`=1 gives per-companion distinct seeds 44// (real collection); `variety`=0 is the SOULLESS control -- every companion rolled from the SAME seed 45// (generic mass-produced loot), which the uniqueness gate MUST reject. 46func comp_new_roster(ros: *i64, cap: i64, n: i64, seed: i64, variety: i64) -> i64 { 47 en_init(ros, cap, COMP_NC) 48 var i: i64 = 0 49 while i < n { 50 let h: i64 = en_spawn(ros) 51 if h != EN_NULL { 52 var per: i64 = seed 53 if variety == 1 { per = seed*COMP_MAGIC_2654435761 + i*COMP_MAGIC_40503 + 1 } 54 var x: i64 = comp_rng(per) 55 en_set(ros, h, C_SPEC, x % COMP_NSPEC) 56 x = comp_rng(x); en_set(ros, h, C_IV0, x % 32) 57 x = comp_rng(x); en_set(ros, h, C_IV1, x % 32) 58 x = comp_rng(x); en_set(ros, h, C_IV2, x % 32) 59 x = comp_rng(x); en_set(ros, h, C_IV3, x % 32) 60 en_set(ros, h, C_XP, 0) 61 en_set(ros, h, C_LVL, 1) 62 en_set(ros, h, C_NICK, i) 63 } 64 i = i + 1 65 } 66 return 0 67} 68 69// the identity vector = species + 4 IVs packed; two companions are "the same creature" iff equal. 70func comp_vec(ros: *i64, h: i64) -> i64 { 71 let sp: i64 = en_get(ros, h, C_SPEC) 72 let a: i64 = en_get(ros, h, C_IV0) 73 let b: i64 = en_get(ros, h, C_IV1) 74 let c: i64 = en_get(ros, h, C_IV2) 75 let d: i64 = en_get(ros, h, C_IV3) 76 return ((((sp*32 + a)*32 + b)*32 + c)*32 + d) 77} 78// count duplicate identity vectors in the roster (0 = every companion is unique) 79func comp_dup_count(ros: *i64) -> i64 { 80 let n: i64 = en_count(ros) 81 var dups: i64 = 0 82 var i: i64 = 0 83 while i < n { 84 let hi: i64 = en_nth(ros, i) 85 let vi: i64 = comp_vec(ros, hi) 86 var j: i64 = i + 1 87 while j < n { 88 let hj: i64 = en_nth(ros, j) 89 if comp_vec(ros, hj) == vi { dups = dups + 1 } 90 j = j + 1 91 } 92 i = i + 1 93 } 94 return dups 95} 96 97// INVEST: pour XP into a companion -> it levels (rpgstats) -> its power grows. What you invest in 98// becomes distinctly yours (the IKEA effect). 99func comp_invest(ros: *i64, h: i64, xp: i64) -> i64 { 100 let nx: i64 = en_get(ros, h, C_XP) + xp 101 en_set(ros, h, C_XP, nx) 102 en_set(ros, h, C_LVL, rs_level_for_xp(nx, COMP_XB, COMP_XQ)) 103 return 0 104} 105// derived power: IV-sum acts as the "con" stat, scaled by invested level (rpgstats derived HP curve). 106func comp_power(ros: *i64, h: i64) -> i64 { 107 let con: i64 = 8 + en_get(ros, h, C_IV0) + en_get(ros, h, C_IV3) 108 return rs_derived_hp(con, en_get(ros, h, C_LVL), COMP_HPB, COMP_HPC, COMP_HPL) 109} 110 111// flatten the roster to a state vector for nx_gamesave (species..nick per companion, dense order) 112func comp_serialize(ros: *i64, S: *i64) -> i64 { 113 let n: i64 = en_count(ros) 114 S[0] = n 115 var i: i64 = 0 116 while i < n { 117 let h: i64 = en_nth(ros, i) 118 let b: i64 = 1 + i*COMP_NC 119 var k: i64 = 0 120 while k < COMP_NC { S[b+k] = en_get(ros, h, k); k = k + 1 } 121 i = i + 1 122 } 123 return 1 + n*COMP_NC 124} 125func comp_restore(ros: *i64, cap: i64, S: *i64) -> i64 { 126 en_init(ros, cap, COMP_NC) 127 let n: i64 = S[0] 128 var i: i64 = 0 129 while i < n { 130 let h: i64 = en_spawn(ros) 131 let b: i64 = 1 + i*COMP_NC 132 var k: i64 = 0 133 while k < COMP_NC { en_set(ros, h, k, S[b+k]); k = k + 1 } 134 i = i + 1 135 } 136 return 0 137}