Compare commits
No commits in common. "main" and "frozen-jokers" have entirely different histories.
main
...
frozen-jok
|
|
@ -33,7 +33,7 @@ table_separator_style = none
|
|||
trailing_table_separator = smart
|
||||
|
||||
# keep/remove/remove_table_only/remove_string_only
|
||||
call_arg_parentheses = remove
|
||||
call_arg_parentheses = keep
|
||||
|
||||
detect_end_of_line = false
|
||||
|
||||
|
|
|
|||
6
.gitignore
vendored
|
|
@ -38,9 +38,3 @@ luac.out
|
|||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Syncthing
|
||||
.stfolder
|
||||
|
||||
# Autogenerated
|
||||
assets/1x/jokers
|
||||
|
|
|
|||
4
.vscode/settings.json
vendored
|
|
@ -65,8 +65,4 @@
|
|||
"unused-local": "Error",
|
||||
"unused-vararg": "Error",
|
||||
},
|
||||
"Lua.runtime.version": "LuaJIT",
|
||||
"Lua.workspace.library": [
|
||||
"${3rd}/love2d/library"
|
||||
],
|
||||
}
|
||||
52
README.md
|
|
@ -1,52 +0,0 @@
|
|||
# Roland
|
||||
|
||||
[](https://github.com/Emik03/Roland/blob/main/LICENSE)
|
||||
|
||||
This is a [Steamodded](https://github.com/Steamodded/smods) mod for the video game [Balatro (2024)](https://playbalatro.com).
|
||||
|
||||
This mod has been in the works since early 2025, and been worked on continously until its official public release as a celebration for my 23rd birthday.
|
||||
|
||||
---
|
||||
|
||||
- [About](#about)
|
||||
- [Contents](#contents)
|
||||
- [Installation](#installation)
|
||||
- [License](#license)
|
||||
|
||||
---
|
||||
|
||||
## About
|
||||
|
||||
The main theme of this mod centers around the addition of a new edition: Frozen.
|
||||
|
||||
Frozen can be applied to playing cards or jokers and will cause whatever state they have to be locked in place, removing any possibility of future scaling; positive or negative.
|
||||
|
||||
The primary goal is to create interesting interactions in-and-outside of the added editions. This does not necessarily mean that these mechanics have to be balanced, but does hopefully make new strategies viable and breathe new life into some of the base game's weaker jokers. It is designed to work very well with its parent mod [Bakery](https://github.com/BakersDozenBagels/BalatroBakery), but can work just as well on its own or with other content mods.
|
||||
|
||||
The mod offers a config for accessibility options, general convenience, modifications that I believe make the game healthier, and otherwise purely cosmetic.
|
||||
|
||||
## Contents
|
||||
|
||||
- 31 Jokers
|
||||
- 1 Tarot Card
|
||||
- 4 Spectral Cards
|
||||
- 2 Vouchers
|
||||
- 1 Seal
|
||||
- 1 Edition
|
||||
- 2 Tags
|
||||
- 9 Blinds
|
||||
- 4 Decks
|
||||
- 4 [Deck Sleeves (CardSleeves)](https://github.com/larswijn/CardSleeves)
|
||||
- 5 [Charms (Bakery)](https://github.com/BakersDozenBagels/BalatroBakery)
|
||||
|
||||
## Installation
|
||||
|
||||
1. Set up [Steamodded](https://github.com/Steamodded/smods/wiki#i-want-to-play-with-mods).
|
||||
2. Set up [Bakery](https://github.com/BakersDozenBagels). You are free to use the [Lite version](https://github.com/BakersDozenBagels/BalatroBakery/tree/lite) if you want to play Roland standalone.
|
||||
3. Clone the repository into your mods folder, or download it as a zip and place it there.
|
||||
|
||||
## License
|
||||
|
||||
This repository falls under the [MPL-2 license](https://www.mozilla.org/en-US/MPL/2.0/).
|
||||
|
||||
You may copy individual or multiple source files, granted that you keep the copyright license, and disclose the source back to this repository.
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 9 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/sh
|
||||
directory=$(dirname $(readlink -f "$0"))
|
||||
mkdir -p "$directory/1x/jokers"
|
||||
|
||||
for i in $(seq 0 $(cd "$directory/1x/jokers/" && find *.png | tail -n +2 | wc -l)); do
|
||||
files="$files $directory/1x/jokers/$i.png";
|
||||
done
|
||||
|
||||
magick montage -background '#00000000' $files -geometry +0+0 "$directory/1x/joker.png"
|
||||
"$directory/upscale.sh"
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/sh
|
||||
directory=$(dirname $(readlink -f "$0"))
|
||||
mkdir -p "$directory/1x/jokers"
|
||||
magick "$directory/1x/joker.png" -crop 71x95 +repage +adjoin "$directory/1x/jokers/%01d.png"
|
||||
|
|
@ -1,18 +1 @@
|
|||
@echo off
|
||||
for /F %%x in ('dir /B/D 2x') do (
|
||||
if %%~xx == .png (
|
||||
if not exist 1x\%%x (
|
||||
echo Removing deleted file 1x\%%x from 2x\
|
||||
del 2x\%%x
|
||||
)
|
||||
)
|
||||
)
|
||||
for /F %%x in ('dir /B/D 1x') do (
|
||||
if %%~xx == .png (
|
||||
REM https://stackoverflow.com/questions/1687014/how-do-i-compare-timestamps-of-files-in-a-batch-script/58323817#58323817
|
||||
xcopy /LDY /-I 1x\%%x 2x\%%x | findstr /B /C:"1 " > nul 2>&1 && (
|
||||
echo Updating changed file 1x\%%x in 2x\
|
||||
magick 1x\%%x -filter point -resize 200%% 2x\%%x
|
||||
)
|
||||
)
|
||||
)
|
||||
for /F %%x in ('dir /B/D 1x') do magick 1x\%%x -scale 200%% 2x\%%x
|
||||
|
|
|
|||
|
|
@ -1,19 +1,8 @@
|
|||
#!/bin/sh
|
||||
cd "$(dirname "$0")"
|
||||
directory=$(dirname $(readlink -f "$0"))
|
||||
|
||||
for file in 2x/*.png; do
|
||||
for file in "$directory"/1x/*.png; do
|
||||
filename=$(basename "$file")
|
||||
if [ ! -f "1x/${filename}" ]; then
|
||||
echo "Removing deleted file ${file} from 2x"
|
||||
rm "2x/${filename}"
|
||||
fi
|
||||
done
|
||||
|
||||
for file in 1x/*.png; do
|
||||
filename=$(basename "$file")
|
||||
output_file="2x/${filename}"
|
||||
if [ ! -f "$output_file" ] || [ "$file" -nt "$output_file" ]; then
|
||||
echo "Updating changed file ${file} in 2x/"
|
||||
output_file="$directory/2x/${filename}"
|
||||
magick "$file" -filter point -resize 200% "$output_file"
|
||||
fi
|
||||
done
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
return {
|
||||
animated_icon = true,
|
||||
cool_phones = true,
|
||||
equinox_assist = false,
|
||||
faster_planets = false,
|
||||
harsh_ante_scaling = false,
|
||||
fusable_escapey = false,
|
||||
harsh_ante_scaling = true,
|
||||
illusion_seal = true,
|
||||
import_funky = false,
|
||||
no_highlight_limit = true,
|
||||
no_wild_debuff = true,
|
||||
scribable_basket = false,
|
||||
vitriol = true,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,71 +6,52 @@ return {
|
|||
text = {
|
||||
"{C:attention}Small{} and {C:attention}Big Blinds{} are",
|
||||
"replaced with {C:attention}Boss Blinds",
|
||||
"that are {C:dark_edition}debuffed thrice",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
"that are {C:dark_edition}debuffed #1# times",
|
||||
},
|
||||
},
|
||||
b_Roland_dropship = {
|
||||
name = "Dropship Deck",
|
||||
b_Roland_go = {
|
||||
name = "Pass GO Deck",
|
||||
text = {
|
||||
"{C:attention}Jokers {}are {C:money}free",
|
||||
"and {C:attention}Perishable",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
"Start with a {C:attention}Credit Card",
|
||||
"Set money to {C:money}$0 {}when",
|
||||
"entering the shop",
|
||||
},
|
||||
unlock = {"Have exclusively", "{C:attention}Perishable Jokers"},
|
||||
},
|
||||
b_Roland_swapper = {
|
||||
name = "Swapper Deck",
|
||||
text = {
|
||||
"{C:tarot}Tarot {}and {C:spectral}Spectral",
|
||||
"cards swap places",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
},
|
||||
},
|
||||
b_Roland_wish = {
|
||||
name = "Wish Deck",
|
||||
text = {
|
||||
"Redeem a random {C:attention}Voucher",
|
||||
"after {C:attention}Small {}and {C:attention}Big Blinds",
|
||||
"{C:attention}Vouchers {}no longer",
|
||||
"appear in the shop",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
},
|
||||
unlock = {"Discover all {C:attention}Vouchers"},
|
||||
},
|
||||
},
|
||||
BakeryCharm = {
|
||||
BakeryCharm_Roland_cocacola = {
|
||||
name = SMODS.Mods.Roland.config.cool_phones and "coca cola phone" or "Pentagram",
|
||||
name = "coca cola phone",
|
||||
text = {
|
||||
"{C:attention}Discard 0 cards {}to",
|
||||
"gain {C:red}#1# {}discards and",
|
||||
"lose {C:attention}#2# {}hand size",
|
||||
"this round",
|
||||
"Values on consumables",
|
||||
"increase by {C:attention}1",
|
||||
"{C:inactive}(excluding {C:planet}Planets{C:inactive})",
|
||||
},
|
||||
},
|
||||
BakeryCharm_Roland_fat = {
|
||||
name = SMODS.Mods.Roland.config.cool_phones and "fat i phone" or "Product",
|
||||
name = "fat i phone",
|
||||
text = {
|
||||
"{C:attention}+#1# Booster Pack {}slots",
|
||||
-- "{C:attention}+#1# Booster Pack {}slots",
|
||||
"All {C:attention}Booster Packs {}are {C:attention}Mega",
|
||||
"{C:inactive}(Whenever applicable)",
|
||||
},
|
||||
},
|
||||
BakeryCharm_Roland_flexible = {
|
||||
name = SMODS.Mods.Roland.config.cool_phones and "flexi ble phone" or "Ring",
|
||||
name = "flexi ble phone",
|
||||
text = {unpack(G.localization.descriptions.Joker.j_ring_master.text)},
|
||||
},
|
||||
BakeryCharm_Roland_hand = {
|
||||
name = SMODS.Mods.Roland.config.cool_phones and "hand phone" or "Shell",
|
||||
name = "hand phone",
|
||||
text = {"{C:attention}+#1# {}hand size", "{C:blue}#2# {}hands"},
|
||||
},
|
||||
BakeryCharm_Roland_wii = {
|
||||
name = SMODS.Mods.Roland.config.cool_phones and "wii phone" or "Tire",
|
||||
name = "wii phone",
|
||||
text = {
|
||||
"Enter the shop",
|
||||
"when any {C:attention}Blind",
|
||||
|
|
@ -81,47 +62,39 @@ return {
|
|||
Blind = {
|
||||
bl_Roland_blizzard = {
|
||||
name = "The Blizzard",
|
||||
text = {"All cards", "are {C:dark_edition}Frozen"},
|
||||
text = {"All cards", "are Frozen"},
|
||||
},
|
||||
bl_Roland_divide = {
|
||||
name = "The Great Divide",
|
||||
text = {"Half of the deck", "is {C:red}discarded"},
|
||||
text = {"Half of the deck", "is discarded"},
|
||||
},
|
||||
bl_Roland_equinox = {
|
||||
name = "The Equinox",
|
||||
text = {"{C:inactive}No UI"},
|
||||
text = {"No UI"},
|
||||
},
|
||||
bl_Roland_falseshuffle = {
|
||||
name = "The False Shuffle",
|
||||
text = {"{C:enhanced}Enhanced {}cards", "are drawn {C:attention}last"},
|
||||
text = {"Enhanced cards", "are drawn last"},
|
||||
},
|
||||
bl_Roland_improbable = {
|
||||
name = "The Improbable",
|
||||
text = {"All {C:green}probabilities", "cannot happen"},
|
||||
text = {"All probabilities", "cannot happen"},
|
||||
},
|
||||
bl_Roland_mitotic = {
|
||||
name = "The Mitotic",
|
||||
text = {"{C:red}Discarded {}cards", "are {C:attention}copied"},
|
||||
text = {"Discarded cards", "are copied"},
|
||||
},
|
||||
bl_Roland_nimble = {
|
||||
name = "The Nimble",
|
||||
text = {"The {C:attention}first 5 {}cards", "drawn are {C:blue}played"},
|
||||
text = {"The first 5 cards", "drawn are played"},
|
||||
},
|
||||
bl_Roland_tranquilizer = {
|
||||
name = "The Tranquilizer",
|
||||
text = {
|
||||
"{C:attention}#1#s {}are {C:red}debuffed",
|
||||
"Changes based on",
|
||||
"most common rank",
|
||||
},
|
||||
text = {"#1#s are debuffed", "Changes based on", "most common rank"},
|
||||
},
|
||||
bl_Roland_venerable_visage = {
|
||||
name = "Venerable Visage",
|
||||
text = {
|
||||
"Infinite {C:red}discards",
|
||||
"Lose if {C:attention}any {}card was",
|
||||
"not {C:blue}played {}or {C:red}discarded",
|
||||
},
|
||||
text = {"Infinite discards", "Lose if any card was", "not played or discarded"},
|
||||
fail = {
|
||||
"Blasphemy.",
|
||||
"Blunder.",
|
||||
|
|
@ -153,28 +126,9 @@ return {
|
|||
},
|
||||
},
|
||||
Joker = {
|
||||
j_Roland_amber = {
|
||||
name = "Amber Acorn",
|
||||
text = {
|
||||
"{X:mult,C:white}X#1#{} Mult",
|
||||
"Moves before",
|
||||
"hand is played",
|
||||
},
|
||||
unlock = {"Defeat {C:attention}#1#"},
|
||||
},
|
||||
j_Roland_arctic = {
|
||||
name = "Arctic Circle",
|
||||
text = {"Retrigger {C:attention}all", "{C:dark_edition}Frozen {}cards"},
|
||||
},
|
||||
j_Roland_artemis = {
|
||||
name = "Artemis X",
|
||||
text = {
|
||||
"Earn {C:money}$#1# {}at end of round",
|
||||
"Payout increases by {C:money}$#2#",
|
||||
"when these {C:planet}Planet {}cards",
|
||||
"are used in order:",
|
||||
"{V:1}Earth{C:inactive} - {V:2}Mars{C:inactive} - {V:3}Earth",
|
||||
},
|
||||
text = {"Retrigger all", "{C:dark_edition}Frozen {}cards"},
|
||||
},
|
||||
j_Roland_basket = {
|
||||
name = "Basket",
|
||||
|
|
@ -187,37 +141,11 @@ return {
|
|||
j_Roland_bulldozer = {
|
||||
name = "Bulldozer",
|
||||
text = {
|
||||
"Give the {C:attention}Blind",
|
||||
"{C:attention}Base {}as {X:red,C:white}XMult",
|
||||
"{C:inactive}(Currently {X:red,C:white}X#1#{C:inactive} Mult)",
|
||||
"Give {X:red,C:white}XMult{} equal to",
|
||||
"the current {C:attention}Blind Size{C:attention}",
|
||||
"{C:inactive}(Currently {X:red,C:white}X#1#{C:inactive})",
|
||||
},
|
||||
},
|
||||
j_Roland_cold = {
|
||||
name = "Cold Turkey",
|
||||
text = {
|
||||
"Third scored card",
|
||||
"gives {X:red,C:white}X#1#{} Mult",
|
||||
"if it is {C:dark_edition}Frozen",
|
||||
},
|
||||
},
|
||||
j_Roland_cerulean = {
|
||||
name = "Cerulean Bell",
|
||||
text = {
|
||||
"{X:mult,C:white}X#1#{} Mult",
|
||||
"All other {C:attention}Jokers {}cannot",
|
||||
"be selected or dragged",
|
||||
},
|
||||
unlock = {"Defeat {C:blue}#1#"},
|
||||
},
|
||||
j_Roland_crimson = {
|
||||
name = "Crimson Heart",
|
||||
text = {
|
||||
"{X:mult,C:white}X#1#{} Mult",
|
||||
"{C:red}Debuffs {C:attention}Joker",
|
||||
"to the left",
|
||||
},
|
||||
unlock = {"Defeat {C:red}#1#"},
|
||||
},
|
||||
j_Roland_domino = {
|
||||
name = "Domino",
|
||||
text = {
|
||||
|
|
@ -227,20 +155,30 @@ return {
|
|||
"{C:inactive}(Currently {C:red}+#3#{C:inactive} Mult)",
|
||||
},
|
||||
},
|
||||
j_Roland_excalibur = {
|
||||
name = "Excalibur",
|
||||
j_Roland_escapey = {
|
||||
name = "Escapey",
|
||||
text = {
|
||||
"Score {C:attention}#1# {C:enhanced}Stone Cards",
|
||||
"to {C:attention}pull {}this {C:attention}Joker",
|
||||
"{C:inactive}(Currently {C:attention}#2#{C:inactive})",
|
||||
"Use to {C:attention}destroy tags{} or {C:attention}unselected consumables",
|
||||
"in exchange for {C:planet}leveling up {X:planet,C:white}#1#{C:planet} random hands",
|
||||
"{C:inactive,s:0.75,E:1}#2#{C:red,s:1.5,E:1}#3#{s:0.9}#4#{C:blue,E:1,s:0.9}#5#{s:0.9}#6#",
|
||||
},
|
||||
merge = {"Since none apply, fuse with other ", " jokers"},
|
||||
quotes = {
|
||||
marble = {"there is no escape..."},
|
||||
normal = {
|
||||
"I can't wait to work with you!",
|
||||
"Did you need something from me?",
|
||||
"Oh! I'm just so happy to see you!",
|
||||
"Can I say something irrelevant? I promise it won't be long.",
|
||||
"Tell me about your buddies! Assuming you have them, anyway.",
|
||||
},
|
||||
scared = {
|
||||
"What am I going to do?!",
|
||||
"I'm not scared, you are!",
|
||||
"Tell me when this is over...",
|
||||
"I can't keep looking at this!",
|
||||
"Let me go hide in this corner... Okay?",
|
||||
},
|
||||
j_Roland_excalibur_Back = {
|
||||
name = "Excalibur",
|
||||
text = {
|
||||
"Scored and held in",
|
||||
"hand {C:enhanced}Stone Cards",
|
||||
"each give {X:mult,C:white}X#3#{} Mult",
|
||||
},
|
||||
},
|
||||
j_Roland_hardboiled = {
|
||||
|
|
@ -251,23 +189,6 @@ return {
|
|||
"hand {C:dark_edition}Frozen",
|
||||
},
|
||||
},
|
||||
j_Roland_idle = {
|
||||
name = "The Idle",
|
||||
text = {
|
||||
"Use to add card's",
|
||||
"rank and suit",
|
||||
"First {C:attention}scoring {}card",
|
||||
"of each entry",
|
||||
"gives {X:mult,C:white}X#19#{} Mult",
|
||||
"{C:inactive}(Must be distinct)",
|
||||
"{V:1,s:0.75}#1#{C:inactive,s:0.75}#2#{V:2,s:0.75}#3#{C:inactive,s:0.75}, " ..
|
||||
"{V:3,s:0.75}#4#{C:inactive,s:0.75}#5#{V:4,s:0.75}#6#{C:inactive,s:0.75}",
|
||||
"{V:5,s:0.75}#7#{C:inactive,s:0.75}#8#{V:6,s:0.75}#9#, " ..
|
||||
"{V:7,s:0.75}#10#{C:inactive,s:0.75}#11#{V:8,s:0.75}#12#{C:inactive,s:0.75}",
|
||||
"{V:9,s:0.75}#13#{C:inactive,s:0.75}#14#{V:10,s:0.75}#15#{C:inactive,s:0.75}, " ..
|
||||
"{V:11,s:0.75}#16#{C:inactive,s:0.75}#17#{V:12,s:0.75}#18#",
|
||||
},
|
||||
},
|
||||
j_Roland_jokersr = {
|
||||
name = "Joker Sr.",
|
||||
text = {"{X:mult,C:white}X#1#{} Mult"},
|
||||
|
|
@ -288,8 +209,9 @@ return {
|
|||
j_Roland_misfortune = {
|
||||
name = "Misfortune Cookie",
|
||||
text = {
|
||||
"Cards created by",
|
||||
"{C:attention}Seals {}become {C:dark_edition}Negative",
|
||||
"{C:tarot}Tarot{} cards created",
|
||||
"by {C:tarot}Purple Seals",
|
||||
"become {C:dark_edition}Negative",
|
||||
},
|
||||
},
|
||||
j_Roland_monomino = {
|
||||
|
|
@ -315,14 +237,6 @@ return {
|
|||
name = "Ms. Joker",
|
||||
text = {"{C:chips}+#1#{} Chips"},
|
||||
},
|
||||
j_Roland_nilly = {
|
||||
name = "Nilly",
|
||||
text = {
|
||||
"Toggleable {X:mult,C:white}X0{} Mult",
|
||||
"{C:inactive}(Currently {C:attention}#1#{C:inactive})",
|
||||
"{C:inactive,s:0.75,E:1}Wait... what?",
|
||||
},
|
||||
},
|
||||
j_Roland_oops = {
|
||||
name = "Oops! All 7s",
|
||||
text = {
|
||||
|
|
@ -333,15 +247,7 @@ return {
|
|||
},
|
||||
j_Roland_phytoestrogens = {
|
||||
name = "Phytoestrogens",
|
||||
text = {"{C:mult}+Chips{} Mult, {X:mult,C:white}X#1#{} Mult"},
|
||||
},
|
||||
j_Roland_polaris = {
|
||||
name = "Polaris",
|
||||
text = {
|
||||
"The {C:attention}first {}scored",
|
||||
"card each round",
|
||||
"becomes {C:dark_edition}Frozen",
|
||||
},
|
||||
text = {"{C:mult}+Chips{} Mult", "{X:mult,C:white}X#1#{} Mult"},
|
||||
},
|
||||
j_Roland_sapling = {
|
||||
name = "Sapling",
|
||||
|
|
@ -352,15 +258,6 @@ return {
|
|||
"least {C:attention}#2# suits",
|
||||
},
|
||||
},
|
||||
j_Roland_snowsquall = {
|
||||
name = "Snowsquall",
|
||||
text = {
|
||||
"This Joker gains",
|
||||
"{C:mult}+#1# {}Mult for every",
|
||||
"played {C:dark_edition}Frozen {}card",
|
||||
"{C:inactive}(Currently {C:red}+#2#{C:inactive} Mult)",
|
||||
},
|
||||
},
|
||||
j_Roland_suitable = {
|
||||
name = "Suitable",
|
||||
text = {"{V:1}#1# {}are {C:attention}Wild", "Suit changes", "every round"},
|
||||
|
|
@ -370,7 +267,7 @@ return {
|
|||
text = {
|
||||
"Sell this Joker to",
|
||||
"{C:attention}draw{} the bottom",
|
||||
"card of the deck",
|
||||
"card of the {C:hand}deck",
|
||||
"{C:inactive}(Currently {V:1}#1#{C:inactive}#2#{V:2}#3#{C:inactive})",
|
||||
},
|
||||
},
|
||||
|
|
@ -391,38 +288,13 @@ return {
|
|||
"{C:attention}#2#",
|
||||
},
|
||||
},
|
||||
j_Roland_verdant = {
|
||||
name = "Verdant Leaf",
|
||||
text = {
|
||||
"{X:mult,C:white}X#1#{} Mult",
|
||||
"{C:red}Debuffs {}the {C:attention}first",
|
||||
"{C:attention}#2# {}scored cards",
|
||||
},
|
||||
unlock = {"Defeat {C:green}#1#"},
|
||||
},
|
||||
j_Roland_violet = {
|
||||
name = "Violet Vessel",
|
||||
text = {
|
||||
"{X:mult,C:white}X#1#{} Mult,",
|
||||
"but {X:mult,C:white}X#2#{} Mult",
|
||||
"{C:attention}before {}scoring",
|
||||
},
|
||||
unlock = {"Defeat {C:purple}#1#"},
|
||||
},
|
||||
j_Roland_venerable = {
|
||||
name = "Venerable Visage",
|
||||
text = {"{X:red,C:white}X#1#{} discards each round"},
|
||||
unlock = {"Defeat {C:dark_edition}#1#"},
|
||||
},
|
||||
j_Roland_yard = {
|
||||
name = "Yard Sale",
|
||||
text = {
|
||||
"Gain {C:money}$#1#{} when a",
|
||||
"card is {C:attention}added",
|
||||
"or {C:attention}removed",
|
||||
"card is {C:attention}removed",
|
||||
"from the deck",
|
||||
},
|
||||
unlock = {"Complete the", "{C:attention}#1#", "challenge"},
|
||||
},
|
||||
},
|
||||
Other = {
|
||||
|
|
@ -441,104 +313,78 @@ return {
|
|||
text = {
|
||||
"{C:attention}Small{} and {C:attention}Big Blinds{} are",
|
||||
"replaced with {C:attention}Boss Blinds",
|
||||
"that are {C:dark_edition}debuffed thrice",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
"that are {C:dark_edition}debuffed #1# times",
|
||||
},
|
||||
},
|
||||
sleeve_Roland_blossom_alt = {
|
||||
name = "Efflorescent Sleeve",
|
||||
text = {
|
||||
"{C:dark_edition}Debuff {X:dark_edition,C:white}#1#X<ante>{C:dark_edition} times",
|
||||
"{C:inactive}(Instead of thrice)",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
"{C:attention}Blinds{} are {C:dark_edition}debuffed",
|
||||
"{C:dark_edition}({X:dark_edition,C:white}ante{} {X:dark_edition,C:white}number{C:dark_edition}) times",
|
||||
"{C:inactive}(Instead of #1#)",
|
||||
},
|
||||
},
|
||||
sleeve_Roland_dropship = {
|
||||
name = "Dropship Sleeve",
|
||||
sleeve_Roland_go = {
|
||||
name = "Pass GO Sleeve",
|
||||
text = {
|
||||
"{C:attention}Jokers {}are {C:money}free",
|
||||
"and {C:attention}Perishable",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
"Start with a {C:attention}Credit Card",
|
||||
"Set money to {C:money}$0 {}when",
|
||||
"entering the shop",
|
||||
},
|
||||
unlock = {"Have exclusively", "{C:attention}Perishable Jokers"},
|
||||
},
|
||||
sleeve_Roland_dropship_alt = {
|
||||
name = "Business Sleeve",
|
||||
sleeve_Roland_go_alt = {
|
||||
name = "Free Parking Sleeve",
|
||||
text = {
|
||||
"{C:attention}Jokers {}are instead",
|
||||
"{C:dark_edition}Negative {}and {C:money}Rental",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
"Start with an additional",
|
||||
"{X:attention,C:white}#1#{C:attention} Credit Cards",
|
||||
},
|
||||
unlock = {"Have exclusively", "{C:attention}Perishable Jokers"},
|
||||
},
|
||||
sleeve_Roland_swapper = {
|
||||
name = "Swapper Sleeve",
|
||||
text = {
|
||||
"{C:tarot}Tarot {}and {C:spectral}Spectral",
|
||||
"cards swap places",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
},
|
||||
},
|
||||
sleeve_Roland_swapper_alt = {
|
||||
name = "Sleeve Swapper",
|
||||
text = {
|
||||
"Swap {C:attention}all {}consumables",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
"{C:attention}All {}consumable",
|
||||
"types swap places",
|
||||
},
|
||||
},
|
||||
sleeve_Roland_wish = {
|
||||
name = "Wish Sleeve",
|
||||
text = {
|
||||
"A random {C:attention}voucher{} is",
|
||||
"{C:attention}redeemed {}at the end",
|
||||
"of {C:attention}Small {}and {C:attention}Big Blinds",
|
||||
"{C:attention}Vouchers {}no longer",
|
||||
"appear in the shop",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
},
|
||||
unlock = {"Discover all {C:attention}Vouchers"},
|
||||
},
|
||||
sleeve_Roland_wish_alt = {
|
||||
name = "Miracle Sleeve",
|
||||
text = {
|
||||
"All {C:attention}vouchers",
|
||||
"start {C:attention}redeemed",
|
||||
"",
|
||||
"{C:Bakery_credit_fg_Roland_bakersdozenbagels,s:0.75}Art: BakersDozenBagels",
|
||||
},
|
||||
unlock = {"Discover all {C:attention}Vouchers"},
|
||||
},
|
||||
},
|
||||
Spectral = {
|
||||
c_Roland_afterimage = {
|
||||
name = "Afterimage",
|
||||
text = {
|
||||
"Add {C:dark_edition}Negative {}to {C:attention}#1#",
|
||||
"selected card in hand",
|
||||
"{C:red}#2#{} hand size",
|
||||
},
|
||||
},
|
||||
c_Roland_dual = {
|
||||
name = "Dual",
|
||||
text = {
|
||||
"Add random seals",
|
||||
"to {C:attention}#1#{} random",
|
||||
"cards in hand",
|
||||
"cards in {C:hands}hand",
|
||||
},
|
||||
},
|
||||
c_Roland_primal = {
|
||||
name = "Primal Force",
|
||||
c_Roland_coolheaded = {
|
||||
name = "Coolheaded",
|
||||
text = {
|
||||
"Enhance {C:attention}all {}cards",
|
||||
"held in hand to",
|
||||
"{C:enhanced}Stone Cards",
|
||||
"Add {C:dark_edition}Frozen {}to {C:attention}#1#",
|
||||
"selected {C:attention}playing",
|
||||
"{C:attention}card {}or {C:attention}Joker",
|
||||
},
|
||||
},
|
||||
c_Roland_refract = {
|
||||
name = "Refract",
|
||||
c_Roland_mirror = {
|
||||
name = "Mirror",
|
||||
text = {
|
||||
"Add a {C:dark_edition}Glass Seal",
|
||||
"Add a {C:dark_edition}Glass Tag",
|
||||
"to {C:attention}#1#{} selected",
|
||||
"cards in hand",
|
||||
"card in {C:hands}hand",
|
||||
},
|
||||
},
|
||||
c_Roland_void = {
|
||||
|
|
@ -550,47 +396,6 @@ return {
|
|||
},
|
||||
},
|
||||
},
|
||||
Tag = {
|
||||
tag_Roland_freeze = {
|
||||
name = "Freeze Tag",
|
||||
text = {"Apply {C:dark_edition}Frozen", "to the next {C:attention}#1#", "scored cards"},
|
||||
},
|
||||
tag_Roland_invisible = {
|
||||
name = "Invisible Tag",
|
||||
text = {
|
||||
"{C:attention}Duplicate {}a random",
|
||||
"Joker after {C:attention}#1#{} rounds",
|
||||
"{C:inactive}(Must have room)",
|
||||
"{C:inactive}(Currently {C:attention}#2#{C:inactive}/#1#)",
|
||||
},
|
||||
},
|
||||
},
|
||||
Tarot = {
|
||||
c_Roland_coolheaded = {
|
||||
name = "Coolheaded",
|
||||
text = {
|
||||
"Add {C:dark_edition}Frozen {}to {C:attention}#1#",
|
||||
"selected {C:attention}playing",
|
||||
"{C:attention}card {}or {C:attention}Joker",
|
||||
},
|
||||
},
|
||||
},
|
||||
Voucher = {
|
||||
v_Roland_ceres = {
|
||||
name = "Ceres",
|
||||
text = {
|
||||
"Level up {C:attention}Flush House",
|
||||
"by {C:attention}#1# {}when it is played",
|
||||
},
|
||||
},
|
||||
v_Roland_neptune = {
|
||||
name = "Neptune",
|
||||
text = {
|
||||
"Level up {C:attention}Straight Flush",
|
||||
"by {C:attention}#1# {}when it is played",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
misc = {
|
||||
challenge_names = {
|
||||
|
|
@ -599,38 +404,28 @@ return {
|
|||
c_Roland_Eternally_Crimson = "Eternally Crimson",
|
||||
c_Roland_Eternally_Verdant = "Eternally Verdant",
|
||||
c_Roland_Eternally_Violet = "Eternally Violet",
|
||||
c_Roland_Glass = "Glass House",
|
||||
c_Roland_Go = "Pass GO",
|
||||
c_Roland_Jokerful = "Jokerful",
|
||||
c_Roland_Ornate = "Ornate",
|
||||
c_Roland_Pastries = "Sweet Pastries",
|
||||
c_Roland_Spin_To_Win = "Spin to Win",
|
||||
c_Roland_Spring_Cleaning = "Spring Cleaning",
|
||||
c_Roland_Showdown = "Showdown",
|
||||
},
|
||||
v_dictionary = {
|
||||
b_Roland_add = "ADD",
|
||||
b_Roland_animated_icon = "Animated Icon (requires restart)",
|
||||
b_Roland_bye = "Bye!",
|
||||
b_Roland_comma = ", ",
|
||||
b_Roland_cool_phones = "cool phones (requires restart)",
|
||||
b_Roland_debuffed = "DEBUFFED",
|
||||
b_Roland_disabled = "Disabled",
|
||||
b_Roland_enabled = "Enabled",
|
||||
b_Roland_entering_shop = "Entering shop!",
|
||||
b_Roland_escape = "ESCAPE",
|
||||
b_Roland_fuse = "FUSE",
|
||||
b_Roland_equinox_assist = "Assist: Only hide text (Equinox)",
|
||||
b_Roland_faster_planets = "Faster Planets",
|
||||
b_Roland_frozen = "Frozen!",
|
||||
b_Roland_full = "FULL",
|
||||
b_Roland_scribable_basket = "Scribable Basket (overpowered)",
|
||||
b_Roland_fusable_escapey = "Fusable Escapey (overpowered)",
|
||||
b_Roland_harsh_ante_scaling = "Harsh ante scaling (Ante 40+)",
|
||||
b_Roland_illusion_seal = "Allow seals from Illusion voucher",
|
||||
b_Roland_import_funky = "Debug: Import funky.lua",
|
||||
b_Roland_most_common_card = "Rank",
|
||||
b_Roland_most_common_card = "(Rank)",
|
||||
b_Roland_no_highlight_limit = "No consumable highlight limit",
|
||||
b_Roland_no_wild_debuff = "No wild card debuffs",
|
||||
b_Roland_na = "N/A",
|
||||
b_Roland_of = " of ",
|
||||
b_Roland_toggle = "TOGGLE",
|
||||
b_Roland_unassigned = "(Unassigned)",
|
||||
b_Roland_vitriol = "Vitriol (Venerable Visage)",
|
||||
},
|
||||
labels = {
|
||||
Roland_frozen = "Frozen",
|
||||
|
|
@ -642,17 +437,15 @@ return {
|
|||
ch_c_Roland_Eternally_Crimson = {"{C:attention}Crimson Heart{}'s effect is active every blind"},
|
||||
ch_c_Roland_Eternally_Verdant = {"{C:attention}Verdant Leaf{}'s effect is active every blind"},
|
||||
ch_c_Roland_Eternally_Violet = {"{C:attention}Violet Vessel{}'s effect is active every blind"},
|
||||
ch_c_Roland_Glass1 = {"Played cards with no seal have a"},
|
||||
ch_c_Roland_Glass2 = {"{C:green}1 in 2{} chance to gain {C:dark_edition}Glass Seal"},
|
||||
ch_c_Roland_Go = {"Set money to {C:money}$0 {}when entering the shop"},
|
||||
ch_c_Roland_Jokerful = {"The only jokers are {C:mult}Joker{} and {C:chips}Ms. Joker"},
|
||||
ch_c_Roland_Ornate = {"Anything vanilla is banned"},
|
||||
ch_c_Roland_Pastries = {"All blinds, cards, and tags are of {C:gold}Bakery{} or {C:blue}Roland"},
|
||||
ch_c_Roland_Showdown = {"Showdown blinds are {C:attention}Venerable Visage"},
|
||||
ch_c_Roland_Showdown_Amber = {"Showdown blinds are {C:attention}Amber Acorn {}(stacks with above)"},
|
||||
ch_c_Roland_Showdown_Cerulean = {"Showdown blinds are {C:attention}Cerulean Bell {}(stacks with above)"},
|
||||
ch_c_Roland_Showdown_Crimson = {"Showdown blinds are {C:attention}Crimson Heart {}(stacks with above)"},
|
||||
ch_c_Roland_Showdown_Verdant = {"Showdown blinds are {C:attention}Verdant Leaf {}(stacks with above)"},
|
||||
ch_c_Roland_Showdown_Violet = {"Showdown blinds are {C:attention}Violet Vessel {}(stacks with above)"},
|
||||
ch_c_Roland_Spring_Cleaning = {"Earn {C:red}no money {}from sources other than {C:attention}Yard Sale"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
137
lovely.toml
|
|
@ -12,12 +12,12 @@ priority = -2
|
|||
target = "game.lua"
|
||||
pattern = "self.GAME.round_resets.blind_choices.Boss = get_new_boss()"
|
||||
position = "before"
|
||||
payload = """
|
||||
payload = '''
|
||||
if G.GAME.modifiers.Roland_blossom_deck then
|
||||
self.GAME.round_resets.blind_choices.Small = get_new_boss()
|
||||
self.GAME.round_resets.blind_choices.Big = get_new_boss()
|
||||
end
|
||||
"""
|
||||
'''
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
|
|
@ -25,12 +25,12 @@ match_indent = true
|
|||
target = "functions/common_events.lua"
|
||||
pattern = "G.GAME.round_resets.blind_choices.Boss = get_new_boss()"
|
||||
position = "before"
|
||||
payload = """
|
||||
payload = '''
|
||||
if G.GAME.modifiers.Roland_blossom_deck then
|
||||
G.GAME.round_resets.blind_choices.Small = get_new_boss()
|
||||
G.GAME.round_resets.blind_choices.Big = get_new_boss()
|
||||
end
|
||||
"""
|
||||
'''
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
|
|
@ -65,19 +65,6 @@ position = "at"
|
|||
payload = "elseif G.GAME.blind_on_deck == 'Big' then"
|
||||
match_indent = true
|
||||
|
||||
# Prevent Incantation from overriding Faster Planets
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = '=[SMODS incantation "Incantation.lua"]'
|
||||
pattern = "function Card:use_consumeable(area, copier)"
|
||||
position = "after"
|
||||
payload = """if SMODS.Mods.Roland.config.faster_planets and
|
||||
self.ability.consumeable.hand_type then
|
||||
return useconsumeref(self, area, copier)
|
||||
end"""
|
||||
match_indent = true
|
||||
|
||||
# Misfortune Cookie
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = "card.lua"
|
||||
|
|
@ -95,120 +82,6 @@ pattern = "local card = create_card('Tarot',G.consumeables, nil, nil, nil, nil,
|
|||
position = "after"
|
||||
times = 1
|
||||
payload = """if next(SMODS.find_card "j_Roland_misfortune") then
|
||||
card:set_edition("e_negative", true, true)
|
||||
card:set_edition "e_negative"
|
||||
end"""
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = "card.lua"
|
||||
pattern = "if self.seal == 'Blue' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and not self.ability.extra_enhancement then"
|
||||
position = "at"
|
||||
payload = """if self.seal == 'Blue' and
|
||||
(next(SMODS.find_card "j_Roland_misfortune") or
|
||||
#G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and
|
||||
not self.ability.extra_enhancement) then
|
||||
"""
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = "card.lua"
|
||||
pattern = "local card = create_card(card_type,G.consumeables, nil, nil, nil, nil, _planet, 'blusl')"
|
||||
position = "after"
|
||||
payload = """if next(SMODS.find_card "j_Roland_misfortune") then
|
||||
card:set_edition("e_negative", true, true)
|
||||
end"""
|
||||
match_indent = true
|
||||
|
||||
# Frozen
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = "card.lua"
|
||||
pattern = """if self.ability.name == 'Throwback' then
|
||||
self.ability.x_mult = 1 + G.GAME.skips*self.ability.extra
|
||||
end
|
||||
if self.ability.name == "Driver's License" then"""
|
||||
position = "at"
|
||||
payload = """if self.ability.name == 'Throwback' then
|
||||
self.ability.x_mult = 1 + G.GAME.skips*self.ability.extra
|
||||
end
|
||||
if self.ability.name == "Driver's License" and not (self.edition and self.edition.Roland_frozen) then"""
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = "card.lua"
|
||||
pattern = """if self.ability.name == "Steel Joker" then"""
|
||||
position = "at"
|
||||
payload = """if self.ability.name == "Steel Joker" and not (self.edition and self.edition.Roland_frozen) then"""
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = "card.lua"
|
||||
pattern = """if self.ability.name == "Cloud 9" then"""
|
||||
position = "at"
|
||||
payload = """if self.ability.name == "Cloud 9" and not (self.edition and self.edition.Roland_frozen) then"""
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = "card.lua"
|
||||
pattern = """if self.ability.name == "Stone Joker" then"""
|
||||
position = "at"
|
||||
payload = """if self.ability.name == "Stone Joker" and not (self.edition and self.edition.Roland_frozen) then"""
|
||||
match_indent = true
|
||||
|
||||
[[patches]]
|
||||
[patches.regex]
|
||||
target = "card.lua"
|
||||
pattern = "math\\.floor\\(\\(G\\.GAME\\.dollars \\+ \\(G\\.GAME\\.dollar_buffer or 0\\)\\)/self\\.ability\\.extra\\.dollars\\)"
|
||||
position = "at"
|
||||
payload = "SMODS.Mods.Roland.bootstraps_mult(self)"
|
||||
|
||||
[[patches]]
|
||||
[patches.regex]
|
||||
target = "card.lua"
|
||||
pattern = "if self\\.ability\\.h_size ~= 0 then"
|
||||
position = "at"
|
||||
payload = "if self.ability.h_size and self.ability.h_size ~= 0 then"
|
||||
|
||||
[[patches]]
|
||||
[patches.regex]
|
||||
target = "card.lua"
|
||||
pattern = "if self\\.ability\\.d_size > 0 then"
|
||||
position = "at"
|
||||
payload = "if self.ability.d_size and self.ability.d_size > 0 then"
|
||||
|
||||
[[patches]]
|
||||
[patches.pattern]
|
||||
target = '=[SMODS _ "src/utils.lua"]'
|
||||
pattern = "value = value + card.ability[property]"
|
||||
position = "at"
|
||||
payload = "value = value + (card.ability[property] or 0)"
|
||||
match_indent = true
|
||||
|
||||
# [[patches]]
|
||||
# [patches.pattern]
|
||||
# target = '=[SMODS DebugPlus "debugplus/console.lua"]'
|
||||
# pattern = "if toCheck == '/' or toCheck == 'kp/' then"
|
||||
# position = "at"
|
||||
# payload = "if toCheck == '/' or toCheck == 'kp/' or toCheck == 'f' then"
|
||||
# match_indent = true
|
||||
|
||||
# [[patches]]
|
||||
# [patches.pattern]
|
||||
# target = '=[SMODS DebugPlus "debugplus/console.lua"]'
|
||||
# pattern = 'local cmdName = string.lower(string.gsub(inputText, "^(%S+).*", "%1"))'
|
||||
# position = "at"
|
||||
# payload = 'local cmdName = "eval"'
|
||||
# match_indent = true
|
||||
|
||||
# [[patches]]
|
||||
# [patches.pattern]
|
||||
# target = '=[SMODS DebugPlus "debugplus/console.lua"]'
|
||||
# pattern = 'local rawArgs = string.gsub(inputText, "^%S+%s*(.*)", "%1")'
|
||||
# position = "at"
|
||||
# payload = 'local cmdName = inputText'
|
||||
# match_indent = true
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@
|
|||
"id": "Roland",
|
||||
"name": "Roland",
|
||||
"prefix": "Roland",
|
||||
"version": "3.0.2",
|
||||
"badge_colour": "8BE9FD",
|
||||
"display_name": "Roland",
|
||||
"main_file": "src/main.lua",
|
||||
"badge_text_colour": "44475A",
|
||||
"description": "Adds mechanics that are meant to have interesting interactions with the base game. Not meant to be balanced, but not entirely broken either.",
|
||||
"provides": [],
|
||||
"conflicts": [],
|
||||
"author": [
|
||||
"Emik"
|
||||
],
|
||||
"version": "2.2.0",
|
||||
"badge_colour": "8BE9FD",
|
||||
"main_file": "src/main.lua",
|
||||
"badge_text_colour": "44475A",
|
||||
"display_name": "Roland",
|
||||
"description": "Adds several disconnected funny ideas I had in my head that I couldn't resist implementing in the game.",
|
||||
"provides": [],
|
||||
"conflicts": [],
|
||||
"dependencies": [
|
||||
"Steamodded (>=1.0.0~BETA-1606b)",
|
||||
"Steamodded (>=1.*)",
|
||||
"Lovely (>=0.6)",
|
||||
"Bakery (>=3.2.0~*)"
|
||||
"Bakery (>=1.3.2~*)"
|
||||
]
|
||||
}
|
||||
1
refs/src
|
|
@ -1 +0,0 @@
|
|||
../../smods/src
|
||||
280
src/back.lua
|
|
@ -1,4 +1,4 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
local f, q = unpack(... or require "lib.shared")
|
||||
|
||||
local function save(ret)
|
||||
q(save_run)
|
||||
|
|
@ -8,7 +8,7 @@ end
|
|||
local back = (function()
|
||||
local x = 0
|
||||
|
||||
---@param tbl SMODS.Back|{attributes?: Attributes[], pronouns: string, is_alt: (fun(self: self): boolean), alt_apply?: fun(self: SMODS.Back|table, back: Back|table), alt_calculate?: fun(self: SMODS.Back|table, back: Back|table, context: CalcContext|table): table?, boolean?}
|
||||
---@param tbl SMODS.Back|{is_alt: function, alt_apply?: fun(self: SMODS.Back|table, back: Back|table), alt_calculate?: fun(self: SMODS.Back|table, back: Back|table, context: CalcContext|table): table?, boolean?}
|
||||
return function(tbl)
|
||||
local key = tbl.key
|
||||
local apply = tbl.apply
|
||||
|
|
@ -23,16 +23,27 @@ local back = (function()
|
|||
end
|
||||
|
||||
tbl.pos = {x = x, y = 0}
|
||||
tbl.is_alt = f.fals
|
||||
tbl.atlas = "back"
|
||||
x = x + 1
|
||||
local back = q(SMODS.Back(tbl))
|
||||
|
||||
local _ = CardSleeves and CardSleeves.Sleeve {
|
||||
-- This API intends that you share the same functions for apply/calculate,
|
||||
-- meaning that this may be called to check if a deck/sleeve combo is used even
|
||||
-- when we are from the deck context. We add this to prevent accidental calls to nil.
|
||||
function tbl:is_alt()
|
||||
return false
|
||||
end
|
||||
|
||||
local sleeve = (_G["CardSleeves"] or {}).Sleeve
|
||||
SMODS.Back(tbl)
|
||||
x = x + 1
|
||||
|
||||
if not sleeve then
|
||||
return
|
||||
end
|
||||
|
||||
sleeve {
|
||||
key = key,
|
||||
pos = tbl.pos,
|
||||
atlas = "sleeve",
|
||||
pronouns = tbl.pronouns,
|
||||
atlas = "back",
|
||||
config = tbl.config and f(tbl.config):table() or nil,
|
||||
loc_vars = function(self, ...)
|
||||
local ret = tbl.loc_vars and tbl.loc_vars(self, ...) or {}
|
||||
|
|
@ -40,7 +51,7 @@ local back = (function()
|
|||
return ret
|
||||
end,
|
||||
apply = function(self, ...)
|
||||
return save((tbl.alt_apply and self:is_alt() and tbl.alt_apply or apply)(self, ...))
|
||||
return (tbl.alt_apply and self:is_alt() and tbl.alt_apply or apply)(self, ...)
|
||||
end,
|
||||
calculate = function(self, ...)
|
||||
return (tbl.alt_calculate and self:is_alt() and tbl.alt_calculate or calculate)(self, ...)
|
||||
|
|
@ -49,176 +60,115 @@ local back = (function()
|
|||
return self.get_current_deck_key() == "b_Roland_" .. key
|
||||
end,
|
||||
}
|
||||
|
||||
return back
|
||||
end
|
||||
end)()
|
||||
|
||||
local back_atlas = SMODS.Atlas {
|
||||
SMODS.Atlas {
|
||||
key = "back",
|
||||
path = "back.png",
|
||||
px = 71,
|
||||
py = 95,
|
||||
}
|
||||
|
||||
local extra_atlas = SMODS.Atlas {
|
||||
key = "back_extra",
|
||||
path = "backExtra.png",
|
||||
px = 71,
|
||||
py = 95,
|
||||
}
|
||||
|
||||
local _ = CardSleeves and SMODS.Atlas {
|
||||
key = "sleeve",
|
||||
path = "sleeve.png",
|
||||
px = 73,
|
||||
py = 95,
|
||||
}
|
||||
|
||||
back {
|
||||
key = "blossom",
|
||||
pronouns = "any_all",
|
||||
config = {extra = {alt_times = 9, times = 3}},
|
||||
attributes = {"passive", "boss_blind"},
|
||||
loc_vars = function(self)
|
||||
return {vars = {self.config.extra.alt_times}}
|
||||
config = {extra = {times = 2}},
|
||||
loc_vars = function(self, _, _)
|
||||
return {vars = {self.config.extra.times}}
|
||||
end,
|
||||
apply = function()
|
||||
apply = function(_, _)
|
||||
G.GAME.modifiers.Roland_blossom_deck = true
|
||||
end,
|
||||
calculate = function(self, b, context)
|
||||
if not context.forcetrigger and not context.setting_blind then
|
||||
calculate = function(self, card, context)
|
||||
if not context.setting_blind then
|
||||
return
|
||||
end
|
||||
|
||||
local blinds = G.GAME.round_resets.blind_states
|
||||
|
||||
if not context.forcetrigger and
|
||||
blinds.Small ~= "Current" and
|
||||
blinds.Big ~= "Current" then
|
||||
if blinds.Small ~= "Current" and blinds.Big ~= "Current" then
|
||||
return
|
||||
end
|
||||
|
||||
local function debuff(times)
|
||||
return function()
|
||||
if times <= 0 then
|
||||
return
|
||||
end
|
||||
local count = self:is_alt() and G.GAME.round_resets.ante or self.config.extra.times
|
||||
|
||||
for _ = 1, count do
|
||||
G.GAME.blind:disable()
|
||||
SMODS.calculate_effect({message = localize "ph_boss_disabled"}, b)
|
||||
|
||||
q {
|
||||
delay = 0.4,
|
||||
func = function()
|
||||
SMODS.calculate_effect({message = localize "ph_boss_disabled"}, card)
|
||||
G.GAME.blind:wiggle()
|
||||
play_sound "timpani"
|
||||
q {func = debuff(times - 1)}
|
||||
end,
|
||||
}
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
back {
|
||||
key = "go",
|
||||
pronouns = "he_him",
|
||||
config = {extra = {times = 1, alt_times = 5}},
|
||||
loc_vars = function(self, info_queue, _)
|
||||
local _ = info_queue and table.insert(info_queue, G.P_CENTERS.j_credit_card)
|
||||
return {vars = {self.config.extra.alt_times - self.config.extra.times}}
|
||||
end,
|
||||
apply = function(self)
|
||||
q(function()
|
||||
local count = self:is_alt() and self.config.extra.alt_times or self.config.extra.times
|
||||
|
||||
for _ = 1, count do
|
||||
local c = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_credit_card", "Roland_go")
|
||||
c:add_to_deck()
|
||||
c:start_materialize()
|
||||
G.jokers:emplace(c)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
calculate = function(_, card, context)
|
||||
if not context.starting_shop then
|
||||
return
|
||||
end
|
||||
|
||||
local times = self:is_alt() and
|
||||
G.GAME.round_resets.ante * self.config.extra.alt_times or
|
||||
self.config.extra.times
|
||||
ease_dollars(-G.GAME.dollars)
|
||||
|
||||
debuff(times)()
|
||||
attention_text {
|
||||
text = localize "k_nope_ex",
|
||||
backdrop_colour = G.C.MONEY,
|
||||
offset = {x = 0, y = 0},
|
||||
silent = true,
|
||||
major = card,
|
||||
align = "cm",
|
||||
scale = 1.3,
|
||||
hold = 1.4,
|
||||
}
|
||||
end,
|
||||
}
|
||||
|
||||
back {
|
||||
key = "swapper",
|
||||
pronouns = "he_him",
|
||||
attributes = {"passive", "editions", "sell_value"},
|
||||
apply = function(self)
|
||||
local modifiers = G.GAME.modifiers
|
||||
modifiers.Roland_swapper_deck = true
|
||||
modifiers.Roland_alt_swapper_deck = modifiers.Roland_alt_swapper_deck or self:is_alt()
|
||||
end,
|
||||
calculate = f.noop,
|
||||
}
|
||||
|
||||
local b_dropship = back {
|
||||
key = "dropship",
|
||||
pronouns = "he_him",
|
||||
attributes = {"passive", "generation"},
|
||||
unlocked = false,
|
||||
discovered = false,
|
||||
check_for_unlock = function(_, args)
|
||||
return args ~= "Bakery_nothing" and
|
||||
G.jokers and
|
||||
next((G.jokers or {}).cards) and
|
||||
not not f(G.jokers.cards):map "ability":all "perishable"
|
||||
end,
|
||||
apply = function(self)
|
||||
G.GAME.modifiers.Roland_dropship = not self:is_alt()
|
||||
G.GAME.modifiers.Roland_dropship_alt = self:is_alt()
|
||||
end,
|
||||
calculate = f.noop,
|
||||
}
|
||||
|
||||
local dropship_tape
|
||||
|
||||
q {
|
||||
blocking = false,
|
||||
no_delete = true,
|
||||
func = function()
|
||||
dropship_tape = SMODS.create_sprite(0, 0, G.CARD_W, G.CARD_H, extra_atlas, {x = 0, y = 0})
|
||||
end,
|
||||
}
|
||||
|
||||
SMODS.DrawStep {
|
||||
key = "dropship_tape",
|
||||
order = 5,
|
||||
conditions = {vortex = false, facing = "back"},
|
||||
func = function(self)
|
||||
if self.children.back.atlas ~= back_atlas or self.children.back.sprite_pos.x ~= b_dropship.pos.x then
|
||||
return
|
||||
end
|
||||
|
||||
dropship_tape.role.draw_major = self
|
||||
local deck = self.area.config.type == "deck"
|
||||
local sticker_offset = self.sticker_offset or {}
|
||||
|
||||
-- Don't draw dissolve since it's baked into the sprite already. Also, I had to boost its alpha for the
|
||||
-- shine to look correct, so drawing this would look *awful*.
|
||||
-- dropship_tape:draw_shader("dissolve", nil, nil, deck, self.children.center, self.sticker_rotation, sticker_offset.x, sticker_offset.y)
|
||||
dropship_tape:draw_shader(
|
||||
"voucher",
|
||||
nil,
|
||||
self.ARGS.send_to_shader,
|
||||
deck,
|
||||
self.children.center,
|
||||
self.sticker_rotation,
|
||||
sticker_offset.x,
|
||||
sticker_offset.y
|
||||
)
|
||||
end,
|
||||
calculate = function() end,
|
||||
}
|
||||
|
||||
local swapper = {Spectral = "Tarot", Tarot = "Spectral"}
|
||||
local orig_create_card = create_card
|
||||
|
||||
local function create_dropshipped_card(_type, ...)
|
||||
local ret = orig_create_card(_type, ...)
|
||||
local ok = _type == "Joker" and ret.ability
|
||||
|
||||
if ok and G.GAME.modifiers.Roland_dropship_alt then
|
||||
ret.ability.rental = true
|
||||
local _ = ret:set_edition({negative = true}, true, true)
|
||||
end
|
||||
|
||||
if ok and G.GAME.modifiers.Roland_dropship then
|
||||
ret.ability.perish_tally = 5
|
||||
ret.ability.perishable = true
|
||||
ret.cost, ret.sell_cost = 0, 0
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function create_card(_type, ...)
|
||||
if not G.GAME.modifiers.Roland_swapper_deck then
|
||||
return create_dropshipped_card(_type, ...)
|
||||
return orig_create_card(_type, ...)
|
||||
end
|
||||
|
||||
if not G.GAME.modifiers.Roland_alt_swapper_deck then
|
||||
return create_dropshipped_card(swapper[_type] or _type, ...)
|
||||
return orig_create_card(swapper[_type] or _type, ...)
|
||||
end
|
||||
|
||||
local type = f(SMODS.ConsumableTypes):keys():where(function(v)
|
||||
|
|
@ -226,79 +176,5 @@ function create_card(_type, ...)
|
|||
end):table()
|
||||
|
||||
local has_type = SMODS.ConsumableTypes[_type]
|
||||
return create_dropshipped_card(
|
||||
has_type and pseudorandom_element(type, pseudoseed "Roland_alt_swapper_deck") or _type, ...)
|
||||
end
|
||||
|
||||
local function redeem(key, fast)
|
||||
if fast then
|
||||
G.GAME.used_vouchers[key] = true
|
||||
end
|
||||
|
||||
q {
|
||||
delay = 1,
|
||||
func = function()
|
||||
local voucher = SMODS.create_card {key = key, set = "Voucher"}
|
||||
voucher.cost = 0
|
||||
voucher.T.x = (fast and pseudorandom(pseudoseed "Roland_wish_deck") + 0.5 or 1) * 9
|
||||
voucher.T.y = (fast and pseudorandom(pseudoseed "Roland_wish_deck") + 0.5 or 1) * 4.25
|
||||
voucher:start_materialize()
|
||||
|
||||
q {
|
||||
delay = 1,
|
||||
func = function()
|
||||
if fast then
|
||||
play_sound "card1"
|
||||
voucher:apply_to_run()
|
||||
voucher:juice_up(0.3, 0.5)
|
||||
else
|
||||
local state = G.STATE
|
||||
voucher:redeem()
|
||||
G.STATE = state
|
||||
end
|
||||
|
||||
q {
|
||||
delay = 1,
|
||||
func = function()
|
||||
voucher:start_dissolve()
|
||||
end,
|
||||
}
|
||||
end,
|
||||
}
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
back {
|
||||
key = "wish",
|
||||
pronouns = "he_him",
|
||||
attributes = {"passive", "generation"},
|
||||
unlocked = false,
|
||||
discovered = false,
|
||||
check_for_unlock = function(_, args)
|
||||
return args ~= "Bakery_nothing" and f(G.P_CENTER_POOLS.Voucher):all "discovered"
|
||||
end,
|
||||
apply = function(self)
|
||||
G.GAME.modifiers.Roland_no_voucher = true
|
||||
local _ = self:is_alt() and f(G.P_CENTER_POOLS.Voucher):map "key":each(redeem)
|
||||
end,
|
||||
calculate = function(_, _, context)
|
||||
local _ = (context.forcetrigger or
|
||||
context.blind_defeated and
|
||||
not context.repetition and
|
||||
not G.GAME.blind.boss) and
|
||||
f(G.P_CENTER_POOLS.Voucher)
|
||||
:map "key"
|
||||
:where(f.index_into(G.GAME.used_vouchers), false)
|
||||
:any() and
|
||||
redeem(get_next_voucher_key())
|
||||
end,
|
||||
}
|
||||
|
||||
local orig_add_voucher_to_shop = SMODS.add_voucher_to_shop
|
||||
|
||||
function SMODS.add_voucher_to_shop(...)
|
||||
if not G.GAME.modifiers.Roland_no_voucher then
|
||||
return orig_add_voucher_to_shop(...)
|
||||
end
|
||||
return orig_create_card(has_type and pseudorandom_element(type, pseudoseed "Roland_alt_swapper_deck") or _type, ...)
|
||||
end
|
||||
|
|
|
|||
215
src/blind.lua
|
|
@ -1,16 +1,16 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
local f, q = unpack(... or require "lib.shared")
|
||||
|
||||
local blind = (function()
|
||||
local y = 0
|
||||
|
||||
---@param tbl SMODS.Blind|{idea?: string}
|
||||
---@param tbl SMODS.Blind
|
||||
---@return SMODS.Blind
|
||||
return function(tbl)
|
||||
tbl.idea = tbl.idea and "Roland_" .. tbl.idea or nil
|
||||
tbl.pos = {x = 0, y = y}
|
||||
tbl.atlas = "blind"
|
||||
local ret = SMODS.Blind(tbl)
|
||||
y = y + 1
|
||||
return q(SMODS.Blind(tbl))
|
||||
return ret
|
||||
end
|
||||
end)()
|
||||
|
||||
|
|
@ -23,12 +23,18 @@ SMODS.Atlas {
|
|||
atlas_table = "ANIMATION_ATLAS",
|
||||
}
|
||||
|
||||
SMODS.Sound {key = "kick", path = "kick.ogg"}
|
||||
SMODS.Sound {
|
||||
key = "kick",
|
||||
path = "kick.ogg",
|
||||
}
|
||||
|
||||
local function common_rank()
|
||||
---@type { [integer]: integer }, { [integer]: string }
|
||||
local tally, to_name = {}, {}
|
||||
|
||||
f(G.playing_cards):where(SMODS.has_no_rank, false):each(function(v)
|
||||
f(G.playing_cards):where(function(v)
|
||||
return not SMODS.has_no_rank(v)
|
||||
end):each(function(v)
|
||||
local id = v:get_id()
|
||||
to_name[id] = v.base.value
|
||||
tally[id] = (tally[id] or 0) + 1
|
||||
|
|
@ -52,7 +58,7 @@ end
|
|||
|
||||
local function has_enhancement(card)
|
||||
local e = SMODS.get_enhancements(card)
|
||||
return e and next(e)
|
||||
return not not (e and next(e))
|
||||
end
|
||||
|
||||
local function set_freeze(state)
|
||||
|
|
@ -62,10 +68,6 @@ local function set_freeze(state)
|
|||
|
||||
---@param card Card|{ Roland_blizzard: true|nil }
|
||||
return function(card)
|
||||
if not card.Roland_blizzard and card.edition and card.edition.Roland_frozen then
|
||||
return
|
||||
end
|
||||
|
||||
local last_edition = card.Roland_blizzard
|
||||
card.Roland_blizzard = state and (copy(card.edition) or true) or nil
|
||||
|
||||
|
|
@ -163,7 +165,7 @@ blind {
|
|||
local _ = not b.disabled and context.drawing_cards and table.sort(G.deck.cards, sort_by_enhancement)
|
||||
end,
|
||||
in_pool = function()
|
||||
return G.playing_cards and not not f(G.playing_cards):any(has_enhancement)
|
||||
return G.playing_cards and f(G.playing_cards):any(has_enhancement)
|
||||
end,
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +176,13 @@ blind {
|
|||
pronouns = "he_they",
|
||||
disable = function()
|
||||
-- Ensures that this runs after 'set_blind' since it also gets added to queue.
|
||||
q {delay = 0.8, trigger = "after", func = G.FUNCS.draw_from_discard_to_deck}
|
||||
q {
|
||||
delay = 0.8,
|
||||
trigger = "after",
|
||||
func = function()
|
||||
G.FUNCS.draw_from_discard_to_deck()
|
||||
end,
|
||||
}
|
||||
end,
|
||||
set_blind = function()
|
||||
-- Allows the background to ease in first before drawing cards.
|
||||
|
|
@ -216,10 +224,6 @@ blind {
|
|||
draw_card(G.hand, G.discard, i / count * 100, "down", false, copy, nil, nil, true)
|
||||
end)
|
||||
|
||||
if not next(cards_added) then
|
||||
return
|
||||
end
|
||||
|
||||
b:wiggle()
|
||||
b.triggered = true
|
||||
playing_card_joker_effects(cards_added)
|
||||
|
|
@ -228,27 +232,25 @@ blind {
|
|||
|
||||
blind {
|
||||
key = "blizzard",
|
||||
idea = "redstoad",
|
||||
boss = {min = 3},
|
||||
boss_colour = HEX "102a41ff",
|
||||
pronouns = "it_its",
|
||||
defeat = function(self)
|
||||
self.cards():where "Roland_blizzard":each(set_freeze())
|
||||
self.cards():each(set_freeze())
|
||||
G.GAME.blind.disabled = true
|
||||
end,
|
||||
disable = function(self)
|
||||
self:defeat()
|
||||
end,
|
||||
calculate = function(self, b, context)
|
||||
return not b.disabled and
|
||||
context.hand_drawn and
|
||||
self.cards()
|
||||
:where("Roland_blizzard", false)
|
||||
:where("facing", "front")
|
||||
:each(set_freeze(true)) or nil
|
||||
calculate = function(self, b)
|
||||
return not b.disabled and self.cards():where(function(v)
|
||||
return not v.Roland_blizzard and v.facing == "front"
|
||||
end):each(set_freeze(true)) or nil
|
||||
end,
|
||||
cards = function()
|
||||
return f(G):where(getmetatable, CardArea):flatmap("cards", ipairs)
|
||||
return f(G):where(function(v)
|
||||
return type(v) == "table" and type(v.cards) == "table"
|
||||
end):flatmap("cards", ipairs)
|
||||
end,
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +259,7 @@ blind {
|
|||
boss = {min = 6},
|
||||
boss_colour = HEX "bdaeccff",
|
||||
pronouns = "they_them",
|
||||
collection_loc_vars = function()
|
||||
collection_loc_vars = function(_)
|
||||
return {
|
||||
vars = {localize {
|
||||
type = "variable",
|
||||
|
|
@ -265,7 +267,7 @@ blind {
|
|||
}},
|
||||
}
|
||||
end,
|
||||
loc_vars = function()
|
||||
loc_vars = function(_)
|
||||
local _, name = common_rank()
|
||||
return {vars = {localize(name or "Ace", "ranks")}}
|
||||
end,
|
||||
|
|
@ -299,12 +301,9 @@ blind {
|
|||
b:set_text()
|
||||
end
|
||||
end,
|
||||
disable = function()
|
||||
G.GAME.blind.disabled = true
|
||||
end,
|
||||
recalc_debuff = function(self, card)
|
||||
local id, _ = common_rank()
|
||||
local ret = not G.GAME.blind.disabled and id == card:get_id()
|
||||
local ret = not self.disabled and id == card:get_id()
|
||||
self.triggered = ret
|
||||
return ret
|
||||
end,
|
||||
|
|
@ -319,7 +318,7 @@ blind {
|
|||
dollars = 5,
|
||||
defeat = disable_improbable,
|
||||
disable = disable_improbable,
|
||||
set_blind = function()
|
||||
set_blind = function(_)
|
||||
G.GAME.modifiers.Roland_improbable = true
|
||||
end,
|
||||
}
|
||||
|
|
@ -332,65 +331,15 @@ if cry_prob then
|
|||
end
|
||||
end
|
||||
|
||||
local function call(key, value)
|
||||
local obj = G[key .. "obj"]
|
||||
local _ = type(obj) == "function" and obj(value)
|
||||
|
||||
if not G[key] or value == "Bakery_nothing" then
|
||||
return
|
||||
end
|
||||
|
||||
if type(G[key]) == "function" then
|
||||
G[key] = {G[key]}
|
||||
end
|
||||
|
||||
if type(G[key]) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
local str
|
||||
|
||||
local _ = f(type(value) == "table" and value or {[value] = true})
|
||||
:keys()
|
||||
:map(f.index_into(G[key]))
|
||||
:where(type, "function")
|
||||
:each(function(v)
|
||||
str = str or type(value) == "table" and f(value):keys():string() or value
|
||||
v(str)
|
||||
end)
|
||||
|
||||
local _ = not str and
|
||||
type(G[key][1]) == "function" and
|
||||
G[key][1](type(value) == "table" and f(value):keys():string() or value)
|
||||
end
|
||||
|
||||
local orig_check_for_unlock = check_for_unlock
|
||||
|
||||
function check_for_unlock(args, ...)
|
||||
call("lock", type(args) == "table" and args.type or args)
|
||||
return orig_check_for_unlock(args, ...)
|
||||
end
|
||||
|
||||
function SMODS.current_mod:calculate(context)
|
||||
call("calc", context)
|
||||
|
||||
local _ = context.before and
|
||||
f {"v_Roland_ceres", "v_Roland_neptune"}
|
||||
:where(f.index_into(G.GAME.used_vouchers))
|
||||
:map(f.index_into(G.P_CENTERS))
|
||||
:where("config.extra.hand_type", context.scoring_name)
|
||||
:pun "SMODS.Voucher"
|
||||
:each(function(v)
|
||||
SMODS.smart_level_up_hand(nil, v.config.extra.hand_type, false, v.config.extra.amount)
|
||||
end)
|
||||
if context.setting_blind and G.GAME.blind.name == "bl_mp_nemesis" then
|
||||
local modifiers = G.GAME.modifiers
|
||||
modifiers.Roland_martingale_seed = (modifiers.Roland_martingale_seed or 0) + 1
|
||||
end
|
||||
|
||||
local _ = type(G.calc) == "function" and G.calc(f(context):keys():string())
|
||||
local improbable, orig = G.GAME.modifiers.Roland_improbable, G.GAME.probabilities
|
||||
|
||||
local _ = context.end_of_round and
|
||||
context.main_eval and
|
||||
not context.blueprint and
|
||||
G.P_TAGS.tag_Roland_invisible.increment()
|
||||
|
||||
-- Normally unreachable since we set it to nil ourselves,
|
||||
-- but other mods may want to use this modifier.
|
||||
if improbable == false then
|
||||
|
|
@ -404,7 +353,7 @@ function SMODS.current_mod:calculate(context)
|
|||
|
||||
local normal = orig.normal
|
||||
|
||||
G.GAME.probabilities = setmetatable({}, {
|
||||
local mt = {
|
||||
orig = orig,
|
||||
__index = function(_, k)
|
||||
return k == "normal" and 0 or orig[k]
|
||||
|
|
@ -412,7 +361,11 @@ function SMODS.current_mod:calculate(context)
|
|||
__newindex = function(_, k, v)
|
||||
orig[k] = (k == "normal" and v == 0) and normal or v
|
||||
end,
|
||||
})
|
||||
}
|
||||
|
||||
local proxy = {}
|
||||
setmetatable(proxy, mt)
|
||||
G.GAME.probabilities = proxy
|
||||
end
|
||||
|
||||
blind {
|
||||
|
|
@ -501,31 +454,15 @@ local venerable_visage = blind {
|
|||
}
|
||||
end,
|
||||
vitriol = function(b)
|
||||
local vitriol = SMODS.Mods.Roland.config.vitriol
|
||||
local resize_to_w, resize_to_h = 320, 200
|
||||
local is_fullscreen = love.window.getFullscreen()
|
||||
|
||||
if vitriol then
|
||||
love.window.setFullscreen(false)
|
||||
delay(1.5)
|
||||
end
|
||||
|
||||
local function jitter()
|
||||
local x, y = love.window.getDesktopDimensions()
|
||||
|
||||
return pseudorandom(pseudoseed "RolandVenerableVisageX", 0, x) - x / 2,
|
||||
pseudorandom(pseudoseed "RolandVenerableVisageY", 0, y) - y / 2
|
||||
end
|
||||
|
||||
if type(b) == "table" and type(b.wiggle) == "function" then
|
||||
b:wiggle()
|
||||
end
|
||||
|
||||
f(G.playing_cards):each(function(v, k)
|
||||
return v.area ~= G.hand and draw_card(v.area, G.hand, k * 100 / #G.playing_cards, "up", true, v)
|
||||
end)
|
||||
|
||||
local fail = G.localization.descriptions.Blind.bl_Roland_venerable_visage.fail
|
||||
local speed = 0.1
|
||||
|
||||
SMODS.draw_cards(#G.deck.cards)
|
||||
play_sound("gong", 0.6)
|
||||
|
||||
attention_text {
|
||||
text = pseudorandom_element(fail, pseudoseed "RolandVenerableVisage"),
|
||||
|
|
@ -535,50 +472,46 @@ local venerable_visage = blind {
|
|||
hold = 2,
|
||||
}
|
||||
|
||||
f {0.15, 0.3, 0.45, 0.6}:each(function(v)
|
||||
play_sound("gong", v)
|
||||
end)
|
||||
delay(1)
|
||||
|
||||
---@type number, number, table
|
||||
local w, h, flags = love.window.getMode()
|
||||
local len = #G.playing_cards
|
||||
|
||||
if vitriol then
|
||||
love.window.setMode(resize_to_w, resize_to_h)
|
||||
love.resize(resize_to_w, resize_to_h)
|
||||
end
|
||||
|
||||
local x, y = love.window.getPosition()
|
||||
|
||||
f(G.playing_cards):each(function(v, i)
|
||||
f(G.playing_cards):each(function(v)
|
||||
q {
|
||||
trigger = "before",
|
||||
delay = 6 / len,
|
||||
delay = speed,
|
||||
func = function()
|
||||
if vitriol then
|
||||
local x_random, y_random = jitter()
|
||||
love.window.setPosition(x + x_random * i / len, y + y_random * i / len)
|
||||
end
|
||||
|
||||
v:start_dissolve()
|
||||
v:shatter()
|
||||
b:wiggle()
|
||||
end,
|
||||
}
|
||||
end)
|
||||
|
||||
local _ = vitriol and q {
|
||||
trigger = "before",
|
||||
delay = 1.5,
|
||||
delay(1)
|
||||
|
||||
f(G.P_CARDS):each(function(v)
|
||||
q {
|
||||
delay = speed,
|
||||
func = function()
|
||||
love.window.setPosition(x, y)
|
||||
love.window.setMode(w, h, flags)
|
||||
love.resize(w, h)
|
||||
love.window.setFullscreen(is_fullscreen)
|
||||
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
|
||||
|
||||
local card = Card(
|
||||
b and b.T.x or 0,
|
||||
b and b.T.y or 0,
|
||||
G.CARD_W,
|
||||
G.CARD_H,
|
||||
v,
|
||||
G.P_CENTERS.m_Bakery_Curse or G.P_CENTERS.c_base,
|
||||
{playing_card = G.playing_card}
|
||||
)
|
||||
|
||||
table.insert(G.playing_cards, card)
|
||||
G.deck:emplace(card)
|
||||
play_sound "card1"
|
||||
card:add_to_deck()
|
||||
end,
|
||||
}
|
||||
end)
|
||||
|
||||
delay(1.5)
|
||||
delay(1)
|
||||
end,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,19 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
local f, q = unpack(... or require "lib.shared")
|
||||
|
||||
---@return {banned_cards: {}, banned_tags: {}, banned_other: {}}
|
||||
local function bans()
|
||||
return {banned_cards = {}, banned_tags = {}, banned_other = {}}
|
||||
end
|
||||
|
||||
---@param tbl table
|
||||
---@return fun(v: SMODS.GameObject)
|
||||
local function adder(tbl)
|
||||
return function(v)
|
||||
table.insert(tbl, {id = v.key, type = "blind"})
|
||||
end
|
||||
end
|
||||
|
||||
---@param v SMODS.GameObject
|
||||
---@return boolean
|
||||
local function is_banned_from_pastry(v)
|
||||
return not ({Bakery = true, Roland = true})[(v.mod or {}).id]
|
||||
end
|
||||
|
||||
---@param v SMODS.Center
|
||||
---@return boolean
|
||||
local function is_center_banned_from_pastry(v)
|
||||
local arcana_boosters = {
|
||||
p_arcana_normal_1 = true,
|
||||
|
|
@ -37,109 +30,40 @@ local function is_center_banned_from_pastry(v)
|
|||
return arcana_boosters[v.key] or pastries_targets[v.set] and is_banned_from_pastry(v)
|
||||
end
|
||||
|
||||
---@param v SMODS.GameObject
|
||||
---@return boolean|string
|
||||
local function is_economy(v)
|
||||
return f(Bakery_API.econ_only_items):where(f.eq(v.key)):any()
|
||||
local function is_joker(v)
|
||||
return v.set == "Joker" and not ({j_joker = true, j_Roland_msjoker = true})[v.key]
|
||||
end
|
||||
|
||||
---@param key string
|
||||
---@return fun(v: SMODS.Blind, k: string): boolean?
|
||||
local function is_showdown_except(key)
|
||||
---@param v SMODS.Blind
|
||||
---@param k string
|
||||
---@return boolean?
|
||||
return function(v, k)
|
||||
return v.boss and v.boss.showdown and key ~= k
|
||||
end
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@param amount number
|
||||
---@return {id: string}[]
|
||||
local function multirule(name, amount)
|
||||
return f(amount):map(function(v)
|
||||
return {id = "Roland_" .. name .. v}
|
||||
end):table()
|
||||
local function is_vanilla(v)
|
||||
return v.set and not v.mod and f(G.P_CENTERS):concat(G.P_CARDS, G.P_TAGS):any(function(c)
|
||||
return c.mod and not c.in_pool and c.set == v.set
|
||||
end)
|
||||
end
|
||||
|
||||
local pastries, amber, cerulean, crimson, verdant, violet, yard =
|
||||
bans(), bans(), bans(), bans(), bans(), bans(), bans()
|
||||
local jokerful, vanillas, pastries, amber, cerulean, crimson, verdant, violet, final
|
||||
= bans(), bans(), bans(), bans(), bans(), bans(), bans(), bans(), bans()
|
||||
|
||||
SMODS.Challenge {
|
||||
key = "Glass",
|
||||
rules = {custom = multirule("Glass", 2)},
|
||||
pronouns = "they_them",
|
||||
config = {extra = {odds = 2}},
|
||||
calculate = function(self, context)
|
||||
if not context.after or context.blueprint_card then
|
||||
return
|
||||
end
|
||||
|
||||
f(G.play.cards):where(function(v)
|
||||
return not v:get_seal(true) and
|
||||
SMODS.pseudorandom_probability(self, self.key, 1, self.config.extra.odds, self.key)
|
||||
end):each(function(v)
|
||||
v:set_seal "Roland_glass"
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
SMODS.Challenge {
|
||||
key = "Spring_Cleaning",
|
||||
config = {no_interest = true},
|
||||
consumeables = {{id = "c_hanged_man"}},
|
||||
jokers = {{id = "j_Roland_yard"}, {id = "j_Roland_yard"}},
|
||||
vouchers = {{id = "v_magic_trick"}, {id = "v_overstock_norm"}},
|
||||
rules = {custom = {{id = "Roland_Spring_Cleaning"}}},
|
||||
restrictions = yard,
|
||||
apply = function()
|
||||
G.GAME.modifiers.no_blind_reward = {Small = true, Big = true, Boss = true}
|
||||
G.GAME.modifiers.no_extra_hand_money = true
|
||||
|
||||
f(Bakery_API.econ_only_items):keys():where(f.nq "j_Roland_yard"):each(function(v)
|
||||
G.GAME.banned_keys[v] = true
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
SMODS.Challenge {
|
||||
key = "Go",
|
||||
rules = {custom = {{id = "Roland_Go"}}},
|
||||
jokers = {{id = "j_credit_card"}},
|
||||
key = "Jokerful",
|
||||
rules = {custom = {{id = "Roland_Jokerful"}}},
|
||||
restrictions = jokerful,
|
||||
pronouns = "he_him",
|
||||
calculate = function(self, context)
|
||||
if context.starting_shop then
|
||||
ease_dollars(-G.GAME.dollars)
|
||||
|
||||
attention_text {
|
||||
text = localize "k_nope_ex",
|
||||
backdrop_colour = G.C.MONEY,
|
||||
offset = {x = 0, y = 0},
|
||||
silent = true,
|
||||
major = self,
|
||||
align = "cm",
|
||||
scale = 1.3,
|
||||
hold = 1.4,
|
||||
}
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
local spin_to_win = SMODS.Challenge {
|
||||
key = "Spin_To_Win",
|
||||
jokers = f(4):map(f.const {id = "j_joker", eternal = true}):table(),
|
||||
restrictions = {banned_cards = {{id = "c_Roland_coolheaded"}}},
|
||||
pronouns = "they_them",
|
||||
apply = function(self)
|
||||
self.rotation = 0
|
||||
end,
|
||||
calculate = function(self, context)
|
||||
if not context.card_added or context.card.config.center.key ~= "j_Bakery_Spinner" then
|
||||
return
|
||||
end
|
||||
|
||||
context.card.ability.extra.rotation = self.rotation
|
||||
self.rotation = self.rotation + 1
|
||||
end,
|
||||
rotation = 0,
|
||||
SMODS.Challenge {
|
||||
key = "Ornate",
|
||||
rules = {custom = {{id = "Roland_Ornate"}}},
|
||||
restrictions = vanillas,
|
||||
pronouns = "any_all",
|
||||
}
|
||||
|
||||
SMODS.Challenge {
|
||||
|
|
@ -149,15 +73,12 @@ SMODS.Challenge {
|
|||
pronouns = "she_them",
|
||||
}
|
||||
|
||||
local finalizers = {
|
||||
|
||||
SMODS.Challenge {
|
||||
key = "Eternally_Amber",
|
||||
rules = {custom = {{id = "Roland_Eternally_Amber"}, {id = "Roland_Showdown_Amber"}}},
|
||||
jokers = {{id = "j_Roland_amber"}},
|
||||
restrictions = amber,
|
||||
pronouns = "they_them",
|
||||
unlocked = function()
|
||||
return G.P_CENTERS.j_Roland_amber and G.P_CENTERS.j_Roland_amber.check_for_unlock()
|
||||
end,
|
||||
calculate = function(_, context)
|
||||
local function slide(pitch)
|
||||
q(function()
|
||||
|
|
@ -189,17 +110,11 @@ SMODS.Challenge {
|
|||
end,
|
||||
}
|
||||
end,
|
||||
}
|
||||
|
||||
},
|
||||
SMODS.Challenge {
|
||||
key = "Eternally_Cerulean",
|
||||
rules = {custom = {{id = "Roland_Eternally_Cerulean"}, {id = "Roland_Showdown_Cerulean"}}},
|
||||
jokers = {{id = "j_Roland_cerulean"}},
|
||||
restrictions = cerulean,
|
||||
pronouns = "she_her",
|
||||
unlocked = function()
|
||||
return G.P_CENTERS.j_Roland_cerulean and G.P_CENTERS.j_Roland_cerulean.check_for_unlock()
|
||||
end,
|
||||
calculate = function(_, context)
|
||||
if not context.hand_drawn then
|
||||
return
|
||||
|
|
@ -219,25 +134,20 @@ SMODS.Challenge {
|
|||
G.hand:add_to_highlighted(v)
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
},
|
||||
SMODS.Challenge {
|
||||
key = "Eternally_Crimson",
|
||||
rules = {custom = {{id = "Roland_Eternally_Crimson"}, {id = "Roland_Showdown_Crimson"}}},
|
||||
jokers = {{id = "j_Roland_crimson"}},
|
||||
restrictions = crimson,
|
||||
pronouns = "she_her",
|
||||
unlocked = function()
|
||||
return G.P_CENTERS.j_Roland_crimson and G.P_CENTERS.j_Roland_crimson.check_for_unlock()
|
||||
end,
|
||||
calculate = function(_, context)
|
||||
local _ = context.blind_defeated and f(G.jokers.cards):each(function(v)
|
||||
v.ability.Roland_crimson_heart_chosen = nil
|
||||
end)
|
||||
|
||||
local mod = G.GAME.modifiers
|
||||
mod.Roland_Eternally_Crimson = context.setting_blind and true or mod.Roland_Eternally_Crimson
|
||||
mod.Roland_Eternally_Crimson = not context.setting_blind and mod.Roland_Eternally_Crimson or nil
|
||||
local debuff = context.debuff_card
|
||||
---@type (SMODS.Joker|{ability?: {Roland_crimson_heart_chosen: boolean?}, debuff: boolean?})[]
|
||||
local cards = G.jokers.cards
|
||||
|
||||
if debuff and
|
||||
|
|
@ -265,7 +175,9 @@ SMODS.Challenge {
|
|||
local _ = v.debuff and SMODS.recalc_debuff(v)
|
||||
end)
|
||||
|
||||
jokers = next(jokers) and jokers or f(cards):where("debuff", false):map(function(v)
|
||||
jokers = next(jokers) and jokers or f(cards):where(function(v)
|
||||
return not v.debuff
|
||||
end):map(function(v)
|
||||
local _ = not prev[v] and table.insert(jokers, v)
|
||||
return v
|
||||
end):table()
|
||||
|
|
@ -282,17 +194,11 @@ SMODS.Challenge {
|
|||
mod.Roland_Eternally_Crimson = not context.hand_drawn and
|
||||
mod.Roland_Eternally_Crimson or nil
|
||||
end,
|
||||
}
|
||||
|
||||
},
|
||||
SMODS.Challenge {
|
||||
key = "Eternally_Verdant",
|
||||
rules = {custom = {{id = "Roland_Eternally_Verdant"}, {id = "Roland_Showdown_Verdant"}}},
|
||||
jokers = {{id = "j_Roland_verdant"}},
|
||||
restrictions = verdant,
|
||||
pronouns = "she_her",
|
||||
unlocked = function()
|
||||
return G.P_CENTERS.j_Roland_verdant and G.P_CENTERS.j_Roland_verdant.check_for_unlock()
|
||||
end,
|
||||
calculate = function(_, context)
|
||||
if context.setting_blind then
|
||||
G.GAME.modifiers.Roland_Eternally_Verdant = true
|
||||
|
|
@ -308,55 +214,44 @@ SMODS.Challenge {
|
|||
end)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
},
|
||||
SMODS.Challenge {
|
||||
key = "Eternally_Violet",
|
||||
rules = {custom = {{id = "Roland_Eternally_Violet"}, {id = "Roland_Showdown_Violet"}}},
|
||||
jokers = {{id = "j_joker"}, {id = "j_Roland_violet"}},
|
||||
restrictions = violet,
|
||||
pronouns = "she_they",
|
||||
unlocked = function()
|
||||
return G.P_CENTERS.j_Roland_violet and G.P_CENTERS.j_Roland_violet.check_for_unlock()
|
||||
end,
|
||||
calculate = function(_, context)
|
||||
if not context.setting_blind then
|
||||
return
|
||||
end
|
||||
|
||||
local mult = G.GAME.blind.mult < 6 and G.GAME.blind.mult or 1
|
||||
G.GAME.blind.chips = G.GAME.blind.chips * 6 / mult
|
||||
if context.setting_blind then
|
||||
G.GAME.blind.chips = G.GAME.blind.chips * (6 / G.GAME.blind.mult)
|
||||
G.GAME.blind.chip_text = number_format(G.GAME.blind.chips)
|
||||
end
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
SMODS.Challenge {
|
||||
key = "Showdown",
|
||||
rules = {custom = {
|
||||
{id = "Roland_Eternally_Amber"},
|
||||
{id = "Roland_Eternally_Cerulean"},
|
||||
{id = "Roland_Eternally_Crimson"},
|
||||
{id = "Roland_Eternally_Verdant"},
|
||||
{id = "Roland_Eternally_Violet"},
|
||||
{id = "Roland_Showdown"},
|
||||
}},
|
||||
restrictions = final,
|
||||
calculate = function(_, context)
|
||||
f(finalizers):each(function(v)
|
||||
v:calculate(context)
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
q {
|
||||
blocking = false,
|
||||
no_delete = true,
|
||||
func = function()
|
||||
if not Bakery_API or not Bakery_API.no_money_decks then
|
||||
return false
|
||||
end
|
||||
|
||||
table.insert(Bakery_API.econ_only_items, "j_Roland_yard")
|
||||
table.insert(Bakery_API.econ_only_items, "j_Roland_artemis")
|
||||
local orig = Bakery_API.no_money_decks
|
||||
|
||||
Bakery_API.no_money_decks = setmetatable({}, {
|
||||
orig = orig,
|
||||
__index = function(_, k)
|
||||
return (G.GAME or {}).challenge == "c_Roland_Spring_Cleaning" or orig[k]
|
||||
end,
|
||||
})
|
||||
|
||||
f(spin_to_win.jokers):each(function(v)
|
||||
v.id = G.P_CENTERS.j_Bakery_Spinner and "j_Bakery_Spinner" or v.id
|
||||
end)
|
||||
|
||||
q(function()
|
||||
f {
|
||||
{G.P_TAGS, is_economy, yard.banned_tags},
|
||||
{G.P_BLINDS, is_economy, yard.banned_other},
|
||||
{G.P_CENTERS, is_economy, yard.banned_cards},
|
||||
{G.P_CENTERS, is_joker, jokerful.banned_cards},
|
||||
{G.P_TAGS, is_vanilla, vanillas.banned_tags},
|
||||
{G.P_BLINDS, is_vanilla, vanillas.banned_other},
|
||||
{G.P_CENTERS, is_vanilla, vanillas.banned_cards},
|
||||
{G.P_TAGS, is_banned_from_pastry, pastries.banned_tags},
|
||||
{G.P_BLINDS, is_banned_from_pastry, pastries.banned_other},
|
||||
{G.P_CENTERS, is_center_banned_from_pastry, pastries.banned_cards},
|
||||
|
|
@ -365,8 +260,8 @@ q {
|
|||
{G.P_BLINDS, is_showdown_except "bl_final_heart", crimson.banned_other},
|
||||
{G.P_BLINDS, is_showdown_except "bl_final_leaf", verdant.banned_other},
|
||||
{G.P_BLINDS, is_showdown_except "bl_final_vessel", violet.banned_other},
|
||||
{G.P_BLINDS, is_showdown_except "bl_Roland_venerable_visage", final.banned_other},
|
||||
}:each(function(v)
|
||||
f(v[1]):where(v[2]):each(adder(v[3]))
|
||||
end)
|
||||
end,
|
||||
}
|
||||
end)
|
||||
|
|
|
|||
306
src/charm.lua
|
|
@ -1,32 +1,19 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
local f, q = unpack(... or require "lib.shared")
|
||||
local mod = SMODS.current_mod
|
||||
local cool_phones = SMODS.Mods.Roland.config.cool_phones
|
||||
|
||||
SMODS.Atlas {
|
||||
key = "charm",
|
||||
path = cool_phones and "phorm.png" or "charm.png",
|
||||
path = "charm.png",
|
||||
px = 68,
|
||||
py = 68,
|
||||
}
|
||||
|
||||
local _ = cool_phones and SMODS.Sound {
|
||||
key = "phone",
|
||||
path = "phone.ogg",
|
||||
}
|
||||
|
||||
local charm = (function()
|
||||
local x = 0
|
||||
|
||||
---@param tbl SMODS.Joker|{alerted?: boolean, artist?: string, equip?: fun(self: self, card: Card)}
|
||||
---@param tbl SMODS.Joker|{alerted?: boolean}
|
||||
return function(tbl)
|
||||
q {
|
||||
blocking = false,
|
||||
no_delete = true,
|
||||
func = function()
|
||||
if not Bakery_API or not Bakery_API.Charm then
|
||||
return false
|
||||
end
|
||||
|
||||
q(function()
|
||||
local current_mod = SMODS.current_mod
|
||||
SMODS.current_mod = mod
|
||||
|
||||
|
|
@ -35,143 +22,110 @@ local charm = (function()
|
|||
tbl.unlocked = true
|
||||
tbl.discovered = true
|
||||
tbl.pos = {x = x, y = 0}
|
||||
tbl.atlas = "charm"
|
||||
tbl.artist = not cool_phones and "Roland_bakersdozenbagels" or nil
|
||||
x = x + 1
|
||||
tbl.atlas = "charm"
|
||||
|
||||
local orig_equip = tbl.equip
|
||||
|
||||
function tbl.equip(...)
|
||||
local _ = cool_phones and play_sound("Roland_phone", 1, 0.5)
|
||||
|
||||
if orig_equip then
|
||||
return orig_equip(...)
|
||||
end
|
||||
end
|
||||
|
||||
local charm = Bakery_API.credit(Bakery_API.Charm(tbl))
|
||||
local charm = Bakery_API.Charm(tbl)
|
||||
charm:inject()
|
||||
charm:process_loc_text()
|
||||
SMODS.current_mod = current_mod
|
||||
end,
|
||||
}
|
||||
end, true)
|
||||
end
|
||||
end)()
|
||||
|
||||
local function can_discard_zero()
|
||||
return G.GAME.current_round.discards_left > 0 and
|
||||
not next(G.hand.highlighted) and
|
||||
G.hand.config.card_limit > 0 and
|
||||
G.GAME.Bakery_charm == "BakeryCharm_Roland_cocacola"
|
||||
local function add_to_consumable_ability_by(n)
|
||||
local function new(v)
|
||||
return type(v) == "number" and v + n or type(v) == "table" and f(v):map(new):table() or v
|
||||
end
|
||||
|
||||
charm {
|
||||
key = "hand",
|
||||
pronouns = "he_him",
|
||||
config = {extra = {hands = -2, hand_size = 5}},
|
||||
attributes = {"hands", "hand_size", "passive"},
|
||||
loc_vars = function(_, _, card)
|
||||
local extra = card.ability.extra
|
||||
return {vars = {extra.hand_size, extra.hands}}
|
||||
end,
|
||||
equip = function(_, card)
|
||||
local extra = card.ability.extra
|
||||
local round = G.GAME.round_resets
|
||||
ease_hands_played(extra.hands)
|
||||
G.hand:change_size(extra.hand_size)
|
||||
round.hands = round.hands + extra.hands
|
||||
end,
|
||||
unequip = function(_, card)
|
||||
local extra = card.ability.extra
|
||||
local round = G.GAME.round_resets
|
||||
ease_hands_played(-extra.hands)
|
||||
G.hand:change_size(-extra.hand_size)
|
||||
round.hands = round.hands - extra.hands
|
||||
end,
|
||||
}
|
||||
---@param card Card
|
||||
return function(card)
|
||||
local ability = card.ability or {}
|
||||
|
||||
charm {
|
||||
key = "cocacola",
|
||||
pronouns = "he_they",
|
||||
attributes = {"passive", "tarot", "spectral"},
|
||||
config = {extra = {discard = 2, hand_size = 1, refund = 0}},
|
||||
loc_vars = function(_, _, card)
|
||||
local extra = card.ability.extra
|
||||
return {vars = {extra.discard, extra.hand_size}}
|
||||
end,
|
||||
calculate = function(_, card, context)
|
||||
if not context.end_of_round then
|
||||
local function go(key)
|
||||
---@type { [string]: number }|number
|
||||
local value = ability[key]
|
||||
--print(key)
|
||||
if not value then
|
||||
return
|
||||
end
|
||||
|
||||
local extra = card.ability.extra
|
||||
G.hand:change_size(extra.refund)
|
||||
extra.refund = 0
|
||||
end,
|
||||
}
|
||||
|
||||
local orig_can_discard = G.FUNCS.can_discard
|
||||
|
||||
function G.FUNCS.can_discard(e, ...)
|
||||
if can_discard_zero() then
|
||||
e.config.button, e.config.colour = "Roland_cocacola", G.C.RED
|
||||
else
|
||||
return orig_can_discard(e, ...)
|
||||
end
|
||||
if type(value) == "number" then
|
||||
ability[key] = value + n
|
||||
return
|
||||
end
|
||||
|
||||
G.FUNCS.Roland_cocacola = function()
|
||||
stop_use()
|
||||
G.CONTROLLER.interrupt.focus = true
|
||||
G.CONTROLLER:save_cardarea_focus "hand"
|
||||
if type(value) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
f(G.playing_cards):map "ability":each(function(v)
|
||||
v.forced_selection = nil
|
||||
local new_value = f(value):map(new):table()
|
||||
|
||||
f(new_value):each(function(v, k)
|
||||
ability[k] = v
|
||||
end)
|
||||
|
||||
G.card_area_focus_reset = (G.CONTROLLER.focused.target or {}).area == G.hand and
|
||||
{area = G.hand, rank = G.CONTROLLER.focused.target.rank} or G.card_area_focus_reset
|
||||
|
||||
SMODS.calculate_context {pre_discard = true, full_hand = G.hand.highlighted}
|
||||
G.GAME.current_round.discards_used = G.GAME.current_round.discards_used + 1
|
||||
|
||||
local c = G.Bakery_charm_area.cards[1]
|
||||
local extra = c.ability.extra or {}
|
||||
juice_card(c)
|
||||
ease_discard(extra.discard - 1)
|
||||
G.hand:change_size(-extra.hand_size)
|
||||
extra.refund = extra.refund + extra.hand_size
|
||||
|
||||
local _ = G.GAME.modifiers.discard_cost and ease_dollars(-G.GAME.modifiers.discard_cost)
|
||||
G.STATE = G.STATES.DRAW_TO_HAND
|
||||
|
||||
q {
|
||||
trigger = "immediate",
|
||||
func = function()
|
||||
if G.SCORING_COROUTINE then
|
||||
return false
|
||||
ability[key] = new_value
|
||||
end
|
||||
|
||||
local center_key = (card.config or {}).center_key
|
||||
|
||||
if center_key and center_key:sub(1, 2) == "c_" then
|
||||
f {"extra", "consumeable"}:each(go)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
charm {
|
||||
key = "wii",
|
||||
pronouns = "they_them",
|
||||
calculate = function(_, card, context)
|
||||
if not context.skip_blind then
|
||||
return
|
||||
end
|
||||
|
||||
local message = localize {type = "variable", key = "b_Roland_entering_shop"}
|
||||
SMODS.calculate_effect({card = card, message = message, sound = "whoosh1"}, card)
|
||||
|
||||
q(function()
|
||||
G.blind_prompt_box = G.blind_prompt_box and G.blind_prompt_box:remove()
|
||||
G.blind_select = G.blind_select and G.blind_select:remove()
|
||||
G.round_eval = G.round_eval and G.round_eval:remove()
|
||||
G.GAME.current_round.jokers_purchased = 0
|
||||
G.STATE = G.STATES.SHOP
|
||||
G.GAME.shop_free = nil
|
||||
G.GAME.shop_d6ed = nil
|
||||
G.STATE_COMPLETE = false
|
||||
return true
|
||||
play_sound("whoosh1", 1.33333, 0.8)
|
||||
play_sound("whoosh1", 0.66666, 0.8)
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
charm {
|
||||
key = "flexible",
|
||||
pronouns = "any_all",
|
||||
}
|
||||
|
||||
local orig_showman = SMODS.showman
|
||||
|
||||
function SMODS.showman(...)
|
||||
return G.GAME.Bakery_charm == "BakeryCharm_Roland_flexible" or orig_showman(...)
|
||||
end
|
||||
|
||||
charm {
|
||||
key = "fat",
|
||||
pronouns = "he_they",
|
||||
attributes = {"passive"},
|
||||
config = {extra = {mod = 2}},
|
||||
loc_vars = function(_, _, card)
|
||||
return {vars = {card.ability.extra.mod}}
|
||||
end,
|
||||
equip = function(_, card)
|
||||
SMODS.change_booster_limit(card.ability.extra.mod)
|
||||
end,
|
||||
unequip = function(_, card)
|
||||
SMODS.change_booster_limit(-card.ability.extra.mod)
|
||||
end,
|
||||
-- config = {extra = {mod = 1}},
|
||||
-- loc_vars = function(_, _, card)
|
||||
-- return {vars = {card.ability.extra.mod}}
|
||||
-- end,
|
||||
-- equip = function(_, card)
|
||||
-- SMODS.change_booster_limit(card.ability.extra.mod)
|
||||
-- end,
|
||||
-- unequip = function(card)
|
||||
-- SMODS.change_booster_limit(-card.ability.extra.mod)
|
||||
-- end,
|
||||
}
|
||||
|
||||
local orig_init = Card.init
|
||||
|
|
@ -181,9 +135,7 @@ function Card:init(X, Y, W, H, card, center, params, ...)
|
|||
return orig_init(self, X, Y, W, H, card, center, params, ...)
|
||||
end
|
||||
|
||||
local key = f {"mini", "jumbo", "normal"}:fold(center.key, function(a, v)
|
||||
return a:gsub(v, "mega")
|
||||
end)
|
||||
local key = center.key:gsub("normal", "mega"):gsub("jumbo", "mega"):gsub("mini", "mega")
|
||||
|
||||
if G.P_CENTERS[key] then
|
||||
return orig_init(self, X, Y, W, H, card, G.P_CENTERS[key], params, ...)
|
||||
|
|
@ -206,70 +158,48 @@ function Card:init(X, Y, W, H, card, center, params, ...)
|
|||
end
|
||||
|
||||
charm {
|
||||
key = "flexible",
|
||||
pronouns = "any_all",
|
||||
}
|
||||
|
||||
local orig_showman = SMODS.showman
|
||||
|
||||
function SMODS.showman(...)
|
||||
return G.GAME.Bakery_charm == "BakeryCharm_Roland_flexible" or orig_showman(...)
|
||||
end
|
||||
|
||||
charm {
|
||||
key = "wii",
|
||||
pronouns = "they_them",
|
||||
attributes = {"skip"},
|
||||
config = {extra = {active = true}},
|
||||
calculate = function(_, card, context)
|
||||
if context.prevent_tag_trigger and card.ability.extra.active then
|
||||
return {prevent_trigger = true}
|
||||
end
|
||||
|
||||
if not context.skip_blind then
|
||||
return
|
||||
end
|
||||
|
||||
card.ability.extra.active = true
|
||||
local message = localize {type = "variable", key = "b_Roland_entering_shop"}
|
||||
SMODS.calculate_effect({card = card, message = message, sound = "whoosh1"}, card)
|
||||
|
||||
q(function()
|
||||
G.blind_prompt_box = G.blind_prompt_box and G.blind_prompt_box:remove()
|
||||
G.blind_select = G.blind_select and G.blind_select:remove()
|
||||
G.round_eval = G.round_eval and G.round_eval:remove()
|
||||
G.GAME.current_round.jokers_purchased = 0
|
||||
G.GAME.shop_free = nil
|
||||
G.GAME.shop_d6ed = nil
|
||||
play_sound("whoosh1", 1.33333, 0.8)
|
||||
play_sound("whoosh1", 0.66666, 0.8)
|
||||
|
||||
q(function()
|
||||
G.STATE = G.STATES.SHOP
|
||||
G.STATE_COMPLETE = false
|
||||
delay(1)
|
||||
|
||||
q(function()
|
||||
f((G.GAME.modifiers.extra_boosters or 0) + 2)
|
||||
:map(f.const(nil))
|
||||
:each(SMODS.add_booster_to_shop)
|
||||
|
||||
q(function()
|
||||
card.ability.extra.active = false
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
key = "cocacola",
|
||||
pronouns = "he_they",
|
||||
equip = function()
|
||||
f(G.consumeables.cards):each(add_to_consumable_ability_by(1))
|
||||
end,
|
||||
unequip = function()
|
||||
f(G.consumeables.cards):each(add_to_consumable_ability_by(-1))
|
||||
end,
|
||||
}
|
||||
|
||||
local orig_apply_to_run = Tag.apply_to_run
|
||||
local orig_set_ability = Card.set_ability
|
||||
|
||||
function Tag:apply_to_run(...)
|
||||
if G.GAME.Bakery_charm == "BakeryCharm_Roland_wii" and
|
||||
G.Bakery_charm_area.cards[1].ability.extra.active then
|
||||
return
|
||||
function Card:set_ability(center, initial, delay_sprites, ...)
|
||||
local ret = orig_set_ability(self, center, initial, delay_sprites, ...)
|
||||
|
||||
if G.GAME.Bakery_charm == "BakeryCharm_Roland_cocacola" then
|
||||
add_to_consumable_ability_by(1)(self)
|
||||
end
|
||||
|
||||
return orig_apply_to_run(self, ...)
|
||||
return ret
|
||||
end
|
||||
|
||||
charm {
|
||||
key = "hand",
|
||||
pronouns = "he_him",
|
||||
config = {extra = {hands = -2, hand_size = 5}},
|
||||
loc_vars = function(_, _, card)
|
||||
local extra = card.ability.extra
|
||||
return {vars = {extra.hand_size, extra.hands}}
|
||||
end,
|
||||
equip = function(_, card)
|
||||
local extra = card.ability.extra
|
||||
local round = G.GAME.round_resets
|
||||
ease_hands_played(extra.hands)
|
||||
G.hand:change_size(extra.hand_size)
|
||||
round.hands = round.hands + extra.hands
|
||||
end,
|
||||
unequip = function(_, card)
|
||||
local extra = card.ability.extra
|
||||
local round = G.GAME.round_resets
|
||||
ease_hands_played(-extra.hands)
|
||||
G.hand:change_size(-extra.hand_size)
|
||||
round.hands = round.hands - extra.hands
|
||||
end,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
-- Special shoutout to all contributors. <3
|
||||
return {
|
||||
aster = {
|
||||
name = "asterSSH",
|
||||
fg = HEX "f8f8f2ff",
|
||||
bg = HEX "bd93f9ff",
|
||||
},
|
||||
bakersdozenbagels = {
|
||||
name = "BakersDozenBagels",
|
||||
fg = HEX "362708ff",
|
||||
bg = HEX "edd198ff",
|
||||
},
|
||||
ghostlyfield = {
|
||||
name = "ghostlyfield",
|
||||
fg = HEX "ffffffff",
|
||||
bg = HEX "b290e6ff",
|
||||
},
|
||||
hamester = {
|
||||
name = "Hamester",
|
||||
fg = HEX "ffffffff",
|
||||
bg = HEX "ffa100ff",
|
||||
},
|
||||
redstoad = {
|
||||
name = "RedsToad",
|
||||
fg = HEX "ffffffff",
|
||||
bg = HEX "da4044ff",
|
||||
},
|
||||
}
|
||||
339
src/edition.lua
|
|
@ -1,4 +1,4 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
local f, q = unpack(... or require "lib.shared")
|
||||
|
||||
SMODS.Shader {
|
||||
key = "frozen",
|
||||
|
|
@ -12,14 +12,14 @@ local function frozen_sound(suffix)
|
|||
end
|
||||
|
||||
frozen_sound "_click"
|
||||
local frozen_blocklist = {CardSleeve = true}
|
||||
local frozen_sounds = f(4):map(frozen_sound):map "key":table()
|
||||
local frozen_sounds = f(4):map(frozen_sound):map("key"):table()
|
||||
|
||||
local needs_chip_mult_override = {
|
||||
Bull = true,
|
||||
Erosion = true,
|
||||
Misprint = true,
|
||||
TierList = true,
|
||||
Bootstraps = true,
|
||||
["Blue Joker"] = true,
|
||||
["Abstract Joker"] = true,
|
||||
["Fortune Teller"] = true,
|
||||
|
|
@ -46,42 +46,17 @@ local function freeze(card)
|
|||
---@param x T
|
||||
---@return T
|
||||
local function copy(x)
|
||||
return type(x) == "table" and f(x):map(copy):table() or x
|
||||
return type(x) == "table" and f(x):map(copy):where(function(v, k)
|
||||
return k ~= "Roland_frozen_proxy" and (k ~= "nine_tally" or v ~= 0)
|
||||
end):table() or x
|
||||
end
|
||||
|
||||
if frozen_blocklist[(card.ability or {}).name] then
|
||||
return card.ability
|
||||
end
|
||||
|
||||
local config = card.config or {}
|
||||
|
||||
(card.ability or {}).Roland_crimson = not not (card.ability or {}).Roland_crimson
|
||||
card.Roland_frozen_base = card.Roland_frozen_base or copy(card.base)
|
||||
card.Roland_frozen_card = card.Roland_frozen_card or copy(config.card)
|
||||
card.Roland_frozen_ability = card.Roland_frozen_ability or copy(card.ability)
|
||||
card.base = card.Roland_frozen_base and copy(card.Roland_frozen_base) or card.base
|
||||
|
||||
local diff = type(card.set_sprites) == "function" and
|
||||
f(card.Roland_frozen_card):diff(config.card, f.chain(type, f.nq "table"))
|
||||
|
||||
config.card = card.Roland_frozen_card and copy(card.Roland_frozen_card) or config.card
|
||||
card.ability = card.Roland_frozen_ability and copy(card.Roland_frozen_ability) or card.ability
|
||||
card.Roland_frozen = card.Roland_frozen or {probability = SMODS.get_probability_vars(card, 1, 1)}
|
||||
local ret = card.Roland_frozen_ability
|
||||
local ability = card.ability
|
||||
|
||||
if diff then
|
||||
card:set_sprites(card.config.center, card.config.card)
|
||||
end
|
||||
|
||||
local ability, ret = card.ability, card.Roland_frozen_ability
|
||||
ability.extra = ability.extra == nil and {} or ability.extra
|
||||
|
||||
if type(ability) ~= "table" then
|
||||
return ret
|
||||
end
|
||||
|
||||
ability.seal = ability.seal or {}
|
||||
|
||||
if not ability.name or not G.GAME.current_round then
|
||||
if type(ability) ~= "table" or not ability.name or not G.GAME.current_round then
|
||||
return ret
|
||||
end
|
||||
|
||||
|
|
@ -96,129 +71,23 @@ local function freeze(card)
|
|||
return ret
|
||||
end
|
||||
|
||||
local function hook_estate()
|
||||
---@param card Card|{ Roland_frozen: {estate: integer} }
|
||||
local function estate_pos(card)
|
||||
if card.area ~= G.jokers and card.area.config.type ~= "title" then
|
||||
return 1
|
||||
end
|
||||
|
||||
card.Roland_frozen.estate = card.Roland_frozen.estate or card.rank or 1
|
||||
return card.Roland_frozen.estate
|
||||
end
|
||||
|
||||
local estate = G.P_CENTERS.j_Bakery_Estate
|
||||
local orig_calculate = estate.calculate
|
||||
|
||||
function estate:calculate(card, context, ...)
|
||||
if not (card or {}).Roland_frozen or not (card.edition or {}).Roland_frozen then
|
||||
return orig_calculate(self, card, context, ...)
|
||||
end
|
||||
|
||||
if not context.joker_main then
|
||||
return
|
||||
end
|
||||
|
||||
local joker_count = estate_pos(card)
|
||||
local extra = card.ability.extra
|
||||
return {chips = extra.chips * joker_count, mult = extra.mult * joker_count}
|
||||
end
|
||||
|
||||
local orig_loc_vars = estate.loc_vars
|
||||
|
||||
function estate:loc_vars(info_queue, card, ...)
|
||||
if not (card or {}).Roland_frozen or not (card.edition or {}).Roland_frozen then
|
||||
return orig_loc_vars(self, info_queue, card, ...)
|
||||
end
|
||||
|
||||
local joker_count = estate_pos(card)
|
||||
local extra = card.ability.extra or {}
|
||||
return {vars = {extra.chips * joker_count, extra.mult * joker_count}}
|
||||
end
|
||||
end
|
||||
|
||||
local function hook_proxy()
|
||||
---@param card Card|{ Roland_frozen: {proxy: string} }
|
||||
local function get_proxied_joker(card)
|
||||
if not G.jokers or not G.jokers.cards then
|
||||
return
|
||||
end
|
||||
|
||||
card.Roland_frozen.proxy = card.Roland_frozen.proxy or
|
||||
(Bakery_API.get_proxied_joker() or card).config.center.key
|
||||
|
||||
---@param v Card
|
||||
local function eq(v)
|
||||
return v.config.center.key == card.Roland_frozen.proxy
|
||||
end
|
||||
|
||||
return f(G.jokers.cards):any(eq)
|
||||
end
|
||||
|
||||
local proxy = G.P_CENTERS.j_Bakery_Proxy
|
||||
local orig_calculate = proxy.calculate
|
||||
|
||||
function proxy:calculate(card, context, ...)
|
||||
if not (card or {}).Roland_frozen or not (card.edition or {}).Roland_frozen then
|
||||
return orig_calculate(self, card, context, ...)
|
||||
else
|
||||
return SMODS.blueprint_effect(card, get_proxied_joker(card), context)
|
||||
end
|
||||
end
|
||||
|
||||
local orig_loc_vars = proxy.loc_vars
|
||||
|
||||
function proxy:loc_vars(info_queue, card, ...)
|
||||
if not (card or {}).Roland_frozen or not (card.edition or {}).Roland_frozen then
|
||||
return orig_loc_vars(self, info_queue, card, ...)
|
||||
end
|
||||
|
||||
local other = get_proxied_joker(card)
|
||||
|
||||
local var = (other and other ~= card) and localize {
|
||||
type = "name_text",
|
||||
set = other.config.center.set,
|
||||
key = other.config.center.key,
|
||||
} or localize "k_none"
|
||||
|
||||
return {vars = {var}}
|
||||
end
|
||||
end
|
||||
|
||||
local function hook_scribe()
|
||||
local scribe = G.P_CENTERS.c_Bakery_Scribe
|
||||
local orig_can_use = scribe.can_use
|
||||
|
||||
function scribe.can_use(...)
|
||||
return orig_can_use(...) and
|
||||
(SMODS.Mods.Roland.config.scribable_basket or f(G.jokers.highlighted):all(function(v)
|
||||
return v.config.center.key ~= "j_Roland_basket"
|
||||
end))
|
||||
end
|
||||
end
|
||||
|
||||
SMODS.Edition {
|
||||
key = "frozen",
|
||||
shader = "frozen",
|
||||
sound = {sound = "Roland_frozen", per = 1, vol = 0.8},
|
||||
attributes = {"passive", "scaling", "mod_chance"},
|
||||
pronouns = "any_all",
|
||||
weight = 8,
|
||||
extra_cost = 4,
|
||||
in_shop = true,
|
||||
apply_to_float = false,
|
||||
calculate = function(_, card, context)
|
||||
local _ = not context.fix_probability and not context.mod_probability and freeze(card)
|
||||
calculate = function(_, card)
|
||||
freeze(card)
|
||||
end,
|
||||
on_remove = function(card)
|
||||
card.Roland_frozen,
|
||||
card.Roland_frozen_base,
|
||||
card.Roland_frozen_card,
|
||||
card.Roland_frozen_ability,
|
||||
card.Roland_frozen_current_round = nil, nil, nil, nil, nil
|
||||
card.Roland_frozen_estate = nil
|
||||
card.Roland_frozen_ability = nil
|
||||
end,
|
||||
get_weight = function(self)
|
||||
return self.weight * G.GAME.edition_rate
|
||||
return G.GAME.edition_rate * self.weight
|
||||
end,
|
||||
}
|
||||
|
||||
|
|
@ -250,49 +119,19 @@ function Card:click(...)
|
|||
return ret
|
||||
end
|
||||
|
||||
local orig_save = Card.save
|
||||
|
||||
function Card:save(...)
|
||||
if false then
|
||||
---@type Card|{Roland_frozen: table, Roland_frozen_ability: table, Roland_frozen_base: table, Roland_frozen_card: table, Roland_frozen_current_round: table}
|
||||
self = self
|
||||
end
|
||||
|
||||
local ret = orig_save(self, ...)
|
||||
|
||||
ret.Roland_frozen,
|
||||
ret.Roland_frozen_base,
|
||||
ret.Roland_frozen_card,
|
||||
ret.Roland_frozen_ability,
|
||||
ret.Roland_frozen_current_round =
|
||||
self.Roland_frozen,
|
||||
self.Roland_frozen_base,
|
||||
self.Roland_frozen_card,
|
||||
self.Roland_frozen_ability,
|
||||
self.Roland_frozen_current_round
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
local is_bean = {["Turtle Bean"] = true, j_mp_turtle_bean = true}
|
||||
local orig_calculate_joker = Card.calculate_joker
|
||||
|
||||
---@param self Card|{Roland_frozen_ability?: table}
|
||||
function Card:calculate_joker(context, ...)
|
||||
local is_frozen = self.edition and self.edition.Roland_frozen
|
||||
|
||||
if is_frozen and self.ability.name == "Loyalty Card" then
|
||||
return (context.joker_main and self.ability.loyalty_remaining == 0) and
|
||||
{xmult = self.ability.extra.Xmult} or nil
|
||||
end
|
||||
|
||||
if is_frozen and is_bean[self.ability.name] then
|
||||
if is_frozen and self.ability.name == "Turtle Bean" then
|
||||
return
|
||||
end
|
||||
|
||||
local ret = {orig_calculate_joker(self, context, ...)}
|
||||
|
||||
if not is_frozen or type(ret[1]) ~= "table" then
|
||||
if not is_frozen or not ret[1] then
|
||||
return unpack(ret)
|
||||
end
|
||||
|
||||
|
|
@ -302,11 +141,24 @@ function Card:calculate_joker(context, ...)
|
|||
return unpack(ret)
|
||||
end
|
||||
|
||||
return f {mult = "mult_mod", chips = "chip_mod", xmult = "xmult", x_mult = "x_mult"}:map(function(v)
|
||||
local key = "Roland_frozen_" .. v
|
||||
ability[key] = ability[key] or ret[1][v]
|
||||
return ability[key]
|
||||
end):where(f.id):table()
|
||||
ability.Roland_frozen_mult_mod = ability.Roland_frozen_mult_mod or ret[1].mult_mod
|
||||
ability.Roland_frozen_chip_mod = ability.Roland_frozen_chip_mod or ret[1].chip_mod
|
||||
ability.Roland_frozen_xmult = ability.Roland_frozen_xmult or ret[1].xmult
|
||||
|
||||
return {
|
||||
chip_mod = ability.Roland_frozen_chip_mod,
|
||||
mult_mod = ability.Roland_frozen_mult_mod,
|
||||
xmult = ability.Roland_frozen_xmult,
|
||||
message = localize {
|
||||
type = "variable",
|
||||
key = "a_mult",
|
||||
vars = {
|
||||
ability.Roland_frozen_mult_mod or
|
||||
ability.Roland_frozen_chip_mod or
|
||||
ability.Roland_frozen_xmult,
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local orig_calculate_dollar_bonus = Card.calculate_dollar_bonus
|
||||
|
|
@ -329,49 +181,106 @@ function Card:calculate_dollar_bonus(...)
|
|||
return orig_calculate_dollar_bonus(self, ...)
|
||||
end
|
||||
|
||||
function SMODS.current_mod.bootstraps_mult(card)
|
||||
local ability = card.Roland_frozen_ability
|
||||
local ret = math.floor((G.GAME.dollars + (G.GAME.dollar_buffer or 0)) / card.ability.extra.dollars)
|
||||
q(function()
|
||||
local estate = G.P_CENTERS.j_Bakery_Estate
|
||||
|
||||
if not ability then
|
||||
return ret
|
||||
if not estate then
|
||||
return
|
||||
end
|
||||
|
||||
ability.Roland_bootstraps_mult = ability.Roland_bootstraps_mult or ret
|
||||
return ability.Roland_bootstraps_mult
|
||||
local function estate_pos(card)
|
||||
if card.area ~= G.jokers and card.area.config.type ~= "title" then
|
||||
return 1
|
||||
end
|
||||
|
||||
local orig_get_probability_vars = SMODS.get_probability_vars
|
||||
card.Roland_frozen_estate = card.Roland_frozen_estate and
|
||||
card.Roland_frozen_estate or
|
||||
(f(card.area.cards):swap():any(function(_, k)
|
||||
return k == card
|
||||
end) or 1)
|
||||
|
||||
function SMODS.get_probability_vars(trigger_obj, ...)
|
||||
local numerator, denominator = orig_get_probability_vars(trigger_obj, ...)
|
||||
local override = ((trigger_obj or {}).Roland_frozen or {}).probability
|
||||
|
||||
if override then
|
||||
return type(denominator) == "table" and to_big(override) or override, denominator
|
||||
else
|
||||
return numerator, denominator
|
||||
end
|
||||
return card.Roland_frozen_estate
|
||||
end
|
||||
|
||||
q {
|
||||
blocking = false,
|
||||
no_delete = true,
|
||||
func = function()
|
||||
local orig_flip_double_sided = (Bakery_API or {}).flip_double_sided
|
||||
local orig_calculate = estate.calculate
|
||||
|
||||
if not orig_flip_double_sided then
|
||||
return false
|
||||
---@param card Card|{ Roland_frozen_ability: table, Roland_frozen_estate: integer }
|
||||
function estate:calculate(card, context, ...)
|
||||
if not card or not card.edition or not card.edition.Roland_frozen then
|
||||
return orig_calculate(self, card, context, ...)
|
||||
end
|
||||
|
||||
function Bakery_API.flip_double_sided(card, ...)
|
||||
if not card.edition or not card.edition.Roland_frozen then
|
||||
return orig_flip_double_sided(card, ...)
|
||||
end
|
||||
if not context.joker_main then
|
||||
return
|
||||
end
|
||||
|
||||
local _ = G.P_CENTERS.j_Bakery_Estate and hook_estate()
|
||||
local _ = G.P_CENTERS.c_Bakery_Scribe and hook_scribe()
|
||||
local _ = G.P_CENTERS.j_Bakery_Proxy and hook_proxy()
|
||||
end,
|
||||
}
|
||||
local joker_count = estate_pos(card)
|
||||
local extra = card.ability.extra or {}
|
||||
return {chips = extra.chips * joker_count, mult = extra.mult * joker_count}
|
||||
end
|
||||
|
||||
local orig_loc_vars = estate.loc_vars
|
||||
|
||||
function estate:loc_vars(info_queue, card, ...)
|
||||
if not card or not card.edition or not card.edition.Roland_frozen then
|
||||
return orig_loc_vars(self, info_queue, card, ...)
|
||||
end
|
||||
|
||||
local joker_count = estate_pos(card)
|
||||
local extra = card.ability.extra or {}
|
||||
return {vars = {extra.chips * joker_count, extra.mult * joker_count}}
|
||||
end
|
||||
end)
|
||||
|
||||
q(function()
|
||||
local proxy = G.P_CENTERS.j_Bakery_Proxy
|
||||
|
||||
if not proxy then
|
||||
return
|
||||
end
|
||||
|
||||
local function get_proxied_joker(card)
|
||||
if not G.jokers or not G.jokers.cards then
|
||||
return
|
||||
end
|
||||
|
||||
local ability = freeze(card)
|
||||
|
||||
---@param v Card
|
||||
local function eq(v)
|
||||
return v.unique_val == ability.Roland_frozen_proxy
|
||||
end
|
||||
|
||||
ability.Roland_frozen_proxy = (Bakery_API.get_proxied_joker() or card).unique_val
|
||||
return f(G.jokers.cards):any(eq) ---@type Card?
|
||||
end
|
||||
|
||||
local orig_calculate = proxy.calculate
|
||||
|
||||
---@param card Card|{ Roland_frozen_ability: table }
|
||||
function proxy:calculate(card, context, ...)
|
||||
if not card or not card.edition or not card.edition.Roland_frozen then
|
||||
return orig_calculate(self, card, context, ...)
|
||||
end
|
||||
|
||||
return SMODS.blueprint_effect(card, get_proxied_joker(card), context)
|
||||
end
|
||||
|
||||
local orig_loc_vars = proxy.loc_vars
|
||||
|
||||
function proxy:loc_vars(info_queue, card, ...)
|
||||
if not card or not card.edition or not card.edition.Roland_frozen then
|
||||
return orig_loc_vars(self, info_queue, card, ...)
|
||||
end
|
||||
|
||||
local other = get_proxied_joker(card)
|
||||
|
||||
local var = (other and other ~= card) and localize {
|
||||
type = "name_text",
|
||||
set = other.config.center.set,
|
||||
key = other.config.center.key,
|
||||
} or localize "k_none"
|
||||
|
||||
return {vars = {var}}
|
||||
end
|
||||
end)
|
||||
|
|
|
|||
1467
src/joker.lua
|
|
@ -3,227 +3,10 @@
|
|||
---@license MPL-2.0
|
||||
---@version 1.0.0
|
||||
---
|
||||
---@alias FFrom (fun<K, V>(iter: table<K, V>, fpairs?: fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K?, V?)): F | { [K]: V })|(fun(iter: number, fpairs?: number, step?: number): F | { [number]: number })|(fun<V>(iter: string): (fun(table: { [string]: V }): V))|(fun<V>(iter: string): (fun(table: { [string]: V }): V))|(fun<K, V>(iter: fun(): K, V): F | { [K]: V })|(fun(iter: false): fun(): false)|(fun(iter: true): fun(): true)|(fun(iter: nil): F)
|
||||
---@class F
|
||||
local f = {}
|
||||
|
||||
if not f then
|
||||
---@generic T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R
|
||||
---@param self F
|
||||
---@param first? T1
|
||||
---@param second? T2
|
||||
---@param third? T3
|
||||
---@param fourth? T4
|
||||
---@param fifth? T5
|
||||
---@param sixth? T6
|
||||
---@param seventh? T7
|
||||
---@param eighth? T8
|
||||
---@param ninth? T9
|
||||
---@param tenth? T10
|
||||
---@return fun(v: fun(first: T1, second: T2, third: T3, fourth: T4, fifth: T5, sixth: T6, seventh: T7, eighth: T8, ninth: T9, tenth: T10): R): R
|
||||
---@nodiscard
|
||||
function f:call(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth)
|
||||
error {first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth}
|
||||
end
|
||||
|
||||
---@generic T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R
|
||||
---@param self string
|
||||
---@param first? T1
|
||||
---@param second? T2
|
||||
---@param third? T3
|
||||
---@param fourth? T4
|
||||
---@param fifth? T5
|
||||
---@param sixth? T6
|
||||
---@param seventh? T7
|
||||
---@param eighth? T8
|
||||
---@param ninth? T9
|
||||
---@param tenth? T10
|
||||
---@return fun(v: {[string]: fun(self: self, first: T1, second: T2, third: T3, fourth: T4, fifth: T5, sixth: T6, seventh: T7, eighth: T8, ninth: T9, tenth: T10): R}): R
|
||||
---@nodiscard
|
||||
function f.call(self, first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth)
|
||||
error {self, first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth}
|
||||
end
|
||||
|
||||
---@generic I, O
|
||||
---@param first integer|string|fun(v: I): O
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(first)
|
||||
error {first}
|
||||
end
|
||||
|
||||
---@generic I, T, O
|
||||
---@param first integer|string|fun(v: I): T
|
||||
---@param second integer|string|fun(v: T): O
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(first, second)
|
||||
error {first, second}
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, O
|
||||
---@param first integer|string|fun(v: I): T1
|
||||
---@param second integer|string|fun(v: T1): T2
|
||||
---@param third integer|string|fun(v: T2): O
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(first, second, third)
|
||||
error {first, second, third}
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, O
|
||||
---@param first integer|string|fun(v: I): T1
|
||||
---@param second integer|string|fun(v: T1): T2
|
||||
---@param third integer|string|fun(v: T2): T3
|
||||
---@param fourth integer|string|fun(v: T3): O
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(first, second, third, fourth)
|
||||
error {first, second, third, fourth}
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, T4, O
|
||||
---@param first integer|string|fun(v: I): T1
|
||||
---@param second integer|string|fun(v: T1): T2
|
||||
---@param third integer|string|fun(v: T2): T3
|
||||
---@param fourth integer|string|fun(v: T3): T4
|
||||
---@param fifth integer|string|fun(v: T4): O
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(first, second, third, fourth, fifth)
|
||||
error {first, second, third, fourth, fifth}
|
||||
end
|
||||
|
||||
---@generic I, O
|
||||
---@param all { [1]: (integer|string|fun(v: I): O) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T, O
|
||||
---@param all { [1]: (integer|string|fun(v: I): T), [2]: (integer|string|fun(v: T): O) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, O
|
||||
---@param all { [1]: (integer|string|fun(v: I): T1), [2]: (integer|string|fun(v: T1): T2), [3]: (integer|string|fun(v: T2): O) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, O
|
||||
---@param all { [1]: (integer|string|fun(v: I): T1), [2]: (integer|string|fun(v: T1): T2), [3]: (integer|string|fun(v: T2): T3), [4]: (integer|string|fun(v: T3): O) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, T4, O
|
||||
---@param all { [1]: (integer|string|fun(v: I): T1), [2]: (integer|string|fun(v: T1): T2), [3]: (integer|string|fun(v: T2): T3), [4]: (integer|string|fun(v: T3): T4), [4]: (integer|string|fun(v: T4): O) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.chain(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, O
|
||||
---@param first integer|string|fun(v: I): O
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(first)
|
||||
error {first}
|
||||
end
|
||||
|
||||
---@generic I, T, O
|
||||
---@param first integer|string|fun(v: T): O
|
||||
---@param second integer|string|fun(v: I): T
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(first, second)
|
||||
error {first, second}
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, O
|
||||
---@param first integer|string|fun(v: T2): O
|
||||
---@param second integer|string|fun(v: T1): T2
|
||||
---@param third integer|string|fun(v: I): T1
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(first, second, third)
|
||||
error {first, second, third}
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, O
|
||||
---@param first integer|string|fun(v: T3): O
|
||||
---@param second integer|string|fun(v: T2): T3
|
||||
---@param third integer|string|fun(v: T1): T2
|
||||
---@param fourth integer|string|fun(v: I): T1
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(first, second, third, fourth)
|
||||
error {first, second, third, fourth}
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, T4, O
|
||||
---@param first integer|string|fun(v: T4): O
|
||||
---@param second integer|string|fun(v: T3): T4
|
||||
---@param third integer|string|fun(v: T2): T3
|
||||
---@param fourth integer|string|fun(v: T1): T2
|
||||
---@param fifth integer|string|fun(v: I): T1
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(first, second, third, fourth, fifth)
|
||||
error {first, second, third, fourth, fifth}
|
||||
end
|
||||
|
||||
---@generic I, O
|
||||
---@param all { [1]: (integer|string|fun(v: I): O) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T, O
|
||||
---@param all { [1]: (integer|string|fun(v: T): O), [2]: (integer|string|fun(v: I): T) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, O
|
||||
---@param all { [1]: (integer|string|fun(v: T2): O), [2]: (integer|string|fun(v: T1): T2), [3]: (integer|string|fun(v: I): T1) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, O
|
||||
---@param all { [1]: (integer|string|fun(v: T3): O), [2]: (integer|string|fun(v: T2): T3), [3]: (integer|string|fun(v: T1): T2), [4]: (integer|string|fun(v: I): T1) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic I, T1, T2, T3, T4, O
|
||||
---@param all { [1]: (integer|string|fun(v: T4): O), [2]: (integer|string|fun(v: T3): T4), [3]: (integer|string|fun(v: T2): T3), [4]: (integer|string|fun(v: T1): T2), [4]: (integer|string|fun(v: I): T1) }
|
||||
---@return fun(v: I): O
|
||||
---@nodiscard
|
||||
function f.compose(all)
|
||||
error(all)
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param self F | { [K]: V }
|
||||
---@return K?, V?
|
||||
|
|
@ -235,51 +18,35 @@ end
|
|||
---@type F
|
||||
local none
|
||||
|
||||
---@generic T: F|function|string|nil
|
||||
---@param func T
|
||||
---@return T
|
||||
---@nodiscard
|
||||
local function autofunc(func)
|
||||
if func == false then
|
||||
return f.fals
|
||||
elseif func == true then
|
||||
return f.tru
|
||||
elseif type(func) == "number" then
|
||||
return f.arg(func)
|
||||
elseif type(func) == "string" then
|
||||
return f.indices(func)
|
||||
else
|
||||
return func or f.id
|
||||
end
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param tbl table<K, V>
|
||||
---@param fpairs? fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)
|
||||
---@return fun(tbl: table<K, V>, key: K): K, V
|
||||
---@return table<K, V>
|
||||
---@return K
|
||||
---@return V
|
||||
---@nodiscard
|
||||
local function autopairs(tbl, fpairs)
|
||||
return (fpairs or (tbl[1] and ipairs or pairs))(tbl)
|
||||
return (fpairs or tbl[#tbl] and ipairs or pairs)(tbl)
|
||||
end
|
||||
|
||||
---@param any any
|
||||
---@return boolean
|
||||
local function is_f(any)
|
||||
return type(any) == "table" and any.from == f.from and any.new == f.new
|
||||
end
|
||||
|
||||
--- Always returns nil.
|
||||
---@return nil
|
||||
---@nodiscard
|
||||
function f.noop()
|
||||
end
|
||||
|
||||
--- Always returns false.
|
||||
---@return false
|
||||
---@nodiscard
|
||||
function f.fals()
|
||||
return false
|
||||
end
|
||||
|
||||
--- Always returns true.
|
||||
---@return true
|
||||
---@nodiscard
|
||||
function f.tru()
|
||||
return true
|
||||
end
|
||||
|
|
@ -288,31 +55,10 @@ end
|
|||
---@generic T
|
||||
---@param ... T
|
||||
---@return T
|
||||
---@nodiscard
|
||||
function f.id(...)
|
||||
return ...
|
||||
end
|
||||
|
||||
---@generic T
|
||||
---@param value T
|
||||
---@return fun(v: T): boolean
|
||||
---@nodiscard
|
||||
function f.eq(value)
|
||||
return function(v)
|
||||
return value == v
|
||||
end
|
||||
end
|
||||
|
||||
---@generic T
|
||||
---@param value T
|
||||
---@return fun(T): boolean
|
||||
---@nodiscard
|
||||
function f.nq(value)
|
||||
return function(v)
|
||||
return value ~= v
|
||||
end
|
||||
end
|
||||
|
||||
---@generic T
|
||||
---@param v T
|
||||
---@return fun(): T
|
||||
|
|
@ -331,200 +77,55 @@ function f.const(v)
|
|||
end
|
||||
end
|
||||
|
||||
---@param i integer
|
||||
---@return fun(...: any): any
|
||||
---@nodiscard
|
||||
function f.arg(i)
|
||||
return function(...)
|
||||
return ({...})[i]
|
||||
end
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param v K
|
||||
---@return fun(x: { [K]: V }): V
|
||||
---@nodiscard
|
||||
function f.index(v)
|
||||
return function(x)
|
||||
return type(x) == "table" and x[v] or x
|
||||
return x[v]
|
||||
end
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param v { [K]: V }
|
||||
---@return fun(x: K): V
|
||||
---@nodiscard
|
||||
function f.index_into(v)
|
||||
return type(v) == "table" and function(x)
|
||||
return v[x]
|
||||
end or f.const(v)
|
||||
end
|
||||
|
||||
---@generic V
|
||||
---@param v string
|
||||
---@return fun(x: { [string]: V }): V
|
||||
---@nodiscard
|
||||
function f.indices(v)
|
||||
return function(x)
|
||||
for i in v:gmatch "[^.]+" do
|
||||
if type(x) ~= "table" then
|
||||
return x
|
||||
end
|
||||
|
||||
x = x[i]
|
||||
end
|
||||
|
||||
return x
|
||||
end
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param v V
|
||||
---@param k K
|
||||
---@return fun(x: { [K]: V }): { [K]: V }
|
||||
---@nodiscard
|
||||
function f.insert(v, k)
|
||||
return function(x)
|
||||
if type(x) == "table" then
|
||||
x[k] = v
|
||||
end
|
||||
|
||||
return x
|
||||
end
|
||||
end
|
||||
|
||||
---@generic T
|
||||
---@param tbl T[]
|
||||
---@return fun(t: T[], i?: integer): integer, T
|
||||
---@return T[]
|
||||
function f.revpairs(tbl)
|
||||
return function(t, i)
|
||||
local k = i and i - 1 or #t
|
||||
local v = t[k]
|
||||
|
||||
if v ~= nil then
|
||||
return k, v
|
||||
end
|
||||
end, tbl
|
||||
end
|
||||
|
||||
---@param any any
|
||||
---@return boolean
|
||||
---@nodiscard
|
||||
function f.isf(any)
|
||||
return type(any) == "table" and any.from == f.from and any.new == f.new
|
||||
end
|
||||
|
||||
local unpack = table.unpack or unpack
|
||||
|
||||
f[true and "call"] = function(self, ...)
|
||||
local args = {...}
|
||||
|
||||
return type(self) == "string" and function(v)
|
||||
return v[self](v, unpack(args))
|
||||
end or function(v)
|
||||
return v(unpack(args))
|
||||
end
|
||||
end
|
||||
|
||||
f[true and "chain"] = function(...)
|
||||
local ret
|
||||
|
||||
for _, v in ipairs {...} do
|
||||
v = f.isf(v) and v:table() or v
|
||||
|
||||
if type(v) == "table" then
|
||||
for _, vv in ipairs(v) do
|
||||
local copy = ret
|
||||
vv = autofunc(vv)
|
||||
|
||||
ret = ret and function(...)
|
||||
return vv(copy(...))
|
||||
end or vv
|
||||
end
|
||||
else
|
||||
local copy = ret
|
||||
v = autofunc(v)
|
||||
|
||||
ret = ret and function(...)
|
||||
return v(copy(...))
|
||||
end or v
|
||||
end
|
||||
end
|
||||
|
||||
return ret or f.noop
|
||||
end
|
||||
|
||||
f[true and "compose"] = function(...)
|
||||
return f.chain(f.from({...}, f.revpairs):values())
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param fnext? fun(): K?, V?
|
||||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
function f.new(fnext)
|
||||
-- Iterating over `f` is far easier, but we do this for performance sake.
|
||||
return {
|
||||
all = f.all,
|
||||
any = f.any,
|
||||
arg = f.arg,
|
||||
call = f.call,
|
||||
chain = f.chain,
|
||||
compose = f.compose,
|
||||
concat = f.concat,
|
||||
const = f.const,
|
||||
count = f.count,
|
||||
diff = f.diff,
|
||||
each = f.each,
|
||||
eq = f.eq,
|
||||
fals = f.fals,
|
||||
flatmap = f.flatmap,
|
||||
fold = f.fold,
|
||||
from = f.from,
|
||||
id = f.id,
|
||||
index = f.index,
|
||||
index_into = f.index_into,
|
||||
indices = f.indices,
|
||||
insert = f.insert,
|
||||
isf = f.isf,
|
||||
keys = f.keys,
|
||||
map = f.map,
|
||||
new = f.new,
|
||||
next = fnext or f.noop,
|
||||
noop = f.noop,
|
||||
nq = f.nq,
|
||||
peek = f.peek,
|
||||
pun = f.pun,
|
||||
rev = f.rev,
|
||||
revpairs = f.revpairs,
|
||||
skip = f.skip,
|
||||
slice = f.slice,
|
||||
string = f.string,
|
||||
swap = f.swap,
|
||||
table = f.table,
|
||||
take = f.take,
|
||||
tru = f.tru,
|
||||
values = f.values,
|
||||
where = f.where,
|
||||
}
|
||||
local ret = {next = fnext or f.noop}
|
||||
|
||||
for k, v in pairs(f) do
|
||||
ret[k] = v
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Creates an enumeration.
|
||||
---@type FFrom
|
||||
---@generic K, V
|
||||
---@param iter table<K, V>
|
||||
---@param fpairs? fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K?, V?)
|
||||
---@param step? nil
|
||||
---@return F | { [K]: V }
|
||||
---@overload fun(iter: number, fpairs?: number, step?: number): F | { [number]: number }
|
||||
---@overload fun(iter: string): (fun(table: { [string]: V }): V)
|
||||
---@overload fun(iter: fun(): K, V): F | { [K]: V }
|
||||
---@overload fun(iter: false): fun(): false
|
||||
---@overload fun(iter: true): fun(): true
|
||||
---@overload fun(iter: nil): F
|
||||
function f.from(iter, fpairs, step)
|
||||
if iter == nil then
|
||||
return none
|
||||
elseif iter == true then
|
||||
if iter == true then
|
||||
return f.tru
|
||||
elseif iter == false then
|
||||
return f.fals
|
||||
elseif iter == nil then
|
||||
return none
|
||||
end
|
||||
|
||||
local t = type(iter)
|
||||
|
||||
if t == "string" then
|
||||
return f.indices(iter)
|
||||
return f.index(iter)
|
||||
elseif t == "number" then
|
||||
local ik, is, start = 0, step or 1, fpairs and iter or 1
|
||||
|
||||
|
|
@ -556,10 +157,10 @@ function f.from(iter, fpairs, step)
|
|||
end
|
||||
end)
|
||||
else
|
||||
local next, tbl, k, v = autopairs(iter, type(fpairs) == "function" and fpairs or nil)
|
||||
local next, context, k, v = autopairs(iter, fpairs)
|
||||
|
||||
return f.new(function()
|
||||
k, v = next(tbl, k)
|
||||
k, v = next(context, k)
|
||||
return k, v
|
||||
end)
|
||||
end
|
||||
|
|
@ -571,14 +172,12 @@ end
|
|||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
function f:concat(...)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
local fsi = 0
|
||||
local fs = {...}
|
||||
local sum, last = 0, 0
|
||||
|
||||
for i = 1, #fs do
|
||||
local s = fs[i]
|
||||
fs[i] = f.isf(s) and s or f.from(s)
|
||||
fs[i] = is_f(fs[i]) and fs[i] or f.from(fs[i])
|
||||
end
|
||||
|
||||
return f.new(function()
|
||||
|
|
@ -606,34 +205,14 @@ function f:concat(...)
|
|||
end)
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func fun(v: V, k: K): any
|
||||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
function f:peek(func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
func = autofunc(func)
|
||||
|
||||
return f.new(function()
|
||||
local k, v = self:next()
|
||||
|
||||
if k ~= nil then
|
||||
func(v, k)
|
||||
return k, v
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---@generic K, V, U
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func fun(v: V, k: K): U
|
||||
---@param func F|fun(v: V, k: K): U
|
||||
---@return F|{ [K]: U }
|
||||
---@overload fun(self: F|{ [K]: V }, func: string): F|{ [K]: U }
|
||||
---@nodiscard
|
||||
---@overload fun(self: F|{ [K]: V }, func: string): F|{ [K]: U }
|
||||
function f:map(func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
func = autofunc(func)
|
||||
func = type(func) == "string" and f.index(func) or func
|
||||
|
||||
return f.new(function()
|
||||
local k, v = self:next()
|
||||
|
|
@ -646,20 +225,17 @@ end
|
|||
|
||||
---@generic K, V, U
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func fun(v: V, k: K): { [any]: U }
|
||||
---@param func F|fun(v: V, k: K): { [any]: U }
|
||||
---@param fpairs? fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)
|
||||
---@return F|{ [K]: U }
|
||||
---@overload fun(self: F|{ [K]: V }, func: string, fpairs?: fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)): F|{ [K]: U }
|
||||
---@nodiscard
|
||||
---@overload fun(self: F|{ [K]: V }, func: string, fpairs?: fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)): F|{ [K]: U }
|
||||
function f:flatmap(func, fpairs)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
-- local i = 0
|
||||
local vt, vk, vp
|
||||
func = autofunc(func)
|
||||
local vt, vk, vv, vp
|
||||
func = type(func) == "string" and f.index(func) or func
|
||||
|
||||
return f.new(function()
|
||||
local vv
|
||||
|
||||
if vk then
|
||||
vk, vv = vp(vt, vk)
|
||||
|
||||
|
|
@ -699,14 +275,13 @@ end
|
|||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func fun(v: V, k: K): boolean
|
||||
---@param func F|fun(v: V, k: K): boolean
|
||||
---@param is? any
|
||||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
---@overload fun(self: F|{ [K]: V }, func: string, is?: any): F|{ [K]: V }
|
||||
function f:where(func, is)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
func = autofunc(func)
|
||||
func = type(func) == "string" and f.index(func) or func
|
||||
|
||||
return f.new(function()
|
||||
local k, v
|
||||
|
|
@ -738,7 +313,6 @@ end
|
|||
---@return F|{ [integer]: K }
|
||||
---@nodiscard
|
||||
function f:keys()
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
local i = 0
|
||||
|
||||
return f.new(function()
|
||||
|
|
@ -756,7 +330,6 @@ end
|
|||
---@return F|{ [integer]: V }
|
||||
---@nodiscard
|
||||
function f:values()
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
local i = 0
|
||||
|
||||
return f.new(function()
|
||||
|
|
@ -774,8 +347,6 @@ end
|
|||
---@return F|{ [V]: K }
|
||||
---@nodiscard
|
||||
function f:swap()
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
|
||||
return f.new(function()
|
||||
local k, v = self:next()
|
||||
|
||||
|
|
@ -785,28 +356,6 @@ function f:swap()
|
|||
end)
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
function f:rev()
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
local t, p, k
|
||||
|
||||
return f.new(function()
|
||||
if not t then
|
||||
p, t = f.revpairs(self:table())
|
||||
end
|
||||
|
||||
local v
|
||||
k, v = p(t, k)
|
||||
|
||||
if k ~= nil then
|
||||
return k, v
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param skip? integer
|
||||
|
|
@ -814,8 +363,6 @@ end
|
|||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
function f:slice(skip, take)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
|
||||
if (not skip or skip <= 0) and not take then
|
||||
return self
|
||||
end
|
||||
|
|
@ -847,7 +394,6 @@ end
|
|||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
function f:skip(n)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
return self:slice(n)
|
||||
end
|
||||
|
||||
|
|
@ -857,7 +403,6 @@ end
|
|||
---@return F|{ [K]: V }
|
||||
---@nodiscard
|
||||
function f:take(n)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
return self:slice(0, n)
|
||||
end
|
||||
|
||||
|
|
@ -869,7 +414,6 @@ end
|
|||
---@overload fun(self: F|{ [K]: V }, seed: fun(a: A, v: V, k: K): A): A
|
||||
---@nodiscard
|
||||
function f:fold(seed, func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
local k, v
|
||||
|
||||
if not func then
|
||||
|
|
@ -894,13 +438,12 @@ end
|
|||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func fun(v: V, k: K): any
|
||||
---@param func F|fun(v: V, k: K): boolean
|
||||
---@return boolean|V
|
||||
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
|
||||
---@nodiscard
|
||||
---@overload fun(self: F|{ [K]: V }, func: string): boolean|V
|
||||
function f:any(func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
func = autofunc(func)
|
||||
func = type(func) == "string" and f.index(func) or func
|
||||
|
||||
for k, v in self.next do
|
||||
if not func or func(v, k) then
|
||||
|
|
@ -913,13 +456,12 @@ end
|
|||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func fun(v: V, k: K): any
|
||||
---@param func F|fun(v: V, k: K): boolean
|
||||
---@return boolean|V
|
||||
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
|
||||
---@nodiscard
|
||||
---@overload fun(self: F|{ [K]: V }, func: string): boolean|V
|
||||
function f:all(func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
func = autofunc(func)
|
||||
func = type(func) == "string" and f.index(func) or func
|
||||
|
||||
for k, v in self.next do
|
||||
if not func or not func(v, k) then
|
||||
|
|
@ -932,14 +474,13 @@ end
|
|||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func fun(v: V, k: K): any
|
||||
---@param func F|fun(v: V, k: K): boolean
|
||||
---@return integer
|
||||
---@overload fun(self: F|{ [K]: V }, func: string): integer
|
||||
---@nodiscard
|
||||
---@overload fun(self: F|{ [K]: V }, func: string): integer
|
||||
function f:count(func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
func = autofunc(func)
|
||||
local ret = 0
|
||||
func = type(func) == "string" and f.index(func) or func
|
||||
|
||||
for k, v in self.next do
|
||||
if not func or func(v, k) then
|
||||
|
|
@ -950,39 +491,11 @@ function f:count(func)
|
|||
return ret
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param other { [K]: V }
|
||||
---@param func? fun(v: V, k: K): any
|
||||
---@return K?, V?
|
||||
---@overload fun(self: F|{ [K]: V }, func: string): integer
|
||||
---@nodiscard
|
||||
function f:diff(other, func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
func = autofunc(func)
|
||||
|
||||
for k, v in self.next do
|
||||
if (not func or func(v, k)) and other[k] ~= v then
|
||||
return k, v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@generic K, V, T
|
||||
---@param self F|{ [K]: V }
|
||||
---@param _ `T`
|
||||
---@return F|{ [K]: `T` }
|
||||
---@nodiscard
|
||||
function f:pun(_)
|
||||
return self
|
||||
end
|
||||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@return string
|
||||
---@nodiscard
|
||||
function f:string()
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
local k, v = self:next()
|
||||
|
||||
if k == nil then
|
||||
|
|
@ -1007,7 +520,6 @@ end
|
|||
---@return { [K]: V }
|
||||
---@nodiscard
|
||||
function f:table()
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
local ret = {}
|
||||
|
||||
for k, v in self.next do
|
||||
|
|
@ -1019,10 +531,8 @@ end
|
|||
|
||||
---@generic K, V
|
||||
---@param self F|{ [K]: V }
|
||||
---@param func? fun(v: V, k: K): nil
|
||||
---@param func? fun(v: V, k: K)
|
||||
function f:each(func)
|
||||
self = f.isf(self) and self or f.from(self)
|
||||
|
||||
for k, v in self.next do
|
||||
if func then
|
||||
func(v, k)
|
||||
|
|
@ -1032,11 +542,4 @@ end
|
|||
|
||||
none = f.new()
|
||||
|
||||
---@type F|FFrom
|
||||
local ret = (setmetatable or f.const(f.from))(f, {
|
||||
__call = function(_, ...)
|
||||
return f.from(...)
|
||||
end,
|
||||
})
|
||||
|
||||
return ret
|
||||
return f.from
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
---@meta
|
||||
---@alias Attributes "mult"|"chips"|"xmult"|"xchips"|"score"|"xscore"|"blindsize"|"xblindsize"|"balance"|"swap"|"retrigger"|"scaling"|"reset"|"suit"|"diamonds"|"hearts"|"spades"|"clubs"|"hand_type"|"rank"|"ace"|"two"|"three"|"four"|"five"|"six"|"seven"|"eight"|"nine"|"ten"|"jack"|"queen"|"king"|"face"|"economy"|"generation"|"destroy_card"|"hands"|"discard"|"hand_size"|"chance"|"joker_slot"|"mod_chance"|"copying"|"full_deck"|"passive"|"joker"|"tarot"|"planet"|"spectral"|"enhancements"|"seals"|"editions"|"tag"|"skip"|"modify_card"|"perma_bonus"|"prevents_death"|"boss_blind"|"reroll"|"on_sell"|"sell_value"|"food"|"space"|"bakery_double_sided"|"bakery_usable"|"bakery_werewolf"
|
||||
---@type Card[]
|
||||
CardArea.cards = CardArea.cards
|
||||
|
||||
--- @overload fun(tbl: SMODS.Joker): SMODS.GameObject
|
||||
Bakery_API.Charm = Bakery_API.Charm
|
||||
|
||||
--- @generic T: SMODS.GameObject
|
||||
--- @param obj T
|
||||
--- @return T
|
||||
function Bakery_API.credit(obj)
|
||||
error(obj)
|
||||
end
|
||||
|
||||
---@type table
|
||||
Balatest = Balatest
|
||||
|
||||
--- @type { constants?: { TEN: table }, new: (fun(self: self, arr?: number[], sign?: number, noNormalize?: boolean): table), pow: (fun(x: number, y: number): number) }
|
||||
Big = Big
|
||||
|
||||
--- @type table?
|
||||
CardSleeves = CardSleeves
|
||||
|
||||
--- @type table|fun(obj: SMODS.Back): SMODS.Back
|
||||
CardSleeves.Sleeve = CardSleeves.Sleeve
|
||||
|
||||
--- @type {aliases: { [string]: [string] }}
|
||||
Cryptid = Cryptid
|
||||
|
||||
---@return Card
|
||||
function copy_card(...)
|
||||
error(...)
|
||||
end
|
||||
|
||||
--- @type fun(area: CardArea, ...: ...): Card
|
||||
create_card_for_shop = create_card_for_shop
|
||||
|
||||
--- @type CardArea
|
||||
G.Bakery_charm_area = G.Bakery_charm_area
|
||||
|
||||
--- @type boolean|table
|
||||
G.Bakery_charm_area.cards[1].ability.extra = G.Bakery_charm_area.cards[1].ability.extra
|
||||
|
||||
---@type Card[]
|
||||
G.playing_cards = G.playing_cards
|
||||
|
||||
---@type userdata|{getWidth: fun(self: self): number}
|
||||
SMODS.Atlas.image_data = SMODS.Atlas.image_data
|
||||
|
||||
---@param context CalcContext|table|{hand_drawn: true, other_drawn: true}
|
||||
---@param return_table? table
|
||||
---@return table?
|
||||
function SMODS.calculate_context(context, return_table)
|
||||
error {context, return_table}
|
||||
end
|
||||
|
||||
SMODS.Mods.Roland.config = require "config"
|
||||
|
||||
---@type (fun(rem: number): number|table)[]
|
||||
SMODS.Mods.Roland.harsh_ante_scaling = SMODS.Mods.Roland.harsh_ante_scaling
|
||||
|
||||
--- @type table
|
||||
Talisman = Talisman
|
||||
|
||||
--- @type fun(obj: any): number
|
||||
to_number = to_number
|
||||
|
||||
-- This exists to remove the @deprecated warning.
|
||||
---Returns the elements from the given `list`. This function is equivalent to
|
||||
---```lua
|
||||
--- return list[i], list[i+1], ···, list[j]
|
||||
---```
|
||||
---
|
||||
---
|
||||
---[View documents](command:extension.lua.doc?["en-us/52/manual.html/pdf-unpack"])
|
||||
---
|
||||
---@generic T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
|
||||
---@param list {
|
||||
--- [1]?: T1,
|
||||
--- [2]?: T2,
|
||||
--- [3]?: T3,
|
||||
--- [4]?: T4,
|
||||
--- [5]?: T5,
|
||||
--- [6]?: T6,
|
||||
--- [7]?: T7,
|
||||
--- [8]?: T8,
|
||||
--- [9]?: T9,
|
||||
--- [10]?: T10,
|
||||
---}
|
||||
---@param i? integer
|
||||
---@param j? integer
|
||||
---@return T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
|
||||
---@nodiscard
|
||||
function unpack(list, i, j)
|
||||
error {list, i, j}
|
||||
end
|
||||
|
|
@ -1,89 +1,3 @@
|
|||
local f = assert(SMODS.load_file "src/lib/funky.lua")() or require "lib.funky"
|
||||
|
||||
---@param v string
|
||||
---@return Card|Tag
|
||||
local function add(v)
|
||||
if v == "op" then
|
||||
local op = SMODS.add_card {no_edition = true, key = "j_joker"}
|
||||
op.ability.mult = 1e100
|
||||
return op
|
||||
elseif v == "xop" then
|
||||
local xop = SMODS.add_card {no_edition = true, key = "j_Roland_jokersr"}
|
||||
xop.ability.extra.xmult = 1e100
|
||||
return xop
|
||||
end
|
||||
|
||||
if G.P_BLINDS[v] then
|
||||
if G.STATE ~= G.STATES.MENU then
|
||||
G.from_boss_tag = true
|
||||
G.GAME.perscribed_bosses = G.GAME.perscribed_bosses or {}
|
||||
G.GAME.perscribed_bosses[G.GAME.round_resets.ante] = v
|
||||
G.FUNCS.reroll_boss()
|
||||
end
|
||||
|
||||
return G.P_BLINDS[v]
|
||||
end
|
||||
|
||||
if not G.P_TAGS[v] then
|
||||
return SMODS.add_card {
|
||||
no_edition = true,
|
||||
key = v,
|
||||
area = G.P_CENTERS[v] and
|
||||
(({Default = true, Enhanced = true})[G.P_CENTERS[v].set] and G.hand or
|
||||
G.P_CENTERS[v].set == "Booster" and G.shop_booster or
|
||||
G.P_CENTERS[v].set == "Voucher" and G.shop_vouchers) or nil,
|
||||
}
|
||||
end
|
||||
|
||||
local tag = Tag(v)
|
||||
|
||||
if tag.name == "Orbital Tag" then
|
||||
local hands = f(G.GAME.hands):where "visible":keys():table()
|
||||
tag.ability.orbital_hand = pseudorandom_element(hands, pseudoseed "Roland_c_orbital_tag")
|
||||
end
|
||||
|
||||
add_tag(tag)
|
||||
return tag
|
||||
end
|
||||
|
||||
local function simplify(x)
|
||||
return type(x) == "string" and x:lower():gsub("%s", ""):gsub("_", ""):gsub("^the", "") or x
|
||||
end
|
||||
|
||||
local function flatten(v)
|
||||
return type(v) ~= "table" and {v} or (f.isf(v) and v:table() or v)
|
||||
end
|
||||
|
||||
---@param it string
|
||||
local function find(it)
|
||||
if ({op = true, xop = true})[it] or (G.P_CENTERS[it] or {}).config then
|
||||
return it
|
||||
end
|
||||
|
||||
local match = simplify(it)
|
||||
|
||||
local pool = match == "Blind" and G.P_BLINDS or
|
||||
f(G.P_CENTER_POOLS):any(f.chain(f.arg(2), simplify, f.eq(match)))
|
||||
|
||||
if type(pool) == "table" and next(pool) then
|
||||
return pseudorandom_element(pool, pseudoseed "Roland_c").key
|
||||
end
|
||||
|
||||
if Cryptid and Cryptid.aliases and Cryptid.aliases[it] then
|
||||
return Cryptid.aliases[it]
|
||||
end
|
||||
|
||||
return f(G.localization.descriptions)
|
||||
:flatmap(flatten)
|
||||
:where(type, "table")
|
||||
:where(function(v, k)
|
||||
return ((G.P_CENTERS[k] or {}).config or G.P_BLINDS[k]) and
|
||||
(match == simplify(k) or match == simplify(v.name))
|
||||
end)
|
||||
:keys()
|
||||
:any()
|
||||
end
|
||||
|
||||
local function protect(fun)
|
||||
return function()
|
||||
local res, ret = pcall(fun)
|
||||
|
|
@ -92,83 +6,76 @@ local function protect(fun)
|
|||
sendErrorMessage(tostring(ret), "Roland")
|
||||
end
|
||||
|
||||
return not res or ret ~= false and not (SMODS.current_mod and ret ~= true)
|
||||
return not res or ret ~= false
|
||||
end
|
||||
end
|
||||
|
||||
local function protect_ev(fun)
|
||||
if type(fun) == "function" then
|
||||
return Event {func = protect(fun)}
|
||||
elseif type(fun) ~= "table" then
|
||||
error("Expected a function or table, got a " .. type(fun), 3)
|
||||
elseif type(fun.is) == "function" and fun:is(SMODS.GameObject) then
|
||||
return Event {
|
||||
blocking = false,
|
||||
no_delete = true,
|
||||
func = protect(function()
|
||||
if not Bakery_API or not Bakery_API.credit then
|
||||
return false
|
||||
if type(fun) == "table" then
|
||||
fun.func = protect(fun.func)
|
||||
fun = getmetatable(fun) == Event and fun or Event(fun)
|
||||
elseif type(fun) == "function" then
|
||||
fun = Event {func = protect(fun)}
|
||||
else
|
||||
error("Expected a function or event, got a " .. type(fun), 3)
|
||||
end
|
||||
|
||||
Bakery_API.credit(fun)
|
||||
end),
|
||||
}
|
||||
else
|
||||
fun.func = protect(fun.func or fun[1])
|
||||
return getmetatable(fun) == Event and fun or Event(fun)
|
||||
return fun
|
||||
end
|
||||
|
||||
if false then
|
||||
-- This allows for better type inference.
|
||||
SMODS.Mods.Roland.config = require "config"
|
||||
|
||||
-- This exists to remove the @deprecated warning.
|
||||
---Returns the elements from the given `list`. This function is equivalent to
|
||||
---```lua
|
||||
--- return list[i], list[i+1], ···, list[j]
|
||||
---```
|
||||
---
|
||||
---
|
||||
---[View documents](command:extension.lua.doc?["en-us/52/manual.html/pdf-unpack"])
|
||||
---
|
||||
---@generic T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
|
||||
---@param list {
|
||||
--- [1]?: T1,
|
||||
--- [2]?: T2,
|
||||
--- [3]?: T3,
|
||||
--- [4]?: T4,
|
||||
--- [5]?: T5,
|
||||
--- [6]?: T6,
|
||||
--- [7]?: T7,
|
||||
--- [8]?: T8,
|
||||
--- [9]?: T9,
|
||||
--- [10]?: T10,
|
||||
---}
|
||||
---@param i? integer
|
||||
---@param j? integer
|
||||
---@return T1, T2, T3, T4, T5, T6, T7, T8, T9, T10
|
||||
---@nodiscard
|
||||
function unpack(list, i, j)
|
||||
error {list, i, j}
|
||||
end
|
||||
end
|
||||
|
||||
local f = assert(SMODS.load_file "src/lib/funky.lua")() or require "lib.funky"
|
||||
|
||||
--- Queues an event to be run.
|
||||
--- Note that events added this way implicitly `return true` unless you explicitly `return false`.
|
||||
--- For `front`; boolean `true` to add the event to the front of the queue, rather than the end.
|
||||
--- @generic T: fun():boolean?|Event
|
||||
--- @param fun T|Event|{front?: boolean} The table or function to turn into an event.
|
||||
--- @return T fun
|
||||
local function q(fun)
|
||||
local ev = protect_ev(fun)
|
||||
G.E_MANAGER:add_event(ev, nil, ev.front)
|
||||
return fun
|
||||
--- Note that events added this way implicitly `return true` unless you explicitly `return false`, unlike the vanilla ones.
|
||||
--- @param fun (fun():false|nil)|Event The event or a function to run turn into an event.
|
||||
--- @param front boolean|nil `true` to add the event to the front of the queue, rather than the end.
|
||||
local function q(fun, front)
|
||||
G.E_MANAGER:add_event(protect_ev(fun), nil, front)
|
||||
end
|
||||
|
||||
--- Determines if a center is allowed to be usable.
|
||||
---@return boolean
|
||||
local function u()
|
||||
return not ((G.play and next(G.play.cards) or G.CONTROLLER.locked or G.GAME.STOP_USE and G.GAME.STOP_USE > 0) and
|
||||
return not ((G.play and #G.play.cards > 0 or G.CONTROLLER.locked or
|
||||
(G.GAME.STOP_USE and G.GAME.STOP_USE > 0)) and
|
||||
G.STATE ~= G.STATES.HAND_PLAYED and
|
||||
G.STATE ~= G.STATES.DRAW_TO_HAND and
|
||||
G.STATE ~= G.STATES.PLAY_TAROT)
|
||||
end
|
||||
|
||||
--- Creates one or more cards.
|
||||
---@param ... any
|
||||
---@return Card|Tag|(Card|Tag[])
|
||||
local function c(...)
|
||||
local cards = f {...}
|
||||
:flatmap(flatten)
|
||||
:where(type, "string")
|
||||
:map(string.lower)
|
||||
:map(find)
|
||||
:where(f.id)
|
||||
:map(add)
|
||||
:values()
|
||||
:table()
|
||||
|
||||
return #cards > 1 and cards or cards[1]
|
||||
end
|
||||
|
||||
return {f, q, u, setmetatable({}, {
|
||||
__call = function(_, ...)
|
||||
return c(...)
|
||||
end,
|
||||
__index = function(_, k)
|
||||
return c(k)
|
||||
end,
|
||||
__newindex = function(_, k, v)
|
||||
local n = tonumber(v)
|
||||
|
||||
for _ = 1, type(n) == "number" and n or 1 do
|
||||
c(k)
|
||||
end
|
||||
end,
|
||||
})}
|
||||
return {f, q, u}
|
||||
|
|
|
|||
98
src/main.lua
|
|
@ -1,97 +1,73 @@
|
|||
local qol = assert(SMODS.load_file "src/lib/shared.lua")() or require "lib.shared"
|
||||
local animated = SMODS.current_mod.config.animated_icon
|
||||
SMODS.current_mod.qol = qol
|
||||
local f, q = qol[1], qol[2]
|
||||
local f, q = unpack(qol)
|
||||
|
||||
q {
|
||||
front = true,
|
||||
no_delete = true,
|
||||
blocking = false,
|
||||
blockable = false,
|
||||
func = function()
|
||||
local contributors = (Bakery_API or {}).contributors
|
||||
|
||||
if not contributors then
|
||||
return false
|
||||
end
|
||||
|
||||
f(assert(SMODS.load_file("src/credits.lua", "Roland"))() or require "credits"):each(function(v, k)
|
||||
contributors["Roland_" .. k] = v
|
||||
end)
|
||||
|
||||
if SMODS.Mods.DebugPlus and SMODS.Mods.Roland.config.import_funky then
|
||||
_G.f, _G.q, _G.u, _G.c = unpack(qol)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
f {"challenge", "spectral", "edition", "voucher", "tweaks", "blind", "charm", "joker", "tarot", "back", "seal", "tag"}
|
||||
:each(function(v)
|
||||
f {"challenge", "spectral", "edition", "tweaks", "blind", "charm", "joker", "back", "seal"}:each(function(v)
|
||||
assert(SMODS.load_file("src/" .. v .. ".lua"))(qol)
|
||||
end)
|
||||
|
||||
local _ = Balatest and f {"joker", "blind", "spectral"}:each(function(v)
|
||||
if _G["Balatest"] then
|
||||
f {"joker", "blind", "spectral"}:each(function(v)
|
||||
assert(SMODS.load_file("src/tests/" .. v .. ".tests.lua"))(qol)
|
||||
end)
|
||||
|
||||
local function realign(tbl)
|
||||
f(tbl):where(function(v, k)
|
||||
if k == "align" and type(v) == "string" then
|
||||
tbl[k] = "tr"
|
||||
end
|
||||
|
||||
return k ~= "nodes" and type(v) == "table"
|
||||
end):each(realign)
|
||||
q(function()
|
||||
---@type table<string, {name: string, fg: table, bg: table}>
|
||||
local contributors, mods = Bakery_API.contributors, SMODS.Mods
|
||||
|
||||
return tbl
|
||||
contributors.Roland_aster = {
|
||||
name = "asterSSH",
|
||||
fg = HEX "f8f8f2ff",
|
||||
bg = HEX "bd93f9ff",
|
||||
}
|
||||
|
||||
contributors.Roland_char = {
|
||||
name = "char (@irregulester)",
|
||||
fg = HEX "f8f8f2ff",
|
||||
bg = HEX "ff79c6ff",
|
||||
}
|
||||
|
||||
if mods.DebugPlus and mods.Roland.config.import_funky then
|
||||
_G.f, _G.q, _G.u = unpack(qol)
|
||||
end
|
||||
end, true)
|
||||
|
||||
local function toggle(id)
|
||||
return realign(create_toggle {
|
||||
return create_toggle {
|
||||
label = localize {type = "variable", key = "b_Roland_" .. id},
|
||||
ref_table = SMODS.Mods.Roland.config,
|
||||
ref_value = id,
|
||||
scale = 1.5,
|
||||
})
|
||||
}
|
||||
end
|
||||
|
||||
SMODS.Atlas {
|
||||
px = 256,
|
||||
py = 256,
|
||||
key = "modicon",
|
||||
fps = animated and 12 or nil,
|
||||
frames = animated and 12 or nil,
|
||||
path = animated and "icon.png" or "unicon.png",
|
||||
atlas_table = animated and "ANIMATION_ATLAS" or "ASSET_ATLAS",
|
||||
path = "icon.png",
|
||||
}
|
||||
|
||||
function SMODS.current_mod.config_tab()
|
||||
return {
|
||||
n = G.UIT.ROOT,
|
||||
config = {minw = 1, minh = 1, align = "tr", padding = 0.1, colour = G.C.BLACK},
|
||||
nodes = {
|
||||
{
|
||||
config = {minw = 1, minh = 1, align = "tl", padding = 0.1, colour = G.C.BLACK},
|
||||
nodes = {{
|
||||
n = G.UIT.C,
|
||||
config = {minw = 1, minh = 1, align = "tr", padding = 0.1, colour = G.C.CLEAR},
|
||||
config = {minw = 1, minh = 1, align = "tl", padding = 0.1, colour = G.C.CLEAR},
|
||||
nodes = {
|
||||
toggle "animated_icon",
|
||||
toggle "cool_phones",
|
||||
toggle "vitriol",
|
||||
toggle "equinox_assist",
|
||||
G.P_CENTERS.c_Bakery_Scribe and toggle "scribable_basket",
|
||||
},
|
||||
},
|
||||
{
|
||||
n = G.UIT.C,
|
||||
config = {minw = 1, minh = 1, align = "tr", padding = 0.1, colour = G.C.CLEAR},
|
||||
nodes = {
|
||||
toggle "faster_planets",
|
||||
toggle "illusion_seal",
|
||||
toggle "no_wild_debuff",
|
||||
toggle "no_highlight_limit",
|
||||
_G["Talisman"] and toggle "harsh_ante_scaling",
|
||||
toggle "fusable_escapey",
|
||||
toggle "equinox_assist",
|
||||
SMODS.Mods.DebugPlus and toggle "import_funky",
|
||||
Talisman and toggle "harsh_ante_scaling",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
}
|
||||
end
|
||||
|
||||
function SMODS.current_mod.optional_features()
|
||||
return {cardareas = {deck = true, unscored = true}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
local f, q = unpack(... or require "lib.shared")
|
||||
|
||||
SMODS.Atlas {
|
||||
px = 71,
|
||||
|
|
@ -11,9 +11,8 @@ SMODS.Seal {
|
|||
key = "glass",
|
||||
atlas = "seal",
|
||||
pos = {x = 0, y = 0},
|
||||
attributes = {"destroy_card", "tag"},
|
||||
badge_colour = HEX "a6a6a6ff",
|
||||
pronouns = "they_them",
|
||||
pronouns = "he_him",
|
||||
calculate = function(_, card, context)
|
||||
local function eq(v)
|
||||
return v == card
|
||||
|
|
|
|||
204
src/spectral.lua
|
|
@ -1,4 +1,6 @@
|
|||
local f, q, u = (... or require "lib.shared")[1], (... or require "lib.shared")[2], (... or require "lib.shared")[3]
|
||||
local f, q, u = unpack(... or require "lib.shared")
|
||||
|
||||
local negative = {key = "e_negative_consumable", set = "Edition", config = {extra = 1}}
|
||||
|
||||
local spectral = (function()
|
||||
local x = 0
|
||||
|
|
@ -6,13 +8,19 @@ local spectral = (function()
|
|||
---@param tbl SMODS.Consumable|{artist?: string}
|
||||
---@return SMODS.Consumable
|
||||
return function(tbl)
|
||||
tbl.artist = tbl.artist and "Roland_" .. tbl.artist or nil
|
||||
tbl.pos = {x = x, y = 0}
|
||||
tbl.atlas = "spectral"
|
||||
tbl.set = "Spectral"
|
||||
tbl.cost = 4
|
||||
tbl.set = "Spectral"
|
||||
tbl.atlas = "spectral"
|
||||
tbl.pos = {x = x, y = 0}
|
||||
tbl.artist = tbl.artist and "Roland_" .. tbl.artist or nil
|
||||
local ret = SMODS.Consumable(tbl)
|
||||
x = x + 1
|
||||
return q(SMODS.Consumable(tbl))
|
||||
|
||||
q(function()
|
||||
Bakery_API.credit(ret)
|
||||
end)
|
||||
|
||||
return ret
|
||||
end
|
||||
end)()
|
||||
|
||||
|
|
@ -30,140 +38,122 @@ SMODS.Sound {
|
|||
|
||||
spectral {
|
||||
key = "afterimage",
|
||||
pronouns = "she_they",
|
||||
pronouns = "he_they",
|
||||
artist = "aster",
|
||||
config = {extra = {amount = 1, hand = -2}},
|
||||
loc_vars = function(_, info_queue, card)
|
||||
table.insert(info_queue, negative)
|
||||
return {vars = {card.ability.extra.amount, card.ability.extra.hand}}
|
||||
end,
|
||||
can_use = function(_, card)
|
||||
return u() and card.ability.extra.amount == #Bakery_API.get_highlighted()
|
||||
end,
|
||||
use = function(_, card)
|
||||
f(Bakery_API.get_highlighted()):each(function(v)
|
||||
q {
|
||||
delay = 0.1,
|
||||
func = function()
|
||||
v:set_edition {negative = true}
|
||||
end,
|
||||
}
|
||||
end)
|
||||
|
||||
q {
|
||||
delay = 0.1,
|
||||
func = function()
|
||||
G.hand:change_size(card.ability.extra.hand)
|
||||
Bakery_API.unhighlight_all()
|
||||
end,
|
||||
}
|
||||
end,
|
||||
}
|
||||
|
||||
spectral {
|
||||
key = "coolheaded",
|
||||
config = {extra = {amount = 1}},
|
||||
loc_vars = function(_, info_queue, card)
|
||||
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
|
||||
return {vars = {card.ability.extra.amount}}
|
||||
end,
|
||||
can_use = function(_, card)
|
||||
return u() and f(G.jokers.highlighted):concat(Bakery_API.get_highlighted()):count(function(v)
|
||||
return not v.edition
|
||||
end) == card.ability.extra.amount
|
||||
end,
|
||||
use = function()
|
||||
f(G.jokers.highlighted):concat(Bakery_API.get_highlighted()):each(function(v)
|
||||
q {
|
||||
delay = 0.1,
|
||||
func = function()
|
||||
v:set_edition {Roland_frozen = true}
|
||||
end,
|
||||
}
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
spectral {
|
||||
key = "dual",
|
||||
pronouns = "they_them",
|
||||
config = {extra = {amount = 2}},
|
||||
attributes = {"seal", "modify_card", "spectral"},
|
||||
loc_vars = function(_, _, card)
|
||||
return {vars = {card.ability.extra.amount}}
|
||||
end,
|
||||
can_use = function()
|
||||
return next(G.hand.cards) and u()
|
||||
return u() and #G.hand.cards > 0
|
||||
end,
|
||||
use = function(_, card)
|
||||
use = function(_, card, _)
|
||||
local cards = f(G.hand.cards):table()
|
||||
pseudoshuffle(cards, pseudoseed "RolandDual")
|
||||
|
||||
f(cards):take(card.ability.extra.amount):each(function(v)
|
||||
local seal = SMODS.poll_seal {
|
||||
guaranteed = true,
|
||||
options = f(G.P_SEALS):keys():where(f.nq "Roland_glass"):values():table(),
|
||||
}
|
||||
local seal
|
||||
|
||||
local _ = not card.Roland_immediate and q {
|
||||
delay = 0.5,
|
||||
trigger = "after",
|
||||
func = function()
|
||||
v:set_seal(seal, nil, true)
|
||||
end,
|
||||
} or v:set_seal(seal, true, true)
|
||||
for _ = 1, 31 do
|
||||
seal = SMODS.poll_seal {guaranteed = true}
|
||||
|
||||
if seal ~= "Roland_glass" then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
v:set_seal(seal == "Roland_glass" and "Red" or seal)
|
||||
end)
|
||||
end,
|
||||
bulk_use = function(self, card, area, copier, number)
|
||||
card.Roland_immediate = true
|
||||
f(number):map(f.const(self)):each(f.call("use", card, area, copier))
|
||||
card.Roland_immediate = nil
|
||||
end,
|
||||
}
|
||||
|
||||
spectral {
|
||||
key = "primal",
|
||||
key = "mirror",
|
||||
pronouns = "he_him",
|
||||
artist = "aster",
|
||||
attributes = {"enhancements", "modify_card", "spectral"},
|
||||
loc_vars = function(_, info_queue)
|
||||
table.insert(info_queue, G.P_CENTERS.m_stone)
|
||||
end,
|
||||
can_use = function()
|
||||
return next(G.hand.cards) and u()
|
||||
end,
|
||||
use = function(_, card)
|
||||
q {
|
||||
trigger = "after",
|
||||
delay = 0.4,
|
||||
func = function()
|
||||
card:juice_up(0.3, 0.5)
|
||||
play_sound "tarot1"
|
||||
end,
|
||||
}
|
||||
|
||||
f(G.hand.cards):each(function(v, k)
|
||||
local percent = 1.15 - (k - 0.999) / (#G.hand.cards - 0.998) * 0.3
|
||||
|
||||
q {
|
||||
trigger = "after",
|
||||
delay = 0.15,
|
||||
func = function()
|
||||
v:flip()
|
||||
v:juice_up(0.3, 0.3)
|
||||
play_sound("card1", percent)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
end)
|
||||
|
||||
f(G.hand.cards):each(function(v)
|
||||
q(function()
|
||||
v:set_ability(G.P_CENTERS.m_stone)
|
||||
end)
|
||||
end)
|
||||
|
||||
f(G.hand.cards):each(function(v, k)
|
||||
local percent = 0.85 + (k - 0.999) / (#G.hand.cards - 0.998) * 0.3
|
||||
|
||||
q {
|
||||
trigger = "after",
|
||||
delay = 0.15,
|
||||
func = function()
|
||||
v:flip()
|
||||
v:juice_up(0.3, 0.3)
|
||||
play_sound("tarot2", percent, 0.6)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
end)
|
||||
|
||||
delay(0.5)
|
||||
end,
|
||||
}
|
||||
|
||||
spectral {
|
||||
key = "refract",
|
||||
pronouns = "it_its",
|
||||
artist = "aster",
|
||||
config = {extra = {amount = 2}},
|
||||
attributes = {"seal", "modify_card", "spectral"},
|
||||
config = {extra = {amount = 1}},
|
||||
loc_vars = function(_, info_queue, card)
|
||||
table.insert(info_queue, G.P_SEALS.Roland_glass)
|
||||
return {vars = {card.ability.extra.amount}}
|
||||
end,
|
||||
can_use = function(_, card)
|
||||
local count = #Bakery_API.get_highlighted()
|
||||
return u() and count > 0 and count <= card.ability.extra.amount
|
||||
return u() and #Bakery_API.get_highlighted() == card.ability.extra.amount
|
||||
end,
|
||||
use = function()
|
||||
use = function(_, _, _)
|
||||
f(Bakery_API.get_highlighted()):each(function(v)
|
||||
v:set_seal "Roland_glass"
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
||||
spectral {
|
||||
local void = spectral {
|
||||
key = "void",
|
||||
pronouns = "it_its",
|
||||
artist = "aster",
|
||||
hidden = true,
|
||||
soul_rate = 0.003,
|
||||
soul_set = "Spectral",
|
||||
config = {extra = {amount = 2}},
|
||||
attributes = {"destroy_card", "generation", "spectral"},
|
||||
loc_vars = function(_, info_queue, card)
|
||||
table.insert(info_queue, {key = "e_negative_consumable", set = "Edition", config = {extra = 1}})
|
||||
table.insert(info_queue, negative)
|
||||
table.insert(info_queue, G.P_CENTERS.c_cryptid)
|
||||
return {vars = {card.ability.extra.amount}}
|
||||
end,
|
||||
can_use = function()
|
||||
return next(G.playing_cards) and u()
|
||||
return #G.playing_cards > 1 and not not u()
|
||||
end,
|
||||
use = function(_, card)
|
||||
local function destructible(v)
|
||||
|
|
@ -189,15 +179,25 @@ spectral {
|
|||
f(cards):each(destroy)
|
||||
f(G.jokers.cards):each(calculate_joker)
|
||||
|
||||
f(card.ability.extra.amount):each(function()
|
||||
for _ = 1, card.ability.extra.amount do
|
||||
local cryptid = create_card(nil, G.consumeables, nil, nil, nil, nil, "c_cryptid", "void")
|
||||
cryptid:set_edition({negative = true}, true)
|
||||
cryptid:add_to_deck()
|
||||
G.consumeables:emplace(cryptid)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
play_sound("Roland_void", 1, 0.7)
|
||||
q {delay = 0.28, timer = "REAL", trigger = "after", func = void}
|
||||
|
||||
q {
|
||||
delay = 0.28,
|
||||
timer = "REAL",
|
||||
trigger = "after",
|
||||
func = void,
|
||||
}
|
||||
end,
|
||||
}
|
||||
|
||||
q(function()
|
||||
void.hidden = not SMODS.Mods.Cryptid
|
||||
end)
|
||||
|
|
|
|||
144
src/tag.lua
|
|
@ -1,144 +0,0 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
|
||||
SMODS.Atlas {
|
||||
px = 34,
|
||||
py = 34,
|
||||
key = "tag",
|
||||
path = "tag.png",
|
||||
}
|
||||
|
||||
local function apply_frozen(tag, context)
|
||||
return function()
|
||||
q {
|
||||
delay = 0.4,
|
||||
trigger = "after",
|
||||
func = function()
|
||||
play_sound "tarot1"
|
||||
tag:juice_up(0.3, 0.5)
|
||||
end,
|
||||
}
|
||||
|
||||
q {
|
||||
delay = 0.15,
|
||||
trigger = "after",
|
||||
func = function()
|
||||
context.card:flip()
|
||||
play_sound("card1", 0.85)
|
||||
context.card:juice_up(0.3, 0.3)
|
||||
end,
|
||||
}
|
||||
|
||||
delay(0.2)
|
||||
|
||||
q {
|
||||
delay = 0.1,
|
||||
trigger = "after",
|
||||
func = function()
|
||||
context.card:set_edition {Roland_frozen = true}
|
||||
end,
|
||||
}
|
||||
|
||||
q {
|
||||
delay = 0.15,
|
||||
trigger = "after",
|
||||
func = function()
|
||||
context.card:flip()
|
||||
play_sound("tarot2", 0.85, 0.6)
|
||||
context.card:juice_up(0.3, 0.3)
|
||||
end,
|
||||
}
|
||||
|
||||
delay(0.1)
|
||||
end
|
||||
end
|
||||
|
||||
SMODS.Tag {
|
||||
key = "freeze",
|
||||
atlas = "tag",
|
||||
pronouns = "any_all",
|
||||
min_ante = 1,
|
||||
pos = {x = 0, y = 0},
|
||||
config = {amount = 5},
|
||||
loc_vars = function(self, info_queue, tag)
|
||||
tag.ability = tag.ability or {}
|
||||
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
|
||||
return {vars = {tag.ability.amount or self.config.amount}}
|
||||
end,
|
||||
apply = function(self, tag, context)
|
||||
tag.ability = tag.ability or {}
|
||||
|
||||
if not tag.triggered and context.type == "Bakery_play_hand_late" and tag.ability.amount == 0 then
|
||||
tag.triggered = true
|
||||
tag:yep("X", G.C.RED, f.tru)
|
||||
end
|
||||
|
||||
if tag.triggered or
|
||||
not context.card or
|
||||
context.card.edition or
|
||||
context.type ~= "Bakery_score_card" or
|
||||
(tag.ability.amount or self.config.amount) <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
tag.ability.amount = (tag.ability.amount or self.config.amount) - 1
|
||||
return {func = apply_frozen(tag, context)}
|
||||
end,
|
||||
}
|
||||
|
||||
SMODS.Tag {
|
||||
key = "invisible",
|
||||
atlas = "tag",
|
||||
pronouns = "any_all",
|
||||
min_ante = 2,
|
||||
pos = {x = 1, y = 0},
|
||||
config = {invis_rounds = 0, total_rounds = 2},
|
||||
loc_vars = function(self, _, tag)
|
||||
tag.ability = tag.ability or f(self.config):table()
|
||||
local main_end = {}
|
||||
|
||||
local _ = f((G.jokers or {}).cards or {}):map "edition":any "negative" and
|
||||
localize {type = "other", key = "remove_negative", nodes = main_end, vars = {}}
|
||||
|
||||
return {
|
||||
vars = {
|
||||
tag.ability.total_rounds or self.config.total_rounds,
|
||||
tag.ability.invis_rounds or self.config.invis_rounds,
|
||||
},
|
||||
main_end = main_end[1],
|
||||
}
|
||||
end,
|
||||
increment = function(self)
|
||||
f(G.GAME.tags):where("key", "tag_Roland_invisible"):each(function(v)
|
||||
v.ability = v.ability or {}
|
||||
v.ability.invis_rounds = (v.ability.invis_rounds or self.config.invis_rounds) + 1
|
||||
v:juice_up()
|
||||
end)
|
||||
end,
|
||||
apply = function(self, tag)
|
||||
local modifiers = G.GAME.modifiers
|
||||
tag.ability = tag.ability or {}
|
||||
local ab = tag.ability
|
||||
ab.invis_rounds = ab.invis_rounds or self.config.invis_rounds
|
||||
ab.total_rounds = ab.total_rounds or self.config.total_rounds
|
||||
|
||||
if tag.triggered or
|
||||
not G.jokers or
|
||||
not next(G.jokers.cards) or
|
||||
ab.invis_rounds < ab.total_rounds or
|
||||
#G.jokers.cards + (modifiers.Roland_invisible or 0) >= G.jokers.config.card_limit then
|
||||
return
|
||||
end
|
||||
|
||||
tag.triggered = true
|
||||
modifiers.Roland_invisible = (modifiers.Roland_invisible or 0) + 1
|
||||
|
||||
tag:yep("!", G.C.GREY, function()
|
||||
local copied = pseudorandom_element(G.jokers.cards, pseudoseed "Roland_invisible")
|
||||
local copy = copy_card(copied, nil, nil, nil, copied.edition and copied.edition.negative)
|
||||
G.jokers:emplace(copy)
|
||||
copy:add_to_deck()
|
||||
modifiers.Roland_invisible = (modifiers.Roland_invisible or 0) - 1
|
||||
return true
|
||||
end)
|
||||
end,
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
local f, q, u = (... or require "lib.shared")[1], (... or require "lib.shared")[2], (... or require "lib.shared")[3]
|
||||
|
||||
SMODS.Atlas {
|
||||
px = 71,
|
||||
py = 95,
|
||||
key = "tarot",
|
||||
path = "tarot.png",
|
||||
}
|
||||
|
||||
q(SMODS.Consumable {
|
||||
key = "coolheaded",
|
||||
pos = {x = 0, y = 0},
|
||||
config = {extra = {amount = 1}},
|
||||
cost = 3,
|
||||
set = "Tarot",
|
||||
atlas = "tarot",
|
||||
artist = "Roland_aster",
|
||||
attributes = {"editions", "modify_card", "spectral"},
|
||||
loc_vars = function(_, info_queue, card)
|
||||
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
|
||||
return {vars = {card.ability.extra.amount}}
|
||||
end,
|
||||
can_use = function(_, card)
|
||||
if not u() then
|
||||
return false
|
||||
end
|
||||
|
||||
local highlighted = Bakery_API.get_highlighted()
|
||||
local count = #G.jokers.highlighted + #highlighted
|
||||
|
||||
return count > 0 and count <= card.ability.extra.amount and
|
||||
f(G.jokers.highlighted):concat(highlighted):all(function(v)
|
||||
return not v.edition
|
||||
end)
|
||||
end,
|
||||
use = function()
|
||||
f(G.jokers.highlighted):concat(Bakery_API.get_highlighted()):each(function(v)
|
||||
q {
|
||||
delay = 0.1,
|
||||
func = function()
|
||||
v:set_edition {Roland_frozen = true}
|
||||
end,
|
||||
}
|
||||
end)
|
||||
end,
|
||||
})
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
local f = (... or require "lib.shared")[1]
|
||||
local f = unpack(... or require "lib.shared")
|
||||
|
||||
if not Balatest then
|
||||
return
|
||||
|
|
@ -68,7 +68,8 @@ Balatest.TestPlay {
|
|||
}
|
||||
end)
|
||||
|
||||
Balatest.wait_for_input(G.STATES.ROUND_EVAL)
|
||||
Balatest.wait_for_input()
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_chips(2720)
|
||||
|
|
@ -191,9 +192,9 @@ Balatest.TestPlay {
|
|||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"blind", "mitotic"},
|
||||
name = "mitotic",
|
||||
blind = "bl_Roland_mitotic",
|
||||
category = {"blind", "xerox"},
|
||||
name = "xerox",
|
||||
blind = "bl_Roland_xerox",
|
||||
execute = function()
|
||||
Balatest.discard {"2S"}
|
||||
end,
|
||||
|
|
@ -203,9 +204,9 @@ Balatest.TestPlay {
|
|||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"blind", "mitotic"},
|
||||
name = "mitotic_disabled",
|
||||
blind = "bl_Roland_mitotic",
|
||||
category = {"blind", "xerox"},
|
||||
name = "xerox_disabled",
|
||||
blind = "bl_Roland_xerox",
|
||||
jokers = {"j_chicot"},
|
||||
execute = function()
|
||||
Balatest.discard {"2S"}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,330 @@ if not Balatest then
|
|||
return
|
||||
end
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_none",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
execute = function() end,
|
||||
assert = function()
|
||||
Balatest.assert(not G.jokers.cards[1].config.center:Bakery_can_use(G.jokers.cards[1]))
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_one_consumable",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
consumeables = {"c_strength"},
|
||||
execute = function()
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_two_consumables",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
consumeables = {"c_strength", "c_strength"},
|
||||
execute = function()
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 3)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_one_tag",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
no_auto_start = true,
|
||||
execute = function()
|
||||
Balatest.skip_blind("tag_investment")
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_two_tags",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
no_auto_start = true,
|
||||
execute = function()
|
||||
Balatest.skip_blind("tag_investment")
|
||||
Balatest.skip_blind("tag_investment")
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 3)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_consumables_and_tags",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
consumeables = {"c_strength"},
|
||||
no_auto_start = true,
|
||||
execute = function()
|
||||
Balatest.skip_blind("tag_investment")
|
||||
Balatest.skip_blind("tag_investment")
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_partial_selected_consumables_and_tags",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
consumeables = {"c_strength", "c_strength"},
|
||||
no_auto_start = true,
|
||||
execute = function()
|
||||
Balatest.skip_blind("tag_investment")
|
||||
Balatest.skip_blind("tag_investment")
|
||||
|
||||
Balatest.q(function()
|
||||
G.consumeables:add_to_highlighted(G.consumeables.cards[1])
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "escape"},
|
||||
name = "escapey_full_selected_consumables_and_tags",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
consumeables = {"c_strength"},
|
||||
no_auto_start = true,
|
||||
execute = function()
|
||||
Balatest.skip_blind("tag_investment")
|
||||
Balatest.skip_blind("tag_investment")
|
||||
|
||||
Balatest.q(function()
|
||||
G.consumeables:add_to_highlighted(G.consumeables.cards[1])
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 3)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "fuse"},
|
||||
name = "escapey_fusion",
|
||||
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
|
||||
execute = function()
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(#G.jokers.cards, 1)
|
||||
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
|
||||
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "fuse"},
|
||||
name = "escapey_consumable_takes_precedence",
|
||||
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
|
||||
consumeables = {"c_strength"},
|
||||
execute = function()
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(#G.jokers.cards, 2)
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "fuse"},
|
||||
name = "escapey_tag_takes_precedence",
|
||||
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
|
||||
no_auto_start = true,
|
||||
execute = function()
|
||||
Balatest.skip_blind("tag_investment")
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(#G.jokers.cards, 2)
|
||||
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "fuse"},
|
||||
name = "escapey_fusion_takes_precedence",
|
||||
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
|
||||
consumeables = {"c_strength"},
|
||||
execute = function()
|
||||
Balatest.q(function()
|
||||
G.consumeables:add_to_highlighted(G.consumeables.cards[1])
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(#G.jokers.cards, 1)
|
||||
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
|
||||
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 2)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "fuse"},
|
||||
name = "escapey_scribe_fusion",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
execute = function()
|
||||
if not G.P_CENTERS.c_Bakery_Scribe then
|
||||
sendWarnMessage("escapey_scribe_fusion cannot run without c_Bakery_Scribe, skipping test.")
|
||||
return
|
||||
end
|
||||
|
||||
Balatest.q(function()
|
||||
local scribe = create_card(nil, G.consumeables, nil, nil, nil, nil, "c_Bakery_Scribe", "balatest")
|
||||
scribe:add_to_deck()
|
||||
G.consumeables:emplace(scribe)
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
|
||||
Balatest.q(function()
|
||||
G.jokers:add_to_highlighted(G.jokers.cards[1])
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
Balatest.use(function() return G.consumeables.cards[1] end)
|
||||
|
||||
Balatest.q(function()
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
if not G.P_CENTERS.c_Bakery_Scribe then
|
||||
return
|
||||
end
|
||||
|
||||
Balatest.assert_eq(#G.jokers.cards, 1)
|
||||
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
|
||||
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 1)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "escapey", "fuse"},
|
||||
name = "escapey_scribe_fusion_alt",
|
||||
jokers = {"j_Roland_escapey"},
|
||||
execute = function()
|
||||
if not G.P_CENTERS.c_Bakery_Scribe then
|
||||
sendWarnMessage("escapey_scribe_fusion_alt cannot run without c_Bakery_Scribe, skipping test.")
|
||||
return
|
||||
end
|
||||
|
||||
Balatest.q(function()
|
||||
local scribe = create_card(nil, G.consumeables, nil, nil, nil, nil, "c_Bakery_Scribe", "balatest")
|
||||
scribe:add_to_deck()
|
||||
G.consumeables:emplace(scribe)
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
|
||||
Balatest.q(function()
|
||||
G.jokers:add_to_highlighted(G.jokers.cards[1])
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
Balatest.use(function() return G.consumeables.cards[1] end)
|
||||
|
||||
Balatest.q(function()
|
||||
G.jokers:add_to_highlighted(G.jokers.cards[2])
|
||||
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[2]}}
|
||||
end)
|
||||
|
||||
Balatest.wait()
|
||||
end,
|
||||
assert = function()
|
||||
if not G.P_CENTERS.c_Bakery_Scribe then
|
||||
return
|
||||
end
|
||||
|
||||
Balatest.assert_eq(#G.jokers.cards, 1)
|
||||
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
|
||||
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 1)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"joker", "martingale"},
|
||||
name = "martingale_oops",
|
||||
|
|
@ -10,7 +334,7 @@ Balatest.TestPlay {
|
|||
Balatest.play_hand {"2S"}
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_chips(7)
|
||||
Balatest.assert_chips(7 * 2)
|
||||
end,
|
||||
}
|
||||
|
||||
|
|
@ -23,6 +347,6 @@ Balatest.TestPlay {
|
|||
Balatest.play_hand {"2S"}
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_chips(1 / 0)
|
||||
Balatest.assert_chips(7 * math.pow(2, 32))
|
||||
end,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,22 @@ if not Balatest then
|
|||
return
|
||||
end
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"spectral", "afterimage"},
|
||||
name = "afterimage",
|
||||
consumeables = {"c_Roland_afterimage"},
|
||||
deck = {cards = {{s = "S", r = "2"}}},
|
||||
execute = function()
|
||||
Balatest.highlight({"2S"})
|
||||
Balatest.use(G.consumeables.cards[1])
|
||||
Balatest.end_round()
|
||||
end,
|
||||
assert = function()
|
||||
Balatest.assert_eq(G.hand.config.card_limit, 51)
|
||||
Balatest.assert(G.deck.cards[1].edition.negative)
|
||||
end,
|
||||
}
|
||||
|
||||
Balatest.TestPlay {
|
||||
category = {"spectral", "void"},
|
||||
name = "spectral",
|
||||
|
|
|
|||
144
src/tweaks.lua
|
|
@ -1,40 +1,52 @@
|
|||
local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
|
||||
SMODS.Joker:take_ownership("joker", {cost = 1}, true)
|
||||
local orig_set_debuff = Card.set_debuff
|
||||
local f, q = unpack(... or require "lib.shared")
|
||||
|
||||
function Card:set_debuff(should_debuff, ...)
|
||||
if self.ability.Roland_crimson ~= nil then
|
||||
self.ability.Roland_crimson = not not should_debuff
|
||||
return
|
||||
SMODS.Joker:take_ownership("joker", {cost = 1}, true)
|
||||
local orig_can_highlight = CardArea.can_highlight
|
||||
local orig_set_debuff = Card.set_debuff
|
||||
local orig_highlight = Card.highlight
|
||||
local orig_copy_card = copy_card
|
||||
|
||||
function CardArea:can_highlight(...)
|
||||
if self ~= G.consumeables or not SMODS.Mods.Roland.config.no_highlight_limit then
|
||||
return orig_can_highlight(self, ...)
|
||||
end
|
||||
|
||||
if SMODS.get_enhancements(self).m_wild and SMODS.Mods.Roland.config.no_wild_debuff then
|
||||
--- Allows more flexibility when using the Escapey joker to delete specific consumables.
|
||||
self.config.highlighted_limit = 1 / 0
|
||||
return true
|
||||
end
|
||||
|
||||
function Card:set_debuff(...)
|
||||
if self.config and
|
||||
self.config.center_key == "m_wild" and
|
||||
SMODS.Mods.Roland.config.no_wild_debuff then
|
||||
self.debuff = false
|
||||
else
|
||||
orig_set_debuff(self, should_debuff, ...)
|
||||
orig_set_debuff(self, ...)
|
||||
end
|
||||
end
|
||||
|
||||
function Card:highlight(is_highlighted, ...)
|
||||
self.highlighted = is_highlighted
|
||||
|
||||
if not G.CONTROLLER.HID.controller or not SMODS.Mods.Roland.config.no_highlight_limit then
|
||||
return orig_highlight(self, is_highlighted, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local orig_use_consumeable = Card.use_consumeable
|
||||
|
||||
function Card:use_consumeable(area, copier, ...)
|
||||
if SMODS.Mods.Roland.config.faster_planets and self.ability.consumeable.hand_type then
|
||||
set_consumeable_usage(self)
|
||||
level_up_hand(copier or self, self.ability.consumeable.hand_type, true, self.ability.qty or 1)
|
||||
return
|
||||
end
|
||||
|
||||
local seal_spectrals = {["Deja Vu"] = true, Medium = true, Talisman = true, Trance = true}
|
||||
|
||||
if not seal_spectrals[self.ability.name] then
|
||||
return orig_use_consumeable(self, area, copier, ...)
|
||||
end
|
||||
|
||||
local card = copier or self
|
||||
|
||||
f(Bakery_API.get_highlighted()):each(function(v)
|
||||
q(function()
|
||||
play_sound "tarot1"
|
||||
local card = (copier or self)
|
||||
card:juice_up(0.3, 0.5)
|
||||
end)
|
||||
|
||||
|
|
@ -47,43 +59,42 @@ function Card:use_consumeable(area, copier, ...)
|
|||
}
|
||||
end)
|
||||
|
||||
q {delay = 0.7, trigger = "after", func = Bakery_API.unhighlight_all}
|
||||
q {
|
||||
delay = 0.7,
|
||||
trigger = "after",
|
||||
func = function()
|
||||
Bakery_API.unhighlight_all()
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
local orig_use_card = G.FUNCS.use_card
|
||||
function copy_card(other, new_card, ...)
|
||||
local ret = orig_copy_card(other, new_card, ...)
|
||||
|
||||
function G.FUNCS.use_card(e, ...)
|
||||
local ref = e.config.ref_table or {}
|
||||
local consumeable = (ref.ability or {}).consumeable or {}
|
||||
|
||||
if not SMODS.Mods.Roland.config.faster_planets or
|
||||
(not consumeable.hand_type and not consumeable.hand_types) then
|
||||
return orig_use_card(e, ...)
|
||||
if new_card and new_card.edition and new_card.edition.key == "e_negative" then
|
||||
--- Fixes an issue where using 'c_death' will make negative
|
||||
--- cards do the inverse of what they're supposed to do.
|
||||
local ability = new_card.ability
|
||||
ability.card_limit = math.max(ability.card_limit, 1)
|
||||
end
|
||||
|
||||
local normal = G.STATE == G.STATES.SHOP or
|
||||
ref.area ~= G.pack_cards or
|
||||
not G.GAME.pack_choices or
|
||||
G.GAME.pack_choices <= 0
|
||||
|
||||
ref.from_area = ref.from_area or ref.area
|
||||
play_sound("tarot1", percent, 0.6)
|
||||
discover_card(ref.config.center)
|
||||
ref:use_consumeable(ref.area)
|
||||
SMODS.calculate_context {area = ref.area, consumeable = ref, using_consumeable = true}
|
||||
ref:remove()
|
||||
|
||||
if normal then
|
||||
return
|
||||
return ret
|
||||
end
|
||||
|
||||
G.GAME.pack_choices = G.GAME.pack_choices - 1
|
||||
local _ = G.GAME.pack_choices <= 0 and G.FUNCS.end_consumeable()
|
||||
q(function()
|
||||
local orig_can_highlight_area = Bakery_API.can_highlight_area
|
||||
|
||||
function Bakery_API.can_highlight_area(area, ...)
|
||||
return (area == G.consumeables and
|
||||
SMODS.Mods.Roland.config.no_highlight_limit) or
|
||||
orig_can_highlight_area(area, ...)
|
||||
end
|
||||
end)
|
||||
|
||||
local orig_create_card_for_shop = create_card_for_shop
|
||||
|
||||
function create_card_for_shop(...)
|
||||
---@type Card
|
||||
local ret = orig_create_card_for_shop(...)
|
||||
|
||||
if not SMODS.Mods.Roland.config.illusion_seal or
|
||||
|
|
@ -93,7 +104,11 @@ function create_card_for_shop(...)
|
|||
return ret
|
||||
end
|
||||
|
||||
local seal = SMODS.poll_seal {type_key = "Roland_illusion_seal", guaranteed = true}
|
||||
local seal = SMODS.poll_seal {
|
||||
type_key = "Roland_illusion_seal",
|
||||
guaranteed = true,
|
||||
}
|
||||
|
||||
ret:set_seal(seal, true, true)
|
||||
return ret
|
||||
end
|
||||
|
|
@ -101,44 +116,31 @@ end
|
|||
local orig_get_blind_amount = get_blind_amount
|
||||
|
||||
---@param ante number
|
||||
---@return table|number
|
||||
---@return number
|
||||
local function blind(ante)
|
||||
return ante == 39 and 1e294 or (to_number or f.id)(orig_get_blind_amount(ante))
|
||||
return ante == 39 and 1e294 or (_G["to_number"] or f().id)(orig_get_blind_amount(ante))
|
||||
end
|
||||
|
||||
local function no_harsh_ante_scaling()
|
||||
return not Talisman or not SMODS.Mods.Roland.config.harsh_ante_scaling
|
||||
return not _G["Talisman"] or not SMODS.Mods.Roland.config.harsh_ante_scaling
|
||||
end
|
||||
|
||||
---@type (fun(rem: number): number|table)[]
|
||||
SMODS.current_mod.harsh_ante_scaling = {
|
||||
function(rem)
|
||||
return (Big.constants and Big.constants.TEN or Big:new {10}):pow(blind(rem + 1))
|
||||
end,
|
||||
function(rem)
|
||||
return Big:new {1, rem + 2}
|
||||
end,
|
||||
function(rem)
|
||||
return Big:new {1, 1, [rem + 2] = 1}
|
||||
end,
|
||||
function(rem)
|
||||
return Big:new {1, 1, [blind(rem) + 2] = 1}
|
||||
end,
|
||||
function(rem)
|
||||
return rem <= 1 and Big:new {1.7976931348623157e308, 1, [1.7975e308] = 1} or 1 / 0
|
||||
end,
|
||||
}
|
||||
|
||||
function get_blind_amount(ante, ...)
|
||||
local offset = 40
|
||||
local loop = 39
|
||||
|
||||
if ante < offset or no_harsh_ante_scaling() then
|
||||
if ante < loop or no_harsh_ante_scaling() then
|
||||
return orig_get_blind_amount(ante, ...)
|
||||
end
|
||||
|
||||
local loop = 10
|
||||
if (ante - 9) / 15 >= loop then
|
||||
return 1 / 0
|
||||
end
|
||||
|
||||
return f(SMODS.Mods.Roland.harsh_ante_scaling, f.revpairs):any(function(_, k)
|
||||
return (ante - offset) / loop + 1 >= k
|
||||
end)((ante - offset) % loop + 1)
|
||||
--- @type { constants?: { TEN: table }, new: (fun(self: self, arr?: number[], sign?: number, noNormalize?: boolean): table), pow: (fun(x: number, y: number): number) }
|
||||
local big, rem = _G["Big"], (ante % loop) + 1
|
||||
|
||||
return ante / 15 >= loop and big:new(f(blind(ante - (loop * 15))):map(f().const(10)):table()) or
|
||||
(ante / 9 >= loop and big:new(f(ante / loop - 8):map(f().const(10)):concat {blind(rem)}:table()) or
|
||||
(ante / 2 >= loop and big:new {blind(rem), ante / loop} or
|
||||
(big.constants and big.constants.TEN or big:new {10}):pow(blind(rem))))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
local voucher = (function()
|
||||
local x = 0
|
||||
|
||||
---@param tbl SMODS.Voucher|{attributes: Attributes[]}
|
||||
---@return SMODS.Voucher
|
||||
return function(tbl)
|
||||
tbl.pos = {x = x, y = 0}
|
||||
tbl.atlas = "voucher"
|
||||
tbl.cost = 10
|
||||
x = x + 1
|
||||
return SMODS.Voucher(tbl)
|
||||
end
|
||||
end)()
|
||||
|
||||
SMODS.Atlas {
|
||||
px = 71,
|
||||
py = 95,
|
||||
key = "voucher",
|
||||
path = "voucher.png",
|
||||
}
|
||||
|
||||
voucher {
|
||||
key = "ceres",
|
||||
pronouns = "it_its",
|
||||
config = {extra = {amount = 1, hand_type = "Flush House"}},
|
||||
attributes = {"planet", "passive", "hand_type", "space"},
|
||||
loc_vars = function(_, _, card)
|
||||
return {vars = {card.ability.extra.amount}}
|
||||
end,
|
||||
in_pool = function(self)
|
||||
return G.GAME.hands[self.config.extra.hand_type].visible
|
||||
end,
|
||||
}
|
||||
|
||||
voucher {
|
||||
key = "neptune",
|
||||
pronouns = "it_its",
|
||||
requires = {"v_Roland_ceres"},
|
||||
config = {extra = {amount = 2, hand_type = "Straight Flush"}},
|
||||
attributes = {"planet", "passive", "hand_type", "space"},
|
||||
loc_vars = function(_, _, card)
|
||||
return {vars = {card.ability.extra.amount}}
|
||||
end,
|
||||
}
|
||||