code wiki / (root) / nx_decl_combat_arena.nx

nx_decl_combat_arena.nx source

↩ module page · 127 lines · 4791 B

1// nx_decl_combat_arena.nx -- third declarative #tag-style primitive. 2// 3// license_tier: ORIGINAL 4// 5// Composes a bounded combat arena from one substrate call. 6// Equivalent of TypeScript `#combat_arena <modifier>` directive. 7// Differs from nx_decl_simple_scene in that the environment is 8// BOUNDED (smaller, square, deterministic spawns) for gameplay, 9// not for landscape rendering. 10// 11// Per S-class roadmap §A3 -- third slice toward the user's vision. 12 13// nx_safety_envelope: 14// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 15// sil_target: SIL1 16// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 17// verdict: NOT_YET_EVALUATED 18 19import "nx_syscalls.nx" 20import "nx_types.nx" 21import "nx_tier.nx" 22import "nx_decl_random_environment.nx" 23import "nx_decl_simple_scene.nx" 24 25// ---- Sealed enum: arena shape ------------------------------------- 26const NX_ARENA_SHAPE_SQUARE: nx_int = 0 27const NX_ARENA_SHAPE_CIRCLE: nx_int = 1 28const NX_ARENA_SHAPE_OCTAGON: nx_int = 2 29const NX_ARENA_SHAPE_HEXAGON: nx_int = 3 30const NX_ARENA_SHAPE_N: nx_int = 4 31 32func nx_arena_shape_is_valid(s: nx_int) -> nx_int { 33 if s < 0 { return 0 } 34 if s >= NX_ARENA_SHAPE_N { return 0 } 35 return 1 36} 37 38// Elm-style reflection: shape -> human name. 39func nx_arena_shape_name(s: nx_int) -> *u8 { 40 if s == NX_ARENA_SHAPE_SQUARE { return "SQUARE" as *u8 } 41 if s == NX_ARENA_SHAPE_CIRCLE { return "CIRCLE" as *u8 } 42 if s == NX_ARENA_SHAPE_OCTAGON { return "OCTAGON" as *u8 } 43 if s == NX_ARENA_SHAPE_HEXAGON { return "HEXAGON" as *u8 } 44 return "<invalid shape>" as *u8 45} 46 47// ---- Output struct ----------------------------------------------- 48struct NxCombatArena { 49 seed: nx_int, 50 modifier: nx_int, 51 // Scene context. 52 scene: *NxSimpleScene, 53 // Arena geometry. 54 shape: nx_int, // sealed enum NX_ARENA_SHAPE_* 55 radius_m: nx_int, // bounding radius 56 obstacle_count: nx_int, // procgen obstacles inside the bound 57 // Spawn points. Spawn locations are deterministic from seed; 58 // caller computes positions via spawn_point_xz(seed, i). 59 spawn_count_per_team: nx_int, // typical: 1, 2, or 4 60 team_count: nx_int, // typical: 2 61 is_valid: nx_int, 62} 63 64// ---- Shape defaults per modifier --------------------------------- 65// REAL: square (predictable for melee). FANTASY: octagon (more 66// variety). SCI_FI: circle (clean futuristic look). 67func _arena_default_shape(modifier: nx_int) -> nx_int { 68 if modifier == NX_RE_MODIFIER_FANTASY { return NX_ARENA_SHAPE_OCTAGON } 69 if modifier == NX_RE_MODIFIER_SCI_FI { return NX_ARENA_SHAPE_CIRCLE } 70 return NX_ARENA_SHAPE_SQUARE 71} 72 73func _arena_default_radius(modifier: nx_int) -> nx_int { 74 if modifier == NX_RE_MODIFIER_FANTASY { return 32 } // 32m (medium arena) 75 if modifier == NX_RE_MODIFIER_SCI_FI { return 48 } // 48m (large) 76 return 24 // 24m (compact melee) 77} 78 79func _arena_default_obstacles(modifier: nx_int, seed: nx_int) -> nx_int { 80 // Roll 0..6 obstacles deterministically. 81 let base: nx_int = _re_hash_mod(seed, 11, 7) 82 if modifier == NX_RE_MODIFIER_FANTASY { return base + 2 } 83 if modifier == NX_RE_MODIFIER_SCI_FI { return base + 1 } 84 return base 85} 86 87func _arena_default_spawn_per_team(modifier: nx_int) -> nx_int { 88 if modifier == NX_RE_MODIFIER_FANTASY { return 4 } // 4v4 89 if modifier == NX_RE_MODIFIER_SCI_FI { return 2 } // 2v2 90 return 1 // 1v1 91} 92 93// ---- Main declarator --------------------------------------------- 94func nx_decl_combat_arena(out: *NxCombatArena, modifier: nx_int, seed: nx_int) -> nx_int { 95 if nx_re_modifier_is_valid(modifier) == 0 { 96 out.is_valid = 0 97 return 0 98 } 99 out.seed = seed 100 out.modifier = modifier 101 102 // Compose: a simple_scene with the combat modifier. Note the 103 // scene picks the light kind; we don't override it here but 104 // could (combat usually wants noon/overcast for visibility). 105 let scene: *NxSimpleScene = nx_ss_alloc() 106 nx_decl_simple_scene(scene, modifier, seed) 107 if scene.is_valid == 0 { 108 out.is_valid = 0 109 return 0 110 } 111 out.scene = scene 112 113 out.shape = _arena_default_shape(modifier) 114 out.radius_m = _arena_default_radius(modifier) 115 out.obstacle_count = _arena_default_obstacles(modifier, seed) 116 out.spawn_count_per_team = _arena_default_spawn_per_team(modifier) 117 out.team_count = 2 118 119 out.is_valid = 1 120 return 1 121} 122 123func nx_arena_alloc() -> *NxCombatArena { 124 let raw: *u8 = sys_mmap(256) 125 let a: *NxCombatArena = raw as *NxCombatArena 126 return a 127}