From 8315d6a42c73a4409ad45a6d00a9f32fd0837720 Mon Sep 17 00:00:00 2001 From: Elliptical <70788102+cellos51@users.noreply.github.com> Date: Sat, 2 Aug 2025 10:29:26 -0400 Subject: [PATCH 01/45] Switching to a boss blind now changes the background palette --- source/game.c | 8 ++++++++ source/main.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/source/game.c b/source/game.c index 6f3d8de..939382f 100644 --- a/source/game.c +++ b/source/game.c @@ -18,6 +18,7 @@ #include "background_gfx.h" #include "background_shop_gfx.h" #include "background_blind_select_gfx.h" +#include "affine_background_gfx.h" #include "soundbank.h" @@ -419,6 +420,13 @@ void change_background(int id) else if (current_blind == BOSS_BLIND) { main_bg_se_copy_rect(BOSS_BLIND_TITLE_SRC_RECT, TOP_LEFT_BLIND_TITLE_POINT); + u16 palette[5] = {}; + palette[0] = blind_get_color(current_blind, BLIND_BACKGROUND_SECONDARY_COLOR_INDEX); + palette[1] = blind_get_color(current_blind, BLIND_SHADOW_COLOR_INDEX); + palette[2] = blind_get_color(current_blind, BLIND_BACKGROUND_SHADOW_COLOR_INDEX); + palette[3] = blind_get_color(current_blind, BLIND_MAIN_COLOR_INDEX); + palette[4] = blind_get_color(current_blind, BLIND_TEXT_COLOR_INDEX); + memcpy16(&pal_bg_mem[16 * 15], palette, 5); } bg_copy_current_item_to_top_left_panel(); diff --git a/source/main.c b/source/main.c index bd7b046..2cb29fc 100644 --- a/source/main.c +++ b/source/main.c @@ -33,7 +33,7 @@ void init_map() // Temp function derived from libtonc example // Actually for future reference, each number seems to equate to an XY on the palette, so 0xF0F0F0F0 would just push everything down 15 colors, since the second number isn't set. } - memcpy(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen); + memcpy16(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen); GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); memcpy16(&pal_bg_mem[16 * 15], affine_background_gfxPal, 5); From 0f3d1b3b779cece513126dbb542abf055a951865 Mon Sep 17 00:00:00 2001 From: theturtlemafia Date: Fri, 1 Aug 2025 18:22:20 -0400 Subject: [PATCH 02/45] adds walkie-talkie, fibonnaci, banner, mystic summit, blackboard --- include/game.h | 2 ++ source/game.c | 29 ++++++++++++++++ source/joker_effects.c | 77 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/include/game.h b/include/game.h index 6fdaec1..02c3b01 100644 --- a/include/game.h +++ b/include/game.h @@ -82,4 +82,6 @@ int get_played_top(void); JokerObject** get_jokers(void); int get_jokers_top(void); +int get_num_discards_remaining(void); + #endif // GAME_H \ No newline at end of file diff --git a/source/game.c b/source/game.c index 9e5c7b6..5e4ffe1 100644 --- a/source/game.c +++ b/source/game.c @@ -239,6 +239,35 @@ static const Rect SHOP_REROLL_RECT = {88, 96, UNDEFINED, UNDEFI #define PITCH_STEP_UNDISCARD_SFX 2*PITCH_STEP_DRAW_SFX // Naming the stage where cards return from the discard pile to the deck "undiscard" +// get-functions, for other files to view game state (mainly for jokers) +CardObject **get_hand_array(void) { + return hand; +} + +int get_hand_top(void) { + return hand_top; +} + +CardObject **get_played_array(void) { + return played; +} + +int get_played_top(void) { + return played_top; +} + +JokerObject **get_jokers(void) { + return jokers; +} + +int get_jokers_top(void) { + return jokers_top; +} + +int get_num_discards_remaining(void) { + return discards; +} + // General functions void set_seed(int seed) { diff --git a/source/joker_effects.c b/source/joker_effects.c index 5e934ee..7a2eaf3 100644 --- a/source/joker_effects.c +++ b/source/joker_effects.c @@ -215,6 +215,78 @@ static JokerEffect misprint_joker_effect(Joker *joker, Card *scored_card) { return effect; } +static JokerEffect walkie_talkie_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + if (scored_card->rank == TEN || scored_card->rank == FOUR) { + effect.chips = 10; + effect.mult = 4; + } + + return effect; +} + +static JokerEffect fibonnaci_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card == NULL) + return effect; + + switch (scored_card->rank) { + case ACE: case TWO: case THREE: case FIVE: case EIGHT: + effect.mult = 8; + default: + break; + } + + return effect; +} + +static JokerEffect banner_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + effect.chips = 30 * get_num_discards_remaining(); + + return effect; +} + +static JokerEffect mystic_summit_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + if (get_num_discards_remaining() == 0) + effect.mult = 15; + + return effect; +} + +static JokerEffect blackboard_joker_effect(Joker *joker, Card *scored_card) { + JokerEffect effect = {0}; + if (scored_card != NULL) + return effect; // if card != null, we are not at the end-phase of scoring yet + + bool all_cards_are_spades_or_clubs = true; + CardObject** hand = get_hand_array(); + int hand_top = get_hand_top(); + for (int i = 0; i < hand_top; i++ ) + { + u8 suit = hand[i]->card->suit; + if (suit == HEARTS || suit == DIAMONDS) { + all_cards_are_spades_or_clubs = false; + break; + } + } + + if (all_cards_are_spades_or_clubs) + effect.xmult = 3; + + return effect; +} + const JokerInfo joker_registry[] = { { COMMON_JOKER, 2, default_joker_effect }, // DEFAULT_JOKER_ID = 0 { COMMON_JOKER, 5, greedy_joker_effect }, // GREEDY_JOKER_ID = 1 @@ -234,6 +306,11 @@ const JokerInfo joker_registry[] = { { COMMON_JOKER, 5, half_joker_effect }, { UNCOMMON_JOKER, 8, joker_stencil_effect }, { COMMON_JOKER, 4, misprint_joker_effect }, + { COMMON_JOKER, 4, walkie_talkie_joker_effect }, + { UNCOMMON_JOKER, 8, fibonnaci_joker_effect }, + { COMMON_JOKER, 5, banner_joker_effect }, + { COMMON_JOKER, 5, mystic_summit_joker_effect }, + { UNCOMMON_JOKER, 6, blackboard_joker_effect }, }; static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry); From dcff3267302935718a760ee334c3582467e9fd0d Mon Sep 17 00:00:00 2001 From: Elliptical <70788102+cellos51@users.noreply.github.com> Date: Sat, 2 Aug 2025 14:54:08 -0400 Subject: [PATCH 03/45] Refactor to make it just change the brightness of a chosen color. I will make a seperate .h/.c file for the affine background when I get home. --- source/game.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/source/game.c b/source/game.c index 939382f..68720f3 100644 --- a/source/game.c +++ b/source/game.c @@ -420,13 +420,23 @@ void change_background(int id) else if (current_blind == BOSS_BLIND) { main_bg_se_copy_rect(BOSS_BLIND_TITLE_SRC_RECT, TOP_LEFT_BLIND_TITLE_POINT); - u16 palette[5] = {}; - palette[0] = blind_get_color(current_blind, BLIND_BACKGROUND_SECONDARY_COLOR_INDEX); - palette[1] = blind_get_color(current_blind, BLIND_SHADOW_COLOR_INDEX); - palette[2] = blind_get_color(current_blind, BLIND_BACKGROUND_SHADOW_COLOR_INDEX); - palette[3] = blind_get_color(current_blind, BLIND_MAIN_COLOR_INDEX); - palette[4] = blind_get_color(current_blind, BLIND_TEXT_COLOR_INDEX); - memcpy16(&pal_bg_mem[16 * 15], palette, 5); + + const int palette_length = 5; + memcpy16(&pal_bg_mem[16 * 15], affine_background_gfxPal, palette_length); + for (int i = 0; i < palette_length; i++) + { + COLOR old_color = 0; + memcpy16(&old_color, &pal_bg_mem[16 * 15] + i, 1); // Copy the color from the background palette + + int r, g, b; + r = (old_color >> 10) & 0b11111; // Extract red component + g = (old_color >> 5) & 0b11111; // Extract green component + b = old_color & 0b11111; // Extract blue component + + COLOR new_color = blind_get_color(BOSS_BLIND, BLIND_MAIN_COLOR_INDEX); + int brightness = (r + g + b) / 3; // Calculate brightness + clr_adj_brightness(&pal_bg_mem[16 * 15] + i, &new_color, 1, float2fx(-0.6f + (brightness * 0.05f))); // Adjust brightness for the palette colors + } } bg_copy_current_item_to_top_left_panel(); From 607a17542627ff33213b589753207ed71c784420 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Mon, 4 Aug 2025 18:56:38 +0300 Subject: [PATCH 04/45] Update README.md Reworded the readme and added links to the official version of Balatro on all platforms --- README.md | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0270f47..1e8f868 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,26 @@ # Balatro GBA This is an attempt to recreate the game 'Balatro' as accurately as possible, including all of the visual effects that make Balatro feel satisfying to play. -This port is strictly limited to the content that was available in the January 2024 Balatro Steam demo. -### **Disclaimer: This project is NOT endorsed or supported by Playstack or LocalThunk** -#### This project is solely aimed to recreate Balatro's old demo on the Game Boy Advance and is not meant to infringe or draw sales away from the full game's release or any of the established works by Playstack and LocalThunk. All rights are reserved to their respective holders. +This port is strictly limited in content to a minimal version of Balatro and will not recreate the full game. +### **Disclaimer: This project is NOT endorsed by or affiliated with Playstack or LocalThunk** +#### This is a non-profit community fan project solely aimed to recreate a minimal version of Balatro on the Game Boy Advance as a tribute to the full Balatro and is not meant to infringe or draw sales away from the full game's release or any of the established works by Playstack and LocalThunk. +#### All rights are reserved to their respective holders. +This version is meant for people who already own and know the official full game. + +Buy the official full version + +[Balatro on Steam](https://store.steampowered.com/app/2379780/Balatro/) + +[Balatro on Google Play](https://play.google.com/store/apps/details?id=com.playstack.balatro.android) + +[Balatro on Apple App Store](https://apps.apple.com/us/app/balatro/id6502453075) + +[Balatro on Switch](https://www.nintendo.com/us/store/products/balatro-switch/) + +[Balatro on PlayStation Store](https://store.playstation.com/en-us/concept/10010334) + +[Balatro on Xbox](https://www.xbox.com/games/store/balatro/9PK087LNGJC5) + ![Example](https://github.com/cellos51/balatro-gba/blob/main/example.gif) # **Build Instructions:** @@ -22,7 +39,7 @@ Example: `cd '/home/user/OneDrive/Documents/balatro-gba` or something like this. 9. After it completes, navigate through the `build` directory in the project folder and look for `balatro-gba.gba` and load it on an emulator or flashcart. ## **-Linux-** -[Not Available] +[No Instructions Available] ### **Common Issues:** 1. **When I drag the folder into the window and press enter, it doesn't work!** @@ -36,5 +53,3 @@ Example: `cd '/home/user/OneDrive/Documents/balatro-gba` or something like this. 5. **It says I don't have `Git` or `Make` installed!** -Use `pacman -S git` or `pacman -S make` although it should already be installed if you followed the instructions correctly. -#### Purchasing the official game is highly recommended and almost mandatory in order for this project to have a chance of staying up due to copyright issues and potential legal action. -**Purchase the Steam Version here: https://store.steampowered.com/app/2379780/Balatro/** From 742114792d821d2903cfd086048c9b51258d35a0 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Mon, 4 Aug 2025 20:27:03 +0300 Subject: [PATCH 05/45] Fixed game starting at shop --- source/game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/game.c b/source/game.c index 03dad5a..6fbb685 100644 --- a/source/game.c +++ b/source/game.c @@ -29,7 +29,7 @@ static uint timer = 0; // This might already exist in libtonc but idk so i'm jus static int game_speed = 1; static int background = 0; -static enum GameState game_state = GAME_SHOP; // The current game state, this is used to determine what the game is doing at any given time +static enum GameState game_state = GAME_BLIND_SELECT; // The current game state, this is used to determine what the game is doing at any given time static enum HandState hand_state = HAND_DRAW; static enum PlayState play_state = PLAY_PLAYING; static int state = 0; // General state variable, used for switch statements in each game state related function From 592d7ae8bcfcf59bb73f19ab71e901ed75a236f4 Mon Sep 17 00:00:00 2001 From: cellos51 Date: Tue, 5 Aug 2025 14:35:52 -0400 Subject: [PATCH 06/45] Add affine background color functionality and integrate into game loop --- graphics/affine_background_gfx.png | Bin 2983 -> 2959 bytes include/affine_background.h | 16 ++++++++ source/affine_background.c | 63 +++++++++++++++++++++++++++++ source/game.c | 19 ++------- source/main.c | 45 ++------------------- 5 files changed, 85 insertions(+), 58 deletions(-) create mode 100644 include/affine_background.h create mode 100644 source/affine_background.c diff --git a/graphics/affine_background_gfx.png b/graphics/affine_background_gfx.png index 7a567dc88ab88fa6a85a61877c8a4ab43c2946fd..4abff4b34d35f12f2434af43a1683347f104c73b 100644 GIT binary patch literal 2959 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 DhT-E# diff --git a/include/affine_background.h b/include/affine_background.h new file mode 100644 index 0000000..31440c0 --- /dev/null +++ b/include/affine_background.h @@ -0,0 +1,16 @@ +#ifndef AFFINE_BACKGROUND_H +#define AFFINE_BACKGROUND_H + +#include + +#include "graphic_utils.h" + +#define AFFINE_BG_PAL_LEN 5 +#define AFFINE_BG_PB (PAL_ROW_LEN * 15) // This isn't really a palette bank, just the starting index of the palette +#define AFFINE_BG_DEFAULT_COLOR 0x3E4B + +void affine_background_init(); +void affine_background_update(); +void affine_background_set_color(COLOR color); + +#endif // AFFINE_BACKGROUND_H \ No newline at end of file diff --git a/source/affine_background.c b/source/affine_background.c new file mode 100644 index 0000000..6752be2 --- /dev/null +++ b/source/affine_background.c @@ -0,0 +1,63 @@ +#include "affine_background.h" +#include "affine_background_gfx.h" + +#include "graphic_utils.h" + +BG_AFFINE bgaff; +AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0}; + +void affine_background_init() +{ + unsigned int correctedTiles[affine_background_gfxTilesLen / 4]; + + for (int i = 0; i < affine_background_gfxTilesLen / 4; i++) + { + correctedTiles[i] = affine_background_gfxTiles[i] | 0xF0F0F0F0; + } + + memcpy16(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen/2); + GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); + memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN); + + bgaff = bg_aff_default; + + affine_background_set_color(AFFINE_BG_DEFAULT_COLOR); +} + +void affine_background_update() +{ + static uint timer = 0; + timer++; + + // These values are not permament, just the current configuration for the affine background + asx.tex_x += 5; + asx.tex_y += 12; + asx.sx = (lu_sin(timer * 100)) >> 8; // Scale the sine value to fit in a s16 + asx.sx += 256; // Add 256 to the sine value to make it positive + asx.sy = (lu_sin(timer * 100 + 0x4000)) >> 8; // Scale the sine value to fit in a s16 + asx.sy += 256; // Add 256 to the sine value to make it positive + bg_rotscale_ex(&bgaff, &asx); + REG_BG_AFFINE[2] = bgaff; +} + +void affine_background_set_color(COLOR color) +{ + memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN); + for (int i = 0; i < AFFINE_BG_PAL_LEN; i++) + { + COLOR old_color; + memcpy16(&old_color, &pal_bg_mem[AFFINE_BG_PB] + i, 1); // Copy the color from the background palette + + int r, g, b; + r = (old_color >> 10) & 0b11111; // Extract red component + g = (old_color >> 5) & 0b11111; // Extract green component + b = old_color & 0b11111; // Extract blue component + + int brightness = (r + g + b) / 3; // Calculate brightness + + const float brightness_divergence = 0.03f; // The difference in brightness between each color in the palette + const float brightness_modifier = -0.4f; // The overall brightness modifier for the palette + + clr_adj_brightness(&pal_bg_mem[AFFINE_BG_PB] + i, &color, 1, float2fx(brightness_modifier + (brightness * brightness_divergence))); // Adjust brightness for the palette colors + } +} \ No newline at end of file diff --git a/source/game.c b/source/game.c index e1e4e82..0f74e88 100644 --- a/source/game.c +++ b/source/game.c @@ -11,6 +11,7 @@ #include "hand_analysis.h" #include "blind.h" #include "joker.h" +#include "affine_background.h" #include "graphic_utils.h" #include "tonc_video.h" #include "audio_utils.h" @@ -430,22 +431,7 @@ void change_background(int id) { main_bg_se_copy_rect(BOSS_BLIND_TITLE_SRC_RECT, TOP_LEFT_BLIND_TITLE_POINT); - const int palette_length = 5; - memcpy16(&pal_bg_mem[16 * 15], affine_background_gfxPal, palette_length); - for (int i = 0; i < palette_length; i++) - { - COLOR old_color = 0; - memcpy16(&old_color, &pal_bg_mem[16 * 15] + i, 1); // Copy the color from the background palette - - int r, g, b; - r = (old_color >> 10) & 0b11111; // Extract red component - g = (old_color >> 5) & 0b11111; // Extract green component - b = old_color & 0b11111; // Extract blue component - - COLOR new_color = blind_get_color(BOSS_BLIND, BLIND_MAIN_COLOR_INDEX); - int brightness = (r + g + b) / 3; // Calculate brightness - clr_adj_brightness(&pal_bg_mem[16 * 15] + i, &new_color, 1, float2fx(-0.6f + (brightness * 0.05f))); // Adjust brightness for the palette colors - } + affine_background_set_color(blind_get_color(BOSS_BLIND, BLIND_SHADOW_COLOR_INDEX)); } bg_copy_current_item_to_top_left_panel(); @@ -2004,6 +1990,7 @@ void game_round_end() tte_erase_rect_wrapper(BLIND_REWARD_RECT); tte_erase_rect_wrapper(BLIND_REQ_TEXT_RECT); obj_hide(playing_blind_token->obj); + affine_background_set_color(AFFINE_BG_DEFAULT_COLOR); state = 5; timer = 0; } diff --git a/source/main.c b/source/main.c index 2cb29fc..76abc07 100644 --- a/source/main.c +++ b/source/main.c @@ -7,6 +7,7 @@ #include "game.h" #include "blind.h" #include "joker.h" +#include "affine_background.h" #include "graphic_utils.h" // Graphics @@ -17,29 +18,6 @@ #include "soundbank.h" #include "soundbank_bin.h" -#define MAP_AFF_SIZE 0x0100 -BG_AFFINE bgaff; -AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0}; - - -void init_map() // Temp function derived from libtonc example -{ - // Grit is fucking garbage and doesn't allow you to have a palette offset, they all get loaded at 0x0000. I have to manually change each tile's palette bank - - unsigned int correctedTiles[affine_background_gfxTilesLen / 4]; - for (int i = 0; i < affine_background_gfxTilesLen / 4; i++) - { - correctedTiles[i] = affine_background_gfxTiles[i] | 0xF0F0F0F0; // I brute forced this. I have no idea how this would and does work, but it does. We'll just leave this here for now. - // Actually for future reference, each number seems to equate to an XY on the palette, so 0xF0F0F0F0 would just push everything down 15 colors, since the second number isn't set. - } - - memcpy16(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen); - GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); - memcpy16(&pal_bg_mem[16 * 15], affine_background_gfxPal, 5); - - bgaff = bg_aff_default; -} - void init() { irq_init(NULL); @@ -93,9 +71,8 @@ void init() REG_DISPCNT = DCNT_MODE1 | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_OBJ | DCNT_WIN0 | DCNT_WIN1; - init_map(); // Initialize the map for the background - // Initialize subsystems + affine_background_init(); sprite_init(); card_init(); blind_init(); @@ -103,24 +80,9 @@ void init() game_init(); } -void background_update() // This needs to be called before update() and draw() because setting REG_BG_AFFINE during an HBlank can cause issues -{ - static uint timer = 0; - timer++; - - // These values are not permament, just the current configuration for the affine background - asx.tex_x += 5; - asx.tex_y += 12; - asx.sx = (lu_sin(timer * 100)) >> 8; // Scale the sine value to fit in a s16 - asx.sx += 256; // Add 256 to the sine value to make it positive - asx.sy = (lu_sin(timer * 100 + 0x4000)) >> 8; // Scale the sine value to fit in a s16 - asx.sy += 256; // Add 256 to the sine value to make it positive - bg_rotscale_ex(&bgaff, &asx); - REG_BG_AFFINE[2]= bgaff; -} - void update() { + affine_background_update(); game_update(); } @@ -138,7 +100,6 @@ int main() VBlankIntrWait(); mmFrame(); key_poll(); - background_update(); update(); draw(); } From d0ca4a483d1019239e6450e8d0be1f1a7f67b313 Mon Sep 17 00:00:00 2001 From: cellos51 Date: Tue, 5 Aug 2025 14:42:37 -0400 Subject: [PATCH 07/45] Fix indentation in affine_background.c for consistency --- source/affine_background.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/affine_background.c b/source/affine_background.c index 6752be2..da09b7f 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -15,11 +15,11 @@ void affine_background_init() correctedTiles[i] = affine_background_gfxTiles[i] | 0xF0F0F0F0; } - memcpy16(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen/2); + memcpy16(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen/2); GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN); - bgaff = bg_aff_default; + bgaff = bg_aff_default; affine_background_set_color(AFFINE_BG_DEFAULT_COLOR); } @@ -37,7 +37,7 @@ void affine_background_update() asx.sy = (lu_sin(timer * 100 + 0x4000)) >> 8; // Scale the sine value to fit in a s16 asx.sy += 256; // Add 256 to the sine value to make it positive bg_rotscale_ex(&bgaff, &asx); - REG_BG_AFFINE[2] = bgaff; + REG_BG_AFFINE[2] = bgaff; } void affine_background_set_color(COLOR color) From fe4b8e081d22845122224373f56c975a2fa7f1ae Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Tue, 5 Aug 2025 22:03:54 +0300 Subject: [PATCH 08/45] Changed clubs symbol to improve card readability --- graphics/deck_gfx.png | Bin 10399 -> 10459 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/deck_gfx.png b/graphics/deck_gfx.png index 1b775262a558bb430cf6532fbc7ceee2393f3780..98c61d96f7bc567ebede4b89e31436c396a93c16 100644 GIT binary patch literal 10459 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 From f84268c14d8d8170018da52d4f8829c31c09a2db Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Thu, 7 Aug 2025 19:47:55 +0300 Subject: [PATCH 09/45] Added int list for joker pooling --- include/list.h | 19 +++++++++++++++ source/int_list.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 include/list.h create mode 100644 source/int_list.c diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..b3ee749 --- /dev/null +++ b/include/list.h @@ -0,0 +1,19 @@ +#ifndef LIST_H +#define LIST_H + +#include + +typedef struct IntList +{ + int* _array; + int size; + int allocated_size; +} IntList; + +IntList *int_list_new(int init_size); +void int_list_destroy(IntList **list); +bool int_list_add(IntList *list, int value); +bool int_list_remove(IntList *list, int index); +int int_list_get(IntList *list, int index); + +#endif diff --git a/source/int_list.c b/source/int_list.c new file mode 100644 index 0000000..458b564 --- /dev/null +++ b/source/int_list.c @@ -0,0 +1,61 @@ +#include +#include +#include "list.h" + +IntList *int_list_new(int init_size) { + IntList *list = (IntList *)malloc(sizeof(IntList)); + if (list == NULL) return NULL; + list->_array = (int *)malloc(sizeof(int) * init_size); + if (!list->_array) + { + free(list); + return NULL; + } + list->size = 0; + list->allocated_size = init_size; + return list; +} + +void int_list_destroy(IntList **list) { + if (list == NULL || *list == NULL) + return; + { + free((*list)->_array); + free(*list); + } + + *list = NULL; +} + +bool int_list_add(IntList *list, int value) +{ + if (list->size >= list->allocated_size) + { + int new_size = list->allocated_size * 2; + int *new_arr = (int *)realloc(list->_array, sizeof(int) * new_size); + if (new_arr == NULL) + return false; + list->_array = new_arr; + list->allocated_size = new_size; + } + list->_array[list->size++] = value; + return true; +} + +bool int_list_remove(IntList *list, int index) { + if (index < 0 || index >= list->size) + return false; + for (int i = index; i < list->size - 1; ++i) + { + list->_array[i] = list->_array[i + 1]; + } + list->size--; + return true; +} + +int int_list_get(IntList *list, int index) +{ + if (index < 0 || index >= list->size) + return 0; + return list->_array[index]; +} \ No newline at end of file From b0a4fc968c11f2914ea5a2b0e190a37f51206b21 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Thu, 7 Aug 2025 22:48:06 +0300 Subject: [PATCH 10/45] Removed duplicate declarations to fix build --- source/game.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/source/game.c b/source/game.c index 5e4ffe1..e067082 100644 --- a/source/game.c +++ b/source/game.c @@ -239,31 +239,6 @@ static const Rect SHOP_REROLL_RECT = {88, 96, UNDEFINED, UNDEFI #define PITCH_STEP_UNDISCARD_SFX 2*PITCH_STEP_DRAW_SFX // Naming the stage where cards return from the discard pile to the deck "undiscard" -// get-functions, for other files to view game state (mainly for jokers) -CardObject **get_hand_array(void) { - return hand; -} - -int get_hand_top(void) { - return hand_top; -} - -CardObject **get_played_array(void) { - return played; -} - -int get_played_top(void) { - return played_top; -} - -JokerObject **get_jokers(void) { - return jokers; -} - -int get_jokers_top(void) { - return jokers_top; -} - int get_num_discards_remaining(void) { return discards; } From 50ec1bcdabc927c59a8aaff8a50f054be627f29d Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Thu, 7 Aug 2025 23:08:35 +0300 Subject: [PATCH 11/45] Added art by @GreenNinja2525 for jokers Walkie-Talkie, Fibonacci, Banner, Mystic Summit, and Blackboard --- graphics/joker_gfx10.grit | 1 + graphics/joker_gfx10.png | Bin 0 -> 1297 bytes graphics/joker_gfx11.grit | 1 + graphics/joker_gfx11.png | Bin 0 -> 543 bytes graphics/joker_gfx9.grit | 1 + graphics/joker_gfx9.png | Bin 0 -> 951 bytes include/joker_gfx.h | 3 +++ source/joker.c | 6 ++++++ 8 files changed, 12 insertions(+) create mode 100644 graphics/joker_gfx10.grit create mode 100644 graphics/joker_gfx10.png create mode 100644 graphics/joker_gfx11.grit create mode 100644 graphics/joker_gfx11.png create mode 100644 graphics/joker_gfx9.grit create mode 100644 graphics/joker_gfx9.png diff --git a/graphics/joker_gfx10.grit b/graphics/joker_gfx10.grit new file mode 100644 index 0000000..a8ac3f6 --- /dev/null +++ b/graphics/joker_gfx10.grit @@ -0,0 +1 @@ +-gB4 -Mw4 -Mh4 -m! -pn 16 \ No newline at end of file diff --git a/graphics/joker_gfx10.png b/graphics/joker_gfx10.png new file mode 100644 index 0000000000000000000000000000000000000000..a87df841486a2e96c128cd632550431600d5a42e GIT binary patch literal 1297 zcmV+s1@8KZP)q~Mdn;uqgJUg11omttT9|(JAc7DF^ zy?JkD)`0{Me){c&th`^m|K6L9$$Kwz{GI|DeB2v3)WLsf{;r&aZ2Z9!1Bu3IH9E-V zQa$DW{JAe3{}ov$s!6!6%ShKME6T~buFFXB&tiEJ5NV$LdTTTC zBSEOn7E%u&C4MbS?dB*l-WGfA?Cs;DY7O{y(4>1KsI18c zKXG}Oc!H4t0C4x%5Y9i}J1AIQ3_ak|99!$7Lk_V06|gad-9Fa8DI(;v(bPwt5C>xc zcx1dSoc=h>=|L%vKi;a~^-pGivq^fBLuNgGlcOUqw$s5nPaQ8dG5X8f2-X|~YX{k2 zcc}twOhr2{Cg0K0Iwm2AFs=1$E`>riba}p9gl_!<79K!Z;aw`&n2H3slS2alMf@Ug z(zN3kkR>V2WphzNy3}{5F@W&bng=X3L&5+f+fT}i1FdJCBrgns_YVFY9jpYPYyf!p znKnJki(v+M2RLohnE^x#s@$CF_-tUh8M2N6caIH4p7)`mP76Mt^XCAW z5EK){fT$AJb@ziz5WF~&OB?`@rZGld0+nDgBs#C&|M%}O z?^7qMRis}#ylt-tem@|>Z~M~nY%axqI#>(9yS=+w?Q64R0$R&_FeK}%$ct@tuv!8^ zDbKdMpD*3S?ee_7L7(8)IDy=rCr^P+ge*RYu#W*7Q*c+S@Vm$3qX1cs$ck%SX8HBj zCeoR7q&}TVM+7|n#;ZN;jF&)A%42t_5{dMaMtRDk#JnSD2AIkrSzV@F7D4i--GXWFmZ2P`HuLd$ObCQ#BTQ^V(!A#*!TXApU3|LOZ|5hB9UtS00000NkvXX Hu0mjfq048x literal 0 HcmV?d00001 diff --git a/graphics/joker_gfx11.grit b/graphics/joker_gfx11.grit new file mode 100644 index 0000000..a8ac3f6 --- /dev/null +++ b/graphics/joker_gfx11.grit @@ -0,0 +1 @@ +-gB4 -Mw4 -Mh4 -m! -pn 16 \ No newline at end of file diff --git a/graphics/joker_gfx11.png b/graphics/joker_gfx11.png new file mode 100644 index 0000000000000000000000000000000000000000..8dd805ced547cc7b9063fb62113605dbfc180214 GIT binary patch literal 543 zcmV+)0^t3LP)MBQJ*`s)c#D)tLvEl;lC31o6+C}xPshQYL6JXpv z2}N?8!2cf4*k%TW{cX}O+Rj%1?3wVOHB$Uxv-F>_ zOl{~?s0NVr{`lkC$5bZWgQx*H95zerPG{^+=ORt$H6TX}#RI_0^8)Mru{aZY4WO95 z@R#BN_y|Z%7i&DmZiZsy=t}XxcLcCcNhU-Mkc7gt@bBwunXDu@R8UE|AZdUmzHk0Z zN-<$j84Lxvwu5WCXdmlDa{xzQisI-?;jZlf5e2-aDv1S>D?tjN2!?)WioD1E*2M!E zRX`Kq+73=c2KzL1m3-D3*=3Npw!4_;(ukKSe$@>blmx@DmQ$mYkPrD)6=>?p3#Mp> z|DUP?l5ljJy7Eb{sVkosw7!-Zyb^5c$_pm0?R+~>&LRjHxDup53MSH!(oD!IgVF?w z4_AO}lewUTX^<5GTLdUF002ovPDHLkV1h^O{G$K> literal 0 HcmV?d00001 diff --git a/graphics/joker_gfx9.grit b/graphics/joker_gfx9.grit new file mode 100644 index 0000000..a8ac3f6 --- /dev/null +++ b/graphics/joker_gfx9.grit @@ -0,0 +1 @@ +-gB4 -Mw4 -Mh4 -m! -pn 16 \ No newline at end of file diff --git a/graphics/joker_gfx9.png b/graphics/joker_gfx9.png new file mode 100644 index 0000000000000000000000000000000000000000..298f796ddaa08d29d19db08d202f2b1784d5d5c0 GIT binary patch literal 951 zcmV;o14#UdP)_0* zp_Jf70$q~QOImXhwG>Kw^FJ_x;OZgHb~d}Szh)9Geh_B%&Fsv+Z{BO z*~vu_ja(e@(r=jaTLg6SsfjVElW%VCazDau{>fL5ENv$y-v*w)HNIy%|4F;fQxjv* zbsaPF3x;fc<)z~Ugb?VuZY!r_QWD%il_!;&A=5KSPw(;&{dB<~!SsE+7YHGS()Ci2 zJ1`*xgb*Zhd85w$L_n1mRo)4<7C^yMpkJQI<&BcHl%NEx#S2C~$vjul0RW`B;Xvcs zflELlm$zMcH>G&4;0LN!M!i%-B9}+<&Q+*d+0PCkOwXA}%#sZPy?lV? z41hU>{<(GA(tm6Gu|?*a0529GiuafA8}(|a16307|81UiyR{(tf zr|p28Jb_id((VOURV$;?Zlcm|8Ya)Kyk7)L*9N)zJWw}CD_NZSb|`IJUoOx%*aObF zv`YfJ`l)W%6xe>89yJjn;sU;7fJ`NMxc>1O5Q%Z0WhoB?aDl^(mTO%GSRcLmeUIfgxCc zXiChIz!E`s2{+~0qjfuYjsb@oEsRb_T`hnmf}Sbz4p_aS(rzO2Clh2-VwxQ~DX(Xe zMrj961njFdoKGh``}w|VW?e>BNd3O5m}Pc3e?Oe=6+Bx&zfxYI>$=qQL78^~zyJ?L zsqfFsF9_cg1OfH^Krvu*dsp~!wBPK#-U|Z2gY->2Ro@BC-*5I?_pE<~0h`-l;QzWF Z{|!9h<4@gXzIy-w002ovPDHLkV1g=0un+(M literal 0 HcmV?d00001 diff --git a/include/joker_gfx.h b/include/joker_gfx.h index 92c3edc..75cfbbc 100644 --- a/include/joker_gfx.h +++ b/include/joker_gfx.h @@ -10,5 +10,8 @@ #include "joker_gfx6.h" #include "joker_gfx7.h" #include "joker_gfx8.h" +#include "joker_gfx9.h" +#include "joker_gfx10.h" +#include "joker_gfx11.h" #endif \ No newline at end of file diff --git a/source/joker.c b/source/joker.c index c302faf..41d1fd1 100644 --- a/source/joker.c +++ b/source/joker.c @@ -105,6 +105,9 @@ void joker_init() joker_gfxTiles[6] = joker_gfx6Tiles; joker_gfxTiles[7] = joker_gfx7Tiles; joker_gfxTiles[8] = joker_gfx8Tiles; + joker_gfxTiles[9] = joker_gfx9Tiles; + joker_gfxTiles[10] = joker_gfx10Tiles; + joker_gfxTiles[11] = joker_gfx11Tiles; joker_gfxPal[0] = joker_gfx0Pal; joker_gfxPal[1] = joker_gfx1Pal; @@ -115,6 +118,9 @@ void joker_init() joker_gfxPal[6] = joker_gfx6Pal; joker_gfxPal[7] = joker_gfx7Pal; joker_gfxPal[8] = joker_gfx8Pal; + joker_gfxPal[9] = joker_gfx9Pal; + joker_gfxPal[10] = joker_gfx10Pal; + joker_gfxPal[11] = joker_gfx11Pal; for (int i = 0; i < num_spritesheets; i++) { From 4492176df21e36d02c745d46c97518fcd4693219 Mon Sep 17 00:00:00 2001 From: theturtlemafia Date: Sat, 2 Aug 2025 00:27:35 -0400 Subject: [PATCH 12/45] allows multiple joker-effect popup texts --- source/joker.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/source/joker.c b/source/joker.c index 41d1fd1..4ffca63 100644 --- a/source/joker.c +++ b/source/joker.c @@ -241,33 +241,44 @@ bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips *money += joker_effect.money; // TODO: Retrigger - tte_set_pos(fx2int(joker_object->sprite_object->x) + 8, JOKER_SCORE_TEXT_Y); // Offset of 16 pixels to center the text on the card - - char score_buffer[12]; - + int cursorPosX = fx2int(joker_object->sprite_object->x) + 8; // Offset of 16 pixels to center the text on the card if (joker_effect.chips > 0) { + char score_buffer[12]; + tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xD000); // Blue snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.chips); + tte_write(score_buffer); + cursorPosX += 30; } - else if (joker_effect.mult > 0) + if (joker_effect.mult > 0) { + char score_buffer[12]; + tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xE000); // Red snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult); + tte_write(score_buffer); + cursorPosX += 30; } - else if (joker_effect.xmult > 0) + if (joker_effect.xmult > 0) { + char score_buffer[12]; + tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xE000); // Red snprintf(score_buffer, sizeof(score_buffer), "X%d", joker_effect.xmult); + tte_write(score_buffer); + cursorPosX += 30; } - else if (joker_effect.money > 0) + if (joker_effect.money > 0) { + char score_buffer[12]; + tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xC000); // Yellow snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.money); + tte_write(score_buffer); + cursorPosX += 30; } - tte_write(score_buffer); - joker_object->joker->processed = true; // Mark the joker as processed joker_object_shake(joker_object, SFX_CARD_SELECT); // TODO: Add a sound effect for scoring the joker From 5e6d28c66377901329b12b585bdc4fb9e13c4cf2 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 00:01:36 +0300 Subject: [PATCH 13/45] Fixed stack top bugs in joker_effects.c - e.g. Blackboard activated if just the first card in hand was not spades/clubs --- include/game.h | 1 + source/game.c | 10 +++++----- source/joker_effects.c | 15 +++++++++------ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/game.h b/include/game.h index 02c3b01..1d99865 100644 --- a/include/game.h +++ b/include/game.h @@ -77,6 +77,7 @@ typedef struct CardObject CardObject; // forward declaration, actually declared typedef struct JokerObject JokerObject; CardObject** get_hand_array(void); int get_hand_top(void); +int hand_get_size(void); CardObject** get_played_array(void); int get_played_top(void); JokerObject** get_jokers(void); diff --git a/source/game.c b/source/game.c index e067082..fe820c5 100644 --- a/source/game.c +++ b/source/game.c @@ -148,6 +148,11 @@ int get_hand_top(void) { return hand_top; } +int hand_get_size(void) +{ + return hand_top + 1; +} + CardObject **get_played_array(void) { return played; } @@ -853,11 +858,6 @@ void hand_change_sort() sort_cards(); } -int hand_get_size() -{ - return hand_top + 1; -} - int hand_get_max_size() { return hand_size; diff --git a/source/joker_effects.c b/source/joker_effects.c index 7a2eaf3..fa6c897 100644 --- a/source/joker_effects.c +++ b/source/joker_effects.c @@ -1,3 +1,4 @@ +#include "game.h" #include "joker.h" #include "util.h" #include "hand_analysis.h" @@ -178,7 +179,8 @@ static JokerEffect half_joker_effect(Joker *joker, Card *scored_card) { if (scored_card != NULL) return effect; // if card != null, we are not at the end-phase of scoring yet - if (get_played_top() + 1 <= 3) // game.c has hand_get_size() but it's not accesible here + int played_size = get_played_top() + 1; + if (played_size <= 3) effect.mult = 20; return effect; @@ -190,12 +192,13 @@ static JokerEffect joker_stencil_effect(Joker *joker, Card *scored_card) { return effect; // if card != null, we are not at the end-phase of scoring yet // +1 xmult per empty joker slot... - int jokers_top = get_jokers_top(); - effect.xmult = (MAX_JOKERS_HELD_SIZE-1) - jokers_top; + int num_jokers = get_jokers_top() + 1; + + effect.xmult = (MAX_JOKERS_HELD_SIZE) - num_jokers; // ...and also each stencil_joker adds +1 xmult JokerObject** jokers = get_jokers(); - for (int i = 0; i < jokers_top; i++ ) + for (int i = 0; i < num_jokers; i++ ) { if (jokers[i]->joker->id == JOKER_STENCIL_ID) effect.xmult++; @@ -271,8 +274,8 @@ static JokerEffect blackboard_joker_effect(Joker *joker, Card *scored_card) { bool all_cards_are_spades_or_clubs = true; CardObject** hand = get_hand_array(); - int hand_top = get_hand_top(); - for (int i = 0; i < hand_top; i++ ) + int hand_size = hand_get_size(); + for (int i = 0; i < hand_size; i++ ) { u8 suit = hand[i]->card->suit; if (suit == HEARTS || suit == DIAMONDS) { From 863e3a34ae0fb9ea2cd429dbe7e05e816a7f4933 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 00:31:10 +0300 Subject: [PATCH 14/45] Rearranged jokers for palette optimization (Banner and Mystic Summit don't go well together) --- graphics/joker_gfx10.png | Bin 1297 -> 1023 bytes graphics/joker_gfx11.png | Bin 543 -> 845 bytes source/joker_effects.c | 5 +++-- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/graphics/joker_gfx10.png b/graphics/joker_gfx10.png index a87df841486a2e96c128cd632550431600d5a42e..aca51bc66d535bd70ac6c3ebc6ede6a4d5ac365f 100644 GIT binary patch delta 1002 zcmV}@Alr_?&(fxG9YBX-PLL4 z&3n6d+JS=c{kK0_JTE%UmpdWz{^j)(0bcz5*AInW{N3?u=YN;buD`dxyU}%K(*+u> zY9jvg$1nBz&$JIA`Ma}@iJgwd8+{@9nH0eXk{?`Mo7mv;0>GM}gd{tgE^srOpoexs zguVS;BZ5RJ?Te7KkNn+PCni==AZbbdW;ThvC0B2|D8+?{oBJGsa0u-%d3yyhxV*sN z>e|?!NF&FwlY{m9m&b*3F5wgaNY=j0t|Skv9l$w7ia?~1VjpOTLfI$l+CY)c5E!f2|-OTE1@ELK^kJ@t$*656MSXh6+k2Js(*>RBAgsl zO$G^h21p|hgw;QgaT~M=4VNnnm#fq{n}XS+2qY})z1LV&QZ`MmUn!fupv}z-Z5uP>6@Rz{(~$Wj*sqigVPd#knK)4VNl=~# zY((=&jk6ql%`nqRkOWDXkb)E~0_#`q1kApRyuCIJLEE4df#mHIAY(=L0$Jk(Z7<35 zF_;alKiKdJz>^=dIUJ4AZ8sC=0LHrQCc4P?e1MrFS-aM?%-_r=sMTw+@mjqW6Y$01 z^MAy;%np!(_+pznz}4KMd4yWM79+~PCF~f><^1q%Vs20qlth^AkXRmQS(e0I&ay%yLDD`*QKET-$Is(LTq5^V;WTJ>lOd2c2jVsD8n?xX<`JIe4=B}- zj0hSs-wSMlyyf7^o@?9|qf|dy$Bthm)?;qf0eRudtZz*gcpr#p&^o>L&{T_OK}d&} zkmR4{59Ym8KXR^79T4&xo?YKIN!}?k9{Rf=0GugS^+B^eUjT6aCbq~Mdn;uqgJUg11omttT9|(JAc7DF^y?JkD)`0{Me){c&tbe>;y#L;tj>&s3bNrqH z8hqRvIn=>_X#TF8glzo569b9HX*D{?=2AW7|NOZx9sdp0n9z5Arql5L#u>$8q2Ytr!N1*HJB%1T58 z-kSC4LP&IZ5de@;@C-_MxT{s;$?zy&n^%gU0@aNThkt(`?{t*!60|-_b$D zTkE4k4u7!y6|gad-9Fa8DI(;v(bPwt5C>xccx1dSoc=h>=|L%vKi;a~^-pGivq^fB zLuNgGlcOUqw$s5nPaQ8dG5X8f2-X|~YX{k2cc}twOhr2{Cg0K0Iwm2AFs=1$E`>ri zba}p9gl_!<79K!Z;aw`&n2H3slS2alMf@Ug(tot$7?33?&1G{@Lb}v*O~_` zHABJxBim2Pivz7^o+K{}f%gvn9UZI$plkqm_?b36%Zp(Kcn3Ib)0qK83##0l>iBG6 zx*4*L0e6oLMV|McJ_QiQhM<(U?M@3mpY!JcnGh5c#DJ(14M>;;u5XQ_b}!r{1;y{f zw0~Dj(vul<2OT~$$cU>>hXiW@YLyjSDTl{YJ_`UivKSzq0r*t-@Yy!dkROXpkjMjk zzteU1gG>;-IFd^o0Fb6JMqUDyU@{~+uipRn?=bIEC#zMYUpu^QuLyoWAi{6^((-IB z#eO#N9%ZGUyJS^_~S&$hdtFWtoL^1Qx5pWxRxf!v-a zPk~N^EIx>^j{zG~a96AFyT{|B09lU6ifdhF`SsQ&(wTImKAlNN1U&x6t3BtRDk#JnS zD2AIkrSzV@F7D4i--GXWFmZ2P`FD=^rN{;<%f_{_fsp_cIS-F+jf5AYjb`^q3`Sh$ z;#79-;^o95$Skk(1fG1*eiHes!l8T|y;5F?-4xk=9R23kE!}H9h_n3F4?dKRFP)6- o=jp{SZ({Dk)!6s`kDtf?155pP6(W&p{Qv*}07*qoM6N<$f|Pw}aR2}S diff --git a/graphics/joker_gfx11.png b/graphics/joker_gfx11.png index 8dd805ced547cc7b9063fb62113605dbfc180214..1281a78f7e28e13c8e4e82d22e2f201e270deb0d 100644 GIT binary patch delta 823 zcmV-71IYZJ1kDDJBYy)FNklffRrvuRdP%tB zWXy;uP)f19wrSXoKD-||5FrErKq+;!XT+3|geXB=Ul3vhElU;m0SGaIG(X$zQN>XK z9M=E@0Yq?DGFL&Y6R=cTcbs`a5FprsKiOsb#hH=@Hnt4=;+zsTtS1L)5-0LyIK>21FP7Cr^wVz_u( zq_R{&@v_Ti-hneEZF$zZJv^z)!+SRZ25y38_Qw(^UUvJ2y&a~2jV)uXrxOD3^CQq) z!FdeUKj0$)W~Rhb%sgi`offkA^-#it7bRdJP~S#^?|(XVKd&JD{SjzQ0Il__!FgE% znk&}9^P!xm1I2R!WT}Gvu|(fs3w9zg4pOayN^`4`u+BFq4jurNutHx;5RpLzn zSL=Qdyj8}VBZLs6rx@iVcuK(Mr!QUKC6kkAgiM8u!J^E>u;+;=!To zXY4mcQNvRL7Ux8q?55Djt)g+P7|l^0xRb=WZFy}o@=37JYIpQjyQBNz+3Pp|{R|)X zwlL$fbL}WRKRYe7+8y1`MW(81o-RJ4b~6kB{{T~oO{xP!NKgO(002ovPDHLkV1n?P BfCvBp delta 518 zcmV+h0{Q*T2A>3wBYy$rNklMBQJ*`s)c z#D)tLvEl;lC31o6+C}xPshQYL6JXpv2}N?8!2cf4*k%TW{cX}O+Rj%1?3wVOHB$Uxv-F>_Ol{~?s0NVr{`lkC$A45N-GitBIUF`i>`rIw zPUj*`=rtfm48;S$%ku*3{joR`dJUkMzVMgg0r&_=O&4oC#%_jUdFhIXomlvssfU5bep>JNw29ZpBJ>gmKnSfZ0gDj zCa&##J5bId2pG5$q(BNL(vZ?j$SQ-<1d0z=fNYbwpnrsEkQD)3>vPL1x4s-@c~3rL zoxu?x#iiOxhye9iJavNGw?j+`-p*HL9E+#WgvO4}EHnC4IEJ>Hw8m8pAeM8%O$@M1 z@<2pG%k Date: Fri, 8 Aug 2025 01:59:21 +0300 Subject: [PATCH 15/45] Removed magic numbers for card score length and intmax buffer sizes --- include/game.h | 2 ++ include/graphic_utils.h | 3 +++ include/util.h | 2 ++ source/game.c | 2 +- source/joker.c | 19 +++++++++++-------- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/game.h b/include/game.h index 1d99865..55e8730 100644 --- a/include/game.h +++ b/include/game.h @@ -6,6 +6,8 @@ #define MAX_JOKERS_HELD_SIZE 5 // This doesn't account for negatives right now. #define MAX_SHOP_JOKERS 2 // TODO: Make this dynamic and allow for other items besides jokers #define MAX_SELECTION_SIZE 5 +#define MAX_CARD_SCORE_DIGITS 2 // Current digit limit for score received from cards including mult etc. from jokers +#define MAX_CARD_SCORE_STR_LEN (MAX_CARD_SCORE_DIGITS + 1) // For the '+' or 'X' #define FRAMES(x) (((x) + game_speed - 1) / game_speed) // TODO: Turn into enum? diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 6c169c7..2791791 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -43,6 +43,9 @@ // Tile size in pixels, both height and width as tiles are square #define TILE_SIZE 8 +// By default TTE characters occupy a single tile +#define TTE_CHAR_SIZE TILE_SIZE + typedef struct { int left; diff --git a/include/util.h b/include/util.h index 5b3160e..7d9b915 100644 --- a/include/util.h +++ b/include/util.h @@ -37,6 +37,8 @@ static inline int get_digits_even(int n) #define NUM_ELEM_IN_ARR(arr) (sizeof(arr) / sizeof((arr)[0])) +#define INT_MAX_DIGITS 10 // strlen(str(INT_MAX)) = strlen("2147483647") + int int_arr_max(int int_arr[], int size); #endif // UTIL_H \ No newline at end of file diff --git a/source/game.c b/source/game.c index f89a1b6..8acd864 100644 --- a/source/game.c +++ b/source/game.c @@ -1619,7 +1619,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection tte_set_special(0xD000); // Set text color to blue from background memory // Write the score to a character buffer variable - char score_buffer[5]; // Assuming the maximum score is 99, we need 4 characters (2 digits + null terminator) + char score_buffer[INT_MAX_DIGITS + 2]; // for '+' and null terminator snprintf(score_buffer, sizeof(score_buffer), "+%d", card_get_value(played[j]->card)); tte_write(score_buffer); diff --git a/source/joker.c b/source/joker.c index e0a382d..6b30061 100644 --- a/source/joker.c +++ b/source/joker.c @@ -270,42 +270,45 @@ bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips *money += joker_effect.money; // TODO: Retrigger + const int joker_score_display_offset_px = (MAX_CARD_SCORE_STR_LEN + 1)*TTE_CHAR_SIZE; + // + 1 For space + int cursorPosX = fx2int(joker_object->sprite_object->x) + 8; // Offset of 16 pixels to center the text on the card if (joker_effect.chips > 0) { - char score_buffer[12]; + char score_buffer[INT_MAX_DIGITS + 2]; // For '+' and null terminator tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xD000); // Blue snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.chips); tte_write(score_buffer); - cursorPosX += 30; + cursorPosX += joker_score_display_offset_px; } if (joker_effect.mult > 0) { - char score_buffer[12]; + char score_buffer[INT_MAX_DIGITS + 2]; tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xE000); // Red snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult); tte_write(score_buffer); - cursorPosX += 30; + cursorPosX += joker_score_display_offset_px; } if (joker_effect.xmult > 0) { - char score_buffer[12]; + char score_buffer[INT_MAX_DIGITS + 2]; tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xE000); // Red snprintf(score_buffer, sizeof(score_buffer), "X%d", joker_effect.xmult); tte_write(score_buffer); - cursorPosX += 30; + cursorPosX += joker_score_display_offset_px; } if (joker_effect.money > 0) { - char score_buffer[12]; + char score_buffer[INT_MAX_DIGITS + 2]; tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y); tte_set_special(0xC000); // Yellow snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.money); tte_write(score_buffer); - cursorPosX += 30; + cursorPosX += joker_score_display_offset_px; } joker_object->joker->processed = true; // Mark the joker as processed From 039c5771e1707e1111d777ca903671d74bae585d Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 02:22:02 +0300 Subject: [PATCH 16/45] Grouped Banner with Stencil to optimize palettes (Swapped with Misprint) --- graphics/joker_gfx11.png | Bin 845 -> 855 bytes graphics/joker_gfx8.png | Bin 1105 -> 1085 bytes source/joker_effects.c | 5 ++--- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/graphics/joker_gfx11.png b/graphics/joker_gfx11.png index 1281a78f7e28e13c8e4e82d22e2f201e270deb0d..07b537c4b3f16e80ba8decafaea4179ef21a4375 100644 GIT binary patch delta 832 zcmV-G1Hb&u2G<6VB!3=BL_t(&f#q32OB+EH{$`SEFTE5(d(|qv2E7CW{(yu9iy)%J zG-@uzo(mGl*;}m@4|J|(t04Sws93R4}RM9*+0_WWL8l@D) z@{Uio_u=DcvmFB>F+c~U)Z9P_DCsZrVtEIR-fv&C{g^)+GX@$U_3i)w;4Hib&{wQ^ zaun!C2mvuDZ-1p<%07Fe&-ckOGy|F^N74wKa}Y{F0Q49`I+Y51d9|KM2C!Fe+?uz6 z3kHa#pssbD_EX0I9mVnv8cW|i!R3mtU2U@wzfCY?H&d|2fHj7zn|7cnpnL)mnE^`+ zbG~Pz^4ixA$YzF`+e9#s0am37t5P*GK=!%X_78e`4u5)jKKkq?fKUcdN<*C-aS9a6 ziqQSis^awY9DMWr)68^I&|`tH7@)AV?W?nm6^ET6C_jTNiH!vS;OeIB+Xqa}5M6iB zT!&mP{XR;+2bR%uVW0tW*;$~p3fqkZ1RTeao*w|%yEWuoy60RO|Edk9jS)+j!eK#Q z6`XV9l7Ck8MFGuXfE%ICx~AeWsr9)qe8gz~Dw0Dof70JAGxS_QtRkUHqXs#Ik@P=$#5 z3!OTCeCg*1#c!cgN1;=fGEw4)M~A~|Vg&F`f7H delta 822 zcmV-61Ihf?2F(VLB!3i1L_t(&fz_F@Yui8+#y=e$GNta+k~n{WQ;G>46v*Jv>>&hV zGT2~@8OUUAGT_TkVT?Nr*Bs)(XMe<0pg;6g`2iq$Nx0)= z%!nyaO0m4QY1ocFydO9aAp`(GDRs1G#FUYQC_!9b5Ml%^OBMG42r+^*Kiln5#Zdtq z*8l_oL~vI!S3#^3uvA)ioOwYIAlQOG*=761nUV%Jwha5?oEVg!q2ZbUS*lo)V4lrJ zZj}YPw*vr}a({`F7P27KdVuZ*&p?gx;Fn74SSqap=+8C)%WT`}ZNCB*J_X=nxOiHm zvQ$Cwvdd=Pfiop-dDgl;JgLjWdp80GZh~g^#}X)BcKe3C9j1VdEn}^x69Vw_BhXyI zc?{M+;3ENMro>asJZCkX7P9#DP{M;3C14>?-$sJ(I)8OPuOR*X5ok>St@W$Hd07IQ zE7rmDp`54##d88=se=8nMBiWwb|NtjQmupJb&zTu6N&M_oD37+OW=1+1jgPQ~?07+yid(cTH6_CU;XMpnCL6o)b4p zz|r47tnTwcs&ypq-3`pCQQ~_KV6ta3A4kdC@udLsF8{XtE^udV1OH2)xdKwHLshj9 z+!;Nd6F>`DoR=kw?0JtM&iGP*`Fw9KhjGSJ0)OoFo};STH5D|D751I0#%R=4;!Ocp z>wXZtRmPhmgb<^r8092*O2Fr*FJ0dylapxVR*eRU6NBy*ZkwSR_r=RDR8_;`!J+GC z>^DVG!&3ql=R}lf=1gd2KWDNwCmrcl1`fqx<36>o@=X3?KKl z<1e#w?I=7yJ1w-@9o^4GrmAY5E5H=Q*2B5q>1%AdFwc_EHktOG#9xr%-+2V*TY7 z)?aRE@knC;091+vjL*)YQY?Tm20|$|g)^iIX0>|5lf{Cl5cvVWH&mymfcXXBrw0Il zAxCb5%}j!p$~}2{9s!Yjv$Ny;qncyO14RDu*}1MqY=18a*N$Cw1v3-ey_dr68z~7`+m3f_VIbSqGdZ&fT)Y--~rJVemOPZALzJ0<``Ysif{7+d}kf9>sq%}g5E(mDeF zC!EQ<7=M0!9&CkxtsL#m+r=XAbi#Kp&4*XiN&({TK8GzYs1ytSV{mM-g9E2QOJ&f! z2U;p)aNx9-U1b`~I7!s%4KJHc5ne$>{WHVo+N|sUUU7g$_h^B6U=VsKPX?s`z>x@1 z>Uh~)Tc{KZolM~1H+Q&O3k*3szy)B$z-DL+xPN@8SNUfcetq89R;U03?KSHL#cVo7Heda2{6Jx-6bncs z&H{ih3ji>R0pT7%s8J=@kNnTkY_{6&E@T4cnKhA4OeHAd$-zJEyx##Wm67=5Vm~4(|Q&hy^wTZyk*WcgoZ&MTiJoqa*?iH6W zo%6MvkMA~bi`m$v(`+tZ6J zLg(D~0&kV&Mx99fAEY0^dwZr>zxl25S|V{4)#)jW+*JqLUi^I*z{dLl6|TSEL$ldJ zZgtI=zi$F?x4U}lPHYi!qmHld&zqxs;W8ID=I3e5He@N&7Qaq5Q1L5YZs<#5DPcIG2;Ih5asD|_Mxz(00000NkvXXu0mjfo7NDe delta 1085 zcmV-D1j75h2+;_TBYyw^b5ch_0Itp)=>Px(3rR#lRA_0f$k$$S2^e~f zW09+CT~rJ50b~R=h7e*LS9WwM={XP#KKs_z2|k!WE2U5n&ug*@L41(Kxv>J8MYScw=dk-mPs#V6`&a@TO zOG=4Ox0h-h*nbGnnXnK7QV1)gXrEFfcyT}py#Qcy{}7jxzf+F`j+aZw=Ki5W25&rp zBEc7G&rVQ#b`tOXEWKz98Q)oY6gLje2)H^s#peDYuFg&oh9QKM_^Rz;*I~vTVm`s? zB>+s6!cwhft-RjnB4F+opgks~bgsAwa~o8Jdi?#Ymw#kHT`wRV6=vA$EB}_^Ki2_- zyv7sA3BFS)ht2&%TyA_w2-jPw=lZh%KU?!NPpP8D6IzYBD4X_Dc%gt7icO)G@g*=f z0?Has@EHjv57u~N^)1>H`|)D(lt)kwpBGJ?!9nW3JimZEzsSYk>42)MPbj+;=G73C z1v-O+#DDnNO6!K_bwUdLo4bfW_k#Y-T~y>EqL1hJWzAJe#f^BGXum#4_0_AbNPU7$ z|Ae@4^5>ob8|$l}JzR7Z^|?MU7>-is09OXfml3XBCKs>i7;PM5LuMNM@rS1+)SbeI z@y)drU~dP(o1+vxiXsS+?9kxN5t_T((>XI*_%;3So47V^03x}{iM@N}0pp=Tk z*QJ-fCDf~}n5Oq#@-wr5m{nj!D#5Sc##zG(q4w9GPQ8Gn5*!RikmnZ&cefGlZs$4# zvnxT7zYHe$t_0OD%djq3A}NEvJbecM_!0npjFM0vj?fCei>LIPu#oA1DwUuwCv>_! z_J7dRjX!$6Je7O>5cl6}eE`5e_AT{)Q3<~N$*$o!<4uE)o-gD5^+Wu>a0E~)E9(Sb z5zt&)Vbh@Q1TtPX7(iwO%sm8sL_nzv(cTX5xrW-w13KMa{60_z-TT|)WBl>!^mP~g zw#Ub4kB?&-H4eEWfKrI=kSy9Fuf+O`5q}`b1nu#0ik9_4!~$1#y2|6pWMa{{IhE@G zrP#W{1l0nh7tyHYD(9_&gAqiAf@%%yr=`(uMeCK;7hH@(#zDlR0Na-8Bf1O z96-j?uMfRSRf0Y+@BMui=o`SI&XR>YAPhq(5c+%_6j?JzT&vP<~H~Q zn+DCIqYTWjFS3H>_ddD@_|VIQ^W%nBDKq>RKac+l6NdP!yMOx?00000NkvXXu0mjf DZ`u@m diff --git a/source/joker_effects.c b/source/joker_effects.c index 2b12211..bab4512 100644 --- a/source/joker_effects.c +++ b/source/joker_effects.c @@ -308,13 +308,12 @@ const JokerInfo joker_registry[] = { { COMMON_JOKER, 4, crafty_joker_effect }, { COMMON_JOKER, 5, half_joker_effect }, { UNCOMMON_JOKER, 8, joker_stencil_effect }, - { COMMON_JOKER, 4, misprint_joker_effect }, + { COMMON_JOKER, 5, banner_joker_effect }, { COMMON_JOKER, 4, walkie_talkie_joker_effect }, { UNCOMMON_JOKER, 8, fibonnaci_joker_effect }, { UNCOMMON_JOKER, 6, blackboard_joker_effect }, { COMMON_JOKER, 5, mystic_summit_joker_effect }, - { COMMON_JOKER, 5, banner_joker_effect }, - + { COMMON_JOKER, 4, misprint_joker_effect }, }; static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry); From 9be6a31dce70336989263400b8db336ab9b301c7 Mon Sep 17 00:00:00 2001 From: cellos51 Date: Thu, 7 Aug 2025 23:31:23 -0400 Subject: [PATCH 17/45] Use tonc defines for getting colors --- source/affine_background.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/affine_background.c b/source/affine_background.c index da09b7f..c530bb8 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -49,9 +49,9 @@ void affine_background_set_color(COLOR color) memcpy16(&old_color, &pal_bg_mem[AFFINE_BG_PB] + i, 1); // Copy the color from the background palette int r, g, b; - r = (old_color >> 10) & 0b11111; // Extract red component - g = (old_color >> 5) & 0b11111; // Extract green component - b = old_color & 0b11111; // Extract blue component + r = (old_color & RED_MASK) >> RED_SHIFT; // Extract red component + g = (old_color & GREEN_MASK) >> GREEN_SHIFT; // Extract green component + b = (old_color & BLUE_MASK) >> BLUE_SHIFT; // Extract blue component int brightness = (r + g + b) / 3; // Calculate brightness From bebe2237e48500aa369a79b0f82b2b3586321ffa Mon Sep 17 00:00:00 2001 From: cellos51 Date: Fri, 8 Aug 2025 00:00:20 -0400 Subject: [PATCH 18/45] Add memcpy16_tile8_with_palette_offset function and update affine_background_init to use it --- include/graphic_utils.h | 5 +++++ source/affine_background.c | 9 +-------- source/graphic_utils.c | 11 +++++++++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 2791791..695c388 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -120,4 +120,9 @@ void tte_erase_rect_wrapper(Rect rect); */ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direction); +/*Copies 16 bit data from src to dst, applying a palette offset to the data. + * This is intended solely for use with tile8/8bpp data for dst and src. + */ +void memcpy16_tile8_with_palette_offset(void* dst, const void* src, uint hwcount, u8 palette_offset); + #endif //GRAPHIC_UTILS_H \ No newline at end of file diff --git a/source/affine_background.c b/source/affine_background.c index c530bb8..b51ecda 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -8,14 +8,7 @@ AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0}; void affine_background_init() { - unsigned int correctedTiles[affine_background_gfxTilesLen / 4]; - - for (int i = 0; i < affine_background_gfxTilesLen / 4; i++) - { - correctedTiles[i] = affine_background_gfxTiles[i] | 0xF0F0F0F0; - } - - memcpy16(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen/2); + memcpy16_tile8_with_palette_offset(&tile8_mem[AFFINE_BG_CBB], affine_background_gfxTiles, affine_background_gfxTilesLen/2, AFFINE_BG_PB); GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN); diff --git a/source/graphic_utils.c b/source/graphic_utils.c index 5311711..890cb33 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -168,3 +168,14 @@ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direc } } +void memcpy16_tile8_with_palette_offset(void* dst, const void* src, uint hwcount, u8 palette_offset) +{ + u16* dst16 = (u16*)dst; + const u16* src16 = (const u16*)src; + + for (int i = 0; i < hwcount; i++) + { + // Copying u8 data twice across u16 data + dst16[i] = src16[i] + (((palette_offset) << 8) | (palette_offset)); + } +} \ No newline at end of file From dbe8585c0af01951b4dc8ff5d7886c9911fe63ec Mon Sep 17 00:00:00 2001 From: cellos51 Date: Fri, 8 Aug 2025 00:08:28 -0400 Subject: [PATCH 19/45] Refactor affine_background_set_color to simplify brightness adjustment logic --- source/affine_background.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/source/affine_background.c b/source/affine_background.c index b51ecda..fd4a718 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -38,19 +38,6 @@ void affine_background_set_color(COLOR color) memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN); for (int i = 0; i < AFFINE_BG_PAL_LEN; i++) { - COLOR old_color; - memcpy16(&old_color, &pal_bg_mem[AFFINE_BG_PB] + i, 1); // Copy the color from the background palette - - int r, g, b; - r = (old_color & RED_MASK) >> RED_SHIFT; // Extract red component - g = (old_color & GREEN_MASK) >> GREEN_SHIFT; // Extract green component - b = (old_color & BLUE_MASK) >> BLUE_SHIFT; // Extract blue component - - int brightness = (r + g + b) / 3; // Calculate brightness - - const float brightness_divergence = 0.03f; // The difference in brightness between each color in the palette - const float brightness_modifier = -0.4f; // The overall brightness modifier for the palette - - clr_adj_brightness(&pal_bg_mem[AFFINE_BG_PB] + i, &color, 1, float2fx(brightness_modifier + (brightness * brightness_divergence))); // Adjust brightness for the palette colors + clr_rgbscale(&pal_bg_mem[AFFINE_BG_PB] + i, &pal_bg_mem[AFFINE_BG_PB] + i, 1, color); } } \ No newline at end of file From 3c79a35b92189b172d06aa3554cd735be80a9cda Mon Sep 17 00:00:00 2001 From: cellos51 Date: Fri, 8 Aug 2025 00:22:04 -0400 Subject: [PATCH 20/45] Redefined affinge background default color to use RGB15 and reverted grayscale of background image --- graphics/affine_background_gfx.png | Bin 2959 -> 2983 bytes include/affine_background.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/affine_background_gfx.png b/graphics/affine_background_gfx.png index 4abff4b34d35f12f2434af43a1683347f104c73b..7a567dc88ab88fa6a85a61877c8a4ab43c2946fd 100644 GIT binary patch literal 2983 zcmeH}e@qi+7{?ETP%$77(E&qjaQ*-k9U}$-FBYUAf`Tl9h(ESPL^nYJ3#IEJmLKAv z+1zB4;^7(wk(JINbAt7hO;O`G5urkaA~+8yLQAQ%<$AaGXtt4M0G{z?eS6G4y(l=6lkC~G|gjU0fWOY~N(XqQDt&DROatCF16 zBYw0&3DZ-C-?Zjwm2gTsIH()Ek|`jylmw&9(`neW3ZcnY1bkEIOHIR+0BOTfI!B}1 zttU40C-~p<5(jJ@Aml@0M}tvq^0F3EO%&@Ciq*rMenPIEUG@zj_J)z&g$ew&>%|7C zte7OfG6(vLh<@DedEhZ2b(xYhI^T5QXR_pjzk{B*EBl7~Xsu&k={Xd;082v?++MV^ zeM`kC_66(}n$XPgaB1mrxqxCNu$1$ZU-~#mBvT$HNf*-9sim*^O9kg?Zuxl>IY|$M zS5>Q`rkXZr#}Z76Ou4&1P?-}?tK2#2n7UQMG?pw#W-z8qrM!A@EkLx-pzt{;AJFOW zQT#ld+g13;9Sack-606H6P4Yo#>FjiGg-?BhVY9nW4$@t!Sc4CCId+}7#pVC2t65V z;1Oc)%`m;48oiAbu6LtNigu>K9rPt3L07>9xycyl2h*kIXpd8Sc-tD6$%3l)ED}=9 z(^AkU%N#3U%v`-0Mv{@mC}U{}j_+4`f+lh`{hj7NHDa(orJk!bg2_|}9Y(M9ljPKE zF3w~6Ca=9cDFEB~1-rhc_To56>I@qj=PPxUD6)(phJbbzp`QJ3~}P zBcUgXHA0!B&mPB-RHV#KdnT=S`0B=AiJy~rd@bXc6Z?i`h#nye494++9pjFD_9x?6 z<97p(IBRsO`{+fsul>Z38+i*yxCmeLgWj#0$4Zj7^LNYx zu9!O9{+j7eO6Ic$I0Ot>qA&hvvXm{P>P!_&@>->z*2JmXn|7T=u^-=L@C`IGGFd4$ zTCMT;NEqnY1WWTZm=#RxNvC;?@1k3b<7^G%Ba1P7b{RYK5=;XBhCSo~yr_p$WFmg6 zPKS;IaA!*PNO(~dFBqn?NLSbVJ}pTqCsN{BjA%cOI$1=~0M6y(#b6XlG{B%>Umd&3 zADAk9)YMS|$VIy91xcYp1*&G}*9=V$sgI2fDW9+uT2M^}ge01~OZJ+`)npGogWG4+ zXyWs}O5S_I;TzJkI1X39x$@)taL)pSN6irX0$)ZRWl6PimHSKsGF8}S%$dk&lb=I% z6FSvX)f1=MteSYn#mjo&O7m>+W8;+zQ42E*Gs?&Kp zLuMdZQIS8wz$Zp_C8f_GHz5~pD4t=|xLe_7k(tl>*>*Ct?nBC0SQ<5!LM@Qt(o9 zqXD8p(;Z$SMQfrsB3$*>0D)b`QmwLsdwAZ=(QY&teWw34A1!Qhi_#A{dZL~+F(6Cp zrv1HHw7Ul2@=p-XVpCgjm^s-J3u=TZqib6&L!Xh7I9ce^q-0v?Yehe|(6<%|FPK48 z4>Hptn)EwnJyDh|q;lp0axNg}0y1$fApb`JNz>0Bj(i)eD_a8ogrUf-F=6$b1Nnad DhT-E# literal 2959 zcmajh4Nwzj8VB&jQ%O-U_N1tYinQWKJv#+N#JC3$BRYs6$bd?uy(20WXaVsO$XW@0 zE2Gw)UuCsaK|G)*h!uoY)Z?I%6%jDDB%)}5gl=#NNno>k@0;}QnBnL#!)*4=vmbf# z%m3NK8#joYon|^A2;v;Nc6B6zIDnT92yY_TZ2h7r5$>f$ih>N}T~gdW$J0Q!8$~>Z$*@ixhhp1CE=zPWWl4WEHQjWqgbKLz532Ul4j;2+ z@o?Iod1Vb^*SaJ%!$eze@AA&V2lRZk_D53Oj4uv0`>J9+v(9^?m>-sS@O!_8X3x)> z@^Io5>LYwsEj;d&K)E!L;)i&w=d2o0k4Igz%va7jv5$D2`b~}To)@#%{YVm37(MrK z8+An{IBWK;lrQbj-J1;Wd+-H$;IZ^cZ!YQ{tP5Q%XIrhRYTCp3vKy=4@a(#oVZaS` z;R2bk`#3r?n0iUmWxZrXSDUuLAVcRwXUSPtYe4z^?5bp6xvr}Dp;jwy!plv|sdlms ztCDZ-w^(A{YA3S-h01IqE^Gq_L^C_B`Sce=PC75+~AyUTeEYa_QJK z94AWABP8r7IA57A4_p=W6`V>pQ~+)%!-`JJ|Gza6;8IoWf>rQ)Xd%C}zIPGlRBX3J z3C@cZe{eRRVwfcJ6#ogW^fx%>!CkI=A*}@;@3qGI316VGSlVey>Sr$-@)x@lYXecP ziao}o{O-8t%cI2m zCS>I`9)5h@m#|O4FJKq>X3)Qp%LT$8K0ZWI)OxpZDA!><=c?e`4YY>*O~-cL{TFt? z({G)zU)|3z?L%p;8;UYlqMVW4I@PvhGD!CDr1dndsmITGc6*Q{wiHXuy#$M_%(-8S z22y5^e|uuDoXxPRa%=>zyRo0~O1w+VmKc+SQfB%p;?3oO31twTo;-;S>YXq9vpaY- zM@f<>MnxyL;CXeFH7g228_+&-G4)h6n@eV1&Lf2|9>(OKd z6hXSWA)k47+6~Fz^0Hx{MGxF+jo-DX_+mO)(DRTaZlGSld+k9IXfyN>SA!VQ|Bb(@ zDXneZ3oUjE6$qc5@9O4PzVVkrWleZIM7SpR`^ppRh9cI)aC-ufj_K5xng!!NOJZnC&ENWKxoalPvFmmx;3wEmAb>sYh?mt zd9>X6AycT6xB{9VV9FO7;o0LDSFM5vJjC0mfU-LAO&UP&O6lc2l|~kW4g!v#$EJ~l z#!$%#JO3MyW7LeyQ-ABMXDRnA7Q8PHddjdC#_jKc><)0Ln>N}4uz$|3Nu@CM;@FO* z6Psa93b@jk99!8{jDCH|Mps83GQ{7n2A8M$$RfVj+;)0{M3~i7ZT!v+L(i%B8EnXYwe59w2g^;=XB z4C3%fAV|g?HEtjQH(7T&|7XJelmr2*@Y$XhJz}y$J|4cuN4ag*F!#IdF~gx(+M1=2 zM{)42je<8SAAMFR7U!5*wl*CMb4>>x8)PQH)vU~@fj-(Jarh0$S@MisTL~J|r?8o% zNLTyP6fnVU0JE8M_T)6Zm29>HB=H&cqHyj_&|K;eFwu?+>;wTkIHix^SOzxuOO{C3 zor_lgesB?h*T~MYNJuqb`YP|h<7zM*uMee7yKS^AVAP}tLJPr^`c%Bs{kWzoIUQym zt Date: Fri, 8 Aug 2025 00:32:30 -0400 Subject: [PATCH 21/45] Removed default color for affine background and changed to load palette from image instead --- include/affine_background.h | 2 +- source/affine_background.c | 9 ++++++--- source/game.c | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/affine_background.h b/include/affine_background.h index 12865d8..bb98067 100644 --- a/include/affine_background.h +++ b/include/affine_background.h @@ -7,10 +7,10 @@ #define AFFINE_BG_PAL_LEN 5 #define AFFINE_BG_PB (PAL_ROW_LEN * 15) // This isn't really a palette bank, just the starting index of the palette -#define AFFINE_BG_DEFAULT_COLOR RGB15(11, 18, 15) // 0x3E4B void affine_background_init(); void affine_background_update(); void affine_background_set_color(COLOR color); +void affine_background_load_palette(const void *src); #endif // AFFINE_BACKGROUND_H \ No newline at end of file diff --git a/source/affine_background.c b/source/affine_background.c index fd4a718..66ddb3f 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -10,11 +10,9 @@ void affine_background_init() { memcpy16_tile8_with_palette_offset(&tile8_mem[AFFINE_BG_CBB], affine_background_gfxTiles, affine_background_gfxTilesLen/2, AFFINE_BG_PB); GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); - memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN); + affine_background_load_palette(affine_background_gfxPal); bgaff = bg_aff_default; - - affine_background_set_color(AFFINE_BG_DEFAULT_COLOR); } void affine_background_update() @@ -40,4 +38,9 @@ void affine_background_set_color(COLOR color) { clr_rgbscale(&pal_bg_mem[AFFINE_BG_PB] + i, &pal_bg_mem[AFFINE_BG_PB] + i, 1, color); } +} + +void affine_background_load_palette(const void *src) +{ + memcpy16(&pal_bg_mem[AFFINE_BG_PB], src, AFFINE_BG_PAL_LEN); } \ No newline at end of file diff --git a/source/game.c b/source/game.c index f14c4ae..05f7a94 100644 --- a/source/game.c +++ b/source/game.c @@ -1994,7 +1994,7 @@ void game_round_end() tte_erase_rect_wrapper(BLIND_REWARD_RECT); tte_erase_rect_wrapper(BLIND_REQ_TEXT_RECT); obj_hide(playing_blind_token->obj); - affine_background_set_color(AFFINE_BG_DEFAULT_COLOR); + affine_background_load_palette(affine_background_gfxPal); state = 5; timer = 0; } From 54edefdc12b4acf7c953522ef5f7379e02574bb1 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 10:22:28 +0300 Subject: [PATCH 22/45] Added recolors to hand type jokers by @GreenNinja2525 --- graphics/joker_gfx2.png | Bin 1308 -> 1367 bytes graphics/joker_gfx3.png | Bin 1056 -> 1109 bytes graphics/joker_gfx4.png | Bin 958 -> 1032 bytes graphics/joker_gfx5.png | Bin 1028 -> 1058 bytes graphics/joker_gfx6.png | Bin 1027 -> 932 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx2.png b/graphics/joker_gfx2.png index b848ff050b5e0862ee7be521965d73530e348823..6379ffdc4cc8c3eb9fb12aadc78c61e59acc15cc 100644 GIT binary patch delta 1349 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 Hu0mjfH#`nB delta 1036 zcmV+n1oQjV2%rd%BYy+uNklB~LZA_QP)hIKyvSy@hh%nVHZ!}k+0`EW zVA!{B-t0H;?fiJNt3iNztK*3Daq;rS6HUeLF8K!(lsuamPk)rWadIZ@#Q)?^iHx(E zaS%d~D->N__3M|Rh;?0epGi9rhP&j~gBnuOTDcTRkSi3CD-@yY`al^Lcf}uQA$@?R zxdeu3;d*ic*OL=4Obdh%x5R}ie>J;t~)m0!3B zvYi0Dp~$`!)_K4i0fuP}yFaRtJ)57N3jeEaR=j++JT%nj)5Lo`I zeI>1D>!R>0Ez^GI!?3w_lh|57`GcJIqiSC%^M?jN3lg3P1TB z-qw%M062~VP4f;=>rZDu7Uuu}(|sM;?p+Tn`!Jdo;5dM$bn*>_pa1w#2h$RMz2X3k znEd`BNC*)Q$?n^{tD`cl^S6mJ1#X)^bQjRzwSS=tO5@}VdSxGEaSmj04tiyuvtirB z#clHoKZuAvM)-68^`|pjJv;x?&9-p-_77j{)=?rt-nXIVaPjaZ(2(&iMz=0Q4R1%eXw{WSRu2@GE74e&<<-ss7;NoU@@p zh<^)_^PIy}e|gH;B$f%*$|d)t2YAjOT%2=-4FVva22oKfm-y_CI)8b}7d8lxPXj-c zM!?j39_eNqKfm=dEqYBi+iq~!I`(KB7hE>@_YVMgS0+Pb>!@xhe*ZSaZZA}(h1GpN z`Vp9g4Z97h@`q)Cs{FzZ$U0=(b|7I=0e`qlex(i!3)KMFwjH~u@`rAN>^!22ieE?X z*?RVyUQ~>Xj6~*U??rkUly(6Xy`MA*)XF6xzldAbJ`749L{uK+cRq{7c>Is&k`B#{m)ThXYSMQ@qg#Jlm9-|K-KG#`}&0^;`hRWm2({4}V5e()ZRNSdifN!QUTF zTwVl`0LW!ha2yAPN|pM0zn&ry>$*<+T#FEjL-OlE4GF2;X$2A#DpeFJRp`3Dbw$OY z_ycSBcA#mLAa9tklXKX~Ir4@H$8qSjD`fe5iy3;0StNd60rH0F!>vKrG+M__&R6!| zj{x9F+g%{b-+x=oR=h`vNc_G6*qzoYz)lN}<3L+0zFaHI1`mMRLFuXj8GaHx0BWo9 z3nxK#5WprC*{8w=4{S0ZZcwmzOs{DZhu*e%G(zi^<_E%3iTUMx4V-tbp zmxT(y)HJ;ndB-ReTOy1VreR7hs}@ne++MxQhr_}V6Aq(0djLtmubinSsxULIL+k8L`KK($pbPWK=u6=}9x4M8~0nxzQKPY6E=el-E60`0qUO`2b7C&&g5 z0BRaHD g{2~E>|LE`We^^3}Cw+coDF6Tf07*qoM6N<$f}&;YT>t<8 delta 936 zcmV;Z16TZr2)+l9B!7iTL_t(&f#q2-Z{jc%{u1^60COv~BR8^e3*!F4<&aw4R-{XN zDIHMvlTd#FVrUN?44D}a{Rg01U}1!@mAdl>8k`&2XB^`sP6+AHPqJ{HpZ(d-&U?W4jB|@B>K9A8LS6zYEKDFzR=~7=!U< z@%5W!MREXq2Y;fDYZ9d4r+!JGbb{g}fXz`9cSR%zHalS1PHKns9{iC85MkL4O4q`` zogaaAv8{I5$jk^Lzb=ySYq{yI#mAs@eV>^xApWG#<&QOhYVp6N-B-y<*Y~L=uHu&= zAOA3!4u7IRJ--WD)pQ3i-9e&rJ5x%10MkTIq_ zlI!zRE`OsswaI;Uc?I^(9~%V>Z2FKxnaq|j-2qtr46J?@a7dQz1p4fXee)|5BC2GB zWjpB9H(vJX(`}&r_@%|`O}C(Y|0c7gRzf6<|K_3@)s>^&>uB?9-vnv#M<*p5os@9= z(n96%0hPlC9KW=<8~{4?6yYa^pBDe>0E?0Jn}3U@How+QP+U9!JU`BPo#fAt^MFoP zMvxZ|yzZoUO2lkWQX|9~VASuT=@$4iE&lm&9w?#_fbiEKDMtM++Pw~cro~TY%RrG+ zUSY3+46PF|^j2uP1=Lzk0Kk8nZh;#|Y$I7#Ct&EU(C&5kc=X%ub+~cFHd&Skau^cB z3xCzAh_bj_SlTd{H@|WMVH5H^FOo1T1LVmcx&yM+(;zDY`2Oo}PUa*1J^ml_yp$hflsMY}0000< KMNUMnLSTZ$vCaVi diff --git a/graphics/joker_gfx5.png b/graphics/joker_gfx5.png index c220cf3afff0372de36aad4d4383378845ebc418..70c21b6a059696696b1c518dc8f33262da3961d0 100644 GIT binary patch delta 1037 zcmV+o1oHcY2%-p(B!B5iL_t(&f#sP$NE|^F#=luY8cmrZUDfrn73#w8?|<$jqV0jC9R+|yydzZj z{?QrhyJ`@;nDh1E>$w6IgCGk467de0riszXY0LKQ%jZB~P1CGC?}Ff|M)Ebc7a26W zvE~YJ`w6N>@uf3>?_4TEpb_~@Hciv}eML2b@7N-lN;|Nf;S5@<UNQ`W8irA2SJ~Yg&39b_Z0)g#ihmXMT(k$>u)vRU z^FTQus(jA?I63d7uE7zH|7*LIozI)7`cFZMKJVQkoDJK5d#)1@yp z9p-KIo$+b3w{6;N?>;^B)u-nkklk35Msl&I*(xuL4P#;JyH#gFa7$oR<;33^uT1gw zwoMc-#;rOFf(l=024pwZY@H2hSGGYVQ)vu5Yjtd2tHl21BLh|Z-+$f);wygzcqQT; zNW|By+<%(E_I_Ok=`J*W@xp&!o&lhgf^eDFkah)MT3M@|9&{W%f*bCukle$_nDa|J59jDJX`(zc|B-}C_c`ajv-mTp4(M`zMo z8C5=?^zfS=0DL&zv&v0}d1b!RCdiyGo}N3lF&oMRf0s!#CdF$KAQP`(jztIOIqA_yWg$QS}0hxsxCJ1qtNo<4|@skAiUP8X!&7<}`^ z!$=rnSJXicL-poMXMpPe@KmK~ny)?^$(J35fdA;<9=n*mHP(C?=et#DmfV`ynlXvEgi&j@?VH$`D>4|vBG)-cfW{+KEcONw0 zbqUb5MHZ*J%*k5*Ss<_(x0KA7gy1g4??#yH10k!dIFB)q^tES*q3K24!TjsJ;6m zy+5p+{T1SKJ^Ww4KL+9}KLuE&l9Na!%XV&U!%ps9T16)r|Mt#*U!DOVgg|35uT-lE zZEv_!>wkQA94Bj|FfsrL0bH^*KXUR5@i}I>Ir$X;*>HR|6C;EW%d)sS&Cam<)3(tv zz2t$YdjX5>V&!wS;Xergs6rwiVMC_O(0`%6!iNu+DQ%&W|9~Y67h$(kH`Qa5j%0 zA`1fRJm+LBfkJ!^g*fo)<*p+*7s^3UPJ}kW&wzF!)Sjv&2`&-Znjeua1HYpD;`#;W zB!8O-0TmR{O@#8bgmf7=<-G(5LG|lCjOA4{Zn|c}aoYk@ZrlLXulvzF4jFz7-Bj2( zb!La%6gY-UWxjU+G_5@d8cjm@Yi_nEa)Cbc)n10!j%ZoaV47x+P1q)^`p8$>1gV@a zCMxx?67^>+uL_y$2@$n>jY0WkNLHt1k!LLm$@&tFDaiSQ@`;dJU3C8-g5YEZ8AG7g zVYW=cvZcVD(+81}$qEB5J0NwA!8hOeG7^R85p|H4p?>p)GeGq}JXPts?yJv1@`cZe c|LO1Xe>=G#Vb*@H!T!7nIJz`C78gyI zu8JJxTDJ^#v9)w6C4-puC>a9XT#S>mnnePQ(m|}Cv1kU7b}XTkyAJ2Q++E(gdoTCL z!5b`;I5g-_4qsQGbRaCEl(c2+dE5pDKV& zo>etsD;M=pH;_?=xJ5{kzsv7SHfdP$PLTw^uK?EpOaYwR?<$Zazv;X-clJ%gFigWR z%&EB-q#ebzxwCJ2`L3Fu`4j-!&z|>JvBz2VutBj0p|yX%+w4&XuB@tI zU2eK;)0h0|SAU;7=I086H0J@JknU-79$V zvX&=psk91n_BrX>B191f%0-==btlZF5@|1vNO-^3dVi&{Md0D*+5zRF?po|7zd2^N1&Mz(`BnVA^vva>UMJS8@}9hA9=W`arZ3q1ww zbGKbRfPayb(UotYE8l>TliTLRfjIajP%1*SVnkNeTuF~J=mEg5jTO@V+Ayd=XuEpA zRS{zGFVD32Pj0yRhYNG0t=@dZ&CeABi1VpYVtb;$1pur+xCa1G?mM5+%}CQ>+xh-f zx@D|e{5@aJ006xMgJh_9{GFRWPym0HU-QB;~O7vaePR|dItu%Mc__^*6O>i9U#4Vjf~w<@=){~8LOT*na4mB zHvjTW&9wuhz6E6ZthT9?(7QBC#x9Nzna98jt|LIQ!PB2DV?eNpIuWvh+lj;K<#!xG zPJibCfjr=<>Vk3eU;CP%?+&1qrM)&1U2K=hAH9*C@& kBtJ6-#BmcMNQ(bI+%yT`i+XCE00000Ne4wvM6N<$f@b5t#Q*>R delta 1005 zcmVOS(ix$_F5dL^mX) z29m(aPzi}Bm5?fxg`p&r44FZ)(hq=yl?9e`3u+gT$jk>Qv9CjN_MLsU&o6|be<@P# zxtHHPkI#3HZ3P0|+>VIIo>c1}))bj`^W=LB6s{F=sltuBdw<_ayd^&)YOED{R9VxWm?F0gXesMJ~zHkMwgA1i7P!;h?wk#{Wzoh2D z_ia(G)_vIia0*T8_?z-?ZbyV_<5P_gLWpUa#G2V&CKD1S(=>@`njX8%?mlmR;4MJ! zJsMH>RiX86dw<*w>n-?!0bo_G)}d?XF53(^dFJeu-M!R;!0}xi>Ue&iXGP&l-7F&K z0YKNzJ(B{a0b!4@q!Kw#Id12HX+UK8p#ku7K1}-L*>@w0B0uNDl;1y-;z!ypD@Kj) zyhWh)F8MZ@#VA8Yl6!2mcZs9-ybHtc(NF!woiA9dVN?SL+xwTE6X*%ENE8Jbdl%?^t~4 zQ-GCL$U!S~?A)5dtahBy(&HPP$NcvgBhGfvB-cL`MM03kp? zwiZPmet)Co&p*hbJna;p&t_tT5Mo&tSEkt+zCGDC`k&Uh`^3!z=fMx%0~9!Y=zVA0 z-Gdxtp`47NoQy#ZvRoUsPg1=$KYR~RoHW!vkK0WcXyK*^dqTxOYtXgXBzDp{0o?r4 z?HT{23FFSiZ#SWX^7qo+1a0R_SGKK4H#};)-hZ^~^wK%X)%1cuonKzbJI0450ARU0 zD<3;``r#1eYF&yS8UW6D#z~Z}FjyS{Xrb6{a>2p%W@pCDw)M}RsaY=|DuiZP6J?5VZ)W3v1zJNL;s?k&T+`{@yJvJVP7YCBQ~h00000NkvXXu0mjfNptS+ From a1c64ef5a66da14bb23a5f1006d50f43e5b6fbe5 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 11:24:18 +0300 Subject: [PATCH 23/45] Added sprite improvements by @GreenNinja2525 for Blackboard, Mystic Summit, and Fibonacci with minor tweaks --- graphics/joker_gfx10.png | Bin 1023 -> 1037 bytes graphics/joker_gfx2.png | Bin 1367 -> 1332 bytes graphics/joker_gfx9.png | Bin 951 -> 960 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx10.png b/graphics/joker_gfx10.png index aca51bc66d535bd70ac6c3ebc6ede6a4d5ac365f..8d5cbc1bd790509be8dd58d3504bfe1c450c6365 100644 GIT binary patch delta 1015 zcmVirj{{h$xYwq;ds^BFl0?Dpz(2JmZY#@}efj&3dVfuTko_ zPSzqq5;RYzg@2j?z>1iQ=g%%D0D#_J3!Tx}={gr29vz3CC)`$+IN3jleAmX(h+-7L zMuw9I5JrFx^1v$Wr3j`1N1(B0qY40+&KB1D7zF_0xz9tKlLuB2Ky!SGKu9WZR0nP= zOEeqR7;zHhn^FW51>lgxwD330^$95gFMcQc2bkiCynjn1I0=xJkk48`&~jXo=aHdB zf(C0B(1@7wpMylmie{r4dJuTZe;4wATmAzn+n^*gyt%{h<}PtgR!nCLOlJ!;8`Y33 zUj*@pkYgNDNQuN0An$Wh^qCVM-rS+b#^~KgDoke!pc3_RnA=z+wmz2{U|k6k0Zu}O zyi5t2?|-WfG#gc8h|9F#kw8(D1ZxqL1nB#4G)BK%jM;qdAEXC~9Ix~QTTL**xeap2 zJnuce`)+;Qdp3euSAwaEpbTrC8tZ6%grtp*ER2$Tt|BNwp6{27k>c24>97tFOnZQ> z>k>Zy_=0zM8?o_XnY#uMB(Z+E7#6;MxwvYHkALI7MQApvvAiep(#BVcx%UDDPKZ1$ z`#-n)P6t{KXoP}!0K8azrbzKx15D)ma_?_`phA1lrDqUZ(?(u z)&ZOddE3R72bz~TaT9s%x+G*e6xGNj9i63xMuJG&z(on>0cPLFF*`@@Q{g0NyGa-D zFbASJZ5o&21oHs*^D7kUJD~^~GVKM@B5-dyn7n5imtqv^J1g7n%h;G+W+nG_+NG#+XS0t#18-f002ovPDHLkV1mzS;UWM4 delta 1001 zcmV%C=B!9+9L_t(&f#q4TY8ycm9E%icVpk#HOnHU5DpA_^|kB!w_3tP?3zB~4U0Da0)A_TJv^=}u`fAY{MY)oJF< zd%Jhqfr9bR4z?z_hBs-ffa5I~rhjv1Q zz5QJyfN!*1pWHBoC||z&S;VK%|jkA853yI60^$=5Xytr3t1A zAYl{J?C+Xe1YFsa&98@cY%IhHK}|3#p(1-h8e-(F+JC1Ld}ZJjKqK#}e~G*zoE%h5 z1_^lvNFxt~)jyDN8?*@xmn#gHtJFE0g4v@8BrNN_*H~L##%*XqN~HDxW?zzG_9gM* zas>z%@ZGnQgn*fBw5sNWCke6cwcR0i50C^%g4VZ1kz<@+R5K(INm2^K_-wj}IU%G6 zcy|Gfz<+SL!caJabNZFCcWoBf8Fbm4V{$hLJq!hJgT!#TO4PX&qMP*tQy{bFBghir z-*R1=7@3-&ZEIN?MOxlQ+KrBMg;ow}4HC%c0A{*hDaV@Q>1b^1zYP&&cKJWBCi&_2 zcVMdD7KdQtlVHD6HchWzDVx5a&CLsK8#Ck;xPJuGkohFouapg8Vz^wHI8gjaP@V^D zMDs|EvmAWQFw;qp1WA~Xf)p(R>sRgs%)X1fy*3R&+n^MIpt4FUj*U zm<_Ez*zgL#lOMA=9F5U!HxuUo#=7k$y2$r@fSDs%yVkYL-^?bc)oZcwTD=w%@WtWt z#DBWX4v>QQVw*a^)!d?agj&58Bg(%e>=?`C{P1mJZcr1HM40W6SRQCumc(7;eSN{k zMh`_ba%qpwvO*(4(mqI0qIrbJ&*MZ~BKK3_G-!8|A&@o);x+9Wx5bI(5uWA`DAkXQ z2pTfq3v7bC<>1PmYupy2R6knBj$b9#ZerB|dEv^eZ%r0>ABbqsI=%MLREuXpNQak@ zO4B3bYE4BYy<@NklK`B1`~J*-^JmtA2JK&d9q8=iqVVZQmVZgTfAjqz1HJt5yEo|e z`k_X$8D}K>{+-RpkI=n;VLlgEEj3QgI@Y&NuD%oZSR`!Q7Uh$(PU!u1=m`V_y1hPbK70URNS^G}(?qg& z+(z%X9kQ$S(|>+Ak#04@&gb=3D>bZEYOrlPbR@nf^_MB=9k-ELDj>5|fZgqn+nj_* z0+uBRmdY-srgNB@&Y@Ix;rqTgjNTD-yHjv4NnRi6GS@T=EDbg|LCa*gV2NBzJDMOK$QKglj;Ma&}w)nm0h$N z9(>=2b=~8CU-v904?v87xNyAs}aT|U%aDvp%E#oFaD3x8zZ4Zh4_U$*)eSUAX zQZsgfk$(t|B5souM3sCJ=C*f?wIFgDq_d8QI{c$-QG%ETI`V4o>uht|JCQ=lG1fGA zuvNpsRyx%k2XCLr?>c;PABRuw$JR-L)&Uf^s?r0)p60}S<1#%5;zF(@YYF*i6vRI#QxTD9+3xzrH4}^MC7WD9+4^YpPFTIBE#+sgO@^)saBvmE4EY{d(t5 zQNB9e)5gDUKOj*90GT`&Iw}`uW~H)Qslu!80vX4o`9yH?vmbu~0H|M_i}IyXzH$4W z@xsU`6I97_!epmuknC=yI?y{qo{mszXjlLZS%zStsbtYY_S3%&c^9Cw~CL zFc=rDhKH-uJ#kIsFE7regF69;4g(djnP4{Kh-}cS?}j!#y!x(i4!=h>T1SkU2?E1) z|JCW9$Oh?rb-E{PegvzRolUMJ@A<+R`5D7fLr!$dP?XNSKKL5QoD%AY|UM6Qmg@SF{u|G-v|2Z1>5gU`nfARPD YKP|K`eNUtri2wiq07*qoM6N<$f?xlRSpWb4 delta 1349 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 Z{|!9h<4@gXzIy-w002ovPDHLkV1fb Date: Fri, 8 Aug 2025 11:29:19 +0300 Subject: [PATCH 24/45] Transparency fix for joker_gfx6.png --- graphics/joker_gfx6.png | Bin 932 -> 927 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx6.png b/graphics/joker_gfx6.png index 7b45d1f3f8eb1b75ba2ce8abab91da2973d49454..2a86ee5010aa0497a58263344bfb90e53811c9d8 100644 GIT binary patch delta 905 zcmV;419tqR2cHL!B!6Z}L_t(&f#sPoNE=ZY$NwjmmOz)bQt${R7DOD1MmV}OIu;jA zm#&H&0)c?R7wWX_9z(w-CT^5vzkQ$jnYA^ps~aZBJEg0DR&*t_i}f6FZV8Y zxeR^~eD8bD_j})$_rCk?iv)&j?;V;feNdTtJSvIIi;~}>Ab;?bG7>6$w|vCiL@)XM ztjPqPRyC?C=Jh}uNGT(96C!h?;`g=tCjt!$?^L4Tw{^gE5UvC4$FCRCGyeA8p=lU~ zX&8n%v+#np!}y3q_o(^IAV|c0_uStK8RzMPN)-II4sgTQk}>9nHvau?(T5$l(yE3{ zx#7^wUh$K!K7V)27Yc$b;{jkT8EY{fupAQR9cCF10Go27#dyGSh$!FF0X*ZqBrGTJ zjQ0{zC-`~{E>`|H`m&aTR9JWDp7r1Hv!pMXt>1F=&E*1?#+->|<`Efv;b&OfJp;)F2bKrye=yKWbAxj@@XV-nsUG=Bp;ae@e6=mZq=x?{1E3Dx10 zw5p+`z2nXgD(>}mrn4>l$-h53;tM|o?2=MOkWzG-TN9WWQO3;U?;QAliS+G&lL-~^ zT>Ywd+xk7E)bR*Psm>3^VB%8{r z#gBbC2LKEV4b!3g>33nirvn_uSNEF(iE)&k&VS-AfQR4mC|@+QHOm>{IKggwty-b_ zcp{0?`3$fKOm2O^<>@gU8yFfEc7kvsv{Bu6oB-*~Yotg=$wARGbgX>Q;9dj2Lij6l z6~_sX2D3;FT5VG)U|@Nkj$NJ}bFYD0gsuS125Uc?N{?U@b|Pd2w=Vn!7nIJz`C78gyI zu8JJxTDJ^#v9)w6C4-puC>a9XT#S>mnnePQ(m|}Cv1kU7b}XTkyAJ2Q++E(gdoTCL z!5b`;I5g-_4qsQGbRaCEl(c2+dE5pDKV& zo>etsD;M=pH;_?=xJ5{kzsv7SHfdP$PLTw^uK?EpOaYwR?<$Zazv;X-clJ%gFigWR z%&EB-q#ebzxwCJ2`L3Fu`4j-!&z|>JvBz2VutBj0p|yX%+w4&XuB@tI zU2eK;)0h0|SAU;7=I086H0J@JknU-79$V zvX&=psk91n_BrX>B191f%0-==btlZF5@|1vNO-^3dVi&{Md0D*+5zRF?po|7zd2^N1&Mz(`BnVA^vva>UMJS8@}9hA9=W`arZ3q1ww zbGKbRfPayb(UotYE8l>TliTLRfjIajP%1*SVnkNeTuF~J=mEg5jTO@V+Ayd=XuEpA zRS{zGFVD32Pj0yRhYNG0t=@dZ&CeABi1VpYVtb;$1pur+xCa1G?mM5+%}CQ>+xh-f zx@D|e{5@aJ006xMgJh_9{GFRWPym0HU-QB;~O7vaePR|dItu%Mc__^*6O>i9U#4Vjf~w<@=){~8LOT*na4mB zHvjTW&9wuhz6E6ZthT9?(7QBC#x9Nzna98jt|LIQ!PB2DV?eNpIuWvh+lj;K<#!xG zPJibCfjr=<>Vk3eU;CP%?+&1qrM)&1U2K=hAH9*C@& kBtJ6-#BmcMNQ(bI+%yT`i+XCE00000Ne4wvM6N<$g2vvz-~a#s From e615588e2954bd0be8630fb6ff4a37a76c48d725 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 11:44:16 +0300 Subject: [PATCH 25/45] Changed Fibonacci spiral border color to be more like the original --- graphics/joker_gfx9.png | Bin 960 -> 961 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx9.png b/graphics/joker_gfx9.png index a529d0aabb09ff9f7e6d695c61fed49028d8d4b2..d220413453e14c79968a237122309c80bfc9f20d 100644 GIT binary patch delta 939 zcmV;c162IL2f+uBB!7rWL_t(&f#sP&YZE~f$NwEg2p;?d9$FftTD*9u1WP0KB8ZfN zMT&f zi25IX@i1`h#PA#C{++=CVgDyZjYozCKqrZ1CL;Y;M)vbLPXyod$^JkH@r>SFwWT*Egn$r&vFV&w=6^acqjilBL+AkvnE|c! zW79eB$a{*a0Dtvj*(>*R=PnumfOI9LbYBrt0mi0t!Z+W}C|M}Pp07!B0H6T+xOz4VFb^nLhPDVDv#gV%r7J09nwc7U_n#}&?wSG;oPmaknQdo9*O=%OP+Bmqok z2V3<6Jh*VRZQI9R-UC3_MNlR7NcHs9v(V$eMkE33mE+i7oLLAxviAIdnFRG>8E&TG z`|+sG3V*Q%L7@4j7iSiv$0WFM=92GxIX55327zWiz;XrvsArB-=pTEx1MT+)9|h`S z3lPNvba{92zE^fL4HPURkPQOOM93_beImpq))?@y@eP1H{@HaPnLL3vK5v%*G>y*N zCFJdr=kol=Q(TnNwNAc$87vG;!@{Yf!^G|zD}MyG>IeShTy#Al__v>~qo&dhjpsP!XhByclc_mL_Z=2qK}> zM1zMA(h_?qg@_kH1TWG;=|y83LQY!~N(o*h&?PCoq%|i|OQEzk{{tfkjvmt4&SrP^ z*KDKW2VrL3%+Bol_PsYRGXtg4O ztv~kqnW^v0*jwN0H%Im@*FS4Dczkpilu}I2%<8g@l~=Y45JEsHwUo0t83|5c%9C)w3c*K3&mCFub4W0YZqbbgftrPD}^^Aq4SkPOtMn88D?~mA8YX1u%#d=#|H_ zIlbg9#V-Ntv46Z?PjKxD+5muLC**5hD+mdQXLFWc-bpEuD|msbl~5}d5YOh2cyJS{ zRxe?<+O2*L72&pLYB-pwD zvjACN_KKetOQfWaIgO83fj2c~l15h98e)Cxn!e z>AFErpMM=ZZ-Yy#%b1^@6P7{X&V?I>b~+q2WrIL>8)P{HU`(NZZr?YJ-yV5xl6fY; zjRnZ!{q@Isy)xK_s+COHAaI-!#_|Rdyuwoq`0)KJ0I~nGeju1UfmgoV>IPR;E1}$K zpxkQcCeMF)uke+wo#xjUfw@6S$>7|#qrm3%!%@RF$6JOhJX^rfM8vUvT3{(J ztMgco<$YPjUuyv(Bs-zNlm~ne&`%5C-M}jQs|>cKln44?0kSDEPXbQ_+a;Wo=a1H{ z;D0&>9Bno+G!b#M0G;}yDCue4*?+N^X`M$3h zu(h)%eL31|_HOS50pLmME?%ndq}J~>`y=f~=D)&##qBWge_fCN2CQn`QPz45kpKVy M07*qoM6N<$f>49GL;wH) From ecbfd97de175c55e0c3af3d8452bbbd03580ffa4 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 14:47:45 +0300 Subject: [PATCH 26/45] Added some documentation to memcpy16_tile8_with_palette_offset() --- include/graphic_utils.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 695c388..8160d81 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -122,7 +122,11 @@ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direc /*Copies 16 bit data from src to dst, applying a palette offset to the data. * This is intended solely for use with tile8/8bpp data for dst and src. + * The palette offset allows the tiles to use a different location in the palette + * memory + * This is useful because grit always loads the palette to the beginning of + * pal_bg_mem[] */ void memcpy16_tile8_with_palette_offset(void* dst, const void* src, uint hwcount, u8 palette_offset); -#endif //GRAPHIC_UTILS_H \ No newline at end of file +#endif //GRAPHIC_UTILS_H From 31ba1f166ca29d9888ac102a217e91c1bb3ebab5 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 8 Aug 2025 15:03:18 +0300 Subject: [PATCH 27/45] Added some documentation for affine_background_load_palette() --- include/affine_background.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/affine_background.h b/include/affine_background.h index bb98067..1b9ca4e 100644 --- a/include/affine_background.h +++ b/include/affine_background.h @@ -11,6 +11,7 @@ void affine_background_init(); void affine_background_update(); void affine_background_set_color(COLOR color); +// Must be called with an array of size at least AFFINE_BG_PAL_LEN void affine_background_load_palette(const void *src); -#endif // AFFINE_BACKGROUND_H \ No newline at end of file +#endif // AFFINE_BACKGROUND_H From ab91438a0dd2c5fc63028556157f52dcc6c61467 Mon Sep 17 00:00:00 2001 From: Wheeler <118409873+GreenNinja2525@users.noreply.github.com> Date: Fri, 8 Aug 2025 08:32:12 -0400 Subject: [PATCH 28/45] Change "A" in Zany and Wily Joker for consistency --- graphics/joker_gfx3.png | Bin 1109 -> 658 bytes graphics/joker_gfx5.png | Bin 1058 -> 620 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx3.png b/graphics/joker_gfx3.png index 959c457b1bc5e5ebe79bf7434c8141042f747e48..3f70877572db0b72b8dc61519961e2eb25a28f58 100644 GIT binary patch delta 644 zcmV-~0(uw3j{qq0<@N&5vuho=OgPjGq8`?(8L&P8 ztTbAH#VY_aCVln_fY-+WSg--``lQd;0Mh!MQ0~H5=rbySWmw?>2e8Ya0_Jfggatc~ zEx?@aT%`xi4qV359m`$l9hXpUflnPaMj{WaJ@w8a@_)285<&igesq~$Y@>P5_H=MS zF>AAp{Tg)ZGCcu~2T)#@2`-aCp0of}Pk_%G)zEbpm}tD*8o)C> zccMu~ks>Hg{H5`{`KWQC0k%RogwQzA!YYUA#BDw7gxW}9G3YOg3zlJ1TUgO z4^^y`N-YQ;4GS$4iWZGEtX{l$C?3T_1y8N6vO*D|P(k)uDwu*STR{&6xAb74)Ts*gn2_*%sKgZE?>= zC$u_Bz8!ZVhn9+kSU_$%kKA+~wr#f@?dqubu`MERU|9m-xE}V0`msOM56AVu7!yZY zneyibx-mD<-G3H8G60V2MX)W{mL=Nk5A_28ddlknAPw6zGUd+=bOQh$e*e=JKQaKN zVgZipp;Rn@F$Sv<@xP78Qs)7Pa@=rDA`?D$9)Kt(O9aK0ZI9>0ibeR53@4|;{1Ux*VDS(bUw2nP=Ed+>lNp}QIqOvT@t?0G#z$c zr`ef<%;o~lrw;10$a;)%em1>LKuT+EUZ|7U= zR3@7&9e-#3Q6zt7{!wDSb`?;qt0RNwFfv#WxixR|^v7rIwMmtP|LdFn+OV_%2!a5X z)!aZmxiAVgH4Xr{+OV-#hrcTeOK{2_5Cnjw-GBKSDa`+Q@g7b^@cR~)05>H+JOmkI z$|3pp_L#8oGOr6?ljafVG+(<4SmfOVpHNoUHefF-flZBrO^w4|Sd!XU8NScxG{0q> z_?2p)dKnSU{hwSImFns9-&0;!K7Xrg8``%*aeSH&e7%25s=xgDohVP(yT*K@RG2z{ z#TOk3mwEiUldVGK z!ZI2G!;@p^DX-(p`wsvhetXL6A~>{;Zhwu_ie`hkooxURzcfRnb==k#KfDal<%O5| zL2b`Je~Qh*+Fb@s`MNC7l&|bSREO&IdMq%j030RXr~~cFGywH_J@sMA*DizfIpUK_ z*v8LkJ$GStLS^>qIH< zqhdu}uj_-+GN=NCZJituDi-C%jR5|!BudJ?0MN0IlSX@iqvR_)^FMta{|BJ3qH$C^ Rf205a002ovPDHLkV1kBR5NZGb diff --git a/graphics/joker_gfx5.png b/graphics/joker_gfx5.png index 70c21b6a059696696b1c518dc8f33262da3961d0..620086af1a2728cddb2e82d6271bccc2dc3eb1bc 100644 GIT binary patch delta 606 zcmZ3)@rGrBWIZzj1H)A3zHLB?u{g-xiSg!1oq8aLv%n*=n1O*?7=#%aX3dcR3YrD@ zgt!9f11GNi|NsB*-@pFJ>3{!$!Tvfx?0d>SC`7Z7%Cuu%iCB>VpXtnc2Sk zS|-h7NNG)DZ7nn8ak!R|mT|$ajq%3Mh3R5*8Q=U_;BUqJ0DN?zub(2G!+v3 zrqkcBjH4oQZz|(;-kasxJe%s@8asIUGv3I%%WzlWYw2T#HFAvc{yvwZOAH?5e?P;Z zYWvoO)$FwSefLQ9q(=5=))}VE6Sx?+M1R=!z-psmp7_PIc{BY&wp_o$EL9{>schQT zB53s}f=T=!f57f3$_2eg+zQ$Szg={yXPWZGwyC<`PrzrsYruueek#k~w+qh<*ZS~l zp35DDm!)hT|ILc{DxT!0mN(d{ZkH}CNn(6>l7(U0M4JOvMzsqPufJ5y^YSieH;fUw mtmre(#qIz6{@3w#@Aq%K6>L!Qv;~xE7(8A5T-G@yGywpD4i@16 delta 1048 zcmV+z1n2wg1fmF#8Gi-<005$$euMx31L;XbK~!jg<(WT796=Puzga>WO_?HK3JnqT z;IKG2web7{DJ;xkX{i^zXpzRG5D6kl3cc1S(O6oB!y=7DR|9f_g&cUoNwn}FMQR)4 z?xZ+pZ+32WcXn^@Eb@Uk^LBQA^PV%aZ$<(^daeKfRJ4aA(tqFG>Dfrn73#w8@9rd` z?SZ5n1%O1nBUJeQ(HZNzY7o4b^Y!5CxdIh~APWEz@eY`#iP6bv%l7Td=Rjah)2u%4 zg5aq}@-?>?88o}G<_d88393f%r89u z_sZ9E1cU=N(?Xif8e--vzvH|7*LIozI%}&h_B3N* zY}jTy+1>Wjr7txd=56(z@oBWTZQ5+_K0Wl+r{^A!-B^=GaDu^wCPpcxrfJ&hEIY&Um1SdP_Dp;yXeQVQ zzULl5xVsUy?)Hz)KxbP(G9{2q33Rr_)`o<5pMO$se$_nDa|J59j7X-^wxoyO^Z@(% zKiS=uZbJJ1Y^dDQ#W)M^6dj^1azCH5XvKLR!F*Wi60Pw?n3hna1dS$OY=mS33;x9kDVYFn Date: Fri, 8 Aug 2025 09:54:24 -0400 Subject: [PATCH 29/45] Converted void to u16 in functions --- include/affine_background.h | 2 +- include/graphic_utils.h | 2 +- source/affine_background.c | 4 ++-- source/graphic_utils.c | 7 ++----- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/include/affine_background.h b/include/affine_background.h index 1b9ca4e..8e5f78f 100644 --- a/include/affine_background.h +++ b/include/affine_background.h @@ -12,6 +12,6 @@ void affine_background_init(); void affine_background_update(); void affine_background_set_color(COLOR color); // Must be called with an array of size at least AFFINE_BG_PAL_LEN -void affine_background_load_palette(const void *src); +void affine_background_load_palette(const u16 *src); #endif // AFFINE_BACKGROUND_H diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 8160d81..79e0c61 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -127,6 +127,6 @@ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direc * This is useful because grit always loads the palette to the beginning of * pal_bg_mem[] */ -void memcpy16_tile8_with_palette_offset(void* dst, const void* src, uint hwcount, u8 palette_offset); +void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, u8 palette_offset); #endif //GRAPHIC_UTILS_H diff --git a/source/affine_background.c b/source/affine_background.c index 66ddb3f..08ab9ee 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -8,7 +8,7 @@ AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0}; void affine_background_init() { - memcpy16_tile8_with_palette_offset(&tile8_mem[AFFINE_BG_CBB], affine_background_gfxTiles, affine_background_gfxTilesLen/2, AFFINE_BG_PB); + memcpy16_tile8_with_palette_offset((u16*)tile8_mem[AFFINE_BG_CBB], (const u16*)affine_background_gfxTiles, affine_background_gfxTilesLen/2, AFFINE_BG_PB); GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); affine_background_load_palette(affine_background_gfxPal); @@ -40,7 +40,7 @@ void affine_background_set_color(COLOR color) } } -void affine_background_load_palette(const void *src) +void affine_background_load_palette(const u16 *src) { memcpy16(&pal_bg_mem[AFFINE_BG_PB], src, AFFINE_BG_PAL_LEN); } \ No newline at end of file diff --git a/source/graphic_utils.c b/source/graphic_utils.c index 890cb33..931f674 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -168,14 +168,11 @@ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direc } } -void memcpy16_tile8_with_palette_offset(void* dst, const void* src, uint hwcount, u8 palette_offset) +void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, u8 palette_offset) { - u16* dst16 = (u16*)dst; - const u16* src16 = (const u16*)src; - for (int i = 0; i < hwcount; i++) { // Copying u8 data twice across u16 data - dst16[i] = src16[i] + (((palette_offset) << 8) | (palette_offset)); + dst[i] = src[i] + (((palette_offset) << 8) | (palette_offset)); } } \ No newline at end of file From 6363613f15d125f9997687ebb0bbc59bf4b59db7 Mon Sep 17 00:00:00 2001 From: cellos51 Date: Fri, 8 Aug 2025 10:44:55 -0400 Subject: [PATCH 30/45] Added & back to the tile8_mem in affine_background_init() and changed memcpy16 to 32 --- include/graphic_utils.h | 9 +++++++++ source/affine_background.c | 2 +- source/graphic_utils.c | 13 ++++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 79e0c61..8f75cf3 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -129,4 +129,13 @@ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direc */ void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, u8 palette_offset); +/*Copies 32 bit data from src to dst, applying a palette offset to the data. + * This is intended solely for use with tile8/8bpp data for dst and src. + * The palette offset allows the tiles to use a different location in the palette + * memory + * This is useful because grit always loads the palette to the beginning of + * pal_bg_mem[] + */ +void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint hwcount, u8 palette_offset); + #endif //GRAPHIC_UTILS_H diff --git a/source/affine_background.c b/source/affine_background.c index 08ab9ee..f9e15e7 100644 --- a/source/affine_background.c +++ b/source/affine_background.c @@ -8,7 +8,7 @@ AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0}; void affine_background_init() { - memcpy16_tile8_with_palette_offset((u16*)tile8_mem[AFFINE_BG_CBB], (const u16*)affine_background_gfxTiles, affine_background_gfxTilesLen/2, AFFINE_BG_PB); + memcpy32_tile8_with_palette_offset((u32*)&tile8_mem[AFFINE_BG_CBB], (const u32*)affine_background_gfxTiles, affine_background_gfxTilesLen/4, AFFINE_BG_PB); GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap); affine_background_load_palette(affine_background_gfxPal); diff --git a/source/graphic_utils.c b/source/graphic_utils.c index 931f674..1d5bcb2 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -170,9 +170,20 @@ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direc void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, u8 palette_offset) { + const u16 offset = (((palette_offset) << 8) | (palette_offset)); for (int i = 0; i < hwcount; i++) { // Copying u8 data twice across u16 data - dst[i] = src[i] + (((palette_offset) << 8) | (palette_offset)); + dst[i] = src[i] + offset; + } +} + +void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint hwcount, u8 palette_offset) +{ + const u32 offset = (palette_offset << 24) | (palette_offset << 16) | (palette_offset << 8) | palette_offset; + for (int i = 0; i < hwcount; i++) + { + // Copying u8 data 4 times across u32 data + dst[i] = src[i] + offset; } } \ No newline at end of file From 6007071b7db0b1d0f6d2e9658147d16dc118ff6a Mon Sep 17 00:00:00 2001 From: TheBreadPerson Date: Fri, 8 Aug 2025 14:04:09 -0400 Subject: [PATCH 31/45] Complete refactor of naming conventions for memcpy --- include/graphic_utils.h | 2 +- source/graphic_utils.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/graphic_utils.h b/include/graphic_utils.h index 8f75cf3..2e80828 100644 --- a/include/graphic_utils.h +++ b/include/graphic_utils.h @@ -136,6 +136,6 @@ void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, * This is useful because grit always loads the palette to the beginning of * pal_bg_mem[] */ -void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint hwcount, u8 palette_offset); +void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint wcount, u8 palette_offset); #endif //GRAPHIC_UTILS_H diff --git a/source/graphic_utils.c b/source/graphic_utils.c index 1d5bcb2..b568442 100644 --- a/source/graphic_utils.c +++ b/source/graphic_utils.c @@ -178,10 +178,10 @@ void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, } } -void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint hwcount, u8 palette_offset) +void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint wcount, u8 palette_offset) { const u32 offset = (palette_offset << 24) | (palette_offset << 16) | (palette_offset << 8) | palette_offset; - for (int i = 0; i < hwcount; i++) + for (int i = 0; i < wcount; i++) { // Copying u8 data 4 times across u32 data dst[i] = src[i] + offset; From 08689d41eaf46d81c40ce7feee79909cdcd22a28 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Sat, 9 Aug 2025 08:32:11 +0300 Subject: [PATCH 32/45] Revert "Fix "A" in Zany and Wily Joker for consistency" --- graphics/joker_gfx3.png | Bin 658 -> 1109 bytes graphics/joker_gfx5.png | Bin 620 -> 1058 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx3.png b/graphics/joker_gfx3.png index 3f70877572db0b72b8dc61519961e2eb25a28f58..959c457b1bc5e5ebe79bf7434c8141042f747e48 100644 GIT binary patch delta 1099 zcmV-R1ho5-1=R?U8Gi-<005$$euMx31RP03K~!jg<(WZf)Ib!5|D>YOg3zlJ1TUgO z4^^y`N-YQ;4GS$4iWZGEtX{l$C?3T_1y8N6vO*D|P(k)uDwu*STR{&6xAb74)Ts*gn2_*%sKgZE?>= zC$u_Bz8!ZVhn9+kSU_$%kKA+~wr#f@?dqubu`MERU|9m-xE}V0`msOM56AVu7!yZY zneyibx-mD<-G3H8G60V2MX)W{mL=Nk5A_28ddlknAPw6zGUd+=bOQh$e*e=JKQaKN zVgZipp;Rn@F$Sv<@xP78Qs)7Pa@=rDA`?D$9)Kt(O9aK0ZI9>0ibeR53@4|;{1Ux*VDS(bUw2nP=Ed+>lNp}QIqOvT@t?0G#z$c zr`ef<%;o~lrw;10$a;)%em1>LKuT+EUZ|7U= zR3@7&9e-#3Q6zt7{!wDSb`?;qt0RNwFfv#WxixR|^v7rIwMmtP|LdFn+OV_%2!a5X z)!aZmxiAVgH4Xr{+OV-#hrcTeOK{2_5Cnjw-GBKSDa`+Q@g7b^@cR~)05>H+JOmkI z$|3pp_L#8oGOr6?ljafVG+(<4SmfOVpHNoUHefF-flZBrO^w4|Sd!XU8NScxG{0q> z_?2p)dKnSU{hwSImFns9-&0;!K7Xrg8``%*aeSH&e7%25s=xgDohVP(yT*K@RG2z{ z#TOk3mwEiUldVGK z!ZI2G!;@p^DX-(p`wsvhetXL6A~>{;Zhwu_ie`hkooxURzcfRnb==k#KfDal<%O5| zL2b`Je~Qh*+Fb@s`MNC7l&|bSREO&IdMq%j030RXr~~cFGywH_J@sMA*DizfIpUK_ z*v8LkJ$GStLS^>qIH< zqhdu}uj_-+GN=NCZJituDi-C%jR5|!BudJ?0MN0IlSX@iqvR_)^FMta{|BJ3qH$C^ Rf205a002ovPDHLkV1kBR5NZGb delta 644 zcmV-~0(uw3j{qq0<@N&5vuho=OgPjGq8`?(8L&P8 ztTbAH#VY_aCVln_fY-+WSg--``lQd;0Mh!MQ0~H5=rbySWmw?>2e8Ya0_Jfggatc~ zEx?@aT%`xi4qV359m`$l9hXpUflnPaMj{WaJ@w8a@_)285<&igesq~$Y@>P5_H=MS zF>AAp{Tg)ZGCcu~2T)#@2`-aCp0of}Pk_%G)zEbpm}tD*8o)C> zccMu~ks>Hg{H5`{`KWQC0k%RogwQzA!YYUA#BDw7gxW}9G3WO_?HK3JnqT z;IKG2web7{DJ;xkX{i^zXpzRG5D6kl3cc1S(O6oB!y=7DR|9f_g&cUoNwn}FMQR)4 z?xZ+pZ+32WcXn^@Eb@Uk^LBQA^PV%aZ$<(^daeKfRJ4aA(tqFG>Dfrn73#w8@9rd` z?SZ5n1%O1nBUJeQ(HZNzY7o4b^Y!5CxdIh~APWEz@eY`#iP6bv%l7Td=Rjah)2u%4 zg5aq}@-?>?88o}G<_d88393f%r89u z_sZ9E1cU=N(?Xif8e--vzvH|7*LIozI%}&h_B3N* zY}jTy+1>Wjr7txd=56(z@oBWTZQ5+_K0Wl+r{^A!-B^=GaDu^wCPpcxrfJ&hEIY&Um1SdP_Dp;yXeQVQ zzULl5xVsUy?)Hz)KxbP(G9{2q33Rr_)`o<5pMO$se$_nDa|J59j7X-^wxoyO^Z@(% zKiS=uZbJJ1Y^dDQ#W)M^6dj^1azCH5XvKLR!F*Wi60Pw?n3hna1dS$OY=mS33;x9kDVYFn3{!$!Tvfx?0d>SC`7Z7%Cuu%iCB>VpXtnc2Sk zS|-h7NNG)DZ7nn8ak!R|mT|$ajq%3Mh3R5*8Q=U_;BUqJ0DN?zub(2G!+v3 zrqkcBjH4oQZz|(;-kasxJe%s@8asIUGv3I%%WzlWYw2T#HFAvc{yvwZOAH?5e?P;Z zYWvoO)$FwSefLQ9q(=5=))}VE6Sx?+M1R=!z-psmp7_PIc{BY&wp_o$EL9{>schQT zB53s}f=T=!f57f3$_2eg+zQ$Szg={yXPWZGwyC<`PrzrsYruueek#k~w+qh<*ZS~l zp35DDm!)hT|ILc{DxT!0mN(d{ZkH}CNn(6>l7(U0M4JOvMzsqPufJ5y^YSieH;fUw mtmre(#qIz6{@3w#@Aq%K6>L!Qv;~xE7(8A5T-G@yGywpD4i@16 From 3260769023984bbd0843ea15ee17b2b6dda22ef6 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Sat, 9 Aug 2025 17:35:17 +0300 Subject: [PATCH 33/45] Card corner fixes --- graphics/joker_gfx10.png | Bin 1037 -> 1033 bytes graphics/joker_gfx4.png | Bin 1032 -> 1000 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx10.png b/graphics/joker_gfx10.png index 8d5cbc1bd790509be8dd58d3504bfe1c450c6365..c5b269d53e3b420efec0a410ee0a8a77ea7ee550 100644 GIT binary patch delta 950 zcmV;n14;ai2#E-gB!AFJL_t(&f#q2}Ya2ljeHJNHS%ne8=%aEK6QWX;QM%v+H3C)o z0q#_#OMjbGZ{%rwr{O$m3E zWz4?3{;iJxO#2fef8K3}w$5mr>4Ervk_a{s`NN~*(02Io1ArAl4o-IKri8)8DNgne zVj`5bH$xFP3P}$_q;2HSyX}ZrzCffo`N73$W}^xKn9df~af|{0@!aPj&dCF-2%tVb zMIa;uYK%Au@=Ym%i2`s)Vp{l{`uc8@}Gl5$ckp88hQ|T%6}K~fLs0pDW^e6Xn1>%;q855pRAb9 z7MRW!Xf~=LS-uG35h2?+q>vJcDL~%mr06>*KD@n0kG0X&M=DHb3!oD9a+up#Bu;%U zHNd(OBm$g-40)Ln)ZbSfXf~?G5SMAeBY~nQ3DzPg34hS<;b@G0xfrwg+&@SU5;LVm=bYx+aj8~WFb{witM3#kUTc7fe7{_bd`J*JGx%5(g_WPp1myi- z9>n^~6CxX&ra>+Ok=G)C+LQ1C9e*)+sMTu`qV%0Z+9+KHuiwP_I;{gZ5%RW+Ee|v=bK)lQ z+I>mLbSSEkOFBAB3ylPkwt@7-+0($K z!gFx)5A&<=TBz?B?@=Sbirj{{h$xYwq;ds^BFl0?Dpz(2JmZY#@}efj&3dVfuTko_ zPSzqq5;RYzg_9fs6B0TX93CBqo+sQ^mN?lzhWBxx?`0E^$s)OlJ#BXA3kN)sQS- z1o4QFV;oXQiNq8j?{iZ0nG+x0+@Z(D=-o#uOlJ$A67_PJ+gK#FK9?F`T?rBaPC|yf zObMFrs}3|9Rbz#!? z?>)ZzZhhQ)HiB7Kf~kt23~Qbm>u7z1q>YX&jFNn=A}B$g@0W{_;@Dy7unrMSdw{L$ z5v3|K27QTMDxN3=y?FG^z zZ#tN~XBwAc6zV%G+wRNQwQG%lyfAszc1;>s4@5L*m0mkE)$D2DQsFr``TO}*_+F^* z7_U(yz~vd9%x~@7fbSMvp9=y&R|!=cw6Lca0JQ}I%9Gmv?eX|ub{pFSn`Xoh00000 MNkvXXu0jG}f(g^M)Bpeg diff --git a/graphics/joker_gfx4.png b/graphics/joker_gfx4.png index f492a3f5837d2489d4318bec503a03a5e3d9ae08..76dd5b964245bb179705d0d408ed5a4fa0e583f4 100644 GIT binary patch delta 978 zcmV;@11A0Z>_$Uswd$NdTKvWS#z@liF$X+u8+h2U`Y+I>XODqU1zbsVvrONb{^AX5iKO|NQ2)`<1 z`6B}$a{iWk`XXKS`XScDMf^PY^bgX>@GC9UlY1_zcYl_5h1u*8y48bj^>!O0tdUgu z$$gDFMxQk6_*y1y#GdR8;)1XAz~)J_juTmAtIR(bOeN~~t@BC2bj|_n8y3n-E z2h{N6cYow77XX0#T1SX=s|Oe+;JSb&_2nB0p8wC)-G2G`6m%R%n3AjVIn@!FwDEm* zc?I^(AGr!>*z_RCK(5 z{q&_l<+_y;zJJ5p; z(x7?(XjNh?KN0-Id9MIwLgkywx-`GkPLOpT0G=NwR3`f8$BEA-sUYyq1KyKlvxGhE zQ4K<50PJoXbt^^hiSy5o6W_%K0SJB#RAG19Xm(oko;W`o&wLkuV9ko-~;h>N5G;JV&sCuqZ?!Y_3q2Z#ueB!ACIL_t(&f#q4hZ`wc@eYR4mGb@RdjAUdX3nFuuQlw-BwT3!m zK$*G)m9-|K-KG#`}&0^;`hRWm2({4}V5e()ZRNSdifN!QUTF zTwVl`0LW!ha2yAPN|pM0zn&ry>$*<+T#FEjL-OlE4GF2;X$2A#DpeFJRp`3Dbw$OY z_ycSBcA#mLAa9tklXKX~Ir4@H$8qSjD`fe5iy3;0StNd60rH0F!>vKrG+M__&R6!| zj{x9F+g%{b-+x=oR=h`vNc_G6*qzoYz)lN}<3L+0zFaHI1`mMRLFuXj8GaHx0BWo9 z3nxK#5WprC*{8w=4{S0ZZcwmzOs{DZhu*e%G(zi^<_E%3iTUMx4V-tbp zmxT(y)HJ;ndB-ReTOy1VreR7hs}@ne++MxQhr_}V6Aq(0djLtmubinSsxULIL+k8L`KK($pbPWK=u6=}9x4M8~0nxzQKPY6E=el-E60`0qUO`2b7C&&g5 z0BRaHD g{2~E>|LE`We^^3}Cw+coDF6Tf07*qoM6N<$f=DRrhX4Qo From 3441a1dae83b86959c8df2729e7e5d847723064e Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Sat, 9 Aug 2025 20:48:18 +0300 Subject: [PATCH 34/45] Joker pooling - Existing or owned jokers can't appear in shop + shop code refactor --- include/list.h | 10 +- source/game.c | 421 ++++++++++++++++++++++++++-------------------- source/int_list.c | 29 +++- 3 files changed, 274 insertions(+), 186 deletions(-) diff --git a/include/list.h b/include/list.h index b3ee749..64341f7 100644 --- a/include/list.h +++ b/include/list.h @@ -3,6 +3,10 @@ #include +/* Defining an int list for simplicity + * If another list is needed, a generic void* + * list should be defined.... + */ typedef struct IntList { int* _array; @@ -12,8 +16,10 @@ typedef struct IntList IntList *int_list_new(int init_size); void int_list_destroy(IntList **list); -bool int_list_add(IntList *list, int value); -bool int_list_remove(IntList *list, int index); +bool int_list_append(IntList *list, int value); +bool int_list_remove_by_idx(IntList *list, int index); int int_list_get(IntList *list, int index); +int int_list_get_size(IntList *list); +bool int_list_remove_by_value(IntList *list, int value); #endif diff --git a/source/game.c b/source/game.c index 05f7a94..9ec5d81 100644 --- a/source/game.c +++ b/source/game.c @@ -23,6 +23,8 @@ #include "soundbank.h" +#include "list.h" + // This seed system is temporary. static uint rng_seed = 2048; static bool seeded = false; @@ -171,6 +173,8 @@ int get_jokers_top(void) { return jokers_top; } +IntList* jokers_available_to_shop; + // Consts // Rects left top right bottom @@ -998,8 +1002,21 @@ void game_set_state(enum GameState new_game_state) game_state = new_game_state; } +void jokers_avialable_to_shop_init() +{ + int num_defined_jokers = get_joker_registry_size(); + jokers_available_to_shop = int_list_new(get_joker_registry_size()); + for (int i = 0; i < num_defined_jokers; i++) + { + // Add all joker IDs sequentially + int_list_append(jokers_available_to_shop, i); + } +} + void game_init() { + jokers_avialable_to_shop_init(); + hands = max_hands; discards = max_discards; @@ -1818,41 +1835,6 @@ static void game_round_end_cashout() display_score(score); // Set the score display } -static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time) -{ - tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); - - for (int i = 0; i < MAX_SHOP_JOKERS; i++) - { - if (shop_jokers[i] != NULL) - { - joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists - } - - u8 joker_id = random() % get_joker_registry_size(); - // TODO: don't pick a joker that we already own - // TODO: weight the random choice by joker rarity - - shop_jokers[i] = joker_object_new(joker_new(joker_id)); - shop_jokers[i]->sprite_object->x = int2fx(120 + i * 32); - shop_jokers[i]->sprite_object->y = int2fx(160); - shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x; - shop_jokers[i]->sprite_object->ty = int2fx(71); - - int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE; - int y = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE; - tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, shop_jokers[i]->joker->value); - - if (first_time == false) - { - shop_jokers[i]->sprite_object->y = shop_jokers[i]->sprite_object->ty; // If it's not the first time, set the y position to the target position - joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation - } - - sprite_position(joker_object_get_sprite(shop_jokers[i]), fx2int(shop_jokers[i]->sprite_object->x), fx2int(shop_jokers[i]->sprite_object->y)); - } -} - void game_playing() { // TODO: Blind rect sliding into view animation... @@ -2155,13 +2137,47 @@ void game_round_end() } } -void game_shop_intro(JokerObject* shop_jokers[]) +static void game_shop_create_items(JokerObject *shop_jokers[]) +{ + tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); + + for (int i = 0; i < MAX_SHOP_JOKERS; i++) + { + + // Note: this needs to happen after the existing joker destruction above + if (int_list_get_size(jokers_available_to_shop) == 0) + { + // No jokers to create + continue; + } + + // TODO: weight the random choice by joker rarity + int joker_idx = random() % int_list_get_size(jokers_available_to_shop); + int joker_id = int_list_get(jokers_available_to_shop, joker_idx); + int_list_remove_by_idx(jokers_available_to_shop, joker_idx); + + shop_jokers[i] = joker_object_new(joker_new(joker_id)); + shop_jokers[i]->sprite_object->x = int2fx(120 + i * 32); + shop_jokers[i]->sprite_object->y = int2fx(160); + shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x; + shop_jokers[i]->sprite_object->ty = int2fx(71); + + int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE; + int y = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE; + tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, shop_jokers[i]->joker->value); + + sprite_position(joker_object_get_sprite(shop_jokers[i]), fx2int(shop_jokers[i]->sprite_object->x), fx2int(shop_jokers[i]->sprite_object->y)); + } +} + +// Intro sequence (menu and shop icon coming into frame) +static void game_shop_intro(JokerObject* shop_jokers[]) { main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); if (timer == 1) { - game_shop_create_items(shop_jokers, true); + game_shop_create_items(shop_jokers); } if (timer >= 7) // Shift the shop icon @@ -2188,6 +2204,181 @@ void game_shop_intro(JokerObject* shop_jokers[]) } } +static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost) +{ + money -= *reroll_cost; + display_money(money); // Update the money display + for (int i = 0; i < MAX_SHOP_JOKERS; i++) + { + if (shop_jokers[i] != NULL) + { + int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id); + joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists + } + } + + game_shop_create_items(shop_jokers); + + for (int i = 0; i < MAX_SHOP_JOKERS; i++) + { + if (shop_jokers[i] != NULL) + { + shop_jokers[i]->sprite_object->y = shop_jokers[i]->sprite_object->ty; // Set the y position to the target position + joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation + } + } + + (*reroll_cost)++; + tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, *reroll_cost); +} + +// Shop menu input and selection +static void game_shop_process_user_input(JokerObject** shop_jokers) +{ + const int REROLL_BASE_COST = 5; // Base cost for rerolling the shop items + static int reroll_cost = REROLL_BASE_COST; + + // temp variables for future implementation + const ushort max_items_top = MAX_SHOP_JOKERS; + const ushort max_items_bottom = 0; + + if (timer == 1) + { + tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost); + } + + // Shop input logic + if (key_hit(KEY_UP)) + { + selection_y = 0; + + if (selection_x > max_items_top) + { + selection_x = max_items_top; + } + } + else if (key_hit(KEY_DOWN)) + { + selection_y = 1; + + if (selection_x > max_items_bottom) + { + selection_x = max_items_bottom; + } + } + else if (key_hit(KEY_LEFT)) + { + if (selection_x > 0) + { + selection_x--; + } + } + else if (key_hit(KEY_RIGHT)) + { + // TODO: Don't allow cursor on sold items + if (selection_y == 0 && selection_x < max_items_top) + { + selection_x++; + } + else if (selection_y == 1 && selection_x < max_items_bottom) + { + selection_x++; + } + } + + memcpy16(&pal_bg_mem[7], &pal_bg_mem[3], 1); + memcpy16(&pal_bg_mem[5], &pal_bg_mem[16], 1); + + // Shop selection logic + if (selection_x == 0 && selection_y == 0) // Next round button + { + memset16(&pal_bg_mem[5], 0xFFFF, 1); + + if (key_hit(SELECT_CARD)) + { + // Go to next blind selection game state + state = 2; // Go to the outro sequence state + timer = 0; // Reset the timer + reroll_cost = REROLL_BASE_COST; + + memcpy16(&pal_bg_mem[5], &pal_bg_mem[6], 1); + + // memcpy16(&pal_bg_mem[16], &pal_bg_mem[6], 1); + // This changes the color of the button to a dark red. + // However, it shares a palette with the shop icon, so it will change the color of the shop icon as well. + // And I don't care enough to fix it right now. + } + } + else if (selection_x == 0 && selection_y == 1) // Reroll button + { + memset16(&pal_bg_mem[7], 0xFFFF, 1); + + if (key_hit(SELECT_CARD) && money >= reroll_cost) + { + game_shop_reroll(shop_jokers, &reroll_cost); + } + } + + for (int i = 0; i < MAX_SHOP_JOKERS; i++) // Item selection logic + { + if (shop_jokers[i] != NULL) + { + if (i == selection_x - 1 && selection_y == 0) + { + shop_jokers[i]->sprite_object->ty = int2fx(61); + + if (key_hit(SELECT_CARD) && jokers_top < MAX_JOKERS_HELD_SIZE - 1 && money >= shop_jokers[i]->joker->value) + { + joker_push(shop_jokers[i]); + money -= shop_jokers[i]->joker->value; // Deduct the money spent on the joker + display_money(money); // Update the money display + + Rect joker_price_rect; + joker_price_rect.left = fx2int(shop_jokers[i]->sprite_object->tx); + // 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile + joker_price_rect.top = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + 2*TILE_SIZE; + joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3; + joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE; + + tte_erase_rect_wrapper(joker_price_rect); + + shop_jokers[i] = NULL; // Remove the joker from the shop + } + } + else + { + shop_jokers[i]->sprite_object->ty = int2fx(71); + } + } + } +} + +static void game_shop_lights_anim_frame() +{ + // Shift palette around the border of the shop icon + COLOR shifted_palette[4]; + memcpy16(&shifted_palette[0], &pal_bg_mem[14], 1); + memcpy16(&shifted_palette[1], &pal_bg_mem[17], 1); + memcpy16(&shifted_palette[2], &pal_bg_mem[22], 1); + memcpy16(&shifted_palette[3], &pal_bg_mem[8], 1); + + // Circularly shift the palette + int last = shifted_palette[3]; + + for (int i = 3; i > 0; --i) + { + shifted_palette[i] = shifted_palette[i - 1]; + } + + shifted_palette[0] = last; + + memcpy16(&pal_bg_mem[14], &shifted_palette[0], 1); // Copy the shifted palette to the next 4 slots + memcpy16(&pal_bg_mem[17], &shifted_palette[1], 1); + memcpy16(&pal_bg_mem[22], &shifted_palette[2], 1); + memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1); +} + + void game_shop() { change_background(BG_ID_SHOP); @@ -2202,159 +2393,21 @@ void game_shop() } } - const int reroll_base_cost = 5; // Base cost for rerolling the shop items - static int reroll_cost = reroll_base_cost; - - // temp variables for future implementation - const ushort max_items_top = MAX_SHOP_JOKERS; - const ushort max_items_bottom = 0; - - if (timer % 20 == 0) // Shift palette around the border of the shop icon + if (timer % 20 == 0) { - COLOR shifted_palette[4]; - memcpy16(&shifted_palette[0], &pal_bg_mem[14], 1); - memcpy16(&shifted_palette[1], &pal_bg_mem[17], 1); - memcpy16(&shifted_palette[2], &pal_bg_mem[22], 1); - memcpy16(&shifted_palette[3], &pal_bg_mem[8], 1); - - // Circularly shift the palette - int last = shifted_palette[3]; - - for (int i = 3; i > 0; --i) { - shifted_palette[i] = shifted_palette[i - 1]; - } - - shifted_palette[0] = last; - - memcpy16(&pal_bg_mem[14], &shifted_palette[0], 1); // Copy the shifted palette to the next 4 slots - memcpy16(&pal_bg_mem[17], &shifted_palette[1], 1); - memcpy16(&pal_bg_mem[22], &shifted_palette[2], 1); - memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1); + game_shop_lights_anim_frame(); } switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer { - case 0: // Intro sequence (menu and shop icon coming into frame) + case 0: { game_shop_intro(shop_jokers); break; } - case 1: // Shop menu input and selection + case 1: { - if (timer == 1) - { - tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost); - } - - // Shop input logic - if (key_hit(KEY_UP)) - { - selection_y = 0; - - if (selection_x > max_items_top) - { - selection_x = max_items_top; - } - } - else if (key_hit(KEY_DOWN)) - { - selection_y = 1; - - if (selection_x > max_items_bottom) - { - selection_x = max_items_bottom; - } - } - else if (key_hit(KEY_LEFT)) - { - if (selection_x > 0) - { - selection_x--; - } - } - else if (key_hit(KEY_RIGHT)) - { - if (selection_y == 0 && selection_x < max_items_top) - { - selection_x++; - } - else if (selection_y == 1 && selection_x < max_items_bottom) - { - selection_x++; - } - } - - memcpy16(&pal_bg_mem[7], &pal_bg_mem[3], 1); - memcpy16(&pal_bg_mem[5], &pal_bg_mem[16], 1); - - // Shop selection logic - if (selection_x == 0 && selection_y == 0) - { - memset16(&pal_bg_mem[5], 0xFFFF, 1); - - if (key_hit(SELECT_CARD)) - { - // Go to next blind selection game state - state = 2; // Go to the outro sequence state - timer = 0; // Reset the timer - - memcpy16(&pal_bg_mem[5], &pal_bg_mem[6], 1); - - // memcpy16(&pal_bg_mem[16], &pal_bg_mem[6], 1); - // This changes the color of the button to a dark red. - // However, it shares a palette with the shop icon, so it will change the color of the shop icon as well. - // And I don't care enough to fix it right now. - } - } - else if (selection_x == 0 && selection_y == 1) - { - memset16(&pal_bg_mem[7], 0xFFFF, 1); - - if (key_hit(SELECT_CARD) && money >= reroll_cost) - { - money -= reroll_cost; - display_money(money); // Update the money display - - game_shop_create_items(shop_jokers, false); - - reroll_cost++; - tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost); - } - } - - for (int i = 0; i < MAX_SHOP_JOKERS; i++) - { - if (shop_jokers[i] != NULL) - { - if (i == selection_x - 1 && selection_y == 0) - { - shop_jokers[i]->sprite_object->ty = int2fx(61); - - if (key_hit(SELECT_CARD) && jokers_top < MAX_JOKERS_HELD_SIZE - 1 && money >= shop_jokers[i]->joker->value) - { - joker_push(shop_jokers[i]); - money -= shop_jokers[i]->joker->value; // Deduct the money spent on the joker - display_money(money); // Update the money display - - Rect joker_price_rect; - joker_price_rect.left = fx2int(shop_jokers[i]->sprite_object->tx); - // 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile - joker_price_rect.top = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + 2*TILE_SIZE; - joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3; - joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE; - - tte_erase_rect_wrapper(joker_price_rect); - - shop_jokers[i] = NULL; // Remove the joker from the shop - } - } - else - { - shop_jokers[i]->sprite_object->ty = int2fx(71); - } - } - } - + game_shop_process_user_input(shop_jokers); break; } case 2: // Outro sequence (menu and shop icon going out of frame) @@ -2402,13 +2455,17 @@ void game_shop() } default: state = 0; // Reset the state - reroll_cost = reroll_base_cost; selection_x = 0; // Reset the selection selection_y = 0; // Reset the selection for (int i = 0; i < MAX_SHOP_JOKERS; i++) { + if (shop_jokers[i] != NULL) + { + // Make the joker available back to shop + int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id); + } joker_object_destroy(&shop_jokers[i]); // Destroy the joker objects } @@ -2419,6 +2476,8 @@ void game_shop() } } + + void game_blind_select() { switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer diff --git a/source/int_list.c b/source/int_list.c index 458b564..0b65f3d 100644 --- a/source/int_list.c +++ b/source/int_list.c @@ -1,6 +1,7 @@ #include #include #include "list.h" +#include "util.h" IntList *int_list_new(int init_size) { IntList *list = (IntList *)malloc(sizeof(IntList)); @@ -27,7 +28,7 @@ void int_list_destroy(IntList **list) { *list = NULL; } -bool int_list_add(IntList *list, int value) +bool int_list_append(IntList *list, int value) { if (list->size >= list->allocated_size) { @@ -42,7 +43,7 @@ bool int_list_add(IntList *list, int value) return true; } -bool int_list_remove(IntList *list, int index) { +bool int_list_remove_by_idx(IntList *list, int index) { if (index < 0 || index >= list->size) return false; for (int i = index; i < list->size - 1; ++i) @@ -53,9 +54,31 @@ bool int_list_remove(IntList *list, int index) { return true; } +bool int_list_remove_by_value(IntList *list, int value) +{ + for (int i = 0; i < list->size; i++) + { + if (list->_array[i] == value) + { + return int_list_remove_by_idx(list, i); + } + } + + return false; +} + int int_list_get(IntList *list, int index) { if (index < 0 || index >= list->size) return 0; return list->_array[index]; -} \ No newline at end of file +} + +int int_list_get_size(IntList *list) +{ + if (list == NULL) + { + return UNDEFINED; + } + return list->size; +} From 38282d0f2af4d0f0a5234cf78da188bcd23cc113 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Sat, 9 Aug 2025 21:31:41 +0300 Subject: [PATCH 35/45] Small refactors --- source/game.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/source/game.c b/source/game.c index 9ec5d81..f58d644 100644 --- a/source/game.c +++ b/source/game.c @@ -173,7 +173,7 @@ int get_jokers_top(void) { return jokers_top; } -IntList* jokers_available_to_shop; +IntList* jokers_available_to_shop; // List of joker IDs // Consts @@ -1005,7 +1005,7 @@ void game_set_state(enum GameState new_game_state) void jokers_avialable_to_shop_init() { int num_defined_jokers = get_joker_registry_size(); - jokers_available_to_shop = int_list_new(get_joker_registry_size()); + jokers_available_to_shop = int_list_new(num_defined_jokers); for (int i = 0; i < num_defined_jokers; i++) { // Add all joker IDs sequentially @@ -2140,17 +2140,14 @@ void game_round_end() static void game_shop_create_items(JokerObject *shop_jokers[]) { tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); + if (int_list_get_size(jokers_available_to_shop) == 0) + { + // No jokers to create + return; + } for (int i = 0; i < MAX_SHOP_JOKERS; i++) { - - // Note: this needs to happen after the existing joker destruction above - if (int_list_get_size(jokers_available_to_shop) == 0) - { - // No jokers to create - continue; - } - // TODO: weight the random choice by joker rarity int joker_idx = random() % int_list_get_size(jokers_available_to_shop); int joker_id = int_list_get(jokers_available_to_shop, joker_idx); @@ -2235,7 +2232,7 @@ static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost) // Shop menu input and selection static void game_shop_process_user_input(JokerObject** shop_jokers) { - const int REROLL_BASE_COST = 5; // Base cost for rerolling the shop items + static const int REROLL_BASE_COST = 5; // Base cost for rerolling the shop items static int reroll_cost = REROLL_BASE_COST; // temp variables for future implementation @@ -2469,7 +2466,7 @@ void game_shop() joker_object_destroy(&shop_jokers[i]); // Destroy the joker objects } - increment_blind(BLIND_DEFEATED); + increment_blind(BLIND_DEFEATED); // TODO: Move to game_round_end()? game_set_state(GAME_BLIND_SELECT); // If we reach here, we should go to the blind select state break; From 05af8217ff8dd6596f11011b7c81c0cd17f5e01d Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Tue, 12 Aug 2025 01:59:04 +0300 Subject: [PATCH 36/45] Small affine background CBB/SBB fix --- source/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/main.c b/source/main.c index 76abc07..269fc09 100644 --- a/source/main.c +++ b/source/main.c @@ -44,7 +44,7 @@ void init() // BG1 is the main background layer REG_BG1CNT = BG_PRIO(1) | BG_CBB(MAIN_BG_CBB) | BG_SBB(MAIN_BG_SBB) | BG_8BPP; // BG2 is the affine background layer - REG_BG2CNT = BG_PRIO(2) | BG_CBB(AFFINE_BG_CBB) | BG_SBB(AFFINE_BG_CBB) | BG_8BPP | BG_WRAP | BG_AFF_32x32; + REG_BG2CNT = BG_PRIO(2) | BG_CBB(AFFINE_BG_CBB) | BG_SBB(AFFINE_BG_SBB) | BG_8BPP | BG_WRAP | BG_AFF_32x32; int win1_left = 72; int win1_top = 44; From 658b0572d9a391e15bf3822d803ee48031d9a673 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Tue, 12 Aug 2025 03:01:02 +0300 Subject: [PATCH 37/45] Removed all uses of float for optimization --- source/game.c | 2 +- source/sprite.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/game.c b/source/game.c index f58d644..83ef525 100644 --- a/source/game.c +++ b/source/game.c @@ -1576,7 +1576,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection FIXED played_x = int2fx(120); FIXED played_y = int2fx(70); - FIXED played_scale = float2fx(1.0f); + FIXED played_scale = FIX_ONE; played_x = played_x + (int2fx(played_top - i) - int2fx(played_top) / 2) * -27; diff --git a/source/sprite.c b/source/sprite.c index a93b953..fb973c3 100644 --- a/source/sprite.c +++ b/source/sprite.c @@ -145,9 +145,9 @@ void sprite_object_reset_transform(SpriteObject* sprite_object) sprite_object->y = 0; sprite_object->vx = 0; sprite_object->vy = 0; - sprite_object->tscale = float2fx(1.0f); // Target scale - sprite_object->scale = float2fx(1.0f); - sprite_object->vscale = float2fx(0.0f); + sprite_object->tscale = FIX_ONE; // Target scale + sprite_object->scale = FIX_ONE; + sprite_object->vscale = 0; sprite_object->trotation = 0; // Target rotation sprite_object->rotation = 0; sprite_object->vrotation = 0; @@ -163,7 +163,7 @@ void sprite_object_update(SpriteObject* sprite_object) sprite_object->vrotation += (sprite_object->trotation - sprite_object->rotation) / 8; // Rotate the card when it's played // set velocity to 0 if it's close enough to the target - const float epsilon = float2fx(0.01f); + const FIXED epsilon = FIX_ONE>>7; // 1/(2^7) = 1/128 = 0.0078125 if (sprite_object->vx < epsilon && sprite_object->vx > -epsilon && sprite_object->vy < epsilon && sprite_object->vy > -epsilon) { sprite_object->vx = 0; @@ -211,8 +211,8 @@ void sprite_object_update(SpriteObject* sprite_object) void sprite_object_shake(SpriteObject* sprite_object, mm_word sound_id) { - sprite_object->vscale = float2fx(0.3f); // Scale down the card when it's scored - sprite_object->vrotation = float2fx(8.0f); // Rotate the card when it's scored + sprite_object->vscale = FIX_ONE >> 2; // (1/4 = 0.25) Scale down the card when it's scored + sprite_object->vrotation = FIX_ONE << 3; // (2^3 = 8) Rotate the card when it's scored if (sound_id == UNDEFINED) return; // If no sound ID is provided, do nothing From 0e080b916e5caf704ffb9f86784adc59ff7b23c1 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Tue, 12 Aug 2025 11:40:22 +0300 Subject: [PATCH 38/45] Reverted removals of float2fx() as they're compiler-optimized but kept float optimization --- source/sprite.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/sprite.c b/source/sprite.c index fb973c3..df1e917 100644 --- a/source/sprite.c +++ b/source/sprite.c @@ -163,7 +163,7 @@ void sprite_object_update(SpriteObject* sprite_object) sprite_object->vrotation += (sprite_object->trotation - sprite_object->rotation) / 8; // Rotate the card when it's played // set velocity to 0 if it's close enough to the target - const FIXED epsilon = FIX_ONE>>7; // 1/(2^7) = 1/128 = 0.0078125 + const FIXED epsilon = float2fx(0.01f); if (sprite_object->vx < epsilon && sprite_object->vx > -epsilon && sprite_object->vy < epsilon && sprite_object->vy > -epsilon) { sprite_object->vx = 0; @@ -211,8 +211,8 @@ void sprite_object_update(SpriteObject* sprite_object) void sprite_object_shake(SpriteObject* sprite_object, mm_word sound_id) { - sprite_object->vscale = FIX_ONE >> 2; // (1/4 = 0.25) Scale down the card when it's scored - sprite_object->vrotation = FIX_ONE << 3; // (2^3 = 8) Rotate the card when it's scored + sprite_object->vscale = float2fx(0.3f); + sprite_object->vrotation = float2fx(8.0f); //Rotate the card when it's scored if (sound_id == UNDEFINED) return; // If no sound ID is provided, do nothing From 5ef7fa49aa8505c76d8500ba3d96e2511a3bcd1b Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Tue, 12 Aug 2025 17:22:42 +0300 Subject: [PATCH 39/45] Added more undesired IDE artifacts to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 542edaa..be9866f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /build /.vs *.sln -*.vcxproj* \ No newline at end of file +*.vcxproj* +/balatro-gba/x64/** From 06dc4f9c6227a65aa77c0a798b356a3a19fe9a64 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 15 Aug 2025 10:38:20 +0300 Subject: [PATCH 40/45] Extracted focus to SpriteObject for joker selling - WIP --- include/sprite.h | 5 ++++- source/game.c | 25 +++++++------------------ source/sprite.c | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/include/sprite.h b/include/sprite.h index b4d6bca..b3f27b8 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -27,6 +27,8 @@ typedef struct FIXED rotation; FIXED vrotation; bool selected; + bool focused; + } SpriteObject; // Sprite methods @@ -58,6 +60,7 @@ void sprite_object_shake(SpriteObject* sprite_object, mm_word sound_id); void sprite_object_set_selected(SpriteObject* sprite_object, bool selected); bool sprite_object_is_selected(SpriteObject* sprite_object); Sprite* sprite_object_get_sprite(SpriteObject* sprite_object); - +void sprite_object_set_focus(SpriteObject* sprite_object, bool focus); +bool sprite_object_is_focused(SpriteObject* sprite_object); #endif // SPRITE_H \ No newline at end of file diff --git a/source/game.c b/source/game.c index 83ef525..8066f79 100644 --- a/source/game.c +++ b/source/game.c @@ -239,6 +239,7 @@ static const Rect ROUND_END_NUM_HANDS_RECT = {88, 116, UNDEFINED, UNDEF static const Rect HAND_REWARD_RECT = {168, UNDEFINED, UNDEFINED, UNDEFINED }; static const Rect CASHOUT_RECT = {88, 72, UNDEFINED, UNDEFINED }; static const Rect SHOP_REROLL_RECT = {88, 96, UNDEFINED, UNDEFINED }; +#define ITEM_SHOP_Y 71 // TODO: Needs to be a rect? //TODO: Properly define and use #define MENU_POP_OUT_ANIM_FRAMES 20 @@ -1002,7 +1003,7 @@ void game_set_state(enum GameState new_game_state) game_state = new_game_state; } -void jokers_avialable_to_shop_init() +void jokers_available_to_shop_init() { int num_defined_jokers = get_joker_registry_size(); jokers_available_to_shop = int_list_new(num_defined_jokers); @@ -1015,7 +1016,7 @@ void jokers_avialable_to_shop_init() void game_init() { - jokers_avialable_to_shop_init(); + jokers_available_to_shop_init(); hands = max_hands; discards = max_discards; @@ -1789,11 +1790,6 @@ static void held_jokers_update_loop() jokers[i]->sprite_object->tx = hand_x - int2fx(spacing_lut[jokers_top][i]); jokers[i]->sprite_object->ty = hand_y; - if (joker_object_is_selected(jokers[i])) - { - jokers[i]->sprite_object->ty -= int2fx(10); - } - joker_object_update(jokers[i]); } } @@ -2154,10 +2150,10 @@ static void game_shop_create_items(JokerObject *shop_jokers[]) int_list_remove_by_idx(jokers_available_to_shop, joker_idx); shop_jokers[i] = joker_object_new(joker_new(joker_id)); - shop_jokers[i]->sprite_object->x = int2fx(120 + i * 32); + shop_jokers[i]->sprite_object->x = int2fx(120 + i * CARD_SPRITE_SIZE); shop_jokers[i]->sprite_object->y = int2fx(160); shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x; - shop_jokers[i]->sprite_object->ty = int2fx(71); + shop_jokers[i]->sprite_object->ty = int2fx(ITEM_SHOP_Y); int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE; int y = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE; @@ -2229,6 +2225,8 @@ static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost) tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, *reroll_cost); } + + // Shop menu input and selection static void game_shop_process_user_input(JokerObject** shop_jokers) { @@ -2322,8 +2320,6 @@ static void game_shop_process_user_input(JokerObject** shop_jokers) { if (i == selection_x - 1 && selection_y == 0) { - shop_jokers[i]->sprite_object->ty = int2fx(61); - if (key_hit(SELECT_CARD) && jokers_top < MAX_JOKERS_HELD_SIZE - 1 && money >= shop_jokers[i]->joker->value) { joker_push(shop_jokers[i]); @@ -2342,10 +2338,6 @@ static void game_shop_process_user_input(JokerObject** shop_jokers) shop_jokers[i] = NULL; // Remove the joker from the shop } } - else - { - shop_jokers[i]->sprite_object->ty = int2fx(71); - } } } } @@ -2375,7 +2367,6 @@ static void game_shop_lights_anim_frame() memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1); } - void game_shop() { change_background(BG_ID_SHOP); @@ -2473,8 +2464,6 @@ void game_shop() } } - - void game_blind_select() { switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer diff --git a/source/sprite.c b/source/sprite.c index df1e917..ef7ae91 100644 --- a/source/sprite.c +++ b/source/sprite.c @@ -8,6 +8,7 @@ #define MAX_SPRITES 128 #define MAX_AFFINES 32 +#define SPRITE_FOCUS_RAISE_PX 10 OBJ_ATTR obj_buffer[MAX_SPRITES]; OBJ_AFFINE *obj_aff_buffer = (OBJ_AFFINE*)obj_buffer; @@ -239,3 +240,18 @@ Sprite* sprite_object_get_sprite(SpriteObject* sprite_object) return NULL; return sprite_object->sprite; } + +void sprite_object_set_focus(SpriteObject* sprite_object, bool focus) +{ + if (sprite_object->focused == focus) + { + return; + } + + sprite_object->ty = sprite_object->ty + (focus ? -1 : 1) * SPRITE_FOCUS_RAISE_PX; +} + +bool sprite_object_is_focused(SpriteObject* sprite_object) +{ + return sprite_object->focused; +} From d1677e82d29b762243cd98ea35db3768212f85e6 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 15 Aug 2025 19:30:07 +0300 Subject: [PATCH 41/45] Added Selection Grid system and refactored shop code to use it --- include/selection_grid.h | 41 +++++++ source/game.c | 240 ++++++++++++++++++++++----------------- source/selection_grid.c | 79 +++++++++++++ source/sprite.c | 7 +- 4 files changed, 260 insertions(+), 107 deletions(-) create mode 100644 include/selection_grid.h create mode 100644 source/selection_grid.c diff --git a/include/selection_grid.h b/include/selection_grid.h new file mode 100644 index 0000000..9ddd2bf --- /dev/null +++ b/include/selection_grid.h @@ -0,0 +1,41 @@ +#ifndef SELECTION_GRID_H +#define SELECTION_GRID_H +#include + +typedef POINT Selection; + +struct SelectionGridRow; +struct SelectionGrid; +typedef struct SelectionGridRow SelectionGridRow; +typedef struct SelectionGrid SelectionGrid; + +// Called whenever there is a change in the selection cursor +// row_idx is the index of the row whose function is invoked - can be used to identify whether it is the previous or new selection row. +typedef void (*RowOnSelectionChangedFunc)(SelectionGrid* selection_grid, int row_idx, const Selection* prev_selection, const Selection* new_selection); +typedef int (*RowGetSizeFunc)(); +// Called for any non-directional key hit +// The key will not be passed, the function will have to check key_hit() etc. for the key it wants to check +typedef void (*RowOnKeyHitFunc)(SelectionGrid* selection_grid, Selection* selection); + +struct SelectionGridRow +{ + int row_idx; + RowGetSizeFunc get_size; + RowOnSelectionChangedFunc on_selection_changed; + RowOnKeyHitFunc on_key_hit; +}; + +struct SelectionGrid +{ + SelectionGridRow* rows; + const int num_rows; + Selection selection; + }; + + +void selection_grid_process_input(SelectionGrid* selection_grid); + +void selection_grid_move_selection_horz(SelectionGrid* selection_grid, int direction_tribool); +void selection_grid_move_selection_vert(SelectionGrid* selection_grid, int direction_tribool); + +#endif \ No newline at end of file diff --git a/source/game.c b/source/game.c index 8066f79..0cf06a2 100644 --- a/source/game.c +++ b/source/game.c @@ -15,6 +15,7 @@ #include "graphic_utils.h" #include "tonc_video.h" #include "audio_utils.h" +#include "selection_grid.h" #include "background_gfx.h" #include "background_shop_gfx.h" @@ -246,6 +247,8 @@ static const Rect SHOP_REROLL_RECT = {88, 96, UNDEFINED, UNDEFI #define SCORED_CARD_TEXT_Y 48 +#define HIGHLIGHT_COLOR 0xFFFF + #define PITCH_STEP_DISCARD_SFX (-64) #define PITCH_STEP_DRAW_SFX 24 #define PITCH_STEP_UNDISCARD_SFX 2*PITCH_STEP_DRAW_SFX @@ -2133,6 +2136,18 @@ void game_round_end() } } +// Shop +static JokerObject *shop_jokers[MAX_SHOP_JOKERS] = {NULL}; +#define REROLL_BASE_COST 5 // Base cost for rerolling the shop items +static int reroll_cost = REROLL_BASE_COST; + +#define NEXT_ROUND_BTN_SEL_X 0 + +#define NEXT_ROUND_BTN_FRAME_PAL_IDX 5 +#define NEXT_ROUND_BTN_PAL_IDX 16 +#define REROLL_BTN_FRAME_PAL_IDX 7 +#define REROLL_BTN_PAL_IDX 3 + static void game_shop_create_items(JokerObject *shop_jokers[]) { tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); @@ -2225,17 +2240,130 @@ static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost) tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, *reroll_cost); } +// Shop input +static int shop_top_row_get_size() +{ + // TODO: Make dynamic to not allow selecting sold items + return MAX_SHOP_JOKERS + 1; // + 1 to account for next round button +} +static void shop_top_row_on_key_hit(SelectionGrid* selection_grid, Selection* selection) +{ + if (!key_hit(SELECT_CARD)) + return; + + if (selection->x == NEXT_ROUND_BTN_SEL_X) + { + // Go to next blind selection game state + state = 2; // Go to the outro sequence state + timer = 0; // Reset the timer + reroll_cost = REROLL_BASE_COST; + + memcpy16(&pal_bg_mem[NEXT_ROUND_BTN_FRAME_PAL_IDX], &pal_bg_mem[6], 1); + + // memcpy16(&pal_bg_mem[16], &pal_bg_mem[6], 1); + // This changes the color of the button to a dark red. + // However, it shares a palette with the shop icon, so it will change the color of the shop icon as well. + // And I don't care enough to fix it right now. + } + else + { + int shop_joker_idx = selection->x - 1; // - 1 to account for next round button + if (shop_jokers[shop_joker_idx] == NULL + || jokers_top >= MAX_JOKERS_HELD_SIZE - 1 + || money < shop_jokers[shop_joker_idx]->joker->value) + { + return; + } + + joker_push(shop_jokers[shop_joker_idx]); + money -= shop_jokers[shop_joker_idx]->joker->value; // Deduct the money spent on the joker + display_money(money); // Update the money display + + Rect joker_price_rect; + joker_price_rect.left = fx2int(shop_jokers[shop_joker_idx]->sprite_object->tx); + // 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile + joker_price_rect.top = fx2int(shop_jokers[shop_joker_idx]->sprite_object->ty) + CARD_SPRITE_SIZE + 2*TILE_SIZE; + joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3; + joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE; + + tte_erase_rect_wrapper(joker_price_rect); + + shop_jokers[shop_joker_idx] = NULL; // Remove the joker from the shop + + selection_grid_move_selection_horz(selection_grid, -1); + } +} + +static void shop_top_row_on_selection_changed(SelectionGrid* selection_grid, int row_idx, const Selection* prev_selection, const Selection* new_selection) +{ + if (prev_selection->y == row_idx) + { + if (prev_selection->x == NEXT_ROUND_BTN_SEL_X) + { + // Remove next round button highlight + memcpy16(&pal_bg_mem[NEXT_ROUND_BTN_FRAME_PAL_IDX], &pal_bg_mem[NEXT_ROUND_BTN_PAL_IDX], 1); + } + else + { + sprite_object_set_focus(shop_jokers[prev_selection->x - 1]->sprite_object, false); + // -1 to account for next round button + } + } + + if (new_selection->y == row_idx) + { + if (new_selection->x == NEXT_ROUND_BTN_SEL_X) + { + // Highlight next round button + memset16(&pal_bg_mem[NEXT_ROUND_BTN_FRAME_PAL_IDX], HIGHLIGHT_COLOR, 1); + } + else + { + sprite_object_set_focus(shop_jokers[new_selection->x - 1]->sprite_object, true); + // -1 to account for next round button + } + } +} + +static int shop_bottom_row_get_size() +{ + return 1; // Currently only the reroll button +} + +static void shop_bottom_row_on_selection_changed(SelectionGrid* selection_grid, int row_idx, const Selection* prev_selection, const Selection* new_selection) +{ + if (row_idx == prev_selection->y) + { + // Remove highlight + memcpy16(&pal_bg_mem[REROLL_BTN_FRAME_PAL_IDX], &pal_bg_mem[REROLL_BTN_PAL_IDX], 1); + } + else if (row_idx == new_selection->y) + { + memset16(&pal_bg_mem[REROLL_BTN_FRAME_PAL_IDX], HIGHLIGHT_COLOR, 1); + } +} + +static void shop_bottom_row_on_key_hit(SelectionGrid* selection_grid, Selection* selection) +{ + if (money >= reroll_cost) + { + game_shop_reroll(shop_jokers, &reroll_cost); + } +} + +SelectionGridRow shop_selection_rows[] = +{ + {0, shop_top_row_get_size, shop_top_row_on_selection_changed, shop_top_row_on_key_hit}, + {1, shop_bottom_row_get_size, shop_bottom_row_on_selection_changed, shop_bottom_row_on_key_hit} +}; + +// TODO: Initialize selection better +SelectionGrid shop_selection_grid = {shop_selection_rows, NUM_ELEM_IN_ARR(shop_selection_rows), {0, 0}}; // Shop menu input and selection static void game_shop_process_user_input(JokerObject** shop_jokers) { - static const int REROLL_BASE_COST = 5; // Base cost for rerolling the shop items - static int reroll_cost = REROLL_BASE_COST; - - // temp variables for future implementation - const ushort max_items_top = MAX_SHOP_JOKERS; - const ushort max_items_bottom = 0; if (timer == 1) { @@ -2243,103 +2371,7 @@ static void game_shop_process_user_input(JokerObject** shop_jokers) } // Shop input logic - if (key_hit(KEY_UP)) - { - selection_y = 0; - - if (selection_x > max_items_top) - { - selection_x = max_items_top; - } - } - else if (key_hit(KEY_DOWN)) - { - selection_y = 1; - - if (selection_x > max_items_bottom) - { - selection_x = max_items_bottom; - } - } - else if (key_hit(KEY_LEFT)) - { - if (selection_x > 0) - { - selection_x--; - } - } - else if (key_hit(KEY_RIGHT)) - { - // TODO: Don't allow cursor on sold items - if (selection_y == 0 && selection_x < max_items_top) - { - selection_x++; - } - else if (selection_y == 1 && selection_x < max_items_bottom) - { - selection_x++; - } - } - - memcpy16(&pal_bg_mem[7], &pal_bg_mem[3], 1); - memcpy16(&pal_bg_mem[5], &pal_bg_mem[16], 1); - - // Shop selection logic - if (selection_x == 0 && selection_y == 0) // Next round button - { - memset16(&pal_bg_mem[5], 0xFFFF, 1); - - if (key_hit(SELECT_CARD)) - { - // Go to next blind selection game state - state = 2; // Go to the outro sequence state - timer = 0; // Reset the timer - reroll_cost = REROLL_BASE_COST; - - memcpy16(&pal_bg_mem[5], &pal_bg_mem[6], 1); - - // memcpy16(&pal_bg_mem[16], &pal_bg_mem[6], 1); - // This changes the color of the button to a dark red. - // However, it shares a palette with the shop icon, so it will change the color of the shop icon as well. - // And I don't care enough to fix it right now. - } - } - else if (selection_x == 0 && selection_y == 1) // Reroll button - { - memset16(&pal_bg_mem[7], 0xFFFF, 1); - - if (key_hit(SELECT_CARD) && money >= reroll_cost) - { - game_shop_reroll(shop_jokers, &reroll_cost); - } - } - - for (int i = 0; i < MAX_SHOP_JOKERS; i++) // Item selection logic - { - if (shop_jokers[i] != NULL) - { - if (i == selection_x - 1 && selection_y == 0) - { - if (key_hit(SELECT_CARD) && jokers_top < MAX_JOKERS_HELD_SIZE - 1 && money >= shop_jokers[i]->joker->value) - { - joker_push(shop_jokers[i]); - money -= shop_jokers[i]->joker->value; // Deduct the money spent on the joker - display_money(money); // Update the money display - - Rect joker_price_rect; - joker_price_rect.left = fx2int(shop_jokers[i]->sprite_object->tx); - // 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile - joker_price_rect.top = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + 2*TILE_SIZE; - joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3; - joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE; - - tte_erase_rect_wrapper(joker_price_rect); - - shop_jokers[i] = NULL; // Remove the joker from the shop - } - } - } - } + selection_grid_process_input(&shop_selection_grid); } static void game_shop_lights_anim_frame() @@ -2371,8 +2403,6 @@ void game_shop() { change_background(BG_ID_SHOP); - static JokerObject *shop_jokers[MAX_SHOP_JOKERS] = {NULL}; - for (int i = 0; i < MAX_SHOP_JOKERS; i++) { if (shop_jokers[i] != NULL) diff --git a/source/selection_grid.c b/source/selection_grid.c new file mode 100644 index 0000000..ab5e1d8 --- /dev/null +++ b/source/selection_grid.c @@ -0,0 +1,79 @@ +#include "selection_grid.h" + + +static void selection_grid_process_directional_input(SelectionGrid *selection_grid) +{ + int horz_tri_input = bit_tribool(key_hit(KEY_ANY), KI_RIGHT, KI_LEFT); + + if (horz_tri_input != 0) + { + selection_grid_move_selection_horz(selection_grid, horz_tri_input); + /* Avoid handling both vertical and horizontal input at the same time, + * it creates all sorts of difficult edge cases. + */ + return; + } + + int vert_tri_input = bit_tribool(key_hit(KEY_ANY), KI_DOWN, KI_UP); + + + if (vert_tri_input != 0) + { + selection_grid_move_selection_vert(selection_grid, vert_tri_input); + } + +} + +void selection_grid_move_selection_horz(SelectionGrid* selection_grid, + int direction_tribool) +{ + Selection new_selection = selection_grid->selection; + new_selection.x += direction_tribool; + if( selection_grid->selection.y >= 0 + && selection_grid->selection.y < selection_grid->num_rows + && new_selection.x >= 0 + && new_selection.x < selection_grid->rows[new_selection.y].get_size()) + { + selection_grid->rows[new_selection.y].on_selection_changed(selection_grid, new_selection.y, &selection_grid->selection, &new_selection); + selection_grid->selection = new_selection; + } +} + +void selection_grid_move_selection_vert(SelectionGrid *selection_grid, int direction_tribool) +{ + Selection selection = selection_grid->selection; + Selection new_selection = selection; + new_selection.y += direction_tribool; + + if (new_selection.y >= 0 + && new_selection.y < selection_grid->num_rows) + { + int new_row_size = selection_grid->rows[new_selection.y].get_size(); + if (selection.x >= new_row_size) + { + // TODO: Maintain relative horizontal position + // Clip selection to row size + new_selection.x = new_row_size - 1; + } + selection_grid->rows[selection.y].on_selection_changed(selection_grid, selection.y, &selection, &new_selection); + selection_grid->rows[new_selection.y].on_selection_changed(selection_grid, new_selection.y, &selection, &new_selection); + selection_grid->selection = new_selection; + } +} + +void selection_grid_process_input(SelectionGrid *selection_grid) +{ + if (selection_grid == NULL || selection_grid->rows == NULL) + return; + + selection_grid_process_directional_input(selection_grid); + + u32 non_directional_key = KEY_ANY & ~KEY_DIR; + if (key_hit(non_directional_key)) + { + Selection* selection = &selection_grid->selection; // To make the next line shorter and more readable + selection_grid->rows[selection->y].on_key_hit(selection_grid, selection); + } +} + + diff --git a/source/sprite.c b/source/sprite.c index ef7ae91..90cb7b5 100644 --- a/source/sprite.c +++ b/source/sprite.c @@ -1,6 +1,7 @@ #include "sprite.h" #include "util.h" #include "audio_utils.h" +#include "soundbank.h" #include #include @@ -247,8 +248,10 @@ void sprite_object_set_focus(SpriteObject* sprite_object, bool focus) { return; } - - sprite_object->ty = sprite_object->ty + (focus ? -1 : 1) * SPRITE_FOCUS_RAISE_PX; + sprite_object->focused = focus; + + play_sfx(SFX_CARD_FOCUS , MM_BASE_PITCH_RATE + rand() % 512); + sprite_object->ty = sprite_object->ty + int2fx((focus ? -1 : 1) * SPRITE_FOCUS_RAISE_PX); } bool sprite_object_is_focused(SpriteObject* sprite_object) From 2a4f045db63c0d20cb53463230f8814ab926575e Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 15 Aug 2025 20:03:17 +0300 Subject: [PATCH 42/45] Refactored list code to be generic void* list --- include/list.h | 28 ++++++++++++++-------------- source/game.c | 18 +++++++++--------- source/int_list.c | 40 ++++++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/include/list.h b/include/list.h index 64341f7..fd1c366 100644 --- a/include/list.h +++ b/include/list.h @@ -3,23 +3,23 @@ #include -/* Defining an int list for simplicity - * If another list is needed, a generic void* - * list should be defined.... - */ -typedef struct IntList +typedef struct List { - int* _array; + void** _array; int size; int allocated_size; -} IntList; +} List; -IntList *int_list_new(int init_size); -void int_list_destroy(IntList **list); -bool int_list_append(IntList *list, int value); -bool int_list_remove_by_idx(IntList *list, int index); -int int_list_get(IntList *list, int index); -int int_list_get_size(IntList *list); -bool int_list_remove_by_value(IntList *list, int value); +List *list_new(int init_size); +void list_destroy(List **list); +bool list_append(List *list, void *value); +bool list_remove_by_idx(List *list, int index); +void* list_get(List *list, int index); +int list_get_size(List *list); +bool list_remove_by_value(List *list, void *value); + +bool int_list_append(List *list, intptr_t value); +intptr_t int_list_get(List *list, int index); +bool int_list_remove_by_value(List *list, intptr_t value); #endif diff --git a/source/game.c b/source/game.c index 0cf06a2..6adc82b 100644 --- a/source/game.c +++ b/source/game.c @@ -174,7 +174,7 @@ int get_jokers_top(void) { return jokers_top; } -IntList* jokers_available_to_shop; // List of joker IDs +List* jokers_available_to_shop; // List of joker IDs // Consts @@ -1009,8 +1009,8 @@ void game_set_state(enum GameState new_game_state) void jokers_available_to_shop_init() { int num_defined_jokers = get_joker_registry_size(); - jokers_available_to_shop = int_list_new(num_defined_jokers); - for (int i = 0; i < num_defined_jokers; i++) + jokers_available_to_shop = list_new(num_defined_jokers); + for (intptr_t i = 0; i < num_defined_jokers; i++) { // Add all joker IDs sequentially int_list_append(jokers_available_to_shop, i); @@ -2151,7 +2151,7 @@ static int reroll_cost = REROLL_BASE_COST; static void game_shop_create_items(JokerObject *shop_jokers[]) { tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); - if (int_list_get_size(jokers_available_to_shop) == 0) + if (list_get_size(jokers_available_to_shop) == 0) { // No jokers to create return; @@ -2160,9 +2160,9 @@ static void game_shop_create_items(JokerObject *shop_jokers[]) for (int i = 0; i < MAX_SHOP_JOKERS; i++) { // TODO: weight the random choice by joker rarity - int joker_idx = random() % int_list_get_size(jokers_available_to_shop); - int joker_id = int_list_get(jokers_available_to_shop, joker_idx); - int_list_remove_by_idx(jokers_available_to_shop, joker_idx); + int joker_idx = random() % list_get_size(jokers_available_to_shop); + intptr_t joker_id = int_list_get(jokers_available_to_shop, joker_idx); + list_remove_by_idx(jokers_available_to_shop, joker_idx); shop_jokers[i] = joker_object_new(joker_new(joker_id)); shop_jokers[i]->sprite_object->x = int2fx(120 + i * CARD_SPRITE_SIZE); @@ -2220,7 +2220,7 @@ static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost) { if (shop_jokers[i] != NULL) { - int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id); + int_list_append(jokers_available_to_shop, (intptr_t)shop_jokers[i]->joker->id); joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists } } @@ -2482,7 +2482,7 @@ void game_shop() if (shop_jokers[i] != NULL) { // Make the joker available back to shop - int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id); + int_list_append(jokers_available_to_shop, (intptr_t)shop_jokers[i]->joker->id); } joker_object_destroy(&shop_jokers[i]); // Destroy the joker objects } diff --git a/source/int_list.c b/source/int_list.c index 0b65f3d..1a39dc4 100644 --- a/source/int_list.c +++ b/source/int_list.c @@ -3,10 +3,10 @@ #include "list.h" #include "util.h" -IntList *int_list_new(int init_size) { - IntList *list = (IntList *)malloc(sizeof(IntList)); +List *list_new(int init_size) { + List *list = (List *)malloc(sizeof(List)); if (list == NULL) return NULL; - list->_array = (int *)malloc(sizeof(int) * init_size); + list->_array = (void **)malloc(sizeof(void*) * init_size); if (!list->_array) { free(list); @@ -17,7 +17,7 @@ IntList *int_list_new(int init_size) { return list; } -void int_list_destroy(IntList **list) { +void list_destroy(List **list) { if (list == NULL || *list == NULL) return; { @@ -28,22 +28,28 @@ void int_list_destroy(IntList **list) { *list = NULL; } -bool int_list_append(IntList *list, int value) +bool int_list_append(List *list, intptr_t value) +{ + return list_append(list, (void*)value); +} + +bool list_append(List *list, void *value) { if (list->size >= list->allocated_size) { int new_size = list->allocated_size * 2; - int *new_arr = (int *)realloc(list->_array, sizeof(int) * new_size); + void **new_arr = (void **)realloc(list->_array, sizeof(void*) * new_size); if (new_arr == NULL) return false; list->_array = new_arr; list->allocated_size = new_size; } + list->_array[list->size++] = value; return true; } -bool int_list_remove_by_idx(IntList *list, int index) { +bool list_remove_by_idx(List *list, int index) { if (index < 0 || index >= list->size) return false; for (int i = index; i < list->size - 1; ++i) @@ -54,27 +60,37 @@ bool int_list_remove_by_idx(IntList *list, int index) { return true; } -bool int_list_remove_by_value(IntList *list, int value) +bool list_remove_by_value(List *list, void* value) { for (int i = 0; i < list->size; i++) { if (list->_array[i] == value) { - return int_list_remove_by_idx(list, i); + return list_remove_by_idx(list, i); } } return false; } -int int_list_get(IntList *list, int index) +bool int_list_remove_by_value(List *list, intptr_t value) +{ + return list_remove_by_value(list, (void*)value); +} + +void* list_get(List *list, int index) { if (index < 0 || index >= list->size) - return 0; + return NULL; return list->_array[index]; } -int int_list_get_size(IntList *list) +intptr_t int_list_get(List *list, int index) +{ + return (intptr_t)list_get(list, index); +} + +int list_get_size(List *list) { if (list == NULL) { From 168e34375d2bbb1961f0d998370965d6875f3b58 Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Fri, 15 Aug 2025 21:32:10 +0300 Subject: [PATCH 43/45] Refactored shop_jokers to use list so purchased jokers can't be selected --- source/game.c | 146 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 57 deletions(-) diff --git a/source/game.c b/source/game.c index 6adc82b..dab7ff5 100644 --- a/source/game.c +++ b/source/game.c @@ -2137,7 +2137,7 @@ void game_round_end() } // Shop -static JokerObject *shop_jokers[MAX_SHOP_JOKERS] = {NULL}; +static List *shop_jokers = NULL; #define REROLL_BASE_COST 5 // Base cost for rerolling the shop items static int reroll_cost = REROLL_BASE_COST; @@ -2148,7 +2148,7 @@ static int reroll_cost = REROLL_BASE_COST; #define REROLL_BTN_FRAME_PAL_IDX 7 #define REROLL_BTN_PAL_IDX 3 -static void game_shop_create_items(JokerObject *shop_jokers[]) +static void game_shop_create_items() { tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); if (list_get_size(jokers_available_to_shop) == 0) @@ -2157,6 +2157,8 @@ static void game_shop_create_items(JokerObject *shop_jokers[]) return; } + shop_jokers = list_new(MAX_SHOP_JOKERS); + for (int i = 0; i < MAX_SHOP_JOKERS; i++) { // TODO: weight the random choice by joker rarity @@ -2164,28 +2166,30 @@ static void game_shop_create_items(JokerObject *shop_jokers[]) intptr_t joker_id = int_list_get(jokers_available_to_shop, joker_idx); list_remove_by_idx(jokers_available_to_shop, joker_idx); - shop_jokers[i] = joker_object_new(joker_new(joker_id)); - shop_jokers[i]->sprite_object->x = int2fx(120 + i * CARD_SPRITE_SIZE); - shop_jokers[i]->sprite_object->y = int2fx(160); - shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x; - shop_jokers[i]->sprite_object->ty = int2fx(ITEM_SHOP_Y); + JokerObject *joker_object = joker_object_new(joker_new(joker_id)); - int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE; - int y = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE; - tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, shop_jokers[i]->joker->value); + joker_object->sprite_object->x = int2fx(120 + i * CARD_SPRITE_SIZE); + joker_object->sprite_object->y = int2fx(160); + joker_object->sprite_object->tx = joker_object->sprite_object->x; + joker_object->sprite_object->ty = int2fx(ITEM_SHOP_Y); - sprite_position(joker_object_get_sprite(shop_jokers[i]), fx2int(shop_jokers[i]->sprite_object->x), fx2int(shop_jokers[i]->sprite_object->y)); + int x = fx2int(joker_object->sprite_object->tx) + TILE_SIZE - (get_digits_even(joker_object->joker->value) - 1) * TILE_SIZE; + int y = fx2int(joker_object->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE; + tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, joker_object->joker->value); + + sprite_position(joker_object_get_sprite(joker_object), fx2int(joker_object->sprite_object->x), fx2int(joker_object->sprite_object->y)); + list_append(shop_jokers, joker_object); } } // Intro sequence (menu and shop icon coming into frame) -static void game_shop_intro(JokerObject* shop_jokers[]) +static void game_shop_intro() { main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP); if (timer == 1) { - game_shop_create_items(shop_jokers); + game_shop_create_items(); } if (timer >= 7) // Shift the shop icon @@ -2212,27 +2216,31 @@ static void game_shop_intro(JokerObject* shop_jokers[]) } } -static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost) +static void game_shop_reroll(int *reroll_cost) { money -= *reroll_cost; display_money(money); // Update the money display - for (int i = 0; i < MAX_SHOP_JOKERS; i++) + for (int i = 0; i < list_get_size(shop_jokers); i++) { - if (shop_jokers[i] != NULL) + JokerObject *joker_object = list_get(shop_jokers, i); + if (joker_object != NULL) { - int_list_append(jokers_available_to_shop, (intptr_t)shop_jokers[i]->joker->id); - joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists + int_list_append(jokers_available_to_shop, joker_object->joker->id); + joker_object_destroy(&joker_object); // Destroy the joker object if it exists } } - game_shop_create_items(shop_jokers); + list_destroy(&shop_jokers); + + game_shop_create_items(); - for (int i = 0; i < MAX_SHOP_JOKERS; i++) + for (int i = 0; i < list_get_size(shop_jokers); i++) { - if (shop_jokers[i] != NULL) + JokerObject *joker_object = list_get(shop_jokers, i); + if (joker_object != NULL) { - shop_jokers[i]->sprite_object->y = shop_jokers[i]->sprite_object->ty; // Set the y position to the target position - joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation + joker_object->sprite_object->y = joker_object->sprite_object->ty; // Set the y position to the target position + joker_object_shake(joker_object, UNDEFINED); // Give the joker a little wiggle animation } } @@ -2244,7 +2252,26 @@ static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost) static int shop_top_row_get_size() { // TODO: Make dynamic to not allow selecting sold items - return MAX_SHOP_JOKERS + 1; // + 1 to account for next round button + return list_get_size(shop_jokers) + 1; // + 1 to account for next round button +} + +static void game_shop_buy_joker(int shop_joker_idx) +{ + JokerObject *joker_object = list_get(shop_jokers, shop_joker_idx); + joker_push(joker_object); + money -= joker_object->joker->value; // Deduct the money spent on the joker + display_money(money); // Update the money display + + Rect joker_price_rect; + joker_price_rect.left = fx2int(joker_object->sprite_object->tx); + // 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile + joker_price_rect.top = fx2int(joker_object->sprite_object->ty) + CARD_SPRITE_SIZE + 2 * TILE_SIZE; + joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3; + joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE; + + tte_erase_rect_wrapper(joker_price_rect); + + list_remove_by_idx(shop_jokers, shop_joker_idx); // Remove the joker from the shop } static void shop_top_row_on_key_hit(SelectionGrid* selection_grid, Selection* selection) @@ -2269,33 +2296,26 @@ static void shop_top_row_on_key_hit(SelectionGrid* selection_grid, Selection* se else { int shop_joker_idx = selection->x - 1; // - 1 to account for next round button - if (shop_jokers[shop_joker_idx] == NULL + JokerObject *joker_object = list_get(shop_jokers, shop_joker_idx); + if (joker_object == NULL || jokers_top >= MAX_JOKERS_HELD_SIZE - 1 - || money < shop_jokers[shop_joker_idx]->joker->value) + || money < joker_object->joker->value) { return; } - joker_push(shop_jokers[shop_joker_idx]); - money -= shop_jokers[shop_joker_idx]->joker->value; // Deduct the money spent on the joker - display_money(money); // Update the money display - - Rect joker_price_rect; - joker_price_rect.left = fx2int(shop_jokers[shop_joker_idx]->sprite_object->tx); - // 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile - joker_price_rect.top = fx2int(shop_jokers[shop_joker_idx]->sprite_object->ty) + CARD_SPRITE_SIZE + 2*TILE_SIZE; - joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3; - joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE; - - tte_erase_rect_wrapper(joker_price_rect); - - shop_jokers[shop_joker_idx] = NULL; // Remove the joker from the shop + game_shop_buy_joker(shop_joker_idx); + // In Balatro the selection actually stays on the purchased joker it's easier to just move it left selection_grid_move_selection_horz(selection_grid, -1); } } -static void shop_top_row_on_selection_changed(SelectionGrid* selection_grid, int row_idx, const Selection* prev_selection, const Selection* new_selection) + + +static void shop_top_row_on_selection_changed(SelectionGrid* selection_grid, int row_idx, + const Selection* prev_selection, + const Selection* new_selection) { if (prev_selection->y == row_idx) { @@ -2306,7 +2326,8 @@ static void shop_top_row_on_selection_changed(SelectionGrid* selection_grid, int } else { - sprite_object_set_focus(shop_jokers[prev_selection->x - 1]->sprite_object, false); + JokerObject *joker = list_get(shop_jokers, prev_selection->x - 1); + sprite_object_set_focus(joker->sprite_object, false); // -1 to account for next round button } } @@ -2320,7 +2341,8 @@ static void shop_top_row_on_selection_changed(SelectionGrid* selection_grid, int } else { - sprite_object_set_focus(shop_jokers[new_selection->x - 1]->sprite_object, true); + JokerObject *joker = list_get(shop_jokers, new_selection->x - 1); + sprite_object_set_focus(joker->sprite_object, true); // -1 to account for next round button } } @@ -2348,7 +2370,7 @@ static void shop_bottom_row_on_key_hit(SelectionGrid* selection_grid, Selection* { if (money >= reroll_cost) { - game_shop_reroll(shop_jokers, &reroll_cost); + game_shop_reroll(&reroll_cost); } } @@ -2362,7 +2384,7 @@ SelectionGridRow shop_selection_rows[] = SelectionGrid shop_selection_grid = {shop_selection_rows, NUM_ELEM_IN_ARR(shop_selection_rows), {0, 0}}; // Shop menu input and selection -static void game_shop_process_user_input(JokerObject** shop_jokers) +static void game_shop_process_user_input() { if (timer == 1) @@ -2403,13 +2425,18 @@ void game_shop() { change_background(BG_ID_SHOP); - for (int i = 0; i < MAX_SHOP_JOKERS; i++) + if (shop_jokers != NULL) { - if (shop_jokers[i] != NULL) + for (int i = 0; i < list_get_size(shop_jokers); i++) { - joker_object_update(shop_jokers[i]); + JokerObject *joker_object = list_get(shop_jokers, i); + if (joker_object != NULL) + { + joker_object_update(joker_object); + } } } + if (timer % 20 == 0) { @@ -2420,12 +2447,12 @@ void game_shop() { case 0: { - game_shop_intro(shop_jokers); + game_shop_intro(); break; } case 1: { - game_shop_process_user_input(shop_jokers); + game_shop_process_user_input(); break; } case 2: // Outro sequence (menu and shop icon going out of frame) @@ -2439,11 +2466,12 @@ void game_shop() { tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); // Erase the shop prices text - for (int i = 0; i < MAX_SHOP_JOKERS; i++) + for (int i = 0; i < list_get_size(shop_jokers); i++) { - if (shop_jokers[i] != NULL) + JokerObject *joker_object = list_get(shop_jokers, i); + if (joker_object != NULL) { - shop_jokers[i]->sprite_object->ty = int2fx(160); + joker_object->sprite_object->ty = int2fx(160); } } @@ -2477,16 +2505,20 @@ void game_shop() selection_x = 0; // Reset the selection selection_y = 0; // Reset the selection - for (int i = 0; i < MAX_SHOP_JOKERS; i++) + for (int i = 0; i < list_get_size(shop_jokers); i++) { - if (shop_jokers[i] != NULL) + JokerObject* joker_object = list_get(shop_jokers, i); + if (joker_object != NULL) { // Make the joker available back to shop - int_list_append(jokers_available_to_shop, (intptr_t)shop_jokers[i]->joker->id); + + int_list_append(jokers_available_to_shop, (intptr_t)joker_object->joker->id); } - joker_object_destroy(&shop_jokers[i]); // Destroy the joker objects + joker_object_destroy(&joker_object); // Destroy the joker objects } + list_destroy(&shop_jokers); + increment_blind(BLIND_DEFEATED); // TODO: Move to game_round_end()? game_set_state(GAME_BLIND_SELECT); // If we reach here, we should go to the blind select state From ae019be190776498df784207ac95e0a46527addb Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Sat, 16 Aug 2025 06:41:33 +0300 Subject: [PATCH 44/45] Fixed shop initial selection to be visible + extracted shop outro --- source/game.c | 109 +++++++++++++++++++++------------------- source/selection_grid.c | 5 +- 2 files changed, 62 insertions(+), 52 deletions(-) diff --git a/source/game.c b/source/game.c index dab7ff5..0c3f9f0 100644 --- a/source/game.c +++ b/source/game.c @@ -2251,7 +2251,6 @@ static void game_shop_reroll(int *reroll_cost) // Shop input static int shop_top_row_get_size() { - // TODO: Make dynamic to not allow selecting sold items return list_get_size(shop_jokers) + 1; // + 1 to account for next round button } @@ -2317,7 +2316,8 @@ static void shop_top_row_on_selection_changed(SelectionGrid* selection_grid, int const Selection* prev_selection, const Selection* new_selection) { - if (prev_selection->y == row_idx) + // The selection grid system only guarantees that the new selection is within bounds + if (prev_selection->y == row_idx && prev_selection->x >= 0 && prev_selection->x < shop_top_row_get_size()) { if (prev_selection->x == NEXT_ROUND_BTN_SEL_X) { @@ -2380,15 +2380,19 @@ SelectionGridRow shop_selection_rows[] = {1, shop_bottom_row_get_size, shop_bottom_row_on_selection_changed, shop_bottom_row_on_key_hit} }; -// TODO: Initialize selection better -SelectionGrid shop_selection_grid = {shop_selection_rows, NUM_ELEM_IN_ARR(shop_selection_rows), {0, 0}}; +static const Selection SHOP_INIT_SEL = {-1, 0}; + +SelectionGrid shop_selection_grid = {shop_selection_rows, NUM_ELEM_IN_ARR(shop_selection_rows), SHOP_INIT_SEL}; // Shop menu input and selection static void game_shop_process_user_input() { - if (timer == 1) { + // The selection grid is initialized outside of bounds and moved + // to trigger the selection change so the initial selection is visible + shop_selection_grid.selection = SHOP_INIT_SEL; + selection_grid_move_selection_horz(&shop_selection_grid, 1); tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost); } @@ -2421,6 +2425,50 @@ static void game_shop_lights_anim_frame() memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1); } +// Outro sequence (menu and shop icon going out of frame) +static void game_shop_outro() +{ + // Shift the shop panel + main_bg_se_move_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_DOWN); + + main_bg_se_copy_rect_1_tile_vert(TOP_LEFT_PANEL_ANIM_RECT, SE_UP); + + if (timer == 1) + { + tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); // Erase the shop prices text + + for (int i = 0; i < list_get_size(shop_jokers); i++) + { + JokerObject *joker_object = list_get(shop_jokers, i); + if (joker_object != NULL) + { + joker_object->sprite_object->ty = int2fx(160); + } + } + + int y = 6; + memset16(&se_mem[MAIN_BG_SBB][32 * (y - 1)], 0x0006, 1); + memset16(&se_mem[MAIN_BG_SBB][1 + 32 * (y - 1)], 0x0007, 2); + memset16(&se_mem[MAIN_BG_SBB][3 + 32 * (y - 1)], 0x0008, 1); + memset16(&se_mem[MAIN_BG_SBB][4 + 32 * (y - 1)], 0x0009, 4); + memset16(&se_mem[MAIN_BG_SBB][7 + 32 * (y - 1)], 0x000A, 1); + memset16(&se_mem[MAIN_BG_SBB][8 + 32 * (y - 1)], 0x0406, 1); + } + else if (timer == 2) + { + int y = 5; + memset16(&se_mem[MAIN_BG_SBB][32 * (y - 1)], 0x0001, 1); + memset16(&se_mem[MAIN_BG_SBB][1 + 32 * (y - 1)], 0x0002, 7); + memset16(&se_mem[MAIN_BG_SBB][8 + 32 * (y - 1)], 0x0401, 1); + } + + if (timer >= MENU_POP_OUT_ANIM_FRAMES) + { + state = 3; // Go to the next state + timer = 0; // Reset the timer + } +} + void game_shop() { change_background(BG_ID_SHOP); @@ -2455,63 +2503,20 @@ void game_shop() game_shop_process_user_input(); break; } - case 2: // Outro sequence (menu and shop icon going out of frame) + case 2: { - // Shift the shop panel - main_bg_se_move_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_DOWN); - - main_bg_se_copy_rect_1_tile_vert(TOP_LEFT_PANEL_ANIM_RECT, SE_UP); - - if (timer == 1) - { - tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT); // Erase the shop prices text - - for (int i = 0; i < list_get_size(shop_jokers); i++) - { - JokerObject *joker_object = list_get(shop_jokers, i); - if (joker_object != NULL) - { - joker_object->sprite_object->ty = int2fx(160); - } - } - - int y = 6; - memset16(&se_mem[MAIN_BG_SBB][32 * (y - 1)], 0x0006, 1); - memset16(&se_mem[MAIN_BG_SBB][1 + 32 * (y - 1)], 0x0007, 2); - memset16(&se_mem[MAIN_BG_SBB][3 + 32 * (y - 1)], 0x0008, 1); - memset16(&se_mem[MAIN_BG_SBB][4 + 32 * (y - 1)], 0x0009, 4); - memset16(&se_mem[MAIN_BG_SBB][7 + 32 * (y - 1)], 0x000A, 1); - memset16(&se_mem[MAIN_BG_SBB][8 + 32 * (y - 1)], 0x0406, 1); - } - else if (timer == 2) - { - int y = 5; - memset16(&se_mem[MAIN_BG_SBB][32 * (y - 1)], 0x0001, 1); - memset16(&se_mem[MAIN_BG_SBB][1 + 32 * (y - 1)], 0x0002, 7); - memset16(&se_mem[MAIN_BG_SBB][8 + 32 * (y - 1)], 0x0401, 1); - } - - if (timer >= MENU_POP_OUT_ANIM_FRAMES) - { - state = 3; // Go to the next state - timer = 0; // Reset the timer - } - + game_shop_outro(); break; } default: state = 0; // Reset the state - selection_x = 0; // Reset the selection - selection_y = 0; // Reset the selection - for (int i = 0; i < list_get_size(shop_jokers); i++) { JokerObject* joker_object = list_get(shop_jokers, i); if (joker_object != NULL) { - // Make the joker available back to shop - + // Make the joker available back to shop int_list_append(jokers_available_to_shop, (intptr_t)joker_object->joker->id); } joker_object_destroy(&joker_object); // Destroy the joker objects @@ -2526,6 +2531,8 @@ void game_shop() } } + + void game_blind_select() { switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer diff --git a/source/selection_grid.c b/source/selection_grid.c index ab5e1d8..8acc017 100644 --- a/source/selection_grid.c +++ b/source/selection_grid.c @@ -55,7 +55,10 @@ void selection_grid_move_selection_vert(SelectionGrid *selection_grid, int direc // Clip selection to row size new_selection.x = new_row_size - 1; } - selection_grid->rows[selection.y].on_selection_changed(selection_grid, selection.y, &selection, &new_selection); + if (selection.y >= 0 && selection.y < selection_grid->num_rows) + { + selection_grid->rows[selection.y].on_selection_changed(selection_grid, selection.y, &selection, &new_selection); + } selection_grid->rows[new_selection.y].on_selection_changed(selection_grid, new_selection.y, &selection, &new_selection); selection_grid->selection = new_selection; } From 3557e7d34d827ae7a90a97ebb845e7df5578b70b Mon Sep 17 00:00:00 2001 From: MeirGavish Date: Sat, 16 Aug 2025 10:56:22 +0300 Subject: [PATCH 45/45] Fixed inconsistent joker 'A's and rounded card corners --- graphics/joker_gfx3.png | Bin 1109 -> 1073 bytes graphics/joker_gfx5.png | Bin 1058 -> 1053 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/joker_gfx3.png b/graphics/joker_gfx3.png index 959c457b1bc5e5ebe79bf7434c8141042f747e48..9e84c1e1a9bba6d4f61a093f3447050310dc76f8 100644 GIT binary patch delta 1053 zcmV+&1mgSE2(bu|BYy+$>QZ4$FiZ<4y`4De?Sx@kV2p_?DpdIwyIQc=)zT2ZrvnVr^5E8>YnsqG>Fopn zB+6R=;Fz{ipnuB0*wq36c=_W`L;Ri&DCV*-Obf+a7K|}y7al*m@GLbRfGGP-*Dz4w z=f(pN<*@wHO^^-(s7*!sR;cknZ3Y;o)$oQDhMyV_)Mh|feqRSr7^a2!nN#sRS#s9X zy5x8|HYZU2W!5U54^eT{)4DMHO53#C_#n*BoW`~naDRSkU=WsBt1^F}17yZemb&Zo z+_L$ZQ_qbo3}nV1c30~3+_GiXs>B~EP*2Y_JDyj^(pVi!`|8ArVg1PQ+?HNITYAA) zCkVa{FiZ=5BPmSJH4DS|o2G{IGOy$MeIuzzvw-jP!}^ghjK67WI4|=$uFrFWP$+F| z+Z0cpPk%VdgG(8^w6R?$FKukwgG-q@Ifcq0Cy4(bGv&#DkeLe29~cE>akamv9sNC7 zky~?}S3lPR+lECL{@>q&+qx0x0Nb{qX|)5?Y{vlD=nw$l;f0L7J-@H!3oyzSVB3JE zbn*>^oB!9n7r5!c-zmn9GWj9#AuWWpCGUQ6~W2 z%OEU@xvV3*@4+XdMV4>8j6bco#tP>C2nSGO; zWG0(zFa8jA@@A56-rLE{o5X@bex(|y>}hrF%6UuI#;;TXpnoHL0M@lD=Ox22MF#=^ z7#Td5DS35m1Ae6%7zCkX{KmZ{eoFv2oH2&nbY9p#zIoXe*tTtP&qgP-I!eABcOi$C ziiKD}ZaRCw;b*2sQ9rhB5z<>0^qnF_J{hhKhzJ$^}rYtM_QTk=LWhlH_+V{ zKQaK0>qW3F*ngHK+UyVY0|0u;>i{4P+cYxe&kb|~03Lq-(-uE60HtC9j_aXREPycv zs}b?PjmT2x0f=(ka7`i;K6f5~C@1ABCqdc?pg9!jze1e{nj^q*y|yQ;Bz)>T&>R6t z`LO|@a$FCyGY8`QfiKt7y4-X=vmj9ZBI_0BzfqIwX@6Z3zR@%tc3!91nS;#c0?wxn z>a@sujrrODsGNV`UutO=w$08QL{4N$q;mfErCLk7ux*j`8u1e?)Q_JXm(Ex2GR)HUROSUt7{wDw?c7znh$)ve@m*r{Q8|JPuRQ0e4|vDI)CHLSpbI)^YZf6 zrhioCTjQ)YM%4Ker%wVnbeNZG+j~-(CqX8Bqf9XDJaw4cm$x>hHarMvrE;D+%HPB6rgYFC0MU;@Qk9AYDZAs&*S7bhg9ZVJehk7g8Ue$TW9TWb z_Ak9>h*doFslF@CEut6?aDL&^?E(^VanGogY-G#lST4p>vb}EA!2f)u=80YLXPVx@1tTxU9and(K<4y z0)%ay91$uO<;9Hv{;?!V%Dn*4v5%8Rdx4|mD?9T)eIEY@ps=EGR6Bp900000NkvXX Hu0mjfe~k`B diff --git a/graphics/joker_gfx5.png b/graphics/joker_gfx5.png index 70c21b6a059696696b1c518dc8f33262da3961d0..bc4e1125a567e3cb6616ddc0acee1ec1bd98be3f 100644 GIT binary patch delta 1032 zcmV+j1o!)*2%QL!B!A>dL_t(&f#q30NLxV||J|c>(T*JocFd9}oO=P6m zwG~$aw@*;ii(k3}c;!+M0)xnRvSnG`^EFWqe&vXGBB|h3lQYt44Zm0ZT)sdVUQSF= zN+~r>lUgO&-+#M1>IKs@scD)Oa-Hm6Z+_PhV6n$MD*h_$xhM~sui6lBE zG8Hla=o}nz$VVrqLvsSpb<@`&%MJ7Bb@j;HIym z!g!$Q5M6#x2dIqqLg(O!GLiX#%6Km<%-(A8`%0I`Uw>1M{(NsE=EjB{vZL)yKPr8p zVgK0C-x{ArYsdE=uM!P*XHjKHA?{=R#!L5MNg^GV`yu8I* zTh?)QF>d#n6Lk2sc0hJ*#i4A-xN;|uJ#-k!7ec@~mQXH)W^!H1 zFc9G#0+b@Vx{Ua%*AB5)ot<4>4(D~q@i(Ac3di?F{&ET2fMacbZwC-kTma(^? z76w$h+}7j=+BZUOecAYWI6>qLvW7s%VZP0XRiVJ&(+5F3k(4@IbwMhw!8gBn7zqRH ziaN+)sMh?_9iaOko-Pc-@TIe!{IbIk@E`p>{tpuM7aR++mVf{N002ovPDHLkU;%=* CNd3P6 delta 1037 zcmV+o1oHcx2%-p(B!B5iL_t(&f#sP$NE|^F#=luY8cmrZUDfrn73#w8?|<$jqV0jC9R+|yydzZj z{?QrhyJ`@;nDh1E>$w6IgCGk467de0riszXY0LKQ%jZB~P1CGC?}Ff|M)Ebc7a26W zvE~YJ`w6N>@uf3>?_4TEpb_~@Hciv}eML2b@7N-lN;|Nf;S5@<UNQ`W8irA2SJ~Yg&39b_Z0)g#ihmXMT(k$>u)vRU z^FTQus(jA?I63d7uE7zH|7*LIozI)7`cFZMKJVQkoDJK5d#)1@yp z9p-KIo$+b3w{6;N?>;^B)u-nkklk35Msl&I*(xuL4P#;JyH#gFa7$oR<;33^uT1gw zwoMc-#;rOFf(l=024pwZY@H2hSGGYVQ)vu5Yjtd2tHl21BLh|Z-+$f);wygzcqQT; zNW|By+<%(E_I_Ok=`J*W@xp&!o&lhgf^eDFkah)MT3M@|9&{W%f*bCukle$_nDa|J59jDJX`(zc|B-}C_c`ajv-mTp4(M`zMo z8C5=?^zfS=0DL&zv&v0}d1b!RCdiyGo}N3lF&oMRf0s!#CdF$KAQP`(jztIOIqA_yWg$QS}0hxsxCJ1qtNo<4|@skAiUP8X!&7<}`^ z!$=rnSJXicL-poMXMpPe@KmK~ny)?^$(J35fdA;<