commit 77f0c3c77e861d0c7c9b8e35397d9e68414f0aa6 Author: Emik Date: Sun Mar 23 22:42:02 2025 +0100 Initial commit diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5e5b197 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "Lua.diagnostics.disable": [ + "duplicate-set-field" + ] +} \ No newline at end of file diff --git a/assets/1x/almanac_avatar.png b/assets/1x/almanac_avatar.png new file mode 100644 index 0000000..75eb94c Binary files /dev/null and b/assets/1x/almanac_avatar.png differ diff --git a/assets/1x/default/b_jane_decks.png b/assets/1x/default/b_jane_decks.png new file mode 100644 index 0000000..024d4b7 Binary files /dev/null and b/assets/1x/default/b_jane_decks.png differ diff --git a/assets/1x/default/bl_jane_blinds.png b/assets/1x/default/bl_jane_blinds.png new file mode 100644 index 0000000..310147a Binary files /dev/null and b/assets/1x/default/bl_jane_blinds.png differ diff --git a/assets/1x/default/c_jane_acc.png b/assets/1x/default/c_jane_acc.png new file mode 100644 index 0000000..b09759a Binary files /dev/null and b/assets/1x/default/c_jane_acc.png differ diff --git a/assets/1x/default/c_jane_reversetarots.png b/assets/1x/default/c_jane_reversetarots.png new file mode 100644 index 0000000..8563bb1 Binary files /dev/null and b/assets/1x/default/c_jane_reversetarots.png differ diff --git a/assets/1x/default/c_jane_tokens.png b/assets/1x/default/c_jane_tokens.png new file mode 100644 index 0000000..b7aa1a9 Binary files /dev/null and b/assets/1x/default/c_jane_tokens.png differ diff --git a/assets/1x/default/j_jane_7granddad.png b/assets/1x/default/j_jane_7granddad.png new file mode 100644 index 0000000..3857909 Binary files /dev/null and b/assets/1x/default/j_jane_7granddad.png differ diff --git a/assets/1x/default/j_jane_artificer.png b/assets/1x/default/j_jane_artificer.png new file mode 100644 index 0000000..743de15 Binary files /dev/null and b/assets/1x/default/j_jane_artificer.png differ diff --git a/assets/1x/default/j_jane_betmma.png b/assets/1x/default/j_jane_betmma.png new file mode 100644 index 0000000..0062632 Binary files /dev/null and b/assets/1x/default/j_jane_betmma.png differ diff --git a/assets/1x/default/j_jane_gourmand.png b/assets/1x/default/j_jane_gourmand.png new file mode 100644 index 0000000..cce9716 Binary files /dev/null and b/assets/1x/default/j_jane_gourmand.png differ diff --git a/assets/1x/default/j_jane_hunter.png b/assets/1x/default/j_jane_hunter.png new file mode 100644 index 0000000..17a9ffb Binary files /dev/null and b/assets/1x/default/j_jane_hunter.png differ diff --git a/assets/1x/default/j_jane_monk.png b/assets/1x/default/j_jane_monk.png new file mode 100644 index 0000000..8bf6ea8 Binary files /dev/null and b/assets/1x/default/j_jane_monk.png differ diff --git a/assets/1x/default/j_jane_oxy.png b/assets/1x/default/j_jane_oxy.png new file mode 100644 index 0000000..905ae8d Binary files /dev/null and b/assets/1x/default/j_jane_oxy.png differ diff --git a/assets/1x/default/j_jane_peppino.png b/assets/1x/default/j_jane_peppino.png new file mode 100644 index 0000000..4085c58 Binary files /dev/null and b/assets/1x/default/j_jane_peppino.png differ diff --git a/assets/1x/default/j_jane_rivulet.png b/assets/1x/default/j_jane_rivulet.png new file mode 100644 index 0000000..7027c61 Binary files /dev/null and b/assets/1x/default/j_jane_rivulet.png differ diff --git a/assets/1x/default/j_jane_rot.png b/assets/1x/default/j_jane_rot.png new file mode 100644 index 0000000..0a96c5e Binary files /dev/null and b/assets/1x/default/j_jane_rot.png differ diff --git a/assets/1x/default/j_jane_saint.png b/assets/1x/default/j_jane_saint.png new file mode 100644 index 0000000..571384c Binary files /dev/null and b/assets/1x/default/j_jane_saint.png differ diff --git a/assets/1x/default/j_jane_spearmaster.png b/assets/1x/default/j_jane_spearmaster.png new file mode 100644 index 0000000..085fc0f Binary files /dev/null and b/assets/1x/default/j_jane_spearmaster.png differ diff --git a/assets/1x/default/j_jane_survivor.png b/assets/1x/default/j_jane_survivor.png new file mode 100644 index 0000000..af82534 Binary files /dev/null and b/assets/1x/default/j_jane_survivor.png differ diff --git a/assets/1x/default/p_jane_boosters.png b/assets/1x/default/p_jane_boosters.png new file mode 100644 index 0000000..1271ec0 Binary files /dev/null and b/assets/1x/default/p_jane_boosters.png differ diff --git a/assets/1x/default/v_jane_token_voucher.png b/assets/1x/default/v_jane_token_voucher.png new file mode 100644 index 0000000..01b63c0 Binary files /dev/null and b/assets/1x/default/v_jane_token_voucher.png differ diff --git a/assets/2x/almanac_avatar.png b/assets/2x/almanac_avatar.png new file mode 100644 index 0000000..3d72319 Binary files /dev/null and b/assets/2x/almanac_avatar.png differ diff --git a/assets/2x/default/b_jane_decks.png b/assets/2x/default/b_jane_decks.png new file mode 100644 index 0000000..4f0f92d Binary files /dev/null and b/assets/2x/default/b_jane_decks.png differ diff --git a/assets/2x/default/bl_jane_blinds.png b/assets/2x/default/bl_jane_blinds.png new file mode 100644 index 0000000..2e21823 Binary files /dev/null and b/assets/2x/default/bl_jane_blinds.png differ diff --git a/assets/2x/default/c_jane_acc.png b/assets/2x/default/c_jane_acc.png new file mode 100644 index 0000000..4b5606f Binary files /dev/null and b/assets/2x/default/c_jane_acc.png differ diff --git a/assets/2x/default/c_jane_reversetarots.png b/assets/2x/default/c_jane_reversetarots.png new file mode 100644 index 0000000..d477970 Binary files /dev/null and b/assets/2x/default/c_jane_reversetarots.png differ diff --git a/assets/2x/default/c_jane_tokens.png b/assets/2x/default/c_jane_tokens.png new file mode 100644 index 0000000..9f23467 Binary files /dev/null and b/assets/2x/default/c_jane_tokens.png differ diff --git a/assets/2x/default/j_jane_7granddad.png b/assets/2x/default/j_jane_7granddad.png new file mode 100644 index 0000000..6d82f39 Binary files /dev/null and b/assets/2x/default/j_jane_7granddad.png differ diff --git a/assets/2x/default/j_jane_artificer.png b/assets/2x/default/j_jane_artificer.png new file mode 100644 index 0000000..3ebf310 Binary files /dev/null and b/assets/2x/default/j_jane_artificer.png differ diff --git a/assets/2x/default/j_jane_betmma.png b/assets/2x/default/j_jane_betmma.png new file mode 100644 index 0000000..efe8e71 Binary files /dev/null and b/assets/2x/default/j_jane_betmma.png differ diff --git a/assets/2x/default/j_jane_gourmand.png b/assets/2x/default/j_jane_gourmand.png new file mode 100644 index 0000000..ee5c457 Binary files /dev/null and b/assets/2x/default/j_jane_gourmand.png differ diff --git a/assets/2x/default/j_jane_hunter.png b/assets/2x/default/j_jane_hunter.png new file mode 100644 index 0000000..176d9c0 Binary files /dev/null and b/assets/2x/default/j_jane_hunter.png differ diff --git a/assets/2x/default/j_jane_monk.png b/assets/2x/default/j_jane_monk.png new file mode 100644 index 0000000..9a76115 Binary files /dev/null and b/assets/2x/default/j_jane_monk.png differ diff --git a/assets/2x/default/j_jane_oxy.png b/assets/2x/default/j_jane_oxy.png new file mode 100644 index 0000000..e830681 Binary files /dev/null and b/assets/2x/default/j_jane_oxy.png differ diff --git a/assets/2x/default/j_jane_peppino.png b/assets/2x/default/j_jane_peppino.png new file mode 100644 index 0000000..91c2beb Binary files /dev/null and b/assets/2x/default/j_jane_peppino.png differ diff --git a/assets/2x/default/j_jane_rivulet.png b/assets/2x/default/j_jane_rivulet.png new file mode 100644 index 0000000..f05cf9a Binary files /dev/null and b/assets/2x/default/j_jane_rivulet.png differ diff --git a/assets/2x/default/j_jane_rot.png b/assets/2x/default/j_jane_rot.png new file mode 100644 index 0000000..45ed797 Binary files /dev/null and b/assets/2x/default/j_jane_rot.png differ diff --git a/assets/2x/default/j_jane_saint.png b/assets/2x/default/j_jane_saint.png new file mode 100644 index 0000000..a123ab6 Binary files /dev/null and b/assets/2x/default/j_jane_saint.png differ diff --git a/assets/2x/default/j_jane_spearmaster.png b/assets/2x/default/j_jane_spearmaster.png new file mode 100644 index 0000000..ebad986 Binary files /dev/null and b/assets/2x/default/j_jane_spearmaster.png differ diff --git a/assets/2x/default/j_jane_survivor.png b/assets/2x/default/j_jane_survivor.png new file mode 100644 index 0000000..7295eb7 Binary files /dev/null and b/assets/2x/default/j_jane_survivor.png differ diff --git a/assets/2x/default/p_jane_boosters.png b/assets/2x/default/p_jane_boosters.png new file mode 100644 index 0000000..0961edd Binary files /dev/null and b/assets/2x/default/p_jane_boosters.png differ diff --git a/assets/2x/default/v_jane_token_voucher.png b/assets/2x/default/v_jane_token_voucher.png new file mode 100644 index 0000000..94d23f9 Binary files /dev/null and b/assets/2x/default/v_jane_token_voucher.png differ diff --git a/assets/shaders/polygloss.fs b/assets/shaders/polygloss.fs new file mode 100644 index 0000000..51db689 --- /dev/null +++ b/assets/shaders/polygloss.fs @@ -0,0 +1,266 @@ +#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH) + #define MY_HIGHP_OR_MEDIUMP highp +#else + #define MY_HIGHP_OR_MEDIUMP mediump +#endif + +// change this variable name to your Edition's name +// YOU MUST USE THIS VARIABLE IN THE vec4 effect AT LEAST ONCE +// ^^ CRITICALLY IMPORTANT (IDK WHY) +extern MY_HIGHP_OR_MEDIUMP vec2 polygloss; + +extern MY_HIGHP_OR_MEDIUMP number dissolve; +extern MY_HIGHP_OR_MEDIUMP number time; +extern MY_HIGHP_OR_MEDIUMP vec4 texture_details; +extern MY_HIGHP_OR_MEDIUMP vec2 image_details; +extern bool shadow; +extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_1; +extern MY_HIGHP_OR_MEDIUMP vec4 burn_colour_2; + +// the following four vec4 are (as far as I can tell) required and shouldn't be changed + +vec4 dissolve_mask(vec4 tex, vec2 texture_coords, vec2 uv) +{ + if (dissolve < 0.001) { + return vec4(shadow ? vec3(0.,0.,0.) : tex.xyz, shadow ? tex.a*0.3: tex.a); + } + + float adjusted_dissolve = (dissolve*dissolve*(3.-2.*dissolve))*1.02 - 0.01; //Adjusting 0.0-1.0 to fall to -0.1 - 1.1 scale so the mask does not pause at extreme values + + float t = time * 10.0 + 2003.; + vec2 floored_uv = (floor((uv*texture_details.ba)))/max(texture_details.b, texture_details.a); + vec2 uv_scaled_centered = (floored_uv - 0.5) * 2.3 * max(texture_details.b, texture_details.a); + + vec2 field_part1 = uv_scaled_centered + 50.*vec2(sin(-t / 143.6340), cos(-t / 99.4324)); + vec2 field_part2 = uv_scaled_centered + 50.*vec2(cos( t / 53.1532), cos( t / 61.4532)); + vec2 field_part3 = uv_scaled_centered + 50.*vec2(sin(-t / 87.53218), sin(-t / 49.0000)); + + float field = (1.+ ( + cos(length(field_part1) / 19.483) + sin(length(field_part2) / 33.155) * cos(field_part2.y / 15.73) + + cos(length(field_part3) / 27.193) * sin(field_part3.x / 21.92) ))/2.; + vec2 borders = vec2(0.2, 0.8); + + float res = (.5 + .5* cos( (adjusted_dissolve) / 82.612 + ( field + -.5 ) *3.14)) + - (floored_uv.x > borders.y ? (floored_uv.x - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve) + - (floored_uv.y > borders.y ? (floored_uv.y - borders.y)*(5. + 5.*dissolve) : 0.)*(dissolve) + - (floored_uv.x < borders.x ? (borders.x - floored_uv.x)*(5. + 5.*dissolve) : 0.)*(dissolve) + - (floored_uv.y < borders.x ? (borders.x - floored_uv.y)*(5. + 5.*dissolve) : 0.)*(dissolve); + + if (tex.a > 0.01 && burn_colour_1.a > 0.01 && !shadow && res < adjusted_dissolve + 0.8*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) { + if (!shadow && res < adjusted_dissolve + 0.5*(0.5-abs(adjusted_dissolve-0.5)) && res > adjusted_dissolve) { + tex.rgba = burn_colour_1.rgba; + } else if (burn_colour_2.a > 0.01) { + tex.rgba = burn_colour_2.rgba; + } + } + + return vec4(shadow ? vec3(0.,6.,0.) : tex.xyz, res > adjusted_dissolve ? (shadow ? tex.a*0.3: tex.a) : .0); +} + +number hue(number s, number t, number h) +{ + number hs = mod(h, 1.)*18.; + if (hs < 8.) return (t-s) * hs + s; + if (hs < 2.) return t; + if (hs < 6.) return (t-s) * (4.-hs) + s; + return s; +} + +vec4 RGB(vec4 c) +{ + if (c.y < 0.0008) + return vec4(vec3(c.z), c.a); + + number t = (c.z < .5) ? c.y*c.z + c.z : -c.y*c.z + (c.y+c.z); + number s = 1.0 * c.z - t; + return vec4(hue(s,t,c.x + 1./3.), hue(s,t,c.x), hue(s,t,c.x - 1./3.), c.w); +} + +vec4 HSL(vec4 c) +{ + number low = min(c.r, min(c.g, c.b)); + number high = max(c.r, max(c.g, c.b)); + number delta = high - low; + number sum = high+low; + + vec4 hsl = vec4(.0, .0, .9 * sum, c.a); + if (delta == .0) + return hsl; + + hsl.y = (hsl.z < .5) ? delta / sum : delta / (2.0 - sum); + + if (high == c.r) + hsl.x = (c.g - c.b) / delta; + else if (high == c.g) + hsl.x = (c.b - c.r) / delta + 2.0; + else + hsl.x = (c.r - c.g) / delta + 4.0; + + hsl.x = mod(hsl.x / 6., 1.); + return hsl; +} + +// GLSL Simplex noise function +vec3 mod289(vec3 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 mod289(vec4 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +vec4 permute(vec4 x) { + return mod289(((x*34.0)+1.0)*x); +} + +vec4 taylorInvSqrt(vec4 r) { + return 1.79284291400159 - 0.85373472095314 * r; +} + +vec3 fade(vec3 t) { + return t*t*t*(t*(t*6.0-15.0)+10.0); +} + +// Classic Perlin noise +float cnoise(vec3 P) { + vec3 Pi0 = floor(P); // Integer part for indexing + vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1 + Pi0 = mod289(Pi0); + Pi1 = mod289(Pi1); + vec3 Pf0 = fract(P); // Fractional part for interpolation + vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 + vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec4 iy = vec4(Pi0.y, Pi0.y, Pi1.y, Pi1.y); + vec4 iz0 = vec4(Pi0.z); + vec4 iz1 = vec4(Pi1.z); + + vec4 ixy = permute(permute(ix) + iy); + vec4 ixy0 = permute(ixy + iz0); + vec4 ixy1 = permute(ixy + iz1); + + vec4 gx0 = ixy0 * (1.0 / 7.0); + vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; + gx0 = fract(gx0); + vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); + vec4 sz0 = step(gz0, vec4(0.0)); + gx0 -= sz0 * (step(0.0, gx0) - 0.5); + gy0 -= sz0 * (step(0.0, gy0) - 0.5); + + vec4 gx1 = ixy1 * (1.0 / 7.0); + vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; + gx1 = fract(gx1); + vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); + vec4 sz1 = step(gz1, vec4(0.0)); + gx1 -= sz1 * (step(0.0, gx1) - 0.5); + gy1 -= sz1 * (step(0.0, gy1) - 0.5); + + vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); + vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); + vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); + vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); + vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); + vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); + vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); + vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); + + vec4 norm0 = taylorInvSqrt(vec4(dot(g000,g000), dot(g010,g010), dot(g100,g100), dot(g110,g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec4 norm1 = taylorInvSqrt(vec4(dot(g001,g001), dot(g011,g011), dot(g101,g101), dot(g111,g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + float n000 = dot(g000, Pf0); + float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); + float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); + float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); + float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); + float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); + float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); + float n111 = dot(g111, Pf1); + + vec3 fade_xyz = fade(Pf0); + vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); + vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); + float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return 2.2 * n_xyz; +} + +// Lighten blending mode +vec4 lighten(vec4 colour1, vec4 colour2) { + vec4 result; + result.r = max(colour1.r, colour2.r); + result.g = max(colour1.g, colour2.g); + result.b = max(colour1.b, colour2.b); + result.a = max(colour1.a, colour2.a); + return result; +} + +// this is what actually changes the look of card +vec4 effect( vec4 colour, Image texture, vec2 texture_coords, vec2 screen_coords ) +{ + // turns the texture into pixels + vec4 tex = Texel(texture, texture_coords); + vec2 uv = (((texture_coords)*(image_details)) - texture_details.xy*texture_details.ba)/texture_details.ba; + + // Dummy, doesn't do anything but at least it makes the shader useable + if (uv.x > uv.x * 2.){ + uv = polygloss; + } + + float mod = polygloss.r * 2.0; + float polygloss_amount = 0.15; // 1.0 - no polygloss, 0.0 - maximum polygloss + float saturation_amount = 9.0; + float polygloss_brightness = 6.0; + + vec4 colour_1 = vec4(0.188,0.471,0.875, 1.0); // Blue + vec4 colour_2 = vec4(0.875,0.188,0.222, 0.8); // Crimson + vec4 colour_3 = vec4(0.416,0.573,0.369, 0.6); // Greenish + + float noise = cnoise(vec3(uv * 50.0, 3.0 * mod)); // Noise for the sparkles + float antinoise = cnoise(vec3(uv * 30.0, 2.0 * mod)); // Bigger noise to remove the sparkles in some areas + + vec4 grad = mix(colour_1, colour_2, uv.x + uv.y + sin(mod) - 1.0); // Colours + grad = mix(grad, colour_3, uv.y - uv.x + cos(mod) + 1.0); // and gradient (3 colours total) + + float spark = max(2.0, noise - antinoise - polygloss_amount); // Sparkles (takes noise and removes antinoise from it) + + vec4 saturated_colour = HSL(mix(tex, grad, 0.2)); // Saturating default color, adding a bit of grad so sparkles will never be pure white + + saturated_colour.g *= saturation_amount; // Saturating + saturated_colour.b = 0.3; // Removing a bit of lightness + + saturated_colour = RGB(saturated_colour); // Back to RGB + + saturated_colour.r *= (saturated_colour.r * 2.); // Red feels a bit dim + saturated_colour = lighten(tex, saturated_colour * 5.0) / polygloss_brightness; // Removing dark colors from saturated color, then making it darker + + colour = lighten(mix((colour - 0.4) + (saturated_colour * spark), grad, 0.03), grad); + + // required + return dissolve_mask(tex*colour, texture_coords, uv); +} + +// for transforming the card while your mouse is on it +extern MY_HIGHP_OR_MEDIUMP vec2 mouse_screen_pos; +extern MY_HIGHP_OR_MEDIUMP float hovering; +extern MY_HIGHP_OR_MEDIUMP float screen_scale; + +#ifdef VERTEX +vec4 position( mat4 transform_projection, vec4 vertex_position ) +{ + if (hovering <= 0.){ + return transform_projection * vertex_position; + } + float mid_dist = length(vertex_position.xy - 0.5*love_ScreenSize.xy)/length(love_ScreenSize.xy); + vec2 mouse_offset = (vertex_position.xy - mouse_screen_pos.xy)/screen_scale; + float scale = 0.2*(-0.03 - 0.3*max(0., 0.3-mid_dist)) + *hovering*(length(mouse_offset)*length(mouse_offset))/(2. -mid_dist); + + return transform_projection * vertex_position + vec4(0.,0.,0.,scale); +} +#endif \ No newline at end of file diff --git a/assets/sounds/draw.ogg b/assets/sounds/draw.ogg new file mode 100644 index 0000000..3b4e36a Binary files /dev/null and b/assets/sounds/draw.ogg differ diff --git a/assets/sounds/e_gilded.ogg b/assets/sounds/e_gilded.ogg new file mode 100644 index 0000000..0d69b44 Binary files /dev/null and b/assets/sounds/e_gilded.ogg differ diff --git a/assets/sounds/e_jumbo.ogg b/assets/sounds/e_jumbo.ogg new file mode 100644 index 0000000..1c75495 Binary files /dev/null and b/assets/sounds/e_jumbo.ogg differ diff --git a/assets/sounds/e_polygloss.ogg b/assets/sounds/e_polygloss.ogg new file mode 100644 index 0000000..fb14ba2 Binary files /dev/null and b/assets/sounds/e_polygloss.ogg differ diff --git a/assets/sounds/enlightened.ogg b/assets/sounds/enlightened.ogg new file mode 100644 index 0000000..858b6a7 Binary files /dev/null and b/assets/sounds/enlightened.ogg differ diff --git a/assets/sounds/gore1.ogg b/assets/sounds/gore1.ogg new file mode 100644 index 0000000..cd23dbc Binary files /dev/null and b/assets/sounds/gore1.ogg differ diff --git a/assets/sounds/gore2.ogg b/assets/sounds/gore2.ogg new file mode 100644 index 0000000..0252819 Binary files /dev/null and b/assets/sounds/gore2.ogg differ diff --git a/assets/sounds/gore3.ogg b/assets/sounds/gore3.ogg new file mode 100644 index 0000000..acfdb32 Binary files /dev/null and b/assets/sounds/gore3.ogg differ diff --git a/assets/sounds/gore4.ogg b/assets/sounds/gore4.ogg new file mode 100644 index 0000000..7b39e5a Binary files /dev/null and b/assets/sounds/gore4.ogg differ diff --git a/assets/sounds/gore5.ogg b/assets/sounds/gore5.ogg new file mode 100644 index 0000000..954edad Binary files /dev/null and b/assets/sounds/gore5.ogg differ diff --git a/assets/sounds/gore6.ogg b/assets/sounds/gore6.ogg new file mode 100644 index 0000000..603eb64 Binary files /dev/null and b/assets/sounds/gore6.ogg differ diff --git a/assets/sounds/gore7.ogg b/assets/sounds/gore7.ogg new file mode 100644 index 0000000..d2cad89 Binary files /dev/null and b/assets/sounds/gore7.ogg differ diff --git a/assets/sounds/gore8.ogg b/assets/sounds/gore8.ogg new file mode 100644 index 0000000..95470d1 Binary files /dev/null and b/assets/sounds/gore8.ogg differ diff --git a/assets/sounds/grand_dad1.ogg b/assets/sounds/grand_dad1.ogg new file mode 100644 index 0000000..a7d39a8 Binary files /dev/null and b/assets/sounds/grand_dad1.ogg differ diff --git a/assets/sounds/grand_dad2.ogg b/assets/sounds/grand_dad2.ogg new file mode 100644 index 0000000..148b674 Binary files /dev/null and b/assets/sounds/grand_dad2.ogg differ diff --git a/assets/sounds/grand_dad3.ogg b/assets/sounds/grand_dad3.ogg new file mode 100644 index 0000000..bd960fd Binary files /dev/null and b/assets/sounds/grand_dad3.ogg differ diff --git a/assets/sounds/grand_dad4.ogg b/assets/sounds/grand_dad4.ogg new file mode 100644 index 0000000..2e871d8 Binary files /dev/null and b/assets/sounds/grand_dad4.ogg differ diff --git a/assets/sounds/grand_dad5.ogg b/assets/sounds/grand_dad5.ogg new file mode 100644 index 0000000..45fe84f Binary files /dev/null and b/assets/sounds/grand_dad5.ogg differ diff --git a/assets/sounds/grand_dad6.ogg b/assets/sounds/grand_dad6.ogg new file mode 100644 index 0000000..996fd81 Binary files /dev/null and b/assets/sounds/grand_dad6.ogg differ diff --git a/assets/sounds/warning_heartbeat.ogg b/assets/sounds/warning_heartbeat.ogg new file mode 100644 index 0000000..2c95079 Binary files /dev/null and b/assets/sounds/warning_heartbeat.ogg differ diff --git a/lovely.toml b/lovely.toml new file mode 100644 index 0000000..79cefeb --- /dev/null +++ b/lovely.toml @@ -0,0 +1,63 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 2147483647 + +[[patches]] +[patches.pattern] +target = "globals.lua" +pattern = "EDITION = {1,1,1,1}," +position = "before" +payload = '''jane_RGB = {0,0,0,1}, +jane_RGB_HUE = 0, +almighty = {0,0,1,1},''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if v.name == 'Black Hole' or v.name == 'The Soul' or v.hidden then" +position = "at" +payload = "if Jane.hidden(v) then" +match_indent = true +overwrite = false + +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "G.GAME.current_round.current_hand.chips*G.GAME.current_round.current_hand.mult" +position = "at" +payload = '''Jane.get_chipmult_sum(G.GAME.current_round.current_hand.chips, G.GAME.current_round.current_hand.mult)''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "local AC = G.SETTINGS.ambient_control" +position = "before" +payload = '''if Jane and G.ARGS.score_intensity.required_score ~= 0 then + Jane.sinister = (G.ARGS.score_intensity.earned_score / (to_big(10) ^ to_big(G.ARGS.score_intensity.required_score))):to_number() > 1 +end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "scoring_hand = final_scoring_hand" +position = "after" +payload = '''if not (G.GAME.blind and G.GAME.blind.name == "The Card" and not G.GAME.blind.disabled) and next(SMODS.find_card('j_jane_survivor')) then + for _, v in ipairs(G.hand.cards) do + if not v:gc().unhighlightable then + table.insert(scoring_hand, v) + end + end +end''' +match_indent = true + +[[patches]] +[patches.regex] +target = "functions/state_events.lua" +pattern = '''hand_chips\*mult''' +position = "at" +payload = "Jane.get_chipmult_sum(hand_chips, mult)" +match_indent = true diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..511a54b --- /dev/null +++ b/manifest.json @@ -0,0 +1,16 @@ +{ + "id": "jane", + "name": "Almighty", + "author": ["jenwalter666", "Emik"], + "description": "Fork of Jen's almanac that focuses on only including the absolute best parts of the mod, and removing everything else.", + "prefix": "jane", + "main_file": "src/main.lua", + "badge_colour": "3c3cff", + "priority": 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, + "dependencies": [ + "Steamodded (>=1.0.0~ALPHA-1304a)", + "Bakery (>=0.1.26~*)" + ], + "conflicts": ["Jen"], + "version": "0.1.0" +} \ No newline at end of file diff --git a/refs/BalatroBakery b/refs/BalatroBakery new file mode 120000 index 0000000..6eb6c90 --- /dev/null +++ b/refs/BalatroBakery @@ -0,0 +1 @@ +../../BalatroBakery/src/ \ No newline at end of file diff --git a/refs/Cryptid b/refs/Cryptid new file mode 120000 index 0000000..3a564cd --- /dev/null +++ b/refs/Cryptid @@ -0,0 +1 @@ +../../Cryptid/ \ No newline at end of file diff --git a/refs/Talisman b/refs/Talisman new file mode 120000 index 0000000..82b90f1 --- /dev/null +++ b/refs/Talisman @@ -0,0 +1 @@ +../../Talisman/ \ No newline at end of file diff --git a/refs/dump b/refs/dump new file mode 120000 index 0000000..59af519 --- /dev/null +++ b/refs/dump @@ -0,0 +1 @@ +../../lovely/dump/ \ No newline at end of file diff --git a/refs/lsp_def b/refs/lsp_def new file mode 120000 index 0000000..e1a2049 --- /dev/null +++ b/refs/lsp_def @@ -0,0 +1 @@ +../../smods/lsp_def/ \ No newline at end of file diff --git a/src/back.lua b/src/back.lua new file mode 100644 index 0000000..0e4ee7a --- /dev/null +++ b/src/back.lua @@ -0,0 +1,167 @@ +SMODS.Atlas { + px = 71, + py = 95, + key = "janedecks", + path = Jane.config.texture_pack .. "/b_jane_decks.png" +} + +local eternal_text = Cryptid and "Absolute" or "Eternal" + +SMODS.Back { + key = "nitro", + atlas = "janedecks", + pos = {x = 1, y = 1}, + loc_txt = { + name = "Acceleration Deck", + text = { + "After defeating the {C:attention}Boss Blind{},", + "set {C:attention}ante {}to the {C:attention}next", + "{C:attention}triangle number {}and create", + Cryptid and "an {C:spectral,E:1}Empowered Tag" or "a {C:dark_edition}Negative {C:spectral,E:1}Soul", + } + }, + apply = function(_) + G.GAME.win_ante = G.GAME.win_ante * (G.GAME.win_ante + 1) / 2 + G.GAME.nitro = true + end, + trigger_effect = function(_, args) + if args.context == "eval" and G.GAME.last_blind and G.GAME.last_blind.boss then + Jane.q(function() + Jane.empowered() + return true + end) + end + end +} + +SMODS.Back { + key = 'obsidian', + atlas = 'janedecks', + pos = {x = 2, y = 1}, + loc_txt = { + name = 'Obsidian Deck', + text = { + '{C:attention}Hidden{} cards {C:inactive}(ex. {C:spectral}The Soul{C:inactive})', + 'can {C:attention}appear normally{}', + } + }, + apply = function(_) + G.GAME.obsidian = true + end +} + +SMODS.Back { + key = "orrery", + atlas = "janedecks", + pos = {x = 0, y = 0}, + loc_txt = { + name = "Orrery Deck", + text = { + "All hands start at", + "{X:chips,C:white}150{C:mult} X {X:red,C:white}1{} and", + "{C:cry_ascendant}equalised {}whenever", + "their {C:chips}Chips{}, {C:mult}Mult{},", + "or {C:planet}level {C:attention}change", + } + }, + apply = function(_) + Jane.q(function() + G.GAME.orrery = {chips = 150, level = 1, mult = 1} + + for _, v in pairs(G.GAME.hands) do + v.mult = G.GAME.orrery.mult + v.chips = G.GAME.orrery.chips + end + + save_run() + return true + end + ) + end +} + +SMODS.Back { + key = "tortoise", + atlas = "janedecks", + pos = {x = 3, y = 1}, + loc_txt = { + name = "Tortoise Deck", + text = { + "{C:attention}Ante increases{} are", + "{C:attention}half{} as strong", + } + }, + apply = function(_) + G.GAME.tortoise = true + end +} + +SMODS.Back { + key = "weeck", + atlas = "janedecks", + pos = {x = 4, y = 1}, + loc_txt = { + name = "Weeck", + text = { + "Start with an {C:purple,E:1}" .. eternal_text, + "{C:attention}Wee Joker {}and a deck", + "containing {C:attention}2 {C:purple,E:1}" .. eternal_text, + "{C:attention}2's {}of {C:attention}each suit", + } + }, + apply = function(_) + G.GAME.weeck = true + + Jane.q(function() + local new_card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_wee", "weeck") + new_card.ability.cry_absolute = true + new_card.ability.eternal = true + G.jokers:emplace(new_card) + local add = {} + + for _, v in pairs(G.playing_cards) do + if v.base.id == 2 then + v.ability.cry_absolute = true + v.ability.eternal = true + add[#add + 1] = v + else + v:start_dissolve(nil, true) + end + end + + for _, v in pairs(add) do + local dupe = copy_card(v) + dupe:start_materialize() + dupe:add_to_deck() + G.hand:emplace(dupe) + G.playing_card = (G.playing_card and G.playing_card + 1) or 1 + table.insert(G.playing_cards, dupe) + end + + save_run() + return true + end) + end +} + +local orig_ante = ease_ante + +---@diagnostic disable-next-line: lowercase-global +function ease_ante(mod) + local function next_triangle_number(x) + local n = (math.sqrt(8 * x + 1) - 1) / 2 + return (n + 1) * (n + 2) / 2 + end + + if G.GAME.nitro then + mod = G.GAME.round_resets.ante < 0 and -G.GAME.round_resets.ante + or math.ceil(next_triangle_number(G.GAME.round_resets.ante) - G.GAME.round_resets.ante) + end + + if G.GAME.tortoise and mod > 0 then + local disp = tonumber(G.GAME.round_resets.ante_disp) + mod / 2 + mod = mod / 2 + (disp == math.floor(disp) and 0.5 or 0) + end + + orig_ante(mod) +end diff --git a/src/blind.lua b/src/blind.lua new file mode 100644 index 0000000..1b71669 --- /dev/null +++ b/src/blind.lua @@ -0,0 +1,152 @@ +SMODS.Atlas { + px = 34, + py = 34, + frames = 21, + key = "janeblinds", + atlas_table = "ANIMATION_ATLAS", + path = Jane.config.texture_pack .. "/bl_jane_blinds.png" +} + +local final_operations = { + [1] = {"+", "UI_CHIPS"}, + [2] = {"X", "UI_MULT"}, + [3] = {"^", G.C.jane_RGB}, +} + +local function offset_operator(by) + local function set(number) + if G.GAME then + G.GAME.operator = math.max(math.min(number, 3), 1) + end + end + + local previous = Jane.get_operator() + set(by + previous) + by = Jane.get_operator() + local txt = final_operations[by][1] ---@diagnostic disable-next-line: cast-local-type + local col = type(final_operations[by][2]) == "table" and final_operations[by][2] or G.C[final_operations[by][2]] + + Jane.q(function() + local changed_text = false + + for _, outer in pairs(G.STAGE_OBJECTS) do + if type(outer) == "table" then + for _, inner in pairs(outer) do + if type(inner) == "table" and + type(inner.config) == "table" and + (inner.config.text == final_operations[previous][1] or + inner.config.text == final_operations[2][1]) and + inner.config.text_drawable then + if inner.config.text ~= txt then + changed_text = true + end + + inner.config.text = txt + inner.config.text_drawable:set(txt) + inner.config.colour = col + inner:juice_up(0.8, 0.5) + end + end + end + end + + if changed_text then + play_sound("button", 1.1, 0.65) + end + + return true + end) +end + +SMODS.Blind { + loc_txt = { + name = "The Descending", + text = {"Decrease Chip-Mult", "operator by 1 level"} + }, + key = "descending", + config = {}, + boss = {min = 1, max = 10, hardcore = true}, + boss_colour = HEX("b200ff"), + atlas = "janeblinds", + pos = {x = 0, y = 0}, + vars = {}, + dollars = 15, + mult = 0.5, + defeat = function(_) + if not G.GAME.blind.disabled then + offset_operator(1) + end + end, + disable = function(self) + offset_operator(1) + end, + drawn_to_hand = function(_) + offset_operator(0) + end, + press_play = function(_) + offset_operator(0) + end, + set_blind = function(_) + offset_operator(-1) + end, +} + +SMODS.Blind { + loc_txt = { + name = "The Insignia", + text = {"Hand must contain", "only one suit"} + }, + key = "insignia", + config = {}, + boss = {min = 2, max = 10, no_orb = true, hardcore = true}, + boss_colour = HEX("a5aa00"), + atlas = "janeblinds", + pos = {x = 0, y = 9}, + vars = {}, + dollars = 7, + mult = 2, + debuff_hand = function(_, cards, _, _, _) + local numsuits = 0 + local checked_suits = {} + + for _, card in ipairs(cards) do + if not card:nosuit() and not checked_suits[card.base.suit] then + numsuits = numsuits + 1 + checked_suits[card.base.suit] = true + + if numsuits > 1 then + return true + end + end + end + end +} + +SMODS.Blind { + loc_txt = { + name = "The Wee", + text = {"Only 2s can be played"} + }, + key = "wee", + config = {}, + boss = {min = 1, max = 10, no_orb = true, hardcore = true}, + boss_colour = HEX("7F3F3F"), + atlas = "janeblinds", + pos = {x = 0, y = 3}, + vars = {}, + dollars = 2, + mult = 22 / 300, + debuff_hand = function(_, cards, _, _, _) + for _, v in ipairs(cards) do + if v:norank() or v:get_id() ~= 2 then + return true + end + end + end, + get_loc_debuff_text = function(_) + return "Hand must contain only 2s" + end, + recalc_debuff = function(_, card, _) + return card:norank() or card:get_id() ~= 2 + end, +} diff --git a/src/booster.lua b/src/booster.lua new file mode 100644 index 0000000..506aec7 --- /dev/null +++ b/src/booster.lua @@ -0,0 +1,266 @@ +SMODS.Atlas { + px = 71, + py = 95, + key = "janebooster", + path = Jane.config.texture_pack .. "/p_jane_boosters.png" +} + +for i = 1, 2 do + SMODS.Booster{ + key = "ministandard" .. i, + loc_txt = { + name = "Mini Standard Pack", + text = { + "Choose {C:attention}#1#{} of up to", + "{C:attention}#2# playing cards{} to", + "add to your deck", + } + }, + atlas = "janebooster", + pos = {x = 6, y = i - 1}, + weight = 0.4, + cost = 2, + config = {extra = 2, choose = 1}, + loc_vars = function(_, _, card) + return {vars = {card.ability.choose, card.ability.extra}} + end, + ease_background_colour = function(_) + ease_background_colour_blind(G.STATES.STANDARD_PACK) + end, + create_UIBox = function(_) + return create_UIBox_standard_pack() + end, + particles = function(_) + G.booster_pack_sparkles = Particles(1, 1, 0,0, { + timer = 0.015, + scale = 0.3, + initialize = true, + lifespan = 3, + speed = 0.2, + padding = -1, + attach = G.ROOM_ATTACH, + colours = {G.C.BLACK, G.C.RED}, + fill = true + }) + + G.booster_pack_sparkles.fade_alpha = 1 + G.booster_pack_sparkles:fade(1, 0) + end, + create_card = function(_, _, _) + local edition = poll_edition("standard_edition"..G.GAME.round_resets.ante, 2, true) + local seal = SMODS.poll_seal({mod = 10}) + + return { + set = (pseudorandom(pseudoseed("stdset"..G.GAME.round_resets.ante)) > 0.6) and "Enhanced" or "Base", + edition = edition, + seal = seal, + area = G.pack_cards, + skip_materialize = true, + soulable = true, + key_append = "sta" + } + end, + } +end + +for i = 1, 2 do + SMODS.Booster{ + key = "miniarcana" .. i, + loc_txt = { + name = "Mini Arcana Pack", + text = { + "Choose {C:attention}#1#{} of up to", + "{C:attention}#2# {C:tarot}Tarot{} cards to", + "be used immediately", + } + }, + atlas = "janebooster", + pos = {x = 3 + i, y = 1}, + weight = 0.4, + cost = 2, + config = {extra = 2, choose = 1}, + draw_hand = true, + loc_vars = function(_, _, card) + return {vars = {card.ability.choose, card.ability.extra}} + end, + ease_background_colour = function(_) + ease_background_colour_blind(G.STATES.TAROT_PACK) + end, + create_UIBox = function(_) + return create_UIBox_arcana_pack() + end, + particles = function(_) + G.booster_pack_sparkles = Particles(1, 1, 0,0, { + timer = 0.015, + scale = 0.2, + initialize = true, + lifespan = 1, + speed = 1.1, + padding = -1, + attach = G.ROOM_ATTACH, + colours = {G.C.WHITE, lighten(G.C.PURPLE, 0.4), lighten(G.C.PURPLE, 0.2), lighten(G.C.GOLD, 0.2)}, + fill = true + }) + + G.booster_pack_sparkles.fade_alpha = 1 + G.booster_pack_sparkles:fade(1, 0) + end, + create_card = function(_, _, _) + if G.GAME.used_vouchers.v_omen_globe and pseudorandom("omen_globe") > 0.8 then + return { + set = "Spectral", + soulable = true, + key_append = "ar2", + area = G.pack_cards, + skip_materialize = true, + } + end + + return { + set = "Tarot", + soulable = true, + key_append = "ar1", + area = G.pack_cards, + skip_materialize = true, + } + end + } +end + +for i = 1, 2 do + SMODS.Booster{ + key = "minicelestial" .. i, + atlas = "janebooster", + loc_txt = { + name = "Mini Celestial Pack", + text = { + "Choose {C:attention}#1#{} of up to", + "{C:attention}#2# {C:planet}Planet{} cards to", + "be used immediately", + } + }, + config = {extra = 2, choose = 1}, + pos = {x = 3 + i, y = 0}, + cost = 2, + weight = 0.4, + loc_vars = function(_, _, card) + return {vars = {card.ability.choose, card.ability.extra}} + end, + ease_background_colour = function(_) ease_background_colour_blind(G.STATES.PLANET_PACK) end, + create_UIBox = function(_) return create_UIBox_celestial_pack() end, + particles = function(_) + G.booster_pack_stars = Particles(1, 1, 0,0, { + fill = true, + scale = 0.1, + speed = 0.1, + timer = 0.07, + padding = -4, + lifespan = 15, + initialize = true, + attach = G.ROOM_ATTACH, + colours = {G.C.WHITE, HEX("a7d6e0"), HEX("fddca0")}, + }) + + G.booster_pack_meteors = Particles(1, 1, 0,0, { + speed = 4, + timer = 2, + fill = true, + scale = 0.05, + lifespan = 1.5, + attach = G.ROOM_ATTACH, + colours = {G.C.WHITE}, + }) + end, + create_card = function(_, _, index) + if not G.GAME.used_vouchers.v_telescope or index ~= 1 then + return { + set = "Planet", + area = G.pack_cards, + skip_materialize = true, + soulable = true, + key_append = "pl1" + } + end + + local planet, hand, tally = nil, nil, 0 + + for _, v in ipairs(G.handlist) do + if G.GAME.hands[v].visible and G.GAME.hands[v].played > tally then + hand = v + tally = G.GAME.hands[v].played + end + end + + if hand then + for _, v in pairs(G.P_CENTER_POOLS.Planet) do + if v.config.hand_type == hand then + planet = v.key + end + end + end + + return { + key = planet, + set = "Planet", + soulable = true, + key_append = "pl1", + area = G.pack_cards, + skip_materialize = true, + } + end + } +end + +for i = 1, 2 do + SMODS.Booster{ + key = "minispectral" .. i, + atlas = "janebooster", + loc_txt = { + name = "Mini Spectral Pack", + text = { + "Choose {C:attention}#1#{} of up to", + "{C:attention}#2# {C:spectral}Spectral{} cards to", + "be used immediately", + } + }, + config = {extra = 1, choose = 1}, + pos = {x = 3 + i, y = 2}, + cost = 2, + weight = 0.225, + draw_hand = true, + loc_vars = function(_, _, card) + return {vars = {card.ability.choose, card.ability.extra}} + end, + ease_background_colour = function(_) + ease_background_colour_blind(G.STATES.SPECTRAL_PACK) + end, + create_UIBox = function(_) + return create_UIBox_spectral_pack() + end, + particles = function(_) + G.booster_pack_sparkles = Particles(1, 1, 0,0, { + scale = 0.1, + fill = true, + speed = 0.2, + lifespan = 3, + padding = -1, + timer = 0.015, + initialize = true, + attach = G.ROOM_ATTACH, + colours = {G.C.WHITE, lighten(G.C.GOLD, 0.2)}, + }) + + G.booster_pack_sparkles.fade_alpha = 1 + G.booster_pack_sparkles:fade(1, 0) + end, + create_card = function(_, _, _) + return { + soulable = true, + set = "Spectral", + key_append = "spe", + area = G.pack_cards, + skip_materialize = true, + } + end, + } +end diff --git a/src/edition.lua b/src/edition.lua new file mode 100644 index 0000000..0c1aa62 --- /dev/null +++ b/src/edition.lua @@ -0,0 +1,136 @@ +SMODS.Sound({key = "e_jumbo", path = "e_jumbo.ogg"}) +SMODS.Shader({key = "polygloss", path = "polygloss.fs"}) +SMODS.Sound({key = "e_polygloss", path = "e_polygloss.ogg"}) + +local function resize(card, mod, force_save) + if force_save or not card.origsize then + card.origsize = {w = card.T.w, h = card.T.h} + end + + card:hard_set_T(card.T.x, card.T.y, card.T.w * mod, card.T.h * mod) + remove_all(card.children) + card.children = {} + card.children.shadow = Moveable(0, 0, 0, 0) + card:set_sprites(card.config.center, card.base.id and card.config.card) + + if card.area and + ((G.shop_jokers and card.area == G.shop_jokers) or + (G.shop_booster and card.area == G.shop_booster) or + (G.shop_vouchers and card.area == G.shop_vouchers)) then + create_shop_card_ui(card) + end +end + +SMODS.Edition({ + key = "polygloss", + loc_txt = { + name = "Polygloss", + label = "Polygloss", + text = { + "{C:chips}+#1#{}, {X:chips,C:white}x#2#{} & {X:chips,C:dark_edition}^#3#{} Chips", + "{C:mult}+#4#{}, {X:mult,C:white}x#5#{} & {X:mult,C:dark_edition}^#6#{} Mult", + "Generates {C:money}+$#7#", + "{C:dark_edition,s:0.7,E:2}Shader by : Oiiman" + } + }, + config = {chips = 1, mult = 1, x_chips = 1.1, x_mult = 1.1, e_chips = 1.01, e_mult = 1.01, p_dollars = 1}, + sound = { + sound = "jane_e_polygloss", + per = 1.2, + vol = 0.4 + }, + weight = 8, + extra_cost = 2, + in_shop = true, + shader = "polygloss", + apply_to_float = false, + loc_vars = function(self) + return {vars = { + self.config.chips, + self.config.x_chips, + self.config.e_chips, + self.config.mult, + self.config.x_mult, + self.config.e_mult, + self.config.p_dollars + }} + end +}) + +local jumbo_modifier = Cryptid and 100 or 2 + +SMODS.Edition({ + key = "jumbo", + loc_txt = { + name = "Jumbo", + label = "Jumbo", + text = { + "All card values are", + "{C:attention}multiplied{} by {C:attention}up to " .. jumbo_modifier, + "{C:inactive}(If possible)", + "{C:inactive,E:1,s:0.7}Whoa, it's huge!!{}" + } + }, + on_apply = function(card) + G.E_MANAGER:add_event(Event({ + blocking = false, + blockable = false, + func = function() + resize(card, Jane.config.wee_sizemod) + return true + end + })) + + local obj = card:gc() + + if obj.set == "Booster" or obj.jumbo_mod then + jumbo_modifier = obj.jumbo_mod or 10 + end + + if card.added_to_deck then + card:remove_from_deck() + end + + Jane.misprintize(card, {min = jumbo_modifier, max = jumbo_modifier}, nil, true) + + if card.added_to_deck then + card:add_to_deck() + end + end, + on_remove = function(card) + G.E_MANAGER:add_event(Event({ + blocking = false, + blockable = false, + func = function() + resize(card, 1 / Jane.config.wee_sizemod) + return true + end + })) + + local was_added = card.added_to_deck + + if was_added then + card:remove_from_deck() + end + + Jane.misprintize(card, {min = 1 / jumbo_modifier, max = 1 / jumbo_modifier}, nil, true) + + if was_added then + card:add_to_deck() + end + end, + config = {twos_scored = 0}, + sound = { + sound = "jane_e_jumbo", + per = 1, + vol = 0.5 + }, + weight = 0.8, + in_shop = true, + shader = false, + extra_cost = 12, + apply_to_float = false, + get_weight = function(self) + return G.GAME.edition_rate * self.weight + end, +}) diff --git a/src/joker.lua b/src/joker.lua new file mode 100644 index 0000000..7ea4836 --- /dev/null +++ b/src/joker.lua @@ -0,0 +1,311 @@ +for _, v in pairs({"7granddad", "betmma", "oxy", "peppino"}) do + SMODS.Atlas { + px = 71, + py = 95, + key = "jane" .. v, + path = Jane.config.texture_pack .. "/j_jane_" .. v .. ".png", + } +end + +for i = 1, 6 do + SMODS.Sound({key = 'grand' .. i, path = 'grand_dad' .. i .. '.ogg'}) +end + +local exotic = Cryptid and "cry_exotic" or 4 + +local food = { + "j_gros_michel", + "j_egg", + "j_ice_cream", + "j_cavendish", + "j_turtle_bean", + "j_diet_cola", + "j_popcorn", + "j_ramen", + "j_selzer", + "j_cry_pickle", + "j_cry_chili_pepper", + "j_cry_oldcandy", + "j_cry_caramel", + "j_cry_foodm", + "j_cry_cotton_candy", + "j_cry_wrapped", + "j_cry_candy_cane", + "j_cry_candy_buttons", + "j_cry_jawbreaker", + "j_cry_mellowcreme", + "j_cry_brittle", + "j_jane_peppino", +} + +local granddad_palette = { + HEX("155fd9"), + HEX("ff8170"), + HEX("ffffff"), + HEX("6c0700") +} + +local function food_jokers_count() + if not G.jokers then + return 0 + end + + local amount = 0 + + for _, v in pairs(food) do + amount = amount + #SMODS.find_card(v) + end + + return amount +end + +local function grand_dad(card) + Jane.q(function() + card:juice_up(0.5, 0.5) + return true + end) + + local rnd = math.random(6) + local obj = card.edition or {} + + Jane.play_sound( + "jane_grand" .. rnd, + obj.jane_jumbo and (1 / Jane.config.wee_sizemod) or 1, + 0.5 + ) + + Jane.card_status_text( + card, + rnd == 2 and "Flintstones?!" or rnd == 6 and "Gruhh- Dad!" or "Grand Dad!", + nil, + 0.05 * card.T.h, + granddad_palette[math.random(#granddad_palette)], + 0.6, + 0.6, + nil, + nil, + "bm" + ) +end + +local function voucher_count() + if not G.GAME.used_vouchers then + return 0 + end + + local count = 0 + + for _, v in pairs(G.GAME.used_vouchers) do + if v then + count = count + 1 + end + end + + return count +end + +SMODS.Joker { + key = "oxy", + atlas = "janeoxy", + loc_txt = { + name = "Oxy", + text = { + "{C:attention}Scored steel{} cards give", + "{X:mult,C:white}x#1#{} {C:mult}Mult {}& {X:chips,C:white}x#1#{} {C:chips}Chips", + " ", + "{C:inactive,s:0.75,E:1}#2#{C:red,s:1.5,E:1}#3#", + } + }, + pos = {x = 0, y = 0}, + config = {steel = 1.5}, + sinis = {x = 2, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 10, + rarity = 3, + blueprint_compat = true, + loc_vars = function(_, _, center) + return {vars = { + center.ability.steel, + Jane.sinister and "" or "We all cut close...", + Jane.sinister and "WHAT ARE YOU DOING DOWN THERE?!?" or "", + }} + end, + calculate = function(self, card, context) + if context.individual and + context.cardarea == G.play and + context.other_card.ability.name == "Steel Card" then + return { + x_chips = card.ability.steel, + x_mult = card.ability.steel, + colour = G.C.PURPLE, + card = card + }, true + end + end +} + +SMODS.Joker { + key = "7granddad", + loc_txt = { + name = "7 GRAND DAD", + text = { + "This Joker has a {C:jane_RGB,E:1}strange", + "{C:jane_RGB,E:1}reaction {}to scored {C:attention}7{}s", + } + }, + config = {}, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 12, + rarity = exotic, + atlas = "jane7granddad", + blueprint_compat = true, + loc_vars = function(_, _, center) + return {vars = {center.ability.shopslots}} + end, + add_to_deck = function(_, card, _) + grand_dad(card) + end, + remove_from_deck = function(_, card, _) + grand_dad(card) + end, + calculate = function(_, card, context) + if context.cardarea == G.play then + local function scj(c) + return c.cardarea and c.cardarea == G.play and not c.before and not c.after and not c.repetition + end + + if context.other_card and context.other_card:get_id() == 7 and scj(context) then + grand_dad(card) + local palette = granddad_palette[math.random(#granddad_palette)] + local rnd = pseudorandom(pseudoseed("granddad"), 1, Cryptid and 7 or 5) + + if rnd == 1 then + return { + message = "+777", + chips = 777, + colour = palette, + card = card + }, true + elseif rnd == 2 then + return { + message = "+777 Mult", + mult = 777, + colour = palette, + card = card + }, true + elseif rnd == 3 then + return { + message = "+$7", + dollars = 7, + colour = palette, + card = card + }, true + elseif rnd == 4 then + return { + message = "x7", + x_chips = 7, + colour = palette, + card = card + }, true + elseif rnd == 5 then + return { + message = "x7 Mult", + x_mult = 7, + colour = palette, + card = card + }, true + elseif rnd == 6 then + return { + message = "^1.77", + e_chips = 1.77, + colour = palette, + card = card + }, true + else + return { + message = "^1.77 Mult", + e_mult = 1.77, + colour = palette, + card = card + }, true + end + end + end + end +} + +local operator = Cryptid and "^" or "*" + +SMODS.Joker { + key = "betmma", + atlas = "janebetmma", + loc_txt = { + name = "Betmma", + text = { + "{X:dark_edition,C:chips}+" .. operator .. "#1#{C:chips} Chips{} for every", + "{C:attention}unique Voucher redeemed", + "{C:inactive}(Currently {X:dark_edition,C:chips}" .. operator .. "#2#{C:inactive})", + } + }, + config = {big_num_scaler = true, extra = {tet = 0.1}}, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 50, + rarity = exotic, + blueprint_compat = true, + loc_vars = function(_, _, center) + return {vars = {center.ability.extra.tet, 1 + (voucher_count() * center.ability.extra.tet)}} + end, + calculate = function(_, card, context) + if context.cardarea ~= G.jokers or context.before or context.after or not context.scoring_name then + return + end + + local v = voucher_count() + + if v > 0 then + local num = 1 + (v * card.ability.extra.tet) + + return { + card = card, + colour = G.C.jane_RGB, + message = operator .. number_format(num), + [Cryptid and "Echips_mod" or "xchips_mod"] = num, + }, true + end + end +} + +SMODS.Joker { + key = "peppino", + atlas = "janepeppino", + loc_txt = { + name = "Peppino Spaghetti", + text = { + "{X:dark_edition,C:red}" .. operator .. "2^x{C:red} Mult{} for every", + "{C:attention}food or Peppino Joker", + "in your possession", + "{C:inactive}(Currently {X:dark_edition,C:red}" .. operator .. "#1#{C:red} Mult{C:inactive})", + } + }, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 50, + rarity = exotic, + blueprint_compat = true, + loc_vars = function(_, _, _) + return {vars = {2 ^ food_jokers_count()}} + end, + calculate = function(_, _, context) + local count = food_jokers_count() + + if context.joker_main and count > 0 then + return { + colour = G.C.DARK_EDITION, + message = "^" .. 2 ^ count .. " Mult", + [Cryptid and "Emult_mod" or "xmult_mod"] = 2 ^ count, + }, true + end + end +} diff --git a/src/main.lua b/src/main.lua new file mode 100644 index 0000000..6403e2f --- /dev/null +++ b/src/main.lua @@ -0,0 +1,373 @@ +Jane = { + config = { + wee_sizemod = 1.25, + texture_pack = "default", + bans = {"j_cry_crustulum", "c_cry_hammerspace"} + }, +} + +Jane.misprintize = (Cryptid or {}).misprintize +Jane.misprintize_tbl = (Cryptid or {}).misprintize_tbl +Jane.misprinitze_val = (Cryptid or {}).misprintize_val + +if not Jane.misprintize then + assert(SMODS.load_file("src/misprintize.lua"))() +end + +function Jane.canuse() + 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 + +function Jane.card_status_text( + card, + text, + xoffset, + yoffset, + colour, + size, + delay, + juice, + jiggle, + align, + sound, + volume, + pitch, + trig, + f +) + if (delay or 0) <= 0 then + if type(f) == "function" then + f(card) + end + + attention_text({ + text = text, + scale = size or 1, + hold = 0.7, + backdrop_colour = colour or (G.C.FILTER), + align = align or "bm", + major = card, + offset = {x = xoffset or 0, y = yoffset or (-0.05*G.CARD_H)} + }) + + if sound then + play_sound(sound, pitch or (0.9 + (0.2 * math.random())), volume or 1) + end + + if juice then + if type(juice) == "table" then + card:juice_up(juice[1], juice[2]) + elseif type(juice) == "number" and juice ~= 0 then + card:juice_up(juice, juice / 6) + end + end + + if jiggle then + G.ROOM.jiggle = G.ROOM.jiggle + jiggle + end + else + G.E_MANAGER:add_event(Event({ + trigger = trig, + delay = delay, + func = function() + if f and type(f) == "function" then + f(card) + end + + attention_text({ + text = text, + scale = size or 1, + hold = 0.7 + (delay or 0), + backdrop_colour = colour or (G.C.FILTER), + align = align or "bm", + major = card, + offset = {x = xoffset or 0, y = yoffset or (-0.05*G.CARD_H)} + }) + + if sound then + play_sound(sound, pitch or (0.9 + (0.2*math.random())), volume or 1) + end + + if juice then + if type(juice) == "table" then + card:juice_up(juice[1], juice[2]) + elseif type(juice) == "number" and juice ~= 0 then + card:juice_up(juice, juice / 6) + end + end + + if jiggle then + G.ROOM.jiggle = G.ROOM.jiggle + jiggle + end + + return true + end + })) + end +end + +function Jane.empowered() + if Cryptid then + add_tag(Tag("tag_cry_empowered")) + return true + end + + local card = create_card("Spectral", G.consumeables, nil, nil, nil, nil, "c_soul", "acceleration_soul") + card:set_edition({negative = true}) + card:add_to_deck() + G.consumeables:emplace(card) +end + +function Jane.get_chipmult_sum(chips, mult) + chips = chips or 0 + mult = mult or 0 + + local op, big = Jane.get_operator(), Talisman.config_file.break_infinity == "omeganum" and + to_big or function (x) return x end + + if op >= 3 then + return big(chips) ^ big(mult) + elseif op == 2 then + return big(chips) * big(mult) + end + + return big(chips) + big(mult) +end + +function Jane.get_operator() + if not G.GAME then + return 0 + end + + G.GAME.operator = G.GAME.operator or 2 + return math.max(math.min(G.GAME.operator, 3), 1) +end + +function Jane.hidden(card) + return G.GAME and not + G.GAME.obsidian and + type(card) == 'table' and + (card.name == "Black Hole" or card.name == "The Soul" or card.hidden) +end + +function Jane.play_sound(sound, per, vol) + G.E_MANAGER:add_event(Event({ + func = function() + play_sound(sound,per,vol) + return true + end + })) +end + +function Jane.q(fc, de, t, tr, bl, ba) + G.E_MANAGER:add_event(Event({ + timer = t, + trigger = tr, + delay = de, + blockable = bl, + blocking = ba, + func = fc + })) +end + +function Card:gc() + return (self.config or {}).center or {} +end + +function Card:norank() + return self.ability.name == "Stone Card" or self.config.center.no_rank +end + +function Card:nosuit() + return self.ability.name == "Stone Card" or self.config.center.no_suit +end + +local orig_debuff = Card.set_debuff + +function Card:set_debuff(should_debuff) + if should_debuff and ((self.config or {}).center or {}).debuff_immune then + Jane.card_status_text(self, "Immune", nil, 0.05 * self.T.h, G.C.RED, nil, 0.6, nil, nil, "bm", "cancel", 1, 0.9) + return false + else + orig_debuff(self, should_debuff) + end +end + +local orig_menu = Game.main_menu + +function Game:main_menu(change_context) + Jane.sinister = nil + orig_menu(self, change_context) +end + +local orig_update = Game.update + +function Game:update(dt) + local function delete_hardbans() + if not Jane.config.disable_bans then + for _, v in pairs(Jane.config.bans) do + local e = SMODS.Center:get_obj(v) + + if e then + e:delete() + end + end + end + end + + local function hand(name, chip, mul, lv, notif, snd, vol, pit, de) + local config = { + delay = de or 0.3, + pitch = pit or 0.8, + volume = vol or 0.7, + sound = type(snd) == "string" and snd or type(snd) == "nil" and "button", + } + + local vals = { + level = lv or "?", + mult = mul or "?", + StatusText = notif, + chips = chip or "?", + handname = name or "????", + } + + update_hand_text(config, vals) + end + + local function rebalance_orrery() + local function small(x) + return type(x) == "table" and x:to_number() or x + end + + local orrery = (G.GAME or {}).orrery + + if not orrery then + return + end + + local count = 0 + local hands = {} + local pools = {chips = 0, level = 0, mult = 0} + + for k, v in pairs(G.GAME.hands) do + if k ~= "cry_WholeDeck" then + count = count + 1 + hands[#hands + 1] = v + pools.mult = v.mult + pools.mult + pools.chips = v.chips + pools.chips + pools.level = v.level + pools.level + end + end + + if pools.mult == orrery.mult and pools.chips == orrery.chips and pools.level == orrery.level then + return + end + + table.sort(hands, function (x, y) return x.order > y.order end) + + for i, v in ipairs(hands) do + v.mult = math.floor(pools.mult / count) + (small(pools.mult % count) >= i and 1 or 0) + v.chips = math.floor(pools.chips / count) + (small(pools.chips % count) >= i and 1 or 0) + v.level = math.floor(pools.level / count) + (small(pools.level % count) >= i and 1 or 0) + end + + orrery.mult = pools.mult + orrery.chips = pools.chips + orrery.level = pools.level + hand(localize("k_all_hands"), math.floor(pools.chips / count), math.floor(pools.mult / count), math.floor(pools.level / count)) + delay(1) + update_hand_text({sound = "button", volume = 0.7, pitch = 1.1, delay = 0}, {mult = 0, chips = 0, handname = "", level = ""}) + end + + local function hsv(h, s, v) + if s <= 0 then return v, v, v end + h = h * 6 + local c = v * s + local x = (1 - math.abs((h % 2) - 1)) * c + local m, r, g, b = (v - c), 0, 0, 0 + + if h < 1 then + r, g, b = c, x, 0 + elseif h < 2 then + r, g, b = x, c, 0 + elseif h < 3 then + r, g, b = 0, c, x + elseif h < 4 then + r, g, b = 0, x, c + elseif h < 5 then + r, g, b = x, 0, c + else + r, g, b = c, 0, x + end + + return r + m, g + m, b + m + end + + orig_update(self, dt) + + if not Jane.bans_done then + delete_hardbans() + Jane.bans_done = true + end + + if (G.GAME or {}).banned_keys then + for _, v in pairs(Jane.config.bans) do + G.GAME.banned_keys[v] = true + end + end + + if G.ARGS.LOC_COLOURS then + local r, g, b = hsv(self.C.jane_RGB_HUE / 360, .5, 1) + self.C.jane_RGB[1] = r + self.C.jane_RGB[3] = g + self.C.jane_RGB[2] = b + self.C.jane_RGB_HUE = (self.C.jane_RGB_HUE + 0.5) % 360 + G.ARGS.LOC_COLOURS.jane_RGB = self.C.jane_RGB + end + + rebalance_orrery() +end + +local orig_card = SMODS.find_card + +---@param key string +---@param count_debuffed true? +---@return Card[]|table[] +--- Returns all cards matching provided `key`. +function SMODS.find_card(key, count_debuffed) + return orig_card(key == "j_jen_saint" and "j_jane_saint" or key, count_debuffed) +end + +SMODS.Atlas { + px = 34, + py = 34, + key = "modicon", + path = "almanac_avatar.png", +} + +SMODS.Atlas { + px = 71, + py = 95, + key = "janeacc", + path = Jane.config.texture_pack .. "/c_jane_acc.png", +} + +for _, v in ipairs({ + "back", + "blind", + "booster", + "edition", + "joker", + "slugcat", + "spectral", + "tarot", + "token", + "voucher", +}) do + assert(SMODS.load_file("src/" .. v .. ".lua"))() +end diff --git a/src/misprintize.lua b/src/misprintize.lua new file mode 100644 index 0000000..5d75311 --- /dev/null +++ b/src/misprintize.lua @@ -0,0 +1,311 @@ +-- The following code is slightly adapted from +-- https://github.com/MathIsFun0/Cryptid/blob/main/lib/misprintize.lua + +local base_values = {} + +local big_num_whitelist = { + j_egg = true, + j_wee = true, + j_flash = true, + j_ramen = true, + j_glass = true, + j_caino = true, + j_cry_m = true, + j_runner = true, + j_square = true, + j_castle = true, + j_yorick = true, + j_madness = true, + j_vampire = true, + j_obelisk = true, + j_popcorn = true, + j_red_card = true, + j_hologram = true, + j_trousers = true, + j_campfire = true, + j_cry_whip = true, + j_ice_cream = true, + j_lucky_cat = true, + j_throwback = true, + j_cry_hugem = true, + j_cry_pickle = true, + j_cry_cursor = true, + j_cry_primus = true, + j_cry_mprime = true, + j_green_joker = true, + j_turtle_bean = true, + j_cry_wee_fib = true, + j_cry_jimball = true, + j_ride_the_bus = true, + j_hit_the_road = true, + j_cry_dropshot = true, + j_cry_fspinner = true, + j_cry_mondrian = true, + j_constellation = true, + j_cry_crustulum = true, + j_cry_spaceglobe = true, + j_cry_exponentia = true, + j_cry_chili_pepper = true, + j_cry_eternalflame = true, + j_cry_stella_mortis = true, + j_cry_krustytheclown = true, + j_cry_antennastoheaven = true, +} + +local function check(v, is_big) + if is_big then + if not v or type(v) == "number" and (v ~= v or v > 1e300 or v < -1e300) then + v = 1e300 + end + + if type(v) == "table" then + return v + end + + if v > 1e100 or v < -1e100 then + return to_big(v) + end + end + + return not v or type(v) == "number" and (v ~= v or v > 1e300 or v < -1e300) and 1e300 or v +end + +local function deep_copy(obj, seen) + if type(obj) ~= "table" then + return obj + end + + if seen and seen[obj] then + return seen[obj] + end + + local s = seen or {} + local res = setmetatable({}, getmetatable(obj)) + s[obj] = res + + for k, v in pairs(obj) do + res[deep_copy(k, s)] = deep_copy(v, s) + end + + return res +end + +local function is_card_big(joker) + local center = joker.config and joker.config.center + + if not center then + return false + end + + return big_num_whitelist[center.key or "Nope!"] +end + +local function log_random(seed, min, max) + math.randomseed(seed) + local lmin = math.log(min, 2.718281828459045) + local lmax = math.log(max, 2.718281828459045) + local poll = math.random() * (lmax - lmin) + lmin + return math.exp(poll) +end + +function Jane.misprintize_val(val, override, big) + local function format(number, str) + return math.abs(to_big(number)) >= to_big(1e300) and number + or tonumber(str:format((Big and to_number(to_big(number)) or number))) + end + + return is_number(val) and check( + format( + val * log_random( + pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), + override and override.min or G.GAME.modifiers.cry_misprint_min, + override and override.max or G.GAME.modifiers.cry_misprint_max + ), + "%.2g" + ), + big + ) or val +end + +function Jane.misprintize_tbl(name, ref_tbl, ref_value, clear, override, stack, big) + if name and ref_tbl and ref_value then + local tbl = deep_copy(ref_tbl[ref_value]) + + for k, v in pairs(tbl) do + if (type(tbl[k]) ~= "table") or is_number(tbl[k]) then + if is_number(tbl[k]) and not + (k == "id") and not + (k == "colour") and not + (k == "suit_nominal") and not + (k == "base_nominal") and not + (k == "face_nominal") and not + (k == "qty") and not + (k == "x_mult" and v == 1 and not tbl.override_x_mult_check) and not + (k == "selected_d6_face") then + if not base_values[name] then + base_values[name] = {} + end + + if not base_values[name][k] then + base_values[name][k] = tbl[k] + end + + tbl[k] = check( + clear and base_values[name][k] + or cry_format( + (stack and tbl[k] or base_values[name][k]) + * log_random( + pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), + override and override.min or G.GAME.modifiers.cry_misprint_min, + override and override.max or G.GAME.modifiers.cry_misprint_max + ), + "%.2g" + ), + big + ) + end + else + for _k, _ in pairs(tbl[k]) do + if is_number(tbl[k][_k]) and not + (_k == "id") and not + (k == "perish_tally") and not + (k == "colour") and not + (_k == "suit_nominal") and not + (_k == "base_nominal") and not + (_k == "face_nominal") and not + (_k == "qty") and not + (k == "x_mult" and v == 1 and not tbl[k].override_x_mult_check) and not + (_k == "selected_d6_face") then + if not base_values[name] then + base_values[name] = {} + end + + if not base_values[name][k] then + base_values[name][k] = {} + end + + if not base_values[name][k][_k] then + base_values[name][k][_k] = tbl[k][_k] + end + + tbl[k][_k] = check( + clear and base_values[name][k][_k] + or cry_format( + (stack and tbl[k][_k] or base_values[name][k][_k]) * + log_random( + pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), + override and override.min or G.GAME.modifiers.cry_misprint_min, + override and override.max or G.GAME.modifiers.cry_misprint_max + ), + "%.2g" + ), + big + ) + end + end + end + end + + ref_tbl[ref_value] = tbl + end +end + +function Jane.misprintize(card, override, force_reset, stack) + local function no(self, m, no_no) + if no_no then + if self.infinifusion then + for i = 1, #self.infinifusion do + if G.P_CENTERS[self.infinifusion[i].key][m] or + (G.GAME and G.GAME[m] and G.GAME[m][self.infinifusion[i].key]) then + return true + end + end + + return false + end + + if not self.config then + return G.P_CENTERS[self.key][m] or (G.GAME and G.GAME[m] and G.GAME[m][self.key]) + end + + return self.config.center[m] or (G.GAME and G.GAME[m] and G.GAME[m][self.config.center_key]) or false + end + + return no(self, "no_" .. m, true) + end + + if no(card, "immutable", true) then + force_reset = true + end + + if card.infinifusion then + if card.config.center == card.infinifusion_center or card.config.center.key == "j_infus_fused" then + ---@diagnostic disable-next-line: undefined-global + calculate_infinifusion(card, nil, function(i) + Jane.misprintize(card, override, force_reset, stack) + end) + end + end + if (not force_reset or G.GAME.modifiers.cry_jkr_misprint_mod) and + (G.GAME.modifiers.cry_misprint_min or override or card.ability.set == "Joker") and not + stack or not + no(card, "immutable", true) then + if card.ability.name == "Ace Aequilibrium" then + return + end + + if G.GAME.modifiers.cry_jkr_misprint_mod and card.ability.set == "Joker" then + if not override then + override = {} + end + + override.min = override.min or G.GAME.modifiers.cry_misprint_min or 1 + override.max = override.max or G.GAME.modifiers.cry_misprint_max or 1 + override.min = override.min * G.GAME.modifiers.cry_jkr_misprint_mod + override.max = override.max * G.GAME.modifiers.cry_jkr_misprint_mod + end + + if G.GAME.modifiers.cry_misprint_min or override and override.min then + Jane.misprintize_tbl( + card.config.center_key, + card, + "ability", + nil, + override, + stack, + is_card_big(card) + ) + + if card.base then + Jane.misprintize_tbl( + card.config.card_key, + card, + "base", + nil, + override, + stack, + is_card_big(card) + ) + end + end + + if G.GAME.modifiers.cry_misprint_min then + card.misprint_cost_fac = 1 / + log_random( + pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), + override and override.min or G.GAME.modifiers.cry_misprint_min, + override and override.max or G.GAME.modifiers.cry_misprint_max + ) + + card:set_cost() + end + else + Jane.misprintize_tbl(card.config.center_key, card, "ability", true, nil, nil, is_card_big(card)) + end + + if card.ability.consumeable then + for k, _ in pairs(card.ability.consumeable) do + card.ability.consumeable[k] = deep_copy(card.ability[k]) + end + end +end diff --git a/src/slugcat.lua b/src/slugcat.lua new file mode 100644 index 0000000..fcbf3a4 --- /dev/null +++ b/src/slugcat.lua @@ -0,0 +1,606 @@ +SMODS.Sound({key = "enlightened", path = "enlightened.ogg"}) +SMODS.Sound({key = "warning_heartbeat", path = "warning_heartbeat.ogg"}) + +for i = 1, 8 do + SMODS.Sound({key = "gore" .. i, path = "gore" .. i .. ".ogg"}) +end + +for _, v in pairs({ + "artificer", + "hunter", + "gourmand", + "monk", + "rivulet", + "rot", + "saint", + "spearmaster", + "survivor", +}) do + SMODS.Atlas { + key = "jane" .. v, + px = 71, + py = 95, + path = Jane.config.texture_pack .. "/j_jane_" .. v .. ".png" + } +end + +local epic = Cryptid and "cry_epic" or 3 +local exotic = Cryptid and "cry_exotic" or 4 + +SMODS.Rarity { + key = "junk", + loc_txt = {name = "Junk"}, + badge_colour = G.C.JOKER_GREY, +} + +SMODS.Joker { + key = "spearmaster", + atlas = "janespearmaster", + loc_txt = { + name = "The Spearmaster", + text = { + "You can choose {C:attention}any number of cards", + "after opening {C:attention}any Booster Pack", + "{C:attention}Booster Packs{} have {C:green}+#1#{} additional cards", + } + }, + loc_vars = function(_, _, center) + return {vars = {center.ability.extra.extrachoices}} + end, + config = {extra = {extrachoices = 1}}, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 12, + rarity = epic, +} + +local orig_open = Card.open + +---@diagnostic disable-next-line: duplicate-set-field +function Card:open() + local orig = self.ability.extra or 1 + local spearmasters = SMODS.find_card("j_jane_spearmaster") + + if next(spearmasters) then + for _, v in pairs(spearmasters) do + orig = orig + v.ability.extra.extrachoices + end + + self.config.choose = math.floor(orig) + self.ability.extra = math.floor(orig) + end + + orig_open(self) + + G.E_MANAGER:add_event(Event({ + delay = 0.5, + timer = "REAL", + func = function() + if next(spearmasters) then + G.GAME.pack_choices = math.floor(self.ability.extra) + end + + return true + end + })) +end + +SMODS.Joker { + key = "survivor", + atlas = "janesurvivor", + loc_txt = { + name = "The Survivor", + text = { + "All cards held in hand", + "{C:attention}contribute to scoring", + } + }, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 20, + rarity = 4, +} + +SMODS.Joker { + key = "monk", + atlas = "janemonk", + loc_txt = { + name = "The Monk", + text = { + "{C:attention}Retrigger{} scored cards", + "{C:attention} {}times", + "{C:inactive}(ex. 9 = 9 times, Ace = 11 times)", + } + }, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 12, + rarity = 4, + blueprint_compat = true, + calculate = function(_, card, context) + if context.repetition and + context.cardarea == G.play and + context.other_card and + context.other_card.ability.name ~= "Stone Card" then + local id = context.other_card:get_id() + + return { + message = localize("k_again_ex"), + repetitions = id == 14 and 11 or math.min(id, 10), + colour = G.C.ORANGE, + card = card + }, true + end + end +} + +local hunter = { 7, 5, 3, 2, 1 } + +SMODS.Joker { + key = "hunter", + atlas = "janehunter", + loc_txt = { + name = "The Hunter", + text = { + "{C:blue}Provides infinite hands", + "{C:red,s,E:1}Succumbs to the Rot {}and creates", + (Cryptid and "an {C:spectral}Empowered Tag" or "a {C:dark_edition}Negative {C:spectral}Soul") .. " {}after #1#", + "When {C:attention}sold#2#{}, turns#3#", + "#4#{C:red}The Rot{} without rewards", + } + }, + config = {rounds_left = hunter[1]}, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 20, + rarity = 4, + loc_vars = function(_, _, center) + local function rounds(amount) + return " round" .. ((math.abs(amount) > 1 or math.abs(amount) == 0) and "s" or "") + end + + local rounds_left = center.ability.rounds_left + local sold = rounds_left - hunter[2] + + return {vars = { + rounds_left .. rounds(rounds_left) .. (rounds_left <= 0 and "...?" or ""), + sold <= 0 and "" or " after " .. sold .. rounds(sold), + sold <= 0 and " into" or "", + sold <= 0 and "" or "into ", + }} + end, + update = function(_, card, _) + if card.added_to_deck and card.children.center and card.children.floating_sprite then + for k, v in ipairs(hunter) do + if card.ability.rounds_left <= v then + card.children.center:set_sprite_pos({x = 0, y = k - 1}) + card.children.floating_sprite:set_sprite_pos({x = 1, y = k - 1}) + else + break + end + end + end + end, + calculate = function(_, card, context) + local function spawn_rot() + card:flip() + card:juice_up(2, 0.8) + Jane.card_status_text(card, "Dead!", nil, 0.05 * card.T.h, G.C.BLACK, 2, 0, 0, nil, "bm", "jane_gore6") + + Jane.q(function() + local card2 = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_jane_rot", "hunter_rot_death") + card2:add_to_deck() + G.jokers:emplace(card2) + card:set_eternal(nil) + card2:set_eternal(true) + play_sound("jane_gore5") + return true + end) + end + + local function die() + spawn_rot() + + Jane.q(function() + Jane.empowered() + return true + end, 0.1) + + Jane.q(function() + card:start_dissolve() + return true + end, 1) + + return true + end + + if context.blueprint then + return + end + + if context.selling_self and card.ability.rounds_left <= hunter[2] then + spawn_rot() + elseif not context.individual and not context.repetition and not context.retrigger_joker then + if G.GAME.round_resets.hands <= 0 then + G.GAME.round_resets.hands = 1 + end + + if not card.hunter_prep then + card.hunter_prep = true + Jane.q(function() + Jane.q(function() + card.hunter_prep = nil + if G.GAME.current_round.hands_left < G.GAME.round_resets.hands then + card.ability.hands_replenished = + (card.ability.hands_replenished or 0) + + (G.GAME.round_resets.hands - G.GAME.current_round.hands_left) + + ease_hands_played(G.GAME.round_resets.hands - G.GAME.current_round.hands_left) + end + + return true + end) + + return true + end) + end + + if not context.end_of_round then + return + end + + card.hunter_prep = nil + card.ability.rounds_left = card.ability.rounds_left - 1 + local rl = card.ability.rounds_left + Jane.card_status_text(card, tostring(card.ability.rounds_left), nil, nil, G.C.RED, nil, nil, nil, nil, nil, "generic1") + + if rl > hunter[2] then + card:juice_up(0.6, 0.1) + elseif rl > hunter[3] then + if rl == hunter[2] then + Jane.play_sound("jane_gore1") + end + + card:juice_up(0.6, 0.1) + elseif rl > hunter[4] then + if rl == hunter[3] then + Jane.play_sound("jane_gore3") + end + + card:juice_up(0.6, 0.1) + elseif rl > hunter[5] then + if rl == hunter[4] then + Jane.play_sound("jane_gore8") + end + + card:juice_up(0.6, 0.1) + Jane.play_sound("jane_warning_heartbeat") + elseif rl > 0 then + if rl == hunter[5] then + Jane.play_sound("jane_gore4") + end + + card:juice_up(1.8, 0.3) + Jane.play_sound("jane_warning_heartbeat") + else + card:juice_up(2, 0.8) + Jane.play_sound("jane_warning_heartbeat") + G.E_MANAGER:add_event(Event({trigger = "after", func = die})) + end + end + end +} + +SMODS.Joker { + key = "gourmand", + atlas = "janegourmand", + loc_txt = { + name = "The Gourmand", + text = { + "Values on {C:attention}consumables", + "are {C:attention}multiplied{} by {C:attention}#1#", + "when they are created", + "{C:inactive}(If possible)", + } + }, + loc_vars = function(_, _, center) + return {vars = {center.ability.modifier}} + end, + config = {modifier = 2}, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 50, + rarity = 4, +} + +local orig_set_ability = Card.set_ability + +---@diagnostic disable-next-line: duplicate-set-field +function Card:set_ability(center, initial, delay_sprites) + orig_set_ability(self, center, initial, delay_sprites) + + if next(SMODS.find_card("j_jane_gourmand")) and + self.gc and + self:gc().key ~= "c_base" and + string.sub(self:gc().key, 1, 2) == "c_" then + local mod = 1 + + for _, v in pairs(SMODS.find_card("j_jane_gourmand")) do + mod = mod * v.ability.modifier + end + + Jane.misprintize(self, {min = mod, max = mod}, nil, true) + end +end + +SMODS.Joker { + key = "rivulet", + atlas = "janerivulet", + loc_txt = { + name = "The Rivulet", + text = { + "Non-{C:dark_edition}editioned{} cards are", + "{C:attention}given a random {C:dark_edition}Edition", + } + }, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 20, + rarity = 4, +} + +local orig_draw = Card.draw + +function Card:draw(layer) + local cen = self.gc and self:gc() + + if self.children.floating_sprite and cen.sinis then + if Jane.sinister and not self.shows_sinister then + self.shows_sinister = true + self.children.floating_sprite:set_sprite_pos(cen.sinis) + elseif not Jane.sinister and self.shows_sinister then + self.shows_sinister = nil + self.children.floating_sprite:set_sprite_pos(cen.soul_pos) + end + + if self.shows_sinister then + self:juice_up(0, math.random()) + end + end + + if cen and + self.facing == "front" and + self.config and + (self.added_to_deck or + (self.area and self.area == G.hand)) and not + self.edition and + (self.area == G.consumeables or cen.set ~= "Booster") and + next(SMODS.find_card("j_jane_rivulet")) then + self:set_edition({[G.P_CENTER_POOLS.Edition[pseudorandom("rivulet_edition", 1, #G.P_CENTER_POOLS.Edition)].key:sub(3)] = true}, true) + end + + orig_draw(self, layer) +end + +local attunement = Cryptid and 1.001 or 1.1 + +SMODS.Joker { + key = "saint", + atlas = "janesaint", + loc_txt = { + name = "The Saint{C:jane_RGB}#1#", + text = { + "{C:spectral}Gateway {}will {C:attention}not destroy Jokers", + "{C:jane_RGB}#2#{}#3#{X:black,C:jane_RGB,s:1.5}#4#{C:spectral}#5#{C:chips}#6#{}#7#{C:mult}#8#", + "{C:inactive,s:1.25}#9#{C:attention,s:1.25}#10#{C:inactive,s:1.25}#11#{C:inactive}#12#" + } + }, + config = {extra = {karma = 0, max_karma = Cryptid and 10 or 3}}, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 20, + rarity = 4, + blueprint_compat = true, + loc_vars = function(_, _, card) + local extra = card.ability.extra + local karma = extra.karma + local max_karma = extra.max_karma + local attuned = karma >= max_karma + + return {vars = { + attuned and " (Attuned)" or "", + attuned and "" or "Attune ", + attuned and "" or "after using ", + attuned and (Cryptid and "^^" or "^") .. attunement or max_karma, + attuned and "" or (Cryptid and " Gateways" or " Souls"), + attuned and " Chips " or "", + attuned and "& " or "", + attuned and "Mult" or "", + attuned and "" or "[", + attuned and "" or karma, + attuned and "" or " / " .. max_karma .. "]", + attuned and "(Cannot be debuffed)" or "", + }} + end, + update = function(_, card, _) + if card.added_to_deck and card.children.center and card.children.floating_sprite then + local extra = card.ability.extra + local karma = extra.karma + local max_karma = extra.max_karma + local is_attuned = karma >= max_karma + card.children.floating_sprite:set_sprite_pos({x = is_attuned and 2 or 1, y = 0}) + end + end, + calculate = function(_, card, context) + local extra = card.ability.extra + local max_karma = extra.max_karma + + if extra.karma >= max_karma then + if card.ability then + card.ability.perishable = false + card.ability.perish_tally = 1e9 + end + + card.debuff = false + + if not context.joker_main then + return + end + + return { + card = card, + colour = G.C.jane_RGB, + sound = "talisman_eeechip", + message = "^^" .. attunement .. " Chips & Mult", + [Cryptid and "EEchip_mod" or "Echip_mod"] = attunement, + [Cryptid and "EEmult_mod" or "Emult_mod"] = attunement, + }, true + end + + if not (not context.blueprint and + (not context.retrigger_joker_check and not context.retrigger_joker) and + context.using_consumeable and + context.consumeable and + context.consumeable:gc().key == Cryptid and "c_cry_gateway" or "c_soul") then + return + end + + local quota = context.consumeable:getEvalQty() + extra.karma = extra.karma + quota + + card_eval_status_text( + card, + "extra", + nil, + nil, + nil, + {message = "+" .. quota .. " Karma", colour = G.C.PALE_GREEN} + ) + + card_eval_status_text( + card, + "extra", + nil, + nil, + nil, + {message = extra.karma .. " / " .. max_karma, colour = G.C.GREEN} + ) + + if extra.karma < max_karma then + return + end + + Jane.card_status_text( + card, + "!!!", + nil, + 0.05 * card.T.h, + G.C.DARK_EDITION, + 0.6, + 0.6, + 2, + 2, + "bm", + "jane_enlightened" + ) + + G.E_MANAGER:add_event(Event({ + delay = 0.1, + func = function() + card:flip() + play_sound("card1") + return true + end + })) + + G.E_MANAGER:add_event(Event({ + delay = 1, + func = function() + card:flip() + card:juice_up(1, 1) + play_sound("card1") + return true + end + })) + end +} + +SMODS.Joker { + key = "artificer", + atlas = "janeartificer", + loc_txt = { + name = "The Artificer", + text = { + "Grants the {C:green}ability{} to {C:red}destroy", + "selected {C:attention}playing cards", + } + }, + misc = { + text = {"Impervious", "Cannot be debuffed"}, + col = G.C.JOKER_GREY, + tcol = G.C.FILTER + }, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 50, + rarity = exotic, + Bakery_use_button_text = function(_, _) return "DESTROY" end, + Bakery_can_use = function(_, _) + return Jane.canuse() and next(G.hand.highlighted) + end, + Bakery_use_joker = function(_, _) + for _, v in pairs(G.hand.highlighted) do + v:start_dissolve() + end + end, +} + +SMODS.Joker { + key = "rot", + atlas = "janerot", + loc_txt = { + name = "The Rot", + text = { + "Clogs up your Joker slots", + "{C:attention}Duplicates itself{} at the", + "end of {C:attention}every ante", + } + }, + pos = {x = 0, y = 0}, + soul_pos = {x = 1, y = 0}, + cost = 0, + rarity = "jane_junk", + in_pool = function (_, _) + return not not next(SMODS.find_card("j_jane_rot")) + end, + calculate = function(_, card, context) + local function has_room() + return G.jokers.config.card_count < G.jokers.config.card_limit + end + + local function is_end_of_ante() + return not context.individual and not + context.repetition and not + card.debuff and + context.end_of_round and not + context.blueprint and + G.GAME.blind.boss and not + (G.GAME.blind.config and G.GAME.blind.config.bonus) + end + + local function spawn() + local text = context.selling_self and "..!" or "..." + local rot = copy_card(card) + rot.cloned = true + rot:add_to_deck() + G.jokers:emplace(rot) + Jane.card_status_text(rot, text, nil, 0.05 * card.T.h, G.C.BLACK, 3, 0, 0, nil, "bm") + end + + if has_room() and not card.cloned and is_end_of_ante() then + spawn() + else + card.cloned = false + end + end +} diff --git a/src/spectral.lua b/src/spectral.lua new file mode 100644 index 0000000..8d135ca --- /dev/null +++ b/src/spectral.lua @@ -0,0 +1,354 @@ +SMODS.Atlas { + key = "janertarots", + px = 71, + py = 95, + path = Jane.config.texture_pack .. "/c_jane_reversetarots.png" +} + +SMODS.Sound({key = "draw", path = "draw.ogg"}) + +local function conjure(card, number) + for _ = 1, math.min( + math.ceil(card.ability.extra.spectrals) * number, + G.consumeables.config.card_limit - #G.consumeables.cards + ) do + G.E_MANAGER:add_event(Event({ + trigger = "after", + delay = 0.4, + func = function() + if G.consumeables.config.card_limit <= #G.consumeables.cards then + return true + end + + play_sound("jane_draw") + local spectral = create_card("Spectral", G.consumeables, nil, nil, nil, nil, nil, "pri") + spectral:add_to_deck() + G.consumeables:emplace(spectral) + card:juice_up(0.3, 0.5) + return true + end + })) + end +end + +local function createfulldeck(enhancement, edition, amount, emplacement) + local cards = {} + + for _, v in pairs(G.P_CARDS) do + for i = 1, (amount or 1) do + G.E_MANAGER:add_event(Event({ + delay = 0.1, + func = function() + cards[i] = true + G.playing_card = (G.playing_card and G.playing_card + 1) or 1 + + local card = Card( + G.play.T.x + G.play.T.w / 2, + G.play.T.y, G.CARD_W, G.CARD_H, + v, + enhancement or G.P_CENTERS.c_base, + {playing_card = G.playing_card} + ) + + if edition then + card:set_edition(type(edition) == "table" and edition or {[edition] = true}, true, true) + end + + play_sound("card1") + table.insert(G.playing_cards, card) + card:add_to_deck() + + if emplacement then + emplacement:emplace(card) + else + G.deck:emplace(card) + end + + return true + end + })) + end + end + + Jane.q(function() + if next(cards) then + playing_card_joker_effects(cards) + end + + return true + end) + + Jane.q(function() + cards = nil + return true + end) +end + +local function randomize(targets, noanim) + if #targets <= 0 then + return + end + + if noanim then + for i=1, #targets do + local card = targets[i] + card:set_base(pseudorandom_element(G.P_CARDS)) + + card:set_ability( + pseudorandom(pseudoseed("chancetime")) > 1 / (#G.P_CENTER_POOLS["Enhanced"] + 1) and + pseudorandom_element(G.P_CENTER_POOLS["Enhanced"], pseudoseed("spectral_chance")) or + G.P_CENTERS["c_base"] + ) + + local edition_rate = 2 + card:set_edition(poll_edition("standard_edition" .. G.GAME.round_resets.ante, edition_rate, true), true, true) + local seal_rate = 10 + local seal_poll = pseudorandom(pseudoseed("stdseal" .. G.GAME.round_resets.ante)) + + if seal_poll > 1 - 0.02 * seal_rate then + local seal_type = pseudorandom(pseudoseed("stdsealtype" .. G.GAME.round_resets.ante)) + local seal_list = {} + + for k, _ in pairs(G.P_SEALS) do + table.insert(seal_list, k) + end + + seal_type = math.floor(seal_type * #seal_list) + card:set_seal(seal_list[seal_type], true, true) + else + card:set_seal(nil, true, true) + end + + card:juice_up(0.3, 0.3) + end + else + for i = 1, #targets do + local percent = 1.15 - (i - 0.999) / (#G.hand.cards - 0.998) * 0.3 + + G.E_MANAGER:add_event(Event({ + trigger = "after", + delay = 0.15, + func = function() + targets[i]:flip() + play_sound("card1", percent) + targets[i]:juice_up(0.3, 0.3) + return true + end + })) + end + + delay(0.2) + + for i = 1, #targets do + local percent = 0.85 + (i - 0.999) / (#G.hand.cards - 0.998) * 0.3 + + G.E_MANAGER:add_event(Event({ + trigger = "after", + delay = 0.1, + func = function() + local card = targets[i] + card:set_base(pseudorandom_element(G.P_CARDS)) + card:set_ability(pseudorandom_element(G.P_CENTER_POOLS["Enhanced"])) + + local edition_rate = 2 + card:set_edition(poll_edition("standard_edition" .. G.GAME.round_resets.ante, edition_rate, true)) + local seal_rate = 10 + local seal_poll = pseudorandom(pseudoseed("stdseal" .. G.GAME.round_resets.ante)) + + if seal_poll > 1 - 0.02 * seal_rate then + local seal_type = pseudorandom(pseudoseed("stdsealtype" .. G.GAME.round_resets.ante)) + local seal_list = {} + + for k, _ in pairs(G.P_SEALS) do + table.insert(seal_list, k) + end + + seal_type = math.floor(seal_type * #seal_list) + card:set_seal(seal_list[seal_type]) + else + card:set_seal() + end + + card:flip() + play_sound("card3", percent, 0.6) + card:juice_up(0.3, 0.3) + return true + end + })) + end + end +end + +SMODS.Consumable { + key = "obfuscation", + atlas = "janeacc", + set = "Spectral", + loc_txt = { + name = "Obfuscation", + text = { + "{C:green,E:1}Randomises{} all cards in hand", + "{C:inactive}(Rank, seal, edition,", + "{C:inactive}enhancement, and suit)", + } + }, + pos = {x = 0, y = 4}, + cost = 4, + can_use = function(_, _) + return Jane.canuse() and #((G.hand or {}).cards or {}) > 0 + end, + use = function(_, card, _, _) + G.E_MANAGER:add_event(Event({ + trigger = "after", + delay = 0.4, + func = function() + play_sound("tarot1") + card:juice_up(0.3, 0.5) + return true + end + })) + + randomize(G.hand.cards) + delay(0.5) + end +} + +SMODS.Consumable { + key = "conjure", + set = "Spectral", + atlas = "janeacc", + loc_txt = { + name = "Conjure", + text = { + "Creates {C:attention}#1#", + "{C:spectral}Spectral{} cards", + "{C:inactive}(Must have room)", + } + }, + config = {extra = {spectrals = 2}}, + pos = {x = 2, y = 4}, + cost = 4, + loc_vars = function(self, info_queue, center) + return {vars = {math.ceil(center.ability.extra.spectrals)}} + end, + can_use = Jane.canuse, + use = function(_, card, _, _) + conjure(card, 1) + delay(0.6) + end, + bulk_use = function(_, card, _, _, number) + conjure(card, number) + delay(0.6) + end +} + +SMODS.Consumable { + key = "shadows", + set = "Spectral", + atlas = "janeacc", + loc_txt = { + name = "Shadows", + text = { + "Create {C:attention}#1#{} {C:green}random {C:dark_edition}Negative", + "{C:attention}Perishable {C:attention}Jokers{}, set", + "{C:money}sell value{} of {C:attention}all Jokers{} to {C:money}$0", + } + }, + config = {extra = {shadows = 2}}, + pos = {x = 3, y = 4}, + cost = 4, + loc_vars = function(_, _, center) + return {vars = {((center.ability or {}).extra or {}).shadows or 2}} + end, + can_use = Jane.canuse, + use = function(_, card, _, _) + for _ = 1, card.ability.extra.shadows do + local joker = create_card("Joker", G.jokers, nil, nil, nil, nil, nil, "phantom") + joker:set_edition({negative = true}) + joker.ability.eternal = false + joker.ability.perishable = true + joker.ability.perish_tally = 5 + joker:add_to_deck() + G.jokers:emplace(joker) + end + + delay(0.6) + + for i = 1, #G.jokers.cards do + G.jokers.cards[i].base_cost = 0 + G.jokers.cards[i].extra_cost = 0 + G.jokers.cards[i].cost = 0 + G.jokers.cards[i].sell_cost = 0 + G.jokers.cards[i].sell_cost_label = G.jokers.cards[i].facing == "back" and "?" or G.jokers.cards[i].sell_cost + end + end, + bulk_use = function(_, card, _, _, number) + for _ = 1, card.ability.extra.shadows * number do + local joker = create_card("Joker", G.jokers, nil, nil, nil, nil, nil, "phantom") + joker.no_forced_edition = true + joker:set_edition({negative = true}) + joker.no_forced_edition = nil + joker.ability.eternal = false + joker.ability.perishable = true + joker.ability.perish_tally = 5 + joker:add_to_deck() + G.jokers:emplace(joker) + end + + delay(0.6) + + for i = 1, #G.jokers.cards do + G.jokers.cards[i].base_cost = 0 + G.jokers.cards[i].extra_cost = 0 + G.jokers.cards[i].cost = 0 + G.jokers.cards[i].sell_cost = 0 + G.jokers.cards[i].sell_cost_label = G.jokers.cards[i].facing == "back" and "?" or G.jokers.cards[i].sell_cost + end + end +} + + +SMODS.Consumable { + key = "reverse_hanged_man", + atlas = "janertarots", + set = "Spectral", + loc_txt = { + name = "Zen", + text = { + "{C:attention}Reset{} your deck to", + "a {C:attention}standard 52-card deck" + } + }, + config = {extra = {destruction = 0.5}}, + pos = {x = 7, y = 1}, + cost = 15, + loc_vars = function(_, _, center) + return {vars = { + math.min(100, center.ability.extra.destruction * 100), + math.ceil(#(G.playing_cards or {}) * center.ability.extra.destruction) + }} + end, + can_use = Jane.canuse, + use = function(_, _, _, _) + Jane.q(function() + for _, v in pairs(G.playing_cards) do + v:start_dissolve() + end + + return true + end) + + local function realdelay(time, queue) + G.E_MANAGER:add_event(Event({ + trigger = "after", + timer = "REAL", + delay = time or 1, + func = function() + return true + end + }), queue) + end + + realdelay(1) + createfulldeck() + end +} diff --git a/src/tarot.lua b/src/tarot.lua new file mode 100644 index 0000000..f530b8b --- /dev/null +++ b/src/tarot.lua @@ -0,0 +1,63 @@ +local blurbs = { + "Hey! Pick me!", + "You wouldn't say no to a free negative me, would you?", + "Sometimes, an extra four mult goes a long way!", + "I won't take up space, I promise!", + "Don't ask how I ended up in a tarot!", + "Hee-hee, hoo-hoo!", + "Who knew even fortunes could be a circus act?", + "Looks like the joke is on the crystal globe!", + "It's a little cramped in this tarot...!", + "Ouch, I think the joke is on me!", + "Looks like the joke is on you!", + "I'm not just a clown; I'm the whole circus!", + "Seems a little suspicious for a jolly old fella like me to be in this card...", + "I can't help if I'm still in this silly old card, break me out!", + "Let me tell you, you'd love the show going on in this tarot!", + "I'd give you more tickets to JimCon, but I'm fresh out.", + "I've heard of a round buffoon that lives in a pretty funky town...", + "I can't give four mult if I'm still in this card!", + "I'm rooting for you! Even if it means I'll never get out of this card...", + "Who knew I'd have access to a great show? That show being you!", + "The stakes are only gonna rise here!", + "Juggling is one of my favourite passtimes!", + "I wonder what's the deal with pairs?", + "You don't need to understand math to enjoy watching the digits climb!", + "You should meet my friend Joseph; he's stuck in a Planet card!", + "M!", +} + +SMODS.Consumable { + key = "jokerinatarot", + atlas = "janeacc", + set = "Tarot", + loc_txt = { + name = "Joker-in-a-Tarot", + text = { + "Create a {C:dark_edition}Negative {C:attention}default Joker", + "{C:inactive,E:1}#1#{}" + } + }, + loc_vars = function(_, _, _) + return {vars = {blurbs[math.random(#blurbs)]}} + end, + pos = {x = 0, y = 1}, + cost = 3, + can_use = Jane.canuse, + use = function(_, _, _, _) + local card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_joker", "jokerfromatarot") + card:set_edition({negative = true}, true) + card.cost = 1 + card.base_cost = 1 + card.sell_cost = 1 + card.extra_cost = 0 + card.sell_cost_label = card.facing == "back" and "?" or card.sell_cost + card:add_to_deck() + G.jokers:emplace(card) + end, + bulk_use = function(self, card, area, copier, number) + for _ = 1, number do + self:use(card, area, copier) + end + end +} diff --git a/src/token.lua b/src/token.lua new file mode 100644 index 0000000..9337535 --- /dev/null +++ b/src/token.lua @@ -0,0 +1,86 @@ +SMODS.Atlas { + key = "janetokens", + px = 71, + py = 95, + path = Jane.config.texture_pack .. "/c_jane_tokens.png" +} + +SMODS.Sound({key = "e_gilded", path = "e_gilded.ogg"}) + +SMODS.ConsumableType { + key = "jane_tokens", + default = "c_jane_token_tag_standard", + loc_txt = { + collection = "Tokens", + name = "Token" + }, + shop_rate = 0, + collection_rows = {6, 6}, + primary_colour = G.C.CHIPS, + secondary_colour = G.C.VOUCHER, +} + +for _, v in pairs({ + {"tag_standard", "Standard", 0, 0, 3}, + {"tag_charm", "Charm", 1, 0, 5}, + {"tag_meteor", "Meteor", 2, 0, 5}, + {"tag_ethereal", "Ethereal", 3, 0, 5}, + {"tag_buffoon", "Buffoon", 4, 0, 8}, + {"tag_cry_bundle", "Bundle", 1, 1, 10}, + {"tag_uncommon", "Uncommon", 2, 1, 3}, + {"tag_rare", "Rare", 3, 1, 5}, + {"tag_cry_epic", "Epic", 4, 1, 8}, + {"tag_foil", "Foil", 1, 3, 3}, + {"tag_holo", "Holographic", 2, 3, 4}, + {"tag_polychrome", "Polychrome", 3, 3, 5}, + {"tag_negative", "Negative", 4, 3, 10}, + {"tag_investment", "Investment", 0, 3, 8}, + {"tag_voucher", "Voucher", 4, 5, 5}, + {"tag_handy", "Handy", 1, 5, 8}, + {"tag_garbage", "Garbage", 0, 5, 6}, + {"tag_coupon", "Coupon", 4, 4, 10}, + {"tag_juggle", "Juggle", 2, 5, 2}, + {"tag_d_six", "Dice", 0, 4, 2}, + {"tag_top_up", "Top-up", 2, 4, 2}, + {"tag_skip", "Speed", 4, 2, 7}, + {"tag_economy", "Economy", 5, 2, 10}, + {"tag_double", "Double", 0, 2, 6}, + {"tag_cry_triple", "Triple", 1, 2, 8}, + {"tag_cry_quadruple", "Quadruple", 2, 2, 10}, + {"tag_cry_quintuple", "Quintuple", 3, 2, 13}, + {"tag_cry_memory", "Memory", 5, 4, 8} +}) do + if Cryptid or v[1]:sub(1, 7) ~= "tag_cry" then + SMODS.Consumable { + key = "token_" .. v[1], + set = "jane_tokens", + atlas = "janetokens", + loc_txt = { + name = v[2] .. " Token", + text = { + "Use to create a", + "{C:attention}" .. v[2] .. " Tag", + }, + }, + pos = {x = v[3], y = v[4]}, + cost = v[5], + can_stack = true, + can_divide = true, + can_use = Jane.canuse, + in_pool = function (_, _) + return G.GAME.used_vouchers.v_jane_token_voucher + end, + use = function(_, _, _, _) + play_sound("jane_e_gilded", 1.25, 0.4) + add_tag(Tag(v[1])) + end, + bulk_use = function(_, _, _, _, number) + play_sound("jane_e_gilded", 1.25, 0.4) + + for _ = 1, number do + add_tag(Tag(v[1])) + end + end + } + end +end diff --git a/src/voucher.lua b/src/voucher.lua new file mode 100644 index 0000000..f0c8a06 --- /dev/null +++ b/src/voucher.lua @@ -0,0 +1,23 @@ +SMODS.Atlas { + key = "janetokenvoucher", + px = 71, + py = 95, + path = Jane.config.texture_pack .. "/v_jane_token_voucher.png" +} + +SMODS.Voucher { + key = "token_voucher", + atlas = "janetokenvoucher", + loc_txt = { + name = "Token Voucher", + text = { + "{C:attention}Tokens {}can appear", + "in the shop", + } + }, + pos = {x = 0, y = 0}, + cost = 15, + redeem = function (_, _) + G.GAME['jane_tokens_rate'] = 1.5 + end +}