0,Âeº±º}ï}WÿÍu§ðp8·d%qy)6o;]ÉA¦öHÖÎôôô”°ÂVl†3 #enemies then stage = #enemies end local e = enemies[stage] cur_enemy = {name = e.name, hp = e.hp, max = e.max, dmg = e.dmg, desc = e.desc} end local function heal_party() for _, member in ipairs(party) do member.hp = member.max end end local function generate_mercenaries() merc_candidates = { {name = "Ronin " .. math.random(10,99), hp = 20, max = 20, wpn = "Katana", arm = "Chainmail", dmg = 5, is_player = false}, {name = "Bounty Hunter", hp = 25, max = 25, wpn = "Crossbow", arm = "Leather Armor", dmg = 4, is_player = false} } end local function execute_enemy_attack() local targets = {} for i, member in ipairs(party) do if member.hp > 0 then table.insert(targets, member) end end if #targets > 0 then local target = targets[math.random(1, #targets)] target.hp = math.max(0, target.hp - cur_enemy.dmg) enemy_action_log = "Hit " .. target.name .. " for " .. cur_enemy.dmg .. " DMG!" else enemy_action_log = "No targets remaining!" end change_state("enemy_turn") end init_enemy() music(00) -- 2. Main Game Loop function TIC() cls(0) ------------------------------------ -- STATE: STARTING GEAR SELECTION ------------------------------------ if state == "gear_select" then if gear_step == 1 then print("P1: CHOOSE WEAPON", 20, 20, 01) options = wpn_opts elseif gear_step == 2 then print("P1: CHOOSE ATTIRE", 20, 20, 01) options = arm_opts elseif gear_step == 3 then print("P2: CHOOSE WEAPON", 20, 20, 9) options = wpn_opts elseif gear_step == 4 then print("P2: CHOOSE ATTIRE", 20, 20, 9) options = arm_opts end draw_menu(20, 50, 1) local choice = handle_input() if choice then if gear_step == 1 then party[1].wpn = wpn_opts[choice]; gear_step = 2 elseif gear_step == 2 then party[1].arm = arm_opts[choice]; gear_step = 3 elseif gear_step == 3 then party[2].wpn = wpn_opts[choice]; gear_step = 4 elseif gear_step == 4 then party[2].arm = arm_opts[choice]; change_state("intro") end menu_index = 1 end ------------------------------------ -- STATE: INTRO ------------------------------------ elseif state == "intro" then print("STAGE " .. stage .. " ENTRANCE", 20, 10, 12) print("A " .. cur_enemy.name .. " blocks the path.", 20, 25, 13) print(cur_enemy.desc, 20, 35, 13) options = {"Approach Enemy", "Search Bushes", "Flee"} draw_menu(20, 70, 1) local choice = handle_input() if choice == 1 then start_combat() elseif choice == 2 then last_found = loot_pool[math.random(1, #loot_pool)] table.insert(party_inv, last_found) change_state("search") elseif choice == 3 then change_state("flee") end ------------------------------------ -- STATE: SEARCH ------------------------------------ elseif state == "search" then print("Searching bushes...", 20, 20, 13) print("Found: " .. last_found .. "!", 20, 40, 5) print("Vagrant Shopkeep packs it away.", 20, 50, 6) options = {"Return"} draw_menu(20, 70, 1) if handle_input() == 1 then change_state("intro") end ------------------------------------ -- STATE: COMBAT ------------------------------------ elseif state == "combat" then local p = party[active_p] -- Dynamic Battle UI (Renders all party members including Mercenary) print("VS: " .. cur_enemy.name .. " (HP:" .. cur_enemy.hp .. ")", 20, 4, 2) for i, member in ipairs(party) do local col = 15 if member.hp <= 0 then col = 2 elseif i == 1 then col = 01 elseif i == 2 then col = 9 elseif i == 3 then col = 12 else col = 6 end print(member.name .. ": " .. member.hp .. "/" .. member.max .. " HP [" .. member.wpn .. "]", 10, 11 + (i * 9), col) end -- Auto-skip knocked out actors if p.hp <= 0 then next_turn() return end -- Dynamic AI Ally Turn (Shopkeep / Hired Mercenary) if not p.is_player then local dmg = p.dmg or 2 print(">> " .. p.name .. " STRIKES! <<", 10, 58, 03) print("Deals " .. dmg .. " DMG with " .. p.wpn .. ".", 10, 67, 15) options = {"Continue"} draw_menu(20, 78, 1) if handle_input() == 1 then cur_enemy.hp = cur_enemy.hp - dmg check_enemy_death() end return end -- Player Turn print(">> " .. p.name .. "'S TURN <<", 10, 58, (active_p == 1 and 01 or 9)) print("Eqp: " .. p.wpn .. " / " .. p.arm, 10, 67, 15) options = {"Attack", "Use Item (Shared)", "Pass"} draw_menu(20, 78, active_p) local choice = handle_input() if choice == 1 then cur_enemy.hp = cur_enemy.hp - 4 check_enemy_death() elseif choice == 2 then if #party_inv > 0 then change_state("inventory") end elseif choice == 3 then next_turn() end ------------------------------------ -- STATE: INVENTORY (Shared) ------------------------------------ elseif state == "inventory" then print("Shopkeep's Pack (Shared):", 20, 15, 12) options = {} for i, item in ipairs(party_inv) do table.insert(options, item) end table.insert(options, "Cancel") draw_menu(20, 35, active_p) local choice = handle_input() if choice then if choice <= #party_inv then local used_item = table.remove(party_inv, choice) local p = party[active_p] if used_item == "Health Potion" or used_item == "Stimpack" then p.hp = math.min(p.max, p.hp + 8) elseif used_item == "Talisman" or used_item == "Rune Stone" then cur_enemy.hp = cur_enemy.hp - 7 elseif used_item == "Smoke Bomb" then cur_enemy.hp = cur_enemy.hp - 3 end check_enemy_death() else change_state("combat") end end ------------------------------------ -- STATE: ENEMY TURN ------------------------------------ elseif state == "enemy_turn" then print(cur_enemy.name .. " strikes!", 20, 20, 2) print(enemy_action_log, 20, 40, 13) options = {"Continue"} draw_menu(20, 70, 1) if handle_input() == 1 then if party[1].hp <= 0 and party[2].hp <= 0 then change_state("game_over") else change_state("combat") end end ------------------------------------ -- STATE: POST-RONIN HUB ------------------------------------ elseif state == "hub" then print("OUTSKIRTS HUB", 20, 15, 14) print("Resting spot unlocked.", 20, 28, 13) options = {"Barter Trade Shop", "Resting Tavern", "Proceed to Final Boss"} draw_menu(20, 55, 1) local choice = handle_input() if choice == 1 then change_state("trade_select_offer") elseif choice == 2 then change_state("tavern") elseif choice == 3 then stage = 4 -- Set to Stage 4 for the new encounter heal_party() init_enemy() change_state("intro") end ------------------------------------ -- STATE: BARTER SHOP (Item Trade) ------------------------------------ elseif state == "trade_select_offer" then print("BARTER SHOP: Offer Item", 20, 15, 12) options = {} for i, item in ipairs(party_inv) do table.insert(options, item) end table.insert(options, "Back") draw_menu(20, 35, 1) local choice = handle_input() if choice then if choice <= #party_inv then selected_trade_item = choice change_state("trade_select_want") else change_state("hub") end end elseif state == "trade_select_want" then print("BARTER SHOP: Select Receive Item", 20, 15, 12) options = {} for i, item in ipairs(shop_stock) do table.insert(options, item) end table.insert(options, "Cancel") draw_menu(20, 35, 1) local choice = handle_input() if choice then if choice <= #shop_stock then local received = shop_stock[choice] table.remove(party_inv, selected_trade_item) table.insert(party_inv, received) change_state("hub") else change_state("hub") end end ------------------------------------ -- STATE: TAVERN (Mercenaries) ------------------------------------ elseif state == "tavern" then print("RESTING TAVERN", 20, 10, 11) if hired_merc then print("Hired: " .. hired_merc.name .. " [" .. hired_merc.wpn .. "]", 20, 25, 6) options = {"Return to Hub"} draw_menu(20, 60, 1) if handle_input() == 1 then change_state("hub") end else print("Appraise Available Mercenaries:", 20, 25, 13) options = {} for i, m in ipairs(merc_candidates) do table.insert(options, m.name .. " (" .. m.wpn .. "/" .. m.arm .. ")") end table.insert(options, "Return to Hub") draw_menu(10, 40, 1) local choice = handle_input() if choice then if choice <= #merc_candidates then if #party_inv > 0 and #party == 3 then table.remove(party_inv, 1) local m = merc_candidates[choice] hired_merc = {name = m.name, hp = m.hp, max = m.max, wpn = m.wpn, arm = m.arm, dmg = m.dmg, is_player = false} table.insert(party, hired_merc) change_state("hub") end else change_state("hub") end end end ------------------------------------ -- STATE: WIN / FLEE / GAME OVER ------------------------------------ elseif state == "win" then print("VICTORY!", 20, 30, 11) if stage == 3 then -- Unlocks Hub right before the new Stage 4 boss options = {"Enter Outskirts Hub"} draw_menu(20, 70, 1) if handle_input() == 1 then heal_party() generate_mercenaries() change_state("hub") end else options = {"Proceed to Stage " .. (stage + 1)} draw_menu(20, 70, 1) if handle_input() == 1 then stage = stage + 1 heal_party() init_enemy() change_state("intro") end end elseif state == "flee" then print("Escaped back to safety.", 20, 30, 15) options = {"Try Again"} draw_menu(20, 70, 1) if handle_input() == 1 then change_state("intro") end elseif state == "game_over" then print("PARTY DEFEATED.", 20, 30, 8) options = {"Restart Game"} draw_menu(20, 70, 1) if handle_input() == 1 then reset_game() end end end -- 3. Utility Functions function next_turn() active_p = active_p + 1 if active_p > #party then active_p = 1 execute_enemy_attack() else change_state("combat") end end function check_enemy_death() if cur_enemy.hp <= 0 then change_state("win") else next_turn() end end function reset_game() stage = 1 gear_step = 1 party_inv = {"Health Potion", "Talisman"} if #party > 3 then table.remove(party, 4) end hired_merc = nil heal_party() init_enemy() change_state("gear_select") end function handle_input() -- Navigation Sound (SFX ID 0) if btnp(0) then sfx(0, "C-4", 6, 0, 15, 0) -- Plays when pressing UP menu_index = menu_index - 1 elseif btnp(1) then sfx(0, "C-4", 6, 0, 15, 0) -- Plays when pressing DOWN menu_index = menu_index + 1 end if menu_index < 1 then menu_index = #options end if menu_index > #options then menu_index = 1 end -- Confirmation Sound (SFX ID 1) if btnp(4) then sfx(1, "G-4", 10, 0, 15, 0) -- Plays when pressing ACTION (Z/A button) return menu_index end return nil end function draw_menu(x, y, active_pid) for i = 1, #options do local item_y = y + ((i - 1) * 9) if i == menu_index then local col = (active_pid == 1) and 11 or 9 print("> " .. options[i], x, item_y, col) else print(" " .. options[i], x, item_y, 15) end end end