diff --git a/lucksmith.lua b/lucksmith.lua
index f32cd0f..72b95e4 100644
--- a/lucksmith.lua
+++ b/lucksmith.lua
@@ -7,35 +7,50 @@ player = {
hp = 10,
roll_mod = 0,
mult = 1,
- counter = false
+ energy = 0
}
enemies = {{
+ name = "Goblin",
+ hp = 4,
+ roll_mod = 0,
+ mult = 1
+}, {
+ name = "Orc",
+ hp = 6,
+ roll_mod = 0,
+ mult = 1
+}, {
+ name = "Troll",
hp = 8,
roll_mod = 0,
- mult = 1,
- counter = false
-},
-{
+ mult = 1
+}, {
+ name = "Ogre",
hp = 10,
roll_mod = 0,
- mult = 1,
- counter = false
+ mult = 1
}, {
+ name = "Dragon",
hp = 12,
roll_mod = 0,
- mult = 1,
- counter = false
+ mult = 1
+}, {
+ name = "Demon",
+ hp = 14,
+ roll_mod = 0,
+ mult = 1
}}
level = 1
function get_enemy(level)
return {
- hp = enemies[level].hp,
- roll_mod = enemies[level].roll_mod,
- mult = enemies[level].mult,
- counter = enemies[level].counter
-}
+ name = enemies[level].name,
+ hp = enemies[level].hp,
+ max_hp = enemies[level].hp, -- store original max HP
+ roll_mod = enemies[level].roll_mod,
+ mult = enemies[level].mult
+ }
end
-enemy = get_enemy(level)
+enemy = get_enemy(level)
msg = ""
-- State
@@ -43,20 +58,39 @@ phase = "choose"
phase_time = 0
roll_text = ""
damage_applied = false
+current_damage = {player = 0, enemy = 0} -- store damage for display
pending_effects = {
player = {},
- enemy = {}
+ enemy = {},
+ previous_player = {},
+ previous_enemy = {}
}
+-- Card tracking for two-round strategy
+previous_card = nil
+previous_enemy_card = nil
-- animation + shake
player.display_roll = 0
enemy.display_roll = 0
shake = 0
d = 2 -- shake intensity
+flash = 0
+
+original_palette = {}
+for i = 0, 15 do
+ original_palette[i] = peek(0x3FC0 + i)
+end
+
+-- Deck system
+draw_pile = {}
+discard_pile = {}
+unlocked_cards = {} -- tracks which cards are in your deck
+
-- basic card pool
cards = {{
- name = "Str",
+ name = "Bless",
desc = "+2 to roll",
timing = "pre_roll",
+ energy = -1, -- costs 1 energy
use = function(p, e)
p.roll_mod = p.roll_mod + 2
end
@@ -64,68 +98,80 @@ cards = {{
name = "Hex",
desc = "-2 enemy roll",
timing = "pre_roll",
+ energy = -1, -- costs 1 energy
use = function(p, e)
e.roll_mod = e.roll_mod - 2
end
}, {
- name = "2x",
+ name = "Fury",
desc = "win/lose double dmg",
timing = "pre_roll",
+ energy = -1, -- reduced from -2
use = function(p, e)
- p.mult = 2
+ p.mult = p.mult * 2
+ e.mult = e.mult * 2
end
}, {
- name = "0.5x",
+ name = "Caution",
desc = "win/lose half dmg",
timing = "pre_roll",
+ energy = 0, -- reduced from +1 since we get +1 per turn
use = function(p, e)
- p.mult = 0.5
+ p.mult = p.mult * 0.5
+ e.mult = e.mult * 0.5
end
}, {
name = "Heal",
desc = "+2 hp",
timing = "immediate",
+ energy = -1, -- costs 1 energy
use = function(p, e)
p.hp = math.min(10, p.hp + 2)
+ current_damage.player = current_damage.player - 2 -- show damage taken
end
}, {
name = "Counter",
desc = "hit enemy for 1 if you lose",
timing = "post_result",
+ energy = 0, -- reduced from -1
use = function(p, e, player_won)
- -- player_won is from player's perspective when called on player cards
- if player_won == false then -- player lost
+ if player_won == false then -- fixed: should trigger when player loses
e.hp = e.hp - 1
+ current_damage.enemy = current_damage.enemy + 1 -- show damage taken
end
end
}, {
name = "Weaken",
desc = "-1 enemy dmg",
timing = "pre_roll",
+ energy = 0, -- reduced from -1
use = function(p, e)
- e.mult = math.max(0.5, e.mult - 0.5)
+ e.weaken = (e.weaken or 0) + 1 -- enemy is weakened (does less damage)
end
}, {
name = "Rage",
desc = "+1 your dmg",
- timing = "pre_roll",
+ timing = "pre_roll", -- changed from post_result for clarity
+ energy = -1, -- reduced from -1
use = function(p, e)
- p.mult = p.mult + 0.5
+ p.rage = (p.rage or 0) + 1 -- add rage bonus
end
}, {
- name = "Tier",
- desc = "if tie, you win",
+ name = "Break",
+ desc = "if tied, you win",
timing = "post_result",
+ energy = -1, -- reduced from -2
use = function(p, e, player_won)
if player_won == nil then -- tie occurred
- -- Player wins the tie, so enemy takes damage
e.hp = e.hp - (2 * p.mult)
+ current_damage.enemy = current_damage.enemy + (2 * p.mult) -- show damage taken
end
end
}, {
name = "Shield",
- desc = "take 1 less dmg this turn",
- timing = "pre_roll",
+ desc = "take 1 less dmg until damaged",
+ timing = "immediate",
+ energy = -1, -- increased from 0
use = function(p, e)
p.shield = (p.shield or 0) + 1
end
@@ -133,25 +179,31 @@ cards = {{
name = "Poison",
desc = "enemy loses 1 hp at turn end",
timing = "post_result",
+ energy = 0, -- reduced from -1
use = function(p, e, player_won)
e.hp = e.hp - 1
+ current_damage.enemy = current_damage.enemy + 1 -- show damage taken
end
}, {
name = "Spike",
desc = "deal 1 dmg to whoever wins",
- timing = "post_result",
+ timing = "post_result",
+ energy = 1, -- now gives energy since it's risky
use = function(p, e, player_won)
if player_won == true then
p.hp = p.hp - 1 -- hurt yourself if you win
+ current_damage.player = current_damage.player + 1 -- show damage taken
elseif player_won == false then
e.hp = e.hp - 1 -- hurt enemy if they win
+ current_damage.enemy = current_damage.enemy + 1 -- show damage taken
end
-- ties do nothing
end
}, {
name = "Lucky",
desc = "reroll if you roll 1-3",
- timing = "post_roll", -- New timing needed
+ timing = "post_roll",
+ energy = -1, -- reduced from -2
use = function(p, e)
if p.roll <= 3 then
p.roll = math.random(1, 6)
@@ -162,6 +214,7 @@ cards = {{
name = "Curse",
desc = "enemy rerolls if they roll 4-6",
timing = "post_roll",
+ energy = -1, -- reduced from -2
use = function(p, e)
if e.roll >= 4 then
e.roll = math.random(1, 6)
@@ -169,10 +222,14 @@ cards = {{
end
end
}, {
- name = "Swap",
- desc = "switch your roll with enemy's",
+ name = "Intuition",
+ desc = "Pick the higher roll",
timing = "post_roll",
+ energy = -3, -- reduced from -3
use = function(p, e)
+ if p.roll >= e.roll then
+ return -- no change needed
+ end
local temp = p.roll
p.roll = e.roll
e.roll = temp
@@ -183,22 +240,34 @@ cards = {{
name = "Mirror",
desc = "copy enemy's roll modifier",
timing = "pre_roll",
+ energy = -1, -- reduced from -1
use = function(p, e)
p.roll_mod = p.roll_mod + e.roll_mod
end
+}, {
+ name = "Double Vision",
+ desc = "copy enemy's multiplier",
+ timing = "post_roll",
+ energy = -1, -- reduced from -2
+ use = function(p, e)
+ p.mult = e.mult
+ end
}, {
name = "Drain",
desc = "heal 1 if you win",
timing = "post_result",
+ energy = 0, -- reduced from -1
use = function(p, e, player_won)
if player_won == true then
p.hp = math.min(10, p.hp + 1)
+ current_damage.player = current_damage.player - 1 -- show healing
end
end
}, {
name = "Gamble",
desc = "50% chance: +3 roll or -1 roll",
timing = "pre_roll",
+ energy = 1, -- now gives energy since it's risky
use = function(p, e)
if math.random() < 0.5 then
p.roll_mod = p.roll_mod + 3
@@ -207,17 +276,19 @@ cards = {{
end
end
}, {
- name = "Fury",
- desc = "+1 dmg per hp you're missing",
+ name = "Impulse",
+ desc = "+0.5 dmg per hp missing",
timing = "pre_roll",
+ energy = -1, -- reduced from -1
use = function(p, e)
local missing_hp = 10 - p.hp
- p.mult = p.mult + (missing_hp * 0.1)
+ p.mult = p.mult + (missing_hp * 0.5) -- increased effect
end
}, {
name = "Turtle",
desc = "set your roll to 3",
timing = "post_roll",
+ energy = 2, -- increased from 1
use = function(p, e)
p.roll = 3
p.total = p.roll + p.roll_mod
@@ -226,16 +297,36 @@ cards = {{
name = "Berserk",
desc = "2x dmg but take 1 dmg",
timing = "immediate",
+ energy = -1, -- reduced from -2
use = function(p, e)
p.mult = p.mult * 2
p.hp = p.hp - 1
+ current_damage.player = current_damage.player + 1 -- show damage taken
+ end
+}, {
+ name = "Focus",
+ desc = "+2 energy",
+ timing = "immediate",
+ energy = 2, -- gives 2 energy (net +3 with the +1 per turn)
+ use = function(p, e)
+ -- Energy gain handled automatically
+ end
+}, {
+ name = "Rest",
+ desc = "+1 energy, +1 hp",
+ timing = "immediate",
+ energy = 1, -- gives 1 energy (net +2 with the +1 per turn)
+ use = function(p, e)
+ current_damage.player = current_damage.player - 1 -- show healing
+ p.hp = math.min(10, p.hp + 1)
end
}}
enemy_cards = {{
- name = "Str",
+ name = "Bless",
desc = "+2 to roll",
timing = "pre_roll",
+ energy = -1,
use = function(p, e)
e.roll_mod = e.roll_mod + 2
end
@@ -243,78 +334,240 @@ enemy_cards = {{
name = "Hex",
desc = "-2 enemy roll",
timing = "pre_roll",
+ energy = -2,
use = function(p, e)
p.roll_mod = p.roll_mod - 2
end
}, {
- name = "2x",
+ name = "Fury",
desc = "win/lose double dmg",
timing = "pre_roll",
+ energy = -2,
use = function(p, e)
- e.mult = 2
+ e.mult = e.mult * 2
+ p.mult = p.mult * 2
end
}, {
- name = "0.5x",
+ name = "Caution",
desc = "win/lose half dmg",
timing = "pre_roll",
+ energy = 1,
use = function(p, e)
- e.mult = 0.5
+ e.mult = e.mult * 0.5
+ p.mult = p.mult * 0.5
end
}, {
name = "Heal",
desc = "+2 hp",
timing = "immediate",
+ energy = -1,
use = function(p, e)
- e.hp = math.min(10, e.hp + 2)
+ e.hp = math.min(e.max_hp, e.hp + 2)
+ current_damage.enemy = current_damage.enemy - 2 -- show damage taken
end
}, {
name = "Counter",
desc = "hit enemy for 1 if you lose",
timing = "post_result",
+ energy = -1,
use = function(p, e, player_won)
-- player_won is from player's perspective, so enemy perspective is flipped
if player_won == true then -- enemy lost (player won)
p.hp = p.hp - 1
+ current_damage.player = current_damage.player + 1 -- show damage taken
end
end
}, {
name = "Weaken",
desc = "-1 enemy dmg",
timing = "pre_roll",
+ energy = -1,
use = function(p, e)
- p.mult = math.max(0.5, p.mult - 0.5)
+ p.weaken = (p.weaken or 0) + 1 -- player is weakened (does less damage)
end
}, {
name = "Rage",
desc = "+1 your dmg",
timing = "pre_roll",
+ energy = -1,
use = function(p, e)
- e.mult = e.mult + 0.5
+ e.rage = (e.rage or 0) + 1 -- add rage bonus for enemy
end
}, {
name = "Tier",
desc = "if tie, you win",
timing = "post_result",
+ energy = -2,
use = function(p, e, player_won)
if player_won == nil then -- tie occurred
-- Enemy wins the tie, so player takes damage
p.hp = p.hp - (2 * e.mult)
+ current_damage.player = current_damage.player + (2 * e.mult) -- show damage taken
end
end
}}
-- player's starting hand (random subset)
hand = {}
-function draw_hand()
- hand = {}
- for i = 1, 3 do
- table.insert(hand, cards[math.random(#cards)])
+card_choice_options = {} -- for level up card selection
+
+function shuffle_deck(deck)
+ for i = #deck, 2, -1 do
+ local j = math.random(i)
+ deck[i], deck[j] = deck[j], deck[i]
end
end
+
+function initialize_deck()
+ draw_pile = {}
+ discard_pile = {}
+
+ -- Start with first 8 cards for level 1, or use unlocked_cards for higher levels
+ local cards_to_add = {}
+ if level == 1 then
+ unlocked_cards = {}
+ for i = 1, 8 do
+ unlocked_cards[i] = true
+ cards_to_add = {1, 2, 3, 4, 5, 6, 7, 8}
+ end
+ end
+
+ -- Add 2 copies of each unlocked card to deck
+ for i, card in ipairs(cards) do
+ if unlocked_cards[i] then
+ table.insert(draw_pile, card)
+ table.insert(draw_pile, card)
+ end
+ end
+
+ shuffle_deck(draw_pile)
+end
+
+function generate_card_choices()
+ card_choice_options = {}
+ local available_cards = {}
+
+ -- Find cards not yet unlocked
+ for i, card in ipairs(cards) do
+ if not unlocked_cards[i] then
+ table.insert(available_cards, i)
+ end
+ end
+
+ -- If we have available cards, pick 3 random ones
+ if #available_cards > 0 then
+ shuffle_deck(available_cards)
+ for i = 1, math.min(3, #available_cards) do
+ table.insert(card_choice_options, available_cards[i])
+ end
+ end
+end
+
+function add_card_to_deck(card_index)
+ unlocked_cards[card_index] = true
+ local card = cards[card_index]
+ -- Add 2 copies to discard pile (will be shuffled in next game)
+ table.insert(discard_pile, card)
+ table.insert(discard_pile, card)
+end
+
+-- player's starting hand (random subset)
+hand = {}
+
+function shuffle_deck(deck)
+ for i = #deck, 2, -1 do
+ local j = math.random(i)
+ deck[i], deck[j] = deck[j], deck[i]
+ end
+end
+
+function reshuffle_if_needed()
+ if #draw_pile < 3 and #discard_pile > 0 then
+ -- Move discard pile to draw pile and shuffle
+ for _, card in ipairs(discard_pile) do
+ table.insert(draw_pile, card)
+ end
+ discard_pile = {}
+ shuffle_deck(draw_pile)
+ end
+end
+
+function draw_hand()
+ hand = {}
+ reshuffle_if_needed()
+
+ -- If player has no energy, ensure at least one energy-positive card
+ if player.energy == 0 then
+ local energy_positive_found = false
+ local temp_hand = {}
+
+ -- Try to draw 3 cards, checking for energy-positive ones
+ for i = 1, 3 do
+ if #draw_pile > 0 then
+ local card = table.remove(draw_pile, 1)
+ table.insert(temp_hand, card)
+ if card.energy >= 0 then
+ energy_positive_found = true
+ end
+ end
+ end
+
+ -- If no energy-positive card found, replace one with an energy-positive card
+ if not energy_positive_found and #temp_hand > 0 then
+ -- Find an energy-positive card in remaining deck or discard
+ local energy_card = nil
+
+ -- Look in draw pile first
+ for i, card in ipairs(draw_pile) do
+ if card.energy >= 0 then
+ energy_card = table.remove(draw_pile, i)
+ break
+ end
+ end
+
+ -- If not found, look in discard pile
+ if not energy_card then
+ for i, card in ipairs(discard_pile) do
+ if card.energy >= 0 then
+ energy_card = table.remove(discard_pile, i)
+ break
+ end
+ end
+ end
+
+ -- Replace first card with energy-positive card
+ if energy_card then
+ table.insert(draw_pile, temp_hand[1]) -- Put replaced card back
+ temp_hand[1] = energy_card
+ end
+ end
+
+ hand = temp_hand
+ else
+ -- Normal draw when player has energy
+ for i = 1, 3 do
+ if #draw_pile > 0 then
+ table.insert(hand, table.remove(draw_pile, 1))
+ end
+ end
+ end
+
+ -- Fill remaining slots if deck was too small
+ while #hand < 3 and (#draw_pile > 0 or #discard_pile > 0) do
+ reshuffle_if_needed()
+ if #draw_pile > 0 then
+ table.insert(hand, table.remove(draw_pile, 1))
+ end
+ end
+end
+
+-- Initialize deck at start
+initialize_deck()
draw_hand()
-- === CORE TURN LOGIC ===
function apply_effects(timing, player_won)
+ -- Apply current card effects
for _, effect in ipairs(pending_effects.player) do
if effect.timing == timing then
if timing == "post_result" then
@@ -324,6 +577,19 @@ function apply_effects(timing, player_won)
end
end
end
+
+ -- Apply previous card effects if they exist
+ for _, effect in ipairs(pending_effects.previous_player) do
+ if effect.timing == timing then
+ if timing == "post_result" then
+ effect.use(player, enemy, player_won)
+ else
+ effect.use(player, enemy)
+ end
+ end
+ end
+
+ -- Apply current enemy card effects
for _, effect in ipairs(pending_effects.enemy) do
if effect.timing == timing then
if timing == "post_result" then
@@ -333,14 +599,38 @@ function apply_effects(timing, player_won)
end
end
end
+
+ -- Apply previous enemy card effects if they exist
+ for _, effect in ipairs(pending_effects.previous_enemy) do
+ if effect.timing == timing then
+ if timing == "post_result" then
+ effect.use(player, enemy, player_won)
+ else
+ effect.use(player, enemy)
+ end
+ end
+ end
end
+
function start_turn(card)
+ -- Don't store previous cards here anymore - they're already set when returning to choose phase
current_card = card
enemy_card = enemy_cards[math.random(#enemy_cards)]
- -- Store effects for proper timing
+ -- Apply card energy cost/gain
+ player.energy = math.max(0, math.min(5, player.energy + card.energy))
+
+ -- Discard all cards in hand
+ for _, hand_card in ipairs(hand) do
+ table.insert(discard_pile, hand_card)
+ end
+ hand = {}
+
+ -- Store effects for proper timing - both current and previous cards
pending_effects.player = {card}
pending_effects.enemy = {enemy_card}
+ pending_effects.previous_player = previous_card and {previous_card} or {}
+ pending_effects.previous_enemy = previous_enemy_card and {previous_enemy_card} or {}
-- Apply immediate effects
apply_effects("immediate")
@@ -363,9 +653,119 @@ function start_turn(card)
end
picked = 1
+card_pick_selection = 1
+
+-- === DRAWING FUNCTIONS ===
+function draw_hud()
+ -- Draw level
+ spr(0, 110, 2, 0)
+ print(level, 115, 2, 7, false, 1, true)
+
+ -- Draw energy sprites
+ for i = 1, player.energy do
+ local x = -4 + (8 * i)
+ spr(17, x, 10, 0)
+ end
+
+ for i = player.energy + 1, 5 do
+ local x = -4 + (8 * i)
+ spr(18, x, 10, 0)
+ end
+
+ -- Draw deck info
+ spr(4, 220, 115, 0)
+ print(#draw_pile, 230, 116, 10, false, 1, true)
+ spr(5, 220, 125, 0)
+ print(#discard_pile, 230, 126, 14, false, 1, true)
+
+ -- Draw card play boxes at top
+ -- Player card boxes (left side)
+ rectb(4, 20, 40, 16, phase == "choose" and 8 or 2) -- Current player card (or empty slot)
+ if phase == "choose" then
+ print("Next", 16, 25, 8, false, 1, true)
+ elseif current_card then
+ print(current_card.name, 6, 25, 2, false, 1, true)
+ end
+
+ rectb(45, 20, 40, 16, 8) -- Previous player card
+ if previous_card then
+ print(previous_card.name, 47, 25, 8, false, 1, true)
+ end
+
+ -- Enemy card boxes (right side)
+ rectb(155, 20, 40, 16, 8) -- Previous enemy card
+ if previous_enemy_card then
+ print(previous_enemy_card.name, 157, 25, 8, false, 1, true)
+ end
+
+ rectb(196, 20, 40, 16, phase == "choose" and 8 or 6) -- Current enemy card (or empty slot)
+ if phase == "choose" then
+ print("Next", 208, 25, 8, false, 1, true)
+ elseif enemy_card then
+ print(enemy_card.name, 198, 25, 6, false, 1, true)
+ end
+end
+
+function draw_health_bars()
+ -- Draw player health bar
+ for i = 1, 10 do
+ local x = 4 + (i - 1) * 8
+ if i <= player.hp then
+ spr(1, x, 2, 0) -- healthy HP
+ else
+ spr(3, x, 2, 0) -- damaged HP
+ end
+ end
+
+ -- Show player damage
+ if current_damage.player ~= 0 then
+ print((current_damage.player < 0 and "+" or "") .. -math.floor(current_damage.player), 88, 3, current_damage.player > 0 and 2 or 6, false, 1, true)
+ end
+
+ -- Draw enemy health bar
+ for i = 1, enemy.max_hp do
+ local x = 240 - (enemy.max_hp * 8) + (i - 1) * 8
+ if i <= (enemy.max_hp - enemy.hp) then
+ spr(3, x, 2, 0) -- damaged HP on the left
+ else
+ spr(2, x, 2, 0) -- healthy HP on the right
+ end
+ end
+
+ -- Show enemy damage
+ if current_damage.enemy > 0 then
+ local enemy_bar_start = 240 - (enemy.max_hp * 8) - 8
+ print((current_damage.enemy < 0 and "+" or "") .. -math.floor(current_damage.enemy), enemy_bar_start, 3, current_damage.enemy > 0 and 2 or 6, false, 1, true)
+ end
+
+ -- Draw enemy name under health bar
+ local enemy_name_x = 240 - (#enemy.name * 4)
+ print(enemy.name, enemy_name_x, 12, 7, false, 1, true)
+
+ -- Show shield sprite if player has shield
+ if player.shield and player.shield > 0 then
+ for i = 1, player.shield do
+ spr(16, 44 + (i - 1) * 8, 12, 0)
+ end
+ end
+end
+
+function draw_card(card, x, is_selected, can_afford)
+ local border_color = can_afford and (is_selected and 11 or 9) or (is_selected and 13 or 14)
+ rectb(x, 40, 52, 64, border_color)
+ if is_selected then rect(x+1, 41, 50, 62, 8) end
+ local text_color = can_afford and (is_selected and 11 or 9) or (is_selected and 0 or 14)
+ print(card.name, x + 3, 70, text_color, false, 1, true)
+
+ -- Show energy cost/gain
+ local energy_text = card.energy >= 0 and ("+" .. card.energy) or tostring(card.energy)
+ spr(17, x + 30, 42, 0)
+ print(energy_text, x + 40, 44, card.energy >= 0 and 6 or 2, false, 1, true)
+end
+
-- === INPUT ===
function TIC()
- cls(1)
+ cls(0)
if shake > 0 then
poke(0x3FF9, math.random(-d, d))
@@ -376,11 +776,25 @@ function TIC()
end
end
- -- camera(dx, dy)
- -- Draw HUD
- print("Level: " .. level, 100, 4, 12)
- print("PLAYER HP: " .. player.hp, 4, 4, 12)
- print("ENEMY HP: " .. enemy.hp, 4, 14, 8)
+ -- Handle flash effect
+ if flash > 0 then
+ -- Tint screen red on alternating frames
+ if flash % 4 < 2 then -- Flash on/off every 2 frames
+ poke(0x3FC0, 255) -- Red tint
+ else
+ poke(0x3FC0, original_palette[0])
+ end
+ flash = flash - 1
+
+ -- When effect ends, ensure palette is restored
+ if flash == 0 then
+ poke(0x3FC0, original_palette[0])
+ end
+ end
+
+ -- Draw HUD and health bars
+ draw_hud()
+ draw_health_bars()
if phase == "choose" then
-- Card Picker
@@ -392,19 +806,76 @@ function TIC()
picked = picked + 1
end
picked = math.min(3, math.max(1, picked))
+
-- Show cards
for i, card in ipairs(hand) do
local x = 10 + (i - 1) * 64
- rectb(x, 80, 62, 24, i == picked and 1 or 12)
- print(card.name, x + 3, 90, i == picked and 11 or 10, false,1,true)
+ local can_afford = (card.energy >= 0) or (player.energy >= -card.energy)
+ local is_selected = i == picked
+ draw_card(card, x, is_selected, can_afford)
+ end
+
+ local selected_card = hand[picked]
+ local can_afford = (selected_card.energy >= 0) or (player.energy >= -selected_card.energy)
+ print(selected_card.desc, 4, 120, can_afford and 6 or 14)
+ if not can_afford then
+ print("Not enough energy!", 4, 130, 3)
end
- print(hand[picked].desc, 4, 120, 15)
print(msg, 4, 40, 15)
- if btnp(4) then
+ if btnp(4) and can_afford then
start_turn(hand[picked])
end
+ elseif phase == "card_reward" then
+ -- Card selection after level victory
+ print("Choose a card to add to your deck:", 4, 30, 12)
+
+ if btnp(2) then
+ card_pick_selection = card_pick_selection - 1
+ end
+ if btnp(3) then
+ card_pick_selection = card_pick_selection + 1
+ end
+ card_pick_selection = math.min(#card_choice_options, math.max(1, card_pick_selection))
+
+ -- Show card options
+ for i, card_index in ipairs(card_choice_options) do
+ local card = cards[card_index]
+ local x = 10 + (i - 1) * 64
+ local is_selected = i == card_pick_selection
+ draw_card(card, x, is_selected, true) -- always affordable in reward phase
+ end
+
+ -- Show selected card description
+ if #card_choice_options > 0 then
+ local selected_card = cards[card_choice_options[card_pick_selection]]
+ print(selected_card.desc, 4, 110, 15)
+ end
+
+ if btnp(4) and #card_choice_options > 0 then
+ add_card_to_deck(card_choice_options[card_pick_selection])
+ -- Advance to next level
+ level = math.min(level + 1, #enemies)
+ player = {
+ hp = 10,
+ roll_mod = 0,
+ mult = 1,
+ energy = 0
+ }
+ enemy = get_enemy(level)
+ -- Clear card displays for new level
+ current_card = nil
+ enemy_card = nil
+ previous_card = nil
+ previous_enemy_card = nil
+ initialize_deck()
+ draw_hand()
+ phase = "choose"
+ phase_time = 0
+ damage_applied = false
+ end
+
elseif phase == "roll" then
phase_time = phase_time + 1
@@ -422,62 +893,100 @@ function TIC()
phase_time = 0
end
- card_text = "You played " .. current_card.name
- enemy_card_text = "Enemy played " .. enemy_card.name
- print(card_text, 4, 30, 14)
- print(enemy_card_text, 4, 20, 8)
- -- show rolls
- roll_text = "You roll " .. player.display_roll .. " / Enemy rolls " .. enemy.display_roll
- print(roll_text, 4, 40, 12)
+ card_text = ""--"You played " .. current_card.name
+ enemy_card_text = ""--enemy.name .. " played " .. enemy_card.name
+ print(card_text, 4, 40, 2)
+ print(enemy_card_text, 4, 50, 6)
+ -- show dice rolls as sprites
+ local player_dice_sprite = 256 + (player.display_roll - 1) * 2
+ local enemy_dice_sprite = 288 + (enemy.display_roll - 1) * 2
+ spr(player_dice_sprite, 50, 50, 0, 1, 0, 0, 2, 2) -- player dice on left, 16x16
+ spr(enemy_dice_sprite, 150, 50, 0, 1, 0, 0, 2, 2) -- enemy dice on right, 16x16
elseif phase == "mod" then
- print(card_text, 4, 30, 14)
- print(enemy_card_text, 4, 20, 8)
- print(roll_text, 4, 40, 12)
+ print(card_text, 4, 40, 2)
+ print(enemy_card_text, 4, 50, 6)
+ -- show dice rolls as sprites
+ local player_dice_sprite = 256 + (player.display_roll - 1) * 2
+ local enemy_dice_sprite = 288 + (enemy.display_roll - 1) * 2
+ spr(player_dice_sprite, 50, 50, 0, 1, 0, 0, 2, 2) -- player dice on left, 16x16
+ spr(enemy_dice_sprite, 150, 50, 0, 1, 0, 0, 2, 2) -- enemy dice on right, 16x16
mod_text = "mods applied: +" .. player.roll_mod .. " / " .. enemy.roll_mod
- print(mod_text, 4, 50, 10)
+ print(mod_text, 4, 80, 12)
phase_time = phase_time + 1
if phase_time > 60 then
phase = "total"
phase_time = 0
end
elseif phase == "total" then
- print(card_text, 4, 30, 14)
- print(enemy_card_text, 4, 20, 8)
- print(roll_text, 4, 40, 12)
- print(mod_text, 4, 50, 12)
- print("Total " .. player.total .. " / " .. enemy.total, 4, 60, 10)
+ current_damage.player, current_damage.enemy = 0, 0 -- reset damage display
+ print(card_text, 4, 40, 2)
+ print(enemy_card_text, 4, 50, 6)
+ -- show dice rolls as sprites
+ local player_dice_sprite = 256 + (player.display_roll - 1) * 2
+ local enemy_dice_sprite = 288 + (enemy.display_roll - 1) * 2
+ spr(player_dice_sprite, 50, 50, 0, 1, 0, 0, 2, 2) -- player dice on left, 16x16
+ spr(enemy_dice_sprite, 150, 50, 0, 1, 0, 0, 2, 2) -- enemy dice on right, 16x16
+ print(mod_text, 4, 80, 14)
+ print("Total " .. player.total .. " / " .. enemy.total, 4, 90, 12)
phase_time = phase_time + 1
if phase_time > 120 then
phase = "result"
phase_time = 0
end
elseif phase == "result" then
- print(card_text, 4, 30, 14)
- print(enemy_card_text, 4, 20, 8)
- print(roll_text, 4, 40, 12)
- print(mod_text, 4, 50, 12)
- print("Total " .. player.total .. " / " .. enemy.total, 4, 60, 10)
+ print(card_text, 4, 40, 2)
+ print(enemy_card_text, 4, 50, 6)
+ -- show dice rolls as sprites
+ local player_dice_sprite = 256 + (player.display_roll - 1) * 2
+ local enemy_dice_sprite = 288 + (enemy.display_roll - 1) * 2
+ spr(player_dice_sprite, 50, 50, 0, 1, 0, 0, 2, 2) -- player dice on left, 16x16
+ spr(enemy_dice_sprite, 150, 50, 0, 1, 0, 0, 2, 2) -- enemy dice on right, 16x16
+ print(mod_text, 4, 80, 14)
+ print("Total " .. player.total .. " / " .. enemy.total, 4, 90, 14)
local msgtxt = ""
local player_won = nil
if player.total > enemy.total then
player_won = true
local dmg = 2 * player.mult
+ -- Apply rage bonus to increase damage
+ local rage_bonus = player.rage or 0
+ dmg = dmg + rage_bonus
+ -- Apply weaken debuff (player is weakened, so their attacks do less damage)
+ local weaken_reduction = player.weaken or 0
+ dmg = math.max(0, dmg - weaken_reduction)
+
if not damage_applied then
+
enemy.hp = enemy.hp - dmg
+ current_damage.enemy = current_damage.enemy + dmg
+ flash = 8
end
- msgtxt = "You win! Enemy -" .. dmg
+ msgtxt = "You win!"
elseif enemy.total > player.total then
player_won = false
local dmg = 2 * enemy.mult
+ -- Apply rage bonus to increase damage
+ local rage_bonus = enemy.rage or 0
+ dmg = dmg + rage_bonus
+ -- Apply weaken debuff (enemy is weakened, so their attacks do less damage)
+ local weaken_reduction = enemy.weaken or 0
+ dmg = math.max(0, dmg - weaken_reduction)
+
if not damage_applied then
+
-- Apply shield reduction
local shield_reduction = player.shield or 0
dmg = math.max(0, dmg - shield_reduction)
player.hp = player.hp - dmg
+ current_damage.player = current_damage.player + dmg
+ -- Remove shield after taking damage
+ if shield_reduction > 0 and dmg < (2 * enemy.mult) then
+ player.shield = math.max(0, (player.shield or 0) - 1)
+ end
shake = 10
end
- msgtxt = "Enemy wins! You -" .. dmg
+ msgtxt = enemy.name .. " wins!"
else
msgtxt = "Tie!"
end
@@ -488,62 +997,171 @@ function TIC()
end
damage_applied = true
- print(msgtxt, 4, 70, 14)
+ local color = player_won == true and 2 or (player_won == false and 6 or 9)
+ print(msgtxt, 4, 100, color)
if btnp(4) then
-- reset mods & back to choose
player.roll_mod, enemy.roll_mod = 0, 0
player.mult, enemy.mult = 1, 1
- player.counter, enemy.counter = false, false
- player.shield, enemy.shield = 0, 0
- draw_hand()
+ player.weaken, enemy.weaken = 0, 0 -- reset weaken debuffs
+ player.rage, enemy.rage = 0, 0 -- reset rage bonuses
+ -- Don't reset shield - it persists until damage taken
+ -- Add 1 energy at end of turn
+ player.energy = math.min(5, player.energy + 1)
+ -- Reset damage display
+ current_damage.player = 0
+ current_damage.enemy = 0
+
+ -- Move current cards to previous when returning to choose phase
+ previous_card = current_card
+ previous_enemy_card = enemy_card
+ current_card = nil
+ enemy_card = nil
+
+ draw_hand() -- Draw new hand from deck
phase = (enemy.hp <= 0 or player.hp <= 0) and "game_over" or "choose"
phase_time = 0
damage_applied = false
end
elseif phase == "game_over" then
- if enemy.hp < player.hp then
- print("You Win", 4, 60, 12)
+ if enemy.hp <= 0 and player.hp > 0 then
+ local victory_text = "You defeated " .. enemy.name .. "!"
+ local victory_x = 120 - (#victory_text * 3) -- center text (6 pixel font, so 3 pixels per char from center)
+ print(victory_text, victory_x, 60, 6)
+
+ local continue_text = "Press Z to choose new card"
+ local continue_x = 120 - (#continue_text * 3)
+ print(continue_text, continue_x, 100, 9)
else
- print("You Lose", 4, 60, 14)
+ local defeat_text = enemy.name .. " defeated you!"
+ local defeat_x = 120 - (#defeat_text * 3)
+ print(defeat_text, defeat_x, 60, 2)
+
+ local restart_text = "Press X to restart"
+ local restart_x = 120 - (#restart_text * 3)
+ print(restart_text, restart_x, 100, 14)
end
- if btnp(5) then
- if enemy.hp < player.hp then
- level = math.min(level + 1, #enemies)
+ if btnp(4) and enemy.hp <= 0 and player.hp > 0 then
+ -- Victory - go to card selection
+ generate_card_choices()
+ if #card_choice_options > 0 then
+ phase = "card_reward"
+ card_pick_selection = 1
else
- level = 1
+ -- No more cards to unlock, just advance level
+ level = math.min(level + 1, #enemies)
+ player = {
+ hp = 10,
+ roll_mod = 0,
+ mult = 1,
+ energy = 0
+ }
+ enemy = get_enemy(level)
+ -- Clear card displays for new level
+ current_card = nil
+ enemy_card = nil
+ previous_card = nil
+ previous_enemy_card = nil
+ initialize_deck()
+ draw_hand()
+ phase = "choose"
end
+ phase_time = 0
+ damage_applied = false
+ elseif btnp(5) and (enemy.hp > 0 or player.hp <= 0) then
+ -- Loss - restart from level 1
+ level = 1
player = {
hp = 10,
roll_mod = 0,
mult = 1,
- counter = false
+ energy = 0
}
-
enemy = get_enemy(level)
+ -- Clear card displays on restart
+ current_card = nil
+ enemy_card = nil
+ previous_card = nil
+ previous_enemy_card = nil
msg = ""
-
- -- State
+ initialize_deck()
+ draw_hand()
phase = "choose"
phase_time = 0
roll_text = ""
damage_applied = false
end
end
- -- camera(0,0)
end
--
--- 001:eccccccccc888888caaaaaaaca888888cacccccccacc0ccccacc0ccccacc0ccc
--- 002:ccccceee8888cceeaaaa0cee888a0ceeccca0ccc0cca0c0c0cca0c0c0cca0c0c
--- 003:eccccccccc888888caaaaaaaca888888cacccccccacccccccacc0ccccacc0ccc
--- 004:ccccceee8888cceeaaaa0cee888a0ceeccca0cccccca0c0c0cca0c0c0cca0c0c
--- 017:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec
--- 018:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee
--- 019:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec
--- 020:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee
+-- 000:3200000032000000322200003332000033322200333332003333322200000000
+-- 001:0ff00ff0f22ff33ff22f223ff222223f0f2222f000f22f00000ff00000000000
+-- 002:0ff00ff0f66ff55ff66f665ff666665f0f6666f000f66f00000ff00000000000
+-- 003:0ff00ff0feeffddffeefeedffeeeeedf0feeeef000feef00000ff00000000000
+-- 004:0aaaaaa00aa99aa00a9999a00a9999a00a9999a00a9999a00aa99aa00aaaaaa0
+-- 005:0eeeeee00eeffee00effffe00effffe00effffe00effffe00eeffee00eeeeee0
+-- 016:0011110001333310133223311333233113323331013323100013310000011000
+-- 017:0000000000333300033443300344c43003444430033443300033330000000000
+-- 018:0000000000eeee000eeddee00eddcde00edddde00eeddee000eeee0000000000
+-- 019:0006600000666600066666600666666000066000000660000006600000066000
+-- 020:0002200000022000000220000002200002222220022222200022220000022000
+-- 021:3300000034300000034300000034300100034110000012100000112100010011
+-- 022:ee000000ede000000ede000000ede00f000edff00000f2f00000ff2f000f00ff
--
+--
+-- 000:0000000000022222002222220222222202222222022222220222222f022222ff
+-- 001:000000002222200022222200222222202222222022222220f2222220ff222220
+-- 002:000000000002222200222222022f222202fff22202fff222022f222202222222
+-- 003:0000000022222000222222002222222022222220222222202222222022222220
+-- 004:000000000002222200222222022f222202fff22202fff222022f222f022222ff
+-- 005:000000002222200022222200222222202222222022222220f2222220ff222220
+-- 006:000000000002222200222222022f222202fff22202fff222022f222202222222
+-- 007:0000000022222000222222002222f220222fff20222fff202222f22022222220
+-- 008:000000000002222200222222022f222202fff22202fff222022f222f022222ff
+-- 009:0000000022222000222222002222f220222fff20222fff20f222f220ff222220
+-- 010:000000000002222200222222022f222f02fff2ff02fff2ff022f222202222222
+-- 011:0000000022222000222222002222f220ff2fff20ff2fff20f222f22022222220
+-- 016:022222ff0222222f022222220222222202222222002222220002222200000000
+-- 017:ff222220f2222220222222202222222022222220222222002222200000000000
+-- 018:0222222202222222022222220222222202222222002222220002222200000000
+-- 019:2222222022222220222f222022fff22022fff220222f22002222200000000000
+-- 020:022222ff0222222f022222220222222202222222002222220002222200000000
+-- 021:ff222220f222f220222fff20222fff202222f220222222002222200000000000
+-- 022:02222222022f222202fff22202fff222022f2222002222220002222200000000
+-- 023:222222202222f220222fff20222fff202222f220222222002222200000000000
+-- 024:022222ff022f222f02fff22202fff222022f2222002222220002222200000000
+-- 025:ff222220f222f220222fff20222fff202222f220222222002222200000000000
+-- 026:02222222022f222202fff2ff02fff2ff022f222f002222220002222200000000
+-- 027:22222220f222f220ff2fff20ff2fff202222f220222222002222200000000000
+-- 032:0000000000066666006666660666666606666666066666660666666f066666ff
+-- 033:000000006666600066666600666666606666666066666660f6666660ff666660
+-- 034:000000000006666600666666066f666606fff66606fff666066f666606666666
+-- 035:0000000066666000666666006666666066666660666666606666666066666660
+-- 036:000000000006666600666666066f666606fff66606fff666066f666f066666ff
+-- 037:000000006666600066666600666666606666666066666660f6666660ff666660
+-- 038:000000000006666600666666066f666606fff66606fff666066f666606666666
+-- 039:0000000066666000666666006666f660666fff60666fff606666f66066666660
+-- 040:000000000006666600666666066f666606fff66606fff666066f666f066666ff
+-- 041:0000000066666000666666006666f660666fff60666fff60f666f660ff666660
+-- 042:000000000006666600666666066f666f06fff6ff06fff6ff066f666606666666
+-- 043:0000000066666000666666006666f660ff6fff60ff6fff60f666f66066666660
+-- 048:066666ff0666666f066666660666666606666666006666660006666600000000
+-- 049:ff666660f6666660666666606666666066666660666666006666600000000000
+-- 050:0666666606666666066666660666666606666666006666660006666600000000
+-- 051:6666666066666660666f666066fff66066fff660666f66006666600000000000
+-- 052:066666ff0666666f066666660666666606666666006666660006666600000000
+-- 053:ff666660f666f660666fff60666fff606666f660666666006666600000000000
+-- 054:06666666066f666606fff66606fff666066f6666006666660006666600000000
+-- 055:666666606666f660666fff60666fff606666f660666666006666600000000000
+-- 056:066666ff066f666f06fff66606fff666066f6666006666660006666600000000
+-- 057:ff666660f666f660666fff60666fff606666f660666666006666600000000000
+-- 058:06666666066f666606fff6ff06fff6ff066f666f006666660006666600000000
+-- 059:66666660f666f660ff6fff60ff6fff606666f660666666006666600000000000
+--
+
--
-- 000:00000000ffffffff00000000ffffffff
-- 001:0123456789abcdeffedcba9876543210