refactor(runtime,packages,examples): named constants, package enums, idiom sweep
- runtime: HEADLESS_FRAME_PATH, STICK_DEADZONE / STICK_LEFT_X/Y, key and byte codes as char literals throughout (`k == 'w'`, `fill(rt_map, ' ', …)`) - ludic.gameplay/stats: drop the duplicate `stat_field` (it answered "atk" for every build stat); Stats.base uses stats_field_name - ludic.shooter: compare aim modes and fire patterns with AimMode.* and WeaponPattern.* instead of raw ints; STICK_RIGHT_X/Y - ludic.npcai: DecisionMade / brain_set_state use AiState.* - examples/games/menu.ludic uses Font.load / Ui.* with FONT_PATH and BACKDROP named; strings.ludic header says what it prints - whole tree: `x = x + 1` → `x += 1` (single-term right-hand sides only), `0 - x` → `-x`, ASCII codes → char literals; every .ludic and every ```ludic fence reformatted with the fixed formatter (whitespace only) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
e3e1bc7784
commit
bf36bc8a8f
103 changed files with 1256 additions and 1252 deletions
|
|
@ -19,8 +19,8 @@ program Hello {
|
|||
# runs once per match, each property bound by name and self() giving that entity.
|
||||
@Queries(these: [Pos, Vel])
|
||||
handler Move phase FixedUpdate {
|
||||
Pos.x = Pos.x + Vel.dx
|
||||
Pos.y = Pos.y + Vel.dy
|
||||
Pos.x += Vel.dx
|
||||
Pos.y += Vel.dy
|
||||
}
|
||||
|
||||
handler Report phase Update {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ program WorldQuery {
|
|||
var sum = 0
|
||||
var e = world_query_next(H, 0)
|
||||
while e >= 0 {
|
||||
count = count + 1
|
||||
sum = sum + world_get(e, H, hp)
|
||||
count += 1
|
||||
sum += world_get(e, H, hp)
|
||||
e = world_query_next(H, e + 1)
|
||||
}
|
||||
print(count) # 2
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ program WorldScan {
|
|||
var e = 0
|
||||
while e < n {
|
||||
if world_kind(e) == Um {
|
||||
count = count + 1
|
||||
sum = sum + world_get(e, H, hp)
|
||||
count += 1
|
||||
sum += world_get(e, H, hp)
|
||||
}
|
||||
e = e + 1
|
||||
e += 1
|
||||
}
|
||||
print(count) # 2
|
||||
print(sum) # 110
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ program Cancel {
|
|||
|
||||
# the realistic shape: only apply the effect when the decision isn't vetoed
|
||||
var hp = 100
|
||||
if emit BeforeHurt(amount: 8) == 0 { hp = hp - 8 } # allowed -> 92
|
||||
if emit BeforeHurt(amount: 50) == 0 { hp = hp - 50 } # vetoed -> unchanged
|
||||
if emit BeforeHurt(amount: 8) == 0 { hp -= 8 } # allowed -> 92
|
||||
if emit BeforeHurt(amount: 50) == 0 { hp -= 50 } # vetoed -> unchanged
|
||||
print(hp) # 92
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ program LayerEvents {
|
|||
}
|
||||
layer Ctrl {
|
||||
handler Drive phase LateUpdate {
|
||||
step = step + 1
|
||||
step += 1
|
||||
if step == 1 { disable layer Hud } # frame 1: hide -> Hidden 2, Draw stops
|
||||
if step == 2 { enable layer Hud } # frame 2: show -> Shown 1, Draw resumes
|
||||
if step == 3 { quit() } # frame 3: after Draw ran again
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ program ModEvents {
|
|||
var total: int = 0
|
||||
event Damage { amount: int = 0 }
|
||||
@On(Damage) handler Native { print(amount) } # prints each hit
|
||||
@On(Damage) handler Accum { total = total + amount } # sums them
|
||||
@On(Damage) handler Accum { total += amount } # sums them
|
||||
|
||||
entry {
|
||||
emit Damage(amount: 10) # Native prints 10
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ program ProgramEvents {
|
|||
@Public @OnStart handler Boot { print(1) } # -> program_start
|
||||
@Public @OnQuit handler Bye { print(2) } # -> program_quit
|
||||
|
||||
@On(program_start) handler ModInit { print(100) } # mod boots after the game
|
||||
@On(program_quit) handler ModDone { print(200) } # mod tears down as the game exits
|
||||
@On(program_start) handler ModInit { print(100) } # mod boots after the game
|
||||
@On(program_quit) handler ModDone { print(200) } # mod tears down as the game exits
|
||||
|
||||
handler Run phase Update { quit() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ program Recurse {
|
|||
event Ping { }
|
||||
event Pong { }
|
||||
|
||||
@On(Ping) handler A { n = n + 1; emit Pong() } # each Ping deepens by one Pong
|
||||
@On(Ping) handler A { n += 1; emit Pong() } # each Ping deepens by one Pong
|
||||
@On(Pong) handler B { emit Ping() } # ...and each Pong by one Ping
|
||||
|
||||
entry {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ program Scoped {
|
|||
model Unit { Health }
|
||||
var fires: int = 0
|
||||
event Tick { }
|
||||
@On(Tick) handler OnTick { for (Health) in query [Health, {Unit}] { fires = fires + 1 } }
|
||||
@On(Tick) handler OnTick { for (Health) in query [Health, {Unit}] { fires += 1 } }
|
||||
|
||||
entry {
|
||||
spawn Unit { Health { hp: 1 } }
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ handler Battle phase Update {
|
|||
match menu_cursor {
|
||||
KnightAct.Attack => {
|
||||
let d = max(1, st.atk - e.def + Random.range(0, 4))
|
||||
e.hp = e.hp - d
|
||||
e.hp -= d
|
||||
player_hit = d
|
||||
}
|
||||
KnightAct.Guard => { st.guard = 1; player_hit = 0 }
|
||||
KnightAct.Item => {
|
||||
if potions > 0 {
|
||||
potions = potions - 1
|
||||
potions -= 1
|
||||
st.hp = min(st.maxhp, st.hp + 24)
|
||||
player_hit = 24
|
||||
} else { player_hit = 0 }
|
||||
|
|
@ -55,7 +55,7 @@ handler Battle phase Update {
|
|||
if k != 0 {
|
||||
if e.hp <= 0 {
|
||||
grant_xp(e.xp)
|
||||
gold = gold + e.xp
|
||||
gold += e.xp
|
||||
if enemy_type == 2 { boss_down = 1; game_mode = 3; ack = 0 }
|
||||
else { game_mode = 0 }
|
||||
become KnightMenu
|
||||
|
|
@ -78,12 +78,12 @@ handler Battle phase Update {
|
|||
match menu_cursor {
|
||||
MageAct.Attack => {
|
||||
let d = max(1, st.atk + 5 - e.def + Random.range(0, 5))
|
||||
e.hp = e.hp - d
|
||||
e.hp -= d
|
||||
player_hit = d
|
||||
}
|
||||
MageAct.Heal => {
|
||||
if st.mp >= 4 {
|
||||
st.mp = st.mp - 4
|
||||
st.mp -= 4
|
||||
for (t2, p2) in query [Stats, Party] {
|
||||
if p2.slot == 0 { t2.hp = min(t2.maxhp, t2.hp + 16) }
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ handler Battle phase Update {
|
|||
if k != 0 {
|
||||
if e.hp <= 0 {
|
||||
grant_xp(e.xp)
|
||||
gold = gold + e.xp
|
||||
gold += e.xp
|
||||
if enemy_type == 2 { boss_down = 1; game_mode = 3; ack = 0 }
|
||||
else { game_mode = 0 }
|
||||
become KnightMenu
|
||||
|
|
@ -121,8 +121,8 @@ handler Battle phase Update {
|
|||
if done == 0 {
|
||||
if t3.hp > 0 {
|
||||
var ed = max(1, e.atk - t3.def + Random.range(0, 4))
|
||||
if t3.guard == 1 { ed = ed / 2; t3.guard = 0 }
|
||||
t3.hp = t3.hp - ed
|
||||
if t3.guard == 1 { ed /= 2; t3.guard = 0 }
|
||||
t3.hp -= ed
|
||||
enemy_hit = ed
|
||||
done = 1
|
||||
}
|
||||
|
|
@ -130,7 +130,7 @@ handler Battle phase Update {
|
|||
}
|
||||
var alive = 0
|
||||
for (t4) in query [Stats, {Party}] {
|
||||
if t4.hp > 0 { alive = alive + 1 }
|
||||
if t4.hp > 0 { alive += 1 }
|
||||
}
|
||||
if alive == 0 { game_mode = 2; ack = 0 }
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -84,33 +84,33 @@ handler Control phase Input {
|
|||
if tc != 'D' {
|
||||
if tc != 'S' {
|
||||
if tc != 'B' {
|
||||
if tc != 'h' {
|
||||
encounter = encounter - 1
|
||||
if encounter <= 0 {
|
||||
encounter = Random.range(4, 9)
|
||||
var et = 0
|
||||
if world_map == 1 { et = 1 }
|
||||
if world_map == 0 {
|
||||
if Random.chance(40) { et = 1 }
|
||||
}
|
||||
enemy_type = et
|
||||
if et == 0 {
|
||||
spawn Enemy {
|
||||
Actor { kind: 6 }
|
||||
Stats { hp: 18, maxhp: 18, mp: 0, maxmp: 0, atk: 8, def: 2, lvl: 1, xp: 7, guard: 0 }
|
||||
if tc != 'h' {
|
||||
encounter -= 1
|
||||
if encounter <= 0 {
|
||||
encounter = Random.range(4, 9)
|
||||
var et = 0
|
||||
if world_map == 1 { et = 1 }
|
||||
if world_map == 0 {
|
||||
if Random.chance(40) { et = 1 }
|
||||
}
|
||||
}
|
||||
if et == 1 {
|
||||
spawn Enemy {
|
||||
Actor { kind: 7 }
|
||||
Stats { hp: 30, maxhp: 30, mp: 0, maxmp: 0, atk: 11, def: 5, lvl: 1, xp: 15, guard: 0 }
|
||||
enemy_type = et
|
||||
if et == 0 {
|
||||
spawn Enemy {
|
||||
Actor { kind: 6 }
|
||||
Stats { hp: 18, maxhp: 18, mp: 0, maxmp: 0, atk: 8, def: 2, lvl: 1, xp: 7, guard: 0 }
|
||||
}
|
||||
}
|
||||
if et == 1 {
|
||||
spawn Enemy {
|
||||
Actor { kind: 7 }
|
||||
Stats { hp: 30, maxhp: 30, mp: 0, maxmp: 0, atk: 11, def: 5, lvl: 1, xp: 15, guard: 0 }
|
||||
}
|
||||
}
|
||||
game_mode = 1
|
||||
turn_phase = 0
|
||||
menu_cursor = 0
|
||||
}
|
||||
game_mode = 1
|
||||
turn_phase = 0
|
||||
menu_cursor = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -130,8 +130,8 @@ handler Shop phase Update {
|
|||
if is_confirm(k) {
|
||||
if menu_cursor == 0 {
|
||||
if gold >= 10 {
|
||||
gold = gold - 10
|
||||
potions = potions + 1
|
||||
gold -= 10
|
||||
potions += 1
|
||||
}
|
||||
}
|
||||
if menu_cursor == 1 { game_mode = 0 }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function walkable(x: int, y: int) -> bool {
|
|||
let c = Map.tile(x, y)
|
||||
return c == '.' or c == 'D' or c == 'r' or c == ',' or c == 'S' or c == 'B' or c == 'h'
|
||||
}
|
||||
function is_confirm(k: int) -> bool { return k == 32 or k == 10 or k == 13 }
|
||||
function is_confirm(k: int) -> bool { return k == ' ' or k == '\n' or k == '\r' }
|
||||
function enemy_name(et: int) -> string {
|
||||
if et == 0 { return "SLIME" }
|
||||
if et == 1 { return "SKELETON" }
|
||||
|
|
@ -70,15 +70,15 @@ function build_dungeon(x: int) -> int {
|
|||
function grant_xp(amount: int) -> int {
|
||||
for (t) in query [Stats, {Party}] {
|
||||
if t.hp > 0 {
|
||||
t.xp = t.xp + amount
|
||||
t.xp += amount
|
||||
while t.xp >= t.lvl * 20 {
|
||||
t.xp = t.xp - t.lvl * 20
|
||||
t.lvl = t.lvl + 1
|
||||
t.maxhp = t.maxhp + 8
|
||||
t.lvl += 1
|
||||
t.maxhp += 8
|
||||
t.hp = t.maxhp
|
||||
t.maxmp = t.maxmp + 2
|
||||
t.atk = t.atk + 2
|
||||
t.def = t.def + 1
|
||||
t.maxmp += 2
|
||||
t.atk += 2
|
||||
t.def += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
# and activation. The game only loads a font, opens the UI, and reads clicks.
|
||||
program Menu {
|
||||
|
||||
# the macOS system font: the toolchain targets macOS today, and the sample keeps
|
||||
# the repo free of a bundled font
|
||||
const FONT_PATH: string = "/System/Library/Fonts/Supplemental/Arial.ttf"
|
||||
const BACKDROP: int = 0x0e0e16
|
||||
|
||||
var title_font: int = 0
|
||||
|
||||
ui MainMenu {
|
||||
|
|
@ -19,22 +24,22 @@ program Menu {
|
|||
}
|
||||
|
||||
handler Boot phase Start {
|
||||
title_font = font_load("/System/Library/Fonts/Supplemental/Arial.ttf")
|
||||
ui_build()
|
||||
ui_open(UI_MainMenu)
|
||||
title_font = Font.load(FONT_PATH)
|
||||
Ui.build()
|
||||
Ui.open(UI_MainMenu)
|
||||
}
|
||||
|
||||
handler Nav phase Update {
|
||||
ui_tick(Input.key())
|
||||
if ui_clicked(UI_NewGame) { ui_set_text(UI_NewGame, "Starting...") }
|
||||
if ui_clicked(UI_Continue) { ui_set_text(UI_Continue, "No save") }
|
||||
if ui_clicked(UI_Options) { ui_set_text(UI_Options, "Soon (TM)") }
|
||||
if ui_clicked(UI_Quit) { quit() }
|
||||
Ui.tick(Input.key())
|
||||
if Ui.clicked(UI_NewGame) { Ui.set_text(UI_NewGame, "Starting...") }
|
||||
if Ui.clicked(UI_Continue) { Ui.set_text(UI_Continue, "No save") }
|
||||
if Ui.clicked(UI_Options) { Ui.set_text(UI_Options, "Soon (TM)") }
|
||||
if Ui.clicked(UI_Quit) { quit() }
|
||||
}
|
||||
|
||||
handler Draw phase Render {
|
||||
Screen.clear(0x0e0e16)
|
||||
ui_render()
|
||||
Screen.clear(BACKDROP)
|
||||
Ui.render()
|
||||
Screen.show()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ program NpcAiDemo {
|
|||
@OnSpawn(Dummy) handler DInit { }
|
||||
|
||||
var spotted: int = 0
|
||||
@On(TargetSpotted) handler OnSpot { spotted = spotted + 1 }
|
||||
@On(TargetSpotted) handler OnSpot { spotted += 1 }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
function gx(e: int) -> int { let P = World.prop_id("Position"); return World.get(e, P, World.field_id(P, "x")) }
|
||||
function gy(e: int) -> int { let P = World.prop_id("Position"); return World.get(e, P, World.field_id(P, "y")) }
|
||||
|
|
@ -52,7 +52,7 @@ program NpcAiDemo {
|
|||
let PBr = World.prop_id("Brain")
|
||||
var e = World.query_next(PS, 0)
|
||||
while e >= 0 { if World.has(e, PBr) == 0 { return e }; e = World.query_next(PS, e + 1) }
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
entry {
|
||||
|
|
@ -102,7 +102,7 @@ program NpcAiDemo {
|
|||
# ---- E. companion follower advances toward its leader ------------------
|
||||
spawn Ally { Position { x: 40, y: 40 }, Collider { w: 12, h: 12 },
|
||||
TopDown { move_speed: 3 }, Faction { id: 2 }, Stats { hp: 30, max_hp: 30 },
|
||||
Brain { model: 0 }, Follower { leader: 0 - 1, distance: 24 } }
|
||||
Brain { model: 0 }, Follower { leader: -1, distance: 24 } }
|
||||
# the ally is the Brain+Follower entity that isn't the enemy
|
||||
var ally = World.query_next(PBr, 0)
|
||||
while (ally >= 0) and (World.has(ally, World.prop_id("Follower")) == 0) { ally = World.query_next(PBr, ally + 1) }
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ program PlatformerDemo {
|
|||
@OnSpawn(Wall) handler WallInit { }
|
||||
|
||||
var jumps: int = 0
|
||||
@On(JumpPerformed) handler CountJumps { jumps = jumps + 1 }
|
||||
@On(JumpPerformed) handler CountJumps { jumps += 1 }
|
||||
# a game rule: forbid the air (double) jump unless a "power" flag is set — pure
|
||||
# lever-4 veto, no controller edit.
|
||||
var have_power: int = 0
|
||||
var vetoed_air: int = 0
|
||||
@On(JumpRequested) handler GateAir { if (kind == 2) and (have_power == 0) { vetoed_air = 1; cancel } }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
function pf_coyote(e: int) -> int {
|
||||
let P = World.prop_id("Platformer")
|
||||
|
|
@ -78,7 +78,7 @@ program PlatformerDemo {
|
|||
Platformer.jump(h)
|
||||
var top = World.get(h, PP, fy)
|
||||
var i = 0
|
||||
while i < 20 { tick_fixed(); let y = World.get(h, PP, fy); if y < top { top = y }; i = i + 1 }
|
||||
while i < 20 { tick_fixed(); let y = World.get(h, PP, fy); if y < top { top = y }; i += 1 }
|
||||
let rise = floor_y - top # px risen at apex (target 64 = 4 tiles)
|
||||
print(bi((rise >= 56) and (rise <= 72))) # 1
|
||||
Platformer.hold(h, 0)
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ program PlatformerScaffolding {
|
|||
@OnSpawn(Spike) handler SI { }
|
||||
|
||||
var picked: int = 0
|
||||
@On(ItemPickedUp) handler OnPick { picked = picked + 1 }
|
||||
@On(ItemPickedUp) handler OnPick { picked += 1 }
|
||||
var sprang: int = 0
|
||||
@On(Sprang) handler OnSpring { sprang = sprang + 1 }
|
||||
@On(Sprang) handler OnSpring { sprang += 1 }
|
||||
var hurt: int = 0
|
||||
@On(Hurt) handler OnHurt { hurt = hurt + 1 }
|
||||
@On(Hurt) handler OnHurt { hurt += 1 }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
|
||||
entry {
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ program RpgDemo {
|
|||
var locked: int = 0
|
||||
@On(MoveRequested) handler LockDoor { if (locked == 1) and (dx == 1) { cancel } }
|
||||
var entered: int = 0
|
||||
@On(TileEntered) handler CountEnter { entered = entered + 1 }
|
||||
@On(TileEntered) handler CountEnter { entered += 1 }
|
||||
var talked: int = 0
|
||||
@On(Interacted) handler OnTalk { if target >= 0 { talked = talked + 1 } }
|
||||
@On(Interacted) handler OnTalk { if target >= 0 { talked += 1 } }
|
||||
var quest_done: int = 0
|
||||
@On(QuestCompleted) handler OnQuestDone { quest_done = quest_done + 1 }
|
||||
@On(QuestCompleted) handler OnQuestDone { quest_done += 1 }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
function px(e: int) -> int { let P = World.prop_id("Position"); return World.get(e, P, World.field_id(P, "x")) }
|
||||
function py(e: int) -> int { let P = World.prop_id("Position"); return World.get(e, P, World.field_id(P, "y")) }
|
||||
|
|
@ -112,7 +112,7 @@ program RpgDemo {
|
|||
let before = Inventory.count(h, "herb")
|
||||
print(bi(Craft.can(h, "potion") == 1)) # 1
|
||||
print(bi(Craft.make(h, "potion") == 1)) # 1 — consumed 2, produced 1
|
||||
print(bi(Inventory.count(h, "herb") == before - 1)) # 1 — net -2 + 1
|
||||
print(bi(Inventory.count(h, "herb") == before - 1)) # 1 — net -2 + 1
|
||||
|
||||
# ================= Module D: quests =================
|
||||
Quest.define("hunt")
|
||||
|
|
@ -126,7 +126,7 @@ program RpgDemo {
|
|||
let dn0 = Dialog.node("elder", "hello")
|
||||
let dn1 = Dialog.node("elder", "farewell")
|
||||
Dialog.choice(dn0, "greet", dn1)
|
||||
Dialog.choice(dn1, "leave", 0 - 1)
|
||||
Dialog.choice(dn1, "leave", -1)
|
||||
Dialog.start(h, "elder")
|
||||
print(bi(Dialog.line(h) == "hello")) # 1 — entry node text
|
||||
Dialog.choose(h, 0)
|
||||
|
|
|
|||
|
|
@ -31,20 +31,20 @@ program ShooterDemo {
|
|||
@OnSpawn(Nest) handler NInit { }
|
||||
|
||||
var spawn_reqs: int = 0
|
||||
@On(SpawnRequested) handler OnSpawnReq { spawn_reqs = spawn_reqs + 1 }
|
||||
@On(SpawnRequested) handler OnSpawnReq { spawn_reqs += 1 }
|
||||
var waves_cleared: int = 0
|
||||
@On(WaveCleared) handler OnWaveClear { waves_cleared = waves_cleared + 1 }
|
||||
@On(WaveCleared) handler OnWaveClear { waves_cleared += 1 }
|
||||
|
||||
var spawned: int = 0
|
||||
@On(ProjectileSpawned) handler CountSpawn { spawned = spawned + 1 }
|
||||
@On(ProjectileSpawned) handler CountSpawn { spawned += 1 }
|
||||
var hits: int = 0
|
||||
@On(ProjectileHit) handler CountHit { hits = hits + 1 }
|
||||
@On(ProjectileHit) handler CountHit { hits += 1 }
|
||||
# reap the dead (the realistic policy: a Died body leaves the world) so stale
|
||||
# corpses do not sit in the faction/targeting scans.
|
||||
var deaths: int = 0
|
||||
@On(Died) handler Reap { deaths = deaths + 1; despawn e }
|
||||
@On(Died) handler Reap { deaths += 1; despawn e }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
function hp_of(e: int) -> int {
|
||||
let P = World.prop_id("Stats")
|
||||
|
|
@ -57,7 +57,7 @@ program ShooterDemo {
|
|||
let PT = World.prop_id("TopDown")
|
||||
var e = World.query_next(PS, 0)
|
||||
while e >= 0 { if World.has(e, PT) == 0 { return e }; e = World.query_next(PS, e + 1) }
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
# a mob still alive (hp > 0) — the dead one from an earlier test stays in the world.
|
||||
function find_live_mob() -> int {
|
||||
|
|
@ -69,7 +69,7 @@ program ShooterDemo {
|
|||
if (World.has(e, PT) == 0) and (World.get(e, PS, fhp) > 0) { return e }
|
||||
e = World.query_next(PS, e + 1)
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
entry {
|
||||
|
|
@ -138,7 +138,7 @@ program ShooterDemo {
|
|||
var f = 0
|
||||
while (deaths == d0) and (f < 400) {
|
||||
TopDown.fire(g, 1); tick_fixed(); TopDown.fire(g, 0); tick_fixed()
|
||||
f = f + 1
|
||||
f += 1
|
||||
}
|
||||
print(bi(deaths == d0 + 1)) # 1 — enemy destroyed (Died fired)
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ program Snake {
|
|||
|
||||
handler Move phase Update {
|
||||
if mode == MODE_PLAY {
|
||||
tick = tick + 1
|
||||
tick += 1
|
||||
if tick >= 6 {
|
||||
tick = 0
|
||||
# remember the tail cell, then drag every segment onto the one ahead of it
|
||||
|
|
@ -102,10 +102,10 @@ program Snake {
|
|||
ate = 0
|
||||
for (ph, sh) in query [Pos, Seg] {
|
||||
if sh.order == 0 {
|
||||
if direction == DIR_UP { ph.y = ph.y - 1 }
|
||||
if direction == DIR_DOWN { ph.y = ph.y + 1 }
|
||||
if direction == DIR_LEFT { ph.x = ph.x - 1 }
|
||||
if direction == DIR_RIGHT { ph.x = ph.x + 1 }
|
||||
if direction == DIR_UP { ph.y -= 1 }
|
||||
if direction == DIR_DOWN { ph.y += 1 }
|
||||
if direction == DIR_LEFT { ph.x -= 1 }
|
||||
if direction == DIR_RIGHT { ph.x += 1 }
|
||||
if ph.x < 0 { mode = MODE_OVER }
|
||||
if ph.x >= GRID_W { mode = MODE_OVER }
|
||||
if ph.y < 0 { mode = MODE_OVER }
|
||||
|
|
@ -124,9 +124,9 @@ program Snake {
|
|||
}
|
||||
}
|
||||
if ate == 1 {
|
||||
score = score + 1
|
||||
score += 1
|
||||
spawn Body { Seg { order: length }; Pos { x: tail_x, y: tail_y } }
|
||||
length = length + 1
|
||||
length += 1
|
||||
food_x = Random.range(low: 0, high: GRID_W - 1)
|
||||
food_y = Random.range(low: 0, high: GRID_H - 1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,6 @@ program AnimEcs {
|
|||
# run the Update phase n times; the engine systems advance one tick each call.
|
||||
function tick_n(n: int) -> void {
|
||||
var i = 0
|
||||
while i < n { tick_fixed(); i = i + 1 }
|
||||
while i < n { tick_fixed(); i += 1 }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ program AnimSugar {
|
|||
model Sprite { SpriteAnim }
|
||||
model Mover { Motion }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
|
||||
entry {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ program AtlasDemo {
|
|||
let d = Sprite.define("hero", sheet, 2, 3) # name a cell
|
||||
print(bi(Sprite.named("hero") == d)) # 1 — looked up by name
|
||||
print(bi(Assets.get("hero") == d)) # 1 — Assets.get is the same lookup
|
||||
print(bi(Sprite.named("nope") == (0 - 1))) # 1 — an unknown name is -1
|
||||
print(bi(Sprite.named("nope") == (-1))) # 1 — an unknown name is -1
|
||||
|
||||
let whole = Assets.image("assets/kenney/tiny-dungeon/Tiles/tile_0096.png")
|
||||
print(Sprite.width(whole)) # 16 — a whole tile as one sprite
|
||||
|
|
@ -34,7 +34,7 @@ program AtlasDemo {
|
|||
Screen.clear(0)
|
||||
Sprite.draw(whole, 10, 10)
|
||||
var n = 0
|
||||
for yy in 10 .. 26 { for xx in 10 .. 26 { if Screen.pixel(xx, yy) != 0 { n = n + 1 } } }
|
||||
for yy in 10 .. 26 { for xx in 10 .. 26 { if Screen.pixel(xx, yy) != 0 { n += 1 } } }
|
||||
print(bi(n > 0)) # 1 — the sprite drew content
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ program Combat {
|
|||
@export function damage(attack: int, armour: int, roll: int) -> int {
|
||||
var raw = attack - armour
|
||||
if raw < 1 { raw = 1 }
|
||||
if roll == 20 { raw = raw * CRIT_MULT }
|
||||
if roll == 20 { raw *= CRIT_MULT }
|
||||
return raw
|
||||
}
|
||||
|
||||
|
|
@ -29,8 +29,8 @@ program Combat {
|
|||
var left = hp
|
||||
var n = 0
|
||||
while left > 0 {
|
||||
left = left - damage(attack, armour, 0)
|
||||
n = n + 1
|
||||
left -= damage(attack, armour, 0)
|
||||
n += 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ program ComponentAccess {
|
|||
Hero.of(player).iframes -= 5
|
||||
print(Hero.of(player).iframes) # 15
|
||||
let hero = Hero.of(player)
|
||||
hero.roll_frames = hero.roll_frames + 1
|
||||
hero.roll_frames += 1
|
||||
print(Hero.of(player).roll_frames) # 10
|
||||
print(Position.of(player).x + Position.of(1).x) # 33
|
||||
print(Hero.has(player)) # 1
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ program Containers {
|
|||
if Dict.get(bank, "gold") == 150 { print(1) }
|
||||
if Dict.get(bank, "wood") == 50 { print(2) }
|
||||
if Dict.get(bank, "stone") == 0 { print(3) } # absent -> 0
|
||||
if Dict.get_or(bank, "stone", 0 - 1) == 0 - 1 { print(4) }
|
||||
if Dict.get_or(bank, "stone", -1) == -1 { print(4) }
|
||||
if Dict.has(bank, "wood") { print(5) }
|
||||
if Dict.size(bank) == 2 { print(6) }
|
||||
Dict.remove(bank, "wood")
|
||||
|
|
@ -21,7 +21,7 @@ program Containers {
|
|||
|
||||
# grow past the initial capacity, then read back
|
||||
var i = 0
|
||||
while i < 100 { Dict.set(bank, "k" + string(i), i * 2); i = i + 1 }
|
||||
while i < 100 { Dict.set(bank, "k" + string(i), i * 2); i += 1 }
|
||||
if Dict.get(bank, "k42") == 84 { print(9) }
|
||||
if Dict.size(bank) == 101 { print(10) } # gold + k0..k99
|
||||
if len(Dict.keys(bank)) == 101 { print(11) }
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ program CoreComponents {
|
|||
# subclassing, just another property on the same model.
|
||||
property Health { hp: int = 0 }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
|
||||
entry {
|
||||
let pp = World.prop_id("Position")
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ program CoverageSpec {
|
|||
return 1
|
||||
}
|
||||
if n < 0 {
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ program CoverageSpec {
|
|||
|
||||
test "sign covers every branch" {
|
||||
expect_eq(sign(7), 1)
|
||||
expect_eq(sign(0 - 3), 0 - 1)
|
||||
expect_eq(sign(-3), -1)
|
||||
expect_eq(sign(0), 0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ program Errors {
|
|||
entry {
|
||||
print(checked_div(10, 2)) # 5
|
||||
print(clampi(15, 0, 10)) # 10 (above hi)
|
||||
print(clampi(0 - 3, 0, 10)) # 0 (below lo)
|
||||
print(clampi(-3, 0, 10)) # 0 (below lo)
|
||||
print(clampi(7, 0, 10)) # 7 (in range)
|
||||
print(1) # reached: every assertion held
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ program GameplayFoundation {
|
|||
}
|
||||
|
||||
var deaths: int = 0
|
||||
@On(Died) handler Tally { deaths = deaths + 1 }
|
||||
@On(Died) handler Tally { deaths += 1 }
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
|
||||
entry {
|
||||
|
|
@ -74,7 +74,7 @@ program GameplayFoundation {
|
|||
|
||||
# finish it off with sub-100 hits so the veto never blocks the kill
|
||||
var guard = 0
|
||||
while (World.get(t, PS, fhp) > 0) and (guard < 100) { Combat.damage(t, a, 90); guard = guard + 1 }
|
||||
while (World.get(t, PS, fhp) > 0) and (guard < 100) { Combat.damage(t, a, 90); guard += 1 }
|
||||
print(deaths) # 1
|
||||
|
||||
quit()
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@ program Grid {
|
|||
let dx = p[i].x - p[i - 1].x
|
||||
let dy = p[i].y - p[i - 1].y
|
||||
var ad = dx
|
||||
if ad < 0 { ad = 0 - ad }
|
||||
if ad < 0 { ad = -ad }
|
||||
var ay = dy
|
||||
if ay < 0 { ay = 0 - ay }
|
||||
if ay < 0 { ay = -ay }
|
||||
if ad + ay != 1 { ok = false }
|
||||
if Grid.blocked(p[i].x, p[i].y, '#') { ok = false }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if ok { print(9) }
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ program Grid {
|
|||
if len(Grid.a_star(1, 1, 3, 2, '#')) == 0 { print(10) } # (3,2) is a wall
|
||||
if Grid.blocked(3, 2, '#') { print(11) }
|
||||
if not Grid.blocked(1, 1, '#') { print(12) }
|
||||
if Grid.blocked(0 - 1, 0, '#') { print(13) } # out of bounds
|
||||
if Grid.blocked(-1, 0, '#') { print(13) } # out of bounds
|
||||
}
|
||||
|
||||
handler Run phase Update { quit() }
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ program InputAuto {
|
|||
var hits: int = 0
|
||||
|
||||
@OnStart handler Boot { Input.action("go", 'l') } # 'l' == 108
|
||||
handler Sense phase Update { if Input.active("go") { hits = hits + 1 } }
|
||||
handler Sense phase Update { if Input.active("go") { hits += 1 } }
|
||||
@OnQuit handler Report { print(hits) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ program InputEdge {
|
|||
|
||||
handler In phase Update {
|
||||
var v = 0
|
||||
if Input.key_down('k') { v = v + 1 } # held
|
||||
if Input.key_pressed('k') { v = v + 10 } # went down this frame
|
||||
if Input.key_released('k') { v = v + 100 } # went up this frame
|
||||
if Input.key_down('k') { v += 1 } # held
|
||||
if Input.key_pressed('k') { v += 10 } # went down this frame
|
||||
if Input.key_released('k') { v += 100 } # went up this frame
|
||||
print(v)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ program LightTiers {
|
|||
dark()
|
||||
Light.clear_normals()
|
||||
Light.normal(18, 30, 8, 8, 0.7, 0.0) # this patch faces right (toward the light)
|
||||
Light.normal(46, 30, 8, 8, 0.0 - 0.7, 0.0) # this patch faces left (away)
|
||||
Light.normal(46, 30, 8, 8, 0.0 - 0.7, 0.0) # this patch faces left (away)
|
||||
Light.point(32, 34, 44, 16777215, 1.0) # a light centred between the patches
|
||||
let toward = lum(22, 34) # patch facing the light
|
||||
let away = lum(48, 34) # patch facing away
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ program Numeric {
|
|||
if Huge.str(Huge.add(Huge.from(1000000000), Huge.from(1))) == "1.00e9" { print(6) } # +1 negligible
|
||||
if Huge.cmp(Huge.from(1000000000), Huge.from(1000000)) == 1 { print(7) }
|
||||
if Huge.exp(Huge.mul(Huge.from(1000000), Huge.from(1000000))) == 12 { print(8) }
|
||||
if Huge.str(Huge.from(0 - 42)) == "-4.20e1" { print(9) }
|
||||
if Huge.str(Huge.from(-42)) == "-4.20e1" { print(9) }
|
||||
if Huge.str(Huge.from(0)) == "0" { print(10) }
|
||||
|
||||
# --- Angle: wrapping radians (built on the deterministic Math.*) ---
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ program OptionResult {
|
|||
}
|
||||
# a fallible parse — a value or a message
|
||||
function to_digit(c: int) -> result {
|
||||
if c >= 48 and c <= 57 { return ok(c - 48) } # '0'..'9'
|
||||
if c >= '0' and c <= '9' { return ok(c - 48) } # '0'..'9'
|
||||
return err("not a digit")
|
||||
}
|
||||
entry {
|
||||
|
|
@ -20,20 +20,20 @@ program OptionResult {
|
|||
let a = some(42)
|
||||
if is_some(a) { print(1) }
|
||||
if not is_none(a) { print(2) }
|
||||
if unwrap_or(a, 0 - 1) == 42 { print(3) }
|
||||
if unwrap_or(a, -1) == 42 { print(3) }
|
||||
let b = none()
|
||||
if is_none(b) { print(4) }
|
||||
if unwrap_or(b, 0 - 1) == 0 - 1 { print(5) }
|
||||
if unwrap_or(b, -1) == -1 { print(5) }
|
||||
if unwrap_or(slot_of(5), 0) == 50 { print(6) }
|
||||
if is_none(slot_of(0 - 1)) { print(7) }
|
||||
if is_none(slot_of(-1)) { print(7) }
|
||||
|
||||
# --- result + try/else ---
|
||||
if is_ok(to_digit(55)) { print(8) }
|
||||
if is_err(to_digit(120)) { print(9) }
|
||||
let d = try to_digit(55) else { 0 } # '7' -> 7
|
||||
if d == 7 { print(10) }
|
||||
let bad = try to_digit(120) else { 0 - 1 } # not a digit -> fallback
|
||||
if bad == 0 - 1 { print(11) }
|
||||
let bad = try to_digit(120) else { -1 } # not a digit -> fallback
|
||||
if bad == -1 { print(11) }
|
||||
let msg = try to_digit(120) else { print(12); 0 } # else binds `error`
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ program Physics {
|
|||
hit: int = 0, entered: int = 0, exited: int = 0
|
||||
}
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
|
||||
# despawn every live entity carrying a property, so each scenario starts clean.
|
||||
|
|
@ -65,7 +65,7 @@ program Physics {
|
|||
# re-apply the run velocity each frame, the way a controller drives it from
|
||||
# held input — so hit_wall stays asserted while pressed against the wall.
|
||||
var bi2 = 0
|
||||
while bi2 < 80 { World.set(a, pb, f_vx, fixed(4)); tick_fixed(); bi2 = bi2 + 1 }
|
||||
while bi2 < 80 { World.set(a, pb, f_vx, fixed(4)); tick_fixed(); bi2 += 1 }
|
||||
print(World.get(a, pp, f_x)) # 284 — right edge stops at the wall (300)
|
||||
print(World.get(a, pb, f_hw)) # 1 — hit_wall while pressed
|
||||
print(bi(World.get(a, pb, f_vx) == 0)) # 1 — the sweep zeroed it this frame
|
||||
|
|
@ -93,7 +93,7 @@ program Physics {
|
|||
spawn Plat { Position { x: 400, y: 150 }, Collider { w: 64, h: 8, one_way: 1 } }
|
||||
spawn Runner { Position { x: 405, y: 60 }, Body { gravity: fixed(1), max_fall: fixed(6) }, Collider { w: 16, h: 16 } }
|
||||
let e1 = World.query_next(pb, 0)
|
||||
spawn Riser { Position { x: 430, y: 200 }, Body { vy: fixed(0 - 4), policy: 1 }, Collider { w: 16, h: 16 } }
|
||||
spawn Riser { Position { x: 430, y: 200 }, Body { vy: fixed(-4), policy: 1 }, Collider { w: 16, h: 16 } }
|
||||
var e2 = World.query_next(pb, 0)
|
||||
if e2 == e1 { e2 = World.query_next(pb, e1 + 1) }
|
||||
tick_n(20)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ program PhysicsTiles {
|
|||
spawn Runner { Position { x: 32, y: 16 }, Body { gravity: fixed(1), max_fall: fixed(6) }, Collider { w: 16, h: 16 } }
|
||||
var a = World.query_next(pb, 0)
|
||||
var i = 0
|
||||
while i < 80 { tick_fixed(); i = i + 1 }
|
||||
while i < 80 { tick_fixed(); i += 1 }
|
||||
print(World.get(a, pp, f_y)) # 112 — feet rest on the tile floor top (128)
|
||||
print(World.get(a, pb, f_grd)) # 1
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ program PhysicsTiles {
|
|||
spawn Runner { Position { x: 16, y: 112 }, Body { gravity: fixed(1), max_fall: fixed(6) }, Collider { w: 16, h: 16 } }
|
||||
a = World.query_next(pb, 0)
|
||||
i = 0
|
||||
while i < 60 { World.set(a, pb, f_vx, fixed(4)); tick_fixed(); i = i + 1 }
|
||||
while i < 60 { World.set(a, pb, f_vx, fixed(4)); tick_fixed(); i += 1 }
|
||||
print(World.get(a, pp, f_x)) # 80 — right edge stops at the wall column (96)
|
||||
print(World.get(a, pb, f_hw)) # 1
|
||||
|
||||
|
|
@ -67,16 +67,16 @@ program PhysicsTiles {
|
|||
spawn Runner { Position { x: 176, y: 16 }, Body { gravity: fixed(1), max_fall: fixed(6) }, Collider { w: 16, h: 16 } }
|
||||
a = World.query_next(pb, 0)
|
||||
i = 0
|
||||
while i < 40 { tick_fixed(); i = i + 1 }
|
||||
while i < 40 { tick_fixed(); i += 1 }
|
||||
print(World.get(a, pp, f_y)) # 48 — feet on the one-way top (64)
|
||||
print(World.get(a, pb, f_grd)) # 1
|
||||
|
||||
# ---- T3b. rise straight up through the one-way tile --------------------
|
||||
clear()
|
||||
spawn Riser { Position { x: 176, y: 120 }, Body { vy: fixed(0 - 4), policy: 1 }, Collider { w: 16, h: 16 } }
|
||||
spawn Riser { Position { x: 176, y: 120 }, Body { vy: fixed(-4), policy: 1 }, Collider { w: 16, h: 16 } }
|
||||
a = World.query_next(pb, 0)
|
||||
i = 0
|
||||
while i < 15 { tick_fixed(); i = i + 1 }
|
||||
while i < 15 { tick_fixed(); i += 1 }
|
||||
print(World.get(a, pp, f_y)) # 60 — passed through (120 - 4*15), above the platform
|
||||
|
||||
quit()
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ program Query {
|
|||
let near0 = Query.within(P, P, 0, 0, 0, cx, cy)
|
||||
if len(near0) == 1 { print(14) } # only e0 at (0,0)
|
||||
if World.get(near0[0], P, cx) == 0 { print(15) } # and it is e0
|
||||
if len(Query.within(G, P, 0, 0, 100, cx, cy)) == 0 { print(16) } # empty
|
||||
if len(Query.within(G, P, 0, 0, 100, cx, cy)) == 0 { print(16) } # empty
|
||||
if len(Query.within(K, P, 0, 0, 6, cx, cy)) == 2 { print(17) } # Mobs e0, e2 (filter K, pos P)
|
||||
|
||||
if World.get(Query.nearest(P, P, cx, cy, 20, 20), P, cx) == 20 { print(18) } # e4
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ program Reflect {
|
|||
let fc = Reflect.field_count(p)
|
||||
var f = 0
|
||||
while f < fc {
|
||||
total = total + Reflect.get(e, p, f)
|
||||
f = f + 1
|
||||
total += Reflect.get(e, p, f)
|
||||
f += 1
|
||||
}
|
||||
}
|
||||
p = p + 1
|
||||
p += 1
|
||||
}
|
||||
if total == 327697 { print(17) } # 7 + 10 + 131072 + 196608
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ program Regex {
|
|||
var tags = ""
|
||||
var cur = Regex.exec("#a #bb #ccc", re)
|
||||
while Regex.ok(cur) {
|
||||
tags = tags + Regex.group(cur, 1)
|
||||
tags += Regex.group(cur, 1)
|
||||
cur = Regex.next("#a #bb #ccc", re, Regex.end(cur, 0))
|
||||
}
|
||||
if tags == "abbccc" { print(16) }
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ program TestingSpec {
|
|||
|
||||
test "loops and locals work in a test" {
|
||||
var sum = 0
|
||||
for i in 0 .. 5 { sum = sum + i } # 0+1+2+3+4 = 10
|
||||
for i in 0 .. 5 { sum += i } # 0+1+2+3+4 = 10
|
||||
expect_eq(sum, 10)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ program TiledP05 {
|
|||
# --- four layers, every encoding decodes to the SAME 16-GID array ---
|
||||
let layers = Value.get(m, "layers")
|
||||
if Value.count(layers) == 4 { print(8) }
|
||||
let FLIP = 0 - 2147483647 # 0x80000001 as i32
|
||||
let FLIP = -2147483647 # 0x80000001 as i32
|
||||
var same = 1
|
||||
var li = 0
|
||||
while li < 4 {
|
||||
|
|
@ -35,7 +35,7 @@ program TiledP05 {
|
|||
if Value.as_int(Value.at(data, 0)) != 1 { same = 0 }
|
||||
if Value.as_int(Value.at(data, 14)) != 15 { same = 0 }
|
||||
if Value.as_int(Value.at(data, 15)) != FLIP { same = 0 }
|
||||
li = li + 1
|
||||
li += 1
|
||||
}
|
||||
if same == 1 { print(9) }
|
||||
# the CSV path and the gzip path agree on the flip-flagged GID
|
||||
|
|
@ -61,9 +61,9 @@ program TiledP05 {
|
|||
var gi = 0
|
||||
while gi < 16 {
|
||||
if Value.as_int(Value.at(jdata, gi)) != Value.as_int(Value.at(csvdata, gi)) { jsame = 0 }
|
||||
gi = gi + 1
|
||||
gi += 1
|
||||
}
|
||||
jli = jli + 1
|
||||
jli += 1
|
||||
}
|
||||
if jsame == 1 { print(16) }
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ program TiledP1 {
|
|||
var x = 0
|
||||
while x < 320 {
|
||||
h = h * 31 + rt_get_px(x, y)
|
||||
x = x + 4
|
||||
x += 4
|
||||
}
|
||||
y = y + 4
|
||||
y += 4
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ program TiledP1 {
|
|||
|
||||
# --- flips draw with the correct orientation ---
|
||||
# find a horizontally-asymmetric tile so the mirror test is meaningful
|
||||
var chosen = 0 - 1
|
||||
var chosen = -1
|
||||
var t = 0
|
||||
while t < 132 {
|
||||
rt_clear(0)
|
||||
|
|
@ -67,12 +67,12 @@ program TiledP1 {
|
|||
var xx = 0
|
||||
while xx < 8 {
|
||||
if rt_get_px(xx, yy) != rt_get_px(15 - xx, yy) { asym = 1 }
|
||||
xx = xx + 1
|
||||
xx += 1
|
||||
}
|
||||
yy = yy + 1
|
||||
yy += 1
|
||||
}
|
||||
if asym == 1 and chosen < 0 { chosen = t }
|
||||
t = t + 1
|
||||
t += 1
|
||||
}
|
||||
if chosen >= 0 { print(12) }
|
||||
|
||||
|
|
@ -88,9 +88,9 @@ program TiledP1 {
|
|||
while xx2 < 16 {
|
||||
if rt_get_px(xx2, yy2) != rt_get_px(31 - xx2, yy2) { mirror = 0 } # H-flip mirrors
|
||||
if rt_get_px(xx2, yy2) != rt_get_px(15 - xx2, yy2) { diff = 1 } # the tile isn't symmetric
|
||||
xx2 = xx2 + 1
|
||||
xx2 += 1
|
||||
}
|
||||
yy2 = yy2 + 1
|
||||
yy2 += 1
|
||||
}
|
||||
if mirror == 1 { print(13) }
|
||||
if diff == 1 { print(14) }
|
||||
|
|
|
|||
|
|
@ -23,16 +23,16 @@ program TiledP2 {
|
|||
var n = 0
|
||||
var y = 0
|
||||
while y < 10 { var x = 0
|
||||
while x < 16 { if rt_tile(x, y) == 35 { n = n + 1 }; x = x + 1 }
|
||||
y = y + 1 }
|
||||
while x < 16 { if rt_tile(x, y) == 35 { n += 1 }; x += 1 }
|
||||
y += 1 }
|
||||
return n
|
||||
}
|
||||
function grid_hash() -> int {
|
||||
var h = 0
|
||||
var y = 0
|
||||
while y < 10 { var x = 0
|
||||
while x < 16 { h = h * 31 + rt_tile(x, y); x = x + 1 }
|
||||
y = y + 1 }
|
||||
while x < 16 { h = h * 31 + rt_tile(x, y); x += 1 }
|
||||
y += 1 }
|
||||
return h
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ program TiledP2 {
|
|||
let f_grd = World.field_id(pb, "on_ground")
|
||||
let a = World.query_next(pb, 0)
|
||||
var i = 0
|
||||
while i < 80 { tick_fixed(); i = i + 1 }
|
||||
while i < 80 { tick_fixed(); i += 1 }
|
||||
if World.get(a, pp, f_y) == 112 { print(13) } # feet rest on the tile floor top (128)
|
||||
if World.get(a, pb, f_grd) == 1 { print(14) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ program TiledP3 {
|
|||
var h = 0
|
||||
var y = 0
|
||||
while y < 64 { var x = 0
|
||||
while x < 64 { h = h * 31 + rt_get_px(x, y); x = x + 2 }
|
||||
y = y + 2 }
|
||||
while x < 64 { h = h * 31 + rt_get_px(x, y); x += 2 }
|
||||
y += 2 }
|
||||
return h
|
||||
}
|
||||
|
||||
|
|
@ -38,13 +38,13 @@ program TiledP3 {
|
|||
|
||||
# --- tile object parsed from the object layer ---
|
||||
let tree = Tiled.tree(m)
|
||||
var oglayer = Value.null()
|
||||
var oglayer = Value.null ()
|
||||
let layers = Value.get(tree, "layers")
|
||||
var li = 0
|
||||
while li < Value.count(layers) {
|
||||
let L = Value.at(layers, li)
|
||||
if Value.as_str(Value.get(L, "type")) == "objectgroup" { oglayer = L }
|
||||
li = li + 1
|
||||
li += 1
|
||||
}
|
||||
let objs = Value.get(oglayer, "objects")
|
||||
if Value.count(objs) == 1 { print(8) }
|
||||
|
|
@ -62,7 +62,7 @@ program TiledP3 {
|
|||
|
||||
# --- tile objects draw with correct GID flips (mirror test) ---
|
||||
# find an asymmetric tile, draw it normal vs H-flipped as a tile object
|
||||
var chosen = 0 - 1
|
||||
var chosen = -1
|
||||
var t = 0
|
||||
while t < 132 {
|
||||
rt_clear(0)
|
||||
|
|
@ -70,10 +70,10 @@ program TiledP3 {
|
|||
var asym = 0
|
||||
var yy = 0
|
||||
while yy < 16 { var xx = 0
|
||||
while xx < 8 { if rt_get_px(xx, yy) != rt_get_px(15 - xx, yy) { asym = 1 }; xx = xx + 1 }
|
||||
yy = yy + 1 }
|
||||
while xx < 8 { if rt_get_px(xx, yy) != rt_get_px(15 - xx, yy) { asym = 1 }; xx += 1 }
|
||||
yy += 1 }
|
||||
if asym == 1 and chosen < 0 { chosen = t }
|
||||
t = t + 1
|
||||
t += 1
|
||||
}
|
||||
rt_clear(0)
|
||||
tmap_draw_gid(m, 1 + chosen, 0, 0)
|
||||
|
|
@ -81,8 +81,8 @@ program TiledP3 {
|
|||
var mirror = 1
|
||||
var yy2 = 0
|
||||
while yy2 < 16 { var xx2 = 0
|
||||
while xx2 < 16 { if rt_get_px(xx2, yy2) != rt_get_px(31 - xx2, yy2) { mirror = 0 }; xx2 = xx2 + 1 }
|
||||
yy2 = yy2 + 1 }
|
||||
while xx2 < 16 { if rt_get_px(xx2, yy2) != rt_get_px(31 - xx2, yy2) { mirror = 0 }; xx2 += 1 }
|
||||
yy2 += 1 }
|
||||
if mirror == 1 and chosen >= 0 { print(12) }
|
||||
|
||||
# --- the design's named fixture: rpg/beach_tileset.tsx (33 animations) ---
|
||||
|
|
@ -94,8 +94,8 @@ program TiledP3 {
|
|||
while ti < Value.count(tiles) {
|
||||
let tt = Value.at(tiles, ti)
|
||||
let an = Value.get(tt, "animation")
|
||||
if Value.count(an) > 0 { nanim = nanim + 1; nframes = nframes + Value.count(an) }
|
||||
ti = ti + 1
|
||||
if Value.count(an) > 0 { nanim += 1; nframes += Value.count(an) }
|
||||
ti += 1
|
||||
}
|
||||
if nanim == 33 { print(13) }
|
||||
if nframes == 131 { print(14) }
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@ program TiledP4 {
|
|||
|
||||
# --- the design's named fixture: orthogonal-outside.tmx object shapes ---
|
||||
let og = Tiled.load("assets/tiled-fixtures/orthogonal-outside.tmx")
|
||||
var olayer = 0 - 1
|
||||
var olayer = -1
|
||||
var oli = 0
|
||||
while oli < Tiled.layer_count(og) {
|
||||
if Tiled.object_count(og, oli) > 0 { olayer = oli }
|
||||
oli = oli + 1
|
||||
oli += 1
|
||||
}
|
||||
var nell = 0
|
||||
var npt = 0
|
||||
|
|
@ -64,11 +64,11 @@ program TiledP4 {
|
|||
var oi = 0
|
||||
while oi < Tiled.object_count(og, olayer) {
|
||||
let sh = Tiled.object_shape(Tiled.object(og, olayer, oi))
|
||||
if sh == "ellipse" { nell = nell + 1 }
|
||||
if sh == "point" { npt = npt + 1 }
|
||||
if sh == "polygon" { npg = npg + 1 }
|
||||
if sh == "polyline" { npl = npl + 1 }
|
||||
oi = oi + 1
|
||||
if sh == "ellipse" { nell += 1 }
|
||||
if sh == "point" { npt += 1 }
|
||||
if sh == "polygon" { npg += 1 }
|
||||
if sh == "polyline" { npl += 1 }
|
||||
oi += 1
|
||||
}
|
||||
if nell == 1 and npt == 1 and npg == 1 { print(17) }
|
||||
if npl == 2 { print(18) }
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ program TiledP5 {
|
|||
let iso = Tiled.load("assets/tiled-fixtures/isometric_grass_and_water.tmx")
|
||||
if Value.as_str(Value.get(Tiled.tree(iso), "orientation")) == "isometric" { print(1) }
|
||||
if Tiled.cell_x(iso, 1, 0) == 32 { print(2) } # (1-0)*64/2
|
||||
if Tiled.cell_x(iso, 0, 1) == 0 - 32 { print(3) } # (0-1)*64/2
|
||||
if Tiled.cell_x(iso, 0, 1) == -32 { print(3) } # (0-1)*64/2
|
||||
if Tiled.cell_y(iso, 1, 1) == 32 { print(4) } # (1+1)*32/2
|
||||
if Tiled.cell_y(iso, 2, 0) == 32 { print(5) } # (2+0)*32/2
|
||||
|
||||
|
|
@ -23,8 +23,8 @@ program TiledP5 {
|
|||
var cy = 0
|
||||
while cy < Tiled.height(iso) and g == 0 {
|
||||
var cx = 0
|
||||
while cx < Tiled.width(iso) and g == 0 { g = Tiled.gid(iso, 0, cx, cy); cx = cx + 1 }
|
||||
cy = cy + 1
|
||||
while cx < Tiled.width(iso) and g == 0 { g = Tiled.gid(iso, 0, cx, cy); cx += 1 }
|
||||
cy += 1
|
||||
}
|
||||
let r = Tiled.resolve(iso, g)
|
||||
if r.tileset == 0 and r.local >= 0 { print(6) }
|
||||
|
|
@ -48,8 +48,8 @@ program TiledP5 {
|
|||
var yy = 0
|
||||
while yy < 32 and painted == 0 {
|
||||
var xx = 0
|
||||
while xx < 32 and painted == 0 { if rt_get_px(xx, yy) != 0 { painted = 1 }; xx = xx + 1 }
|
||||
yy = yy + 1
|
||||
while xx < 32 and painted == 0 { if rt_get_px(xx, yy) != 0 { painted = 1 }; xx += 1 }
|
||||
yy += 1
|
||||
}
|
||||
if painted == 1 { print(14) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ program TiledP6 {
|
|||
var i = 0
|
||||
while i < Value.count(csv) {
|
||||
if Value.as_int(Value.at(csv, i)) != Value.as_int(Value.at(zstd, i)) { same = 0 }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if same == 1 { print(12) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
program WorldBounds {
|
||||
import "ludic.core/components.ludic"
|
||||
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i = i + 1 } }
|
||||
function tick_n(n: int) -> void { var i = 0; while i < n { tick_fixed(); i += 1 } }
|
||||
function bi(b: bool) -> int { if b { return 1 }; return 0 }
|
||||
|
||||
function clear_all() -> void {
|
||||
|
|
@ -57,7 +57,7 @@ program WorldBounds {
|
|||
tick_n(1)
|
||||
var live = 0
|
||||
var q = World.query_next(PBody, 0)
|
||||
while q >= 0 { live = live + 1; q = World.query_next(PBody, q + 1) }
|
||||
while q >= 0 { live += 1; q = World.query_next(PBody, q + 1) }
|
||||
print(live) # 0 — the out-of-bounds body was killed
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ program NetDemo {
|
|||
|
||||
@ToServer event Move { dx: int = 0 } # client → server RPC
|
||||
@On(Move) handler DoMove { # the authority applies input
|
||||
for (Pos) in query [Pos, {Ship}] { Pos.x = Pos.x + dx }
|
||||
for (Pos) in query [Pos, {Ship}] { Pos.x += dx }
|
||||
}
|
||||
|
||||
entry {
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@
|
|||
program NetEcho {
|
||||
entry {
|
||||
let out = bytes(4)
|
||||
out[0] = 10
|
||||
out[0] = '\n'
|
||||
out[1] = 20
|
||||
out[2] = 30
|
||||
out[3] = 42
|
||||
out[3] = '*'
|
||||
net_send(0, out, 4) # onto the wire (the built-in loopback)
|
||||
|
||||
let inb = bytes(64)
|
||||
let n = net_poll(inb, 64) # take the next datagram back off
|
||||
print(n) # 4
|
||||
var i = 0
|
||||
while i < n { print(inb[i]); i = i + 1 } # 10 20 30 42
|
||||
while i < n { print(inb[i]); i += 1 } # 10 20 30 42
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ program NetRoles {
|
|||
property Score { n: int = 0 }
|
||||
model Board { Score }
|
||||
|
||||
handler Both phase Update { for (Score) in query [Score] { Score.n = Score.n + 1 } } # runs everywhere
|
||||
@Server handler ServerOnly phase Update { for (Score) in query [Score] { Score.n = Score.n + 100 } } # authority only
|
||||
handler Both phase Update { for (Score) in query [Score] { Score.n += 1 } } # runs everywhere
|
||||
@Server handler ServerOnly phase Update { for (Score) in query [Score] { Score.n += 100 } } # authority only
|
||||
|
||||
entry {
|
||||
spawn Board { Score { n: 0 } }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ program NetRpc {
|
|||
|
||||
@ToServer event Fire { dir: int = 0 }
|
||||
@On(Fire) handler OnFire {
|
||||
for (Log) in query [Log] { Log.hits = Log.hits + dir }
|
||||
for (Log) in query [Log] { Log.hits += dir }
|
||||
}
|
||||
|
||||
entry {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ var combat_pending: int = 0
|
|||
# the attacker's build: damage_pct, then a crit_pct chance to double
|
||||
var raw = amount * stats_field(src, "damage_pct", 100) / 100
|
||||
let crit = stats_field(src, "crit_pct", 0)
|
||||
if (crit > 0) and Random.chance(percent: crit) { raw = raw * 2; emit Crit(target: target, src: src) }
|
||||
if (crit > 0) and Random.chance(percent: crit) { raw *= 2; emit Crit(target: target, src: src) }
|
||||
combat_pending = combat_mitigate(target, raw)
|
||||
if emit DamageAboutToApply(target: target, src: src, amount: combat_pending) != 0 { return 0 }
|
||||
var dmg = combat_pending
|
||||
|
|
|
|||
|
|
@ -55,10 +55,10 @@ function fac_ensure() -> void {
|
|||
# Faction.id_of(e) — the faction id an entity carries (-1 if it has no Faction).
|
||||
@Namespace(Faction) function faction_id_of(e: int) -> int {
|
||||
let P = World.prop_id("Faction")
|
||||
if P < 0 { return 0 - 1 }
|
||||
if World.has(e, P) == 0 { return 0 - 1 }
|
||||
if P < 0 { return -1 }
|
||||
if World.has(e, P) == 0 { return -1 }
|
||||
let f = World.field_id(P, "id")
|
||||
if f < 0 { return 0 - 1 }
|
||||
if f < 0 { return -1 }
|
||||
return World.get(e, P, f)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,21 +89,11 @@ model ModifierFx { Modifier }
|
|||
}
|
||||
}
|
||||
|
||||
# map a stat code to the matching Stats field name.
|
||||
function stat_field(stat: int) -> pointer {
|
||||
if stat == 0 { return "max_hp" }
|
||||
if stat == 1 { return "atk" }
|
||||
if stat == 2 { return "def" }
|
||||
if stat == 3 { return "spd" }
|
||||
if stat == 4 { return "max_mp" }
|
||||
return "atk"
|
||||
}
|
||||
|
||||
# Stats.base(e, stat) — the raw stored field, no modifiers.
|
||||
@Namespace(Stats) function stats_base(e: int, stat: int) -> int {
|
||||
let P = World.prop_id("Stats")
|
||||
if P < 0 { return 0 }
|
||||
let f = World.field_id(P, stat_field(stat))
|
||||
let f = World.field_id(P, stats_field_name(stat))
|
||||
if f < 0 { return 0 }
|
||||
return World.get(e, P, f)
|
||||
}
|
||||
|
|
@ -123,7 +113,7 @@ function stat_field(stat: int) -> pointer {
|
|||
while m >= 0 {
|
||||
if (World.get(m, P, ft) == e) and (World.get(m, P, fs) == stat) {
|
||||
let amt = World.get(m, P, fa)
|
||||
if World.get(m, P, fo) == 1 { pct = pct + amt } else { flat = flat + amt }
|
||||
if World.get(m, P, fo) == 1 { pct += amt } else { flat += amt }
|
||||
}
|
||||
m = World.query_next(P, m + 1)
|
||||
}
|
||||
|
|
@ -133,7 +123,7 @@ function stat_field(stat: int) -> pointer {
|
|||
# Stats.modify(target, stat, op, amount, ttl) — push a modifier onto the stack.
|
||||
@Namespace(Stats) function stats_modify(target: int, stat: int, op: int, amount: int, ttl: int) -> int {
|
||||
let m = World.model_id("ModifierFx")
|
||||
if m < 0 { return 0 - 1 }
|
||||
if m < 0 { return -1 }
|
||||
let e = World.spawn(m)
|
||||
let P = World.prop_id("Modifier")
|
||||
World.set(e, P, World.field_id(P, "target"), target)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ property Brain {
|
|||
home_x: int = 0, home_y: int = 0, seed: int = 1,
|
||||
hunt_blind: int = 0 # 1 = with no target in sight, seek the nearest hostile anyway (no idle patrol)
|
||||
}
|
||||
property Follower { leader: int = 0 - 1, distance: int = 40, mode: int = 0 } # mode 0 follow,1 guard,2 aggressive
|
||||
property Follower { leader: int = -1, distance: int = 40, mode: int = 0 } # mode 0 follow,1 guard,2 aggressive
|
||||
property Steering { separate: int = 0, cohere: int = 0, align: int = 0, radius: int = 48 }
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -59,7 +59,7 @@ function ai_has(prop: pointer, e: int) -> int {
|
|||
let P = World.prop_id(prop); if P < 0 { return 0 }
|
||||
return World.has(e, P)
|
||||
}
|
||||
function sign_i(a: int) -> int { if a > 0 { return 1 }; if a < 0 { return 0 - 1 }; return 0 }
|
||||
function sign_i(a: int) -> int { if a > 0 { return 1 }; if a < 0 { return -1 }; return 0 }
|
||||
|
||||
# optional line-of-sight over the tilemap (only when a Solids config exists);
|
||||
# without a tilemap the field is open, so LOS is always clear.
|
||||
|
|
@ -104,7 +104,7 @@ function ai_los(px: int, py: int, tx: int, ty: int) -> int {
|
|||
let fac = Faction.id_of(e)
|
||||
# nearest hostile in range + LOS
|
||||
let PF = World.prop_id("Faction")
|
||||
var best = 0 - 1
|
||||
var best = -1
|
||||
var bestd = 0
|
||||
var o = World.query_next(PF, 0)
|
||||
while o >= 0 {
|
||||
|
|
@ -196,8 +196,8 @@ function brain_seek(e: int, tx: int, ty: int) -> void {
|
|||
function brain_flee(e: int, tx: int, ty: int) -> void {
|
||||
let px = ai_get("Position", e, "x")
|
||||
let py = ai_get("Position", e, "y")
|
||||
ai_set("Brain", e, "intent_x", 0 - sign_i(tx - px))
|
||||
ai_set("Brain", e, "intent_y", 0 - sign_i(ty - py))
|
||||
ai_set("Brain", e, "intent_x", -sign_i(tx - px))
|
||||
ai_set("Brain", e, "intent_y", -sign_i(ty - py))
|
||||
}
|
||||
function brain_stop(e: int) -> void { ai_set("Brain", e, "intent_x", 0); ai_set("Brain", e, "intent_y", 0) }
|
||||
|
||||
|
|
@ -257,20 +257,20 @@ function ai_decide_fsm(e: int) -> void {
|
|||
let tx = ai_get("Memory", e, "last_x")
|
||||
let ty = ai_get("Memory", e, "last_y")
|
||||
if brain_low_hp(e, ai_get("Brain", e, "flee_pct")) == 1 {
|
||||
if emit DecisionMade(e: e, action: 3) == 0 { brain_set_state(e, 3); brain_flee(e, tx, ty) }
|
||||
if emit DecisionMade(e: e, action: AiState.Flee) == 0 { brain_set_state(e, AiState.Flee); brain_flee(e, tx, ty) }
|
||||
} else {
|
||||
if d2 <= ar * ar {
|
||||
if emit DecisionMade(e: e, action: 2) == 0 { brain_set_state(e, 2); brain_stop(e); ai_set("Brain", e, "want_fire", 1) }
|
||||
if emit DecisionMade(e: e, action: AiState.Attack) == 0 { brain_set_state(e, AiState.Attack); brain_stop(e); ai_set("Brain", e, "want_fire", 1) }
|
||||
} else {
|
||||
if emit DecisionMade(e: e, action: 1) == 0 { brain_set_state(e, 1); brain_seek(e, tx, ty) }
|
||||
if emit DecisionMade(e: e, action: AiState.Chase) == 0 { brain_set_state(e, AiState.Chase); brain_seek(e, tx, ty) }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let prey = brain_nearest_hostile(e)
|
||||
if (ai_get("Brain", e, "hunt_blind") == 1) and (prey >= 0) {
|
||||
if emit DecisionMade(e: e, action: 1) == 0 { brain_set_state(e, 1); brain_seek(e, ai_get("Position", prey, "x"), ai_get("Position", prey, "y")) }
|
||||
if emit DecisionMade(e: e, action: AiState.Chase) == 0 { brain_set_state(e, AiState.Chase); brain_seek(e, ai_get("Position", prey, "x"), ai_get("Position", prey, "y")) }
|
||||
} else {
|
||||
if emit DecisionMade(e: e, action: 0) == 0 { brain_set_state(e, 0); brain_wander(e) }
|
||||
if emit DecisionMade(e: e, action: AiState.Patrol) == 0 { brain_set_state(e, AiState.Patrol); brain_wander(e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -278,11 +278,11 @@ function ai_decide_fsm(e: int) -> void {
|
|||
function brain_nearest_hostile(e: int) -> int {
|
||||
let PF = World.prop_id("Faction")
|
||||
let PP = World.prop_id("Position")
|
||||
if (PF < 0) or (PP < 0) { return 0 - 1 }
|
||||
if (PF < 0) or (PP < 0) { return -1 }
|
||||
let fac = Faction.id_of(e)
|
||||
let px = ai_get("Position", e, "x")
|
||||
let py = ai_get("Position", e, "y")
|
||||
var best = 0 - 1
|
||||
var best = -1
|
||||
var bestd = 0
|
||||
var o = World.query_next(PF, 0)
|
||||
while o >= 0 {
|
||||
|
|
@ -338,11 +338,11 @@ function ai_decide_bt(e: int) -> void {
|
|||
let ar = ai_get("Brain", e, "attack_range")
|
||||
if ai_get("Memory", e, "has_target") == 1 { # leaf: see_target
|
||||
if brain_target_d2(e) <= ar * ar { # leaf: in_range
|
||||
if emit DecisionMade(e: e, action: 2) == 0 { brain_set_state(e, 2); brain_stop(e); ai_set("Brain", e, "want_fire", 1); return }
|
||||
if emit DecisionMade(e: e, action: AiState.Attack) == 0 { brain_set_state(e, AiState.Attack); brain_stop(e); ai_set("Brain", e, "want_fire", 1); return }
|
||||
}
|
||||
if emit DecisionMade(e: e, action: 1) == 0 { brain_set_state(e, 1); brain_seek(e, tx, ty); return }
|
||||
if emit DecisionMade(e: e, action: AiState.Chase) == 0 { brain_set_state(e, AiState.Chase); brain_seek(e, tx, ty); return }
|
||||
}
|
||||
if emit DecisionMade(e: e, action: 0) == 0 { brain_set_state(e, 0); brain_wander(e) }
|
||||
if emit DecisionMade(e: e, action: AiState.Patrol) == 0 { brain_set_state(e, AiState.Patrol); brain_wander(e) }
|
||||
}
|
||||
|
||||
# ===========================================================================
|
||||
|
|
@ -404,8 +404,8 @@ function ai_decide_bt(e: int) -> void {
|
|||
let dx = ox - px; let dy = oy - py
|
||||
let d2 = dx * dx + dy * dy
|
||||
if d2 <= radius * radius {
|
||||
sepx = sepx - sign_i(dx); sepy = sepy - sign_i(dy)
|
||||
cx = cx + ox; cy = cy + oy; n = n + 1
|
||||
sepx -= sign_i(dx); sepy -= sign_i(dy)
|
||||
cx += ox; cy += oy; n += 1
|
||||
}
|
||||
}
|
||||
o = World.query_next(PS, o + 1)
|
||||
|
|
@ -413,8 +413,8 @@ function ai_decide_bt(e: int) -> void {
|
|||
if n > 0 {
|
||||
var ix = ai_get("Brain", e, "intent_x")
|
||||
var iy = ai_get("Brain", e, "intent_y")
|
||||
if wsep > 0 { ix = ix + sign_i(sepx); iy = iy + sign_i(sepy) }
|
||||
if wcoh > 0 { ix = ix + sign_i(cx / n - px); iy = iy + sign_i(cy / n - py) }
|
||||
if wsep > 0 { ix += sign_i(sepx); iy += sign_i(sepy) }
|
||||
if wcoh > 0 { ix += sign_i(cx / n - px); iy += sign_i(cy / n - py) }
|
||||
ai_set("Brain", e, "intent_x", sign_i(ix))
|
||||
ai_set("Brain", e, "intent_y", sign_i(iy))
|
||||
}
|
||||
|
|
@ -457,7 +457,7 @@ function ai_decide_bt(e: int) -> void {
|
|||
@Namespace(Ai) function ai_state(e: int) -> int { return ai_get("Brain", e, "state") }
|
||||
@Namespace(Ai) function ai_target(e: int) -> int {
|
||||
if ai_get("Memory", e, "has_target") == 1 { return ai_get("Memory", e, "target") }
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
@Namespace(Follower) function follower_set(e: int, leader: int, distance: int, mode: int) -> void {
|
||||
ai_set("Follower", e, "leader", leader)
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ property Platformer {
|
|||
friction: int = 50, # ground stopping, % of speed shed / frame when idle
|
||||
jump_height: int = 4, # tiles; gravity + impulse are derived from this + apex
|
||||
apex_frames: int = 14, # frames to the top of the jump (defines gravity — feel)
|
||||
fall_gravity_mul: int = 160, # 100 = symmetric; >100 = snappier fall (Celeste)
|
||||
fall_gravity_mul: int = 160, # 100 = symmetric; >100 = snappier fall (Celeste)
|
||||
coyote_frames: int = 6, # grace frames to still jump after leaving a ledge
|
||||
jump_buffer_frames: int = 6, # grace frames to buffer a jump pressed before landing
|
||||
jump_buffer_frames: int = 6, # grace frames to buffer a jump pressed before landing
|
||||
max_fall: int = 8, # terminal fall speed, px/frame
|
||||
air_jumps: int = 0, # extra mid-air jumps (1 = double jump, N = multi)
|
||||
policy: int = 0, # gravity profile (lever 6): 0 asymmetric, 1 symmetric, 2 floaty
|
||||
|
|
@ -129,8 +129,8 @@ function bd_set(e: int, name: pointer, v: int) -> void {
|
|||
var e = World.query_next(P, 0)
|
||||
while e >= 0 {
|
||||
var wx = 0
|
||||
if Input.down("move_right") { wx = wx + 1 }
|
||||
if Input.down("move_left") { wx = wx - 1 }
|
||||
if Input.down("move_right") { wx += 1 }
|
||||
if Input.down("move_left") { wx -= 1 }
|
||||
pf_set(e, "want_x", wx)
|
||||
var wj = 0; if Input.pressed("jump") { wj = 1 }
|
||||
pf_set(e, "want_jump", wj)
|
||||
|
|
@ -185,14 +185,14 @@ function bd_set(e: int, name: pointer, v: int) -> void {
|
|||
let apex = pf_get(e, "apex_frames")
|
||||
var g = plat_g(jh, apex, tile)
|
||||
let pol = pf_get(e, "policy")
|
||||
if pol == 2 { g = g / 2 } # floaty
|
||||
if pol == 2 { g /= 2 } # floaty
|
||||
let vy = bd_get(e, "vy")
|
||||
if vy > 0 { # falling
|
||||
var fm = pf_get(e, "fall_gravity_mul")
|
||||
if pol == 1 { fm = 100 } # symmetric profile ignores the fall multiplier
|
||||
g = g * fm / 100
|
||||
} else {
|
||||
if pf_get(e, "hold_jump") == 0 { g = g * 2 } # released while rising -> short hop
|
||||
if pf_get(e, "hold_jump") == 0 { g *= 2 } # released while rising -> short hop
|
||||
}
|
||||
bd_set(e, "gravity", g)
|
||||
bd_set(e, "max_fall", pf_get(e, "max_fall") * PLAT_Q)
|
||||
|
|
@ -205,7 +205,7 @@ function plat_do_jump(e: int, kind: int) -> bool {
|
|||
if emit JumpRequested(e: e, kind: kind) != 0 { return false }
|
||||
let tile = plat_tile()
|
||||
let v0 = plat_v0(pf_get(e, "jump_height"), pf_get(e, "apex_frames"), tile)
|
||||
bd_set(e, "vy", 0 - v0)
|
||||
bd_set(e, "vy", -v0)
|
||||
pf_set(e, "buffer_t", 0)
|
||||
pf_set(e, "coyote_t", 0)
|
||||
emit JumpPerformed(e: e, kind: kind)
|
||||
|
|
@ -280,7 +280,7 @@ function plat_do_jump(e: int, kind: int) -> bool {
|
|||
# state
|
||||
var st = 0
|
||||
if grounded == 1 {
|
||||
var ax = vx; if ax < 0 { ax = 0 - ax }
|
||||
var ax = vx; if ax < 0 { ax = -ax }
|
||||
if ax > (PLAT_Q / 4) { st = 1 } else { st = 0 } # running vs idle (>0.25 px/frame)
|
||||
} else {
|
||||
if vy < 0 { st = 2 } else { st = 3 } # rise vs fall
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ event PlatformCrumbled { e: int = 0 }
|
|||
# platform's top edge within the horizontal span.
|
||||
function plat_rider_on(p: int) -> int {
|
||||
let PB = World.prop_id("Body")
|
||||
if PB < 0 { return 0 - 1 }
|
||||
if PB < 0 { return -1 }
|
||||
let px = sc_pos(p, "x") + sc_col(p, "offx")
|
||||
let py = sc_pos(p, "y") + sc_col(p, "offy")
|
||||
let pw = sc_col(p, "w")
|
||||
|
|
@ -79,7 +79,7 @@ function plat_rider_on(p: int) -> int {
|
|||
}
|
||||
b = World.query_next(PB, b + 1)
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
@EngineSystem(Platform, FixedUpdate) function esys_platform() -> void {
|
||||
|
|
@ -103,8 +103,8 @@ function plat_rider_on(p: int) -> int {
|
|||
var tx = bx; var ty = by
|
||||
if dir < 0 { tx = ax; ty = ay }
|
||||
var dx = 0; var dy = 0
|
||||
if ox < tx { dx = speed } else { if ox > tx { dx = 0 - speed } }
|
||||
if oy < ty { dy = speed } else { if oy > ty { dy = 0 - speed } }
|
||||
if ox < tx { dx = speed } else { if ox > tx { dx = -speed } }
|
||||
if oy < ty { dy = speed } else { if oy > ty { dy = -speed } }
|
||||
# clamp the step so we do not overshoot the endpoint
|
||||
if dx > 0 { if ox + dx > tx { dx = tx - ox } }
|
||||
if dx < 0 { if ox + dx < tx { dx = tx - ox } }
|
||||
|
|
@ -120,7 +120,7 @@ function plat_rider_on(p: int) -> int {
|
|||
}
|
||||
# flip direction at an endpoint
|
||||
if (sc_pos(e, "x") == tx) and (sc_pos(e, "y") == ty) {
|
||||
World.set(e, P, World.field_id(P, "dir"), 0 - dir)
|
||||
World.set(e, P, World.field_id(P, "dir"), -dir)
|
||||
}
|
||||
}
|
||||
if kind == 3 { # crumble
|
||||
|
|
@ -222,7 +222,7 @@ event Sprang { body: int = 0, spring: int = 0, power: int = 0 }
|
|||
let body = World.get(e, PC, fhit)
|
||||
if body >= 0 {
|
||||
let power = World.get(e, P, fpow)
|
||||
sc_body_set(body, "vy", 0 - power * SCAF_Q)
|
||||
sc_body_set(body, "vy", -power * SCAF_Q)
|
||||
sc_body_set(body, "ry", 0)
|
||||
emit Sprang(body: body, spring: e, power: power)
|
||||
}
|
||||
|
|
@ -269,7 +269,7 @@ property Hazard { dmg: int = 1, knockback: int = 6 }
|
|||
let dmg = World.get(e, P, fdmg)
|
||||
if life_hurt(body, e, dmg) > 0 {
|
||||
let kb = World.get(e, P, fkb)
|
||||
sc_body_set(body, "vy", 0 - kb * SCAF_Q) # pop up on hit
|
||||
sc_body_set(body, "vy", -kb * SCAF_Q) # pop up on hit
|
||||
}
|
||||
}
|
||||
e = World.query_next(P, e + 1)
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ namespace Prefs {
|
|||
|
||||
internal function find(key: pointer) -> int {
|
||||
var i = 0
|
||||
while i < prefs_n { if prefs_names[i] == key { return i }; i = i + 1 }
|
||||
return 0 - 1
|
||||
while i < prefs_n { if prefs_names[i] == key { return i }; i += 1 }
|
||||
return -1
|
||||
}
|
||||
|
||||
export function get(key: pointer, fallback: int) -> int {
|
||||
|
|
@ -49,7 +49,7 @@ namespace Prefs {
|
|||
if prefs_n >= PREFS_MAX { return }
|
||||
i = prefs_n
|
||||
prefs_names[i] = key
|
||||
prefs_n = prefs_n + 1
|
||||
prefs_n += 1
|
||||
}
|
||||
prefs_vals[i] = value
|
||||
}
|
||||
|
|
@ -71,18 +71,18 @@ namespace Prefs {
|
|||
# digits after `=` on one line -> an int (a leading '-' negates)
|
||||
internal function parse_line(buf: pointer, from: int, to: int) -> void {
|
||||
var eq = from
|
||||
while (eq < to) and (buf[eq] != 61) { eq = eq + 1 } # '='
|
||||
while (eq < to) and (buf[eq] != '=') { eq += 1 } # '='
|
||||
if eq >= to { return }
|
||||
let key = bytes(eq - from + 1)
|
||||
var k = 0
|
||||
while k < eq - from { key[k] = buf[from + k]; k = k + 1 }
|
||||
while k < eq - from { key[k] = buf[from + k]; k += 1 }
|
||||
key[eq - from] = 0
|
||||
var v = 0
|
||||
var neg = false
|
||||
var p = eq + 1
|
||||
if (p < to) and (buf[p] == 45) { neg = true; p = p + 1 } # '-'
|
||||
while (p < to) and (buf[p] >= 48) and (buf[p] <= 57) { v = v * 10 + (buf[p] - 48); p = p + 1 }
|
||||
if neg { v = 0 - v }
|
||||
if (p < to) and (buf[p] == '-') { neg = true; p += 1 } # '-'
|
||||
while (p < to) and (buf[p] >= '0') and (buf[p] <= '9') { v = v * 10 + (buf[p] - 48); p += 1 }
|
||||
if neg { v = -v }
|
||||
set(key, v)
|
||||
}
|
||||
|
||||
|
|
@ -94,15 +94,15 @@ namespace Prefs {
|
|||
var start = 0
|
||||
var i = 0
|
||||
while buf[i] != 0 {
|
||||
if buf[i] == 10 { parse_line(buf, start, i); start = i + 1 } # newline
|
||||
i = i + 1
|
||||
if buf[i] == '\n' { parse_line(buf, start, i); start = i + 1 } # newline
|
||||
i += 1
|
||||
}
|
||||
if i > start { parse_line(buf, start, i) }
|
||||
}
|
||||
|
||||
internal function write_text(f: pointer, s: pointer) -> void {
|
||||
var n = 0
|
||||
while s[n] != 0 { n = n + 1 }
|
||||
while s[n] != 0 { n += 1 }
|
||||
file_write(f, s, n)
|
||||
}
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ namespace Prefs {
|
|||
var i = 0
|
||||
while i < prefs_n {
|
||||
write_text(f, `{prefs_names[i]}={string(prefs_vals[i])}\n`)
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
file_close(f)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@ 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(name: pointer, out_item: pointer, out_qty: int) -> int {
|
||||
craft_ensure()
|
||||
if recipe_n >= CRAFT_MAX { return 0 - 1 }
|
||||
if recipe_n >= CRAFT_MAX { return -1 }
|
||||
let id = recipe_n
|
||||
recipe_out[id] = out_item; recipe_outqty[id] = out_qty
|
||||
recipe_n = recipe_n + 1
|
||||
recipe_n += 1
|
||||
Dict.set(recipe_reg, name, id)
|
||||
return id
|
||||
}
|
||||
@Namespace(Craft) function craft_id(name: pointer) -> int { craft_ensure(); return Dict.get_or(recipe_reg, name, 0 - 1) }
|
||||
@Namespace(Craft) function craft_id(name: pointer) -> int { craft_ensure(); return Dict.get_or(recipe_reg, name, -1) }
|
||||
# Craft.ingredient(recipe_name, item, qty) — add an ingredient requirement.
|
||||
@Namespace(Craft) function craft_ingredient(recipe_name: pointer, item: pointer, qty: int) -> void {
|
||||
craft_ensure()
|
||||
|
|
@ -47,7 +47,7 @@ event CraftCompleted { e: int = 0, recipe: int = 0 }
|
|||
if rid < 0 { return }
|
||||
if ing_n >= CRAFT_ING_MAX { return }
|
||||
ing_rid[ing_n] = rid; ing_name[ing_n] = item; ing_qty[ing_n] = qty
|
||||
ing_n = ing_n + 1
|
||||
ing_n += 1
|
||||
}
|
||||
|
||||
# Craft.can(e, recipe_name) — does the owner hold every ingredient?
|
||||
|
|
@ -60,7 +60,7 @@ event CraftCompleted { e: int = 0, recipe: int = 0 }
|
|||
if ing_rid[i] == rid {
|
||||
if Inventory.count(e, ing_name[i]) < ing_qty[i] { return 0 }
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ event CraftCompleted { e: int = 0, recipe: int = 0 }
|
|||
var i = 0
|
||||
while i < ing_n {
|
||||
if ing_rid[i] == rid { Inventory.remove(e, ing_name[i], ing_qty[i]) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
Inventory.add(e, recipe_out[rid], recipe_outqty[rid])
|
||||
emit CraftCompleted(e: e, recipe: rid)
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@ event DialogEnded { e: int = 0 }
|
|||
# Dialog.tree(name) — register (or fetch) a tree id.
|
||||
@Namespace(Dialog) function dialog_tree(name: pointer) -> int {
|
||||
dlg_ensure()
|
||||
let ex = Dict.get_or(dlg_reg, name, 0 - 1)
|
||||
let ex = Dict.get_or(dlg_reg, name, -1)
|
||||
if ex >= 0 { return ex }
|
||||
if dlg_tree_n >= DLG_TREE_MAX { return 0 - 1 }
|
||||
if dlg_tree_n >= DLG_TREE_MAX { return -1 }
|
||||
let id = dlg_tree_n
|
||||
dlg_tree_start[id] = 0 - 1
|
||||
dlg_tree_n = dlg_tree_n + 1
|
||||
dlg_tree_start[id] = -1
|
||||
dlg_tree_n += 1
|
||||
Dict.set(dlg_reg, name, id)
|
||||
return id
|
||||
}
|
||||
|
|
@ -52,21 +52,21 @@ event DialogEnded { e: int = 0 }
|
|||
@Namespace(Dialog) function dialog_node(tree_name: pointer, text: pointer) -> int {
|
||||
dlg_ensure()
|
||||
let tid = dialog_tree(tree_name)
|
||||
if tid < 0 { return 0 - 1 }
|
||||
if dlg_node_n >= DLG_NODE_MAX { return 0 - 1 }
|
||||
if tid < 0 { return -1 }
|
||||
if dlg_node_n >= DLG_NODE_MAX { return -1 }
|
||||
let id = dlg_node_n
|
||||
dlg_node_tree[id] = tid; dlg_node_text[id] = text
|
||||
dlg_node_n = dlg_node_n + 1
|
||||
dlg_node_n += 1
|
||||
if dlg_tree_start[tid] < 0 { dlg_tree_start[tid] = id }
|
||||
return id
|
||||
}
|
||||
# Dialog.choice(node, label, next_node) — add a branch (next_node -1 ends).
|
||||
@Namespace(Dialog) function dialog_choice(node: int, label: pointer, next_node: int) -> int {
|
||||
dlg_ensure()
|
||||
if dlg_choice_n >= DLG_CHOICE_MAX { return 0 - 1 }
|
||||
if dlg_choice_n >= DLG_CHOICE_MAX { return -1 }
|
||||
let id = dlg_choice_n
|
||||
dlg_choice_node[id] = node; dlg_choice_label[id] = label; dlg_choice_next[id] = next_node
|
||||
dlg_choice_n = dlg_choice_n + 1
|
||||
dlg_choice_n += 1
|
||||
return id
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ function dlg_set(e: int, name: pointer, v: int) -> void {
|
|||
if dlg_get(e, "active") == 0 { return 0 }
|
||||
let node = dlg_get(e, "node")
|
||||
var n = 0; var i = 0
|
||||
while i < dlg_choice_n { if dlg_choice_node[i] == node { n = n + 1 }; i = i + 1 }
|
||||
while i < dlg_choice_n { if dlg_choice_node[i] == node { n += 1 }; i += 1 }
|
||||
return n
|
||||
}
|
||||
# Dialog.choose(e, i) — take the i-th choice (veto-able); advance or end.
|
||||
|
|
@ -109,12 +109,12 @@ function dlg_set(e: int, name: pointer, v: int) -> void {
|
|||
dlg_ensure()
|
||||
if dlg_get(e, "active") == 0 { return 0 }
|
||||
let node = dlg_get(e, "node")
|
||||
var seen = 0; var i = 0; var pick = 0 - 1
|
||||
var seen = 0; var i = 0; var pick = -1
|
||||
while i < dlg_choice_n {
|
||||
if dlg_choice_node[i] == node {
|
||||
if seen == idx { pick = i; i = dlg_choice_n } else { seen = seen + 1 }
|
||||
if seen == idx { pick = i; i = dlg_choice_n } else { seen += 1 }
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if pick < 0 { return 0 }
|
||||
if emit DialogChoice(e: e, node: node, choice: idx) != 0 { return 0 }
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ function item_ensure() -> void {
|
|||
# Item.def(name, stack_max, weight, value) — register an item template. Returns id.
|
||||
@Namespace(Item) function item_def(name: pointer, stack_max: int, weight: int, value: int) -> int {
|
||||
item_ensure()
|
||||
if item_n >= INV_MAX { return 0 - 1 }
|
||||
if item_n >= INV_MAX { return -1 }
|
||||
let id = item_n
|
||||
item_stackmax[id] = stack_max; item_weight[id] = weight; item_value[id] = value
|
||||
item_n = item_n + 1
|
||||
item_n += 1
|
||||
Dict.set(item_reg, name, id)
|
||||
return id
|
||||
}
|
||||
@Namespace(Item) function item_id(name: pointer) -> int { item_ensure(); return Dict.get_or(item_reg, name, 0 - 1) }
|
||||
@Namespace(Item) function item_id(name: pointer) -> int { item_ensure(); return Dict.get_or(item_reg, name, -1) }
|
||||
@Namespace(Item) function item_value_of(name: pointer) -> int {
|
||||
let id = item_id(name); if id < 0 { return 0 }
|
||||
return item_value[id]
|
||||
|
|
@ -97,7 +97,7 @@ event cancellable ItemUse { e: int = 0, item: int = 0 } # veto a use (
|
|||
@Namespace(Inventory) function inventory_spend_gold(e: int, n: int) -> int {
|
||||
let g = inventory_gold(e)
|
||||
if g < n { return 0 }
|
||||
inventory_add_gold(e, 0 - n)
|
||||
inventory_add_gold(e, -n)
|
||||
return 1
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ function mv_body_set(e: int, name: pointer, v: int) -> void {
|
|||
let P = World.prop_id("Body"); if P < 0 { return }
|
||||
let f = World.field_id(P, name); if f >= 0 { World.set(e, P, f, v) }
|
||||
}
|
||||
function mv_sign(a: int) -> int { if a > 0 { return 1 }; if a < 0 { return 0 - 1 }; return 0 }
|
||||
function mv_sign(a: int) -> int { if a > 0 { return 1 }; if a < 0 { return -1 }; return 0 }
|
||||
|
||||
# is the destination cell walkable? Uses the Solids tilemap when configured,
|
||||
# otherwise the whole field is open.
|
||||
|
|
@ -159,19 +159,19 @@ function mover_free(e: int) -> void {
|
|||
let ax = mv_pos(e, "x") + mv_get(e, "facing_x") * step
|
||||
let ay = mv_pos(e, "y") + mv_get(e, "facing_y") * step
|
||||
let PP = World.prop_id("Position")
|
||||
if PP < 0 { return 0 - 1 }
|
||||
if PP < 0 { return -1 }
|
||||
var o = World.query_next(PP, 0)
|
||||
while o >= 0 {
|
||||
if o != e {
|
||||
let ox = World.get(o, PP, World.field_id(PP, "x"))
|
||||
let oy = World.get(o, PP, World.field_id(PP, "y"))
|
||||
let dx = ox - ax; let dy = oy - ay
|
||||
var adx = dx; if adx < 0 { adx = 0 - adx }
|
||||
var ady = dy; if ady < 0 { ady = 0 - ady }
|
||||
var adx = dx; if adx < 0 { adx = -adx }
|
||||
var ady = dy; if ady < 0 { ady = -ady }
|
||||
if (adx < step) and (ady < step) { emit Interacted(e: e, target: o); return o }
|
||||
}
|
||||
o = World.query_next(PP, o + 1)
|
||||
}
|
||||
emit Interacted(e: e, target: 0 - 1)
|
||||
return 0 - 1
|
||||
emit Interacted(e: e, target: -1)
|
||||
return -1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const PZ_Q: int = 65536
|
|||
property Pushable { }
|
||||
property Switch { on: int = 0 }
|
||||
property Pressure { on: int = 0, step: int = 16 }
|
||||
property Gate { open: int = 0, src: int = 0 - 1 }
|
||||
property Gate { open: int = 0, src: int = -1 }
|
||||
|
||||
event BlockPushed { block: int = 0, dx: int = 0, dy: int = 0 }
|
||||
event cancellable PushBlocked { block: int = 0 }
|
||||
|
|
@ -27,13 +27,13 @@ function pz_pos_set(e: int, name: pointer, v: int) -> void {
|
|||
# the pushable whose cell is exactly (x, y), or -1.
|
||||
function pz_block_at(x: int, y: int) -> int {
|
||||
let P = World.prop_id("Pushable")
|
||||
if P < 0 { return 0 - 1 }
|
||||
if P < 0 { return -1 }
|
||||
var e = World.query_next(P, 0)
|
||||
while e >= 0 {
|
||||
if (pz_pos(e, "x") == x) and (pz_pos(e, "y") == y) { return e }
|
||||
e = World.query_next(P, e + 1)
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# reuse the Mover module's tilemap walkability check when present.
|
||||
|
|
@ -120,9 +120,9 @@ function pz_source_on(src: int) -> int {
|
|||
if (o != e) and (World.has(o, P) == 0) {
|
||||
let ox = World.get(o, PP, World.field_id(PP, "x"))
|
||||
let oy = World.get(o, PP, World.field_id(PP, "y"))
|
||||
var adx = ox - px; if adx < 0 { adx = 0 - adx }
|
||||
var ady = oy - py; if ady < 0 { ady = 0 - ady }
|
||||
if (adx < step) and (ady < step) { on = 1; o = 0 - 1 }
|
||||
var adx = ox - px; if adx < 0 { adx = -adx }
|
||||
var ady = oy - py; if ady < 0 { ady = -ady }
|
||||
if (adx < step) and (ady < step) { on = 1; o = -1 }
|
||||
}
|
||||
if o >= 0 { o = World.query_next(PP, o + 1) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,24 +41,24 @@ 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(name: pointer) -> int {
|
||||
quest_ensure()
|
||||
if quest_n >= QUEST_MAX { return 0 - 1 }
|
||||
if quest_n >= QUEST_MAX { return -1 }
|
||||
let id = quest_n
|
||||
quest_state[id] = 0
|
||||
quest_n = quest_n + 1
|
||||
quest_n += 1
|
||||
Dict.set(quest_reg, name, id)
|
||||
return id
|
||||
}
|
||||
@Namespace(Quest) function quest_id(name: pointer) -> int { quest_ensure(); return Dict.get_or(quest_reg, name, 0 - 1) }
|
||||
@Namespace(Quest) function quest_id(name: pointer) -> int { quest_ensure(); return Dict.get_or(quest_reg, name, -1) }
|
||||
# Quest.objective(quest_name, kind, target, need) — add an objective.
|
||||
@Namespace(Quest) function quest_objective(quest_name: pointer, kind: int, target: int, need: int) -> int {
|
||||
quest_ensure()
|
||||
let qid = quest_id(quest_name)
|
||||
if qid < 0 { return 0 - 1 }
|
||||
if obj_n >= OBJ_MAX { return 0 - 1 }
|
||||
if qid < 0 { return -1 }
|
||||
if obj_n >= OBJ_MAX { return -1 }
|
||||
let id = obj_n
|
||||
obj_qid[id] = qid; obj_kind[id] = kind; obj_target[id] = target
|
||||
obj_need[id] = need; obj_have[id] = 0
|
||||
obj_n = obj_n + 1
|
||||
obj_n += 1
|
||||
return id
|
||||
}
|
||||
# Quest.start(name) — activate a quest (emits QuestStarted).
|
||||
|
|
@ -72,7 +72,7 @@ event ObjectiveProgressed { quest: int = 0, objective: int = 0, have: int = 0, n
|
|||
@Namespace(Quest) function quest_state_of(name: pointer) -> int {
|
||||
quest_ensure()
|
||||
let qid = quest_id(name)
|
||||
if qid < 0 { return 0 - 1 }
|
||||
if qid < 0 { return -1 }
|
||||
return quest_state[qid]
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ function quest_all_done(qid: int) -> int {
|
|||
var i = 0
|
||||
while i < obj_n {
|
||||
if obj_qid[i] == qid { if obj_have[i] < obj_need[i] { return 0 } }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ function quest_all_done(qid: int) -> int {
|
|||
if obj_kind[i] == kind {
|
||||
if (obj_target[i] == 0) or (obj_target[i] == target) {
|
||||
if obj_have[i] < obj_need[i] {
|
||||
obj_have[i] = obj_have[i] + amount
|
||||
obj_have[i] += amount
|
||||
if obj_have[i] > obj_need[i] { obj_have[i] = obj_need[i] }
|
||||
emit ObjectiveProgressed(quest: qid, objective: i, have: obj_have[i], need: obj_need[i])
|
||||
if quest_all_done(qid) == 1 {
|
||||
|
|
@ -109,7 +109,7 @@ function quest_all_done(qid: int) -> int {
|
|||
}
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ event StatusExpired { target: int = 0, kind: int = 0 }
|
|||
# Status.apply(target, kind, amount, interval, ttl) — attach a timed effect.
|
||||
@Namespace(Status) function status_apply(target: int, kind: int, amount: int, interval: int, ttl: int) -> int {
|
||||
let m = World.model_id("StatusFx")
|
||||
if m < 0 { return 0 - 1 }
|
||||
if m < 0 { return -1 }
|
||||
let e = World.spawn(m)
|
||||
let P = World.prop_id("Status")
|
||||
World.set(e, P, World.field_id(P, "target"), target)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ const WPN_MAX: int = 64
|
|||
# ---------------------------------------------------------------------------
|
||||
enum AimMode { Mouse, RightStick, MoveDirection, NearestEnemy, Manual, Auto } # TopDown.aim_mode; Auto = mouse, or the right stick while a pad is connected
|
||||
enum WeaponPattern { Single, Cone, Ring, Spiral } # Weapon.def pattern
|
||||
|
||||
# gamepad axis indices as Input.pad_axis numbers them: left stick 0/1, right stick 2/3
|
||||
const STICK_RIGHT_X: int = 2
|
||||
const STICK_RIGHT_Y: int = 3
|
||||
property TopDown {
|
||||
move_speed: int = 4, # px/frame
|
||||
accel: int = 80, # responsiveness %, gap closed / frame
|
||||
|
|
@ -41,7 +45,7 @@ property TopDown {
|
|||
|
||||
# a Weapon instance points at a registry entry (def_id). cooldown counts down to
|
||||
# the next allowed shot; ammo -1 = infinite; phase drives spiral emitters.
|
||||
property Weapon { def_id: int = 0, ammo: int = 0 - 1, cooldown: int = 0, phase: int = 0 }
|
||||
property Weapon { def_id: int = 0, ammo: int = -1, cooldown: int = 0, phase: int = 0 }
|
||||
|
||||
property Projectile {
|
||||
color: int = 0xffffff, # drawn by the engine as a 3x3 square (Weapon.set_color)
|
||||
|
|
@ -92,20 +96,20 @@ function wpn_ensure() -> void {
|
|||
# gun. pattern: 0 single/aimed, 1 spread cone, 2 ring, 3 spiral. Returns the def id.
|
||||
@Namespace(Weapon) function weapon_def(name: pointer, fire_rate: int, damage: int, speed: int, spread: int, pellets: int, pattern: int) -> int {
|
||||
wpn_ensure()
|
||||
if wpn_n >= WPN_MAX { return 0 - 1 }
|
||||
if wpn_n >= WPN_MAX { return -1 }
|
||||
let id = wpn_n
|
||||
wpn_rate[id] = fire_rate; wpn_dmg[id] = damage; wpn_speed[id] = speed
|
||||
wpn_spread[id] = spread; wpn_pellets[id] = pellets; wpn_pattern[id] = pattern
|
||||
wpn_ttl[id] = 120
|
||||
wpn_color[id] = 0xffffff
|
||||
wpn_rate_base[id] = fire_rate
|
||||
wpn_n = wpn_n + 1
|
||||
wpn_n += 1
|
||||
Dict.set(wpn_reg, name, id)
|
||||
return id
|
||||
}
|
||||
@Namespace(Weapon) function weapon_id(name: pointer) -> int {
|
||||
wpn_ensure()
|
||||
return Dict.get_or(wpn_reg, name, 0 - 1)
|
||||
return Dict.get_or(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(id: int, frames: int) -> void {
|
||||
|
|
@ -180,10 +184,10 @@ function pr_set(e: int, name: pointer, v: int) -> void {
|
|||
# nearest entity with a Faction hostile to `fac`, by centre distance. -1 if none.
|
||||
function sh_nearest_enemy(self_e: int, fac: int, px: int, py: int) -> int {
|
||||
let PF = World.prop_id("Faction")
|
||||
if PF < 0 { return 0 - 1 }
|
||||
if PF < 0 { return -1 }
|
||||
let PP = World.prop_id("Position")
|
||||
if PP < 0 { return 0 - 1 }
|
||||
var best = 0 - 1
|
||||
if PP < 0 { return -1 }
|
||||
var best = -1
|
||||
var bestd = 0
|
||||
var e = World.query_next(PF, 0)
|
||||
while e >= 0 {
|
||||
|
|
@ -292,7 +296,7 @@ function melee_get(e: int, name: pointer) -> int { return sh_get("Melee", e, nam
|
|||
@Namespace(Melee) function melee_ready(e: int) -> bool { return melee_get(e, "cooldown") == 0 }
|
||||
@Namespace(Melee) function melee_active(e: int) -> bool { return melee_get(e, "frames_left") > 0 }
|
||||
@Namespace(Melee) function melee_swing(e: int) -> int {
|
||||
if melee_get(e, "cooldown") > 0 { return 0 - 1 }
|
||||
if melee_get(e, "cooldown") > 0 { return -1 }
|
||||
sh_set("Melee", e, "frames_left", melee_get(e, "frames"))
|
||||
sh_set("Melee", e, "cooldown", melee_get(e, "cooldown_frames"))
|
||||
let PF = World.prop_id("Faction")
|
||||
|
|
@ -316,7 +320,7 @@ function melee_get(e: int, name: pointer) -> int { return sh_get("Melee", e, nam
|
|||
let ny = pos_get(o, "y") + push.y
|
||||
if not Map.is_solid_at(nx, ny) { pos_set(o, "x", nx); pos_set(o, "y", ny) }
|
||||
emit MeleeHit(attacker: e, target: o)
|
||||
hits = hits + 1
|
||||
hits += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -405,23 +409,23 @@ function sh_half_w(e: int) -> int {
|
|||
let py = sh_cy(e)
|
||||
var target = td_get(e, "aim_angle") # default: keep current
|
||||
var have = 0
|
||||
if mode == 0 { # mouse / point
|
||||
if mode == AimMode.Mouse {
|
||||
let mx = Input.mouse_x()
|
||||
let my = Input.mouse_y()
|
||||
target = sh_angle_to(px, py, mx, my); have = 1
|
||||
}
|
||||
if mode == 1 { # right stick
|
||||
let ax = Input.pad_axis(0, 2)
|
||||
let ay = Input.pad_axis(0, 3)
|
||||
if mode == AimMode.RightStick {
|
||||
let ax = Input.pad_axis(0, STICK_RIGHT_X)
|
||||
let ay = Input.pad_axis(0, STICK_RIGHT_Y)
|
||||
if (ax != 0) or (ay != 0) { target = sh_dir_angle(ax, ay); have = 1 }
|
||||
}
|
||||
if mode == 2 { # move direction (from the intent)
|
||||
if mode == AimMode.MoveDirection { # from the movement intent
|
||||
let wx = td_get(e, "want_x")
|
||||
let wy = td_get(e, "want_y")
|
||||
if (wx != 0) or (wy != 0) { target = sh_dir_angle(wx, wy); have = 1 }
|
||||
}
|
||||
# mode 4 = manual: the game/AI owns aim_angle; the aim system leaves it alone.
|
||||
if mode == 3 { # nearest enemy (auto-aim)
|
||||
# AimMode.Manual: the game/AI owns aim_angle; the aim system leaves it alone.
|
||||
if mode == AimMode.NearestEnemy { # auto-aim
|
||||
let fac = Faction.id_of(e)
|
||||
let t = sh_nearest_enemy(e, fac, px, py)
|
||||
if t >= 0 { target = sh_angle_to(px, py, sh_cx(t), sh_cy(t)); have = 1 }
|
||||
|
|
@ -433,7 +437,7 @@ function sh_half_w(e: int) -> int {
|
|||
} else {
|
||||
let cur = td_get(e, "aim_angle")
|
||||
let d = sh_angle_diff(cur, target) # shortest signed arc, degrees
|
||||
if (d >= 0 - tr) and (d <= tr) { td_set(e, "aim_angle", target) }
|
||||
if (d >= -tr) and (d <= tr) { td_set(e, "aim_angle", target) }
|
||||
else { if d > 0 { td_set(e, "aim_angle", sh_wrap_deg(cur + tr)) } else { td_set(e, "aim_angle", sh_wrap_deg(cur - tr)) } }
|
||||
}
|
||||
}
|
||||
|
|
@ -471,21 +475,21 @@ function sh_dir_angle(dx: int, dy: int) -> int {
|
|||
}
|
||||
function sh_wrap_deg(d: int) -> int {
|
||||
var a = d
|
||||
while a < 0 { a = a + 360 }
|
||||
while a >= 360 { a = a - 360 }
|
||||
while a < 0 { a += 360 }
|
||||
while a >= 360 { a -= 360 }
|
||||
return a
|
||||
}
|
||||
function sh_angle_diff(from: int, to: int) -> int {
|
||||
var d = sh_wrap_deg(to) - sh_wrap_deg(from)
|
||||
while d > 180 { d = d - 360 }
|
||||
while d < 0 - 180 { d = d + 360 }
|
||||
while d > 180 { d -= 360 }
|
||||
while d < -180 { d += 360 }
|
||||
return d
|
||||
}
|
||||
|
||||
# spawn one projectile travelling at `deg` degrees from (px,py).
|
||||
function sh_spawn_bullet(owner: int, fac: int, px: int, py: int, deg: int, speed: int, dmg: int, ttl: int, pierce: int, homing: int) -> int {
|
||||
let m = World.model_id("Bullet")
|
||||
if m < 0 { return 0 - 1 }
|
||||
if m < 0 { return -1 }
|
||||
let b = World.spawn(m)
|
||||
pos_set(b, "x", px)
|
||||
pos_set(b, "y", py)
|
||||
|
|
@ -508,7 +512,7 @@ function sh_spawn_bullet(owner: int, fac: int, px: int, py: int, deg: int, speed
|
|||
}
|
||||
# announce it: a listener may veto (cancel -> despawn) or tweak the Projectile.
|
||||
pr_set(b, "color", wpn_fire_color)
|
||||
if emit ProjectileSpawned(proj: b, owner: owner, damage: dmg) != 0 { despawn b; return 0 - 1 }
|
||||
if emit ProjectileSpawned(proj: b, owner: owner, damage: dmg) != 0 { despawn b; return -1 }
|
||||
return b
|
||||
}
|
||||
var wpn_fire_color: int = 0xffffff # the colour of the weapon being fired (sh_fire)
|
||||
|
|
@ -554,17 +558,17 @@ function sh_fire(owner: int, id: int) -> void {
|
|||
wpn_fire_color = wpn_color[id]
|
||||
var pellets = pellets0; if pellets < 1 { pellets = 1 }
|
||||
emit WeaponFired(owner: owner, def_id: id)
|
||||
if pattern == 2 { # ring: pellets around 360
|
||||
if pattern == WeaponPattern.Ring { # pellets around 360
|
||||
var i = 0
|
||||
while i < pellets { sh_spawn_bullet(owner, fac, px, py, sh_wrap_deg(base + i * 360 / pellets), speed, dmg, ttl, pierce, homing); i = i + 1 }
|
||||
while i < pellets { sh_spawn_bullet(owner, fac, px, py, sh_wrap_deg(base + i * 360 / pellets), speed, dmg, ttl, pierce, homing); i += 1 }
|
||||
return
|
||||
}
|
||||
if pattern == 3 { # spiral: ring + a rotating phase
|
||||
if pattern == WeaponPattern.Spiral { # ring + a rotating phase
|
||||
let PW = World.prop_id("Weapon")
|
||||
let fph = World.field_id(PW, "phase")
|
||||
var ph = 0; if fph >= 0 { ph = World.get(owner, PW, fph) }
|
||||
var i = 0
|
||||
while i < pellets { sh_spawn_bullet(owner, fac, px, py, sh_wrap_deg(base + ph + i * 360 / pellets), speed, dmg, ttl, pierce, homing); i = i + 1 }
|
||||
while i < pellets { sh_spawn_bullet(owner, fac, px, py, sh_wrap_deg(base + ph + i * 360 / pellets), speed, dmg, ttl, pierce, homing); i += 1 }
|
||||
if fph >= 0 { World.set(owner, PW, fph, sh_wrap_deg(ph + 15)) }
|
||||
return
|
||||
}
|
||||
|
|
@ -574,9 +578,9 @@ function sh_fire(owner: int, id: int) -> void {
|
|||
} else {
|
||||
var i = 0
|
||||
while i < pellets {
|
||||
let off = 0 - (spread / 2) + i * spread / (pellets - 1)
|
||||
let off = -(spread / 2) + i * spread / (pellets - 1)
|
||||
sh_spawn_bullet(owner, fac, px, py, sh_wrap_deg(base + off), speed, dmg, ttl, pierce, homing)
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -610,7 +614,7 @@ function sh_fire(owner: int, id: int) -> void {
|
|||
let cur = pr_get(e, "dir")
|
||||
let d = sh_angle_diff(cur, want)
|
||||
var na = cur
|
||||
if (d >= 0 - hom) and (d <= hom) { na = want }
|
||||
if (d >= -hom) and (d <= hom) { na = want }
|
||||
else { if d > 0 { na = sh_wrap_deg(cur + hom) } else { na = sh_wrap_deg(cur - hom) } }
|
||||
pr_set(e, "dir", na)
|
||||
let sp = pr_get(e, "speed")
|
||||
|
|
@ -688,7 +692,7 @@ event WaveCleared { spawner: int = 0, wave: int = 0 }
|
|||
var t = World.get(e, P, ft) - 1
|
||||
if t <= 0 {
|
||||
emit SpawnRequested(spawner: e, wave: World.get(e, P, fwave), index: spawned)
|
||||
spawned = spawned + 1
|
||||
spawned += 1
|
||||
World.set(e, P, fsp, spawned)
|
||||
World.set(e, P, ft, World.get(e, P, frate))
|
||||
if spawned >= budget { emit WaveCleared(spawner: e, wave: World.get(e, P, fwave)) }
|
||||
|
|
|
|||
|
|
@ -77,40 +77,40 @@ function atlas_register_name(name: pointer, id: int) -> void {
|
|||
if at_nname >= ATLAS_MAX_NAME { return }
|
||||
at_name_str[at_nname] = name
|
||||
at_name_id[at_nname] = id
|
||||
at_nname = at_nname + 1
|
||||
at_nname += 1
|
||||
}
|
||||
|
||||
# load a spritesheet PNG whose cells are cw x ch px; returns a sheet handle (>= 0).
|
||||
function atlas_sheet(path: pointer, cw: int, ch: int) -> int {
|
||||
atlas_init()
|
||||
if at_nsheet >= ATLAS_MAX_SHEET { return 0 - 1 }
|
||||
if at_nsheet >= ATLAS_MAX_SHEET { return -1 }
|
||||
let img = rt_image_load(path)
|
||||
if img < 0 { return 0 - 1 }
|
||||
if img < 0 { return -1 }
|
||||
let h = at_nsheet
|
||||
at_sheet_img[h] = img
|
||||
at_sheet_cw[h] = cw
|
||||
at_sheet_ch[h] = ch
|
||||
at_nsheet = at_nsheet + 1
|
||||
at_nsheet += 1
|
||||
return h
|
||||
}
|
||||
|
||||
# register an atlas sprite for a sub-rect (px) of a sheet's image.
|
||||
function atlas_make(sheet: int, sx: int, sy: int, w: int, h: int) -> int {
|
||||
atlas_init()
|
||||
if at_nspr >= ATLAS_MAX_SPR { return 0 - 1 }
|
||||
if at_nspr >= ATLAS_MAX_SPR { return -1 }
|
||||
let id = at_nspr
|
||||
at_spr_sheet[id] = sheet
|
||||
at_spr_sx[id] = sx
|
||||
at_spr_sy[id] = sy
|
||||
at_spr_w[id] = w
|
||||
at_spr_h[id] = h
|
||||
at_nspr = at_nspr + 1
|
||||
at_nspr += 1
|
||||
return id
|
||||
}
|
||||
|
||||
# one cell (col, row) of a sheet, addressed by grid coords.
|
||||
function atlas_cell(sheet: int, col: int, row: int) -> int {
|
||||
if (sheet < 0) or (sheet >= at_nsheet) { return 0 - 1 }
|
||||
if (sheet < 0) or (sheet >= at_nsheet) { return -1 }
|
||||
let cw = at_sheet_cw[sheet]
|
||||
let ch = at_sheet_ch[sheet]
|
||||
return atlas_make(sheet, col * cw, row * ch, cw, ch)
|
||||
|
|
@ -119,7 +119,7 @@ function atlas_cell(sheet: int, col: int, row: int) -> int {
|
|||
# a sprite spanning cols x rows cells from (col, row) — some sprites cover more
|
||||
# than one cell (a tall character, a wide object).
|
||||
function atlas_cell_span(sheet: int, col: int, row: int, cols: int, rows: int) -> int {
|
||||
if (sheet < 0) or (sheet >= at_nsheet) { return 0 - 1 }
|
||||
if (sheet < 0) or (sheet >= at_nsheet) { return -1 }
|
||||
let cw = at_sheet_cw[sheet]
|
||||
let ch = at_sheet_ch[sheet]
|
||||
return atlas_make(sheet, col * cw, row * ch, cols * cw, rows * ch)
|
||||
|
|
@ -129,11 +129,11 @@ function atlas_cell_span(sheet: int, col: int, row: int, cols: int, rows: int) -
|
|||
function atlas_define(name: pointer, sheet: int, col: int, row: int) -> int {
|
||||
atlas_init()
|
||||
let id = atlas_cell(sheet, col, row)
|
||||
if id < 0 { return 0 - 1 }
|
||||
if id < 0 { return -1 }
|
||||
if at_nname < ATLAS_MAX_NAME {
|
||||
at_name_str[at_nname] = name
|
||||
at_name_id[at_nname] = id
|
||||
at_nname = at_nname + 1
|
||||
at_nname += 1
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
|
@ -144,24 +144,24 @@ function atlas_named(name: pointer) -> int {
|
|||
var i = 0
|
||||
while i < at_nname {
|
||||
if at_name_str[i] == name { return at_name_id[i] }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# load a whole image file as one atlas sprite (a 1x1 sheet the size of the image).
|
||||
function atlas_image(path: pointer) -> int {
|
||||
atlas_init()
|
||||
if at_nsheet >= ATLAS_MAX_SHEET { return 0 - 1 }
|
||||
if at_nsheet >= ATLAS_MAX_SHEET { return -1 }
|
||||
let img = rt_image_load(path)
|
||||
if img < 0 { return 0 - 1 }
|
||||
if img < 0 { return -1 }
|
||||
let w = img_w[img]
|
||||
let h = img_h[img]
|
||||
let sh = at_nsheet
|
||||
at_sheet_img[sh] = img
|
||||
at_sheet_cw[sh] = w
|
||||
at_sheet_ch[sh] = h
|
||||
at_nsheet = at_nsheet + 1
|
||||
at_nsheet += 1
|
||||
return atlas_make(sh, 0, 0, w, h)
|
||||
}
|
||||
|
||||
|
|
@ -191,10 +191,10 @@ function atlas_draw(id: int, dx: int, dy: int) -> void {
|
|||
let px = s[srcy * iw + srcx]
|
||||
if ((px >> 24) & 255) >= 128 { rt_put_px(dx + x, dy + y, px & 16777215) }
|
||||
}
|
||||
x = x + 1
|
||||
x += 1
|
||||
}
|
||||
}
|
||||
y = y + 1
|
||||
y += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -223,10 +223,10 @@ function atlas_draw_scaled(id: int, dx: int, dy: int, sc: int) -> void {
|
|||
let px = s[srcy * iw + srcx]
|
||||
if ((px >> 24) & 255) >= 128 { rt_fill_rect(dx + x * sc, dy + y * sc, sc, sc, px & 16777215) }
|
||||
}
|
||||
x = x + 1
|
||||
x += 1
|
||||
}
|
||||
}
|
||||
y = y + 1
|
||||
y += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,22 +265,22 @@ function atlas_draw_ex(id: int, dx: int, dy: int, sc0: int, flip: int, tint: int
|
|||
else { rt_fill_rect(dx + x * sc, dy + y * sc, sc, sc, col) }
|
||||
}
|
||||
}
|
||||
x = x + 1
|
||||
x += 1
|
||||
}
|
||||
}
|
||||
y = y + 1
|
||||
y += 1
|
||||
}
|
||||
}
|
||||
|
||||
# a strip of `count` frames starting at (col,row), each `rows` cells tall, registered
|
||||
# as consecutive ids so `first + SpriteAnim.frame` addresses the current frame.
|
||||
function atlas_strip(sheet: int, col: int, row: int, count: int, rows: int) -> int {
|
||||
var first = 0 - 1
|
||||
var first = -1
|
||||
var i = 0
|
||||
while i < count {
|
||||
let id = atlas_cell_span(sheet, col + i, row, 1, rows)
|
||||
if first < 0 { first = id }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return first
|
||||
}
|
||||
|
|
@ -299,7 +299,7 @@ function atlas_draw_meter(x: int, y: int, value: int, max: int, per_icon: int, s
|
|||
if value >= i * per_icon + per_icon / 2 { id = half }
|
||||
if value >= (i + 1) * per_icon { id = full }
|
||||
atlas_draw(id, x + i * spacing, y)
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -312,9 +312,9 @@ function assets_enqueue_dir(dir: pointer) -> void {
|
|||
while i < len(names) {
|
||||
let file = names[i]
|
||||
var dot = len(file) - 1
|
||||
while (dot > 0) and (file[dot] != 46) { dot = dot - 1 }
|
||||
while (dot > 0) and (file[dot] != '.') { dot -= 1 }
|
||||
if dot > 0 { assets_enqueue(file[0..dot], dir + ("/") + file) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ function assets_enqueue(name: pointer, path: pointer) -> void {
|
|||
if at_q_n >= ATLAS_MAX_QUEUE { return }
|
||||
at_q_name[at_q_n] = name
|
||||
at_q_path[at_q_n] = path
|
||||
at_q_n = at_q_n + 1
|
||||
at_q_n += 1
|
||||
}
|
||||
|
||||
# Load up to `max` queued assets this frame, registering each under its name, and
|
||||
|
|
@ -338,8 +338,8 @@ function assets_pump(max: int) -> int {
|
|||
var done = 0
|
||||
while (done < max) and (at_q_pos < at_q_n) {
|
||||
assets_load_one(at_q_name[at_q_pos], at_q_path[at_q_pos])
|
||||
at_q_pos = at_q_pos + 1
|
||||
done = done + 1
|
||||
at_q_pos += 1
|
||||
done += 1
|
||||
}
|
||||
if (at_q_pos >= at_q_n) and (not at_q_announced) { at_q_announced = true; emit AssetsReady() }
|
||||
return done
|
||||
|
|
@ -362,7 +362,7 @@ function path_has_suffix(path: pointer, suffix: pointer) -> bool {
|
|||
var i = 0
|
||||
while i < m {
|
||||
if path[n - m + i] != suffix[i] { return false }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -380,7 +380,7 @@ function assets_load_one(name: pointer, path: pointer) -> void {
|
|||
if at_font_n < ATLAS_MAX_FONT {
|
||||
at_font_name[at_font_n] = name
|
||||
at_font_id[at_font_n] = rt_font_load(path)
|
||||
at_font_n = at_font_n + 1
|
||||
at_font_n += 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -391,7 +391,7 @@ function assets_font(name: pointer) -> int {
|
|||
var i = 0
|
||||
while i < at_font_n {
|
||||
if at_font_name[i] == name { return at_font_id[i] }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ function audio_define(name: pointer, path: pointer) -> int {
|
|||
if snd_bank_n < AUDIO_CAP {
|
||||
snd_bank_name[snd_bank_n] = name
|
||||
snd_bank_id[snd_bank_n] = id
|
||||
snd_bank_n = snd_bank_n + 1
|
||||
snd_bank_n += 1
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ function audio_named(name: pointer) -> int {
|
|||
var i = 0
|
||||
while i < snd_bank_n {
|
||||
if snd_bank_name[i] == name { return snd_bank_id[i] }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ function audio_load(path: pointer) -> int {
|
|||
snd_tab[i] = p
|
||||
return i + 1
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -132,7 +132,7 @@ function audio_stop_all() -> void {
|
|||
var i = 0
|
||||
while i < AUDIO_CAP {
|
||||
if snd_tab[i] != null { snd_stop(snd_tab[i]) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
snd_music = 0
|
||||
}
|
||||
|
|
@ -146,7 +146,7 @@ function audio_volume(v: fixed) -> void {
|
|||
var i = 0
|
||||
while i < AUDIO_CAP {
|
||||
if snd_tab[i] != null { snd_set_volume(snd_tab[i], v) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ function audio_pitch(v: fixed) -> void {
|
|||
var i = 0
|
||||
while i < AUDIO_CAP {
|
||||
if snd_tab[i] != null { snd_set_rate(snd_tab[i], v) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@
|
|||
# the standard alphabet value of a base64 character, or -1 for anything else
|
||||
# (whitespace, '=', stray bytes — the decoder skips them / stops on '=').
|
||||
function b64_val(c: int) -> int {
|
||||
if c >= 65 and c <= 90 { return c - 65 } # 'A'..'Z' -> 0..25
|
||||
if c >= 97 and c <= 122 { return c - 71 } # 'a'..'z' -> 26..51
|
||||
if c >= 48 and c <= 57 { return c + 4 } # '0'..'9' -> 52..61
|
||||
if c == 43 { return 62 } # '+'
|
||||
if c == 47 { return 63 } # '/'
|
||||
return 0 - 1
|
||||
if c >= 'A' and c <= 'Z' { return c - 65 } # 'A'..'Z' -> 0..25
|
||||
if c >= 'a' and c <= 'z' { return c - 71 } # 'a'..'z' -> 26..51
|
||||
if c >= '0' and c <= '9' { return c + 4 } # '0'..'9' -> 52..61
|
||||
if c == '+' { return 62 } # '+'
|
||||
if c == '/' { return 63 } # '/'
|
||||
return -1
|
||||
}
|
||||
|
||||
# decode NUL-terminated base64 `src` into the caller's `out` buffer; returns the
|
||||
|
|
@ -33,18 +33,18 @@ function b64_decode(src: pointer, out: pointer) -> int {
|
|||
var i = 0
|
||||
var c = src[i]
|
||||
while c != 0 {
|
||||
if c == 61 { return w } # '=' -> done
|
||||
if c == '=' { return w } # '=' -> done
|
||||
let v = b64_val(c)
|
||||
if v >= 0 {
|
||||
acc = (acc << 6) | v
|
||||
nbits = nbits + 6
|
||||
nbits += 6
|
||||
if nbits >= 8 {
|
||||
nbits = nbits - 8
|
||||
nbits -= 8
|
||||
out[w] = (acc >> nbits) & 255
|
||||
w = w + 1
|
||||
w += 1
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
c = src[i]
|
||||
}
|
||||
return w
|
||||
|
|
@ -79,9 +79,9 @@ function base64_encode(src: pointer) -> pointer {
|
|||
let e2 = ((b1 & 15) << 2) | (b2 >> 6)
|
||||
let e3 = b2 & 63
|
||||
out = out + tab[e0..e0 + 1] + tab[e1..e1 + 1]
|
||||
if have >= 2 { out = out + tab[e2..e2 + 1] } else { out = out + "=" }
|
||||
if have >= 3 { out = out + tab[e3..e3 + 1] } else { out = out + "=" }
|
||||
i = i + 3
|
||||
if have >= 2 { out += tab[e2..e2 + 1] } else { out += "=" }
|
||||
if have >= 3 { out += tab[e3..e3 + 1] } else { out += "=" }
|
||||
i += 3
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ function bn_alloc(cap: int) -> BigNum {
|
|||
let b = new BigNum
|
||||
b.sign = 0; b.n = 0; b.limbs = words(c)
|
||||
var i = 0
|
||||
while i < c { b.limbs[i] = 0; i = i + 1 }
|
||||
while i < c { b.limbs[i] = 0; i += 1 }
|
||||
return b
|
||||
}
|
||||
|
||||
# drop high zero limbs; a magnitude of zero forces sign 0
|
||||
function bn_norm(b: BigNum) -> BigNum {
|
||||
var k = b.n
|
||||
while k > 0 and b.limbs[k - 1] == 0 { k = k - 1 }
|
||||
while k > 0 and b.limbs[k - 1] == 0 { k -= 1 }
|
||||
b.n = k
|
||||
if k == 0 { b.sign = 0 }
|
||||
return b
|
||||
|
|
@ -58,7 +58,7 @@ function bigint_from(value: int) -> BigNum {
|
|||
if value == 0 { return bigint_zero() }
|
||||
var sign = 1
|
||||
var v: long = value
|
||||
if v < 0 { sign = -1; v = 0 - v }
|
||||
if v < 0 { sign = -1; v = -v }
|
||||
let b = bn_alloc(3)
|
||||
var i = 0
|
||||
while v > 0 {
|
||||
|
|
@ -66,7 +66,7 @@ function bigint_from(value: int) -> BigNum {
|
|||
let lo: int = v - q * BN_BASE
|
||||
b.limbs[i] = lo
|
||||
v = q
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
b.n = i; b.sign = sign
|
||||
return bn_norm(b)
|
||||
|
|
@ -77,9 +77,9 @@ function bigint_from_str(text: pointer) -> BigNum {
|
|||
let e = len(text)
|
||||
var i = 0
|
||||
var sign = 1
|
||||
if e > 0 and text[0] == 45 { sign = -1; i = 1 } # '-'
|
||||
if e > 0 and text[0] == 43 { i = 1 } # '+'
|
||||
while i < e - 1 and text[i] == 48 { i = i + 1 } # skip leading zeros
|
||||
if e > 0 and text[0] == '-' { sign = -1; i = 1 } # '-'
|
||||
if e > 0 and text[0] == '+' { i = 1 } # '+'
|
||||
while i < e - 1 and text[i] == '0' { i += 1 } # skip leading zeros
|
||||
let ndig = e - i
|
||||
if ndig <= 0 { return bigint_zero() }
|
||||
let nlimb = (ndig + 8) / 9
|
||||
|
|
@ -91,8 +91,8 @@ function bigint_from_str(text: pointer) -> BigNum {
|
|||
if start < i { start = i }
|
||||
var v = 0
|
||||
var k = start
|
||||
while k < pos { v = v * 10 + (text[k] - 48); k = k + 1 }
|
||||
b.limbs[li] = v; li = li + 1
|
||||
while k < pos { v = v * 10 + (text[k] - 48); k += 1 }
|
||||
b.limbs[li] = v; li += 1
|
||||
pos = start
|
||||
}
|
||||
b.n = nlimb; b.sign = sign
|
||||
|
|
@ -105,7 +105,7 @@ function bn_ucmp(a: BigNum, b: BigNum) -> int {
|
|||
var i = a.n - 1
|
||||
while i >= 0 {
|
||||
if a.limbs[i] != b.limbs[i] { if a.limbs[i] > b.limbs[i] { return 1 }; return -1 }
|
||||
i = i - 1
|
||||
i -= 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -119,10 +119,10 @@ function bn_uadd(a: BigNum, b: BigNum) -> BigNum {
|
|||
var i = 0
|
||||
while i < m {
|
||||
var s = carry
|
||||
if i < a.n { s = s + a.limbs[i] }
|
||||
if i < b.n { s = s + b.limbs[i] }
|
||||
if i < a.n { s += a.limbs[i] }
|
||||
if i < b.n { s += b.limbs[i] }
|
||||
if s >= BN_BASE { r.limbs[i] = s - BN_BASE; carry = 1 } else { r.limbs[i] = s; carry = 0 }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
r.limbs[m] = carry
|
||||
r.n = m + 1
|
||||
|
|
@ -136,10 +136,10 @@ function bn_usub(a: BigNum, b: BigNum) -> BigNum {
|
|||
var i = 0
|
||||
while i < a.n {
|
||||
var s = a.limbs[i] - borrow
|
||||
if i < b.n { s = s - b.limbs[i] }
|
||||
if s < 0 { s = s + BN_BASE; borrow = 1 } else { borrow = 0 }
|
||||
if i < b.n { s -= b.limbs[i] }
|
||||
if s < 0 { s += BN_BASE; borrow = 1 } else { borrow = 0 }
|
||||
r.limbs[i] = s
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
r.n = a.n
|
||||
return bn_norm(r)
|
||||
|
|
@ -148,8 +148,8 @@ function bn_usub(a: BigNum, b: BigNum) -> BigNum {
|
|||
function bigint_neg(a: BigNum) -> BigNum {
|
||||
let r = bn_alloc(a.n)
|
||||
var i = 0
|
||||
while i < a.n { r.limbs[i] = a.limbs[i]; i = i + 1 }
|
||||
r.n = a.n; r.sign = 0 - a.sign
|
||||
while i < a.n { r.limbs[i] = a.limbs[i]; i += 1 }
|
||||
r.n = a.n; r.sign = -a.sign
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ function bigint_mul(a: BigNum, b: BigNum) -> BigNum {
|
|||
let lo: int = t - q * BN_BASE
|
||||
r.limbs[i + j] = lo
|
||||
carry = q
|
||||
j = j + 1
|
||||
j += 1
|
||||
}
|
||||
var k = i + b.n
|
||||
while carry > 0 {
|
||||
|
|
@ -195,9 +195,9 @@ function bigint_mul(a: BigNum, b: BigNum) -> BigNum {
|
|||
let lo2: int = t2 - q2 * BN_BASE
|
||||
r.limbs[k] = lo2
|
||||
carry = q2
|
||||
k = k + 1
|
||||
k += 1
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
r.n = a.n + b.n; r.sign = a.sign * b.sign
|
||||
return bn_norm(r)
|
||||
|
|
@ -211,7 +211,7 @@ function bigint_pow(a: BigNum, exp: int) -> BigNum {
|
|||
while e > 0 {
|
||||
if e - (e / 2) * 2 == 1 { result = bigint_mul(result, base) }
|
||||
base = bigint_mul(base, base)
|
||||
e = e / 2
|
||||
e /= 2
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
@ -220,7 +220,7 @@ function bigint_pow(a: BigNum, exp: int) -> BigNum {
|
|||
function bigint_div_int(a: BigNum, d: int) -> BigNum {
|
||||
var dd = d
|
||||
var dsign = 1
|
||||
if d < 0 { dsign = -1; dd = 0 - d }
|
||||
if d < 0 { dsign = -1; dd = -d }
|
||||
let r = bn_alloc(a.n)
|
||||
var rem: long = 0
|
||||
let ddl: long = dd
|
||||
|
|
@ -230,7 +230,7 @@ function bigint_div_int(a: BigNum, d: int) -> BigNum {
|
|||
let q: long = cur / ddl
|
||||
rem = cur - q * ddl
|
||||
r.limbs[i] = q
|
||||
i = i - 1
|
||||
i -= 1
|
||||
}
|
||||
r.n = a.n; r.sign = a.sign * dsign
|
||||
return bn_norm(r)
|
||||
|
|
@ -239,14 +239,14 @@ function bigint_div_int(a: BigNum, d: int) -> BigNum {
|
|||
# remainder of dividing by a nonzero int; carries the sign of `a`
|
||||
function bigint_mod_int(a: BigNum, d: int) -> int {
|
||||
var dd = d
|
||||
if d < 0 { dd = 0 - d }
|
||||
if d < 0 { dd = -d }
|
||||
let ddl: long = dd
|
||||
var rem: long = 0
|
||||
var i = a.n - 1
|
||||
while i >= 0 {
|
||||
let cur: long = rem * BN_BASE + a.limbs[i]
|
||||
rem = cur - (cur / ddl) * ddl
|
||||
i = i - 1
|
||||
i -= 1
|
||||
}
|
||||
let r: int = rem
|
||||
return r * a.sign
|
||||
|
|
@ -257,7 +257,7 @@ function bigint_cmp(a: BigNum, b: BigNum) -> int {
|
|||
if a.sign == 0 { return 0 }
|
||||
let c = bn_ucmp(a, b)
|
||||
if a.sign > 0 { return c }
|
||||
return 0 - c
|
||||
return -c
|
||||
}
|
||||
|
||||
function bigint_eq(a: BigNum, b: BigNum) -> bool { return bigint_cmp(a, b) == 0 }
|
||||
|
|
@ -268,12 +268,12 @@ function bigint_to_int(a: BigNum) -> int {
|
|||
if a.sign == 0 { return 0 }
|
||||
var v: long = 0
|
||||
var i = a.n - 1
|
||||
while i >= 0 { v = v * BN_BASE + a.limbs[i]; i = i - 1 }
|
||||
if a.sign < 0 { v = 0 - v }
|
||||
while i >= 0 { v = v * BN_BASE + a.limbs[i]; i -= 1 }
|
||||
if a.sign < 0 { v = -v }
|
||||
let hi: long = 2147483647
|
||||
let lo: long = 0 - hi - 1
|
||||
let lo: long = -hi - 1
|
||||
if v > hi { let r: int = hi; return r }
|
||||
if v < lo { return 0 - 2147483647 - 1 }
|
||||
if v < lo { return -2147483647 - 1 }
|
||||
let r: int = v
|
||||
return r
|
||||
}
|
||||
|
|
@ -283,7 +283,7 @@ function bn_pad9(x: int) -> pointer {
|
|||
var s = string(x)
|
||||
var pad = 9 - len(s)
|
||||
var out = ""
|
||||
while pad > 0 { out = out + "0"; pad = pad - 1 }
|
||||
while pad > 0 { out += "0"; pad -= 1 }
|
||||
return out + s
|
||||
}
|
||||
|
||||
|
|
@ -291,9 +291,9 @@ function bigint_str(a: BigNum) -> pointer {
|
|||
if a.sign == 0 { return "0" }
|
||||
var out = ""
|
||||
if a.sign < 0 { out = "-" }
|
||||
out = out + string(a.limbs[a.n - 1])
|
||||
out += string(a.limbs[a.n - 1])
|
||||
var i = a.n - 2
|
||||
while i >= 0 { out = out + bn_pad9(a.limbs[i]); i = i - 1 }
|
||||
while i >= 0 { out += bn_pad9(a.limbs[i]); i -= 1 }
|
||||
return out
|
||||
}
|
||||
|
||||
|
|
@ -312,12 +312,12 @@ function decimal_from(value: int) -> Dec { return dec_make(bigint_from(value), 0
|
|||
# "[-]int[.frac]" -> Dec, scale = number of fractional digits
|
||||
function decimal_from_str(text: pointer) -> Dec {
|
||||
let e = len(text)
|
||||
var dot = 0 - 1
|
||||
var dot = -1
|
||||
var i = 0
|
||||
while i < e { if text[i] == 46 { dot = i }; i = i + 1 } # '.'
|
||||
while i < e { if text[i] == '.' { dot = i }; i += 1 } # '.'
|
||||
if dot < 0 { return dec_make(bigint_from_str(text), 0) }
|
||||
let intp = text[0..dot]
|
||||
let fracp = text[dot + 1 .. e]
|
||||
let fracp = text[dot + 1..e]
|
||||
let scale = len(fracp)
|
||||
return dec_make(bigint_from_str(intp + fracp), scale)
|
||||
}
|
||||
|
|
@ -360,7 +360,7 @@ function decimal_rescale(d: Dec, places: int) -> Dec {
|
|||
var diff = d.scale - places
|
||||
var m = d.m
|
||||
var i = 0
|
||||
while i < diff { m = bigint_div_int(m, 10); i = i + 1 }
|
||||
while i < diff { m = bigint_div_int(m, 10); i += 1 }
|
||||
return dec_make(m, places)
|
||||
}
|
||||
|
||||
|
|
@ -372,7 +372,7 @@ function decimal_str(d: Dec) -> pointer {
|
|||
if d.scale == 0 { return neg + digits }
|
||||
var nd = len(digits)
|
||||
var pad = d.scale + 1 - nd
|
||||
while pad > 0 { digits = "0" + digits; pad = pad - 1; nd = nd + 1 }
|
||||
while pad > 0 { digits = "0" + digits; pad -= 1; nd += 1 }
|
||||
let cut = nd - d.scale
|
||||
let ip = digits[0..cut]
|
||||
let fp = digits[cut..nd]
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
# ============================================================================
|
||||
|
||||
# ---- state ----------------------------------------------------------------
|
||||
# where a headless build leaves its last frame (relative to the working directory)
|
||||
const HEADLESS_FRAME_PATH: string = "build/out.ppm"
|
||||
|
||||
var rt_fb: words = null # framebuffer, one i32 (0x00RRGGBB) per pixel
|
||||
var rt_fbw: int = 320
|
||||
var rt_fbh: int = 240
|
||||
|
|
@ -63,7 +66,7 @@ function rt_init() -> void {
|
|||
rt_regs = words(64)
|
||||
fill(rt_regs, 0, 64 * 4)
|
||||
rt_map = bytes(96 * 64)
|
||||
fill(rt_map, 32, 96 * 64)
|
||||
fill(rt_map, ' ', 96 * 64)
|
||||
rt_clip_x1 = rt_fbw
|
||||
rt_clip_y1 = rt_fbh
|
||||
rt_statusbuf = bytes(96)
|
||||
|
|
@ -82,7 +85,7 @@ function rt_shutdown() -> void {
|
|||
win_close()
|
||||
return
|
||||
}
|
||||
rt_dump_ppm("build/out.ppm")
|
||||
rt_dump_ppm(HEADLESS_FRAME_PATH)
|
||||
}
|
||||
|
||||
# ---- framebuffer ----------------------------------------------------------
|
||||
|
|
@ -153,9 +156,9 @@ function rt_fill_rect(x: int, y: int, w: int, h: int, c: int) -> void {
|
|||
while i < x1 {
|
||||
if rt_blend == 1 { rt_fb[row + i] = rt_blend_add(rt_fb[row + i], c) }
|
||||
else { rt_fb[row + i] = c }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
j = j + 1
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,16 +172,16 @@ function rt_frame_rect(x: int, y: int, w: int, h: int, c: int) -> void {
|
|||
# A straight line by Bresenham's algorithm — integer only, any direction.
|
||||
function rt_line(x0: int, y0: int, x1: int, y1: int, c: int) -> void {
|
||||
var x = x0; var y = y0
|
||||
let dx = abs(x1 - x0); let dy = 0 - abs(y1 - y0)
|
||||
var sx = 0 - 1; if x0 < x1 { sx = 1 }
|
||||
var sy = 0 - 1; if y0 < y1 { sy = 1 }
|
||||
let dx = abs(x1 - x0); let dy = -abs(y1 - y0)
|
||||
var sx = -1; if x0 < x1 { sx = 1 }
|
||||
var sy = -1; if y0 < y1 { sy = 1 }
|
||||
var err = dx + dy
|
||||
while true {
|
||||
rt_put_px(x, y, c)
|
||||
if (x == x1) and (y == y1) { return }
|
||||
let e2 = 2 * err
|
||||
if e2 >= dy { err = err + dy; x = x + sx }
|
||||
if e2 <= dx { err = err + dx; y = y + sy }
|
||||
if e2 >= dy { err += dy; x += sx }
|
||||
if e2 <= dx { err += dx; y += sy }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,9 +194,9 @@ function rt_circle(cx: int, cy: int, r: int, c: int) -> void {
|
|||
rt_put_px(cx - y, cy + x, c); rt_put_px(cx - x, cy + y, c)
|
||||
rt_put_px(cx - x, cy - y, c); rt_put_px(cx - y, cy - x, c)
|
||||
rt_put_px(cx + y, cy - x, c); rt_put_px(cx + x, cy - y, c)
|
||||
y = y + 1
|
||||
y += 1
|
||||
if err < 0 { err = err + 2 * y + 1 }
|
||||
else { x = x - 1; err = err + 2 * (y - x) + 1 }
|
||||
else { x -= 1; err = err + 2 * (y - x) + 1 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,12 +204,12 @@ function rt_circle(cx: int, cy: int, r: int, c: int) -> void {
|
|||
function rt_fill_circle(cx: int, cy: int, r: int, c: int) -> void {
|
||||
if r < 0 { return }
|
||||
let r2 = r * r
|
||||
var dy = 0 - r
|
||||
var dy = -r
|
||||
while dy <= r {
|
||||
var dx = 0
|
||||
while (dx + 1) * (dx + 1) + dy * dy <= r2 { dx = dx + 1 }
|
||||
while (dx + 1) * (dx + 1) + dy * dy <= r2 { dx += 1 }
|
||||
rt_fill_rect(cx - dx, cy + dy, 2 * dx + 1, 1, c)
|
||||
dy = dy + 1
|
||||
dy += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -231,9 +234,9 @@ function rt_fill_triangle(x0: int, y0: int, x1: int, y1: int, x2: int, y2: int,
|
|||
let neg = (d0 < 0) or (d1 < 0) or (d2 < 0)
|
||||
let pos = (d0 > 0) or (d1 > 0) or (d2 > 0)
|
||||
if not (neg and pos) { rt_put_px(px, py, c) }
|
||||
px = px + 1
|
||||
px += 1
|
||||
}
|
||||
py = py + 1
|
||||
py += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -261,18 +264,18 @@ function rt_oval(x: int, y: int, rx: int, ry: int, c: int) -> void {
|
|||
rt_oval_pts(x, y, ex, ey, c)
|
||||
var p = ry2 - rx2 * ry + rx2 / 4 # region 1
|
||||
while px < py {
|
||||
ex = ex + 1
|
||||
px = px + two_ry2
|
||||
ex += 1
|
||||
px += two_ry2
|
||||
if p < 0 { p = p + ry2 + px }
|
||||
else { ey = ey - 1; py = py - two_rx2; p = p + ry2 + px - py }
|
||||
else { ey -= 1; py -= two_rx2; p = p + ry2 + px - py }
|
||||
rt_oval_pts(x, y, ex, ey, c)
|
||||
}
|
||||
p = ry2 * (ex * 2 + 1) * (ex * 2 + 1) / 4 + rx2 * (ey - 1) * (ey - 1) - rx2 * ry2 # region 2
|
||||
while ey > 0 {
|
||||
ey = ey - 1
|
||||
py = py - two_rx2
|
||||
ey -= 1
|
||||
py -= two_rx2
|
||||
if p > 0 { p = p + rx2 - py }
|
||||
else { ex = ex + 1; px = px + two_ry2; p = p + rx2 - py + px }
|
||||
else { ex += 1; px += two_ry2; p = p + rx2 - py + px }
|
||||
rt_oval_pts(x, y, ex, ey, c)
|
||||
}
|
||||
}
|
||||
|
|
@ -291,7 +294,7 @@ function rt_get_px(x: int, y: int) -> int {
|
|||
# glyph (5 wide + 1 gap), matching rt_text's cursor step.
|
||||
function rt_measure_text(text: string) -> int {
|
||||
var i = 0
|
||||
while text[i] != 0 { i = i + 1 }
|
||||
while text[i] != 0 { i += 1 }
|
||||
return i * 6
|
||||
}
|
||||
|
||||
|
|
@ -316,8 +319,8 @@ function rt_camera_follow(x: int, y: int, lerp: fixed) -> void {
|
|||
let ty = y - rt_fbh / 2
|
||||
let sx = fixed(tx - rt_cam_x) * lerp # fixed * fixed, then floor to whole pixels
|
||||
let sy = fixed(ty - rt_cam_y) * lerp
|
||||
rt_cam_x = rt_cam_x + floor(sx)
|
||||
rt_cam_y = rt_cam_y + floor(sy)
|
||||
rt_cam_x += floor(sx)
|
||||
rt_cam_y += floor(sy)
|
||||
}
|
||||
|
||||
# Add a random screen shake of up to +/- amount pixels, drawn from the seeded
|
||||
|
|
@ -325,8 +328,8 @@ function rt_camera_follow(x: int, y: int, lerp: fixed) -> void {
|
|||
# amount <= 0 clears it.
|
||||
function rt_camera_shake(amount: int) -> void {
|
||||
if amount <= 0 { rt_shake_x = 0; rt_shake_y = 0; return }
|
||||
rt_shake_x = rt_rng_range(0 - amount, amount)
|
||||
rt_shake_y = rt_rng_range(0 - amount, amount)
|
||||
rt_shake_x = rt_rng_range(-amount, amount)
|
||||
rt_shake_y = rt_rng_range(-amount, amount)
|
||||
}
|
||||
|
||||
# Camera.shake_for(amount, frames): shake by up to +/- amount pixels for `frames`
|
||||
|
|
@ -340,7 +343,7 @@ function rt_camera_shake_for(amount: int, frames: int) -> void {
|
|||
}
|
||||
function rt_camera_tick() -> void {
|
||||
if rt_shake_left > 0 {
|
||||
rt_shake_left = rt_shake_left - 1
|
||||
rt_shake_left -= 1
|
||||
rt_camera_shake(rt_shake_amount)
|
||||
return
|
||||
}
|
||||
|
|
@ -377,11 +380,11 @@ function rt_present() -> void {
|
|||
# ---- text -----------------------------------------------------------------
|
||||
function rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void {
|
||||
var c = ch
|
||||
if c >= 97 {
|
||||
if c <= 122 { c = c - 32 }
|
||||
if c >= 'a' {
|
||||
if c <= 'z' { c -= 32 }
|
||||
}
|
||||
if c < 32 { return }
|
||||
if c > 90 { return }
|
||||
if c < ' ' { return }
|
||||
if c > 'Z' { return }
|
||||
let base = (c - 32) * 7
|
||||
let font = rt_font()
|
||||
for row in 0 .. 7 {
|
||||
|
|
@ -404,38 +407,38 @@ function rt_text(x: int, y: int, s: string, colour: int, sc: int) -> void {
|
|||
while ch != 0 {
|
||||
rt_glyph(cx, y, ch, colour, sc)
|
||||
cx = cx + 6 * sc
|
||||
i = i + 1
|
||||
i += 1
|
||||
ch = s[i]
|
||||
}
|
||||
}
|
||||
|
||||
function rt_text_int(x: int, y: int, n: int, colour: int, sc: int) -> void {
|
||||
if n == 0 {
|
||||
rt_glyph(x, y, 48, colour, sc)
|
||||
rt_glyph(x, y, '0', colour, sc)
|
||||
return
|
||||
}
|
||||
var v = n
|
||||
var cx = x
|
||||
if v < 0 {
|
||||
rt_glyph(cx, y, 45, colour, sc)
|
||||
rt_glyph(cx, y, '-', colour, sc)
|
||||
cx = cx + 6 * sc
|
||||
v = 0 - v
|
||||
v = -v
|
||||
}
|
||||
var digits = 0
|
||||
var t = v
|
||||
while t > 0 {
|
||||
digits = digits + 1
|
||||
t = t / 10
|
||||
digits += 1
|
||||
t /= 10
|
||||
}
|
||||
var p = digits
|
||||
while p > 0 {
|
||||
var div = 1
|
||||
for k in 1 .. p {
|
||||
div = div * 10
|
||||
div *= 10
|
||||
}
|
||||
rt_glyph(cx, y, 48 + (v / div) % 10, colour, sc)
|
||||
cx = cx + 6 * sc
|
||||
p = p - 1
|
||||
p -= 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +499,7 @@ function rt_rng_int(max: int) -> int {
|
|||
# a deterministic +1 or -1
|
||||
function rt_rng_sign() -> int {
|
||||
if rt_rng_chance(50) { return 1 }
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# ---- platform: input ------------------------------------------------------
|
||||
|
|
@ -509,7 +512,7 @@ function rt_poll() -> int {
|
|||
rt_alive = 0
|
||||
return 0
|
||||
}
|
||||
if c == 113 { # 'q' quits, as in the headless C platform
|
||||
if c == 'q' { # 'q' quits, as in the headless C platform
|
||||
rt_alive = 0
|
||||
}
|
||||
return c
|
||||
|
|
@ -529,8 +532,8 @@ function rt_put_str(buf: pointer, at: int, s: string) -> int {
|
|||
var ch = s[0]
|
||||
while ch != 0 {
|
||||
buf[n] = ch
|
||||
n = n + 1
|
||||
i = i + 1
|
||||
n += 1
|
||||
i += 1
|
||||
ch = s[i]
|
||||
}
|
||||
return n
|
||||
|
|
@ -538,25 +541,25 @@ function rt_put_str(buf: pointer, at: int, s: string) -> int {
|
|||
|
||||
function rt_put_int(buf: pointer, at: int, v: int) -> int {
|
||||
if v == 0 {
|
||||
buf[at] = 48
|
||||
buf[at] = '0'
|
||||
return at + 1
|
||||
}
|
||||
var digits = 0
|
||||
var t = v
|
||||
while t > 0 {
|
||||
digits = digits + 1
|
||||
t = t / 10
|
||||
digits += 1
|
||||
t /= 10
|
||||
}
|
||||
var n = at
|
||||
var p = digits
|
||||
while p > 0 {
|
||||
var div = 1
|
||||
for k in 1 .. p {
|
||||
div = div * 10
|
||||
div *= 10
|
||||
}
|
||||
buf[n] = 48 + (v / div) % 10
|
||||
n = n + 1
|
||||
p = p - 1
|
||||
n += 1
|
||||
p -= 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
@ -604,7 +607,7 @@ var rt_maph: int = 0
|
|||
function rt_map_size(w: int, h: int) -> void {
|
||||
rt_mapw = clamp(w, 0, 96)
|
||||
rt_maph = clamp(h, 0, 64)
|
||||
fill(rt_map, 32, 96 * 64)
|
||||
fill(rt_map, ' ', 96 * 64)
|
||||
}
|
||||
|
||||
function rt_map_row(y: int, s: string) -> void {
|
||||
|
|
@ -615,7 +618,7 @@ function rt_map_row(y: int, s: string) -> void {
|
|||
while ch != 0 {
|
||||
if x >= 96 { return }
|
||||
rt_map[y * 96 + x] = ch
|
||||
x = x + 1
|
||||
x += 1
|
||||
ch = s[x]
|
||||
}
|
||||
}
|
||||
|
|
@ -627,12 +630,12 @@ function rt_map_set(x: int, y: int, glyph: int) -> void {
|
|||
}
|
||||
function rt_map_fill(glyph: int) -> void {
|
||||
var y = 0
|
||||
while y < rt_maph { var x = 0; while x < rt_mapw { rt_map[y * 96 + x] = glyph; x = x + 1 }; y = y + 1 }
|
||||
while y < rt_maph { var x = 0; while x < rt_mapw { rt_map[y * 96 + x] = glyph; x += 1 }; y += 1 }
|
||||
}
|
||||
# every cell of the rectangle (x, y, w, h)
|
||||
function rt_map_rect(x: int, y: int, w: int, h: int, glyph: int) -> void {
|
||||
var yy = y
|
||||
while yy < y + h { var xx = x; while xx < x + w { rt_map_set(xx, yy, glyph); xx = xx + 1 }; yy = yy + 1 }
|
||||
while yy < y + h { var xx = x; while xx < x + w { rt_map_set(xx, yy, glyph); xx += 1 }; yy += 1 }
|
||||
}
|
||||
# the outermost ring of cells
|
||||
function rt_map_border(glyph: int) -> void {
|
||||
|
|
@ -648,11 +651,11 @@ function rt_map_random_cell(glyph: int) -> IVec2 {
|
|||
let x = rt_rng_range(0, rt_mapw - 1)
|
||||
let y = rt_rng_range(0, rt_maph - 1)
|
||||
if rt_tile(x, y) == glyph { return IVec2.make(x, y) }
|
||||
tries = tries + 1
|
||||
tries += 1
|
||||
}
|
||||
var y2 = 0
|
||||
while y2 < rt_maph { var x2 = 0; while x2 < rt_mapw { if rt_tile(x2, y2) == glyph { return IVec2.make(x2, y2) }; x2 = x2 + 1 }; y2 = y2 + 1 }
|
||||
return IVec2.make(0 - 1, 0 - 1)
|
||||
while y2 < rt_maph { var x2 = 0; while x2 < rt_mapw { if rt_tile(x2, y2) == glyph { return IVec2.make(x2, y2) }; x2 += 1 }; y2 += 1 }
|
||||
return IVec2.make(-1, -1)
|
||||
}
|
||||
# a random cell holding `glyph` at least `min_tiles` from `from` (tiles); falls back to any such cell
|
||||
function rt_map_random_cell_far(glyph: int, from: IVec2, min_tiles: int) -> IVec2 {
|
||||
|
|
@ -661,7 +664,7 @@ function rt_map_random_cell_far(glyph: int, from: IVec2, min_tiles: int) -> IVec
|
|||
while tries < 40 {
|
||||
if not IVec2.within(tile, from, min_tiles - 1) { return tile }
|
||||
tile = rt_map_random_cell(glyph)
|
||||
tries = tries + 1
|
||||
tries += 1
|
||||
}
|
||||
return tile
|
||||
}
|
||||
|
|
@ -696,8 +699,8 @@ function rt_ivec_step(degrees: int) -> IVec2 {
|
|||
}
|
||||
function rt_angle_diff_degrees(a: int, b: int) -> int {
|
||||
var d = (b - a) % 360
|
||||
if d > 180 { d = d - 360 }
|
||||
if d <= 0 - 180 { d = d + 360 }
|
||||
if d > 180 { d -= 360 }
|
||||
if d <= -180 { d += 360 }
|
||||
return d
|
||||
}
|
||||
|
||||
|
|
@ -714,18 +717,18 @@ function rt_bar(x: int, y: int, w: int, h: int, value: int, max: int, color: int
|
|||
function rt_rng_weighted(weights: []int) -> int {
|
||||
var total = 0
|
||||
var i = 0
|
||||
while i < len(weights) { if weights[i] > 0 { total = total + weights[i] }; i = i + 1 }
|
||||
if total <= 0 { return 0 - 1 }
|
||||
while i < len(weights) { if weights[i] > 0 { total += weights[i] }; i += 1 }
|
||||
if total <= 0 { return -1 }
|
||||
var roll = rt_rng_range(0, total - 1)
|
||||
i = 0
|
||||
while i < len(weights) {
|
||||
if weights[i] > 0 {
|
||||
if roll < weights[i] { return i }
|
||||
roll = roll - weights[i]
|
||||
roll -= weights[i]
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# List.sample(pool, count): `count` picks from an int slice, distinct while the
|
||||
|
|
@ -735,20 +738,20 @@ function rt_list_sample(pool: []int, count: int) -> []int {
|
|||
let n = len(pool)
|
||||
var i = 0
|
||||
while i < count {
|
||||
if n == 0 { push(out, 0); i = i + 1; continue }
|
||||
if n == 0 { push(out, 0); i += 1; continue }
|
||||
var pick = rt_rng_range(0, n - 1)
|
||||
var distinct = n > i
|
||||
var tries = 0
|
||||
while distinct and (tries < 64) {
|
||||
var seen = false
|
||||
var j = 0
|
||||
while j < len(out) { if out[j] == pool[pick] { seen = true }; j = j + 1 }
|
||||
while j < len(out) { if out[j] == pool[pick] { seen = true }; j += 1 }
|
||||
if not seen { break }
|
||||
pick = rt_rng_range(0, n - 1)
|
||||
tries = tries + 1
|
||||
tries += 1
|
||||
}
|
||||
push(out, pool[pick])
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
@ -773,7 +776,7 @@ function rt_status(s: string) -> void {
|
|||
if i >= 95 { ch = 0 }
|
||||
if ch != 0 {
|
||||
rt_statusbuf[i] = ch
|
||||
i = i + 1
|
||||
i += 1
|
||||
ch = s[i]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,27 +40,27 @@ function dict_new() -> Dict {
|
|||
|
||||
# FNV-1a over the key's bytes -> a non-negative slot index in [0, cap)
|
||||
function dict_slot(key: pointer, cap: int) -> int {
|
||||
var h = 0 - 2128831035 # FNV-1a offset basis, as a signed i32
|
||||
var h = -2128831035 # FNV-1a offset basis, as a signed i32
|
||||
var i = 0
|
||||
while key[i] != 0 { h = (h ^ key[i]) * 16777619; i = i + 1 }
|
||||
while key[i] != 0 { h = (h ^ key[i]) * 16777619; i += 1 }
|
||||
h = h & 2147483647 # clear the sign bit -> non-negative
|
||||
return h - (h / cap) * cap # h % cap
|
||||
}
|
||||
|
||||
# slot index of `key`, or -1 if absent
|
||||
function dict_find(d: Dict, key: pointer) -> int {
|
||||
if d.cap == 0 { return 0 - 1 }
|
||||
if d.cap == 0 { return -1 }
|
||||
var idx = dict_slot(key, d.cap)
|
||||
var probes = 0
|
||||
while probes < d.cap {
|
||||
let u = d.used[idx]
|
||||
if u == DICT_EMPTY { return 0 - 1 }
|
||||
if u == DICT_EMPTY { return -1 }
|
||||
if u == DICT_USED and d.keys[idx] == key { return idx }
|
||||
idx = idx + 1
|
||||
idx += 1
|
||||
if idx >= d.cap { idx = 0 }
|
||||
probes = probes + 1
|
||||
probes += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# grow to double capacity and reinsert every live key
|
||||
|
|
@ -75,7 +75,7 @@ function dict_grow(d: Dict) -> void {
|
|||
var i = 0
|
||||
while i < oldcap {
|
||||
if oldused[i] == DICT_USED { dict_set(d, oldkeys[i], oldvals[i]) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ function dict_set(d: Dict, key: pointer, value: int) -> void {
|
|||
if d.cap == 0 { dict_init(d, 16) }
|
||||
if (d.count + 1) * 10 >= d.cap * 7 { dict_grow(d) } # load factor 0.7
|
||||
var idx = dict_slot(key, d.cap)
|
||||
var tomb = 0 - 1
|
||||
var tomb = -1
|
||||
var probes = 0
|
||||
while probes < d.cap {
|
||||
let u = d.used[idx]
|
||||
|
|
@ -92,18 +92,18 @@ function dict_set(d: Dict, key: pointer, value: int) -> void {
|
|||
var slot = idx
|
||||
if tomb >= 0 { slot = tomb }
|
||||
d.keys[slot] = key; d.vals[slot] = value; d.used[slot] = DICT_USED
|
||||
d.count = d.count + 1
|
||||
d.count += 1
|
||||
return
|
||||
}
|
||||
if u == DICT_TOMB { if tomb < 0 { tomb = idx } }
|
||||
if u == DICT_USED and d.keys[idx] == key { d.vals[idx] = value; return }
|
||||
idx = idx + 1
|
||||
idx += 1
|
||||
if idx >= d.cap { idx = 0 }
|
||||
probes = probes + 1
|
||||
probes += 1
|
||||
}
|
||||
if tomb >= 0 {
|
||||
d.keys[tomb] = key; d.vals[tomb] = value; d.used[tomb] = DICT_USED
|
||||
d.count = d.count + 1
|
||||
d.count += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ function dict_remove(d: Dict, key: pointer) -> void {
|
|||
if i < 0 { return }
|
||||
d.used[i] = DICT_TOMB
|
||||
d.keys[i] = null
|
||||
d.count = d.count - 1
|
||||
d.count -= 1
|
||||
}
|
||||
|
||||
function dict_size(d: Dict) -> int { return d.count }
|
||||
|
|
@ -146,7 +146,7 @@ function dict_keys(d: Dict) -> []pointer {
|
|||
var i = 0
|
||||
while i < d.cap {
|
||||
if d.used[i] == DICT_USED { push(out, d.keys[i]) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,13 +52,13 @@ function fx_sparks(x: int, y: int, color: int, count: int) -> void {
|
|||
if fx_sn >= FX_MAX_SPARKS { return }
|
||||
fx_sx[fx_sn] = x
|
||||
fx_sy[fx_sn] = y
|
||||
fx_svx[fx_sn] = rt_rng_range(0 - FX_SPARK_SPEED, FX_SPARK_SPEED)
|
||||
fx_svy[fx_sn] = rt_rng_range(0 - FX_SPARK_SPEED, FX_SPARK_SPEED)
|
||||
fx_svx[fx_sn] = rt_rng_range(-FX_SPARK_SPEED, FX_SPARK_SPEED)
|
||||
fx_svy[fx_sn] = rt_rng_range(-FX_SPARK_SPEED, FX_SPARK_SPEED)
|
||||
fx_slife[fx_sn] = FX_SPARK_LIFE + rt_rng_range(0, FX_SPARK_LIFE_JITTER)
|
||||
fx_scolor[fx_sn] = color
|
||||
fx_ssize[fx_sn] = 1 + rt_rng_range(0, 2)
|
||||
fx_sn = fx_sn + 1
|
||||
i = i + 1
|
||||
fx_sn += 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ function fx_number(x: int, y: int, value: int, color: int) -> void {
|
|||
fx_nvalue[fx_nn] = value
|
||||
fx_nlife[fx_nn] = FX_NUMBER_LIFE
|
||||
fx_ncolor[fx_nn] = color
|
||||
fx_nn = fx_nn + 1
|
||||
fx_nn += 1
|
||||
}
|
||||
|
||||
function fx_clear() -> void { fx_sn = 0; fx_nn = 0 }
|
||||
|
|
@ -95,16 +95,16 @@ function fx_tick() -> void {
|
|||
if not fx_ready { return }
|
||||
var i = 0
|
||||
while i < fx_sn {
|
||||
fx_sx[i] = fx_sx[i] + fx_svx[i]
|
||||
fx_sy[i] = fx_sy[i] + fx_svy[i]
|
||||
fx_slife[i] = fx_slife[i] - 1
|
||||
if fx_slife[i] <= 0 { fx_drop_spark(i) } else { i = i + 1 }
|
||||
fx_sx[i] += fx_svx[i]
|
||||
fx_sy[i] += fx_svy[i]
|
||||
fx_slife[i] -= 1
|
||||
if fx_slife[i] <= 0 { fx_drop_spark(i) } else { i += 1 }
|
||||
}
|
||||
i = 0
|
||||
while i < fx_nn {
|
||||
fx_nlife[i] = fx_nlife[i] - 1
|
||||
if fx_nlife[i] % 2 == 0 { fx_ny[i] = fx_ny[i] - 1 }
|
||||
if fx_nlife[i] <= 0 { fx_drop_number(i) } else { i = i + 1 }
|
||||
fx_nlife[i] -= 1
|
||||
if fx_nlife[i] % 2 == 0 { fx_ny[i] -= 1 }
|
||||
if fx_nlife[i] <= 0 { fx_drop_number(i) } else { i += 1 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,11 +114,11 @@ function fx_draw() -> void {
|
|||
var i = 0
|
||||
while i < fx_sn {
|
||||
rt_fill_rect(fx_sx[i], fx_sy[i], fx_ssize[i], fx_ssize[i], fx_scolor[i])
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
i = 0
|
||||
while i < fx_nn {
|
||||
rt_text_int(fx_nx[i] - 4, fx_ny[i] - 10, fx_nvalue[i], fx_ncolor[i], 1)
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
property Cell { x: int = 0, y: int = 0 }
|
||||
|
||||
function grid_abs(v: int) -> int { if v < 0 { return 0 - v }; return v }
|
||||
function grid_abs(v: int) -> int { if v < 0 { return -v }; return v }
|
||||
function grid_in_bounds(x: int, y: int) -> bool { return x >= 0 and y >= 0 and x < rt_mapw and y < rt_maph }
|
||||
# a cell blocks movement if it is out of bounds or holds the `wall` tile.
|
||||
function grid_blocked(x: int, y: int, wall: int) -> bool {
|
||||
|
|
@ -30,9 +30,9 @@ function grid_line(x0: int, y0: int, x1: int, y1: int) -> []Cell {
|
|||
var y = y0
|
||||
let dx = grid_abs(x1 - x0)
|
||||
let dy = grid_abs(y1 - y0)
|
||||
var sx = 0 - 1
|
||||
var sx = -1
|
||||
if x0 < x1 { sx = 1 }
|
||||
var sy = 0 - 1
|
||||
var sy = -1
|
||||
if y0 < y1 { sy = 1 }
|
||||
var err = dx - dy
|
||||
while true {
|
||||
|
|
@ -41,8 +41,8 @@ function grid_line(x0: int, y0: int, x1: int, y1: int) -> []Cell {
|
|||
push(out, c)
|
||||
if x == x1 and y == y1 { break }
|
||||
let e2 = 2 * err
|
||||
if e2 > 0 - dy { err = err - dy; x = x + sx }
|
||||
if e2 < dx { err = err + dx; y = y + sy }
|
||||
if e2 > -dy { err -= dy; x += sx }
|
||||
if e2 < dx { err += dx; y += sy }
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ function grid_line_of_sight(x0: int, y0: int, x1: int, y1: int, wall: int) -> bo
|
|||
var i = 0
|
||||
while i < len(cells) {
|
||||
if grid_blocked(cells[i].x, cells[i].y, wall) { return false }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -66,17 +66,17 @@ function grid_flood(sx: int, sy: int, wall: int) -> []Cell {
|
|||
let n = w * rt_maph
|
||||
let seen = bytes(n)
|
||||
var i = 0
|
||||
while i < n { seen[i] = 0; i = i + 1 }
|
||||
while i < n { seen[i] = 0; i += 1 }
|
||||
let qx = words(n)
|
||||
let qy = words(n)
|
||||
var head = 0
|
||||
var tail = 0
|
||||
qx[tail] = sx; qy[tail] = sy; tail = tail + 1
|
||||
qx[tail] = sx; qy[tail] = sy; tail += 1
|
||||
seen[sy * w + sx] = 1
|
||||
while head < tail {
|
||||
let cx = qx[head]
|
||||
let cy = qy[head]
|
||||
head = head + 1
|
||||
head += 1
|
||||
let c = new Cell
|
||||
c.x = cx; c.y = cy
|
||||
push(out, c)
|
||||
|
|
@ -90,9 +90,9 @@ function grid_flood(sx: int, sy: int, wall: int) -> []Cell {
|
|||
if dir == 3 { ny = cy - 1 }
|
||||
if grid_in_bounds(nx, ny) and seen[ny * w + nx] == 0 and not grid_blocked(nx, ny, wall) {
|
||||
seen[ny * w + nx] = 1
|
||||
qx[tail] = nx; qy[tail] = ny; tail = tail + 1
|
||||
qx[tail] = nx; qy[tail] = ny; tail += 1
|
||||
}
|
||||
dir = dir + 1
|
||||
dir += 1
|
||||
}
|
||||
}
|
||||
return out
|
||||
|
|
@ -113,14 +113,14 @@ function path_a_star(x0: int, y0: int, x1: int, y1: int, wall: int) -> []Cell {
|
|||
let inopen = bytes(n)
|
||||
let closed = bytes(n)
|
||||
var i = 0
|
||||
while i < n { g[i] = INF; came[i] = 0 - 1; inopen[i] = 0; closed[i] = 0; i = i + 1 }
|
||||
while i < n { g[i] = INF; came[i] = -1; inopen[i] = 0; closed[i] = 0; i += 1 }
|
||||
let start = y0 * w + x0
|
||||
let goal = y1 * w + x1
|
||||
g[start] = 0
|
||||
inopen[start] = 1
|
||||
var found = false
|
||||
while true {
|
||||
var best = 0 - 1
|
||||
var best = -1
|
||||
var bestf = INF
|
||||
i = 0
|
||||
while i < n {
|
||||
|
|
@ -130,7 +130,7 @@ function path_a_star(x0: int, y0: int, x1: int, y1: int, wall: int) -> []Cell {
|
|||
let f = g[i] + grid_abs(cx - x1) + grid_abs(cy - y1)
|
||||
if f < bestf { bestf = f; best = i }
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if best < 0 { break }
|
||||
if best == goal { found = true; break }
|
||||
|
|
@ -153,7 +153,7 @@ function path_a_star(x0: int, y0: int, x1: int, y1: int, wall: int) -> []Cell {
|
|||
if ng < g[ni] { g[ni] = ng; came[ni] = best; inopen[ni] = 1 }
|
||||
}
|
||||
}
|
||||
dir = dir + 1
|
||||
dir += 1
|
||||
}
|
||||
}
|
||||
if not found { return out }
|
||||
|
|
@ -169,6 +169,6 @@ function path_a_star(x0: int, y0: int, x1: int, y1: int, wall: int) -> []Cell {
|
|||
cur = came[cur]
|
||||
}
|
||||
var k = len(rev) - 1
|
||||
while k >= 0 { push(out, rev[k]); k = k - 1 }
|
||||
while k >= 0 { push(out, rev[k]); k -= 1 }
|
||||
return out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ function http_init() -> void {
|
|||
h_used[i] = 0; h_native[i] = 0; h_sent[i] = 0; h_res[i] = 0
|
||||
h_status[i] = 0; h_blen[i] = 0
|
||||
h_req[i] = null; h_body[i] = null; h_hdr[i] = null
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
h_ready = true
|
||||
}
|
||||
|
|
@ -62,9 +62,9 @@ function http_slot_alloc() -> int {
|
|||
h_req[i] = null; h_body[i] = null; h_hdr[i] = null
|
||||
return i
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
function http_valid(h: int) -> bool {
|
||||
|
|
@ -77,7 +77,7 @@ function http_valid(h: int) -> bool {
|
|||
function http_cstr_len(p: pointer) -> int {
|
||||
if p == null { return 0 }
|
||||
var n = 0
|
||||
while p[n] != 0 { n = n + 1 }
|
||||
while p[n] != 0 { n += 1 }
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -147,9 +147,9 @@ function http_poll(h: int) -> int {
|
|||
if not http_valid(h) { return 0 }
|
||||
let s = h - 1
|
||||
if h_native[s] == 0 { return h_status[s] } # a parsed handle is ready immediately
|
||||
if h_sent[s] == 0 { return 0 - 1 }
|
||||
if h_sent[s] == 0 { return -1 }
|
||||
if h_res[s] == 1 { return h_status[s] }
|
||||
if hs_done(s) == 0 { return 0 - 1 }
|
||||
if hs_done(s) == 0 { return -1 }
|
||||
# first time we see it finished: cache the fields off the worker.
|
||||
h_status[s] = hs_status(s)
|
||||
h_body[s] = hs_body(s)
|
||||
|
|
@ -204,13 +204,13 @@ function http_slice_dup(src: pointer, a: int, b: int) -> pointer {
|
|||
if n < 0 { n = 0 }
|
||||
let out = bytes(n + 1)
|
||||
var i = 0
|
||||
while i < n { out[i] = src[a + i]; i = i + 1 }
|
||||
while i < n { out[i] = src[a + i]; i += 1 }
|
||||
out[n] = 0
|
||||
return out
|
||||
}
|
||||
|
||||
function http_is_digit(c: int) -> bool { return (c >= 48) and (c <= 57) }
|
||||
function http_lower(c: int) -> int { if (c >= 65) and (c <= 90) { return c + 32 }; return c }
|
||||
function http_is_digit(c: int) -> bool { return (c >= '0') and (c <= '9') }
|
||||
function http_lower(c: int) -> int { if (c >= 'A') and (c <= 'Z') { return c + 32 }; return c }
|
||||
|
||||
# Parse a raw HTTP/1.1 response (status line + headers + blank line + body) into
|
||||
# a ready handle. Useful for cached/custom transports and offline tests.
|
||||
|
|
@ -221,20 +221,20 @@ function http_parse(resp: pointer, len: int) -> int {
|
|||
|
||||
# status: the token after the first space on the status line.
|
||||
var i = 0
|
||||
while (i < len) and (resp[i] != 32) { i = i + 1 } # skip "HTTP/1.1"
|
||||
while (i < len) and (resp[i] == 32) { i = i + 1 } # skip the space(s)
|
||||
while (i < len) and (resp[i] != ' ') { i += 1 } # skip "HTTP/1.1"
|
||||
while (i < len) and (resp[i] == ' ') { i += 1 } # skip the space(s)
|
||||
var st = 0
|
||||
while (i < len) and http_is_digit(resp[i]) { st = (st * 10) + (resp[i] - 48); i = i + 1 }
|
||||
while (i < len) and http_is_digit(resp[i]) { st = (st * 10) + (resp[i] - 48); i += 1 }
|
||||
h_status[s] = st
|
||||
|
||||
# header/body split at the first CRLFCRLF.
|
||||
var split = 0 - 1
|
||||
var split = -1
|
||||
var j = 0
|
||||
while (j + 3) < len {
|
||||
if (resp[j] == 13) and (resp[j + 1] == 10) and (resp[j + 2] == 13) and (resp[j + 3] == 10) {
|
||||
if (resp[j] == '\r') and (resp[j + 1] == '\n') and (resp[j + 2] == '\r') and (resp[j + 3] == '\n') {
|
||||
split = j
|
||||
j = len
|
||||
} else { j = j + 1 }
|
||||
} else { j += 1 }
|
||||
}
|
||||
var hdr_end = split
|
||||
var body_start = split + 4
|
||||
|
|
@ -243,8 +243,8 @@ function http_parse(resp: pointer, len: int) -> int {
|
|||
# header block starts after the status line's CRLF.
|
||||
var hs = 0
|
||||
while (hs + 1) < len {
|
||||
if (resp[hs] == 13) and (resp[hs + 1] == 10) { hs = hs + 2; break }
|
||||
hs = hs + 1
|
||||
if (resp[hs] == '\r') and (resp[hs + 1] == '\n') { hs += 2; break }
|
||||
hs += 1
|
||||
}
|
||||
if hs > hdr_end { hs = hdr_end }
|
||||
h_hdr[s] = http_slice_dup(resp, hs, hdr_end)
|
||||
|
|
@ -264,17 +264,17 @@ function http_find_header(hdr: pointer, name: pointer) -> pointer {
|
|||
while i < hlen {
|
||||
# match name at the start of a line, followed by ':'.
|
||||
var k = 0
|
||||
while (k < nlen) and ((i + k) < hlen) and (http_lower(hdr[i + k]) == http_lower(name[k])) { k = k + 1 }
|
||||
if (k == nlen) and ((i + k) < hlen) and (hdr[i + k] == 58) {
|
||||
while (k < nlen) and ((i + k) < hlen) and (http_lower(hdr[i + k]) == http_lower(name[k])) { k += 1 }
|
||||
if (k == nlen) and ((i + k) < hlen) and (hdr[i + k] == ':') {
|
||||
var v = i + k + 1
|
||||
while (v < hlen) and (hdr[v] == 32) { v = v + 1 } # skip spaces after ':'
|
||||
while (v < hlen) and (hdr[v] == ' ') { v += 1 } # skip spaces after ':'
|
||||
var e = v
|
||||
while (e < hlen) and (hdr[e] != 13) and (hdr[e] != 10) { e = e + 1 }
|
||||
while (e < hlen) and (hdr[e] != '\r') and (hdr[e] != '\n') { e += 1 }
|
||||
return http_slice_dup(hdr, v, e)
|
||||
}
|
||||
# advance to the next line.
|
||||
while (i < hlen) and (hdr[i] != 10) { i = i + 1 }
|
||||
i = i + 1
|
||||
while (i < hlen) and (hdr[i] != '\n') { i += 1 }
|
||||
i += 1
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ function rt_decode_png(path: string) -> bool {
|
|||
let size = rt_file_len
|
||||
if size < 8 { free(d); return false }
|
||||
if d[0] != 137 { free(d); return false }
|
||||
if d[1] != 80 { free(d); return false }
|
||||
if d[1] != 'P' { free(d); return false }
|
||||
|
||||
var w = 0
|
||||
var h = 0
|
||||
|
|
@ -110,7 +110,7 @@ function rt_decode_png(path: string) -> bool {
|
|||
}
|
||||
if png_tag(d, typ, 73, 68, 65, 84) { # IDAT
|
||||
for k in 0 .. ln { idat[idlen + k] = d[body + k] }
|
||||
idlen = idlen + ln
|
||||
idlen += ln
|
||||
}
|
||||
if png_tag(d, typ, 73, 69, 78, 68) { done = 1 } # IEND
|
||||
i = i + 12 + ln
|
||||
|
|
@ -150,8 +150,8 @@ function rt_decode_png(path: string) -> bool {
|
|||
if y > 0 { b = raw[prev + x] }
|
||||
if x >= fbpp { if y > 0 { c = raw[prev + x - fbpp] } }
|
||||
var v = raw[cur + x]
|
||||
if ft == 1 { v = v + a }
|
||||
if ft == 2 { v = v + b }
|
||||
if ft == 1 { v += a }
|
||||
if ft == 2 { v += b }
|
||||
if ft == 3 { v = v + (a + b) / 2 }
|
||||
if ft == 4 {
|
||||
let p = a + b - c
|
||||
|
|
@ -161,7 +161,7 @@ function rt_decode_png(path: string) -> bool {
|
|||
var pick = c
|
||||
if pb <= pc { pick = b }
|
||||
if pa <= pb { if pa <= pc { pick = a } }
|
||||
v = v + pick
|
||||
v += pick
|
||||
}
|
||||
raw[cur + x] = (v & 255)
|
||||
}
|
||||
|
|
@ -228,10 +228,10 @@ function rt_decode_png(path: string) -> bool {
|
|||
|
||||
# ---- images ---------------------------------------------------------------
|
||||
function rt_image_load(path: string) -> int {
|
||||
if img_n >= IMG_MAX { return 0 - 1 }
|
||||
if rt_decode_png(path) == false { return 0 - 1 }
|
||||
if img_n >= IMG_MAX { return -1 }
|
||||
if rt_decode_png(path) == false { return -1 }
|
||||
let id = img_n
|
||||
img_n = img_n + 1
|
||||
img_n += 1
|
||||
img_px[id] = png_px
|
||||
img_w[id] = png_w
|
||||
img_h[id] = png_h
|
||||
|
|
@ -316,10 +316,10 @@ function rt_draw_9slice(id: int, dx: int, dy: int, dw: int, dh: int, inset: int)
|
|||
|
||||
# ---- sprites (16x16 art) --------------------------------------------------
|
||||
function rt_png_load(path: string) -> int {
|
||||
if spr_n >= SPR_MAX { return 0 - 1 }
|
||||
if rt_decode_png(path) == false { return 0 - 1 }
|
||||
if spr_n >= SPR_MAX { return -1 }
|
||||
if rt_decode_png(path) == false { return -1 }
|
||||
let id = spr_n
|
||||
spr_n = spr_n + 1
|
||||
spr_n += 1
|
||||
let base = id * SPR_SZ * SPR_SZ
|
||||
for y in 0 .. SPR_SZ {
|
||||
for x in 0 .. SPR_SZ {
|
||||
|
|
@ -395,10 +395,10 @@ function rt_draw_sprite_ex(id: int, px: int, py: int, sc: int, flip: int, tint:
|
|||
|
||||
# ---- .lspr sprite sheets (palette + ASCII rows) ---------------------------
|
||||
function rt_hexval(c: int) -> int {
|
||||
if c >= 48 { if c <= 57 { return c - 48 } }
|
||||
if c >= 97 { if c <= 102 { return c - 87 } }
|
||||
if c >= 65 { if c <= 70 { return c - 55 } }
|
||||
return 0 - 1
|
||||
if c >= '0' { if c <= '9' { return c - 48 } }
|
||||
if c >= 'a' { if c <= 'f' { return c - 87 } }
|
||||
if c >= 'A' { if c <= 'F' { return c - 55 } }
|
||||
return -1
|
||||
}
|
||||
|
||||
function rt_sprites_load(path: string) -> void {
|
||||
|
|
@ -407,7 +407,7 @@ function rt_sprites_load(path: string) -> void {
|
|||
let size = rt_file_len
|
||||
let pal: words = words(128)
|
||||
fill(pal, 0, 128 * 4)
|
||||
var cur = 0 - 1
|
||||
var cur = -1
|
||||
var row = 0
|
||||
var i = 0
|
||||
while i < size {
|
||||
|
|
@ -416,10 +416,10 @@ function rt_sprites_load(path: string) -> void {
|
|||
var j = start
|
||||
while j < size {
|
||||
let ch = d[j]
|
||||
if ch == 10 { j = size } else { len = len + 1; j = j + 1 }
|
||||
if ch == '\n' { j = size } else { len += 1; j += 1 }
|
||||
}
|
||||
let c0 = d[start]
|
||||
if c0 == 112 { # 'p' — "pal <char> <rrggbb>"
|
||||
if c0 == 'p' { # 'p' — "pal <char> <rrggbb>"
|
||||
let ch = d[start + 4]
|
||||
var v = 0
|
||||
for k in 0 .. 6 {
|
||||
|
|
@ -428,18 +428,18 @@ function rt_sprites_load(path: string) -> void {
|
|||
}
|
||||
if ch < 128 { pal[ch] = ((255 << 24) | v) }
|
||||
}
|
||||
if c0 == 115 { # 's' — "spr" starts a new sprite
|
||||
cur = 0 - 1
|
||||
if c0 == 's' { # 's' — "spr" starts a new sprite
|
||||
cur = -1
|
||||
if spr_n < SPR_MAX {
|
||||
cur = spr_n
|
||||
spr_n = spr_n + 1
|
||||
spr_n += 1
|
||||
fill(offset(spr_px, cur * SPR_SZ * SPR_SZ * 4), 0, SPR_SZ * SPR_SZ * 4)
|
||||
}
|
||||
row = 0
|
||||
}
|
||||
if c0 != 112 {
|
||||
if c0 != 115 {
|
||||
if c0 != 35 { # '#' comment
|
||||
if c0 != 'p' {
|
||||
if c0 != 's' {
|
||||
if c0 != '#' { # '#' comment
|
||||
if cur >= 0 {
|
||||
if row < SPR_SZ {
|
||||
for x in 0 .. SPR_SZ {
|
||||
|
|
@ -447,7 +447,7 @@ function rt_sprites_load(path: string) -> void {
|
|||
spr_px[cur * SPR_SZ * SPR_SZ + row * SPR_SZ + x] = pal[(d[start + x] & 127)]
|
||||
}
|
||||
}
|
||||
row = row + 1
|
||||
row += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ function z_bits(need: int) -> int {
|
|||
return 0
|
||||
}
|
||||
val = (val | (z_src[z_pos] << z_bitcnt))
|
||||
z_pos = z_pos + 1
|
||||
z_bitcnt = z_bitcnt + 8
|
||||
z_pos += 1
|
||||
z_bitcnt += 8
|
||||
}
|
||||
z_bitbuf = (val >> need)
|
||||
z_bitcnt = z_bitcnt - need
|
||||
z_bitcnt -= need
|
||||
return (val & ((1 << need) - 1))
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ function z_table_build(table: words, lengths: words, n: int) -> void {
|
|||
}
|
||||
for s in 0 .. n {
|
||||
let l = lengths[s]
|
||||
table[l] = table[l] + 1
|
||||
table[l] += 1
|
||||
}
|
||||
table[0] = 0 # length 0 means "not present"
|
||||
# offset of each length's first symbol
|
||||
|
|
@ -72,7 +72,7 @@ function z_table_build(table: words, lengths: words, n: int) -> void {
|
|||
let l = lengths[s]
|
||||
if l != 0 {
|
||||
table[16 + offs[l]] = s
|
||||
offs[l] = offs[l] + 1
|
||||
offs[l] += 1
|
||||
}
|
||||
}
|
||||
free(offs)
|
||||
|
|
@ -88,7 +88,7 @@ function z_decode(table: words) -> int {
|
|||
if code - first < count {
|
||||
return table[16 + index + (code - first)]
|
||||
}
|
||||
index = index + count
|
||||
index += count
|
||||
first = ((first + count) << 1)
|
||||
code = (code << 1)
|
||||
}
|
||||
|
|
@ -130,14 +130,14 @@ function z_stored(out: pointer, at: int, cap: int) -> int {
|
|||
z_bitcnt = 0 # stored blocks are byte-aligned
|
||||
if z_pos + 4 > z_len { return -1 }
|
||||
let n = z_src[z_pos] + (z_src[z_pos + 1] << 8)
|
||||
z_pos = z_pos + 4 # LEN then its one's complement
|
||||
z_pos += 4 # LEN then its one's complement
|
||||
var w = at
|
||||
for i in 0 .. n {
|
||||
if z_pos >= z_len { return -1 }
|
||||
if w >= cap { return -1 }
|
||||
out[w] = z_src[z_pos]
|
||||
w = w + 1
|
||||
z_pos = z_pos + 1
|
||||
w += 1
|
||||
z_pos += 1
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ function z_codes(out: pointer, at: int, cap: int, lit: pointer, dist: pointer) -
|
|||
if sym < 256 {
|
||||
if w >= cap { return -1 }
|
||||
out[w] = sym
|
||||
w = w + 1
|
||||
w += 1
|
||||
}
|
||||
if sym > 256 {
|
||||
let s = sym - 257
|
||||
|
|
@ -164,7 +164,7 @@ function z_codes(out: pointer, at: int, cap: int, lit: pointer, dist: pointer) -
|
|||
for k in 0 .. length {
|
||||
if w >= cap { return -1 }
|
||||
out[w] = out[w - distance]
|
||||
w = w + 1
|
||||
w += 1
|
||||
}
|
||||
}
|
||||
sym = z_decode(lit)
|
||||
|
|
@ -208,7 +208,7 @@ function z_dynamic_tables(lit: pointer, dist: pointer) -> int {
|
|||
if sym < 0 { return 0 }
|
||||
if sym < 16 {
|
||||
lengths[n] = sym
|
||||
n = n + 1
|
||||
n += 1
|
||||
}
|
||||
if sym >= 16 {
|
||||
var prev = 0
|
||||
|
|
@ -223,7 +223,7 @@ function z_dynamic_tables(lit: pointer, dist: pointer) -> int {
|
|||
for k in 0 .. rep {
|
||||
if n < 320 {
|
||||
lengths[n] = prev
|
||||
n = n + 1
|
||||
n += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -294,14 +294,14 @@ function z_gunzip(src: pointer, len: int, out: pointer, cap: int) -> int {
|
|||
pos = pos + 2 + xlen
|
||||
}
|
||||
if (flg & 8) != 0 { # FNAME: NUL-terminated
|
||||
while pos < len and src[pos] != 0 { pos = pos + 1 }
|
||||
pos = pos + 1
|
||||
while pos < len and src[pos] != 0 { pos += 1 }
|
||||
pos += 1
|
||||
}
|
||||
if (flg & 16) != 0 { # FCOMMENT: NUL-terminated
|
||||
while pos < len and src[pos] != 0 { pos = pos + 1 }
|
||||
pos = pos + 1
|
||||
while pos < len and src[pos] != 0 { pos += 1 }
|
||||
pos += 1
|
||||
}
|
||||
if (flg & 2) != 0 { pos = pos + 2 } # FHCRC: 2-byte header CRC
|
||||
if (flg & 2) != 0 { pos += 2 } # FHCRC: 2-byte header CRC
|
||||
if pos + 8 > len { return -1 }
|
||||
return z_inflate(offset(src, pos), len - pos - 8, out, cap)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@ function input_find(name: pointer) -> int {
|
|||
var i = 0
|
||||
while i < input_nact {
|
||||
if input_names[i] == name { return i }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# get-or-create the slot for `name`.
|
||||
|
|
@ -63,7 +63,7 @@ function input_slot(name: pointer) -> int {
|
|||
if input_nact >= INPUT_MAX_ACT { return INPUT_MAX_ACT - 1 } # silently reuse the last slot when full
|
||||
let s = input_nact
|
||||
input_names[s] = name
|
||||
input_nact = input_nact + 1
|
||||
input_nact += 1
|
||||
return s
|
||||
}
|
||||
|
||||
|
|
@ -75,12 +75,12 @@ function input_bind(name: pointer, key: int) -> void {
|
|||
var i = 0
|
||||
while i < INPUT_MAX_KEYS {
|
||||
if input_keys[base + i] == key { return } # already bound
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
i = 0
|
||||
while i < INPUT_MAX_KEYS {
|
||||
if input_keys[base + i] == 0 { input_keys[base + i] = key; return }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ function input_default(name: pointer, key: int) -> void {
|
|||
var i = 0
|
||||
while i < INPUT_MAX_KEYS {
|
||||
if input_keys[base + i] != 0 { return } # already has a binding — keep it
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
input_keys[base] = key
|
||||
}
|
||||
|
|
@ -107,12 +107,12 @@ function input_bind_pad(name: pointer, button: int) -> void {
|
|||
var i = 0
|
||||
while i < INPUT_MAX_KEYS {
|
||||
if input_pads[base + i] == (button + 1) { return } # already bound
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
i = 0
|
||||
while i < INPUT_MAX_KEYS {
|
||||
if input_pads[base + i] == 0 { input_pads[base + i] = button + 1; return }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ function input_rebind(name: pointer, oldkey: int, newkey: int) -> void {
|
|||
var i = 0
|
||||
while i < INPUT_MAX_KEYS {
|
||||
if input_keys[base + i] == oldkey { input_keys[base + i] = newkey; return }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ function input_slot_has(s: int, k: int) -> bool {
|
|||
var i = 0
|
||||
while i < INPUT_MAX_KEYS {
|
||||
if input_keys[base + i] == k { return true }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -158,7 +158,7 @@ function input_commit() -> int {
|
|||
input_last = input_frame
|
||||
if input_mode == 2 { # replay
|
||||
var k = 0
|
||||
if input_pos < input_recn { k = input_rec[input_pos]; input_pos = input_pos + 1 }
|
||||
if input_pos < input_recn { k = input_rec[input_pos]; input_pos += 1 }
|
||||
input_frame = k
|
||||
input_device_commit(k, 1) # rebuild the device state from the tape
|
||||
return k
|
||||
|
|
@ -166,7 +166,7 @@ function input_commit() -> int {
|
|||
let k = rt_poll()
|
||||
if input_mode == 1 { # record
|
||||
if input_rec == null { input_rec = words(INPUT_REC_CAP) }
|
||||
if input_recn < INPUT_REC_CAP { input_rec[input_recn] = k; input_recn = input_recn + 1 }
|
||||
if input_recn < INPUT_REC_CAP { input_rec[input_recn] = k; input_recn += 1 }
|
||||
}
|
||||
input_frame = k
|
||||
input_device_commit(k, 0)
|
||||
|
|
@ -264,9 +264,9 @@ function in_bit_set(set: words, k: int, on: bool) -> void {
|
|||
let m = 1 << (k & 31)
|
||||
if on { set[w] = set[w] | m } else { set[w] = set[w] & (~m) }
|
||||
}
|
||||
function in_set_clear(set: words) -> void { var i = 0; while i < IN_WORDS { set[i] = 0; i = i + 1 } }
|
||||
function in_set_copy(dst: words, src: words) -> void { var i = 0; while i < IN_WORDS { dst[i] = src[i]; i = i + 1 } }
|
||||
function in_set_or(dst: words, a: words, b: words) -> void { var i = 0; while i < IN_WORDS { dst[i] = a[i] | b[i]; i = i + 1 } }
|
||||
function in_set_clear(set: words) -> void { var i = 0; while i < IN_WORDS { set[i] = 0; i += 1 } }
|
||||
function in_set_copy(dst: words, src: words) -> void { var i = 0; while i < IN_WORDS { dst[i] = src[i]; i += 1 } }
|
||||
function in_set_or(dst: words, a: words, b: words) -> void { var i = 0; while i < IN_WORDS { dst[i] = a[i] | b[i]; i += 1 } }
|
||||
|
||||
# ---- the per-frame device commit (called by input_poll) --------------------
|
||||
# Snapshot the committed set into prev (for edges), refresh the platform set (or
|
||||
|
|
@ -278,7 +278,7 @@ function input_device_commit(k: int, replaying: int) -> void {
|
|||
# Taken before the platform refresh (win_pad, below, runs after this), so it holds
|
||||
# the previous frame's committed value against which this frame's edge is measured.
|
||||
var pj = 0
|
||||
while pj < IN_PADS { in_pad_btn0[pj] = in_pad_btn[pj]; pj = pj + 1 }
|
||||
while pj < IN_PADS { in_pad_btn0[pj] = in_pad_btn[pj]; pj += 1 }
|
||||
|
||||
if replaying == 1 {
|
||||
# rebuild the platform set + mouse from the tape; sim/injection is ignored so
|
||||
|
|
@ -286,7 +286,7 @@ function input_device_commit(k: int, replaying: int) -> void {
|
|||
let base = (input_pos - 1) * IN_STRIDE
|
||||
if (in_tape != null) and (base >= 0) {
|
||||
var i = 0
|
||||
while i < IN_WORDS { in_dev[i] = in_tape[base + i]; i = i + 1 }
|
||||
while i < IN_WORDS { in_dev[i] = in_tape[base + i]; i += 1 }
|
||||
in_mx = in_tape[base + 8]
|
||||
in_my = in_tape[base + 9]
|
||||
in_mbtn = in_tape[base + 10]
|
||||
|
|
@ -312,7 +312,7 @@ function input_device_commit(k: int, replaying: int) -> void {
|
|||
input_set_pad(pi, pbuf[pb] != 0, pbuf[pb + 1],
|
||||
as_fixed(pbuf[pb + 2]), as_fixed(pbuf[pb + 3]),
|
||||
as_fixed(pbuf[pb + 4]), as_fixed(pbuf[pb + 5]))
|
||||
pi = pi + 1
|
||||
pi += 1
|
||||
}
|
||||
let tbuf = words(IN_TOUCH * 3) # [active, x, y]/point
|
||||
win_touch(tbuf)
|
||||
|
|
@ -320,7 +320,7 @@ function input_device_commit(k: int, replaying: int) -> void {
|
|||
while ti < IN_TOUCH {
|
||||
let tb = ti * 3
|
||||
input_set_touch(ti, tbuf[tb + 1], tbuf[tb + 2], tbuf[tb] != 0)
|
||||
ti = ti + 1
|
||||
ti += 1
|
||||
}
|
||||
} else {
|
||||
in_set_clear(in_dev)
|
||||
|
|
@ -345,7 +345,7 @@ function input_device_record() -> void {
|
|||
if (f < 0) or (f >= INPUT_REC_CAP) { return }
|
||||
let base = f * IN_STRIDE
|
||||
var i = 0
|
||||
while i < IN_WORDS { in_tape[base + i] = in_held[i]; i = i + 1 }
|
||||
while i < IN_WORDS { in_tape[base + i] = in_held[i]; i += 1 }
|
||||
in_tape[base + 8] = in_mx
|
||||
in_tape[base + 9] = in_my
|
||||
in_tape[base + 10] = in_mbtn
|
||||
|
|
@ -366,8 +366,8 @@ function input_release(k: int) -> void { in_init(); in_bit_set(in_sim, k, false
|
|||
function input_axis(neg: int, pos: int) -> fixed {
|
||||
in_init()
|
||||
var v = fixed(0)
|
||||
if in_bit_get(in_held, pos) { v = v + fixed(1) }
|
||||
if in_bit_get(in_held, neg) { v = v - fixed(1) }
|
||||
if in_bit_get(in_held, pos) { v += fixed(1) }
|
||||
if in_bit_get(in_held, neg) { v -= fixed(1) }
|
||||
return v
|
||||
}
|
||||
# #79 — a directional intent as a plain int: +1 if the positive key is held, -1 if
|
||||
|
|
@ -377,38 +377,44 @@ function input_axis(neg: int, pos: int) -> fixed {
|
|||
function input_axis_i(neg: int, pos: int) -> int {
|
||||
in_init()
|
||||
var v = 0
|
||||
if in_bit_get(in_held, pos) { v = v + 1 }
|
||||
if in_bit_get(in_held, neg) { v = v - 1 }
|
||||
if in_bit_get(in_held, pos) { v += 1 }
|
||||
if in_bit_get(in_held, neg) { v -= 1 }
|
||||
return v
|
||||
}
|
||||
# a stick has to leave its centre by this much before it counts as a direction
|
||||
const STICK_DEADZONE: fixed = 0.35
|
||||
# gamepad axis indices as input_pad_axis numbers them
|
||||
const STICK_LEFT_X: int = 0
|
||||
const STICK_LEFT_Y: int = 1
|
||||
|
||||
# The standard top-down movement intent as -1/0/1 per axis: WASD or the arrow
|
||||
# keys, and the left stick of pad 0 (past a 0.35 deadzone) when one is connected.
|
||||
# keys, and the left stick of pad 0 (past the deadzone) when one is connected.
|
||||
function input_move_i() -> IVec2 {
|
||||
in_init()
|
||||
var x = input_axis_i(Key.A, Key.D) + input_axis_i(Key.Left, Key.Right)
|
||||
var y = input_axis_i(Key.W, Key.S) + input_axis_i(Key.Up, Key.Down)
|
||||
if input_pad_connected(0) {
|
||||
let sx = input_pad_axis(0, 0)
|
||||
let sy = input_pad_axis(0, 1)
|
||||
if sx > 0.35 { x = 1 }
|
||||
if sx < -0.35 { x = 0 - 1 }
|
||||
if sy > 0.35 { y = 1 }
|
||||
if sy < -0.35 { y = 0 - 1 }
|
||||
let sx = input_pad_axis(0, STICK_LEFT_X)
|
||||
let sy = input_pad_axis(0, STICK_LEFT_Y)
|
||||
if sx > STICK_DEADZONE { x = 1 }
|
||||
if sx < -STICK_DEADZONE { x = -1 }
|
||||
if sy > STICK_DEADZONE { y = 1 }
|
||||
if sy < -STICK_DEADZONE { y = -1 }
|
||||
}
|
||||
return IVec2.make(clamp(x, 0 - 1, 1), clamp(y, 0 - 1, 1))
|
||||
return IVec2.make(clamp(x, -1, 1), clamp(y, -1, 1))
|
||||
}
|
||||
# A 2D vector from four direction keys, normalized so a diagonal is not faster.
|
||||
function input_vector(left: int, right: int, up: int, down: int) -> Vector {
|
||||
in_init()
|
||||
var x = fixed(0)
|
||||
var y = fixed(0)
|
||||
if in_bit_get(in_held, right) { x = x + fixed(1) }
|
||||
if in_bit_get(in_held, left) { x = x - fixed(1) }
|
||||
if in_bit_get(in_held, down) { y = y + fixed(1) }
|
||||
if in_bit_get(in_held, up) { y = y - fixed(1) }
|
||||
if in_bit_get(in_held, right) { x += fixed(1) }
|
||||
if in_bit_get(in_held, left) { x -= fixed(1) }
|
||||
if in_bit_get(in_held, down) { y += fixed(1) }
|
||||
if in_bit_get(in_held, up) { y -= fixed(1) }
|
||||
if (x != 0) and (y != 0) { # diagonal: scale by 1/sqrt(2)
|
||||
x = x * 0.7071 # fixed multiply (64-bit intermediate)
|
||||
y = y * 0.7071
|
||||
x *= 0.7071 # fixed multiply (64-bit intermediate)
|
||||
y *= 0.7071
|
||||
}
|
||||
return Vector.make(x, y)
|
||||
}
|
||||
|
|
@ -486,7 +492,7 @@ function input_touch_count() -> int {
|
|||
in_init()
|
||||
var n = 0
|
||||
var i = 0
|
||||
while i < IN_TOUCH { if in_touch_on[i] != 0 { n = n + 1 }; i = i + 1 }
|
||||
while i < IN_TOUCH { if in_touch_on[i] != 0 { n += 1 }; i += 1 }
|
||||
return n
|
||||
}
|
||||
function input_touch_x(i: int) -> int { in_init(); if (i < 0) or (i >= IN_TOUCH) { return 0 }; return in_touch_x[i] }
|
||||
|
|
@ -523,7 +529,7 @@ function input_active_in(name: pointer, held: words, padmask: int) -> bool {
|
|||
if (k != 0) and in_bit_get(held, k) { return true }
|
||||
let pb = input_pads[base + i]
|
||||
if (pb != 0) and ((padmask & (1 << (pb - 1))) != 0) { return true }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ function jb_alloc(kind: int) -> int {
|
|||
jb_nmem[i] = 0
|
||||
return i + 1
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -161,16 +161,16 @@ function jb_refresh_group(s: int) -> void {
|
|||
let ms = mh - 1
|
||||
let mst = jb_state[ms]
|
||||
if mst != J_PENDING {
|
||||
settled = settled + 1
|
||||
settled += 1
|
||||
if mst == J_DONE {
|
||||
ok = ok + 1
|
||||
ok += 1
|
||||
if first_ok == 0 { first_ok = mh }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
settled = settled + 1 # a freed/invalid member counts as settled-failed
|
||||
settled += 1 # a freed/invalid member counts as settled-failed
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if k == JK_ALL {
|
||||
if ok == n { jb_state[s] = J_DONE; jb_result[s] = n }
|
||||
|
|
@ -227,8 +227,8 @@ function job_pending() -> int {
|
|||
var n = 0
|
||||
var i = 0
|
||||
while i < JOB_SLOTS {
|
||||
if jb_state[i] == J_PENDING { n = n + 1 }
|
||||
i = i + 1
|
||||
if jb_state[i] == J_PENDING { n += 1 }
|
||||
i += 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
@ -246,7 +246,7 @@ function jb_step(s: int) -> int {
|
|||
var i = jb_i[s]
|
||||
if k == JK_SUM {
|
||||
jb_acc[s] = jb_acc[s] + (i + 1)
|
||||
i = i + 1
|
||||
i += 1
|
||||
jb_i[s] = i
|
||||
if i >= n { jb_state[s] = J_DONE; jb_result[s] = jb_acc[s]; return 1 }
|
||||
return 0
|
||||
|
|
@ -256,14 +256,14 @@ function jb_step(s: int) -> int {
|
|||
let t = jb_acc[s] + jb_acc2[s]
|
||||
jb_acc[s] = jb_acc2[s]
|
||||
jb_acc2[s] = t
|
||||
i = i + 1
|
||||
i += 1
|
||||
jb_i[s] = i
|
||||
if i >= n { jb_state[s] = J_DONE; jb_result[s] = jb_acc[s]; return 1 }
|
||||
return 0
|
||||
}
|
||||
if k == JK_PRIMES {
|
||||
if jb_is_prime(i) { jb_acc[s] = jb_acc[s] + 1 }
|
||||
i = i + 1
|
||||
if jb_is_prime(i) { jb_acc[s] += 1 }
|
||||
i += 1
|
||||
jb_i[s] = i
|
||||
if i > n { jb_state[s] = J_DONE; jb_result[s] = jb_acc[s]; return 1 }
|
||||
return 0
|
||||
|
|
@ -276,7 +276,7 @@ function jb_is_prime(v: int) -> bool {
|
|||
var d = 2
|
||||
while d * d <= v {
|
||||
if v - (v / d) * d == 0 { return false }
|
||||
d = d + 1
|
||||
d += 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -296,10 +296,10 @@ function job_pump(budget: int) -> int {
|
|||
while (jb_state[s] == J_PENDING) and compute {
|
||||
if (budget > 0) and (spent >= budget) { s = JOB_SLOTS + 1; break }
|
||||
let fin = jb_step(s)
|
||||
spent = spent + 1
|
||||
if fin == 1 { completed = completed + 1 }
|
||||
spent += 1
|
||||
if fin == 1 { completed += 1 }
|
||||
}
|
||||
s = s + 1
|
||||
s += 1
|
||||
}
|
||||
# settle groups after the compute jobs advanced this frame.
|
||||
s = 0
|
||||
|
|
@ -308,10 +308,10 @@ function job_pump(budget: int) -> int {
|
|||
let k = jb_kind[s]
|
||||
if (k == JK_ALL) or (k == JK_RACE) {
|
||||
jb_refresh_group(s)
|
||||
if jb_state[s] != J_PENDING { completed = completed + 1 }
|
||||
if jb_state[s] != J_PENDING { completed += 1 }
|
||||
}
|
||||
}
|
||||
s = s + 1
|
||||
s += 1
|
||||
}
|
||||
return completed
|
||||
}
|
||||
|
|
@ -324,7 +324,7 @@ function jb_set_members(s: int, handles: []int) -> void {
|
|||
if n > JOB_MAXMEM { n = JOB_MAXMEM }
|
||||
let base = s * JOB_MAXMEM
|
||||
var i = 0
|
||||
while i < n { jb_mem[base + i] = handles[i]; i = i + 1 }
|
||||
while i < n { jb_mem[base + i] = handles[i]; i += 1 }
|
||||
jb_nmem[s] = n
|
||||
}
|
||||
|
||||
|
|
@ -354,8 +354,8 @@ function prom_count_done(handles: []int) -> int {
|
|||
var n = 0
|
||||
var i = 0
|
||||
while i < len(handles) {
|
||||
if job_done(handles[i]) { n = n + 1 }
|
||||
i = i + 1
|
||||
if job_done(handles[i]) { n += 1 }
|
||||
i += 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
@ -364,7 +364,7 @@ function prom_all_done(handles: []int) -> bool {
|
|||
var i = 0
|
||||
while i < len(handles) {
|
||||
if not job_done(handles[i]) { return false }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -415,7 +415,7 @@ function sync_mutex() -> int {
|
|||
var i = 0
|
||||
while i < SYNC_MUTEX {
|
||||
if mx_used[i] == 0 { mx_used[i] = 1; mx_held[i] = 0; return i + 1 }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -447,7 +447,7 @@ function sync_atomic() -> int {
|
|||
var i = 0
|
||||
while i < SYNC_ATOMIC {
|
||||
if at_used[i] == 0 { at_used[i] = 1; at_val[i] = 0; return i + 1 }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -468,7 +468,7 @@ function sync_set(a: int, v: int) -> void {
|
|||
function sync_add(a: int, delta: int) -> int {
|
||||
sy_init()
|
||||
if (a < 1) or (a > SYNC_ATOMIC) { return 0 }
|
||||
at_val[a - 1] = at_val[a - 1] + delta
|
||||
at_val[a - 1] += delta
|
||||
return at_val[a - 1]
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +487,7 @@ function sync_channel() -> int {
|
|||
var i = 0
|
||||
while i < SYNC_CHAN {
|
||||
if ch_used[i] == 0 { ch_used[i] = 1; ch_head[i] = 0; ch_count[i] = 0; return i + 1 }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -500,9 +500,9 @@ function sync_send(c: int, v: int) -> bool {
|
|||
if ch_count[s] >= CHAN_CAP { return false }
|
||||
let pos = ch_head[s] + ch_count[s]
|
||||
var idx = pos
|
||||
if idx >= CHAN_CAP { idx = idx - CHAN_CAP }
|
||||
if idx >= CHAN_CAP { idx -= CHAN_CAP }
|
||||
ch_buf[s * CHAN_CAP + idx] = v
|
||||
ch_count[s] = ch_count[s] + 1
|
||||
ch_count[s] += 1
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +516,7 @@ function sync_recv(c: int) -> int {
|
|||
var nh = ch_head[s] + 1
|
||||
if nh >= CHAN_CAP { nh = 0 }
|
||||
ch_head[s] = nh
|
||||
ch_count[s] = ch_count[s] - 1
|
||||
ch_count[s] -= 1
|
||||
return v
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ function light_occlude(x: int, y: int, w: int, h: int) -> void {
|
|||
rt_light_occ[i + 1] = y
|
||||
rt_light_occ[i + 2] = w
|
||||
rt_light_occ[i + 3] = h
|
||||
rt_light_occ_n = rt_light_occ_n + 1
|
||||
rt_light_occ_n += 1
|
||||
}
|
||||
|
||||
# ---- shadow geometry ------------------------------------------------------
|
||||
|
|
@ -63,7 +63,7 @@ function light_occlude(x: int, y: int, w: int, h: int) -> void {
|
|||
function light_orient(ax: int, ay: int, bx: int, by: int, cx: int, cy: int) -> int {
|
||||
let v = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax)
|
||||
if v > 0 { return 1 }
|
||||
if v < 0 { return 0 - 1 }
|
||||
if v < 0 { return -1 }
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ function light_blocked(lx: int, ly: int, px: int, py: int) -> bool {
|
|||
if light_seg_cross(lx, ly, px, py, x1, y0, x1, y1) { return true } # right
|
||||
if light_seg_cross(lx, ly, px, py, x1, y1, x0, y1) { return true } # bottom
|
||||
if light_seg_cross(lx, ly, px, py, x0, y1, x0, y0) { return true } # left
|
||||
k = k + 1
|
||||
k += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ function light_fsqrt(v: fixed) -> fixed {
|
|||
var rt_light_falloff: int = 1 # brightness ramp exponent: 1 linear, 2 quadratic, 3 cubic…
|
||||
var rt_light_soft: int = 0 # penumbra radius in px (0 = hard single-sample shadow)
|
||||
var rt_light_gel: int = 0 # outer gel colour 0x00RRGGBB (used only when rt_light_gel_on)
|
||||
var rt_light_gel_on: bool = false # gel active? off = a flat single-colour light
|
||||
var rt_light_gel_on: bool = false # gel active? off = a flat single-colour light
|
||||
var rt_light_h: int = 64 # virtual light height above the surface, for normal-map N·L
|
||||
|
||||
function light_set_falloff(exp: int) -> void {
|
||||
|
|
@ -163,7 +163,7 @@ function light_clear_normals() -> void {
|
|||
if rt_light_nrm == null { return }
|
||||
let n = rt_fbw * rt_fbh
|
||||
var i = 0
|
||||
while i < n { rt_light_nrm[i] = 0; i = i + 1 }
|
||||
while i < n { rt_light_nrm[i] = 0; i += 1 }
|
||||
}
|
||||
|
||||
# stamp a rectangular region's surface normal. nx, ny are the normal's x/y as a
|
||||
|
|
@ -182,10 +182,10 @@ function light_normal_rect(x: int, y: int, w: int, h: int, nx: fixed, ny: fixed)
|
|||
var px = x
|
||||
while px < x + w {
|
||||
if (px >= 0) and (px < rt_fbw) { rt_light_nrm[py * rt_fbw + px] = packed }
|
||||
px = px + 1
|
||||
px += 1
|
||||
}
|
||||
}
|
||||
py = py + 1
|
||||
py += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ function light_atan2_deg(y: int, x: int) -> int {
|
|||
# smallest absolute difference between two whole-degree angles, 0..180.
|
||||
function light_ang_diff(a: int, b: int) -> int {
|
||||
var d = a - b
|
||||
if d < 0 { d = 0 - d }
|
||||
if d < 0 { d = -d }
|
||||
if d > 180 { d = 360 - d }
|
||||
return d
|
||||
}
|
||||
|
|
@ -231,7 +231,7 @@ function light_pow_t(t: fixed, exp: int) -> fixed {
|
|||
if exp <= 1 { return t }
|
||||
var r = t
|
||||
var i = 1
|
||||
while i < exp { r = r * t; i = i + 1 }
|
||||
while i < exp { r *= t; i += 1 }
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
@ -246,11 +246,11 @@ function light_vis(cx: int, cy: int, px: int, py: int) -> fixed {
|
|||
}
|
||||
let s = rt_light_soft
|
||||
var hit = 0
|
||||
if not light_blocked(cx, cy, px, py) { hit = hit + 1 }
|
||||
if not light_blocked(cx + s, cy, px, py) { hit = hit + 1 }
|
||||
if not light_blocked(cx - s, cy, px, py) { hit = hit + 1 }
|
||||
if not light_blocked(cx, cy + s, px, py) { hit = hit + 1 }
|
||||
if not light_blocked(cx, cy - s, px, py) { hit = hit + 1 }
|
||||
if not light_blocked(cx, cy, px, py) { hit += 1 }
|
||||
if not light_blocked(cx + s, cy, px, py) { hit += 1 }
|
||||
if not light_blocked(cx - s, cy, px, py) { hit += 1 }
|
||||
if not light_blocked(cx, cy + s, px, py) { hit += 1 }
|
||||
if not light_blocked(cx, cy - s, px, py) { hit += 1 }
|
||||
return fixed(hit) / fixed(5)
|
||||
}
|
||||
|
||||
|
|
@ -297,7 +297,7 @@ function light_ambient(color: int) -> void {
|
|||
let ng = (((cur >> 8) & 255) * ag) / 255
|
||||
let nb = ((cur & 255) * ab) / 255
|
||||
rt_fb[i] = (nr << 16) | (ng << 8) | nb
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,17 +368,17 @@ function light_emit(cx: int, cy: int, radius: int, color: int, energy: fixed, di
|
|||
}
|
||||
}
|
||||
}
|
||||
px = px + 1
|
||||
px += 1
|
||||
}
|
||||
}
|
||||
py = py + 1
|
||||
py += 1
|
||||
}
|
||||
}
|
||||
|
||||
# a radial (omnidirectional) point light — the original short-signature call,
|
||||
# now a thin wrapper over light_emit with the cone disabled.
|
||||
function light_point(cx: int, cy: int, radius: int, color: int, energy: fixed) -> void {
|
||||
light_emit(cx, cy, radius, color, energy, 0, 0 - 1)
|
||||
light_emit(cx, cy, radius, color, energy, 0, -1)
|
||||
}
|
||||
|
||||
# a cone / spot light aimed at `direction` degrees (0 = +x, CCW) with a half-angle
|
||||
|
|
@ -396,7 +396,7 @@ function light_spot(cx: int, cy: int, radius: int, color: int, energy: fixed, di
|
|||
function light_time_of_day(t: fixed) -> void {
|
||||
# day factor 0..1: 0 at midnight, 1 at noon (triangle over the day).
|
||||
var day = t * fixed(2) # 0..2 across the day
|
||||
if day > fixed(1) { day = fixed(2) - day } # fold 0.5..1 back down: peak at noon
|
||||
if day > fixed(1) { day = fixed(2) - day } # fold 0.5..1 back down: peak at noon
|
||||
if day < 0 { day = fixed(0) }
|
||||
# night tint 0x14142a (deep blue) -> day 0xffffff, per channel.
|
||||
let nr = 20; let ng = 20; let nb = 42
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ function huge_make(m: fixed, e: int) -> Huge {
|
|||
var mm = m
|
||||
if mm < 0.0 { neg = true; mm = 0.0 - mm }
|
||||
var ee = e
|
||||
while mm >= HUGE_TEN { mm = mm / HUGE_TEN; ee = ee + 1 }
|
||||
while mm < HUGE_ONE { mm = mm * HUGE_TEN; ee = ee - 1 }
|
||||
while mm >= HUGE_TEN { mm /= HUGE_TEN; ee += 1 }
|
||||
while mm < HUGE_ONE { mm *= HUGE_TEN; ee -= 1 }
|
||||
if neg { mm = 0.0 - mm }
|
||||
h.m = mm; h.e = ee
|
||||
return h
|
||||
|
|
@ -45,10 +45,10 @@ function huge_from(value: int) -> Huge {
|
|||
if value == 0 { return huge_make(0.0, 0) }
|
||||
var neg = false
|
||||
var v: long = value
|
||||
if v < 0 { neg = true; v = 0 - v }
|
||||
if v < 0 { neg = true; v = -v }
|
||||
var e = 0
|
||||
var p: long = 1
|
||||
while p * 10 <= v { p = p * 10; e = e + 1 }
|
||||
while p * 10 <= v { p *= 10; e += 1 }
|
||||
let raw: long = (v * 65536) / p # v / 10^e in Q16.16 (in [1,10))
|
||||
let rawi: int = raw
|
||||
var m: fixed = as_fixed(rawi)
|
||||
|
|
@ -78,7 +78,7 @@ function huge_add(a: Huge, b: Huge) -> Huge {
|
|||
if diff > 8 { return big } # negligible at display precision
|
||||
var sm = small.m
|
||||
var k = 0
|
||||
while k < diff { sm = sm / HUGE_TEN; k = k + 1 }
|
||||
while k < diff { sm /= HUGE_TEN; k += 1 }
|
||||
return huge_make(big.m + sm, big.e)
|
||||
}
|
||||
|
||||
|
|
@ -90,9 +90,9 @@ function huge_cmp(a: Huge, b: Huge) -> int {
|
|||
if sa != sb { if sa > sb { return 1 }; return -1 }
|
||||
if sa == 0 { return 0 }
|
||||
var c = 0
|
||||
if a.e != b.e { if a.e > b.e { c = 1 } else { c = 0 - 1 } }
|
||||
else { if a.m > b.m { c = 1 } else { if a.m < b.m { c = 0 - 1 } else { c = 0 } } }
|
||||
if sa < 0 { c = 0 - c }
|
||||
if a.e != b.e { if a.e > b.e { c = 1 } else { c = -1 } }
|
||||
else { if a.m > b.m { c = 1 } else { if a.m < b.m { c = -1 } else { c = 0 } } }
|
||||
if sa < 0 { c = -c }
|
||||
return c
|
||||
}
|
||||
|
||||
|
|
@ -109,8 +109,8 @@ function huge_str(a: Huge) -> pointer {
|
|||
let frac: fixed = m - fixed(ip)
|
||||
var dd: int = floor(frac * 100.0 + 0.5) # round the two decimals to nearest
|
||||
var ex = a.e
|
||||
if dd >= 100 { dd = 0; ip = ip + 1 } # rounding carried into the ones place
|
||||
if ip >= 10 { ip = 1; ex = ex + 1 } # ...and on into the exponent
|
||||
if dd >= 100 { dd = 0; ip += 1 } # rounding carried into the ones place
|
||||
if ip >= 10 { ip = 1; ex += 1 } # ...and on into the exponent
|
||||
var ds = string(dd)
|
||||
if dd < 10 { ds = "0" + ds }
|
||||
return neg + string(ip) + "." + ds + "e" + string(ex)
|
||||
|
|
@ -124,8 +124,8 @@ const ANGLE_TAU: fixed = 6.28318531
|
|||
# wrap any radian value into the half-open range [-pi, pi)
|
||||
function angle_wrap(a: fixed) -> fixed {
|
||||
var x = a
|
||||
while x >= ANGLE_PI { x = x - ANGLE_TAU }
|
||||
while x < 0.0 - ANGLE_PI { x = x + ANGLE_TAU }
|
||||
while x >= ANGLE_PI { x -= ANGLE_TAU }
|
||||
while x < 0.0 - ANGLE_PI { x += ANGLE_TAU }
|
||||
return x
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function query_count(prop: int) -> int {
|
|||
var n = 0
|
||||
var e = world_query_next(prop, 0)
|
||||
while e >= 0 {
|
||||
n = n + 1
|
||||
n += 1
|
||||
e = world_query_next(prop, e + 1)
|
||||
}
|
||||
return n
|
||||
|
|
@ -40,7 +40,7 @@ function query_first(prop: int) -> int {
|
|||
# y_field); pass the same id for `prop` and `pos` to query by the position
|
||||
# component itself, or a separate tag for `prop` (e.g. "nearest Enemy").
|
||||
function query_nearest(prop: int, pos: int, x_field: int, y_field: int, px: int, py: int) -> int {
|
||||
var best = 0 - 1
|
||||
var best = -1
|
||||
var bestd = 0
|
||||
var e = world_query_next(prop, 0)
|
||||
while e >= 0 {
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ function reflect_serialize(e: int) -> Val {
|
|||
var node = value_int(raw)
|
||||
if world_field_type(p, f) == "fixed" { node = value_fixed(raw) }
|
||||
value_put(comp, fname, node)
|
||||
f = f + 1
|
||||
f += 1
|
||||
}
|
||||
value_put(obj, world_prop_name(p), comp)
|
||||
}
|
||||
p = p + 1
|
||||
p += 1
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ function reflect_apply(e: int, v: Val) -> int {
|
|||
var i = 0
|
||||
while i < value_count(v) {
|
||||
let pname = value_key_at(v, i)
|
||||
if pname[0] != 64 { # skip reserved "@…" keys
|
||||
if pname[0] != '@' { # skip reserved "@…" keys
|
||||
let p = world_prop_id(pname)
|
||||
if p >= 0 and world_has(e, p) != 0 {
|
||||
let comp = value_at(v, i)
|
||||
|
|
@ -59,13 +59,13 @@ function reflect_apply(e: int, v: Val) -> int {
|
|||
let f = world_field_id(p, fname)
|
||||
if f >= 0 {
|
||||
world_set(e, p, f, value_as_int(value_at(comp, j)))
|
||||
set = set + 1
|
||||
set += 1
|
||||
}
|
||||
j = j + 1
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
# ============================================================================
|
||||
|
||||
# ---- small helpers ----------------------------------------------------------
|
||||
function rx_slen(s: pointer) -> int { var n = 0; while s[n] != 0 { n = n + 1 }; return n }
|
||||
function rx_slen(s: pointer) -> int { var n = 0; while s[n] != 0 { n += 1 }; return n }
|
||||
|
||||
# ---- growable int vector ----------------------------------------------------
|
||||
property IVec { d: words, n: int, cap: int }
|
||||
|
|
@ -37,17 +37,17 @@ function iv_new() -> IVec {
|
|||
function iv_grow(v: IVec, need: int) -> void {
|
||||
if v.n + need <= v.cap { return }
|
||||
var nc = v.cap * 2
|
||||
while nc < v.n + need { nc = nc * 2 }
|
||||
while nc < v.n + need { nc *= 2 }
|
||||
let nd = words(nc)
|
||||
var i = 0
|
||||
while i < v.n { nd[i] = v.d[i]; i = i + 1 }
|
||||
while i < v.n { nd[i] = v.d[i]; i += 1 }
|
||||
v.d = nd; v.cap = nc
|
||||
}
|
||||
function iv_push(v: IVec, x: int) -> int {
|
||||
iv_grow(v, 1)
|
||||
let idx = v.n
|
||||
v.d[v.n] = x
|
||||
v.n = v.n + 1
|
||||
v.n += 1
|
||||
return idx
|
||||
}
|
||||
|
||||
|
|
@ -80,13 +80,13 @@ const N_EMPTY: int = 13
|
|||
|
||||
property RNode {
|
||||
op: int = 0, ch: int = 0, cls: int = 0, lo: int = 0, hi: int = 0,
|
||||
greedy: int = 1, gidx: int = 0 - 1, kids: []RNode
|
||||
greedy: int = 1, gidx: int = -1, kids: []RNode
|
||||
}
|
||||
function rx_node(op: int) -> RNode {
|
||||
let n = new RNode
|
||||
n.op = op
|
||||
n.greedy = 1
|
||||
n.gidx = 0 - 1
|
||||
n.gidx = -1
|
||||
n.kids = new []RNode
|
||||
return n
|
||||
}
|
||||
|
|
@ -101,16 +101,16 @@ var rx_err: int = 0
|
|||
var rx_ngroup: int = 0
|
||||
var rx_prog: Prog = null
|
||||
|
||||
function rx_peek() -> int { if rx_pos < rx_len { return rx_pat[rx_pos] & 255 }; return 0 - 1 }
|
||||
function rx_peek2() -> int { if rx_pos + 1 < rx_len { return rx_pat[rx_pos + 1] & 255 }; return 0 - 1 }
|
||||
function rx_adv() -> int { let c = rx_peek(); rx_pos = rx_pos + 1; return c }
|
||||
function rx_peek() -> int { if rx_pos < rx_len { return rx_pat[rx_pos] & 255 }; return -1 }
|
||||
function rx_peek2() -> int { if rx_pos + 1 < rx_len { return rx_pat[rx_pos + 1] & 255 }; return -1 }
|
||||
function rx_adv() -> int { let c = rx_peek(); rx_pos += 1; return c }
|
||||
|
||||
# ---- character classes ------------------------------------------------------
|
||||
# a class is 8 i32 words (256 bits) in prog.cls; class k occupies cls[8k .. 8k+8)
|
||||
function rx_class_new() -> int {
|
||||
let idx = rx_prog.cls.n / 8
|
||||
var i = 0
|
||||
while i < 8 { iv_push(rx_prog.cls, 0); i = i + 1 }
|
||||
while i < 8 { iv_push(rx_prog.cls, 0); i += 1 }
|
||||
return idx
|
||||
}
|
||||
function rx_class_set(idx: int, c: int) -> void {
|
||||
|
|
@ -119,11 +119,11 @@ function rx_class_set(idx: int, c: int) -> void {
|
|||
}
|
||||
function rx_class_set_range(idx: int, a: int, b: int) -> void {
|
||||
var c = a
|
||||
while c <= b { rx_class_set(idx, c); c = c + 1 }
|
||||
while c <= b { rx_class_set(idx, c); c += 1 }
|
||||
}
|
||||
function rx_class_negate(idx: int) -> void {
|
||||
var i = 0
|
||||
while i < 8 { let w = idx * 8 + i; rx_prog.cls.d[w] = ~rx_prog.cls.d[w]; i = i + 1 }
|
||||
while i < 8 { let w = idx * 8 + i; rx_prog.cls.d[w] = ~rx_prog.cls.d[w]; i += 1 }
|
||||
}
|
||||
function rx_class_unset(idx: int, c: int) -> void {
|
||||
let w = idx * 8 + (c >> 5)
|
||||
|
|
@ -131,11 +131,11 @@ function rx_class_unset(idx: int, c: int) -> void {
|
|||
}
|
||||
function rx_class_unset_range(idx: int, a: int, b: int) -> void {
|
||||
var c = a
|
||||
while c <= b { rx_class_unset(idx, c); c = c + 1 }
|
||||
while c <= b { rx_class_unset(idx, c); c += 1 }
|
||||
}
|
||||
function rx_class_set_all(idx: int) -> void {
|
||||
var i = 0
|
||||
while i < 8 { rx_prog.cls.d[idx * 8 + i] = 0 - 1; i = i + 1 }
|
||||
while i < 8 { rx_prog.cls.d[idx * 8 + i] = -1; i += 1 }
|
||||
}
|
||||
function rx_class_set_word(idx: int) -> void {
|
||||
rx_class_set_range(idx, 48, 57)
|
||||
|
|
@ -151,12 +151,12 @@ function rx_class_has(prog: Prog, idx: int, c: int) -> bool {
|
|||
let w = prog.cls.d[idx * 8 + (c >> 5)]
|
||||
return (w & (1 << (c & 31))) != 0
|
||||
}
|
||||
function rx_is_digit(c: int) -> bool { return c >= 48 and c <= 57 }
|
||||
function rx_is_digit(c: int) -> bool { return c >= '0' and c <= '9' }
|
||||
function rx_is_word(c: int) -> bool {
|
||||
return (c >= 48 and c <= 57) or (c >= 65 and c <= 90) or (c >= 97 and c <= 122) or c == 95
|
||||
return (c >= '0' and c <= '9') or (c >= 'A' and c <= 'Z') or (c >= 'a' and c <= 'z') or c == '_'
|
||||
}
|
||||
function rx_is_ws(c: int) -> bool {
|
||||
return c == 32 or c == 9 or c == 10 or c == 13 or c == 12 or c == 11
|
||||
return c == ' ' or c == '\t' or c == '\n' or c == '\r' or c == 12 or c == 11
|
||||
}
|
||||
# OR the set named by \d \D \w \W \s \S into class idx. The negated forms OR in
|
||||
# the complement set bit-by-bit (never via set-all+unset, which would clobber a
|
||||
|
|
@ -170,7 +170,7 @@ function rx_class_add_pre(idx: int, kind: int) -> void {
|
|||
if kind == 68 { if not rx_is_digit(c) { rx_class_set(idx, c) } } # \D
|
||||
else if kind == 87 { if not rx_is_word(c) { rx_class_set(idx, c) } } # \W
|
||||
else if kind == 83 { if not rx_is_ws(c) { rx_class_set(idx, c) } } # \S
|
||||
c = c + 1
|
||||
c += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ function rx_parse_class() -> RNode {
|
|||
var lo = rx_adv()
|
||||
if lo == 92 { # escape inside class
|
||||
let e = rx_adv()
|
||||
if e == 100 or e == 68 or e == 119 or e == 87 or e == 115 or e == 83 {
|
||||
if e == 'd' or e == 'D' or e == 'w' or e == 'W' or e == 's' or e == 'S' {
|
||||
rx_class_add_pre(idx, e)
|
||||
continue
|
||||
}
|
||||
|
|
@ -210,12 +210,12 @@ function rx_parse_class() -> RNode {
|
|||
}
|
||||
# map an escaped char inside a class to its byte
|
||||
function rx_class_escape_char(e: int) -> int {
|
||||
if e == 110 { return 10 }
|
||||
if e == 116 { return 9 }
|
||||
if e == 114 { return 13 }
|
||||
if e == 102 { return 12 }
|
||||
if e == 118 { return 11 }
|
||||
if e == 48 { return 0 }
|
||||
if e == 'n' { return 10 }
|
||||
if e == 't' { return 9 }
|
||||
if e == 'r' { return 13 }
|
||||
if e == 'f' { return 12 }
|
||||
if e == 'v' { return 11 }
|
||||
if e == '0' { return 0 }
|
||||
return e
|
||||
}
|
||||
|
||||
|
|
@ -223,21 +223,21 @@ function rx_class_escape_char(e: int) -> int {
|
|||
function rx_parse_escape() -> RNode {
|
||||
rx_adv() # consume '\'
|
||||
let e = rx_adv()
|
||||
if e == 100 or e == 68 or e == 119 or e == 87 or e == 115 or e == 83 {
|
||||
if e == 'd' or e == 'D' or e == 'w' or e == 'W' or e == 's' or e == 'S' {
|
||||
let idx = rx_class_new()
|
||||
rx_class_add_pre(idx, e)
|
||||
let node = rx_node(N_CLASS)
|
||||
node.cls = idx
|
||||
return node
|
||||
}
|
||||
if e >= 49 and e <= 57 { rx_err = 1; return rx_node(N_EMPTY) } # backrefs unsupported
|
||||
if e >= '1' and e <= '9' { rx_err = 1; return rx_node(N_EMPTY) } # backrefs unsupported
|
||||
var ch = e
|
||||
if e == 110 { ch = 10 }
|
||||
else if e == 116 { ch = 9 }
|
||||
else if e == 114 { ch = 13 }
|
||||
else if e == 102 { ch = 12 }
|
||||
else if e == 118 { ch = 11 }
|
||||
else if e == 48 { ch = 0 }
|
||||
if e == 'n' { ch = 10 }
|
||||
else if e == 't' { ch = 9 }
|
||||
else if e == 'r' { ch = 13 }
|
||||
else if e == 'f' { ch = 12 }
|
||||
else if e == 'v' { ch = 11 }
|
||||
else if e == '0' { ch = 0 }
|
||||
else if e < 0 { rx_err = 1; return rx_node(N_EMPTY) }
|
||||
let node = rx_node(N_LIT)
|
||||
node.ch = ch
|
||||
|
|
@ -261,7 +261,7 @@ function rx_parse_concat() -> RNode {
|
|||
let cat = rx_node(N_CONCAT)
|
||||
while true {
|
||||
let c = rx_peek()
|
||||
if c < 0 or c == 124 or c == 41 { break }
|
||||
if c < 0 or c == '|' or c == ')' { break }
|
||||
push(cat.kids, rx_parse_repeat())
|
||||
if rx_err == 1 { break }
|
||||
}
|
||||
|
|
@ -278,17 +278,17 @@ function rx_parse_repeat() -> RNode {
|
|||
let atom = rx_parse_atom()
|
||||
if rx_err == 1 { return atom }
|
||||
let c = rx_peek()
|
||||
if c == 42 or c == 43 or c == 63 {
|
||||
if c == '*' or c == '+' or c == '?' {
|
||||
rx_adv()
|
||||
var op = N_STAR
|
||||
if c == 43 { op = N_PLUS }
|
||||
if c == 63 { op = N_QUEST }
|
||||
if c == '+' { op = N_PLUS }
|
||||
if c == '?' { op = N_QUEST }
|
||||
let r = rx_node(op)
|
||||
r.greedy = rx_lazy()
|
||||
push(r.kids, atom)
|
||||
return r
|
||||
}
|
||||
if c == 123 { return rx_parse_brace(atom) }
|
||||
if c == '{' { return rx_parse_brace(atom) }
|
||||
return atom
|
||||
}
|
||||
# {n} {n,} {n,m}
|
||||
|
|
@ -300,7 +300,7 @@ function rx_parse_brace(atom: RNode) -> RNode {
|
|||
while rx_peek() >= 48 and rx_peek() <= 57 { lo = lo * 10 + (rx_adv() - 48); haslo = true }
|
||||
var hi = lo
|
||||
var hasComma = false
|
||||
if rx_peek() == 44 { hasComma = true; rx_adv(); hi = 0 - 1
|
||||
if rx_peek() == 44 { hasComma = true; rx_adv(); hi = -1
|
||||
var hashi = false
|
||||
while rx_peek() >= 48 and rx_peek() <= 57 { if not hashi { hi = 0 }; hi = hi * 10 + (rx_adv() - 48); hashi = true }
|
||||
}
|
||||
|
|
@ -319,18 +319,18 @@ function rx_parse_brace(atom: RNode) -> RNode {
|
|||
}
|
||||
function rx_parse_atom() -> RNode {
|
||||
let c = rx_peek()
|
||||
if c == 40 { # '('
|
||||
if c == '(' { # '('
|
||||
rx_adv()
|
||||
var gidx = 0 - 1
|
||||
var gidx = -1
|
||||
if rx_peek() == 63 { # (? ...
|
||||
rx_adv()
|
||||
let d = rx_peek()
|
||||
if d == 58 { rx_adv() } # (?: non-capturing
|
||||
else if d == 80 { rx_adv(); rx_skip_name() } # (?P<name> (captured, name ignored for now)
|
||||
else if d == 60 { rx_skip_name() } # (?<name>
|
||||
if d == ':' { rx_adv() } # (?: non-capturing
|
||||
else if d == 'P' { rx_adv(); rx_skip_name() } # (?P<name> (captured, name ignored for now)
|
||||
else if d == '<' { rx_skip_name() } # (?<name>
|
||||
else { rx_err = 1; return rx_node(N_EMPTY) }
|
||||
} else {
|
||||
rx_ngroup = rx_ngroup + 1
|
||||
rx_ngroup += 1
|
||||
gidx = rx_ngroup
|
||||
}
|
||||
let inner = rx_parse_alt()
|
||||
|
|
@ -341,12 +341,12 @@ function rx_parse_atom() -> RNode {
|
|||
push(g.kids, inner)
|
||||
return g
|
||||
}
|
||||
if c == 91 { return rx_parse_class() }
|
||||
if c == 46 { rx_adv(); return rx_node(N_ANY) }
|
||||
if c == 94 { rx_adv(); return rx_node(N_BOL) }
|
||||
if c == 36 { rx_adv(); return rx_node(N_EOL) }
|
||||
if c == 92 { return rx_parse_escape() }
|
||||
if c == 42 or c == 43 or c == 63 or c == 41 { rx_err = 1; return rx_node(N_EMPTY) }
|
||||
if c == '[' { return rx_parse_class() }
|
||||
if c == '.' { rx_adv(); return rx_node(N_ANY) }
|
||||
if c == '^' { rx_adv(); return rx_node(N_BOL) }
|
||||
if c == '$' { rx_adv(); return rx_node(N_EOL) }
|
||||
if c == '\\' { return rx_parse_escape() }
|
||||
if c == '*' or c == '+' or c == '?' or c == ')' { rx_err = 1; return rx_node(N_EMPTY) }
|
||||
if c < 0 { rx_err = 1; return rx_node(N_EMPTY) }
|
||||
rx_adv()
|
||||
let n = rx_node(N_LIT)
|
||||
|
|
@ -359,7 +359,7 @@ function rx_skip_name() -> void {
|
|||
if rx_peek() == 60 { rx_adv() } # consume '<'
|
||||
while rx_peek() != 62 and rx_peek() >= 0 { rx_adv() }
|
||||
if rx_peek() == 62 { rx_adv() } # consume '>'
|
||||
rx_ngroup = rx_ngroup + 1
|
||||
rx_ngroup += 1
|
||||
# note: the caller set gidx = -1; fix it up to a real capture index
|
||||
rx_named_gidx = rx_ngroup
|
||||
}
|
||||
|
|
@ -387,7 +387,7 @@ function rx_compile(node: RNode) -> void {
|
|||
if op == N_EOL { pg_emit(OP_EOL, 0, 0); return }
|
||||
if op == N_CONCAT {
|
||||
var i = 0
|
||||
while i < len(node.kids) { rx_compile(node.kids[i]); i = i + 1 }
|
||||
while i < len(node.kids) { rx_compile(node.kids[i]); i += 1 }
|
||||
return
|
||||
}
|
||||
if op == N_GROUP {
|
||||
|
|
@ -414,11 +414,11 @@ function rx_compile(node: RNode) -> void {
|
|||
} else {
|
||||
rx_compile(node.kids[i])
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
let end = pg_pc()
|
||||
i = 0
|
||||
while i < jmps.n { pg_set_a(jmps.d[i], end); i = i + 1 }
|
||||
while i < jmps.n { pg_set_a(jmps.d[i], end); i += 1 }
|
||||
return
|
||||
}
|
||||
if op == N_STAR {
|
||||
|
|
@ -453,7 +453,7 @@ function rx_compile(node: RNode) -> void {
|
|||
if op == N_REP {
|
||||
let kid = node.kids[0]
|
||||
var i = 0
|
||||
while i < node.lo { rx_compile(kid); i = i + 1 }
|
||||
while i < node.lo { rx_compile(kid); i += 1 }
|
||||
if node.hi < 0 {
|
||||
let st = rx_node(N_STAR)
|
||||
st.greedy = node.greedy
|
||||
|
|
@ -466,7 +466,7 @@ function rx_compile(node: RNode) -> void {
|
|||
q.greedy = node.greedy
|
||||
push(q.kids, kid)
|
||||
rx_compile(q)
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
@ -503,4 +503,3 @@ function regex_compile(pattern: pointer) -> Prog {
|
|||
pg_emit(OP_MATCH, 0, 0)
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ function rx_add(list: TList, pc: int, caps: words, sp: int, s: pointer, slen: in
|
|||
let t = list.n
|
||||
list.pc[t] = pc
|
||||
var i = 0
|
||||
while i < rx_nc { list.caps[t * rx_nc + i] = caps[i]; i = i + 1 }
|
||||
list.n = list.n + 1
|
||||
while i < rx_nc { list.caps[t * rx_nc + i] = caps[i]; i += 1 }
|
||||
list.n += 1
|
||||
}
|
||||
|
||||
# run prog over s (length slen) from startpos; returns caps words or null
|
||||
|
|
@ -54,7 +54,7 @@ function rx_run(prog: Prog, s: pointer, slen: int, startpos: int) -> words {
|
|||
let ncode = prog.code.n / 3
|
||||
rx_seen = words(ncode)
|
||||
var i = 0
|
||||
while i < ncode { rx_seen[i] = 0; i = i + 1 }
|
||||
while i < ncode { rx_seen[i] = 0; i += 1 }
|
||||
rx_gen = 0
|
||||
var clist = new TList
|
||||
clist.pc = words(ncode); clist.caps = words(ncode * rx_nc); clist.n = 0
|
||||
|
|
@ -63,29 +63,29 @@ function rx_run(prog: Prog, s: pointer, slen: int, startpos: int) -> words {
|
|||
let wcaps = words(rx_nc)
|
||||
var matched: words = null
|
||||
|
||||
rx_gen = rx_gen + 1
|
||||
rx_gen += 1
|
||||
i = 0
|
||||
while i < rx_nc { wcaps[i] = 0 - 1; i = i + 1 }
|
||||
while i < rx_nc { wcaps[i] = -1; i += 1 }
|
||||
rx_add(clist, 0, wcaps, startpos, s, slen)
|
||||
|
||||
var sp = startpos
|
||||
while true {
|
||||
if clist.n == 0 { break }
|
||||
var c = 0 - 1
|
||||
var c = -1
|
||||
if sp < slen { c = s[sp] & 255 }
|
||||
nlist.n = 0
|
||||
rx_gen = rx_gen + 1
|
||||
rx_gen += 1
|
||||
var ti = 0
|
||||
var stop = false
|
||||
while ti < clist.n and not stop {
|
||||
let pc = clist.pc[ti]
|
||||
var k = 0
|
||||
while k < rx_nc { wcaps[k] = clist.caps[ti * rx_nc + k]; k = k + 1 }
|
||||
while k < rx_nc { wcaps[k] = clist.caps[ti * rx_nc + k]; k += 1 }
|
||||
let op = rx_code[3 * pc]
|
||||
if op == OP_CHAR {
|
||||
if c >= 0 and c == rx_code[3 * pc + 1] { rx_add(nlist, pc + 1, wcaps, sp + 1, s, slen) }
|
||||
} else if op == OP_ANY {
|
||||
if c >= 0 and c != 10 { rx_add(nlist, pc + 1, wcaps, sp + 1, s, slen) }
|
||||
if c >= 0 and c != '\n' { rx_add(nlist, pc + 1, wcaps, sp + 1, s, slen) }
|
||||
} else if op == OP_ANYNL {
|
||||
if c >= 0 { rx_add(nlist, pc + 1, wcaps, sp + 1, s, slen) }
|
||||
} else if op == OP_CLASS {
|
||||
|
|
@ -93,14 +93,14 @@ function rx_run(prog: Prog, s: pointer, slen: int, startpos: int) -> words {
|
|||
} else if op == OP_MATCH {
|
||||
if matched == null { matched = words(rx_nc) }
|
||||
k = 0
|
||||
while k < rx_nc { matched[k] = wcaps[k]; k = k + 1 }
|
||||
while k < rx_nc { matched[k] = wcaps[k]; k += 1 }
|
||||
stop = true
|
||||
}
|
||||
ti = ti + 1
|
||||
ti += 1
|
||||
}
|
||||
let tmp = clist; clist = nlist; nlist = tmp
|
||||
if sp >= slen { break }
|
||||
sp = sp + 1
|
||||
sp += 1
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
|
@ -143,11 +143,11 @@ function regex_next(str: pointer, re: Prog, from: int) -> Match {
|
|||
function regex_ok(m: Match) -> bool { return m != null }
|
||||
function regex_group_count(m: Match) -> int { if m == null { return 0 }; return m.ng }
|
||||
function regex_start(m: Match, n: int) -> int {
|
||||
if m == null or n < 0 or n > m.ng { return 0 - 1 }
|
||||
if m == null or n < 0 or n > m.ng { return -1 }
|
||||
return m.caps[2 * n]
|
||||
}
|
||||
function regex_end(m: Match, n: int) -> int {
|
||||
if m == null or n < 0 or n > m.ng { return 0 - 1 }
|
||||
if m == null or n < 0 or n > m.ng { return -1 }
|
||||
return m.caps[2 * n + 1]
|
||||
}
|
||||
function regex_group(m: Match, n: int) -> pointer {
|
||||
|
|
@ -157,7 +157,7 @@ function regex_group(m: Match, n: int) -> pointer {
|
|||
if a < 0 or b < 0 { return "" }
|
||||
let out = bytes(b - a + 1)
|
||||
var i = 0
|
||||
while i < b - a { out[i] = m.str[a + i]; i = i + 1 }
|
||||
while i < b - a { out[i] = m.str[a + i]; i += 1 }
|
||||
out[b - a] = 0
|
||||
return out
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@ function regex_valid(pattern: pointer) -> bool { return regex_compile(pattern) !
|
|||
# repl expands \0..\9 (groups; \0 = whole match) and \\ (a literal backslash).
|
||||
function rx_append(out: IVec, s: pointer, a: int, b: int) -> void {
|
||||
var i = a
|
||||
while i < b { iv_push(out, s[i] & 255); i = i + 1 }
|
||||
while i < b { iv_push(out, s[i] & 255); i += 1 }
|
||||
}
|
||||
function regex_replace(str: pointer, pattern: pointer, repl: pointer) -> pointer {
|
||||
let p = regex_compile(pattern)
|
||||
|
|
@ -186,16 +186,16 @@ function regex_replace(str: pointer, pattern: pointer, repl: pointer) -> pointer
|
|||
# expand replacement
|
||||
var i = 0
|
||||
while i < rn {
|
||||
if repl[i] == 92 and i + 1 < rn {
|
||||
if repl[i] == '\\' and i + 1 < rn {
|
||||
let d = repl[i + 1] & 255
|
||||
if d >= 48 and d <= 57 {
|
||||
if d >= '0' and d <= '9' {
|
||||
let g = d - 48
|
||||
if g <= p.ngroups { let a = caps[2 * g]; let b = caps[2 * g + 1]; if a >= 0 and b >= 0 { rx_append(out, str, a, b) } }
|
||||
i = i + 2
|
||||
} else if d == 92 { iv_push(out, 92); i = i + 2 }
|
||||
else { iv_push(out, d); i = i + 2 }
|
||||
i += 2
|
||||
} else if d == '\\' { iv_push(out, 92); i += 2 }
|
||||
else { iv_push(out, d); i += 2 }
|
||||
} else {
|
||||
iv_push(out, repl[i] & 255); i = i + 1
|
||||
iv_push(out, repl[i] & 255); i += 1
|
||||
}
|
||||
}
|
||||
prev = me
|
||||
|
|
@ -204,8 +204,7 @@ function regex_replace(str: pointer, pattern: pointer, repl: pointer) -> pointer
|
|||
rx_append(out, str, prev, n) # trailing text
|
||||
let res = bytes(out.n + 1)
|
||||
var i = 0
|
||||
while i < out.n { res[i] = out.d[i]; i = i + 1 }
|
||||
while i < out.n { res[i] = out.d[i]; i += 1 }
|
||||
res[out.n] = 0
|
||||
return res
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ function anim_clip(name: pointer, frames: int, fps: int, mode: int) -> void {
|
|||
anim_clip_frames[i] = frames; anim_clip_fps[i] = fps; anim_clip_mode[i] = mode
|
||||
return
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if anim_nclips >= ANIM_MAX_CLIPS { return } # silently ignore past capacity
|
||||
let s = anim_nclips
|
||||
|
|
@ -68,7 +68,7 @@ function anim_clip(name: pointer, frames: int, fps: int, mode: int) -> void {
|
|||
anim_clip_frames[s] = frames
|
||||
anim_clip_fps[s] = fps
|
||||
anim_clip_mode[s] = mode
|
||||
anim_nclips = anim_nclips + 1
|
||||
anim_nclips += 1
|
||||
}
|
||||
|
||||
function anim_clip_find(name: pointer) -> int {
|
||||
|
|
@ -76,9 +76,9 @@ function anim_clip_find(name: pointer) -> int {
|
|||
var i = 0
|
||||
while i < anim_nclips {
|
||||
if anim_clip_names[i] == name { return i }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# ---- Anim.play / Anim.on_frame / Anim.fired (#48) --------------------------
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ function esys_bounds() -> void {
|
|||
if y < by { y = by; hity = 1 }
|
||||
if y + h > y1 { y = y1 - h; hity = 1 }
|
||||
if pol == BND_BOUNCE {
|
||||
if (hitx == 1) and (f_vx >= 0) { World.set(e, PBody, f_vx, 0 - World.get(e, PBody, f_vx)) }
|
||||
if (hity == 1) and (f_vy >= 0) { World.set(e, PBody, f_vy, 0 - World.get(e, PBody, f_vy)) }
|
||||
if (hitx == 1) and (f_vx >= 0) { World.set(e, PBody, f_vx, -World.get(e, PBody, f_vx)) }
|
||||
if (hity == 1) and (f_vy >= 0) { World.set(e, PBody, f_vy, -World.get(e, PBody, f_vy)) }
|
||||
}
|
||||
}
|
||||
World.set(e, PP, fx, x)
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ function esys_light2d() -> void {
|
|||
light_set_soft(soft)
|
||||
if lgf >= 0 { light_set_gel(World.get(e, pl, lgf)) } else { light_clear_gel() }
|
||||
|
||||
var spread = 0 - 1
|
||||
var spread = -1
|
||||
if lsf >= 0 { spread = World.get(e, pl, lsf) }
|
||||
var direction = 0
|
||||
if ldf >= 0 { direction = World.get(e, pl, ldf) }
|
||||
|
|
|
|||
|
|
@ -60,18 +60,18 @@
|
|||
const PHYS_ONE: int = 65536 # Q16.16 one whole pixel
|
||||
|
||||
# ---- per-frame config + reflected ids (filled at the top of esys_move) -------
|
||||
var pm_pos: int = 0 - 1 # Position prop id
|
||||
var pm_pos_x: int = 0 - 1
|
||||
var pm_pos_y: int = 0 - 1
|
||||
var pm_col: int = 0 - 1 # Collider prop id
|
||||
var pm_c_w: int = 0 - 1
|
||||
var pm_c_h: int = 0 - 1
|
||||
var pm_c_offx: int = 0 - 1
|
||||
var pm_c_offy: int = 0 - 1
|
||||
var pm_c_trig: int = 0 - 1
|
||||
var pm_c_oneway: int = 0 - 1
|
||||
var pm_c_layer: int = 0 - 1
|
||||
var pm_c_mask: int = 0 - 1
|
||||
var pm_pos: int = -1 # Position prop id
|
||||
var pm_pos_x: int = -1
|
||||
var pm_pos_y: int = -1
|
||||
var pm_col: int = -1 # Collider prop id
|
||||
var pm_c_w: int = -1
|
||||
var pm_c_h: int = -1
|
||||
var pm_c_offx: int = -1
|
||||
var pm_c_offy: int = -1
|
||||
var pm_c_trig: int = -1
|
||||
var pm_c_oneway: int = -1
|
||||
var pm_c_layer: int = -1
|
||||
var pm_c_mask: int = -1
|
||||
var phys_ts: int = 0 # tile size px (0 = grid off)
|
||||
var phys_wall: int = 0 # solid glyph
|
||||
var phys_wall2: int = 0 # optional second solid glyph (Solids.solid2), e.g. a closed door
|
||||
|
|
@ -96,7 +96,7 @@ var phys_trig_prev: words = null
|
|||
function phys_floordiv(a: int, b: int) -> int {
|
||||
var q = a / b
|
||||
let r = a - q * b
|
||||
if (r != 0) and ((a < 0) != (b < 0)) { q = q - 1 }
|
||||
if (r != 0) and ((a < 0) != (b < 0)) { q -= 1 }
|
||||
return q
|
||||
}
|
||||
|
||||
|
|
@ -123,13 +123,13 @@ function phys_tile_oneway(c: int, r: int) -> bool {
|
|||
# is any full-solid tile present in column c over the row span [r0, r1]?
|
||||
function phys_col_solid(c: int, r0: int, r1: int) -> bool {
|
||||
var r = r0
|
||||
while r <= r1 { if phys_tile_solid(c, r) { return true }; r = r + 1 }
|
||||
while r <= r1 { if phys_tile_solid(c, r) { return true }; r += 1 }
|
||||
return false
|
||||
}
|
||||
# is any full-solid tile present in row r over the column span [c0, c1]?
|
||||
function phys_row_solid(r: int, c0: int, c1: int) -> bool {
|
||||
var c = c0
|
||||
while c <= c1 { if phys_tile_solid(c, r) { return true }; c = c + 1 }
|
||||
while c <= c1 { if phys_tile_solid(c, r) { return true }; c += 1 }
|
||||
return false
|
||||
}
|
||||
# is any full-OR-one-way tile present in row r over [c0, c1]? (downward landings)
|
||||
|
|
@ -138,7 +138,7 @@ function phys_row_land(r: int, c0: int, c1: int) -> bool {
|
|||
while c <= c1 {
|
||||
if phys_tile_solid(c, r) { return true }
|
||||
if phys_tile_oneway(c, r) { return true }
|
||||
c = c + 1
|
||||
c += 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -147,10 +147,10 @@ function phys_row_land(r: int, c0: int, c1: int) -> bool {
|
|||
# 0 mask reads as "all" (all-ones), so default-0 components still collide.
|
||||
function phys_match(la: int, ma: int, lb: int, mb: int) -> bool {
|
||||
var al = la; var bl = lb; var am = ma; var bm = mb
|
||||
if al == 0 { al = 0 - 1 }
|
||||
if bl == 0 { bl = 0 - 1 }
|
||||
if am == 0 { am = 0 - 1 }
|
||||
if bm == 0 { bm = 0 - 1 }
|
||||
if al == 0 { al = -1 }
|
||||
if bl == 0 { bl = -1 }
|
||||
if am == 0 { am = -1 }
|
||||
if bm == 0 { bm = -1 }
|
||||
if (am & bl) == 0 { return false }
|
||||
if (bm & al) == 0 { return false }
|
||||
return true
|
||||
|
|
@ -223,7 +223,7 @@ function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) ->
|
|||
let allow = c * ts - (px + w)
|
||||
if allow < best { best = allow }
|
||||
c = endc + 1 # nearest wins; stop
|
||||
} else { c = c + 1 }
|
||||
} else { c += 1 }
|
||||
}
|
||||
} else {
|
||||
let startc = phys_floordiv(px, ts)
|
||||
|
|
@ -234,7 +234,7 @@ function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) ->
|
|||
let allow = (c + 1) * ts - px
|
||||
if allow > best { best = allow }
|
||||
c = endc - 1 # nearest wins; stop
|
||||
} else { c = c - 1 }
|
||||
} else { c -= 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -305,7 +305,7 @@ function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) ->
|
|||
let allow = r * ts - (py + h)
|
||||
if allow < best { best = allow }
|
||||
r = endr + 1
|
||||
} else { r = r + 1 }
|
||||
} else { r += 1 }
|
||||
}
|
||||
} else {
|
||||
let startr = phys_floordiv(py, ts)
|
||||
|
|
@ -316,7 +316,7 @@ function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) ->
|
|||
let allow = (r + 1) * ts - py
|
||||
if allow > best { best = allow }
|
||||
r = endr - 1
|
||||
} else { r = r - 1 }
|
||||
} else { r -= 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -429,7 +429,7 @@ function esys_move() -> void {
|
|||
var vy = 0; if f_vy >= 0 { vy = World.get(e, pb, f_vy) }
|
||||
var policy = 0; if f_pol >= 0 { policy = World.get(e, pb, f_pol) }
|
||||
if policy != 1 {
|
||||
if f_grav >= 0 { vy = vy + World.get(e, pb, f_grav) }
|
||||
if f_grav >= 0 { vy += World.get(e, pb, f_grav) }
|
||||
if f_maxf >= 0 {
|
||||
let mf = World.get(e, pb, f_maxf)
|
||||
if (mf > 0) and (vy > mf) { vy = mf }
|
||||
|
|
@ -476,9 +476,9 @@ function esys_move() -> void {
|
|||
phys_set_y(e, phys_pos_y(e) + cdy)
|
||||
|
||||
# derived flags + contact normal
|
||||
if phys_hit_x == 1 { hit_wall = 1; vx = 0; if dx > 0 { nx = 0 - 1 } else { nx = 1 } }
|
||||
if phys_hit_x == 1 { hit_wall = 1; vx = 0; if dx > 0 { nx = -1 } else { nx = 1 } }
|
||||
if phys_hit_up == 1 { hit_ceiling = 1; vy = 0; ny = 1 }
|
||||
if phys_hit_down == 1 { vy = 0; ny = 0 - 1 }
|
||||
if phys_hit_down == 1 { vy = 0; ny = -1 }
|
||||
let gy = phys_aabb_y(e)
|
||||
if phys_grounded(e, px, gy, w, h) { on_ground = 1 }
|
||||
# a body pressed onto the ground carries no downward velocity, whatever
|
||||
|
|
@ -531,7 +531,7 @@ function esys_triggers() -> void {
|
|||
let tx = phys_aabb_x(t); let ty = phys_aabb_y(t)
|
||||
let tw = phys_c_int(t, pm_c_w); let th = phys_c_int(t, pm_c_h)
|
||||
let tl = phys_c_int(t, pm_c_layer); let tm = phys_c_int(t, pm_c_mask)
|
||||
var cur = 0 - 1
|
||||
var cur = -1
|
||||
var b = World.query_next(pm_col, 0)
|
||||
while b >= 0 {
|
||||
if b != t {
|
||||
|
|
|
|||
|
|
@ -57,17 +57,17 @@ function esys_sprite() -> void {
|
|||
let f_atlas = World.field_id(P, "atlas")
|
||||
|
||||
let SA = World.prop_id("SpriteAnim")
|
||||
var f_frame = 0 - 1
|
||||
var f_frame = -1
|
||||
if SA >= 0 { f_frame = World.field_id(SA, "frame") }
|
||||
let f_move = World.field_id(P, "move_id")
|
||||
let f_face = World.field_id(P, "face")
|
||||
let f_flash = World.field_id(P, "flash")
|
||||
let f_blink = World.field_id(P, "blink")
|
||||
let TD = World.prop_id("TopDown")
|
||||
var f_wx = 0 - 1; var f_wy = 0 - 1
|
||||
var f_wx = -1; var f_wy = -1
|
||||
if TD >= 0 { f_wx = World.field_id(TD, "want_x"); f_wy = World.field_id(TD, "want_y") }
|
||||
let PB = World.prop_id("Body")
|
||||
var f_vx = 0 - 1; var f_vy = 0 - 1
|
||||
var f_vx = -1; var f_vy = -1
|
||||
if PB >= 0 { f_vx = World.field_id(PB, "vx"); f_vy = World.field_id(PB, "vy") }
|
||||
|
||||
var e = World.query_next(P, 0)
|
||||
|
|
@ -94,12 +94,12 @@ function esys_sprite() -> void {
|
|||
}
|
||||
# add the current animation frame when the entity also carries SpriteAnim.
|
||||
if (SA >= 0) and (f_frame >= 0) {
|
||||
if World.has(e, SA) != 0 { id = id + World.get(e, SA, f_frame) }
|
||||
if World.has(e, SA) != 0 { id += World.get(e, SA, f_frame) }
|
||||
}
|
||||
var x = spr_pos(e, 0)
|
||||
var y = spr_pos(e, 1)
|
||||
if f_offx >= 0 { x = x + World.get(e, P, f_offx) }
|
||||
if f_offy >= 0 { y = y + World.get(e, P, f_offy) }
|
||||
if f_offx >= 0 { x += World.get(e, P, f_offx) }
|
||||
if f_offy >= 0 { y += World.get(e, P, f_offy) }
|
||||
var sc = 1
|
||||
if f_scale >= 0 { let sv = World.get(e, P, f_scale); if sv > 1 { sc = sv } }
|
||||
var flip = 0
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ function esys_tileskin() -> void {
|
|||
if is_atlas != 0 { atlas_draw_ex(sprite, tx * size, ty * size, sc, 0, 0) }
|
||||
else { rt_draw_sprite_ex(sprite, tx * size, ty * size, sc, 0, 0) }
|
||||
}
|
||||
tx = tx + 1
|
||||
tx += 1
|
||||
}
|
||||
ty = ty + 1
|
||||
ty += 1
|
||||
}
|
||||
e = World.query_next(P, e + 1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ function tiled_csv_list(text: pointer) -> Val {
|
|||
var have = 0
|
||||
while i < n {
|
||||
let c = text[i]
|
||||
if c >= 48 and c <= 57 { cur = cur * 10 + (c - 48); have = 1 }
|
||||
if c >= '0' and c <= '9' { cur = cur * 10 + (c - 48); have = 1 }
|
||||
else {
|
||||
if c == 44 or c == 32 or c == 9 or c == 10 or c == 13 {
|
||||
if c == ',' or c == ' ' or c == '\t' or c == '\n' or c == '\r' {
|
||||
if have == 1 { push(out.kids, value_int(cur)); cur = 0; have = 0 }
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if have == 1 { push(out.kids, value_int(cur)) }
|
||||
return out
|
||||
|
|
@ -59,7 +59,7 @@ function tiled_b64_list(text: pointer, compression: pointer, count: int) -> Val
|
|||
while i + 3 < rawlen {
|
||||
let g = raw[i] | (raw[i + 1] << 8) | (raw[i + 2] << 16) | (raw[i + 3] << 24)
|
||||
push(out.kids, value_int(g))
|
||||
i = i + 4
|
||||
i += 4
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
@ -83,8 +83,8 @@ function tiled_chunked_layer(data: Xml, o: Val) -> void {
|
|||
# pass 1: bounds over every chunk (tile coordinates)
|
||||
var minx = 1000000000
|
||||
var miny = 1000000000
|
||||
var maxx = 0 - 1000000000
|
||||
var maxy = 0 - 1000000000
|
||||
var maxx = -1000000000
|
||||
var maxy = -1000000000
|
||||
var i = 0
|
||||
while i < xml_child_count(data) {
|
||||
let ch = xml_child(data, i)
|
||||
|
|
@ -96,13 +96,13 @@ function tiled_chunked_layer(data: Xml, o: Val) -> void {
|
|||
if cx + xml_attr_int(ch, "width", 0) > maxx { maxx = cx + xml_attr_int(ch, "width", 0) }
|
||||
if cy + xml_attr_int(ch, "height", 0) > maxy { maxy = cy + xml_attr_int(ch, "height", 0) }
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
let W = maxx - minx
|
||||
let H = maxy - miny
|
||||
let gids = value_list()
|
||||
var k = 0
|
||||
while k < W * H { push(gids.kids, value_int(0)); k = k + 1 }
|
||||
while k < W * H { push(gids.kids, value_int(0)); k += 1 }
|
||||
# pass 2: place each chunk's decoded data at its offset
|
||||
i = 0
|
||||
while i < xml_child_count(data) {
|
||||
|
|
@ -118,12 +118,12 @@ function tiled_chunked_layer(data: Xml, o: Val) -> void {
|
|||
var xx = 0
|
||||
while xx < cw {
|
||||
gids.kids[(cy + yy) * W + (cx + xx)] = value_at(cdata, yy * cw + xx)
|
||||
xx = xx + 1
|
||||
xx += 1
|
||||
}
|
||||
yy = yy + 1
|
||||
yy += 1
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
value_put(o, "width", value_int(W))
|
||||
value_put(o, "height", value_int(H))
|
||||
|
|
@ -152,7 +152,7 @@ function tmx_props_list(parent: Xml) -> Val {
|
|||
value_put(o, "value", value_str(v))
|
||||
push(out.kids, o)
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
@ -201,18 +201,18 @@ function tmx_points_list(s: pointer) -> Val {
|
|||
let n = len(s)
|
||||
var i = 0
|
||||
while i < n {
|
||||
while i < n and (s[i] == 32 or s[i] == 9) { i = i + 1 }
|
||||
while i < n and (s[i] == ' ' or s[i] == '\t') { i += 1 }
|
||||
if i >= n { break }
|
||||
# read "x,y"
|
||||
var xv = 0; var xn = 0; var xs = 0
|
||||
if s[i] == 45 { xs = 1; i = i + 1 }
|
||||
while i < n and s[i] >= 48 and s[i] <= 57 { xv = xv * 10 + (s[i] - 48); xn = 1; i = i + 1 }
|
||||
if xs == 1 { xv = 0 - xv }
|
||||
if i < n and s[i] == 44 { i = i + 1 }
|
||||
if s[i] == '-' { xs = 1; i += 1 }
|
||||
while i < n and s[i] >= '0' and s[i] <= '9' { xv = xv * 10 + (s[i] - 48); xn = 1; i += 1 }
|
||||
if xs == 1 { xv = -xv }
|
||||
if i < n and s[i] == ',' { i += 1 }
|
||||
var yv = 0; var ys = 0
|
||||
if i < n and s[i] == 45 { ys = 1; i = i + 1 }
|
||||
while i < n and s[i] >= 48 and s[i] <= 57 { yv = yv * 10 + (s[i] - 48); i = i + 1 }
|
||||
if ys == 1 { yv = 0 - yv }
|
||||
if i < n and s[i] == '-' { ys = 1; i += 1 }
|
||||
while i < n and s[i] >= '0' and s[i] <= '9' { yv = yv * 10 + (s[i] - 48); i += 1 }
|
||||
if ys == 1 { yv = -yv }
|
||||
if xn == 1 {
|
||||
let o = value_object()
|
||||
value_put(o, "x", value_int(xv))
|
||||
|
|
@ -252,7 +252,7 @@ function tmx_tile_to_value(t: Xml) -> Val {
|
|||
value_put(f, "duration", value_int(xml_attr_int(fr, "duration", 0)))
|
||||
push(frames.kids, f)
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
value_put(o, "animation", frames)
|
||||
}
|
||||
|
|
@ -264,7 +264,7 @@ function tmx_tile_to_value(t: Xml) -> Val {
|
|||
while j < xml_child_count(og) {
|
||||
let ch = xml_child(og, j)
|
||||
if xml_tag(ch) == "object" { push(objs.kids, tmx_object_to_value(ch)) }
|
||||
j = j + 1
|
||||
j += 1
|
||||
}
|
||||
let ogo = value_object()
|
||||
value_put(ogo, "objects", objs)
|
||||
|
|
@ -296,7 +296,7 @@ function tmx_fill_tileset(o: Val, ts: Xml) -> void {
|
|||
while i < xml_child_count(ts) {
|
||||
let ch = xml_child(ts, i)
|
||||
if xml_tag(ch) == "tile" { push(tiles.kids, tmx_tile_to_value(ch)) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
if len(tiles.kids) > 0 { value_put(o, "tiles", tiles) }
|
||||
}
|
||||
|
|
@ -366,7 +366,7 @@ function tmx_objectlayer_to_value(el: Xml) -> Val {
|
|||
while i < xml_child_count(el) {
|
||||
let ch = xml_child(el, i)
|
||||
if xml_tag(ch) == "object" { push(objs.kids, tmx_object_to_value(ch)) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
value_put(o, "objects", objs)
|
||||
return o
|
||||
|
|
@ -402,7 +402,7 @@ function tmx_to_value(root: Xml) -> Val {
|
|||
else { if tag == "objectgroup" { push(layers.kids, tmx_objectlayer_to_value(ch)) }
|
||||
else { if tag == "imagelayer" { push(layers.kids, tmx_imagelayer_to_value(ch)) }
|
||||
else { if tag == "group" { push(layers.kids, tmx_group_to_value(ch, mapw, maph)) } } } } }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
let props = tmx_props_list(root)
|
||||
if len(props.kids) > 0 { value_put(m, "properties", props) }
|
||||
|
|
@ -437,7 +437,7 @@ function tmx_group_to_value(el: Xml, mapw: int, maph: int) -> Val {
|
|||
else { if tag == "objectgroup" { push(layers.kids, tmx_objectlayer_to_value(ch)) }
|
||||
else { if tag == "imagelayer" { push(layers.kids, tmx_imagelayer_to_value(ch)) }
|
||||
else { if tag == "group" { push(layers.kids, tmx_group_to_value(ch, mapw, maph)) } } } }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
value_put(o, "layers", layers)
|
||||
return o
|
||||
|
|
@ -453,7 +453,7 @@ function tmj_normalize_layer(layer: Val) -> void {
|
|||
if ty == "group" {
|
||||
let ls = value_get(layer, "layers")
|
||||
var i = 0
|
||||
while i < value_count(ls) { tmj_normalize_layer(value_at(ls, i)); i = i + 1 }
|
||||
while i < value_count(ls) { tmj_normalize_layer(value_at(ls, i)); i += 1 }
|
||||
return
|
||||
}
|
||||
if ty != "tilelayer" { return }
|
||||
|
|
@ -484,8 +484,8 @@ function tmj_chunk_gids(chunk: Val, enc: pointer, comp: pointer, count: int) ->
|
|||
function tmj_flatten_chunks(layer: Val, chunks: Val, enc: pointer, comp: pointer) -> void {
|
||||
var minx = 1000000000
|
||||
var miny = 1000000000
|
||||
var maxx = 0 - 1000000000
|
||||
var maxy = 0 - 1000000000
|
||||
var maxx = -1000000000
|
||||
var maxy = -1000000000
|
||||
var i = 0
|
||||
while i < value_count(chunks) {
|
||||
let c = value_at(chunks, i)
|
||||
|
|
@ -495,13 +495,13 @@ function tmj_flatten_chunks(layer: Val, chunks: Val, enc: pointer, comp: pointer
|
|||
if cy < miny { miny = cy }
|
||||
if cx + value_as_int(value_get(c, "width")) > maxx { maxx = cx + value_as_int(value_get(c, "width")) }
|
||||
if cy + value_as_int(value_get(c, "height")) > maxy { maxy = cy + value_as_int(value_get(c, "height")) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
let W = maxx - minx
|
||||
let H = maxy - miny
|
||||
let gids = value_list()
|
||||
var k = 0
|
||||
while k < W * H { push(gids.kids, value_int(0)); k = k + 1 }
|
||||
while k < W * H { push(gids.kids, value_int(0)); k += 1 }
|
||||
i = 0
|
||||
while i < value_count(chunks) {
|
||||
let c = value_at(chunks, i)
|
||||
|
|
@ -515,11 +515,11 @@ function tmj_flatten_chunks(layer: Val, chunks: Val, enc: pointer, comp: pointer
|
|||
var xx = 0
|
||||
while xx < cw {
|
||||
gids.kids[(cy + yy) * W + (cx + xx)] = value_at(cdata, yy * cw + xx)
|
||||
xx = xx + 1
|
||||
xx += 1
|
||||
}
|
||||
yy = yy + 1
|
||||
yy += 1
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
value_put(layer, "width", value_int(W))
|
||||
value_put(layer, "height", value_int(H))
|
||||
|
|
@ -529,7 +529,7 @@ function tmj_flatten_chunks(layer: Val, chunks: Val, enc: pointer, comp: pointer
|
|||
function tmj_normalize(m: Val) -> Val {
|
||||
let ls = value_get(m, "layers")
|
||||
var i = 0
|
||||
while i < value_count(ls) { tmj_normalize_layer(value_at(ls, i)); i = i + 1 }
|
||||
while i < value_count(ls) { tmj_normalize_layer(value_at(ls, i)); i += 1 }
|
||||
return m
|
||||
}
|
||||
|
||||
|
|
@ -540,7 +540,7 @@ function tiled_first_byte(s: pointer) -> int {
|
|||
let n = len(s)
|
||||
while i < n {
|
||||
let c = s[i]
|
||||
if c == 32 or c == 9 or c == 10 or c == 13 { i = i + 1 } else { return c }
|
||||
if c == ' ' or c == '\t' or c == '\n' or c == '\r' { i += 1 } else { return c }
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -580,7 +580,7 @@ property TmTileset {
|
|||
spacing: int = 0
|
||||
margin: int = 0
|
||||
tilecount: int = 0
|
||||
imgid: int = 0 - 1 # loaded image handle (rt_image_load), -1 = none
|
||||
imgid: int = -1 # loaded image handle (rt_image_load), -1 = none
|
||||
meta: Val # the tileset Value object (per-tile metadata)
|
||||
}
|
||||
|
||||
|
|
@ -590,7 +590,7 @@ property TmLayer {
|
|||
w: int = 0
|
||||
h: int = 0
|
||||
visible: int = 1
|
||||
imgid: int = 0 - 1 # loaded image handle (imagelayer only), -1 = none
|
||||
imgid: int = -1 # loaded image handle (imagelayer only), -1 = none
|
||||
gids: []int # dense w*h GID array (tilelayer only)
|
||||
data: Val # the layer Value object (objects, image, …)
|
||||
}
|
||||
|
|
@ -604,12 +604,12 @@ property Tmap {
|
|||
layers: []TmLayer
|
||||
tilesets: []TmTileset
|
||||
tree: Val # the source intermediate tree
|
||||
coll: int = 0 - 1 # designated collision layer index, or -1
|
||||
coll: int = -1 # designated collision layer index, or -1
|
||||
}
|
||||
|
||||
# ---- GID resolver ----------------------------------------------------------
|
||||
property GidInfo {
|
||||
tileset: int = 0 - 1 # index into Tmap.tilesets (-1 = none/empty)
|
||||
tileset: int = -1 # index into Tmap.tilesets (-1 = none/empty)
|
||||
local: int = 0 # local tile id within that tileset
|
||||
fh: int = 0 # horizontal flip
|
||||
fv: int = 0 # vertical flip
|
||||
|
|
@ -622,7 +622,7 @@ property GidInfo {
|
|||
# whose firstgid is the greatest not exceeding it. gid == 0 is the empty cell.
|
||||
function tmap_resolve(m: Tmap, gid: int) -> GidInfo {
|
||||
let r = new GidInfo
|
||||
if gid == 0 { r.empty = 1; r.tileset = 0 - 1; return r }
|
||||
if gid == 0 { r.empty = 1; r.tileset = -1; return r }
|
||||
let H = 1 << 31
|
||||
let V = 1 << 30
|
||||
let D = 1 << 29
|
||||
|
|
@ -630,13 +630,13 @@ function tmap_resolve(m: Tmap, gid: int) -> GidInfo {
|
|||
if (gid & V) != 0 { r.fv = 1 }
|
||||
if (gid & D) != 0 { r.fd = 1 }
|
||||
let id = gid & 536870911 # low 29 bits = global tile id
|
||||
var best = 0 - 1
|
||||
var best = -1
|
||||
var bestfg = 0
|
||||
var i = 0
|
||||
while i < len(m.tilesets) {
|
||||
let fg = m.tilesets[i].firstgid
|
||||
if fg <= id and fg >= bestfg { bestfg = fg; best = i }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
r.tileset = best
|
||||
if best >= 0 { r.local = id - m.tilesets[best].firstgid }
|
||||
|
|
@ -678,7 +678,7 @@ function tmap_tile_meta(m: Tmap, gid: int) -> Val {
|
|||
while i < value_count(tiles) {
|
||||
let t = value_at(tiles, i)
|
||||
if value_as_int(value_get(t, "id")) == r.local { return t }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return value_null()
|
||||
}
|
||||
|
|
@ -696,7 +696,7 @@ function tmap_tile_prop(m: Tmap, gid: int, name: pointer) -> int {
|
|||
if value_as_str(value_get(p, "value")) == "true" { return 1 }
|
||||
return 0
|
||||
}
|
||||
j = j + 1
|
||||
j += 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
@ -750,14 +750,14 @@ function tmap_project_layer(m: Tmap, layer: int, whole_layer_solid: int) -> void
|
|||
if gid != 0 {
|
||||
var k = tmap_collision_kind(m, gid)
|
||||
if k == 0 and whole_layer_solid != 0 { k = 1 } # collision-layer fallback
|
||||
if k == 1 { rt_map[y * 96 + x] = 35 } # '#'
|
||||
if k == 2 { rt_map[y * 96 + x] = 61 } # '='
|
||||
if k == 1 { rt_map[y * 96 + x] = '#' } # '#'
|
||||
if k == 2 { rt_map[y * 96 + x] = '=' } # '='
|
||||
}
|
||||
}
|
||||
x = x + 1
|
||||
x += 1
|
||||
}
|
||||
}
|
||||
y = y + 1
|
||||
y += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -775,9 +775,9 @@ function tmap_find_collision(m: Tmap) -> int {
|
|||
while i < len(m.layers) {
|
||||
let n = m.layers[i].name
|
||||
if m.layers[i].kind == 0 and (n == "collision" or n == "solids" or n == "walls" or n == "Collision" or n == "Solids") { return i }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# ---- rendering -------------------------------------------------------------
|
||||
|
|
@ -799,9 +799,9 @@ function tmap_blit_tile(imgid: int, sx: int, sy: int, tw: int, th: int, dx: int,
|
|||
if fv == 1 { v = th - 1 - v }
|
||||
let argb = s[(sy + v) * iw + (sx + u)]
|
||||
rt_blend_px(dx + i, dy + j, argb)
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
j = j + 1
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -832,7 +832,7 @@ function tmap_gids_from_layer(lv: Val) -> []int {
|
|||
let out = new []int
|
||||
let data = value_get(lv, "data")
|
||||
var i = 0
|
||||
while i < value_count(data) { push(out, value_as_int(value_at(data, i))); i = i + 1 }
|
||||
while i < value_count(data) { push(out, value_as_int(value_at(data, i))); i += 1 }
|
||||
return out
|
||||
}
|
||||
|
||||
|
|
@ -887,12 +887,12 @@ function tmap_build(tree: Val, basedir: pointer) -> Tmap {
|
|||
let img = value_as_str(value_get(tv, "image"))
|
||||
if img != "" { ts.imgid = rt_image_load(tiled_join(imgdir, img)) }
|
||||
push(m.tilesets, ts)
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
# layers (flat; groups' children are lifted so tile layers render/resolve)
|
||||
let ls = value_get(tree, "layers")
|
||||
i = 0
|
||||
while i < value_count(ls) { tmap_add_layer(m, value_at(ls, i)); i = i + 1 }
|
||||
while i < value_count(ls) { tmap_add_layer(m, value_at(ls, i)); i += 1 }
|
||||
# image layers (#73): load each <imagelayer> image relative to the map file
|
||||
i = 0
|
||||
while i < len(m.layers) {
|
||||
|
|
@ -900,7 +900,7 @@ function tmap_build(tree: Val, basedir: pointer) -> Tmap {
|
|||
let img = value_as_str(value_get(m.layers[i].data, "image"))
|
||||
if img != "" { m.layers[i].imgid = rt_image_load(tiled_join(basedir, img)) }
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
# infinite map (#74): the header w/h are 0 — take the flattened layer bounds.
|
||||
if m.w <= 0 or m.h <= 0 {
|
||||
|
|
@ -912,7 +912,7 @@ function tmap_build(tree: Val, basedir: pointer) -> Tmap {
|
|||
if m.layers[i].w > mw { mw = m.layers[i].w }
|
||||
if m.layers[i].h > mh { mh = m.layers[i].h }
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
m.w = mw
|
||||
m.h = mh
|
||||
|
|
@ -954,7 +954,7 @@ function tmap_add_layer(m: Tmap, lv: Val) -> void {
|
|||
l.kind = 3; push(m.layers, l)
|
||||
let sub = value_get(lv, "layers")
|
||||
var i = 0
|
||||
while i < value_count(sub) { tmap_add_layer(m, value_at(sub, i)); i = i + 1 }
|
||||
while i < value_count(sub) { tmap_add_layer(m, value_at(sub, i)); i += 1 }
|
||||
return
|
||||
}
|
||||
push(m.layers, l)
|
||||
|
|
@ -1005,7 +1005,7 @@ function tmap_frame_gid(m: Tmap, gid: int, frame: int) -> int {
|
|||
if nfr == 0 { return gid }
|
||||
var total = 0
|
||||
var i = 0
|
||||
while i < nfr { total = total + value_as_int(value_get(value_at(anim, i), "duration")); i = i + 1 }
|
||||
while i < nfr { total = total + value_as_int(value_get(value_at(anim, i), "duration")); i += 1 }
|
||||
if total <= 0 { return gid }
|
||||
let t_ms = (frame * 1000 / 60) % total
|
||||
var cur = value_as_int(value_get(value_at(anim, 0), "tileid"))
|
||||
|
|
@ -1015,7 +1015,7 @@ function tmap_frame_gid(m: Tmap, gid: int, frame: int) -> int {
|
|||
let fr = value_at(anim, i)
|
||||
acc = acc + value_as_int(value_get(fr, "duration"))
|
||||
if t_ms < acc { cur = value_as_int(value_get(fr, "tileid")); i = nfr }
|
||||
else { i = i + 1 }
|
||||
else { i += 1 }
|
||||
}
|
||||
let ts = m.tilesets[r.tileset]
|
||||
return (ts.firstgid + cur) | tmap_flag_bits(gid)
|
||||
|
|
@ -1049,9 +1049,9 @@ function tmap_draw_full(m: Tmap, camx: int, camy: int, frame: int, animate: int)
|
|||
# orientation transform places the cell (orthogonal / iso / hex / staggered)
|
||||
tmap_draw_gid(m, gid, tmap_cell_sx(m, x, y) + lox - camx, tmap_cell_sy(m, x, y) + loy - camy)
|
||||
}
|
||||
x = x + 1
|
||||
x += 1
|
||||
}
|
||||
y = y + 1
|
||||
y += 1
|
||||
}
|
||||
}
|
||||
if l.kind == 2 and l.visible != 0 { # image layer (parallax / repeat)
|
||||
|
|
@ -1070,10 +1070,10 @@ function tmap_draw_full(m: Tmap, camx: int, camy: int, frame: int, animate: int)
|
|||
# Tiled anchors a tile object by its bottom-left corner
|
||||
tmap_draw_gid(m, g, ox - camx, oy - m.tileh - camy)
|
||||
}
|
||||
oi = oi + 1
|
||||
oi += 1
|
||||
}
|
||||
}
|
||||
li = li + 1
|
||||
li += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1125,7 +1125,7 @@ function tiled_prop_node(container: Val, name: pointer) -> Val {
|
|||
while i < value_count(props) {
|
||||
let p = value_at(props, i)
|
||||
if value_as_str(value_get(p, "name")) == name { return p }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return value_null()
|
||||
}
|
||||
|
|
@ -1201,12 +1201,12 @@ function tiled_load_types(path: pointer) -> int {
|
|||
value_put(o, "value", value_str(xml_attr(pr, "default")))
|
||||
push(props.kids, o)
|
||||
}
|
||||
j = j + 1
|
||||
j += 1
|
||||
}
|
||||
value_put(tbl, xml_attr(ot, "name"), props)
|
||||
n = n + 1
|
||||
n += 1
|
||||
}
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
@ -1220,7 +1220,7 @@ function tiled_type_default(typename: pointer, propname: pointer) -> Val {
|
|||
while i < value_count(props) {
|
||||
let p = value_at(props, i)
|
||||
if value_as_str(value_get(p, "name")) == propname { return p }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return value_null()
|
||||
}
|
||||
|
|
@ -1251,7 +1251,7 @@ function tiled_merge_template(inst: Val, tmpl: Val) -> void {
|
|||
while i < value_count(tmpl) {
|
||||
let k = value_key_at(tmpl, i)
|
||||
if value_has(inst, k) == 0 { value_put(inst, k, value_at(tmpl, i)) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1268,10 +1268,10 @@ function tmap_resolve_templates(m: Tmap, basedir: pointer) -> void {
|
|||
let ob = value_at(objs, oi)
|
||||
let tp = value_as_str(value_get(ob, "template"))
|
||||
if tp != "" { tiled_merge_template(ob, tiled_read_template(tiled_join(basedir, tp))) }
|
||||
oi = oi + 1
|
||||
oi += 1
|
||||
}
|
||||
}
|
||||
li = li + 1
|
||||
li += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1330,9 +1330,9 @@ function tmap_draw_imagelayer(m: Tmap, l: TmLayer, camx: int, camy: int) -> void
|
|||
let repy = value_as_int(value_get(l.data, "repeaty"))
|
||||
# starting origin: for a repeating axis, back up to before the screen
|
||||
var sx0 = px
|
||||
if repx != 0 { while sx0 > 0 { sx0 = sx0 - iw }; }
|
||||
if repx != 0 { while sx0 > 0 { sx0 -= iw }; }
|
||||
var sy0 = py
|
||||
if repy != 0 { while sy0 > 0 { sy0 = sy0 - ih }; }
|
||||
if repy != 0 { while sy0 > 0 { sy0 -= ih }; }
|
||||
var yy = sy0
|
||||
var first_y = 1
|
||||
while (yy < rt_screen_h()) and (first_y == 1 or repy != 0) {
|
||||
|
|
@ -1341,16 +1341,16 @@ function tmap_draw_imagelayer(m: Tmap, l: TmLayer, camx: int, camy: int) -> void
|
|||
while (xx < rt_screen_w()) and (first_x == 1 or repx != 0) {
|
||||
rt_draw_image(l.imgid, xx, yy)
|
||||
first_x = 0
|
||||
if repx == 0 { xx = rt_screen_w() } else { xx = xx + iw }
|
||||
if repx == 0 { xx = rt_screen_w() } else { xx += iw }
|
||||
}
|
||||
first_y = 0
|
||||
if repy == 0 { yy = rt_screen_h() } else { yy = yy + ih }
|
||||
if repy == 0 { yy = rt_screen_h() } else { yy += ih }
|
||||
}
|
||||
}
|
||||
|
||||
# ---- image/group-layer accessors -------------------------------------------
|
||||
function tmap_layer_kind(m: Tmap, layer: int) -> int {
|
||||
if layer < 0 or layer >= len(m.layers) { return 0 - 1 }
|
||||
if layer < 0 or layer >= len(m.layers) { return -1 }
|
||||
return m.layers[layer].kind
|
||||
}
|
||||
function tmap_layer_opacity(m: Tmap, layer: int) -> pointer {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ function tiled_apply_field(e: int, fname: pointer, v: int) -> void {
|
|||
let fid = world_field_id(pi, fname)
|
||||
if fid >= 0 { world_set(e, pi, fid, v) }
|
||||
}
|
||||
pi = pi + 1
|
||||
pi += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ function tiled_apply_field(e: int, fname: pointer, v: int) -> void {
|
|||
# unknown. Opt-in — the core load never calls this.
|
||||
function tiled_spawn_object(m: Tmap, obj: Val, model_name: pointer) -> int {
|
||||
let mid = world_model_id(model_name)
|
||||
if mid < 0 { return 0 - 1 }
|
||||
if mid < 0 { return -1 }
|
||||
let e = world_spawn(mid)
|
||||
let pp = world_prop_id("Position")
|
||||
if pp >= 0 and world_has(e, pp) == 1 {
|
||||
|
|
@ -40,7 +40,7 @@ function tiled_spawn_object(m: Tmap, obj: Val, model_name: pointer) -> int {
|
|||
while i < value_count(props) {
|
||||
let p = value_at(props, i)
|
||||
tiled_apply_field(e, value_as_str(value_get(p, "name")), tiled_prop_int(obj, value_as_str(value_get(p, "name"))))
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
|
@ -50,6 +50,6 @@ function tiled_spawn_layer(m: Tmap, layer: int, model_name: pointer) -> int {
|
|||
var n = 0
|
||||
let c = tmap_object_count(m, layer)
|
||||
var i = 0
|
||||
while i < c { if tiled_spawn_object(m, tmap_object(m, layer, i), model_name) >= 0 { n = n + 1 }; i = i + 1 }
|
||||
while i < c { if tiled_spawn_object(m, tmap_object(m, layer, i), model_name) >= 0 { n += 1 }; i += 1 }
|
||||
return n
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,23 +134,23 @@ function tt_find_table(d: pointer, base: int, a: int, b: int, c: int, e: int) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# pick the most capable Unicode subtable, as the C loader did
|
||||
function tt_pick_cmap(id: int, d: pointer, co: int) -> void {
|
||||
tt_cmap[id] = 0 - 1
|
||||
tt_cmap[id] = -1
|
||||
tt_cfmt[id] = 0
|
||||
if co < 0 { return }
|
||||
let n = tt_u16(d, co + 2)
|
||||
var best = 0 - 1
|
||||
var bestscore = 0 - 1
|
||||
var best = -1
|
||||
var bestscore = -1
|
||||
for i in 0 .. n {
|
||||
let rec = co + 4 + i * 8
|
||||
let plat = tt_u16(d, rec)
|
||||
let enc = tt_u16(d, rec + 2)
|
||||
let off = tt_u32(d, rec + 4)
|
||||
var score = 0 - 1
|
||||
var score = -1
|
||||
if plat == 0 { score = 2 }
|
||||
if plat == 0 { if enc == 4 { score = 4 } }
|
||||
if plat == 0 { if enc == 6 { score = 4 } }
|
||||
|
|
@ -167,14 +167,14 @@ function tt_pick_cmap(id: int, d: pointer, co: int) -> void {
|
|||
}
|
||||
|
||||
function rt_font_load(path: string) -> int {
|
||||
if tt_n >= TT_MAX { return 0 - 1 }
|
||||
if tt_n >= TT_MAX { return -1 }
|
||||
let d = rt_read_file(path)
|
||||
if (d == null) { return 0 - 1 }
|
||||
if (d == null) { return -1 }
|
||||
let size = rt_file_len
|
||||
var base = 0
|
||||
# a .ttc collection points at its first font
|
||||
if size >= 16 {
|
||||
if d[0] == 116 { if d[1] == 116 { if d[2] == 99 { if d[3] == 102 {
|
||||
if d[0] == 't' { if d[1] == 't' { if d[2] == 'c' { if d[3] == 'f' {
|
||||
base = tt_u32(d, 12)
|
||||
} } } }
|
||||
}
|
||||
|
|
@ -184,15 +184,15 @@ function rt_font_load(path: string) -> int {
|
|||
let loca = tt_find_table(d, base, 108, 111, 99, 97)
|
||||
let glyf = tt_find_table(d, base, 103, 108, 121, 102)
|
||||
let hmtx = tt_find_table(d, base, 104, 109, 116, 120)
|
||||
if head < 0 { return 0 - 1 }
|
||||
if maxp < 0 { return 0 - 1 }
|
||||
if hhea < 0 { return 0 - 1 }
|
||||
if loca < 0 { return 0 - 1 }
|
||||
if glyf < 0 { return 0 - 1 }
|
||||
if hmtx < 0 { return 0 - 1 }
|
||||
if head < 0 { return -1 }
|
||||
if maxp < 0 { return -1 }
|
||||
if hhea < 0 { return -1 }
|
||||
if loca < 0 { return -1 }
|
||||
if glyf < 0 { return -1 }
|
||||
if hmtx < 0 { return -1 }
|
||||
|
||||
let id = tt_n
|
||||
tt_n = tt_n + 1
|
||||
tt_n += 1
|
||||
tt_data[id] = d
|
||||
tt_size[id] = size
|
||||
var upem = tt_u16(d, head + 18)
|
||||
|
|
@ -275,7 +275,7 @@ function ol_pt(x: fixed, y: fixed, on: int) -> void {
|
|||
ol_x[ol_n] = x
|
||||
ol_y[ol_n] = y
|
||||
ol_on[ol_n] = on
|
||||
ol_n = ol_n + 1
|
||||
ol_n += 1
|
||||
}
|
||||
|
||||
function tt_glyph_start(id: int, gid: int) -> int {
|
||||
|
|
@ -314,15 +314,15 @@ function tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fix
|
|||
var i = 0
|
||||
while i < npts {
|
||||
let fl = d[p]
|
||||
p = p + 1
|
||||
p += 1
|
||||
flags[i] = fl
|
||||
i = i + 1
|
||||
i += 1
|
||||
if (fl & 8) != 0 { # REPEAT
|
||||
var r = d[p]
|
||||
p = p + 1
|
||||
p += 1
|
||||
while r > 0 {
|
||||
if i < npts { flags[i] = fl; i = i + 1 }
|
||||
r = r - 1
|
||||
if i < npts { flags[i] = fl; i += 1 }
|
||||
r -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -334,10 +334,10 @@ function tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fix
|
|||
let fl = flags[k]
|
||||
if (fl & 2) != 0 {
|
||||
let dxv = d[p]
|
||||
p = p + 1
|
||||
if (fl & 16) != 0 { xv = xv + dxv } else { xv = xv - dxv }
|
||||
p += 1
|
||||
if (fl & 16) != 0 { xv += dxv } else { xv -= dxv }
|
||||
} else {
|
||||
if (fl & 16) == 0 { xv = xv + tt_i16(d, p); p = p + 2 }
|
||||
if (fl & 16) == 0 { xv += tt_i16(d, p); p += 2 }
|
||||
}
|
||||
xs[k] = xv
|
||||
}
|
||||
|
|
@ -346,10 +346,10 @@ function tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fix
|
|||
let fl = flags[k]
|
||||
if (fl & 4) != 0 {
|
||||
let dyv = d[p]
|
||||
p = p + 1
|
||||
if (fl & 32) != 0 { yv = yv + dyv } else { yv = yv - dyv }
|
||||
p += 1
|
||||
if (fl & 32) != 0 { yv += dyv } else { yv -= dyv }
|
||||
} else {
|
||||
if (fl & 32) == 0 { yv = yv + tt_i16(d, p); p = p + 2 }
|
||||
if (fl & 32) == 0 { yv += tt_i16(d, p); p += 2 }
|
||||
}
|
||||
ys[k] = yv
|
||||
}
|
||||
|
|
@ -364,7 +364,7 @@ function tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fix
|
|||
}
|
||||
if ol_ne < 256 {
|
||||
ol_ends[ol_ne] = ol_n
|
||||
ol_ne = ol_ne + 1
|
||||
ol_ne += 1
|
||||
}
|
||||
start = last + 1
|
||||
}
|
||||
|
|
@ -378,17 +378,17 @@ function tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fix
|
|||
while more == 1 {
|
||||
let flags = tt_u16(d, p)
|
||||
let cgid = tt_u16(d, p + 2)
|
||||
p = p + 4
|
||||
p += 4
|
||||
var arg1 = 0
|
||||
var arg2 = 0
|
||||
if (flags & 1) != 0 {
|
||||
arg1 = tt_i16(d, p)
|
||||
arg2 = tt_i16(d, p + 2)
|
||||
p = p + 4
|
||||
p += 4
|
||||
} else {
|
||||
arg1 = tt_i8(d, p)
|
||||
arg2 = tt_i8(d, p + 1)
|
||||
p = p + 2
|
||||
p += 2
|
||||
}
|
||||
var ca = 1.0
|
||||
var cb = 0.0
|
||||
|
|
@ -397,19 +397,19 @@ function tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fix
|
|||
if (flags & 8) != 0 {
|
||||
ca = as_fixed((tt_i16(d, p) << 2)) # F2Dot14 -> Q16.16
|
||||
ce = ca
|
||||
p = p + 2
|
||||
p += 2
|
||||
}
|
||||
if (flags & 64) != 0 {
|
||||
ca = as_fixed((tt_i16(d, p) << 2))
|
||||
ce = as_fixed((tt_i16(d, p + 2) << 2))
|
||||
p = p + 4
|
||||
p += 4
|
||||
}
|
||||
if (flags & 128) != 0 {
|
||||
ca = as_fixed((tt_i16(d, p) << 2))
|
||||
cb = as_fixed((tt_i16(d, p + 2) << 2))
|
||||
cc = as_fixed((tt_i16(d, p + 4) << 2))
|
||||
ce = as_fixed((tt_i16(d, p + 6) << 2))
|
||||
p = p + 8
|
||||
p += 8
|
||||
}
|
||||
var odx = dx
|
||||
var ody = dy
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ function ed_add(x0: fixed, y0: fixed, x1: fixed, y1: fixed) -> void {
|
|||
ed_y0[ed_n] = y0
|
||||
ed_x1[ed_n] = x1
|
||||
ed_y1[ed_n] = y1
|
||||
ed_n = ed_n + 1
|
||||
ed_n += 1
|
||||
}
|
||||
|
||||
function tt_isqrt(v: int) -> int {
|
||||
|
|
@ -18,7 +18,7 @@ function tt_isqrt(v: int) -> int {
|
|||
while b > 0 {
|
||||
let t = r + b
|
||||
if t * t <= v { r = t }
|
||||
b = b / 2
|
||||
b /= 2
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ function tt_raster(id: int, gid: int, px: int) -> pointer {
|
|||
let end = ol_ends[ci]
|
||||
let cnt = end - start
|
||||
if cnt >= 2 {
|
||||
var first_on = 0 - 1
|
||||
var first_on = -1
|
||||
for i in 0 .. cnt {
|
||||
if first_on < 0 { if ol_on[start + i] == 1 { first_on = i } }
|
||||
}
|
||||
|
|
@ -133,7 +133,7 @@ function tt_raster(id: int, gid: int, px: int) -> pointer {
|
|||
var ex = jx
|
||||
var ey = jy
|
||||
if ol_on[start + j] == 1 {
|
||||
step = step + 1
|
||||
step += 1
|
||||
} else {
|
||||
ex = (ix + jx) / 2 # implied on-curve midpoint
|
||||
ey = (iy + jy) / 2
|
||||
|
|
@ -142,7 +142,7 @@ function tt_raster(id: int, gid: int, px: int) -> pointer {
|
|||
curx = ex
|
||||
cury = ey
|
||||
}
|
||||
step = step + 1
|
||||
step += 1
|
||||
}
|
||||
ed_add(curx, cury, sx, sy)
|
||||
}
|
||||
|
|
@ -167,8 +167,8 @@ function tt_raster(id: int, gid: int, px: int) -> pointer {
|
|||
if hit == 1 {
|
||||
let t = (yc - ya) / (yb - ya)
|
||||
sc_x[m] = ed_x0[i] + t * (ed_x1[i] - ed_x0[i])
|
||||
if yb > ya { sc_d[m] = 1 } else { sc_d[m] = 0 - 1 }
|
||||
m = m + 1
|
||||
if yb > ya { sc_d[m] = 1 } else { sc_d[m] = -1 }
|
||||
m += 1
|
||||
}
|
||||
}
|
||||
# insertion sort the crossings by x
|
||||
|
|
@ -181,12 +181,12 @@ function tt_raster(id: int, gid: int, px: int) -> pointer {
|
|||
if sc_x[j] > kx {
|
||||
sc_x[j + 1] = sc_x[j]
|
||||
sc_d[j + 1] = sc_d[j]
|
||||
j = j - 1
|
||||
j -= 1
|
||||
} else {
|
||||
sc_x[j + 1] = kx
|
||||
sc_d[j + 1] = kd
|
||||
placed = 1
|
||||
j = 0 - 1
|
||||
j = -1
|
||||
}
|
||||
}
|
||||
if placed == 0 {
|
||||
|
|
@ -197,7 +197,7 @@ function tt_raster(id: int, gid: int, px: int) -> pointer {
|
|||
var wind = 0
|
||||
let oy = sy / TT_SS
|
||||
for i in 0 .. m - 1 {
|
||||
wind = wind + sc_d[i]
|
||||
wind += sc_d[i]
|
||||
if wind != 0 {
|
||||
var xa = sc_x[i]
|
||||
var xb = sc_x[i + 1]
|
||||
|
|
@ -271,7 +271,7 @@ var u8_next: int = 0 # byte index just past the codepoint last decoded
|
|||
|
||||
function tt_utf8(s: string, at: int) -> int {
|
||||
let c = s[at]
|
||||
var extra = 0 - 1
|
||||
var extra = -1
|
||||
if c < 128 { extra = 0 }
|
||||
if (c >> 5) == 6 { extra = 1 }
|
||||
if (c >> 4) == 14 { extra = 2 }
|
||||
|
|
@ -342,11 +342,11 @@ function rt_text_ttf(font: int, x: int, y: int, s: string, colour: int, px: int)
|
|||
i = u8_next
|
||||
if cp == 10 {
|
||||
penx = x
|
||||
baseline = baseline + lineh
|
||||
baseline += lineh
|
||||
} else {
|
||||
let g = tt_glyph_get(font, cp, px)
|
||||
tt_blit(gc_bmp[g], gc_w[g], gc_h[g], penx + gc_ox[g], baseline - gc_oy[g], colour)
|
||||
penx = penx + gc_adv[g]
|
||||
penx += gc_adv[g]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -365,7 +365,7 @@ function rt_text_w(font: int, s: string, px: int) -> int {
|
|||
if w > best { best = w }
|
||||
w = 0
|
||||
} else {
|
||||
w = w + gc_adv[tt_glyph_get(font, cp, px)]
|
||||
w += gc_adv[tt_glyph_get(font, cp, px)]
|
||||
}
|
||||
}
|
||||
if w > best { best = w }
|
||||
|
|
|
|||
|
|
@ -60,15 +60,15 @@ function tw_alloc() -> int {
|
|||
var i = 0
|
||||
while i < TW_MAX {
|
||||
if tw_used[i] == 0 { return i }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
# none free: reuse the first finished handle so long-lived games don't leak.
|
||||
i = 0
|
||||
while i < TW_MAX {
|
||||
if tw_done[i] != 0 { return i }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
return 0 - 1
|
||||
return -1
|
||||
}
|
||||
|
||||
# append one segment to a handle (internal). Silently ignored past TW_SEGS.
|
||||
|
|
@ -88,7 +88,7 @@ function tw_push(h: int, kind: int, from: int, to: int, dur: int, ease: int) ->
|
|||
# start a new tween handle: from -> to over `dur` ticks with easing `ease`.
|
||||
function tween_to(from: int, to: int, dur: int, ease: int) -> int {
|
||||
let h = tw_alloc()
|
||||
if h < 0 { return 0 - 1 }
|
||||
if h < 0 { return -1 }
|
||||
tw_used[h] = 1
|
||||
tw_seg[h] = 0
|
||||
tw_nseg[h] = 0
|
||||
|
|
@ -187,7 +187,7 @@ function tw_advance_one(h: int) -> void {
|
|||
# (a delay segment holds tw_value unchanged.)
|
||||
if tick >= dur { # this segment finished: advance
|
||||
if kind == 0 { tw_value[h] = tw_to[s] } # rest exactly on the target
|
||||
seg = seg + 1
|
||||
seg += 1
|
||||
tw_seg[h] = seg
|
||||
tw_tick[h] = 0
|
||||
if seg >= n { tw_done[h] = 1 }
|
||||
|
|
@ -203,6 +203,6 @@ function esys_tween() -> void {
|
|||
var i = 0
|
||||
while i < TW_MAX {
|
||||
if (tw_used[i] != 0) and (tw_done[i] == 0) { tw_advance_one(i) }
|
||||
i = i + 1
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ function rt_ui_reset(n: int) -> void {
|
|||
ui_n = n
|
||||
for i in 0 .. n {
|
||||
ui_type[i] = 0
|
||||
ui_parent[i] = 0 - 1
|
||||
ui_parent[i] = -1
|
||||
ui_w[i] = 0
|
||||
ui_h[i] = 0
|
||||
ui_x[i] = 0
|
||||
|
|
@ -124,16 +124,16 @@ function rt_ui_reset(n: int) -> void {
|
|||
ui_haspos[i] = 0
|
||||
ui_pad[i] = 0
|
||||
ui_gap[i] = 0
|
||||
ui_bg[i] = 0 - 1
|
||||
ui_fg[i] = 0 - 1
|
||||
ui_border[i] = 0 - 1
|
||||
ui_align[i] = 0 - 1
|
||||
ui_bg[i] = -1
|
||||
ui_fg[i] = -1
|
||||
ui_border[i] = -1
|
||||
ui_align[i] = -1
|
||||
ui_grow[i] = 0
|
||||
ui_font[i] = 0 - 1
|
||||
ui_font[i] = -1
|
||||
ui_size[i] = 8
|
||||
ui_skin[i] = 0 - 1
|
||||
ui_skin[i] = -1
|
||||
ui_inset[i] = 6
|
||||
ui_img[i] = 0 - 1
|
||||
ui_img[i] = -1
|
||||
ui_focusable[i] = 0
|
||||
ui_visible[i] = 1
|
||||
ui_fired[i] = 0
|
||||
|
|
@ -197,7 +197,7 @@ function ui_tw(font: int, s: pointer, size: int) -> int {
|
|||
if font < tt_n { return rt_text_w(font, s, size) }
|
||||
}
|
||||
var n = 0
|
||||
while s[n] != 0 { n = n + 1 }
|
||||
while s[n] != 0 { n += 1 }
|
||||
return n * 6 * max(size / 8, 1)
|
||||
}
|
||||
|
||||
|
|
@ -239,15 +239,15 @@ function ui_measure() -> void {
|
|||
let pad = ui_pad[i]
|
||||
var cw = 0
|
||||
var ch = 0
|
||||
if t == WT_LABEL { cw = 0 - 1 }
|
||||
if t == WT_BUTTON { cw = 0 - 1 }
|
||||
if cw == 0 - 1 {
|
||||
if t == WT_LABEL { cw = -1 }
|
||||
if t == WT_BUTTON { cw = -1 }
|
||||
if cw == -1 {
|
||||
let s = ui_str(i)
|
||||
cw = ui_tw(ui_font[i], s, ui_size[i]) + 2 * pad
|
||||
ch = ui_th(ui_font[i], ui_size[i]) + 2 * pad
|
||||
if t == WT_BUTTON {
|
||||
cw = cw + 10
|
||||
ch = ch + 6
|
||||
cw += 10
|
||||
ch += 6
|
||||
}
|
||||
} else {
|
||||
if t == WT_IMAGE {
|
||||
|
|
@ -269,13 +269,13 @@ function ui_measure() -> void {
|
|||
if ui_parent[c] == i {
|
||||
if ui_visible[c] == 1 {
|
||||
if dir == 1 {
|
||||
mainsz = mainsz + ui_rh[c]
|
||||
mainsz += ui_rh[c]
|
||||
cross = max(cross, ui_rw[c])
|
||||
} else {
|
||||
mainsz = mainsz + ui_rw[c]
|
||||
mainsz += ui_rw[c]
|
||||
cross = max(cross, ui_rh[c])
|
||||
}
|
||||
nc = nc + 1
|
||||
nc += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -299,7 +299,7 @@ function ui_measure() -> void {
|
|||
ui_rw[i] = rw
|
||||
ui_rh[i] = rh
|
||||
}
|
||||
i = i - 1
|
||||
i -= 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ function ui_arrange(i: int, x: int, y: int) -> void {
|
|||
for c in 0 .. ui_n {
|
||||
if ui_parent[c] == i {
|
||||
if ui_visible[c] == 1 {
|
||||
if dir == 1 { total = total + ui_rh[c] } else { total = total + ui_rw[c] }
|
||||
ng = ng + 1
|
||||
grows = grows + ui_grow[c]
|
||||
if dir == 1 { total += ui_rh[c] } else { total += ui_rw[c] }
|
||||
ng += 1
|
||||
grows += ui_grow[c]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ function ui_focusables() -> int {
|
|||
if ui_visible[i] == 1 {
|
||||
if ui_under(i, ui_active) {
|
||||
ui_fl[n] = i
|
||||
n = n + 1
|
||||
n += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -169,12 +169,12 @@ function ui_focusables() -> int {
|
|||
event UiClicked { id: int = 0 }
|
||||
|
||||
# Ui.close(): no menu is active (the same as opening root -1)
|
||||
function rt_ui_close() -> void { rt_ui_open(0 - 1) }
|
||||
function rt_ui_close() -> void { rt_ui_open(-1) }
|
||||
|
||||
function rt_ui_open(root: int) -> void {
|
||||
ui_active = root
|
||||
let n = ui_focusables()
|
||||
ui_focus = 0 - 1
|
||||
ui_focus = -1
|
||||
if n > 0 { ui_focus = ui_fl[0] }
|
||||
}
|
||||
|
||||
|
|
@ -184,10 +184,10 @@ function rt_ui_tick(k: int) -> void {
|
|||
ui_layout()
|
||||
let n = ui_focusables()
|
||||
if n == 0 {
|
||||
ui_focus = 0 - 1
|
||||
ui_focus = -1
|
||||
return
|
||||
}
|
||||
var cur = 0 - 1
|
||||
var cur = -1
|
||||
for i in 0 .. n {
|
||||
if ui_fl[i] == ui_focus { cur = i }
|
||||
}
|
||||
|
|
@ -195,18 +195,18 @@ function rt_ui_tick(k: int) -> void {
|
|||
cur = 0
|
||||
ui_focus = ui_fl[0]
|
||||
}
|
||||
if k == 119 { # 'w'
|
||||
if k == 'w' { # 'w'
|
||||
cur = (cur - 1 + n) % n
|
||||
ui_focus = ui_fl[cur]
|
||||
}
|
||||
if k == 115 { # 's'
|
||||
if k == 's' { # 's'
|
||||
cur = (cur + 1) % n
|
||||
ui_focus = ui_fl[cur]
|
||||
}
|
||||
var fire = 0
|
||||
if k == 32 { fire = 1 }
|
||||
if k == 10 { fire = 1 }
|
||||
if k == 13 { fire = 1 }
|
||||
if k == ' ' { fire = 1 }
|
||||
if k == '\n' { fire = 1 }
|
||||
if k == '\r' { fire = 1 }
|
||||
if fire == 1 { ui_fired[ui_focus] = 1; emit UiClicked(id: ui_focus) }
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ function rt_ui_set_text(id: int, s: string) -> void {
|
|||
if i >= 95 { ch = 0 }
|
||||
if ch != 0 {
|
||||
ui_dyn[base + i] = ch
|
||||
i = i + 1
|
||||
i += 1
|
||||
ch = s[i]
|
||||
}
|
||||
}
|
||||
|
|
@ -248,27 +248,27 @@ function rt_ui_set_int(id: int, n: int) -> void {
|
|||
var at = 0
|
||||
var v = n
|
||||
if v < 0 {
|
||||
ui_dyn[base] = 45
|
||||
ui_dyn[base] = '-'
|
||||
at = 1
|
||||
v = 0 - v
|
||||
v = -v
|
||||
}
|
||||
if v == 0 {
|
||||
ui_dyn[base + at] = 48
|
||||
at = at + 1
|
||||
ui_dyn[base + at] = '0'
|
||||
at += 1
|
||||
} else {
|
||||
var digits = 0
|
||||
var t = v
|
||||
while t > 0 {
|
||||
digits = digits + 1
|
||||
t = t / 10
|
||||
digits += 1
|
||||
t /= 10
|
||||
}
|
||||
var p = digits
|
||||
while p > 0 {
|
||||
var div = 1
|
||||
for k in 1 .. p { div = div * 10 }
|
||||
for k in 1 .. p { div *= 10 }
|
||||
ui_dyn[base + at] = 48 + (v / div) % 10
|
||||
at = at + 1
|
||||
p = p - 1
|
||||
at += 1
|
||||
p -= 1
|
||||
}
|
||||
}
|
||||
ui_dyn[base + at] = 0
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue