GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
joker_effects.c
1#include "game.h"
2#include "game/round.h"
3#include "game_variables.h"
4#include "hand.h"
5#include "joker.h"
6#include "list.h"
7#include "pool.h"
8#include "random.h"
9#include "util.h"
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#define MISPRINT_MAX_MULT 23
16
17#define DECLARE_JOKER_DESC_FUNC(joker_desc_name) \
18 static int joker_desc_name(Joker* joker, Rect dest_rect);
19
20#define DECLARE_JOKER_EFFECT_FUNC(joker_effect_name) \
21 static u32 joker_effect_name( \
22 Joker* joker, \
23 Card* scored_card, \
24 enum JokerEvent joker_event, \
25 JokerEffect** joker_effect \
26 );
27
28#define SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, restricted_event, checked_event) \
29 if (checked_event != restricted_event || scored_card == NULL) \
30 { \
31 return JOKER_EFFECT_FLAG_NONE; \
32 }
33#define SCORE_ON_EVENT_ONLY(restricted_event, checked_event) \
34 if (checked_event != restricted_event) \
35 { \
36 return JOKER_EFFECT_FLAG_NONE; \
37 }
38
39static JokerEffect s_shared_joker_effect = {0};
40
41// Joker Descriptions
42
43DECLARE_JOKER_DESC_FUNC(default_joker_desc)
44DECLARE_JOKER_DESC_FUNC(greedy_joker_desc)
45DECLARE_JOKER_DESC_FUNC(lusty_joker_desc)
46DECLARE_JOKER_DESC_FUNC(wrathful_joker_desc)
47DECLARE_JOKER_DESC_FUNC(gluttonous_joker_desc)
48DECLARE_JOKER_DESC_FUNC(jolly_joker_desc)
49DECLARE_JOKER_DESC_FUNC(zany_joker_desc)
50DECLARE_JOKER_DESC_FUNC(mad_joker_desc)
51DECLARE_JOKER_DESC_FUNC(crazy_joker_desc)
52DECLARE_JOKER_DESC_FUNC(droll_joker_desc)
53DECLARE_JOKER_DESC_FUNC(sly_joker_desc)
54DECLARE_JOKER_DESC_FUNC(wily_joker_desc)
55DECLARE_JOKER_DESC_FUNC(clever_joker_desc)
56DECLARE_JOKER_DESC_FUNC(devious_joker_desc)
57DECLARE_JOKER_DESC_FUNC(crafty_joker_desc)
58DECLARE_JOKER_DESC_FUNC(half_joker_desc)
59DECLARE_JOKER_DESC_FUNC(stencil_joker_desc)
60DECLARE_JOKER_DESC_FUNC(misprint_joker_desc)
61DECLARE_JOKER_DESC_FUNC(walkie_talkie_joker_desc)
62DECLARE_JOKER_DESC_FUNC(fibonnaci_joker_desc)
63DECLARE_JOKER_DESC_FUNC(banner_joker_desc)
64DECLARE_JOKER_DESC_FUNC(mystic_summit_joker_desc)
65DECLARE_JOKER_DESC_FUNC(blackboard_joker_desc)
66DECLARE_JOKER_DESC_FUNC(blue_joker_desc)
67DECLARE_JOKER_DESC_FUNC(raised_fist_joker_desc)
68DECLARE_JOKER_DESC_FUNC(reserved_parking_joker_desc)
69DECLARE_JOKER_DESC_FUNC(business_card_joker_desc)
70DECLARE_JOKER_DESC_FUNC(scholar_joker_desc)
71DECLARE_JOKER_DESC_FUNC(scary_face_joker_desc)
72DECLARE_JOKER_DESC_FUNC(abstract_joker_desc)
73DECLARE_JOKER_DESC_FUNC(bull_joker_desc)
74DECLARE_JOKER_DESC_FUNC(smiley_face_joker_desc)
75DECLARE_JOKER_DESC_FUNC(even_steven_joker_desc)
76DECLARE_JOKER_DESC_FUNC(odd_todd_joker_desc)
77DECLARE_JOKER_DESC_FUNC(acrobat_joker_desc)
78DECLARE_JOKER_DESC_FUNC(hanging_chad_joker_desc)
79DECLARE_JOKER_DESC_FUNC(the_duo_joker_desc)
80DECLARE_JOKER_DESC_FUNC(the_trio_joker_desc)
81DECLARE_JOKER_DESC_FUNC(the_family_joker_desc)
82DECLARE_JOKER_DESC_FUNC(the_order_joker_desc)
83DECLARE_JOKER_DESC_FUNC(the_tribe_joker_desc)
84DECLARE_JOKER_DESC_FUNC(bootstraps_joker_desc)
85DECLARE_JOKER_DESC_FUNC(shoot_the_moon_joker_desc)
86DECLARE_JOKER_DESC_FUNC(pareidolia_joker_desc)
87DECLARE_JOKER_DESC_FUNC(photograph_joker_desc)
88DECLARE_JOKER_DESC_FUNC(dusk_joker_desc)
89DECLARE_JOKER_DESC_FUNC(shortcut_joker_desc)
90DECLARE_JOKER_DESC_FUNC(blueprint_joker_desc)
91DECLARE_JOKER_DESC_FUNC(brainstorm_joker_desc)
92DECLARE_JOKER_DESC_FUNC(hack_joker_desc)
93DECLARE_JOKER_DESC_FUNC(four_fingers_joker_desc)
94DECLARE_JOKER_DESC_FUNC(seltzer_joker_desc)
95DECLARE_JOKER_DESC_FUNC(sock_and_buskin_joker_desc)
96
97// Joker Effect functions
98
99static u32 sinful_joker_effect(
100 Card* scored_card,
101 u8 sinful_suit,
102 enum JokerEvent joker_event,
103 JokerEffect** joker_effect
104);
105
106DECLARE_JOKER_EFFECT_FUNC(joker_effect_noop)
107DECLARE_JOKER_EFFECT_FUNC(default_joker_effect)
108DECLARE_JOKER_EFFECT_FUNC(greedy_joker_effect)
109DECLARE_JOKER_EFFECT_FUNC(lusty_joker_effect)
110DECLARE_JOKER_EFFECT_FUNC(wrathful_joker_effect)
111DECLARE_JOKER_EFFECT_FUNC(gluttonous_joker_effect)
112DECLARE_JOKER_EFFECT_FUNC(jolly_joker_effect)
113DECLARE_JOKER_EFFECT_FUNC(zany_joker_effect)
114DECLARE_JOKER_EFFECT_FUNC(mad_joker_effect)
115DECLARE_JOKER_EFFECT_FUNC(crazy_joker_effect)
116DECLARE_JOKER_EFFECT_FUNC(droll_joker_effect)
117DECLARE_JOKER_EFFECT_FUNC(sly_joker_effect)
118DECLARE_JOKER_EFFECT_FUNC(wily_joker_effect)
119DECLARE_JOKER_EFFECT_FUNC(clever_joker_effect)
120DECLARE_JOKER_EFFECT_FUNC(devious_joker_effect)
121DECLARE_JOKER_EFFECT_FUNC(crafty_joker_effect)
122DECLARE_JOKER_EFFECT_FUNC(half_joker_effect)
123DECLARE_JOKER_EFFECT_FUNC(stencil_joker_effect)
124DECLARE_JOKER_EFFECT_FUNC(misprint_joker_effect)
125DECLARE_JOKER_EFFECT_FUNC(walkie_talkie_joker_effect)
126DECLARE_JOKER_EFFECT_FUNC(fibonnaci_joker_effect)
127DECLARE_JOKER_EFFECT_FUNC(banner_joker_effect)
128DECLARE_JOKER_EFFECT_FUNC(mystic_summit_joker_effect)
129DECLARE_JOKER_EFFECT_FUNC(blackboard_joker_effect)
130DECLARE_JOKER_EFFECT_FUNC(blue_joker_effect)
131DECLARE_JOKER_EFFECT_FUNC(raised_fist_joker_effect)
132DECLARE_JOKER_EFFECT_FUNC(reserved_parking_joker_effect)
133DECLARE_JOKER_EFFECT_FUNC(business_card_joker_effect)
134DECLARE_JOKER_EFFECT_FUNC(scholar_joker_effect)
135DECLARE_JOKER_EFFECT_FUNC(scary_face_joker_effect)
136DECLARE_JOKER_EFFECT_FUNC(abstract_joker_effect)
137DECLARE_JOKER_EFFECT_FUNC(bull_joker_effect)
138DECLARE_JOKER_EFFECT_FUNC(smiley_face_joker_effect)
139DECLARE_JOKER_EFFECT_FUNC(even_steven_joker_effect)
140DECLARE_JOKER_EFFECT_FUNC(odd_todd_joker_effect)
141DECLARE_JOKER_EFFECT_FUNC(acrobat_joker_effect)
142DECLARE_JOKER_EFFECT_FUNC(hanging_chad_joker_effect)
143DECLARE_JOKER_EFFECT_FUNC(the_duo_joker_effect)
144DECLARE_JOKER_EFFECT_FUNC(the_trio_joker_effect)
145DECLARE_JOKER_EFFECT_FUNC(the_family_joker_effect)
146DECLARE_JOKER_EFFECT_FUNC(the_order_joker_effect)
147DECLARE_JOKER_EFFECT_FUNC(the_tribe_joker_effect)
148DECLARE_JOKER_EFFECT_FUNC(bootstraps_joker_effect)
149DECLARE_JOKER_EFFECT_FUNC(shoot_the_moon_joker_effect)
150DECLARE_JOKER_EFFECT_FUNC(photograph_joker_effect)
151DECLARE_JOKER_EFFECT_FUNC(dusk_joker_effect)
152DECLARE_JOKER_EFFECT_FUNC(blueprint_brainstorm_joker_effect)
153DECLARE_JOKER_EFFECT_FUNC(hack_joker_effect)
154DECLARE_JOKER_EFFECT_FUNC(seltzer_joker_effect)
155DECLARE_JOKER_EFFECT_FUNC(sock_and_buskin_joker_effect)
156
157/* The index of a joker in the registry matches its ID.
158 *
159 * The joker sprites are matched by ID so the position in the registry
160 * determines the joker's sprite.
161 *
162 * Each consecutive NUM_JOKERS_PER_SPRITESHEET (defined in joker.c) jokers
163 * share a spritesheet and thus a color palette.
164 *
165 * To make better use of color palettes jokers may be rearranged here
166 * (and put together in the matching spritesheet) to share a color palette.
167 * Otherwise the order is similar to the wiki.
168 *
169 * TODO: move Name and Description printing out of this when the CardInstance is implemented.
170 */
171// clang-format off
172const JokerInfo joker_registry[] =
173{
174 // Spritesheet 0
175 { "Joker", COMMON_JOKER, 2, false, default_joker_desc, default_joker_effect }, // DEFAULT_JOKER_ID = 0
176 { "Abstract Joker", COMMON_JOKER, 4, false, abstract_joker_desc, abstract_joker_effect }, // 1
177 { "Half Joker", COMMON_JOKER, 5, false, half_joker_desc, half_joker_effect }, // 2
178 { "Misprint", COMMON_JOKER, 4, true, misprint_joker_desc, misprint_joker_effect }, // 3
179 { "Scary Face", COMMON_JOKER, 4, false, scary_face_joker_desc, scary_face_joker_effect }, // 4
180 { "Sock and Buskin", UNCOMMON_JOKER, 6, false, sock_and_buskin_joker_desc, sock_and_buskin_joker_effect }, // 5
181 { "Acrobat", UNCOMMON_JOKER, 6, false, acrobat_joker_desc, acrobat_joker_effect }, // 6
182 { "Fibonacci", UNCOMMON_JOKER, 8, false, fibonnaci_joker_desc, fibonnaci_joker_effect }, // 7
183 { "Scholar", COMMON_JOKER, 4, false, scholar_joker_desc, scholar_joker_effect }, // 8
184 { "Crafty Joker", COMMON_JOKER, 4, false, crafty_joker_desc, crafty_joker_effect }, // 9
185 { "Droll Joker", COMMON_JOKER, 4, false, droll_joker_desc, droll_joker_effect }, // 10
186 { "Raised Fist", COMMON_JOKER, 5, false, raised_fist_joker_desc, raised_fist_joker_effect }, // 11
187 { "Reserved Parking", COMMON_JOKER, 6, false, reserved_parking_joker_desc, reserved_parking_joker_effect }, // 12
188 { "Business Card", COMMON_JOKER, 4, false, business_card_joker_desc, business_card_joker_effect }, // 13
189 { "Hanging Chad", COMMON_JOKER, 4, false, hanging_chad_joker_desc, hanging_chad_joker_effect }, // 14
190 { "Joker Stencil", UNCOMMON_JOKER, 8, false, stencil_joker_desc, stencil_joker_effect }, // 15
191 { "Banner", COMMON_JOKER, 5, false, banner_joker_desc, banner_joker_effect }, // 16
192 { "Shoot the Moon", COMMON_JOKER, 5, false, shoot_the_moon_joker_desc, shoot_the_moon_joker_effect, }, // 17
193 // Spritesheet 1
194 { "Greedy Joker", COMMON_JOKER, 5, false, greedy_joker_desc, greedy_joker_effect }, // 18
195 { "Lusty Joker", COMMON_JOKER, 5, false, lusty_joker_desc, lusty_joker_effect }, // 19
196 // Spritesheet 2
197 { "Wrathful Joker", COMMON_JOKER, 5, false, wrathful_joker_desc, wrathful_joker_effect }, // 20
198 { "Gluttonous Joker", COMMON_JOKER, 5, false, gluttonous_joker_desc, gluttonous_joker_effect }, // 21
199 // Spritesheet 3
200 { "Crazy Joker", COMMON_JOKER, 4, false, crazy_joker_desc, crazy_joker_effect }, // 22
201 { "Mad Joker", COMMON_JOKER, 4, false, mad_joker_desc, mad_joker_effect }, // 23
202 { "Clever Joker", COMMON_JOKER, 4, false, clever_joker_desc, clever_joker_effect }, // 24
203 { "Devious Joker", COMMON_JOKER, 4, false, devious_joker_desc, devious_joker_effect }, // 25
204 { "Even Steven", COMMON_JOKER, 4, false, even_steven_joker_desc, even_steven_joker_effect }, // 26
205 // Spritesheet 4
206 { "Blackboard", UNCOMMON_JOKER, 6, false, blackboard_joker_desc, blackboard_joker_effect }, // 27
207 { "Mystic Summit", COMMON_JOKER, 5, false, mystic_summit_joker_desc, mystic_summit_joker_effect }, // 28
208 { "Walkie Talkie", COMMON_JOKER, 4, false, walkie_talkie_joker_desc, walkie_talkie_joker_effect }, // 29
209 { "Zany Joker", COMMON_JOKER, 4, false, zany_joker_desc, zany_joker_effect }, // 30
210 { "Wily Joker", COMMON_JOKER, 4, false, wily_joker_desc, wily_joker_effect }, // 31
211 // Spritesheet 5
212 { "Sly Joker", COMMON_JOKER, 3, false, sly_joker_desc, sly_joker_effect }, // 32
213 { "Jolly Joker", COMMON_JOKER, 3, false, jolly_joker_desc, jolly_joker_effect }, // 33
214 { "Blue Joker", COMMON_JOKER, 5, false, blue_joker_desc, blue_joker_effect }, // 34
215 { "Odd Todd", COMMON_JOKER, 4, false, odd_todd_joker_desc, odd_todd_joker_effect }, // 35
216 // Spritesheet 6
217 { "The Duo", RARE_JOKER, 8, false, the_duo_joker_desc, the_duo_joker_effect }, // 36
218 { "The Trio", RARE_JOKER, 8, false, the_trio_joker_desc, the_trio_joker_effect }, // 37
219 { "The Order", RARE_JOKER, 8, false, the_order_joker_desc, the_order_joker_effect }, // 38
220 { "The Tribe", RARE_JOKER, 8, false, the_tribe_joker_desc, the_tribe_joker_effect }, // 39
221 // Spritesheet 7
222 { "The Family", RARE_JOKER, 8, false, the_family_joker_desc, the_family_joker_effect }, // 40
223 { "Brainstorm", RARE_JOKER, 10, false, brainstorm_joker_desc, blueprint_brainstorm_joker_effect }, // 41 Brainstorm
224 // Spritesheet 8
225 { "Smiley Face", COMMON_JOKER, 4, false, smiley_face_joker_desc, smiley_face_joker_effect }, // 42
226 { "Bull", UNCOMMON_JOKER, 6, false, bull_joker_desc, bull_joker_effect }, // 43
227 // Individual Jokers (for now :3)
228 { "Photograph", COMMON_JOKER, 5, false, photograph_joker_desc, photograph_joker_effect, }, // 44
229 { "Hack", UNCOMMON_JOKER, 6, false, hack_joker_desc, hack_joker_effect }, // 45
230 { "Pareidolia", UNCOMMON_JOKER, 5, false, pareidolia_joker_desc, joker_effect_noop }, // 46 Pareidolia
231 { "Bootstraps", UNCOMMON_JOKER, 7, false, bootstraps_joker_desc, bootstraps_joker_effect }, // 47
232 { "Shortcut", UNCOMMON_JOKER, 7, false, shortcut_joker_desc, joker_effect_noop, }, // 48 Shortcut
233 { "Dusk", UNCOMMON_JOKER, 5, false, dusk_joker_desc, dusk_joker_effect }, // 49
234 { "Four Fingers", UNCOMMON_JOKER, 7, false, four_fingers_joker_desc, joker_effect_noop, }, // 50 Four Fingers
235 { "Seltzer", UNCOMMON_JOKER, 6, false, seltzer_joker_desc, seltzer_joker_effect, }, // 51
236 { "Blueprint", RARE_JOKER, 10, false, blueprint_joker_desc, blueprint_brainstorm_joker_effect }, // 52 Blueprint
237
238 // The following jokers don't have sprites yet,
239 // uncomment them when their sprites are added.
240#if 0
241#endif
242};
243// clang-format on
244
245static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry);
246
247const JokerInfo* get_joker_registry_entry(int joker_id)
248{
249 if (joker_id < 0 || (size_t)joker_id >= joker_registry_size)
250 {
251 return NULL;
252 }
253 return &joker_registry[joker_id];
254}
255
256size_t get_joker_registry_size(void)
257{
258 return joker_registry_size;
259}
260
261#pragma region JOKER DESCRIPTIONS
262
263static int default_joker_desc(Joker* joker, Rect dest_rect)
264{
265 static const char desc[] = TTE_RED_TAG "+4 " TTE_BLACK_TAG "Mult";
266 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
267}
268
269static int greedy_joker_desc(Joker* joker, Rect dest_rect)
270{
271 static const char desc[] =
272 TTE_BLACK_TAG "Played cards with " TTE_DIAMOND_TAG TTE_BLACK_TAG "suit give " TTE_RED_TAG
273 "+3 " TTE_BLACK_TAG "Mult when scored";
274 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
275}
276
277static int lusty_joker_desc(Joker* joker, Rect dest_rect)
278{
279 static const char desc[] =
280 TTE_BLACK_TAG "Played cards with " TTE_HEART_TAG TTE_BLACK_TAG "suit give " TTE_RED_TAG
281 "+3 " TTE_BLACK_TAG "Mult when scored";
282 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
283}
284
285static int wrathful_joker_desc(Joker* joker, Rect dest_rect)
286{
287 static const char desc[] =
288 TTE_BLACK_TAG "Played cards with " TTE_SPADE_TAG TTE_BLACK_TAG "suit give " TTE_RED_TAG
289 "+3 " TTE_BLACK_TAG "Mult when scored";
290 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
291}
292
293static int gluttonous_joker_desc(Joker* joker, Rect dest_rect)
294{
295 static const char desc[] =
296 TTE_BLACK_TAG "Played cards with " TTE_CLUB_TAG TTE_BLACK_TAG "suit give " TTE_RED_TAG
297 "+3 " TTE_BLACK_TAG "Mult when scored";
298 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
299}
300
301static int jolly_joker_desc(Joker* joker, Rect dest_rect)
302{
303 static const char desc[] =
304 TTE_RED_TAG "+8 " TTE_BLACK_TAG "Mult if played hand contains a " TTE_YELLOW_TAG "Pair";
305 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
306}
307
308static int zany_joker_desc(Joker* joker, Rect dest_rect)
309{
310 static const char desc[] = TTE_RED_TAG
311 "+12 " TTE_BLACK_TAG "Mult if played hand contains a " TTE_YELLOW_TAG "Three of a Kind";
312 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
313}
314
315static int mad_joker_desc(Joker* joker, Rect dest_rect)
316{
317 static const char desc[] = TTE_RED_TAG
318 "+10 " TTE_BLACK_TAG "Mult if played hand contains a " TTE_YELLOW_TAG "Two Pair";
319 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
320}
321
322static int crazy_joker_desc(Joker* joker, Rect dest_rect)
323{
324 static const char desc[] = TTE_RED_TAG
325 "+12 " TTE_BLACK_TAG "Mult if played hand contains a " TTE_YELLOW_TAG "Straight";
326 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
327}
328
329static int droll_joker_desc(Joker* joker, Rect dest_rect)
330{
331 static const char desc[] =
332 TTE_RED_TAG "+10 " TTE_BLACK_TAG "Mult if played hand contains a " TTE_YELLOW_TAG "Flush";
333 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
334}
335
336static int sly_joker_desc(Joker* joker, Rect dest_rect)
337{
338 static const char desc[] =
339 TTE_BLUE_TAG "+50 " TTE_BLACK_TAG "Chips if played hand contains a " TTE_YELLOW_TAG "Pair";
340 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
341}
342
343static int wily_joker_desc(Joker* joker, Rect dest_rect)
344{
345 static const char desc[] = TTE_BLUE_TAG
346 "+100 " TTE_BLACK_TAG "Chips if played hand contains a " TTE_YELLOW_TAG "Three of a Kind";
347 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
348}
349
350static int clever_joker_desc(Joker* joker, Rect dest_rect)
351{
352 static const char desc[] = TTE_BLUE_TAG
353 "+80 " TTE_BLACK_TAG "Chips if played hand contains a " TTE_YELLOW_TAG "Two Pair";
354 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
355}
356
357static int devious_joker_desc(Joker* joker, Rect dest_rect)
358{
359 static const char desc[] = TTE_BLUE_TAG
360 "+100 " TTE_BLACK_TAG "Chips if played hand contains a " TTE_YELLOW_TAG "Straight";
361 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
362}
363
364static int crafty_joker_desc(Joker* joker, Rect dest_rect)
365{
366 static const char desc[] =
367 TTE_BLUE_TAG "+80 " TTE_BLACK_TAG "Chips if played hand contains a " TTE_YELLOW_TAG "Flush";
368 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
369}
370
371static int half_joker_desc(Joker* joker, Rect dest_rect)
372{
373 static const char desc[] =
374 TTE_RED_TAG "+20 " TTE_BLACK_TAG "Mult if played hand contains " TTE_YELLOW_TAG
375 "3 " TTE_BLACK_TAG "or fewer cards";
376 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
377}
378
379static int stencil_joker_desc(Joker* joker, Rect dest_rect)
380{
381 static const char desc_format[] =
382 TTE_RED_TAG "X1 " TTE_BLACK_TAG
383 "Mult for each empty Joker slot Joker Stencil included\n\n(Now " TTE_RED_TAG
384 "X%ld " TTE_BLACK_TAG "Mult)";
385 const u32 desc_max_size = 130;
386
387 List* jokers = get_jokers_list();
388 u32 stencil_bonus = MAX_JOKERS_HELD_SIZE - list_get_len(jokers);
389
390 ListItr itr = list_itr_create(jokers);
391 JokerObject* joker_object;
392 while ((joker_object = list_itr_next(&itr)))
393 {
394 if (joker_object->joker->id == STENCIL_JOKER_ID)
395 stencil_bonus++;
396 }
397
398 char desc[desc_max_size];
399 snprintf(desc, desc_max_size, desc_format, stencil_bonus);
400
401 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
402}
403
404static int misprint_joker_desc(Joker* joker, Rect dest_rect)
405{
406 // TODO: print glitchy desc with occasional next card reveal
407 char desc[] = TTE_YELLOW_TAG "Random" TTE_BLACK_TAG " Mult between " TTE_RED_TAG
408 "+0" TTE_BLACK_TAG " and " TTE_RED_TAG "+23";
409 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
410}
411
412static int walkie_talkie_joker_desc(Joker* joker, Rect dest_rect)
413{
414 static const char desc[] =
415 TTE_BLACK_TAG "Each played " TTE_YELLOW_TAG "10 " TTE_BLACK_TAG "or " TTE_YELLOW_TAG
416 "4 " TTE_BLACK_TAG "gives " TTE_BLUE_TAG "+10 " TTE_BLACK_TAG
417 "Chips and " TTE_RED_TAG "+4 " TTE_BLACK_TAG "Mult when scored";
418 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
419}
420
421static int fibonnaci_joker_desc(Joker* joker, Rect dest_rect)
422{
423 static const char desc[] =
424 TTE_BLACK_TAG "Each played\n" TTE_YELLOW_TAG "Ace" TTE_BLACK_TAG ", " TTE_YELLOW_TAG
425 "2" TTE_BLACK_TAG ", " TTE_YELLOW_TAG "3" TTE_BLACK_TAG ", " TTE_YELLOW_TAG
426 "5" TTE_BLACK_TAG ", " TTE_YELLOW_TAG "8\n" TTE_BLACK_TAG "gives " TTE_RED_TAG
427 "+8 " TTE_BLACK_TAG "Mult when scored";
428
429 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
430}
431
432static int banner_joker_desc(Joker* joker, Rect dest_rect)
433{
434 static const char desc[] =
435 TTE_BLUE_TAG "+30 " TTE_BLACK_TAG "Chips for each remaining " TTE_YELLOW_TAG "discard";
436 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
437}
438
439static int mystic_summit_joker_desc(Joker* joker, Rect dest_rect)
440{
441 static const char desc[] = TTE_RED_TAG "+15 " TTE_BLACK_TAG "Mult when " TTE_YELLOW_TAG
442 "0 " TTE_BLACK_TAG "discards remaining ";
443 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
444}
445
446static int blackboard_joker_desc(Joker* joker, Rect dest_rect)
447{
448 static const char desc[] = TTE_RED_TAG
449 "X3 " TTE_BLACK_TAG "Mult if all cards held in hand are " TTE_SPADE_TAG TTE_BLACK_TAG
450 "or " TTE_CLUB_TAG;
451 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
452}
453
454static int blue_joker_desc(Joker* joker, Rect dest_rect)
455{
456 static const char desc_format[] =
457 TTE_BLUE_TAG "+2 " TTE_BLACK_TAG "Chips for each remaining card in " TTE_YELLOW_TAG
458 "deck" TTE_BLACK_TAG "\n\n(Now " TTE_BLUE_TAG "+%ld" TTE_BLACK_TAG " Chips)";
459 const u32 desc_max_size = 139;
460
461 u32 blue_bonus = (get_deck_top() + 1) * 2;
462
463 char desc[desc_max_size];
464 snprintf(desc, desc_max_size, desc_format, blue_bonus);
465
466 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
467}
468
469static int raised_fist_joker_desc(Joker* joker, Rect dest_rect)
470{
471 static const char desc[] =
472 TTE_BLACK_TAG "Adds " TTE_YELLOW_TAG "double" TTE_BLACK_TAG " the rank of " TTE_YELLOW_TAG
473 "lowest" TTE_BLACK_TAG " ranked card held in hand to Mult";
474 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
475}
476
477static int reserved_parking_joker_desc(Joker* joker, Rect dest_rect)
478{
479 static const char desc[] = TTE_BLACK_TAG
480 "Each " TTE_YELLOW_TAG "face" TTE_BLACK_TAG " card held in hand has a " TTE_GREEN_TAG
481 "1 in 2" TTE_BLACK_TAG " chance to give " TTE_YELLOW_TAG "$1";
482 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
483}
484
485static int business_card_joker_desc(Joker* joker, Rect dest_rect)
486{
487 static const char desc[] = TTE_BLACK_TAG
488 "Played " TTE_YELLOW_TAG "face" TTE_BLACK_TAG " cards have a " TTE_GREEN_TAG
489 "1 in 2" TTE_BLACK_TAG " chance to give " TTE_YELLOW_TAG "$2" TTE_BLACK_TAG " when scored";
490 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
491}
492
493static int scholar_joker_desc(Joker* joker, Rect dest_rect)
494{
495 static const char desc[] = TTE_BLACK_TAG
496 "Played " TTE_YELLOW_TAG "Aces" TTE_BLACK_TAG " give " TTE_BLUE_TAG "+20" TTE_BLACK_TAG
497 " Chips and " TTE_RED_TAG "+4" TTE_BLACK_TAG " Mult when scored";
498 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
499}
500
501static int scary_face_joker_desc(Joker* joker, Rect dest_rect)
502{
503 static const char desc[] =
504 TTE_BLACK_TAG "Played " TTE_YELLOW_TAG "face" TTE_BLACK_TAG " cards give " TTE_BLUE_TAG
505 "+30" TTE_BLACK_TAG " Chips when scored";
506 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
507}
508
509static int abstract_joker_desc(Joker* joker, Rect dest_rect)
510{
511 static const char desc_format[] =
512 TTE_RED_TAG "+3" TTE_BLACK_TAG " Mult for each " TTE_YELLOW_TAG "Joker" TTE_BLACK_TAG
513 " card\n\n(Now " TTE_RED_TAG "+%ld" TTE_BLACK_TAG " Mult)";
514 const u32 desc_max_size = 125;
515
516 u32 abstract_bonus = list_get_len(get_jokers_list()) * 3;
517
518 char desc[desc_max_size];
519 snprintf(desc, desc_max_size, desc_format, abstract_bonus);
520
521 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
522}
523
524static int bull_joker_desc(Joker* joker, Rect dest_rect)
525{
526 static const char desc_format[] =
527 TTE_BLUE_TAG "+2" TTE_BLACK_TAG " Chips for each " TTE_YELLOW_TAG "$1" TTE_BLACK_TAG
528 " you have\n\n(Now " TTE_BLUE_TAG "+%ld" TTE_BLACK_TAG " Chips)";
529 const u32 desc_max_size = 127;
530
531 u32 bull_bonus = (g_game_vars.money > 0) ? g_game_vars.money * 2 : 0;
532
533 char desc[desc_max_size];
534 snprintf(desc, desc_max_size, desc_format, bull_bonus);
535
536 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
537}
538
539static int smiley_face_joker_desc(Joker* joker, Rect dest_rect)
540{
541 static const char desc[] =
542 TTE_BLACK_TAG "Played " TTE_YELLOW_TAG "face" TTE_BLACK_TAG " cards give " TTE_RED_TAG
543 "+5" TTE_BLACK_TAG " Mult when scored";
544 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
545}
546
547static int even_steven_joker_desc(Joker* joker, Rect dest_rect)
548{
549 static const char desc[] =
550 TTE_BLACK_TAG "Played cards with " TTE_YELLOW_TAG "even rank give " TTE_RED_TAG
551 "+4" TTE_BLACK_TAG " Mult when scored\n(10, 8, 6, 4, 2)";
552 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
553}
554
555static int odd_todd_joker_desc(Joker* joker, Rect dest_rect)
556{
557 static const char desc[] =
558 TTE_BLACK_TAG "Played cards with " TTE_YELLOW_TAG "odd rank give " TTE_BLUE_TAG
559 "+31" TTE_BLACK_TAG " Chips when scored\n(A, 9, 7, 5, 3)";
560 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
561}
562
563static int acrobat_joker_desc(Joker* joker, Rect dest_rect)
564{
565 static const char desc[] = TTE_RED_TAG "X3" TTE_BLACK_TAG " Mult on " TTE_YELLOW_TAG
566 "final hand" TTE_BLACK_TAG " of round";
567 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
568}
569
570static int hanging_chad_joker_desc(Joker* joker, Rect dest_rect)
571{
572 static const char desc[] = TTE_BLACK_TAG "Retrigger " TTE_YELLOW_TAG "first" TTE_BLACK_TAG
573 " played card used in scoring " TTE_YELLOW_TAG
574 "2" TTE_BLACK_TAG " additional times ";
575 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
576}
577
578static int the_duo_joker_desc(Joker* joker, Rect dest_rect)
579{
580 static const char desc[] =
581 TTE_RED_TAG "X2" TTE_BLACK_TAG " Mult if played hand contains a " TTE_YELLOW_TAG "Pair";
582 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
583}
584
585static int the_trio_joker_desc(Joker* joker, Rect dest_rect)
586{
587 static const char desc[] = TTE_RED_TAG
588 "X3" TTE_BLACK_TAG " Mult if played hand contains a " TTE_YELLOW_TAG "Three of a Kind";
589 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
590}
591
592static int the_family_joker_desc(Joker* joker, Rect dest_rect)
593{
594 static const char desc[] = TTE_RED_TAG
595 "X4" TTE_BLACK_TAG " Mult if played hand contains a " TTE_YELLOW_TAG "Four of a Kind";
596 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
597}
598
599static int the_order_joker_desc(Joker* joker, Rect dest_rect)
600{
601 static const char desc[] =
602 TTE_RED_TAG "X3" TTE_BLACK_TAG " Mult if played hand contains a " TTE_YELLOW_TAG "Straight";
603 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
604}
605
606static int the_tribe_joker_desc(Joker* joker, Rect dest_rect)
607{
608 static const char desc[] =
609 TTE_RED_TAG "X2" TTE_BLACK_TAG " Mult if played hand contains a " TTE_YELLOW_TAG "Flush";
610 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
611}
612
613static int bootstraps_joker_desc(Joker* joker, Rect dest_rect)
614{
615 static const char desc_format[] =
616 TTE_RED_TAG "+2" TTE_BLACK_TAG " Mult for every " TTE_YELLOW_TAG "$5" TTE_BLACK_TAG
617 " you have\n\n(Now " TTE_RED_TAG "+%ld" TTE_BLACK_TAG " Mult)";
618 const u32 desc_max_size = 125;
619
620 u32 bootstrap_bonus = (g_game_vars.money > 0) ? (g_game_vars.money / 5) * 2 : 0;
621
622 char desc[desc_max_size];
623 snprintf(desc, desc_max_size, desc_format, bootstrap_bonus);
624
625 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
626}
627
628static int shoot_the_moon_joker_desc(Joker* joker, Rect dest_rect)
629{
630 static const char desc[] =
631 TTE_BLACK_TAG "Each " TTE_YELLOW_TAG "Queen" TTE_BLACK_TAG
632 " held in hand gives " TTE_RED_TAG "+13" TTE_BLACK_TAG " Mult";
633 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
634}
635
636static int photograph_joker_desc(Joker* joker, Rect dest_rect)
637{
638 static const char desc[] =
639 TTE_BLACK_TAG "First played " TTE_YELLOW_TAG "face" TTE_BLACK_TAG " card gives " TTE_RED_TAG
640 "X2" TTE_BLACK_TAG " Mult when scored";
641 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
642}
643
644static int dusk_joker_desc(Joker* joker, Rect dest_rect)
645{
646 static const char desc[] = TTE_BLACK_TAG "Retrigger all played cards in " TTE_YELLOW_TAG
647 "final hand" TTE_BLACK_TAG " of the round";
648 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
649}
650
651static int brainstorm_joker_desc(Joker* joker, Rect dest_rect)
652{
653 static const char desc[] =
654 TTE_BLACK_TAG "Copies ability of the leftmost " TTE_YELLOW_TAG "Joker";
655 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
656}
657
658static int blueprint_joker_desc(Joker* joker, Rect dest_rect)
659{
660 static const char desc[] =
661 TTE_BLACK_TAG "Copies ability of " TTE_YELLOW_TAG "Joker" TTE_BLACK_TAG " to the right";
662 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
663}
664
665static int hack_joker_desc(Joker* joker, Rect dest_rect)
666{
667 static const char desc[] = TTE_BLACK_TAG
668 "Retrigger each played " TTE_YELLOW_TAG "2" TTE_BLACK_TAG ", " TTE_YELLOW_TAG
669 "3" TTE_BLACK_TAG ", " TTE_YELLOW_TAG "4" TTE_BLACK_TAG ", or " TTE_YELLOW_TAG "5";
670 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
671}
672
673static int seltzer_joker_desc(Joker* joker, Rect dest_rect)
674{
675 static const char desc_format[] = TTE_BLACK_TAG
676 "Retrigger all cards played for the next " TTE_YELLOW_TAG "%ld" TTE_BLACK_TAG " hands";
677 const u32 desc_max_size = 94;
678
679 char desc[desc_max_size];
680 snprintf(desc, desc_max_size, desc_format, joker->persistent_state);
681
682 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
683}
684
685static int sock_and_buskin_joker_desc(Joker* joker, Rect dest_rect)
686{
687 static const char desc[] =
688 TTE_BLACK_TAG "Retrigger all played " TTE_YELLOW_TAG "face" TTE_BLACK_TAG " cards";
689 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
690}
691
692static int pareidolia_joker_desc(Joker* joker, Rect dest_rect)
693{
694 static const char desc[] =
695 TTE_BLACK_TAG "All cards are considered " TTE_YELLOW_TAG "face" TTE_BLACK_TAG " cards";
696 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
697}
698
699static int shortcut_joker_desc(Joker* joker, Rect dest_rect)
700{
701 static const char desc[] =
702 TTE_BLACK_TAG "Allows " TTE_YELLOW_TAG "Straights" TTE_BLACK_TAG
703 " to be made with gaps of " TTE_YELLOW_TAG "1 rank" TTE_BLACK_TAG
704 "\n\n(ex: " TTE_YELLOW_TAG "10 8 6 5 3" TTE_BLACK_TAG ")";
705 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
706}
707
708static int four_fingers_joker_desc(Joker* joker, Rect dest_rect)
709{
710 static const char desc[] =
711 TTE_BLACK_TAG "All " TTE_YELLOW_TAG "Flushes" TTE_BLACK_TAG " and " TTE_YELLOW_TAG
712 "Straights" TTE_BLACK_TAG " can be made with 4 cards";
713 return tte_printf_justified_in_rect(desc, dest_rect, JUSTIFY_CENTER, SCREEN_LEFT, true);
714}
715
716#pragma endregion
717
718#pragma region JOKER EFFECTS
719
720static u32 joker_effect_noop(
721 Joker* joker,
722 Card* scored_card,
723 enum JokerEvent joker_event,
724 JokerEffect** joker_effect
725)
726{
727 return JOKER_EFFECT_FLAG_NONE;
728}
729
730static u32 default_joker_effect(
731 Joker* joker,
732 Card* scored_card,
733 enum JokerEvent joker_event,
734 JokerEffect** joker_effect
735)
736{
737 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
738 *joker_effect = &s_shared_joker_effect;
739
740 (*joker_effect)->mult = 4;
741
742 return JOKER_EFFECT_FLAG_MULT;
743}
744
745static u32 sinful_joker_effect(
746 Card* scored_card,
747 u8 sinful_suit,
748 enum JokerEvent joker_event,
749 JokerEffect** joker_effect
750)
751{
752 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
753
754 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
755
756 if (scored_card->suit == sinful_suit)
757 {
758 *joker_effect = &s_shared_joker_effect;
759
760 (*joker_effect)->mult = 3;
761 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
762 }
763 return effect_flags_ret;
764}
765
766static u32 greedy_joker_effect(
767 Joker* joker,
768 Card* scored_card,
769 enum JokerEvent joker_event,
770 JokerEffect** joker_effect
771)
772{
773 return sinful_joker_effect(scored_card, DIAMONDS, joker_event, joker_effect);
774}
775
776static u32 lusty_joker_effect(
777 Joker* joker,
778 Card* scored_card,
779 enum JokerEvent joker_event,
780 JokerEffect** joker_effect
781)
782{
783 return sinful_joker_effect(scored_card, HEARTS, joker_event, joker_effect);
784}
785
786static u32 wrathful_joker_effect(
787 Joker* joker,
788 Card* scored_card,
789 enum JokerEvent joker_event,
790 JokerEffect** joker_effect
791)
792{
793 return sinful_joker_effect(scored_card, SPADES, joker_event, joker_effect);
794}
795
796static u32 gluttonous_joker_effect(
797 Joker* joker,
798 Card* scored_card,
799 enum JokerEvent joker_event,
800 JokerEffect** joker_effect
801)
802{
803 return sinful_joker_effect(scored_card, CLUBS, joker_event, joker_effect);
804}
805
806static u32 jolly_joker_effect(
807 Joker* joker,
808 Card* scored_card,
809 enum JokerEvent joker_event,
810 JokerEffect** joker_effect
811)
812{
813 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
814
815 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
816
817 if (get_contained_hands()->PAIR)
818 {
819 *joker_effect = &s_shared_joker_effect;
820
821 (*joker_effect)->mult = 8;
822 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
823 }
824
825 return effect_flags_ret;
826}
827
828static u32 zany_joker_effect(
829 Joker* joker,
830 Card* scored_card,
831 enum JokerEvent joker_event,
832 JokerEffect** joker_effect
833)
834{
835 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
836
837 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
838
839 if (get_contained_hands()->THREE_OF_A_KIND)
840 {
841 *joker_effect = &s_shared_joker_effect;
842
843 (*joker_effect)->mult = 12;
844 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
845 }
846
847 return effect_flags_ret;
848}
849
850static u32 mad_joker_effect(
851 Joker* joker,
852 Card* scored_card,
853 enum JokerEvent joker_event,
854 JokerEffect** joker_effect
855)
856{
857 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
858
859 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
860
861 if (get_contained_hands()->TWO_PAIR)
862 {
863 *joker_effect = &s_shared_joker_effect;
864
865 (*joker_effect)->mult = 10;
866 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
867 }
868
869 return effect_flags_ret;
870}
871
872static u32 crazy_joker_effect(
873 Joker* joker,
874 Card* scored_card,
875 enum JokerEvent joker_event,
876 JokerEffect** joker_effect
877)
878{
879 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
880
881 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
882
883 if (get_contained_hands()->STRAIGHT)
884 {
885 *joker_effect = &s_shared_joker_effect;
886
887 (*joker_effect)->mult = 12;
888 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
889 }
890
891 return effect_flags_ret;
892}
893
894static u32 droll_joker_effect(
895 Joker* joker,
896 Card* scored_card,
897 enum JokerEvent joker_event,
898 JokerEffect** joker_effect
899)
900{
901 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
902
903 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
904
905 if (get_contained_hands()->FLUSH)
906 {
907 *joker_effect = &s_shared_joker_effect;
908
909 (*joker_effect)->mult = 10;
910 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
911 }
912
913 return effect_flags_ret;
914}
915
916static u32 sly_joker_effect(
917 Joker* joker,
918 Card* scored_card,
919 enum JokerEvent joker_event,
920 JokerEffect** joker_effect
921)
922{
923 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
924
925 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
926
927 if (get_contained_hands()->PAIR)
928 {
929 *joker_effect = &s_shared_joker_effect;
930
931 (*joker_effect)->chips = 50;
932 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
933 }
934
935 return effect_flags_ret;
936}
937
938static u32 wily_joker_effect(
939 Joker* joker,
940 Card* scored_card,
941 enum JokerEvent joker_event,
942 JokerEffect** joker_effect
943)
944{
945 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
946
947 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
948
949 if (get_contained_hands()->THREE_OF_A_KIND)
950 {
951 *joker_effect = &s_shared_joker_effect;
952
953 (*joker_effect)->chips = 100;
954 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
955 }
956
957 return effect_flags_ret;
958}
959
960static u32 clever_joker_effect(
961 Joker* joker,
962 Card* scored_card,
963 enum JokerEvent joker_event,
964 JokerEffect** joker_effect
965)
966{
967 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
968
969 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
970
971 if (get_contained_hands()->TWO_PAIR)
972 {
973 *joker_effect = &s_shared_joker_effect;
974
975 (*joker_effect)->chips = 80;
976 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
977 }
978
979 return effect_flags_ret;
980}
981
982static u32 devious_joker_effect(
983 Joker* joker,
984 Card* scored_card,
985 enum JokerEvent joker_event,
986 JokerEffect** joker_effect
987)
988{
989 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
990
991 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
992
993 if (get_contained_hands()->STRAIGHT)
994 {
995 *joker_effect = &s_shared_joker_effect;
996
997 (*joker_effect)->chips = 100;
998 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
999 }
1000
1001 return effect_flags_ret;
1002}
1003
1004static u32 crafty_joker_effect(
1005 Joker* joker,
1006 Card* scored_card,
1007 enum JokerEvent joker_event,
1008 JokerEffect** joker_effect
1009)
1010{
1011 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1012
1013 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1014
1015 if (get_contained_hands()->FLUSH)
1016 {
1017 *joker_effect = &s_shared_joker_effect;
1018
1019 (*joker_effect)->chips = 80;
1020 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
1021 }
1022
1023 return effect_flags_ret;
1024}
1025
1026static u32 half_joker_effect(
1027 Joker* joker,
1028 Card* scored_card,
1029 enum JokerEvent joker_event,
1030 JokerEffect** joker_effect
1031)
1032{
1033 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1034
1035 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1036
1037 int played_size = get_played_size();
1038 if (played_size <= 3)
1039 {
1040 *joker_effect = &s_shared_joker_effect;
1041
1042 (*joker_effect)->mult = 20;
1043 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1044 }
1045
1046 return effect_flags_ret;
1047}
1048
1049static u32 stencil_joker_effect(
1050 Joker* joker,
1051 Card* scored_card,
1052 enum JokerEvent joker_event,
1053 JokerEffect** joker_effect
1054)
1055{
1056 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1057
1058 *joker_effect = &s_shared_joker_effect;
1059
1060 List* jokers = get_jokers_list();
1061
1062 // +1 xmult per empty joker slot...
1063 int num_jokers = list_get_len(jokers);
1064
1065 (*joker_effect)->xmult = (MAX_JOKERS_HELD_SIZE)-num_jokers;
1066
1067 // ...and also each stencil_joker adds +1 xmult
1068 ListItr itr = list_itr_create(jokers);
1069 JokerObject* joker_object;
1070
1071 while ((joker_object = list_itr_next(&itr)))
1072 {
1073 if (joker_object->joker->id == STENCIL_JOKER_ID)
1074 (*joker_effect)->xmult++;
1075 }
1076
1077 return JOKER_EFFECT_FLAG_XMULT;
1078}
1079
1080#define MISPRINT_MAX_MULT 23
1081static u32 misprint_joker_effect(
1082 Joker* joker,
1083 Card* scored_card,
1084 enum JokerEvent joker_event,
1085 JokerEffect** joker_effect
1086)
1087{
1088 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1089
1090 *joker_effect = &s_shared_joker_effect;
1091
1092 (*joker_effect)->mult = rng_get_u32(RNG_SEQ_JOKER_MISPRINT) % (MISPRINT_MAX_MULT + 1);
1093
1094 return JOKER_EFFECT_FLAG_MULT;
1095}
1096
1097static u32 walkie_talkie_joker_effect(
1098 Joker* joker,
1099 Card* scored_card,
1100 enum JokerEvent joker_event,
1101 JokerEffect** joker_effect
1102)
1103{
1104 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1105
1106 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1107
1108 if (scored_card->rank == TEN || scored_card->rank == FOUR)
1109 {
1110 *joker_effect = &s_shared_joker_effect;
1111
1112 (*joker_effect)->chips = 10;
1113 (*joker_effect)->mult = 4;
1114 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS | JOKER_EFFECT_FLAG_MULT;
1115 }
1116
1117 return effect_flags_ret;
1118}
1119
1120static u32 fibonnaci_joker_effect(
1121 Joker* joker,
1122 Card* scored_card,
1123 enum JokerEvent joker_event,
1124 JokerEffect** joker_effect
1125)
1126{
1127 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1128
1129 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1130
1131 switch (scored_card->rank)
1132 {
1133 case ACE:
1134 case TWO:
1135 case THREE:
1136 case FIVE:
1137 case EIGHT:
1138 *joker_effect = &s_shared_joker_effect;
1139 (*joker_effect)->mult = 8;
1140 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1141 break;
1142 default:
1143 break;
1144 }
1145
1146 return effect_flags_ret;
1147}
1148
1149static u32 banner_joker_effect(
1150 Joker* joker,
1151 Card* scored_card,
1152 enum JokerEvent joker_event,
1153 JokerEffect** joker_effect
1154)
1155{
1156 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1157
1158 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1159
1160 if (get_num_discards_remaining() > 0)
1161 {
1162 *joker_effect = &s_shared_joker_effect;
1163
1164 (*joker_effect)->chips = 30 * get_num_discards_remaining();
1165 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
1166 }
1167
1168 return effect_flags_ret;
1169}
1170
1171static u32 mystic_summit_joker_effect(
1172 Joker* joker,
1173 Card* scored_card,
1174 enum JokerEvent joker_event,
1175 JokerEffect** joker_effect
1176)
1177{
1178 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1179
1180 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1181
1182 if (get_num_discards_remaining() == 0)
1183 {
1184 *joker_effect = &s_shared_joker_effect;
1185
1186 (*joker_effect)->mult = 15;
1187 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1188 }
1189
1190 return effect_flags_ret;
1191}
1192
1193static u32 blackboard_joker_effect(
1194 Joker* joker,
1195 Card* scored_card,
1196 enum JokerEvent joker_event,
1197 JokerEffect** joker_effect
1198)
1199{
1200 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1201
1202 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1203
1204 bool all_cards_are_spades_or_clubs = true;
1205 CardObject** hand = get_hand_array();
1206 for (int i = 0; i < g_game_vars.hand_size; i++)
1207 {
1208 u8 suit = hand[i]->card->suit;
1209 if (suit == HEARTS || suit == DIAMONDS)
1210 {
1211 all_cards_are_spades_or_clubs = false;
1212 break;
1213 }
1214 }
1215
1216 if (all_cards_are_spades_or_clubs)
1217 {
1218 *joker_effect = &s_shared_joker_effect;
1219
1220 (*joker_effect)->xmult = 3;
1221 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1222 }
1223
1224 return effect_flags_ret;
1225}
1226
1227static u32 blue_joker_effect(
1228 Joker* joker,
1229 Card* scored_card,
1230 enum JokerEvent joker_event,
1231 JokerEffect** joker_effect
1232)
1233{
1234 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1235
1236 *joker_effect = &s_shared_joker_effect;
1237
1238 (*joker_effect)->chips = (get_deck_top() + 1) * 2;
1239
1240 return JOKER_EFFECT_FLAG_CHIPS;
1241}
1242
1243static u32 raised_fist_joker_effect(
1244 Joker* joker,
1245 Card* scored_card,
1246 enum JokerEvent joker_event,
1247 JokerEffect** joker_effect
1248)
1249{
1250 s32* p_lowest_value_index = &(joker->scoring_state);
1251
1252 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1253
1254 switch (joker_event)
1255 {
1256 // Use this event to compute the index of the lowest value card only once.
1257 // Aces are always considered high value, even in an ace-low straight
1258 case JOKER_EVENT_ON_HAND_PLAYED:
1259 // index initialized at 0 but accessed only if
1260 // hand_size > 0 so we're never out of bounds
1261 *p_lowest_value_index = 0;
1262 u8 lowest_value = IMPOSSIBLY_HIGH_CARD_VALUE;
1263 CardObject** hand = get_hand_array();
1264 for (int i = 0; i < g_game_vars.hand_size; i++)
1265 {
1266 u8 value = card_get_value(hand[i]->card);
1267 if (lowest_value > value)
1268 {
1269 *p_lowest_value_index = i;
1270 lowest_value = value;
1271 }
1272 }
1273 break;
1274
1275 case JOKER_EVENT_ON_CARD_HELD:
1276 if (get_scored_card_index() == *p_lowest_value_index)
1277 {
1278 *joker_effect = &s_shared_joker_effect;
1279
1280 (*joker_effect)->mult = 2 * card_get_value(scored_card);
1281 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1282 }
1283 break;
1284
1285 default:
1286 break;
1287 }
1288
1289 return effect_flags_ret;
1290}
1291
1292static u32 reserved_parking_joker_effect(
1293 Joker* joker,
1294 Card* scored_card,
1295 enum JokerEvent joker_event,
1296 JokerEffect** joker_effect
1297)
1298{
1299 SCORE_ON_EVENT_ONLY(JOKER_EVENT_ON_CARD_HELD, joker_event)
1300
1301 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1302
1303 if (card_is_face(scored_card) && (rng_get_u32(RNG_SEQ_JOKER_RESERVED_PARKING) % 2 == 0))
1304 {
1305 *joker_effect = &s_shared_joker_effect;
1306
1307 (*joker_effect)->money = 1;
1308 effect_flags_ret = JOKER_EFFECT_FLAG_MONEY;
1309 }
1310
1311 return effect_flags_ret;
1312};
1313
1314static u32 business_card_joker_effect(
1315 Joker* joker,
1316 Card* scored_card,
1317 enum JokerEvent joker_event,
1318 JokerEffect** joker_effect
1319)
1320{
1321 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1322
1323 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1324
1325 if (card_is_face(scored_card) && (rng_get_u32(RNG_SEQ_JOKER_BUSINESS_CARD) % 2 == 0))
1326 {
1327 *joker_effect = &s_shared_joker_effect;
1328
1329 (*joker_effect)->money = 2;
1330 effect_flags_ret = JOKER_EFFECT_FLAG_MONEY;
1331 }
1332
1333 return effect_flags_ret;
1334}
1335
1336static u32 scholar_joker_effect(
1337 Joker* joker,
1338 Card* scored_card,
1339 enum JokerEvent joker_event,
1340 JokerEffect** joker_effect
1341)
1342{
1343 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1344
1345 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1346
1347 if (scored_card->rank == ACE)
1348 {
1349 *joker_effect = &s_shared_joker_effect;
1350
1351 (*joker_effect)->chips = 20;
1352 (*joker_effect)->mult = 4;
1353 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS | JOKER_EFFECT_FLAG_MULT;
1354 }
1355
1356 return effect_flags_ret;
1357}
1358
1359static u32 scary_face_joker_effect(
1360 Joker* joker,
1361 Card* scored_card,
1362 enum JokerEvent joker_event,
1363 JokerEffect** joker_effect
1364)
1365{
1366 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1367
1368 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1369
1370 if (card_is_face(scored_card))
1371 {
1372 *joker_effect = &s_shared_joker_effect;
1373
1374 (*joker_effect)->chips = 30;
1375 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
1376 }
1377
1378 return effect_flags_ret;
1379}
1380
1381static u32 abstract_joker_effect(
1382 Joker* joker,
1383 Card* scored_card,
1384 enum JokerEvent joker_event,
1385 JokerEffect** joker_effect
1386)
1387{
1388 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1389
1390 *joker_effect = &s_shared_joker_effect;
1391
1392 // +1 xmult per occupied joker slot
1393 int num_jokers = list_get_len(get_jokers_list());
1394
1395 (*joker_effect)->mult = num_jokers * 3;
1396
1397 return JOKER_EFFECT_FLAG_MULT;
1398}
1399
1400static u32 bull_joker_effect(
1401 Joker* joker,
1402 Card* scored_card,
1403 enum JokerEvent joker_event,
1404 JokerEffect** joker_effect
1405)
1406{
1407 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1408
1409 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1410
1411 // The wiki says it does nothing if money is 0 or below
1412 // This allows us to avoid scoring negative Chips
1413 if (g_game_vars.money > 0)
1414 {
1415 *joker_effect = &s_shared_joker_effect;
1416
1417 (*joker_effect)->chips = g_game_vars.money * 2;
1418 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
1419 }
1420
1421 return effect_flags_ret;
1422}
1423
1424static u32 smiley_face_joker_effect(
1425 Joker* joker,
1426 Card* scored_card,
1427 enum JokerEvent joker_event,
1428 JokerEffect** joker_effect
1429)
1430{
1431 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1432
1433 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1434
1435 if (card_is_face(scored_card))
1436 {
1437 *joker_effect = &s_shared_joker_effect;
1438
1439 (*joker_effect)->mult = 5;
1440 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1441 }
1442
1443 return effect_flags_ret;
1444}
1445
1446static u32 even_steven_joker_effect(
1447 Joker* joker,
1448 Card* scored_card,
1449 enum JokerEvent joker_event,
1450 JokerEffect** joker_effect
1451)
1452{
1453 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1454
1455 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1456
1457 switch (scored_card->rank)
1458 {
1459 case KING:
1460 case QUEEN:
1461 case JACK:
1462 break;
1463 default:
1464 if (card_get_value(scored_card) % 2 == 0)
1465 {
1466 *joker_effect = &s_shared_joker_effect;
1467
1468 (*joker_effect)->mult = 4;
1469 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1470 }
1471 break;
1472 }
1473
1474 return effect_flags_ret;
1475}
1476
1477static u32 odd_todd_joker_effect(
1478 Joker* joker,
1479 Card* scored_card,
1480 enum JokerEvent joker_event,
1481 JokerEffect** joker_effect
1482)
1483{
1484 SCORE_ON_EVENT_ONLY_WITH_CARD(scored_card, JOKER_EVENT_ON_CARD_SCORED, joker_event)
1485
1486 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1487
1488 if (card_get_value(scored_card) % 2 == 1) // todo test ace
1489 {
1490 *joker_effect = &s_shared_joker_effect;
1491
1492 (*joker_effect)->chips = 31;
1493 effect_flags_ret = JOKER_EFFECT_FLAG_CHIPS;
1494 }
1495
1496 return effect_flags_ret;
1497}
1498
1499static u32 acrobat_joker_effect(
1500 Joker* joker,
1501 Card* scored_card,
1502 enum JokerEvent joker_event,
1503 JokerEffect** joker_effect
1504)
1505{
1506 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1507
1508 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1509
1510 // 0 remaining hands mean we're scoring the last hand
1511 if (get_num_hands_remaining() == 0)
1512 {
1513 *joker_effect = &s_shared_joker_effect;
1514
1515 (*joker_effect)->xmult = 3;
1516 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1517 }
1518
1519 return effect_flags_ret;
1520}
1521
1522static u32 hanging_chad_joker_effect(
1523 Joker* joker,
1524 Card* scored_card,
1525 enum JokerEvent joker_event,
1526 JokerEffect** joker_effect
1527)
1528{
1529 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1530 s32* p_remaining_retriggers = &(joker->scoring_state);
1531
1532 switch (joker_event)
1533 {
1534 case JOKER_EVENT_ON_HAND_PLAYED:
1535 *p_remaining_retriggers = 2;
1536 break;
1537
1538 // No need to check if this is the first card scored or not
1539 // p_remaining_retriggers will always reach 0 on the first card, then retrigger
1540 // will be false and scoring will go onto the next card
1541 case JOKER_EVENT_ON_CARD_SCORED_END:
1542 *joker_effect = &s_shared_joker_effect;
1543
1544 (*joker_effect)->retrigger = (*p_remaining_retriggers > 0);
1545 if ((*joker_effect)->retrigger)
1546 {
1547 *p_remaining_retriggers -= 1;
1548 (*joker_effect)->message = "Again!";
1549 effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE;
1550 }
1551 break;
1552
1553 default:
1554 break;
1555 }
1556
1557 return effect_flags_ret;
1558}
1559
1560static u32 the_duo_joker_effect(
1561 Joker* joker,
1562 Card* scored_card,
1563 enum JokerEvent joker_event,
1564 JokerEffect** joker_effect
1565)
1566{
1567 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1568
1569 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1570
1571 if (get_contained_hands()->PAIR)
1572 {
1573 *joker_effect = &s_shared_joker_effect;
1574
1575 (*joker_effect)->xmult = 2;
1576 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1577 }
1578
1579 return effect_flags_ret;
1580}
1581
1582static u32 the_trio_joker_effect(
1583 Joker* joker,
1584 Card* scored_card,
1585 enum JokerEvent joker_event,
1586 JokerEffect** joker_effect
1587)
1588{
1589 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1590
1591 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1592
1593 if (get_contained_hands()->THREE_OF_A_KIND)
1594 {
1595 *joker_effect = &s_shared_joker_effect;
1596
1597 (*joker_effect)->xmult = 3;
1598 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1599 }
1600
1601 return effect_flags_ret;
1602}
1603
1604static u32 the_family_joker_effect(
1605 Joker* joker,
1606 Card* scored_card,
1607 enum JokerEvent joker_event,
1608 JokerEffect** joker_effect
1609)
1610{
1611 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1612
1613 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1614
1615 if (get_contained_hands()->FOUR_OF_A_KIND)
1616 {
1617 *joker_effect = &s_shared_joker_effect;
1618
1619 (*joker_effect)->xmult = 4;
1620 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1621 }
1622
1623 return effect_flags_ret;
1624}
1625
1626static u32 the_order_joker_effect(
1627 Joker* joker,
1628 Card* scored_card,
1629 enum JokerEvent joker_event,
1630 JokerEffect** joker_effect
1631)
1632{
1633 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1634
1635 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1636
1637 if (get_contained_hands()->STRAIGHT)
1638 {
1639 *joker_effect = &s_shared_joker_effect;
1640
1641 (*joker_effect)->xmult = 3;
1642 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1643 }
1644
1645 return effect_flags_ret;
1646}
1647
1648static u32 the_tribe_joker_effect(
1649 Joker* joker,
1650 Card* scored_card,
1651 enum JokerEvent joker_event,
1652 JokerEffect** joker_effect
1653)
1654{
1655 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1656
1657 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1658
1659 if (get_contained_hands()->FLUSH)
1660 {
1661 *joker_effect = &s_shared_joker_effect;
1662
1663 (*joker_effect)->xmult = 2;
1664 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1665 }
1666
1667 return effect_flags_ret;
1668}
1669
1670static u32 bootstraps_joker_effect(
1671 Joker* joker,
1672 Card* scored_card,
1673 enum JokerEvent joker_event,
1674 JokerEffect** joker_effect
1675)
1676{
1677 SCORE_ON_EVENT_ONLY(JOKER_EVENT_INDEPENDENT, joker_event)
1678
1679 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1680
1681 // Same protection as the Bull Joker
1682 if (g_game_vars.money > 0)
1683 {
1684 *joker_effect = &s_shared_joker_effect;
1685
1686 (*joker_effect)->mult = (g_game_vars.money / 5) * 2;
1687 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1688 }
1689
1690 return effect_flags_ret;
1691}
1692
1693static u32 shoot_the_moon_joker_effect(
1694 Joker* joker,
1695 Card* scored_card,
1696 enum JokerEvent joker_event,
1697 JokerEffect** joker_effect
1698)
1699{
1700 SCORE_ON_EVENT_ONLY(JOKER_EVENT_ON_CARD_HELD, joker_event)
1701
1702 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1703
1704 if (scored_card->rank == QUEEN)
1705 {
1706 *joker_effect = &s_shared_joker_effect;
1707
1708 (*joker_effect)->mult = 13;
1709 effect_flags_ret = JOKER_EFFECT_FLAG_MULT;
1710 }
1711
1712 return effect_flags_ret;
1713}
1714
1715static u32 photograph_joker_effect(
1716 Joker* joker,
1717 Card* scored_card,
1718 enum JokerEvent joker_event,
1719 JokerEffect** joker_effect
1720)
1721{
1722 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1723
1724 s32* p_first_face_index = &(joker->scoring_state);
1725
1726 switch (joker_event)
1727 {
1728 case JOKER_EVENT_ON_HAND_PLAYED:
1729 *p_first_face_index = UNDEFINED;
1730 break;
1731
1732 case JOKER_EVENT_ON_CARD_SCORED:
1733 // has a face card been encountered already, and if not, is the current scoring card a
1734 // face card?
1735 if (*p_first_face_index == UNDEFINED && card_is_face(scored_card))
1736 {
1737 *p_first_face_index = get_scored_card_index();
1738 }
1739 // if we have a face card index saved, check against it and give mult accordingly
1740 // Doing this now will trigger the effect the first time we encounter the face card,
1741 // and we will catch potential retriggers
1742 if (*p_first_face_index == get_scored_card_index())
1743 {
1744 *joker_effect = &s_shared_joker_effect;
1745
1746 (*joker_effect)->xmult = 2;
1747 effect_flags_ret = JOKER_EFFECT_FLAG_XMULT;
1748 }
1749 break;
1750 default:
1751 break;
1752 }
1753
1754 return effect_flags_ret;
1755}
1756
1757static u32 dusk_joker_effect(
1758 Joker* joker,
1759 Card* scored_card,
1760 enum JokerEvent joker_event,
1761 JokerEffect** joker_effect
1762)
1763{
1764 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1765
1766 s32* p_last_retriggered_index = &(joker->scoring_state);
1767
1768 switch (joker_event)
1769 {
1770 case JOKER_EVENT_ON_HAND_PLAYED:
1771 // start at -1 so that a first index of 0 can satisfy the retrigger condition below
1772 *p_last_retriggered_index = UNDEFINED;
1773 break;
1774
1775 case JOKER_EVENT_ON_CARD_SCORED_END:
1776 // Only retrigger current card if it's strictly after the last one we retriggered
1777 if (get_num_hands_remaining() == 0)
1778 {
1779 *joker_effect = &s_shared_joker_effect;
1780
1781 (*joker_effect)->retrigger = (*p_last_retriggered_index < get_scored_card_index());
1782 if ((*joker_effect)->retrigger)
1783 {
1784 *p_last_retriggered_index = get_scored_card_index();
1785 (*joker_effect)->message = "Again!";
1786 effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE;
1787 }
1788 }
1789
1790 break;
1791
1792 default:
1793 break;
1794 }
1795
1796 return effect_flags_ret;
1797}
1798
1799static u32 blueprint_brainstorm_joker_effect(
1800 Joker* joker,
1801 Card* scored_card,
1802 enum JokerEvent joker_event,
1803 JokerEffect** joker_effect
1804)
1805{
1806 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1807
1808 // No need for this kind of init since these Jokers
1809 // will have their data copied when needed
1810 if (joker_event == JOKER_EVENT_ON_JOKER_CREATED ||
1811 joker_event == JOKER_EVENT_ON_HAND_SCORED_END || joker_event == JOKER_EVENT_ON_ROUND_END)
1812 {
1813 return effect_flags_ret;
1814 }
1815
1816 // find ourselves in the Jokers list
1817 List* jokers = get_jokers_list();
1818 ListItr itr = list_itr_create(jokers);
1819 JokerObject* copied_joker_object;
1820 while ((copied_joker_object = list_itr_next(&itr)))
1821 {
1822 if (copied_joker_object->joker == joker)
1823 {
1824 break;
1825 }
1826 }
1827
1828 // This shouldn't happen since if we are a scoring Joker, we should always
1829 // be part of the Jokers list, but being extra careful doesn't cost much
1830 if (copied_joker_object == NULL)
1831 {
1832 return effect_flags_ret;
1833 }
1834
1835 // find the copied Joker, may need to bounce around Blueprints and a Brainstorm
1836 // If we encounter NULL, we have a Blueprint at the end of the list that can't copy anything.
1837 // If we go through a Brainstorms twice, we will be in a loop and need to exit
1838 u8 brainstorm_counter = 0;
1839 do
1840 {
1841 switch (copied_joker_object->joker->id)
1842 {
1843 // get the next Joker for Blueprint
1844 case BLUEPRINT_JOKER_ID:
1845 copied_joker_object = list_itr_next(&itr);
1846 break;
1847
1848 // Get the first (leftmost) Joker for Brainstorm
1849 case BRAINSTORM_JOKER_ID:
1850 brainstorm_counter++;
1851 itr = list_itr_create(jokers);
1852 copied_joker_object = list_itr_next(&itr);
1853 break;
1854
1855 // We encountered a Joker that isn't a Copying Joker and copy it now
1856 // but how we copy it depends on this Joker's ID because they don't
1857 // all handle data the same way.
1858 default:
1859 u8 copied_joker_id = copied_joker_object->joker->id;
1860 const JokerInfo* copied_joker_info = get_joker_registry_entry(copied_joker_id);
1861
1862 // Copy the persistent data
1863 joker->persistent_state = copied_joker_object->joker->persistent_state;
1864
1865 // Then regardless of if we copied the data above, apply the
1866 // copied JokerEffect function to the local data
1867 effect_flags_ret =
1868 copied_joker_info
1869 ->joker_effect_func(joker, scored_card, joker_event, joker_effect);
1870
1871 // make also sure we don't expire
1872 effect_flags_ret &= ~JOKER_EFFECT_FLAG_EXPIRE;
1873
1874 // exit the loop
1875 copied_joker_object = NULL;
1876
1877 break;
1878 }
1879 } while (copied_joker_object != NULL && brainstorm_counter < 2);
1880
1881 return effect_flags_ret;
1882}
1883
1884static u32 hack_joker_effect(
1885 Joker* joker,
1886 Card* scored_card,
1887 enum JokerEvent joker_event,
1888 JokerEffect** joker_effect
1889)
1890{
1891 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1892
1893 s32* p_last_retriggered_index = &(joker->scoring_state);
1894
1895 switch (joker_event)
1896 {
1897 case JOKER_EVENT_ON_HAND_PLAYED:
1898 *p_last_retriggered_index = UNDEFINED;
1899 break;
1900
1901 case JOKER_EVENT_ON_CARD_SCORED_END:
1902 // Works the same way as Dusk, but check what rank the card is
1903 switch (scored_card->rank)
1904 {
1905 case TWO:
1906 case THREE:
1907 case FOUR:
1908 case FIVE:
1909 *joker_effect = &s_shared_joker_effect;
1910
1911 (*joker_effect)->retrigger =
1912 (*p_last_retriggered_index < get_scored_card_index());
1913 if ((*joker_effect)->retrigger)
1914 {
1915 *p_last_retriggered_index = get_scored_card_index();
1916 (*joker_effect)->message = "Again!";
1917 effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE;
1918 }
1919 break;
1920 }
1921 break;
1922
1923 default:
1924 break;
1925 }
1926
1927 return effect_flags_ret;
1928}
1929
1930static u32 seltzer_joker_effect(
1931 Joker* joker,
1932 Card* scored_card,
1933 enum JokerEvent joker_event,
1934 JokerEffect** joker_effect
1935)
1936{
1937 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
1938
1939 s32* p_last_retriggered_idx = &(joker->scoring_state);
1940 s32* p_hands_left_until_exp = &(joker->persistent_state);
1941
1942 switch (joker_event)
1943 {
1944 case JOKER_EVENT_ON_JOKER_CREATED:
1945 *p_hands_left_until_exp = 10; // remaining retriggered hands
1946 break;
1947
1948 case JOKER_EVENT_ON_HAND_PLAYED:
1949 *p_last_retriggered_idx = UNDEFINED;
1950 break;
1951
1952 case JOKER_EVENT_ON_CARD_SCORED_END:
1953 // Works the same way as Dusk
1954 // No need to check for p_hands_left_until_exp because the Joker
1955 // will be destroyed the moment we hit 0
1956 *joker_effect = &s_shared_joker_effect;
1957
1958 (*joker_effect)->retrigger = ((*p_last_retriggered_idx) < get_scored_card_index());
1959 if ((*joker_effect)->retrigger)
1960 {
1961 *p_last_retriggered_idx = get_scored_card_index();
1962 (*joker_effect)->message = "Again!";
1963 effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE;
1964 }
1965 break;
1966
1967 case JOKER_EVENT_ON_HAND_SCORED_END:
1968 *joker_effect = &s_shared_joker_effect;
1969 effect_flags_ret = JOKER_EFFECT_FLAG_MESSAGE;
1970
1971 (*p_hands_left_until_exp)--;
1972 if (*p_hands_left_until_exp > 0)
1973 {
1974 // Need to do this for now because the message's memory can't really be allocated
1975 // So we can't use snprintf to craft a message depending on the number of hands left
1976 static const char* SELTZER_MESSAGES[] =
1977 {"1", "2", "3", "4", "5", "6", "7", "8", "9"};
1978 (*joker_effect)->message = (char*)SELTZER_MESSAGES[(*p_hands_left_until_exp) - 1];
1979 }
1980 else
1981 {
1982 (*joker_effect)->message = "Drank!";
1983 (*joker_effect)->expire = true;
1984 effect_flags_ret |= JOKER_EFFECT_FLAG_EXPIRE;
1985 }
1986 break;
1987
1988 default:
1989 break;
1990 }
1991
1992 return effect_flags_ret;
1993}
1994
1995static u32 sock_and_buskin_joker_effect(
1996 Joker* joker,
1997 Card* scored_card,
1998 enum JokerEvent joker_event,
1999 JokerEffect** joker_effect
2000)
2001{
2002 u32 effect_flags_ret = JOKER_EFFECT_FLAG_NONE;
2003
2004 s32* p_last_retriggered_face_index = &(joker->scoring_state);
2005
2006 switch (joker_event)
2007 {
2008 case JOKER_EVENT_ON_HAND_PLAYED:
2009 *p_last_retriggered_face_index = UNDEFINED;
2010 break;
2011
2012 case JOKER_EVENT_ON_CARD_SCORED_END:
2013 *joker_effect = &s_shared_joker_effect;
2014
2015 // Works the same way as Dusk, but for face cards
2016 (*joker_effect)->retrigger =
2017 ((*p_last_retriggered_face_index < get_scored_card_index()) &&
2018 card_is_face(scored_card));
2019 if ((*joker_effect)->retrigger)
2020 {
2021 *p_last_retriggered_face_index = get_scored_card_index();
2022 (*joker_effect)->message = "Again!";
2023 effect_flags_ret = JOKER_EFFECT_FLAG_RETRIGGER | JOKER_EFFECT_FLAG_MESSAGE;
2024 }
2025 break;
2026
2027 default:
2028 break;
2029 }
2030
2031 return effect_flags_ret;
2032}
2033
2034#pragma endregion
Game global game variables struct definition.
int tte_printf_justified_in_rect(const char *raw_text, Rect dst_rect, enum TextJustifyFlag justify_direction, enum ScreenHorzDir bias_direction, bool do_print)
Justify a text with custom formatting tags according to the given justification and bias direction ta...
Functions relative to manipulating and analyzing the contents of the Hand, a.k.a. the Cards we hold a...
ContainedHandTypes * get_contained_hands(void)
Get the contained hands within the selected hand.
Definition hand.c:136
CardObject ** get_hand_array(void)
Get the hand array of Cards currently held in hand.
Definition hand.c:101
Functions relative to the handling of Jokers.
A doubly-linked list.
int list_get_len(const List *list)
Definition list.c:214
void * list_itr_next(ListItr *itr)
Definition list.c:281
ListItr list_itr_create(List *list)
Definition list.c:257
Common functions to handle RNG manipulation. Using this interface has three goals:
u32 rng_get_u32(enum RngSequence key)
Get the next "randomly" generated number in the sequence corresponding to the given type.
Definition random.c:56
API relative to the Rounds we play.
int get_scored_card_index(void)
Get the index of the card that is currently being scored.
Definition round.c:301
int get_played_size(void)
Get the number of cards played.
Definition round.c:253
Definition card.h:46
Definition joker.h:83
An iterator into a list.
Definition list.h:91
A doubly-linked list.
Definition list.h:61
Utilities relating around number string representation and protected arithmatic helper functions.
#define NUM_ELEM_IN_ARR(arr)
Get the number of elements in an array.
Definition util.h:55