0,]']±>Sï}WÿÍu§ðp8·d%qy)6o;]ÉA¦ösï÷ôôô”°ÂVl†3 ÿ Ý"îÒÝÒ"   𙀘‰©�ˆ‰‰ùù©‰Š ˆš¨™¯™š ™  vÐpvà}gm`>ðððÿgfgvgwÿðððÇÃÂÂÂÂÂÃÁ€€€€€ÁÁ€€€€€ÁÁ€€€€€ÁÃÂÂÂÂÂà ut=<<<=>????????????????????????A©?ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ íîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî íîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî íîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî íîÝÞíîîîîîîîîîîîîîîîîîîîÞíîîîîîîÞíîîÝîÝíîîîîîîîÝÝÞÝíÞÝíîîîîîîîî íîÝÝíÞÝîÝîíÞÝîîîÝîíÝÝîîîÝÝíÞÝîîîÝíîÝÝÞíîîîîíîîÞÝîÞíÞÞíÞîîîîîîîî íîÝÝíÝîíÝîíÝÞíîîÝîíÝîíîîÞíîÝîíîîÞíÞîÝÞÝíîîÞÝîîîÝíÞíÞÞíÞîîîîîîîî íîíííÝîíÞÝîÝíîîîÝîíÝîíîîÞíîÝîíîîÞíÞîÝÞíÞîîîíîîîÞÝÞÝíÞíÞîîîîîîîî íîíîíÞÝîîíîÞÝîîîÞÝîÝÝîîîîÝíÞÝîîîÝÝîÝÝîÝíîîîîîîÞÝíÞíîÞÝíîîîîîîîî íîîîîîîîîîîîîîîîîîîÝîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî íîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî ÝÝÝÝÝÝíîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî ÝÝÝÝÝÝíîÞÝíÝÝîÞÝíÞÝíÞÝîÞÝíîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîÝÝÝÝÝÝÝÝÝÝÝÝÿîÝîÿÝîíîÝíîÝîííÞíÝíîÝÞíÝíîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîÝÝÝÝÝÝÝÝÝÝÝÝÿîÝîÿÝîíîîÝíÝîííÞíÝíîÝíîîÝíÝîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîíîÝîîîîîîîÝîîÝîÿîÿÿÝÿíîÝÝîÝÝîÞÝíÞÝíÞÝîÝÝîÝîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîíîÝîîîîîîîÝîîÝîÿîÿÿÝÿíîîîîÝîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî îîîÝÝÝÝÝîíîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî îîîÝÝÝÝÝîíîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî ÿÿÿÝîîîîîÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ ÿÿÿÝîîîîîÝÿÿÿÿÿÿÿÿÿÿÝÿÿÿÿÿÝÿÿÿÿÿÿÿÿÿÿÝÿÿÿÿÿÝÿÿÿÿÿÝÝÿÿÿÿÿÝÝ ÝÝ ÝÝî!ÝîÝî"""ÝîÝÝÝ ÝÝîÿÝîÿÝîÿ`VUÝîÿÝÿÿ0`fÝÿÿÝÿÿ# #ÝÿÿÝÿÿ23 ÝÿÿÝÿÿ #`ÝÿÿÝîÿÿwwww" rwwwwwwwwwÝîÿÿÝîÿÿwwwwwwwwwwwwwwwÝîÿÿÝîÿwqwwwwwwwwwwwwwÝîÿÝîÿwrwwwwwwwwwwwpwwÝîÿÝî gÝîÐ Ð Ýî gwÝîÝÝ Ý ÝÝÝÝÝ Ýî!pfvÝîÐ Ý Ý Ý Ð Ýî"""`1aÝîÐ Ý ÝÝ Ð Ý`4dÝÝ ÐÝÝÝ ÝÝÝ pFdÝÝîÿ vgÝîÿÝîÿ`VUÐpvfgÝîÿÝÿÿ0`fà}gvgÝÿÿÝÿÿ# #m`wÝÿÿðòÝÿÿ23 >ðÿÝÿÿ/"îîîîÝÿÿ #`ððÝÿÿð"ÂòîàîÝîÿÿw" rwwwwwwwwww÷ðwÝîÿÿð""òîîîîÝîÿÿwwwwwwwwwwwwwÿðÝîÿÿð!"ñàààÝîÿwwwwwwwwwwwwwwwÝîÿîîîîÝîÿwwwwwwwwwwwwwwwÝîÿðÿÝîÝîÝîÝîÝîÝî" 03@DÝîÝî""3DÝÝ""3@DÝÝ33DÝîÿÝîÿ3DDÝîÿÝîÿÝÿÿÝÿÿÝÿÿÝÿÿÝÿÿÝÿÿÝÿÿÝÿÿ033ÝîÿÿwwwwwwwwwwwwwwwÝîÿÿ0"2ÝîÿÿwwwwwwwwwwwwwwwÝîÿÿ033ÿðÿÿÿÝîÿwwwwwwwwwwwwwwwÝîÿ00ðððÿðÝîÿwwwwwwwwwwwwwwwÝîÿ00ÿÿðÿÿÝîÝî033ðÿðÝîÝî""ÿððÿðÿÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÿîÝîÿÝîÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÿîÝîÿÝî""ÝÿîÝîÿÝîÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÿîÝîÿÝî"!ÿðÿÿÿÝîÿîÿÿÝÿîîîîîÝîîîîîîîÝîîîîîîîÝîîîîîîîÝîîîîîîîÝîîÝîÿîÿÿÝÿðÿðÿðÝîÿîÿÿÝÿîîîîîÝîîîîîîîÝîîîîîîîÝîîîîîîîÝîîîîîîîÝîîÝîÿîÿÿÝÿ"!ðÿððÿÿîÝÝÝÝÝîîîîîîîÝÝÝÝÝîÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ ððÿðîÝÝÝÝÝîîîîîîîÝÝÝÝÝî,"""""""""""""""""""""""" ""ÿððÿðÿÿÝîîîîîÿÿÿÿÿÿÝîîîîî,"""""""""""""""""""""""" ÿÝîîîîîÿÿÿÿÿÿÝîîîîî,""""""""Ì"""Ì""""""""""" ÝÿÿÿÿÿÿÿÿÿÿÝÿÿÿÿÿ,"Ì,ÂÌ,"ÌÌ""ÂÌÌÂ,ÂÂÌ,ÂÌ," 33ÝÿÿÿÿÿÿÿÿÿÿÝÿÿÿÿÿ,Â,ÌÂ,ÂÂ"Ì"""Ì"Â,ÂÂ,ÂÂ,Â" 32#ÿððÿÿÝÿÿÿÿÿÝ,ÂÌ"Â,ÂÂ"Ì"""Ì"Â,ÂÂ,"Â,Â" ###ðÿðÝÿÿÿÿÿÝ,"Ì,Â,Â"ÌÌ"""ÂÌ"Ì,Â,"Â,Â" 32#ðÿðððÿÝÝÝÐ ,"""""""""""""""""""""""" ###ððÿÝÝÝÝ ÐÝÝ ÐÝ,"""""""""""""""""""""""" 33#ÿððÿÝÝ Ý Ý ÝÐÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ "" Ý ÐÝÝ ÐÝ ÐÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ  """""""""""""""" """""""""""""""" """"""""""""""/" "ÌÍÜ"""""""ÂÌýò" "ÌÌÜ"""""""ÌÍÜ"/ "ÌÌÜ"""""""ÌÜÜÂò """"""""""""""""""ÜÜÜ"""""""ÌýÜ"ò """"""""""""""""23333333333333333!"""""""""""""""""Ü"Ü"""""""ÂÌ-"ñ """"""""""""""""23333333333333333!"""""""""""""""""""""""""""""/ """"""""""""""/"23333333333333ó33!"""""""""""""ò"""""""""""""""òÿ" "ÂÌ-ÂÌÜ""""Ì-òò"2ÃÜÌ=333333ÃÌÜ/?3!ÂÜÌ-"""""""ÌÜ//""""""""""""""""" "Ì-ÜÌÜ""""ÂÌ-/"/2ÃÌÌ=33333333Ì-ò3!ÂÌÌ-""""""ÂÜÌ-ò""""""""""""""""" "Ì-ÜÂÌ-""""Ìý"Âò2ÃÌÌ=3333333ÌÜ",?!ÂÌÌ-""""""ÂÌÍ-,/ "ÌÌÜ"ÌÜ""""Ìý""ò2ÃÍÍ=333333ÃÜ/""?!ÂÍÍ-""""""ÂÜÏ-"/"""""""""""""""" "Ì-ÜÌÌ-"""ÂÌÜ!"ñ2Ã=Ã=333333ÃÌÌ-?!Â-Â-"""""""ÌÜ"/ÂÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ """""""""""""/2333333333333óñ3!""""""""""""òñ"ÂÀ """""""""""""òÿ"23333333333333ÿ?3!"""""""""""""ÿ/"ÂÀ """"""""""""""""23333333333333333!""""""""""""""""ÂÀ """"""""""""""""23333333333333333!""""""""""""""""Â""À """""""""""""""""Â""À """"""""""""""""23333333333333333!""""""""""""""""Â"À ÂÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ2ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ0 and true or false end;function mouse.toggle_lock()poke(0x7FC3F,peek(0x7FC3F,1)>0 and 0 or 1,1)end;function mouse.in_bound(x,y,a,b)return mouse.x>=x and mouse.x=y and mouse.y= self.actor.max_hand then trace(self.actor.name .. " has a full hand.") return end id = self.cards[1] table.remove(self.cards, 1) trace(self.actor.name .. " drew '"..id.."'.") table.insert(self.actor.hand.cards, make_card(id, self.actor)) end -- loads all discarded cards into the deck function deck_methods.refill(self) self.cards = self.actor.discard_pile self.actor.discard_pile = {} self:shuffle() end -- end hand functions deckmt.__index = deck_methods -------------------- -- hand functions -- -------------------- function make_hand(actor) local hand = {cards={}, actor=actor} setmetatable(hand,handmt) return hand end -- discard our hand function hand_methods.discard(self) for k,card in pairs(self.cards) do table.insert(self.actor.discard_pile, card.id) end self.cards = {} end function hand_methods.add_card(self, id) table.insert(self.cards, make_card(id, self.actor)) end -- end hand functions handmt.__index = hand_methods --------------------- -- actor functions -- --------------------- function make_actor(a) local actor = { name = a.name or "actor", sprite = a.sprite, pos = a.pos, max_energy = a.max_energy or 1, energy = a.max_energy or 1, max_hand = a.max_hand or 6, draw_count = a.draw_count or 4, turn = 0, move_range = nil, -- if char is about to move, we have a move range initiative = 0, hand = {}, deck = {}, discard_pile = {}, encounter_discard_pile = {}, max_actions = { M=1, A=1, S=1 }, actions = { M=1, A=1, S=1 }, } actor.hand = make_hand(actor) actor.deck = make_deck(actor, a.deck or {"move", "claw"}) actor.deck:shuffle() setmetatable(actor, actormt) return actor end function actor_methods.start_turn(self) trace(self.name.."'s turn.",13) self.turn = self.turn + 1 self.actions = { M=self.max_actions.M, A=self.max_actions.A, S=self.max_actions.S, } if self.energy < self.max_energy then self.energy = self.energy + 1 end self.hand:discard() self.deck:deal_hand(self.draw_count) end function actor_methods.any_remaining_actions(self) for i, card in ipairs(self.hand.cards) do if card:playable() then return true end end return false end function actor_methods.roll_initiative(self) self.initiative = roll_dice(1,20) end -- TODO: refactor this to target different card pools function actor_methods.cards_with_flag(self, flag) local found_cards = {} for i, card in ipairs(self.hand.cards) do if card:has_flag(flag) then table.insert(found_cards, card) end end for i, id in ipairs(self.deck.cards) do local card = make_card(id) if card:has_flag(flag) then table.insert(found_cards, card) end end for i, id in ipairs(self.discard_pile) do local card = make_card(id) if card:has_flag(flag) then table.insert(found_cards, card) end end for i, id in ipairs(self.encounter_discard_pile) do local card = make_card(id) if card:has_flag(flag) then table.insert(found_cards, card) end end return found_cards end function actor_methods.display(self) spr(self.sprite,60 + self.pos.x * 16, 14 - 4 + self.pos.y * 16, 0, 1, 0, 0, 2, 2) end function actor_methods.move(self, tilepos) self.pos = tilepos self.move_range = nil end -- end actor functions actormt.__index = actor_methods -------------------- -- dice functions -- -------------------- function roll_dice(n, d) total = 0 for i = 1,n do roll = math.random(d) total = total + roll end return total end ------------------ -- UI functions -- ------------------ function display_debug_log() end function make_movement_button(tilepos, actor) local x = 60 + tilepos.x * 16 local y = 14 + tilepos.y * 16 if global_map:is_solid_tile(tilepos) then return end if global_map:is_tile_occupied(tilepos) then spr(38,x, y, 0, 2) return end spr(36,x, y, 0, 2) if mouse.in_bound(x, y, 16, 16) then spr(37,x, y, 0, 2) if mouse.released(1) then actor:move(tilepos) end end end function display_movement_ui(actor, range) for i = math.max(0, actor.pos.x-range), math.min(global_map.size.x - 1, actor.pos.x+range) do for j = math.max(0, actor.pos.y-range), math.min(global_map.size.y - 1, actor.pos.y+range) do local dist = actor.pos:tile_distance(make_vec2d(i,j)) if dist <= range then make_movement_button(make_vec2d(i,j), actor) end end end end function textbox(message, x,y,w,c) words = split(message, " ") len_words = #words local lines = {{}} local line = 1 local line_w = 0 for i = 1,#words do word_with_space = words[i].." " word_length = print(words[i],0,-6) word_with_space_length = print(words[i].." ",0,-6) line_w = line_w + word_length if line_w > w then table.insert(lines, {}) line = line + 1 line_w = word_with_space_length else line_w = line_w - word_length + word_with_space_length -- hacky code to add just the width of the " " char end table.insert(lines[line], word_with_space) end rect(x-4,y-4,w+7,#lines * 8 +4, 13) rect(x-3,y-3,w+5,#lines * 8 +2, 14) for i, line in ipairs(lines) do text_line = "" for j=1,#line do text_line = text_line..line[j] end print(text_line, x, y + (i-1) * 7,c) end end function display_turn_wi_ui() print("turn " .. player_actor.turn,2,45,13) spr(22,1,53) print(player_actor.energy .. "/" .. player_actor.max_energy, 10, 55, 14) local width_add = 0 local color = 2 local order = {"M","A","S"} for i = 1,3 do g = player_actor.actions[order[i]] for j = 1, g do local w = print(order[i],2 + width_add,63,color) width_add = width_add + w end color = color + 1 end if width_add == 0 then -- if there's nothing print "none" print("none", 2, 63, 13) end end function display_play_line() if holding_card then line(2,play_line_y,238,play_line_y,2) width = print("- clear this line and release to play card -",0,-6) offset = (240 - width) / 2 print("- clear this line and release to play card -",offset,97,2) end end -- show played cards fading out function display_played_card_animations() for k, c in pairs(kill_hand) do frame = math.floor((tick - c.start_tick)/8) + 1 if frame >= 5 then table.remove(kill_hand,k) end display_dead_card(c, frame) end end -- temporary "draw card" function function handle_and_display_turn_button() if player_actor.move_range then return end x=188 y=86 w=48 h=8 local color = 2 if not player_actor:any_remaining_actions() then color = 6 end rect(x-2,y-2,w+3,h+3,12) rect(x-1,y-1,w+1,h+1,color) print("end turn", x+1, y+1, 12) if mouse.in_bound(x,y,w,h) then if mouse.pressed(1) then rect(x-1,y-1,w+1,h+1,color-1) print("end turn", x+1, y+1, 13) end if mouse.released(1) then end_turn() end end end -- display deck widget function display_deck_count() spr(19,1,72) ld = #player_actor.deck.cards print(ld.."/"..#player_actor.discard_pile+ld+#player_actor.hand.cards,11,74) end -- display discard pile widget function display_discard_count() spr(20,1,80) ld = #player_actor.discard_pile print(ld.."/"..ld+#player_actor.deck.cards+#player_actor.hand.cards,11,82) end -- display encounter discard pile widget function display_encounter_discard_count() spr(21,1,88) ld = #player_actor.encounter_discard_pile print(ld.."/"..#player_actor:cards_with_flag("encounter_discard"),11,90) end ------------------- -- map functions -- ------------------- function make_map() local m = { start_pos = make_vec2d(0,0), size = make_vec2d(7,5), screen_pos = make_vec2d(60, 14) } setmetatable(m, mapmt) return m end function map_methods.is_solid_tile(self, pos) return mget(pos.x - self.start_pos.x,pos.y - self.start_pos.y) >= 192 -- 192 is where solid tiles start end function map_methods.is_tile_occupied(self, pos) for i, actor in ipairs(actors) do if actor.pos == pos then return true end -- TODO: big actors need a w/h calculation end return false end function map_methods.display(self) map(self.start_pos.x,self.start_pos.y,self.size.x,self.size.y, self.screen_pos.x, self.screen_pos.y, 0, 2) end mapmt.__index = map_methods -------------------- -- card functions -- -------------------- -- returns a card object function make_card(id, actor) local card = {p=cards[id], -- prototype p comes from immutable card record in global store `cards` actor=actor, id=id, -- key for this card in the `cards` global x=120 - card_width / 2, y=68 - card_height / 2, hover=false, held=false, held_x=0, held_y=0, spread_x=0, spread_y=0, play_me=false, start_tick=1} setmetatable(card, cardmt) return card end -- handles the input and interaction logic for a card function process_card_input(card, hand_index) x=card.x y=card.y small_bound = mouse.in_bound(x-1,y-1,card_width / crowd_factor,card_height) in_bound = small_bound or (hand_index == #player_actor.hand.cards and mouse.in_bound(x-1,y-1,card_width,card_height)) -- the "or" handles hovering on final card -- hover over cards if we peek them with the mouse if in_bound then if not hover_card and not holding_card then card.hover=true hover_card=card sfx(2) end end -- check for presses when we are hovering if card.hover then if mouse.pressed(1) and not holding_card then card.held = true card.hover = false card.held_x = mouse.x - x card.held_y = mouse.y - y sfx(1) holding_card = card hover_card = nil end -- if we go out of bounds, un-hover if not in_bound then card.hover = false hover_card = nil end end -- when we're holding check for plays if card.held then card.x = mouse.x - card.held_x card.y = mouse.y - card.held_y if mouse.released(1) and holding_card then -- play the card if we clear the play line if card.y + card_height < play_line_y then if card == hover_card then hover_card = nil end if card == holding_card then holding_card = nil end if card:playable() then card.play_me = true end end -- unhold the played card card.held = false holding_card = nil end end end -- play card animation function display_dead_card(card, frame) x=card.x y=card.y r=card.p.rarity+1 if frame == 1 then rect(x+1,y+29,31,20,12) rect(x+2,y+30,29,18,0) spr(card.p.sprite,x+8,y+31,0,2,0,0,1,1) elseif frame == 2 then local width=print(card.p.name,0,-6) min_r = r - 1 if min_r < 1 then min_r = 1 end print(card.p.name,x - width/2 + card_width/2,y+14, min_r) spr(card.p.sprite,x,y+23,0,4,0,0,1,1) elseif frame >= 3 then local width=print(card.p.name,0,-6) print(card.p.name,x - width/2 + card_width/2,y+14, r) spr(card.p.sprite,x,y+23,0,4,0,0,1,1) end end -- handles the smoothing function for spreading the card. Decides where a card is "supposed to .cardsbe". function spread_card(card,hand_index,total) if card.play_me then card.spread_x = card.x card.spread_y = card.y return end -- manually set when and how much we cram cards together crowd_factor = 1 if total > 18 then crowd_factor = 4 elseif total > 15 then crowd_factor = 3 elseif total > 12 then crowd_factor = 2.5 elseif total > 9 then crowd_factor = 2 elseif total > 6 then crowd_factor = 1.5 end -- highlight cards which match the current action add_y_level = 0 if card:playable() then add_y_level = 8 end if card.hover then add_y_level = 16 end if turn_actor ~= player_actor and card.actor == player_actor then add_y_level = add_y_level - 12 end card.spread_x = 120 + ((hand_index - total/2) * card_width / crowd_factor) - card_width + (card_x_level / 12) * total card.spread_y = card_y_level - add_y_level x_dist = card.spread_x - card.x y_dist = card.spread_y - card.y card.x = card.x + x_dist / 10 card.y = card.y + y_dist / 10 end function card_methods.playable(self) return self:match_current_available_actions() and player_actor.energy >= self.p.energy end function card_methods.has_flag(self, flag) if not self.p.flags then return end for i, f in ipairs(self.p.flags) do if f.id == flag then return true end end return false end -- big play card function function card_methods.play(self, hand_index) sfx(0) self.start_tick = tick table.remove(player_actor.hand.cards,hand_index) -- remove us from hand anim_index = table.insert(kill_hand, self) -- start play animation -- discard card if self:has_flag("encounter_discard") then table.insert(player_actor.encounter_discard_pile, self.id) elseif not self:has_flag("return") then table.insert(player_actor.discard_pile, self.id) end -- subtract energy player_actor.energy = player_actor.energy - self.p.energy -- do card flag functions if self.p.flags then for i, flag in ipairs(self.p.flags) do -- move -- if flag.id == "move" then player_actor.move_range = roll_dice(flag.value[1],flag.value[2]) + player[flag.value[3]] -- draw N cards -- elseif flag.id == "draw" then for i=1,flag.value do player_actor.deck:deal_top_card() end -- return to hand -- elseif flag.id == "return" then player_actor.hand:add_card(self.id) -- add a copy of this to the hand -- grant action -- elseif flag.id == "grant_action" then player_actor.actions[flag.value[1]] = player_actor.actions[flag.value[1]] + flag.value[2] -- grant energy -- elseif flag.id == "energy" then player_actor.energy = player_actor.energy + flag.value if player_actor.energy > player_actor.max_energy then player_actor.energy = player_actor.max_energy end end end end -- roll action a = self:match_current_available_actions() if a then -- "N" actions don't decrement anywhere else so avoid nil error by checking actions array if player_actor.actions[a] then player_actor.actions[a] = player_actor.actions[a] - 1 end end end function card_methods.match_current_available_actions(self) local actions = self.p.action if string.find(actions, "N") then return "N" end for i=1,#actions do local action = string.sub(actions,i,i) for j, g in pairs(player_actor.actions) do if action == j then -- same action if g > 0 then -- if we have actions remaining, we can play this card. return action end end end end return false end function card_methods.display_back(self) x=self.x y=self.y r=self.p.rarity color = 2 bg_color = 1 if self:has_flag("encounter_discard") then color = 3 bg_color = 2 end rect(x-1,y-1,card_width,card_height,bg_color) rect(x,y,33,12,color) rect(x,y+13,33,37,color) end -- display a card (every frame) function card_methods.display(self) if self.play_me then return end x=self.x y=self.y r=self.p.rarity color = 2 bg_color = 1 if self:has_flag("encounter_discard") then color = 3 bg_color = 2 end -- print reasons card is not playable if not self.hover and not self.held then -- energy UI if player_actor.energy < self.p.energy then spr(22,x+2,y-10) end -- action UI if not self:match_current_available_actions() then local w = print(self.p.action,0,-6) print(self.p.action,x-3-w+card_width,y-8,13) end end if self.hover then rect(x-2,y-2,card_width+2,card_height+2,13) textbox(self.p.description,8,8,120,13,14) local width=print(self.p.name,0,-6) print(self.p.name,x - width/2 + card_width/2,y - 8,13) end if self.held then rect(x-2,y-2,card_width+2,card_height+2,12) textbox(self.p.description,8,8,120,12,14) local width=print(self.p.name,0,-6) print(self.p.name,x - width/2 + card_width/2,y - 8,12) end rect(x-1,y-1,card_width,card_height,bg_color) rect(x,y,33,12,color) rect(x,y+13,33,37,color) -- card art rect(x+1,y+14,31,20,12) rect(x+2,y+15,29,18,0) spr(self.p.sprite,x+8,y+16,-1,2,0,0,1,1) -- print action (MAS) print(self.p.action, x+3, y+3, 13) print(self.p.action, x+2, y+3, 12) -- print energy local ew= print(self.p.energy, 0, -6) spr(22,x+25,y+2,0) print(self.p.energy,x+17+ew,y+3, 13) print(self.p.energy,x+16+ew,y+3, 12) -- quality rect(x+22,y+39,10,10,r+1) spr(r+3,x+23,y+40) end -- end of card methods cardmt.__index = card_methods -- string split function function split(s, delimiter) result = {}; for match in (s..delimiter):gmatch("(.-)"..delimiter) do table.insert(result, match); end return result; end -- metatable copy function function copymt(o) local c if type(o) == 'table' then c = {} for k, v in pairs(o) do c[k] = copymt(v) end else c = o end return c end -- dump table function function dump(o) if type(o) == 'table' then local s = '{ ' for k,v in pairs(o) do if type(k) ~= 'number' then k = '"'..k..'"' end s = s .. '['..k..'] = ' .. dump(v) .. ',' end return s .. '} ' else return tostring(o) end end -- run init function init()