# combat.ludic — the co-op turn-based battle state machine. # The battle is a state machine over the `turn_phase` variable. `machine` # dispatches on its value and `become` transitions to a named state — no more # `if ph == N` ladders. Knight turn (0,1), Mage turn (2,3), Enemy turn (4). # Menu selections, named instead of matched on bare integers (menu_cursor holds one). enum KnightAct { Attack, Guard, Item, Flee } enum MageAct { Attack, Heal, Guard } handler Battle(games_chronorift_st: mut GamesChronoriftState) phase Update { if games_chronorift_st.game_mode == 1 { let k = Input.key() for (e) in query [Stats, {Enemy}] { machine games_chronorift_st.turn_phase { state KnightMenu { for (st, pt) in query [Stats, Party] { if pt.slot == 0 { if st.hp <= 0 { become MageMenu games_chronorift_st.menu_cursor = 0 } else { if k == 'w' { games_chronorift_st.menu_cursor = max(0, games_chronorift_st.menu_cursor - 1) } if k == 's' { games_chronorift_st.menu_cursor = min(3, games_chronorift_st.menu_cursor + 1) } if is_confirm(k) { match games_chronorift_st.menu_cursor { KnightAct.Attack => { let d = max(1, st.atk - e.def + Random.range(0, 4)) e.hp -= d games_chronorift_st.player_hit = d } KnightAct.Guard => { st.guard = 1; games_chronorift_st.player_hit = 0 } KnightAct.Item => { if games_chronorift_st.potions > 0 { games_chronorift_st.potions -= 1 st.hp = min(st.maxhp, st.hp + 24) games_chronorift_st.player_hit = 24 } else { games_chronorift_st.player_hit = 0 } } KnightAct.Flee => { if Random.chance(50) { e.hp = 0; games_chronorift_st.game_mode = 0 } else { games_chronorift_st.player_hit = 0 } } } become KnightResolve games_chronorift_st.menu_cursor = 0 } } } } } state KnightResolve { if k != 0 { if e.hp <= 0 { grant_xp(e.xp) games_chronorift_st.gold += e.xp if games_chronorift_st.enemy_type == 2 { games_chronorift_st.boss_down = 1; games_chronorift_st.game_mode = 3; games_chronorift_st.ack = 0 } else { games_chronorift_st.game_mode = 0 } become KnightMenu } else { become MageMenu games_chronorift_st.menu_cursor = 0 } } } state MageMenu { for (st, pt) in query [Stats, Party] { if pt.slot == 1 { if st.hp <= 0 { become EnemyTurn } else { if k == 'i' { games_chronorift_st.menu_cursor = max(0, games_chronorift_st.menu_cursor - 1) } if k == 'k' { games_chronorift_st.menu_cursor = min(2, games_chronorift_st.menu_cursor + 1) } if k == 'j' { match games_chronorift_st.menu_cursor { MageAct.Attack => { let d = max(1, st.atk + 5 - e.def + Random.range(0, 5)) e.hp -= d games_chronorift_st.player_hit = d } MageAct.Heal => { if 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) } } games_chronorift_st.player_hit = 16 } else { games_chronorift_st.player_hit = 0 } } MageAct.Guard => { st.guard = 1; games_chronorift_st.player_hit = 0 } } become MageResolve games_chronorift_st.menu_cursor = 0 } } } } } state MageResolve { if k != 0 { if e.hp <= 0 { grant_xp(e.xp) games_chronorift_st.gold += e.xp if games_chronorift_st.enemy_type == 2 { games_chronorift_st.boss_down = 1; games_chronorift_st.game_mode = 3; games_chronorift_st.ack = 0 } else { games_chronorift_st.game_mode = 0 } become KnightMenu } else { become EnemyTurn } } } state EnemyTurn { if k != 0 { var done = 0 for (t3) in query [Stats, {Party}] { if done == 0 { if t3.hp > 0 { var ed = max(1, e.atk - t3.def + Random.range(0, 4)) if t3.guard == 1 { ed /= 2; t3.guard = 0 } t3.hp -= ed games_chronorift_st.enemy_hit = ed done = 1 } } } var alive = 0 for (t4) in query [Stats, {Party}] { if t4.hp > 0 { alive += 1 } } if alive == 0 { games_chronorift_st.game_mode = 2; games_chronorift_st.ack = 0 } else { become KnightMenu games_chronorift_st.menu_cursor = 0 } } } } } } } handler CleanBattle(games_chronorift_st: GamesChronoriftState) phase LateUpdate { if games_chronorift_st.game_mode != 1 { for (e) in query [Stats, {Enemy}] { despawn self() } } } handler Meta(games_chronorift_st: mut GamesChronoriftState) phase Update { let k = Input.key() if games_chronorift_st.game_mode == 2 { if k == 0 { games_chronorift_st.ack = 1 } if k != 0 { if games_chronorift_st.ack == 1 { for (h) in query [Stats, {Party}] { h.hp = h.maxhp } games_chronorift_st.game_mode = 0 } } } if games_chronorift_st.game_mode == 3 { if k == 0 { games_chronorift_st.ack = 1 } if k != 0 { if games_chronorift_st.ack == 1 { games_chronorift_st.game_mode = 0 } } } }