├── .gitignore ├── assets ├── 1x │ ├── icon.png │ ├── tags.png │ ├── backs.png │ ├── cines.png │ ├── jokers.png │ ├── sleeves.png │ ├── boosters.png │ └── vouchers.png ├── 2x │ ├── icon.png │ ├── tags.png │ ├── backs.png │ ├── cines.png │ ├── jokers.png │ ├── sleeves.png │ ├── boosters.png │ └── vouchers.png └── shaders │ ├── ticket.fs │ ├── cine_negative.fs │ ├── ticket_polychrome.fs │ ├── ticket_negative.fs │ └── cine_polychrome.fs ├── config.lua ├── README.md ├── Reverie.json ├── data ├── shaders.lua ├── atlases.lua ├── jokers.lua ├── backs.lua ├── consumables.lua ├── vouchers.lua ├── sleeves.lua ├── tags.lua ├── boosters.lua ├── joker_display.lua └── cines.lua ├── Reverie.lua ├── lovely ├── card_draw_patches.toml └── risky_patches.toml ├── lovely.toml ├── localization ├── ko.lua ├── zh_CN.lua └── en-us.lua └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *.aseprite 2 | *.zip 3 | -------------------------------------------------------------------------------- /assets/1x/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/icon.png -------------------------------------------------------------------------------- /assets/1x/tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/tags.png -------------------------------------------------------------------------------- /assets/2x/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/icon.png -------------------------------------------------------------------------------- /assets/2x/tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/tags.png -------------------------------------------------------------------------------- /assets/1x/backs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/backs.png -------------------------------------------------------------------------------- /assets/1x/cines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/cines.png -------------------------------------------------------------------------------- /assets/1x/jokers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/jokers.png -------------------------------------------------------------------------------- /assets/1x/sleeves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/sleeves.png -------------------------------------------------------------------------------- /assets/2x/backs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/backs.png -------------------------------------------------------------------------------- /assets/2x/cines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/cines.png -------------------------------------------------------------------------------- /assets/2x/jokers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/jokers.png -------------------------------------------------------------------------------- /assets/2x/sleeves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/sleeves.png -------------------------------------------------------------------------------- /assets/1x/boosters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/boosters.png -------------------------------------------------------------------------------- /assets/1x/vouchers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/1x/vouchers.png -------------------------------------------------------------------------------- /assets/2x/boosters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/boosters.png -------------------------------------------------------------------------------- /assets/2x/vouchers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumbocarrot0/reverie/HEAD/assets/2x/vouchers.png -------------------------------------------------------------------------------- /config.lua: -------------------------------------------------------------------------------- 1 | return { 2 | jokerdisplay_compat = true, 3 | custom_morsel_compat = true, 4 | tag_packs_shop = false, 5 | crazy_packs_shop = false, 6 | cartomancer_compat = true 7 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | # Reverie 🎥 5 | 6 | A movie-themed [Balatro](https://store.steampowered.com/app/2379780/Balatro/) expansion that focuses on providing special shops and various contents around it 7 | 8 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/jumbocarrot0/reverie)](https://github.com/jumbocarrot0/reverie/releases) 9 |
-------------------------------------------------------------------------------- /Reverie.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "Reverie", 3 | "name": "Reverie", 4 | "author": ["DVRP"], 5 | "description": "A movie-themed expansion that focuses on providing special shops and various contents around it", 6 | "badge_colour": "9db95f", 7 | "version": "1.5.4b", 8 | "prefix": "dvrprv", 9 | "main_file": "Reverie.lua", 10 | "priority": 1, 11 | "dependencies": [ 12 | "Steamodded (>=1.0.0~BETA-0301a)", 13 | "Lovely (>=0.7.1)" 14 | ], 15 | "conflicts": [ 16 | "CardSleeves (<<1.6.0)" 17 | ] 18 | } -------------------------------------------------------------------------------- /data/shaders.lua: -------------------------------------------------------------------------------- 1 | Reverie.shaders = { 2 | { 3 | key = "cine_polychrome", 4 | path = "cine_polychrome.fs" 5 | }, 6 | { 7 | key = "cine_negative", 8 | path = "cine_negative.fs" 9 | }, 10 | { 11 | key = "ticket", 12 | path = "ticket.fs" 13 | }, 14 | { 15 | key = "ticket_negative", 16 | path = "ticket_negative.fs" 17 | }, 18 | { 19 | key = "ticket_polychrome", 20 | path = "ticket_polychrome.fs" 21 | } 22 | } 23 | 24 | for _, v in pairs(Reverie.shaders) do 25 | SMODS.Shader(v) 26 | end -------------------------------------------------------------------------------- /Reverie.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------- 2 | ------------MOD CODE ------------------------- 3 | 4 | SMODS.load_file("data/main.lua")() 5 | SMODS.load_file("data/jokers.lua")() 6 | SMODS.load_file("data/boosters.lua")() 7 | SMODS.load_file("data/cines.lua")() 8 | SMODS.load_file("data/tags.lua")() 9 | SMODS.load_file("data/backs.lua")() 10 | SMODS.load_file("data/consumables.lua")() 11 | SMODS.load_file("data/vouchers.lua")() 12 | SMODS.load_file("data/atlases.lua")() 13 | SMODS.load_file("data/shaders.lua")() 14 | 15 | if Reverie.find_mod("JokerDisplay") and _G["JokerDisplay"] then 16 | SMODS.load_file("data/joker_display.lua")() 17 | end 18 | 19 | if Reverie.find_mod("CardSleeves") and CardSleeves.Sleeve then 20 | SMODS.load_file("data/sleeves.lua")() 21 | end -------------------------------------------------------------------------------- /data/atlases.lua: -------------------------------------------------------------------------------- 1 | Reverie.atlases = { 2 | { 3 | key = "modicon", 4 | path = "icon.png", 5 | px = 34, 6 | py = 34 7 | }, 8 | { 9 | key = "Cine", 10 | path = "cines.png", 11 | px = 71, 12 | py = 95 13 | }, 14 | { 15 | key = "cine_jokers", 16 | path = "jokers.png", 17 | px = 71, 18 | py = 95 19 | }, 20 | { 21 | key = "cine_boosters", 22 | path = "boosters.png", 23 | px = 71, 24 | py = 95 25 | }, 26 | { 27 | key = "cine_vouchers", 28 | path = "vouchers.png", 29 | px = 71, 30 | py = 95 31 | }, 32 | { 33 | key = "cine_tags", 34 | path = "tags.png", 35 | px = 34, 36 | py = 34 37 | }, 38 | { 39 | key = "cine_backs", 40 | path = "backs.png", 41 | px = 71, 42 | py = 95 43 | }, 44 | { 45 | key = "cine_sleeves", 46 | path = "sleeves.png", 47 | px = 73, 48 | py = 95 49 | } 50 | } 51 | 52 | for _, v in pairs(Reverie.atlases) do 53 | SMODS.Atlas(v) 54 | end -------------------------------------------------------------------------------- /data/jokers.lua: -------------------------------------------------------------------------------- 1 | local function calculate_dynamic_film(self, card, context) 2 | if context.cine_progress and not context.blueprint then 3 | card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_mod 4 | 5 | return { 6 | message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } } 7 | } 8 | elseif context.joker_main and card.ability.extra.chips > 0 then 9 | return { 10 | chips = card.ability.extra.chips 11 | } 12 | end 13 | end 14 | 15 | Reverie.jokers = { 16 | { 17 | key = "dynamic_film", 18 | order = 1, 19 | name = "Dynamic Film", 20 | config = { 21 | extra = { 22 | chips = 0, 23 | chip_mod = 15 24 | } 25 | }, 26 | rarity = 1, 27 | cost = 4, 28 | blueprint_compat = true, 29 | perishable_compat = false, 30 | loc_vars = function(self, info_queue, center) 31 | return { vars = { center.ability.extra.chips, center.ability.extra.chip_mod } } 32 | end, 33 | calculate = calculate_dynamic_film 34 | } 35 | } 36 | 37 | for _, v in ipairs(Reverie.jokers) do 38 | v.atlas = "cine_jokers" 39 | 40 | SMODS.Joker(v) 41 | end -------------------------------------------------------------------------------- /data/backs.lua: -------------------------------------------------------------------------------- 1 | local function apply_filmstrip(self) 2 | G.GAME.starting_params.cine_quest_slots = G.GAME.starting_params.cine_quest_slots + self.config.cine_slot 3 | end 4 | 5 | local function trigger_stamp(self, args) 6 | if args.context == "setting_tags" then 7 | G.GAME.round_resets.blind_tags.Small = "tag_dvrprv_jumbo_tag" 8 | G.GAME.round_resets.blind_tags.Big = "tag_dvrprv_jumbo_tag" 9 | 10 | return 11 | end 12 | end 13 | 14 | Reverie.backs = { 15 | { 16 | key = "filmstrip", 17 | order = 1, 18 | name = "Filmstrip Deck", 19 | config = { 20 | cine_slot = 1 21 | }, 22 | pos = { 23 | x = 0, 24 | y = 0 25 | }, 26 | unlocked = false, 27 | check_for_unlock = function(self, args) 28 | if args.type == 'win_stake' then 29 | unlock_card(self) 30 | end 31 | end, 32 | loc_vars = function (self, info_queue, center) 33 | return {vars = {self.config.cine_slot}} 34 | end, 35 | apply = apply_filmstrip 36 | }, 37 | { 38 | key = "stamp", 39 | order = 2, 40 | name = "Stamp Deck", 41 | config = {}, 42 | pos = { 43 | x = 1, 44 | y = 0 45 | }, 46 | unlocked = false, 47 | check_for_unlock = function(self, args) 48 | if args.type == 'win_stake' and G.GAME.skips <= 0 then 49 | unlock_card(self) 50 | end 51 | end, 52 | loc_vars = function (self, info_queue, center) 53 | return {vars = { 54 | localize{ 55 | type = "name_text", 56 | key = "p_dvrprv_tag_jumbo", 57 | set = "Other" 58 | } 59 | }} 60 | end, 61 | trigger_effect = trigger_stamp 62 | } 63 | } 64 | 65 | for _, v in pairs(Reverie.backs) do 66 | v.atlas = "cine_backs" 67 | 68 | SMODS.Back(v) 69 | end -------------------------------------------------------------------------------- /lovely/card_draw_patches.toml: -------------------------------------------------------------------------------- 1 | [manifest] 2 | version = "1.0.0" 3 | dump_lua = true 4 | priority = 0 5 | 6 | ## Pre v0819 7 | 8 | # Disable edition shaders for cine cards (they mess up purchase animation) 9 | [[patches]] 10 | [patches.regex] 11 | target = '=[SMODS _ "src/card_draw.lua"]' 12 | pattern = '''(?[\t ]*)if self\.edition(?.* then)(?\n[\t ]*for k, v in pairs\(G\.P_CENTER_POOLS\.Edition\) do\n[\t ]*if self\.edition\[v\.key:sub\(3\)\] and v\.shader then)''' 13 | position = "at" 14 | line_prepend = "$indent" 15 | payload = ''' 16 | if self.edition and not Reverie.is_cine_or_reverie(self)$cond 17 | $post 18 | ''' 19 | # Disable edition shaders for cine cards (they mess up purchase animation) 20 | # Disables negative shine 21 | [[patches]] 22 | [patches.regex] 23 | target = '=[SMODS _ "src/card_draw.lua"]' 24 | pattern = '''(?[\t ]*)if \(self\.edition and self\.edition\.negative\)(?.*)''' 25 | position = "at" 26 | line_prepend = "$indent" 27 | payload = ''' 28 | if (self.edition and self.edition.negative and not Reverie.is_cine_or_reverie(self))$post 29 | ''' 30 | 31 | 32 | 33 | ## Post v0819a 34 | 35 | # Disable edition shaders for cine cards (they mess up purchase animation) 36 | [[patches]] 37 | [patches.regex] 38 | target = '=[SMODS _ "src/card_draw.lua"]' 39 | pattern = '''(?[\t ]*)if edition(?.* then)(?\n[\t ]*for k, v in pairs\(G\.P_CENTER_POOLS\.Edition\) do\n[\t ]*if edition\[v\.key:sub\(3\)\] and v\.shader then)''' 40 | position = "at" 41 | line_prepend = "$indent" 42 | payload = ''' 43 | if self.edition and not Reverie.is_cine_or_reverie(self)$cond 44 | $indent$post 45 | ''' 46 | # Disable edition shaders for cine cards (they mess up purchase animation) 47 | # Disables negative shine 48 | [[patches]] 49 | [patches.regex] 50 | target = '=[SMODS _ "src/card_draw.lua"]' 51 | pattern = '''(?[\t ]*)if \(edition and edition\.negative\)(?.*)''' 52 | position = "at" 53 | line_prepend = "$indent" 54 | payload = ''' 55 | if (self.edition and self.edition.negative and not Reverie.is_cine_or_reverie(self))$post 56 | ''' -------------------------------------------------------------------------------- /data/consumables.lua: -------------------------------------------------------------------------------- 1 | Reverie.consumables = { 2 | { 3 | key = "reverie", 4 | set = "Spectral", 5 | atlas = "Cine", 6 | order = 1, 7 | name = "Reverie", 8 | pos = { 9 | x = 1, 10 | y = 1 11 | }, 12 | cost = 4, 13 | hidden = true, 14 | soul_set = "Cine", 15 | can_use = function (self, card) 16 | return G.STATE == G.STATES.SHOP and G.shop 17 | end, 18 | use = Reverie.use_cine, 19 | set_sprites = function(self, card, front) 20 | card.ignore_base_shader = { ticket = true } 21 | end, 22 | draw = function(self, card, layer) 23 | if not card.ARGs then 24 | card.ARGS = card.ARGS or {} 25 | end 26 | if not card.ARGS.send_to_shader then 27 | card.ARGS.send_to_shader = card.ARGS.send_to_shader or {} 28 | card.ARGS.send_to_shader[1] = math.min(card.VT.r*3, 1) + math.sin(G.TIMERS.REAL/28) + 1 + (card.juice and card.juice.r*20 or 0) + card.tilt_var.amt 29 | card.ARGS.send_to_shader[2] = G.TIMERS.REAL 30 | 31 | for k, v in pairs(card.children) do 32 | v.VT.scale = card.VT.scale 33 | end 34 | end 35 | if not (card.edition and card.edition.negative) then 36 | card.ARGS.send_to_shader = card.ARGS.send_to_shader or {} 37 | card.ARGS.send_to_shader[3] = card.omit_top_half or 0 38 | card.ARGS.send_to_shader[4] = card.omit_bottom_half or 0 39 | 40 | card.children.center:draw_shader("dvrprv_ticket", nil, card.ARGS.send_to_shader) 41 | end 42 | if card.edition and card.edition.negative then 43 | card.ARGS.send_to_shader[3] = card.omit_top_half or 0 44 | card.ARGS.send_to_shader[4] = card.omit_bottom_half or 0 45 | 46 | card.children.center:draw_shader("dvrprv_cine_negative", nil, card.ARGS.send_to_shader) 47 | end 48 | end 49 | } 50 | } 51 | 52 | for _, v in pairs(Reverie.consumables) do 53 | SMODS.Consumable(v) 54 | end -------------------------------------------------------------------------------- /data/vouchers.lua: -------------------------------------------------------------------------------- 1 | local function redeem_script(center_table) 2 | if center_table.name == "Script" and G.GAME.current_round.used_cine 3 | and not G.GAME.current_round.cine_temporary_shop_card_limit then 4 | G.GAME.current_round.cine_temporary_shop_card_limit = true 5 | change_shop_size(center_table.config.extra) 6 | end 7 | end 8 | 9 | local function redeem_megaphone(center_table) 10 | if center_table.name == "Megaphone" and G.cine_quests then 11 | G.E_MANAGER:add_event(Event({ 12 | func = function() 13 | for _, v in ipairs(G.cine_quests.cards) do 14 | if v.ability.progress then 15 | v.ability.extra.goal = Reverie.halve_cine_quest_goal(v.ability.extra.goal) 16 | 17 | if v.ability.progress >= v.ability.extra.goal then 18 | Reverie.complete_cine_quest(v) 19 | end 20 | end 21 | end 22 | 23 | return true 24 | end 25 | })) 26 | end 27 | end 28 | 29 | Reverie.vouchers = { 30 | { 31 | key = "script", 32 | order = 1, 33 | name = "Script", 34 | config = { 35 | extra = 2 36 | }, 37 | pos = { 38 | x = 0, 39 | y = 0 40 | }, 41 | redeem = redeem_script, 42 | loc_vars = function (self, info_queue, center) 43 | return {vars = {center.ability.extra}} 44 | end 45 | }, 46 | { 47 | key = "megaphone", 48 | order = 2, 49 | name = "Megaphone", 50 | requires = { 51 | "v_dvrprv_script" 52 | }, 53 | unlocked = false, 54 | unlock_condition = { 55 | type = "c_Reverie_cines_used", 56 | extra = 5 57 | }, 58 | locked_loc_vars = function(self, info_queue) 59 | return { vars = { self.unlock_condition.extra, G.PROFILES[G.SETTINGS.profile].career_stats.c_Reverie_cines_used or 0 } } 60 | end, 61 | config = { 62 | extra = 0.5 63 | }, 64 | pos = { 65 | x = 0, 66 | y = 1 67 | }, 68 | redeem = redeem_megaphone 69 | } 70 | } 71 | 72 | for _, v in pairs(Reverie.vouchers) do 73 | v.atlas = "cine_vouchers" 74 | 75 | SMODS.Voucher(v) 76 | end -------------------------------------------------------------------------------- /data/sleeves.lua: -------------------------------------------------------------------------------- 1 | local function apply_filmstrip(self) 2 | CardSleeves.Sleeve.apply(self) 3 | 4 | if self.get_current_deck_key() ~= "b_dvrprv_filmstrip" then 5 | G.GAME.starting_params.cine_quest_slots = G.GAME.starting_params.cine_quest_slots + self.config.cine_slot 6 | end 7 | end 8 | 9 | local function trigger_stamp(self, args) 10 | CardSleeves.Sleeve.trigger_effect(self, args) 11 | 12 | if args.context == "setting_tags" then 13 | local tag = self.get_current_deck_key() == "b_dvrprv_stamp" and "tag_dvrprv_mega_tag" or "tag_dvrprv_jumbo_tag" 14 | 15 | G.GAME.round_resets.blind_tags.Small = tag 16 | G.GAME.round_resets.blind_tags.Big = tag 17 | end 18 | end 19 | 20 | Reverie.sleeves = { 21 | { 22 | key = "filmstrip", 23 | order = 1, 24 | name = "Filmstrip Sleeve", 25 | config = { 26 | cine_slot = 1, 27 | odds = 4, 28 | rate = 2 29 | }, 30 | pos = { 31 | x = 0, 32 | y = 0 33 | }, 34 | unlocked = false, 35 | unlock_condition = { deck = "b_dvrprv_filmstrip", stake = "stake_purple" }, 36 | loc_vars = function (self) 37 | local key = self.key 38 | 39 | if self.get_current_deck_key() == "b_dvrprv_filmstrip" then 40 | key = key.."_alt" 41 | end 42 | 43 | return {key = key, vars = {self.config.cine_slot, ""..(G.GAME and G.GAME.probabilities.normal or 1), self.config.odds}} 44 | end, 45 | apply = apply_filmstrip 46 | }, 47 | { 48 | key = "stamp", 49 | order = 2, 50 | name = "Stamp Sleeve", 51 | config = {}, 52 | pos = { 53 | x = 1, 54 | y = 0 55 | }, 56 | unlocked = false, 57 | unlock_condition = { deck = "b_dvrprv_stamp", stake = "stake_blue" }, 58 | loc_vars = function (self) 59 | local key = self.key 60 | 61 | if self.get_current_deck_key() == "b_dvrprv_stamp" then 62 | key = key.."_alt" 63 | end 64 | 65 | return {key = key, vars = { 66 | localize{ 67 | type = "name_text", 68 | key = "p_dvrprv_tag_jumbo", 69 | set = "Other" 70 | } 71 | }} 72 | end, 73 | trigger_effect = trigger_stamp 74 | } 75 | } 76 | 77 | for _, v in pairs(Reverie.sleeves) do 78 | v.atlas = "cine_sleeves" 79 | 80 | CardSleeves.Sleeve(v) 81 | end -------------------------------------------------------------------------------- /lovely/risky_patches.toml: -------------------------------------------------------------------------------- 1 | [manifest] 2 | version = "1.0.0" 3 | dump_lua = true 4 | priority = 101 5 | 6 | # This file is for patches that are more likely to break other mods, and thus are being patched later in the priority queue 7 | # "breaking patches" are patches that replace code (position = "at" and pattern not present in payload), thus causing other patch patterns to not match where they should 8 | 9 | # Tag:get_uibox_table 10 | # Make skip tag show correctly in the shop (by default it adds one to the tag, now it won't do so if in shop/pack) 11 | [[patches]] 12 | [patches.pattern] 13 | target = "tag.lua" 14 | pattern = '''elseif name_to_check == 'Skip Tag' then*''' 15 | position = "at" 16 | payload = ''' 17 | elseif name_to_check == 'Skip Tag' then loc_vars = {self.config.skip_bonus, self.config.skip_bonus*((G.GAME.skips or 0)+(self.ability.as_card and 0 or 1))} 18 | ''' 19 | match_indent = true 20 | 21 | 22 | 23 | # Card:redeem() 24 | # Dont play coin sfx if card has no cost 25 | [[patches]] 26 | [patches.regex] 27 | target = "card.lua" 28 | pattern = '''(?[ \t]*)(?bot_dynatext = DynaText\(\{string = localize\('k_redeemed_ex'\).*(\n.*?)*)(?play_sound\('coin1'\))''' 29 | position = "at" 30 | line_prepend = "$indent" 31 | payload = ''' 32 | $capture 33 | if self.cost ~= 0 then 34 | $target 35 | end 36 | ''' 37 | 38 | 39 | 40 | # Card:add_to_deck() 41 | # Make negative cine cards change card_limit correctly when added to deck as negative 42 | [[patches]] 43 | [patches.regex] 44 | target = "card.lua" 45 | pattern = '''(?[\t ]*)(?
if self.edition and self.edition.card_limit then.*)\n[\t ]*(?if self.ability.consumeable then)\n[\t ]*G\.consumeables\.config\.card_limit = G\.consumeables\.config\.card_limit \+ self\.edition\.card_limit(?(\n.*?)*end)'''
46 | position = "at"
47 | line_prepend = "$indent"
48 | payload = '''
49 | $pre
50 |     $cond
51 |         if Reverie.is_cine_or_reverie(self) then
52 |             G.cine_quests.config.card_limit = G.cine_quests.config.card_limit + self.edition.card_limit
53 |         else
54 |             G.consumeables.config.card_limit = G.consumeables.config.card_limit + self.edition.card_limit
55 |         end
56 |     $post
57 | '''
58 | 
59 | # Card:set_edition()
60 | # Make negative cine cards change card_limit correctly when negative is applied to it
61 | [[patches]]
62 | [patches.regex]
63 | target = "card.lua"
64 | pattern = '''(?[\t ]*)(?
self.edition = \{\}\n.*if self.added_to_deck then.*)\n[\t ]*(?if self.ability.consumeable then)\n[\t ]*G\.consumeables\.config\.card_limit = G\.consumeables\.config\.card_limit \+ 1(?(\n.*?)*end)'''
65 | position = "at"
66 | line_prepend = "$indent"
67 | payload = '''
68 | $pre
69 |     $cond
70 |         if Reverie.is_cine_or_reverie(self) then
71 |             G.cine_quests.config.card_limit = G.cine_quests.config.card_limit + 1
72 |         else
73 |             G.consumeables.config.card_limit = G.consumeables.config.card_limit + 1
74 |         end
75 |     $post
76 | '''
77 | 
78 | # Card:remove_from_deck() and Card:remove()
79 | # Make removed negative cine cards modify card limit
80 | [[patches]]
81 | [patches.regex]
82 | target = "card.lua"
83 | pattern = '''(?[\t ]*)(?
if self.edition and self.edition.card_limit then.*)\n[\t ]*(?if self.ability.consumeable then)\n[\t ]*G\.consumeables\.config\.card_limit = G\.consumeables\.config\.card_limit - self\.edition\.card_limit(?(\n.*?)*end)'''
84 | position = "at"
85 | line_prepend = "$indent"
86 | payload = '''
87 | $pre
88 |     $cond
89 |         if Reverie.is_cine_or_reverie(self) then
90 |             G.cine_quests.config.card_limit = G.cine_quests.config.card_limit - self.edition.card_limit
91 |         else
92 |             G.consumeables.config.card_limit = G.consumeables.config.card_limit - self.edition.card_limit
93 |         end
94 |     $post
95 | '''
96 | times = 2


--------------------------------------------------------------------------------
/data/tags.lua:
--------------------------------------------------------------------------------
  1 | local function apply_stub(self, tag, context)
  2 |     if context.type == "new_blind_choice" then
  3 |         local lock = tag.ID
  4 |         G.CONTROLLER.locks[lock] = true
  5 | 
  6 |         tag:yep("+", G.C.SECONDARY_SET.Cine, function()
  7 |             local key = "p_dvrprv_film_normal_"..(math.random(1, 2))
  8 |             local card = Card(G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2, G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2,
  9 |                 G.CARD_W * 1.27, G.CARD_H * 1.27, G.P_CARDS.empty, G.P_CENTERS[key], {
 10 |                     bypass_discovery_center = true,
 11 |                     bypass_discovery_ui = true
 12 |                 })
 13 |             card.cost = 0
 14 |             card.from_tag = true
 15 | 
 16 |             G.FUNCS.use_card({
 17 |                 config = {
 18 |                     ref_table = card
 19 |                 }
 20 |             })
 21 |             card:start_materialize()
 22 |             G.CONTROLLER.locks[lock] = nil
 23 | 
 24 |             return true
 25 |         end)
 26 |         tag.triggered = true
 27 | 
 28 |         return true
 29 |     end
 30 | end
 31 | 
 32 | local function apply_stamp(self, tag, context)
 33 |     if context.type == "new_blind_choice" then
 34 |         local lock = tag.ID
 35 |         G.CONTROLLER.locks[lock] = true
 36 | 
 37 |         tag:yep("+", G.C.SECONDARY_SET.Tag, function()
 38 |             if tag.name == "Mega Stamp Tag" then
 39 |                 local random_tag = Tag(get_next_tag_key("mega_stamp"))
 40 | 
 41 |                 if random_tag.name == "Orbital Tag" then
 42 |                     local poker_hands = {}
 43 |                     for k, v in pairs(G.GAME.hands) do
 44 |                         if v.visible then
 45 |                             table.insert(poker_hands, k)
 46 |                         end
 47 |                     end
 48 | 
 49 |                     random_tag.ability.orbital_hand = pseudorandom_element(poker_hands, pseudoseed("mega_stamp_orbital"))
 50 |                 end
 51 | 
 52 |                 add_tag(random_tag)
 53 |             end
 54 | 
 55 |             local pack_key = "p_dvrprv_tag_jumbo_1"
 56 |             local card = Card(G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2, G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2,
 57 |                 G.CARD_W * 1.27, G.CARD_H * 1.27, G.P_CARDS.empty, G.P_CENTERS[pack_key], {
 58 |                     bypass_discovery_center = true,
 59 |                     bypass_discovery_ui = true
 60 |                 })
 61 |             card.cost = 0
 62 |             card.from_tag = true
 63 | 
 64 |             G.FUNCS.use_card({
 65 |                 config = {
 66 |                     ref_table = card
 67 |                 }
 68 |             })
 69 |             card:start_materialize()
 70 | 
 71 |             G.CONTROLLER.locks[lock] = nil
 72 | 
 73 |             return true
 74 |         end)
 75 |         tag.triggered = true
 76 | 
 77 |         return true
 78 |     end
 79 | end
 80 | 
 81 | Reverie.tags = {
 82 |     {
 83 |         key = "cine",
 84 |         order = 1,
 85 |         name = "Stub Tag",
 86 |         config = {
 87 |             type = "new_blind_choice"
 88 |         },
 89 |         pos = {
 90 |             x = 0,
 91 |             y = 0
 92 |         },
 93 |         loc_vars = function (self, info_queue)
 94 |             local fake_card = G.P_CENTERS.p_dvrprv_film_normal_1:create_fake_card()
 95 |             local info = G.P_CENTERS.p_dvrprv_film_normal_1:loc_vars(info_queue, fake_card)
 96 | 
 97 |             info_queue[#info_queue + 1] = {
 98 |                 key = info.key,
 99 |                 set = "Other",
100 |                 vars = info.vars
101 |             }
102 | 
103 |             return {}
104 |         end,
105 |         apply = apply_stub
106 |     },
107 |     {
108 |         key = "jumbo_tag",
109 |         order = 2,
110 |         name = "Stamp Tag",
111 |         config = {
112 |             type = "new_blind_choice"
113 |         },
114 |         pos = {
115 |             x = 1,
116 |             y = 0
117 |         },
118 |         yes_pool_flag = "tag_tag_available",
119 |         loc_vars = function (self, info_queue)
120 |             local fake_card = G.P_CENTERS.p_dvrprv_tag_jumbo_1:create_fake_card()
121 |             local info = G.P_CENTERS.p_dvrprv_tag_jumbo_1:loc_vars(info_queue, fake_card)
122 | 
123 |             info_queue[#info_queue + 1] = {
124 |                 key = info.key,
125 |                 set = "Other",
126 |                 vars = info.vars
127 |             }
128 | 
129 |             return {}
130 |         end,
131 |         apply = apply_stamp
132 |     },
133 |     {
134 |         key = "mega_tag",
135 |         order = 3,
136 |         name = "Mega Stamp Tag",
137 |         config = {
138 |             type = "new_blind_choice"
139 |         },
140 |         pos = {
141 |             x = 2,
142 |             y = 0
143 |         },
144 |         yes_pool_flag = "tag_tag_available",
145 |         loc_vars = function (self, info_queue)
146 |             local fake_card = G.P_CENTERS.p_dvrprv_tag_jumbo_1:create_fake_card()
147 |             local info = G.P_CENTERS.p_dvrprv_tag_jumbo_1:loc_vars(info_queue, fake_card)
148 | 
149 |             info_queue[#info_queue + 1] = {
150 |                 key = info.key,
151 |                 set = "Other",
152 |                 vars = info.vars
153 |             }
154 | 
155 |             return {}
156 |         end,
157 |         apply = apply_stamp,
158 |         dependencies = "CardSleeves"
159 |     }
160 | }
161 | 
162 | for _, v in pairs(Reverie.tags) do
163 |     v.atlas = "cine_tags"
164 | 
165 |     SMODS.Tag(v)
166 | end


--------------------------------------------------------------------------------
/assets/shaders/ticket.fs:
--------------------------------------------------------------------------------
  1 | #if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
  2 | 	#define MY_HIGHP_OR_MEDIUMP highp
  3 | #else
  4 | 	#define MY_HIGHP_OR_MEDIUMP mediump
  5 | #endif
  6 | 
  7 | extern MY_HIGHP_OR_MEDIUMP vec4 ticket;
  8 | extern MY_HIGHP_OR_MEDIUMP number dissolve;
  9 | extern MY_HIGHP_OR_MEDIUMP number time;
 10 | extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
 11 | extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
 12 | extern bool shadow;
 13 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
 14 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
 15 | 
 16 | vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
 17 | {
 18 |     if (dissolve < 0.001) {
 19 |         return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
 20 |     }
 21 | 
 22 |     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
 23 | 
 24 | 	float t = time * 10.0 + 2003.;
 25 | 	vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
 26 |     vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
 27 | 
 28 | 	vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
 29 | 	vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532),  cos( t / 61.4532));
 30 | 	vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
 31 | 
 32 |     float field = (1.+ (
 33 |         cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
 34 |         cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
 35 |     vec2 borders = vec2(0.2, 0.8);
 36 | 
 37 |     float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
 38 |     - (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 39 |     - (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 40 |     - (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
 41 |     - (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
 42 | 
 43 |     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) {
 44 |         if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
 45 |             tex.rgba = burn_colour_1.rgba;
 46 |         } else if (burn_colour_2.a > 0.01) {
 47 |             tex.rgba = burn_colour_2.rgba;
 48 |         }
 49 |     }
 50 | 
 51 |     return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
 52 | }
 53 | 
 54 | vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
 55 | {
 56 |     vec4 tex = Texel( texture, texture_coords);
 57 |     vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
 58 | 
 59 |     float omit_top_half = ticket[2];
 60 |     float omit_bottom_half = ticket[3];
 61 | 
 62 |     if (uv.y <= 0.375 && omit_top_half > 0){
 63 |         tex.a = 0.;
 64 |     } else if (uv.y > 0.375 && omit_bottom_half > 0) {
 65 |         tex.a = 0.;
 66 |     }
 67 | 
 68 |     vec4 border_1 = vec4(255. / 255., 244. / 255., 180. / 255., 1.);
 69 |     vec4 border_2 = vec4(189. / 255., 188. / 255., 132. / 255., 1.);
 70 |     vec4 border_3 = vec4(171. / 255., 170. / 255., 120. / 255., 1.);
 71 |     vec4 joker_black = vec4(79. / 255., 99. / 255., 103. / 255., 1.);
 72 | 
 73 |     if (any(greaterThan(abs(tex.rgb - border_1.rgb), vec3(0.1))) &&
 74 |         any(greaterThan(abs(tex.rgb - border_2.rgb), vec3(0.1))) &&
 75 |         any(greaterThan(abs(tex.rgb - border_3.rgb), vec3(0.1))) &&
 76 |         any(greaterThan(abs(tex.rgb - joker_black.rgb), vec3(0.1))))
 77 |     {
 78 |         number low = min(tex.r, min(tex.g, tex.b));
 79 |         number high = max(tex.r, max(tex.g, tex.b));
 80 |         number delta = max(high-low, low*0.7);
 81 | 
 82 |         number fac = 0.8 + 0.9*sin(13.*uv.x+5.32*uv.y + ticket.r*12. + cos(ticket.r*5.3 + uv.y*4.2 - uv.x*4.));
 83 |         number fac2 = 0.5 + 0.5*sin(10.*uv.x+2.32*uv.y + ticket.r*5. - cos(ticket.r*2.3 + uv.x*8.2));
 84 |         number fac3 = 0.5 + 0.5*sin(12.*uv.x+6.32*uv.y + ticket.r*6.111 + sin(ticket.r*5.3 + uv.y*3.2));
 85 |         number fac4 = 0.5 + 0.5*sin(4.*uv.x+2.32*uv.y + ticket.r*8.111 + sin(ticket.r*1.3 + uv.y*13.2));
 86 |         number fac5 = sin(0.5*16.*uv.x+5.32*uv.y + ticket.r*12. + cos(ticket.r*5.3 + uv.y*4.2 - uv.x*4.));
 87 | 
 88 |         number maxfac = 0.6*max(max(fac, max(fac2, max(fac3,0.0))) + (fac+fac2+fac3*fac4), 0.);
 89 | 
 90 |         vec4 orig_rgba = tex.rgba;
 91 |         tex.rgb = tex.rgb*0.5 + vec3(0.4, 0.4, 0.8);
 92 | 
 93 |         tex.r = tex.r-delta + delta*maxfac*(0.7 + fac5*0.07) - 0.1;
 94 |         tex.g = tex.g-delta + delta*maxfac*(0.7 - fac5*0.17) - 0.1;
 95 |         tex.b = tex.b-delta + delta*maxfac*0.7 - 0.1;
 96 |         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));
 97 | 
 98 |         tex.a *= 0.6;
 99 | 
100 |         tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
101 |         tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
102 |         tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
103 |         tex.a = orig_rgba.a;
104 | 
105 |     }
106 | 
107 |     return dissolve_mask(tex*colour, texture_coords, uv);
108 | }
109 | 
110 | extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
111 | extern MY_HIGHP_OR_MEDIUMP float hovering;
112 | extern MY_HIGHP_OR_MEDIUMP float screen_scale;
113 | 
114 | #ifdef VERTEX
115 | vec4 position( mat4 transform_projection, vec4 vertex_position )
116 | {
117 |     if (hovering <= 0.){
118 |         return transform_projection * vertex_position;
119 |     }
120 |     float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
121 |     vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
122 |     float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
123 |                 *hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
124 | 
125 |     return transform_projection * vertex_position + vec4(0,0,0,scale);
126 | }
127 | #endif
128 | 


--------------------------------------------------------------------------------
/assets/shaders/cine_negative.fs:
--------------------------------------------------------------------------------
  1 | #if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
  2 | 	#define MY_HIGHP_OR_MEDIUMP highp
  3 | #else
  4 | 	#define MY_HIGHP_OR_MEDIUMP mediump
  5 | #endif
  6 | 
  7 | extern MY_HIGHP_OR_MEDIUMP vec4 cine_negative;
  8 | extern MY_HIGHP_OR_MEDIUMP number dissolve;
  9 | extern MY_HIGHP_OR_MEDIUMP number time;
 10 | extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
 11 | extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
 12 | extern bool shadow;
 13 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
 14 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
 15 | 
 16 | vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
 17 | {
 18 |     if (dissolve < 0.001) {
 19 |         return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
 20 |     }
 21 | 
 22 |     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
 23 | 
 24 | 	float t = time * 10.0 + 2003.;
 25 | 	vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
 26 |     vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
 27 | 	
 28 | 	vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
 29 | 	vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532),  cos( t / 61.4532));
 30 | 	vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
 31 | 
 32 |     float field = (1.+ (
 33 |         cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
 34 |         cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
 35 |     vec2 borders = vec2(0.2, 0.8);
 36 | 
 37 |     float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
 38 |     - (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 39 |     - (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 40 |     - (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
 41 |     - (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
 42 | 
 43 |     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) {
 44 |         if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
 45 |             tex.rgba = burn_colour_1.rgba;
 46 |         } else if (burn_colour_2.a > 0.01) {
 47 |             tex.rgba = burn_colour_2.rgba;
 48 |         }
 49 |     }
 50 | 
 51 |     return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
 52 | }
 53 | 
 54 | number hue(number s, number t, number h)
 55 | {
 56 | 	number hs = mod(h, 1.)*6.;
 57 | 	if (hs < 1.) return (t-s) * hs + s;
 58 | 	if (hs < 3.) return t;
 59 | 	if (hs < 4.) return (t-s) * (4.-hs) + s;
 60 | 	return s;
 61 | }
 62 | 
 63 | vec4 RGB(vec4 c)
 64 | {
 65 | 	if (c.y < 0.0001)
 66 | 		return vec4(vec3(c.z), c.a);
 67 | 
 68 | 	number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
 69 | 	number s = 2.0 * c.z - t;
 70 | 	return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
 71 | }
 72 | 
 73 | vec4 HSL(vec4 c)
 74 | {
 75 | 	number low = min(c.r, min(c.g, c.b));
 76 | 	number high = max(c.r, max(c.g, c.b));
 77 | 	number delta = high - low;
 78 | 	number sum = high+low;
 79 | 
 80 | 	vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
 81 | 	if (delta == .0)
 82 | 		return hsl;
 83 | 
 84 | 	hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
 85 | 
 86 | 	if (high == c.r)
 87 | 		hsl.x = (c.g - c.b) / delta;
 88 | 	else if (high == c.g)
 89 | 		hsl.x = (c.b - c.r) / delta + 2.0;
 90 | 	else
 91 | 		hsl.x = (c.r - c.g) / delta + 4.0;
 92 | 
 93 | 	hsl.x = mod(hsl.x / 6., 1.);
 94 | 	return hsl;
 95 | }
 96 | 
 97 | vec4 shine_effect( vec4 colour, vec4 tex, vec2 uv, vec2 texture_coords ){
 98 | 
 99 |     vec4 orig_rgba = tex.rgba;
100 | 
101 |     number low = min(tex.r, min(tex.g, tex.b));
102 |     number high = max(tex.r, max(tex.g, tex.b));
103 | 	number delta = high-low -0.1;
104 | 
105 |     number fac = 0.8 + 0.9*sin(11.*uv.x+4.32*uv.y + cine_negative.r*12. + cos(cine_negative.r*5.3 + uv.y*4.2 - uv.x*4.));
106 |     number fac2 = 0.5 + 0.5*sin(8.*uv.x+2.32*uv.y + cine_negative.r*5. - cos(cine_negative.r*2.3 + uv.x*8.2));
107 |     number fac3 = 0.5 + 0.5*sin(10.*uv.x+5.32*uv.y + cine_negative.r*6.111 + sin(cine_negative.r*5.3 + uv.y*3.2));
108 |     number fac4 = 0.5 + 0.5*sin(3.*uv.x+2.32*uv.y + cine_negative.r*8.111 + sin(cine_negative.r*1.3 + uv.y*11.2));
109 |     number fac5 = sin(0.9*16.*uv.x+5.32*uv.y + cine_negative.r*12. + cos(cine_negative.r*5.3 + uv.y*4.2 - uv.x*4.));
110 | 
111 |     number maxfac = 0.7*max(max(fac, max(fac2, max(fac3,0.0))) + (fac+fac2+fac3*fac4), 0.);
112 | 
113 |     tex.rgb = tex.rgb*0.5 + vec3(0.4, 0.4, 0.8);
114 | 
115 |     tex.r = tex.r-delta + delta*maxfac*(0.7 + fac5*0.27) - 0.1;
116 |     tex.g = tex.g-delta + delta*maxfac*(0.7 - fac5*0.27) - 0.1;
117 |     tex.b = tex.b-delta + delta*maxfac*0.7 - 0.1;
118 |     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));
119 | 
120 |     tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
121 |     tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
122 |     tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
123 |     tex.a = orig_rgba.a;
124 | 
125 |     return dissolve_mask(tex*colour, texture_coords, uv);
126 | }
127 | 
128 | vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
129 | {
130 |     vec4 tex = Texel(texture, texture_coords);
131 | 	vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
132 | 
133 |     float omit_top_half = cine_negative[2];
134 |     float omit_bottom_half = cine_negative[3];
135 | 
136 |     if (uv.y <= 0.375 && omit_top_half > 0){
137 |         tex.a = 0.;
138 |     } else if (uv.y > 0.375 && omit_bottom_half > 0) {
139 |         tex.a = 0.;
140 |     }
141 | 
142 |     vec4 orig_rgba = tex.rgba;
143 | 
144 |     vec4 SAT = HSL(tex);
145 | 
146 | 	if (cine_negative.g > 0.0 || cine_negative.g < 0.0) {
147 | 		SAT.b = (1.-SAT.b);
148 | 	}
149 | 	SAT.r = -SAT.r+0.2;
150 | 
151 |     tex = RGB(SAT) + 0.8*vec4(79./255., 99./255.,103./255.,0.);
152 | 
153 | 	if (tex[3] < 0.7)
154 | 		tex[3] = tex[3]/3.;
155 | 
156 |     tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
157 |     tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
158 |     tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
159 |     tex.a = orig_rgba.a;
160 | 
161 | 	return shine_effect(colour, tex, uv, texture_coords);
162 | }
163 | 
164 | extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
165 | extern MY_HIGHP_OR_MEDIUMP float hovering;
166 | extern MY_HIGHP_OR_MEDIUMP float screen_scale;
167 | 
168 | #ifdef VERTEX
169 | vec4 position( mat4 transform_projection, vec4 vertex_position )
170 | {
171 |     if (hovering <= 0.){
172 |         return transform_projection * vertex_position;
173 |     }
174 |     float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
175 |     vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
176 |     float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
177 |                 *hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
178 | 
179 |     return transform_projection * vertex_position + vec4(0,0,0,scale);
180 | }
181 | #endif


--------------------------------------------------------------------------------
/assets/shaders/ticket_polychrome.fs:
--------------------------------------------------------------------------------
  1 | #if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
  2 | 	#define MY_HIGHP_OR_MEDIUMP highp
  3 | #else
  4 | 	#define MY_HIGHP_OR_MEDIUMP mediump
  5 | #endif
  6 | 
  7 | extern MY_HIGHP_OR_MEDIUMP vec4 ticket_polychrome;
  8 | extern MY_HIGHP_OR_MEDIUMP number dissolve;
  9 | extern MY_HIGHP_OR_MEDIUMP number time;
 10 | extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
 11 | extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
 12 | extern bool shadow;
 13 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
 14 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
 15 | 
 16 | vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
 17 | {
 18 |     if (dissolve < 0.001) {
 19 |         return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
 20 |     }
 21 | 
 22 |     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
 23 | 
 24 | 	float t = time * 10.0 + 2003.;
 25 | 	vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
 26 |     vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
 27 | 
 28 | 	vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
 29 | 	vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532),  cos( t / 61.4532));
 30 | 	vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
 31 | 
 32 |     float field = (1.+ (
 33 |         cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
 34 |         cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
 35 |     vec2 borders = vec2(0.2, 0.8);
 36 | 
 37 |     float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
 38 |     - (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 39 |     - (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 40 |     - (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
 41 |     - (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
 42 | 
 43 |     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) {
 44 |         if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
 45 |             tex.rgba = burn_colour_1.rgba;
 46 |         } else if (burn_colour_2.a > 0.01) {
 47 |             tex.rgba = burn_colour_2.rgba;
 48 |         }
 49 |     }
 50 | 
 51 |     return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
 52 | }
 53 | 
 54 | number hue(number s, number t, number h)
 55 | {
 56 | 	number hs = mod(h, 1.)*6.;
 57 | 	if (hs < 1.) return (t-s) * hs + s;
 58 | 	if (hs < 3.) return t;
 59 | 	if (hs < 4.) return (t-s) * (4.-hs) + s;
 60 | 	return s;
 61 | }
 62 | 
 63 | vec4 RGB(vec4 c)
 64 | {
 65 | 	if (c.y < 0.0001)
 66 | 		return vec4(vec3(c.z), c.a);
 67 | 
 68 | 	number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
 69 | 	number s = 2.0 * c.z - t;
 70 | 	return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
 71 | }
 72 | 
 73 | vec4 HSL(vec4 c)
 74 | {
 75 | 	number low = min(c.r, min(c.g, c.b));
 76 | 	number high = max(c.r, max(c.g, c.b));
 77 | 	number delta = high - low;
 78 | 	number sum = high+low;
 79 | 
 80 | 	vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
 81 | 	if (delta == .0)
 82 | 		return hsl;
 83 | 
 84 | 	hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
 85 | 
 86 | 	if (high == c.r)
 87 | 		hsl.x = (c.g - c.b) / delta;
 88 | 	else if (high == c.g)
 89 | 		hsl.x = (c.b - c.r) / delta + 2.0;
 90 | 	else
 91 | 		hsl.x = (c.r - c.g) / delta + 4.0;
 92 | 
 93 | 	hsl.x = mod(hsl.x / 6., 1.);
 94 | 	return hsl;
 95 | }
 96 | 
 97 | vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
 98 | {
 99 |     vec4 tex = Texel(texture, texture_coords);
100 | 	vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
101 | 
102 |     float omit_top_half = ticket_polychrome[2];
103 |     float omit_bottom_half = ticket_polychrome[3];
104 | 
105 |     if (uv.y <= 0.375 && omit_top_half > 0){
106 |         tex.a = 0.;
107 |     } else if (uv.y > 0.375 && omit_bottom_half > 0) {
108 |         tex.a = 0.;
109 |     }
110 | 
111 |     vec4 orig_rgba = tex.rgba;
112 | 
113 |     vec4 border_1 = vec4(255. / 255., 244. / 255., 180. / 255., 1.);
114 |     vec4 border_2 = vec4(189. / 255., 188. / 255., 132. / 255., 1.);
115 |     vec4 border_3 = vec4(171. / 255., 170. / 255., 120. / 255., 1.);
116 |     vec4 joker_black = vec4(79. / 255., 99. / 255., 103. / 255., 1.);
117 | 
118 |     if (any(greaterThan(abs(tex.rgb - border_1.rgb), vec3(0.1))) &&
119 |         any(greaterThan(abs(tex.rgb - border_2.rgb), vec3(0.1))) &&
120 |         any(greaterThan(abs(tex.rgb - border_3.rgb), vec3(0.1))) &&
121 |         any(greaterThan(abs(tex.rgb - joker_black.rgb), vec3(0.1))))
122 |     {
123 |         number low = min(tex.r, min(tex.g, tex.b));
124 |         number high = max(tex.r, max(tex.g, tex.b));
125 |         number delta = high - low;
126 | 
127 |         number saturation_fac = 1. - max(0., 0.05*(1.1-delta));
128 | 
129 |         vec4 hsl = HSL(vec4(tex.r*saturation_fac, tex.g*saturation_fac, tex.b, tex.a));
130 | 
131 |         float t = ticket_polychrome.y*2.221 + time;
132 |         vec2 floored_uv = (floor((uv*texture_details.ba)))/texture_details.ba;
133 |         vec2 uv_scaled_centered = (floored_uv - 0.5) * 50.;
134 | 
135 |         vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
136 |         vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532),  cos( t / 61.4532));
137 |         vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
138 | 
139 |         float field = (1.+ (
140 |             cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
141 |             cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
142 | 
143 |         float res = (.5 + .5* cos( (ticket_polychrome.x) * 2.612 + ( field + -.5 ) *3.14));
144 |         hsl.x = hsl.x+ res + ticket_polychrome.y*0.04;
145 |         hsl.y = min(0.6,hsl.y+0.5);
146 | 
147 |         tex.rgb = RGB(hsl).rgb;
148 |     }
149 | 
150 |     if (tex[3] < 0.7)
151 |         tex[3] = tex[3]/3.;
152 | 
153 |     tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
154 |     tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
155 |     tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
156 |     tex.a = orig_rgba.a;
157 |     
158 | 	return dissolve_mask(tex*colour, texture_coords, uv);
159 | }
160 | 
161 | extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
162 | extern MY_HIGHP_OR_MEDIUMP float hovering;
163 | extern MY_HIGHP_OR_MEDIUMP float screen_scale;
164 | 
165 | #ifdef VERTEX
166 | vec4 position( mat4 transform_projection, vec4 vertex_position )
167 | {
168 |     if (hovering <= 0.){
169 |         return transform_projection * vertex_position;
170 |     }
171 |     float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
172 |     vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
173 |     float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
174 |                 *hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
175 | 
176 |     return transform_projection * vertex_position + vec4(0,0,0,scale);
177 | }
178 | #endif
179 | 


--------------------------------------------------------------------------------
/assets/shaders/ticket_negative.fs:
--------------------------------------------------------------------------------
  1 | #if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
  2 | 	#define MY_HIGHP_OR_MEDIUMP highp
  3 | #else
  4 | 	#define MY_HIGHP_OR_MEDIUMP mediump
  5 | #endif
  6 | 
  7 | extern MY_HIGHP_OR_MEDIUMP vec4 ticket_negative;
  8 | extern MY_HIGHP_OR_MEDIUMP number dissolve;
  9 | extern MY_HIGHP_OR_MEDIUMP number time;
 10 | extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
 11 | extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
 12 | extern bool shadow;
 13 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
 14 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
 15 | 
 16 | vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
 17 | {
 18 |     if (dissolve < 0.001) {
 19 |         return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
 20 |     }
 21 | 
 22 |     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
 23 | 
 24 | 	float t = time * 10.0 + 2003.;
 25 | 	vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
 26 |     vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
 27 | 
 28 | 	vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
 29 | 	vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532),  cos( t / 61.4532));
 30 | 	vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
 31 | 
 32 |     float field = (1.+ (
 33 |         cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
 34 |         cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
 35 |     vec2 borders = vec2(0.2, 0.8);
 36 | 
 37 |     float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
 38 |     - (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 39 |     - (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 40 |     - (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
 41 |     - (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
 42 | 
 43 |     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) {
 44 |         if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
 45 |             tex.rgba = burn_colour_1.rgba;
 46 |         } else if (burn_colour_2.a > 0.01) {
 47 |             tex.rgba = burn_colour_2.rgba;
 48 |         }
 49 |     }
 50 | 
 51 |     return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
 52 | }
 53 | 
 54 | number hue(number s, number t, number h)
 55 | {
 56 | 	number hs = mod(h, 1.)*6.;
 57 | 	if (hs < 1.) return (t-s) * hs + s;
 58 | 	if (hs < 3.) return t;
 59 | 	if (hs < 4.) return (t-s) * (4.-hs) + s;
 60 | 	return s;
 61 | }
 62 | 
 63 | vec4 RGB(vec4 c)
 64 | {
 65 | 	if (c.y < 0.0001)
 66 | 		return vec4(vec3(c.z), c.a);
 67 | 
 68 | 	number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
 69 | 	number s = 2.0 * c.z - t;
 70 | 	return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
 71 | }
 72 | 
 73 | vec4 HSL(vec4 c)
 74 | {
 75 | 	number low = min(c.r, min(c.g, c.b));
 76 | 	number high = max(c.r, max(c.g, c.b));
 77 | 	number delta = high - low;
 78 | 	number sum = high+low;
 79 | 
 80 | 	vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
 81 | 	if (delta == .0)
 82 | 		return hsl;
 83 | 
 84 | 	hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
 85 | 
 86 | 	if (high == c.r)
 87 | 		hsl.x = (c.g - c.b) / delta;
 88 | 	else if (high == c.g)
 89 | 		hsl.x = (c.b - c.r) / delta + 2.0;
 90 | 	else
 91 | 		hsl.x = (c.r - c.g) / delta + 4.0;
 92 | 
 93 | 	hsl.x = mod(hsl.x / 6., 1.);
 94 | 	return hsl;
 95 | }
 96 | 
 97 | vec4 shine_effect( vec4 colour, vec4 tex, vec2 uv, vec2 texture_coords ){
 98 | 
 99 |     vec4 orig_rgba = tex.rgba;
100 | 
101 |     number low = min(tex.r, min(tex.g, tex.b));
102 |     number high = max(tex.r, max(tex.g, tex.b));
103 | 	number delta = high-low -0.1;
104 | 
105 |     number fac = 0.8 + 0.9*sin(11.*uv.x+4.32*uv.y + ticket_negative.r*12. + cos(ticket_negative.r*5.3 + uv.y*4.2 - uv.x*4.));
106 |     number fac2 = 0.5 + 0.5*sin(8.*uv.x+2.32*uv.y + ticket_negative.r*5. - cos(ticket_negative.r*2.3 + uv.x*8.2));
107 |     number fac3 = 0.5 + 0.5*sin(10.*uv.x+5.32*uv.y + ticket_negative.r*6.111 + sin(ticket_negative.r*5.3 + uv.y*3.2));
108 |     number fac4 = 0.5 + 0.5*sin(3.*uv.x+2.32*uv.y + ticket_negative.r*8.111 + sin(ticket_negative.r*1.3 + uv.y*11.2));
109 |     number fac5 = sin(0.9*16.*uv.x+5.32*uv.y + ticket_negative.r*12. + cos(ticket_negative.r*5.3 + uv.y*4.2 - uv.x*4.));
110 | 
111 |     number maxfac = 0.7*max(max(fac, max(fac2, max(fac3,0.0))) + (fac+fac2+fac3*fac4), 0.);
112 | 
113 |     tex.rgb = tex.rgb*0.5 + vec3(0.4, 0.4, 0.8);
114 | 
115 |     tex.r = tex.r-delta + delta*maxfac*(0.7 + fac5*0.27) - 0.1;
116 |     tex.g = tex.g-delta + delta*maxfac*(0.7 - fac5*0.27) - 0.1;
117 |     tex.b = tex.b-delta + delta*maxfac*0.7 - 0.1;
118 |     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));
119 | 
120 |     tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
121 |     tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
122 |     tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
123 |     tex.a = orig_rgba.a;
124 | 
125 |     return dissolve_mask(tex*colour, texture_coords, uv);
126 | }
127 | 
128 | vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
129 | {
130 |     vec4 tex = Texel(texture, texture_coords);
131 | 	vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
132 | 
133 |     float omit_top_half = ticket_negative[2];
134 |     float omit_bottom_half = ticket_negative[3];
135 | 
136 |     if (uv.y <= 0.375 && omit_top_half > 0){
137 |         tex.a = 0.;
138 |     } else if (uv.y > 0.375 && omit_bottom_half > 0) {
139 |         tex.a = 0.;
140 |     }
141 | 
142 |     vec4 orig_rgba = tex.rgba;
143 | 
144 |     vec4 border_1 = vec4(255. / 255., 244. / 255., 180. / 255., 1.);
145 |     vec4 border_2 = vec4(189. / 255., 188. / 255., 132. / 255., 1.);
146 |     vec4 border_3 = vec4(171. / 255., 170. / 255., 120. / 255., 1.);
147 | 
148 |     if (any(greaterThan(abs(tex.rgb - border_1.rgb), vec3(0.1))) &&
149 |         any(greaterThan(abs(tex.rgb - border_2.rgb), vec3(0.1))) &&
150 |         any(greaterThan(abs(tex.rgb - border_3.rgb), vec3(0.1))))
151 |     {
152 |         vec4 SAT = HSL(tex);
153 | 
154 |         if (ticket_negative.g > 0.0 || ticket_negative.g < 0.0) {
155 |             SAT.b = (1.-SAT.b);
156 |         }
157 |         SAT.r = -SAT.r+0.2;
158 | 
159 |         tex = RGB(SAT) + 0.8*vec4(79./255., 99./255.,103./255.,0.);
160 |     }
161 | 
162 | 	if (tex[3] < 0.7)
163 | 		tex[3] = tex[3]/3.;
164 | 
165 |     tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
166 |     tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
167 |     tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
168 |     tex.a = orig_rgba.a;
169 | 
170 | 	return shine_effect(colour, tex, uv, texture_coords);
171 | }
172 | 
173 | extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
174 | extern MY_HIGHP_OR_MEDIUMP float hovering;
175 | extern MY_HIGHP_OR_MEDIUMP float screen_scale;
176 | 
177 | #ifdef VERTEX
178 | vec4 position( mat4 transform_projection, vec4 vertex_position )
179 | {
180 |     if (hovering <= 0.){
181 |         return transform_projection * vertex_position;
182 |     }
183 |     float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
184 |     vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
185 |     float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
186 |                 *hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
187 | 
188 |     return transform_projection * vertex_position + vec4(0,0,0,scale);
189 | }
190 | #endif
191 | 


--------------------------------------------------------------------------------
/assets/shaders/cine_polychrome.fs:
--------------------------------------------------------------------------------
  1 | #if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
  2 | 	#define MY_HIGHP_OR_MEDIUMP highp
  3 | #else
  4 | 	#define MY_HIGHP_OR_MEDIUMP mediump
  5 | #endif
  6 | 
  7 | extern MY_HIGHP_OR_MEDIUMP vec4 cine_polychrome;
  8 | extern MY_HIGHP_OR_MEDIUMP number dissolve;
  9 | extern MY_HIGHP_OR_MEDIUMP number time;
 10 | extern MY_HIGHP_OR_MEDIUMP vec4 texture_details;
 11 | extern MY_HIGHP_OR_MEDIUMP vec2 image_details;
 12 | extern bool shadow;
 13 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1;
 14 | extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2;
 15 | 
 16 | vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv)
 17 | {
 18 |     if (dissolve < 0.001) {
 19 |         return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a);
 20 |     }
 21 | 
 22 |     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
 23 | 
 24 | 	float t = time * 10.0 + 2003.;
 25 | 	vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a);
 26 |     vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a);
 27 | 	
 28 | 	vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
 29 | 	vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532),  cos( t / 61.4532));
 30 | 	vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
 31 | 
 32 |     float field = (1.+ (
 33 |         cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
 34 |         cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
 35 |     vec2 borders = vec2(0.2, 0.8);
 36 | 
 37 |     float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14))
 38 |     - (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 39 |     - (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve)
 40 |     - (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve)
 41 |     - (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve);
 42 | 
 43 |     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) {
 44 |         if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) {
 45 |             tex.rgba = burn_colour_1.rgba;
 46 |         } else if (burn_colour_2.a > 0.01) {
 47 |             tex.rgba = burn_colour_2.rgba;
 48 |         }
 49 |     }
 50 | 
 51 |     return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0);
 52 | }
 53 | 
 54 | number hue(number s, number t, number h)
 55 | {
 56 | 	number hs = mod(h, 1.)*6.;
 57 | 	if (hs < 1.) return (t-s) * hs + s;
 58 | 	if (hs < 3.) return t;
 59 | 	if (hs < 4.) return (t-s) * (4.-hs) + s;
 60 | 	return s;
 61 | }
 62 | 
 63 | vec4 RGB(vec4 c)
 64 | {
 65 | 	if (c.y < 0.0001)
 66 | 		return vec4(vec3(c.z), c.a);
 67 | 
 68 | 	number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z);
 69 | 	number s = 2.0 * c.z - t;
 70 | 	return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w);
 71 | }
 72 | 
 73 | vec4 HSL(vec4 c)
 74 | {
 75 | 	number low = min(c.r, min(c.g, c.b));
 76 | 	number high = max(c.r, max(c.g, c.b));
 77 | 	number delta = high - low;
 78 | 	number sum = high+low;
 79 | 
 80 | 	vec4 hsl = vec4(.0, .0, .5 * sum, c.a);
 81 | 	if (delta == .0)
 82 | 		return hsl;
 83 | 
 84 | 	hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum);
 85 | 
 86 | 	if (high == c.r)
 87 | 		hsl.x = (c.g - c.b) / delta;
 88 | 	else if (high == c.g)
 89 | 		hsl.x = (c.b - c.r) / delta + 2.0;
 90 | 	else
 91 | 		hsl.x = (c.r - c.g) / delta + 4.0;
 92 | 
 93 | 	hsl.x = mod(hsl.x / 6., 1.);
 94 | 	return hsl;
 95 | }
 96 | 
 97 | vec4 shine_effect( vec4 colour, vec4 tex, vec2 uv, vec2 texture_coords ){
 98 | 
 99 |     vec4 orig_rgba = tex.rgba;
100 | 
101 |     number low = min(tex.r, min(tex.g, tex.b));
102 |     number high = max(tex.r, max(tex.g, tex.b));
103 | 	number delta = high-low -0.1;
104 | 
105 |     number fac = 0.8 + 0.9*sin(11.*uv.x+4.32*uv.y + cine_polychrome.r*12. + cos(cine_polychrome.r*5.3 + uv.y*4.2 - uv.x*4.));
106 |     number fac2 = 0.5 + 0.5*sin(8.*uv.x+2.32*uv.y + cine_polychrome.r*5. - cos(cine_polychrome.r*2.3 + uv.x*8.2));
107 |     number fac3 = 0.5 + 0.5*sin(10.*uv.x+5.32*uv.y + cine_polychrome.r*6.111 + sin(cine_polychrome.r*5.3 + uv.y*3.2));
108 |     number fac4 = 0.5 + 0.5*sin(3.*uv.x+2.32*uv.y + cine_polychrome.r*8.111 + sin(cine_polychrome.r*1.3 + uv.y*11.2));
109 |     number fac5 = sin(0.9*16.*uv.x+5.32*uv.y + cine_polychrome.r*12. + cos(cine_polychrome.r*5.3 + uv.y*4.2 - uv.x*4.));
110 | 
111 |     number maxfac = 0.7*max(max(fac, max(fac2, max(fac3,0.0))) + (fac+fac2+fac3*fac4), 0.);
112 | 
113 |     tex.rgb = tex.rgb*0.5 + vec3(0.4, 0.4, 0.8);
114 | 
115 |     tex.r = tex.r-delta + delta*maxfac*(0.7 + fac5*0.27) - 0.1;
116 |     tex.g = tex.g-delta + delta*maxfac*(0.7 - fac5*0.27) - 0.1;
117 |     tex.b = tex.b-delta + delta*maxfac*0.7 - 0.1;
118 |     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));
119 | 
120 |     tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
121 |     tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
122 |     tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
123 |     tex.a = orig_rgba.a;
124 | 
125 |     return dissolve_mask(tex*colour, texture_coords, uv);
126 | }
127 | 
128 | vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords )
129 | {
130 |     vec4 tex = Texel(texture, texture_coords);
131 | 	vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba;
132 | 
133 |     float omit_top_half = cine_polychrome[2];
134 |     float omit_bottom_half = cine_polychrome[3];
135 | 
136 |     if (uv.y <= 0.375 && omit_top_half > 0){
137 |         tex.a = 0.;
138 |     } else if (uv.y > 0.375 && omit_bottom_half > 0) {
139 |         tex.a = 0.;
140 |     }
141 | 
142 |     vec4 orig_rgba = tex.rgba;
143 | 
144 | 	number low = min(tex.r, min(tex.g, tex.b));
145 |     number high = max(tex.r, max(tex.g, tex.b));
146 | 	number delta = high - low;
147 | 
148 | 	number saturation_fac = 1. - max(0., 0.05*(1.1-delta));
149 | 
150 | 	vec4 hsl = HSL(vec4(tex.r*saturation_fac, tex.g*saturation_fac, tex.b, tex.a));
151 | 
152 | 	float t = cine_polychrome.y*2.221 + time;
153 | 	vec2 floored_uv = (floor((uv*texture_details.ba)))/texture_details.ba;
154 |     vec2 uv_scaled_centered = (floored_uv - 0.5) * 50.;
155 | 	
156 | 	vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324));
157 | 	vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532),  cos( t / 61.4532));
158 | 	vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000));
159 | 
160 |     float field = (1.+ (
161 |         cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) +
162 |         cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.;
163 | 
164 |     float res = (.5 + .5* cos( (cine_polychrome.x) * 2.612 + ( field + -.5 ) *3.14));
165 | 	hsl.x = hsl.x+ res + cine_polychrome.y*0.04;
166 | 	hsl.y = min(0.6,hsl.y+0.5);
167 | 
168 |     tex.rgb = RGB(hsl).rgb;
169 | 
170 | 	if (tex[3] < 0.7)
171 | 		tex[3] = tex[3]/3.;
172 | 
173 |     tex.r = orig_rgba.r * (1 - tex.a) + tex.r * tex.a;
174 |     tex.g = orig_rgba.g * (1 - tex.a) + tex.g * tex.a;
175 |     tex.b = orig_rgba.b * (1 - tex.a) + tex.b * tex.a;
176 |     tex.a = orig_rgba.a;
177 | 
178 | 	return shine_effect(colour, tex, uv, texture_coords);
179 | }
180 | 
181 | extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos;
182 | extern MY_HIGHP_OR_MEDIUMP float hovering;
183 | extern MY_HIGHP_OR_MEDIUMP float screen_scale;
184 | 
185 | #ifdef VERTEX
186 | vec4 position( mat4 transform_projection, vec4 vertex_position )
187 | {
188 |     if (hovering <= 0.){
189 |         return transform_projection * vertex_position;
190 |     }
191 |     float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy);
192 |     vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale;
193 |     float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist))
194 |                 *hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist);
195 | 
196 |     return transform_projection * vertex_position + vec4(0,0,0,scale);
197 | }
198 | #endif


--------------------------------------------------------------------------------
/data/boosters.lua:
--------------------------------------------------------------------------------
  1 | local crazy_pack_sparkles = {
  2 |     timer = 0.05,
  3 |     scale = 0.1,
  4 |     lifespan = 2.5,
  5 |     speed = 0.7,
  6 |     padding = -3,
  7 |     colours = {G.C.WHITE, lighten(Reverie.badge_colour, 0.4), lighten(G.C.RED, 0.2)}
  8 | }
  9 | local film_pack_meteors = {
 10 |     timer = 0.035,
 11 |     scale = 0.1,
 12 |     lifespan = 1.5,
 13 |     speed = 4,
 14 |     colours = {lighten(Reverie.badge_colour, 0.2), G.C.WHITE}
 15 | }
 16 | 
 17 | local function create_tag_pack_card(self, card)
 18 |     return Reverie.create_tag_as_card(G.pack_cards or G.jokers, true)
 19 | end
 20 | 
 21 | local function ease_tag_pack_colour(self)
 22 |     ease_colour(G.C.DYN_UI.MAIN, mix_colours(G.C.SECONDARY_SET.Tag, G.C.BLACK, 0.9))
 23 |     ease_background_colour{new_colour = G.C.SECONDARY_SET.Tag, special_colour = G.C.BLACK, contrast = 2}
 24 | end
 25 | 
 26 | local function create_crazy_pack_card(self, card)
 27 |     return Reverie.create_crazy_random_card(G.pack_cards or G.jokers)
 28 | end
 29 | 
 30 | local function ease_crazy_pack_colour(self)
 31 |     ease_colour(G.C.DYN_UI.MAIN, mix_colours(G.C.SECONDARY_SET.Cine, G.C.BLACK, 0.9))
 32 |     ease_background_colour{new_colour = darken(G.C.RED, 0.2), special_colour = darken(G.C.SECONDARY_SET.Cine, 0.4), tertiary_colour = darken(G.C.BLACK, 0.2), contrast = 3}
 33 | end
 34 | 
 35 | local function create_film_pack_card(self, card)
 36 |     return create_card(card.ability.name:find("Mega") and "Cine" or "Cine_Quest", G.pack_cards, nil, nil, true, true, nil, "film")
 37 | end
 38 | 
 39 | local function ease_film_pack_colour(self)
 40 |     ease_colour(G.C.DYN_UI.MAIN, mix_colours(G.C.SECONDARY_SET.Cine, G.C.BLACK, 0.9))
 41 |     ease_background_colour{new_colour = G.C.SECONDARY_SET.Cine, special_colour = G.C.BLACK, contrast = 2}
 42 | end
 43 | 
 44 | Reverie.boosters = {
 45 |     {
 46 |         key = "crazy_lucky_1",
 47 |         group_key = "k_dvrprv_crazy_pack",
 48 |         loc_key = "p_dvrprv_crazy_lucky",
 49 |         order = 6,
 50 |         name = "Pack",
 51 |         config = {
 52 |             extra = 4,
 53 |             choose = 1,
 54 |             weights = {
 55 |                 ["Joker"] = 1,
 56 |                 ["Consumeables"] = 0.75,
 57 |                 ["Playing"] = 1,
 58 |                 ["Tag"] = 0.15,
 59 |                 ["Voucher"] = 0.05,
 60 |                 ["Cine"] = 0.01
 61 |             }
 62 |         },
 63 |         weight = 1,
 64 |         kind = "Crazy",
 65 |         cost = 6,
 66 |         yes_pool_flag = "Crazy Lucky",
 67 |         pos = {
 68 |             x = 4,
 69 |             y = 0
 70 |         },
 71 |         create_card = create_crazy_pack_card,
 72 |         ease_background_colour = ease_crazy_pack_colour,
 73 |         sparkles = crazy_pack_sparkles
 74 |     },
 75 |     {
 76 |         key = "tag_normal_1",
 77 |         group_key = "k_dvrprv_tag_pack",
 78 |         loc_key = "p_dvrprv_tag_normal",
 79 |         order = 1,
 80 |         name = "Tag Pack",
 81 |         config = {
 82 |             extra = 2,
 83 |             choose = 1
 84 |         },
 85 |         weight = 1,
 86 |         kind = "Tag",
 87 |         cost = 4,
 88 |         yes_pool_flag = "Tag or Die",
 89 |         pos = {
 90 |             x = 0,
 91 |             y = 0
 92 |         },
 93 |         create_card = create_tag_pack_card,
 94 |         ease_background_colour = ease_tag_pack_colour
 95 |     },
 96 |     {
 97 |         key = "tag_normal_2",
 98 |         group_key = "k_dvrprv_tag_pack",
 99 |         loc_key = "p_dvrprv_tag_normal",
100 |         order = 2,
101 |         name = "Tag Pack",
102 |         config = {
103 |             extra = 2,
104 |             choose = 1
105 |         },
106 |         weight = 1,
107 |         kind = "Tag",
108 |         cost = 4,
109 |         yes_pool_flag = "Tag or Die",
110 |         pos = {
111 |             x = 1,
112 |             y = 0
113 |         },
114 |         create_card = create_tag_pack_card,
115 |         ease_background_colour = ease_tag_pack_colour
116 |     },
117 |     {
118 |         key = "tag_jumbo_1",
119 |         group_key = "k_dvrprv_tag_pack",
120 |         loc_key = "p_dvrprv_tag_jumbo",
121 |         order = 3,
122 |         name = "Jumbo Tag Pack",
123 |         config = {
124 |             extra = 4,
125 |             choose = 1
126 |         },
127 |         weight = 1,
128 |         kind = "Tag",
129 |         cost = 6,
130 |         yes_pool_flag = "Tag or Die",
131 |         pos = {
132 |             x = 2,
133 |             y = 0
134 |         },
135 |         create_card = create_tag_pack_card,
136 |         ease_background_colour = ease_tag_pack_colour
137 |     },
138 |     {
139 |         key = "tag_mega_1",
140 |         group_key = "k_dvrprv_tag_pack",
141 |         loc_key = "p_dvrprv_tag_mega",
142 |         order = 4,
143 |         name = "Mega Tag Pack",
144 |         config = {
145 |             extra = 4,
146 |             choose = 2
147 |         },
148 |         weight = 0.25,
149 |         kind = "Tag",
150 |         cost = 8,
151 |         yes_pool_flag = "Tag or Die",
152 |         pos = {
153 |             x = 3,
154 |             y = 0
155 |         },
156 |         create_card = create_tag_pack_card,
157 |         ease_background_colour = ease_tag_pack_colour
158 |     },
159 |     {
160 |         key = "film_normal_1",
161 |         group_key = "k_dvrprv_film_pack",
162 |         loc_key = "p_dvrprv_film_normal",
163 |         order = 7,
164 |         name = "Film Pack",
165 |         config = {
166 |             extra = 2,
167 |             choose = 1
168 |         },
169 |         weight = 1,
170 |         kind = "Cine",
171 |         cost = 4,
172 |         pos = {
173 |             x = 1,
174 |             y = 1
175 |         },
176 |         create_card = create_film_pack_card,
177 |         ease_background_colour = ease_film_pack_colour,
178 |         meteors = film_pack_meteors
179 |     },
180 |     {
181 |         key = "film_normal_2",
182 |         group_key = "k_dvrprv_film_pack",
183 |         loc_key = "p_dvrprv_film_normal",
184 |         order = 8,
185 |         name = "Film Pack",
186 |         config = {
187 |             extra = 2,
188 |             choose = 1
189 |         },
190 |         weight = 1,
191 |         kind = "Cine",
192 |         cost = 4,
193 |         pos = {
194 |             x = 2,
195 |             y = 1
196 |         },
197 |         create_card = create_film_pack_card,
198 |         ease_background_colour = ease_film_pack_colour,
199 |         meteors = film_pack_meteors
200 |     },
201 |     {
202 |         key = "film_jumbo_1",
203 |         group_key = "k_dvrprv_film_pack",
204 |         loc_key = "p_dvrprv_film_jumbo",
205 |         order = 9,
206 |         name = "Jumbo Film Pack",
207 |         config = {
208 |             extra = 4,
209 |             choose = 1
210 |         },
211 |         weight = 0.6,
212 |         kind = "Cine",
213 |         cost = 6,
214 |         pos = {
215 |             x = 3,
216 |             y = 1
217 |         },
218 |         create_card = create_film_pack_card,
219 |         ease_background_colour = ease_film_pack_colour,
220 |         meteors = film_pack_meteors
221 |     },
222 |     {
223 |         key = "film_mega_1",
224 |         group_key = "k_dvrprv_film_pack",
225 |         loc_key = "p_dvrprv_film_mega",
226 |         order = 10,
227 |         name = "Mega Film Pack",
228 |         config = {
229 |             extra = 2,
230 |             choose = 1
231 |         },
232 |         weight = 0.07,
233 |         kind = "Cine",
234 |         cost = 8,
235 |         pos = {
236 |             x = 4,
237 |             y = 1
238 |         },
239 |         create_card = create_film_pack_card,
240 |         ease_background_colour = ease_film_pack_colour,
241 |         meteors = film_pack_meteors
242 |     }
243 | }
244 | 
245 | for _, v in pairs(Reverie.boosters) do
246 |     v.atlas = "cine_boosters"
247 |     v.loc_vars = function(self, info_queue, card)
248 |         return { vars = { card.ability.choose, card.ability.extra }, key = v.loc_key }
249 |     end
250 | 
251 |     SMODS.Booster(v)
252 | end
253 | 
254 | SMODS.Booster:take_ownership_by_kind('Standard', {
255 |     create_card = function(self, card, i)
256 |         if Reverie.find_used_cine("Poker Face") then
257 |             card = Reverie.create_poker_face_card(G.pack_cards)
258 |             return card
259 |         else
260 |             local _edition = poll_edition('standard_edition'..G.GAME.round_resets.ante, 2, true)
261 |             local _seal = SMODS.poll_seal({mod = 10})
262 |             return {set = (pseudorandom(pseudoseed('stdset'..G.GAME.round_resets.ante)) > 0.6) and "Enhanced" or "Base", edition = _edition, seal = _seal, area = G.pack_cards, skip_materialize = true, soulable = true, key_append = "sta"}
263 |         end
264 |     end,
265 | }, true)
266 | 
267 | SMODS.Booster:take_ownership_by_kind('Buffoon', {
268 |     create_card = function(self, card)
269 |         special_reverie_joker = Reverie.create_special_joker(G.pack_cards)
270 |         if special_reverie_joker then
271 |             return special_reverie_joker
272 |         end
273 |         return {set = "Joker", area = G.pack_cards, skip_materialize = true, soulable = true, key_append = "buf"}
274 |     end,
275 | }, true)


--------------------------------------------------------------------------------
/data/joker_display.lua:
--------------------------------------------------------------------------------
  1 | -- JokerDisplay by nh6574
  2 | -- https://github.com/nh6574/JokerDisplay/blob/main/src/display_functions.lua
  3 | 
  4 | local progress_text = {
  5 |     { ref_table = "card.ability", ref_value = "progress", colour = Reverie.badge_colour },
  6 |     { text = "/" },
  7 |     { ref_table = "card.ability.extra", ref_value = "goal" }
  8 | }
  9 | 
 10 | function Card:update_cine_display(force_update, force_reload, _from)
 11 |     if self.ability and self.ability.set == "Cine" then
 12 |         if not self.children.joker_display then
 13 |             self.joker_display_values = {}
 14 |             self.joker_display_values.disabled = JokerDisplay.config.hide_by_default
 15 |             self.joker_display_values.small = false
 16 | 
 17 |             --Regular Display
 18 |             self.children.joker_display = JokerDisplayBox(self, "joker_display_disable", { type = "NORMAL" })
 19 |             self.children.joker_display_small = JokerDisplayBox(self, "joker_display_small_enable", { type = "SMALL" })
 20 |             self.children.joker_display_debuff = JokerDisplayBox(self, "joker_display_debuff", { type = "DEBUFF" })
 21 |             self:initialize_joker_display()
 22 | 
 23 |             --Perishable Display
 24 |             self.config.joker_display_perishable = {
 25 |                 n = G.UIT.ROOT,
 26 |                 config = {
 27 |                     minh = 0.5,
 28 |                     maxh = 0.5,
 29 |                     minw = 0.75,
 30 |                     maxw = 0.75,
 31 |                     r = 0.001,
 32 |                     padding = 0.1,
 33 |                     align = 'cm',
 34 |                     colour = adjust_alpha(darken(G.C.BLACK, 0.2), 0.8),
 35 |                     shadow = false,
 36 |                     func = 'joker_display_perishable',
 37 |                     ref_table = self
 38 |                 },
 39 |                 nodes = {
 40 |                     {
 41 |                         n = G.UIT.R,
 42 |                         config = { align = "cm" },
 43 |                         nodes = { { n = G.UIT.R, config = { align = "cm" }, nodes = { JokerDisplay.create_display_text_object({ ref_table = self.joker_display_values, ref_value = "perishable", colour = lighten(G.C.PERISHABLE, 0.35), scale = 0.35 }) } } }
 44 |                     }
 45 | 
 46 |                 }
 47 |             }
 48 | 
 49 |             self.config.joker_display_perishable_config = {
 50 |                 align = "tl",
 51 |                 bond = 'Strong',
 52 |                 parent = self,
 53 |                 offset = { x = 0.8, y = 0 },
 54 |             }
 55 |             if self.config.joker_display_perishable then
 56 |                 self.children.joker_display_perishable = UIBox {
 57 |                     definition = self.config.joker_display_perishable,
 58 |                     config = self.config.joker_display_perishable_config,
 59 |                 }
 60 |                 self.children.joker_display_perishable.states.collide.can = true
 61 |                 self.children.joker_display_perishable.name = "JokerDisplay"
 62 |             end
 63 | 
 64 |             --Rental Display
 65 |             self.config.joker_display_rental = {
 66 |                 n = G.UIT.ROOT,
 67 |                 config = {
 68 |                     minh = 0.5,
 69 |                     maxh = 0.5,
 70 |                     minw = 0.75,
 71 |                     maxw = 0.75,
 72 |                     r = 0.001,
 73 |                     padding = 0.1,
 74 |                     align = 'cm',
 75 |                     colour = adjust_alpha(darken(G.C.BLACK, 0.2), 0.8),
 76 |                     shadow = false,
 77 |                     func = 'joker_display_rental',
 78 |                     ref_table = self
 79 |                 },
 80 |                 nodes = {
 81 |                     {
 82 |                         n = G.UIT.R,
 83 |                         config = { align = "cm" },
 84 |                         nodes = { { n = G.UIT.R, config = { align = "cm" }, nodes = { JokerDisplay.create_display_text_object({ ref_table = self.joker_display_values, ref_value = "rental", colour = G.C.GOLD, scale = 0.35 }) } } }
 85 |                     }
 86 | 
 87 |                 }
 88 |             }
 89 | 
 90 |             self.config.joker_display_rental_config = {
 91 |                 align = "tr",
 92 |                 bond = 'Strong',
 93 |                 parent = self,
 94 |                 offset = { x = -0.8, y = 0 },
 95 |             }
 96 |             if self.config.joker_display_rental then
 97 |                 self.children.joker_display_rental = UIBox {
 98 |                     definition = self.config.joker_display_rental,
 99 |                     config = self.config.joker_display_rental_config,
100 |                 }
101 |                 self.children.joker_display_rental.states.collide.can = true
102 |                 self.children.joker_display_rental.name = "JokerDisplay"
103 |             end
104 |         else
105 |             if force_update or (JokerDisplay.config.enabled and
106 |                     (self:joker_display_has_info() or not JokerDisplay.config.hide_empty)
107 |                     and (not self.joker_display_values.disabled)) then
108 |                 if force_reload then
109 |                     self:initialize_joker_display()
110 |                 else
111 |                     self:calculate_joker_display()
112 |                 end
113 |             end
114 |         end
115 |     end
116 | end
117 | 
118 | local card_update_ref = Card.update
119 | function Card:update(dt)
120 |     card_update_ref(self, dt)
121 | 
122 |     if JokerDisplay.config.enabled and Reverie.config.jokerdisplay_compat and G.cine_quests and self.area == G.cine_quests then
123 |         if not self.joker_display_last_update_time then
124 |             self.joker_display_last_update_time = 0
125 |             self.joker_display_update_time_variance = math.random()
126 |             local joker_number_delta_variance = math.max(0.2, #G.jokers.cards / 20)
127 |             self.joker_display_next_update_time = joker_number_delta_variance / 2 +
128 |                 joker_number_delta_variance / 2 * self.joker_display_update_time_variance
129 |         elseif self.joker_display_values and G.real_dt > 0.05 and #G.jokers.cards > 20 then
130 |             self.joker_display_values.disabled = true
131 |         else
132 |             self.joker_display_last_update_time = self.joker_display_last_update_time + dt
133 |             if self.joker_display_last_update_time > self.joker_display_next_update_time then
134 |                 self.joker_display_last_update_time = 0
135 |                 local joker_number_delta_variance = math.max(0.2, #G.jokers.cards / 20)
136 |                 self.joker_display_next_update_time = joker_number_delta_variance / 2 +
137 |                     joker_number_delta_variance / 2 * self.joker_display_update_time_variance
138 |                 self:update_cine_display(false, false, "Card:update")
139 |             end
140 |         end
141 |     end
142 | end
143 | 
144 | Reverie.joker_display_definitions = {
145 |     j_dvrprv_dynamic_film = { -- Dynamic Film Joker
146 |         text = {
147 |             { text = "+" },
148 |             { ref_table = "card.ability.extra", ref_value = "chips", retrigger_type = "mult" }
149 |         },
150 |         text_config = { colour = G.C.CHIPS }
151 |     },
152 | 
153 |     c_dvrprv_ive_no_shape_quest = {
154 |         text = progress_text,
155 |         reminder_text = {
156 |             { text = "(" },
157 |             { text = "X", colour = G.C.ORANGE },
158 |             { ref_table = "card.ability.extra", ref_value = "chips", colour = G.C.ORANGE },
159 |             { text = " Chips)" }
160 |         }
161 |     },
162 |     c_dvrprv_unseen_quest = {
163 |         text = progress_text,
164 |         reminder_text = {
165 |             { text = "(" },
166 |             { ref_table = "card.ability.extra", ref_value = "slots", colour = G.C.ORANGE },
167 |             { text = " Joker slot", colour = G.C.ORANGE },
168 |             { text = ")" }
169 |         }
170 |     },
171 |     c_dvrprv_gem_heist_quest = {
172 |         text = progress_text,
173 |         reminder_text = {
174 |             { text = "(" },
175 |             { text = "Editioned Joker", colour = G.C.DARK_EDITION },
176 |             { text = ")" }
177 |         }
178 |     },
179 |     c_dvrprv_crazy_lucky_quest = {
180 |         text = progress_text,
181 |         reminder_text = {
182 |             { text = "(" },
183 |             { text = "Booster Pack", colour = G.C.ORANGE },
184 |             { text = ")" }
185 |         }
186 |     },
187 |     c_dvrprv_tag_or_die_quest = {
188 |         text = progress_text,
189 |         reminder_text = {
190 |             { text = "(" },
191 |             { text = "Skip Blind", colour = G.C.ORANGE },
192 |             { text = ")" }
193 |         }
194 |     },
195 |     c_dvrprv_let_it_moon_quest = {
196 |         text = progress_text,
197 |         reminder_text = {
198 |             { text = "(" },
199 |             { text = "Planet", colour = G.C.SECONDARY_SET.Planet },
200 |             { text = "/" },
201 |             { text = "Tarot", colour = G.C.SECONDARY_SET.Tarot },
202 |             { text = ")" }
203 |         }
204 |     },
205 |     c_dvrprv_poker_face_quest = {
206 |         text = progress_text,
207 |         reminder_text = {
208 |             { text = "(" },
209 |             { text = "Enhance", colour = G.C.ORANGE },
210 |             { text = ")" }
211 |         }
212 |     },
213 |     c_dvrprv_eerie_inn_quest = {
214 |         text = progress_text,
215 |         reminder_text = {
216 |             { text = "(" },
217 |             { text = "Destroy", colour = G.C.ORANGE },
218 |             { text = ")" }
219 |         }
220 |     },
221 |     c_dvrprv_adrifting_quest = {
222 |         text = progress_text,
223 |         reminder_text = {
224 |             { text = "(" },
225 |             { text = "Debuffed", colour = G.C.ORANGE },
226 |             { text = "/" },
227 |             { text = "Flipped", colour = G.C.ORANGE },
228 |             { text = ")" }
229 |         }
230 |     },
231 |     c_dvrprv_morsel_quest = {
232 |         text = progress_text,
233 |         reminder_text = {
234 |             { text = "(" },
235 |             { text = "Food Joker", colour = G.C.ORANGE },
236 |             { text = ")" }
237 |         }
238 |     },
239 |     c_dvrprv_alchemist_quest = {
240 |         text = progress_text,
241 |         reminder_text = {
242 |             { text = "(" },
243 |             { text = "Alchemical", colour = G.C.ORANGE },
244 |             { text = ")" }
245 |         }
246 |     },
247 |     c_dvrprv_every_hue_quest = {
248 |         text = progress_text,
249 |         reminder_text = {
250 |             { text = "(" },
251 |             { text = "Colour", colour = G.C.ORANGE },
252 |             { text = ")" }
253 |         }
254 |     },
255 |     c_dvrprv_radioactive_quest = {
256 |         text = progress_text,
257 |         reminder_text = {
258 |             { text = "(" },
259 |             { text = "Fusion", colour = G.C.GOLD },
260 |             { text = ")" }
261 |         }
262 |     },
263 |     c_dvrprv_jovial_m_quest = {
264 |         text = progress_text,
265 |         reminder_text = {
266 |             { text = "(" },
267 |             { ref_table = "card.joker_display_values", ref_value = "localized_text", colour = G.C.ORANGE },
268 |             { text = ")" }
269 |         },
270 |         calc_function = function (card)
271 |             card.joker_display_values.localized_text = localize{
272 |                 type = "name_text",
273 |                 set = "Joker",
274 |                 key = "j_jolly"
275 |             }
276 |         end
277 |     }
278 | }
279 | 
280 | for k, v in pairs(Reverie.joker_display_definitions) do
281 |     JokerDisplay.Definitions[k] = v
282 | end


--------------------------------------------------------------------------------
/lovely.toml:
--------------------------------------------------------------------------------
  1 | [manifest]
  2 | version = "1.0.0"
  3 | dump_lua = true
  4 | priority = 0
  5 | 
  6 | # add_joker()
  7 | # patch to spawn Cine cards correctly with debug menu and challenges (if that ever happens)
  8 | [[patches]]
  9 | [patches.pattern]
 10 | target = "functions/common_events.lua"
 11 | pattern = '''local _area = G.P_CENTERS[joker].consumeable and G.consumeables or G.jokers'''
 12 | position = "after"
 13 | payload = '''
 14 | if G.P_CENTERS[joker].set == "Cine" then
 15 |     _area = G.cine_quests
 16 | end
 17 | '''
 18 | match_indent = true
 19 | 
 20 | # add_joker()
 21 | # patch to spawn Cine cards correctly with debug menu and challenges (if that ever happens)
 22 | [[patches]]
 23 | [patches.pattern]
 24 | target = "functions/common_events.lua"
 25 | pattern = '''elseif G.consumeables then G.consumeables:emplace(card) end'''
 26 | position = "before"
 27 | payload = '''
 28 | elseif G.cine_quests and card.ability.set == "Cine" then
 29 |     G.cine_quests:emplace(card)
 30 | '''
 31 | match_indent = true
 32 | 
 33 | 
 34 | # Game:start_run()
 35 | # patch to add the area for Cine Cards below consumables
 36 | [[patches]]
 37 | [patches.pattern]
 38 | target = "game.lua"
 39 | pattern = '''G.playing_cards = {}'''
 40 | position = "before"
 41 | payload = '''
 42 | self.cine_quests = CardArea(0, 0, CAI.deck_W, CAI.deck_H, {
 43 |     card_limit = self.GAME.starting_params.cine_quest_slots,
 44 |     type = "joker",
 45 |     highlight_limit = 1
 46 | })
 47 | '''
 48 | match_indent = true
 49 | 
 50 | # generate_card_ui()
 51 | # Correct UI for negative cine cards
 52 | # Used for Filmstrip Sleeve + Deck
 53 | [[patches]]
 54 | [patches.pattern]
 55 | target = "functions/common_events.lua"
 56 | pattern = '''for _, v in ipairs(info_queue) do'''
 57 | position = "after"
 58 | payload = '''
 59 | if v.key == "e_negative_consumable" and _c.set == "Cine" then
 60 |     v.key = "e_negative_cine"
 61 | end
 62 | '''
 63 | match_indent = true
 64 | 
 65 | # G.FUNCS.check_for_buy_space()
 66 | # Disable buy space check for Tags
 67 | [[patches]]
 68 | [patches.pattern]
 69 | target = "functions/button_callbacks.lua"
 70 | pattern = '''card.ability.set ~= 'Default' and*'''
 71 | position = "before"
 72 | payload = '''
 73 | card.ability.set ~= "Tag" and
 74 | '''
 75 | match_indent = true
 76 | 
 77 | # G.FUNCS.buy_from_shop
 78 | # Prevent Tags from being added to the deck
 79 | # Position = "at" but not risky because it includes pattern in the payload, so other mods' patches should still work
 80 | [[patches]]
 81 | [patches.pattern]
 82 | target = "functions/button_callbacks.lua"
 83 | pattern = '''c1:add_to_deck()'''
 84 | position = "at"
 85 | payload = '''
 86 | if c1.ability.set ~= "Tag" then
 87 |     c1:add_to_deck()
 88 | end'''
 89 | match_indent = true
 90 | 
 91 | # Tag:apply_to_run()
 92 | # Ensures that the second tag created by a Double Tag triggers because if the Mega Stamp Tag
 93 | # generates a Double Tag as its random tag and any immediate tag as its pack tag then the immediate
 94 | # tag gets duplicated but the second copy will only trigger after clearing a blind
 95 | [[patches]]
 96 | [patches.pattern]
 97 | target = "tag.lua"
 98 | pattern = '''add_tag(Tag(_context.tag.key))'''
 99 | position = "after"
100 | payload = '''
101 | for i = 1, #G.GAME.tags do
102 |     G.GAME.tags[i]:apply_to_run({type = 'immediate'})
103 | end
104 | '''
105 | match_indent = true
106 | 
107 | # G.FUNCS.buy_from_shop()
108 | # When Tags are purchased, properly add them to the game and remove from the shop
109 | # Applying immediate tags is handled in injected update_shop()
110 | [[patches]]
111 | [patches.pattern]
112 | target = "functions/button_callbacks.lua"
113 | pattern = '''elseif e.config.id ~= 'buy_and_use' then'''
114 | position = "before"
115 | payload = '''
116 | elseif c1.ability.set == "Tag" then
117 |     add_tag(c1.ability.tag)
118 |     c1:remove()
119 | 
120 |     play_sound("generic1", 0.9 + math.random() * 0.1, 0.8)
121 |     play_sound("holo1", 1.2 + math.random() * 0.1, 0.4)
122 |     
123 |     for i = 1, #G.GAME.tags do
124 |         G.GAME.tags[i]:apply_to_run({type = 'immediate'})
125 |     end
126 | '''
127 | match_indent = true
128 | 
129 | # G.FUNCS.use_card()
130 | [[patches]]
131 | [patches.pattern]
132 | target = "functions/button_callbacks.lua"
133 | pattern = '''e.config.ref_table:redeem()'''
134 | position = "after"
135 | payload = '''
136 | elseif card.ability.set == "Tag" then
137 |     add_tag(card.ability.tag)
138 |     card:remove()
139 | 
140 |     play_sound("generic1", 0.9 + math.random() * 0.1, 0.8)
141 |     play_sound("holo1", 1.2 + math.random() * 0.1, 0.4)
142 | 
143 |     for i = 1, #G.GAME.tags do
144 |         G.GAME.tags[i]:apply_to_run({type = 'immediate'})
145 |     end
146 | 
147 |     dont_dissolve = true
148 |     delay_fac = 0.2'''
149 | match_indent = true
150 | 
151 | # start_materialize()
152 | # Adds dissolve colour for cine cards
153 | [[patches]]
154 | [patches.pattern]
155 | target = "card.lua"
156 | pattern = '''(self.ability.set == 'Spectral' and {G.C.SECONDARY_SET.Spectral}) or'''
157 | position = "after"
158 | payload = '''
159 | (self.ability.set == 'Cine' and {G.C.SECONDARY_SET.Cine}) or'''
160 | match_indent = true
161 | 
162 | # # Card:draw()
163 | # # Adds shaders for certain cine cards
164 | # [[patches]]
165 | # [patches.pattern]
166 | # target = "card.lua"
167 | # pattern = '''if self.ability.name == 'Invisible Joker' and (self.config.center.discovered or self.bypass_discovery_center) then'''
168 | # position = "before"
169 | # payload = '''
170 | # if self.ability.set == "Cine" and (not self.edition or not self.edition.negative) then
171 | #     if self.ability.name == "The Unseen" and (self.config.center.discovered or self.bypass_discovery_center) then
172 | #         self.children.center:draw_shader("dvrprv_ticket_negative", nil, self.ARGS.send_to_shader)
173 | #         self.children.center:draw_shader("negative_shine", nil, self.ARGS.send_to_shader)
174 | 
175 | #         if self.children.front then
176 | #             self.children.front:draw_shader("dvrprv_ticket_negative", nil, self.ARGS.send_to_shader)
177 | #         end
178 | #     elseif self.ability.name == "I Sing, I've No Shape" and self.config.center.discovered then
179 | #         self.children.center:draw_shader("dvrprv_ticket_polychrome", nil, self.ARGS.send_to_shader)
180 | #     else
181 | #         self.children.center:draw_shader("dvrprv_ticket", nil, self.ARGS.send_to_shader)
182 | #     end
183 | # end
184 | # '''
185 | # match_indent = true
186 | 
187 | # G.FUNCS.use_card()
188 | [[patches]]
189 | [patches.pattern]
190 | target = "functions/button_callbacks.lua"
191 | pattern = '''elseif card.ability.set == 'Enhanced' or card.ability.set == 'Default'*'''
192 | position = "before"
193 | payload = '''
194 | ::reverie_use_card_consumable_skip::'''
195 | match_indent = true
196 | 
197 | # G.FUNCS.use_card()
198 | [[patches]]
199 | [patches.pattern]
200 | target = "functions/button_callbacks.lua"
201 | pattern = '''if card:check_use() then '''
202 | position = "before"
203 | payload = '''
204 | local is_pack_card = card.area and card.area == G.pack_cards'''
205 | match_indent = true
206 | 
207 | # G.FUNCS.use_card()
208 | [[patches]]
209 | [patches.pattern]
210 | target = "functions/button_callbacks.lua"
211 | pattern = '''*G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED*'''
212 | position = "before"
213 | payload = '''
214 | local is_cine = Reverie.is_cine_or_reverie(card)
215 | if is_pack_card and (Reverie.is_in_reverie_pack() or is_cine) then
216 |     (is_cine and G.cine_quests or G.consumeables):emplace(card)
217 |     card:add_to_deck()
218 |     play_sound('card1', 0.8, 0.6)
219 |     play_sound('generic1')
220 |     dont_dissolve = true
221 |     delay_fac = 0.2
222 | 
223 |     goto reverie_use_card_consumable_skip
224 | end'''
225 | match_indent = true
226 | 
227 | # card_eval_status_text()
228 | # Position card tooltips for cine cards
229 | [[patches]]
230 | [patches.pattern]
231 | target = "functions/common_events.lua"
232 | pattern = '''elseif card.area == G.hand*'''
233 | position = "before"
234 | payload = '''
235 | elseif card.area == G.cine_quests then
236 |     y_off = 0.05 * card.T.h'''
237 | match_indent = true
238 | 
239 | # G.FUNCS.end_consumeable()
240 | # blocks newly gained new_blind_choice tags from triggering in shop
241 | [[patches]]
242 | [patches.regex]
243 | target = "functions/button_callbacks.lua"
244 | pattern = '''ease_background_colour_blind\(G.GAME.PACK_INTERRUPT\)((.|\n)*?)(?[ \t]*)for i = 1, #G\.GAME\.tags do\n'''
245 | position = "after"
246 | line_prepend = "$indent"
247 | payload = '''
248 | if G.shop then
249 |     break -- blocking newly gained new_blind_choice tags from triggering in shop
250 | end
251 | 
252 | '''
253 | 
254 | # Card:hover()
255 | # Add tooltip for jokers affected by morsel
256 | [[patches]]
257 | [patches.pattern]
258 | target = "card.lua"
259 | pattern = '''self.ability_UIBox_table = self:generate_UIBox_ability_table()'''
260 | position = "after"
261 | payload = '''
262 | 
263 | if self.ability.morseled then
264 |     Reverie.morselize_UI(self)
265 | end
266 | '''
267 | match_indent = true
268 | 
269 | # Card:set_edition() SMOD override
270 | [[patches]]
271 | [patches.pattern]
272 | target = '=[SMODS _ "src/overrides.lua"]'
273 | pattern = '''elseif self.ability.set == 'Joker' and self.area == G.jokers then'''
274 | position = "before"
275 | payload = '''
276 | elseif self.ability.consumeable and self.area == G.cine_quests then
277 |     G.cine_quests.config.card_limit = G.cine_quests.config.card_limit - self.edition.card_limit
278 | '''
279 | match_indent = true
280 | 
281 | # Card:set_edition() SMOD override
282 | [[patches]]
283 | [patches.pattern]
284 | target = '=[SMODS _ "src/overrides.lua"]'
285 | pattern = '''elseif self.ability.set == 'Joker' then'''
286 | position = "before"
287 | payload = '''
288 |     if self.ability.consumeable and self.area == G.cine_quests then
289 |         G.consumeables.config.card_limit = G.consumeables.config.card_limit - self.edition.card_limit
290 |         G.cine_quests.config.card_limit = G.cine_quests.config.card_limit + self.edition.card_limit
291 |     end
292 | '''
293 | match_indent = true
294 | 
295 | # G.FUNCS.use_card()
296 | # As the maintainer of the fork, couldn't tell ya what this is for
297 | [[patches]]
298 | [patches.pattern]
299 | target = "functions/button_callbacks.lua"
300 | pattern = '''e.config.ref_table:use_consumeable(area)'''
301 | position = "after"
302 | payload = '''
303 | e.config.ref_table.ability.not_destroyed = true
304 | '''
305 | match_indent = true
306 | 
307 | # G.FUNCS.buy_from_shop
308 | # Patch to make controller go to the correct card area after buying a shop tag
309 | [[patches]]
310 | [patches.pattern]
311 | target = "functions/button_callbacks.lua"
312 | pattern = '''G.CONTROLLER:save_cardarea_focus('jokers')'''
313 | position = "before"
314 | payload = '''
315 | if c1.ability.set == "Tag" then
316 |     G.CONTROLLER:save_cardarea_focus("shop_jokers")
317 |     G.CONTROLLER:recall_cardarea_focus("shop_jokers")
318 | 
319 | else
320 | '''
321 | match_indent = true
322 | 
323 | # G.FUNCS.buy_from_shop
324 | # Patch to make controller go to the correct card area after buying a shop tag
325 | # This just adds the end of the else statement
326 | [[patches]]
327 | [patches.pattern]
328 | target = "functions/button_callbacks.lua"
329 | pattern = '''G.CONTROLLER:recall_cardarea_focus('jokers')'''
330 | position = "after"
331 | payload = '''
332 | end
333 | '''
334 | match_indent = true
335 | 
336 | # get_badge_colour()
337 | # Adds colour for Morsel badge
338 | [[patches]]
339 | [patches.pattern]
340 | target = "functions/UI_definitions.lua"
341 | pattern = '''pinned_left = G.C.ORANGE,'''
342 | position = "before"
343 | payload = '''
344 | morseled = HEX("b0aa9f"),'''
345 | match_indent = true
346 | 
347 | # G.FUNCS.reroll_shop()
348 | # Set adjusted reroll prices for active cine cards
349 | [[patches]]
350 | [patches.pattern]
351 | target = "functions/button_callbacks.lua"
352 | pattern = '''calculate_reroll_cost(final_free)'''
353 | position = "after"
354 | payload = '''
355 | Reverie.calculate_reroll_cost()
356 | '''
357 | match_indent = true
358 | 
359 | [[patches]]
360 | [patches.pattern]
361 | target = "functions/UI_definitions.lua"
362 | pattern = '''if polled_rate > check_rate and polled_rate <= check_rate + v.val then'''
363 | position = "before"
364 | payload = '''
365 | if _ == 1 and G.GAME.selected_sleeve and G.GAME.selected_sleeve == "sleeve_dvrprv_filmstrip" and G.GAME.selected_back.name == "Filmstrip Deck" then
366 |     local rate = CardSleeves.Sleeve:get_obj(G.GAME.selected_sleeve).config.rate
367 |     table.insert(rates, {
368 |         type = "Cine_Quest",
369 |         val = rate
370 |     })
371 |     total_rate = total_rate + rate
372 |     polled_rate = pseudorandom(pseudoseed("cdt"..G.GAME.round_resets.ante)) * total_rate
373 | end
374 | '''
375 | match_indent = true
376 | 
377 | # Card:flip()
378 | # Creates illusion of Cine card flipping over to its back without actually flipping it over
379 | # Copied from Bunco's Cassette
380 | [[patches]]
381 | [patches.pattern]
382 | target = 'card.lua'
383 | pattern = "self.facing='back'"
384 | position = 'after'
385 | match_indent = true
386 | payload = '''
387 | if self.config.center.set == 'Cine' then
388 |     self:flip()
389 | end
390 | '''
391 | 
392 | # Tag:set_ability()
393 | # Fixes orbital tags
394 | # Stolen from Ortalab, clearly they ran into the same problems as I
395 | [[patches]]
396 | [patches.pattern]
397 | target = 'tag.lua'
398 | pattern = '''
399 | if G.GAME.orbital_choices and G.GAME.orbital_choices[G.GAME.round_resets.ante][self.ability.blind_type] then
400 |     self.ability.orbital_hand = G.GAME.orbital_choices[G.GAME.round_resets.ante][self.ability.blind_type]
401 | end
402 | '''
403 | position = 'at'
404 | match_indent = true
405 | payload = '''
406 | if G.GAME.orbital_choices and G.GAME.orbital_choices[G.GAME.round_resets.ante] and G.GAME.orbital_choices[G.GAME.round_resets.ante][self.ability.blind_type] then
407 |     self.ability.orbital_hand = G.GAME.orbital_choices[G.GAME.round_resets.ante][self.ability.blind_type]       
408 | else
409 |     local _poker_hands = {}
410 |     for k, v in pairs(G.GAME.hands) do
411 |         if v.visible then _poker_hands[#_poker_hands+1] = k end
412 |     end
413 |     G.GAME.orbital_choices[G.GAME.round_resets.ante] = G.GAME.orbital_choices[G.GAME.round_resets.ante] or {}
414 |     G.GAME.orbital_choices[G.GAME.round_resets.ante][self.ability.blind_type] = pseudorandom_element(_poker_hands, pseudoseed('orbital'))
415 | end
416 | '''
417 | 


