29 {.chips = 0, .mult = 0, .display_name = NULL },
30 {.chips = 5, .mult = 1, .display_name =
"Hi-Card"},
31 {.chips = 10, .mult = 2, .display_name =
"Pair" },
32 {.chips = 20, .mult = 2, .display_name =
"2 Pair" },
33 {.chips = 30, .mult = 3, .display_name =
"3 OAK" },
34 {.chips = 30, .mult = 4, .display_name =
"Strt" },
35 {.chips = 35, .mult = 4, .display_name =
"Flush" },
36 {.chips = 40, .mult = 4, .display_name =
"Full H" },
37 {.chips = 60, .mult = 7, .display_name =
"4 OAK" },
38 {.chips = 100, .mult = 8, .display_name =
"Strt F" },
39 {.chips = 100, .mult = 8, .display_name =
"Royal F"},
40 {.chips = 120, .mult = 12, .display_name =
"5 OAK" },
41 {.chips = 140, .mult = 14, .display_name =
"Flush H"},
42 {.chips = 160, .mult = 16, .display_name =
"Flush 5"}
47static const Rect HAND_TYPE_RECT = {8, 64, 64, 72};
58 enum HandType hand_type;
70 .contained_hands = {{{0}}},
81const char* get_hand_type_name(
enum HandType hand_type)
83 if (hand_type <= NONE || hand_type > FLUSH_FIVE)
86 return HAND_BASE_VALUES[hand_type].display_name;
98 s_hand.state = new_hand_state;
108 return s_hand.hand_top;
113 s_hand.hand_top = new_hand_top;
118 return s_hand.hand_top + 1;
123 return s_hand.hand_selections;
128 s_hand.hand_selections = new_selections;
133 return s_hand.hand_type;
138 return &s_hand.contained_hands;
141static void print_hand_type(
const char* hand_type_str)
143 if (hand_type_str == NULL)
146 Rect hand_type_rect = HAND_TYPE_RECT;
149 "#{P:%d,%d; cx:0x%X000}%s",
160 s_hand.contained_hands = compute_contained_hand_types();
161 s_hand.hand_type = compute_hand_type(s_hand.contained_hands);
163 HandValues hand_values = HAND_BASE_VALUES[s_hand.hand_type];
165 g_game_vars.chips = hand_values.chips;
166 g_game_vars.mult = hand_values.mult;
168 print_hand_type(hand_values.display_name);
178 s_hand.cards[idx_a] = s_hand.cards[idx_b];
179 s_hand.cards[idx_b] = temp;
182static inline void sort_hand_by_suit(
void)
184 for (
int idx_a = 0; idx_a < s_hand.hand_top; idx_a++)
186 for (
int idx_b = idx_a + 1; idx_b <= s_hand.hand_top; idx_b++)
188 if (s_hand.cards[idx_a] == NULL ||
189 (s_hand.cards[idx_b] != NULL &&
190 (s_hand.cards[idx_a]->card->suit > s_hand.cards[idx_b]->card->suit ||
191 (s_hand.cards[idx_a]->card->suit == s_hand.cards[idx_b]->card->suit &&
192 s_hand.cards[idx_a]->card->rank > s_hand.cards[idx_b]->card->rank))))
200static inline void sort_hand_by_rank(
void)
202 for (
int idx_a = 0; idx_a < s_hand.hand_top; idx_a++)
204 for (
int idx_b = idx_a + 1; idx_b <= s_hand.hand_top; idx_b++)
206 if (s_hand.cards[idx_a] == NULL ||
207 (s_hand.cards[idx_b] != NULL &&
208 s_hand.cards[idx_a]->card->rank > s_hand.cards[idx_b]->card->rank))
216static inline bool shift_null_card_to_end(
int null_card_idx)
220 int non_null_card_idx = null_card_idx;
221 for (; non_null_card_idx <= s_hand.hand_top; non_null_card_idx++)
223 if (s_hand.cards[non_null_card_idx] != NULL)
230 if (non_null_card_idx > s_hand.hand_top)
237 for (
int j = 0; j <= s_hand.hand_top - non_null_card_idx; j++)
239 s_hand.cards[null_card_idx + j] = s_hand.cards[non_null_card_idx + j];
249 for (
int i = 0; i <= s_hand.hand_top; i++)
253 if (s_hand.cards[i] == NULL)
255 if (!shift_null_card_to_end(i))
266 for (
int i = 0; i <= s_hand.hand_top; i++)
268 if (s_hand.cards[i] != NULL)
271 card_object_set_sprite(s_hand.cards[i], i);
273 card_object_get_sprite(s_hand.cards[i]),
274 fx2int(s_hand.cards[i]->x),
275 fx2int(s_hand.cards[i]->y)
283 if (s_hand.sort_by_suit)
297 if (to_sort_by_suit != s_hand.sort_by_suit)
299 s_hand.sort_by_suit = to_sort_by_suit;
307 s_hand.cards[index] == NULL)
310 if (card_object_is_selected(s_hand.cards[index]))
312 card_object_set_selected(s_hand.cards[index],
false);
313 s_hand.hand_selections--;
316 else if (s_hand.hand_selections < MAX_SELECTION_SIZE)
318 card_object_set_selected(s_hand.cards[index],
true);
319 s_hand.hand_selections++;
327 bool any_cards_deselected =
false;
328 for (
int i = 0; i <= s_hand.hand_top; i++)
330 if (card_object_is_selected(s_hand.cards[i]))
332 card_object_set_selected(s_hand.cards[i],
false);
333 s_hand.hand_selections--;
334 any_cards_deselected =
true;
338 if (any_cards_deselected)
355 for (
int i = 0; i < NUM_RANKS; i++)
357 for (
int i = 0; i < NUM_SUITS; i++)
360 int top = s_hand.hand_top;
361 for (
int i = 0; i <= top; i++)
363 if (s_hand.cards[i] && card_object_is_selected(s_hand.cards[i]))
365 ranks_out[s_hand.cards[i]->card->rank]++;
366 suits_out[s_hand.cards[i]->card->suit]++;
372static u8 hand_contains_n_of_a_kind(u8* ranks)
375 for (
int i = 0; i < NUM_RANKS; i++)
377 if (ranks[i] > highest_n)
378 highest_n = ranks[i];
383static bool hand_contains_two_pair(u8* ranks)
385 bool contains_other_pair =
false;
386 for (
int i = 0; i < NUM_RANKS; i++)
390 if (contains_other_pair)
392 contains_other_pair =
true;
398static bool hand_contains_full_house(u8* ranks)
402 for (
int i = 0; i < NUM_RANKS; i++)
408 else if (ranks[i] >= 2)
418 return (count_three >= 2 || (count_three && count_pair));
422static bool hand_contains_straight(u8* ranks)
424 if (!is_shortcut_joker_active())
426 int straight_size = get_straight_and_flush_size();
429 for (
int i = 0; i < NUM_RANKS; ++i)
433 if (++run >= straight_size)
443 if (straight_size >= 2 && ranks[ACE])
447 int last_needed = TWO + (straight_size - 2);
448 if (last_needed <= FIVE)
451 for (
int r = TWO; r <= last_needed; ++r)
472 u8 longest_short_cut_at[NUM_RANKS] = {0};
476 int ace_low_len = ranks[ACE] ? 1 : 0;
479 for (
int i = 0; i < NUM_RANKS; i++)
484 longest_short_cut_at[i] = 0;
495 prev_len1 = ace_low_len;
500 prev_len1 = longest_short_cut_at[TWO];
501 prev_len2 = ace_low_len;
506 prev_len1 = longest_short_cut_at[KING];
507 prev_len2 = longest_short_cut_at[QUEEN];
512 prev_len1 = longest_short_cut_at[i - 1];
513 prev_len2 = longest_short_cut_at[i - 2];
518 longest_short_cut_at[i] = 1 + max(prev_len1, prev_len2);
521 if (longest_short_cut_at[i] >= get_straight_and_flush_size())
531static bool hand_contains_flush(u8* suits)
533 for (
int i = 0; i < NUM_SUITS; i++)
535 if (suits[i] >= get_straight_and_flush_size())
549 for (
int i = 0; i <= top; i++)
550 out_selection[i] =
false;
552 int suit_counts[NUM_SUITS] = {0};
553 for (
int i = 0; i <= top; i++)
555 if (played[i] && played[i]->card)
557 suit_counts[played[i]->card->suit]++;
563 for (
int i = 0; i < NUM_SUITS; i++)
565 if (suit_counts[i] > best_count)
567 best_count = suit_counts[i];
572 if (best_count >= min_len)
574 for (
int i = 0; i <= top; i++)
576 if (played[i] && played[i]->card && played[i]->card->suit == best_suit)
578 out_selection[i] =
true;
592 for (
int i = 0; i <= top; i++)
593 out_selection[i] =
false;
596 u8 longest_straight_at[NUM_RANKS] = {0};
597 int parent[NUM_RANKS];
598 for (
int i = 0; i < NUM_RANKS; i++)
601 u8 ranks[NUM_RANKS] = {0};
602 for (
int i = 0; i <= top; i++)
604 if (played[i] && played[i]->card)
606 ranks[played[i]->card->rank]++;
614 int ace_low_len = ranks[ACE] ? 1 : 0;
615 bool is_shortcut_active = is_shortcut_joker_active();
616 for (
int i = 0; i < NUM_RANKS; i++)
620 int prev1 = 0, prev2 = 0;
621 int parent1 = -1, parent2 = -1;
623 if (is_shortcut_active)
632 prev1 = longest_straight_at[TWO];
639 prev1 = longest_straight_at[KING];
641 prev2 = longest_straight_at[QUEEN];
646 prev1 = longest_straight_at[i - 1];
650 prev2 = longest_straight_at[i - 2];
664 prev1 = longest_straight_at[KING];
669 prev1 = longest_straight_at[i - 1];
678 longest_straight_at[i] = 1 + prev1;
683 longest_straight_at[i] = 1 + prev2;
692 for (
int i = 0; i < NUM_RANKS; i++)
694 if (longest_straight_at[i] >= best_len)
696 best_len = longest_straight_at[i];
701 if (best_len >= min_len)
703 u8 needed_ranks[NUM_RANKS] = {0};
704 int current_rank = end_rank;
705 while (current_rank != -1 && best_len > 0)
707 needed_ranks[current_rank]++;
708 current_rank = parent[current_rank];
712 for (
int i = 0; i <= top; i++)
714 if (played[i] && played[i]->card && needed_ranks[played[i]->card->rank] > 0)
716 out_selection[i] =
true;
717 needed_ranks[played[i]->card->rank]--;
721 int final_card_count = 0;
722 for (
int i = 0; i <= top; i++)
724 if (out_selection[i])
727 return final_card_count;
735 bool rank_selected[NUM_RANKS] = {0};
736 bool any_selected_rank =
false;
738 for (
int i = 0; i <= played_top; i++)
740 if (selection[i] && played[i] && played[i]->card)
742 rank_selected[played[i]->card->rank] =
true;
743 any_selected_rank =
true;
748 if (!any_selected_rank)
752 for (
int i = 0; i <= played_top; i++)
754 if (played[i] && played[i]->card && !selection[i])
756 if (rank_selected[played[i]->card->rank])
769 if (s_hand.hand_selections == 0 || s_hand.state == HAND_DISCARD)
774 hand_types.HIGH_CARD = 1;
781 u8 n_of_a_kind = hand_contains_n_of_a_kind(ranks);
784 if (n_of_a_kind >= 2)
788 if (hand_contains_two_pair(ranks))
790 hand_types.TWO_PAIR = 1;
795 if (n_of_a_kind >= 3)
797 hand_types.THREE_OF_A_KIND = 1;
801 if (hand_contains_straight(ranks))
803 hand_types.STRAIGHT = 1;
807 if (hand_contains_flush(suits))
809 hand_types.FLUSH = 1;
813 if (n_of_a_kind >= 3 && hand_contains_full_house(ranks))
815 hand_types.FULL_HOUSE = 1;
819 if (n_of_a_kind >= 4)
821 hand_types.FOUR_OF_A_KIND = 1;
825 if (hand_types.STRAIGHT && hand_types.FLUSH)
827 hand_types.STRAIGHT_FLUSH = 1;
831 if (hand_types.STRAIGHT_FLUSH)
833 if (ranks[TEN] && ranks[JACK] && ranks[QUEEN] && ranks[KING] && ranks[ACE])
835 hand_types.ROYAL_FLUSH = 1;
840 if (n_of_a_kind >= 5)
842 hand_types.FIVE_OF_A_KIND = 1;
846 if (hand_types.FLUSH)
848 if (hand_types.FULL_HOUSE)
850 hand_types.FLUSH_HOUSE = 1;
853 if (hand_types.FIVE_OF_A_KIND)
855 hand_types.FLUSH_FIVE = 1;
867 for (ret = FLUSH_FIVE; ret > NONE; ret--)
872 if ((contained_types.value >> (ret - 1)) & 0x1)
Utilities for using maxmod to play sound effects.
#define MM_BASE_PITCH_RATE
The default pitch rate for the sound effect played.
void play_sfx(mm_word id, mm_word rate, mm_byte volume)
Play a sound effect, wrapper for mmEffectEx() See https://maxmod.org/ref/functions/mm_sound_effect....
#define SFX_DEFAULT_VOLUME
Default volume for sound effects.
Common functions to render UI elements.
Game global game variables struct definition.
Graphic utility functions.
void update_text_rect_to_center_str(Rect *rect, const char *str, enum ScreenHorzDir bias_direction)
Updates a rect so a string is centered within it.
void tte_erase_rect_wrapper(Rect rect)
A wrapper for tte_erase_rect that would use the rect struct.
void hand_set_nb_selected_cards(int new_selections)
Set the current number of selected Cards.
ContainedHandTypes * get_contained_hands(void)
Get the contained hands within the selected hand.
int find_flush_in_played_cards(CardObject **played, int top, int min_len, bool *out_selection)
Finds the best flush (set of cards with the same suit) in the given array of played cards.
enum HandType get_hand_type(void)
Get the current hand type.
int get_hand_top(void)
Get the position in hand array of the last card obtained.
enum HandState get_hand_state(void)
Get the hand state.
void swap_cards_in_hand(int idx_a, int idx_b)
Swaps the order of two cards in hand.
int find_straight_in_played_cards(CardObject **played, int top, int min_len, bool *out_selection)
Finds the best straight in the given array of played cards.
static void get_hand_distribution(u8 ranks_out[NUM_RANKS], u8 suits_out[NUM_SUITS])
Outputs the distribution of ranks and suits in the hand.
CardObject ** get_hand_array(void)
Get the hand array of Cards currently held in hand.
int hand_get_nb_selected_cards(void)
Get the current number of selected Cards.
void set_hand_state(enum HandState new_hand_state)
Set the hand state. Primarily used by the GAME_PLAYING game state.
void reorder_card_sprites_layers(void)
Destroy the sprites of the Cards held in hand and recreate then in the same order as the Cards in the...
void set_hand_top(int new_hand_top)
Set the position in hand array of the last card obtained.
void hand_select_card(int index)
Set the card at a given index in Hand as selected.
void hand_change_sort(bool to_sort_by_suit)
Switch to the given sort method. Can sort playing cards in two ways: by rank and suit....
void compute_hand_value_info(void)
Determine the HandType and ContainedHandTypes of the currently selected Cards, then print the Hand's ...
void sort_cards(void)
Sort the hand array according to the selected method to do that.
void hand_deselect_all_cards(void)
Deselect all cards in hand.
int hand_nb_held_cards(void)
Get the current number of Cards in hand.
void select_paired_cards_in_hand(CardObject **played, int played_top, bool *selection)
This is used for the special case in "Four Fingers" where you can add a pair into a straight (e....
Functions relative to manipulating and analyzing the contents of the Hand, a.k.a. the Cards we hold a...
API relative to the Rounds we play.
INLINE void sprite_position(Sprite *sprite, int x, int y)
Set sprite position. Inlined for efficiency.
void sprite_destroy(Sprite **sprite)
Destroy Sprite.
Utilities relating around number string representation and protected arithmatic helper functions.