remove lovely root directory

This commit is contained in:
Vomitblood 2025-02-11 02:12:03 +08:00
parent feefd09596
commit c41e0ec457
21 changed files with 0 additions and 38734 deletions

View file

@ -1,321 +0,0 @@
LOVELY_INTEGRITY = 'd3c881055f5938773f6b44e7c8b207117963612b2eaf889f5b7ef8b61e1143cd'
--Class
Back = Object:extend()
--Class Methods
function Back:init(selected_back)
if not selected_back then selected_back = G.P_CENTERS.b_red end
self.atlas = selected_back.unlocked and selected_back.atlas or nil
self.name = selected_back.name or 'Red Deck'
self.effect = {
center = selected_back,
text_UI = '',
config = copy_table(selected_back.config)
}
self.loc_name = localize{type = 'name_text', set = 'Back', key = self.effect.center.key}
local pos = (self.effect.center.unlocked and self.effect.center.pos) or {x = 4, y = 0}
self.pos = self.pos or {}
self.pos.x = pos.x
self.pos.y = pos.y
end
function Back:get_name()
if self.effect.center.unlocked then return self.loc_name else return localize('k_locked') end
end
function Back:generate_UI(other, ui_scale, min_dims, challenge)
min_dims = min_dims or 0.7
ui_scale = ui_scale or 0.9
local back_config = other or self.effect.center
local name_to_check = other and other.name or self.name
local effect_config = other and other.config or self.effect.config
challenge = G.CHALLENGES[get_challenge_int_from_id(challenge or '') or ''] or {name = 'ERROR'}
local loc_args, loc_nodes = nil, {}
if not back_config.unlocked then
local localized_by_smods
local key_override
if back_config.locked_loc_vars and type(back_config.locked_loc_vars) == 'function' then
local res = back_config:locked_loc_vars() or {}
loc_args = res.vars or {}
key_override = res.key
end
if G.localization.descriptions.Back[key_override or back_config.key].unlock_parsed then
localize{type = 'unlocks', key = key_override or back_config.key, set = 'Back', nodes = loc_nodes, vars = loc_args}
localized_by_smods = true
end
if not back_config.unlock_condition then
if not localized_by_smods then
localize{type = 'descriptions', key = 'demo_locked', set = "Other", nodes = loc_nodes, vars = loc_args}
end
elseif back_config.unlock_condition.type == 'win_deck' then
local other_name = localize('k_unknown')
if G.P_CENTERS[back_config.unlock_condition.deck].unlocked then
other_name = localize{type = 'name_text', set = 'Back', key = back_config.unlock_condition.deck}
end
loc_args = loc_args or {other_name}
localize{type = 'descriptions', key = 'deck_locked_win', set = "Other", nodes = loc_nodes, vars = loc_args}
elseif back_config.unlock_condition.type == 'discover_amount' then
loc_args = loc_args or {tostring(back_config.unlock_condition.amount)}
localize{type = 'descriptions', key = 'deck_locked_discover', set = "Other", nodes = loc_nodes, vars = loc_args}
elseif back_config.unlock_condition.type == 'win_stake' then
local other_name = localize{type = 'name_text', set = 'Stake', key = G.P_CENTER_POOLS.Stake[back_config.unlock_condition.stake].key}
loc_args = loc_args or {other_name, colours = {get_stake_col(back_config.unlock_condition.stake)}}
localize{type = 'descriptions', key = 'deck_locked_stake', set = "Other", nodes = loc_nodes, vars = loc_args}
end
else
local key_override
if back_config.loc_vars and type(back_config.loc_vars) == 'function' then
local res = back_config:loc_vars() or {}
loc_args = res.vars or {}
key_override = res.key
elseif name_to_check == 'Blue Deck' then loc_args = {effect_config.hands}
elseif name_to_check == 'Red Deck' then loc_args = {effect_config.discards}
elseif name_to_check == 'Yellow Deck' then loc_args = {effect_config.dollars}
elseif name_to_check == 'Green Deck' then loc_args = {effect_config.extra_hand_bonus, effect_config.extra_discard_bonus}
elseif name_to_check == 'Black Deck' then loc_args = {effect_config.joker_slot, -effect_config.hands}
elseif name_to_check == 'Magic Deck' then loc_args = {localize{type = 'name_text', key = 'v_crystal_ball', set = 'Voucher'}, localize{type = 'name_text', key = 'c_fool', set = 'Tarot'}}
elseif name_to_check == 'Nebula Deck' then loc_args = {localize{type = 'name_text', key = 'v_telescope', set = 'Voucher'}, -1}
elseif name_to_check == 'Ghost Deck' then
elseif name_to_check == 'Abandoned Deck' then
elseif name_to_check == 'Checkered Deck' then
elseif name_to_check == 'Zodiac Deck' then loc_args = {localize{type = 'name_text', key = 'v_tarot_merchant', set = 'Voucher'},
localize{type = 'name_text', key = 'v_planet_merchant', set = 'Voucher'},
localize{type = 'name_text', key = 'v_overstock_norm', set = 'Voucher'}}
elseif name_to_check == 'Painted Deck' then loc_args = {effect_config.hand_size,effect_config.joker_slot}
elseif name_to_check == 'Anaglyph Deck' then loc_args = {localize{type = 'name_text', key = 'tag_double', set = 'Tag'}}
elseif name_to_check == 'Plasma Deck' then loc_args = {effect_config.ante_scaling}
elseif name_to_check == 'Erratic Deck' then
end
localize{type = 'descriptions', key = key_override or back_config.key, set = 'Back', nodes = loc_nodes, vars = loc_args}
end
return
{n=G.UIT.ROOT, config={align = "cm", minw = min_dims*5, minh = min_dims*2.5, id = self.name, colour = G.C.CLEAR}, nodes={
name_to_check == 'Challenge Deck' and UIBox_button({button = 'deck_view_challenge', label = {localize(challenge.id, 'challenge_names')}, minw = 2.2, minh = 1, scale = 0.6, id = challenge})
or desc_from_rows(loc_nodes, true, min_dims*5)
}}
end
function Back:change_to(new_back)
if not new_back then new_back = G.P_CENTERS.b_red end
self.atlas = new_back.unlocked and new_back.atlas or nil
self.name = new_back.name or 'Red Deck'
self.effect = {
center = new_back,
text_UI = '',
config = copy_table(new_back.config)
}
self.loc_name = localize{type = 'name_text', set = 'Back', key = self.effect.center.key}
local pos = self.effect.center.unlocked and copy_table(new_back.pos) or {x = 4, y = 0}
self.pos.x = pos.x
self.pos.y = pos.y
end
function Back:save()
local backTable = {
name = self.name,
pos = self.pos,
effect = self.effect,
key = self.effect.center.key or 'b_red'
}
return backTable
end
function Back:trigger_effect(args)
if not args then return end
local obj = self.effect.center
if obj.trigger_effect and type(obj.trigger_effect) == 'function' then
local o = {obj:trigger_effect(args)}
if o then return unpack(o) end
end
if self.name == 'Anaglyph Deck' and args.context == 'eval' and G.GAME.last_blind and G.GAME.last_blind.boss then
G.E_MANAGER:add_event(Event({
func = (function()
add_tag(Tag('tag_double'))
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
play_sound('holo1', 1.2 + math.random()*0.1, 0.4)
return true
end)
}))
end
if self.name == 'Plasma Deck' and args.context == 'blind_amount' then
return
end
if self.name == 'Plasma Deck' and args.context == 'final_scoring_step' then
local tot = args.chips + args.mult
args.chips = math.floor(tot/2)
args.mult = math.floor(tot/2)
update_hand_text({delay = 0}, {mult = args.mult, chips = args.chips})
G.E_MANAGER:add_event(Event({
func = (function()
local text = localize('k_balanced')
play_sound('gong', 0.94, 0.3)
play_sound('gong', 0.94*1.5, 0.2)
play_sound('tarot1', 1.5)
ease_colour(G.C.UI_CHIPS, {0.8, 0.45, 0.85, 1})
ease_colour(G.C.UI_MULT, {0.8, 0.45, 0.85, 1})
attention_text({
scale = 1.4, text = text, hold = 2, align = 'cm', offset = {x = 0,y = -2.7},major = G.play
})
G.E_MANAGER:add_event(Event({
trigger = 'after',
blockable = false,
blocking = false,
delay = 4.3,
func = (function()
ease_colour(G.C.UI_CHIPS, G.C.BLUE, 2)
ease_colour(G.C.UI_MULT, G.C.RED, 2)
return true
end)
}))
G.E_MANAGER:add_event(Event({
trigger = 'after',
blockable = false,
blocking = false,
no_delete = true,
delay = 6.3,
func = (function()
G.C.UI_CHIPS[1], G.C.UI_CHIPS[2], G.C.UI_CHIPS[3], G.C.UI_CHIPS[4] = G.C.BLUE[1], G.C.BLUE[2], G.C.BLUE[3], G.C.BLUE[4]
G.C.UI_MULT[1], G.C.UI_MULT[2], G.C.UI_MULT[3], G.C.UI_MULT[4] = G.C.RED[1], G.C.RED[2], G.C.RED[3], G.C.RED[4]
return true
end)
}))
return true
end)
}))
delay(0.6)
return args.chips, args.mult
end
end
function Back:apply_to_run()
local obj = self.effect.center
if obj.apply and type(obj.apply) == 'function' then
obj:apply()
end
if self.effect.config.voucher then
G.GAME.used_vouchers[self.effect.config.voucher] = true
G.GAME.cry_owned_vouchers[self.effect.config.voucher] = true
G.GAME.starting_voucher_count = (G.GAME.starting_voucher_count or 0) + 1
Card.apply_to_run(nil, G.P_CENTERS[self.effect.config.voucher])
end
if self.effect.config.hands then
G.GAME.starting_params.hands = G.GAME.starting_params.hands + self.effect.config.hands
end
if self.effect.config.consumables then
delay(0.4)
G.E_MANAGER:add_event(Event({
func = function()
for k, v in ipairs(self.effect.config.consumables) do
local card = create_card('Tarot', G.consumeables, nil, nil, nil, nil, v, 'deck')
card:add_to_deck()
G.consumeables:emplace(card)
end
return true
end
}))
end
if self.effect.config.dollars then
G.GAME.starting_params.dollars = G.GAME.starting_params.dollars + self.effect.config.dollars
end
if self.effect.config.remove_faces then
G.GAME.starting_params.no_faces = true
end
if self.effect.config.spectral_rate then
G.GAME.spectral_rate = self.effect.config.spectral_rate
end
if self.effect.config.discards then
G.GAME.starting_params.discards = G.GAME.starting_params.discards + self.effect.config.discards
end
if self.effect.config.reroll_discount then
G.GAME.starting_params.reroll_cost = G.GAME.starting_params.reroll_cost - self.effect.config.reroll_discount
end
if self.effect.config.edition then
G.E_MANAGER:add_event(Event({
func = function()
local i = 0
while i < self.effect.config.edition_count do
local card = pseudorandom_element(G.playing_cards, pseudoseed('edition_deck'))
if not card.edition then
i = i + 1
card:set_edition({[self.effect.config.edition] = true}, nil, true)
end
end
return true
end
}))
end
if self.effect.config.vouchers then
for k, v in pairs(self.effect.config.vouchers) do
G.GAME.used_vouchers[v ] = true
G.GAME.cry_owned_vouchers[v ] = true
G.GAME.starting_voucher_count = (G.GAME.starting_voucher_count or 0) + 1
Card.apply_to_run(nil, G.P_CENTERS[v])
end
end
if self.name == 'Checkered Deck' then
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(G.playing_cards) do
if v.base.suit == 'Clubs' then
v:change_suit('Spades')
end
if v.base.suit == 'Diamonds' then
v:change_suit('Hearts')
end
end
return true
end
}))
end
if self.effect.config.randomize_rank_suit then
G.GAME.starting_params.erratic_suits_and_ranks = true
end
if self.effect.config.joker_slot then
G.GAME.starting_params.joker_slots = G.GAME.starting_params.joker_slots + self.effect.config.joker_slot
end
if self.effect.config.hand_size then
G.GAME.starting_params.hand_size = G.GAME.starting_params.hand_size + self.effect.config.hand_size
end
if self.effect.config.ante_scaling then
G.GAME.starting_params.ante_scaling = self.effect.config.ante_scaling
end
if self.effect.config.consumable_slot then
G.GAME.starting_params.consumable_slots = G.GAME.starting_params.consumable_slots + self.effect.config.consumable_slot
end
if self.effect.config.no_interest then
G.GAME.modifiers.no_interest = true
end
if self.effect.config.extra_hand_bonus then
G.GAME.modifiers.money_per_hand = self.effect.config.extra_hand_bonus
end
if self.effect.config.extra_discard_bonus then
G.GAME.modifiers.money_per_discard = self.effect.config.extra_discard_bonus
end
end
function Back:load(backTable)
self.name = backTable.name
self.pos = backTable.pos
self.effect = backTable.effect
self.effect.center = G.P_CENTERS[backTable.key] or G.P_CENTERS.b_red
self.loc_name = localize{type = 'name_text', set = 'Back', key = self.effect.center.key}
end

View file