--------------------------------------------------------------------------------
/localization/ko.lua:
--------------------------------------------------------------------------------
  1 | return {
  2 |     descriptions = {
  3 |         Cine = {
  4 |             c_dvrprv_ive_no_shape_quest = {
  5 |                 name = "교환권",
  6 |                 text = {
  7 |                     "필요한 칩의 {C:attention}#1#{}배 이상을 획득해",
  8 |                     "{C:attention}#2#{}개의 {C:attention}블라인드{}에서 승리하면",
  9 |                     "{C:cine}허무한 허무함을 보라{}로 바뀝니다",
 10 |                     "{C:inactive}(현재 {C:attention}#3#{C:inactive}/#2#)"
 11 |                 }
 12 |             },
 13 |             c_dvrprv_ive_no_shape = {
 14 |                 name = "허무한 허무함을 보라",
 15 |                 text = {
 16 |                     "이번 상점 동안에는",
 17 |                     "보유 중인 {C:attention}조커{}만",
 18 |                     "나타납니다",
 19 |                     "새로고침 비용 {C:red}+$#1#"
 20 |                 }
 21 |             },
 22 |             c_dvrprv_unseen_quest = {
 23 |                 name = "교환권",
 24 |                 text = {
 25 |                     "{C:attention}#2#{} 라운드 동안 {C:attention}조커{} 슬롯 {C:attention}#1#{}개를",
 26 |                     "비워 두면 {C:cine}불가시{}로 바뀝니다",
 27 |                     "{C:inactive}(현재 {C:attention}#3#{C:inactive}/#2#)"
 28 |                 }
 29 |             },
 30 |             c_dvrprv_unseen = {
 31 |                 name = "불가시",
 32 |                 text = {
 33 |                     "이번 상점 동안에는",
 34 |                     "모든 {C:attention}조커{}와 {C:attention}소모품{}이",
 35 |                     "{C:dark_edition}네거티브{}가 됩니다",
 36 |                     "새로고침 비용 {C:red}#1#{}배",
 37 |                     "{s:0.8}카드 새로고침"
 38 |                 }
 39 |             },
 40 |             c_dvrprv_gem_heist_quest = {
 41 |                 name = "교환권",
 42 |                 text = {
 43 |                     "{C:attention}에디션{} 있는 {C:attention}조커 #1#{}장을 판매하면",
 44 |                     "{C:cine}보석 강탈 사건{}으로 바뀝니다",
 45 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
 46 |                 }
 47 |             },
 48 |             c_dvrprv_gem_heist = {
 49 |                 name = "보석 강탈 사건",
 50 |                 text = {
 51 |                     "이번 상점 동안에는",
 52 |                     "모든 카드가 {C:dark_edition}홀로그래픽{}이",
 53 |                     "되고 {C:attention}#1#%{} 할인됩니다",
 54 |                     "카드 및 {s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
 55 |                 }
 56 |             },
 57 |             c_dvrprv_crazy_lucky_quest = {
 58 |                 name = "교환권",
 59 |                 text = {
 60 |                     "{C:attention}부스터 팩 #1#{}개를 열면",
 61 |                     "{C:cine}크레이지 럭키{}로 바뀝니다",
 62 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
 63 |                 }
 64 |             },
 65 |             c_dvrprv_crazy_lucky = {
 66 |                 name = "크레이지 럭키",
 67 |                 text = {
 68 |                     "이번 상점 동안에는",
 69 |                     "{C:attention}팩{}만 나타납니다",
 70 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
 71 |                 }
 72 |             },
 73 |             c_dvrprv_tag_or_die_quest = {
 74 |                 name = "교환권",
 75 |                 text = {
 76 |                     "{C:attention}블라인드 #1#{}개를 건너뛰면",
 77 |                     "{C:cine}위기일발{}로 바뀝니다",
 78 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
 79 |                 }
 80 |             },
 81 |             c_dvrprv_tag_or_die = {
 82 |                 name = "위기일발",
 83 |                 text = {
 84 |                     "이번 상점 동안에는",
 85 |                     "{C:money}$#1#{}로 구매 가능한",
 86 |                     "{C:attention}태그{}만 나타납니다",
 87 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
 88 |                 }
 89 |             },
 90 |             c_dvrprv_let_it_moon_quest = {
 91 |                 name = "교환권",
 92 |                 text = {
 93 |                     "{C:planet}행성{} 또는 {C:tarot}타로{} 카드를 {C:attention}#1#{}장",
 94 |                     "사용하면 {C:cine}렛 잇 문{}으로 바뀝니다",
 95 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
 96 |                 }
 97 |             },
 98 |             c_dvrprv_let_it_moon = {
 99 |                 name = "렛 잇 문",
100 |                 text = {
101 |                     "이번 상점 동안에는",
102 |                     "{C:planet}행성{}과 {C:tarot}타로{} 카드만",
103 |                     "나타납니다",
104 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
105 |                 }
106 |             },
107 |             c_dvrprv_poker_face_quest = {
108 |                 name = "교환권",
109 |                 text = {
110 |                     "{C:attention}플레잉 카드 #1#{}장을 {C:attention}강화{}하면",
111 |                     "{C:cine}포커 페이스{}로 바뀝니다",
112 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
113 |                 }
114 |             },
115 |             c_dvrprv_poker_face = {
116 |                 name = "포커 페이스",
117 |                 text = {
118 |                     "이번 상점 동안에는",
119 |                     "덱에 있는 {C:attention}플레잉 카드{}만",
120 |                     "나타납니다",
121 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
122 |                 }
123 |             },
124 |             c_dvrprv_eerie_inn_quest = {
125 |                 name = "교환권",
126 |                 text = {
127 |                     "카드를 {C:attention}#1#{}장 파괴하면",
128 |                     "{C:cine}오싹한 여관{}으로 바뀝니다",
129 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
130 |                 }
131 |             },
132 |             c_dvrprv_eerie_inn = {
133 |                 name = "오싹한 여관",
134 |                 text = {
135 |                     "이번 상점 동안에는",
136 |                     "{C:spectral}유령 팩{}만 나타납니다",
137 |                     "새로고침 비용 {C:red}#1#{}배",
138 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
139 |                 }
140 |             },
141 |             c_dvrprv_adrifting_quest = {
142 |                 name = "교환권",
143 |                 text = {
144 |                     "{C:attention}디버프{}됐거나 {C:attention}뒤집힌{} 카드 {C:attention}#1#{}장을",
145 |                     "플레이하면 {C:cine}파랑 끝에서{}로 바뀝니다",
146 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
147 |                 }
148 |             },
149 |             c_dvrprv_adrifting = {
150 |                 name = "파랑 끝에서",
151 |                 text = {
152 |                     "이번 상점 동안에는",
153 |                     "모든 것이 {C:attention}$#1#{} 지만",
154 |                     "{C:attention}뒤집혀서{} 나타납니다",
155 |                     "카드 및 {s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
156 |                 }
157 |             },
158 |             c_dvrprv_morsel_quest = {
159 |                 name = "교환권",
160 |                 text = {
161 |                     "{C:attention}음식 조커 #1#{}장을 획득하면",
162 |                     "{C:cine}식탁의 길이{}로 바뀝니다",
163 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
164 |                 }
165 |             },
166 |             c_dvrprv_morsel = {
167 |                 name = "식탁의 길이",
168 |                 text = {
169 |                     "이번 상점 동안에는",
170 |                     "모든 능력치가 {C:attention}두 배{}가 된",
171 |                     "{C:attention}음식 조커{}만 나타납니다",
172 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
173 |                 }
174 |             },
175 |             c_dvrprv_alchemist_quest = {
176 |                 name = "교환권",
177 |                 text = {
178 |                     "{C:alchemical}연금술{} 카드를 {C:attention}#1#{}장 사용하면",
179 |                     "{C:cine}풀 메탈 알케미스트{}로 바뀝니다",
180 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
181 |                 }
182 |             },
183 |             c_dvrprv_alchemist = {
184 |                 name = "풀 메탈 알케미스트",
185 |                 text = {
186 |                     "이번 상점 동안에는",
187 |                     "소모품 슬롯이 {C:attention}+#1#{}개 증가하고",
188 |                     "{C:alchemical}연금술{} 카드만 나타납니다",
189 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
190 |                 }
191 |             },
192 |             c_dvrprv_every_hue_quest = {
193 |                 name = "교환권",
194 |                 text = {
195 |                     "{C:colourcard}색상{} 카드를 {C:attention}#1#{}장 사용하면",
196 |                     "{C:cine}모든 빛깔의{}로 바뀝니다",
197 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
198 |                 }
199 |             },
200 |             c_dvrprv_every_hue = {
201 |                 name = "모든 빛깔의",
202 |                 text = {
203 |                     "이번 상점 동안에는",
204 |                     "{C:attention}#1# 라운드{}가 추가된",
205 |                     "{C:colourcard}색상{} 카드만 나타납니다",
206 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
207 |                 }
208 |             },
209 |             c_dvrprv_radioactive_quest = {
210 |                 name = "교환권",
211 |                 text = {
212 |                     "{C:colourcard}융합{} 조커를 {C:attention}#1#{}장 획득하면",
213 |                     "{C:cine}라디오액티브{}로 바뀝니다",
214 |                     "{C:inactive}(현재 {C:attention}#2#{C:inactive}/#1#)"
215 |                 }
216 |             },
217 |             c_dvrprv_radioactive = {
218 |                 name = "라디오액티브",
219 |                 text = {
220 |                     "이번 상점 동안에는",
221 |                     "{C:attention}융합{}에 사용될 수 있는",
222 |                     "{C:attention}조커{}만 나타납니다",
223 |                     "{s:0.8,C:attention}부스터 팩 {s:0.8}새로고침"
224 |                 }
225 |             }
226 |         },
227 |         Joker = {
228 |             j_diet_cola_morsel_alternative = {
229 |                 text = {
230 |                     ".",
231 |                     ".",
232 |                     "두 개 생성합니다",
233 |                 }
234 |             },
235 |             j_dvrprv_dynamic_film = {
236 |                 name = "역동적인 필름",
237 |                 text = {
238 |                     "이 조커는 {C:cine}교환권{}에",
239 |                     "진척도가 쌓일 때마다",
240 |                     "칩 획득량이 {C:chips}+#2#{}개 증가합니다",
241 |                     "{C:inactive}(현재 칩 {C:chips}+#1#{C:inactive}개)"
242 |                 }
243 |             }
244 |         },
245 |         Back = {
246 |             b_dvrprv_filmstrip = {
247 |                 name = "필름스트립 덱",
248 |                 text = {
249 |                     "{C:cine}영화{} 카드가 중첩될 수 있습니다",
250 |                     "영화 슬롯 {C:attention}+#1#{}개"
251 |                 }
252 |             },
253 |             b_dvrprv_stamp = {
254 |                 name = "스탬프 덱",
255 |                 text = {
256 |                     "{C:attention}블라인드{}를 건너뛰면",
257 |                     "{C:attention,T:p_tag_jumbo_1}#1#{}을 대신 획득합니다"
258 |                 }
259 |             }
260 |         },
261 |         Tag = {
262 |             tag_dvrprv_cine = {
263 |                 name = "반쪽 태그",
264 |                 text = {
265 |                     "무료 {C:cine}영화 팩{}을",
266 |                     "획득합니다"
267 |                 }
268 |             },
269 |             tag_dvrprv_jumbo_tag = {
270 |                 name = "기호 태그",
271 |                 text = {
272 |                     "무료 {C:attention}태그 팩{}을",
273 |                     "획득합니다"
274 |                 }
275 |             },
276 |             tag_dvrprv_mega_tag = {
277 |                 name = "도장 태그",
278 |                 text = {
279 |                     "무료 {C:attention}점보 태그 팩{}을",
280 |                     "획득합니다"
281 |                 }
282 |             }
283 |         },
284 |         Spectral = {
285 |             c_dvrprv_reverie = {
286 |                 name = "몽상",
287 |                 text = {
288 |                     "이번 상점에",
289 |                     "모든 {C:cine,E:1}영화 카드{}를",
290 |                     "적용합니다"
291 |                 }
292 |             }
293 |         },
294 |         Voucher = {
295 |             v_dvrprv_script = {
296 |                 name = "각본",
297 |                 text = {
298 |                     "{C:cine}영화{} 카드가 활성화된 동안",
299 |                     "상점의 카드 판매 슬롯이",
300 |                     "{C:attention}+#1#{}개 증가합니다"
301 |                 }
302 |             },
303 |             v_dvrprv_megaphone = {
304 |                 name = "확성기",
305 |                 text = {
306 |                     "{C:cine}교환권{} 달성 목표가",
307 |                     "절반으로 줄어듭니다"
308 |                 }
309 |             }
310 |         },
311 |         Edition = {
312 |             e_negative_cine = {
313 |                 name = "네거티브",
314 |                 text = {
315 |                     "영화 슬롯 {C:dark_edition}+#1#{}개"
316 |                 }
317 |             }
318 |         },
319 |         Other = {
320 |             p_dvrprv_tag_normal = {
321 |                 name = "태그 팩",
322 |                 text = {
323 |                     "최대 {C:attention}#2#{}개의 {C:attention}태그{} 중",
324 |                     "{C:attention}#1#{}개를 선택합니다"
325 |                 }
326 |             },
327 |             p_dvrprv_tag_jumbo = {
328 |                 name = "점보 태그 팩",
329 |                 text = {
330 |                     "최대 {C:attention}#2#{}개의 {C:attention}태그{} 중",
331 |                     "{C:attention}#1#{}개를 선택합니다"
332 |                 }
333 |             },
334 |             p_dvrprv_tag_mega = {
335 |                 name = "메가 태그 팩",
336 |                 text = {
337 |                     "최대 {C:attention}#2#{}개의 {C:attention}태그{} 중",
338 |                     "{C:attention}#1#{}개를 선택합니다"
339 |                 }
340 |             },
341 |             p_dvrprv_crazy_lucky = {
342 |                 name = "팩",
343 |                 text = {
344 |                     "최대 {C:attention}#2#{}개의 {C:attention,E:1}아무거나{} 중",
345 |                     "{C:attention}#1#{}개를 선택해 보유합니다"
346 |                 }
347 |             },
348 |             p_dvrprv_adrifting = {
349 |                 name = "뒤집힌 팩",
350 |                 text = {
351 |                     "{C:attention}무언가{} 중",
352 |                     "{C:attention}몇 개{}를 선택합니다"
353 |                 }
354 |             },
355 |             p_dvrprv_film_normal = {
356 |                 name = "영화 팩",
357 |                 text = {
358 |                     "최대 {C:attention}#2#{}개의 {C:cine}교환권{} 중",
359 |                     "{C:attention}#1#{}개를 선택해 보유합니다"
360 |                 }
361 |             },
362 |             p_dvrprv_film_jumbo = {
363 |                 name = "점보 영화 팩",
364 |                 text = {
365 |                     "최대 {C:attention}#2#{}개의 {C:cine}교환권{} 중",
366 |                     "{C:attention}#1#{}개를 선택해 보유합니다"
367 |                 }
368 |             },
369 |             p_dvrprv_film_mega = {
370 |                 name = "메가 영화 팩",
371 |                 text = {
372 |                     "최대 {C:attention}#2#{}개의 {C:cine}영화{} 카드 중",
373 |                     "{C:attention}#1#{}개를 선택해 보유합니다"
374 |                 }
375 |             },
376 |             undiscovered_cine = {
377 |                 name = "발견되지 않음",
378 |                 text = {
379 |                     "시드를 설정하지 않은",
380 |                     "런에서 이 카드를",
381 |                     "구매하거나 사용하여",
382 |                     "기능을 알아보세요",
383 |                 }
384 |             },
385 |             undiscovered_cine_quest = {
386 |                 name = "발견되지 않음",
387 |                 text = {
388 |                     "시드를 설정하지 않은",
389 |                     "런에서 이 카드를",
390 |                     "구매하거나 사용하여",
391 |                     "기능을 알아보세요",
392 |                 }
393 |             },
394 |             morseled = {
395 |                 name = "식탁의 길이",
396 |                 text = {
397 |                     "모든 능력치가",
398 |                     "{C:attention}두 배{}로 증가했습니다"
399 |                 }
400 |             },
401 |         }
402 |     },
403 |     misc = {
404 |         dictionary = {
405 |             k_cine = "영화",
406 |             k_dvrprv_tag = "태그",
407 |             k_dvrprv_tag_pack = "태그 팩",
408 |             k_dvrprv_crazy_pack = "팩",
409 |             k_dvrprv_film_pack = "영화 팩",
410 |             b_cine_cards = "영화 카드"
411 |         },
412 |         labels = {
413 |             morseled = "식탁의 길이"
414 |         }
415 |     }
416 | }


