Merge branch 'main' into jokers_refactors

This commit is contained in:
MeirGavish
2025-07-23 19:33:39 +03:00
7 changed files with 235 additions and 175 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 B

After

Width:  |  Height:  |  Size: 1.5 KiB

+3 -3
View File
@@ -8,8 +8,8 @@
// Card suits
#define HEARTS 0
#define DIAMONDS 1
#define CLUBS 2
#define CLUBS 1
#define DIAMONDS 2
#define SPADES 3
#define NUM_SUITS 4
@@ -66,6 +66,6 @@ CardObject *card_object_new(Card *card);
void card_object_destroy(CardObject **card_object);
void card_object_update(CardObject *card_object); // Update the card object position and scale
void card_object_set_sprite(CardObject *card_object, int layer);
void card_object_score(CardObject *card_object, mm_word sound_id); // This doesn't actually score anything, it just performs an animation and plays a sound effect
void card_object_shake(CardObject *card_object, mm_word sound_id); // This doesn't actually score anything, it just performs an animation and plays a sound effect
#endif // CARD_H
+5 -14
View File
@@ -36,7 +36,7 @@ typedef struct
u8 modifier; // base, foil, holo, poly, negative
u8 value;
u8 rarity;
bool proccessed;
bool processed;
} Joker;
typedef struct // copy of CardObject in card.h
@@ -66,16 +66,7 @@ typedef struct // These jokers are triggered after the played hand has finished
int xmult;
int money;
bool retrigger; // Retrigger played hand (e.g. "Dusk" joker, even though on the wiki it says "On Scored" it makes more sense to have it here)
} IndependentEffect;
typedef struct
{
int chips;
int mult;
int xmult;
int money;
bool retrigger; // Retrigger scored card
} OnScoredEffect;
} JokerEffect;
void joker_init();
@@ -84,12 +75,12 @@ void joker_destroy(Joker **joker);
// Unique effects like "Four Fingers" or "Credit Card" will be hard coded into game.c with a conditional check for the joker ID from the players owned jokers
// game.c should probably be restructured so most of the variables in it are moved to some sort of global variable header file so they can be easily accessed and modified for the jokers
IndependentEffect joker_independent_effect(Joker *joker);
OnScoredEffect joker_on_scored(Joker *joker, Card *scored_card);
JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card);
JokerObject *joker_object_new(Joker *joker);
void joker_object_destroy(JokerObject **joker_object);
void joker_object_update(JokerObject *joker_object);
void joker_object_score(JokerObject *joker_object, mm_word sound_id); // This doesn't actually score anything, it just performs an animation and plays a sound effect
void joker_object_shake(JokerObject *joker_object, mm_word sound_id); // This doesn't actually score anything, it just performs an animation and plays a sound effect
bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips, int *mult, int *xmult, int *money, bool *retrigger); // This scores the joker and returns true if it was scored successfully (Card = NULL means the joker is independent and not scored by a card)
#endif // JOKER_H
+1 -1
View File
@@ -153,7 +153,7 @@ void card_object_set_sprite(CardObject *card_object, int layer)
card_object->sprite = sprite_new(ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF, ATTR1_SIZE_32, card_sprite_lut[card_object->card->suit][card_object->card->rank], 0, layer);
}
void card_object_score(CardObject *card_object, mm_word sound_id)
void card_object_shake(CardObject *card_object, mm_word sound_id)
{
card_object->vscale = float2fx(0.3f); // Scale down the card when it's scored
card_object->vrotation = float2fx(8.0f); // Rotate the card when it's scored
+160 -142
View File
@@ -30,6 +30,7 @@ static int background = 0;
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
static enum HandType hand_type = NONE;
@@ -63,8 +64,7 @@ static int hand_size = 8; // Default hand size is 8
static int cards_drawn = 0;
static int hand_selections = 0;
static int card_focused = 0;
static int previous_card_focused = 0;
static int selection_x = 0;
static int selection_y = 0;
static bool sort_by_suit = false;
@@ -422,12 +422,13 @@ void change_background(int id)
}
else if (id == BG_ID_CARD_SELECTING)
{
tte_erase_rect_wrapper(HAND_SIZE_RECT_PLAYING);
REG_WIN0V = (REG_WIN0V << 8) | 0x80; // Set window 0 top to 128
if (background == BG_ID_CARD_PLAYING)
{
int offset = 11;
memcpy16(&se_mem[MAIN_BG_SBB][SE_ROW_LEN * offset], &background_gfxMap[SE_ROW_LEN * offset], SE_ROW_LEN * 8);
tte_erase_rect_wrapper(HAND_SIZE_RECT_PLAYING);
REG_WIN0V = (REG_WIN0V << 8) | 0x80;
}
else
{
@@ -438,8 +439,6 @@ void change_background(int id)
GRIT_CPY(&tile8_mem[MAIN_BG_CBB], background_gfxTiles); // Deadass i have no clue how any of these memory things work but I just messed with them until stuff worked
GRIT_CPY(&se_mem[MAIN_BG_SBB], background_gfxMap);
tte_erase_rect_wrapper(HAND_SIZE_RECT_PLAYING);
if (current_blind == BIG_BLIND) // Change text and palette depending on blind type
{
main_bg_se_copy_rect(BIG_BLIND_TITLE_SRC_RECT, TOP_LEFT_BLIND_TITLE_POINT);
@@ -469,7 +468,7 @@ void change_background(int id)
background = BG_ID_CARD_PLAYING;
}
REG_WIN0V = (REG_WIN0V << 8) | 0xA0;
REG_WIN0V = (REG_WIN0V << 8) | 0xA0; // Set window 0 bottom to 160
for (int i = 0; i <= 2; i++)
{
@@ -480,7 +479,7 @@ void change_background(int id)
}
else if (id == BG_ID_ROUND_END)
{
if (background != BG_ID_CARD_SELECTING || background != BG_ID_CARD_PLAYING)
if (background != BG_ID_CARD_SELECTING && background != BG_ID_CARD_PLAYING)
{
change_background(BG_ID_CARD_SELECTING);
background = BG_ID_ROUND_END;
@@ -638,15 +637,31 @@ void set_temp_score(int value)
void set_score(int value)
{
if (value == 0) // Clear if 0
// Clear the existing text before redrawing
tte_erase_rect_wrapper(SCORE_RECT);
char score_suffix = ' ';
int display_value = value;
if(value >= 10000)
{
Rect rect = SCORE_RECT;
rect.left += 1;
tte_erase_rect_wrapper(rect);
score_suffix = 'k';
display_value = value / 1000; // 12,986 = 12k
}
int x_offset = 32;
tte_printf("#{P:%d,48; cx:0xF000}%d", x_offset, value);
// Calculate text width: digits + suffix character (if 'k')
int num_digits = get_digits(display_value);
int text_width = num_digits * TILE_SIZE;
if(score_suffix == 'k')
{
text_width += TILE_SIZE; // Add width for 'k' suffix
}
// Calculate center position within SCORE_RECT
int rect_width = SCORE_RECT.right - SCORE_RECT.left;
int x_offset = SCORE_RECT.left + (rect_width - text_width) / 2;
tte_printf("#{P:%d,48; cx:0xF000}%d%c", x_offset, display_value, score_suffix);
}
void set_money(int value)
@@ -806,7 +821,7 @@ void card_draw()
void hand_set_focus(int index)
{
if (index < 0 || index > hand_top || hand_state != HAND_SELECT) return;
card_focused = index;
selection_x = index;
mm_sound_effect sfx_focus = {{SFX_CARD_FOCUS}, 1024 + rand() % 512, 0, 255, 128,};
mmEffectEx(&sfx_focus);
@@ -814,11 +829,11 @@ void hand_set_focus(int index)
void hand_select()
{
if (hand_state != HAND_SELECT || hand[card_focused] == NULL) return;
if (hand_state != HAND_SELECT || hand[selection_x] == NULL) return;
if (hand[card_focused]->selected)
if (hand[selection_x]->selected)
{
hand[card_focused]->selected = false;
hand[selection_x]->selected = false;
hand_selections--;
mm_sound_effect sfx_select = {{SFX_CARD_SELECT}, 1024, 0, 255, 128,};
@@ -826,7 +841,7 @@ void hand_select()
}
else if (hand_selections < MAX_SELECTION_SIZE)
{
hand[card_focused]->selected = true;
hand[selection_x]->selected = true;
hand_selections++;
mm_sound_effect sfx_deselect = {{SFX_CARD_DESELECT}, 1024, 0, 255, 128,};
@@ -924,9 +939,27 @@ void game_round_init()
Rect blind_req_text_rect = BLIND_REQ_TEXT_RECT;
int blind_requirement = blind_get_requirement(current_blind, ante);
char score_suffix = ' ';
if(blind_requirement >= 10000)
{
// clear existing text
tte_erase_rect_wrapper(blind_req_text_rect);
score_suffix = 'k';
blind_requirement /= 1000; // 11,000 = 11k
}
// Update text rect for right alignment AFTER shortening the number
update_text_rect_to_right_align_num(&blind_req_text_rect, blind_requirement, OVERFLOW_RIGHT);
tte_printf("#{P:%d,%d; cx:0xE000}%d", blind_req_text_rect.left, blind_req_text_rect.top, blind_requirement); // Blind requirement
// If we added a suffix, adjust position to account for the extra character
if(score_suffix == 'k')
{
blind_req_text_rect.left -= TILE_SIZE; // Move left by one character width to make room for 'k'
}
tte_printf("#{P:%d,%d; cx:0xE000}%d%c", blind_req_text_rect.left, blind_req_text_rect.top, blind_requirement, score_suffix); // Blind requirement
tte_printf("#{P:%d,%d; cx:0xC000}$%d", BLIND_REWARD_RECT.left, BLIND_REWARD_RECT.top, blind_get_reward(current_blind)); // Blind reward
deck_shuffle(); // Shuffle the deck at the start of the round
@@ -1007,80 +1040,81 @@ static void game_playing_process_input_and_state()
{
if (hand_state == HAND_SELECT)
{
static bool discard_button_highlighted = false; // true = play button highlighted, false = discard button highlighted
if (key_hit(KEY_LEFT))
{
if (selection_y == 0)
{
hand_set_focus(card_focused + 1); // The reason why this adds 1 is because the hand is drawn from right to left. There is no particular reason for this, it's just how I did it.
hand_set_focus(selection_x + 1); // The reason why this adds 1 is because the hand is drawn from right to left. There is no particular reason for this, it's just how I did it.
}
else
{
card_focused = -2; // Play button
discard_button_highlighted = false; // Play button
}
}
else if (key_hit(KEY_RIGHT))
{
if (selection_y == 0)
{
hand_set_focus(card_focused - 1);
hand_set_focus(selection_x - 1);
}
else
{
card_focused = -3; // Discard button
discard_button_highlighted = true; // Discard button
}
}
else if (key_hit(KEY_UP) && selection_y != 0)
{
selection_y = 0;
card_focused = previous_card_focused;
}
else if (key_hit(KEY_DOWN) && selection_y != 1)
{
selection_y = 1;
previous_card_focused = card_focused;
if (card_focused > hand_top / 2)
if (selection_x > hand_top / 2)
{
card_focused = -2; // Play button
discard_button_highlighted = false; // Play button
}
else
{
card_focused = -3; // Discard button
discard_button_highlighted = true; // Discard button
}
}
if (card_focused == -2) // Play button logic
if (selection_y == 1) // On row of play/discard buttons
{
memset16(&pal_bg_mem[1], 0xFFFF, 1);
memcpy16(&pal_bg_mem[9], &pal_bg_mem[12], 1);
if (key_hit(SELECT_CARD) && hands > 0 && hand_play())
if (discard_button_highlighted == false) // Play button logic
{
hand_state = HAND_PLAY;
card_focused = 0;
selection_y = 0;
previous_card_focused = 0;
set_hands(--hands);
memset16(&pal_bg_mem[1], 0xFFFF, 1);
memcpy16(&pal_bg_mem[9], &pal_bg_mem[12], 1);
if (key_hit(SELECT_CARD) && hands > 0 && hand_play())
{
hand_state = HAND_PLAY;
selection_x = 0;
selection_y = 0;
set_hands(--hands);
}
}
}
else if (card_focused == -3) // Discard button logic
{
memcpy16(&pal_bg_mem[1], &pal_bg_mem[7], 1);
memset16(&pal_bg_mem[9], 0xFFFF, 1);
if (key_hit(SELECT_CARD) && discards > 0 && hand_discard())
else // Discard button logic
{
hand_state = HAND_DISCARD;
card_focused = 0;
selection_y = 0;
previous_card_focused = 0;
set_hands(--discards);
set_hand();
tte_printf("#{P:%d,%d; cx:0xE000}%d", DISCARDS_TEXT_RECT.left, DISCARDS_TEXT_RECT.top, discards);
memcpy16(&pal_bg_mem[1], &pal_bg_mem[7], 1);
memset16(&pal_bg_mem[9], 0xFFFF, 1);
if (key_hit(SELECT_CARD) && discards > 0 && hand_discard())
{
hand_state = HAND_DISCARD;
selection_x = 0;
selection_y = 0;
set_hands(--discards);
set_hand();
tte_printf("#{P:%d,%d; cx:0xE000}%d", DISCARDS_TEXT_RECT.left, DISCARDS_TEXT_RECT.top, discards);
}
}
}
if (card_focused >= 0)
if (selection_y == 0) // On row of cards
{
memcpy16(&pal_bg_mem[1], &pal_bg_mem[7], 1); // Play button highlight color
memcpy16(&pal_bg_mem[9], &pal_bg_mem[12], 1); // Discard button highlight color
@@ -1229,20 +1263,22 @@ static void cards_in_hand_update_loop(bool* discarded_card, int* played_selectio
hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top];
break;
case HAND_SELECT:
if (i == card_focused && !hand[i]->selected)
bool is_focused = (i == selection_x && selection_y == 0);
if (is_focused && !hand[i]->selected)
{
hand_y -= int2fx(10);
}
else if (i != card_focused && hand[i]->selected)
else if (!is_focused && hand[i]->selected)
{
hand_y -= int2fx(15);
}
else if (i == card_focused && hand[i]->selected)
else if (is_focused && hand[i]->selected)
{
hand_y -= int2fx(20);
}
if (i != card_focused && hand[i]->y > hand_y)
if (i != selection_x && hand[i]->y > hand_y)
{
hand[i]->y = hand_y;
hand[i]->vy = 0;
@@ -1547,82 +1583,70 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection
{
// So pretend "played_selections" is now called "scored_cards" and it counts the number of cards that have been scored
int scored_cards = 0;
for (int j = played_top; j >= 0; j--)
for (int j = 0; j <= played_top; j++)
{
if (played[played_top - j]->selected)
tte_erase_rect_wrapper(PLAYED_CARDS_SCORES_RECT);
if (*played_selections > 0)
{
scored_cards++;
for (int k = 0; k <= jokers_top; k++)
{
if (joker_object_score(jokers[k], played[*played_selections - 1]->card, &chips, &mult, NULL, &money, NULL)) // NULLs aren't implemented yet
{
set_chips(chips);
set_mult(mult);
set_money(money);
return;
}
}
}
if (played[j]->selected)
{
scored_cards = j + 1; // Count the number of cards that have been scored
if (scored_cards > *played_selections)
{
tte_erase_rect_wrapper(PLAYED_CARDS_SCORES_RECT);
tte_set_pos(fx2int(played[played_top - j]->x) + 8, 48); // Offset of 16 pixels to center the text on the card
for (int k = 0; k <= jokers_top; k++)
{
if (jokers[k] != NULL)
{
jokers[k]->joker->processed = false; // Reset the joker's processed state for the next score
}
}
tte_set_pos(fx2int(played[j]->x) + 8, 48); // Offset of 16 pixels to center the text on the card
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)
snprintf(score_buffer, sizeof(score_buffer), "+%d", card_get_value(played[played_top - j]->card));
snprintf(score_buffer, sizeof(score_buffer), "+%d", card_get_value(played[j]->card));
tte_write(score_buffer);
*played_selections = scored_cards;
card_object_score(played[played_top - j], SFX_CARD_SELECT);
card_object_shake(played[j], SFX_CARD_SELECT);
// Relocated card scoring logic here
chips += card_get_value(played[played_top - j]->card);
chips += card_get_value(played[j]->card);
set_chips(chips);
break;
}
}
if (j == 0 && scored_cards == *played_selections) // Check if it's the last card
if (j == played_top && scored_cards == *played_selections) // Check if it's the last card
{
tte_erase_rect_wrapper(PLAYED_CARDS_SCORES_RECT);
for (int k = 0; k <= jokers_top; k++)
for (int k = 0; k <= jokers_top; k++) // Independent joker scoring loop
{
if (jokers[k]->joker->proccessed == false)
{
IndependentEffect joker_effect = joker_independent_effect(jokers[k]->joker);
IndependentEffect zero_effect = {0};
if (joker_object_score(jokers[k], NULL, &chips, &mult, NULL, &money, NULL)) // NULLs aren't implemented yet
{
set_chips(chips);
set_mult(mult);
set_money(money);
if (memcmp(&joker_effect, &zero_effect, sizeof(IndependentEffect)) != 0)
{
chips += joker_effect.chips;
set_chips(chips);
mult += joker_effect.mult;
set_mult(mult);
// TODO: XMult
money += joker_effect.money;
set_money(money);
// TODO: Retrigger
tte_set_pos(fx2int(jokers[k]->x) + 8, 48); // Offset of 16 pixels to center the text on the card
char score_buffer[12];
if (joker_effect.chips > 0)
{
tte_set_special(0xD000); // Blue
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.chips);
}
else if (joker_effect.mult > 0)
{
tte_set_special(0xE000); // Red
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult);
}
else if (joker_effect.money > 0)
{
tte_set_special(0xC000); // Yellow
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.money);
}
tte_write(score_buffer);
jokers[k]->joker->proccessed = true; // Mark the joker as processed
joker_object_score(jokers[k], SFX_CARD_SELECT);
return; // Returning was just the easiest way to break out of the loop
}
return; // Returning was just the easiest way to break out of the loop
}
}
@@ -1630,7 +1654,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection
{
if (jokers[k] != NULL)
{
jokers[k]->joker->proccessed = false; // Reset the joker's processed state for the next round
jokers[k]->joker->processed = false; // Reset the joker's processed state for the next round
}
}
@@ -1803,7 +1827,9 @@ static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists
}
shop_jokers[i] = joker_object_new(joker_new(DEFAULT_JOKER_ID));
u8 joker_id = random() % MAX_JOKERS;
shop_jokers[i] = joker_object_new(joker_new(joker_id));
shop_jokers[i]->x = int2fx(120 + i * 32);
shop_jokers[i]->y = int2fx(160);
shop_jokers[i]->tx = shop_jokers[i]->x;
@@ -1816,7 +1842,7 @@ static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
if (first_time == false)
{
shop_jokers[i]->y = shop_jokers[i]->ty; // If it's not the first time, set the y position to the target position
joker_object_score(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
}
sprite_position(shop_jokers[i]->sprite, fx2int(shop_jokers[i]->x), fx2int(shop_jokers[i]->y));
@@ -1871,8 +1897,6 @@ void game_round_end_cleanup()
void game_round_end()
{
static int state = 0;
static int blind_reward = 0;
static int hand_reward = 0;
static int interest_reward = 0;
@@ -2127,9 +2151,6 @@ void game_round_end()
void game_shop()
{
change_background(BG_ID_SHOP);
// TODO: Later move these static variables somewhere else so they can be reused for each game state
static int state = 0;
static JokerObject *shop_jokers[MAX_SHOP_JOKERS] = {NULL};
@@ -2144,10 +2165,6 @@ void game_shop()
const int reroll_base_cost = 5; // Base cost for rerolling the shop items
static int reroll_cost = reroll_base_cost;
// these are for controlling the shop menu
static bool top_row = true;
static ushort selection_x = 0;
// temp variables for future implementation
const ushort max_items_top = MAX_SHOP_JOKERS;
const ushort max_items_bottom = 0;
@@ -2221,7 +2238,7 @@ void game_shop()
// Shop input logic
if (key_hit(KEY_UP))
{
top_row = true;
selection_y = 0;
if (selection_x > max_items_top)
{
@@ -2230,7 +2247,7 @@ void game_shop()
}
else if (key_hit(KEY_DOWN))
{
top_row = false;
selection_y = 1;
if (selection_x > max_items_bottom)
{
@@ -2246,11 +2263,11 @@ void game_shop()
}
else if (key_hit(KEY_RIGHT))
{
if (top_row && selection_x < max_items_top)
if (selection_y == 0 && selection_x < max_items_top)
{
selection_x++;
}
else if (!top_row && selection_x < max_items_bottom)
else if (selection_y == 1 && selection_x < max_items_bottom)
{
selection_x++;
}
@@ -2260,7 +2277,7 @@ void game_shop()
memcpy16(&pal_bg_mem[5], &pal_bg_mem[16], 1);
// Shop selection logic
if (selection_x == 0 && top_row)
if (selection_x == 0 && selection_y == 0)
{
memset16(&pal_bg_mem[5], 0xFFFF, 1);
@@ -2278,7 +2295,7 @@ void game_shop()
// And I don't care enough to fix it right now.
}
}
else if (selection_x == 0 && !top_row)
else if (selection_x == 0 && selection_y == 1)
{
memset16(&pal_bg_mem[7], 0xFFFF, 1);
@@ -2298,7 +2315,7 @@ void game_shop()
{
if (shop_jokers[i] != NULL)
{
if (i == selection_x - 1 && top_row)
if (i == selection_x - 1 && selection_y == 0)
{
shop_jokers[i]->ty = int2fx(61);
@@ -2376,7 +2393,7 @@ void game_shop()
reroll_cost = reroll_base_cost;
selection_x = 0; // Reset the selection
top_row = true; // Reset the top row selection
selection_y = 0; // Reset the selection
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
{
@@ -2392,10 +2409,6 @@ void game_shop()
void game_blind_select()
{
static int state = 0;
static bool top_row = true; // There's only one row in this game state, but this is here for consistency with the shop state if we make these variables global or something
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 coming into frame)
@@ -2418,18 +2431,23 @@ void game_blind_select()
}
case 1: // Blind select input and selection
{
if (timer == 1 && current_blind == BOSS_BLIND)
{
selection_y = 0;
}
// Blind select input logic
if (key_hit(KEY_UP))
{
top_row = true;
selection_y = 0;
}
else if (key_hit(KEY_DOWN))
else if (key_hit(KEY_DOWN) && current_blind != BOSS_BLIND)
{
top_row = false;
selection_y = 1;
}
else if (key_hit(SELECT_CARD))
{
if (top_row) // Blind selected
if (selection_y == 0) // Blind selected
{
state++;
timer = 0;
@@ -2457,7 +2475,7 @@ void game_blind_select()
}
}
if (top_row)
if (selection_y == 0)
{
memset16(&pal_bg_mem[18], 0xFFFF, 1);
memcpy16(&pal_bg_mem[10], &pal_bg_mem[5], 1);
@@ -2546,7 +2564,7 @@ void game_blind_select()
default:
state = 0;
timer = 0;
top_row = true;
selection_y = 0;
background = UNDEFINED;
game_set_state(GAME_PLAYING);
break;
+9 -9
View File
@@ -26,7 +26,7 @@ static void clip_se_rect_to_screenblock(Rect* rect)
u16 main_bg_se_get_tile(BG_POINT pos)
{
return se_mem[MAIN_BG_SBB][pos.x + SE_ROW_LEN * pos.y];
return se_mat[MAIN_BG_SBB][pos.y][pos.x];
}
// Clips a rect of screenblock entries to be within one step of
@@ -55,7 +55,7 @@ void main_bg_se_clear_rect(Rect se_rect)
for (int y = se_rect.top; y < se_rect.bottom; y++)
{
memset16(&(se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * y]), 0x0000, rect_width(&se_rect));
memset16(&(se_mat[MAIN_BG_SBB][y][se_rect.left]), 0x0000, rect_width(&se_rect));
}
}
@@ -77,14 +77,14 @@ static void main_bg_se_copy_or_move_rect_1_tile_vert(Rect se_rect, int direction
for (int y = start; y != end - direction; y -= direction)
{
memcpy16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (y + direction)],
&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * y],
memcpy16(&(se_mat[MAIN_BG_SBB][y + direction][se_rect.left]),
&se_mat[MAIN_BG_SBB][y][se_rect.left],
rect_width(&se_rect));
}
if (move)
{
memset16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (end)], 0x0000, rect_width(&se_rect));
memset16(&se_mat[MAIN_BG_SBB][end][se_rect.left], 0x0000, rect_width(&se_rect));
}
}
@@ -124,7 +124,7 @@ void main_bg_se_copy_rect(Rect se_rect, BG_POINT pos)
for (int sy = 0; sy < height; sy++)
{
memcpy16(&se_mem[MAIN_BG_SBB][pos.x + SE_ROW_LEN * (pos.y + sy)],
memcpy16(&se_mat[MAIN_BG_SBB][pos.y + sy][pos.x],
&tile_map[sy][0],
width);
}
@@ -143,7 +143,7 @@ void main_bg_se_copy_tile_to_rect(u16 tile, Rect se_rect)
for (int sy = 0; sy < height; sy++)
{
memset16(&se_mem[MAIN_BG_SBB][se_rect.left + SE_ROW_LEN * (se_rect.top + sy)], tile, width);
memset16(&se_mat[MAIN_BG_SBB][se_rect.top + sy][se_rect.left], tile, width);
}
}
@@ -155,11 +155,11 @@ void tte_erase_rect_wrapper(Rect rect)
void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direction)
{
int num_digits = get_digits(num);
if (overflow_direction == OVERFLOW_RIGHT)
if (overflow_direction == OVERFLOW_LEFT)
{
rect->left = max(0, rect->right - num_digits * TILE_SIZE);
}
else if (overflow_direction == OVERFLOW_LEFT)
else if (overflow_direction == OVERFLOW_RIGHT)
{
int num_fitting_digits = rect_width(rect) / TILE_SIZE;
if (num_digits < num_fitting_digits)
+57 -6
View File
@@ -4,9 +4,11 @@
#include "joker_gfx.h"
#include "graphic_utils.h"
#include "card.h"
#include "soundbank.h"
#include <maxmod.h>
#include <stdlib.h>
#include <string.h>
const static u8 joker_data_lut[MAX_JOKERS][2] = // Rarity, Value
{
@@ -46,7 +48,7 @@ Joker *joker_new(u8 id)
joker->modifier = BASE_EDITION; // TODO: Make this random later
joker->value = joker_data_lut[id][1] + edition_price_lut[joker->modifier]; // Base value + edition price
joker->rarity = joker_data_lut[id][0];
joker->proccessed = false;
joker->processed = false;
return joker;
}
@@ -58,17 +60,21 @@ void joker_destroy(Joker **joker)
*joker = NULL;
}
IndependentEffect joker_independent_effect(Joker *joker)
JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card)
{
IndependentEffect effect = {0};
JokerEffect effect = {0};
switch (joker->id)
{
case DEFAULT_JOKER_ID: // Default Joker
if (scored_card != NULL) break; // Joker is independent, no effect
effect.mult = 4;
break;
case GREEDY_JOKER_ID: // Greedy Joker
// Nothing because this joker is a scored type
if (scored_card != NULL && scored_card->suit == DIAMONDS) // If the scored card is a diamond
{
effect.mult = 3;
}
break;
default:
break;
@@ -140,8 +146,53 @@ void joker_object_update(JokerObject *joker_object)
card_object_update(card_object);
}
void joker_object_score(JokerObject *joker_object, mm_word sound_id) // Another derived function of card_object
void joker_object_shake(JokerObject *joker_object, mm_word sound_id)
{
CardObject *card_object = (CardObject *)joker_object;
card_object_score(card_object, sound_id);
card_object_shake(card_object, sound_id);
}
bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips, int *mult, int *xmult, int *money, bool *retrigger)
{
if (joker_object->joker->processed == true) return false; // If the joker has already been processed, return false
JokerEffect joker_effect = joker_get_score_effect(joker_object->joker, scored_card);
if (memcmp(&joker_effect, &(JokerEffect){0}, sizeof(JokerEffect)) != 0)
{
*chips += joker_effect.chips;
*mult += joker_effect.mult;
// TODO: XMult
*money += joker_effect.money;
// TODO: Retrigger
tte_set_pos(fx2int(joker_object->x) + 8, 48); // Offset of 16 pixels to center the text on the card
char score_buffer[12];
if (joker_effect.chips > 0)
{
tte_set_special(0xD000); // Blue
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.chips);
}
else if (joker_effect.mult > 0)
{
tte_set_special(0xE000); // Red
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult);
}
else if (joker_effect.money > 0)
{
tte_set_special(0xC000); // Yellow
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.money);
}
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
return true;
}
return false;
}