code wiki / (root) / nx_decl_dungeon_floor.nx

nx_decl_dungeon_floor.nx source

↩ module page · 172 lines · 6785 B

1// nx_decl_dungeon_floor.nx -- fourth declarative #tag-style primitive. 2// 3// license_tier: ORIGINAL 4// 5// Composes an indoor dungeon-floor layout from one substrate call. 6// Distinct from outdoor declarators: dungeons are bounded grid-like 7// structures with rooms + corridors + treasures + traps, no biome, 8// no sky. Equivalent of `#dungeon_floor <modifier>`. 9// 10// Per S-class roadmap §A3 -- fourth slice, validates the #tag 11// pattern scales to non-environment scenes. 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" 23const NX_MAGIC_1024: i64 = 1024 24 25// ---- Sealed enum: dungeon mood ----------------------------------- 26const NX_DUNGEON_MOOD_CRYPT: nx_int = 0 // dark, undead-themed 27const NX_DUNGEON_MOOD_RUIN: nx_int = 1 // collapsed, overgrown 28const NX_DUNGEON_MOOD_FORGE: nx_int = 2 // industrial, hot 29const NX_DUNGEON_MOOD_LIBRARY: nx_int = 3 // quiet, archive 30const NX_DUNGEON_MOOD_GARDEN: nx_int = 4 // verdant, fey-themed 31const NX_DUNGEON_MOOD_REACTOR: nx_int = 5 // sci-fi power core 32const NX_DUNGEON_MOOD_LAB: nx_int = 6 // sci-fi research wing 33const NX_DUNGEON_MOOD_N: nx_int = 7 34 35func nx_dungeon_mood_is_valid(m: nx_int) -> nx_int { 36 if m < 0 { return 0 } 37 if m >= NX_DUNGEON_MOOD_N { return 0 } 38 return 1 39} 40 41func nx_dungeon_mood_name(m: nx_int) -> *u8 { 42 if m == NX_DUNGEON_MOOD_CRYPT { return "CRYPT" as *u8 } 43 if m == NX_DUNGEON_MOOD_RUIN { return "RUIN" as *u8 } 44 if m == NX_DUNGEON_MOOD_FORGE { return "FORGE" as *u8 } 45 if m == NX_DUNGEON_MOOD_LIBRARY { return "LIBRARY" as *u8 } 46 if m == NX_DUNGEON_MOOD_GARDEN { return "GARDEN" as *u8 } 47 if m == NX_DUNGEON_MOOD_REACTOR { return "REACTOR" as *u8 } 48 if m == NX_DUNGEON_MOOD_LAB { return "LAB" as *u8 } 49 return "<invalid mood>" as *u8 50} 51 52// ---- Output struct ----------------------------------------------- 53struct NxDungeonFloor { 54 seed: nx_int, 55 modifier: nx_int, 56 mood: nx_int, // sealed enum NX_DUNGEON_MOOD_* 57 grid_width: nx_int, // tiles 58 grid_height: nx_int, // tiles 59 room_count: nx_int, 60 corridor_count: nx_int, 61 treasure_count: nx_int, 62 trap_count: nx_int, 63 boss_present: nx_int, // 0 / 1 64 light_level_q10: nx_int, // ambient light, 0..NX_MAGIC_1024 65 is_valid: nx_int, 66} 67 68// ---- Mood selection per modifier --------------------------------- 69// REAL: roll CRYPT/RUIN/FORGE/LIBRARY/GARDEN (fantasy-genre dungeons). 70// FANTASY: same plus more variety from seed. 71// SCI_FI: REACTOR or LAB only. 72func _df_default_mood(modifier: nx_int, seed: nx_int) -> nx_int { 73 if modifier == NX_RE_MODIFIER_SCI_FI { 74 let r: nx_int = _re_hash_mod(seed, 17, 2) 75 if r == 0 { return NX_DUNGEON_MOOD_REACTOR } 76 return NX_DUNGEON_MOOD_LAB 77 } 78 let r: nx_int = _re_hash_mod(seed, 17, 5) 79 if r == 0 { return NX_DUNGEON_MOOD_CRYPT } 80 if r == 1 { return NX_DUNGEON_MOOD_RUIN } 81 if r == 2 { return NX_DUNGEON_MOOD_FORGE } 82 if r == 3 { return NX_DUNGEON_MOOD_LIBRARY } 83 return NX_DUNGEON_MOOD_GARDEN 84} 85 86// ---- Grid size per modifier -------------------------------------- 87func _df_default_grid_width(modifier: nx_int) -> nx_int { 88 if modifier == NX_RE_MODIFIER_FANTASY { return 48 } 89 if modifier == NX_RE_MODIFIER_SCI_FI { return 32 } 90 return 24 91} 92 93func _df_default_grid_height(modifier: nx_int) -> nx_int { 94 if modifier == NX_RE_MODIFIER_FANTASY { return 48 } 95 if modifier == NX_RE_MODIFIER_SCI_FI { return 32 } 96 return 24 97} 98 99// ---- Feature counts per modifier --------------------------------- 100func _df_default_room_count(modifier: nx_int, seed: nx_int) -> nx_int { 101 let base: nx_int = _re_hash_mod(seed, 21, 3) // 0..2 102 if modifier == NX_RE_MODIFIER_FANTASY { return base + 8 } 103 if modifier == NX_RE_MODIFIER_SCI_FI { return base + 5 } 104 return base + 4 105} 106 107func _df_default_corridor_count(modifier: nx_int, rooms: nx_int) -> nx_int { 108 // Roughly one fewer corridor than rooms (forms a spanning graph). 109 if rooms <= 1 { return 0 } 110 return rooms - 1 111} 112 113func _df_default_treasure_count(modifier: nx_int, rooms: nx_int) -> nx_int { 114 // ~25% of rooms get treasure (rounded), with modifier bonus. 115 var t: nx_int = rooms / 4 116 if modifier == NX_RE_MODIFIER_FANTASY { t = t + 2 } 117 if t < 1 { t = 1 } 118 return t 119} 120 121func _df_default_trap_count(modifier: nx_int, rooms: nx_int, mood: nx_int) -> nx_int { 122 // GARDEN has fewer traps; CRYPT has more. 123 var t: nx_int = rooms / 3 124 if mood == NX_DUNGEON_MOOD_GARDEN { t = t / 2 } 125 if mood == NX_DUNGEON_MOOD_CRYPT { t = t + 1 } 126 if mood == NX_DUNGEON_MOOD_REACTOR { t = t + 1 } 127 if t < 0 { t = 0 } 128 return t 129} 130 131func _df_default_light_q10(mood: nx_int) -> nx_int { 132 if mood == NX_DUNGEON_MOOD_CRYPT { return 102 } // dim 133 if mood == NX_DUNGEON_MOOD_RUIN { return 256 } 134 if mood == NX_DUNGEON_MOOD_FORGE { return 768 } // bright forge 135 if mood == NX_DUNGEON_MOOD_LIBRARY { return 384 } 136 if mood == NX_DUNGEON_MOOD_GARDEN { return 640 } 137 if mood == NX_DUNGEON_MOOD_REACTOR { return 896 } // very bright 138 if mood == NX_DUNGEON_MOOD_LAB { return 512 } 139 return 512 140} 141 142// ---- Main declarator --------------------------------------------- 143func nx_decl_dungeon_floor(out: *NxDungeonFloor, modifier: nx_int, seed: nx_int) -> nx_int { 144 if nx_re_modifier_is_valid(modifier) == 0 { 145 out.is_valid = 0 146 return 0 147 } 148 out.seed = seed 149 out.modifier = modifier 150 out.mood = _df_default_mood(modifier, seed) 151 out.grid_width = _df_default_grid_width(modifier) 152 out.grid_height = _df_default_grid_height(modifier) 153 out.room_count = _df_default_room_count(modifier, seed) 154 out.corridor_count = _df_default_corridor_count(modifier, out.room_count) 155 out.treasure_count = _df_default_treasure_count(modifier, out.room_count) 156 out.trap_count = _df_default_trap_count(modifier, out.room_count, out.mood) 157 out.light_level_q10 = _df_default_light_q10(out.mood) 158 // Boss present iff seed rolls a 1-in-3 AND >= 5 rooms. 159 let roll: nx_int = _re_hash_mod(seed, 29, 3) 160 var boss: nx_int = 0 161 if roll == 0 { boss = 1 } 162 if out.room_count < 5 { boss = 0 } 163 out.boss_present = boss 164 out.is_valid = 1 165 return 1 166} 167 168func nx_df_alloc() -> *NxDungeonFloor { 169 let raw: *u8 = sys_mmap(128) 170 let d: *NxDungeonFloor = raw as *NxDungeonFloor 171 return d 172}