--------------------------------------------------------------------------------
/localization/zh_CN.lua:
--------------------------------------------------------------------------------
  1 | return {
  2 |     descriptions = {
  3 |         Cine = {
  4 |             c_dvrprv_ive_no_shape_quest = {
  5 |                 name = "兑换券",
  6 |                 text = {
  7 |                     "",
  8 |                     "以{C:attention}X#1#{}分数要求",
  9 |                     "通过{C:attention}#2#次盲注{}后",
 10 |                     "转换为{C:cine}我型我秀",
 11 |                     "{C:inactive}(当前为{C:attention}#3#{C:inactive}/#2#)"
 12 |                 }
 13 |             },
 14 |             c_dvrprv_ive_no_shape = {
 15 |                 name = "我型我秀",
 16 |                 text = {
 17 |                     "本回合商店中",
 18 |                     "只会出现已获得的{C:attention}小丑{}",
 19 |                     "重掷费用{C:red}+$#1#{}"
 20 |                 }
 21 |             },
 22 |             c_dvrprv_unseen_quest = {
 23 |                 name = "兑换券",
 24 |                 text = {
 25 |                     "累计{C:attention}#2#回合{}中",
 26 |                     "拥有{C:attention}#1#{}个空的{C:attention}小丑{}槽",
 27 |                     "转换为{C:cine}怪形{}",
 28 |                     "{C:inactive}(当前为{C:attention}#3#{C:inactive}/#2#)"
 29 |                 }
 30 |             },
 31 |             c_dvrprv_unseen = {
 32 |                 name = "怪形",
 33 |                 text = {
 34 |                     "本回合商店中",
 35 |                     "所有{C:attention}小丑牌{}和{C:attention}消耗牌",
 36 |                     "带有{C:dark_edition}负片",
 37 |                     "重掷费用{C:red}X#1#{}"
 38 |                 }
 39 |             },
 40 |             c_dvrprv_gem_heist_quest = {
 41 |                 name = "兑换券",
 42 |                 text = {
 43 |                     "累计出售",
 44 |                     "{C:attention}#1#张版本小丑{}后",
 45 |                     "转换为{C:cine}宝石劫案{}",
 46 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
 47 |                 }
 48 |             },
 49 |             c_dvrprv_gem_heist = {
 50 |                 name = "宝石劫案",
 51 |                 text = {
 52 |                     "本回合商店中",
 53 |                     "所有卡牌带有",
 54 |                     "{C:dark_edition}多彩{}并且获得{C:attention}#1#%{}折扣"
 55 |                 }
 56 |             },
 57 |             c_dvrprv_crazy_lucky_quest = {
 58 |                 name = "兑换券",
 59 |                 text = {
 60 |                     "累计打开{C:attention}#1#个补充包{}后",
 61 |                     "转换为{C:cine}疯狂幸运{}",
 62 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
 63 |                 }
 64 |             },
 65 |             c_dvrprv_crazy_lucky = {
 66 |                 name = "疯狂幸运",
 67 |                 text = {
 68 |                     "本回合商店中",
 69 |                     "所有东西都变成{C:attention}疯狂包",
 70 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
 71 |                 }
 72 |             },
 73 |             c_dvrprv_tag_or_die_quest = {
 74 |                 name = "兑换券",
 75 |                 text = {
 76 |                     "累计跳过{C:attention}#1#次盲注{}后",
 77 |                     "转换为{C:cine}标签之死{}",
 78 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
 79 |                 }
 80 |             },
 81 |             c_dvrprv_tag_or_die = {
 82 |                 name = "标签之死",
 83 |                 text = {
 84 |                     "本回合商店中",
 85 |                     "只有花费{C:money}$#1#{}的",
 86 |                     "{C:attention}标签{}能够出现",
 87 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
 88 |                 }
 89 |             },
 90 |             c_dvrprv_let_it_moon_quest = {
 91 |                 name = "兑换券",
 92 |                 text = {
 93 |                     "累计使用{C:attention}#1#张{C:planet}星球牌",
 94 |                     "或{C:tarot}塔罗牌{}后",
 95 |                     "转换为{C:cine}月亮之上{}",
 96 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
 97 |                 }
 98 |             },
 99 |             c_dvrprv_let_it_moon = {
100 |                 name = "月亮之上",
101 |                 text = {
102 |                     "本回合商店中",
103 |                     "只会出现{C:planet}星球牌{}",
104 |                     "和{C:tarot}塔罗牌{}",
105 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
106 |                 }
107 |             },
108 |             c_dvrprv_poker_face_quest = {
109 |                 name = "兑换券",
110 |                 text = {
111 |                     "累计增强{C:attention}#1#{}张",
112 |                     "{C:attention}游戏牌{}后",
113 |                     "转换为{C:cine}扑克脸{}",
114 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
115 |                 }
116 |             },
117 |             c_dvrprv_poker_face = {
118 |                 name = "扑克脸",
119 |                 text = {
120 |                     "本回合商店中",
121 |                     "只有你牌组中的",
122 |                     "{C:attention}游戏牌{}会出现",
123 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
124 |                 }
125 |             },
126 |             c_dvrprv_eerie_inn_quest = {
127 |                 name = "兑换券",
128 |                 text = {
129 |                     "累计摧毁",
130 |                     "{C:attention}#1#张{C:spectral}牌{}后",
131 |                     "转换为{C:cine}诡异旅馆{}",
132 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
133 |                 }
134 |             },
135 |             c_dvrprv_eerie_inn = {
136 |                 name = "诡异旅馆",
137 |                 text = {
138 |                     "本回合商店中",
139 |                     "只有{C:spectral}幻灵包",
140 |                     "会出现",
141 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
142 |                 }
143 |             },
144 |             c_dvrprv_adrifting_quest = {
145 |                 name = "兑换券",
146 |                 text = {
147 |                     "累计打出{C:attention}#1#张被削弱的{}",
148 |                     "或{C:attention}背面朝上的牌{}后",
149 |                     "转换为{C:cine}漂流记{}",
150 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
151 |                 }
152 |             },
153 |             c_dvrprv_adrifting = {
154 |                 name = "漂流记",
155 |                 text = {
156 |                     "本回合商店中",
157 |                     "所有东西都是{C:attention}背面朝上",
158 |                     "{C:attention}售出{}且价格都是{C:money}$#1#",
159 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
160 |                 }
161 |             },
162 |             c_dvrprv_morsel_quest = {
163 |                 name = "兑换券",
164 |                 text = {
165 |                     "累计获得{C:attention}#1#张",
166 |                     "{C:attention}食物小丑{}后",
167 |                     "转换为{C:cine}莫瑟尔{}",
168 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
169 |                 }
170 |             },
171 |             c_dvrprv_morsel = {
172 |                 name = "莫瑟尔",
173 |                 text = {
174 |                     "本回合商店中",
175 |                     "只有能力翻倍的",
176 |                     "{C:attention}食物小丑会出现",
177 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
178 |                 }
179 |             },
180 |             c_dvrprv_alchemist_quest = {
181 |                 name = "兑换券",
182 |                 text = {
183 |                     "累计使用{C:attention}#1#张",
184 |                     "{C:alchemical}炼金牌{}后",
185 |                     "转换为{C:cine}化学狂暴",
186 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
187 |                 }
188 |             },
189 |             c_dvrprv_alchemist = {
190 |                 name = "化学狂暴",
191 |                 text = {
192 |                     "本回合商店中",
193 |                     "临时{C:attention}+#1#{}消耗牌槽位",
194 |                     "只有{C:alchemical}炼金牌{}会出现",
195 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
196 |                 }
197 |             },
198 |             c_dvrprv_every_hue_quest = {
199 |                 name = "兑换券",
200 |                 text = {
201 |                     "累计使用{C:attention}#1#张",
202 |                     "{C:colourcard}色彩牌{}后",
203 |                     "转换为{C:cine}缤纷时刻",
204 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
205 |                 }
206 |             },
207 |             c_dvrprv_every_hue = {
208 |                 name = "缤纷时刻",
209 |                 text = {
210 |                     "本回合商店中",
211 |                     "只有已经积累",
212 |                     "{C:attention}#1#个回合{}的",
213 |                     "{C:colourcard}色彩牌{}会出现",
214 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
215 |                 }
216 |             },
217 |             c_dvrprv_radioactive_quest = {
218 |                 name = "兑换券",
219 |                 text = {
220 |                     "在获得{C:attention}#1#张",
221 |                     "{C:attention}融合小丑{}后",
222 |                     "转换为{C:cine}放射性",
223 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
224 |                 }
225 |             },
226 |             c_dvrprv_radioactive = {
227 |                 name = "放射性",
228 |                 text = {
229 |                     "本回合商店中",
230 |                     "只有能够被",
231 |                     "{C:attention}融合{}",
232 |                     "的{C:attention}小丑{}会出现",
233 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
234 |                 }
235 |             },
236 |             c_dvrprv_jovial_m_quest = {
237 |                 name = "兑换券",
238 |                 text = {
239 |                     "在出售{C:attention}#1#{}张",
240 |                     "{C:attention}#3#{}后",
241 |                     "转换为{C:cine}乐乐券",
242 |                     "{C:inactive}(当前为{C:attention}#2#{C:inactive}/#1#)"
243 |                 }
244 |             },
245 |             c_dvrprv_jovial_m = {
246 |                 name = "乐乐券M",
247 |                 text = {
248 |                     "本回合商店中",
249 |                     "只有{C:cry_epic}史诗{}或{C:cry_exotic}域外{}稀有度{C:attention}小丑{}出现",
250 |                     "{s:0.8}且能改变{s:0.8,C:attention}补充包"
251 |                 }
252 |             }
253 |         },
254 |         Joker = {
255 |             j_diet_cola_morsel_alternative = {
256 |                 text = {
257 |                     ".",
258 |                     "创建两个免费的",
259 |                     "{C:attention}双倍标签"
260 |                 }
261 |             },
262 |             j_olab_fine_wine_morsel_alternative = {
263 |                 text = {
264 |                     "每回合{C:red}+#1#{}出牌和{C:red}+2{}弃牌",
265 |                 }
266 |             },
267 |             j_olab_mystery_soda_morsel_alternative = {
268 |                 text = {
269 |                     ".",
270 |                     "四个免费{C:attention}标签"
271 |                 }
272 |             },
273 |             j_mf_tonersoup_morsel_alternative = {
274 |                 text = {
275 |                     "生成2张{C:tarot}塔罗牌{}"
276 |                 }
277 |             },
278 |             j_bunc_fondue_morsel_alternative = {
279 |                 text = {
280 |                     ".",
281 |                     "每回合的{C:attention}f前两次出牌{}"
282 |                 }
283 |             },
284 |             j_evo_full_sugar_cola_morsel_alternative = {
285 |                 text = {
286 |                     ".",
287 |                     "生成{C:attention}4{}个免费"
288 |                 }
289 |             },
290 |             j_kcva_swiss_morsel_alternative = {
291 |                 text = {
292 |                     "{C:mult}+20{}倍率"
293 |                 }
294 |             },
295 |             j_jank_cut_the_cheese_morsel_alternative = {
296 |                 text = {
297 |                     ".",
298 |                     "生成2张随机{C:attention}食物小丑"
299 |                 }
300 |             },
301 |             j_pape_ghost_cola_morsel_alternative = {
302 |                 text = {
303 |                     "出售此牌以生成两张{C:attention}#1#{}",
304 |                     "和两张随机{C:dark_edition}负片{}{C:spectral}幻灵牌{}"
305 |                 }
306 |             },
307 |             j_twewy_candleService_morsel_alternative = {
308 |                 text = {
309 |                     "每八次计分"
310 |                 }
311 |             },
312 |             j_dvrprv_dynamic_film = {
313 |                 name = "活力电影",
314 |                 text = {
315 |                     "每当一张{C:cine}兑换券",
316 |                     "积累进度时",
317 |                     "此牌获得{C:chips}+#2#{}筹码",
318 |                     "{C:inactive}(当前为+{C:chips}#1#{C:inactive}筹码)"
319 |                 }
320 |             }
321 |         },
322 |         Back = {
323 |             b_dvrprv_filmstrip = {
324 |                 name = "录影牌组",
325 |                 text = {
326 |                     "{C:cine}影视牌{}可以堆叠",
327 |                     "{C:attention}+#1#{}影视牌槽位"
328 |                 },
329 |                 unlock = {
330 |                     '',
331 |                     "在启用{C:attention}影视{}模组的情况下",
332 |                     "赢得一局游戏"
333 |                 }
334 |             },
335 |             b_dvrprv_stamp = {
336 |                 name = "标签牌组",
337 |                 text = {
338 |                     "跳过{C:attention}盲注{}时改为",
339 |                     "给予{C:attention,T:p_tag_jumbo_1}标签包{}"
340 |                 },
341 |                 unlock = {
342 |                     '没有跳过{C:attention}盲注{}情况下',
343 |                     '赢得一局游戏',
344 |                 }
345 |             }
346 |         },
347 |         Sleeve = {
348 |             sleeve_dvrprv_filmstrip = {
349 |                 name = "录影牌套",
350 |                 text = {
351 |                     "{C:cine}影视牌{}可以堆叠",
352 |                     "{C:attention}+#1#{}影视牌槽位"
353 |                 }
354 |             },
355 |             sleeve_dvrprv_filmstrip_alt = {
356 |                 name = "录影牌套",
357 |                 text = {
358 |                     "{C:cine}兑换券{}可能出现在商店",
359 |                     "并且有{C:green}#2#/#3#几率",
360 |                     "带有{C:dark_edition}负片"
361 |                 }
362 |             },
363 |             sleeve_dvrprv_stamp = {
364 |                 name = "标签牌套",
365 |                 text = {
366 |                     "跳过{C:attention}盲注{}时改为",
367 |                     "给予{C:attention,T:p_tag_jumbo_1}标签包{}"
368 |                 }
369 |             },
370 |             sleeve_dvrprv_stamp_alt = {
371 |                 name = "标签牌套",
372 |                 text = {
373 |                     "跳过{C:attention}盲注{}时还会",
374 |                     "额外给予{C:attention}随机标签{}"
375 |                 }
376 |             }
377 |         },
378 |         Tag = {
379 |             tag_dvrprv_cine = {
380 |                 name = "存折标签",
381 |                 text = {
382 |                     "获得一个免费的",
383 |                     "{C:cine}影视包"
384 |                 }
385 |             },
386 |             tag_dvrprv_jumbo_tag = {
387 |                 name = "记号标签",
388 |                 text = {
389 |                     "获得一个免费的",
390 |                     "{C:attention}巨型标签包"
391 |                 }
392 |             },
393 |             tag_dvrprv_mega_tag = {
394 |                 name = "邮递标签",
395 |                 text = {
396 |                     "获得一个免费的",
397 |                     "{C:attention}巨型标签包",
398 |                     "和一个{C:attention}随机标签{}"
399 |                 }
400 |             }
401 |         },
402 |         Spectral = {
403 |             c_dvrprv_reverie = {
404 |                 name = "空想",
405 |                 text = {
406 |                     "将所有的",
407 |                     "{C:cine,E:1}影视牌{}效果",
408 |                     "应用于本回合商店"
409 |                 }
410 |             }
411 |         },
412 |         Voucher = {
413 |             v_dvrprv_script = {
414 |                 name = "脚本",
415 |                 text = {
416 |                     "当激活{C:cine}影视牌{}时",
417 |                     "临时{C:attention}+#1#{}商店槽位",
418 |                     "",
419 |                     ""
420 |                 }
421 |             },
422 |             v_dvrprv_megaphone = {
423 |                 name = "扩音器",
424 |                 text = {
425 |                     "本赛局中",
426 |                     "{C:cine}兑换券{}的",
427 |                     "要求减半"
428 |                 },
429 |                 unlock = {
430 |                     "累计使用#1#张",
431 |                     "{C:cine}影视牌{}",
432 |                     "{C:inactive}(#2#)",
433 |                 }
434 |             }
435 |         },
436 |         Edition = {
437 |             e_negative_cine = {
438 |                 name = "负片",
439 |                 text = {
440 |                     "{C:dark_edition}+#1#{}影视牌槽位"
441 |                 }
442 |             }
443 |         },
444 |         Other = {
445 |             p_dvrprv_tag_normal = {
446 |                 name = "标签包",
447 |                 text = {
448 |                     "从最多{C:attention}#2#张{}标签中",
449 |                     "选择{C:attention}#1#{}张"
450 |                 }
451 |             },
452 |             p_dvrprv_tag_jumbo = {
453 |                 name = "巨型标签包",
454 |                 text = {
455 |                     "从最多{C:attention}#2#张{}标签中",
456 |                     "选择{C:attention}#1#{}张"
457 |                 }
458 |             },
459 |             p_dvrprv_tag_mega = {
460 |                 name = "超级标签包",
461 |                 text = {
462 |                     "从最多{C:attention}#2#张{}标签中",
463 |                     "选择{C:attention}#1#{}张"
464 |                 }
465 |             },
466 |             p_dvrprv_luxe_mega = {
467 |                 name = "超级优惠包",
468 |                 text = {
469 |                     "从最多{C:attention}#2#张{}优惠券中",
470 |                     "选择{C:attention}#1#{}张"
471 |                 }
472 |             },
473 |             p_dvrprv_crazy_lucky = {
474 |                 name = "疯狂包",
475 |                 text = {
476 |                     "",
477 |                     "从最多{C:attention}#2#张{}随机牌中",
478 |                     "选择{C:attention}#1#{}张",
479 |                 }
480 |             },
481 |             p_dvrprv_film_normal = {
482 |                 name = "影视包",
483 |                 text = {
484 |                     "从最多{C:attention}#2#张{}{C:cine}兑换券{}中",
485 |                     "选择{C:attention}#1#{}张",
486 |                     "添加到你的影视牌槽位"
487 |                 }
488 |             },
489 |             p_dvrprv_film_jumbo = {
490 |                 name = "巨型影视包",
491 |                 text = {
492 |                     "从最多{C:attention}#2#张{}{C:cine}兑换券{}中",
493 |                     "选择{C:attention}#1#{}张",
494 |                     "添加到你的影视牌槽位"
495 |                 }
496 |             },
497 |             p_dvrprv_film_mega = {
498 |                 name = "超级影视包",
499 |                 text = {
500 |                     "从最多{C:attention}#2#张{}{C:cine}影视牌{}中",
501 |                     "选择{C:attention}#1#{}张",
502 |                     "添加到你的影视牌槽位"
503 |                 }
504 |             },
505 |             undiscovered_cine = {
506 |                 name = "未发现",
507 |                 text = {
508 |                     "在非预设局",
509 |                     "中使用此牌",
510 |                     "以了解其效果",
511 |                     ""
512 |                 }
513 |             },
514 |             morseled = {
515 |                 name = "莫瑟尔",
516 |                 text = {
517 |                     "能力{C:attention}翻倍"
518 |                 }
519 |             },
520 |         }
521 |     },
522 |     misc = {
523 |         dictionary = {
524 |             k_dvrprv_title = "Reverie",
525 |             k_dvrprv_description = "准备好你的电影票,因为这里有一场电影盛宴等着你!",
526 |             k_cine = "影视牌",
527 |             k_dvrprv_tag = "标签",
528 |             k_dvrprv_tag_pack = "标签包",
529 |             k_dvrprv_crazy_pack = "疯狂包",
530 |             k_dvrprv_film_pack = "影视包",
531 |             k_dvrprv_redeemed_cine = "开始玩吧",
532 |             b_cine_cards = "影视牌",
533 |             b_dvrprv_jokerdisplay_compat = "小丑显示兼容",
534 |             b_dvrprv_jokerdisplay_compat_info = {
535 |                 "启用兑换券相关",
536 |                 "小丑显示兼容"
537 |             },
538 |             b_dvrprv_tag_packs_shop = "商店中的标签包",
539 |             b_dvrprv_tag_packs_shop_info = {
540 |                 "允许标签包在商店中出现"
541 |             },
542 |             b_dvrprv_crazy_packs_shop = "商店中的疯狂包",
543 |             b_dvrprv_crazy_packs_shop_info = {
544 |                 "允许疯狂包在商店中出现"
545 |             },
546 |             b_dvrprv_custom_morsel_compat = "莫瑟尔对模组作用",
547 |             b_dvrprv_custom_morsel_compat_info =
548 |             {
549 |                 "启用莫瑟尔兼容其他模组小丑",
550 |                 "(e.g. TWEWJ's Candle Service: Every forth scoring >>>",
551 |                 "Every eighth scoring)"
552 |             },
553 |             b_dvrprv_cartomancer_compat = "Cartomancer兼容",
554 |             b_dvrprv_cartomancer_compat_info = {
555 |                 "启用Cartomancer兼容",
556 |                 "以在槽位中缩放移动影视牌"
557 |             }
558 |         },
559 |         labels = {
560 |             morseled = "莫瑟尔"
561 |         }
562 |     }
563 | }


