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