Initial Commit - 1.0.0k
This commit is contained in:
commit
9d14fb1dcb
288
back.lua
Normal file
288
back.lua
Normal file
@ -0,0 +1,288 @@
|
||||
--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.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
|
||||
if not back_config.unlock_condition then
|
||||
localize{type = 'descriptions', key = 'demo_locked', set = "Other", nodes = loc_nodes, vars = loc_args}
|
||||
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 = {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 = {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 = {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
|
||||
if 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 = 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.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
|
||||
|
||||
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()
|
||||
|
||||
if self.effect.config.voucher then
|
||||
G.GAME.used_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.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
|
751
blind.lua
Normal file
751
blind.lua
Normal file
@ -0,0 +1,751 @@
|
||||
--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 = ''
|
||||
self.loc_debuff_lines[1] = ''
|
||||
self.loc_debuff_lines[2] = ''
|
||||
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 loc_target = localize{type = 'raw_descriptions', key = self.config.blind.key, set = 'Blind', vars = loc_vars or self.config.blind.vars}
|
||||
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 = ''
|
||||
for k, v in ipairs(loc_target) do
|
||||
self.loc_debuff_text = self.loc_debuff_text..v..(k <= #loc_target and ' ' or '')
|
||||
end
|
||||
self.loc_debuff_lines[1] = loc_target[1] or ''
|
||||
self.loc_debuff_lines[2] = loc_target[2] or ''
|
||||
else
|
||||
self.loc_name = ''; self.loc_debuff_text = ''
|
||||
self.loc_debuff_lines[1] = ''
|
||||
self.loc_debuff_lines[2] = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Blind:set_blind(blind, reset, silent)
|
||||
if not reset then
|
||||
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()
|
||||
|
||||
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
|
||||
|
||||
--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 = (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 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
|
||||
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
|
||||
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)
|
||||
|
||||
G.FUNCS.draw_from_deck_to_hand(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 G.GAME.chips - G.GAME.blind.chips >= 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
|
||||
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
|
||||
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
|
||||
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.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
|
||||
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 jokers = {}
|
||||
for i = 1, #G.jokers.cards do
|
||||
if not G.jokers.cards[i].debuff or #G.jokers.cards < 2 then jokers[#jokers+1] =G.jokers.cards[i] end
|
||||
G.jokers.cards[i]:set_debuff(false)
|
||||
end
|
||||
local _card = pseudorandom_element(jokers, pseudoseed('crimson_heart'))
|
||||
if _card then
|
||||
_card:set_debuff(true)
|
||||
_card:juice_up()
|
||||
self:wiggle()
|
||||
end
|
||||
end
|
||||
end
|
||||
self.prepped = nil
|
||||
end
|
||||
|
||||
function Blind:stay_flipped(area, card)
|
||||
if not self.disabled then
|
||||
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)
|
||||
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)
|
||||
return
|
||||
end
|
||||
if self.debuff.is_face =='face' and card:is_face(true) then
|
||||
card:set_debuff(true)
|
||||
return
|
||||
end
|
||||
if self.name == 'The Pillar' and card.ability.played_this_ante then
|
||||
card:set_debuff(true)
|
||||
return
|
||||
end
|
||||
if self.debuff.value and self.debuff.value == card.base.value then
|
||||
card:set_debuff(true)
|
||||
return
|
||||
end
|
||||
if self.debuff.nominal and self.debuff.nominal == card.base.nominal then
|
||||
card:set_debuff(true)
|
||||
return
|
||||
end
|
||||
end
|
||||
if self.name == 'Crimson Heart' and not self.disabled and card.area == G.jokers then
|
||||
return
|
||||
end
|
||||
if self.name == 'Verdant Leaf' and not self.disabled and card.area ~= G.jokers then card:set_debuff(true); 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 = {
|
||||
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.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 = (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
|
||||
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)
|
||||
G.HUD_blind.alignment.offset.y = 0
|
||||
end
|
||||
self:set_text()
|
||||
end
|
164
card_character.lua
Normal file
164
card_character.lua
Normal file
@ -0,0 +1,164 @@
|
||||
--class
|
||||
Card_Character = Moveable:extend()
|
||||
|
||||
--class methods
|
||||
function Card_Character:init(args)
|
||||
Moveable.init(self,args.x or 1, args.y or 1, args.w or G.CARD_W*1.1, args.h or G.CARD_H*1.1)
|
||||
|
||||
self.states.collide.can = false
|
||||
|
||||
self.children = {}
|
||||
self.config = {args = args}
|
||||
self.children.card = Card(self.T.x, self.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, args.center or G.P_CENTERS.j_joker, {bypass_discovery_center = true})
|
||||
self.children.card.states.visible = false
|
||||
self.children.card:start_materialize({G.C.BLUE, G.C.WHITE, G.C.RED})
|
||||
self.children.card:set_alignment{
|
||||
major = self, type = 'cm', offset = {x=0, y=0}
|
||||
}
|
||||
self.children.card.jimbo = self
|
||||
self.children.card.states.collide.can = true
|
||||
self.children.card.states.focus.can = false
|
||||
self.children.card.states.hover.can = true
|
||||
self.children.card.states.drag.can = false
|
||||
self.children.card.hover = Node.hover
|
||||
|
||||
self.children.particles = Particles(0, 0, 0,0, {
|
||||
timer = 0.03,
|
||||
scale = 0.3,
|
||||
speed = 1.2,
|
||||
lifespan = 2,
|
||||
attach = self,
|
||||
colours = {G.C.RED, G.C.BLUE, G.C.ORANGE},
|
||||
fill = true
|
||||
})
|
||||
self.children.particles.static_rotation = true
|
||||
self.children.particles:set_role{
|
||||
role_type = 'Minor',
|
||||
xy_bond = 'Weak',
|
||||
r_bond = 'Strong',
|
||||
major = self,
|
||||
}
|
||||
|
||||
if getmetatable(self) == Card_Character then
|
||||
table.insert(G.I.CARD, self)
|
||||
end
|
||||
end
|
||||
|
||||
function Card_Character:move(dt)
|
||||
Moveable.move(self, dt)
|
||||
end
|
||||
|
||||
function Card_Character:hard_set_VT()
|
||||
self:align_to_major()
|
||||
Moveable.hard_set_VT(self)
|
||||
self:align()
|
||||
self.children.card:hard_set_VT()
|
||||
end
|
||||
|
||||
function Card_Character:align()
|
||||
if self.children.card then
|
||||
self.children.card.T.x = self.T.x + (self.T.w - self.children.card.T.w)/2
|
||||
self.children.card.T.y = self.T.y + (self.T.h - self.children.card.T.h)/2
|
||||
end
|
||||
end
|
||||
|
||||
function Card_Character:add_button(button, func, colour, update_func, snap_to, yoff)
|
||||
if self.children.button then self.children.button:remove() end
|
||||
self.config.button_align = {align="bm", offset = {x=0,y=yoff or 0.3},major = self, parent = self}
|
||||
self.children.button = UIBox{
|
||||
definition = create_UIBox_character_button({button = button, func = func, colour = colour, update_func = update_func, maxw = 3}),
|
||||
config = self.config.button_align
|
||||
}
|
||||
if snap_to then G.CONTROLLER:snap_to{node = self.children.button} end
|
||||
end
|
||||
|
||||
function Card_Character:add_speech_bubble(text_key, align, loc_vars)
|
||||
if self.children.speech_bubble then self.children.speech_bubble:remove() end
|
||||
self.config.speech_bubble_align = {align=align or 'bm', offset = {x=0,y=0},parent = self}
|
||||
self.children.speech_bubble =
|
||||
UIBox{
|
||||
definition = G.UIDEF.speech_bubble(text_key, loc_vars),
|
||||
config = self.config.speech_bubble_align
|
||||
}
|
||||
self.children.speech_bubble:set_role{
|
||||
role_type = 'Minor',
|
||||
xy_bond = 'Weak',
|
||||
r_bond = 'Strong',
|
||||
major = self,
|
||||
}
|
||||
self.children.speech_bubble.states.visible = false
|
||||
end
|
||||
|
||||
function Card_Character:remove_button()
|
||||
if self.children.button then self.children.button:remove(); self.children.button = nil end
|
||||
end
|
||||
|
||||
function Card_Character:remove_speech_bubble()
|
||||
if self.children.speech_bubble then self.children.speech_bubble:remove(); self.children.speech_bubble = nil end
|
||||
end
|
||||
|
||||
function Card_Character:say_stuff(n, not_first)
|
||||
self.talking = true
|
||||
if not not_first then
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'after',
|
||||
delay = 0.1,
|
||||
func = function()
|
||||
if self.children.speech_bubble then self.children.speech_bubble.states.visible = true end
|
||||
self:say_stuff(n, true)
|
||||
return true
|
||||
end
|
||||
}))
|
||||
else
|
||||
if n <= 0 then self.talking = false; return end
|
||||
local new_said = math.random(1, 11)
|
||||
while new_said == self.last_said do
|
||||
new_said = math.random(1, 11)
|
||||
end
|
||||
self.last_said = new_said
|
||||
play_sound('voice'..math.random(1, 11), G.SPEEDFACTOR*(math.random()*0.2+1), 0.5)
|
||||
self.children.card:juice_up()
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'after',
|
||||
blockable = false, blocking = false,
|
||||
delay = 0.13,
|
||||
func = function()
|
||||
self:say_stuff(n-1, true)
|
||||
return true
|
||||
end
|
||||
}), 'tutorial')
|
||||
end
|
||||
end
|
||||
|
||||
function Card_Character:draw(dt)
|
||||
if self.highlight then
|
||||
self.children.highlight:draw()
|
||||
self.highlight:draw()
|
||||
if self.highlight.draw_children then self.highlight:draw_children() end
|
||||
end
|
||||
if self.children.particles then
|
||||
self.children.particles:draw()
|
||||
end
|
||||
if self.children.speech_bubble then
|
||||
self.children.speech_bubble:draw()
|
||||
end
|
||||
if self.children.button and not self.talking then
|
||||
self.children.button:draw()
|
||||
end
|
||||
if self.children.card then
|
||||
self.children.card:draw()
|
||||
end
|
||||
add_to_drawhash(self)
|
||||
self:draw_boundingrect()
|
||||
end
|
||||
|
||||
function Card_Character:remove()
|
||||
G.jimboed = nil
|
||||
remove_all(self.children)
|
||||
for k, v in pairs(G.I.CARD) do
|
||||
if v == self then
|
||||
table.remove(G.I.CARD, k)
|
||||
end
|
||||
end
|
||||
Moveable.remove(self)
|
||||
end
|
668
cardarea.lua
Normal file
668
cardarea.lua
Normal file
@ -0,0 +1,668 @@
|
||||
--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 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 location == 'front' or self.config.type == 'deck' then
|
||||
table.insert(self.cards, 1, card)
|
||||
else
|
||||
self.cards[#self.cards+1] = card
|
||||
end
|
||||
if 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
|
||||
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 = G.GAME.hands[text].mult, chips = 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 == '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 = 'DEFEAT', scale = 0.6, colour = G.C.WHITE}}
|
||||
}},
|
||||
{n=G.UIT.R, config={align = "cm"}, nodes={
|
||||
{n=G.UIT.T, config={text = 'BOSS BLIND', scale = 0.4, colour = G.C.WHITE}}
|
||||
}},
|
||||
{n=G.UIT.R, config={align = "cm"}, nodes={
|
||||
{n=G.UIT.T, config={text = '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()
|
||||
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 == 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 deck_height = (self.config.deck_height or 0.15)/52
|
||||
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 + 0.5*(self.T.w - card.T.w) + self.shadow_parrallax.x*deck_height*(#self.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*(#self.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
|
||||
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) 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)+ 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 + 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 < b.T.x + b.T.w/2 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) 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)+ 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 + 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 < b.T.x + b.T.w/2 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)+ 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 + 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 < b.T.x + b.T.w/2 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)+ 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 + 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 < b.T.x + b.T.w/2 end)
|
||||
end
|
||||
if 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)+ 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+ 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 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 == '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 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 < b.T.x + b.T.w/2 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
|
||||
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
|
729
challenges.lua
Normal file
729
challenges.lua
Normal file
@ -0,0 +1,729 @@
|
||||
G.CHALLENGES = {
|
||||
--[[{
|
||||
name = 'TEST',
|
||||
id = 'c_test_1',
|
||||
rules = {
|
||||
custom = {
|
||||
--{id = 'no_reward'},
|
||||
{id = 'no_reward_specific', value = 'Big'},
|
||||
{id = 'no_extra_hand_money'},
|
||||
{id = 'no_interest'},
|
||||
{id = 'daily'},
|
||||
{id = 'set_seed', value = 'SEEDEEDS'},
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'dollars', value = 100},
|
||||
{id = 'discards', value = 1},
|
||||
{id = 'hands', value = 6},
|
||||
{id = 'reroll_cost', value = 10},
|
||||
{id = 'joker_slots', value = 8},
|
||||
{id = 'consumable_slots', value = 3},
|
||||
{id = 'hand_size', value = 5},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg', edition = 'foil', eternal = true}
|
||||
},
|
||||
consumeables = {
|
||||
{id = 'c_sigil'}
|
||||
},
|
||||
vouchers = {
|
||||
{id = 'v_hieroglyph'},
|
||||
},
|
||||
deck = {
|
||||
--enhancement = 'm_glass',
|
||||
--edition = 'foil',
|
||||
--gold_seal = true,
|
||||
--yes_ranks = {['3'] = true,T = true},
|
||||
--no_ranks = {['4'] = true},
|
||||
--yes_suits = {S=true},
|
||||
--no_suits = {D=true},
|
||||
cards = {{s='D',r='2',e='m_glass',},{s='D',r='3',e='m_glass',},{s='D',r='4',e='m_glass',},{s='D',r='5',e='m_glass',},{s='D',r='6',e='m_glass',},{s='D',r='7',e='m_glass',},{s='D',r='8',e='m_glass',},{s='D',r='9',e='m_glass',},{s='D',r='T',e='m_glass',},{s='D',r='J',e='m_glass',},{s='D',r='Q',e='m_glass',},{s='D',r='K',e='m_glass',},{s='D',r='A',e='m_glass',},{s='C',r='2',e='m_glass',},{s='C',r='3',e='m_glass',},{s='C',r='4',e='m_glass',},{s='C',r='5',e='m_glass',},{s='C',r='6',e='m_glass',},{s='C',r='7',e='m_glass',},{s='C',r='8',e='m_glass',},{s='C',r='9',e='m_glass',},{s='C',r='T',e='m_glass',},{s='C',r='J',e='m_glass',},{s='C',r='Q',e='m_glass',},{s='C',r='K',e='m_glass',},{s='C',r='A',e='m_glass',},{s='H',r='2',e='m_glass',},{s='H',r='3',e='m_glass',},{s='H',r='4',e='m_glass',},{s='H',r='5',e='m_glass',},{s='H',r='6',e='m_glass',},{s='H',r='7',e='m_glass',},{s='H',r='8',e='m_glass',},{s='H',r='9',e='m_glass',},{s='H',r='T',e='m_glass',},{s='H',r='J',e='m_glass',},{s='H',r='Q',e='m_glass',},{s='H',r='K',e='m_glass',},{s='H',r='A',e='m_glass',},{s='S',r='2',e='m_glass',},{s='S',r='3',e='m_glass',},{s='S',r='4',e='m_glass',},{s='S',r='5',e='m_glass',},{s='S',r='6',e='m_glass',},{s='S',r='7',e='m_glass',},{s='S',r='8',e='m_glass',},{s='S',r='9',e='m_glass',},{s='S',r='T',e='m_glass',},{s='S',r='J',e='m_glass',},{s='S',r='Q',e='m_glass',},{s='S',r='K',e='m_glass',},{s='S',r='A',e='m_glass',},},
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'j_joker'},
|
||||
{id = 'j_egg'},
|
||||
},
|
||||
banned_tags = {
|
||||
{id = 'tag_garbage'},
|
||||
{id = 'tag_handy'},
|
||||
},
|
||||
banned_other = {
|
||||
|
||||
}
|
||||
}
|
||||
},]]--
|
||||
{
|
||||
name = 'The Omelette',
|
||||
id = 'c_omelette_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'no_reward'},
|
||||
{id = 'no_extra_hand_money'},
|
||||
{id = 'no_interest'}
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg'},
|
||||
{id = 'j_egg'},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'v_seed_money'},
|
||||
{id = 'v_money_tree'},
|
||||
{id = 'j_to_the_moon'},
|
||||
{id = 'j_rocket'},
|
||||
{id = 'j_golden'},
|
||||
{id = 'j_satellite'},
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "15 Minute City",
|
||||
id = 'c_city_1',
|
||||
rules = {
|
||||
custom = {
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_ride_the_bus', eternal = true},
|
||||
{id = 'j_shortcut', eternal = true},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
cards = {{s='D',r='4',},{s='D',r='5',},{s='D',r='6',},{s='D',r='7',},{s='D',r='8',},{s='D',r='9',},{s='D',r='T',},{s='D',r='J',},{s='D',r='Q',},{s='D',r='K',},{s='D',r='J',},{s='D',r='Q',},{s='D',r='K',},{s='C',r='4',},{s='C',r='5',},{s='C',r='6',},{s='C',r='7',},{s='C',r='8',},{s='C',r='9',},{s='C',r='T',},{s='C',r='J',},{s='C',r='Q',},{s='C',r='K',},{s='C',r='J',},{s='C',r='Q',},{s='C',r='K',},{s='H',r='4',},{s='H',r='5',},{s='H',r='6',},{s='H',r='7',},{s='H',r='8',},{s='H',r='9',},{s='H',r='T',},{s='H',r='J',},{s='H',r='Q',},{s='H',r='K',},{s='H',r='J',},{s='H',r='Q',},{s='H',r='K',},{s='S',r='4',},{s='S',r='5',},{s='S',r='6',},{s='S',r='7',},{s='S',r='8',},{s='S',r='9',},{s='S',r='T',},{s='S',r='J',},{s='S',r='Q',},{s='S',r='K',},{s='S',r='J',},{s='S',r='Q',},{s='S',r='K',}},
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Rich get Richer",
|
||||
id = 'c_rich_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'chips_dollar_cap'},
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'dollars', value = 100},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
{id = 'v_seed_money'},
|
||||
{id = 'v_money_tree'},
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "On a Knife's Edge",
|
||||
id = 'c_knife_1',
|
||||
rules = {
|
||||
custom = {
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_ceremonial', eternal = true, pinned = true},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "X-ray Vision",
|
||||
id = 'c_xray_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'flipped_cards', value = 4},
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Mad World",
|
||||
id = 'c_mad_world_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'no_extra_hand_money'},
|
||||
{id = 'no_interest'},
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_pareidolia', edition = 'negative', eternal = true},
|
||||
{id = 'j_business', eternal = true},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
cards = {{s='D',r='2',},{s='D',r='3',},{s='D',r='4',},{s='D',r='5',},{s='D',r='6',},{s='D',r='7',},{s='D',r='8',},{s='D',r='9',},{s='C',r='2',},{s='C',r='3',},{s='C',r='4',},{s='C',r='5',},{s='C',r='6',},{s='C',r='7',},{s='C',r='8',},{s='C',r='9',},{s='H',r='2',},{s='H',r='3',},{s='H',r='4',},{s='H',r='5',},{s='H',r='6',},{s='H',r='7',},{s='H',r='8',},{s='H',r='9',},{s='S',r='2',},{s='S',r='3',},{s='S',r='4',},{s='S',r='5',},{s='S',r='6',},{s='S',r='7',},{s='S',r='8',},{s='S',r='9',}},
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Luxury Tax",
|
||||
id = 'c_luxury_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'minus_hand_size_per_X_dollar', value = 5},
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'hand_size', value = 10},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Non-Perishable",
|
||||
id = 'c_non_perishable_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'all_eternal'},
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'j_gros_michel'},
|
||||
{id = 'j_ice_cream'},
|
||||
{id = 'j_cavendish'},
|
||||
{id = 'j_turtle_bean'},
|
||||
{id = 'j_ramen'},
|
||||
{id = 'j_diet_cola'},
|
||||
{id = 'j_selzer'},
|
||||
{id = 'j_popcorn'},
|
||||
{id = 'j_mr_bones'},
|
||||
{id = 'j_invisible'},
|
||||
{id = 'j_luchador'},
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Medusa",
|
||||
id = 'c_medusa_1',
|
||||
rules = {
|
||||
custom = {
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_marble', eternal = true},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck',
|
||||
cards = {{s='D',r='2',},{s='D',r='3',},{s='D',r='4',},{s='D',r='5',},{s='D',r='6',},{s='D',r='7',},{s='D',r='8',},{s='D',r='9',},{s='D',r='T',},{s='D',r='J',e='m_stone',},{s='D',r='Q',e='m_stone',},{s='D',r='K',e='m_stone',},{s='D',r='A',},{s='C',r='2',},{s='C',r='3',},{s='C',r='4',},{s='C',r='5',},{s='C',r='6',},{s='C',r='7',},{s='C',r='8',},{s='C',r='9',},{s='C',r='T',},{s='C',r='J',e='m_stone',},{s='C',r='Q',e='m_stone',},{s='C',r='K',e='m_stone',},{s='C',r='A',},{s='H',r='2',},{s='H',r='3',},{s='H',r='4',},{s='H',r='5',},{s='H',r='6',},{s='H',r='7',},{s='H',r='8',},{s='H',r='9',},{s='H',r='T',},{s='H',r='J',e='m_stone',},{s='H',r='Q',e='m_stone',},{s='H',r='K',e='m_stone',},{s='H',r='A',},{s='S',r='2',},{s='S',r='3',},{s='S',r='4',},{s='S',r='5',},{s='S',r='6',},{s='S',r='7',},{s='S',r='8',},{s='S',r='9',},{s='S',r='T',},{s='S',r='J',e='m_stone',},{s='S',r='Q',e='m_stone',},{s='S',r='K',e='m_stone',},{s='S',r='A',}, }
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Double or Nothing",
|
||||
id = 'c_double_nothing_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'debuff_played_cards'},
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck',
|
||||
cards = {{s='D',r='2',g='Red',},{s='D',r='3',g='Red',},{s='D',r='4',g='Red',},{s='D',r='5',g='Red',},{s='D',r='6',g='Red',},{s='D',r='7',g='Red',},{s='D',r='8',g='Red',},{s='D',r='9',g='Red',},{s='D',r='T',g='Red',},{s='D',r='J',g='Red',},{s='D',r='Q',g='Red',},{s='D',r='K',g='Red',},{s='D',r='A',g='Red',},{s='C',r='2',g='Red',},{s='C',r='3',g='Red',},{s='C',r='4',g='Red',},{s='C',r='5',g='Red',},{s='C',r='6',g='Red',},{s='C',r='7',g='Red',},{s='C',r='8',g='Red',},{s='C',r='9',g='Red',},{s='C',r='T',g='Red',},{s='C',r='J',g='Red',},{s='C',r='Q',g='Red',},{s='C',r='K',g='Red',},{s='C',r='A',g='Red',},{s='H',r='2',g='Red',},{s='H',r='3',g='Red',},{s='H',r='4',g='Red',},{s='H',r='5',g='Red',},{s='H',r='6',g='Red',},{s='H',r='7',g='Red',},{s='H',r='8',g='Red',},{s='H',r='9',g='Red',},{s='H',r='T',g='Red',},{s='H',r='J',g='Red',},{s='H',r='Q',g='Red',},{s='H',r='K',g='Red',},{s='H',r='A',g='Red',},{s='S',r='2',g='Red',},{s='S',r='3',g='Red',},{s='S',r='4',g='Red',},{s='S',r='5',g='Red',},{s='S',r='6',g='Red',},{s='S',r='7',g='Red',},{s='S',r='8',g='Red',},{s='S',r='9',g='Red',},{s='S',r='T',g='Red',},{s='S',r='J',g='Red',},{s='S',r='Q',g='Red',},{s='S',r='K',g='Red',},{s='S',r='A',g='Red',},}
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Typecast",
|
||||
id = 'c_typecast_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'set_eternal_ante', value = 4},
|
||||
{id = 'set_joker_slots_ante', value = 4},
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Inflation",
|
||||
id = 'c_inflation_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'inflation'},
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_credit_card'},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'v_clearance_sale'},
|
||||
{id = 'v_liquidation'},
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Bram Poker",
|
||||
id = 'c_bram_poker_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'no_shop_jokers'},
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_vampire', eternal = true},
|
||||
},
|
||||
consumeables = {
|
||||
{id = 'c_empress'},
|
||||
{id = 'c_emperor'},
|
||||
},
|
||||
vouchers = {
|
||||
{id = 'v_magic_trick'},
|
||||
{id = 'v_illusion'},
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck',
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Fragile",
|
||||
id = 'c_fragile_1',
|
||||
rules = {
|
||||
custom = {
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_oops', eternal = true, edition = 'negative'},
|
||||
{id = 'j_oops', eternal = true, edition = 'negative'},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
cards = {{s='D',r='2',e='m_glass',},{s='D',r='3',e='m_glass',},{s='D',r='4',e='m_glass',},{s='D',r='5',e='m_glass',},{s='D',r='6',e='m_glass',},{s='D',r='7',e='m_glass',},{s='D',r='8',e='m_glass',},{s='D',r='9',e='m_glass',},{s='D',r='T',e='m_glass',},{s='D',r='J',e='m_glass',},{s='D',r='Q',e='m_glass',},{s='D',r='K',e='m_glass',},{s='D',r='A',e='m_glass',},{s='C',r='2',e='m_glass',},{s='C',r='3',e='m_glass',},{s='C',r='4',e='m_glass',},{s='C',r='5',e='m_glass',},{s='C',r='6',e='m_glass',},{s='C',r='7',e='m_glass',},{s='C',r='8',e='m_glass',},{s='C',r='9',e='m_glass',},{s='C',r='T',e='m_glass',},{s='C',r='J',e='m_glass',},{s='C',r='Q',e='m_glass',},{s='C',r='K',e='m_glass',},{s='C',r='A',e='m_glass',},{s='H',r='2',e='m_glass',},{s='H',r='3',e='m_glass',},{s='H',r='4',e='m_glass',},{s='H',r='5',e='m_glass',},{s='H',r='6',e='m_glass',},{s='H',r='7',e='m_glass',},{s='H',r='8',e='m_glass',},{s='H',r='9',e='m_glass',},{s='H',r='T',e='m_glass',},{s='H',r='J',e='m_glass',},{s='H',r='Q',e='m_glass',},{s='H',r='K',e='m_glass',},{s='H',r='A',e='m_glass',},{s='S',r='2',e='m_glass',},{s='S',r='3',e='m_glass',},{s='S',r='4',e='m_glass',},{s='S',r='5',e='m_glass',},{s='S',r='6',e='m_glass',},{s='S',r='7',e='m_glass',},{s='S',r='8',e='m_glass',},{s='S',r='9',e='m_glass',},{s='S',r='T',e='m_glass',},{s='S',r='J',e='m_glass',},{s='S',r='Q',e='m_glass',},{s='S',r='K',e='m_glass',},{s='S',r='A',e='m_glass',},},
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'c_magician'},
|
||||
{id = 'c_empress'},
|
||||
{id = 'c_heirophant'},
|
||||
{id = 'c_chariot'},
|
||||
{id = 'c_devil'},
|
||||
{id = 'c_tower'},
|
||||
{id = 'c_lovers'},
|
||||
{id = 'c_incantation'},
|
||||
{id = 'c_grim'},
|
||||
{id = 'c_familiar'},
|
||||
{id = 'p_standard_normal_1', ids = {
|
||||
'p_standard_normal_1','p_standard_normal_2','p_standard_normal_3','p_standard_normal_4','p_standard_jumbo_1','p_standard_jumbo_2','p_standard_mega_1','p_standard_mega_2',
|
||||
}},
|
||||
{id = 'j_marble'},
|
||||
{id = 'j_vampire'},
|
||||
{id = 'j_midas_mask'},
|
||||
{id = 'j_certificate'},
|
||||
{id = 'v_magic_trick'},
|
||||
{id = 'v_illusion'},
|
||||
},
|
||||
banned_tags = {
|
||||
{id = 'tag_standard'},
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Monolith",
|
||||
id = 'c_monolith_1',
|
||||
rules = {
|
||||
custom = {
|
||||
},
|
||||
modifiers = {
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_obelisk', eternal = true},
|
||||
{id = 'j_marble', eternal = true, edition = 'negative'},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Blast Off",
|
||||
id = 'c_blast_off_1',
|
||||
rules = {
|
||||
custom = {
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'hands', value = 2},
|
||||
{id = 'discards', value = 2},
|
||||
{id = 'joker_slots', value = 4},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_constellation', eternal = true},
|
||||
{id = 'j_rocket', eternal = true},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
{id = 'v_planet_merchant'},
|
||||
{id = 'v_planet_tycoon'},
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'v_grabber'},
|
||||
{id = 'v_nacho_tong'},
|
||||
{id = 'j_burglar'},
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Five-Card Draw",
|
||||
id = 'c_five_card_1',
|
||||
rules = {
|
||||
custom = {
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'hand_size', value = 5},
|
||||
{id = 'joker_slots', value = 7},
|
||||
{id = 'discards', value = 6},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_card_sharp'},
|
||||
{id = 'j_joker'},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'j_juggler'},
|
||||
{id = 'j_troubadour'},
|
||||
{id = 'j_turtle_bean'},
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Golden Needle",
|
||||
id = 'c_golden_needle_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'discard_cost', value = 1},
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'hands', value = 1},
|
||||
{id = 'discards', value = 6},
|
||||
{id = 'dollars', value = 10},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
{id = 'j_credit_card'},
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'v_grabber'},
|
||||
{id = 'v_nacho_tong'},
|
||||
{id = 'j_burglar'},
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Cruelty",
|
||||
id = 'c_cruelty_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'no_reward_specific', value = 'Small'},
|
||||
{id = 'no_reward_specific', value = 'Big'},
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'joker_slots', value = 3},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
},
|
||||
banned_tags = {
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name = "Jokerless",
|
||||
id = 'c_jokerless_1',
|
||||
rules = {
|
||||
custom = {
|
||||
{id = 'no_shop_jokers'},
|
||||
},
|
||||
modifiers = {
|
||||
{id = 'joker_slots', value = 0},
|
||||
}
|
||||
},
|
||||
jokers = {
|
||||
},
|
||||
consumeables = {
|
||||
},
|
||||
vouchers = {
|
||||
},
|
||||
deck = {
|
||||
type = 'Challenge Deck'
|
||||
},
|
||||
restrictions = {
|
||||
banned_cards = {
|
||||
{id = 'c_judgement'},
|
||||
{id = 'c_wraith'},
|
||||
{id = 'c_soul'},
|
||||
{id = 'p_buffoon_normal_1', ids = {
|
||||
'p_buffoon_normal_1','p_buffoon_normal_2','p_buffoon_jumbo_1','p_buffoon_mega_1',
|
||||
}},
|
||||
},
|
||||
banned_tags = {
|
||||
{id = 'tag_rare'},
|
||||
{id = 'tag_uncommon'},
|
||||
{id = 'tag_holo'},
|
||||
{id = 'tag_polychrome'},
|
||||
{id = 'tag_negative'},
|
||||
{id = 'tag_foil'},
|
||||
{id = 'tag_buffoon'},
|
||||
},
|
||||
banned_other = {
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
11
conf.lua
Normal file
11
conf.lua
Normal file
@ -0,0 +1,11 @@
|
||||
_RELEASE_MODE = true
|
||||
_DEMO = false
|
||||
|
||||
function love.conf(t)
|
||||
t.console = not _RELEASE_MODE
|
||||
t.title = 'Balatro'
|
||||
t.window.width = 0
|
||||
t.window.height = 0
|
||||
t.window.minwidth = 100
|
||||
t.window.minheight = 100
|
||||
end
|
107
engine/animatedsprite.lua
Normal file
107
engine/animatedsprite.lua
Normal file
@ -0,0 +1,107 @@
|
||||
--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 _, v in pairs(G.ANIMATIONS) do
|
||||
if v == self then
|
||||
table.remove(G.ANIMATIONS, k)
|
||||
end
|
||||
end
|
||||
for _, v in pairs(G.I.SPRITE) do
|
||||
if v == self then
|
||||
table.remove(G.I.SPRITE, k)
|
||||
end
|
||||
end
|
||||
Sprite.remove(self)
|
||||
end
|
1380
engine/controller.lua
Normal file
1380
engine/controller.lua
Normal file
File diff suppressed because it is too large
Load Diff
195
engine/event.lua
Normal file
195
engine/event.lua
Normal file
@ -0,0 +1,195 @@
|
||||
--Class
|
||||
Event = Object:extend()
|
||||
|
||||
--Class Methods
|
||||
function Event:init(config)
|
||||
self.trigger = config.trigger or 'immediate'
|
||||
if config.blocking ~= nil then
|
||||
self.blocking = config.blocking
|
||||
else
|
||||
self.blocking = true
|
||||
end
|
||||
if config.blockable ~= nil then
|
||||
self.blockable = config.blockable
|
||||
else
|
||||
self.blockable = true
|
||||
end
|
||||
self.complete = false
|
||||
self.start_timer = config.start_timer or false
|
||||
self.func = config.func or function() return true end
|
||||
self.delay = config.delay or 0
|
||||
self.no_delete = config.no_delete
|
||||
self.created_on_pause = config.pause_force or G.SETTINGS.paused
|
||||
self.timer = config.timer or (self.created_on_pause and 'REAL') or 'TOTAL'
|
||||
|
||||
if self.trigger == 'ease' then
|
||||
self.ease = {
|
||||
type = config.ease or 'lerp',
|
||||
ref_table = config.ref_table,
|
||||
ref_value = config.ref_value,
|
||||
start_val = config.ref_table[config.ref_value],
|
||||
end_val = config.ease_to,
|
||||
start_time = nil,
|
||||
end_time = nil,
|
||||
}
|
||||
self.func = config.func or function(t) return t end
|
||||
end
|
||||
if self.trigger == 'condition' then
|
||||
self.condition = {
|
||||
ref_table = config.ref_table,
|
||||
ref_value = config.ref_value,
|
||||
stop_val = config.stop_val,
|
||||
}
|
||||
self.func = config.func or function() return self.condition.ref_table[self.condition.ref_value] == self.condition.stop_val end
|
||||
end
|
||||
self.time = G.TIMERS[self.timer]
|
||||
end
|
||||
|
||||
function Event:handle(_results)
|
||||
_results.blocking, _results.completed = self.blocking, self.complete
|
||||
if self.created_on_pause == false and G.SETTINGS.paused then _results.pause_skip = true; return end
|
||||
if not self.start_timer then self.time = G.TIMERS[self.timer]; self.start_timer = true end
|
||||
if self.trigger == 'after' then
|
||||
if self.time + self.delay <= G.TIMERS[self.timer] then
|
||||
_results.time_done = true
|
||||
_results.completed = self.func()
|
||||
end
|
||||
end
|
||||
if self.trigger == 'ease' then
|
||||
if not self.ease.start_time then
|
||||
self.ease.start_time = G.TIMERS[self.timer]
|
||||
self.ease.end_time = G.TIMERS[self.timer] + self.delay
|
||||
self.ease.start_val = self.ease.ref_table[self.ease.ref_value]
|
||||
end
|
||||
if not self.complete then
|
||||
|
||||
if self.ease.end_time >= G.TIMERS[self.timer] then
|
||||
local percent_done = ((self.ease.end_time - G.TIMERS[self.timer])/(self.ease.end_time - self.ease.start_time))
|
||||
|
||||
if self.ease.type == 'lerp' then
|
||||
self.ease.ref_table[self.ease.ref_value] = self.func(percent_done*self.ease.start_val + (1-percent_done)*self.ease.end_val)
|
||||
end
|
||||
if self.ease.type == 'elastic' then
|
||||
percent_done = -math.pow(2, 10 * percent_done - 10) * math.sin((percent_done * 10 - 10.75) * 2*math.pi/3);
|
||||
self.ease.ref_table[self.ease.ref_value] = self.func(percent_done*self.ease.start_val + (1-percent_done)*self.ease.end_val)
|
||||
end
|
||||
if self.ease.type == 'quad' then
|
||||
percent_done = percent_done * percent_done;
|
||||
self.ease.ref_table[self.ease.ref_value] = self.func(percent_done*self.ease.start_val + (1-percent_done)*self.ease.end_val)
|
||||
end
|
||||
else
|
||||
self.ease.ref_table[self.ease.ref_value] = self.func(self.ease.end_val)
|
||||
self.complete = true
|
||||
_results.completed = true
|
||||
_results.time_done = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.trigger == 'condition' then
|
||||
if not self.complete then _results.completed = self.func() end
|
||||
_results.time_done = true
|
||||
end
|
||||
if self.trigger == 'before' then
|
||||
if not self.complete then _results.completed = self.func() end
|
||||
if self.time + self.delay <= G.TIMERS[self.timer] then
|
||||
_results.time_done = true
|
||||
end
|
||||
end
|
||||
if self.trigger == 'immediate' then
|
||||
_results.completed = self.func()
|
||||
_results.time_done = true
|
||||
end
|
||||
if _results.completed then self.complete = true end
|
||||
end
|
||||
|
||||
--Class
|
||||
EventManager = Object:extend()
|
||||
|
||||
--Class Methods
|
||||
function EventManager:init()
|
||||
self.queues = {
|
||||
unlock = {},
|
||||
base ={},
|
||||
tutorial = {},
|
||||
achievement = {},
|
||||
other = {}
|
||||
}
|
||||
self.queue_timer = G.TIMERS.REAL
|
||||
self.queue_dt = 1/60
|
||||
self.queue_last_processed = G.TIMERS.REAL
|
||||
end
|
||||
|
||||
function EventManager:add_event(event, queue, front)
|
||||
queue = queue or 'base'
|
||||
if event:is(Event) then
|
||||
if front then
|
||||
table.insert(self.queues[queue], 1, event)
|
||||
else
|
||||
self.queues[queue][#self.queues[queue]+1] = event
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function EventManager:clear_queue(queue, exception)
|
||||
if not queue then
|
||||
--clear all queues
|
||||
for k, v in pairs(self.queues) do
|
||||
local i=1
|
||||
while i <= #v do
|
||||
if not v[i].no_delete then
|
||||
table.remove(v, i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif exception then --clear all but exception
|
||||
for k, v in pairs(self.queues) do
|
||||
if k ~= exception then
|
||||
local i=1
|
||||
while i <= #v do
|
||||
if not v[i].no_delete then
|
||||
table.remove(v, i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local i=1
|
||||
while i <= #self.queues[queue] do
|
||||
if not self.queues[queue][i].no_delete then
|
||||
table.remove(self.queues[queue], i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function EventManager:update(dt, forced)
|
||||
self.queue_timer = self.queue_timer+dt
|
||||
if self.queue_timer >= self.queue_last_processed + self.queue_dt or forced then
|
||||
self.queue_last_processed = self.queue_last_processed + (forced and 0 or self.queue_dt)
|
||||
for k, v in pairs(self.queues) do
|
||||
local blocked = false
|
||||
local i=1
|
||||
while i <= #v do
|
||||
G.ARGS.event_manager_update = G.ARGS.event_manager_update or {}
|
||||
local results = G.ARGS.event_manager_update
|
||||
results.blocking, results.completed, results.time_done, results.pause_skip = false, false, false, false
|
||||
if (not blocked or not v[i].blockable) then v[i]:handle(results) end
|
||||
if results.pause_skip then
|
||||
i = i + 1
|
||||
else if not blocked and results.blocking then blocked = true end
|
||||
if results.completed and results.time_done then
|
||||
table.remove(v, i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
23
engine/http_manager.lua
Normal file
23
engine/http_manager.lua
Normal file
@ -0,0 +1,23 @@
|
||||
require "love.system"
|
||||
|
||||
HTTPS = require('https')
|
||||
local httpencode = function(str)
|
||||
str = str..''
|
||||
local char_to_hex = function(c)
|
||||
return string.format("%%%02X", string.byte(c))
|
||||
end
|
||||
str = str:gsub("\n", "\r\n"):gsub("([^%w _%%%-%.~])", char_to_hex):gsub(" ", "+")
|
||||
return str
|
||||
end
|
||||
|
||||
if (love.system.getOS() == 'OS X' )and (jit.arch == 'arm64' or jit.arch == 'arm' or true) then jit.off() end
|
||||
|
||||
IN_CHANNEL = love.thread.getChannel("http_request")
|
||||
OUT_CHANNEL = love.thread.getChannel("http_response")
|
||||
|
||||
while true do
|
||||
--Monitor the channel for any new requests
|
||||
local request = IN_CHANNEL:demand() -- Value from channel
|
||||
if request then
|
||||
end
|
||||
end
|
502
engine/moveable.lua
Normal file
502
engine/moveable.lua
Normal file
@ -0,0 +1,502 @@
|
||||
---@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
|
||||
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 self.alignment.prev_offset.x == self.alignment.offset.x and
|
||||
self.alignment.prev_offset.y == self.alignment.offset.y and
|
||||
self.alignment.prev_type == self.alignment.type 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)
|
||||
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.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
|
||||
self.NEW_ALIGNMENT = false
|
||||
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
|
||||
|
||||
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 not MWM then
|
||||
MWM = {
|
||||
rotated_offset = {},
|
||||
angles = {},
|
||||
WH = {},
|
||||
offs = {},
|
||||
}
|
||||
end
|
||||
|
||||
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 (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 = EMPTY(self.FRAME.MAJOR)
|
||||
local major = self.role.major:get_major()
|
||||
self.FRAME.MAJOR.major = major.major
|
||||
self.FRAME.MAJOR.offset = self.FRAME.MAJOR.offset or {}
|
||||
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 ipairs(G.MOVEABLES) do
|
||||
if v == self then
|
||||
table.remove(G.MOVEABLES, k)
|
||||
end
|
||||
end
|
||||
for k, v in ipairs(G.I.MOVEABLE) do
|
||||
if v == self then
|
||||
table.remove(G.I.MOVEABLE, k)
|
||||
end
|
||||
end
|
||||
Node.remove(self)
|
||||
end
|
389
engine/node.lua
Normal file
389
engine/node.lua
Normal file
@ -0,0 +1,389 @@
|
||||
---@class Node
|
||||
Node = Object:extend()
|
||||
|
||||
--Node represent any game object that needs to have some transform available in the game itself.\
|
||||
--Everything that you see in the game is a Node, and some invisible things like the G.ROOM are also\
|
||||
--represented here.
|
||||
--
|
||||
---@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 Node:init(args)
|
||||
--From args, set the values of self transform
|
||||
args = args or {}
|
||||
args.T = args.T or {}
|
||||
|
||||
--Store all argument and return tables here for reuse, because Lua likes to generate garbage
|
||||
self.ARGS = self.ARGS or {}
|
||||
self.RETS = {}
|
||||
|
||||
--Config table used for any metadata about this node
|
||||
self.config = self.config or {}
|
||||
|
||||
--For transform init, accept params in the form x|1, y|2, w|3, h|4, r|5
|
||||
self.T = {
|
||||
x = args.T.x or args.T[1] or 0,
|
||||
y = args.T.y or args.T[2] or 0,
|
||||
w = args.T.w or args.T[3] or 1,
|
||||
h = args.T.h or args.T[4] or 1,
|
||||
r = args.T.r or args.T[5] or 0,
|
||||
scale = args.T.scale or args.T[6] or 1,
|
||||
}
|
||||
--Transform to use for collision detection
|
||||
self.CT = self.T
|
||||
|
||||
--Create the offset tables, used to determine things like drag offset and 3d shader effects
|
||||
self.click_offset = {x = 0, y = 0}
|
||||
self.hover_offset = {x = 0, y = 0}
|
||||
|
||||
--To keep track of all nodes created on pause. If true, this node moves normally even when the G.TIMERS.TOTAL doesn't increment
|
||||
self.created_on_pause = G.SETTINGS.paused
|
||||
|
||||
--ID tracker, every Node has a unique ID
|
||||
G.ID = G.ID or 1
|
||||
self.ID = G.ID
|
||||
G.ID = G.ID + 1
|
||||
|
||||
--Frame tracker to aid in not doing too many extra calculations
|
||||
self.FRAME = {
|
||||
DRAW = -1,
|
||||
MOVE = -1
|
||||
}
|
||||
|
||||
--The states for this Node and all derived nodes. This is how we control the visibility and interactibility of any object
|
||||
--All nodes do not collide by default. This reduces the size of n for the O(n^2) collision detection
|
||||
self.states = {
|
||||
visible = true,
|
||||
collide = {can = false, is = false},
|
||||
focus = {can = false, is = false},
|
||||
hover = {can = true, is = false},
|
||||
click = {can = true, is = false},
|
||||
drag = {can = true, is = false},
|
||||
release_on = {can = true, is = false}
|
||||
}
|
||||
|
||||
--If we provide a container, all nodes within that container are translated with that container as the reference frame.
|
||||
--For example, if G.ROOM is set at x = 5 and y = 5, and we create a new game object at 0, 0, it will actually be drawn at
|
||||
--5, 5. This allows us to control things like screen shake, room positioning, rotation, padding, etc. without needing to modify
|
||||
--every game object that we need to draw
|
||||
self.container = args.container or G.ROOM
|
||||
|
||||
--The list of children give Node a treelike structure. This can be used for things like drawing, deterministice movement and parallax
|
||||
--calculations when child nodes rely on updated information from parents, and inherited attributes like button click functions
|
||||
if not self.children then
|
||||
self.children = {}
|
||||
end
|
||||
|
||||
--Add this object to the appropriate instance table only if the metatable matches with NODE
|
||||
if getmetatable(self) == Node then
|
||||
table.insert(G.I.NODE, self)
|
||||
end
|
||||
|
||||
--Unless node was created during a stage transition (when G.STAGE_OBJECT_INTERRUPT is true), add all nodes to their appropriate
|
||||
--stage object table so they can be easily deleted on stage transition
|
||||
if not G.STAGE_OBJECT_INTERRUPT then
|
||||
table.insert(G.STAGE_OBJECTS[G.STAGE], self)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--Draw a bounding rectangle representing the transform of this node. Used in debugging.
|
||||
function Node:draw_boundingrect()
|
||||
self.under_overlay = G.under_overlay
|
||||
|
||||
if G.DEBUG then
|
||||
local transform = self.VT or self.T
|
||||
love.graphics.push()
|
||||
love.graphics.scale(G.TILESCALE, G.TILESCALE)
|
||||
love.graphics.translate(transform.x*G.TILESIZE+transform.w*G.TILESIZE*0.5,
|
||||
transform.y*G.TILESIZE+transform.h*G.TILESIZE*0.5)
|
||||
love.graphics.rotate(transform.r)
|
||||
love.graphics.translate(-transform.w*G.TILESIZE*0.5,
|
||||
-transform.h*G.TILESIZE*0.5)
|
||||
if self.DEBUG_VALUE then
|
||||
love.graphics.setColor(1, 1, 0, 1)
|
||||
love.graphics.print((self.DEBUG_VALUE or ''), transform.w*G.TILESIZE,transform.h*G.TILESIZE, nil, 1/G.TILESCALE)
|
||||
end
|
||||
love.graphics.setLineWidth(1 + (self.states.focus.is and 1 or 0))
|
||||
if self.states.collide.is then
|
||||
love.graphics.setColor(0, 1, 0, 0.3)
|
||||
else
|
||||
love.graphics.setColor(1, 0, 0, 0.3)
|
||||
end
|
||||
if self.states.focus.can then
|
||||
love.graphics.setColor(G.C.GOLD)
|
||||
love.graphics.setLineWidth(1)
|
||||
end
|
||||
if self.CALCING then
|
||||
love.graphics.setColor({0,0,1,1})
|
||||
love.graphics.setLineWidth(3)
|
||||
end
|
||||
love.graphics.rectangle('line', 0, 0, transform.w*G.TILESIZE,transform.h*G.TILESIZE, 3)
|
||||
love.graphics.pop()
|
||||
end
|
||||
end
|
||||
|
||||
--Draws self, then adds self the the draw hash, then draws all children
|
||||
function Node:draw()
|
||||
self:draw_boundingrect()
|
||||
if self.states.visible then
|
||||
add_to_drawhash(self)
|
||||
for _, v in pairs(self.children) do
|
||||
v:draw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Determines if this node collides with some point. Applies any container translations and rotations, then\
|
||||
--applies translations and rotations specific to this node. This means the collision detection effectively\
|
||||
--determines if some point intersects this node regargless of rotation.
|
||||
--
|
||||
---@param point {x: number, y: number}
|
||||
--**x and y** The coordinates of the cursor transformed into game units
|
||||
function Node:collides_with_point(point)
|
||||
--First reset the collision state to false
|
||||
if self.container then
|
||||
local T = self.CT or self.T
|
||||
self.ARGS.collides_with_point_point = self.ARGS.collides_with_point_point or {}
|
||||
self.ARGS.collides_with_point_translation = self.ARGS.collides_with_point_translation or {}
|
||||
self.ARGS.collides_with_point_rotation = self.ARGS.collides_with_point_rotation or {}
|
||||
local _p = self.ARGS.collides_with_point_point
|
||||
local _t = self.ARGS.collides_with_point_translation
|
||||
local _r = self.ARGS.collides_with_point_rotation
|
||||
|
||||
local _b = self.states.hover.is and G.COLLISION_BUFFER or 0
|
||||
|
||||
_p.x, _p.y = point.x, point.y
|
||||
|
||||
if self.container ~= self then --if there is some valid container, we need to apply all translations and rotations for the container first
|
||||
if math.abs(self.container.T.r) < 0.1 then
|
||||
--Translate to normalize this Node to the center of the container
|
||||
_t.x, _t.y = -self.container.T.w/2, -self.container.T.h/2
|
||||
point_translate(_p, _t)
|
||||
|
||||
--Rotate node about the center of the container
|
||||
point_rotate(_p, self.container.T.r)
|
||||
|
||||
--Translate node to undo the container translation, essentially reframing it in 'container' space
|
||||
_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)
|
||||
else
|
||||
--Translate node to undo the container translation, essentially reframing it in 'container' space
|
||||
_t.x, _t.y = -self.container.T.x, -self.container.T.y
|
||||
point_translate(_p, _t)
|
||||
end
|
||||
end
|
||||
if math.abs(T.r) < 0.1 then
|
||||
--If we can essentially disregard transform rotation, just treat it like a normal rectangle
|
||||
if _p.x >= T.x - _b and _p.y >= T.y - _b and _p.x <= T.x + T.w + _b and _p.y <= T.y + T.h + _b then
|
||||
return true
|
||||
end
|
||||
else
|
||||
--Otherwise we need to do some silly point rotation garbage to determine if the point intersects the rotated rectangle
|
||||
_r.cos, _r.sin = math.cos(T.r+math.pi/2), math.sin(T.r+math.pi/2)
|
||||
_p.x, _p.y = _p.x - (T.x + 0.5*(T.w)), _p.y - (T.y + 0.5*(T.h))
|
||||
_t.x, _t.y = _p.y*_r.cos - _p.x*_r.sin, _p.y*_r.sin + _p.x*_r.cos
|
||||
_p.x, _p.y = _t.x + (T.x + 0.5*(T.w)), _t.y + (T.y + 0.5*(T.h))
|
||||
|
||||
if _p.x >= T.x - _b and _p.y >= T.y - _b
|
||||
and _p.x <= T.x + T.w + _b and _p.y <= T.y + T.h + _b then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Sets the offset of passed point in terms of this nodes T.x and T.y
|
||||
--
|
||||
---@param point {x: number, y: number}
|
||||
---@param type string
|
||||
--**x and y** The coordinates of the cursor transformed into game units
|
||||
--**type** the type of offset to set for this Node, either 'Click' or 'Hover'
|
||||
function Node:set_offset(point, type)
|
||||
self.ARGS.set_offset_point = self.ARGS.set_offset_point or {}
|
||||
self.ARGS.set_offset_translation = self.ARGS.set_offset_translation or {}
|
||||
local _p = self.ARGS.set_offset_point
|
||||
local _t = self.ARGS.set_offset_translation
|
||||
|
||||
_p.x, _p.y = point.x, point.y
|
||||
|
||||
--Translate to middle of the container
|
||||
_t.x = -self.container.T.w/2
|
||||
_t.y = -self.container.T.h/2
|
||||
point_translate(_p, _t)
|
||||
|
||||
--Rotate about the container midpoint according to node rotation
|
||||
point_rotate(_p, self.container.T.r)
|
||||
|
||||
--Translate node to undo the container translation, essentially reframing it in 'container' space
|
||||
_t.x = self.container.T.w/2-self.container.T.x
|
||||
_t.y = self.container.T.h/2-self.container.T.y
|
||||
point_translate(_p, _t)
|
||||
|
||||
if type == 'Click' then
|
||||
self.click_offset.x = (_p.x - self.T.x)
|
||||
self.click_offset.y = (_p.y - self.T.y)
|
||||
elseif type == 'Hover' then
|
||||
self.hover_offset.x = (_p.x - self.T.x)
|
||||
self.hover_offset.y = (_p.y - self.T.y)
|
||||
end
|
||||
end
|
||||
|
||||
--If the current container is being 'Dragged', usually by a cursor, determine if any drag popups need to be generated and do so
|
||||
function Node:drag()
|
||||
if self.config and self.config.d_popup then
|
||||
if not self.children.d_popup then
|
||||
self.children.d_popup = UIBox{
|
||||
definition = self.config.d_popup,
|
||||
config = self.config.d_popup_config
|
||||
}
|
||||
self.children.h_popup.states.collide.can = false
|
||||
table.insert(G.I.POPUP, self.children.d_popup)
|
||||
self.children.d_popup.states.drag.can = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Determines if this Node can be dragged. This is a simple function but more complex objects may redefine this to return a parent\
|
||||
--if the parent needs to drag other children with it
|
||||
function Node:can_drag()
|
||||
return self.states.drag.can and self or nil
|
||||
end
|
||||
|
||||
--Called by the CONTROLLER when this node is no longer being dragged, removes any d_popups
|
||||
function Node:stop_drag()
|
||||
if self.children.d_popup then
|
||||
for k, v in pairs(G.I.POPUP) do
|
||||
if v == self.children.d_popup then
|
||||
table.remove(G.I.POPUP, k)
|
||||
end
|
||||
end
|
||||
self.children.d_popup:remove()
|
||||
self.children.d_popup = nil
|
||||
end
|
||||
end
|
||||
|
||||
--If the current container is being 'Hovered', usually by a cursor, determine if any hover popups need to be generated and do so
|
||||
function Node:hover()
|
||||
if self.config and self.config.h_popup then
|
||||
if not self.children.h_popup then
|
||||
self.config.h_popup_config.instance_type = 'POPUP'
|
||||
self.children.h_popup = UIBox{
|
||||
definition = self.config.h_popup,
|
||||
config = self.config.h_popup_config,
|
||||
}
|
||||
self.children.h_popup.states.collide.can = false
|
||||
self.children.h_popup.states.drag.can = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Called by the CONTROLLER when this node is no longer being hovered, removes any h_popups
|
||||
function Node:stop_hover()
|
||||
if self.children.h_popup then
|
||||
self.children.h_popup:remove()
|
||||
self.children.h_popup = nil
|
||||
end
|
||||
end
|
||||
|
||||
--Called by the CONTROLLER to determine the position the cursor should be set to for this node
|
||||
function Node:put_focused_cursor()
|
||||
return (self.T.x + self.T.w/2 + self.container.T.x)*(G.TILESCALE*G.TILESIZE), (self.T.y + self.T.h/2 + self.container.T.y)*(G.TILESCALE*G.TILESIZE)
|
||||
end
|
||||
|
||||
--Sets the container of this node and all child nodes to be a new container node
|
||||
--
|
||||
---@param container Node The new node that will behave as this nodes container
|
||||
function Node:set_container(container)
|
||||
if self.children then
|
||||
for _, v in pairs(self.children) do
|
||||
v:set_container(container)
|
||||
end
|
||||
end
|
||||
self.container = container
|
||||
end
|
||||
|
||||
--Translation function used before any draw calls, translates this node according to the transform of the container node
|
||||
function Node:translate_container()
|
||||
if self.container and self.container ~= self then
|
||||
love.graphics.translate(self.container.T.w*G.TILESCALE*G.TILESIZE*0.5, self.container.T.h*G.TILESCALE*G.TILESIZE*0.5)
|
||||
love.graphics.rotate(self.container.T.r)
|
||||
love.graphics.translate(
|
||||
-self.container.T.w*G.TILESCALE*G.TILESIZE*0.5 + self.container.T.x*G.TILESCALE*G.TILESIZE,
|
||||
-self.container.T.h*G.TILESCALE*G.TILESIZE*0.5 + self.container.T.y*G.TILESCALE*G.TILESIZE)
|
||||
end
|
||||
end
|
||||
|
||||
--When this Node needs to be deleted, removes self from any tables it may have been added to to destroy any weak references\
|
||||
--Also calls the remove method of all children to have them do the same
|
||||
function Node:remove()
|
||||
|
||||
for k, v in ipairs(G.I.POPUP) do
|
||||
if v == self then
|
||||
table.remove(G.I.POPUP, k)
|
||||
break;
|
||||
end
|
||||
end
|
||||
for k, v in ipairs(G.I.NODE) do
|
||||
if v == self then
|
||||
table.remove(G.I.NODE, k)
|
||||
break;
|
||||
end
|
||||
end
|
||||
for k, v in ipairs(G.STAGE_OBJECTS[G.STAGE]) do
|
||||
if v == self then
|
||||
table.remove(G.STAGE_OBJECTS[G.STAGE], k)
|
||||
break;
|
||||
end
|
||||
end
|
||||
if self.children then
|
||||
for k, v in pairs(self.children) do
|
||||
v:remove()
|
||||
end
|
||||
end
|
||||
if G.CONTROLLER.clicked.target ==self then
|
||||
G.CONTROLLER.clicked.target = nil
|
||||
end
|
||||
if G.CONTROLLER.focused.target ==self then
|
||||
G.CONTROLLER.focused.target = nil
|
||||
end
|
||||
if G.CONTROLLER.dragging.target ==self then
|
||||
G.CONTROLLER.dragging.target = nil
|
||||
end
|
||||
if G.CONTROLLER.hovering.target ==self then
|
||||
G.CONTROLLER.hovering.target = nil
|
||||
end
|
||||
if G.CONTROLLER.released_on.target ==self then
|
||||
G.CONTROLLER.released_on.target = nil
|
||||
end
|
||||
if G.CONTROLLER.cursor_down.target ==self then
|
||||
G.CONTROLLER.cursor_down.target = nil
|
||||
end
|
||||
if G.CONTROLLER.cursor_up.target ==self then
|
||||
G.CONTROLLER.cursor_up.target = nil
|
||||
end
|
||||
if G.CONTROLLER.cursor_hover.target ==self then
|
||||
G.CONTROLLER.cursor_hover.target = nil
|
||||
end
|
||||
|
||||
self.REMOVED = true
|
||||
end
|
||||
|
||||
--returns the squared(fast) distance in game units from the center of this node to the center of another node
|
||||
--
|
||||
---@param other_node Node to measure the distance from
|
||||
function Node:fast_mid_dist(other_node)
|
||||
return math.sqrt((other_node.T.x + 0.5*other_node.T.w) - (self.T.x + self.T.w))^2 + ((other_node.T.y + 0.5*other_node.T.h) - (self.T.y + self.T.h))^2
|
||||
end
|
||||
|
||||
--Prototype for a click release function, when the cursor is released on this node
|
||||
function Node:release(dragged) end
|
||||
|
||||
--Prototype for a click function
|
||||
function Node:click() end
|
||||
|
||||
--Prototype animation function for any frame manipulation needed
|
||||
function Node:animate() end
|
||||
|
||||
--Prototype update function for any object specific logic that needs to occur every frame
|
||||
function Node:update(dt) end
|
37
engine/object.lua
Normal file
37
engine/object.lua
Normal file
@ -0,0 +1,37 @@
|
||||
--||--
|
||||
--This Object implementation was taken from SNKRX (MIT license). Slightly modified, this is a very simple OOP base
|
||||
|
||||
Object = {}
|
||||
Object.__index = Object
|
||||
function Object:init()
|
||||
end
|
||||
|
||||
function Object:extend()
|
||||
local cls = {}
|
||||
for k, v in pairs(self) do
|
||||
if k:find("__") == 1 then
|
||||
cls[k] = v
|
||||
end
|
||||
end
|
||||
cls.__index = cls
|
||||
cls.super = self
|
||||
setmetatable(cls, self)
|
||||
return cls
|
||||
end
|
||||
|
||||
function Object:is(T)
|
||||
local mt = getmetatable(self)
|
||||
while mt do
|
||||
if mt == T then
|
||||
return true
|
||||
end
|
||||
mt = getmetatable(mt)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Object:__call(...)
|
||||
local obj = setmetatable({}, self)
|
||||
obj:init(...)
|
||||
return obj
|
||||
end
|
177
engine/particles.lua
Normal file
177
engine/particles.lua
Normal file
@ -0,0 +1,177 @@
|
||||
---@class Particles: Moveable
|
||||
Particles = Moveable:extend()
|
||||
|
||||
--Class Methods
|
||||
function Particles:init(X, Y, W, H, config)
|
||||
config = config or {}
|
||||
|
||||
Moveable.init(self,X, Y, W, H)
|
||||
|
||||
self.fill = config.fill
|
||||
self.padding = config.padding or 0
|
||||
|
||||
if config.attach then
|
||||
self:set_alignment{
|
||||
major = config.attach,
|
||||
type = 'cm',
|
||||
bond = 'Strong'
|
||||
}
|
||||
table.insert(self.role.major.children,self)
|
||||
self.parent = self.role.major
|
||||
self.T.x = self.role.major.T.x + self.padding
|
||||
self.T.y = self.role.major.T.y + self.padding
|
||||
if self.fill then
|
||||
self.T.w = self.role.major.T.w - self.padding
|
||||
self.T.h = self.role.major.T.h - self.padding
|
||||
end
|
||||
end
|
||||
|
||||
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.timer = config.timer or 0.5
|
||||
self.timer_type = (self.created_on_pause and 'REAL') or config.timer_type or 'REAL'
|
||||
self.last_real_time = G.TIMERS[self.timer_type] - self.timer
|
||||
self.last_drawn = 0
|
||||
self.lifespan = config.lifespan or 1
|
||||
self.fade_alpha = 0
|
||||
self.speed = config.speed or 1
|
||||
self.max = config.max or 1000000000000000
|
||||
self.pulse_max = math.min(20, config.pulse_max or 0)
|
||||
self.pulsed = 0
|
||||
self.vel_variation = config.vel_variation or 1
|
||||
self.particles = {}
|
||||
self.scale = config.scale or 1
|
||||
self.colours = config.colours or {G.C.BACKGROUND.D}
|
||||
|
||||
if config.initialize then
|
||||
for i = 1, 60 do
|
||||
self.last_real_time = self.last_real_time - 15/60
|
||||
self:update(15/60)
|
||||
self:move(15/60)
|
||||
end
|
||||
end
|
||||
|
||||
if getmetatable(self) == Particles then
|
||||
table.insert(G.I.MOVEABLE, self)
|
||||
end
|
||||
end
|
||||
|
||||
function Particles:update(dt)
|
||||
if G.SETTINGS.paused and not self.created_on_pause then self.last_real_time = G.TIMERS[self.timer_type] ; return end
|
||||
local added_this_frame = 0
|
||||
while G.TIMERS[self.timer_type] > self.last_real_time + self.timer and (#self.particles < self.max or self.pulsed < self.pulse_max) and added_this_frame < 20 do
|
||||
self.last_real_time = self.last_real_time + self.timer
|
||||
local new_offset = {
|
||||
x=self.fill and (0.5-math.random())*self.T.w or 0,
|
||||
y=self.fill and (0.5-math.random())*self.T.h or 0
|
||||
}
|
||||
if self.fill and self.T.r < 0.1 and self.T.r > -0.1 then
|
||||
local newer_offset = {
|
||||
x = math.sin(self.T.r)*new_offset.y + math.cos(self.T.r)*new_offset.x,
|
||||
y = math.sin(self.T.r)*new_offset.x + math.cos(self.T.r)*new_offset.y,
|
||||
}
|
||||
new_offset = newer_offset
|
||||
end
|
||||
table.insert(self.particles, {
|
||||
draw = false,
|
||||
dir = math.random()*2*math.pi,
|
||||
facing = math.random()*2*math.pi,
|
||||
size = math.random()*0.5+0.1,
|
||||
age = 0,
|
||||
velocity = self.speed*(self.vel_variation*math.random() + (1-self.vel_variation))*0.7,
|
||||
r_vel = 0.2*(0.5 - math.random()),
|
||||
e_prev = 0,
|
||||
e_curr = 0,
|
||||
scale = 0,
|
||||
visible_scale = 0,
|
||||
time = G.TIMERS[self.timer_type],
|
||||
colour = pseudorandom_element(self.colours),
|
||||
offset = new_offset
|
||||
})
|
||||
added_this_frame = added_this_frame + 1
|
||||
if self.pulsed <= self.pulse_max then self.pulsed = self.pulsed + 1 end
|
||||
end
|
||||
end
|
||||
|
||||
function Particles:move(dt)
|
||||
if G.SETTINGS.paused and not self.created_on_pause then return end
|
||||
|
||||
Moveable.move(self, dt)
|
||||
|
||||
if self.timer_type ~= 'REAL' then dt = dt*G.SPEEDFACTOR end
|
||||
|
||||
for i=#self.particles,1,-1 do
|
||||
self.particles[i].draw = true
|
||||
self.particles[i].e_vel = self.particles[i].e_vel or dt*self.scale
|
||||
self.particles[i].e_prev = self.particles[i].e_curr
|
||||
self.particles[i].age = self.particles[i].age + dt
|
||||
|
||||
self.particles[i].e_curr = math.min(2*math.min((self.particles[i].age/self.lifespan)*self.scale, self.scale*((self.lifespan - self.particles[i].age)/self.lifespan)), self.scale)
|
||||
|
||||
self.particles[i].e_vel = (self.particles[i].e_curr - self.particles[i].e_prev)*self.scale*dt + (1-self.scale*dt)*self.particles[i].e_vel
|
||||
|
||||
self.particles[i].scale = self.particles[i].scale + self.particles[i].e_vel
|
||||
self.particles[i].scale = math.min(2*math.min((self.particles[i].age/self.lifespan)*self.scale, self.scale*((self.lifespan - self.particles[i].age)/self.lifespan)), self.scale)
|
||||
|
||||
if self.particles[i].scale < 0 then
|
||||
table.remove(self.particles, i)
|
||||
else
|
||||
self.particles[i].offset.x = self.particles[i].offset.x + self.particles[i].velocity*math.sin(self.particles[i].dir)*dt
|
||||
self.particles[i].offset.y = self.particles[i].offset.y + self.particles[i].velocity*math.cos(self.particles[i].dir)*dt
|
||||
self.particles[i].facing = self.particles[i].facing + self.particles[i].r_vel*dt
|
||||
self.particles[i].velocity = math.max(0, self.particles[i].velocity - self.particles[i].velocity*0.07*dt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Particles:fade(delay, to)
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'ease',
|
||||
timer = self.timer_type,
|
||||
blockable = false,
|
||||
blocking = false,
|
||||
ref_value = 'fade_alpha',
|
||||
ref_table = self,
|
||||
ease_to = to or 1,
|
||||
delay = delay
|
||||
}))
|
||||
end
|
||||
|
||||
function Particles:draw(alpha)
|
||||
alpha = alpha or 1
|
||||
prep_draw(self, 1)
|
||||
love.graphics.translate(self.T.w/2, self.T.h/2)
|
||||
for k, v in pairs(self.particles) do
|
||||
if v.draw then
|
||||
love.graphics.push()
|
||||
love.graphics.setColor(v.colour[1], v.colour[2], v.colour[3], v.colour[4]*alpha*(1-self.fade_alpha))
|
||||
love.graphics.translate(v.offset.x, v.offset.y)
|
||||
love.graphics.rotate(v.facing)
|
||||
|
||||
love.graphics.rectangle('fill', -v.scale/2, -v.scale/2, v.scale, v.scale) -- origin in the middle
|
||||
love.graphics.pop()
|
||||
end
|
||||
end
|
||||
love.graphics.pop()
|
||||
|
||||
add_to_drawhash(self)
|
||||
self:draw_boundingrect()
|
||||
end
|
||||
|
||||
function Particles:remove()
|
||||
if self.role.major then
|
||||
for k, v in pairs(self.role.major.children) do
|
||||
if v == self and type(k) == 'number' then
|
||||
table.remove(self.role.major.children, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
remove_all(self.children)
|
||||
|
||||
Moveable.remove(self)
|
||||
end
|
188
engine/profile.lua
Normal file
188
engine/profile.lua
Normal file
@ -0,0 +1,188 @@
|
||||
local clock = os.clock
|
||||
|
||||
--- Simple profiler written in Lua.
|
||||
-- @module profile
|
||||
-- @alias profile
|
||||
local profile = {}
|
||||
|
||||
-- function labels
|
||||
local _labeled = {}
|
||||
-- function definitions
|
||||
local _defined = {}
|
||||
-- time of last call
|
||||
local _tcalled = {}
|
||||
-- total execution time
|
||||
local _telapsed = {}
|
||||
-- number of calls
|
||||
local _ncalls = {}
|
||||
-- list of internal profiler functions
|
||||
local _internal = {}
|
||||
|
||||
--- This is an internal function.
|
||||
-- @tparam string event Event type
|
||||
-- @tparam number line Line number
|
||||
-- @tparam[opt] table info Debug info table
|
||||
function profile.hooker(event, line, info)
|
||||
info = info or debug.getinfo(2, 'fnS')
|
||||
local f = info.func
|
||||
-- ignore the profiler itself
|
||||
if _internal[f] or info.what ~= "Lua" then
|
||||
return
|
||||
end
|
||||
-- get the function name if available
|
||||
if info.name then
|
||||
_labeled[f] = info.name
|
||||
end
|
||||
-- find the line definition
|
||||
if not _defined[f] then
|
||||
_defined[f] = info.short_src..":"..info.linedefined
|
||||
_ncalls[f] = 0
|
||||
_telapsed[f] = 0
|
||||
end
|
||||
if _tcalled[f] then
|
||||
local dt = clock() - _tcalled[f]
|
||||
_telapsed[f] = _telapsed[f] + dt
|
||||
_tcalled[f] = nil
|
||||
end
|
||||
if event == "tail call" then
|
||||
local prev = debug.getinfo(3, 'fnS')
|
||||
profile.hooker("return", line, prev)
|
||||
profile.hooker("call", line, info)
|
||||
elseif event == 'call' then
|
||||
_tcalled[f] = clock()
|
||||
else
|
||||
_ncalls[f] = _ncalls[f] + 1
|
||||
end
|
||||
end
|
||||
|
||||
--- Sets a clock function to be used by the profiler.
|
||||
-- @tparam function func Clock function that returns a number
|
||||
function profile.setclock(f)
|
||||
assert(type(f) == "function", "clock must be a function")
|
||||
clock = f
|
||||
end
|
||||
|
||||
--- Starts collecting data.
|
||||
function profile.start()
|
||||
if rawget(_G, 'jit') then
|
||||
jit.off()
|
||||
jit.flush()
|
||||
end
|
||||
debug.sethook(profile.hooker, "cr")
|
||||
end
|
||||
|
||||
--- Stops collecting data.
|
||||
function profile.stop()
|
||||
debug.sethook()
|
||||
for f in pairs(_tcalled) do
|
||||
local dt = clock() - _tcalled[f]
|
||||
_telapsed[f] = _telapsed[f] + dt
|
||||
_tcalled[f] = nil
|
||||
end
|
||||
-- merge closures
|
||||
local lookup = {}
|
||||
for f, d in pairs(_defined) do
|
||||
local id = (_labeled[f] or '?')..d
|
||||
local f2 = lookup[id]
|
||||
if f2 then
|
||||
_ncalls[f2] = _ncalls[f2] + (_ncalls[f] or 0)
|
||||
_telapsed[f2] = _telapsed[f2] + (_telapsed[f] or 0)
|
||||
_defined[f], _labeled[f] = nil, nil
|
||||
_ncalls[f], _telapsed[f] = nil, nil
|
||||
else
|
||||
lookup[id] = f
|
||||
end
|
||||
end
|
||||
collectgarbage('collect')
|
||||
end
|
||||
|
||||
--- Resets all collected data.
|
||||
function profile.reset()
|
||||
for f in pairs(_ncalls) do
|
||||
_ncalls[f] = 0
|
||||
end
|
||||
for f in pairs(_telapsed) do
|
||||
_telapsed[f] = 0
|
||||
end
|
||||
for f in pairs(_tcalled) do
|
||||
_tcalled[f] = nil
|
||||
end
|
||||
collectgarbage('collect')
|
||||
end
|
||||
|
||||
--- This is an internal function.
|
||||
-- @tparam function a First function
|
||||
-- @tparam function b Second function
|
||||
function profile.comp(a, b)
|
||||
local dt = _telapsed[b] - _telapsed[a]
|
||||
if dt == 0 then
|
||||
return _ncalls[b] < _ncalls[a]
|
||||
end
|
||||
return dt < 0
|
||||
end
|
||||
|
||||
--- Iterates all functions that have been called since the profile was started.
|
||||
-- @tparam[opt] number limit Maximum number of rows
|
||||
function profile.query(limit)
|
||||
local t = {}
|
||||
for f, n in pairs(_ncalls) do
|
||||
if n > 0 then
|
||||
t[#t + 1] = f
|
||||
end
|
||||
end
|
||||
table.sort(t, profile.comp)
|
||||
if limit then
|
||||
while #t > limit do
|
||||
table.remove(t)
|
||||
end
|
||||
end
|
||||
for i, f in ipairs(t) do
|
||||
local dt = 0
|
||||
if _tcalled[f] then
|
||||
dt = clock() - _tcalled[f]
|
||||
end
|
||||
t[i] = { i, _labeled[f] or '?', _ncalls[f], _telapsed[f] + dt, _defined[f] }
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local cols = { 3, 29, 11, 24, 32 }
|
||||
|
||||
--- Generates a text report.
|
||||
-- @tparam[opt] number limit Maximum number of rows
|
||||
function profile.report(n)
|
||||
local out = {}
|
||||
local report = profile.query(n)
|
||||
for i, row in ipairs(report) do
|
||||
for j = 1, 5 do
|
||||
local s = row[j]
|
||||
local l2 = cols[j]
|
||||
s = tostring(s)
|
||||
local l1 = s:len()
|
||||
if l1 < l2 then
|
||||
s = s..(' '):rep(l2-l1)
|
||||
elseif l1 > l2 then
|
||||
s = s:sub(l1 - l2 + 1, l1)
|
||||
end
|
||||
row[j] = s
|
||||
end
|
||||
out[i] = table.concat(row, ' | ')
|
||||
end
|
||||
|
||||
local row = " +-----+-------------------------------+-------------+--------------------------+----------------------------------+ \n"
|
||||
local col = " | # | Function | Calls | Time | Code | \n"
|
||||
local sz = row..col..row
|
||||
if #out > 0 then
|
||||
sz = sz..' | '..table.concat(out, ' | \n | ')..' | \n'
|
||||
end
|
||||
return '\n'..sz..row
|
||||
end
|
||||
|
||||
-- store all internal profiler functions
|
||||
for _, v in pairs(profile) do
|
||||
if type(v) == "function" then
|
||||
_internal[v] = true
|
||||
end
|
||||
end
|
||||
|
||||
return profile
|
84
engine/save_manager.lua
Normal file
84
engine/save_manager.lua
Normal file
@ -0,0 +1,84 @@
|
||||
require "love.system"
|
||||
|
||||
if (love.system.getOS() == 'OS X' ) and (jit.arch == 'arm64' or jit.arch == 'arm' or true) then jit.off() end
|
||||
|
||||
require "love.timer"
|
||||
require "love.thread"
|
||||
require 'love.filesystem'
|
||||
require "engine/object"
|
||||
require "engine/string_packer"
|
||||
|
||||
--vars needed for sound manager thread
|
||||
CHANNEL = love.thread.getChannel("save_request")
|
||||
|
||||
while true do
|
||||
--Monitor the channel for any new requests
|
||||
local request = CHANNEL:demand() -- Value from channel
|
||||
if request then
|
||||
--Saves progress for settings, unlocks, alerts and discoveries
|
||||
if request.type == 'save_progress' then
|
||||
local prefix_profile = (request.save_progress.SETTINGS.profile or 1)..''
|
||||
if not love.filesystem.getInfo(prefix_profile) then love.filesystem.createDirectory( prefix_profile ) end
|
||||
prefix_profile = prefix_profile..'/'
|
||||
|
||||
if not love.filesystem.getInfo(prefix_profile..'meta.jkr') then
|
||||
love.filesystem.append( prefix_profile..'meta.jkr', 'return {}' )
|
||||
end
|
||||
|
||||
local meta = STR_UNPACK(get_compressed(prefix_profile..'meta.jkr') or 'return {}')
|
||||
meta.unlocked = meta.unlocked or {}
|
||||
meta.discovered = meta.discovered or {}
|
||||
meta.alerted = meta.alerted or {}
|
||||
|
||||
local _append = false
|
||||
|
||||
for k, v in pairs(request.save_progress.UDA) do
|
||||
if string.find(v, 'u') and not meta.unlocked[k] then
|
||||
meta.unlocked[k] = true
|
||||
_append = true
|
||||
end
|
||||
if string.find(v, 'd') and not meta.discovered[k] then
|
||||
meta.discovered[k] = true
|
||||
_append = true
|
||||
end
|
||||
if string.find(v, 'a') and not meta.alerted[k] then
|
||||
meta.alerted[k] = true
|
||||
_append = true
|
||||
end
|
||||
end
|
||||
if _append then compress_and_save( prefix_profile..'meta.jkr', STR_PACK(meta)) end
|
||||
|
||||
compress_and_save('settings.jkr', request.save_progress.SETTINGS)
|
||||
compress_and_save(prefix_profile..'profile.jkr', request.save_progress.PROFILE)
|
||||
|
||||
CHANNEL:push('done')
|
||||
--Saves the settings file
|
||||
elseif request.type == 'save_settings' then
|
||||
compress_and_save('settings.jkr', request.save_settings)
|
||||
compress_and_save(request.profile_num..'/profile.jkr', request.save_profile)
|
||||
--Saves the metrics file
|
||||
elseif request.type == 'save_metrics' then
|
||||
compress_and_save('metrics.jkr', request.save_metrics)
|
||||
--Saves any notifications
|
||||
elseif request.type == 'save_notify' then
|
||||
local prefix_profile = (request.profile_num or 1)..''
|
||||
if not love.filesystem.getInfo(prefix_profile) then love.filesystem.createDirectory( prefix_profile ) end
|
||||
prefix_profile = prefix_profile..'/'
|
||||
|
||||
if not love.filesystem.getInfo(prefix_profile..'unlock_notify.jkr') then love.filesystem.append( prefix_profile..'unlock_notify.jkr', '') end
|
||||
local unlock_notify = get_compressed(prefix_profile..'unlock_notify.jkr') or ''
|
||||
|
||||
if request.save_notify and not string.find(unlock_notify, request.save_notify) then
|
||||
compress_and_save( prefix_profile..'unlock_notify.jkr', unlock_notify..request.save_notify..'\n')
|
||||
end
|
||||
|
||||
--Saves the run
|
||||
elseif request.type == 'save_run' then
|
||||
local prefix_profile = (request.profile_num or 1)..''
|
||||
if not love.filesystem.getInfo(prefix_profile) then love.filesystem.createDirectory( prefix_profile ) end
|
||||
prefix_profile = prefix_profile..'/'
|
||||
|
||||
compress_and_save(prefix_profile..'save.jkr', request.save_table)
|
||||
end
|
||||
end
|
||||
end
|
207
engine/sound_manager.lua
Normal file
207
engine/sound_manager.lua
Normal file
@ -0,0 +1,207 @@
|
||||
require "love.audio"
|
||||
require "love.sound"
|
||||
require "love.system"
|
||||
|
||||
if (love.system.getOS() == 'OS X' )and (jit.arch == 'arm64' or jit.arch == 'arm' or true) 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
|
||||
|
||||
--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 s = {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.per or 1
|
||||
s.original_volume = 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)
|
||||
for k, v in pairs(SOURCES) do
|
||||
if (string.find(k,'music') and (args.desired_track ~= '')) then
|
||||
if v[1] and v[1].sound and v[1].sound:isPlaying() then
|
||||
else
|
||||
RESTART_MUSIC(args)
|
||||
break;
|
||||
end
|
||||
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
|
||||
|
||||
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 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 == '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()
|
||||
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
|
215
engine/sprite.lua
Normal file
215
engine/sprite.lua
Normal file
@ -0,0 +1,215 @@
|
||||
--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)
|
||||
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(_shader,_send) 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
|
72
engine/string_packer.lua
Normal file
72
engine/string_packer.lua
Normal file
@ -0,0 +1,72 @@
|
||||
--[[
|
||||
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.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
|
315
engine/text.lua
Normal file
315
engine/text.lua
Normal file
@ -0,0 +1,315 @@
|
||||
--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
|
||||
|
||||
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 '')..tostring(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 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
|
||||
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
|
||||
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 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)+ 0.02*math.sin(2*G.TIMERS.REAL+k)) end
|
||||
if self.config.pulse then
|
||||
letter.scale = letter.scale + (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 + (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 + (0.1*self.config.quiver.amount)
|
||||
letter.r = letter.r + 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 = 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 = 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 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
|
||||
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
|
||||
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
|
1049
engine/ui.lua
Normal file
1049
engine/ui.lua
Normal file
File diff suppressed because it is too large
Load Diff
5842
functions/UI_definitions.lua
Normal file
5842
functions/UI_definitions.lua
Normal file
File diff suppressed because it is too large
Load Diff
3158
functions/button_callbacks.lua
Normal file
3158
functions/button_callbacks.lua
Normal file
File diff suppressed because it is too large
Load Diff
2715
functions/common_events.lua
Normal file
2715
functions/common_events.lua
Normal file
File diff suppressed because it is too large
Load Diff
1908
functions/misc_functions.lua
Normal file
1908
functions/misc_functions.lua
Normal file
File diff suppressed because it is too large
Load Diff
1635
functions/state_events.lua
Normal file
1635
functions/state_events.lua
Normal file
File diff suppressed because it is too large
Load Diff
237
functions/test_functions.lua
Normal file
237
functions/test_functions.lua
Normal file
@ -0,0 +1,237 @@
|
||||
function live_test()
|
||||
add_joker('j_popcorn', 'negative')
|
||||
end
|
||||
|
||||
function do_action(action)
|
||||
local action = {
|
||||
type = 'use_card',
|
||||
target_area = "shop_booster",
|
||||
target_card = 1,
|
||||
}
|
||||
|
||||
do_action(action)
|
||||
|
||||
if action.type == 'use_card' then
|
||||
G.FUNCS.use_card({config = {ref_table = G[action.target_area].cards[action.target_card]}})
|
||||
end
|
||||
end
|
||||
|
||||
function graphics_stress()
|
||||
local _r = {}
|
||||
for i = 1,50 do
|
||||
local _c = {}
|
||||
for j =1,50 do
|
||||
_c[#_c+1] = {n=G.UIT.C, config={align = "cm", minw = 0.05,minh = 0.05,colour = G.C.BLUE}, nodes={
|
||||
{n=G.UIT.T, config={text = "A", scale = 0.15, colour = G.C.WHITE}}
|
||||
}}
|
||||
end
|
||||
_r[#_r+1] = {n=G.UIT.R, config={align = "cm", minw = 0.05,minh = 0.05,colour = G.C.BLUE, padding = 0.05}, nodes=_c}
|
||||
end
|
||||
local uidef = {n=G.UIT.ROOT, config={align = "cm", colour = G.C.CLEAR}, nodes=_r}
|
||||
|
||||
G.STRESS = UIBox{
|
||||
definition = uidef,
|
||||
config = {align="cm", offset = {x=0,y=0},major = G.ROOM_ATTACH}
|
||||
}
|
||||
end
|
||||
|
||||
function aprint(text)
|
||||
if _RELEASE_MODE then return end
|
||||
attention_text({
|
||||
text = text,
|
||||
scale = 0.8,
|
||||
hold = 5.7,
|
||||
cover = G.deck or G.MAIN_MENU_UI,
|
||||
cover_colour = G.C.RED,
|
||||
align = 'cm',
|
||||
})
|
||||
end
|
||||
|
||||
function play_video()
|
||||
G.video_control = G.video_control or {
|
||||
{video = 'A3', _s = 0.1, _e = 4.65, track = 'music1'},
|
||||
{video = 'E1', _s = 3.69, _e = 6.55},
|
||||
{video = 'C3', _s = 1.9, _e = 4.3, track = 'music3'},
|
||||
{video = 'E5', _s = 5.9, _e = 9.2, track = 'music1'},
|
||||
{video = 'C4a', _s = 1.3, _e = 4.5, track = 'music2'},
|
||||
{video = 'E4', _s = 4, _e = 7.2, track = 'music1'},
|
||||
{video = 'D4', _s = 0.3, _e = 3.2, track = 'music4'},
|
||||
{video = 'C2', _s = 2.0, _e = 4.4, track = 'music1'},
|
||||
{video = 'B3', _s = 2.7, _e = 5.3},
|
||||
{video = 'B4', _s = 21.5, _e = 24.8},
|
||||
{video = 'D5', _s = 1.2, _e = 3.8, track = 'music1'},
|
||||
{video_organ = 0.1,video = 'E2', _s = 1.5, _e = 4.1},
|
||||
{video_organ = 0.2,video = 'E3', _s = 3.5, _e = 7.5},
|
||||
{video_organ = 0.4, video = 'D3', _s = 1.9, _e = 4.3, track = 'music1'},
|
||||
--[[ old one
|
||||
{video = 'A1', _s = 2.5, _e = 13.9, track = 'music1'},
|
||||
{video = '_A2', _s = 0.4, _e = 3.15},
|
||||
{video = 'A3', _s = 0.2, _e = 2.25},
|
||||
{video = 'A4', _s = 3.4, _e = 8.2},
|
||||
{video = '_B1', _s = 0.15, _e = 4.4},
|
||||
{video = 'B3', _s = 2.7, _e = 5.3},
|
||||
{video = 'B4', _s = 21.5, _e = 27.6},
|
||||
{video = '_C1', _s = 0.25, _e = 3.2, track = 'music4'},
|
||||
{video = 'C2', _s = 1.4, _e = 4.4},
|
||||
{video = 'C3', _s = 1.9, _e = 4.3, track = 'music3'},
|
||||
{video = 'C4a', _s = 1.3, _e = 4.5, track = 'music2'},
|
||||
{video = '_C5', _s = 0.1, _e = 3.4, track = 'music1'},
|
||||
{video = 'C4b', _s = 0.15, _e = 3.5},
|
||||
{video = 'D4', _s = 0.3, _e = 3.7, track = 'music4'},
|
||||
{video = 'D3', _s = 1.6, _e = 4.8, track = 'music1'},
|
||||
{video = 'D1', _s = 1.4, _e = 3.5, track = 'music4'},
|
||||
{video = 'D5', _s = 1.0, _e = 3.8, track = 'music1'},
|
||||
{video = 'E1', _s = 3, _e = 6.55},
|
||||
{video = 'E2', _s = 0., _e = 4.1},
|
||||
{video = 'E3', _s = 3.5, _e = 7.5},
|
||||
{video = 'E4', _s = 4, _e = 7.2},
|
||||
{video = 'E5', _s = 5.9, _e = 9.2, track = 'music1'},
|
||||
{video = 'F1', _s = 4.2, _e = 8.1},
|
||||
{video_organ = 0.1, video = 'F5', _s = 2.25, _e = 5.4},
|
||||
{video_organ = 0.05, video = 'F6', _s = 0, _e = 2.3},
|
||||
{video_organ = 0.2, video = 'F2', _s = 0.2, _e = 1.6},
|
||||
{video_organ = 0.4, video = 'F3', _s = 2.6, _e = 4.2}, ]]--
|
||||
}
|
||||
|
||||
G.video_volume = 1
|
||||
G.video_volume_real = 0
|
||||
|
||||
G.E_MANAGER:add_event(Event({
|
||||
blocking = false, blockable = false,
|
||||
func = function()
|
||||
G.video_volume_real = G.video_volume_real*(1 - 4*G.real_dt) + 4*G.real_dt*G.video_volume
|
||||
if G.video then G.video:getSource( ):setVolume(G.video_volume_real) end
|
||||
end
|
||||
}))
|
||||
|
||||
local trailer_time = 0
|
||||
|
||||
for k, v in pairs(G.video_control) do
|
||||
if v.start then
|
||||
local nu_vc = {}
|
||||
for i = k, #G.video_control do
|
||||
nu_vc[#nu_vc+1] = G.video_control[i]
|
||||
end
|
||||
G.video_control = nu_vc
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--prep clips because keyframes
|
||||
for k, v in pairs(G.video_control) do
|
||||
trailer_time = trailer_time + (v._e - v._s)
|
||||
v.video_file = love.graphics.newVideo('resources/videos/'..v.video..'.ogv')
|
||||
v.video_file:seek(math.max(v._s or 0.3, 0.3) - 0.29)
|
||||
G.E_MANAGER:add_event(Event({
|
||||
func = function()
|
||||
v.video_file:play()
|
||||
return true
|
||||
end
|
||||
}))
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'after',
|
||||
delay = 0.29,
|
||||
func = function()
|
||||
v.video_file:pause()
|
||||
v.video_file:seek(v._s or 0)
|
||||
return true
|
||||
end
|
||||
}))
|
||||
end
|
||||
delay(1.5)
|
||||
|
||||
for k, v in pairs(G.video_control) do
|
||||
if v.text then
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'before',
|
||||
delay = 1.4,
|
||||
func = function()
|
||||
G.FUNCS.wipe_on(v.text, true, 1.4)
|
||||
G.video_volume = 0
|
||||
return true
|
||||
end
|
||||
}))
|
||||
G.E_MANAGER:add_event(Event({
|
||||
func = function()
|
||||
if G.video then G.video:pause() end
|
||||
G.video = v.video_file
|
||||
if v.track then G.video_soundtrack = v.track end
|
||||
if v.video_organ then G.video_organ = v.video_organ end
|
||||
G.video:play()
|
||||
G.video_volume = 1
|
||||
return true
|
||||
end
|
||||
}))
|
||||
G.FUNCS.wipe_off()
|
||||
else
|
||||
G.E_MANAGER:add_event(Event({
|
||||
func = function()
|
||||
if G.video then G.video:pause() end
|
||||
G.video = v.video_file
|
||||
if v.track then G.video_soundtrack = v.track end
|
||||
if v.video_organ then G.video_organ = v.video_organ end
|
||||
G.video:play()
|
||||
return true
|
||||
end
|
||||
}))
|
||||
end
|
||||
local _delay = v._e - (v._s or 0) - (v.text and 1.5 or 0)
|
||||
delay(_delay - 0.15)
|
||||
G.E_MANAGER:add_event(Event({
|
||||
func = function()
|
||||
G.screenglitch = true
|
||||
G.screenwipe_amt = 1
|
||||
return true
|
||||
end
|
||||
}))
|
||||
delay(0.15)
|
||||
G.E_MANAGER:add_event(Event({
|
||||
blocking = false,
|
||||
trigger = 'after',
|
||||
delay = 0.3,
|
||||
func = function()
|
||||
G.screenglitch = false
|
||||
return true
|
||||
end
|
||||
}))
|
||||
end
|
||||
local flash_col = copy_table(G.C.WHITE)
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'before',
|
||||
delay = 0.6,
|
||||
func = function()
|
||||
G.FUNCS.wipe_on(nil, true, 2, flash_col)
|
||||
return true
|
||||
end
|
||||
}))
|
||||
G.E_MANAGER:add_event(Event({
|
||||
func = function()
|
||||
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'after', delay = 0.9, blockable = false,
|
||||
func = function()
|
||||
G.video:pause()
|
||||
G.video = nil
|
||||
G.video_soundtrack = 'music1'
|
||||
G.video_organ = 0
|
||||
return true
|
||||
end
|
||||
}))
|
||||
G.E_MANAGER:add_event(Event({
|
||||
trigger = 'after', delay = 0.9, blockable = false,
|
||||
func = function()
|
||||
G.screenglitch = false
|
||||
G.TIMERS.REAL = 4
|
||||
G.TIMERS.TOTAL = 4
|
||||
flash_col[4] = 0
|
||||
G:main_menu('splash')
|
||||
return true
|
||||
end
|
||||
}))
|
||||
|
||||
return true
|
||||
end
|
||||
}))
|
||||
G.FUNCS.wipe_off()
|
||||
end
|
460
globals.lua
Normal file
460
globals.lua
Normal file
@ -0,0 +1,460 @@
|
||||
VERSION = '1.0.0k'
|
||||
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 = true --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
|
||||
|
||||
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_ENGLISH_ONLY = false
|
||||
self.F_CRASH_REPORTS = true
|
||||
end
|
||||
|
||||
if love.system.getOS() == 'OS X' then
|
||||
self.F_DISCORD = true
|
||||
self.F_ENGLISH_ONLY = false
|
||||
self.F_CRASH_REPORTS = false
|
||||
end
|
||||
|
||||
if love.system.getOS() == 'Nintendo Switch' then
|
||||
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 = true
|
||||
|
||||
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_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_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,
|
||||
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,
|
||||
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},
|
||||
}
|
||||
},
|
||||
},
|
||||
GRAPHICS = {
|
||||
texture_scaling = 2,
|
||||
shadows = 'On',
|
||||
crt = 70,
|
||||
bloom = 1
|
||||
},
|
||||
}
|
||||
|
||||
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 = {
|
||||
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'),
|
||||
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 = {0,1,1,1},
|
||||
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()
|
4237
localization/de.lua
Normal file
4237
localization/de.lua
Normal file
File diff suppressed because it is too large
Load Diff
4138
localization/en-us.lua
Normal file
4138
localization/en-us.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/es_419.lua
Normal file
4237
localization/es_419.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/es_ES.lua
Normal file
4237
localization/es_ES.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/fr.lua
Normal file
4237
localization/fr.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/id.lua
Normal file
4237
localization/id.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/it.lua
Normal file
4237
localization/it.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/ja.lua
Normal file
4237
localization/ja.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/ko.lua
Normal file
4237
localization/ko.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/nl.lua
Normal file
4237
localization/nl.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/pl.lua
Normal file
4237
localization/pl.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/pt_BR.lua
Normal file
4237
localization/pt_BR.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/ru.lua
Normal file
4237
localization/ru.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/zh_CN.lua
Normal file
4237
localization/zh_CN.lua
Normal file
File diff suppressed because it is too large
Load Diff
4237
localization/zh_TW.lua
Normal file
4237
localization/zh_TW.lua
Normal file
File diff suppressed because it is too large
Load Diff
370
main.lua
Normal file
370
main.lua
Normal file
@ -0,0 +1,370 @@
|
||||
if (love.system.getOS() == 'OS X' ) and (jit.arch == 'arm64' or jit.arch == 'arm' or true) then jit.off() end
|
||||
require "engine/object"
|
||||
require "bit"
|
||||
require "engine/string_packer"
|
||||
require "engine/controller"
|
||||
require "back"
|
||||
require "tag"
|
||||
require "engine/event"
|
||||
require "engine/node"
|
||||
require "engine/moveable"
|
||||
require "engine/sprite"
|
||||
require "engine/animatedsprite"
|
||||
require "functions/misc_functions"
|
||||
require "game"
|
||||
require "globals"
|
||||
require "engine/ui"
|
||||
require "functions/UI_definitions"
|
||||
require "functions/state_events"
|
||||
require "functions/common_events"
|
||||
require "functions/button_callbacks"
|
||||
require "functions/misc_functions"
|
||||
require "functions/test_functions"
|
||||
require "card"
|
||||
require "cardarea"
|
||||
require "blind"
|
||||
require "card_character"
|
||||
require "engine/particles"
|
||||
require "engine/text"
|
||||
require "challenges"
|
||||
|
||||
math.randomseed( G.SEED )
|
||||
|
||||
function love.run()
|
||||
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
|
||||
|
||||
-- We don't want the first frame's dt to include time taken by love.load.
|
||||
if love.timer then love.timer.step() end
|
||||
|
||||
local dt = 0
|
||||
local dt_smooth = 1/100
|
||||
local run_time = 0
|
||||
|
||||
-- Main loop time.
|
||||
return function()
|
||||
run_time = love.timer.getTime()
|
||||
-- Process events.
|
||||
if love.event and G and G.CONTROLLER then
|
||||
love.event.pump()
|
||||
local _n,_a,_b,_c,_d,_e,_f,touched
|
||||
for name, a,b,c,d,e,f in love.event.poll() do
|
||||
if name == "quit" then
|
||||
if not love.quit or not love.quit() then
|
||||
return a or 0
|
||||
end
|
||||
end
|
||||
if name == 'touchpressed' then
|
||||
touched = true
|
||||
elseif name == 'mousepressed' then
|
||||
_n,_a,_b,_c,_d,_e,_f = name,a,b,c,d,e,f
|
||||
else
|
||||
love.handlers[name](a,b,c,d,e,f)
|
||||
end
|
||||
end
|
||||
if _n then
|
||||
love.handlers['mousepressed'](_a,_b,_c,touched)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update dt, as we'll be passing it to update
|
||||
if love.timer then dt = love.timer.step() end
|
||||
dt_smooth = math.min(0.8*dt_smooth + 0.2*dt, 0.1)
|
||||
-- Call update and draw
|
||||
if love.update then love.update(dt_smooth) end -- will pass 0 if love.timer is disabled
|
||||
|
||||
if love.graphics and love.graphics.isActive() then
|
||||
if love.draw then love.draw() end
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
run_time = math.min(love.timer.getTime() - run_time, 0.1)
|
||||
G.FPS_CAP = G.FPS_CAP or 500
|
||||
if run_time < 1./G.FPS_CAP then love.timer.sleep(1./G.FPS_CAP - run_time) end
|
||||
end
|
||||
end
|
||||
|
||||
function love.load()
|
||||
G:start_up()
|
||||
--Steam integration
|
||||
local os = love.system.getOS()
|
||||
if os == 'OS X' or os == 'Windows' then
|
||||
local st = nil
|
||||
--To control when steam communication happens, make sure to send updates to steam as little as possible
|
||||
if os == 'OS X' then
|
||||
local dir = love.filesystem.getSourceBaseDirectory()
|
||||
local old_cpath = package.cpath
|
||||
package.cpath = package.cpath .. ';' .. dir .. '/?.so'
|
||||
st = require 'luasteam'
|
||||
package.cpath = old_cpath
|
||||
else
|
||||
st = require 'luasteam'
|
||||
end
|
||||
|
||||
st.send_control = {
|
||||
last_sent_time = -200,
|
||||
last_sent_stage = -1,
|
||||
force = false,
|
||||
}
|
||||
if not (st.init and st:init()) then
|
||||
love.event.quit()
|
||||
end
|
||||
--Set up the render window and the stage for the splash screen, then enter the gameloop with :update
|
||||
G.STEAM = st
|
||||
else
|
||||
end
|
||||
|
||||
--Set the mouse to invisible immediately, this visibility is handled in the G.CONTROLLER
|
||||
love.mouse.setVisible(false)
|
||||
end
|
||||
|
||||
function love.quit()
|
||||
--Steam integration
|
||||
if G.SOUND_MANAGER then G.SOUND_MANAGER.channel:push({type = 'stop'}) end
|
||||
if G.STEAM then G.STEAM:shutdown() end
|
||||
end
|
||||
|
||||
function love.update( dt )
|
||||
--Perf monitoring checkpoint
|
||||
timer_checkpoint(nil, 'update', true)
|
||||
G:update(dt)
|
||||
end
|
||||
|
||||
function love.draw()
|
||||
--Perf monitoring checkpoint
|
||||
timer_checkpoint(nil, 'draw', true)
|
||||
G:draw()
|
||||
end
|
||||
|
||||
function love.keypressed(key)
|
||||
if not _RELEASE_MODE and G.keybind_mapping[key] then love.gamepadpressed(G.CONTROLLER.keyboard_controller, G.keybind_mapping[key])
|
||||
else
|
||||
G.CONTROLLER:set_HID_flags('mouse')
|
||||
G.CONTROLLER:key_press(key)
|
||||
end
|
||||
end
|
||||
|
||||
function love.keyreleased(key)
|
||||
if not _RELEASE_MODE and G.keybind_mapping[key] then love.gamepadreleased(G.CONTROLLER.keyboard_controller, G.keybind_mapping[key])
|
||||
else
|
||||
G.CONTROLLER:set_HID_flags('mouse')
|
||||
G.CONTROLLER:key_release(key)
|
||||
end
|
||||
end
|
||||
|
||||
function love.gamepadpressed(joystick, button)
|
||||
button = G.button_mapping[button] or button
|
||||
G.CONTROLLER:set_gamepad(joystick)
|
||||
G.CONTROLLER:set_HID_flags('button', button)
|
||||
G.CONTROLLER:button_press(button)
|
||||
end
|
||||
|
||||
function love.gamepadreleased(joystick, button)
|
||||
button = G.button_mapping[button] or button
|
||||
G.CONTROLLER:set_gamepad(joystick)
|
||||
G.CONTROLLER:set_HID_flags('button', button)
|
||||
G.CONTROLLER:button_release(button)
|
||||
end
|
||||
|
||||
function love.mousepressed(x, y, button, touch)
|
||||
G.CONTROLLER:set_HID_flags(touch and 'touch' or 'mouse')
|
||||
if button == 1 then
|
||||
G.CONTROLLER:queue_L_cursor_press(x, y)
|
||||
end
|
||||
if button == 2 then
|
||||
G.CONTROLLER:queue_R_cursor_press(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function love.mousereleased(x, y, button)
|
||||
if button == 1 then G.CONTROLLER:L_cursor_release(x, y) end
|
||||
end
|
||||
|
||||
function love.mousemoved(x, y, dx, dy, istouch)
|
||||
G.CONTROLLER.last_touch_time = G.CONTROLLER.last_touch_time or -1
|
||||
if next(love.touch.getTouches()) ~= nil then
|
||||
G.CONTROLLER.last_touch_time = G.TIMERS.UPTIME
|
||||
end
|
||||
G.CONTROLLER:set_HID_flags(G.CONTROLLER.last_touch_time > G.TIMERS.UPTIME - 0.2 and 'touch' or 'mouse')
|
||||
end
|
||||
|
||||
function love.joystickaxis( joystick, axis, value )
|
||||
if math.abs(value) > 0.2 and joystick:isGamepad() then
|
||||
G.CONTROLLER:set_gamepad(joystick)
|
||||
G.CONTROLLER:set_HID_flags('axis')
|
||||
end
|
||||
end
|
||||
|
||||
function love.errhand(msg)
|
||||
if G.F_NO_ERROR_HAND then return end
|
||||
msg = tostring(msg)
|
||||
|
||||
if G.SETTINGS.crashreports and _RELEASE_MODE and G.F_CRASH_REPORTS then
|
||||
local http_thread = love.thread.newThread([[
|
||||
local https = require('https')
|
||||
CHANNEL = love.thread.getChannel("http_channel")
|
||||
|
||||
while true do
|
||||
--Monitor the channel for any new requests
|
||||
local request = CHANNEL:demand()
|
||||
if request then
|
||||
https.request(request)
|
||||
end
|
||||
end
|
||||
]])
|
||||
local http_channel = love.thread.getChannel('http_channel')
|
||||
http_thread:start()
|
||||
local httpencode = function(str)
|
||||
local char_to_hex = function(c)
|
||||
return string.format("%%%02X", string.byte(c))
|
||||
end
|
||||
str = str:gsub("\n", "\r\n"):gsub("([^%w _%%%-%.~])", char_to_hex):gsub(" ", "+")
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
local error = msg
|
||||
local file = string.sub(msg, 0, string.find(msg, ':'))
|
||||
local function_line = string.sub(msg, string.len(file)+1)
|
||||
function_line = string.sub(function_line, 0, string.find(function_line, ':')-1)
|
||||
file = string.sub(file, 0, string.len(file)-1)
|
||||
local trace = debug.traceback()
|
||||
local boot_found, func_found = false, false
|
||||
for l in string.gmatch(trace, "(.-)\n") do
|
||||
if string.match(l, "boot.lua") then
|
||||
boot_found = true
|
||||
elseif boot_found and not func_found then
|
||||
func_found = true
|
||||
trace = ''
|
||||
function_line = string.sub(l, string.find(l, 'in function')+12)..' line:'..function_line
|
||||
end
|
||||
|
||||
if boot_found and func_found then
|
||||
trace = trace..l..'\n'
|
||||
end
|
||||
end
|
||||
|
||||
http_channel:push('https://958ha8ong3.execute-api.us-east-2.amazonaws.com/?error='..httpencode(error)..'&file='..httpencode(file)..'&function_line='..httpencode(function_line)..'&trace='..httpencode(trace)..'&version='..(G.VERSION))
|
||||
end
|
||||
|
||||
if not love.window or not love.graphics or not love.event then
|
||||
return
|
||||
end
|
||||
|
||||
if not love.graphics.isCreated() or not love.window.isOpen() then
|
||||
local success, status = pcall(love.window.setMode, 800, 600)
|
||||
if not success or not status then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset state.
|
||||
if love.mouse then
|
||||
love.mouse.setVisible(true)
|
||||
love.mouse.setGrabbed(false)
|
||||
love.mouse.setRelativeMode(false)
|
||||
end
|
||||
if love.joystick then
|
||||
-- Stop all joystick vibrations.
|
||||
for i,v in ipairs(love.joystick.getJoysticks()) do
|
||||
v:setVibration()
|
||||
end
|
||||
end
|
||||
if love.audio then love.audio.stop() end
|
||||
love.graphics.reset()
|
||||
local font = love.graphics.setNewFont("resources/fonts/m6x11plus.ttf", 20)
|
||||
|
||||
love.graphics.setBackgroundColor(G.C.BLACK)
|
||||
love.graphics.setColor(255, 255, 255, 255)
|
||||
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.origin()
|
||||
|
||||
|
||||
local p = 'Oops! Something went wrong:\n'..msg..'\n\n'..(not _RELEASE_MODE and debug.traceback() or G.SETTINGS.crashreports and
|
||||
'Since you are opted in to sending crash reports, LocalThunk HQ was sent some useful info about what happened.\nDon\'t worry! There is no identifying or personal information. If you would like\nto opt out, change the \'Crash Report\' setting to Off' or
|
||||
'Crash Reports are set to Off. If you would like to send crash reports, please opt in in the Game settings.\nThese crash reports help us avoid issues like this in the future')
|
||||
|
||||
local function draw()
|
||||
local pos = love.window.toPixels(70)
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos)
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
while true do
|
||||
love.event.pump()
|
||||
|
||||
for e, a, b, c in love.event.poll() do
|
||||
if e == "quit" then
|
||||
return
|
||||
elseif e == "keypressed" and a == "escape" then
|
||||
return
|
||||
elseif e == "touchpressed" then
|
||||
local name = love.window.getTitle()
|
||||
if #name == 0 or name == "Untitled" then name = "Game" end
|
||||
local buttons = {"OK", "Cancel"}
|
||||
local pressed = love.window.showMessageBox("Quit "..name.."?", "", buttons)
|
||||
if pressed == 1 then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
draw()
|
||||
|
||||
if love.timer then
|
||||
love.timer.sleep(0.1)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function love.resize(w, h)
|
||||
if w/h < 1 then --Dont allow the screen to be too square, since pop in occurs above and below screen
|
||||
h = w/1
|
||||
end
|
||||
|
||||
--When the window is resized, this code resizes the Canvas, then places the 'room' or gamearea into the middle without streching it
|
||||
if w/h < G.window_prev.orig_ratio then
|
||||
G.TILESCALE = G.window_prev.orig_scale*w/G.window_prev.w
|
||||
else
|
||||
G.TILESCALE = G.window_prev.orig_scale*h/G.window_prev.h
|
||||
end
|
||||
|
||||
if G.ROOM then
|
||||
G.ROOM.T.w = G.TILE_W
|
||||
G.ROOM.T.h = G.TILE_H
|
||||
G.ROOM_ATTACH.T.w = G.TILE_W
|
||||
G.ROOM_ATTACH.T.h = G.TILE_H
|
||||
|
||||
if w/h < G.window_prev.orig_ratio then
|
||||
G.ROOM.T.x = G.ROOM_PADDING_W
|
||||
G.ROOM.T.y = (h/(G.TILESIZE*G.TILESCALE) - (G.ROOM.T.h+G.ROOM_PADDING_H))/2 + G.ROOM_PADDING_H/2
|
||||
else
|
||||
G.ROOM.T.y = G.ROOM_PADDING_H
|
||||
G.ROOM.T.x = (w/(G.TILESIZE*G.TILESCALE) - (G.ROOM.T.w+G.ROOM_PADDING_W))/2 + G.ROOM_PADDING_W/2
|
||||
end
|
||||
|
||||
G.ROOM_ORIG = {
|
||||
x = G.ROOM.T.x,
|
||||
y = G.ROOM.T.y,
|
||||
r = G.ROOM.T.r
|
||||
}
|
||||
|
||||
if G.buttons then G.buttons:recalculate() end
|
||||
if G.HUD then G.HUD:recalculate() end
|
||||
end
|
||||
|
||||
G.WINDOWTRANS = {
|
||||
x = 0, y = 0,
|
||||
w = G.TILE_W+2*G.ROOM_PADDING_W,
|
||||
h = G.TILE_H+2*G.ROOM_PADDING_H,
|
||||
real_window_w = w,
|
||||
real_window_h = h
|
||||
}
|
||||
G.CANV_SCALE = 1
|
||||
|
||||
G.CANVAS = love.graphics.newCanvas(w*G.CANV_SCALE, h*G.CANV_SCALE, {type = '2d', readable = true})
|
||||
G.CANVAS:setFilter('linear', 'linear')
|
||||
end
|
BIN
resources/.DS_Store
vendored
Normal file
BIN
resources/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
resources/fonts/GoNotoCJKCore.ttf
Normal file
BIN
resources/fonts/GoNotoCJKCore.ttf
Normal file
Binary file not shown.
BIN
resources/fonts/GoNotoCurrent-Bold.ttf
Normal file
BIN
resources/fonts/GoNotoCurrent-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/fonts/NotoSans-Bold.ttf
Normal file
BIN
resources/fonts/NotoSans-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/fonts/NotoSansJP-Bold.ttf
Normal file
BIN
resources/fonts/NotoSansJP-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/fonts/NotoSansKR-Bold.ttf
Normal file
BIN
resources/fonts/NotoSansKR-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/fonts/NotoSansSC-Bold.ttf
Normal file
BIN
resources/fonts/NotoSansSC-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/fonts/NotoSansTC-Bold.ttf
Normal file
BIN
resources/fonts/NotoSansTC-Bold.ttf
Normal file
Binary file not shown.
BIN
resources/fonts/m6x11plus.ttf
Normal file
BIN
resources/fonts/m6x11plus.ttf
Normal file
Binary file not shown.
1515
resources/gamecontrollerdb.txt
Normal file
1515
resources/gamecontrollerdb.txt
Normal file
File diff suppressed because it is too large
Load Diff
154
resources/shaders/CRT.fs
Normal file
154
resources/shaders/CRT.fs
Normal file
@ -0,0 +1,154 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 distortion_fac;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 scale_fac;
|
||||
extern MY_HIGHP_OR_MEDIUMP number feather_fac;
|
||||
extern MY_HIGHP_OR_MEDIUMP number noise_fac;
|
||||
extern MY_HIGHP_OR_MEDIUMP number bloom_fac;
|
||||
extern MY_HIGHP_OR_MEDIUMP number crt_intensity;
|
||||
extern MY_HIGHP_OR_MEDIUMP number glitch_intensity;
|
||||
extern MY_HIGHP_OR_MEDIUMP number scanlines;
|
||||
|
||||
#define BUFF 0.01
|
||||
#define BLOOM_AMT 3
|
||||
|
||||
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc)
|
||||
{
|
||||
//Keep the original texture coords
|
||||
vec2 orig_tc = tc;
|
||||
|
||||
//recenter
|
||||
tc = tc*2.0 - vec2(1.0);
|
||||
tc *= scale_fac;
|
||||
|
||||
//bulge from middle
|
||||
tc += (tc.yx*tc.yx) * tc * (distortion_fac - 1.0);
|
||||
|
||||
//smoothly transition the edge to black
|
||||
//buffer for the outer edge, this gets wonky if there is no buffer
|
||||
number mask = (1.0 - smoothstep(1.0-feather_fac,1.0,abs(tc.x) - BUFF))
|
||||
* (1.0 - smoothstep(1.0-feather_fac,1.0,abs(tc.y) - BUFF));
|
||||
|
||||
//undo the recenter
|
||||
tc = (tc + vec2(1.0))/2.0;
|
||||
|
||||
//Create the horizontal glitch offset effects
|
||||
number offset_l = 0.;
|
||||
number offset_r = 0.;
|
||||
if(glitch_intensity > 0.01){
|
||||
number timefac = 3.0*time;
|
||||
offset_l = 50.0*(-3.5+sin(timefac*0.512 + tc.y*40.0)
|
||||
+ sin(-timefac*0.8233 + tc.y*81.532)
|
||||
+ sin(timefac*0.333 + tc.y*30.3)
|
||||
+ sin(-timefac*0.1112331 + tc.y*13.0));
|
||||
offset_r = -50.0*(-3.5+sin(timefac*0.6924 + tc.y*29.0)
|
||||
+ sin(-timefac*0.9661 + tc.y*41.532)
|
||||
+ sin(timefac*0.4423 + tc.y*40.3)
|
||||
+ sin(-timefac*0.13321312 + tc.y*11.0));
|
||||
|
||||
if(glitch_intensity > 1.0){
|
||||
offset_l = 50.0*(-1.5+sin(timefac*0.512 + tc.y*4.0)
|
||||
+ sin(-timefac*0.8233 + tc.y*1.532)
|
||||
+ sin(timefac*0.333 + tc.y*3.3)
|
||||
+ sin(-timefac*0.1112331 + tc.y*1.0));
|
||||
offset_r = -50.0*(-1.5+sin(timefac*0.6924 + tc.y*19.0)
|
||||
+ sin(-timefac*0.9661 + tc.y*21.532)
|
||||
+ sin(timefac*0.4423 + tc.y*20.3)
|
||||
+ sin(-timefac*0.13321312 + tc.y*5.0));
|
||||
}
|
||||
tc.x = tc.x + 0.001*glitch_intensity*clamp(offset_l, clamp(offset_r, -1.0, 0.0), 1.0);
|
||||
}
|
||||
|
||||
//Apply mask and bulging effect
|
||||
vec4 crt_tex = Texel( tex, tc);
|
||||
|
||||
//intensity multiplier for any visual artifacts
|
||||
float artifact_amplifier = (abs(clamp(offset_l, clamp(offset_r, -1.0, 0.0), 1.0))*glitch_intensity > 0.9 ? 3. : 1.);
|
||||
|
||||
//Horizontal Chromatic Aberration
|
||||
float crt_amout_adjusted = (max(0., (crt_intensity)/(0.16*0.3)))*artifact_amplifier;
|
||||
if(crt_amout_adjusted > 0.0000001) {
|
||||
crt_tex.r = crt_tex.r*(1.-crt_amout_adjusted) + crt_amout_adjusted*Texel( tex, tc + vec2(0.0005*(1. +10.*(artifact_amplifier - 1.))*1600./love_ScreenSize.x, 0.)).r;
|
||||
crt_tex.g = crt_tex.g*(1.-crt_amout_adjusted) + crt_amout_adjusted*Texel( tex, tc + vec2(-0.0005*(1. +10.*(artifact_amplifier - 1.))*1600./love_ScreenSize.x, 0.)).g;
|
||||
}
|
||||
vec3 rgb_result = crt_tex.rgb*(1.0 - (1.0*crt_intensity*artifact_amplifier));
|
||||
|
||||
//post processing on the glitch effect to amplify green or red for a few lines of pixels
|
||||
if (sin(time + tc.y*200.0) > 0.85) {
|
||||
if (offset_l < 0.99 && offset_l > 0.01) rgb_result.r = rgb_result.g*1.5;
|
||||
if (offset_r > -0.99 && offset_r < -0.01) rgb_result.g = rgb_result.r*1.5;
|
||||
}
|
||||
|
||||
//Add the pixel scanline overlay, a repeated 'pixel' mask that doesn't actually render the real image. If these pixels were used to render the image it would be too harsh
|
||||
vec3 rgb_scanline = 1.0*vec3(
|
||||
clamp(-0.3+2.0*sin( tc.y * scanlines-3.14/4.0) - 0.8*clamp(sin( tc.x*scanlines*4.0), 0.4, 1.0), -1.0, 2.0),
|
||||
clamp(-0.3+2.0*cos( tc.y * scanlines) - 0.8*clamp(cos( tc.x*scanlines*4.0), 0.0, 1.0), -1.0, 2.0),
|
||||
clamp(-0.3+2.0*cos( tc.y * scanlines -3.14/3.0) - 0.8*clamp(cos( tc.x*scanlines*4.0-3.14/4.0), 0.0, 1.0), -1.0, 2.0));
|
||||
|
||||
rgb_result += crt_tex.rgb * rgb_scanline * crt_intensity * artifact_amplifier;
|
||||
|
||||
//Add in some noise
|
||||
number x = (tc.x - mod(tc.x, 0.002)) * (tc.y - mod(tc.y, 0.0013)) * time * 1000.0;
|
||||
x = mod( x, 13.0 ) * mod( x, 123.0 );
|
||||
number dx = mod( x, 0.11 )/0.11;
|
||||
rgb_result = (1.0-clamp( noise_fac*artifact_amplifier, 0.0,1.0 ))*rgb_result + dx * clamp( noise_fac*artifact_amplifier, 0.0,1.0 ) * vec3(1.0,1.0,1.0);
|
||||
|
||||
//contrast and brightness correction for the CRT effect, also adjusting brightness for bloom
|
||||
rgb_result -= vec3(0.55 - 0.02*(artifact_amplifier - 1. - crt_amout_adjusted*bloom_fac*0.7));
|
||||
rgb_result = rgb_result*(1.0 + 0.14 + crt_amout_adjusted*(0.012 - bloom_fac*0.12));
|
||||
rgb_result += vec3(0.5);
|
||||
|
||||
//Prepare the final colour to return
|
||||
vec4 final_col = vec4( rgb_result*1.0, 1.0 );
|
||||
|
||||
//Finally apply bloom
|
||||
vec4 col = vec4(0.0);
|
||||
float bloom = 0.0;
|
||||
|
||||
if (bloom_fac > 0.00001 && crt_intensity > 0.000001){
|
||||
bloom = 0.03*(max(0., (crt_intensity)/(0.16*0.3)));
|
||||
float bloom_dist = 0.0015*float(BLOOM_AMT);
|
||||
vec4 samp;
|
||||
float cutoff = 0.6;
|
||||
|
||||
for (int i = -BLOOM_AMT; i <= BLOOM_AMT; ++i)
|
||||
for (int j = -BLOOM_AMT; j <= BLOOM_AMT; ++j){
|
||||
samp = Texel( tex, tc + (bloom_dist/float(BLOOM_AMT))*vec2(float(i), float(j)));
|
||||
samp.r = max(1./(1.-cutoff)*samp.r - 1./(1.-cutoff) + 1., 0.);
|
||||
samp.g = max(1./(1.-cutoff)*samp.g - 1./(1.-cutoff) + 1., 0.);
|
||||
samp.b = max(1./(1.-cutoff)*samp.b - 1./(1.-cutoff) + 1., 0.);
|
||||
col += min(min(samp.r,samp.g),samp.b) * (2. - float(abs(float(i+j)))/float(BLOOM_AMT+BLOOM_AMT));
|
||||
}
|
||||
|
||||
col /= float(BLOOM_AMT*BLOOM_AMT);
|
||||
col.a = final_col.a;
|
||||
}
|
||||
|
||||
return (final_col*(1. -1.*bloom) + bloom*col)*mask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef VERTEX
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.002*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
46
resources/shaders/background.fs
Normal file
46
resources/shaders/background.fs
Normal file
@ -0,0 +1,46 @@
|
||||
extern number time;
|
||||
extern number spin_time;
|
||||
extern vec4 colour_1;
|
||||
extern vec4 colour_2;
|
||||
extern vec4 colour_3;
|
||||
extern number contrast;
|
||||
extern number spin_amount;
|
||||
|
||||
#define PIXEL_SIZE_FAC 700.
|
||||
#define SPIN_EASE 0.5
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
//Convert to UV coords (0-1) and floor for pixel effect
|
||||
number pixel_size = length(love_ScreenSize.xy)/PIXEL_SIZE_FAC;
|
||||
vec2 uv = (floor(screen_coords.xy*(1./pixel_size))*pixel_size - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy) - vec2(0.12, 0.);
|
||||
number uv_len = length(uv);
|
||||
|
||||
//Adding in a center swirl, changes with time. Only applies meaningfully if the 'spin amount' is a non-zero number
|
||||
number speed = (spin_time*SPIN_EASE*0.2) + 302.2;
|
||||
number new_pixel_angle = (atan(uv.y, uv.x)) + speed - SPIN_EASE*20.*(1.*spin_amount*uv_len + (1. - 1.*spin_amount));
|
||||
vec2 mid = (love_ScreenSize.xy/length(love_ScreenSize.xy))/2.;
|
||||
uv = (vec2((uv_len * cos(new_pixel_angle) + mid.x), (uv_len * sin(new_pixel_angle) + mid.y)) - mid);
|
||||
|
||||
//Now add the paint effect to the swirled UV
|
||||
uv *= 30.;
|
||||
speed = time*(2.);
|
||||
vec2 uv2 = vec2(uv.x+uv.y);
|
||||
|
||||
for(int i=0; i < 5; i++) {
|
||||
uv2 += sin(max(uv.x, uv.y)) + uv;
|
||||
uv += 0.5*vec2(cos(5.1123314 + 0.353*uv2.y + speed*0.131121),sin(uv2.x - 0.113*speed));
|
||||
uv -= 1.0*cos(uv.x + uv.y) - 1.0*sin(uv.x*0.711 - uv.y);
|
||||
}
|
||||
|
||||
//Make the paint amount range from 0 - 2
|
||||
number contrast_mod = (0.25*contrast + 0.5*spin_amount + 1.2);
|
||||
number paint_res =min(2., max(0.,length(uv)*(0.035)*contrast_mod));
|
||||
number c1p = max(0.,1. - contrast_mod*abs(1.-paint_res));
|
||||
number c2p = max(0.,1. - contrast_mod*abs(paint_res));
|
||||
number c3p = 1. - min(1., c1p + c2p);
|
||||
|
||||
vec4 ret_col = (0.3/contrast)*colour_1 + (1. - 0.3/contrast)*(colour_1*c1p + colour_2*c2p + vec4(c3p*colour_3.rgb, c3p*colour_1.a));
|
||||
|
||||
return ret_col;
|
||||
}
|
98
resources/shaders/booster.fs
Normal file
98
resources/shaders/booster.fs
Normal file
@ -0,0 +1,98 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 booster;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel( texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
number low = min(tex.r, min(tex.g, tex.b));
|
||||
number high = max(tex.r, max(tex.g, tex.b));
|
||||
number delta = max(high-low, low*0.7);
|
||||
|
||||
number fac = 0.8 + 0.9*sin(13.*uv.x+5.32*uv.y + booster.r*12. + cos(booster.r*5.3 + uv.y*4.2 - uv.x*4.));
|
||||
number fac2 = 0.5 + 0.5*sin(10.*uv.x+2.32*uv.y + booster.r*5. - cos(booster.r*2.3 + uv.x*8.2));
|
||||
number fac3 = 0.5 + 0.5*sin(12.*uv.x+6.32*uv.y + booster.r*6.111 + sin(booster.r*5.3 + uv.y*3.2));
|
||||
number fac4 = 0.5 + 0.5*sin(4.*uv.x+2.32*uv.y + booster.r*8.111 + sin(booster.r*1.3 + uv.y*13.2));
|
||||
number fac5 = sin(0.5*16.*uv.x+5.32*uv.y + booster.r*12. + cos(booster.r*5.3 + uv.y*4.2 - uv.x*4.));
|
||||
|
||||
number maxfac = 0.6*max(max(fac, max(fac2, max(fac3,0.0))) + (fac+fac2+fac3*fac4), 0.);
|
||||
|
||||
tex.rgb = tex.rgb*0.5 + vec3(0.4, 0.4, 0.8);
|
||||
|
||||
tex.r = tex.r-delta + delta*maxfac*(0.7 + fac5*0.07) - 0.1;
|
||||
tex.g = tex.g-delta + delta*maxfac*(0.7 - fac5*0.17) - 0.1;
|
||||
tex.b = tex.b-delta + delta*maxfac*0.7 - 0.1;
|
||||
tex.a = tex.a*(0.8*max(min(1., max(0.,0.3*max(low*0.2, delta)+ min(max(maxfac*0.1,0.), 0.4)) ), 0.) + 0.15*maxfac*(0.1+delta));
|
||||
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
149
resources/shaders/debuff.fs
Normal file
149
resources/shaders/debuff.fs
Normal file
@ -0,0 +1,149 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 debuff;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
number hue(number s, number t, number h)
|
||||
{
|
||||
number hs = mod(h, 1.)*6.;
|
||||
if (hs < 1.) return (t-s) * hs + s;
|
||||
if (hs < 3.) return t;
|
||||
if (hs < 4.) return (t-s) * (4.-hs) + s;
|
||||
return s;
|
||||
}
|
||||
|
||||
vec4 RGB(vec4 c)
|
||||
{
|
||||
if (c.y == 0.)
|
||||
return vec4(vec3(c.z), c.a);
|
||||
|
||||
number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
|
||||
number s = 2.0 * c.z - t;
|
||||
return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
|
||||
}
|
||||
|
||||
vec4 HSL(vec4 c)
|
||||
{
|
||||
number low = min(c.r, min(c.g, c.b));
|
||||
number high = max(c.r, max(c.g, c.b));
|
||||
number delta = high - low;
|
||||
number sum = high+low;
|
||||
|
||||
vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
|
||||
if (delta == .0)
|
||||
return hsl;
|
||||
|
||||
hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
|
||||
|
||||
if (high == c.r)
|
||||
hsl.x = (c.g - c.b) / delta;
|
||||
else if (high == c.g)
|
||||
hsl.x = (c.b - c.r) / delta + 2.0;
|
||||
else
|
||||
hsl.x = (c.r - c.g) / delta + 4.0;
|
||||
|
||||
hsl.x = mod(hsl.x / 6., 1.);
|
||||
return hsl;
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel(texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
vec4 SAT = HSL(tex*0.8 + 0.2*vec4(1., 0., 0., tex.a));
|
||||
SAT.g = 0.5;
|
||||
|
||||
number width = 0.0;
|
||||
|
||||
if (debuff.g > 0.0 || debuff.g < 0.0) {
|
||||
width = 0.1;
|
||||
}
|
||||
bool test = false;
|
||||
if ((uv.x+uv.y > 1. - width && uv.x+uv.y < 1. + width) || ((1.-uv.x)+uv.y > 1. - width && (1.-uv.x)+uv.y < 1. + width))
|
||||
{
|
||||
test = true;
|
||||
SAT.r = 1.;
|
||||
SAT.g = 0.7;
|
||||
SAT.b = 0.8*SAT.b;
|
||||
} else{
|
||||
SAT.g = SAT.g*0.5;
|
||||
SAT.b = SAT.b*0.7;
|
||||
}
|
||||
|
||||
|
||||
tex = RGB(SAT);
|
||||
if (!test){
|
||||
tex.a = tex.a*0.3;
|
||||
}
|
||||
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
86
resources/shaders/dissolve.fs
Normal file
86
resources/shaders/dissolve.fs
Normal file
@ -0,0 +1,86 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel( texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
if (!shadow && dissolve > 0.01){
|
||||
if (burn_colour_2.a > 0.01){
|
||||
tex.rgb = tex.rgb*(1.-0.6*dissolve) + 0.6*burn_colour_2.rgb*dissolve;
|
||||
} else if (burn_colour_1.a > 0.01){
|
||||
tex.rgb = tex.rgb*(1.-0.6*dissolve) + 0.6*burn_colour_1.rgb*dissolve;
|
||||
}
|
||||
}
|
||||
|
||||
return dissolve_mask(tex, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
69
resources/shaders/flame.fs
Normal file
69
resources/shaders/flame.fs
Normal file
@ -0,0 +1,69 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP float time;
|
||||
extern MY_HIGHP_OR_MEDIUMP float amount;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 colour_2;
|
||||
extern MY_HIGHP_OR_MEDIUMP float id;
|
||||
|
||||
#define PIXEL_SIZE_FAC 60.
|
||||
#define WHITE vec4(1.,1.,1.,1.)
|
||||
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
float intensity = 1.0*min(10.,amount);
|
||||
if(intensity < 0.1){
|
||||
return vec4(0.,0.,0.,0.);
|
||||
}
|
||||
|
||||
//Convert to UV coords (0-1) and floor for pixel effect
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba - 0.5;
|
||||
vec2 floored_uv = (floor((uv*PIXEL_SIZE_FAC)))/PIXEL_SIZE_FAC;
|
||||
vec2 uv_scaled_centered = (floored_uv);
|
||||
uv_scaled_centered += uv_scaled_centered*0.01*(sin(-1.123*floored_uv.x + 0.2*time)*cos(5.3332*floored_uv.y + time*0.931));
|
||||
vec2 flame_up_vec = vec2(0., mod(4.*time, 10000.) - 5000. + mod(1.781*id, 1000.) );
|
||||
|
||||
float scale_fac = (7.5 + 3./(2. + 2.*intensity));
|
||||
vec2 sv = uv_scaled_centered*scale_fac + flame_up_vec;
|
||||
float speed = mod(20.781*id, 100.) + 1.*sin(time+id)*cos(time*0.151+id);
|
||||
vec2 sv2 = vec2(0.,0.);
|
||||
|
||||
for(int i=0; i < 5; i++) {
|
||||
sv2 += sv + 0.05*sv2.yx*(mod(float(i), 2.)>1.?-1.:1.) + 0.3*(cos(length(sv)*0.411) + 0.3344*sin(length(sv)) - 0.23*cos(length(sv)));
|
||||
sv += 0.5*vec2(
|
||||
cos(cos(sv2.y) + speed*0.0812)*sin(3.22 + (sv2.x) - speed*0.1531),
|
||||
sin(-sv2.x*1.21222 + 0.113785*speed)*cos(sv2.y*0.91213 - 0.13582*speed));
|
||||
}
|
||||
|
||||
//Make the smoke amount range from 0 - 2
|
||||
float smoke_res = max(0.,((length((sv - flame_up_vec)/scale_fac*5.)+ 0.1*(length(uv_scaled_centered) - 0.5))*(2./(2.+ intensity*0.2)))) ;
|
||||
smoke_res = intensity < 0.1 ? 1.: smoke_res + max(0., 2. - 0.3*intensity)*max(0., 2.*(uv_scaled_centered.y - 0.5)*(uv_scaled_centered.y - 0.5));
|
||||
|
||||
if(abs(uv.x) > 0.4){
|
||||
smoke_res = smoke_res + 10.*(abs(uv.x) - 0.4);
|
||||
}
|
||||
if(length((uv - vec2(0., 0.1))*vec2(0.19, 1.)) < min(0.1, intensity*0.5) && smoke_res > 1.){
|
||||
smoke_res = smoke_res + min(8.5,intensity*10.)*(length((uv - vec2(0., 0.1))*vec2(0.19, 1.))-0.1);
|
||||
}
|
||||
|
||||
vec4 ret_col = colour_1;
|
||||
if(smoke_res > 1.){
|
||||
ret_col.a = 0.;
|
||||
}else{
|
||||
if( uv.y < 0.12){
|
||||
ret_col = ret_col*(1. - 0.5*(0.12 - uv.y)) + 2.5*(0.12 - uv.y)*colour_2;
|
||||
ret_col += ret_col*(-2.+0.5*intensity*smoke_res)*(0.12 - uv.y);
|
||||
}
|
||||
ret_col.a = 1.;
|
||||
}
|
||||
|
||||
return ret_col;
|
||||
}
|
23
resources/shaders/flash.fs
Normal file
23
resources/shaders/flash.fs
Normal file
@ -0,0 +1,23 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP number mid_flash;
|
||||
|
||||
#define PIXEL_SIZE_FAC 700.
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
//Convert to UV coords (0-1) and floor for pixel effect
|
||||
number pixel_size = length(love_ScreenSize.xy)/PIXEL_SIZE_FAC;
|
||||
vec2 uv = (floor(screen_coords.xy*(1./pixel_size))*pixel_size - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
|
||||
float mid_white = min(1.,(time > 2.5 ? max(0., sqrt(time - 2.5) - 60.*length(uv)) : 0.)
|
||||
+ (time > 11. ? max(0., (time-11.)*(time-11.) - 5.*length(uv)) : 0.));
|
||||
|
||||
return vec4(1., 1., 1., mid_flash*mid_white);
|
||||
}
|
143
resources/shaders/foil.fs
Normal file
143
resources/shaders/foil.fs
Normal file
@ -0,0 +1,143 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 foil;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
number hue(number s, number t, number h)
|
||||
{
|
||||
number hs = mod(h, 1.)*6.;
|
||||
if (hs < 1.) return (t-s) * hs + s;
|
||||
if (hs < 3.) return t;
|
||||
if (hs < 4.) return (t-s) * (4.-hs) + s;
|
||||
return s;
|
||||
}
|
||||
|
||||
vec4 RGB(vec4 c)
|
||||
{
|
||||
if (c.y < 0.0001)
|
||||
return vec4(vec3(c.z), c.a);
|
||||
|
||||
number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
|
||||
number s = 2.0 * c.z - t;
|
||||
return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
|
||||
}
|
||||
|
||||
vec4 HSL(vec4 c)
|
||||
{
|
||||
number low = min(c.r, min(c.g, c.b));
|
||||
number high = max(c.r, max(c.g, c.b));
|
||||
number delta = high - low;
|
||||
number sum = high+low;
|
||||
|
||||
vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
|
||||
if (delta == .0)
|
||||
return hsl;
|
||||
|
||||
hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
|
||||
|
||||
if (high == c.r)
|
||||
hsl.x = (c.g - c.b) / delta;
|
||||
else if (high == c.g)
|
||||
hsl.x = (c.b - c.r) / delta + 2.0;
|
||||
else
|
||||
hsl.x = (c.r - c.g) / delta + 4.0;
|
||||
|
||||
hsl.x = mod(hsl.x / 6., 1.);
|
||||
return hsl;
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel( texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
vec2 adjusted_uv = uv - vec2(0.5, 0.5);
|
||||
adjusted_uv.x = adjusted_uv.x*texture_details.b/texture_details.a;
|
||||
|
||||
number low = min(tex.r, min(tex.g, tex.b));
|
||||
number high = max(tex.r, max(tex.g, tex.b));
|
||||
number delta = min(high, max(0.5, 1. - low));
|
||||
|
||||
number fac = max(min(2.*sin((length(90.*adjusted_uv) + foil.r*2.) + 3.*(1.+0.8*cos(length(113.1121*adjusted_uv) - foil.r*3.121))) - 1. - max(5.-length(90.*adjusted_uv), 0.), 1.), 0.);
|
||||
vec2 rotater = vec2(cos(foil.r*0.1221), sin(foil.r*0.3512));
|
||||
number angle = dot(rotater, adjusted_uv)/(length(rotater)*length(adjusted_uv));
|
||||
number fac2 = max(min(5.*cos(foil.g*0.3 + angle*3.14*(2.2+0.9*sin(foil.r*1.65 + 0.2*foil.g))) - 4. - max(2.-length(20.*adjusted_uv), 0.), 1.), 0.);
|
||||
number fac3 = 0.3*max(min(2.*sin(foil.r*5. + uv.x*3. + 3.*(1.+0.5*cos(foil.r*7.))) - 1., 1.), -1.);
|
||||
number fac4 = 0.3*max(min(2.*sin(foil.r*6.66 + uv.y*3.8 + 3.*(1.+0.5*cos(foil.r*3.414))) - 1., 1.), -1.);
|
||||
|
||||
number maxfac = max(max(fac, max(fac2, max(fac3, max(fac4, 0.0)))) + 2.2*(fac+fac2+fac3+fac4), 0.);
|
||||
|
||||
tex.r = tex.r-delta + delta*maxfac*0.3;
|
||||
tex.g = tex.g-delta + delta*maxfac*0.3;
|
||||
tex.b = tex.b + delta*maxfac*1.9;
|
||||
tex.a = min(tex.a, 0.3*tex.a + 0.9*min(0.5, maxfac*0.1));
|
||||
|
||||
return dissolve_mask(tex, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
22
resources/shaders/gold_seal.fs
Normal file
22
resources/shaders/gold_seal.fs
Normal file
@ -0,0 +1,22 @@
|
||||
extern vec4 gold_seal;
|
||||
|
||||
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
//r controls timing
|
||||
//a controls alpha, but white will always be 1
|
||||
vec4 pixel;
|
||||
pixel = Texel(texture, texture_coords);
|
||||
number low = min(pixel.r, min(pixel.g, pixel.b));
|
||||
number high = max(pixel.r, max(pixel.g, pixel.b));
|
||||
number delta;
|
||||
delta = high*0.5;
|
||||
|
||||
number fac;
|
||||
fac = 0.3+sin((texture_coords.x*450. + sin(gold_seal.r*6.)*180.)-700.*gold_seal.r) - sin((texture_coords.x*190. + texture_coords.y*30.)+1080.3*gold_seal.r);
|
||||
|
||||
pixel.r = max(pixel.r, (1. - pixel.r)*delta*fac + pixel.r);
|
||||
pixel.g = max(pixel.g, (1. - pixel.g)*delta*fac + pixel.g);
|
||||
pixel.b = max(pixel.b, (1. - pixel.b)*delta*fac + pixel.b);
|
||||
|
||||
return pixel;
|
||||
}
|
152
resources/shaders/holo.fs
Normal file
152
resources/shaders/holo.fs
Normal file
@ -0,0 +1,152 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 holo;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
number hue(number s, number t, number h)
|
||||
{
|
||||
number hs = mod(h, 1.)*6.;
|
||||
if (hs < 1.) return (t-s) * hs + s;
|
||||
if (hs < 3.) return t;
|
||||
if (hs < 4.) return (t-s) * (4.-hs) + s;
|
||||
return s;
|
||||
}
|
||||
|
||||
vec4 RGB(vec4 c)
|
||||
{
|
||||
if (c.y < 0.0001)
|
||||
return vec4(vec3(c.z), c.a);
|
||||
|
||||
number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
|
||||
number s = 2.0 * c.z - t;
|
||||
return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
|
||||
}
|
||||
|
||||
vec4 HSL(vec4 c)
|
||||
{
|
||||
number low = min(c.r, min(c.g, c.b));
|
||||
number high = max(c.r, max(c.g, c.b));
|
||||
number delta = high - low;
|
||||
number sum = high+low;
|
||||
|
||||
vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
|
||||
if (delta == .0)
|
||||
return hsl;
|
||||
|
||||
hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
|
||||
|
||||
if (high == c.r)
|
||||
hsl.x = (c.g - c.b) / delta;
|
||||
else if (high == c.g)
|
||||
hsl.x = (c.b - c.r) / delta + 2.0;
|
||||
else
|
||||
hsl.x = (c.r - c.g) / delta + 4.0;
|
||||
|
||||
hsl.x = mod(hsl.x / 6., 1.);
|
||||
return hsl;
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel(texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
vec4 hsl = HSL(0.5*tex + 0.5*vec4(0.,0.,1.,tex.a));
|
||||
|
||||
float t = holo.y*7.221 + time;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/texture_details.ba;
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 250.;
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
|
||||
float res = (.5 + .5* cos( (holo.x) * 2.612 + ( field + -.5 ) *3.14));
|
||||
|
||||
number low = min(tex.r, min(tex.g, tex.b));
|
||||
number high = max(tex.r, max(tex.g, tex.b));
|
||||
number delta = 0.2+0.3*(high- low) + 0.1*high;
|
||||
|
||||
number gridsize = 0.79;
|
||||
number fac = 0.5*max(max(max(0., 7.*abs(cos(uv.x*gridsize*20.))-6.),max(0., 7.*cos(uv.y*gridsize*45. + uv.x*gridsize*20.)-6.)), max(0., 7.*cos(uv.y*gridsize*45. - uv.x*gridsize*20.)-6.));
|
||||
|
||||
hsl.x = hsl.x + res + fac;
|
||||
hsl.y = hsl.y*1.3;
|
||||
hsl.z = hsl.z*0.6+0.4;
|
||||
|
||||
tex =(1.-delta)*tex + delta*RGB(hsl)*vec4(0.9,0.8,1.2,tex.a);
|
||||
|
||||
if (tex[3] < 0.7)
|
||||
tex[3] = tex[3]/3.;
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
129
resources/shaders/hologram.fs
Normal file
129
resources/shaders/hologram.fs
Normal file
@ -0,0 +1,129 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 hologram;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
//Glow effect
|
||||
number glow = 0.;
|
||||
int glow_samples = 4;
|
||||
int actual_glow_samples = 0;
|
||||
number glow_dist = 0.0015;
|
||||
number _a = 0.;
|
||||
|
||||
for (int i = -glow_samples; i <= glow_samples; ++i){
|
||||
for (int j = -glow_samples; j <= glow_samples; ++j){
|
||||
_a = Texel( texture, texture_coords + (glow_dist)*vec2(float(i), float(j))).a;
|
||||
if (_a < 0.9){
|
||||
actual_glow_samples += 1;
|
||||
glow = glow + _a;
|
||||
}
|
||||
}
|
||||
}
|
||||
glow /= 0.7*float(actual_glow_samples);
|
||||
|
||||
//Create the horizontal glitch offset effects
|
||||
number offset_l = 0.;
|
||||
number offset_r = 0.;
|
||||
number timefac = 1.0*hologram.g;
|
||||
offset_l = -10.0*(-0.5+sin(timefac*0.512 + texture_coords.y*14.0)
|
||||
+ sin(-timefac*0.8233 + texture_coords.y*11.532)
|
||||
+ sin(timefac*0.333 + texture_coords.y*13.3)
|
||||
+ sin(-timefac*0.1112331 + texture_coords.y*4.044343));
|
||||
offset_r = -10.0*(-0.5+sin(timefac*0.6924 + texture_coords.y*19.0)
|
||||
+ sin(-timefac*0.9661 + texture_coords.y*21.532)
|
||||
+ sin(timefac*0.4423 + texture_coords.y*30.3)
|
||||
+ sin(-timefac*0.13321312 + texture_coords.y*3.011));
|
||||
if (offset_r >= 1.5 || offset_r <= 0.){offset_r = 0.;}
|
||||
if (offset_l >= 1.5 || offset_l <= 0.){offset_l = 0.;}
|
||||
texture_coords.x = texture_coords.x + 0.002*(-offset_l + offset_r);
|
||||
|
||||
vec4 tex = Texel( texture, texture_coords);
|
||||
if (tex.a > 0.999){tex = vec4(0.,0.,0.,0.);}
|
||||
if (tex.a < 0.001){tex.rgb = vec3(0.,1.,1.);}
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
if (uv.x >0.95 || uv.x < 0.05 || uv.y > 0.95 || uv.y < 0.05){
|
||||
return vec4(0.,0.,0.,0.);
|
||||
}
|
||||
|
||||
number light_strength = 0.4*(0.3*sin(2.*hologram.g) + 0.6 + 0.3*sin(hologram.r*3.) + 0.9);
|
||||
vec4 final_col;
|
||||
if (tex.a < 0.001){
|
||||
final_col = tex*colour + vec4(0., 1., .5,0.6)*light_strength*(1.+abs(offset_l)+abs(offset_r))*glow;
|
||||
}
|
||||
else{
|
||||
final_col = tex*colour + vec4(0., 0.3, 0.2,0.3)*light_strength*(1.+abs(offset_l)+abs(offset_r))*glow;
|
||||
}
|
||||
|
||||
//
|
||||
return dissolve_mask(final_col, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
133
resources/shaders/negative.fs
Normal file
133
resources/shaders/negative.fs
Normal file
@ -0,0 +1,133 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 negative;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
number hue(number s, number t, number h)
|
||||
{
|
||||
number hs = mod(h, 1.)*6.;
|
||||
if (hs < 1.) return (t-s) * hs + s;
|
||||
if (hs < 3.) return t;
|
||||
if (hs < 4.) return (t-s) * (4.-hs) + s;
|
||||
return s;
|
||||
}
|
||||
|
||||
vec4 RGB(vec4 c)
|
||||
{
|
||||
if (c.y < 0.0001)
|
||||
return vec4(vec3(c.z), c.a);
|
||||
|
||||
number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
|
||||
number s = 2.0 * c.z - t;
|
||||
return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
|
||||
}
|
||||
|
||||
vec4 HSL(vec4 c)
|
||||
{
|
||||
number low = min(c.r, min(c.g, c.b));
|
||||
number high = max(c.r, max(c.g, c.b));
|
||||
number delta = high - low;
|
||||
number sum = high+low;
|
||||
|
||||
vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
|
||||
if (delta == .0)
|
||||
return hsl;
|
||||
|
||||
hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
|
||||
|
||||
if (high == c.r)
|
||||
hsl.x = (c.g - c.b) / delta;
|
||||
else if (high == c.g)
|
||||
hsl.x = (c.b - c.r) / delta + 2.0;
|
||||
else
|
||||
hsl.x = (c.r - c.g) / delta + 4.0;
|
||||
|
||||
hsl.x = mod(hsl.x / 6., 1.);
|
||||
return hsl;
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel(texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
vec4 SAT = HSL(tex);
|
||||
|
||||
if (negative.g > 0.0 || negative.g < 0.0) {
|
||||
SAT.b = (1.-SAT.b);
|
||||
}
|
||||
SAT.r = -SAT.r+0.2;
|
||||
|
||||
tex = RGB(SAT) + 0.8*vec4(79./255., 99./255.,103./255.,0.);
|
||||
|
||||
if (tex[3] < 0.7)
|
||||
tex[3] = tex[3]/3.;
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
98
resources/shaders/negative_shine.fs
Normal file
98
resources/shaders/negative_shine.fs
Normal file
@ -0,0 +1,98 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 negative_shine;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel( texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
number low = min(tex.r, min(tex.g, tex.b));
|
||||
number high = max(tex.r, max(tex.g, tex.b));
|
||||
number delta = high-low -0.1;
|
||||
|
||||
number fac = 0.8 + 0.9*sin(11.*uv.x+4.32*uv.y + negative_shine.r*12. + cos(negative_shine.r*5.3 + uv.y*4.2 - uv.x*4.));
|
||||
number fac2 = 0.5 + 0.5*sin(8.*uv.x+2.32*uv.y + negative_shine.r*5. - cos(negative_shine.r*2.3 + uv.x*8.2));
|
||||
number fac3 = 0.5 + 0.5*sin(10.*uv.x+5.32*uv.y + negative_shine.r*6.111 + sin(negative_shine.r*5.3 + uv.y*3.2));
|
||||
number fac4 = 0.5 + 0.5*sin(3.*uv.x+2.32*uv.y + negative_shine.r*8.111 + sin(negative_shine.r*1.3 + uv.y*11.2));
|
||||
number fac5 = sin(0.9*16.*uv.x+5.32*uv.y + negative_shine.r*12. + cos(negative_shine.r*5.3 + uv.y*4.2 - uv.x*4.));
|
||||
|
||||
number maxfac = 0.7*max(max(fac, max(fac2, max(fac3,0.0))) + (fac+fac2+fac3*fac4), 0.);
|
||||
|
||||
tex.rgb = tex.rgb*0.5 + vec3(0.4, 0.4, 0.8);
|
||||
|
||||
tex.r = tex.r-delta + delta*maxfac*(0.7 + fac5*0.27) - 0.1;
|
||||
tex.g = tex.g-delta + delta*maxfac*(0.7 - fac5*0.27) - 0.1;
|
||||
tex.b = tex.b-delta + delta*maxfac*0.7 - 0.1;
|
||||
tex.a = tex.a*(0.5*max(min(1., max(0.,0.3*max(low*0.2, delta)+ min(max(maxfac*0.1,0.), 0.4)) ), 0.) + 0.15*maxfac*(0.1+delta));
|
||||
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
130
resources/shaders/played.fs
Normal file
130
resources/shaders/played.fs
Normal file
@ -0,0 +1,130 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 played;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
number hue(number s, number t, number h)
|
||||
{
|
||||
number hs = mod(h, 1.)*6.;
|
||||
if (hs < 1.) return (t-s) * hs + s;
|
||||
if (hs < 3.) return t;
|
||||
if (hs < 4.) return (t-s) * (4.-hs) + s;
|
||||
return s;
|
||||
}
|
||||
|
||||
vec4 RGB(vec4 c)
|
||||
{
|
||||
if (c.y == 0.)
|
||||
return vec4(vec3(c.z), c.a);
|
||||
|
||||
number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
|
||||
number s = 2.0 * c.z - t;
|
||||
return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
|
||||
}
|
||||
|
||||
vec4 HSL(vec4 c)
|
||||
{
|
||||
number low = min(c.r, min(c.g, c.b));
|
||||
number high = max(c.r, max(c.g, c.b));
|
||||
number delta = high - low;
|
||||
number sum = high+low;
|
||||
|
||||
vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
|
||||
if (delta == .0)
|
||||
return hsl;
|
||||
|
||||
hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
|
||||
|
||||
if (high == c.r)
|
||||
hsl.x = (c.g - c.b) / delta;
|
||||
else if (high == c.g)
|
||||
hsl.x = (c.b - c.r) / delta + 2.0;
|
||||
else
|
||||
hsl.x = (c.r - c.g) / delta + 4.0;
|
||||
|
||||
hsl.x = mod(hsl.x / 6., 1.);
|
||||
return hsl;
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel(texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
vec4 SAT = HSL(tex);
|
||||
SAT.g = SAT.g*0.5 + 0.000001*played.r;
|
||||
SAT.b = SAT.b*0.8;
|
||||
|
||||
tex = RGB(SAT);
|
||||
tex.a = tex.a*0.5;
|
||||
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
150
resources/shaders/polychrome.fs
Normal file
150
resources/shaders/polychrome.fs
Normal file
@ -0,0 +1,150 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 polychrome;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
number hue(number s, number t, number h)
|
||||
{
|
||||
number hs = mod(h, 1.)*6.;
|
||||
if (hs < 1.) return (t-s) * hs + s;
|
||||
if (hs < 3.) return t;
|
||||
if (hs < 4.) return (t-s) * (4.-hs) + s;
|
||||
return s;
|
||||
}
|
||||
|
||||
vec4 RGB(vec4 c)
|
||||
{
|
||||
if (c.y < 0.0001)
|
||||
return vec4(vec3(c.z), c.a);
|
||||
|
||||
number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
|
||||
number s = 2.0 * c.z - t;
|
||||
return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
|
||||
}
|
||||
|
||||
vec4 HSL(vec4 c)
|
||||
{
|
||||
number low = min(c.r, min(c.g, c.b));
|
||||
number high = max(c.r, max(c.g, c.b));
|
||||
number delta = high - low;
|
||||
number sum = high+low;
|
||||
|
||||
vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
|
||||
if (delta == .0)
|
||||
return hsl;
|
||||
|
||||
hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
|
||||
|
||||
if (high == c.r)
|
||||
hsl.x = (c.g - c.b) / delta;
|
||||
else if (high == c.g)
|
||||
hsl.x = (c.b - c.r) / delta + 2.0;
|
||||
else
|
||||
hsl.x = (c.r - c.g) / delta + 4.0;
|
||||
|
||||
hsl.x = mod(hsl.x / 6., 1.);
|
||||
return hsl;
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel(texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
number low = min(tex.r, min(tex.g, tex.b));
|
||||
number high = max(tex.r, max(tex.g, tex.b));
|
||||
number delta = high - low;
|
||||
|
||||
number saturation_fac = 1. - max(0., 0.05*(1.1-delta));
|
||||
|
||||
vec4 hsl = HSL(vec4(tex.r*saturation_fac, tex.g*saturation_fac, tex.b, tex.a));
|
||||
|
||||
float t = polychrome.y*2.221 + time;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/texture_details.ba;
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 50.;
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
|
||||
float res = (.5 + .5* cos( (polychrome.x) * 2.612 + ( field + -.5 ) *3.14));
|
||||
hsl.x = hsl.x+ res + polychrome.y*0.04;
|
||||
hsl.y = min(0.6,hsl.y+0.5);
|
||||
|
||||
tex.rgb = RGB(hsl).rgb;
|
||||
|
||||
if (tex[3] < 0.7)
|
||||
tex[3] = tex[3]/3.;
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
18
resources/shaders/skew.fs
Normal file
18
resources/shaders/skew.fs
Normal file
@ -0,0 +1,18 @@
|
||||
extern vec2 mouse_screen_pos;
|
||||
extern float hovering;
|
||||
extern float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
50
resources/shaders/splash.fs
Normal file
50
resources/shaders/splash.fs
Normal file
@ -0,0 +1,50 @@
|
||||
extern number time;
|
||||
extern number vort_speed;
|
||||
extern vec4 colour_1;
|
||||
extern vec4 colour_2;
|
||||
extern number mid_flash;
|
||||
extern number vort_offset;
|
||||
|
||||
#define PIXEL_SIZE_FAC 700.
|
||||
#define BLACK 0.6*vec4(79./255.,99./255., 103./255., 1./0.6)
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
//Convert to UV coords (0-1) and floor for pixel effect
|
||||
number pixel_size = length(love_ScreenSize.xy)/PIXEL_SIZE_FAC;
|
||||
vec2 uv = (floor(screen_coords.xy*(1./pixel_size))*pixel_size - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
number uv_len = length(uv);
|
||||
|
||||
//Adding in a center swirl, changes with time
|
||||
number speed = time*vort_speed;
|
||||
number new_pixel_angle = atan(uv.y, uv.x) + (2.2 + 0.4*min(6.,speed))*uv_len - 1. - speed*0.05 - min(6.,speed)*speed*0.02 + vort_offset;
|
||||
vec2 mid = (love_ScreenSize.xy/length(love_ScreenSize.xy))/2.;
|
||||
vec2 sv = vec2((uv_len * cos(new_pixel_angle) + mid.x), (uv_len * sin(new_pixel_angle) + mid.y)) - mid;
|
||||
|
||||
//Now add the smoke effect to the swirled UV
|
||||
|
||||
sv *= 30.;
|
||||
speed = time*(6.)*vort_speed + vort_offset + 1033.;
|
||||
vec2 uv2 = vec2(sv.x+sv.y);
|
||||
|
||||
for(int i=0; i < 5; i++) {
|
||||
uv2 += sin(max(sv.x, sv.y)) + sv;
|
||||
sv += 0.5*vec2(cos(5.1123314 + 0.353*uv2.y + speed*0.131121),sin(uv2.x - 0.113*speed));
|
||||
sv -= 1.0*cos(sv.x + sv.y) - 1.0*sin(sv.x*0.711 - sv.y);
|
||||
}
|
||||
|
||||
//Make the smoke amount range from 0 - 2
|
||||
number smoke_res =min(2., max(-2., 1.5 + length(sv)*0.12 - 0.17*(min(10.,time*1.2 - 4.))));
|
||||
if (smoke_res < 0.2) {
|
||||
smoke_res = (smoke_res - 0.2)*0.6 + 0.2;
|
||||
}
|
||||
|
||||
number c1p = max(0.,1. - 2.*abs(1.-smoke_res));
|
||||
number c2p = max(0.,1. - 2.*(smoke_res));
|
||||
number cb = 1. - min(1., c1p + c2p);
|
||||
|
||||
vec4 ret_col = colour_1*c1p + colour_2*c2p + vec4(cb*BLACK.rgb, cb*colour_1.a);
|
||||
number mod_flash = max(mid_flash*0.8, max(c1p, c2p)*5. - 4.4) + mid_flash*max(c1p, c2p);
|
||||
|
||||
return ret_col*(1. - mod_flash) + mod_flash*vec4(1., 1., 1., 1.);
|
||||
}
|
21
resources/shaders/vortex.fs
Normal file
21
resources/shaders/vortex.fs
Normal file
@ -0,0 +1,21 @@
|
||||
extern float vortex_amt;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
vec2 uv = (vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
|
||||
float effectRadius = 1.6 - 0.05*vortex_amt;
|
||||
float effectAngle = 0.5 + 0.15*vortex_amt;
|
||||
|
||||
float len = length(uv * vec2(love_ScreenSize.x / love_ScreenSize.y, 1.));
|
||||
float angle = atan(uv.y, uv.x) + effectAngle * smoothstep(effectRadius, 0., len);
|
||||
float radius = length(uv);
|
||||
|
||||
vec2 center = 0.5*love_ScreenSize.xy/length(love_ScreenSize.xy);
|
||||
|
||||
vertex_position.x = (radius * cos(angle) + center.x)*length(love_ScreenSize.xy);
|
||||
vertex_position.y = (radius * sin(angle) + center.y)*length(love_ScreenSize.xy);
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
#endif
|
98
resources/shaders/voucher.fs
Normal file
98
resources/shaders/voucher.fs
Normal file
@ -0,0 +1,98 @@
|
||||
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
|
||||
#define MY_HIGHP_OR_MEDIUMP highp
|
||||
#else
|
||||
#define MY_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 voucher;
|
||||
extern MY_HIGHP_OR_MEDIUMP number dissolve;
|
||||
extern MY_HIGHP_OR_MEDIUMP number time;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
|
||||
extern bool shadow;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
|
||||
extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
|
||||
|
||||
vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
|
||||
{
|
||||
if (dissolve < 0.001) {
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
|
||||
}
|
||||
|
||||
float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values
|
||||
|
||||
float t = time * 10.0 + 2003.;
|
||||
vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
|
||||
vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
|
||||
|
||||
vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
|
||||
vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532));
|
||||
vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
|
||||
|
||||
float field = (1.+ (
|
||||
cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
|
||||
cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
|
||||
vec2 borders = vec2(0.2, 0.8);
|
||||
|
||||
float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
|
||||
- (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
|
||||
- (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
|
||||
|
||||
if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
|
||||
tex.rgba = burn_colour_1.rgba;
|
||||
} else if (burn_colour_2.a > 0.01) {
|
||||
tex.rgba = burn_colour_2.rgba;
|
||||
}
|
||||
}
|
||||
|
||||
return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
|
||||
}
|
||||
|
||||
vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
|
||||
{
|
||||
vec4 tex = Texel( texture, texture_coords);
|
||||
vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
|
||||
|
||||
number low = min(tex.r, min(tex.g, tex.b));
|
||||
number high = max(tex.r, max(tex.g, tex.b));
|
||||
number delta = high-low;
|
||||
|
||||
number fac = 0.8 + 0.9*sin(13.*uv.x+5.32*uv.y + voucher.r*12. + cos(voucher.r*5.3 + uv.y*4.2 - uv.x*4.));
|
||||
number fac2 = 0.5 + 0.5*sin(10.*uv.x+2.32*uv.y + voucher.r*5. - cos(voucher.r*2.3 + uv.x*8.2));
|
||||
number fac3 = 0.5 + 0.5*sin(12.*uv.x+6.32*uv.y + voucher.r*6.111 + sin(voucher.r*5.3 + uv.y*3.2));
|
||||
number fac4 = 0.5 + 0.5*sin(4.*uv.x+2.32*uv.y + voucher.r*8.111 + sin(voucher.r*1.3 + uv.y*13.2));
|
||||
number fac5 = sin(0.5*16.*uv.x+5.32*uv.y + voucher.r*12. + cos(voucher.r*5.3 + uv.y*4.2 - uv.x*4.));
|
||||
|
||||
number maxfac = 0.6*max(max(fac, max(fac2, max(fac3,0.0))) + (fac+fac2+fac3*fac4), 0.);
|
||||
|
||||
tex.rgb = tex.rgb*0.5 + vec3(0.4, 0.4, 0.8);
|
||||
|
||||
tex.r = tex.r-delta + delta*maxfac*(0.7 + fac5*0.07) - 0.1;
|
||||
tex.g = tex.g-delta + delta*maxfac*(0.7 - fac5*0.17) - 0.1;
|
||||
tex.b = tex.b-delta + delta*maxfac*0.7 - 0.1;
|
||||
tex.a = tex.a*(0.8*max(min(1., max(0.,0.3*max(low*0.2, delta)+ min(max(maxfac*0.1,0.), 0.4)) ), 0.) + 0.15*maxfac*(0.1+delta));
|
||||
|
||||
return dissolve_mask(tex*colour, texture_coords, uv);
|
||||
}
|
||||
|
||||
extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
|
||||
extern MY_HIGHP_OR_MEDIUMP float hovering;
|
||||
extern MY_HIGHP_OR_MEDIUMP float screen_scale;
|
||||
|
||||
#ifdef VERTEX
|
||||
vec4 position( mat4 transform_projection, vec4 vertex_position )
|
||||
{
|
||||
if (hovering <= 0.){
|
||||
return transform_projection * vertex_position;
|
||||
}
|
||||
float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
|
||||
vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
|
||||
float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
|
||||
*hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
|
||||
|
||||
return transform_projection * vertex_position + vec4(0,0,0,scale);
|
||||
}
|
||||
#endif
|
BIN
resources/sounds/ambientFire1.ogg
Normal file
BIN
resources/sounds/ambientFire1.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/ambientFire2.ogg
Normal file
BIN
resources/sounds/ambientFire2.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/ambientFire3.ogg
Normal file
BIN
resources/sounds/ambientFire3.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/ambientOrgan1.ogg
Normal file
BIN
resources/sounds/ambientOrgan1.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/button.ogg
Normal file
BIN
resources/sounds/button.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/cancel.ogg
Normal file
BIN
resources/sounds/cancel.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/card1.ogg
Normal file
BIN
resources/sounds/card1.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/card3.ogg
Normal file
BIN
resources/sounds/card3.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/cardFan2.ogg
Normal file
BIN
resources/sounds/cardFan2.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/cardSlide1.ogg
Normal file
BIN
resources/sounds/cardSlide1.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/cardSlide2.ogg
Normal file
BIN
resources/sounds/cardSlide2.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/chips1.ogg
Normal file
BIN
resources/sounds/chips1.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/chips2.ogg
Normal file
BIN
resources/sounds/chips2.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/coin1.ogg
Normal file
BIN
resources/sounds/coin1.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/coin2.ogg
Normal file
BIN
resources/sounds/coin2.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/coin3.ogg
Normal file
BIN
resources/sounds/coin3.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/coin4.ogg
Normal file
BIN
resources/sounds/coin4.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/coin5.ogg
Normal file
BIN
resources/sounds/coin5.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/coin6.ogg
Normal file
BIN
resources/sounds/coin6.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/coin7.ogg
Normal file
BIN
resources/sounds/coin7.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/crumple1.ogg
Normal file
BIN
resources/sounds/crumple1.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/crumple2.ogg
Normal file
BIN
resources/sounds/crumple2.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/crumple3.ogg
Normal file
BIN
resources/sounds/crumple3.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/crumple4.ogg
Normal file
BIN
resources/sounds/crumple4.ogg
Normal file
Binary file not shown.
BIN
resources/sounds/crumple5.ogg
Normal file
BIN
resources/sounds/crumple5.ogg
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user