--------------------------------------------------------------------------------
/localization/en-us.lua:
--------------------------------------------------------------------------------
  1 | return {
  2 |     descriptions = {
  3 |         Cine = {
  4 |             c_dvrprv_ive_no_shape_quest = {
  5 |                 name = "Exchange Coupon",
  6 |                 text = {
  7 |                     "Converts to {C:cine}I Sing, I've No Shape",
  8 |                     "after scoring more than {C:attention}X#1#{} of",
  9 |                     "required Chips in {C:attention}#2# Blinds",
 10 |                     "{C:inactive}(Currently {C:attention}#3#{C:inactive}/#2#)"
 11 |                 }
 12 |             },
 13 |             c_dvrprv_ive_no_shape = {
 14 |                 name = "I Sing, I've No Shape",
 15 |                 text = {
 16 |                     "During this shop,",
 17 |                     "only owned {C:attention}Jokers{} appear",
 18 |                     "{C:red}+$#1#{} reroll cost"
 19 |                 }
 20 |             },
 21 |             c_dvrprv_unseen_quest = {
 22 |                 name = "Exchange Coupon",
 23 |                 text = {
 24 |                     "Converts to {C:cine}The Unseen{}",
 25 |                     "after having {C:attention}#1#{} empty",
 26 |                     "{C:attention}Joker{} slot for {C:attention}#2#{} rounds",
 27 |                     "{C:inactive}(Currently {C:attention}#3#{C:inactive}/#2#)"
 28 |                 }
 29 |             },
 30 |             c_dvrprv_unseen = {
 31 |                 name = "The Unseen",
 32 |                 text = {
 33 |                     "During this shop,",
 34 |                     "all {C:attention}Jokers{} and {C:attention}consumables",
 35 |                     "become {C:dark_edition}Negative",
 36 |                     "{C:red}X#1#{} reroll cost",
 37 |                     "{s:0.8}Rerolls cards"
 38 |                 }
 39 |             },
 40 |             c_dvrprv_gem_heist_quest = {
 41 |                 name = "Exchange Coupon",
 42 |                 text = {
 43 |                     "Converts to {C:cine}Gem Heist{}",
 44 |                     "after selling",
 45 |                     "{C:attention}#1# Editioned Jokers{}",
 46 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
 47 |                 }
 48 |             },
 49 |             c_dvrprv_gem_heist = {
 50 |                 name = "Gem Heist",
 51 |                 text = {
 52 |                     "During this shop,",
 53 |                     "all cards become",
 54 |                     "{C:dark_edition}Polychrome{} and {C:attention}#1#%{} off",
 55 |                     "{s:0.8}Rerolls cards and {s:0.8,C:attention}Booster Packs"
 56 |                 }
 57 |             },
 58 |             c_dvrprv_crazy_lucky_quest = {
 59 |                 name = "Exchange Coupon",
 60 |                 text = {
 61 |                     "Converts to {C:cine}Crazy Lucky{}",
 62 |                     "after opening {C:attention}#1# Booster Packs",
 63 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
 64 |                 }
 65 |             },
 66 |             c_dvrprv_crazy_lucky = {
 67 |                 name = "Crazy Lucky",
 68 |                 text = {
 69 |                     "During this shop,",
 70 |                     "everything becomes {C:attention}Pack",
 71 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
 72 |                 }
 73 |             },
 74 |             c_dvrprv_tag_or_die_quest = {
 75 |                 name = "Exchange Coupon",
 76 |                 text = {
 77 |                     "Converts to {C:cine}Tag or Die{}",
 78 |                     "after skipping {C:attention}#1# Blinds",
 79 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
 80 |                 }
 81 |             },
 82 |             c_dvrprv_tag_or_die = {
 83 |                 name = "Tag or Die",
 84 |                 text = {
 85 |                     "During this shop,",
 86 |                     "only {C:attention}Tags{} that",
 87 |                     "cost {C:money}$#1#{} appear",
 88 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
 89 |                 }
 90 |             },
 91 |             c_dvrprv_let_it_moon_quest = {
 92 |                 name = "Exchange Coupon",
 93 |                 text = {
 94 |                     "Converts to {C:cine}Let It Moon{}",
 95 |                     "after using {C:attention}#1# {C:planet}Planet",
 96 |                     "or {C:tarot}Tarot{} cards",
 97 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
 98 |                 }
 99 |             },
100 |             c_dvrprv_let_it_moon = {
101 |                 name = "Let It Moon",
102 |                 text = {
103 |                     "During this shop,",
104 |                     "only {C:planet}Planet{} and",
105 |                     "{C:tarot}Tarot{} cards appear",
106 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
107 |                 }
108 |             },
109 |             c_dvrprv_poker_face_quest = {
110 |                 name = "Exchange Coupon",
111 |                 text = {
112 |                     "Converts to {C:cine}Poker Face{}",
113 |                     "after enhancing {C:attention}#1#",
114 |                     "{C:attention}Playing cards",
115 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
116 |                 }
117 |             },
118 |             c_dvrprv_poker_face = {
119 |                 name = "Poker Face",
120 |                 text = {
121 |                     "During this shop,",
122 |                     "only {C:attention}Playing cards",
123 |                     "from your deck appear",
124 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
125 |                 }
126 |             },
127 |             c_dvrprv_eerie_inn_quest = {
128 |                 name = "Exchange Coupon",
129 |                 text = {
130 |                     "Converts to {C:cine}Eerie Inn{}",
131 |                     "after destroying {C:attention}#1#{} cards",
132 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
133 |                 }
134 |             },
135 |             c_dvrprv_eerie_inn = {
136 |                 name = "Eerie Inn",
137 |                 text = {
138 |                     "During this shop,",
139 |                     "only {C:spectral}Spectral Packs",
140 |                     "appear",
141 |                     "{C:red}X#1#{} reroll cost",
142 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
143 |                 }
144 |             },
145 |             c_dvrprv_adrifting_quest = {
146 |                 name = "Exchange Coupon",
147 |                 text = {
148 |                     "Converts to {C:cine}Adrifting{}",
149 |                     "after playing {C:attention}#1# debuffed{}",
150 |                     "or {C:attention}faced down{} cards",
151 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
152 |                 }
153 |             },
154 |             c_dvrprv_adrifting = {
155 |                 name = "Adrifting",
156 |                 text = {
157 |                     "During this shop,",
158 |                     "everything is {C:attention}faced",
159 |                     "{C:attention}down{} and costs {C:money}$#1#",
160 |                     "{s:0.8}Rerolls cards and {s:0.8,C:attention}Booster Packs"
161 |                 }
162 |             },
163 |             c_dvrprv_morsel_quest = {
164 |                 name = "Exchange Coupon",
165 |                 text = {
166 |                     "Converts to {C:cine}Morsel{}",
167 |                     "after getting {C:attention}#1#",
168 |                     "{C:attention}Food Jokers{}",
169 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
170 |                 }
171 |             },
172 |             c_dvrprv_morsel = {
173 |                 name = "Morsel",
174 |                 text = {
175 |                     "During this shop,",
176 |                     "only {C:attention}Food Jokers",
177 |                     "with {C:attention}doubled{} ability",
178 |                     "values appear",
179 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
180 |                 }
181 |             },
182 |             c_dvrprv_alchemist_quest = {
183 |                 name = "Exchange Coupon",
184 |                 text = {
185 |                     "Converts to {C:cine}Fool Metal",
186 |                     "{C:cine}Alchemist{} after using",
187 |                     "{C:attention}#1# {C:alchemical}Alchemical{} cards",
188 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
189 |                 }
190 |             },
191 |             c_dvrprv_alchemist = {
192 |                 name = "Fool Metal Alchemist",
193 |                 text = {
194 |                     "During this shop,",
195 |                     "{C:attention}+#1#{} consumable slots and",
196 |                     "only {C:alchemical}Alchemical{} cards appear",
197 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
198 |                 }
199 |             },
200 |             c_dvrprv_every_hue_quest = {
201 |                 name = "Exchange Coupon",
202 |                 text = {
203 |                     "Converts to {C:cine}Every Hue",
204 |                     "after using {C:attention}#1# {C:colourcard}Colour{} cards",
205 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
206 |                 }
207 |             },
208 |             c_dvrprv_every_hue = {
209 |                 name = "Every Hue",
210 |                 text = {
211 |                     "During this shop,",
212 |                     "only {C:colourcard}Colour{} cards that",
213 |                     "already have {C:attention}#1# rounds{}",
214 |                     "appear",
215 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
216 |                 }
217 |             },
218 |             c_dvrprv_radioactive_quest = {
219 |                 name = "Exchange Coupon",
220 |                 text = {
221 |                     "Converts to {C:cine}Radioactive",
222 |                     "after getting {C:attention}#1#",
223 |                     "{C:attention}Fusion Joker",
224 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
225 |                 }
226 |             },
227 |             c_dvrprv_radioactive = {
228 |                 name = "Radioactive",
229 |                 text = {
230 |                     "During this shop,",
231 |                     "only {C:attention}Jokers{} that",
232 |                     "can be used in {C:attention}Fusions",
233 |                     "appear",
234 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
235 |                 }
236 |             },
237 |             c_dvrprv_jovial_m_quest = {
238 |                 name = "Exchange Coupon",
239 |                 text = {
240 |                     "Converts to {C:cine}Jovial M",
241 |                     "after selling {C:attention}#1#",
242 |                     "{C:attention}#3#",
243 |                     "{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)"
244 |                 }
245 |             },
246 |             c_dvrprv_jovial_m = {
247 |                 name = "Jovial M",
248 |                 text = {
249 |                     "During this shop,",
250 |                     "only {C:cry_epic}Epic{} or {C:cry_exotic}Exotic",
251 |                     "{C:attention}Jokers{} appear",
252 |                     "{s:0.8}Rerolls {s:0.8,C:attention}Booster Packs"
253 |                 }
254 |             }
255 |         },
256 |         Joker = {
257 |             j_diet_cola_morsel_alternative = {
258 |                 text = {
259 |                     ".", -- Blank strings are ignored, so putting random character to preserve index info
260 |                     "create two free",
261 |                     "{C:attention}#1#s",
262 |                 }
263 |             },
264 |             j_olab_fine_wine_morsel_alternative = {
265 |                 text = {
266 |                     "{C:red}+#1#{} discards, gains {C:red}+2{} discards",
267 |                 }
268 |             },
269 |             j_olab_mystery_soda_morsel_alternative = {
270 |                 text = {
271 |                     ".",
272 |                     "four free {C:attention}tags"
273 |                 }
274 |             },
275 |             j_mf_tonersoup_morsel_alternative = {
276 |                 text = {
277 |                     "Create two {C:tarot}Tarot{} cards"
278 |                 }
279 |             },
280 |             j_bunc_fondue_morsel_alternative = {
281 |                 text = {
282 |                     ".",
283 |                     "{C:attention}first and second hand{} of round are"
284 |                 }
285 |             },
286 |             j_evo_full_sugar_cola_morsel_alternative = {
287 |                 text = {
288 |                     ".",
289 |                     "create {C:attention}4{} free"
290 |                 }
291 |             },
292 |             j_kcva_swiss_morsel_alternative = {
293 |                 text = {
294 |                     "{C:mult}+20{} Mult for each"
295 |                 }
296 |             },
297 |             j_jank_cut_the_cheese_morsel_alternative = {
298 |                 text = {
299 |                     ".",
300 |                     "create two random {C:attention}Food Jokers"
301 |                 }
302 |             },
303 |             j_pape_ghost_cola_morsel_alternative = {
304 |                 text = {
305 |                     "Sell this card to create two {C:attention}#1#{}",
306 |                     "and two random {C:dark_edition}Negative{} {C:spectral}Spectral{} cards"
307 |                 }
308 |             },
309 |             j_twewy_candleService_morsel_alternative = {
310 |                 text = {
311 |                     "Every eighth scoring"
312 |                 }
313 |             },
314 |             j_dvrprv_dynamic_film = {
315 |                 name = "Dynamic Film",
316 |                 text = {
317 |                     "This Joker gains",
318 |                     "{C:chips}+#2#{} Chips every time an",
319 |                     "{C:cine}Exchange Coupon{} progresses",
320 |                     "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chips)"
321 |                 }
322 |             }
323 |         },
324 |         Back = {
325 |             b_dvrprv_filmstrip = {
326 |                 name = "Filmstrip Deck",
327 |                 text = {
328 |                     "{C:cine}Cine{} cards can stack",
329 |                     "{C:attention}+#1#{} Cine slot"
330 |                 },
331 |                 unlock = {
332 |                     'Win a run with the',
333 |                     '{C:attention}Reverie{} mod',
334 |                     'enabled'
335 |                 }
336 |             },
337 |             b_dvrprv_stamp = {
338 |                 name = "Stamp Deck",
339 |                 text = {
340 |                     "Skipping a {C:attention}Blind{} gives",
341 |                     "{C:attention,T:p_dvrprv_tag_jumbo_1}#1#{} instead"
342 |                 },
343 |                 unlock = {
344 |                     'Win a run without',
345 |                     '{C:attention}Skipping a Blind{}'
346 |                 }
347 |             }
348 |         },
349 |         Sleeve = {
350 |             sleeve_dvrprv_filmstrip = {
351 |                 name = "Filmstrip Sleeve",
352 |                 text = {
353 |                     "{C:cine}Cine{} cards can stack",
354 |                     "{C:attention}+#1#{} Cine slot"
355 |                 }
356 |             },
357 |             sleeve_dvrprv_filmstrip_alt = {
358 |                 name = "Filmstrip Sleeve",
359 |                 text = {
360 |                     "{C:cine}Exchange Coupons{} may appear",
361 |                     "in the shop and has {C:green}#2# in #3#",
362 |                     "chance of being {C:dark_edition}Negative"
363 |                 }
364 |             },
365 |             sleeve_dvrprv_stamp = {
366 |                 name = "Stamp Sleeve",
367 |                 text = {
368 |                     "Skipping a {C:attention}Blind{} gives",
369 |                     "{C:attention,T:p_dvrprv_tag_jumbo_1}#1#{} instead"
370 |                 }
371 |             },
372 |             sleeve_dvrprv_stamp_alt = {
373 |                 name = "Stamp Sleeve",
374 |                 text = {
375 |                     "Skipping a {C:attention}Blind{} also",
376 |                     "gives a {C:attention}random Tag{}"
377 |                 }
378 |             }
379 |         },
380 |         Tag = {
381 |             tag_dvrprv_cine = {
382 |                 name = "Stub Tag",
383 |                 text = {
384 |                     "Gives a free",
385 |                     "{C:cine}Film Pack"
386 |                 }
387 |             },
388 |             tag_dvrprv_jumbo_tag = {
389 |                 name = "Stamp Tag",
390 |                 text = {
391 |                     "Gives a free",
392 |                     "{C:attention}Jumbo Tag Pack"
393 |                 }
394 |             },
395 |             tag_dvrprv_mega_tag = {
396 |                 name = "Mega Stamp Tag",
397 |                 text = {
398 |                     "Gives a free",
399 |                     "{C:attention}Jumbo Tag Pack",
400 |                     "and a {C:attention}random Tag"
401 |                 }
402 |             }
403 |         },
404 |         Spectral = {
405 |             c_dvrprv_reverie = {
406 |                 name = "Reverie",
407 |                 text = {
408 |                     "Applies {C:legendary,E:1}every{}",
409 |                     "{C:legendary,E:1}Cine card{}",
410 |                     "to this shop"
411 |                 }
412 |             }
413 |         },
414 |         Voucher = {
415 |             v_dvrprv_script = {
416 |                 name = "Script",
417 |                 text = {
418 |                     "{C:attention}+#1#{} card slot",
419 |                     "available in shop",
420 |                     "while a {C:cine}Cine{} card",
421 |                     "is active"
422 |                 }
423 |             },
424 |             v_dvrprv_megaphone = {
425 |                 name = "Megaphone",
426 |                 text = {
427 |                     "Requirements of",
428 |                     "{C:cine}Exchange Coupons{} are",
429 |                     "halved"
430 |                 },
431 |                 unlock = {
432 |                     "Use a total of #1#",
433 |                     "{C:cine}Cine{} cards",
434 |                     "{C:inactive}(#2#)",
435 |                 }
436 |             }
437 |         },
438 |         Edition = {
439 |             e_negative_cine = {
440 |                 name = "Negative",
441 |                 text = {
442 |                     "{C:dark_edition}+#1#{} Cine slot"
443 |                 }
444 |             }
445 |         },
446 |         Other = {
447 |             p_dvrprv_tag_normal = {
448 |                 name = "Tag Pack",
449 |                 text = {
450 |                     "Choose {C:attention}#1#{} of up to",
451 |                     "{C:attention}#2# Tags"
452 |                 }
453 |             },
454 |             p_dvrprv_tag_jumbo = {
455 |                 name = "Jumbo Tag Pack",
456 |                 text = {
457 |                     "Choose {C:attention}#1#{} of up to",
458 |                     "{C:attention}#2# Tags"
459 |                 }
460 |             },
461 |             p_dvrprv_tag_mega = {
462 |                 name = "Mega Tag Pack",
463 |                 text = {
464 |                     "Choose {C:attention}#1#{} of up to",
465 |                     "{C:attention}#2# Tags"
466 |                 }
467 |             },
468 |             p_dvrprv_luxe_mega = {
469 |                 name = "Mega Luxe Pack",
470 |                 text = {
471 |                     "Choose {C:attention}#1#{} of up to",
472 |                     "{C:attention}#2# Vouchers"
473 |                 }
474 |             },
475 |             p_dvrprv_crazy_lucky = {
476 |                 name = "Pack",
477 |                 text = {
478 |                     "Choose {C:attention}#1#{} of up to",
479 |                     "{C:attention}#2# {C:attention,E:1}anything{} to add",
480 |                     "to your possession"
481 |                 }
482 |             },
483 |             p_dvrprv_film_normal = {
484 |                 name = "Film Pack",
485 |                 text = {
486 |                     "Choose {C:attention}#1#{} of up to",
487 |                     "{C:attention}#2#{} {C:cine}Exchange Coupon{} cards",
488 |                     "to add to your possession"
489 |                 }
490 |             },
491 |             p_dvrprv_film_jumbo = {
492 |                 name = "Jumbo Film Pack",
493 |                 text = {
494 |                     "Choose {C:attention}#1#{} of up to",
495 |                     "{C:attention}#2# {C:cine}Exchange Coupon{} cards",
496 |                     "to add to your possession"
497 |                 }
498 |             },
499 |             p_dvrprv_film_mega = {
500 |                 name = "Mega Film Pack",
501 |                 text = {
502 |                     "Choose {C:attention}#1#{} of up to",
503 |                     "{C:attention}#2# {E:1,C:cine}Cine{} cards to add",
504 |                     "to your possession"
505 |                 }
506 |             },
507 |             undiscovered_cine = {
508 |                 name = "Not Discovered",
509 |                 text = {
510 |                     "Purchase or use",
511 |                     "this card in an",
512 |                     "unseeded run to",
513 |                     "learn what it does"
514 |                 }
515 |             },
516 |             morseled = {
517 |                 name = "Morsel",
518 |                 text = {
519 |                     "Ability is {C:attention}doubled"
520 |                 }
521 |             },
522 |         }
523 |     },
524 |     misc = {
525 |         dictionary = {
526 |             k_dvrprv_title = "Reverie",
527 |             k_dvrprv_description = "Prepare Your Tickets",
528 |             k_cine = "Cine",
529 |             k_dvrprv_tag = "Tag",
530 |             k_dvrprv_tag_pack = "Tag Pack",
531 |             k_dvrprv_crazy_pack = "Pack",
532 |             k_dvrprv_film_pack = "Film Pack",
533 |             k_dvrprv_redeemed_cine = "Now Playing",
534 |             b_cine_cards = "Cine Cards",
535 |             b_dvrprv_jokerdisplay_compat = "JokerDisplay compatibility",
536 |             b_dvrprv_jokerdisplay_compat_info = {
537 |                 "Enable JokerDisplay compatibility for",
538 |                 "Exchange Coupons"
539 |             },
540 |             b_dvrprv_tag_packs_shop = "Tag Packs in shop",
541 |             b_dvrprv_tag_packs_shop_info = {
542 |                 "Allow Tag Packs to normally appear",
543 |                 "in the shop"
544 |             },
545 |             b_dvrprv_crazy_packs_shop = "Crazy Packs in shop",
546 |             b_dvrprv_crazy_packs_shop_info = {
547 |                 "Allow Crazy Packs to normally appear",
548 |                 "in the shop"
549 |             },
550 |             b_dvrprv_custom_morsel_compat = "Morsel for modded Jokers",
551 |             b_dvrprv_custom_morsel_compat_info =
552 |             {
553 |                 "Enable custom Morsel compatibilities for Modded Jokers",
554 |                 "(e.g. TWEWJ's Candle Service: Every forth scoring >>>",
555 |                 "Every eighth scoring)"
556 |             },
557 |             b_dvrprv_cartomancer_compat = "Cartomancer compatibility",
558 |             b_dvrprv_cartomancer_compat_info = {
559 |                 "Enable Cartomancer compatibility for",
560 |                 "zooming Cine cards in your possesion"
561 |             }
562 |         },
563 |         labels = {
564 |             morseled = "Morsel"
565 |         }
566 |     }
567 | }