@ -1,865 +0,0 @@
LOVELY_INTEGRITY = 'ceaf7d365cb8eac62c7dcf3be1ef07cc6b0dac3977bde52960496d7f844a668d'
--class
Blind = Moveable:extend()
--class methods
function Blind:init(X, Y, W, H)
Moveable.init(self,X, Y, W, H)
self.children = {}
self.config = {}
self.tilt_var = {mx = 0, my = 0, amt = 0}
self.ambient_tilt = 0.3
self.chips = 0
self.zoom = true
self.states.collide.can = true
self.colour = copy_table(G.C.BLACK)
self.dark_colour = darken(self.colour, 0.2)
self.children.animatedSprite = AnimatedSprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ANIMATION_ATLAS['blind_chips'], G.P_BLINDS.bl_small.pos)
self.children.animatedSprite.states = self.states
self.children.animatedSprite.states.visible = false
self.children.animatedSprite.states.drag.can = true
self.states.collide.can = true
self.states.drag.can = true
self.loc_debuff_lines = {'',''}
self.shadow_height = 0
if getmetatable(self) == Blind then
table.insert(G.I.CARD, self)
end
end
function Blind:change_colour(blind_col)
blind_col = blind_col or get_blind_main_colour(self.config.blind.key or '')
local dark_col = mix_colours(blind_col, G.C.BLACK, 0.4)
ease_colour(G.C.DYN_UI.MAIN, blind_col)
ease_colour(G.C.DYN_UI.DARK, dark_col)
if not self.boss and self.name then
blind_col = darken(G.C.BLACK, 0.05)
dark_col = lighten(G.C.BLACK, 0.07)
else
dark_col = mix_colours(blind_col, G.C.BLACK, 0.2)
end
ease_colour(G.C.DYN_UI.BOSS_MAIN, blind_col)
ease_colour(G.C.DYN_UI.BOSS_DARK, dark_col)
end
function Blind:set_text()
if self.config.blind then
if self.disabled then
self.loc_name = self.name == '' and self.name or localize{type ='name_text', key = self.config.blind.key, set = 'Blind'}
self.loc_debuff_text = ''
EMPTY(self.loc_debuff_lines)
else
local loc_vars = nil
if self.name == 'The Ox' then
loc_vars = {localize(G.GAME.current_round.most_played_poker_hand, 'poker_hands')}
end
local target = {type = 'raw_descriptions', key = self.config.blind.key, set = 'Blind', vars = loc_vars or self.config.blind.vars}
local obj = self.config.blind
if obj.loc_vars and type(obj.loc_vars) == 'function' then
local res = obj:loc_vars() or {}
target.vars = res.vars or target.vars
target.key = res.key or target.key
end
local loc_target = localize(target)
if loc_target then
self.loc_name = self.name == '' and self.name or localize{type ='name_text', key = self.config.blind.key, set = 'Blind'}
self.loc_debuff_text = ''
EMPTY(self.loc_debuff_lines)
for k, v in ipairs(loc_target) do
self.loc_debuff_text = self.loc_debuff_text..v..(k <= #loc_target and ' ' or '')
self.loc_debuff_lines[k] = v
end
else
self.loc_name = ''; self.loc_debuff_text = ''
EMPTY(self.loc_debuff_lines)
end
end
end
end
function Blind:set_blind(blind, reset, silent)
if not reset then
if blind then
self.in_blind = true
end
self.config.blind = blind or {}
self.name = blind and blind.name or ''
self.dollars = blind and blind.dollars or 0
self.sound_pings = self.dollars + 2
if G.GAME.modifiers.no_blind_reward and G.GAME.modifiers.no_blind_reward[self:get_type()] then self.dollars = 0 end
self.debuff = blind and blind.debuff or {}
self.pos = blind and blind.pos
self.mult = blind and blind.mult or 0
self.disabled = false
self.discards_sub = nil
self.hands_sub = nil
self.boss = blind and not not blind.boss
self.blind_set = false
self.triggered = nil
self.prepped = true
self:set_text()
local obj = self.config.blind
self.children.animatedSprite.atlas = G.ANIMATION_ATLAS[obj.atlas] or G.ANIMATION_ATLAS['blind_chips']
G.GAME.last_blind = G.GAME.last_blind or {}
G.GAME.last_blind.boss = self.boss
G.GAME.last_blind.name = self.name
if blind and blind.name then
self:change_colour()
else
self:change_colour(G.C.BLACK)
end
self.chips = get_blind_amount(G.GAME.round_resets.ante)*self.mult*G.GAME.starting_params.ante_scaling
self.chip_text = number_format(self.chips)
if not blind then self.chips = 0 end
G.GAME.current_round.dollars_to_be_earned = self.dollars > 0 and (string.rep(localize('$'), self.dollars)..'') or ('')
G.HUD_blind.alignment.offset.y = -10
G.HUD_blind:recalculate(false)
if blind and blind.name and blind.name ~= '' then
self:alert_debuff(true)
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.05,
blockable = false,
func = (function()
G.HUD_blind:get_UIE_by_ID("HUD_blind_name").states.visible = false
G.HUD_blind:get_UIE_by_ID("dollars_to_be_earned").parent.parent.states.visible = false
G.HUD_blind.alignment.offset.y = 0
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.15,
blockable = false,
func = (function()
G.HUD_blind:get_UIE_by_ID("HUD_blind_name").states.visible = true
G.HUD_blind:get_UIE_by_ID("dollars_to_be_earned").parent.parent.states.visible = true
G.HUD_blind:get_UIE_by_ID("dollars_to_be_earned").config.object:pop_in(0)
G.HUD_blind:get_UIE_by_ID("HUD_blind_name").config.object:pop_in(0)
G.HUD_blind:get_UIE_by_ID("HUD_blind_count"):juice_up()
self.children.animatedSprite:set_sprite_pos(self.config.blind.pos)
self.blind_set = true
G.ROOM.jiggle = G.ROOM.jiggle + 3
if not reset and not silent then
self:juice_up()
if blind then play_sound('chips1', math.random()*0.1 + 0.55, 0.42);play_sound('gold_seal', math.random()*0.1 + 1.85, 0.26)--play_sound('cancel')
end
end
return true
end)
}))
return true
end)
}))
end
self.config.h_popup_config ={align="tm", offset = {x=0,y=-0.1},parent = self}
end
if self.name == 'The Eye' and not reset then
self.hands = {
["Flush Five"] = false,
["Flush House"] = false,
["Five of a Kind"] = false,
["Straight Flush"] = false,
["Four of a Kind"] = false,
["Full House"] = false,
["Flush"] = false,
["Straight"] = false,
["Three of a Kind"] = false,
["Two Pair"] = false,
["Pair"] = false,
["High Card"] = false,
}
end
if self.name == 'The Mouth' and not reset then
self.only_hand = false
end
if self.name == 'The Fish' and not reset then
self.prepped = nil
end
if self.name == 'The Water' and not reset then
self.discards_sub = G.GAME.current_round.discards_left
ease_discard(-self.discards_sub)
end
if self.name == 'The Needle' and not reset then
self.hands_sub = G.GAME.round_resets.hands - 1
ease_hands_played(-self.hands_sub)
end
if self.name == 'The Manacle' and not reset then
G.hand:change_size(-1)
end
if self.name == 'Amber Acorn' and not reset and #G.jokers.cards > 0 then
G.jokers:unhighlight_all()
for k, v in ipairs(G.jokers.cards) do
v:flip()
end
if #G.jokers.cards > 1 then
G.E_MANAGER:add_event(Event({ trigger = 'after', delay = 0.2, func = function()
G.E_MANAGER:add_event(Event({ func = function() G.jokers:shuffle('aajk'); play_sound('cardSlide1', 0.85);return true end }))
delay(0.15)
G.E_MANAGER:add_event(Event({ func = function() G.jokers:shuffle('aajk'); play_sound('cardSlide1', 1.15);return true end }))
delay(0.15)
G.E_MANAGER:add_event(Event({ func = function() G.jokers:shuffle('aajk'); play_sound('cardSlide1', 1);return true end }))
delay(0.5)
return true end }))
end
end
if not reset then
if blind then
self.in_blind = true
end
local obj = self.config.blind
if obj.set_blind and type(obj.set_blind) == 'function' then
obj:set_blind()
end
end
--add new debuffs
for _, v in ipairs(G.playing_cards) do
self:debuff_card(v)
end
for _, v in ipairs(G.jokers.cards) do
if not reset then self:debuff_card(v, true) end
end
G.ARGS.spin.real = (G.SETTINGS.reduced_motion and 0 or 1)*(self.config.blind.boss and (self.config.blind.boss.showdown and 0.5 or 0.25) or 0)
end
function Blind:alert_debuff(first)
if self.loc_debuff_text and self.loc_debuff_text ~= '' then
self.block_play = true
G.E_MANAGER:add_event(Event({
blockable = false,
blocking = false,
func = (function()
if self.disabled then self.block_play = nil; return true end
if G.STATE == G.STATES.SELECTING_HAND then
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = G.SETTINGS.GAMESPEED*0.05,
blockable = false,
func = (function()
play_sound('whoosh1', 0.55, 0.62)
for i = 1, 4 do
local wait_time = (0.1*(i-1))
G.E_MANAGER:add_event(Event({ blockable = false, trigger = 'after', delay = G.SETTINGS.GAMESPEED*wait_time,
func = function()
if i == 1 then self:juice_up() end
play_sound('cancel', 0.7 + 0.05*i, 0.7)
return true end }))
end
local hold_time = G.SETTINGS.GAMESPEED*(#self.loc_debuff_text*0.035 + 1.3)
local disp_text = self:get_loc_debuff_text()
attention_text({
scale = 0.7, text = disp_text, maxw = 12, hold = hold_time, align = 'cm', offset = {x = 0,y = -1},major = G.play
})
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 1,
blocking = false,
blockable = false,
func = (function()
self.block_play = nil
if G.buttons then
local _buttons = G.buttons:get_UIE_by_ID('play_button')
_buttons.disable_button = nil
end
return true
end)
}))
return true
end)
}))
return true
end
end)
}))
end
end
function Blind:get_loc_debuff_text()
local obj = self.config.blind
if obj.get_loc_debuff_text and type(obj.get_loc_debuff_text) == 'function' then
return obj:get_loc_debuff_text()
end
local disp_text = (self.config.blind.name == 'The Wheel' and G.GAME.probabilities.normal or '')..self.loc_debuff_text
if (self.config.blind.name == 'The Mouth') and self.only_hand then disp_text = disp_text..' ['..localize(self.only_hand, 'poker_hands')..']' end
return disp_text
end
function Blind:defeat(silent)
local dissolve_time = 1.3
local extra_time = 0
self.dissolve = 0
self.dissolve_colours = {G.C.BLACK, G.C.RED}
self:juice_up()
self.children.particles = Particles(0, 0, 0,0, {
timer_type = 'TOTAL',
timer = 0.01*dissolve_time,
scale = 0.1,
speed = 1.5,
lifespan = 0.7*dissolve_time,
attach = self,
colours = self.dissolve_colours,
fill = true
})
local blind_name_dynatext = G.HUD_blind:get_UIE_by_ID('HUD_blind_name').config.object
blind_name_dynatext:pop_out(2)
G.E_MANAGER:add_event(Event({
trigger = 'after',
blockable = false,
delay = 0.5*dissolve_time,
func = (function() self.children.particles.max = 0 return true end)
}))
if not silent then
for i = 1, math.min(self.sound_pings or 3, 7) do
extra_time = extra_time + (0.4+0.15*i)*dissolve_time
G.E_MANAGER:add_event(Event({ blockable = false, trigger = 'after', delay = (0.15 - 0.01*(self.sound_pings or 3))*i*dissolve_time,
func = function()
play_sound('cancel', 0.8 - 0.05*i, 1.7)
if i == math.min((self.sound_pings or 3)+1, 6) then play_sound('whoosh2', 0.7, 0.42) end
return true end }))
end
end
G.E_MANAGER:add_event(Event({
trigger = 'ease',
blockable = false,
ref_table = self,
ref_value = 'dissolve',
ease_to = 1,
delay = 0.7*dissolve_time,
func = (function(t) return t end)
}))
G.E_MANAGER:add_event(Event({
trigger = 'after',
blockable = false,
delay = 0.8*dissolve_time,
func = (function()
G.HUD_blind.alignment.offset.y = -10
return true
end)
}))
G.E_MANAGER:add_event(Event({
trigger = 'after',
blockable = false,
delay = 0.95*dissolve_time,
func = (function()
self.dissolve = nil
self:set_blind(nil, nil, true) return true end)
}))
for k, v in ipairs(G.jokers.cards) do
if v.facing == 'back' then v:flip() end
end
local obj = self.config.blind
if obj.defeat and type(obj.defeat) == 'function' then
obj:defeat()
end
if self.name == 'Crimson Heart' then
for _, v in ipairs(G.jokers.cards) do
v.ability.crimson_heart_chosen = nil
end
end
if self.name == 'The Manacle' and not self.disabled then
G.hand:change_size(1)
end
end
function Blind:get_type()
if self.name == "Small Blind" then
return 'Small'
elseif self.name == "Big Blind" then
return 'Big'
elseif self.name and self.name ~= '' then
return 'Boss'
end
end
function Blind:disable()
self.disabled = true
for k, v in ipairs(G.jokers.cards) do
if v.facing == 'back' then v:flip() end
end
local obj = self.config.blind
if obj.disable and type(obj.disable) == 'function' then
obj:disable()
end
if self.name == 'Crimson Heart' then
for _, v in ipairs(G.jokers.cards) do
v.ability.crimson_heart_chosen = nil
end
end
if self.name == 'The Water' then
ease_discard(self.discards_sub)
end
if self.name == 'The Wheel' or self.name == 'The House' or self.name == 'The Mark' or self.name == 'The Fish' then
for i = 1, #G.hand.cards do
if G.hand.cards[i].facing == 'back' then
G.hand.cards[i]:flip()
end
end
for k, v in pairs(G.playing_cards) do
v.ability.wheel_flipped = nil
end
end
if self.name == 'The Needle' then
ease_hands_played(self.hands_sub)
end
if self.name == 'The Wall' then
self.chips = self.chips/2
self.chip_text = number_format(self.chips)
end
if self.name == 'Cerulean Bell' then
for k, v in ipairs(G.playing_cards) do
v.ability.forced_selection = nil
end
end
if self.name == 'The Manacle' then
G.hand:change_size(1)
end
if self.name == 'The Serpent' then
end
if self.name == 'Violet Vessel' then
self.chips = self.chips/3
self.chip_text = number_format(self.chips)
end
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
if self.boss and to_big(G.GAME.chips) - G.GAME.blind.chips >= to_big(0) then
G.STATE = G.STATES.NEW_ROUND
G.STATE_COMPLETE = false
end
return true
end
}))
for _, v in ipairs(G.playing_cards) do
self:debuff_card(v)
end
for _, v in ipairs(G.jokers.cards) do
self:debuff_card(v)
end
self:set_text()
self:wiggle()
end
function Blind:wiggle()
self.children.animatedSprite:juice_up(0.3)
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.06*G.SETTINGS.GAMESPEED, blockable = false, blocking = false, func = function()
play_sound('tarot2', 0.76, 0.4);return true end}))
play_sound('tarot2', 1, 0.4)
end
function Blind:juice_up(_a, _b)
self.children.animatedSprite:juice_up(_a or 0.2, _b or 0.2)
end
function Blind:hover()
if not G.CONTROLLER.dragging.target or G.CONTROLLER.using_touch then
if not self.hovering and self.states.visible and self.children.animatedSprite.states.visible then
self.hovering = true
self.hover_tilt = 2
self.children.animatedSprite:juice_up(0.05, 0.02)
play_sound('chips1', math.random()*0.1 + 0.55, 0.12)
Node.hover(self)
end
end
end
function Blind:stop_hover()
self.hovering = false
self.hover_tilt = 0
Node.stop_hover(self)
end
function Blind:draw()
if not self.states.visible then return end
self.tilt_var = self.tilt_var or {}
self.tilt_var.mx, self.tilt_var.my =G.CONTROLLER.cursor_position.x,G.CONTROLLER.cursor_position.y
self.children.animatedSprite.role.draw_major = self
self.children.animatedSprite:draw_shader('dissolve', 0.1)
self.children.animatedSprite:draw_shader('dissolve')
for k, v in pairs(self.children) do
if k ~= 'animatedSprite' then
v.VT.scale = self.VT.scale
v:draw()
end
end
add_to_drawhash(self)
end
function Blind:press_play()
if self.disabled then return end
local obj = self.config.blind
if obj.press_play and type(obj.press_play) == 'function' then
return obj:press_play()
end
if self.name == "The Hook" then
G.E_MANAGER:add_event(Event({ func = function()
local any_selected = nil
local _cards = {}
for k, v in ipairs(G.hand.cards) do
_cards[#_cards+1] = v
end
for i = 1, 2 do
if G.hand.cards[i] then
local selected_card, card_key = pseudorandom_element(_cards, pseudoseed('hook'))
G.hand:add_to_highlighted(selected_card, true)
table.remove(_cards, card_key)
any_selected = true
play_sound('card1', 1)
end
end
if any_selected then G.FUNCS.discard_cards_from_highlighted(nil, true) end
return true end }))
self.triggered = true
delay(0.7)
return true
end
if self.name == 'Crimson Heart' then
if G.jokers.cards[1] then
self.triggered = true
self.prepped = true
end
end
if self.name == 'The Fish' then
self.prepped = true
end
if self.name == "The Tooth" then
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.2, func = function()
for i = 1, #G.play.cards do
G.E_MANAGER:add_event(Event({func = function() G.play.cards[i]:juice_up(); return true end }))
ease_dollars(-1)
delay(0.23)
end
return true end }))
self.triggered = true
return true
end
end
function Blind:modify_hand(cards, poker_hands, text, mult, hand_chips)
if self.disabled then return mult, hand_chips, false end
local obj = self.config.blind
if obj.modify_hand and type(obj.modify_hand) == 'function' then
return obj:modify_hand(cards, poker_hands, text, mult, hand_chips)
end
if self.name == "The Flint" then
self.triggered = true
return math.max(math.floor(mult*0.5 + 0.5), 1), math.max(math.floor(hand_chips*0.5 + 0.5), 0), true
end
return mult, hand_chips, false
end
function Blind:debuff_hand(cards, hand, handname, check)
if self.disabled then return end
local obj = self.config.blind
if obj.debuff_hand and type(obj.debuff_hand) == 'function' then
return obj:debuff_hand(cards, hand, handname, check)
end
if self.debuff then
self.triggered = false
if self.debuff.hand and next(hand[self.debuff.hand]) then
self.triggered = true
return true
end
if self.name == "The Psychic" and #cards > 5 then
self.triggered = true
return true
end
if self.debuff.h_size_ge and #cards < self.debuff.h_size_ge then
self.triggered = true
return true
end
if self.debuff.h_size_le and #cards > self.debuff.h_size_le then
self.triggered = true
return true
end
if self.name == "The Eye" then
if self.hands[handname] then
self.triggered = true
return true
end
if not check then self.hands[handname] = true end
end
if self.name == "The Mouth" then
if self.only_hand and self.only_hand ~= handname then
self.triggered = true
return true
end
if not check then self.only_hand = handname end
end
end
if self.name == 'The Arm' then
self.triggered = false
if G.GAME.hands[handname].level > 1 then
self.triggered = true
if not check then
level_up_hand(self.children.animatedSprite, handname, nil, -1)
self:wiggle()
end
end
end
if self.name == 'The Ox' then
self.triggered = false
if handname == G.GAME.current_round.most_played_poker_hand then
self.triggered = true
if not check then
ease_dollars(-G.GAME.dollars, true)
self:wiggle()
end
end
end
end
function Blind:drawn_to_hand()
if not self.disabled then
local obj = self.config.blind
if obj.drawn_to_hand and type(obj.drawn_to_hand) == 'function' then
obj:drawn_to_hand()
end if self.name == 'Cerulean Bell' then
local any_forced = nil
for k, v in ipairs(G.hand.cards) do
if v.ability.forced_selection then
any_forced = true
end
end
if not any_forced then
G.hand:unhighlight_all()
local forced_card = pseudorandom_element(G.hand.cards, pseudoseed('cerulean_bell'))
forced_card.ability.forced_selection = true
G.hand:add_to_highlighted(forced_card)
end
end
if self.name == 'Crimson Heart' and self.prepped and G.jokers.cards[1] then
local prev_chosen_set = {}
local fallback_jokers = {}
local jokers = {}
for i = 1, #G.jokers.cards do
if G.jokers.cards[i].ability.crimson_heart_chosen then
prev_chosen_set[G.jokers.cards[i]] = true
G.jokers.cards[i].ability.crimson_heart_chosen = nil
if G.jokers.cards[i].debuff then SMODS.recalc_debuff(G.jokers.cards[i]) end
end
end
for i = 1, #G.jokers.cards do
if not G.jokers.cards[i].debuff then
if not prev_chosen_set[G.jokers.cards[i]] then
jokers[#jokers+1] = G.jokers.cards[i]
end
table.insert(fallback_jokers, G.jokers.cards[i])
end
end
if #jokers == 0 then jokers = fallback_jokers end
local _card = pseudorandom_element(jokers, pseudoseed('crimson_heart'))
if _card then
_card.ability.crimson_heart_chosen = true
SMODS.recalc_debuff(_card)
_card:juice_up()
self:wiggle()
end
end
end
self.prepped = nil
end
function Blind:stay_flipped(area, card)
if not self.disabled then
local obj = self.config.blind
if obj.stay_flipped and type(obj.stay_flipped) == 'function' then
return obj:stay_flipped(area, card)
end
if area == G.hand then
if self.name == 'The Wheel' and pseudorandom(pseudoseed('wheel')) < G.GAME.probabilities.normal/7 then
return true
end
if self.name == 'The House' and G.GAME.current_round.hands_played == 0 and G.GAME.current_round.discards_used == 0 then
return true
end
if self.name == 'The Mark' and card:is_face(true) then
return true
end
if self.name == 'The Fish' and self.prepped then
return true
end
end
end
end
function Blind:debuff_card(card, from_blind)
local obj = self.config.blind
if not self.disabled and obj.recalc_debuff and type(obj.recalc_debuff) == 'function' then
if obj:recalc_debuff(card, from_blind) then
card:set_debuff(true)
if card.debuff then card.debuffed_by_blind = true end
else
card:set_debuff(false)
end
return
elseif not self.disabled and obj.debuff_card and type(obj.debuff_card) == 'function' then
sendWarnMessage(("Blind object %s has debuff_card function, recalc_debuff is preferred"):format(obj.key), obj.set)
if obj:debuff_card(card, from_blind) then
card:set_debuff(true)
if card.debuff then card.debuffed_by_blind = true end
else
card:set_debuff(false)
end
return
end
if self.debuff and not self.disabled and card.area ~= G.jokers then
if self.debuff.suit and card:is_suit(self.debuff.suit, true) then
card:set_debuff(true)
if card.debuff then card.debuffed_by_blind = true end
return
end
if self.debuff.is_face =='face' and card:is_face(true) then
card:set_debuff(true)
if card.debuff then card.debuffed_by_blind = true end
return
end
if self.name == 'The Pillar' and card.ability.played_this_ante then
card:set_debuff(true)
if card.debuff then card.debuffed_by_blind = true end
return
end
if self.debuff.value and self.debuff.value == card.base.value then
card:set_debuff(true)
if card.debuff then card.debuffed_by_blind = true end
return
end
if self.debuff.nominal and self.debuff.nominal == card.base.nominal then
card:set_debuff(true)
if card.debuff then card.debuffed_by_blind = true end
return
end
end
if self.name == 'Crimson Heart' and not self.disabled and card.area == G.jokers then
if card.ability.crimson_heart_chosen then
card:set_debuff(true);
if card.debuff then card.debuffed_by_blind = true end
return
end
end
if self.name == 'Verdant Leaf' and not self.disabled and card.area ~= G.jokers then card:set_debuff(true); if card.debuff then card.debuffed_by_blind = true end; return end
card:set_debuff(false)
end
function Blind:move(dt)
Moveable.move(self, dt)
self:align()
end
function Blind:change_dim(w, h)
self.T.w = w or self.T.w
self.T.h = h or self.T.h
self.children.animatedSprite.T.w = w or self.T.w
self.children.animatedSprite.T.h = h or self.T.h
self.children.animatedSprite:rescale()
end
function Blind:align()
for k, v in pairs(self.children) do
if k == 'animatedSprite' then
if not v.states.drag.is then
v.T.r = 0.02*math.sin(2*G.TIMERS.REAL+self.T.x)
v.T.y = self.T.y + 0.03*math.sin(0.666*G.TIMERS.REAL+self.T.x)
self.shadow_height = 0.1 - (0.04 + 0.03*math.sin(0.666*G.TIMERS.REAL+self.T.x))
v.T.x = self.T.x + 0.03*math.sin(0.436*G.TIMERS.REAL+self.T.x)
end
else
v.T.x = self.T.x
v.T.y = self.T.y
v.T.r = self.T.r
end
end
end
function Blind:save()
local blindTable = {
in_blind = self.in_blind,
name = self.name,
dollars = self.dollars,
debuff = self.debuff,
pos = self.pos,
mult = self.mult,
disabled = self.disabled,
discards_sub = self.discards_sub,
hands_sub = self.hands_sub,
boss = self.boss,
config_blind = '',
chips = self.chips,
chip_text =self.chip_text,
hands = self.hands,
only_hand = self.only_hand,
triggered = self.triggered
}
for k, v in pairs(G.P_BLINDS) do
if v and v.name and v.name == blindTable.name then
blindTable.config_blind = k
end
end
return blindTable
end
function Blind:load(blindTable)
self.in_blind = blindTable.in_blind
self.config.blind = G.P_BLINDS[blindTable.config_blind] or {}
self.name = blindTable.name
self.dollars = blindTable.dollars
self.debuff = blindTable.debuff
self.pos = blindTable.pos
self.mult = blindTable.mult
self.disabled = blindTable.disabled
self.discards_sub = blindTable.discards_sub
self.hands_sub = blindTable.hands_sub
self.boss = blindTable.boss
self.chips = blindTable.chips
self.chip_text = blindTable.chip_text
self.hands = blindTable.hands
self.only_hand = blindTable.only_hand
self.triggered = blindTable.triggered
G.ARGS.spin.real = (G.SETTINGS.reduced_motion and 0 or 1)*(self.config.blind.boss and (self.config.blind.boss.showdown and 1 or 0.3) or 0)
if G.P_BLINDS[blindTable.config_blind] then
if self.config.blind.atlas then
self.children.animatedSprite.atlas = G.ANIMATION_ATLAS[self.config.blind.atlas]
end
self.blind_set = true
self.children.animatedSprite.states.visible = true
self.children.animatedSprite:set_sprite_pos(self.config.blind.pos)
self.children.animatedSprite:juice_up(0.3)
self:align()
self.children.animatedSprite:hard_set_VT()
else
self.children.animatedSprite.states.visible = false
end
self.children.animatedSprite.states = self.states
self:change_colour()
if self.dollars > 0 then
G.GAME.current_round.dollars_to_be_earned = string.rep(localize('$'), self.dollars)..''
G.HUD_blind:get_UIE_by_ID("dollars_to_be_earned").config.object:pop_in(0)
end
if G.GAME.blind.name and G.GAME.blind.name ~= '' then
G.HUD_blind.alignment.offset.y = 0
end
self:set_text()
end

File diff suppressed because it is too large Load diff

View file

@ -1,727 +0,0 @@
LOVELY_INTEGRITY = 'e8693aca875516bf9cb3c84fcb6f392131135da095f221f2ef0e6ac727b926df'
--Class
CardArea = Moveable:extend()
--Class Methods
function CardArea:init(X, Y, W, H, config)
Moveable.init(self, X, Y, W, H)
self.states.drag.can = false
self.states.hover.can = false
self.states.click.can = false
self.config = config or {}
self.card_w = config.card_w or G.CARD_W
self.cards = {}
self.children = {}
self.highlighted = {}
self.config.highlighted_limit = config.highlight_limit or G.GAME.modifiers.cry_highlight_limit or 5
self.config.card_limit = config.card_limit or 52
self.config.temp_limit = self.config.card_limit
self.config.card_count = 0
self.config.type = config.type or 'deck'
self.config.sort = config.sort or 'desc'
self.config.lr_padding = config.lr_padding or 0.1
self.shuffle_amt = 0
if getmetatable(self) == CardArea then
table.insert(G.I.CARDAREA, self)
end
end
function CardArea:emplace(card, location, stay_flipped)
if self == G.jokers then
Cartomancer.handle_joker_added(card)
end
if card.edition and card.edition.card_limit and (self == G.hand) then
self.config.real_card_limit = (self.config.real_card_limit or self.config.card_limit) + card.edition.card_limit
self.config.card_limit = math.max(0, self.config.real_card_limit)
end
if location == 'front' or self.config.type == 'deck' then
table.insert(self.cards, 1, card)
else
self.cards[#self.cards+1] = card
end
if card.cry_flipped then card.facing = 'back'; card.sprite_facing = 'back' end
if not (card.cry_flipped and (self == G.shop_jokers or self == G.shop_vouchers or self == G.shop_booster)) and card.facing == 'back' and self.config.type ~= 'discard' and self.config.type ~= 'deck' and not stay_flipped then
card:flip()
end
if self == G.hand and stay_flipped then
card.ability.wheel_flipped = true
end
if #self.cards > self.config.card_limit then
if self == G.deck then
self.config.card_limit = #self.cards
end
end
card:set_card_area(self)
self:set_ranks()
self:align_cards()
if self == G.jokers then
local joker_tally = 0
for i = 1, #G.jokers.cards do
if G.jokers.cards[i].ability.set == 'Joker' then joker_tally = joker_tally + 1 end
end
if joker_tally > G.GAME.max_jokers then G.GAME.max_jokers = joker_tally end
check_for_unlock({type = 'modify_jokers'})
end
if self == G.deck then check_for_unlock({type = 'modify_deck', deck = self}) end
end
function CardArea:remove_card(card, discarded_only)
if not self.cards then return end
local _cards = discarded_only and {} or self.cards
if discarded_only then
for k, v in ipairs(self.cards) do
if v.ability and v.ability.discarded then
_cards[#_cards+1] = v
end
end
end
if self.config.type == 'discard' or self.config.type == 'deck' then
card = card or _cards[#_cards]
else
card = card or _cards[1]
end
for i = #self.cards,1,-1 do
if self.cards[i] == card then
if card.edition and card.edition.card_limit and (self == G.hand) then
self.config.real_card_limit = (self.config.real_card_limit or self.config.card_limit) - card.edition.card_limit
self.config.card_limit = math.max(0, self.config.real_card_limit)
end
card:remove_from_area()
table.remove(self.cards, i)
self:remove_from_highlighted(card, true)
break
end
end
self:set_ranks()
if self == G.deck then check_for_unlock({type = 'modify_deck', deck = self}) end
return card
end
function CardArea:change_size(delta)
if delta ~= 0 then
G.E_MANAGER:add_event(Event({
func = function()
self.config.real_card_limit = (self.config.real_card_limit or self.config.card_limit) + delta
self.config.card_limit = math.max(0, self.config.real_card_limit)
if delta > 0 and self.config.real_card_limit > 1 and self == G.hand and self.cards[1] and (G.STATE == G.STATES.DRAW_TO_HAND or G.STATE == G.STATES.SELECTING_HAND) then
local card_count = math.abs(delta)
for i=1, card_count do
draw_card(G.deck,G.hand, i*100/card_count,nil, nil , nil, 0.07)
G.E_MANAGER:add_event(Event({func = function() self:sort() return true end}))
end
end
if self == G.hand then check_for_unlock({type = 'min_hand_size'}) end
return true
end}))
end
end
function CardArea:can_highlight(card)
if G.CONTROLLER.HID.controller then
if self.config.type == 'hand'
then
return true
end
else
if self.config.type == 'hand' or
self.config.type == 'joker' or
self.config.type == 'consumeable' or
(self.config.type == 'shop' and self.config.highlighted_limit > 0)
then
return true
end
end
return false
end
function CardArea:add_to_highlighted(card, silent)
--if self.config.highlighted_limit <= #self.highlighted then return end
if self.config.type == 'shop' then
if self.highlighted[1] then
self:remove_from_highlighted(self.highlighted[1])
end
--if not G.FUNCS.check_for_buy_space(card) then return false end
self.highlighted[#self.highlighted+1] = card
card:highlight(true)
if not silent then play_sound('cardSlide1') end
elseif self.config.type == 'joker' or self.config.type == 'consumeable' then
if #self.highlighted >= self.config.highlighted_limit then
self:remove_from_highlighted(self.highlighted[1])
end
self.highlighted[#self.highlighted+1] = card
card:highlight(true)
if not silent then play_sound('cardSlide1') end
else
if #self.highlighted >= self.config.highlighted_limit then
card:highlight(false)
else
self.highlighted[#self.highlighted+1] = card
card:highlight(true)
if not silent then play_sound('cardSlide1') end
end
if self == G.hand and G.STATE == G.STATES.SELECTING_HAND then
self:parse_highlighted()
end
end
end
function CardArea:parse_highlighted()
G.boss_throw_hand = nil
local text,disp_text,poker_hands = G.FUNCS.get_poker_hand_info(self.highlighted)
if text == 'NULL' then
update_hand_text({immediate = true, nopulse = true, delay = 0}, {mult = 0, chips = 0, level = '', handname = ''})
else
if G.GAME.blind and G.GAME.blind:debuff_hand(self.highlighted, poker_hands, text, true) then
G.boss_throw_hand = true
else
end
local backwards = nil
for k, v in pairs(self.highlighted) do
if v.facing == 'back' then
backwards = true
end
end
if backwards then
update_hand_text({immediate = true, nopulse = nil, delay = 0}, {handname='????', level='?', mult = '?', chips = '?'})
else
update_hand_text({immediate = true, nopulse = nil, delay = 0}, {handname=disp_text, level=G.GAME.hands[text].level, mult = cry_ascend(G.GAME.hands[text].mult), chips = cry_ascend(G.GAME.hands[text].chips)})
end
end
end
function CardArea:remove_from_highlighted(card, force)
if (not force) and card and card.ability.forced_selection and self == G.hand then return end
for i = #self.highlighted,1,-1 do
if self.highlighted[i] == card then
table.remove(self.highlighted, i)
break
end
end
card:highlight(false)
if self == G.hand and G.STATE == G.STATES.SELECTING_HAND then
self:parse_highlighted()
end
end
function CardArea:unhighlight_all()
for i = #self.highlighted,1,-1 do
if self.highlighted[i].ability.forced_selection and self == G.hand then
else
self.highlighted[i]:highlight(false)
table.remove(self.highlighted, i)
end
end
if self == G.hand and G.STATE == G.STATES.SELECTING_HAND then
self:parse_highlighted()
end
end
function CardArea:set_ranks()
for k, card in ipairs(self.cards) do
card.rank = k
card.states.collide.can = true
if k > 1 and self.config.type == 'deck' then
card.states.drag.can = false
card.states.collide.can = false
elseif self.config.type == 'play' or self.config.type == 'shop' or self.config.type == 'consumeable' then
card.states.drag.can = false
else
card.states.drag.can = true
end
end
end
function CardArea:move(dt)
--Set sliding up/down for the hand area
if self == G.hand then
local desired_y = G.TILE_H - G.hand.T.h - 1.9*((not G.deck_preview and (G.STATE == G.STATES.SELECTING_HAND or G.STATE == G.STATES.DRAW_TO_HAND)) and 1 or 0)
G.hand.T.y = 15*G.real_dt*desired_y + (1-15*G.real_dt)*G.hand.T.y
if math.abs(desired_y - G.hand.T.y) < 0.01 then G.hand.T.y = desired_y end
if G.STATE == G.STATES.TUTORIAL then
G.play.T.y = G.hand.T.y - (3 + 0.6)
end
end
Moveable.move(self, dt)
self:align_cards()
end
function CardArea:update(dt)
if self == G.hand then
if G.GAME.modifiers.minus_hand_size_per_X_dollar then
self.config.last_poll_size = self.config.last_poll_size or 0
if math.floor(G.GAME.dollars/G.GAME.modifiers.minus_hand_size_per_X_dollar) ~= self.config.last_poll_size then
self:change_size(self.config.last_poll_size - math.floor(G.GAME.dollars/G.GAME.modifiers.minus_hand_size_per_X_dollar))
self.config.last_poll_size = math.floor(G.GAME.dollars/G.GAME.modifiers.minus_hand_size_per_X_dollar)
end
end
for k, v in pairs(self.cards) do
if v.ability.forced_selection and not self.highlighted[1] then
self:add_to_highlighted(v)
end
end
end
if self == G.deck then
self.states.collide.can = true
self.states.hover.can = true
self.states.click.can = true
end
--Check and see if controller is being used
if G.CONTROLLER.HID.controller and self ~= G.hand then self:unhighlight_all() end
if self == G.deck and self.config.card_limit > #G.playing_cards then self.config.card_limit = #G.playing_cards end
self.config.temp_limit = math.max(#self.cards, self.config.card_limit)
self.config.card_count = #self.cards
end
function CardArea:draw()
if not self.states.visible then return end
if G.VIEWING_DECK and (self==G.deck or self==G.hand or self==G.play) then return end
local state = G.TAROT_INTERRUPT or G.STATE
self.ARGS.invisible_area_types = self.ARGS.invisible_area_types or {discard=1, voucher=1, play=1, consumeable=1, title = 1, title_2 = 1}
if self.ARGS.invisible_area_types[self.config.type] or
(self.config.type == 'hand' and ({[G.STATES.SHOP]=1, [G.STATES.TAROT_PACK]=1, [G.STATES.SPECTRAL_PACK]=1, [G.STATES.STANDARD_PACK]=1,[G.STATES.BUFFOON_PACK]=1,[G.STATES.PLANET_PACK]=1, [G.STATES.ROUND_EVAL]=1, [G.STATES.BLIND_SELECT]=1})[state]) or
(self.config.type == 'hand' and state == G.STATES.SMODS_BOOSTER_OPENED) or
(self.config.type == 'deck' and self ~= G.deck) or
(self.config.type == 'shop' and self ~= G.shop_vouchers) then
else
if not self.children.area_uibox then
local card_count = self ~= G.shop_vouchers and {n=G.UIT.R, config={align = self == G.jokers and 'cl' or self == G.hand and 'cm' or 'cr', padding = 0.03, no_fill = true}, nodes={
{n=G.UIT.B, config={w = 0.1,h=0.1}},
{n=G.UIT.T, config={ref_table = self.config, ref_value = 'card_count', scale = 0.3, colour = G.C.WHITE}},
{n=G.UIT.T, config={text = '/', scale = 0.3, colour = G.C.WHITE}},
{n=G.UIT.T, config={ref_table = self.config, ref_value = 'card_limit', scale = 0.3, colour = G.C.WHITE}},
{n=G.UIT.B, config={w = 0.1,h=0.1}}
}} or nil
self.children.area_uibox = UIBox{
definition =
{n=G.UIT.ROOT, config = {align = 'cm', colour = G.C.CLEAR}, nodes={
{n=G.UIT.R, config={minw = self.T.w,minh = self.T.h,align = "cm", padding = 0.1, mid = true, r = 0.1, colour = self ~= G.shop_vouchers and {0,0,0,0.1} or nil, ref_table = self}, nodes={
self == G.shop_vouchers and
{n=G.UIT.C, config={align = "cm", paddin = 0.1, func = 'shop_voucher_empty', visible = false}, nodes={
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.T, config={text = G.GAME.modifiers.cry_no_vouchers and (very_fair_quip[1] or '') or 'DEFEAT', scale = 0.6, colour = G.C.WHITE}}
}},
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.T, config={text = G.GAME.modifiers.cry_no_vouchers and (very_fair_quip[2] or '') or G.GAME.modifiers.cry_voucher_restock_antes and G.GAME.round_resets.ante % G.GAME.modifiers.cry_voucher_restock_antes == 0 and 'TWO BOSS BLINDS' or 'BOSS BLIND', scale = 0.4, colour = G.C.WHITE}}
}},
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.T, config={text = G.GAME.modifiers.cry_no_vouchers and (very_fair_quip[3] or '') or 'TO RESTOCK', scale = 0.4, colour = G.C.WHITE}}
}},
}} or nil,
}},
card_count
}},
config = { align = 'cm', offset = {x=0,y=0}, major = self, parent = self}
}
end
self.children.area_uibox:draw()
if self == G.jokers then
Cartomancer.add_visibility_controls()
end
end
self:draw_boundingrect()
add_to_drawhash(self)
self.ARGS.draw_layers = self.ARGS.draw_layers or self.config.draw_layers or {'shadow', 'card'}
for k, v in ipairs(self.ARGS.draw_layers) do
if self.config.type == 'deck' then
for i = #self.cards, 1, -1 do
if self.cards[i] ~= G.CONTROLLER.focused.target then
if i == 1 or i%(self.config.thin_draw or 9) == 0 or i == #self.cards or math.abs(self.cards[i].VT.x - self.T.x) > 1 or math.abs(self.cards[i].VT.y - self.T.y) > 1 then
if G.CONTROLLER.dragging.target ~= self.cards[i] then self.cards[i]:draw(v) end
end
end
end
end
if self.config.type == 'joker' or self.config.type == 'consumeable' or self.config.type == 'shop' or self.config.type == 'title_2' then
for i = 1, #self.cards do
if self.cards[i] ~= G.CONTROLLER.focused.target then
if not self.cards[i].highlighted then
if G.CONTROLLER.dragging.target ~= self.cards[i] then self.cards[i]:draw(v) end
end
end
end
for i = 1, #self.cards do
if self.cards[i] ~= G.CONTROLLER.focused.target then
if self.cards[i].highlighted then
if G.CONTROLLER.dragging.target ~= self.cards[i] then self.cards[i]:draw(v) end
end
end
end
end
if self.config.type == 'discard' then
for i = 1, #self.cards do
if self.cards[i] ~= G.CONTROLLER.focused.target then
if math.abs(self.cards[i].VT.x - self.T.x) > 1 then
if G.CONTROLLER.dragging.target ~= self.cards[i] then self.cards[i]:draw(v) end
end
end
end
end
if self.config.type == 'hand' or self.config.type == 'play' or self.config.type == 'title' or self.config.type == 'voucher' then
for i = 1, #self.cards do
if self.cards[i] ~= G.CONTROLLER.focused.target or self == G.hand then
if G.CONTROLLER.dragging.target ~= self.cards[i] then self.cards[i]:draw(v) end
end
end
end
end
if self == G.deck then
if G.CONTROLLER.HID.controller and G.STATE == G.STATES.SELECTING_HAND and not self.children.peek_deck then
self.children.peek_deck = UIBox{
definition =
{n=G.UIT.ROOT, config = {align = 'cm', padding = 0.1, r =0.1, colour = G.C.CLEAR}, nodes={
{n=G.UIT.R, config={align = "cm", r =0.1, colour = adjust_alpha(G.C.L_BLACK, 0.5),func = 'set_button_pip', focus_args = {button = 'triggerleft', orientation = 'bm', scale = 0.6, type = 'none'}}, nodes={
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.T, config={text = 'PEEK', scale = 0.48, colour = G.C.WHITE, shadow = true}}
}},
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.T, config={text = 'DECK', scale = 0.38, colour = G.C.WHITE, shadow = true}}
}},
}},
}},
config = { align = 'cl', offset = {x=-0.5,y=0.1}, major = self, parent = self}
}
self.children.peek_deck.states.collide.can = false
elseif (not G.CONTROLLER.HID.controller or G.STATE ~= G.STATES.SELECTING_HAND) and self.children.peek_deck then
self.children.peek_deck:remove()
self.children.peek_deck = nil
end
if not self.children.view_deck then
self.children.view_deck = UIBox{
definition =
{n=G.UIT.ROOT, config = {align = 'cm', padding = 0.1, r =0.1, colour = G.C.CLEAR}, nodes={
{n=G.UIT.R, config={align = "cm", padding = 0.05, r =0.1, colour = adjust_alpha(G.C.BLACK, 0.5),func = 'set_button_pip', focus_args = {button = 'triggerright', orientation = 'bm', scale = 0.6}, button = 'deck_info'}, nodes={
{n=G.UIT.R, config={align = "cm", maxw = 2}, nodes={
{n=G.UIT.T, config={text = localize('k_view'), scale = 0.48, colour = G.C.WHITE, shadow = true}}
}},
{n=G.UIT.R, config={align = "cm", maxw = 2}, nodes={
{n=G.UIT.T, config={text = localize('k_deck'), scale = 0.38, colour = G.C.WHITE, shadow = true}}
}},
}},
}},
config = { align = 'cm', offset = {x=0,y=0}, major = self.cards[1] or self, parent = self}
}
self.children.view_deck.states.collide.can = false
end
if G.deck_preview or self.states.collide.is or (G.buttons and G.buttons.states.collide.is and G.CONTROLLER.HID.controller) then self.children.view_deck:draw() end
if self.children.peek_deck then self.children.peek_deck:draw() end
end
end
function CardArea:align_cards()
if self.config.type == 'hand' then
self.config.temp_limit = math.min(self.config.card_limit, #G.playing_cards)
end
if (self == G.hand or self == G.deck or self == G.discard or self == G.play) and G.view_deck and G.view_deck[1] and G.view_deck[1].cards then return end
if self.config.type == 'deck' then
local display_limit
if not Cartomancer.SETTINGS.compact_deck_enabled then
display_limit = 999999
else
display_limit = Cartomancer.SETTINGS.compact_deck_visible_cards
end
local deck_height = (self.config.deck_height or 0.15)/52
local total_cards = #self.cards <= display_limit and #self.cards or display_limit -- limit height
local fixedX, fixedY, fixedR = nil, nil, nil
for k, card in ipairs(self.cards) do
if card.facing == 'front' then card:flip() end
if not card.states.drag.is then
if fixedX then
card.T.x = fixedX
card.T.y = fixedY
card.T.r = fixedR -- rotation
card.states.visible = false
else
card.T.x = self.T.x + 0.5*(self.T.w - card.T.w) + self.shadow_parrallax.x*deck_height*(total_cards/(self == G.deck and 1 or 2) - k) + 0.9*self.shuffle_amt*(1 - k*0.01)*(k%2 == 1 and 1 or -0)
card.T.y = self.T.y + 0.5*(self.T.h - card.T.h) + self.shadow_parrallax.y*deck_height*(total_cards/(self == G.deck and 1 or 2) - k)
card.T.r = 0 + 0.3*self.shuffle_amt*(1 + k*0.05)*(k%2 == 1 and 1 or -0)
card.T.x = card.T.x + card.shadow_parrallax.x/30
card.states.visible = true
if k >= display_limit then
fixedX = card.T.x
fixedY = card.T.y
fixedR = card.T.r
end
end
end
end
end
if self.config.type == 'discard' then
for k, card in ipairs(self.cards) do
if card.facing == 'front' then card:flip() end
if not card.states.drag.is then
card.T.x = self.T.x + (self.T.w - card.T.w)*card.discard_pos.x
card.T.y = self.T.y + (self.T.h - card.T.h)* card.discard_pos.y
card.T.r = card.discard_pos.r
end
end
end
if self.config.type == 'hand' and (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then
for k, card in ipairs(self.cards) do
if not card.states.drag.is then
card.T.r = 0.4*(-#self.cards/2 - 0.5 + k)/(#self.cards)+ (G.SETTINGS.reduced_motion and 0 or 1)*0.02*math.sin(2*G.TIMERS.REAL+card.T.x)
local max_cards = math.max(#self.cards, self.config.temp_limit)
card.T.x = self.T.x + (self.T.w-self.card_w)*((k-1)/math.max(max_cards-1, 1) - 0.5*(#self.cards-max_cards)/math.max(max_cards-1, 1)) + 0.5*(self.card_w - card.T.w)
local highlight_height = G.HIGHLIGHT_H
if not card.highlighted then highlight_height = 0 end
card.T.y = G.hand.T.y - 1.8*card.T.h - highlight_height + (G.SETTINGS.reduced_motion and 0 or 1)*0.1*math.sin(0.666*G.TIMERS.REAL+card.T.x) + math.abs(1.3*(-#self.cards/2 + k-0.5)/(#self.cards))^2-0.3
card.T.x = card.T.x + card.shadow_parrallax.x/30
end
end
table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end)
end
if self.config.type == 'hand' and not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then
for k, card in ipairs(self.cards) do
if not card.states.drag.is then
card.T.r = 0.2*(-#self.cards/2 - 0.5 + k)/(#self.cards)+ (G.SETTINGS.reduced_motion and 0 or 1)*0.02*math.sin(2*G.TIMERS.REAL+card.T.x)
local max_cards = math.max(#self.cards, self.config.temp_limit)
card.T.x = self.T.x + (self.T.w-self.card_w)*((k-1)/math.max(max_cards-1, 1) - 0.5*(#self.cards-max_cards)/math.max(max_cards-1, 1)) + 0.5*(self.card_w - card.T.w)
local highlight_height = G.HIGHLIGHT_H
if not card.highlighted then highlight_height = 0 end
card.T.y = self.T.y + self.T.h/2 - card.T.h/2 - highlight_height + (G.SETTINGS.reduced_motion and 0 or 1)*0.03*math.sin(0.666*G.TIMERS.REAL+card.T.x) + math.abs(0.5*(-#self.cards/2 + k-0.5)/(#self.cards))-0.2
card.T.x = card.T.x + card.shadow_parrallax.x/30
end
end
table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end)
end
if self.config.type == 'title' or (self.config.type == 'voucher' and #self.cards == 1) then
for k, card in ipairs(self.cards) do
if not card.states.drag.is then
card.T.r = 0.2*(-#self.cards/2 - 0.5 + k)/(#self.cards)+ (G.SETTINGS.reduced_motion and 0 or 1)*0.02*math.sin(2*G.TIMERS.REAL+card.T.x)
local max_cards = math.max(#self.cards, self.config.temp_limit)
card.T.x = self.T.x + (self.T.w-self.card_w)*((k-1)/math.max(max_cards-1, 1) - 0.5*(#self.cards-max_cards)/math.max(max_cards-1, 1)) + 0.5*(self.card_w - card.T.w)
local highlight_height = G.HIGHLIGHT_H
if not card.highlighted then highlight_height = 0 end
card.T.y = self.T.y + self.T.h/2 - card.T.h/2 - highlight_height + (G.SETTINGS.reduced_motion and 0 or 1)*0.03*math.sin(0.666*G.TIMERS.REAL+card.T.x) + math.abs(0.5*(-#self.cards/2 + k-0.5)/(#self.cards))-(#self.cards>1 and 0.2 or 0)
card.T.x = card.T.x + card.shadow_parrallax.x/30
end
end
table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end)
end
if self.config.type == 'voucher' and #self.cards > 1 then
local self_w = math.max(self.T.w, 3.2)
for k, card in ipairs(self.cards) do
if not card.states.drag.is then
card.T.r = 0.2*(-#self.cards/2 - 0.5 + k)/(#self.cards)+ (G.SETTINGS.reduced_motion and 0 or 1)*0.02*math.sin(2*G.TIMERS.REAL+card.T.x+card.T.y) + (k%2 == 0 and 1 or -1)*0.08
local max_cards = math.max(#self.cards, self.config.temp_limit)
card.T.x = self.T.x + (self_w-self.card_w)*((k-1)/math.max(max_cards-1, 1) - 0.5*(#self.cards-max_cards)/math.max(max_cards-1, 1)) + 0.5*(self.card_w - card.T.w) + (k%2 == 1 and 1 or -1)*0.27 + (self.T.w-self_w)/2
local highlight_height = G.HIGHLIGHT_H
if not card.highlighted then highlight_height = 0 end
card.T.y = self.T.y + self.T.h/2 - card.T.h/2 - highlight_height + (G.SETTINGS.reduced_motion and 0 or 1)*0.03*math.sin(0.666*G.TIMERS.REAL+card.T.x) + math.abs(0.5*(-#self.cards/2 + k-0.5)/(#self.cards))-(#self.cards>1 and 0.2 or 0)
card.T.x = card.T.x + card.shadow_parrallax.x/30
end
end
table.sort(self.cards, function (a, b) return a.ability.order < b.ability.order end)
end
if self.config.type == 'play' or self.config.type == 'shop' then
for k, card in ipairs(self.cards) do
if not card.states.drag.is then
card.T.r = 0
local max_cards = math.max(#self.cards, self.config.temp_limit)
card.T.x = self.T.x + (self.T.w-self.card_w)*((k-1)/math.max(max_cards-1, 1) - 0.5*(#self.cards-max_cards)/math.max(max_cards-1, 1)) + 0.5*(self.card_w - card.T.w) + (self.config.card_limit == 1 and 0.5*(self.T.w - card.T.w) or 0)
local highlight_height = G.HIGHLIGHT_H
if not card.highlighted then highlight_height = 0 end
card.T.y = self.T.y + self.T.h/2 - card.T.h/2 - highlight_height
card.T.x = card.T.x + card.shadow_parrallax.x/30
end
end
table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end)
end
if self == G.jokers and G.jokers.cart_jokers_expanded then
local align_cards = Cartomancer.expand_G_jokers()
-- This should work fine without cryptid. But because cryptid's patch is priority=0, it has to be this way
if not G.GAME.modifiers.cry_conveyor then
table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end)
end
if align_cards then
G.jokers:hard_set_cards()
end
elseif self.config.type == 'joker' or self.config.type == 'title_2' then
for k, card in ipairs(self.cards) do
if not card.states.drag.is then
card.T.r = 0.1*(-#self.cards/2 - 0.5 + k)/(#self.cards)+ (G.SETTINGS.reduced_motion and 0 or 1)*0.02*math.sin(2*G.TIMERS.REAL+card.T.x)
local max_cards = math.max(#self.cards, self.config.temp_limit)
card.T.x = self.T.x + (self.T.w-self.card_w)*((k-1)/math.max(max_cards-1, 1) - 0.5*(#self.cards-max_cards)/math.max(max_cards-1, 1)) + 0.5*(self.card_w - card.T.w)
if #self.cards > 2 or (#self.cards > 1 and self == G.consumeables) or (#self.cards > 1 and self.config.spread) then
card.T.x = self.T.x + (self.T.w-self.card_w)*((k-1)/(#self.cards-1)) + 0.5*(self.card_w - card.T.w)
elseif #self.cards > 1 and self ~= G.consumeables then
card.T.x = self.T.x + (self.T.w-self.card_w)*((k - 0.5)/(#self.cards)) + 0.5*(self.card_w - card.T.w)
else
card.T.x = self.T.x + self.T.w/2 - self.card_w/2 + 0.5*(self.card_w - card.T.w)
end
local highlight_height = G.HIGHLIGHT_H/2
if not card.highlighted then highlight_height = 0 end
card.T.y = self.T.y + self.T.h/2 - card.T.h/2 - highlight_height+ (G.SETTINGS.reduced_motion and 0 or 1)*0.03*math.sin(0.666*G.TIMERS.REAL+card.T.x)
card.T.x = card.T.x + card.shadow_parrallax.x/30
end
end
table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*((a.pinned and not a.ignore_pinned) and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*((b.pinned and not b.ignore_pinned) and b.sort_id or 0) end)
end
if self.config.type == 'consumeable'then
for k, card in ipairs(self.cards) do
if not card.states.drag.is then
if #self.cards > 1 then
card.T.x = self.T.x + (self.T.w-self.card_w)*((k-1)/(#self.cards-1)) + 0.5*(self.card_w - card.T.w)
else
card.T.x = self.T.x + self.T.w/2 - self.card_w/2 + 0.5*(self.card_w - card.T.w)
end
local highlight_height = G.HIGHLIGHT_H
if not card.highlighted then highlight_height = 0 end
card.T.y = self.T.y + self.T.h/2 - card.T.h/2 - highlight_height + (not card.highlighted and (G.SETTINGS.reduced_motion and 0 or 1)*0.05*math.sin(2*1.666*G.TIMERS.REAL+card.T.x) or 0)
card.T.x = card.T.x + card.shadow_parrallax.x/30
end
end
table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end)
end
for k, card in ipairs(self.cards) do
card.rank = k
end
if self.children.view_deck then
self.children.view_deck:set_role{major = self.cards[1] or self}
end
end
function CardArea:hard_set_T(X, Y, W, H)
local x = (X or self.T.x)
local y = (Y or self.T.y)
local w = (W or self.T.w)
local h = (H or self.T.h)
Moveable.hard_set_T(self,x, y, w, h)
self:calculate_parrallax()
self:align_cards()
self:hard_set_cards()
end
function CardArea:hard_set_cards()
for k, card in pairs(self.cards) do
card:hard_set_T()
card:calculate_parrallax()
end
end
function CardArea:shuffle(_seed)
pseudoshuffle(self.cards, pseudoseed(_seed or 'shuffle'))
self:set_ranks()
end
function CardArea:sort(method)
self.config.sort = method or self.config.sort
if self.config.sort == 'desc' then
table.sort(self.cards, function (a, b) return a:get_nominal() > b:get_nominal() end )
elseif self.config.sort == 'asc' then
table.sort(self.cards, function (a, b) return a:get_nominal() < b:get_nominal() end )
elseif self.config.sort == 'suit desc' then
table.sort(self.cards, function (a, b) return a:get_nominal('suit') > b:get_nominal('suit') end )
elseif self.config.sort == 'suit asc' then
table.sort(self.cards, function (a, b) return a:get_nominal('suit') < b:get_nominal('suit') end )
elseif self.config.sort == 'order' then
table.sort(self.cards, function (a, b) return (a.config.card.order or a.config.center.order) < (b.config.card.order or b.config.center.order) end )
end
end
function CardArea:draw_card_from(area, stay_flipped, discarded_only)
if area:is(CardArea) then
if #self.cards < self.config.card_limit or self == G.deck or self == G.hand then
local card = area:remove_card(nil, discarded_only)
if card then
if area == G.discard then
card.T.r = 0
end
if self == G.hand and not card.states.visible then
card.states.visible = true
end
local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card)
if (self == G.hand) and G.GAME.modifiers.flipped_cards then
if pseudorandom(pseudoseed('flipped_card')) < 1/G.GAME.modifiers.flipped_cards then
stay_flipped = true
end
end
self:emplace(card, nil, stay_flipped)
return true
end
end
end
end
function CardArea:click()
if self == G.deck then
G.FUNCS.deck_info()
end
end
function CardArea:save()
if not self.cards then return end
local cardAreaTable = {
cards = {},
config = self.config,
}
for i = 1, #self.cards do
cardAreaTable.cards[#cardAreaTable.cards + 1] = self.cards[i]:save()
end
return cardAreaTable
end
function CardArea:load(cardAreaTable)
if self.cards then remove_all(self.cards) end
self.cards = {}
if self.children then remove_all(self.children) end
self.children = {}
self.config = cardAreaTable.config
for i = 1, #cardAreaTable.cards do
loading = true
local card = Card(0, 0, G.CARD_W, G.CARD_H, G.P_CENTERS.j_joker, G.P_CENTERS.c_base)
loading = nil
card:load(cardAreaTable.cards[i])
self.cards[#self.cards + 1] = card
if card.highlighted then
self.highlighted[#self.highlighted + 1] = card
end
card:set_card_area(self)
end
self:set_ranks()
self:align_cards()
self:hard_set_cards()
end
function CardArea:remove()
if self.cards then remove_all(self.cards) end
self.cards = nil
if self.children then remove_all(self.children) end
self.children = nil
for k, v in pairs(G.I.CARDAREA) do
if v == self then
table.remove(G.I.CARDAREA, k)
end
end
Moveable.remove(self)
end

View file

@ -1,109 +0,0 @@
LOVELY_INTEGRITY = '8f16206d263b8b20d4f441ae0cdc8450eef3f2bd3b801abb44802f6b1578b809'
--Class
AnimatedSprite = Sprite:extend()
--Class Methods
function AnimatedSprite:init(X, Y, W, H, new_sprite_atlas, sprite_pos)
Sprite.init(self,X, Y, W, H, new_sprite_atlas, sprite_pos)
self.offset = {x = 0, y = 0}
table.insert(G.ANIMATIONS, self)
if getmetatable(self) == AnimatedSprite then
table.insert(G.I.SPRITE, self)
end
end
function AnimatedSprite:rescale()
self.scale_mag = math.min(self.scale.x/self.T.w,self.scale.y/self.T.h)
end
function AnimatedSprite:reset()
self.atlas = G.ANIMATION_ATLAS[self.atlas.name]
self:set_sprite_pos({x = self.animation.x, y = self.animation.y})
end
function AnimatedSprite:set_sprite_pos(sprite_pos)
self.animation = {
x= sprite_pos and sprite_pos.x or 0,
y=sprite_pos and sprite_pos.y or 0,
frames=self.atlas.frames,current=0,
w=self.scale.x, h=self.scale.y}
self.frame_offset = 0
self.current_animation = {
current = 0,
frames = self.animation.frames,
w = self.animation.w,
h = self.animation.h}
self.image_dims = self.image_dims or {}
self.image_dims[1], self.image_dims[2] = self.atlas.image:getDimensions()
self.sprite = love.graphics.newQuad(
0,
self.animation.h*self.animation.y,
self.animation.w,
self.animation.h,
self.image_dims[1], self.image_dims[2])
self.offset_seconds = G.TIMERS.REAL
end
function AnimatedSprite:get_pos_pixel()
self.RETS.get_pos_pixel = self.RETS.get_pos_pixel or {}
self.RETS.get_pos_pixel[1] = self.current_animation.current
self.RETS.get_pos_pixel[2] = self.animation.y
self.RETS.get_pos_pixel[3] = self.animation.w
self.RETS.get_pos_pixel[4] = self.animation.h
return self.RETS.get_pos_pixel
end
function AnimatedSprite:draw_self()
if not self.states.visible then return end
prep_draw(self, 1)
love.graphics.scale(1/self.scale_mag)
love.graphics.setColor(G.C.WHITE)
love.graphics.draw(
self.atlas.image,
self.sprite,
0 ,0,
0,
self.VT.w/(self.T.w),
self.VT.h/(self.T.h)
)
love.graphics.pop()
end
function AnimatedSprite:animate()
local new_frame = math.floor(G.ANIMATION_FPS*(G.TIMERS.REAL - self.offset_seconds))%self.current_animation.frames
if new_frame ~= self.current_animation.current then
self.current_animation.current = new_frame
self.frame_offset = math.floor(self.animation.w*(self.current_animation.current))
self.sprite:setViewport(
self.frame_offset,
self.animation.h*self.animation.y,
self.animation.w,
self.animation.h)
end
if self.float then
self.T.r = 0.02*math.sin(2*G.TIMERS.REAL+self.T.x)
self.offset.y = -(1+0.3*math.sin(0.666*G.TIMERS.REAL+self.T.y))*self.shadow_parrallax.y
self.offset.x = -(0.7+0.2*math.sin(0.666*G.TIMERS.REAL+self.T.x))*self.shadow_parrallax.x
end
end
function AnimatedSprite:remove()
for k, v in pairs(G.ANIMATIONS) do
if v == self then
table.remove(G.ANIMATIONS, k)
end
end
for k, v in pairs(G.I.SPRITE) do
if v == self then
table.remove(G.I.SPRITE, k)
end
end
Sprite.remove(self)
end

File diff suppressed because it is too large Load diff

View file

@ -1,520 +0,0 @@
LOVELY_INTEGRITY = '2774a24114332371bc4208f854d32c6f93786326d6810fc4139b615d177277e3'
---@class Moveable: Node
Moveable = Node:extend()
--Moveable represents any game object that has the ability to move about the gamespace.\
--All Moveables have a T (transform) that describes their desired transform in game units, as\
--well as a VT (Visible Transform) that eases to T over time. This allows for simplified movement where\
--we only need to set T.x, T.y, etc. to their final position and the engine will ensure the Moveable\
--VT eases to that final location, regargless of any events or timing.
--
---@param args {T: table, container: Node}
--**T** The transform ititializer, with keys of x|1, y|2, w|3, h|4, r|5\
--**container** optional container for this Node, defaults to G.ROOM
function Moveable:init(X,Y,W,H)
local args = (type(X) == 'table') and X or {T ={X or 0,Y or 0,W or 0,H or 0}}
Node.init(self, args)
--The Visible transform is initally set to the same values as the transform T.
--Note that the VT has an extra 'scale' factor, this is used to manipulate the center-adjusted
--scale of any objects that need to be drawn larger or smaller
self.VT = {
x = self.T.x,
y = self.T.y,
w = self.T.w,
h = self.T.h,
r = self.T.r,
scale = self.T.scale
}
--To determine location of VT, we need to keep track of the velocity of VT as it approaches T for the next frame
self.velocity = {x = 0, y = 0, r = 0, scale = 0, mag = 0}
--For more robust drawing, attaching, movement and fewer redundant movement calculations, Moveables each have a 'role'
--that describes a heirarchy of move() calls. Any Moveables with 'Major' role type behave normally, essentially recalculating their
--VT every frame to ensure smooth movement. Moveables can be set to 'Minor' role and attached to some 'Major' moveable
--to weld the Minor moveable to the Major moveable. This makes the dependent moveable set their T and VT to be equal to
--the corresponding 'Major' T and VT, plus some defined offset.
--For finer control over what parts of T and VT are inherited, xy_bond, wh_bond, and r_bond can be set to one of
--'Strong' or 'Weak'. Strong simply copies the values, Weak allows the 'Minor' moveable to calculate their own.
self.role = {
role_type = 'Major', --Major dictates movement, Minor is welded to some major
offset = {x = 0, y = 0}, --Offset from Minor to Major
major = nil,
draw_major = self,
xy_bond = 'Strong',
wh_bond = 'Strong',
r_bond = 'Strong',
scale_bond = 'Strong'
}
self.alignment = {
type = 'a',
offset = {x = 0, y = 0},
prev_type = '',
prev_offset = {x = 0, y = 0},
}
--the pinch table is used to modify the VT.w and VT.h compared to T.w and T.h. If either x or y pinch is
--set to true, the VT width and or height will ease to 0. If pinch is false, they ease to T.w or T.h
self.pinch = {x = false, y = false}
--Keep track of the last time this Moveable was moved via :move(dt). When it is successfully moved, set to equal
--the current G.TIMERS.REAL, and if it is called again this frame, doesn't recalculate move(dt)
self.last_moved = -1
self.last_aligned = -1
self.static_rotation = false
self.offset = {x=0, y=0}
self.Mid = self
self.shadow_parrallax = {x = 0, y = -1.5}
self.layered_parallax = {x = 0, y = 0}
self.shadow_height = 0.2
self:calculate_parrallax()
table.insert(G.MOVEABLES, self)
if getmetatable(self) == Moveable then
table.insert(G.I.MOVEABLE, self)
end
end
function Moveable:draw()
Node.draw(self)
self:draw_boundingrect()
end
--Sets the alignment of moveable using roles
--
---@param args {major: Moveable, bond: string, offset: table, type: string}
--**major** The moveable this moveable will attach to\
--**bond** The bond type, either 'Strong' or 'Weak'. Strong instantly adjusts VT, Weak manually calculates VT changes\
--**offset** {x , y} offset from the alignment\
--**type** the alignment type. Vertical options: c - center, t - top, b - bottom. Horizontal options: l - left, m - middle, r - right. i for inner
function Moveable:set_alignment(args)
args = args or {}
if args.major then
self:set_role({
role_type = 'Minor',
major = args.major,
xy_bond = args.bond or args.xy_bond or 'Weak',
wh_bond = args.wh_bond or self.role.wh_bond,
r_bond = args.r_bond or self.role.r_bond,
scale_bond = args.scale_bond or self.role.scale_bond,
})
end
self.alignment.type = args.type or self.alignment.type
if args.offset and (type(args.offset)=='table' and not (args.offset.y and args.offset.x)) or type(args.offset) ~= 'table' then
args.offset = nil
end
self.alignment.offset = args.offset or self.alignment.offset
self.alignment.lr_clamp = args.lr_clamp
end
function Moveable:align_to_major()
if self.alignment.type ~= self.alignment.prev_type then
self.alignment.type_list = {
a = self.alignment.type == 'a',
m = string.find(self.alignment.type, "m"),
c = string.find(self.alignment.type, "c"),
b = string.find(self.alignment.type, "b"),
t = string.find(self.alignment.type, "t"),
l = string.find(self.alignment.type, "l"),
r = string.find(self.alignment.type, "r"),
i = string.find(self.alignment.type, "i"),
}
end
if not self.alignment.type_list then return end
self.NEW_ALIGNMENT = true
if self.alignment.type ~= self.alignment.prev_type then
self.alignment.prev_type = self.alignment.type
end
if self.alignment.type_list.a or not self.role.major then return end
if self.alignment.type_list.m then
self.role.offset.x = 0.5*self.role.major.T.w - (self.Mid.T.w)/2 + self.alignment.offset.x - self.Mid.T.x + self.T.x
end
if self.alignment.type_list.c then
self.role.offset.y = 0.5*self.role.major.T.h - (self.Mid.T.h)/2 + self.alignment.offset.y - self.Mid.T.y + self.T.y
end
if self.alignment.type_list.b then
if self.alignment.type_list.i then
self.role.offset.y = self.alignment.offset.y + self.role.major.T.h - self.T.h
else
self.role.offset.y = self.alignment.offset.y + self.role.major.T.h
end
end
if self.alignment.type_list.r then
if self.alignment.type_list.i then
self.role.offset.x = self.alignment.offset.x + self.role.major.T.w - self.T.w
else
self.role.offset.x = self.alignment.offset.x + self.role.major.T.w
end
end
if self.alignment.type_list.t then
if self.alignment.type_list.i then
self.role.offset.y = self.alignment.offset.y
else
self.role.offset.y = self.alignment.offset.y - self.T.h
end
end
if self.alignment.type_list.l then
if self.alignment.type_list.i then
self.role.offset.x = self.alignment.offset.x
else
self.role.offset.x = self.alignment.offset.x - self.T.w
end
end
self.role.offset.x = self.role.offset.x or 0
self.role.offset.y = self.role.offset.y or 0
self.T.x = self.role.major.T.x + self.role.offset.x
self.T.y = self.role.major.T.y + self.role.offset.y
self.alignment.prev_offset = self.alignment.prev_offset or {}
self.alignment.prev_offset.x, self.alignment.prev_offset.y = self.alignment.offset.x, self.alignment.offset.y
end
function Moveable:hard_set_T(X, Y, W, H)
self.T.x = X
self.T.y = Y
self.T.w = W
self.T.h = H
self.velocity.x = 0
self.velocity.y = 0
self.velocity.r = 0
self.velocity.scale = 0
self.VT.x = X
self.VT.y = Y
self.VT.w = W
self.VT.h = H
self.VT.r = self.T.r
self.VT.scale = self.T.scale
self:calculate_parrallax()
end
function Moveable:hard_set_VT()
self.VT.x = self.T.x
self.VT.y = self.T.y
self.VT.w = self.T.w
self.VT.h = self.T.h
end
function Moveable:drag(offset)
if self.states.drag.can or offset then
self.ARGS.drag_cursor_trans = self.ARGS.drag_cursor_trans or {}
self.ARGS.drag_translation = self.ARGS.drag_translation or {}
local _p = self.ARGS.drag_cursor_trans
local _t = self.ARGS.drag_translation
_p.x = G.CONTROLLER.cursor_position.x/(G.TILESCALE*G.TILESIZE)
_p.y = G.CONTROLLER.cursor_position.y/(G.TILESCALE*G.TILESIZE)
_t.x, _t.y = -self.container.T.w/2, -self.container.T.h/2
point_translate(_p, _t)
point_rotate(_p, self.container.T.r)
_t.x, _t.y = self.container.T.w/2-self.container.T.x, self.container.T.h/2-self.container.T.y
point_translate(_p, _t)
if not offset then
offset = self.click_offset
end
self.T.x = _p.x - offset.x
self.T.y = _p.y - offset.y
self.NEW_ALIGNMENT = true
for k, v in pairs(self.children) do
v:drag(offset)
end
end
if self.states.drag.can then
Node.drag(self)
end
end
function Moveable:juice_up(amount, rot_amt)
if G.SETTINGS.reduced_motion then return end
local amount = amount or 0.4
local end_time = G.TIMERS.REAL + 0.4
local start_time = G.TIMERS.REAL
self.juice = {
scale = 0,
scale_amt = amount,
r = 0,
r_amt = ((rot_amt or pseudorandom_element({0.6*amount, -0.6*amount})) or 0),
start_time = start_time,
end_time = end_time
}
self.VT.scale = 1-0.6*amount
end
function Moveable:move_juice(dt)
if self.juice and not self.juice.handled_elsewhere then
if self.juice.end_time < G.TIMERS.REAL then
self.juice = nil
else
self.juice.scale = self.juice.scale_amt*math.sin(50.8*(G.TIMERS.REAL-self.juice.start_time))*math.max(0, ((self.juice.end_time - G.TIMERS.REAL)/(self.juice.end_time - self.juice.start_time))^3)
self.juice.r = self.juice.r_amt*math.sin(40.8*(G.TIMERS.REAL-self.juice.start_time))*math.max(0, ((self.juice.end_time - G.TIMERS.REAL)/(self.juice.end_time - self.juice.start_time))^2)
end
end
end
function Moveable:move(dt)
if self.FRAME.MOVE >= G.FRAMES.MOVE then return end
self.FRAME.OLD_MAJOR = self.FRAME.MAJOR
self.FRAME.MAJOR = nil
self.FRAME.MOVE = G.FRAMES.MOVE
if not self.created_on_pause and G.SETTINGS.paused then return end
--WHY ON EARTH DOES THIS LINE MAKE IT RUN 2X AS FAST???
-------------------------------------------------------
--local timestart = love.timer.getTime()
-------------------------------------------------------
self:align_to_major()
self.CALCING = nil
if self.role.role_type == 'Glued' then
if self.role.major then self:glue_to_major(self.role.major) end
elseif self.role.role_type == 'Minor' and self.role.major then
if self.role.major.FRAME.MOVE < G.FRAMES.MOVE then self.role.major:move(dt) end
self.STATIONARY = self.role.major.STATIONARY
if (not self.STATIONARY) or self.NEW_ALIGNMENT or
self.config.refresh_movement or
self.juice or
self.role.xy_bond == 'Weak' or
self.role.r_bond == 'Weak' then
self.CALCING = true
self:move_with_major(dt)
end
elseif self.role.role_type == 'Major' then
self.STATIONARY = true
self:move_juice(dt)
self:move_xy(dt)
self:move_r(dt, self.velocity)
self:move_scale(dt)
self:move_wh(dt)
self:calculate_parrallax()
end
if self.alignment and self.alignment.lr_clamp then
self:lr_clamp()
end
self.NEW_ALIGNMENT = false
end
function Moveable:lr_clamp()
if self.T.x < 0 then self.T.x = 0 end
if self.VT.x < 0 then self.VT.x = 0 end
if (self.T.x + self.T.w) > G.ROOM.T.w then self.T.x = G.ROOM.T.w - self.T.w end
if (self.VT.x + self.VT.w) > G.ROOM.T.w then self.VT.x = G.ROOM.T.w - self.VT.w end
end
function Moveable:glue_to_major(major_tab)
self.T = major_tab.T
self.VT.x = major_tab.VT.x + (0.5*(1 - major_tab.VT.w/(major_tab.T.w))*self.T.w)
self.VT.y = major_tab.VT.y
self.VT.w = major_tab.VT.w
self.VT.h = major_tab.VT.h
self.VT.r = major_tab.VT.r
self.VT.scale = major_tab.VT.scale
self.pinch = major_tab.pinch
self.shadow_parrallax = major_tab.shadow_parrallax
end
MWM = {
rotated_offset = {},
angles = {},
WH = {},
offs = {},
}
function Moveable:move_with_major(dt)
if self.role.role_type ~= 'Minor' then return end
local major_tab = self.role.major:get_major()
self:move_juice(dt)
if self.role.r_bond == 'Weak' then
MWM.rotated_offset.x, MWM.rotated_offset.y = self.role.offset.x + major_tab.offset.x,self.role.offset.y+major_tab.offset.y
else
if major_tab.major.VT.r < 0.0001 and major_tab.major.VT.r > -0.0001 then
MWM.rotated_offset.x = self.role.offset.x + major_tab.offset.x
MWM.rotated_offset.y = self.role.offset.y + major_tab.offset.y
else
MWM.angles.cos, MWM.angles.sin = math.cos(major_tab.major.VT.r),math.sin(major_tab.major.VT.r)
MWM.WH.w, MWM.WH.h = -self.T.w/2 + major_tab.major.T.w/2,-self.T.h/2 + major_tab.major.T.h/2
MWM.offs.x, MWM.offs.y = self.role.offset.x + major_tab.offset.x - MWM.WH.w,self.role.offset.y + major_tab.offset.y - MWM.WH.h
MWM.rotated_offset.x = MWM.offs.x*MWM.angles.cos - MWM.offs.y*MWM.angles.sin + MWM.WH.w
MWM.rotated_offset.y = MWM.offs.x*MWM.angles.sin + MWM.offs.y*MWM.angles.cos + MWM.WH.h
end
end
self.T.x = major_tab.major.T.x + MWM.rotated_offset.x
self.T.y = major_tab.major.T.y + MWM.rotated_offset.y
if self.role.xy_bond == 'Strong' then
self.VT.x = major_tab.major.VT.x + MWM.rotated_offset.x
self.VT.y = major_tab.major.VT.y + MWM.rotated_offset.y
elseif self.role.xy_bond == 'Weak' then
self:move_xy(dt)
end
if self.role.r_bond == 'Strong' then
self.VT.r = self.T.r + major_tab.major.VT.r + (self.juice and self.juice.r or 0)
elseif self.role.r_bond == 'Weak' then
self:move_r(dt, self.velocity)
end
if self.role.scale_bond == 'Strong' then
self.VT.scale = self.T.scale*(major_tab.major.VT.scale/major_tab.major.T.scale) + (self.juice and self.juice.scale or 0)
elseif self.role.scale_bond == 'Weak' then
self:move_scale(dt)
end
if self.role.wh_bond == 'Strong' then
self.VT.x = self.VT.x + (0.5*(1 - major_tab.major.VT.w/(major_tab.major.T.w))*self.T.w)
self.VT.w = (self.T.w)*(major_tab.major.VT.w/major_tab.major.T.w)
self.VT.h = (self.T.h)*(major_tab.major.VT.h/major_tab.major.T.h)
elseif self.role.wh_bond == 'Weak' then
self:move_wh(dt)
end
self:calculate_parrallax()
end
function Moveable:move_xy(dt)
if (self.T.x ~= self.VT.x or math.abs(self.velocity.x) > 0.01) or
(self.T.y ~= self.VT.y or math.abs(self.velocity.y) > 0.01) then
self.velocity.x = G.exp_times.xy*self.velocity.x + (1-G.exp_times.xy)*(self.T.x - self.VT.x)*35*dt
self.velocity.y = G.exp_times.xy*self.velocity.y + (1-G.exp_times.xy)*(self.T.y - self.VT.y)*35*dt
if self.velocity.x*self.velocity.x + self.velocity.y*self.velocity.y > G.exp_times.max_vel*G.exp_times.max_vel then
local actual_vel = math.sqrt(self.velocity.x*self.velocity.x + self.velocity.y*self.velocity.y)
self.velocity.x = G.exp_times.max_vel*self.velocity.x/actual_vel
self.velocity.y = G.exp_times.max_vel*self.velocity.y/actual_vel
end
self.STATIONARY = false
self.VT.x = self.VT.x + self.velocity.x
self.VT.y = self.VT.y + self.velocity.y
if math.abs(self.VT.x - self.T.x) < 0.01 and math.abs(self.velocity.x) < 0.01 then self.VT.x = self.T.x; self.velocity.x = 0 end
if math.abs(self.VT.y - self.T.y) < 0.01 and math.abs(self.velocity.y) < 0.01 then self.VT.y = self.T.y; self.velocity.y = 0 end
end
end
function Moveable:move_scale(dt)
local des_scale = self.T.scale + (self.zoom and ((self.states.drag.is and 0.1 or 0) + (self.states.hover.is and 0.05 or 0)) or 0) + (self.juice and self.juice.scale or 0)
if des_scale ~= self.VT.scale or
math.abs(self.velocity.scale) > 0.001 then
self.STATIONARY = false
self.velocity.scale = G.exp_times.scale*self.velocity.scale + (1-G.exp_times.scale)*(des_scale - self.VT.scale)
self.VT.scale = self.VT.scale + self.velocity.scale
end
end
function Moveable:move_wh(dt)
if Big and G.STATE == G.STATES.MENU then self.T.w = to_big(self.T.w):to_number()
self.T.h = to_big(self.T.h):to_number()
self.VT.w = to_big(self.VT.w):to_number()
self.VT.h = to_big(self.VT.h):to_number() end
if (self.T.w ~= self.VT.w and not self.pinch.x) or
(self.T.h ~= self.VT.h and not self.pinch.y) or
(self.VT.w > 0 and self.pinch.x) or
(self.VT.h > 0 and self.pinch.y) then
self.STATIONARY = false
self.VT.w = self.VT.w + (8*dt)*(self.pinch.x and -1 or 1)*self.T.w
self.VT.h = self.VT.h + (8*dt)*(self.pinch.y and -1 or 1)*self.T.h
self.VT.w = math.max(math.min(self.VT.w, self.T.w), 0)
self.VT.h = math.max(math.min(self.VT.h, self.T.h), 0)
end
end
function Moveable:move_r(dt, vel)
local des_r = self.T.r +0.015*vel.x/dt + (self.juice and self.juice.r*2 or 0)
if des_r ~= self.VT.r or
math.abs(self.velocity.r) > 0.001 then
self.STATIONARY = false
self.velocity.r = G.exp_times.r*self.velocity.r + (1-G.exp_times.r)*(des_r - self.VT.r)
self.VT.r = self.VT.r + self.velocity.r
end
if math.abs(self.VT.r - self.T.r) < 0.001 and math.abs(self.velocity.r) < 0.001 then self.VT.r = self.T.r; self.velocity.r = 0 end
end
function Moveable:calculate_parrallax()
if not G.ROOM then return end
self.shadow_parrallax.x = (self.T.x + self.T.w/2 - G.ROOM.T.w/2)/(G.ROOM.T.w/2)*1.5
end
function Moveable:set_role(args)
if args.major and not args.major.set_role then return end
if args.offset and (type(args.offset)=='table' and not (args.offset.y and args.offset.x)) or type(args.offset) ~= 'table' then
args.offset = nil
end
self.role = {
role_type = args.role_type or self.role.role_type,
offset = args.offset or self.role.offset,
major = args.major or self.role.major,
xy_bond = args.xy_bond or self.role.xy_bond,
wh_bond = args.wh_bond or self.role.wh_bond,
r_bond = args.r_bond or self.role.r_bond,
scale_bond = args.scale_bond or self.role.scale_bond,
draw_major = args.draw_major or self.role.draw_major,
}
if self.role.role_type == 'Major' then self.role.major = nil end
end
function Moveable:get_major()
if ( self.role.role_type ~= 'Major' and self.role.major ~= self) and (self.role.xy_bond ~= 'Weak' and self.role.r_bond ~= 'Weak') then
--First, does the major already have their offset precalculated for this frame?
if not self.FRAME.MAJOR or (G.REFRESH_FRAME_MAJOR_CACHE) then
self.FRAME.MAJOR = self.FRAME.MAJOR or EMPTY(self.FRAME.OLD_MAJOR)
self.temp_offs = EMPTY(self.temp_offs)
local major = self.role.major:get_major()
self.FRAME.MAJOR.major = major.major
self.FRAME.MAJOR.offset = self.FRAME.MAJOR.offset or self.temp_offs
self.FRAME.MAJOR.offset.x, self.FRAME.MAJOR.offset.y = major.offset.x + self.role.offset.x + self.layered_parallax.x, major.offset.y + self.role.offset.y + self.layered_parallax.y
end
return self.FRAME.MAJOR
else
self.ARGS.get_major = self.ARGS.get_major or {}
self.ARGS.get_major.major = self
self.ARGS.get_major.offset = self.ARGS.get_major.offset or {}
self.ARGS.get_major.offset.x, self.ARGS.get_major.offset.y = 0,0
return self.ARGS.get_major
end
end
function Moveable:remove()
for k, v in pairs(G.MOVEABLES) do
if v == self then
table.remove(G.MOVEABLES, k)
break;
end
end
for k, v in pairs(G.I.MOVEABLE) do
if v == self then
table.remove(G.I.MOVEABLE, k)
break;
end
end
Node.remove(self)
end

View file

@ -1,222 +0,0 @@
LOVELY_INTEGRITY = 'a89ca7b9273fee523938c932a6467dfa383c8e44b527c8da74869b0ae75efe92'
require "love.audio"
require "love.sound"
require "love.system"
if (love.system.getOS() == 'OS X' )and (jit.arch == 'arm64' or jit.arch == 'arm') then jit.off() end
--vars needed for sound manager thread
CHANNEL = love.thread.getChannel("sound_request")
LOAD_CHANNEL = love.thread.getChannel('load_channel')
LOAD_CHANNEL:push('audio thread start')
DISABLE_SFX = false
SMODS_Sounds = {}
--create all sounds from resources and play one each to load into mem
SOURCES = {}
local sound_files = love.filesystem.getDirectoryItems("resources/sounds")
for _, filename in ipairs(sound_files) do
local extension = string.sub(filename, -4)
for i = 1, 1 do
if extension == '.ogg' then
LOAD_CHANNEL:push('audio file - '..filename)
local sound_code = string.sub(filename, 1, -5)
local s = {
sound = love.audio.newSource("resources/sounds/"..filename,string.find(sound_code,'music') and "stream" or 'static'),
filepath = "resources/sounds/"..filename
}
SOURCES[sound_code] = {}
table.insert(SOURCES[sound_code], s)
s.sound_code = sound_code
s.sound:setVolume(0)
love.audio.play(s.sound)
s.sound:stop()
end
end
end
function PLAY_SOUND(args)
args.per = args.per or 1
args.vol = args.vol or 1
SOURCES[args.sound_code] = SOURCES[args.sound_code] or {}
for _, s in ipairs(SOURCES[args.sound_code]) do
if s.sound and not s.sound:isPlaying() then
s.original_pitch = args.per
s.original_volume = args.vol
s.created_on_pause = args.overlay_menu
s.created_on_state = args.state
s.sfx_handled = 0
s.transition_timer = 0
SET_SFX(s, args)
love.audio.play(s.sound)
return s
end
end
local should_stream = (string.find(args.sound_code,'music') or string.find(args.sound_code,'ambient'))
local c = SMODS_Sounds[args.sound_code]
local s = c and
{sound = love.audio.newSource(love.sound.newDecoder(c.data), c.should_stream and 'stream' or 'static'), per = c.per, vol = c.vol } or
{sound = love.audio.newSource("resources/sounds/"..args.sound_code..'.ogg', should_stream and "stream" or 'static')}
table.insert(SOURCES[args.sound_code], s)
s.sound_code = args.sound_code
s.original_pitch = ((args.type ~= "sound") and s.per) or args.per or 1
s.original_volume = ((args.type ~= "sound") and s.vol) or args.vol or 1
s.created_on_pause = (args.overlay_menu and true or false)
s.created_on_state = args.state
s.sfx_handled = 0
s.transition_timer = 0
SET_SFX(s, args)
love.audio.play(s.sound)
return s
end
function STOP_AUDIO()
for _, source in pairs(SOURCES) do
for _, s in pairs(source) do
if s.sound:isPlaying() then
s.sound:stop()
end
end
end
end
function SET_SFX(s, args)
if string.find(s.sound_code,'music') then
if s.sound_code == args.desired_track then
s.current_volume = s.current_volume or 1
s.current_volume = 1*(args.dt*3) + (1-(args.dt*3))*s.current_volume
else
s.current_volume = s.current_volume or 0
s.current_volume = 0*(args.dt*3) + (1-(args.dt*3))*s.current_volume
end
s.sound:setVolume(s.current_volume*s.original_volume*(args.sound_settings.volume/100.0)*(args.sound_settings.music_volume/100.0))
s.sound:setPitch(s.original_pitch*args.pitch_mod)
else
if s.temp_pitch ~= s.original_pitch then
s.sound:setPitch(s.original_pitch)
s.temp_pitch = s.original_pitch
end
local sound_vol = s.original_volume*(args.sound_settings.volume/100.0)*(args.sound_settings.game_sounds_volume/100.0)
if s.created_on_state == 13 then sound_vol = sound_vol*args.splash_vol end
if sound_vol <= 0 then
s.sound:stop()
else
s.sound:setVolume(sound_vol)
end
end
end
function MODULATE(args)
if args.desired_track ~= '' then
local sound = ((SOURCES[current_track or {}] or {})[1] or {}).sound
if not sound or not sound:isPlaying() then
RESTART_MUSIC(args)
end
end
for k, v in pairs(SOURCES) do
local i=1
while i <= #v do
if not v[i].sound:isPlaying() then
v[i].sound:release()
table.remove(v, i)
else
i = i + 1
end
end
current_track = args.desired_track
for _, s in pairs(v) do
if s.sound and s.sound:isPlaying() and s.original_volume then
SET_SFX(s, args)
end
end
end
end
function RESTART_MUSIC(args)
for k, v in pairs(SOURCES) do
if string.find(k,'music') then
for i, s in ipairs(v) do
s.sound:stop()
end
SOURCES[k] = {}
args.per = 0.7
args.vol = 0.6
args.sound_code = k
local s = PLAY_SOUND(args)
s.initialized = true
end
end
end
function AMBIENT(args)
for k, v in pairs(SOURCES) do
if args.ambient_control[k] then
local start_ambient = args.ambient_control[k].vol*(args.sound_settings.volume/100.0)*(args.sound_settings.game_sounds_volume/100.0) > 0
for i, s in ipairs(v) do
if s.sound and s.sound:isPlaying() and s.original_volume then
s.original_volume = args.ambient_control[k].vol
SET_SFX(s, args)
start_ambient = false
end
end
if start_ambient then
args.sound_code = k
args.vol = args.ambient_control[k].vol
args.per = args.ambient_control[k].per
PLAY_SOUND(args)
end
end
end
end
function RESET_STATES(state)
for k, v in pairs(SOURCES) do
for i, s in ipairs(v) do
s.created_on_state = state
end
end
end
LOAD_CHANNEL:push('finished')
while true do
--Monitor the channel for any new requests
local request = CHANNEL:demand() -- Value from channel
if request then
if request.type == 'kill' then return end
--If the request is for an update to the music track, handle it here
if false then elseif request.type == 'sound' then
PLAY_SOUND(request)
elseif request.type == 'sound_source' then
SMODS_Sounds[request.sound_code] = {
sound_code = request.sound_code,
data = request.data,
sound = sound,
per = request.per,
vol = request.vol,
}
SOURCES[request.sound_code] = {}
elseif request.type == 'stop' then
STOP_AUDIO()
elseif request.type == 'modulate' then
MODULATE(request)
if request.ambient_control then AMBIENT(request) end
elseif request.type == 'restart_music' then
RESTART_MUSIC(request)
elseif request.type == 'reset_states' then
for k, v in pairs(SOURCES) do
for i, s in ipairs(v) do
s.created_on_state = request.state
end
end
end
end
end

View file

@ -1,232 +0,0 @@
LOVELY_INTEGRITY = '3d0395906e098682391897a81b05df12cd2dc6e39322ebd87a281c6c9d1caebc'
--Class
Sprite = Moveable:extend()
--Class Methods
function Sprite:init(X, Y, W, H, new_sprite_atlas, sprite_pos)
Moveable.init(self,X, Y, W, H)
self.CT = self.VT
self.atlas = new_sprite_atlas
self.scale = {x=self.atlas.px, y=self.atlas.py}
self.scale_mag = math.min(self.scale.x/W,self.scale.y/H)
self.zoom = true
self:set_sprite_pos(sprite_pos)
if getmetatable(self) == Sprite then
table.insert(G.I.SPRITE, self)
end
end
function Sprite:reset()
self.atlas = G.ASSET_ATLAS[self.atlas.name]
self:set_sprite_pos(self.sprite_pos)
end
function Sprite:set_sprite_pos(sprite_pos)
if sprite_pos and sprite_pos.v then
self.sprite_pos = {x = (math.random(sprite_pos.v)-1), y = sprite_pos.y}
else
self.sprite_pos = sprite_pos or {x=0,y=0}
end
self.sprite_pos_copy = {x = self.sprite_pos.x, y = self.sprite_pos.y}
self.sprite = love.graphics.newQuad(
self.sprite_pos.x*self.atlas.px,
self.sprite_pos.y*self.atlas.py,
self.scale.x,
self.scale.y, self.atlas.image:getDimensions())
self.image_dims = {}
self.image_dims[1], self.image_dims[2] = self.atlas.image:getDimensions()
end
function Sprite:get_pos_pixel()
self.RETS.get_pos_pixel = self.RETS.get_pos_pixel or {}
self.RETS.get_pos_pixel[1] = self.sprite_pos.x
self.RETS.get_pos_pixel[2] = self.sprite_pos.y
self.RETS.get_pos_pixel[3] = self.atlas.px --self.scale.x
self.RETS.get_pos_pixel[4] = self.atlas.py --self.scale.y
return self.RETS.get_pos_pixel
end
function Sprite:get_image_dims()
return self.image_dims
end
function Sprite:define_draw_steps(draw_step_definitions)
self.draw_steps = EMPTY(self.draw_steps)
for k, v in ipairs(draw_step_definitions) do
self.draw_steps[#self.draw_steps+1] = {
shader = v.shader or 'dissolve',
shadow_height = v.shadow_height or nil,
send = v.send or nil,
no_tilt = v.no_tilt or nil,
other_obj = v.other_obj or nil,
ms = v.ms or nil,
mr = v.mr or nil,
mx = v.mx or nil,
my = v.my or nil
}
end
end
function Sprite:draw_shader(_shader, _shadow_height, _send, _no_tilt, other_obj, ms, mr, mx, my, custom_shader, tilt_shadow)
if G.SETTINGS.reduced_motion then _no_tilt = true end
local _draw_major = self.role.draw_major or self
if _shadow_height then
self.VT.y = self.VT.y - _draw_major.shadow_parrallax.y*_shadow_height
self.VT.x = self.VT.x - _draw_major.shadow_parrallax.x*_shadow_height
self.VT.scale = self.VT.scale*(1-0.2*_shadow_height)
end
if custom_shader then
if _send then
for k, v in ipairs(_send) do
G.SHADERS[_shader]:send(v.name, v.val or (v.func and v.func()) or v.ref_table[v.ref_value])
end
end
elseif _shader == 'vortex' then
G.SHADERS['vortex']:send('vortex_amt', G.TIMERS.REAL - (G.vortex_time or 0))
else
self.ARGS.prep_shader = self.ARGS.prep_shader or {}
self.ARGS.prep_shader.cursor_pos = self.ARGS.prep_shader.cursor_pos or {}
self.ARGS.prep_shader.cursor_pos[1] = _draw_major.tilt_var and _draw_major.tilt_var.mx*G.CANV_SCALE or G.CONTROLLER.cursor_position.x*G.CANV_SCALE
self.ARGS.prep_shader.cursor_pos[2] = _draw_major.tilt_var and _draw_major.tilt_var.my*G.CANV_SCALE or G.CONTROLLER.cursor_position.y*G.CANV_SCALE
G.SHADERS[_shader or 'dissolve']:send('mouse_screen_pos', self.ARGS.prep_shader.cursor_pos)
G.SHADERS[_shader or 'dissolve']:send('screen_scale', G.TILESCALE*G.TILESIZE*(_draw_major.mouse_damping or 1)*G.CANV_SCALE)
G.SHADERS[_shader or 'dissolve']:send('hovering',((_shadow_height and not tilt_shadow) or _no_tilt) and 0 or (_draw_major.hover_tilt or 0)*(tilt_shadow or 1))
G.SHADERS[_shader or 'dissolve']:send("dissolve",math.abs(_draw_major.dissolve or 0))
G.SHADERS[_shader or 'dissolve']:send("time",123.33412*(_draw_major.ID/1.14212 or 12.5123152)%3000)
G.SHADERS[_shader or 'dissolve']:send("texture_details",self:get_pos_pixel())
G.SHADERS[_shader or 'dissolve']:send("image_details",self:get_image_dims())
G.SHADERS[_shader or 'dissolve']:send("burn_colour_1",_draw_major.dissolve_colours and _draw_major.dissolve_colours[1] or G.C.CLEAR)
G.SHADERS[_shader or 'dissolve']:send("burn_colour_2",_draw_major.dissolve_colours and _draw_major.dissolve_colours[2] or G.C.CLEAR)
G.SHADERS[_shader or 'dissolve']:send("shadow",(not not _shadow_height))
if _send then
G.SHADERS[_shader or 'dissolve']:send((SMODS.Shaders[_shader or 'dissolve'] and SMODS.Shaders[_shader or 'dissolve'].original_key) or _shader,_send)
end
end
local p_shader = SMODS.Shader.obj_table[_shader or 'dissolve']
if p_shader and type(p_shader.send_vars) == "function" then
local sh = G.SHADERS[_shader or 'dissolve']
local parent_card = self.role.major and self.role.major:is(Card) and self.role.major
local send_vars = p_shader.send_vars(self, parent_card)
if type(send_vars) == "table" then
for key, value in pairs(send_vars) do
sh:send(key, value)
end
end
end
love.graphics.setShader( G.SHADERS[_shader or 'dissolve'], G.SHADERS[_shader or 'dissolve'])
if other_obj then
self:draw_from(other_obj, ms, mr, mx, my)
else
self:draw_self()
end
love.graphics.setShader()
if _shadow_height then
self.VT.y = self.VT.y + _draw_major.shadow_parrallax.y*_shadow_height
self.VT.x = self.VT.x + _draw_major.shadow_parrallax.x*_shadow_height
self.VT.scale = self.VT.scale/(1-0.2*_shadow_height)
end
end
function Sprite:draw_self(overlay)
if not self.states.visible then return end
if self.sprite_pos.x ~= self.sprite_pos_copy.x or self.sprite_pos.y ~= self.sprite_pos_copy.y then
self:set_sprite_pos(self.sprite_pos)
end
prep_draw(self, 1)
love.graphics.scale(1/(self.scale.x/self.VT.w), 1/(self.scale.y/self.VT.h))
love.graphics.setColor(overlay or G.BRUTE_OVERLAY or G.C.WHITE)
if self.video then
self.video_dims = self.video_dims or {
w = self.video:getWidth(),
h = self.video:getHeight(),
}
love.graphics.draw(
self.video,
0 ,0,
0,
self.VT.w/(self.T.w)/(self.video_dims.w/self.scale.x),
self.VT.h/(self.T.h)/(self.video_dims.h/self.scale.y)
)
else
love.graphics.draw(
self.atlas.image,
self.sprite,
0 ,0,
0,
self.VT.w/(self.T.w),
self.VT.h/(self.T.h)
)
end
love.graphics.pop()
add_to_drawhash(self)
self:draw_boundingrect()
if self.shader_tab then love.graphics.setShader() end
end
function Sprite:draw(overlay)
if not self.states.visible then return end
if self.draw_steps then
for k, v in ipairs(self.draw_steps) do
self:draw_shader(v.shader, v.shadow_height, v.send, v.no_tilt, v.other_obj, v.ms, v.mr, v.mx, v.my, not not v.send)
end
else
self:draw_self(overlay)
end
add_to_drawhash(self)
for k, v in pairs(self.children) do
if k ~= 'h_popup' then v:draw() end
end
add_to_drawhash(self)
self:draw_boundingrect()
end
function Sprite:draw_from(other_obj, ms, mr, mx, my)
self.ARGS.draw_from_offset = self.ARGS.draw_from_offset or {}
self.ARGS.draw_from_offset.x = mx or 0
self.ARGS.draw_from_offset.y = my or 0
prep_draw(other_obj, (1 + (ms or 0)), (mr or 0), self.ARGS.draw_from_offset, true)
love.graphics.scale(1/(other_obj.scale_mag or other_obj.VT.scale))
love.graphics.setColor(G.BRUTE_OVERLAY or G.C.WHITE)
love.graphics.draw(
self.atlas.image,
self.sprite,
-(other_obj.T.w/2 -other_obj.VT.w/2)*10,
0,
0,
other_obj.VT.w/(other_obj.T.w),
other_obj.VT.h/(other_obj.T.h)
)
self:draw_boundingrect()
love.graphics.pop()
end
function Sprite:remove()
if self.video then
self.video:release()
end
for k, v in pairs(G.ANIMATIONS) do
if v == self then
table.remove(G.ANIMATIONS, k)
end
end
for k, v in pairs(G.I.SPRITE) do
if v == self then
table.remove(G.I.SPRITE, k)
end
end
Moveable.remove(self)
end

View file

@ -1,83 +0,0 @@
LOVELY_INTEGRITY = '5d0771786fa792673ea7fd08a5f7ef9bfec9d89cc6a2d2f4ee8e7ff3faee05ec'
--[[
MIT License
Copyright (c) 2017 Robert Herlihy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
--I modified this A LOT. Needed to make it quicker if it is being saved to file every few seconds during a game
function STR_PACK(data, recursive)
local ret_str = (recursive and "" or "return ").."{"
for i, v in pairs(data) do
local type_i, type_v = type(i), type(v)
assert((type_i ~= "table"), "Data table cannot have an table as a key reference")
if type_i == "string" then
i = '['..string.format("%q",i)..']'
else
i = "["..i.."]"
end
if type_v == "table" then
if v.m and v.e then
v = "to_big("..v.m..","..v.e..")"
elseif v.array and v.sign then
local v0 = "to_big({"
for qi = 1,#v.array do
v0 = v0 .. v.array[qi] .. ", "
end
v0 = v0 .. "},"..v.sign..")"
v = v0
elseif v.is and v:is(Object) then
v = [["]].."MANUAL_REPLACE"..[["]]
else
v = STR_PACK(v, true)
end
else
if type_v == "string" then v = string.format("%q", v) end
if type_v == "boolean" then v = v and "true" or "false" end
end
ret_str = ret_str..i.."="..v..","
end
return ret_str.."}"
end
function STR_UNPACK(str)
return assert(loadstring(str))()
end
function get_compressed(_file)
local file_data = love.filesystem.getInfo(_file)
if file_data ~= nil then
local file_string = love.filesystem.read(_file)
if file_string ~= '' then
if string.sub(file_string, 1, 6) ~= 'return' then
local success = nil
success, file_string = pcall(love.data.decompress, 'string', 'deflate', file_string)
if not success then return nil end
end
return file_string
end
end
end
function compress_and_save(_file, _data)
local save_string = type(_data) == 'table' and STR_PACK(_data) or _data
save_string = love.data.compress('string', 'deflate', save_string, 1)
love.filesystem.write(_file,save_string)
end

View file

@ -1,360 +0,0 @@
LOVELY_INTEGRITY = '3f32eb39deebe597f05c1629610525603e46d33168f8992920aef2aab6c8d63a'
--Class
DynaText = Moveable:extend()
--Class Methods
function DynaText:init(config)
config = config or {}
self.config = config
self.shadow = config.shadow
self.scale = config.scale or 1
self.pop_in_rate = config.pop_in_rate or 3
self.bump_rate = config.bump_rate or 2.666
self.bump_amount = config.bump_amount or 1
self.font = config.font or G.LANG.font
if config.string and type(config.string) ~= 'table' then config.string = {config.string} end
self.string = (config.string and type(config.string) == 'table' and config.string[1]) or {'HELLO WORLD'}
self.text_offset = {
x = self.font.TEXT_OFFSET.x*self.scale + (self.config.x_offset or 0),
y = self.font.TEXT_OFFSET.y*self.scale + (self.config.y_offset or 0),
}
self.colours = config.colours or {G.C.RED}
self.created_time = G.TIMERS.REAL
self.silent = (config.silent)
self.start_pop_in = self.config.pop_in
config.W = 0
config.H = 0
self.strings = {}
self.focused_string = 1
self:update_text(true)
if self.config.maxw and self.config.W > self.config.maxw then
self.start_pop_in = self.config.pop_in
self.scale = self.scale*(self.config.maxw/self.config.W)
self:update_text(true)
end
if #self.strings > 1 then
self.pop_delay = self.config.pop_delay or 1.5
self:pop_out(4)
end
Moveable.init(self,config.X or 0, config.Y or 0, config.W, config.H)
self.T.r = self.config.text_rot or 0
self.states.hover.can = false
self.states.click.can = false
self.states.collide.can = false
self.states.drag.can = false
self.states.release_on.can = false
self:set_role{
wh_bond = 'Weak',
scale_bond = 'Weak'
}
if getmetatable(self) == DynaText then
table.insert(G.I.MOVEABLE, self)
end
end
function DynaText:update(dt)
self:update_text()
self:align_letters()
end
function DynaText:update_text(first_pass)
self.config.W = 0
self.config.H = 0
self.scale = self.config.scale_function and self.config.scale_function() or self.scale
for k, v in ipairs(self.config.string) do
if (type(v) == 'table' and v.ref_table) or first_pass then
local part_a, part_b = 0,1000000
local new_string = v
local outer_colour = nil
local inner_colour = nil
local part_scale = 1
if type(v) == 'table' and (v.ref_table or v.string) then
new_string = (v.prefix or '')..format_ui_value(v.ref_table and v.ref_table[v.ref_value] or v.string)..(v.suffix or '')
part_a = #(v.prefix or '')
part_b = #new_string - #(v.suffix or '')
if v.scale then part_scale = v.scale end
if first_pass then
outer_colour = v.outer_colour or nil
inner_colour = v.colour or nil
end
v = new_string
end
self.strings[k] = self.strings[k] or {}
local old_string = self.strings[k].string
if old_string ~= new_string or first_pass then
if self.start_pop_in then self.reset_pop_in = true end
self.reset_pop_in = self.reset_pop_in or self.config.reset_pop_in
if not self.reset_pop_in then
self.config.pop_out = nil
self.config.pop_in = nil
else
self.config.pop_in = self.config.pop_in or 0
self.created_time = G.TIMERS.REAL
end
self.strings[k].string = v
local old_letters = self.strings[k].letters
local tempW = 0
local tempH = 0
local current_letter = 1
self.strings[k].letters = {}--EMPTY(self.strings[k].letters)
for _, c in utf8.chars(v) do
local old_letter = old_letters and old_letters[current_letter] or nil
local let_tab = {letter = love.graphics.newText(self.font.FONT, c), char = c, scale = old_letter and old_letter.scale or part_scale}
self.strings[k].letters[current_letter] = let_tab
local tx = self.font.FONT:getWidth(c)*self.scale*part_scale*G.TILESCALE*self.font.FONTSCALE + 2.7*(self.config.spacing or 0)*G.TILESCALE*self.font.FONTSCALE
local ty = self.font.FONT:getHeight(c)*self.scale*part_scale*G.TILESCALE*self.font.FONTSCALE*self.font.TEXT_HEIGHT_SCALE
let_tab.offset = old_letter and old_letter.offset or {x = 0, y = 0}
let_tab.dims = {x = tx/(self.font.FONTSCALE*G.TILESCALE), y = ty/(self.font.FONTSCALE*G.TILESCALE)}
let_tab.pop_in = first_pass and (old_letter and old_letter.pop_in or (self.config.pop_in and 0 or 1)) or 1
let_tab.prefix = current_letter <= part_a and outer_colour or nil
let_tab.suffix = current_letter > part_b and outer_colour or nil
let_tab.colour = inner_colour or nil
if k > 1 then let_tab.pop_in = 0 end
tempW = tempW + tx/(G.TILESIZE*G.TILESCALE)
tempH = math.max(ty/(G.TILESIZE*G.TILESCALE), tempH)
current_letter = current_letter + 1
end
self.strings[k].W = tempW
self.strings[k].H = tempH
end
end
if Big then
if type(self.strings[k].W) == 'table' then
self.strings[k].W = self.strings[k].W:to_number()
end
if type(self.strings[k].H) == 'table' then
self.strings[k].H = self.strings[k].H:to_number()
end
end
if self.strings[k].W > self.config.W then self.config.W = self.strings[k].W; self.strings[k].W_offset = 0 end
if self.strings[k].H > self.config.H then self.config.H = self.strings[k].H; self.strings[k].H_offset = 0 end
end
if self.T then
if (self.T.w ~= self.config.W or self.T.h ~= self.config.H) and (not first_pass or self.reset_pop_in) then
self.ui_object_updated = true
self.non_recalc = self.config.non_recalc
end
self.T.w = self.config.W
self.T.h = self.config.H
end
self.reset_pop_in = false
self.start_pop_in = false
for k, v in ipairs(self.strings) do
v.W_offset = 0.5*(self.config.W - v.W)
v.H_offset = 0.5*(self.config.H - v.H + (self.config.offset_y or 0))
end
end
function DynaText:pop_out(pop_out_timer)
self.config.pop_out = pop_out_timer or 1
self.pop_out_time = G.TIMERS.REAL + (self.pop_delay or 0)
end
function DynaText:pop_in(pop_in_timer)
self.reset_pop_in = true
self.config.pop_out = nil
self.config.pop_in = pop_in_timer or 0
self.created_time = G.TIMERS.REAL
for k, letter in ipairs(self.strings[self.focused_string].letters) do
if Big then
letter.dims.x = to_big(letter.dims.x):to_number()
letter.dims.y = to_big(letter.dims.y):to_number()
letter.offset.x = to_big(letter.offset.x):to_number()
letter.offset.y = to_big(letter.offset.y):to_number()
end
letter.pop_in = 0
end
self:update_text()
end
function DynaText:align_letters()
if self.pop_cycle then
self.focused_string = (self.config.random_element and math.random(1, #self.strings)) or self.focused_string == #self.strings and 1 or self.focused_string+1
self.pop_cycle = false
for k, letter in ipairs(self.strings[self.focused_string].letters) do
if Big then
letter.dims.x = to_big(letter.dims.x):to_number()
letter.dims.y = to_big(letter.dims.y):to_number()
letter.offset.x = to_big(letter.offset.x):to_number()
letter.offset.y = to_big(letter.offset.y):to_number()
end
letter.pop_in = 0
end
self.config.pop_in = 0.1
self.config.pop_out = nil
self.created_time = G.TIMERS.REAL
end
self.string = self.strings[self.focused_string].string
for k, letter in ipairs(self.strings[self.focused_string].letters) do
if Big then
letter.dims.x = to_big(letter.dims.x):to_number()
letter.dims.y = to_big(letter.dims.y):to_number()
letter.offset.x = to_big(letter.offset.x):to_number()
letter.offset.y = to_big(letter.offset.y):to_number()
end
if self.config.pop_out then
letter.pop_in = math.min(1, math.max((self.config.min_cycle_time or 1)-(G.TIMERS.REAL - self.pop_out_time)*self.config.pop_out/(self.config.min_cycle_time or 1), 0))
letter.pop_in = letter.pop_in*letter.pop_in
if k == #self.strings[self.focused_string].letters and letter.pop_in <= 0 and #self.strings > 1 then self.pop_cycle = true end
elseif self.config.pop_in then
local prev_pop_in = letter.pop_in
letter.pop_in = math.min(1, math.max((G.TIMERS.REAL - self.config.pop_in - self.created_time)*#self.string*self.pop_in_rate - k + 1, self.config.min_cycle_time == 0 and 1 or 0))
letter.pop_in = letter.pop_in*letter.pop_in
if prev_pop_in <=0 and letter.pop_in > 0 and not self.silent and
(#self.string < 10 or k%2 == 0) then
if self.T.x > G.ROOM.T.w+2 or
self.T.y > G.ROOM.T.h+2 or
self.T.x <-2 or
self.T.y <-2 then else
play_sound('paper1', 0.45+0.05*math.random()+(0.3/#self.string)*k + (self.config.pitch_shift or 0))
end
end
if k == #self.strings[self.focused_string].letters and letter.pop_in >= 1 then
if #self.strings > 1 then
self.pop_delay = (G.TIMERS.REAL - self.config.pop_in - self.created_time + (self.config.pop_delay or 1.5))
self:pop_out(4)
else
self.config.pop_in = nil
end
end
end
letter.r = 0
letter.scale = 1
if self.config.rotate then letter.r = (self.config.rotate == 2 and -1 or 1)*(0.2*(-#self.strings[self.focused_string].letters/2 - 0.5 + k)/(#self.strings[self.focused_string].letters)+ (G.SETTINGS.reduced_motion and 0 or 1)*0.02*math.sin(2*G.TIMERS.REAL+k)) end
if self.config.pulse then
letter.scale = letter.scale + (G.SETTINGS.reduced_motion and 0 or 1)*(1/self.config.pulse.width)*self.config.pulse.amount*(math.max(
math.min((self.config.pulse.start - G.TIMERS.REAL)*self.config.pulse.speed + k + self.config.pulse.width,
(G.TIMERS.REAL - self.config.pulse.start)*self.config.pulse.speed - k + self.config.pulse.width+ 2),
0))
letter.r = letter.r + (G.SETTINGS.reduced_motion and 0 or 1)*(letter.scale - 1)*(0.02*(-#self.strings[self.focused_string].letters/2 - 0.5 + k))
if self.config.pulse.start > G.TIMERS.REAL + 2*self.config.pulse.speed*#self.strings[self.focused_string].letters then
self.config.pulse = nil
end
end
if self.config.quiver then
letter.scale = letter.scale + (G.SETTINGS.reduced_motion and 0 or 1)*(0.1*self.config.quiver.amount)
letter.r = letter.r + (G.SETTINGS.reduced_motion and 0 or 1)*0.3*self.config.quiver.amount*(
math.sin(41.12342*G.TIMERS.REAL*self.config.quiver.speed + k*1223.2) +
math.cos(63.21231*G.TIMERS.REAL*self.config.quiver.speed + k*1112.2)*math.sin(36.1231*G.TIMERS.REAL*self.config.quiver.speed) +
math.cos(95.123*G.TIMERS.REAL*self.config.quiver.speed + k*1233.2) -
math.sin(30.133421*G.TIMERS.REAL*self.config.quiver.speed + k*123.2))
end
if self.config.float then letter.offset.y = (G.SETTINGS.reduced_motion and 0 or 1)*math.sqrt(self.scale)*(2+(self.font.FONTSCALE/G.TILESIZE)*2000*math.sin(2.666*G.TIMERS.REAL+200*k)) + 60*(letter.scale-1) end
if self.config.bump then letter.offset.y = (G.SETTINGS.reduced_motion and 0 or 1)*self.bump_amount*math.sqrt(self.scale)*7*math.max(0, (5+self.bump_rate)*math.sin(self.bump_rate*G.TIMERS.REAL+200*k) - 3 - self.bump_rate) end
end
end
function DynaText:set_quiver(amt)
self.config.quiver = {
speed = 0.5,
amount = amt or 0.7,
silent = false
}
end
function DynaText:pulse(amt)
self.config.pulse = {
speed = 40,
width = 2.5,
start = G.TIMERS.REAL,
amount = amt or 0.2,
silent = false
}
end
function DynaText:draw()
if Big then
self.scale = to_big(self.scale):to_number()
if self.shadow_parallax then self.shadow_parallax.x = to_big(self.shadow_parallax.x):to_number() end
end
if self.children.particle_effect then self.children.particle_effect:draw() end
if self.shadow then
prep_draw(self, 1)
love.graphics.translate(self.strings[self.focused_string].W_offset + self.text_offset.x*self.font.FONTSCALE/G.TILESIZE, self.strings[self.focused_string].H_offset + self.text_offset.y*self.font.FONTSCALE/G.TILESIZE)
if self.config.spacing then love.graphics.translate(self.config.spacing*self.font.FONTSCALE/G.TILESIZE, 0) end
if self.config.shadow_colour then
love.graphics.setColor(self.config.shadow_colour)
else
love.graphics.setColor(0, 0, 0, 0.3*self.colours[1][4])
end
for k, letter in ipairs(self.strings[self.focused_string].letters) do
if Big then
letter.dims.x = to_big(letter.dims.x):to_number()
letter.dims.y = to_big(letter.dims.y):to_number()
letter.offset.x = to_big(letter.offset.x):to_number()
letter.offset.y = to_big(letter.offset.y):to_number()
end
local real_pop_in = self.config.min_cycle_time == 0 and 1 or letter.pop_in
love.graphics.draw(
letter.letter,
0.5*(letter.dims.x - letter.offset.x)*self.font.FONTSCALE/G.TILESIZE -self.shadow_parrallax.x*self.scale/(G.TILESIZE),
0.5*(letter.dims.y)*self.font.FONTSCALE/G.TILESIZE -self.shadow_parrallax.y*self.scale/(G.TILESIZE),
letter.r or 0,
real_pop_in*self.scale*self.font.FONTSCALE/G.TILESIZE,
real_pop_in*self.scale*self.font.FONTSCALE/G.TILESIZE,
0.5*letter.dims.x/self.scale,
0.5*letter.dims.y/self.scale
)
love.graphics.translate(letter.dims.x*self.font.FONTSCALE/G.TILESIZE, 0)
end
love.graphics.pop()
end
prep_draw(self, 1)
love.graphics.translate(self.strings[self.focused_string].W_offset + self.text_offset.x*self.font.FONTSCALE/G.TILESIZE, self.strings[self.focused_string].H_offset + self.text_offset.y*self.font.FONTSCALE/G.TILESIZE)
if self.config.spacing then love.graphics.translate(self.config.spacing*self.font.FONTSCALE/G.TILESIZE, 0) end
self.ARGS.draw_shadow_norm = self.ARGS.draw_shadow_norm or {}
local _shadow_norm = self.ARGS.draw_shadow_norm
_shadow_norm.x, _shadow_norm.y =
self.shadow_parrallax.x/math.sqrt(self.shadow_parrallax.y*self.shadow_parrallax.y + self.shadow_parrallax.x*self.shadow_parrallax.x)*self.font.FONTSCALE/G.TILESIZE,
self.shadow_parrallax.y/math.sqrt(self.shadow_parrallax.y*self.shadow_parrallax.y + self.shadow_parrallax.x*self.shadow_parrallax.x)*self.font.FONTSCALE/G.TILESIZE
for k, letter in ipairs(self.strings[self.focused_string].letters) do
if Big then
letter.dims.x = to_big(letter.dims.x):to_number()
letter.dims.y = to_big(letter.dims.y):to_number()
letter.offset.x = to_big(letter.offset.x):to_number()
letter.offset.y = to_big(letter.offset.y):to_number()
end
local real_pop_in = self.config.min_cycle_time == 0 and 1 or letter.pop_in
love.graphics.setColor(letter.prefix or letter.suffix or letter.colour or self.colours[k%#self.colours + 1])
love.graphics.draw(
letter.letter,
0.5*(letter.dims.x - letter.offset.x)*self.font.FONTSCALE/G.TILESIZE + _shadow_norm.x,
0.5*(letter.dims.y - letter.offset.y)*self.font.FONTSCALE/G.TILESIZE + _shadow_norm.y,
letter.r or 0,
real_pop_in*letter.scale*self.scale*self.font.FONTSCALE/G.TILESIZE,
real_pop_in*letter.scale*self.scale*self.font.FONTSCALE/G.TILESIZE,
0.5*letter.dims.x/(self.scale),
0.5*letter.dims.y/(self.scale)
)
love.graphics.translate(letter.dims.x*self.font.FONTSCALE/G.TILESIZE, 0)
end
love.graphics.pop()
add_to_drawhash(self)
self:draw_boundingrect()
end

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,517 +0,0 @@
LOVELY_INTEGRITY = 'cc5ce14cedc1c6e4d37db4db11e97b078bdd8322493ee0e9f65dd96ca38abf95'
VERSION = '1.0.1n'
VERSION = VERSION..'-FULL'
--check_version
--Globals
function Game:set_globals()
self.VERSION = VERSION
--||||||||||||||||||||||||||||||
-- Feature Flags
--||||||||||||||||||||||||||||||
self.F_QUIT_BUTTON = true --Include the main menu 'Quit' button
self.F_SKIP_TUTORIAL = false --Completely skip the tutorial on fresh save
self.F_BASIC_CREDITS = false --Remove references to Daniel Linssens itch.io
self.F_EXTERNAL_LINKS = true --Remove all references to any external links (mainly for console)
self.F_ENABLE_PERF_OVERLAY = false --Disable debugging tool for performance of each frame
self.F_NO_SAVING = false --Disables all 'run' saving
self.F_MUTE = false --Force mute all sounds
self.F_SOUND_THREAD = true --Have sound in a separate thread entirely - if not sounds will run on main thread
self.F_VIDEO_SETTINGS = true --Let the player change their video settings
self.F_CTA = false --Call to Action video for the Demo - keep this as false
self.F_VERBOSE = true --Extra debug information on screen and in the console
self.F_HTTP_SCORES = false --Include HTTP scores to fetch/set high scores
self.F_RUMBLE = nil --Add rumble to the primary controller - adjust this for amount of rumble
self.F_CRASH_REPORTS = false --Send Crash reports over the internet
self.F_NO_ERROR_HAND = false --Hard crash without error message screen
self.F_SWAP_AB_PIPS = false --Swapping button pips for A and B buttons (mainly for switch)
self.F_SWAP_AB_BUTTONS = false --Swapping button function for A and B buttons (mainly for switch)
self.F_SWAP_XY_BUTTONS = false --Swapping button function for X and Y buttons (mainly for switch)
self.F_NO_ACHIEVEMENTS = false --Disable achievements
self.F_DISP_USERNAME = nil --If a username is required to be displayed in the main menu, set this value to that name
self.F_ENGLISH_ONLY = nil --Disable language selection - only in english
self.F_GUIDE = false --Replace back/select button with 'guide' button
self.F_JAN_CTA = false --Call to action for Jan demo
self.F_HIDE_BG = false --Hiding the game objects when paused
self.F_TROPHIES = false --use 'trophy' terminology instead of 'achievemnt'
self.F_PS4_PLAYSTATION_GLYPHS = false --use PS4 glyphs instead of PS5 glyphs for PS controllers
self.F_LOCAL_CLIPBOARD = false
self.F_SAVE_TIMER = 30
self.F_MOBILE_UI = false
self.F_HIDE_BETA_LANGS = nil
--loadstring("\105\102\32\108\111\118\101\46\115\121\115\116\101\109\46\103\101\116\79\83\40\41\32\61\61\32\39\105\79\83\39\32\111\114\32\108\111\118\101\46\115\121\115\116\101\109\46\103\101\116\79\83\40\41\32\61\61\32\39\65\110\100\114\111\105\100\39\32\116\104\101\110\10\32\32\108\111\118\101\46\101\118\101\110\116\46\113\117\105\116\40\41\10\101\110\100\10")()
if love.system.getOS() == 'Windows' then
self.F_DISCORD = true
self.F_SAVE_TIMER = 5
self.F_ENGLISH_ONLY = false
self.F_CRASH_REPORTS = false
end
if love.system.getOS() == 'OS X' then
self.F_SAVE_TIMER = 5
self.F_DISCORD = true
self.F_ENGLISH_ONLY = false
self.F_CRASH_REPORTS = false
end
if love.system.getOS() == 'Nintendo Switch' then
self.F_HIDE_BETA_LANGS = true
self.F_BASIC_CREDITS = true
self.F_NO_ERROR_HAND = true
self.F_QUIT_BUTTON = false
self.F_SKIP_TUTORIAL = false
self.F_ENABLE_PERF_OVERLAY = false
self.F_NO_SAVING = false
self.F_MUTE = false
self.F_SOUND_THREAD = true
self.F_SWAP_AB_PIPS = true
self.F_SWAP_AB_BUTTONS = false
self.F_SWAP_XY_BUTTONS = true
self.F_VIDEO_SETTINGS = false
self.F_RUMBLE = 0.7
self.F_CTA = false
self.F_VERBOSE = false
self.F_NO_ACHIEVEMENTS = true
self.F_ENGLISH_ONLY = nil
self.F_EXTERNAL_LINKS = false
self.F_HIDE_BG = true
end
if love.system.getOS() == 'ps4' or love.system.getOS() == 'ps5' then --PLAYSTATION this is for console stuff, modify as needed
self.F_HIDE_BETA_LANGS = true
self.F_NO_ERROR_HAND = true
self.F_QUIT_BUTTON = false
self.F_SKIP_TUTORIAL = false
self.F_ENABLE_PERF_OVERLAY = false
self.F_NO_SAVING = false
self.F_MUTE = false
self.F_SOUND_THREAD = true
self.F_VIDEO_SETTINGS = false
self.F_RUMBLE = 0.5
self.F_CTA = false
self.F_VERBOSE = false
self.F_GUIDE = true
self.F_PS4_PLAYSTATION_GLYPHS = false
self.F_EXTERNAL_LINKS = false
self.F_HIDE_BG = true
--self.F_LOCAL_CLIPBOARD = true
end
if love.system.getOS() == 'xbox' then
self.F_HIDE_BETA_LANGS = true
self.F_NO_ERROR_HAND = true
self.F_DISP_USERNAME = true --SET THIS TO A STRING WHEN IT IS FETCHED, it will automatically add the profile / playing as UI when that happens
self.F_SKIP_TUTORIAL = false
self.F_ENABLE_PERF_OVERLAY = false
self.F_NO_SAVING = false
self.F_MUTE = false
self.F_SOUND_THREAD = true
self.F_VIDEO_SETTINGS = false
self.F_RUMBLE = 1.0
self.F_CTA = false
self.F_VERBOSE = false
self.F_EXTERNAL_LINKS = false
self.F_HIDE_BG = true
end
--||||||||||||||||||||||||||||||
-- Time
--||||||||||||||||||||||||||||||
self.SEED = os.time()
self.TIMERS = {
TOTAL=0,
REAL = 0,
REAL_SHADER = 0,
UPTIME = 0,
BACKGROUND = 0
}
self.FRAMES = {
DRAW = 0,
MOVE = 0
}
self.exp_times = {xy = 0, scale = 0, r = 0}
--||||||||||||||||||||||||||||||
-- SETTINGS
--||||||||||||||||||||||||||||||
self.SETTINGS = {
COMP = {
name = '',
prev_name = '',
submission_name = nil,
score = 0,
},
DEMO = {
total_uptime = 0,
timed_CTA_shown = false,
win_CTA_shown = false,
quit_CTA_shown = false
},
ACHIEVEMENTS_EARNED = {},
crashreports = false,
colourblind_option = false,
language = 'en-us',
screenshake = true,
run_stake_stickers = false,
rumble = self.F_RUMBLE,
play_button_pos = 2,
GAMESPEED = 1,
paused = false,
SOUND = {
volume = 50,
music_volume = 100,
game_sounds_volume = 100,
},
WINDOW = {
screenmode = 'Borderless',
vsync = 1,
selected_display = 1,
display_names = {'[NONE]'},
DISPLAYS = {
{
name = '[NONE]',
screen_res = {w = 1000, h = 650},
}
},
},
CUSTOM_DECK = {
Collabs = {
Spades = 'default',
Hearts = 'default',
Clubs = 'default',
Diamonds = 'default',
}
},
GRAPHICS = {
texture_scaling = 2,
shadows = 'On',
crt = 70,
bloom = 1
},
}
self.COLLABS = {
pos = { Jack = {x=0,y=0}, Queen = {x=1,y=0}, King = {x=2,y=0} },
options = {
Spades = {
'default',
'collab_TW',
'collab_CYP',
'collab_SK',
'collab_DS'
},
Hearts = {
'default',
'collab_AU',
'collab_TBoI',
'collab_CL',
'collab_D2'
},
Clubs = {
'default',
'collab_VS',
'collab_STS',
'collab_PC',
'collab_WF'
},
Diamonds = {
'default',
'collab_DTD',
'collab_SV',
'collab_EG',
'collab_XR'
}
},
}
self.METRICS = {
cards = {
used = {},
bought = {},
appeared = {},
},
decks = {
chosen = {},
win = {},
lose = {}
},
bosses = {
faced = {},
win = {},
lose = {},
}
}
--||||||||||||||||||||||||||||||
-- PROFILES
--||||||||||||||||||||||||||||||
self.PROFILES = {
{},
{},
{},
}
--||||||||||||||||||||||||||||||
-- RENDER SCALE
--||||||||||||||||||||||||||||||
self.TILESIZE = 20
self.TILESCALE = 3.65
self.TILE_W = 20
self.TILE_H = 11.5
self.DRAW_HASH_BUFF = 2
self.CARD_W = 2.4*35/41
self.CARD_H = 2.4*47/41
self.HIGHLIGHT_H = 0.2*self.CARD_H
self.COLLISION_BUFFER = 0.05
self.PITCH_MOD = 1
--||||||||||||||||||||||||||||||
-- GAMESTATES
--||||||||||||||||||||||||||||||
self.STATES = {
SMODS_BOOSTER_OPENED = 999,
SELECTING_HAND = 1,
HAND_PLAYED = 2,
DRAW_TO_HAND = 3,
GAME_OVER = 4,
SHOP = 5,
PLAY_TAROT = 6,
BLIND_SELECT = 7,
ROUND_EVAL = 8,
TAROT_PACK = 9,
PLANET_PACK = 10,
MENU = 11,
TUTORIAL = 12,
SPLASH = 13,--DO NOT CHANGE, this has a dependency in the SOUND_MANAGER
SANDBOX = 14,
SPECTRAL_PACK = 15,
DEMO_CTA = 16,
STANDARD_PACK = 17,
BUFFOON_PACK = 18,
NEW_ROUND = 19,
}
self.STAGES = {
MAIN_MENU = 1,
RUN = 2,
SANDBOX = 3
}
self.STAGE_OBJECTS = {
{},{},{}
}
self.STAGE = self.STAGES.MAIN_MENU
self.STATE = self.STATES.SPLASH
self.TAROT_INTERRUPT = nil
self.STATE_COMPLETE = false
--||||||||||||||||||||||||||||||
-- INSTANCES
--||||||||||||||||||||||||||||||
self.ARGS = {}
self.FUNCS = {}
self.I = {
NODE = {},
MOVEABLE = {},
SPRITE = {},
UIBOX = {},
POPUP = {},
CARD = {},
CARDAREA = {},
ALERT = {}
}
self.ANIMATION_ATLAS = {}
self.ASSET_ATLAS = {}
self.MOVEABLES = {}
self.ANIMATIONS = {}
self.DRAW_HASH = {}
--||||||||||||||||||||||||||||||
-- CONSTANTS
--||||||||||||||||||||||||||||||
self.MIN_CLICK_DIST = 0.9
self.MIN_HOVER_TIME = 0.1
self.DEBUG = false
self.ANIMATION_FPS = 10
self.VIBRATION = 0
self.CHALLENGE_WINS = 5
--||||||||||||||||||||||||||||||
-- COLOURS
--||||||||||||||||||||||||||||||
self.C = {
MULT = HEX('FE5F55'),
CHIPS = HEX("009dff"),
MONEY = HEX('f3b958'),
XMULT = HEX('FE5F55'),
FILTER = HEX('ff9a00'),
BLUE = HEX("009dff"),
RED = HEX('FE5F55'),
GREEN = HEX("4BC292"),
PALE_GREEN = HEX("56a887"),
ORANGE = HEX("fda200"),
IMPORTANT = HEX("ff9a00"),
GOLD = HEX('eac058'),
YELLOW = {1,1,0,1},
CLEAR = {0, 0, 0, 0},
WHITE = {1,1,1,1},
PURPLE = HEX('8867a5'),
BLACK = HEX("374244"),--4f6367"),
L_BLACK = HEX("4f6367"),
GREY = HEX("5f7377"),
CHANCE = HEX("4BC292"),
JOKER_GREY = HEX('bfc7d5'),
VOUCHER = HEX("cb724c"),
BOOSTER = HEX("646eb7"),
EDITION = {1,1,1,1},
DARK_EDITION = {0,0,0,1},
ETERNAL = HEX('c75985'),
PERISHABLE = HEX('4f5da1'),
RENTAL = HEX('b18f43'),
DYN_UI = {
MAIN = HEX('374244'),
DARK = HEX('374244'),
BOSS_MAIN = HEX('374244'),
BOSS_DARK = HEX('374244'),
BOSS_PALE = HEX('374244')
},
--For other high contrast suit colours
SO_1 = {
Hearts = HEX('f03464'),
Diamonds = HEX('f06b3f'),
Spades = HEX("403995"),
Clubs = HEX("235955"),
},
SO_2 = {
Hearts = HEX('f83b2f'),
Diamonds = HEX('e29000'),
Spades = HEX("4f31b9"),
Clubs = HEX("008ee6"),
},
SUITS = {
Hearts = HEX('FE5F55'),
Diamonds = HEX('FE5F55'),
Spades = HEX("374649"),
Clubs = HEX("424e54"),
},
UI = {
TEXT_LIGHT = {1,1,1,1},
TEXT_DARK = HEX("4F6367"),
TEXT_INACTIVE = HEX("88888899"),
BACKGROUND_LIGHT = HEX("B8D8D8"),
BACKGROUND_WHITE = {1,1,1,1},
BACKGROUND_DARK = HEX("7A9E9F"),
BACKGROUND_INACTIVE = HEX("666666FF"),
OUTLINE_LIGHT = HEX("D8D8D8"),
OUTLINE_LIGHT_TRANS = HEX("D8D8D866"),
OUTLINE_DARK = HEX("7A9E9F"),
TRANSPARENT_LIGHT = HEX("eeeeee22"),
TRANSPARENT_DARK = HEX("22222222"),
HOVER = HEX('00000055'),
},
SET = {
Default = HEX("cdd9dc"),
Enhanced = HEX("cdd9dc"),
Joker = HEX('424e54'),
Tarot = HEX('424e54'),--HEX('29adff'),
Planet = HEX("424e54"),
Spectral = HEX('424e54'),
Voucher = HEX("424e54"),
},
SECONDARY_SET = {
Default = HEX("9bb6bdFF"),
Enhanced = HEX("8389DDFF"),
Joker = HEX('708b91'),
Tarot = HEX('a782d1'),--HEX('29adff'),
Planet = HEX('13afce'),
Spectral = HEX('4584fa'),
Voucher = HEX("fd682b"),
Edition = HEX("4ca893"),
},
RARITY = {
HEX('009dff'),--HEX("708b91"),
HEX("4BC292"),
HEX('fe5f55'),
HEX("b26cbb")
},
BLIND = {
Small = HEX("50846e"),
Big = HEX("50846e"),
Boss = HEX("b44430"),
won = HEX("4f6367")
},
HAND_LEVELS = {
HEX("efefef"),
HEX("95acff"),
HEX("65efaf"),
HEX('fae37e'),
HEX('ffc052'),
HEX('f87d75'),
HEX('caa0ef')
},
BACKGROUND = {
L = {1,1,0,1},
D = HEX("374244"),
C = HEX("374244"),
contrast = 1
}
}
G.C.HAND_LEVELS[0] = G.C.RED
G.C.UI_CHIPS = copy_table(G.C.BLUE)
G.C.UI_MULT = copy_table(G.C.RED)
--||||||||||||||||||||||||||||||
-- ENUMS
--||||||||||||||||||||||||||||||
self.UIT = {
T=1, --text
B=2, --box (can be rounded)
C=3, --column
R=4, --row
O=5, --object - must be a Node
ROOT=7,
S=8, --slider
I=9, --input text box
padding = 0, --default padding
}
self.handlist = {
"Flush Five",
"Flush House",
"Five of a Kind",
"Straight Flush",
"Four of a Kind",
"Full House",
"Flush",
"Straight",
"Three of a Kind",
"Two Pair",
"Pair",
"High Card",
}
self.button_mapping = {
a = G.F_SWAP_AB_BUTTONS and 'b' or nil,
b = G.F_SWAP_AB_BUTTONS and 'a' or nil,
y = G.F_SWAP_XY_BUTTONS and 'x' or nil,
x = G.F_SWAP_XY_BUTTONS and 'y' or nil,
}
self.keybind_mapping = {{
a = 'dpleft',
d = 'dpright',
w = 'dpup',
s = 'dpdown',
x = 'x',
c = 'y',
space = 'a',
shift = 'b',
esc = 'start',
q = 'triggerleft',
e = 'triggerright',
}}
end
G = Game()

File diff suppressed because it is too large Load diff

View file

@ -1,789 +0,0 @@
LOVELY_INTEGRITY = '28c37f9c0f5cf94954059dedc38a88cb0f1dbceb28b6a40c9df225d84bb10fe5'
--Class
Tag = Object:extend()
--Class Methods
function Tag:init(_tag, for_collection, _blind_type)
self.key = _tag
local proto = G.P_TAGS[_tag] or G.tag_undiscovered
self.config = copy_table(proto.config)
self.pos = proto.pos
self.name = proto.name
self.tally = G.GAME.tag_tally or 0
self.triggered = false
G.tagid = G.tagid or 0
self.ID = G.tagid
G.tagid = G.tagid + 1
self.ability = {
orbital_hand = '['..localize('k_poker_hand')..']',
blind_type = _blind_type
}
G.GAME.tag_tally = G.GAME.tag_tally and (G.GAME.tag_tally + 1) or 1
if not for_collection then self:set_ability() end
end
function Tag:nope()
G.E_MANAGER:add_event(Event({
delay = 0.2,
trigger = 'after',
func = (function()
attention_text({
text = 'NOPE',
colour = G.C.WHITE,
scale = 0.7,
hold = 0.3/G.SETTINGS.GAMESPEED,
cover = self.HUD_tag,
cover_colour = G.C.BLACK,
align = 'cm',
})
play_sound('cancel', 1.4, 0.5)
return true
end)
}))
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.1,
func = (function()
self.HUD_tag.states.visible = false
play_sound('cancel', 1.26, 0.5)
return true
end)
}))
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.5,
func = (function()
self:remove()
return true
end)
}))
end
function Tag:yep(message, _colour, func)
stop_use()
G.E_MANAGER:add_event(Event({
delay = 0.4,
trigger = 'after',
func = (function()
attention_text({
text = message,
colour = G.C.WHITE,
scale = 1,
hold = 0.3/G.SETTINGS.GAMESPEED,
cover = self.HUD_tag,
cover_colour = _colour or G.C.GREEN,
align = 'cm',
})
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
play_sound('holo1', 1.2 + math.random()*0.1, 0.4)
return true
end)
}))
G.E_MANAGER:add_event(Event({
func = (function()
self.HUD_tag.states.visible = false
return true
end)
}))
G.E_MANAGER:add_event(Event({
func = func
}))
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.7,
func = (function()
self:remove()
return true
end)
}))
end
function Tag:set_ability()
local obj = SMODS.Tags[self.key]
local res
if obj and obj.set_ability and type(obj.set_ability) == 'function' then
obj:set_ability(self)
end
if self.name == 'Orbital Tag' then
if G.orbital_hand then
self.ability.orbital_hand = G.orbital_hand
elseif self.ability.blind_type then
if G.GAME.orbital_choices and G.GAME.orbital_choices[G.GAME.round_resets.ante][self.ability.blind_type] then
self.ability.orbital_hand = G.GAME.orbital_choices[G.GAME.round_resets.ante][self.ability.blind_type]
end
end
end
end
function Tag:apply_to_run(_context)
if self.triggered then return end
local obj = SMODS.Tags[self.key]
local res
if obj and obj.apply and type(obj.apply) == 'function' then
res = obj:apply(self, _context)
end
if res then return res end
if not self.triggered and self.config.type == _context.type then
if _context.type == 'eval' then
if self.name == 'Investment Tag' and
G.GAME.last_blind and G.GAME.last_blind.boss then
self:yep('+', G.C.GOLD,function()
return true
end)
self.triggered = true
return {
dollars = self.config.dollars,
condition = localize('ph_defeat_the_boss'),
pos = self.pos,
tag = self
}
end
elseif _context.type == 'immediate' then
local lock = self.ID
G.CONTROLLER.locks[lock] = true
if self.name == 'Top-up Tag' then
self:yep('+', G.C.PURPLE,function()
for i = 1, self.config.spawn_jokers do
if G.jokers and #G.jokers.cards < G.jokers.config.card_limit then
local card = create_card('Joker', G.jokers, nil, 0, nil, nil, nil, 'top')
card:add_to_deck()
G.jokers:emplace(card)
end
end
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
return true
end
if self.name == 'Skip Tag' then
self:yep('+', G.C.MONEY,function()
G.CONTROLLER.locks[lock] = nil
return true
end)
ease_dollars((G.GAME.skips or 0)*self.config.skip_bonus)
self.triggered = true
return true
end
if self.name == 'Garbage Tag' then
self:yep('+', G.C.MONEY,function()
G.CONTROLLER.locks[lock] = nil
return true
end)
ease_dollars((G.GAME.unused_discards or 0)*self.config.dollars_per_discard)
self.triggered = true
return true
end
if self.name == 'Handy Tag' then
self:yep('+', G.C.MONEY,function()
G.CONTROLLER.locks[lock] = nil
return true
end)
ease_dollars((G.GAME.hands_played or 0)*self.config.dollars_per_hand)
self.triggered = true
return true
end
if self.name == 'Economy Tag' then
self:yep('+', G.C.MONEY,function()
G.CONTROLLER.locks[lock] = nil
return true
end)
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
ease_dollars(math.min(self.config.max, math.max(0,G.GAME.dollars)), true)
return true
end
}))
self.triggered = true
return true
end
if self.name == 'Orbital Tag' then
if (not self.ability.orbital_hand) or (not G.GAME.hands[self.ability.orbital_hand]) then
local _poker_hands = {}
for k, v in pairs(G.GAME.hands) do
if v.visible then _poker_hands[#_poker_hands+1] = k end
end
self.ability.orbital_hand = pseudorandom_element(_poker_hands, pseudoseed('orbital'))
end
update_hand_text({sound = 'button', volume = 0.7, pitch = 0.8, delay = 0.3}, {
handname= self.ability.orbital_hand,
chips = G.GAME.hands[self.ability.orbital_hand].chips,
mult = G.GAME.hands[self.ability.orbital_hand].mult,
level= G.GAME.hands[self.ability.orbital_hand].level})
level_up_hand(self, self.ability.orbital_hand, nil, self.config.levels)
update_hand_text({sound = 'button', volume = 0.7, pitch = 1.1, delay = 0}, {mult = 0, chips = 0, handname = '', level = ''})
self:yep('+', G.C.MONEY,function()
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
return true
end
elseif _context.type == 'new_blind_choice' then
local lock = self.ID
G.CONTROLLER.locks[lock] = true
if self.name == 'Charm Tag' then
self:yep('+', G.C.PURPLE,function()
local key = 'p_arcana_mega_'..(math.random(1,2))
local card = Card(G.play.T.x + G.play.T.w/2 - G.CARD_W*1.27/2,
G.play.T.y + G.play.T.h/2-G.CARD_H*1.27/2, G.CARD_W*1.27, G.CARD_H*1.27, G.P_CARDS.empty, G.P_CENTERS[key], {bypass_discovery_center = true, bypass_discovery_ui = true})
card.cost = 0
card.from_tag = true
G.FUNCS.use_card({config = {ref_table = card}})
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
return true
end
if self.name == 'Meteor Tag' then
self:yep('+', G.C.SECONDARY_SET.Planet,function()
local key = 'p_celestial_mega_'..(math.random(1,2))
local card = Card(G.play.T.x + G.play.T.w/2 - G.CARD_W*1.27/2,
G.play.T.y + G.play.T.h/2-G.CARD_H*1.27/2, G.CARD_W*1.27, G.CARD_H*1.27, G.P_CARDS.empty, G.P_CENTERS[key], {bypass_discovery_center = true, bypass_discovery_ui = true})
card.cost = 0
card.from_tag = true
G.FUNCS.use_card({config = {ref_table = card}})
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
return true
end
if self.name == 'Ethereal Tag' then
self:yep('+', G.C.SECONDARY_SET.Spectral,function()
local key = 'p_spectral_normal_1'
local card = Card(G.play.T.x + G.play.T.w/2 - G.CARD_W*1.27/2,
G.play.T.y + G.play.T.h/2-G.CARD_H*1.27/2, G.CARD_W*1.27, G.CARD_H*1.27, G.P_CARDS.empty, G.P_CENTERS[key], {bypass_discovery_center = true, bypass_discovery_ui = true})
card.cost = 0
card.from_tag = true
G.FUNCS.use_card({config = {ref_table = card}})
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
return true
end
if self.name == 'Standard Tag' then
self:yep('+', G.C.SECONDARY_SET.Spectral,function()
local key = 'p_standard_mega_1'
local card = Card(G.play.T.x + G.play.T.w/2 - G.CARD_W*1.27/2,
G.play.T.y + G.play.T.h/2-G.CARD_H*1.27/2, G.CARD_W*1.27, G.CARD_H*1.27, G.P_CARDS.empty, G.P_CENTERS[key], {bypass_discovery_center = true, bypass_discovery_ui = true})
card.cost = 0
card.from_tag = true
G.FUNCS.use_card({config = {ref_table = card}})
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
return true
end
if self.name == 'Buffoon Tag' then
self:yep('+', G.C.SECONDARY_SET.Spectral,function()
local key = 'p_buffoon_mega_1'
local card = Card(G.play.T.x + G.play.T.w/2 - G.CARD_W*1.27/2,
G.play.T.y + G.play.T.h/2-G.CARD_H*1.27/2, G.CARD_W*1.27, G.CARD_H*1.27, G.P_CARDS.empty, G.P_CENTERS[key], {bypass_discovery_center = true, bypass_discovery_ui = true})
card.cost = 0
card.from_tag = true
G.FUNCS.use_card({config = {ref_table = card}})
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
return true
end
if self.name == 'Boss Tag' then
local lock = self.ID
G.CONTROLLER.locks[lock] = true
self:yep('+', G.C.GREEN,function()
G.from_boss_tag = true
G.FUNCS.reroll_boss()
G.E_MANAGER:add_event(Event({func = function()
G.E_MANAGER:add_event(Event({func = function()
G.CONTROLLER.locks[lock] = nil
return true; end}))
return true; end}))
return true
end)
self.triggered = true
return true
end
elseif _context.type == 'voucher_add' then
if self.name == 'Voucher Tag' then
self:yep('+', G.C.SECONDARY_SET.Voucher,function()
G.ARGS.voucher_tag = G.ARGS.voucher_tag or {}
local voucher_key = get_next_voucher_key(true)
G.ARGS.voucher_tag[voucher_key] = true
G.shop_vouchers.config.card_limit = G.shop_vouchers.config.card_limit + 1
local card = Card(G.shop_vouchers.T.x + G.shop_vouchers.T.w/2,
G.shop_vouchers.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS[voucher_key],{bypass_discovery_center = true, bypass_discovery_ui = true})
cry_misprintize(card)
if G.GAME.events.ev_cry_choco2 then
card.misprint_cost_fac = (card.misprint_cost_fac or 1) * 2
card:set_cost()
end
create_shop_card_ui(card, 'Voucher', G.shop_vouchers)
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true)
end
if G.GAME.modifiers.cry_force_sticker == 'eternal' or G.GAME.modifiers.cry_sticker_sheet_plus then
card:set_eternal(true)
card.ability.eternal = true
end
if G.GAME.modifiers.cry_force_sticker == 'perishable' or G.GAME.modifiers.cry_sticker_sheet_plus then
card:set_perishable(true)
card.ability.perishable = true
end
if G.GAME.modifiers.cry_force_sticker == 'rental' or G.GAME.modifiers.cry_sticker_sheet_plus then
card:set_rental(true)
card.ability.rental = true
end
if G.GAME.modifiers.cry_force_sticker == 'pinned' or G.GAME.modifiers.cry_sticker_sheet_plus then
card.pinned = true
end
if G.GAME.modifiers.cry_force_sticker == 'banana' or G.GAME.modifiers.cry_sticker_sheet_plus then
card.ability.banana = true
end
if G.GAME.modifiers.cry_sticker_sheet_plus then
for k, v in pairs(SMODS.Stickers) do
if v.apply and not v.no_sticker_sheet then v:apply(card, true) end
end
end
G.shop_vouchers:emplace(card)
G.ARGS.voucher_tag = nil
return true
end)
self.triggered = true
end
elseif _context.type == 'tag_add' then
if self.name == 'Double Tag' and _context.tag.key ~= 'tag_double' then
local lock = self.ID
G.CONTROLLER.locks[lock] = true
self:yep('+', G.C.BLUE,function()
if _context.tag.ability and _context.tag.ability.orbital_hand then
G.orbital_hand = _context.tag.ability.orbital_hand
end
local tag = Tag(_context.tag.key)
if _context.tag.key == "tag_cry_rework" then
tag.ability.rework_edition = _context.tag.ability.rework_edition
tag.ability.rework_key = _context.tag.ability.rework_key
end
add_tag(tag)
G.orbital_hand = nil
G.CONTROLLER.locks[lock] = nil
return true
end)
self.triggered = true
end
elseif _context.type == 'round_start_bonus' then
if self.name == 'Juggle Tag' then
self:yep('+', G.C.BLUE,function()
return true
end)
G.hand:change_size(self.config.h_size)
G.GAME.round_resets.temp_handsize = (G.GAME.round_resets.temp_handsize or 0) + self.config.h_size
self.triggered = true
return true
end
elseif _context.type == 'store_joker_create' then
local card = nil
if self.name == 'Rare Tag' then
local rares_in_posession = {0}
for k, v in ipairs(G.jokers.cards) do
if v.config.center.rarity == 3 and not rares_in_posession[v.config.center.key] then
rares_in_posession[1] = rares_in_posession[1] + 1
rares_in_posession[v.config.center.key] = true
end
end
if #G.P_JOKER_RARITY_POOLS[3] > rares_in_posession[1] then
card = create_card('Joker', _context.area, nil, 1, nil, nil, nil, 'rta')
create_shop_card_ui(card, 'Joker', _context.area)
card.states.visible = false
self:yep('+', G.C.RED,function()
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
card.ability.couponed = true
card:set_cost()
return true
end)
else
self:nope()
end
self.triggered = true
elseif self.name == 'Uncommon Tag' then
card = create_card('Joker', _context.area, nil, 0.9, nil, nil, nil, 'uta')
create_shop_card_ui(card, 'Joker', _context.area)
card.states.visible = false
self:yep('+', G.C.GREEN,function()
if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
card:set_edition(nil, true, true)
elseif G.GAME.modifiers.cry_force_random_edition then
local edition = cry_poll_random_edition()
card:set_edition(edition, true, true)
end
card:start_materialize()
card.ability.couponed = true
card:set_cost()
return true
end)
end
self.triggered = true
return card
elseif _context.type == 'shop_start' then
if self.name == 'D6 Tag' and not G.GAME.shop_d6ed then
G.GAME.shop_d6ed = true
self:yep('+', G.C.GREEN,function()
G.GAME.round_resets.temp_reroll_cost = 0
calculate_reroll_cost(true)
return true
end)
self.triggered = true
return true
end
elseif _context.type == 'store_joker_modify' then
local _applied = nil
if not _context.card.edition and not _context.card.temp_edition and _context.card.ability.set == 'Joker' then
local lock = self.ID
G.CONTROLLER.locks[lock] = true
if self.name == 'Foil Tag' then
_context.card.temp_edition = true
self:yep('+', G.C.DARK_EDITION,function()
_context.card:set_edition({foil = true}, true)
_context.card.ability.couponed = true
_context.card:set_cost()
_context.card.temp_edition = nil
G.CONTROLLER.locks[lock] = nil
return true
end)
_applied = true
elseif self.name == 'Holographic Tag' then
_context.card.temp_edition = true
self:yep('+', G.C.DARK_EDITION,function()
_context.card.temp_edition = nil
_context.card:set_edition({holo = true}, true)
_context.card.ability.couponed = true
_context.card:set_cost()
G.CONTROLLER.locks[lock] = nil
return true
end)
_applied = true
elseif self.name == 'Polychrome Tag' then
_context.card.temp_edition = true
self:yep('+', G.C.DARK_EDITION,function()
_context.card.temp_edition = nil
_context.card:set_edition({polychrome = true}, true)
_context.card.ability.couponed = true
_context.card:set_cost()
G.CONTROLLER.locks[lock] = nil
return true
end)
_applied = true
elseif self.name == 'Negative Tag' then
_context.card.temp_edition = true
self:yep('+', G.C.DARK_EDITION,function()
_context.card.temp_edition = nil
_context.card:set_edition({negative = true}, true)
_context.card.ability.couponed = true
_context.card:set_cost()
G.CONTROLLER.locks[lock] = nil
return true
end)
_applied = true
end
self.triggered = true
end
return _applied
elseif _context.type == 'shop_final_pass' then
if self.name == 'Coupon Tag' and (G.shop and not G.GAME.shop_free) then
G.GAME.shop_free = true
self:yep('+', G.C.GREEN,function()
if G.shop_jokers and G.shop_booster then
for k, v in pairs(G.shop_jokers.cards) do
v.ability.couponed = true
v:set_cost()
end
for k, v in pairs(G.shop_booster.cards) do
v.ability.couponed = true
v:set_cost()
end
end
return true
end)
self.triggered = true
return true
end
end
end
end
function Tag:save()
return {
key = self.key,
tally = self.tally,
ability = self.ability
}
end
function Tag:load(tag_savetable)
self.key = tag_savetable.key
local proto = G.P_TAGS[self.key] or G.tag_undiscovered
self.config = copy_table(proto.config)
self.pos = proto.pos
self.name = proto.name
self.tally = tag_savetable.tally
self.ability = tag_savetable.ability
G.GAME.tag_tally = math.max(self.tally, G.GAME.tag_tally) + 1
end
function Tag:juice_up(_scale, _rot)
if self.tag_sprite then self.tag_sprite:juice_up(_scale, _rot) end
end
function Tag:generate_UI(_size)
_size = _size or 0.8
local tag_sprite_tab = nil
local tag_sprite = Sprite(0,0,_size*1,_size*1,G.ASSET_ATLAS[(not self.hide_ability) and G.P_TAGS[self.key].atlas or "tags"], (self.hide_ability) and G.tag_undiscovered.pos or self.pos)
tag_sprite.T.scale = 1
tag_sprite_tab = {n= G.UIT.C, config={align = "cm", ref_table = self, group = self.tally}, nodes={
{n=G.UIT.O, config={w=_size*1,h=_size*1, colour = G.C.BLUE, object = tag_sprite, focus_with_object = true}},
}}
tag_sprite:define_draw_steps({
{shader = 'dissolve', shadow_height = 0.05},
{shader = 'dissolve'},
})
tag_sprite.float = true
tag_sprite.states.hover.can = true
tag_sprite.states.drag.can = false
tag_sprite.states.collide.can = true
if self.key == 'tag_cry_cat' then tag_sprite.states.click.can = true; tag_sprite.states.drag.can = true end
tag_sprite.config = {tag = self, force_focus = true}
tag_sprite.hover = function(_self)
if not G.CONTROLLER.dragging.target or G.CONTROLLER.using_touch then
if not _self.hovering and _self.states.visible then
_self.hovering = true
if _self == tag_sprite then
_self.hover_tilt = 3
_self:juice_up(0.05, 0.02)
play_sound('paper1', math.random()*0.1 + 0.55, 0.42)
if self.key == 'tag_cry_cat' then
local rand = math.random(4)
play_sound('cry_meow'..rand, 1.26, 0.25)
end
play_sound('tarot2', math.random()*0.1 + 0.55, 0.09)
end
self:get_uibox_table(tag_sprite)
_self.config.h_popup = G.UIDEF.card_h_popup(_self)
_self.config.h_popup_config = (_self.T.x > G.ROOM.T.w*0.4) and
{align = 'cl', offset = {x=-0.1,y=0},parent = _self} or
{align = 'cr', offset = {x=0.1,y=0},parent = _self}
Node.hover(_self)
if _self.children.alert then
_self.children.alert:remove()
_self.children.alert = nil
if self.key and G.P_TAGS[self.key] then G.P_TAGS[self.key].alerted = true end
G:save_progress()
end
end
end
end
tag_sprite.stop_hover = function(_self) _self.hovering = false; Node.stop_hover(_self); _self.hover_tilt = 0 end
tag_sprite.click = function(_self)
if self.key == 'tag_cry_cat' and self.HUD_tag then
for i = 1, #G.GAME.tags do
local other_cat = G.GAME.tags[i]
if other_cat.key == 'tag_cry_cat' then
if not self.ability.level then self.ability.level = 1 end
if not other_cat.ability.level then other_cat.ability.level = 1 end -- setting ability just doesn't seem to be working... so you get this
if (self.ability.level == other_cat.ability.level) and (other_cat ~= self) and not cry_too_fast_kitty then
cry_too_fast_kitty = true
local perc = (other_cat.ability.level + 1)/10
if perc > 1 then perc = 1 end
G.E_MANAGER:add_event(Event({
delay = 0.0,
trigger = 'immediate',
func = (function()
attention_text({
text = ""..other_cat.ability.level,
colour = G.C.WHITE,
scale = 1,
hold = 0.3/G.SETTINGS.GAMESPEED,
cover = other_cat.HUD_tag,
cover_colour = G.C.DARK_EDITION,
align = 'cm',
})
play_sound('generic1', 0.8 + perc/2, 0.6)
play_sound('multhit1', 0.9 + perc/2, 0.4)
return true
end)
}))
G.E_MANAGER:add_event(Event({
delay = 0.0,
trigger = 'immediate',
func = (function()
attention_text({
text = "-",
colour = G.C.WHITE,
scale = 1,
hold = 0.3/G.SETTINGS.GAMESPEED,
cover = self.HUD_tag,
cover_colour = G.C.RED,
align = 'cm',
})
return true
end)
}))
G.E_MANAGER:add_event(Event({
func = (function()
self.HUD_tag.states.visible = false
return true
end)
}))
G.E_MANAGER:add_event(Event({ -- i have no idea what this does but i'm not messing with it
func = func
}))
other_cat.ability.level = other_cat.ability.level + 1
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.7,
func = (function()
self:remove()
cry_too_fast_kitty = nil
return true
end)
}))
break
end
end
end
end
end
tag_sprite:juice_up()
self.tag_sprite = tag_sprite
return tag_sprite_tab, tag_sprite
end
function Tag:get_uibox_table(tag_sprite)
tag_sprite = tag_sprite or self.tag_sprite
local name_to_check, loc_vars = self.name, {}
if name_to_check == 'Uncommon Tag' then
elseif name_to_check == 'Investment Tag' then loc_vars = {self.config.dollars}
elseif name_to_check == 'Handy Tag' then loc_vars = {self.config.dollars_per_hand, self.config.dollars_per_hand*(G.GAME.hands_played or 0)}
elseif name_to_check == 'Garbage Tag' then loc_vars = {self.config.dollars_per_discard, self.config.dollars_per_discard*(G.GAME.unused_discards or 0)}
elseif name_to_check == 'Juggle Tag' then loc_vars = {self.config.h_size}
elseif name_to_check == 'Top-up Tag' then loc_vars = {self.config.spawn_jokers}
elseif name_to_check == 'Skip Tag' then loc_vars = {self.config.skip_bonus, self.config.skip_bonus*((G.GAME.skips or 0)+1)}
elseif name_to_check == 'Orbital Tag' then loc_vars = {
(self.ability.orbital_hand == '['..localize('k_poker_hand')..']') and self.ability.orbital_hand or localize(self.ability.orbital_hand, 'poker_hands'), self.config.levels}
elseif name_to_check == 'Economy Tag' then loc_vars = {self.config.max}
elseif name_to_check == "cry-Rework Tag" then loc_vars = {
self.ability and self.ability.rework_edition and localize{type = "name_text", set = "Edition", key = self.ability.rework_edition} or "["..string.lower(localize("k_edition")).."]",
self.ability and self.ability.rework_key and localize{type = "name_text", set = "Joker", key = self.ability.rework_key} or "["..string.lower(localize("k_joker")).."]",
}
elseif name_to_check == "cry-Cat Tag" then loc_vars = {self.ability.level or 1}
end
tag_sprite.ability_UIBox_table = generate_card_ui(G.P_TAGS[self.key], nil, loc_vars, (self.hide_ability) and 'Undiscovered' or 'Tag', nil, (self.hide_ability), nil, nil, self)
return tag_sprite
end
function Tag:remove_from_game()
local tag_key = nil
for k, v in pairs(G.GAME.tags) do
if v == self then tag_key = k end
end
table.remove(G.GAME.tags, tag_key)
end
function Tag:remove()
self:remove_from_game()
local HUD_tag_key = nil
for k, v in pairs(G.HUD_tags) do
if v == self.HUD_tag then HUD_tag_key = k end
end
if HUD_tag_key then
if G.HUD_tags and G.HUD_tags[HUD_tag_key+1] then
if HUD_tag_key == 1 then
G.HUD_tags[HUD_tag_key+1]:set_alignment({type = 'bri',
offset = {x=0.7,y=0},
xy_bond = 'Weak',
major = G.ROOM_ATTACH})
else
G.HUD_tags[HUD_tag_key+1]:set_role({
xy_bond = 'Weak',
major = G.HUD_tags[HUD_tag_key-1]})
end
end
table.remove(G.HUD_tags, HUD_tag_key)
end
self.HUD_tag:remove()
end