Merge branch 'main' of https://github.com/cellos51/balatro-gba into main_menu_and_splash_screen
This commit is contained in:
+644
-372
File diff suppressed because it is too large
Load Diff
+101
-18
@@ -24,7 +24,7 @@ static void clip_se_rect_to_screenblock(Rect* rect)
|
||||
clip_se_rect_to_bounding_rect(rect, &FULL_SCREENBLOCK_RECT);
|
||||
}
|
||||
|
||||
u16 main_bg_se_get_tile(BG_POINT pos)
|
||||
SE main_bg_se_get_se(BG_POINT pos)
|
||||
{
|
||||
return se_mat[MAIN_BG_SBB][pos.y][pos.x];
|
||||
}
|
||||
@@ -59,11 +59,10 @@ void main_bg_se_clear_rect(Rect se_rect)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Internal static function to merge implementation of move/copy functions.
|
||||
static void main_bg_se_copy_or_move_rect_1_tile_vert(Rect se_rect, int direction, bool move)
|
||||
static void bg_se_copy_or_move_rect_1_tile_vert(u16 bg_sbb, Rect se_rect, int direction, bool move)
|
||||
{
|
||||
if (se_rect.left > se_rect.right
|
||||
if (se_rect.left > se_rect.right
|
||||
|| (direction != SE_UP && direction != SE_DOWN))
|
||||
{
|
||||
return;
|
||||
@@ -77,17 +76,32 @@ static void main_bg_se_copy_or_move_rect_1_tile_vert(Rect se_rect, int direction
|
||||
|
||||
for (int y = start; y != end - direction; y -= direction)
|
||||
{
|
||||
memcpy16(&(se_mat[MAIN_BG_SBB][y + direction][se_rect.left]),
|
||||
&se_mat[MAIN_BG_SBB][y][se_rect.left],
|
||||
memcpy16(&(se_mat[bg_sbb][y + direction][se_rect.left]),
|
||||
&se_mat[bg_sbb][y][se_rect.left],
|
||||
rect_width(&se_rect));
|
||||
}
|
||||
|
||||
if (move)
|
||||
{
|
||||
memset16(&se_mat[MAIN_BG_SBB][end][se_rect.left], 0x0000, rect_width(&se_rect));
|
||||
memset16(&se_mat[bg_sbb][end][se_rect.left], 0x0000, rect_width(&se_rect));
|
||||
}
|
||||
}
|
||||
|
||||
static void main_bg_se_copy_or_move_rect_1_tile_vert(Rect se_rect, int direction, bool move)
|
||||
{
|
||||
bg_se_copy_or_move_rect_1_tile_vert(MAIN_BG_SBB, se_rect, direction, move);
|
||||
}
|
||||
|
||||
void bg_se_copy_rect_1_tile_vert(u16 bg_sbb, Rect se_rect, int direction)
|
||||
{
|
||||
bg_se_copy_or_move_rect_1_tile_vert(MAIN_BG_SBB, se_rect, direction, false);
|
||||
}
|
||||
|
||||
void bg_se_move_rect_1_tile_vert(u16 bg_sbb, Rect se_rect, int direction)
|
||||
{
|
||||
bg_se_copy_or_move_rect_1_tile_vert(MAIN_BG_SBB, se_rect, direction, true);
|
||||
}
|
||||
|
||||
void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, int direction)
|
||||
{
|
||||
main_bg_se_copy_or_move_rect_1_tile_vert(se_rect, direction, false);
|
||||
@@ -108,20 +122,18 @@ void main_bg_se_copy_rect(Rect se_rect, BG_POINT pos)
|
||||
|
||||
int width = rect_width(&se_rect);
|
||||
int height = rect_height(&se_rect);
|
||||
u16 tile_map[height][width];
|
||||
SE tile_map[height][width];
|
||||
|
||||
// Copy the rect to the tile map
|
||||
for (int sy = 0; sy < height; sy++)
|
||||
{
|
||||
for (int sx = 0; sx < width; sx++)
|
||||
{
|
||||
BG_POINT pt;
|
||||
pt.x = se_rect.left + sx;
|
||||
pt.y = se_rect.top + sy;
|
||||
tile_map[sy][sx] = main_bg_se_get_tile(pt);
|
||||
}
|
||||
memcpy16(&tile_map[sy][0],
|
||||
&se_mat[MAIN_BG_SBB][se_rect.top + sy][se_rect.left],
|
||||
width);
|
||||
}
|
||||
|
||||
|
||||
// TODO: Avoid overflow
|
||||
// Copy the tilemap to the new rect position
|
||||
for (int sy = 0; sy < height; sy++)
|
||||
{
|
||||
memcpy16(&se_mat[MAIN_BG_SBB][pos.y + sy][pos.x],
|
||||
@@ -130,7 +142,7 @@ void main_bg_se_copy_rect(Rect se_rect, BG_POINT pos)
|
||||
}
|
||||
}
|
||||
|
||||
void main_bg_se_copy_tile_to_rect(u16 tile, Rect se_rect)
|
||||
void main_bg_se_fill_rect_with_se(SE se, Rect se_rect)
|
||||
{
|
||||
if (se_rect.left > se_rect.right || se_rect.top > se_rect.bottom)
|
||||
return;
|
||||
@@ -143,7 +155,78 @@ void main_bg_se_copy_tile_to_rect(u16 tile, Rect se_rect)
|
||||
|
||||
for (int sy = 0; sy < height; sy++)
|
||||
{
|
||||
memset16(&se_mat[MAIN_BG_SBB][se_rect.top + sy][se_rect.left], tile, width);
|
||||
memset16(&se_mat[MAIN_BG_SBB][se_rect.top + sy][se_rect.left], se, width);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: Copy the corners of a 3x3 tile block
|
||||
static void main_bg_se_expand_3x3_copy_corners(const Rect* se_dest_rect, const BG_POINT* src_top_left_pnt, int dest_rect_width, int dest_rect_height)
|
||||
{
|
||||
SE top_left_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y][src_top_left_pnt->x];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top][se_dest_rect->left] = top_left_se;
|
||||
|
||||
SE top_right_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y][src_top_left_pnt->x + 2];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top][se_dest_rect->left + dest_rect_width - 1] = top_right_se;
|
||||
|
||||
SE bottom_left_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 2][src_top_left_pnt->x];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top + dest_rect_height - 1][se_dest_rect->left] = bottom_left_se;
|
||||
|
||||
SE bottom_right_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 2][src_top_left_pnt->x + 2];
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top + dest_rect_height - 1][se_dest_rect->left + dest_rect_width - 1] = bottom_right_se;
|
||||
}
|
||||
|
||||
// Helper: Copy the top and bottom sides of a 3x3 tile block
|
||||
static void main_bg_se_expand_3x3_copy_top_bottom(const Rect* se_dest_rect, const BG_POINT* src_top_left_pnt, int dest_rect_width)
|
||||
{
|
||||
if (dest_rect_width > 2)
|
||||
{
|
||||
SE top_middle_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y][src_top_left_pnt->x + 1];
|
||||
SE bottom_middle_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 2][src_top_left_pnt->x + 1];
|
||||
memset16(&se_mat[MAIN_BG_SBB][se_dest_rect->top][se_dest_rect->left + 1], top_middle_se, dest_rect_width - 2);
|
||||
memset16(&se_mat[MAIN_BG_SBB][se_dest_rect->bottom][se_dest_rect->left + 1], bottom_middle_se, dest_rect_width - 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: Copy the left and right sides of a 3x3 tile block
|
||||
static void main_bg_se_expand_3x3_copy_left_right(const Rect* se_dest_rect, const BG_POINT* src_top_left_pnt, int dest_rect_width, int dest_rect_height)
|
||||
{
|
||||
SE middle_left_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 1][src_top_left_pnt->x];
|
||||
SE middle_right_se = se_mat[MAIN_BG_SBB][src_top_left_pnt->y + 1][src_top_left_pnt->x + 2];
|
||||
for (int y = 1; y < dest_rect_height - 1; y++)
|
||||
{
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top + y][se_dest_rect->left] = middle_left_se;
|
||||
se_mat[MAIN_BG_SBB][se_dest_rect->top + y][se_dest_rect->left + dest_rect_width - 1] = middle_right_se;
|
||||
}
|
||||
}
|
||||
|
||||
void main_bg_se_copy_expand_3x3_rect(Rect se_dest_rect, BG_POINT src_top_left_pnt)
|
||||
{
|
||||
clip_se_rect_to_screenblock(&se_dest_rect);
|
||||
|
||||
int dest_rect_width = rect_width(&se_dest_rect);
|
||||
int dest_rect_height = rect_height(&se_dest_rect);
|
||||
|
||||
// Verify the dest rect is at least 2x2
|
||||
if (dest_rect_width < 2 || dest_rect_height < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the corners
|
||||
main_bg_se_expand_3x3_copy_corners(&se_dest_rect, &src_top_left_pnt, dest_rect_width, dest_rect_height);
|
||||
|
||||
// Copy top and bottom sides
|
||||
main_bg_se_expand_3x3_copy_top_bottom(&se_dest_rect, &src_top_left_pnt, dest_rect_width);
|
||||
|
||||
// Copy left and right sides
|
||||
main_bg_se_expand_3x3_copy_left_right(&se_dest_rect, &src_top_left_pnt, dest_rect_width, dest_rect_height);
|
||||
|
||||
// Fill the center if needed
|
||||
if (dest_rect_width > 2 && dest_rect_height > 2)
|
||||
{
|
||||
SE middle_fill_se = se_mat[MAIN_BG_SBB][src_top_left_pnt.y + 1][src_top_left_pnt.x + 1];
|
||||
Rect dest_inner_fill_rect = {se_dest_rect.left + 1, se_dest_rect.top + 1, se_dest_rect.right - 1, se_dest_rect.bottom - 1};
|
||||
main_bg_se_fill_rect_with_se(middle_fill_se, dest_inner_fill_rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -130,6 +130,9 @@ void joker_init()
|
||||
joker_gfxTiles[9] = joker_gfx9Tiles;
|
||||
joker_gfxTiles[10] = joker_gfx10Tiles;
|
||||
joker_gfxTiles[11] = joker_gfx11Tiles;
|
||||
joker_gfxTiles[12] = joker_gfx12Tiles;
|
||||
joker_gfxTiles[13] = joker_gfx13Tiles;
|
||||
joker_gfxTiles[14] = joker_gfx14Tiles;
|
||||
|
||||
joker_gfxPal[0] = joker_gfx0Pal;
|
||||
joker_gfxPal[1] = joker_gfx1Pal;
|
||||
@@ -143,6 +146,9 @@ void joker_init()
|
||||
joker_gfxPal[9] = joker_gfx9Pal;
|
||||
joker_gfxPal[10] = joker_gfx10Pal;
|
||||
joker_gfxPal[11] = joker_gfx11Pal;
|
||||
joker_gfxPal[12] = joker_gfx12Pal;
|
||||
joker_gfxPal[13] = joker_gfx13Pal;
|
||||
joker_gfxPal[14] = joker_gfx14Pal;
|
||||
|
||||
for (int i = 0; i < num_spritesheets; i++)
|
||||
{
|
||||
@@ -181,6 +187,16 @@ JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card)
|
||||
return jinfo->effect(joker, scored_card);
|
||||
}
|
||||
|
||||
int joker_get_sell_value(const Joker* joker)
|
||||
{
|
||||
if (joker == NULL)
|
||||
{
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
return joker->value/2;
|
||||
}
|
||||
|
||||
// JokerObject methods
|
||||
JokerObject *joker_object_new(Joker *joker)
|
||||
{
|
||||
@@ -320,7 +336,6 @@ bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void joker_object_set_selected(JokerObject* joker_object, bool selected)
|
||||
{
|
||||
if (joker_object == NULL)
|
||||
|
||||
+226
-25
@@ -2,6 +2,7 @@
|
||||
#include "joker.h"
|
||||
#include "util.h"
|
||||
#include "hand_analysis.h"
|
||||
#include "list.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static JokerEffect default_joker_effect(Joker *joker, Card *scored_card) {
|
||||
@@ -191,16 +192,19 @@ static JokerEffect joker_stencil_effect(Joker *joker, Card *scored_card) {
|
||||
if (scored_card != NULL)
|
||||
return effect; // if card != null, we are not at the end-phase of scoring yet
|
||||
|
||||
List* jokers = get_jokers();
|
||||
|
||||
// +1 xmult per empty joker slot...
|
||||
int num_jokers = get_jokers_top() + 1;
|
||||
int num_jokers = list_get_size(jokers);
|
||||
|
||||
effect.xmult = (MAX_JOKERS_HELD_SIZE) - num_jokers;
|
||||
|
||||
// ...and also each stencil_joker adds +1 xmult
|
||||
JokerObject** jokers = get_jokers();
|
||||
|
||||
for (int i = 0; i < num_jokers; i++ )
|
||||
{
|
||||
if (jokers[i]->joker->id == JOKER_STENCIL_ID)
|
||||
JokerObject* joker_object = list_get(jokers, i);
|
||||
if (joker_object->joker->id == JOKER_STENCIL_ID)
|
||||
effect.xmult++;
|
||||
}
|
||||
|
||||
@@ -290,30 +294,227 @@ static JokerEffect blackboard_joker_effect(Joker *joker, Card *scored_card) {
|
||||
return effect;
|
||||
}
|
||||
|
||||
static JokerEffect blue_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card != NULL)
|
||||
return effect; // if card != null, we are not at the end-phase of scoring yet
|
||||
|
||||
effect.chips = (get_deck_top() + 1) * 2;
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
// Using __attribute__((unused)) for jokers with no sprites yet to avoid warning
|
||||
// Remove the attribute once they have sprites
|
||||
__attribute__((unused))
|
||||
static JokerEffect raised_fist_joker_effect(Joker *joker, Card *scored_card)
|
||||
{
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card != NULL)
|
||||
return effect; // if card != null, we are not at the end-phase of scoring yet
|
||||
|
||||
// Find the lowest rank card in hand
|
||||
// Aces are always considered high value, even in an ace-low straight
|
||||
u8 lowest_value = IMPOSSIBLY_HIGH_CARD_VALUE;
|
||||
CardObject** hand = get_hand_array();
|
||||
int hand_size = hand_get_size();
|
||||
for (int i = 0; i < hand_size; i++ )
|
||||
{
|
||||
u8 value = card_get_value(hand[i]->card);
|
||||
if (lowest_value > value)
|
||||
lowest_value = value;
|
||||
}
|
||||
|
||||
if (lowest_value != IMPOSSIBLY_HIGH_CARD_VALUE)
|
||||
effect.mult = lowest_value * 2;
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static JokerEffect reserved_parking_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card != NULL)
|
||||
return effect; // if card != null, we are not at the end-phase of scoring yet
|
||||
|
||||
CardObject** hand = get_hand_array();
|
||||
int hand_size = hand_get_size();
|
||||
for (int i = 0; i < hand_size; i++ )
|
||||
{
|
||||
switch (hand[i]->card->rank) {
|
||||
case KING: case QUEEN: case JACK:
|
||||
if (random() % 2 == 0)
|
||||
effect.money += 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return effect;
|
||||
};
|
||||
|
||||
static JokerEffect business_card_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card == NULL)
|
||||
return effect;
|
||||
|
||||
switch (scored_card->rank) {
|
||||
case KING: case QUEEN: case JACK:
|
||||
if (random() % 2 == 0)
|
||||
effect.money = 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
static JokerEffect scholar_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card == NULL)
|
||||
return effect;
|
||||
|
||||
if (scored_card->rank == ACE) {
|
||||
effect.chips = 20;
|
||||
effect.mult = 4;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
static JokerEffect scary_face_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card == NULL)
|
||||
return effect;
|
||||
|
||||
switch (scored_card->rank) {
|
||||
case KING: case QUEEN: case JACK:
|
||||
effect.chips = 30;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static JokerEffect abstract_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card != NULL)
|
||||
return effect; // if card != null, we are not at the end-phase of scoring yet
|
||||
|
||||
// +1 xmult per occupied joker slot
|
||||
int num_jokers = list_get_size(get_jokers());
|
||||
effect.mult = num_jokers * 3;
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static JokerEffect bull_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card != NULL)
|
||||
return effect; // if card != null, we are not at the end-phase of scoring yet
|
||||
|
||||
effect.chips = get_money() * 2;
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
static JokerEffect smiley_face_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card == NULL)
|
||||
return effect;
|
||||
|
||||
switch (scored_card->rank) {
|
||||
case KING: case QUEEN: case JACK:
|
||||
effect.mult = 5;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
static JokerEffect even_steven_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card == NULL)
|
||||
return effect;
|
||||
|
||||
if (card_get_value(scored_card) % 2 == 0) {
|
||||
switch (scored_card->rank) {
|
||||
case KING: case QUEEN: case JACK:
|
||||
break;
|
||||
default:
|
||||
effect.mult = 4;
|
||||
}
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
static JokerEffect odd_todd_joker_effect(Joker *joker, Card *scored_card) {
|
||||
JokerEffect effect = {0};
|
||||
if (scored_card == NULL)
|
||||
return effect;
|
||||
|
||||
if (card_get_value(scored_card) % 2 == 1) // todo test ace
|
||||
effect.chips = 31;
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
/* The index of a joker in the registry matches its ID.
|
||||
* The joker sprites are matched by ID so the position in the registry
|
||||
* determines the joker's sprite.
|
||||
* Each consecutive NUM_JOKERS_PER_SPRITESHEET (defined in joker.c) jokers
|
||||
* share a spritesheet and thus a color palette.
|
||||
* To make better use of color palettes jokers may be rearranged here
|
||||
* (and put together in the matching spritesheet) to share a color palette.
|
||||
* Otherwise the order is similar to the wiki.
|
||||
*/
|
||||
const JokerInfo joker_registry[] = {
|
||||
{ COMMON_JOKER, 2, default_joker_effect }, // DEFAULT_JOKER_ID = 0
|
||||
{ COMMON_JOKER, 5, greedy_joker_effect }, // GREEDY_JOKER_ID = 1
|
||||
{ COMMON_JOKER, 5, lusty_joker_effect }, // etc...
|
||||
{ COMMON_JOKER, 5, wrathful_joker_effect },
|
||||
{ COMMON_JOKER, 5, gluttonous_joker_effect },
|
||||
{ COMMON_JOKER, 3, jolly_joker_effect },
|
||||
{ COMMON_JOKER, 4, zany_joker_effect },
|
||||
{ COMMON_JOKER, 4, mad_joker_effect },
|
||||
{ COMMON_JOKER, 4, crazy_joker_effect },
|
||||
{ COMMON_JOKER, 4, droll_joker_effect },
|
||||
{ COMMON_JOKER, 3, sly_joker_effect },
|
||||
{ COMMON_JOKER, 4, wily_joker_effect },
|
||||
{ COMMON_JOKER, 4, clever_joker_effect },
|
||||
{ COMMON_JOKER, 4, devious_joker_effect },
|
||||
{ COMMON_JOKER, 4, crafty_joker_effect },
|
||||
{ COMMON_JOKER, 5, half_joker_effect },
|
||||
{ UNCOMMON_JOKER, 8, joker_stencil_effect },
|
||||
{ COMMON_JOKER, 5, banner_joker_effect },
|
||||
{ COMMON_JOKER, 4, walkie_talkie_joker_effect },
|
||||
{ UNCOMMON_JOKER, 8, fibonnaci_joker_effect },
|
||||
{ UNCOMMON_JOKER, 6, blackboard_joker_effect },
|
||||
{ COMMON_JOKER, 5, mystic_summit_joker_effect },
|
||||
{ COMMON_JOKER, 4, misprint_joker_effect },
|
||||
{ COMMON_JOKER, 5, greedy_joker_effect }, // GREEDY_JOKER_ID = 1
|
||||
{ COMMON_JOKER, 5, lusty_joker_effect }, // etc... 2
|
||||
{ COMMON_JOKER, 5, wrathful_joker_effect }, // 3
|
||||
{ COMMON_JOKER, 5, gluttonous_joker_effect }, // 4
|
||||
{ COMMON_JOKER, 3, jolly_joker_effect }, // 5
|
||||
{ COMMON_JOKER, 4, zany_joker_effect }, // 6
|
||||
{ COMMON_JOKER, 4, mad_joker_effect }, // 7
|
||||
{ COMMON_JOKER, 4, crazy_joker_effect }, // 8
|
||||
{ COMMON_JOKER, 4, droll_joker_effect }, // 9
|
||||
{ COMMON_JOKER, 3, sly_joker_effect }, // 10
|
||||
{ COMMON_JOKER, 4, wily_joker_effect }, // 11
|
||||
{ COMMON_JOKER, 4, clever_joker_effect }, // 12
|
||||
{ COMMON_JOKER, 4, devious_joker_effect }, // 13
|
||||
{ COMMON_JOKER, 4, crafty_joker_effect }, // 14
|
||||
{ COMMON_JOKER, 5, half_joker_effect }, // 15
|
||||
{ UNCOMMON_JOKER, 8, joker_stencil_effect }, // 16
|
||||
{ COMMON_JOKER, 5, banner_joker_effect }, // 17
|
||||
{ COMMON_JOKER, 4, walkie_talkie_joker_effect }, // 18
|
||||
{ UNCOMMON_JOKER, 8, fibonnaci_joker_effect }, // 19
|
||||
{ UNCOMMON_JOKER, 6, blackboard_joker_effect }, // 20
|
||||
{ COMMON_JOKER, 5, mystic_summit_joker_effect }, // 21
|
||||
{ COMMON_JOKER, 4, misprint_joker_effect }, // 22
|
||||
{ COMMON_JOKER, 4, even_steven_joker_effect }, // 23
|
||||
{ COMMON_JOKER, 5, blue_joker_effect }, // 24
|
||||
{ COMMON_JOKER, 4, odd_todd_joker_effect }, // 25
|
||||
{ COMMON_JOKER, 4, scholar_joker_effect }, // 26
|
||||
{ COMMON_JOKER, 4, business_card_joker_effect }, // 27
|
||||
// Business card should be paired with Shortcut for palette optimization when it's added
|
||||
{ COMMON_JOKER, 4, scary_face_joker_effect }, // 28
|
||||
{ COMMON_JOKER, 4, smiley_face_joker_effect }, // 29
|
||||
|
||||
// The following jokers don't have sprites yet,
|
||||
// uncomment them when their sprites are added.
|
||||
#if 0
|
||||
{ COMMON_JOKER, 5, raised_fist_joker_effect },
|
||||
{ COMMON_JOKER, 6, reserved_parking_joker_effect },
|
||||
|
||||
{ COMMON_JOKER, 4, abstract_joker_effect },
|
||||
{ UNCOMMON_JOKER, 6, bull_joker_effect},
|
||||
#endif
|
||||
};
|
||||
|
||||
static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "list.h"
|
||||
#include "util.h"
|
||||
|
||||
IntList *int_list_new(int init_size) {
|
||||
IntList *list = (IntList *)malloc(sizeof(IntList));
|
||||
List *list_new(int init_size) {
|
||||
List *list = (List *)malloc(sizeof(List));
|
||||
if (list == NULL) return NULL;
|
||||
list->_array = (int *)malloc(sizeof(int) * init_size);
|
||||
list->_array = (void **)malloc(sizeof(void*) * init_size);
|
||||
if (!list->_array)
|
||||
{
|
||||
free(list);
|
||||
@@ -17,7 +18,7 @@ IntList *int_list_new(int init_size) {
|
||||
return list;
|
||||
}
|
||||
|
||||
void int_list_destroy(IntList **list) {
|
||||
void list_destroy(List **list) {
|
||||
if (list == NULL || *list == NULL)
|
||||
return;
|
||||
{
|
||||
@@ -28,22 +29,28 @@ void int_list_destroy(IntList **list) {
|
||||
*list = NULL;
|
||||
}
|
||||
|
||||
bool int_list_append(IntList *list, int value)
|
||||
bool int_list_append(List *list, intptr_t value)
|
||||
{
|
||||
return list_append(list, (void*)value);
|
||||
}
|
||||
|
||||
bool list_append(List *list, void *value)
|
||||
{
|
||||
if (list->size >= list->allocated_size)
|
||||
{
|
||||
int new_size = list->allocated_size * 2;
|
||||
int *new_arr = (int *)realloc(list->_array, sizeof(int) * new_size);
|
||||
void **new_arr = (void **)realloc(list->_array, sizeof(void*) * new_size);
|
||||
if (new_arr == NULL)
|
||||
return false;
|
||||
list->_array = new_arr;
|
||||
list->allocated_size = new_size;
|
||||
}
|
||||
|
||||
list->_array[list->size++] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_list_remove_by_idx(IntList *list, int index) {
|
||||
bool list_remove_by_idx(List *list, int index) {
|
||||
if (index < 0 || index >= list->size)
|
||||
return false;
|
||||
for (int i = index; i < list->size - 1; ++i)
|
||||
@@ -54,27 +61,37 @@ bool int_list_remove_by_idx(IntList *list, int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_list_remove_by_value(IntList *list, int value)
|
||||
bool list_remove_by_value(List *list, void* value)
|
||||
{
|
||||
for (int i = 0; i < list->size; i++)
|
||||
{
|
||||
if (list->_array[i] == value)
|
||||
{
|
||||
return int_list_remove_by_idx(list, i);
|
||||
return list_remove_by_idx(list, i);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int int_list_get(IntList *list, int index)
|
||||
bool int_list_remove_by_value(List *list, intptr_t value)
|
||||
{
|
||||
return list_remove_by_value(list, (void*)value);
|
||||
}
|
||||
|
||||
void* list_get(List *list, int index)
|
||||
{
|
||||
if (index < 0 || index >= list->size)
|
||||
return 0;
|
||||
return NULL;
|
||||
return list->_array[index];
|
||||
}
|
||||
|
||||
int int_list_get_size(IntList *list)
|
||||
intptr_t int_list_get(List *list, int index)
|
||||
{
|
||||
return (intptr_t)list_get(list, index);
|
||||
}
|
||||
|
||||
int list_get_size(List *list)
|
||||
{
|
||||
if (list == NULL)
|
||||
{
|
||||
+5
-5
@@ -28,15 +28,15 @@ void init()
|
||||
irq_add(II_VBLANK, mmVBlank);
|
||||
|
||||
// Initialize text engine
|
||||
tte_init_se(0, BG_CBB(TTE_CBB) | BG_SBB(TTE_SBB), 0, CLR_WHITE, 14, NULL, NULL);
|
||||
tte_init_se(0, BG_CBB(TTE_CBB) | BG_SBB(TTE_SBB), 0, CLR_WHITE, TTE_BIT_UNPACK_OFFSET, NULL, NULL);
|
||||
tte_erase_screen();
|
||||
tte_init_con();
|
||||
|
||||
// TTE palette setup
|
||||
pal_bg_bank[12][15] = 0x029F; // Yellow. honestly fuck libtonc because i cannot figure out how you're supposed to select a color from the palette index so i'm doing it like this
|
||||
pal_bg_bank[13][15] = 0x7E40; // Blue
|
||||
pal_bg_bank[14][15] = 0x213F; // Red
|
||||
pal_bg_bank[15][15] = CLR_WHITE;
|
||||
pal_bg_bank[TTE_YELLOW_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_YELLOW;
|
||||
pal_bg_bank[TTE_BLUE_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_BLUE;
|
||||
pal_bg_bank[TTE_RED_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_RED;
|
||||
pal_bg_bank[TTE_WHITE_PB][TTE_BIT_ON_CLR_IDX] = TEXT_CLR_WHITE;
|
||||
|
||||
// Set up the video mode
|
||||
// BG0 is the TTE text layer
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "selection_grid.h"
|
||||
|
||||
|
||||
static void selection_grid_process_directional_input(SelectionGrid *selection_grid)
|
||||
{
|
||||
int horz_tri_input = bit_tribool(key_hit(KEY_ANY), KI_RIGHT, KI_LEFT);
|
||||
|
||||
if (horz_tri_input != 0)
|
||||
{
|
||||
selection_grid_move_selection_horz(selection_grid, horz_tri_input);
|
||||
/* Avoid handling both vertical and horizontal input at the same time,
|
||||
* it creates all sorts of difficult edge cases.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
int vert_tri_input = bit_tribool(key_hit(KEY_ANY), KI_DOWN, KI_UP);
|
||||
|
||||
|
||||
if (vert_tri_input != 0)
|
||||
{
|
||||
selection_grid_move_selection_vert(selection_grid, vert_tri_input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void selection_grid_move_selection_horz(SelectionGrid* selection_grid,
|
||||
int direction_tribool)
|
||||
{
|
||||
Selection new_selection = selection_grid->selection;
|
||||
new_selection.x += direction_tribool;
|
||||
if( selection_grid->selection.y >= 0
|
||||
&& selection_grid->selection.y < selection_grid->num_rows
|
||||
&& new_selection.x >= 0
|
||||
&& new_selection.x < selection_grid->rows[new_selection.y].get_size())
|
||||
{
|
||||
selection_grid->rows[new_selection.y].on_selection_changed(selection_grid, new_selection.y, &selection_grid->selection, &new_selection);
|
||||
selection_grid->selection = new_selection;
|
||||
}
|
||||
}
|
||||
|
||||
void selection_grid_move_selection_vert(SelectionGrid *selection_grid, int direction_tribool)
|
||||
{
|
||||
Selection selection = selection_grid->selection;
|
||||
Selection new_selection = selection;
|
||||
new_selection.y += direction_tribool;
|
||||
|
||||
if (new_selection.y >= 0
|
||||
&& new_selection.y < selection_grid->num_rows)
|
||||
{
|
||||
int new_row_size = selection_grid->rows[new_selection.y].get_size();
|
||||
if (new_row_size <= 0)
|
||||
return;
|
||||
|
||||
if (selection.x >= new_row_size)
|
||||
{
|
||||
// TODO: Maintain relative horizontal position
|
||||
// Clip selection to row size
|
||||
new_selection.x = new_row_size - 1;
|
||||
}
|
||||
if (selection.y >= 0 && selection.y < selection_grid->num_rows)
|
||||
{
|
||||
selection_grid->rows[selection.y].on_selection_changed(selection_grid, selection.y, &selection, &new_selection);
|
||||
}
|
||||
selection_grid->rows[new_selection.y].on_selection_changed(selection_grid, new_selection.y, &selection, &new_selection);
|
||||
selection_grid->selection = new_selection;
|
||||
}
|
||||
}
|
||||
|
||||
void selection_grid_process_input(SelectionGrid *selection_grid)
|
||||
{
|
||||
if (selection_grid == NULL || selection_grid->rows == NULL)
|
||||
return;
|
||||
|
||||
selection_grid_process_directional_input(selection_grid);
|
||||
|
||||
u32 non_directional_key = KEY_ANY & ~KEY_DIR;
|
||||
if (key_hit(non_directional_key))
|
||||
{
|
||||
Selection* selection = &selection_grid->selection; // To make the next line shorter and more readable
|
||||
selection_grid->rows[selection->y].on_key_hit(selection_grid, selection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "sprite.h"
|
||||
#include "util.h"
|
||||
#include "audio_utils.h"
|
||||
#include "soundbank.h"
|
||||
|
||||
#include <tonc.h>
|
||||
#include <stdlib.h>
|
||||
@@ -8,6 +9,7 @@
|
||||
|
||||
#define MAX_SPRITES 128
|
||||
#define MAX_AFFINES 32
|
||||
#define SPRITE_FOCUS_RAISE_PX 10
|
||||
|
||||
OBJ_ATTR obj_buffer[MAX_SPRITES];
|
||||
OBJ_AFFINE *obj_aff_buffer = (OBJ_AFFINE*)obj_buffer;
|
||||
@@ -117,6 +119,7 @@ SpriteObject* sprite_object_new()
|
||||
sprite_object->sprite = NULL;
|
||||
sprite_object_reset_transform(sprite_object);
|
||||
sprite_object->selected = false;
|
||||
sprite_object->focused = false;
|
||||
|
||||
return sprite_object;
|
||||
}
|
||||
@@ -239,3 +242,20 @@ Sprite* sprite_object_get_sprite(SpriteObject* sprite_object)
|
||||
return NULL;
|
||||
return sprite_object->sprite;
|
||||
}
|
||||
|
||||
void sprite_object_set_focus(SpriteObject* sprite_object, bool focus)
|
||||
{
|
||||
if (sprite_object->focused == focus)
|
||||
{
|
||||
return;
|
||||
}
|
||||
sprite_object->focused = focus;
|
||||
|
||||
play_sfx(SFX_CARD_FOCUS , MM_BASE_PITCH_RATE + rand() % 512);
|
||||
sprite_object->ty = sprite_object->ty + int2fx((focus ? -1 : 1) * SPRITE_FOCUS_RAISE_PX);
|
||||
}
|
||||
|
||||
bool sprite_object_is_focused(SpriteObject* sprite_object)
|
||||
{
|
||||
return sprite_object->focused;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user