diff --git a/packages/ludic.gameplay/combat.ludic b/packages/ludic.gameplay/combat.ludic index 042f8abb..eefa7b30 100644 --- a/packages/ludic.gameplay/combat.ludic +++ b/packages/ludic.gameplay/combat.ludic @@ -23,10 +23,14 @@ event Died { e: int = 0, src: int = 0 } event Healed { e: int = 0, amount: int = 0 } event Crit { target: int = 0, src: int = 0 } # the attacker's crit_pct fired +# the faction table: FAC_MAX ids square, every pair unset (faction.ludic) +const FAC_MAX: int = 32 +function fac_table() -> words { return words(FAC_MAX * FAC_MAX) } + state GameplayState { combat_reflecting: bool = false # thorns never reflect thorns combat_pending: int = 0 - fac_tbl: words = words(FAC_MAX * FAC_MAX) + fac_tbl: words = fac_table() } # the mutable channel for lever 6: listeners rewrite the pending damage here. diff --git a/packages/ludic.gameplay/faction.ludic b/packages/ludic.gameplay/faction.ludic index 0bada609..d72169de 100644 --- a/packages/ludic.gameplay/faction.ludic +++ b/packages/ludic.gameplay/faction.ludic @@ -9,20 +9,14 @@ property Faction { id: int = 0 } -const FAC_MAX: int = 32 const REL_FRIEND: int = 0 const REL_NEUTRAL: int = 1 const REL_HOSTILE: int = 2 -# relationships stored as (rel + 1); a zero slot means "unset -> use the default". -# A global var initialiser must be a literal, so it is allocated lazily. - -function fac_ensure(gameplay_st: mut GameplayState) -> void { -} +# relationships stored as (rel + 1); a zero slot means "unset -> use the default" # Faction.set(a, b, rel) — record a symmetric relationship between two factions. @Namespace(Faction) function faction_set(gameplay_st: mut GameplayState, a: int, b: int, rel: int) -> void { - fac_ensure(gameplay_st) if (a < 0) or (a >= FAC_MAX) { return } if (b < 0) or (b >= FAC_MAX) { return } gameplay_st.fac_tbl[a * FAC_MAX + b] = rel + 1 @@ -31,7 +25,6 @@ function fac_ensure(gameplay_st: mut GameplayState) -> void { # Faction.rel(a, b) — the relationship code (0 friend, 1 neutral, 2 hostile). @Namespace(Faction) function faction_rel(gameplay_st: mut GameplayState, a: int, b: int) -> int { - fac_ensure(gameplay_st) if (a >= 0) and (a < FAC_MAX) and (b >= 0) and (b < FAC_MAX) { let v = gameplay_st.fac_tbl[a * FAC_MAX + b] if v != 0 { return v - 1 } diff --git a/packages/ludic.hints/rail.ludic b/packages/ludic.hints/rail.ludic index 5dcdf044..bc59a176 100644 --- a/packages/ludic.hints/rail.ludic +++ b/packages/ludic.hints/rail.ludic @@ -5,7 +5,7 @@ export state HintsState { hn_foreign: []string = new []string # muted keys with no card in this build, written back as read hn_shown: int = 3 # how many the rail holds hn_every: float = 1.0 # seconds between passes - hn_top: []int = null # the cards on the rail this pass + hn_top: []int = hn_slots(3) # the cards on the rail this pass hn_n: int = 0 hn_t: float = 0.0 # seconds to the next pass hn_pick: int = 0 # which chip the key would open @@ -28,21 +28,19 @@ function hn_fact(hints_st: HintsState, what: int, card: int) -> void { export function hints_config(hints_st: mut HintsState, shown: int, every: float) -> void { hints_st.hn_shown = shown hints_st.hn_every = every - hints_st.hn_top = null + hints_st.hn_top = hn_slots(shown) } - -function hn_ensure(hints_st: mut HintsState) -> void { - if hints_st.hn_top == null or len(hints_st.hn_top) != hints_st.hn_shown { - hints_st.hn_top = new []int - for i in 0 .. hints_st.hn_shown { push(hints_st.hn_top, -1) } - } +# a rail of n empty places +function hn_slots(n: int) -> []int { + let out = new []int + for i in 0 .. n { push(out, -1) } + return out } # the next pass comes on the next tick rather than in a second export function hints_refresh(hints_st: mut HintsState) -> void { hints_st.hn_t = 0.0 } export function hints_tick(hints_st: mut HintsState, dt: float) -> void { - hn_ensure(hints_st) hints_st.hn_t = hints_st.hn_t - dt if hints_st.hn_t > 0.0 { return } hints_st.hn_t = hints_st.hn_every @@ -52,7 +50,6 @@ export function hints_tick(hints_st: mut HintsState, dt: float) -> void { # one pass now: the rail re-sorted, the pick kept in range, and the card following its subject # along the rail - or put down when what it was about stopped being true export function hints_sort(hints_st: mut HintsState) -> void { - hn_ensure(hints_st) hints_st.hn_n = 0 let on = HintsWorld.showing() for u in 0 .. 4 { @@ -75,8 +72,7 @@ export function hints_sort(hints_st: mut HintsState) -> void { } # the cards on the rail, most urgent first (empty while the rail is not showing) -export function hints_rail(hints_st: mut HintsState) -> []int { - hn_ensure(hints_st) +export function hints_rail(hints_st: HintsState) -> []int { let out = new []int if not HintsWorld.showing() { return out } for k in 0 .. hints_st.hn_n { push(out, hints_st.hn_top[k]) } @@ -95,7 +91,7 @@ export function hints_pick(hints_st: HintsState) -> int { return hints_st.hn_pic export function hints_hot(hints_st: HintsState, k: int) -> bool { return k == hints_st.hn_pick } export function hints_reset(hints_st: mut HintsState) -> void { - hints_st.hn_top = null + hints_st.hn_top = hn_slots(hints_st.hn_shown) hints_st.hn_n = 0 hints_st.hn_t = 0.0 hints_st.hn_pick = 0 diff --git a/packages/ludic.lab/png.ludic b/packages/ludic.lab/png.ludic index bd5ed1f6..edd6b7e5 100644 --- a/packages/ludic.lab/png.ludic +++ b/packages/ludic.lab/png.ludic @@ -2,21 +2,21 @@ # compressed (a PNG anything opens, with no zlib here): the shot is the PPM's pixels, filter 0 # on every row, in deflate's stored blocks, with its CRCs and its Adler-32. -function lp_table_init(lab_st: mut LabState) -> void { - if lab_st.lp_table != null { return } - lab_st.lp_table = new []long +# the CRC-32 table, made once with the state +function lp_crc_table() -> []long { + let t = new []long let poly: long = 3988292384 # 0xEDB88320: eight hex digits would be a 32-bit pattern for n in 0 .. 256 { var c = long(n) for k in 0 .. 8 { if (c & long(1)) != long(0) { c = (c >> long(1)) ^ poly } else { c = c >> long(1) } } - push(lab_st.lp_table, c) + push(t, c) } + return t } # CRC-32 of out[from .. from + n) function lp_crc(lab_st: mut LabState, out: []byte, from: int, n: int) -> long { - lp_table_init(lab_st) let mask: long = 4294967295 var c = mask for i in from .. from + n { diff --git a/packages/ludic.lab/state.ludic b/packages/ludic.lab/state.ludic index affac690..be22a12f 100644 --- a/packages/ludic.lab/state.ludic +++ b/packages/ludic.lab/state.ludic @@ -2,7 +2,7 @@ export state LabState { lb_plate: Actor = null lb_plate_dir: string = "" - lp_table: []long = null + lp_table: []long = lp_crc_table() lp_w: int = 0 lp_h: int = 0 lb_scene: string = "" diff --git a/packages/ludic.npc/census.ludic b/packages/ludic.npc/census.ludic index 375c4a91..5b48a5b6 100644 --- a/packages/ludic.npc/census.ludic +++ b/packages/ludic.npc/census.ludic @@ -1,7 +1,6 @@ # census.ludic - making one (a slot reused before a new one, a look, a name, a start on its own # ground out of the players' sight where that can be had), a post's fixed person, and leaving export function npc_spawn(npc_st: mut NpcState, kind: int) -> NpcPerson { - np_ensure() if npc_st.np_n >= npc_st.np_max or kind < 0 or kind >= NPCK_COUNT { return null } var p: NpcPerson = null for i in 0 .. len(npc_st.np_walkers) { @@ -94,7 +93,6 @@ export function npc_set_at(p: NpcPerson, x: float, z: float) -> void { # somebody fixed at a post (a vendor behind the counter): never walks, never counted, never leaves, # turns to a player within its kind's notice and back to `yaw` when they go export function npc_place(npc_st: mut NpcState, kind: int, x: float, z: float, yaw: float, name: string, look: int) -> NpcPerson { - np_ensure() let p = new NpcPerson p.slot = len(npc_st.np_posts) np_fresh(p, kind, look) diff --git a/packages/ludic.npc/mirror.ludic b/packages/ludic.npc/mirror.ludic index ac22a921..a2026cf7 100644 --- a/packages/ludic.npc/mirror.ludic +++ b/packages/ludic.npc/mirror.ludic @@ -3,7 +3,6 @@ # on: this machine's own walkers leave, and only the host's are drawn until it is turned off export function npc_mirror(npc_st: mut NpcState, on: bool) -> void { - np_ensure() if npc_st.np_mirror == on { return } npc_st.np_mirror = on for i in 0 .. len(npc_st.np_walkers) { npc_retire(npc_st, npc_st.np_walkers[i]) } @@ -14,7 +13,6 @@ export function npc_mirroring(npc_st: NpcState) -> bool { return npc_st.np_mirro # the host's slot: somebody new in it (born), or nobody (gone) export function npc_put(npc_st: mut NpcState, slot: int, id: int, kind: int, look: int, seed: float, name: string, hx: float, hz: float) -> NpcPerson { - np_ensure() if slot < 0 or slot >= npc_st.np_max or kind < 0 or kind >= NPCK_COUNT { return null } while len(npc_st.np_walkers) <= slot { let q = new NpcPerson @@ -60,7 +58,6 @@ export function npc_heard(npc_st: NpcState, slot: int, x: float, y: float, z: fl export function npc_heard_lately(npc_st: NpcState, p: NpcPerson) -> bool { return p.heard and npc_st.np_clock - p.heard_t <= 6.0 } export function npc_mirror_tick(npc_st: mut NpcState, dt: float) -> void { - np_ensure() npc_st.np_clock = npc_st.np_clock + dt let k = Math.min(1.0, dt * 8.0) for i in 0 .. len(npc_st.np_walkers) { diff --git a/packages/ludic.npc/person.ludic b/packages/ludic.npc/person.ludic index 093135d9..02dc1754 100644 --- a/packages/ludic.npc/person.ludic +++ b/packages/ludic.npc/person.ludic @@ -39,37 +39,30 @@ function np_fact(npc_st: NpcState, what: int, p: NpcPerson, player: int) -> NpcF return f } -function np_ensure() -> void { -} # how many walkers the place can hold at once export function npc_config(npc_st: mut NpcState, max: int) -> void { npc_st.np_max = max } export function npc_seed(npc_st: NpcState, n: int) -> void { - np_ensure() rng_seed(npc_st.np_dice, n) } # 0 .. 1, and whole seconds lo .. hi, off the package's dice export function npc_rnd(npc_st: NpcState) -> float { - np_ensure() return rng_float(npc_st.np_dice) } export function npc_between(npc_st: NpcState, lo: int, hi: int) -> int { - np_ensure() return rng_between(npc_st.np_dice, lo, hi) } export function npc_secs(npc_st: NpcState, lo: int, hi: int) -> float { return float(npc_between(npc_st, lo, np_hi(lo, hi))) } export function npc_walkers(npc_st: NpcState) -> []NpcPerson { - np_ensure() return npc_st.np_walkers } export function npc_posts(npc_st: NpcState) -> []NpcPerson { - np_ensure() return npc_st.np_posts } @@ -79,19 +72,16 @@ export function npc_max(npc_st: NpcState) -> int { return npc_st.np_max } # a walker's slot or a post, and anyone by id export function npc_at(npc_st: NpcState, slot: int) -> NpcPerson { - np_ensure() if slot < 0 or slot >= len(npc_st.np_walkers) { return null } return npc_st.np_walkers[slot] } export function npc_post(npc_st: NpcState, i: int) -> NpcPerson { - np_ensure() if i < 0 or i >= len(npc_st.np_posts) { return null } return npc_st.np_posts[i] } export function npc_by_id(npc_st: NpcState, id: int) -> NpcPerson { - np_ensure() for i in 0 .. len(npc_st.np_walkers) { if npc_st.np_walkers[i].active and npc_st.np_walkers[i].id == id { return npc_st.np_walkers[i] } } for i in 0 .. len(npc_st.np_posts) { if npc_st.np_posts[i].active and npc_st.np_posts[i].id == id { return npc_st.np_posts[i] } } return null diff --git a/packages/ludic.npc/tick.ludic b/packages/ludic.npc/tick.ludic index 4c0a09cd..72619bbe 100644 --- a/packages/ludic.npc/tick.ludic +++ b/packages/ludic.npc/tick.ludic @@ -1,7 +1,6 @@ # tick.ludic - a step of everyone, on the machine that runs the place: the census on the half hour, # the day's end (only ever out of every player's sight), the walk or the act, and who noticed whom export function npc_tick(npc_st: mut NpcState, dt: float) -> void { - np_ensure() for i in 0 .. len(npc_st.np_posts) { if npc_st.np_posts[i].active { np_step_post(npc_st, npc_st.np_posts[i], dt) } } if npc_st.np_hold or npc_st.np_mirror { return } np_census(npc_st) @@ -15,7 +14,6 @@ export function npc_tick(npc_st: mut NpcState, dt: float) -> void { # the posts alone: a machine that does not run the place still turns its vendors to whoever comes export function npc_posts_tick(npc_st: mut NpcState, dt: float) -> void { - np_ensure() for i in 0 .. len(npc_st.np_posts) { if npc_st.np_posts[i].active { np_step_post(npc_st, npc_st.np_posts[i], dt) } } } @@ -82,7 +80,6 @@ export function npc_hold(npc_st: mut NpcState, on: bool) -> void { npc_st.np_hol # everyone gone, as a new trip starts; the posts are the place's and stay export function npc_reset(npc_st: mut NpcState) -> void { - np_ensure() for i in 0 .. len(npc_st.np_walkers) { npc_retire(npc_st, npc_st.np_walkers[i]) } npc_st.np_n = 0 npc_st.np_next_h = 0.0 diff --git a/packages/ludic.prefs/prefs.ludic b/packages/ludic.prefs/prefs.ludic index 6b1ddcf9..8421a108 100644 --- a/packages/ludic.prefs/prefs.ludic +++ b/packages/ludic.prefs/prefs.ludic @@ -11,18 +11,12 @@ const PREFS_MAX: int = 64 state PrefsState { prefs_path: pointer = null - prefs_names: pointers = null - prefs_vals: words = null + prefs_names: pointers = pointers(PREFS_MAX) + prefs_vals: words = words(PREFS_MAX) prefs_n: int = 0 } namespace Prefs { - internal function init(prefs_st: mut PrefsState) -> void { - if prefs_st.prefs_names != null { return } - prefs_st.prefs_names = pointers(PREFS_MAX) - prefs_st.prefs_vals = words(PREFS_MAX) - prefs_st.prefs_n = 0 - } internal function find(prefs_st: PrefsState, key: pointer) -> int { var i = 0 @@ -31,7 +25,6 @@ namespace Prefs { } export function get(prefs_st: mut PrefsState, key: pointer, fallback: int) -> int { - init(prefs_st) let i = find(prefs_st, key) if i < 0 { return fallback } return prefs_st.prefs_vals[i] @@ -45,7 +38,6 @@ namespace Prefs { } export function set(prefs_st: mut PrefsState, key: pointer, value: int) -> void { - init(prefs_st) var i = find(prefs_st, key) if i < 0 { if prefs_st.prefs_n >= PREFS_MAX { return } @@ -89,7 +81,6 @@ namespace Prefs { } export function load(prefs_st: mut PrefsState, path: pointer) -> void { - init(prefs_st) prefs_st.prefs_path = path let buf = read_all(path) if buf == null { return } @@ -109,7 +100,6 @@ namespace Prefs { } export function save(prefs_st: mut PrefsState) -> void { - init(prefs_st) if prefs_st.prefs_path == null { return } let f = file_open(prefs_st.prefs_path, "wb") if f == null { return } diff --git a/packages/ludic.rpg/crafting.ludic b/packages/ludic.rpg/crafting.ludic index d54c2861..5c44aa93 100644 --- a/packages/ludic.rpg/crafting.ludic +++ b/packages/ludic.rpg/crafting.ludic @@ -10,20 +10,12 @@ const CRAFT_MAX: int = 128 const CRAFT_ING_MAX: int = 512 -function craft_ensure(rpg_st: mut RpgState) -> void { - if rpg_st.recipe_reg == null { - rpg_st.recipe_reg = Dict.new() - rpg_st.recipe_out = pointers(CRAFT_MAX); rpg_st.recipe_outqty = words(CRAFT_MAX) - rpg_st.ing_rid = words(CRAFT_ING_MAX); rpg_st.ing_name = pointers(CRAFT_ING_MAX); rpg_st.ing_qty = words(CRAFT_ING_MAX) - } -} event cancellable CraftRequested { e: int = 0, recipe: int = 0 } event CraftCompleted { e: int = 0, recipe: int = 0 } # Craft.recipe(name, out_item, out_qty) — declare a recipe; returns its id. @Namespace(Craft) function craft_recipe(rpg_st: mut RpgState, name: pointer, out_item: pointer, out_qty: int) -> int { - craft_ensure(rpg_st) if rpg_st.recipe_n >= CRAFT_MAX { return -1 } let id = rpg_st.recipe_n rpg_st.recipe_out[id] = out_item; rpg_st.recipe_outqty[id] = out_qty @@ -31,10 +23,9 @@ event CraftCompleted { e: int = 0, recipe: int = 0 } Dict.set(rpg_st.recipe_reg, name, id) return id } -@Namespace(Craft) function craft_id(rpg_st: mut RpgState, name: pointer) -> int { craft_ensure(rpg_st); return Dict.get_or(rpg_st.recipe_reg, name, -1) } +@Namespace(Craft) function craft_id(rpg_st: mut RpgState, name: pointer) -> int { return Dict.get_or(rpg_st.recipe_reg, name, -1) } # Craft.ingredient(recipe_name, item, qty) — add an ingredient requirement. @Namespace(Craft) function craft_ingredient(rpg_st: mut RpgState, recipe_name: pointer, item: pointer, qty: int) -> void { - craft_ensure(rpg_st) let rid = craft_id(rpg_st, recipe_name) if rid < 0 { return } if rpg_st.ing_n >= CRAFT_ING_MAX { return } @@ -44,7 +35,6 @@ event CraftCompleted { e: int = 0, recipe: int = 0 } # Craft.can(e, recipe_name) — does the owner hold every ingredient? @Namespace(Craft) function craft_can(rpg_st: mut RpgState, e: int, recipe_name: pointer) -> int { - craft_ensure(rpg_st) let rid = craft_id(rpg_st, recipe_name) if rid < 0 { return 0 } var i = 0 @@ -59,7 +49,6 @@ event CraftCompleted { e: int = 0, recipe: int = 0 } # Craft.make(e, recipe_name) — consume ingredients + produce output; 1 on success. @Namespace(Craft) function craft_make(rpg_st: mut RpgState, e: int, recipe_name: pointer) -> int { - craft_ensure(rpg_st) let rid = craft_id(rpg_st, recipe_name) if rid < 0 { return 0 } if craft_can(rpg_st, e, recipe_name) == 0 { return 0 } diff --git a/packages/ludic.rpg/dialog.ludic b/packages/ludic.rpg/dialog.ludic index 91bd8e41..94961300 100644 --- a/packages/ludic.rpg/dialog.ludic +++ b/packages/ludic.rpg/dialog.ludic @@ -9,14 +9,6 @@ const DLG_NODE_MAX: int = 512 const DLG_CHOICE_MAX: int = 1024 -function dlg_ensure(rpg_st: mut RpgState) -> void { - if rpg_st.dlg_reg == null { - rpg_st.dlg_reg = Dict.new() - rpg_st.dlg_tree_start = words(DLG_TREE_MAX) - rpg_st.dlg_node_tree = words(DLG_NODE_MAX); rpg_st.dlg_node_text = pointers(DLG_NODE_MAX) - rpg_st.dlg_choice_node = words(DLG_CHOICE_MAX); rpg_st.dlg_choice_label = pointers(DLG_CHOICE_MAX); rpg_st.dlg_choice_next = words(DLG_CHOICE_MAX) - } -} property Dialog { tree: int = 0, node: int = 0, active: int = 0 } @@ -27,7 +19,6 @@ event DialogEnded { e: int = 0 } # Dialog.tree(name) — register (or fetch) a tree id. @Namespace(Dialog) function dialog_tree(rpg_st: mut RpgState, name: pointer) -> int { - dlg_ensure(rpg_st) let ex = Dict.get_or(rpg_st.dlg_reg, name, -1) if ex >= 0 { return ex } if rpg_st.dlg_tree_n >= DLG_TREE_MAX { return -1 } @@ -40,7 +31,6 @@ event DialogEnded { e: int = 0 } # Dialog.node(tree_name, text) — add a line node; the first node added to a tree is # its entry point. Returns the node id. @Namespace(Dialog) function dialog_node(rpg_st: mut RpgState, tree_name: pointer, text: pointer) -> int { - dlg_ensure(rpg_st) let tid = dialog_tree(rpg_st, tree_name) if tid < 0 { return -1 } if rpg_st.dlg_node_n >= DLG_NODE_MAX { return -1 } @@ -52,7 +42,6 @@ event DialogEnded { e: int = 0 } } # Dialog.choice(node, label, next_node) — add a branch (next_node -1 ends). @Namespace(Dialog) function dialog_choice(rpg_st: mut RpgState, node: int, label: pointer, next_node: int) -> int { - dlg_ensure(rpg_st) if rpg_st.dlg_choice_n >= DLG_CHOICE_MAX { return -1 } let id = rpg_st.dlg_choice_n rpg_st.dlg_choice_node[id] = node; rpg_st.dlg_choice_label[id] = label; rpg_st.dlg_choice_next[id] = next_node @@ -71,7 +60,6 @@ function dlg_set(e: int, name: pointer, v: int) -> void { # Dialog.start(e, tree_name) — open the tree on a speaker (DialogStarted + Line). @Namespace(Dialog) function dialog_start(rpg_st: mut RpgState, e: int, tree_name: pointer) -> void { - dlg_ensure(rpg_st) let tid = dialog_tree(rpg_st, tree_name) if tid < 0 { return } dlg_set(e, "tree", tid) @@ -87,7 +75,6 @@ function dlg_set(e: int, name: pointer, v: int) -> void { } # Dialog.count(e) — number of choices at the current node. @Namespace(Dialog) function dialog_count(rpg_st: mut RpgState, e: int) -> int { - dlg_ensure(rpg_st) if dlg_get(e, "active") == 0 { return 0 } let node = dlg_get(e, "node") var n = 0; var i = 0 @@ -96,7 +83,6 @@ function dlg_set(e: int, name: pointer, v: int) -> void { } # Dialog.choose(e, i) — take the i-th choice (veto-able); advance or end. @Namespace(Dialog) function dialog_choose(rpg_st: mut RpgState, e: int, idx: int) -> int { - dlg_ensure(rpg_st) if dlg_get(e, "active") == 0 { return 0 } let node = dlg_get(e, "node") var seen = 0; var i = 0; var pick = -1 diff --git a/packages/ludic.rpg/inventory.ludic b/packages/ludic.rpg/inventory.ludic index cf188a28..49bcbc0b 100644 --- a/packages/ludic.rpg/inventory.ludic +++ b/packages/ludic.rpg/inventory.ludic @@ -11,52 +11,45 @@ const INV_MAX: int = 256 # ---- item registry -------------------------------------------------------- state RpgState { - recipe_reg: Dict = null # recipe name -> id + recipe_reg: Dict = Dict.new() # recipe name -> id recipe_n: int = 0 - recipe_out: pointers = null # output item name - recipe_outqty: words = null + recipe_out: pointers = pointers(CRAFT_MAX) # output item name + recipe_outqty: words = words(CRAFT_MAX) ing_n: int = 0 - ing_rid: words = null # owning recipe id - ing_name: pointers = null # ingredient item name - ing_qty: words = null - dlg_reg: Dict = null # tree name -> tree id + ing_rid: words = words(CRAFT_ING_MAX) # owning recipe id + ing_name: pointers = pointers(CRAFT_ING_MAX) # ingredient item name + ing_qty: words = words(CRAFT_ING_MAX) + dlg_reg: Dict = Dict.new() # tree name -> tree id dlg_tree_n: int = 0 - dlg_tree_start: words = null # first node id per tree + dlg_tree_start: words = words(DLG_TREE_MAX) # first node id per tree dlg_node_n: int = 0 - dlg_node_tree: words = null - dlg_node_text: pointers = null + dlg_node_tree: words = words(DLG_NODE_MAX) + dlg_node_text: pointers = pointers(DLG_NODE_MAX) dlg_choice_n: int = 0 - dlg_choice_node: words = null # owning node - dlg_choice_label: pointers = null - dlg_choice_next: words = null # next node id, or -1 to end - item_reg: Dict = null + dlg_choice_node: words = words(DLG_CHOICE_MAX) # owning node + dlg_choice_label: pointers = pointers(DLG_CHOICE_MAX) + dlg_choice_next: words = words(DLG_CHOICE_MAX) # next node id, or -1 to end + item_reg: Dict = Dict.new() item_n: int = 0 - item_stackmax: words = null - item_weight: words = null - item_value: words = null - inv_counts: Dict = null - quest_reg: Dict = null # quest name -> id + item_stackmax: words = words(INV_MAX) + item_weight: words = words(INV_MAX) + item_value: words = words(INV_MAX) + inv_counts: Dict = Dict.new() + quest_reg: Dict = Dict.new() # quest name -> id quest_n: int = 0 - quest_state: words = null + quest_state: words = words(QUEST_MAX) obj_n: int = 0 - obj_qid: words = null # owning quest id - obj_kind: words = null - obj_target: words = null # a target id/tag (kind-specific; 0 = any) - obj_need: words = null - obj_have: words = null - quest_flags: Dict = null # global flag store + obj_qid: words = words(OBJ_MAX) # owning quest id + obj_kind: words = words(OBJ_MAX) + obj_target: words = words(OBJ_MAX) # a target id/tag (kind-specific; 0 = any) + obj_need: words = words(OBJ_MAX) + obj_have: words = words(OBJ_MAX) + quest_flags: Dict = Dict.new() # global flag store } -function item_ensure(rpg_st: mut RpgState) -> void { - if rpg_st.item_reg == null { - rpg_st.item_reg = Dict.new() - rpg_st.item_stackmax = words(INV_MAX); rpg_st.item_weight = words(INV_MAX); rpg_st.item_value = words(INV_MAX) - } -} # Item.def(name, stack_max, weight, value) — register an item template. Returns id. @Namespace(Item) function item_def(rpg_st: mut RpgState, name: pointer, stack_max: int, weight: int, value: int) -> int { - item_ensure(rpg_st) if rpg_st.item_n >= INV_MAX { return -1 } let id = rpg_st.item_n rpg_st.item_stackmax[id] = stack_max; rpg_st.item_weight[id] = weight; rpg_st.item_value[id] = value @@ -64,7 +57,7 @@ function item_ensure(rpg_st: mut RpgState) -> void { Dict.set(rpg_st.item_reg, name, id) return id } -@Namespace(Item) function item_id(rpg_st: mut RpgState, name: pointer) -> int { item_ensure(rpg_st); return Dict.get_or(rpg_st.item_reg, name, -1) } +@Namespace(Item) function item_id(rpg_st: mut RpgState, name: pointer) -> int { return Dict.get_or(rpg_st.item_reg, name, -1) } @Namespace(Item) function item_value_of(rpg_st: mut RpgState, name: pointer) -> int { let id = item_id(rpg_st, name); if id < 0 { return 0 } return rpg_st.item_value[id] @@ -73,7 +66,6 @@ function item_ensure(rpg_st: mut RpgState) -> void { # ---- per-owner counts ----------------------------------------------------- property Inventory { gold: int = 0, weight_max: int = 0, slots: int = 0 } -function inv_ensure(rpg_st: mut RpgState) -> void { if rpg_st.inv_counts == null { rpg_st.inv_counts = Dict.new() } } function inv_key(e: int, name: pointer) -> pointer { return `{e}/{name}` } event ItemAdded { e: int = 0, item: int = 0, qty: int = 0 } # item = registry id @@ -82,14 +74,12 @@ event cancellable ItemUse { e: int = 0, item: int = 0 } # veto a use ( # Inventory.add(e, name, n) — add n of an item; emits ItemAdded. @Namespace(Inventory) function inventory_add(rpg_st: mut RpgState, e: int, name: pointer, n: int) -> void { - inv_ensure(rpg_st) let k = inv_key(e, name) Dict.set(rpg_st.inv_counts, k, Dict.get_or(rpg_st.inv_counts, k, 0) + n) emit ItemAdded(e: e, item: item_id(rpg_st, name), qty: n) } # Inventory.count(e, name) — how many the owner holds. @Namespace(Inventory) function inventory_count(rpg_st: mut RpgState, e: int, name: pointer) -> int { - inv_ensure(rpg_st) return Dict.get_or(rpg_st.inv_counts, inv_key(e, name), 0) } @Namespace(Inventory) function inventory_has(rpg_st: mut RpgState, e: int, name: pointer) -> int { @@ -98,7 +88,6 @@ event cancellable ItemUse { e: int = 0, item: int = 0 } # veto a use ( } # Inventory.remove(e, name, n) — remove up to n; returns 1 if it had enough. @Namespace(Inventory) function inventory_remove(rpg_st: mut RpgState, e: int, name: pointer, n: int) -> int { - inv_ensure(rpg_st) let k = inv_key(e, name) let have = Dict.get_or(rpg_st.inv_counts, k, 0) if have < n { return 0 } diff --git a/packages/ludic.rpg/quests.ludic b/packages/ludic.rpg/quests.ludic index 277ec1cb..8d330abb 100644 --- a/packages/ludic.rpg/quests.ludic +++ b/packages/ludic.rpg/quests.ludic @@ -15,14 +15,6 @@ const QUEST_MAX: int = 128 const OBJ_MAX: int = 512 -function quest_ensure(rpg_st: mut RpgState) -> void { - if rpg_st.quest_reg == null { - rpg_st.quest_reg = Dict.new(); rpg_st.quest_flags = Dict.new() - rpg_st.quest_state = words(QUEST_MAX) - rpg_st.obj_qid = words(OBJ_MAX); rpg_st.obj_kind = words(OBJ_MAX); rpg_st.obj_target = words(OBJ_MAX) - rpg_st.obj_need = words(OBJ_MAX); rpg_st.obj_have = words(OBJ_MAX) - } -} event QuestStarted { quest: int = 0 } event QuestCompleted { quest: int = 0 } @@ -30,7 +22,6 @@ event ObjectiveProgressed { quest: int = 0, objective: int = 0, have: int = 0, n # Quest.define(name) — register a quest (state hidden). Returns id. @Namespace(Quest) function quest_define(rpg_st: mut RpgState, name: pointer) -> int { - quest_ensure(rpg_st) if rpg_st.quest_n >= QUEST_MAX { return -1 } let id = rpg_st.quest_n rpg_st.quest_state[id] = 0 @@ -38,10 +29,9 @@ event ObjectiveProgressed { quest: int = 0, objective: int = 0, have: int = 0, n Dict.set(rpg_st.quest_reg, name, id) return id } -@Namespace(Quest) function quest_id(rpg_st: mut RpgState, name: pointer) -> int { quest_ensure(rpg_st); return Dict.get_or(rpg_st.quest_reg, name, -1) } +@Namespace(Quest) function quest_id(rpg_st: mut RpgState, name: pointer) -> int { return Dict.get_or(rpg_st.quest_reg, name, -1) } # Quest.objective(quest_name, kind, target, need) — add an objective. @Namespace(Quest) function quest_objective(rpg_st: mut RpgState, quest_name: pointer, kind: int, target: int, need: int) -> int { - quest_ensure(rpg_st) let qid = quest_id(rpg_st, quest_name) if qid < 0 { return -1 } if rpg_st.obj_n >= OBJ_MAX { return -1 } @@ -53,14 +43,12 @@ event ObjectiveProgressed { quest: int = 0, objective: int = 0, have: int = 0, n } # Quest.start(name) — activate a quest (emits QuestStarted). @Namespace(Quest) function quest_start(rpg_st: mut RpgState, name: pointer) -> void { - quest_ensure(rpg_st) let qid = quest_id(rpg_st, name) if qid < 0 { return } rpg_st.quest_state[qid] = 2 emit QuestStarted(quest: qid) } @Namespace(Quest) function quest_state_of(rpg_st: mut RpgState, name: pointer) -> int { - quest_ensure(rpg_st) let qid = quest_id(rpg_st, name) if qid < 0 { return -1 } return rpg_st.quest_state[qid] @@ -80,7 +68,6 @@ function quest_all_done(rpg_st: RpgState, qid: int) -> int { # quest's matching objectives tick up (target 0 on the objective = "any"); a quest # whose objectives are all met auto-completes. @Namespace(Quest) function quest_notify(rpg_st: mut RpgState, kind: int, target: int, amount: int) -> void { - quest_ensure(rpg_st) var i = 0 while i < rpg_st.obj_n { let qid = rpg_st.obj_qid[i] @@ -104,5 +91,5 @@ function quest_all_done(rpg_st: RpgState, qid: int) -> int { } # ---- global flag store (branching / world state) -------------------------- -@Namespace(Quest) function quest_flag(rpg_st: mut RpgState, name: pointer, value: int) -> void { quest_ensure(rpg_st); Dict.set(rpg_st.quest_flags, name, value) } -@Namespace(Quest) function quest_flag_get(rpg_st: mut RpgState, name: pointer) -> int { quest_ensure(rpg_st); return Dict.get_or(rpg_st.quest_flags, name, 0) } +@Namespace(Quest) function quest_flag(rpg_st: mut RpgState, name: pointer, value: int) -> void { Dict.set(rpg_st.quest_flags, name, value) } +@Namespace(Quest) function quest_flag_get(rpg_st: mut RpgState, name: pointer) -> int { return Dict.get_or(rpg_st.quest_flags, name, 0) } diff --git a/packages/ludic.shooter/shooter.ludic b/packages/ludic.shooter/shooter.ludic index ca38bbba..fc7ef0b6 100644 --- a/packages/ludic.shooter/shooter.ludic +++ b/packages/ludic.shooter/shooter.ludic @@ -70,36 +70,26 @@ event WeaponFired { owner: int = 0, def_id: int = 0 } # Weapon registry (name-keyed, mod-friendly — add a gun with no code) # --------------------------------------------------------------------------- state ShooterState { - wpn_reg: Dict = null + wpn_reg: Dict = Dict.new() wpn_n: int = 0 - wpn_rate: words = null - wpn_dmg: words = null - wpn_speed: words = null - wpn_spread: words = null - wpn_pellets: words = null - wpn_pattern: words = null - wpn_ttl: words = null - wpn_pierce: words = null - wpn_homing: words = null - wpn_color: words = null - wpn_rate_base: words = null + wpn_rate: words = words(WPN_MAX) + wpn_dmg: words = words(WPN_MAX) + wpn_speed: words = words(WPN_MAX) + wpn_spread: words = words(WPN_MAX) + wpn_pellets: words = words(WPN_MAX) + wpn_pattern: words = words(WPN_MAX) + wpn_ttl: words = words(WPN_MAX) + wpn_pierce: words = words(WPN_MAX) + wpn_homing: words = words(WPN_MAX) + wpn_color: words = words(WPN_MAX) + wpn_rate_base: words = words(WPN_MAX) wpn_fire_color: int = 0xffffff # the colour of the weapon being fired (sh_fire) } -function wpn_ensure(shooter_st: mut ShooterState) -> void { - if shooter_st.wpn_reg == null { - shooter_st.wpn_reg = Dict.new() - shooter_st.wpn_rate = words(WPN_MAX); shooter_st.wpn_dmg = words(WPN_MAX); shooter_st.wpn_speed = words(WPN_MAX) - shooter_st.wpn_spread = words(WPN_MAX); shooter_st.wpn_pellets = words(WPN_MAX); shooter_st.wpn_pattern = words(WPN_MAX) - shooter_st.wpn_ttl = words(WPN_MAX); shooter_st.wpn_pierce = words(WPN_MAX); shooter_st.wpn_homing = words(WPN_MAX) - shooter_st.wpn_color = words(WPN_MAX); shooter_st.wpn_rate_base = words(WPN_MAX) - } -} # Weapon.def(name, fire_rate, damage, speed, spread, pellets, pattern) — register a # gun. pattern: 0 single/aimed, 1 spread cone, 2 ring, 3 spiral. Returns the def id. @Namespace(Weapon) function weapon_def(shooter_st: mut ShooterState, name: pointer, fire_rate: int, damage: int, speed: int, spread: int, pellets: int, pattern: int) -> int { - wpn_ensure(shooter_st) if shooter_st.wpn_n >= WPN_MAX { return -1 } let id = shooter_st.wpn_n shooter_st.wpn_rate[id] = fire_rate; shooter_st.wpn_dmg[id] = damage; shooter_st.wpn_speed[id] = speed @@ -112,36 +102,35 @@ function wpn_ensure(shooter_st: mut ShooterState) -> void { return id } @Namespace(Weapon) function weapon_id(shooter_st: mut ShooterState, name: pointer) -> int { - wpn_ensure(shooter_st) return Dict.get_or(shooter_st.wpn_reg, name, -1) } # Weapon.set_rate(id, frames) — frames between shots (a fire-rate upgrade changes it in place). @Namespace(Weapon) function weapon_set_rate(shooter_st: mut ShooterState, id: int, frames: int) -> void { - wpn_ensure(shooter_st); if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_rate[id] = frames } + if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_rate[id] = frames } } @Namespace(Weapon) function weapon_rate(shooter_st: mut ShooterState, id: int) -> int { - wpn_ensure(shooter_st); if (id >= 0) and (id < WPN_MAX) { return shooter_st.wpn_rate[id] }; return 0 + if (id >= 0) and (id < WPN_MAX) { return shooter_st.wpn_rate[id] }; return 0 } # Weapon.reset(id) — back to the definition: no pierce, no homing, the defined fire rate. @Namespace(Weapon) function weapon_reset(shooter_st: mut ShooterState, id: int) -> void { - wpn_ensure(shooter_st); if (id < 0) or (id >= WPN_MAX) { return } + if (id < 0) or (id >= WPN_MAX) { return } shooter_st.wpn_pierce[id] = 0; shooter_st.wpn_homing[id] = 0; shooter_st.wpn_rate[id] = shooter_st.wpn_rate_base[id] } # Weapon.set_color(id, color) — the colour the engine draws this weapon's shots in. @Namespace(Weapon) function weapon_set_color(shooter_st: mut ShooterState, id: int, color: int) -> void { - wpn_ensure(shooter_st); if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_color[id] = color } + if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_color[id] = color } } # Weapon.set_ttl(id, frames) — projectile lifetime for a weapon (range control). @Namespace(Weapon) function weapon_set_ttl(shooter_st: mut ShooterState, id: int, frames: int) -> void { - wpn_ensure(shooter_st); if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_ttl[id] = frames } + if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_ttl[id] = frames } } # Weapon.set_pierce(id, n) — a shot passes through n targets before it dies. @Namespace(Weapon) function weapon_set_pierce(shooter_st: mut ShooterState, id: int, n: int) -> void { - wpn_ensure(shooter_st); if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_pierce[id] = n } + if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_pierce[id] = n } } # Weapon.set_homing(id, deg) — max degrees/frame a shot turns toward an enemy. @Namespace(Weapon) function weapon_set_homing(shooter_st: mut ShooterState, id: int, deg: int) -> void { - wpn_ensure(shooter_st); if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_homing[id] = deg } + if (id >= 0) and (id < WPN_MAX) { shooter_st.wpn_homing[id] = deg } } # --------------------------------------------------------------------------- @@ -534,7 +523,6 @@ function sh_spawn_bullet(shooter_st: ShooterState, owner: int, fac: int, px: int @EngineSystem(Weapon, Update) function esys_weapon(shooter_st: mut ShooterState) -> void { let P = World.prop_id("Weapon") if P < 0 { return } - wpn_ensure(shooter_st) var e = World.query_next(P, 0) while e >= 0 { let cd = World.get(e, P, World.field_id(P, "cooldown"))