28 {.chips = 0, .mult = 0, .display_name = NULL },
29 {.chips = 5, .mult = 1, .display_name =
"Hi-Card"},
30 {.chips = 10, .mult = 2, .display_name =
"Pair" },
31 {.chips = 20, .mult = 2, .display_name =
"2 Pair" },
32 {.chips = 30, .mult = 3, .display_name =
"3 OAK" },
33 {.chips = 30, .mult = 4, .display_name =
"Strt" },
34 {.chips = 35, .mult = 4, .display_name =
"Flush" },
35 {.chips = 40, .mult = 4, .display_name =
"Full H" },
36 {.chips = 60, .mult = 7, .display_name =
"4 OAK" },
37 {.chips = 100, .mult = 8, .display_name =
"Strt F" },
38 {.chips = 100, .mult = 8, .display_name =
"Royal F"},
39 {.chips = 120, .mult = 12, .display_name =
"5 OAK" },
40 {.chips = 140, .mult = 14, .display_name =
"Flush H"},
41 {.chips = 160, .mult = 16, .display_name =
"Flush 5"}
46static const Rect HAND_TYPE_RECT = {8, 64, 64, 72};
57 enum HandType hand_type;
69 .contained_hands = {{{0}}},
80const char* get_hand_type_name(
enum HandType hand_type)
82 if (hand_type <= NONE || hand_type > FLUSH_FIVE)
85 return HAND_BASE_VALUES[hand_type].display_name;
97 s_hand.state = new_hand_state;
107 return s_hand.hand_top;
112 s_hand.hand_top = new_hand_top;
117 return s_hand.hand_top + 1;
122 return s_hand.hand_selections;
127 s_hand.hand_selections = new_selections;
132 return s_hand.hand_type;
137 return &s_hand.contained_hands;
140static void print_hand_type(
const char* hand_type_str)
142 if (hand_type_str == NULL)
145 Rect hand_type_rect = HAND_TYPE_RECT;
148 "#{P:%d,%d; cx:0x%X000}%s",
159 s_hand.contained_hands = compute_contained_hand_types();
160 s_hand.hand_type = compute_hand_type(s_hand.contained_hands);
162 HandValues hand_values = HAND_BASE_VALUES[s_hand.hand_type];
164 g_game_vars.chips = hand_values.chips;
165 g_game_vars.mult = hand_values.mult;
167 print_hand_type(hand_values.display_name);
177 s_hand.cards[idx_a] = s_hand.cards[idx_b];
178 s_hand.cards[idx_b] = temp;
181static inline void sort_hand_by_suit(
void)
183 for (
int idx_a = 0; idx_a < s_hand.hand_top; idx_a++)
185 for (
int idx_b = idx_a + 1; idx_b <= s_hand.hand_top; idx_b++)
187 if (s_hand.cards[idx_a] == NULL ||
188 (s_hand.cards[idx_b] != NULL &&
189 (s_hand.cards[idx_a]->card->suit > s_hand.cards[idx_b]->card->suit ||
190 (s_hand.cards[idx_a]->card->suit == s_hand.cards[idx_b]->card->suit &&
191 s_hand.cards[idx_a]->card->rank > s_hand.cards[idx_b]->card->rank))))
199static inline void sort_hand_by_rank(
void)
201 for (
int idx_a = 0; idx_a < s_hand.hand_top; idx_a++)
203 for (
int idx_b = idx_a + 1; idx_b <= s_hand.hand_top; idx_b++)
205 if (s_hand.cards[idx_a] == NULL ||
206 (s_hand.cards[idx_b] != NULL &&
207 s_hand.cards[idx_a]->card->rank > s_hand.cards[idx_b]->card->rank))
215static inline bool shift_null_card_to_end(
int null_card_idx)
219 int non_null_card_idx = null_card_idx;
220 for (; non_null_card_idx <= s_hand.hand_top; non_null_card_idx++)
222 if (s_hand.cards[non_null_card_idx] != NULL)
229 if (non_null_card_idx > s_hand.hand_top)
236 for (
int j = 0; j <= s_hand.hand_top - non_null_card_idx; j++)
238 s_hand.cards[null_card_idx + j] = s_hand.cards[non_null_card_idx + j];
248 for (
int i = 0; i <= s_hand.hand_top; i++)
252 if (s_hand.cards[i] == NULL)
254 if (!shift_null_card_to_end(i))
265 for (
int i = 0; i <= s_hand.hand_top; i++)
267 if (s_hand.cards[i] != NULL)
270 card_object_set_sprite(s_hand.cards[i], i);
272 card_object_get_sprite(s_hand.cards[i]),
273 fx2int(s_hand.cards[i]->x),
274 fx2int(s_hand.cards[i]->y)
282 if (s_hand.sort_by_suit)
296 if (to_sort_by_suit != s_hand.sort_by_suit)
298 s_hand.sort_by_suit = to_sort_by_suit;
306 s_hand.cards[index] == NULL)
309 if (card_object_is_selected(s_hand.cards[index]))
311 card_object_set_selected(s_hand.cards[index],
false);
312 s_hand.hand_selections--;
315 else if (s_hand.hand_selections < MAX_SELECTION_SIZE)
317 card_object_set_selected(s_hand.cards[index],
true);
318 s_hand.hand_selections++;
326 bool any_cards_deselected =
false;
327 for (
int i = 0; i <= s_hand.hand_top; i++)
329 if (card_object_is_selected(s_hand.cards[i]))
331 card_object_set_selected(s_hand.cards[i],
false);
332 s_hand.hand_selections--;
333 any_cards_deselected =
true;
337 if (any_cards_deselected)
354 for (
int i = 0; i < NUM_RANKS; i++)
356 for (
int i = 0; i < NUM_SUITS; i++)
359 int top = s_hand.hand_top;
360 for (
int i = 0; i <= top; i++)
362 if (s_hand.cards[i] && card_object_is_selected(s_hand.cards[i]))
364 ranks_out[s_hand.cards[i]->card->rank]++;
365 suits_out[s_hand.cards[i]->card->suit]++;
371static u8 hand_contains_n_of_a_kind(u8* ranks)
374 for (
int i = 0; i < NUM_RANKS; i++)
376 if (ranks[i] > highest_n)
377 highest_n = ranks[i];
382static bool hand_contains_two_pair(u8* ranks)
384 bool contains_other_pair =
false;
385 for (
int i = 0; i < NUM_RANKS; i++)
389 if (contains_other_pair)
391 contains_other_pair =
true;
397static bool hand_contains_full_house(u8* ranks)
401 for (
int i = 0; i < NUM_RANKS; i++)
407 else if (ranks[i] >= 2)
417 return (count_three >= 2 || (count_three && count_pair));
421static bool hand_contains_straight(u8* ranks)
423 if (!is_shortcut_joker_active())
425 int straight_size = get_straight_and_flush_size();
428 for (
int i = 0; i < NUM_RANKS; ++i)
432 if (++run >= straight_size)
442 if (straight_size >= 2 && ranks[ACE])
446 int last_needed = TWO + (straight_size - 2);
447 if (last_needed <= FIVE)
450 for (
int r = TWO; r <= last_needed; ++r)
471 u8 longest_short_cut_at[NUM_RANKS] = {0};
475 int ace_low_len = ranks[ACE] ? 1 : 0;
478 for (
int i = 0; i < NUM_RANKS; i++)
483 longest_short_cut_at[i] = 0;
494 prev_len1 = ace_low_len;
499 prev_len1 = longest_short_cut_at[TWO];
500 prev_len2 = ace_low_len;
505 prev_len1 = longest_short_cut_at[KING];
506 prev_len2 = longest_short_cut_at[QUEEN];
511 prev_len1 = longest_short_cut_at[i - 1];
512 prev_len2 = longest_short_cut_at[i - 2];
517 longest_short_cut_at[i] = 1 + max(prev_len1, prev_len2);
520 if (longest_short_cut_at[i] >= get_straight_and_flush_size())
530static bool hand_contains_flush(u8* suits)
532 for (
int i = 0; i < NUM_SUITS; i++)
534 if (suits[i] >= get_straight_and_flush_size())
548 for (
int i = 0; i <= top; i++)
549 out_selection[i] =
false;
551 int suit_counts[NUM_SUITS] = {0};
552 for (
int i = 0; i <= top; i++)
554 if (played[i] && played[i]->card)
556 suit_counts[played[i]->card->suit]++;
562 for (
int i = 0; i < NUM_SUITS; i++)
564 if (suit_counts[i] > best_count)
566 best_count = suit_counts[i];
571 if (best_count >= min_len)
573 for (
int i = 0; i <= top; i++)
575 if (played[i] && played[i]->card && played[i]->card->suit == best_suit)
577 out_selection[i] =
true;
591 for (
int i = 0; i <= top; i++)
592 out_selection[i] =
false;
595 u8 longest_straight_at[NUM_RANKS] = {0};
596 int parent[NUM_RANKS];
597 for (
int i = 0; i < NUM_RANKS; i++)
600 u8 ranks[NUM_RANKS] = {0};
601 for (
int i = 0; i <= top; i++)
603 if (played[i] && played[i]->card)
605 ranks[played[i]->card->rank]++;
613 int ace_low_len = ranks[ACE] ? 1 : 0;
614 bool is_shortcut_active = is_shortcut_joker_active();
615 for (
int i = 0; i < NUM_RANKS; i++)
619 int prev1 = 0, prev2 = 0;
620 int parent1 = -1, parent2 = -1;
622 if (is_shortcut_active)
631 prev1 = longest_straight_at[TWO];
638 prev1 = longest_straight_at[KING];
640 prev2 = longest_straight_at[QUEEN];
645 prev1 = longest_straight_at[i - 1];
649 prev2 = longest_straight_at[i - 2];
663 prev1 = longest_straight_at[KING];
668 prev1 = longest_straight_at[i - 1];
677 longest_straight_at[i] = 1 + prev1;
682 longest_straight_at[i] = 1 + prev2;
691 for (
int i = 0; i < NUM_RANKS; i++)
693 if (longest_straight_at[i] >= best_len)
695 best_len = longest_straight_at[i];
700 if (best_len >= min_len)
702 u8 needed_ranks[NUM_RANKS] = {0};
703 int current_rank = end_rank;
704 while (current_rank != -1 && best_len > 0)
706 needed_ranks[current_rank]++;
707 current_rank = parent[current_rank];
711 for (
int i = 0; i <= top; i++)
713 if (played[i] && played[i]->card && needed_ranks[played[i]->card->rank] > 0)
715 out_selection[i] =
true;
716 needed_ranks[played[i]->card->rank]--;
720 int final_card_count = 0;
721 for (
int i = 0; i <= top; i++)
723 if (out_selection[i])
726 return final_card_count;
734 bool rank_selected[NUM_RANKS] = {0};
735 bool any_selected_rank =
false;
737 for (
int i = 0; i <= played_top; i++)
739 if (selection[i] && played[i] && played[i]->card)
741 rank_selected[played[i]->card->rank] =
true;
742 any_selected_rank =
true;
747 if (!any_selected_rank)
751 for (
int i = 0; i <= played_top; i++)
753 if (played[i] && played[i]->card && !selection[i])
755 if (rank_selected[played[i]->card->rank])
768 if (s_hand.hand_selections == 0 || s_hand.state == HAND_DISCARD)
773 hand_types.HIGH_CARD = 1;
780 u8 n_of_a_kind = hand_contains_n_of_a_kind(ranks);
783 if (n_of_a_kind >= 2)
787 if (hand_contains_two_pair(ranks))
789 hand_types.TWO_PAIR = 1;
794 if (n_of_a_kind >= 3)
796 hand_types.THREE_OF_A_KIND = 1;
800 if (hand_contains_straight(ranks))
802 hand_types.STRAIGHT = 1;
806 if (hand_contains_flush(suits))
808 hand_types.FLUSH = 1;
812 if (n_of_a_kind >= 3 && hand_contains_full_house(ranks))
814 hand_types.FULL_HOUSE = 1;
818 if (n_of_a_kind >= 4)
820 hand_types.FOUR_OF_A_KIND = 1;
824 if (hand_types.STRAIGHT && hand_types.FLUSH)
826 hand_types.STRAIGHT_FLUSH = 1;
830 if (hand_types.STRAIGHT_FLUSH)
832 if (ranks[TEN] && ranks[JACK] && ranks[QUEEN] && ranks[KING] && ranks[ACE])
834 hand_types.ROYAL_FLUSH = 1;
839 if (n_of_a_kind >= 5)
841 hand_types.FIVE_OF_A_KIND = 1;
845 if (hand_types.FLUSH)
847 if (hand_types.FULL_HOUSE)
849 hand_types.FLUSH_HOUSE = 1;
852 if (hand_types.FIVE_OF_A_KIND)
854 hand_types.FLUSH_FIVE = 1;
866 for (ret = FLUSH_FIVE; ret > NONE; ret--)
871 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.
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.