--------------------------------------------------------------------------------
/data/cines.lua:
--------------------------------------------------------------------------------
  1 | SMODS.UndiscoveredSprite {
  2 |     key = "Cine",
  3 |     atlas = "Cine",
  4 |     pos = {
  5 |         x = 0,
  6 |         y = 1
  7 |     }
  8 | }
  9 | 
 10 | local function your_collection_cine_page(args)
 11 |     if not args or not args.cycle_config then
 12 |         return
 13 |     end
 14 | 
 15 |     for j = 1, #G.your_collection do
 16 |         for i = #G.your_collection[j].cards, 1, -1 do
 17 |             local c = G.your_collection[j]:remove_card(G.your_collection[j].cards[i])
 18 |             c:remove()
 19 |             c = nil
 20 |         end
 21 |     end
 22 | 
 23 |     local cines = {}
 24 |     for _, v in pairs(G.P_CENTER_POOLS.Cine) do
 25 |         table.insert(cines, v)
 26 |     end
 27 |     for _, v in pairs(G.P_CENTER_POOLS.Cine_Quest) do
 28 |         table.insert(cines, v)
 29 |     end
 30 | 
 31 |     table.sort(cines, function(a, b) return a.order < b.order end)
 32 | 
 33 |     for j = 1, #G.your_collection do
 34 |         for i = 1, (1 + j) * 2 do
 35 |             local center = cines[i + (j - 1) * 4 + (10 * (args.cycle_config.current_option - 1))]
 36 |             if not center then
 37 |                 break
 38 |             end
 39 | 
 40 |             local card = Card(G.your_collection[j].T.x + G.your_collection[j].T.w / 2, G.your_collection[j].T.y, G
 41 |                 .CARD_W, G.CARD_H, G.P_CARDS.empty, center)
 42 |             card:start_materialize(nil, i > 1 or j > 1)
 43 |             G.your_collection[j]:emplace(card)
 44 |         end
 45 |     end
 46 | 
 47 |     INIT_COLLECTION_CARD_ALERTS()
 48 | end
 49 | 
 50 | local function create_UIBox_your_collection_cines(self)
 51 |     local deck_tables = {}
 52 | 
 53 |     G.your_collection = {}
 54 |     for j = 1, 2 do
 55 |         G.your_collection[j] = CardArea(G.ROOM.T.x + 0.2 * G.ROOM.T.w / 2, G.ROOM.T.h,
 56 |             (4.25 + (j == 2 and 2 or 0)) * G.CARD_W, 1 * G.CARD_H, {
 57 |                 card_limit = (1 + j) * 2,
 58 |                 type = "voucher",
 59 |                 highlight_limit = 0,
 60 |                 collection = true
 61 |             })
 62 |         table.insert(deck_tables, {
 63 |             n = G.UIT.R,
 64 |             config = {
 65 |                 align = "cm",
 66 |                 padding = 0,
 67 |                 no_fill = true
 68 |             },
 69 |             nodes = {
 70 |                 {
 71 |                     n = G.UIT.O,
 72 |                     config = {
 73 |                         object = G.your_collection[j]
 74 |                     }
 75 |                 }
 76 |             }
 77 |         })
 78 |     end
 79 | 
 80 |     local cines = {}
 81 |     for _, v in pairs(G.P_CENTER_POOLS.Cine) do
 82 |         table.insert(cines, v)
 83 |     end
 84 |     for _, v in pairs(G.P_CENTER_POOLS.Cine_Quest) do
 85 |         table.insert(cines, v)
 86 |     end
 87 | 
 88 |     table.sort(cines, function(a, b) return a.order < b.order end)
 89 | 
 90 |     local cine_options = {}
 91 |     for i = 1, math.ceil(#cines / (5 * #G.your_collection)) do
 92 |         table.insert(cine_options,
 93 |             localize("k_page") .. " " .. tostring(i) .. "/" .. tostring(math.ceil(#cines / (5 * #G.your_collection))))
 94 |     end
 95 | 
 96 |     for j = 1, #G.your_collection do
 97 |         for i = 1, (1 + j) * 2 do
 98 |             local center = cines[i + (j - 1) * 4]
 99 |             local card = Card(G.your_collection[j].T.x + G.your_collection[j].T.w / 2, G.your_collection[j].T.y, G
100 |                 .CARD_W, G.CARD_H, nil, center)
101 |             card.ability.order = i + (j - 1) * 4
102 | 
103 |             card:start_materialize(nil, i > 1 or j > 1)
104 |             G.your_collection[j]:emplace(card)
105 |         end
106 |     end
107 | 
108 |     INIT_COLLECTION_CARD_ALERTS()
109 | 
110 |     local option_nodes = {
111 |         create_option_cycle({
112 |             options = cine_options,
113 |             w = 4.5,
114 |             cycle_shoulders = true,
115 |             opt_callback = "your_collection_cine_page",
116 |             focus_args = {
117 |                 snap_to = true,
118 |                 nav = "wide"
119 |             },
120 |             current_option = 1,
121 |             colour = G.C.RED,
122 |             no_pips = true
123 |         })
124 |     }
125 |     local type_buf = {}
126 | 
127 |     if G.ACTIVE_MOD_UI then
128 |         for _, v in ipairs(SMODS.ConsumableType.obj_buffer) do
129 |             if modsCollectionTally(G.P_CENTER_POOLS[v]).of > 0 then type_buf[#type_buf + 1] = v end
130 |         end
131 |     else
132 |         type_buf = SMODS.ConsumableType.obj_buffer
133 |     end
134 | 
135 |     local t = create_UIBox_generic_options({
136 |         back_func = #type_buf > 3 and 'your_collection_consumables' or
137 |             G.ACTIVE_MOD_UI and "openModUI_" .. G.ACTIVE_MOD_UI.id or 'your_collection',
138 |         contents = {
139 |             { n = G.UIT.R, config = { align = "cm", minw = 2.5, padding = 0.1, r = 0.1, colour = G.C.BLACK, emboss = 0.05 }, nodes = deck_tables },
140 |             { n = G.UIT.R, config = { align = "cm", padding = 0 },                                                           nodes = option_nodes },
141 |         }
142 |     })
143 | 
144 |     return t
145 | end
146 | 
147 | SMODS.ConsumableType {
148 |     key = "Cine",
149 |     collection_rows = { 4, 6 },
150 |     primary_colour = G.C.SET.Joker,
151 |     secondary_colour = Reverie.badge_colour,
152 |     create_UIBox_your_collection = create_UIBox_your_collection_cines,
153 |     inject = function(self)
154 |         SMODS.ConsumableType.inject(self)
155 | 
156 |         G.P_CENTER_POOLS.Cine = {}
157 |         G.P_CENTER_POOLS.Cine_Quest = {}
158 |         G.C.SECONDARY_SET.Tag = HEX("a6b8ce")
159 |         G.FUNCS.your_collection_cine_page = your_collection_cine_page
160 |     end,
161 |     inject_card = function(self, center)
162 |         SMODS.ConsumableType.inject_card(self, center)
163 | 
164 |         if center.reward then
165 |             SMODS.remove_pool(G.P_CENTER_POOLS.Cine, center.key)
166 |             SMODS.insert_pool(G.P_CENTER_POOLS.Cine_Quest, center)
167 |         end
168 |     end,
169 |     delete_card = function(self, center)
170 |         SMODS.ConsumableType.delete_card(self, center)
171 |         SMODS.remove_pool(G.P_CENTER_POOLS[center.reward and "Cine_Quest" or "Cine"], center.key)
172 |     end,
173 |     shop_rate = 0
174 | }
175 | 
176 | SMODS.ObjectTypes["Cine"].default = "c_dvrprv_gem_heist"
177 | SMODS.ObjectTypes["Cine_Quest"] = { default = "c_dvrprv_gem_heist_quest" }
178 | 
179 | local function can_use(self, card)
180 |     if card.config.center.reward then
181 |         return false
182 |     else
183 |         return G.STATE == G.STATES.SHOP and G.shop
184 |     end
185 | end
186 | 
187 | local function loc_vars_cine(self, info_queue, card)
188 |     local vars = nil
189 | 
190 |     if self.name == "Tag or Die" then
191 |         vars = { card.ability.extra.cost }
192 |     elseif self.name == "The Unseen" or self.name == "Eerie Inn" then
193 |         vars = { card.ability.extra.mult }
194 |     elseif self.name == "I Sing, I've No Shape" then
195 |         vars = { card.ability.extra.add }
196 |     elseif self.name == "Crazy Lucky" then
197 |         local fake_card = G.P_CENTERS.p_dvrprv_crazy_lucky_1:create_fake_card()
198 |         local info = G.P_CENTERS.p_dvrprv_crazy_lucky_1:loc_vars(info_queue, fake_card)
199 | 
200 |         info_queue[#info_queue + 1] = {
201 |             key = info.key,
202 |             set = "Other",
203 |             vars = info.vars
204 |         }
205 |     elseif self.name == "Fool Metal Alchemist" then
206 |         vars = { card.ability.extra.slot }
207 |     elseif self.name == "Every Hue" then
208 |         vars = { card.ability.extra.rounds }
209 |     elseif self.name == "Gem Heist" then
210 |         vars = { card.ability.extra.discount }
211 |     elseif self.name == "Adrifting" then
212 |         vars = { card.ability.extra.set_price }
213 |     else
214 |         vars = { card.ability.extra }
215 |     end
216 | 
217 |     return { vars = vars }
218 | end
219 | 
220 | local function loc_vars_quest(self, info_queue, card)
221 |     local vars = nil
222 | 
223 |     local reward_card = self.reward
224 | 
225 |     info_queue[#info_queue + 1] = G.P_CENTERS[reward_card]
226 | 
227 |     if reward_card == "c_dvrprv_unseen" then
228 |         vars = { card.ability.extra.slots, card.ability.extra.goal, card.ability.progress }
229 |     elseif reward_card == "c_dvrprv_ive_no_shape" then
230 |         vars = { card.ability.extra.chips, card.ability.extra.goal, card.ability.progress }
231 |     elseif reward_card == "c_dvrprv_jovial_m" then
232 |         info_queue[#info_queue + 1] = {
233 |             key = "j_jolly",
234 |             set = "Joker",
235 |             specific_vars = { G.P_CENTERS.j_jolly.config.t_mult, G.P_CENTERS.j_jolly.config.type }
236 |         }
237 |         vars = { card.ability.extra.goal, card.ability.progress, localize {
238 |             type = "name_text",
239 |             set = "Joker",
240 |             key = "j_jolly"
241 |         } }
242 |     else
243 |         vars = { card.ability.extra.goal, card.ability.progress }
244 |     end
245 | 
246 |     return { vars = vars }
247 | end
248 | 
249 | local function inject(self)
250 |     local order_cache = self.order
251 |     local reward_cache = self.reward
252 | 
253 |     SMODS.Consumable.inject(self)
254 |     self.order = order_cache
255 |     self.reward = reward_cache
256 | end
257 | 
258 | Reverie.cines = {
259 |     {
260 |         key = "ive_no_shape",
261 |         order = 20,
262 |         name = "I Sing, I've No Shape",
263 |         config = {
264 |             extra = {
265 |                 add = 20
266 |             }
267 |         },
268 |         cost = 4,
269 |         pos = {
270 |             x = 6,
271 |             y = 0
272 |         }
273 |     },
274 |     {
275 |         key = "ive_no_shape_quest",
276 |         order = 19,
277 |         name = "I Sing, I've No Shape Exchange Coupon",
278 |         reward = "c_dvrprv_ive_no_shape",
279 |         config = {
280 |             extra = {
281 |                 chips = 2,
282 |                 goal = 3
283 |             }
284 |         },
285 |         cost = 4,
286 |         pos = {
287 |             x = 8,
288 |             y = 1
289 |         }
290 |     },
291 |     {
292 |         key = "unseen",
293 |         order = 18,
294 |         name = "The Unseen",
295 |         config = {
296 |             extra = {
297 |                 mult = 5
298 |             }
299 |         },
300 |         cost = 4,
301 |         pos = {
302 |             x = 2,
303 |             y = 0
304 |         }
305 |     },
306 |     {
307 |         key = "unseen_quest",
308 |         order = 17,
309 |         name = "The Unseen Exchange Coupon",
310 |         reward = "c_dvrprv_unseen",
311 |         config = {
312 |             extra = {
313 |                 slots = 1,
314 |                 goal = 5
315 |             }
316 |         },
317 |         cost = 4,
318 |         pos = {
319 |             x = 4,
320 |             y = 1
321 |         }
322 |     },
323 |     {
324 |         key = "gem_heist",
325 |         order = 2,
326 |         name = "Gem Heist",
327 |         config = {
328 |             extra = {
329 |                 discount = 25,
330 |                 kind = {
331 |                     "p_buffoon_",
332 |                     "p_standard_"
333 |                 }
334 |             },
335 |         },
336 |         cost = 4,
337 |         pos = {
338 |             x = 1,
339 |             y = 0
340 |         }
341 |     },
342 |     {
343 |         key = "gem_heist_quest",
344 |         order = 1,
345 |         name = "Gem Heist Exchange Coupon",
346 |         reward = "c_dvrprv_gem_heist",
347 |         config = {
348 |             extra = {
349 |                 goal = 2
350 |             }
351 |         },
352 |         cost = 4,
353 |         pos = {
354 |             x = 3,
355 |             y = 1
356 |         }
357 |     },
358 |     {
359 |         key = "crazy_lucky",
360 |         order = 12,
361 |         name = "Crazy Lucky",
362 |         config = {
363 |             extra = {
364 |                 mult = 1,
365 |                 kind = {
366 |                     "p_dvrprv_crazy_lucky"
367 |                 }
368 |             }
369 |         },
370 |         cost = 4,
371 |         pos = {
372 |             x = 7,
373 |             y = 0
374 |         }
375 |     },
376 |     {
377 |         key = "crazy_lucky_quest",
378 |         order = 11,
379 |         name = "Crazy Lucky Exchange Coupon",
380 |         reward = "c_dvrprv_crazy_lucky",
381 |         config = {
382 |             extra = {
383 |                 goal = 6
384 |             }
385 |         },
386 |         cost = 4,
387 |         pos = {
388 |             x = 9,
389 |             y = 1
390 |         }
391 |     },
392 |     {
393 |         key = "tag_or_die",
394 |         order = 4,
395 |         name = "Tag or Die",
396 |         config = {
397 |             extra = {
398 |                 cost = 8,
399 |                 kind = {
400 |                     "p_dvrprv_tag_"
401 |                 }
402 |             }
403 |         },
404 |         cost = 4,
405 |         pos = {
406 |             x = 3,
407 |             y = 0
408 |         }
409 |     },
410 |     {
411 |         key = "tag_or_die_quest",
412 |         order = 3,
413 |         name = "Tag or Die Exchange Coupon",
414 |         reward = "c_dvrprv_tag_or_die",
415 |         config = {
416 |             extra = {
417 |                 goal = 4
418 |             }
419 |         },
420 |         cost = 4,
421 |         pos = {
422 |             x = 5,
423 |             y = 1
424 |         }
425 |     },
426 |     {
427 |         key = "let_it_moon",
428 |         order = 8,
429 |         name = "Let It Moon",
430 |         config = {
431 |             extra = {
432 |                 kind = {
433 |                     "p_arcana_",
434 |                     "p_celestial_"
435 |                 }
436 |             }
437 |         },
438 |         cost = 4,
439 |         pos = {
440 |             x = 0,
441 |             y = 0
442 |         }
443 |     },
444 |     {
445 |         key = "let_it_moon_quest",
446 |         order = 7,
447 |         name = "Let It Moon Exchange Coupon",
448 |         reward = "c_dvrprv_let_it_moon",
449 |         config = {
450 |             extra = {
451 |                 goal = 10
452 |             }
453 |         },
454 |         cost = 4,
455 |         pos = {
456 |             x = 2,
457 |             y = 1
458 |         }
459 |     },
460 |     {
461 |         key = "poker_face",
462 |         order = 10,
463 |         name = "Poker Face",
464 |         config = {
465 |             extra = {
466 |                 kind = {
467 |                     "p_standard_"
468 |                 }
469 |             }
470 |         },
471 |         cost = 4,
472 |         pos = {
473 |             x = 4,
474 |             y = 0
475 |         }
476 |     },
477 |     {
478 |         key = "poker_face_quest",
479 |         order = 9,
480 |         name = "Poker Face Exchange Coupon",
481 |         reward = "c_dvrprv_poker_face",
482 |         config = {
483 |             extra = {
484 |                 goal = 8
485 |             }
486 |         },
487 |         cost = 4,
488 |         pos = {
489 |             x = 6,
490 |             y = 1
491 |         }
492 |     },
493 |     {
494 |         key = "eerie_inn",
495 |         order = 6,
496 |         name = "Eerie Inn",
497 |         config = {
498 |             extra = {
499 |                 mult = 2,
500 |                 kind = {
501 |                     "p_spectral_"
502 |                 }
503 |             }
504 |         },
505 |         cost = 4,
506 |         pos = {
507 |             x = 5,
508 |             y = 0
509 |         }
510 |     },
511 |     {
512 |         key = "eerie_inn_quest",
513 |         order = 5,
514 |         name = "Eerie Inn Exchange Coupon",
515 |         reward = "c_dvrprv_eerie_inn",
516 |         config = {
517 |             extra = {
518 |                 goal = 5
519 |             }
520 |         },
521 |         cost = 4,
522 |         pos = {
523 |             x = 7,
524 |             y = 1
525 |         }
526 |     },
527 |     {
528 |         key = "adrifting",
529 |         order = 14,
530 |         name = "Adrifting",
531 |         config = {
532 |             extra = {
533 |                 set_price = 1
534 |             }
535 |         },
536 |         cost = 4,
537 |         pos = {
538 |             x = 8,
539 |             y = 0
540 |         }
541 |     },
542 |     {
543 |         key = "adrifting_quest",
544 |         order = 13,
545 |         name = "Adrifting Exchange Coupon",
546 |         reward = "c_dvrprv_adrifting",
547 |         config = {
548 |             extra = {
549 |                 goal = 5
550 |             }
551 |         },
552 |         cost = 4,
553 |         pos = {
554 |             x = 0,
555 |             y = 2
556 |         }
557 |     },
558 |     {
559 |         key = "morsel",
560 |         order = 16,
561 |         name = "Morsel",
562 |         config = {
563 |             extra = {
564 |                 kind = {
565 |                     "p_buffoon_"
566 |                 }
567 |             }
568 |         },
569 |         cost = 4,
570 |         pos = {
571 |             x = 9,
572 |             y = 0
573 |         }
574 |     },
575 |     {
576 |         key = "morsel_quest",
577 |         order = 15,
578 |         name = "Morsel Exchange Coupon",
579 |         reward = "c_dvrprv_morsel",
580 |         config = {
581 |             extra = {
582 |                 goal = 2
583 |             }
584 |         },
585 |         cost = 4,
586 |         pos = {
587 |             x = 1,
588 |             y = 2
589 |         }
590 |     },
591 |     {
592 |         key = "alchemist",
593 |         order = 22,
594 |         name = "Fool Metal Alchemist",
595 |         config = {
596 |             extra = {
597 |                 slot = 2,
598 |                 kind = {
599 |                     SMODS.find_mod("ReduxArcanum") and "p_ReduxArcanum_alchemy_" or "p_alchemy_",
600 |                 }
601 |             }
602 |         },
603 |         cost = 4,
604 |         pos = {
605 |             x = 2,
606 |             y = 2
607 |         },
608 |         dependencies = "CodexArcanum"
609 |     },
610 |     {
611 |         key = "alchemist_quest",
612 |         order = 21,
613 |         name = "Fool Metal Alchemist Exchange Coupon",
614 |         reward = "c_dvrprv_alchemist",
615 |         config = {
616 |             extra = {
617 |                 goal = 5
618 |             }
619 |         },
620 |         cost = 4,
621 |         pos = {
622 |             x = 3,
623 |             y = 2
624 |         },
625 |         dependencies = "CodexArcanum"
626 |     },
627 |     {
628 |         key = "every_hue",
629 |         order = 24,
630 |         name = "Every Hue",
631 |         config = {
632 |             extra = {
633 |                 rounds = 3,
634 |                 kind = {
635 |                     "p_mf_colour_"
636 |                 }
637 |             }
638 |         },
639 |         cost = 4,
640 |         pos = {
641 |             x = 4,
642 |             y = 2
643 |         },
644 |         dependencies = "MoreFluff"
645 |     },
646 |     {
647 |         key = "every_hue_quest",
648 |         order = 23,
649 |         name = "Every Hue Exchange Coupon",
650 |         reward = "c_dvrprv_every_hue",
651 |         config = {
652 |             extra = {
653 |                 goal = 2
654 |             }
655 |         },
656 |         cost = 4,
657 |         pos = {
658 |             x = 5,
659 |             y = 2
660 |         },
661 |         dependencies = "MoreFluff"
662 |     },
663 |     {
664 |         key = "radioactive",
665 |         order = 26,
666 |         name = "Radioactive",
667 |         config = {
668 |             extra = {
669 |                 kind = {
670 |                     "p_buffoon_"
671 |                 }
672 |             }
673 |         },
674 |         cost = 4,
675 |         pos = {
676 |             x = 6,
677 |             y = 2
678 |         },
679 |         dependencies = "FusionJokers"
680 |     },
681 |     {
682 |         key = "radioactive_quest",
683 |         order = 25,
684 |         name = "Radioactive Exchange Coupon",
685 |         reward = "c_dvrprv_radioactive",
686 |         config = {
687 |             extra = {
688 |                 goal = 1
689 |             }
690 |         },
691 |         cost = 4,
692 |         pos = {
693 |             x = 7,
694 |             y = 2
695 |         },
696 |         dependencies = "FusionJokers"
697 |     },
698 |     {
699 |         key = "jovial_m",
700 |         order = 28,
701 |         name = "Jovial M",
702 |         config = {
703 |             extra = {
704 |                 kind = {
705 |                     "p_buffoon_"
706 |                 }
707 |             }
708 |         },
709 |         cost = 4,
710 |         pos = {
711 |             x = 8,
712 |             y = 2
713 |         },
714 |         dependencies = "Cryptid"
715 |     },
716 |     {
717 |         key = "jovial_m_quest",
718 |         order = 27,
719 |         name = "Jovial M Exchange Coupon",
720 |         reward = "c_dvrprv_jovial_m",
721 |         config = {
722 |             extra = {
723 |                 goal = 3
724 |             }
725 |         },
726 |         cost = 4,
727 |         pos = {
728 |             x = 9,
729 |             y = 2
730 |         },
731 |         dependencies = "Cryptid"
732 |     }
733 | }
734 | 
735 | table.sort(Reverie.cines, function(a, b) return a.order < b.order end)
736 | 
737 | -- Custom DrawStep for shadows on cine cards
738 | SMODS.DrawStep {
739 |     key = 'cine_shadow',
740 |     order = -999,
741 |     layers = { shadow = true, both = true },
742 |     func = function(self)
743 | 
744 |         if not Reverie.is_cine_or_reverie(self) then return end
745 | 
746 |         self.ARGS.send_to_shader = self.ARGS.send_to_shader or {}
747 |         self.ARGS.send_to_shader[1] = math.min(self.VT.r*3, 1) + math.sin(G.TIMERS.REAL/28) + 1 + (self.juice and self.juice.r*20 or 0) + self.tilt_var.amt
748 |         self.ARGS.send_to_shader[2] = G.TIMERS.REAL
749 |         self.ARGS.send_to_shader[3] = self.omit_top_half or 0
750 |         self.ARGS.send_to_shader[4] = self.omit_bottom_half or 0
751 | 
752 |         for k, v in pairs(self.children) do
753 |             v.VT.scale = self.VT.scale
754 |         end
755 |     
756 |         G.shared_shadow = self.sprite_facing == 'front' and self.children.center or self.children.back
757 |     
758 |         --Draw the shadow
759 |         if (self.reverie_custom_shadow) and G.SETTINGS.GRAPHICS.shadows == 'On' and ((self.ability.effect ~= 'Glass Card' and not self.greyed) and ((self.area and self.area ~= G.discard and self.area.config.type ~= 'deck') or not self.area or self.states.drag.is)) then
760 |             self.shadow_height = 0 * (0.08 + 0.4 * math.sqrt(self.velocity.x ^ 2)) + ((((self.highlighted and self.area == G.play) or self.states.drag.is) and 0.35) or (self.area and self.area.config.type == 'title_2') and 0.04 or 0.1)
761 |             G.shared_shadow:draw_shader('dvrprv_ticket', self.shadow_height, self.ARGS.send_to_shader)
762 |         end
763 | 
764 |         self.ARGS.send_to_shader[4] = nil
765 |         self.ARGS.send_to_shader[3] = nil
766 |     end,
767 | }
768 | 
769 | for _, v in pairs(Reverie.cines) do
770 | 
771 |     if v.dependencies == "MoreFluff" then
772 |         if next(SMODS.find_mod("MoreFluff")) and (not SMODS.Mods.MoreFluff.config['Colour Cards']) then
773 |             goto continue
774 |         end
775 |     end
776 | 
777 |     v.set = "Cine"
778 |     v.atlas = "Cine"
779 |     v.can_use = can_use
780 |     v.loc_vars = v.reward and loc_vars_quest or loc_vars_cine
781 |     v.inject = inject
782 |     v.use = not v.reward and Reverie.use_cine or nil
783 |     v.set_sprites = function(self, card, front)
784 |         card.ignore_base_shader = { ticket = true }
785 |     end
786 |     v.draw = function(self, card, layer)
787 |         card.ARGS = card.ARGS or {}
788 |         if not card.ARGS.send_to_shader then
789 |             card.ARGS.send_to_shader = card.ARGS.send_to_shader or {}
790 |             card.ARGS.send_to_shader[1] = math.min(card.VT.r*3, 1) + math.sin(G.TIMERS.REAL/28) + 1 + (card.juice and card.juice.r*20 or 0) + card.tilt_var.amt
791 |             card.ARGS.send_to_shader[2] = G.TIMERS.REAL
792 | 
793 |             for k, v in pairs(card.children) do
794 |                 v.VT.scale = card.VT.scale
795 |             end
796 |         end
797 |         if not (card.edition and card.edition.negative) then
798 |             card.ARGS.send_to_shader = card.ARGS.send_to_shader or {}
799 |             card.ARGS.send_to_shader[3] = card.omit_top_half or 0
800 |             card.ARGS.send_to_shader[4] = card.omit_bottom_half or 0
801 | 
802 |             if card.ability.name == "The Unseen" and card.ability.progress == nil and (card.config.center.discovered or card.bypass_discovery_center) then
803 |                 card.children.center:draw_shader("dvrprv_ticket_negative", nil, card.ARGS.send_to_shader)
804 |             elseif card.ability.name == "I Sing, I've No Shape" and card.ability.progress == nil and card.config.center.discovered then
805 |                 card.children.center:draw_shader("dvrprv_ticket_polychrome", nil, card.ARGS.send_to_shader)
806 |             else
807 |                 card.children.center:draw_shader("dvrprv_ticket", nil, card.ARGS.send_to_shader)
808 |             end
809 |         end
810 |         if card.edition and card.edition.polychrome then
811 |             card.ARGS.send_to_shader[3] = card.omit_top_half or 0
812 |             card.ARGS.send_to_shader[4] = card.omit_bottom_half or 0
813 | 
814 |             -- Different from "ticket_negative", this is a direct copy of negative with no intended visual changes
815 |             card.children.center:draw_shader("dvrprv_cine_polychrome", nil, card.ARGS.send_to_shader)
816 |         end
817 |         if card.edition and card.edition.negative then
818 |             card.ARGS.send_to_shader[3] = card.omit_top_half or 0
819 |             card.ARGS.send_to_shader[4] = card.omit_bottom_half or 0
820 | 
821 |             -- Different from "ticket_negative", this is a direct copy of negative with no intended visual changes
822 |             card.children.center:draw_shader("dvrprv_cine_negative", nil, card.ARGS.send_to_shader)
823 |         end
824 |     end
825 | 
826 |     -- Set cine card to its reward when flipped
827 |     -- Copied from Bunco's Cassette
828 |     v.update = function(self, card)
829 |         if card.VT.w <= 0 then
830 |             card.children.center:set_sprite_pos(G.P_CENTERS[card.config.center.key].pos)
831 |             card.ability.progress = nil
832 |         end
833 |     end
834 | 
835 |     SMODS.Consumable(v)
836 | 
837 |     :: continue ::
838 | end
839 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
  1 |                     GNU GENERAL PUBLIC LICENSE
  2 |                        Version 3, 29 June 2007
  3 | 
  4 |  Copyright (C) 2007 Free Software Foundation, Inc. 
  5 |  Everyone is permitted to copy and distribute verbatim copies
  6 |  of this license document, but changing it is not allowed.
  7 | 
  8 |                             Preamble
  9 | 
 10 |   The GNU General Public License is a free, copyleft license for
 11 | software and other kinds of works.
 12 | 
 13 |   The licenses for most software and other practical works are designed
 14 | to take away your freedom to share and change the works.  By contrast,
 15 | the GNU General Public License is intended to guarantee your freedom to
 16 | share and change all versions of a program--to make sure it remains free
 17 | software for all its users.  We, the Free Software Foundation, use the
 18 | GNU General Public License for most of our software; it applies also to
 19 | any other work released this way by its authors.  You can apply it to
 20 | your programs, too.
 21 | 
 22 |   When we speak of free software, we are referring to freedom, not
 23 | price.  Our General Public Licenses are designed to make sure that you
 24 | have the freedom to distribute copies of free software (and charge for
 25 | them if you wish), that you receive source code or can get it if you
 26 | want it, that you can change the software or use pieces of it in new
 27 | free programs, and that you know you can do these things.
 28 | 
 29 |   To protect your rights, we need to prevent others from denying you
 30 | these rights or asking you to surrender the rights.  Therefore, you have
 31 | certain responsibilities if you distribute copies of the software, or if
 32 | you modify it: responsibilities to respect the freedom of others.
 33 | 
 34 |   For example, if you distribute copies of such a program, whether
 35 | gratis or for a fee, you must pass on to the recipients the same
 36 | freedoms that you received.  You must make sure that they, too, receive
 37 | or can get the source code.  And you must show them these terms so they
 38 | know their rights.
 39 | 
 40 |   Developers that use the GNU GPL protect your rights with two steps:
 41 | (1) assert copyright on the software, and (2) offer you this License
 42 | giving you legal permission to copy, distribute and/or modify it.
 43 | 
 44 |   For the developers' and authors' protection, the GPL clearly explains
 45 | that there is no warranty for this free software.  For both users' and
 46 | authors' sake, the GPL requires that modified versions be marked as
 47 | changed, so that their problems will not be attributed erroneously to
 48 | authors of previous versions.
 49 | 
 50 |   Some devices are designed to deny users access to install or run
 51 | modified versions of the software inside them, although the manufacturer
 52 | can do so.  This is fundamentally incompatible with the aim of
 53 | protecting users' freedom to change the software.  The systematic
 54 | pattern of such abuse occurs in the area of products for individuals to
 55 | use, which is precisely where it is most unacceptable.  Therefore, we
 56 | have designed this version of the GPL to prohibit the practice for those
 57 | products.  If such problems arise substantially in other domains, we
 58 | stand ready to extend this provision to those domains in future versions
 59 | of the GPL, as needed to protect the freedom of users.
 60 | 
 61 |   Finally, every program is threatened constantly by software patents.
 62 | States should not allow patents to restrict development and use of
 63 | software on general-purpose computers, but in those that do, we wish to
 64 | avoid the special danger that patents applied to a free program could
 65 | make it effectively proprietary.  To prevent this, the GPL assures that
 66 | patents cannot be used to render the program non-free.
 67 | 
 68 |   The precise terms and conditions for copying, distribution and
 69 | modification follow.
 70 | 
 71 |                        TERMS AND CONDITIONS
 72 | 
 73 |   0. Definitions.
 74 | 
 75 |   "This License" refers to version 3 of the GNU General Public License.
 76 | 
 77 |   "Copyright" also means copyright-like laws that apply to other kinds of
 78 | works, such as semiconductor masks.
 79 | 
 80 |   "The Program" refers to any copyrightable work licensed under this
 81 | License.  Each licensee is addressed as "you".  "Licensees" and
 82 | "recipients" may be individuals or organizations.
 83 | 
 84 |   To "modify" a work means to copy from or adapt all or part of the work
 85 | in a fashion requiring copyright permission, other than the making of an
 86 | exact copy.  The resulting work is called a "modified version" of the
 87 | earlier work or a work "based on" the earlier work.
 88 | 
 89 |   A "covered work" means either the unmodified Program or a work based
 90 | on the Program.
 91 | 
 92 |   To "propagate" a work means to do anything with it that, without
 93 | permission, would make you directly or secondarily liable for
 94 | infringement under applicable copyright law, except executing it on a
 95 | computer or modifying a private copy.  Propagation includes copying,
 96 | distribution (with or without modification), making available to the
 97 | public, and in some countries other activities as well.
 98 | 
 99 |   To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies.  Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 | 
103 |   An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License.  If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 | 
112 |   1. Source Code.
113 | 
114 |   The "source code" for a work means the preferred form of the work
115 | for making modifications to it.  "Object code" means any non-source
116 | form of a work.
117 | 
118 |   A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 | 
123 |   The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form.  A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 | 
134 |   The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities.  However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work.  For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 | 
147 |   The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 | 
151 |   The Corresponding Source for a work in source code form is that
152 | same work.
153 | 
154 |   2. Basic Permissions.
155 | 
156 |   All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met.  This License explicitly affirms your unlimited
159 | permission to run the unmodified Program.  The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work.  This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 | 
164 |   You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force.  You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright.  Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 | 
175 |   Conveying under any other circumstances is permitted solely under
176 | the conditions stated below.  Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 | 
179 |   3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 | 
181 |   No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 | 
187 |   When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 | 
195 |   4. Conveying Verbatim Copies.
196 | 
197 |   You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 | 
205 |   You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 | 
208 |   5. Conveying Modified Source Versions.
209 | 
210 |   You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 | 
214 |     a) The work must carry prominent notices stating that you modified
215 |     it, and giving a relevant date.
216 | 
217 |     b) The work must carry prominent notices stating that it is
218 |     released under this License and any conditions added under section
219 |     7.  This requirement modifies the requirement in section 4 to
220 |     "keep intact all notices".
221 | 
222 |     c) You must license the entire work, as a whole, under this
223 |     License to anyone who comes into possession of a copy.  This
224 |     License will therefore apply, along with any applicable section 7
225 |     additional terms, to the whole of the work, and all its parts,
226 |     regardless of how they are packaged.  This License gives no
227 |     permission to license the work in any other way, but it does not
228 |     invalidate such permission if you have separately received it.
229 | 
230 |     d) If the work has interactive user interfaces, each must display
231 |     Appropriate Legal Notices; however, if the Program has interactive
232 |     interfaces that do not display Appropriate Legal Notices, your
233 |     work need not make them do so.
234 | 
235 |   A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit.  Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 | 
245 |   6. Conveying Non-Source Forms.
246 | 
247 |   You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 | 
252 |     a) Convey the object code in, or embodied in, a physical product
253 |     (including a physical distribution medium), accompanied by the
254 |     Corresponding Source fixed on a durable physical medium
255 |     customarily used for software interchange.
256 | 
257 |     b) Convey the object code in, or embodied in, a physical product
258 |     (including a physical distribution medium), accompanied by a
259 |     written offer, valid for at least three years and valid for as
260 |     long as you offer spare parts or customer support for that product
261 |     model, to give anyone who possesses the object code either (1) a
262 |     copy of the Corresponding Source for all the software in the
263 |     product that is covered by this License, on a durable physical
264 |     medium customarily used for software interchange, for a price no
265 |     more than your reasonable cost of physically performing this
266 |     conveying of source, or (2) access to copy the
267 |     Corresponding Source from a network server at no charge.
268 | 
269 |     c) Convey individual copies of the object code with a copy of the
270 |     written offer to provide the Corresponding Source.  This
271 |     alternative is allowed only occasionally and noncommercially, and
272 |     only if you received the object code with such an offer, in accord
273 |     with subsection 6b.
274 | 
275 |     d) Convey the object code by offering access from a designated
276 |     place (gratis or for a charge), and offer equivalent access to the
277 |     Corresponding Source in the same way through the same place at no
278 |     further charge.  You need not require recipients to copy the
279 |     Corresponding Source along with the object code.  If the place to
280 |     copy the object code is a network server, the Corresponding Source
281 |     may be on a different server (operated by you or a third party)
282 |     that supports equivalent copying facilities, provided you maintain
283 |     clear directions next to the object code saying where to find the
284 |     Corresponding Source.  Regardless of what server hosts the
285 |     Corresponding Source, you remain obligated to ensure that it is
286 |     available for as long as needed to satisfy these requirements.
287 | 
288 |     e) Convey the object code using peer-to-peer transmission, provided
289 |     you inform other peers where the object code and Corresponding
290 |     Source of the work are being offered to the general public at no
291 |     charge under subsection 6d.
292 | 
293 |   A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 | 
297 |   A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling.  In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage.  For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product.  A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 | 
310 |   "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source.  The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 | 
318 |   If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information.  But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 | 
329 |   The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed.  Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 | 
337 |   Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 | 
343 |   7. Additional Terms.
344 | 
345 |   "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law.  If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 | 
354 |   When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it.  (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.)  You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 | 
361 |   Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 | 
365 |     a) Disclaiming warranty or limiting liability differently from the
366 |     terms of sections 15 and 16 of this License; or
367 | 
368 |     b) Requiring preservation of specified reasonable legal notices or
369 |     author attributions in that material or in the Appropriate Legal
370 |     Notices displayed by works containing it; or
371 | 
372 |     c) Prohibiting misrepresentation of the origin of that material, or
373 |     requiring that modified versions of such material be marked in
374 |     reasonable ways as different from the original version; or
375 | 
376 |     d) Limiting the use for publicity purposes of names of licensors or
377 |     authors of the material; or
378 | 
379 |     e) Declining to grant rights under trademark law for use of some
380 |     trade names, trademarks, or service marks; or
381 | 
382 |     f) Requiring indemnification of licensors and authors of that
383 |     material by anyone who conveys the material (or modified versions of
384 |     it) with contractual assumptions of liability to the recipient, for
385 |     any liability that these contractual assumptions directly impose on
386 |     those licensors and authors.
387 | 
388 |   All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10.  If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term.  If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 | 
398 |   If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 | 
403 |   Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 | 
407 |   8. Termination.
408 | 
409 |   You may not propagate or modify a covered work except as expressly
410 | provided under this License.  Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 | 
415 |   However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 | 
422 |   Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 | 
429 |   Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License.  If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 | 
435 |   9. Acceptance Not Required for Having Copies.
436 | 
437 |   You are not required to accept this License in order to receive or
438 | run a copy of the Program.  Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance.  However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work.  These actions infringe copyright if you do
443 | not accept this License.  Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 | 
446 |   10. Automatic Licensing of Downstream Recipients.
447 | 
448 |   Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License.  You are not responsible
451 | for enforcing compliance by third parties with this License.
452 | 
453 |   An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations.  If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 | 
463 |   You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License.  For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 | 
471 |   11. Patents.
472 | 
473 |   A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based.  The
475 | work thus licensed is called the contributor's "contributor version".
476 | 
477 |   A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version.  For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 | 
487 |   Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 | 
492 |   In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement).  To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 | 
499 |   If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients.  "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 | 
513 |   If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 | 
521 |   A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License.  You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 | 
536 |   Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 | 
540 |   12. No Surrender of Others' Freedom.
541 | 
542 |   If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License.  If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all.  For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 | 
552 |   13. Use with the GNU Affero General Public License.
553 | 
554 |   Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work.  The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 | 
563 |   14. Revised Versions of this License.
564 | 
565 |   The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time.  Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 | 
570 |   Each version is given a distinguishing version number.  If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation.  If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 | 
579 |   If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 | 
584 |   Later license versions may give you additional or different
585 | permissions.  However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 | 
589 |   15. Disclaimer of Warranty.
590 | 
591 |   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 | 
600 |   16. Limitation of Liability.
601 | 
602 |   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 | 
612 |   17. Interpretation of Sections 15 and 16.
613 | 
614 |   If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 | 
621 |                      END OF TERMS AND CONDITIONS
622 | 
623 |             How to Apply These Terms to Your New Programs
624 | 
625 |   If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 | 
629 |   To do so, attach the following notices to the program.  It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 | 
634 |     
635 |     Copyright (C)   
636 | 
637 |     This program is free software: you can redistribute it and/or modify
638 |     it under the terms of the GNU General Public License as published by
639 |     the Free Software Foundation, either version 3 of the License, or
640 |     (at your option) any later version.
641 | 
642 |     This program is distributed in the hope that it will be useful,
643 |     but WITHOUT ANY WARRANTY; without even the implied warranty of
644 |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
645 |     GNU General Public License for more details.
646 | 
647 |     You should have received a copy of the GNU General Public License
648 |     along with this program.  If not, see .
649 | 
650 | Also add information on how to contact you by electronic and paper mail.
651 | 
652 |   If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 | 
655 |       Copyright (C)   
656 |     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 |     This is free software, and you are welcome to redistribute it
658 |     under certain conditions; type `show c' for details.
659 | 
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License.  Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 | 
664 |   You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 | 
669 |   The GNU General Public License does not permit incorporating your program
670 | into proprietary programs.  If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library.  If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License.  But first, please read
674 | .
675 | 


--------------------------------------------------------------------------------