Merge branch 'main' into hblank_affine_background_effects
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 855 B After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
-gB4 -Mw4 -Mh4 -m! -pn 16
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
-gB4 -Mw4 -Mh4 -m! -pn 16
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
-gB4 -Mw4 -Mh4 -m! -pn 16
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
@@ -35,6 +35,8 @@
|
||||
#define NUM_RANKS 13
|
||||
#define RANK_OFFSET 2 // Because the first rank is 2 and ranks start at 0
|
||||
|
||||
#define IMPOSSIBLY_HIGH_CARD_VALUE 100
|
||||
|
||||
// Card types
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define PEEK_DECK KEY_L // Not implemented
|
||||
#define SORT_HAND KEY_R
|
||||
#define PAUSE_GAME KEY_START // Not implemented
|
||||
#define SELL_KEY KEY_L
|
||||
|
||||
enum GameState
|
||||
{
|
||||
@@ -31,6 +32,7 @@ enum GameState
|
||||
GAME_SHOP,
|
||||
GAME_BLIND_SELECT,
|
||||
GAME_LOSE,
|
||||
GAME_WIN
|
||||
};
|
||||
|
||||
enum HandState
|
||||
@@ -74,6 +76,10 @@ enum HandType
|
||||
void game_init();
|
||||
void game_update();
|
||||
|
||||
// Forward declaration
|
||||
struct List;
|
||||
typedef struct List List;
|
||||
|
||||
// Utility functions for other files
|
||||
typedef struct CardObject CardObject; // forward declaration, actually declared in card.h
|
||||
typedef struct JokerObject JokerObject;
|
||||
@@ -82,9 +88,10 @@ int get_hand_top(void);
|
||||
int hand_get_size(void);
|
||||
CardObject** get_played_array(void);
|
||||
int get_played_top(void);
|
||||
JokerObject** get_jokers(void);
|
||||
int get_jokers_top(void);
|
||||
List* get_jokers(void);
|
||||
|
||||
int get_deck_top(void);
|
||||
int get_num_discards_remaining(void);
|
||||
int get_money(void);
|
||||
|
||||
#endif // GAME_H
|
||||
#endif // GAME_H
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef GRAPHIC_UTILS_H
|
||||
#define GRAPHIC_UTILS_H
|
||||
|
||||
#include <tonc_video.h>
|
||||
|
||||
/* This file contains general utils and wrappers that relate to
|
||||
* graphics/video/vram and generally displaying things on the screen.
|
||||
* Mostly wrappers and defines for using tonc.
|
||||
@@ -24,6 +26,19 @@
|
||||
#define PAL_ROW_LEN 16
|
||||
#define NUM_PALETTES 16
|
||||
|
||||
#define TTE_BIT_UNPACK_OFFSET 14
|
||||
#define TTE_BIT_ON_CLR_IDX TTE_BIT_UNPACK_OFFSET + 1
|
||||
|
||||
#define TTE_YELLOW_PB 12 // 0xC
|
||||
#define TTE_BLUE_PB 13 // 0xD
|
||||
#define TTE_RED_PB 14 // 0xE
|
||||
#define TTE_WHITE_PB 15 // 0xF
|
||||
|
||||
#define TEXT_CLR_YELLOW RGB15(31, 20, 0) // 0x029F
|
||||
#define TEXT_CLR_BLUE RGB15(0, 18, 31) // 0x7E40
|
||||
#define TEXT_CLR_RED RGB15(31, 9, 8) // 0x213F
|
||||
#define TEXT_CLR_WHITE CLR_WHITE
|
||||
|
||||
/* Dimensions for a screenblock.
|
||||
* A 1024 size screenblock is arranged in a grid of 32x32 screen entries
|
||||
* Interestingly since each block is 8x8 pixels, the 240x160 GBA screen
|
||||
@@ -34,45 +49,55 @@
|
||||
#define SE_COL_LEN 32
|
||||
|
||||
// Since y direction goes from the top of the screen to the bottom
|
||||
#define SE_UP -1
|
||||
#define SE_DOWN 1
|
||||
#define SCREEN_UP -1
|
||||
#define SCREEN_DOWN 1
|
||||
#define SCREEN_LEFT -1
|
||||
#define SCREEN_RIGHT 1
|
||||
|
||||
#define OVERFLOW_LEFT -1
|
||||
#define OVERFLOW_RIGHT 1
|
||||
#define SE_UP SCREEN_UP
|
||||
#define SE_DOWN SCREEN_DOWN
|
||||
|
||||
#define OVERFLOW_LEFT SCREEN_LEFT
|
||||
#define OVERFLOW_RIGHT SCREEN_RIGHT
|
||||
|
||||
// Tile size in pixels, both height and width as tiles are square
|
||||
#define TILE_SIZE 8
|
||||
#define EFFECT_TEXT_SEPARATION_AMOUNT 32; // If we need to show multiple effects at once
|
||||
|
||||
// By default TTE characters occupy a single tile
|
||||
#define TTE_CHAR_SIZE TILE_SIZE
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
} Rect;
|
||||
// When making this, missed that it already exists in tonc_math.h
|
||||
typedef RECT Rect;
|
||||
|
||||
/* Gets the screenblock tile for the given coordinates (x, y).
|
||||
/* Gets the screenblock entry for the given coordinates (x, y).
|
||||
* x and y are in number of tiles.
|
||||
* Returns the screenblock tile.
|
||||
* Returns the screenblock entry.
|
||||
*/
|
||||
u16 main_bg_se_get_tile(BG_POINT pos);
|
||||
SE main_bg_se_get_se(BG_POINT pos);
|
||||
|
||||
INLINE int rect_width(const Rect* rect)
|
||||
{
|
||||
/* Extra parens to avoid issues in case compiler turns INLINE into macro
|
||||
* Not sure if necessary, could be just paranoia
|
||||
*/
|
||||
return (((rect)->right) - ((rect)->left) + 1);
|
||||
/* Extra parens to avoid issues in case compiler turns INLINE into macro
|
||||
* Not sure if necessary, could be just paranoia
|
||||
*/
|
||||
return (((rect)->right) - ((rect)->left) + 1);
|
||||
}
|
||||
|
||||
INLINE int rect_height(const Rect* rect)
|
||||
{
|
||||
return (((rect)->bottom) - ((rect)->top) + 1);
|
||||
return (((rect)->bottom) - ((rect)->top) + 1);
|
||||
}
|
||||
|
||||
/* Copies an SE rect vertically in direction by a single tile.
|
||||
* bg_sbb is the SBB of the background in which to move the rect
|
||||
* direction must be either SE_UP or SE_DOWN.
|
||||
* se_rect dimensions are in number of tiles.
|
||||
*
|
||||
* NOTE: This does not work with TTE_SBB, probably because it's 4BPP...
|
||||
*/
|
||||
void bg_se_copy_rect_1_tile_vert(u16 bg_sbb, Rect se_rect, int direction);
|
||||
|
||||
/* Clears a rect in the main background.
|
||||
* The se_rect dimensions need to be in number of tiles.
|
||||
*/
|
||||
@@ -90,11 +115,21 @@ void main_bg_se_copy_rect_1_tile_vert(Rect se_rect, int direction);
|
||||
*/
|
||||
void main_bg_se_copy_rect(Rect se_rect, BG_POINT pos);
|
||||
|
||||
/* Copies a tile to a rect in the main background.
|
||||
/* Copies a screen entry to a rect in the main background.
|
||||
* se_rect dimensions are in number of tiles.
|
||||
* The tile is copied to the top left corner of the rect.
|
||||
*/
|
||||
void main_bg_se_copy_tile_to_rect(u16 tile, Rect se_rect);
|
||||
void main_bg_se_fill_rect_with_se(SE tile, Rect se_rect);
|
||||
|
||||
/* Copies a 3x3 rect into se_rect_dest, the 3x3 rect is stretched to fill se_rect_dest.
|
||||
* The corners are copied, the sides are stretched, and the center is filled.
|
||||
* The parameter se_rect_src_3x3_top_left points to the top left corner of the source
|
||||
* 3x3 rect.
|
||||
* Dest rect sides can be of length 2, then the sides are not copied, only the corners.
|
||||
* But dest rect sides must be at least 2.
|
||||
*/
|
||||
void main_bg_se_copy_expand_3x3_rect(Rect se_rect_dest, BG_POINT se_rect_src_3x3_top_left);
|
||||
|
||||
/* Moves a rect in the main background vertically in direction by a single tile.
|
||||
* Note that tiles in the previous location will be transparent (0x000)
|
||||
* so maybe copy would be a better choice if you don't want to delete things
|
||||
|
||||
@@ -78,6 +78,7 @@ void joker_destroy(Joker **joker);
|
||||
// Unique effects like "Four Fingers" or "Credit Card" will be hard coded into game.c with a conditional check for the joker ID from the players owned jokers
|
||||
// game.c should probably be restructured so most of the variables in it are moved to some sort of global variable header file so they can be easily accessed and modified for the jokers
|
||||
JokerEffect joker_get_score_effect(Joker *joker, Card *scored_card);
|
||||
int joker_get_sell_value(const Joker* joker);
|
||||
|
||||
JokerObject *joker_object_new(Joker *joker);
|
||||
void joker_object_destroy(JokerObject **joker_object);
|
||||
|
||||
@@ -13,5 +13,8 @@
|
||||
#include "joker_gfx9.h"
|
||||
#include "joker_gfx10.h"
|
||||
#include "joker_gfx11.h"
|
||||
#include "joker_gfx12.h"
|
||||
#include "joker_gfx13.h"
|
||||
#include "joker_gfx14.h"
|
||||
|
||||
#endif
|
||||
@@ -3,23 +3,23 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Defining an int list for simplicity
|
||||
* If another list is needed, a generic void*
|
||||
* list should be defined....
|
||||
*/
|
||||
typedef struct IntList
|
||||
typedef struct List
|
||||
{
|
||||
int* _array;
|
||||
void** _array;
|
||||
int size;
|
||||
int allocated_size;
|
||||
} IntList;
|
||||
} List;
|
||||
|
||||
IntList *int_list_new(int init_size);
|
||||
void int_list_destroy(IntList **list);
|
||||
bool int_list_append(IntList *list, int value);
|
||||
bool int_list_remove_by_idx(IntList *list, int index);
|
||||
int int_list_get(IntList *list, int index);
|
||||
int int_list_get_size(IntList *list);
|
||||
bool int_list_remove_by_value(IntList *list, int value);
|
||||
List *list_new(int init_size);
|
||||
void list_destroy(List **list);
|
||||
bool list_append(List *list, void *value);
|
||||
bool list_remove_by_idx(List *list, int index);
|
||||
void* list_get(List *list, int index);
|
||||
int list_get_size(List *list);
|
||||
bool list_remove_by_value(List *list, void *value);
|
||||
|
||||
bool int_list_append(List *list, intptr_t value);
|
||||
intptr_t int_list_get(List *list, int index);
|
||||
bool int_list_remove_by_value(List *list, intptr_t value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef SELECTION_GRID_H
|
||||
#define SELECTION_GRID_H
|
||||
#include <tonc.h>
|
||||
|
||||
typedef POINT Selection;
|
||||
|
||||
struct SelectionGridRow;
|
||||
struct SelectionGrid;
|
||||
typedef struct SelectionGridRow SelectionGridRow;
|
||||
typedef struct SelectionGrid SelectionGrid;
|
||||
|
||||
// Called whenever there is a change in the selection cursor
|
||||
// row_idx is the index of the row whose function is invoked - can be used to identify whether it is the previous or new selection row.
|
||||
typedef void (*RowOnSelectionChangedFunc)(SelectionGrid* selection_grid, int row_idx, const Selection* prev_selection, const Selection* new_selection);
|
||||
typedef int (*RowGetSizeFunc)();
|
||||
// Called for any non-directional key hit
|
||||
// The key will not be passed, the function will have to check key_hit() etc. for the key it wants to check
|
||||
typedef void (*RowOnKeyHitFunc)(SelectionGrid* selection_grid, Selection* selection);
|
||||
|
||||
struct SelectionGridRow
|
||||
{
|
||||
int row_idx;
|
||||
RowGetSizeFunc get_size;
|
||||
RowOnSelectionChangedFunc on_selection_changed;
|
||||
RowOnKeyHitFunc on_key_hit;
|
||||
};
|
||||
|
||||
struct SelectionGrid
|
||||
{
|
||||
SelectionGridRow* rows;
|
||||
const int num_rows;
|
||||
Selection selection;
|
||||
};
|
||||
|
||||
|
||||
void selection_grid_process_input(SelectionGrid* selection_grid);
|
||||
|
||||
void selection_grid_move_selection_horz(SelectionGrid* selection_grid, int direction_tribool);
|
||||
void selection_grid_move_selection_vert(SelectionGrid* selection_grid, int direction_tribool);
|
||||
|
||||
#endif
|
||||
@@ -27,6 +27,8 @@ typedef struct
|
||||
FIXED rotation;
|
||||
FIXED vrotation;
|
||||
bool selected;
|
||||
bool focused;
|
||||
|
||||
} SpriteObject;
|
||||
|
||||
// Sprite methods
|
||||
@@ -58,6 +60,7 @@ void sprite_object_shake(SpriteObject* sprite_object, mm_word sound_id);
|
||||
void sprite_object_set_selected(SpriteObject* sprite_object, bool selected);
|
||||
bool sprite_object_is_selected(SpriteObject* sprite_object);
|
||||
Sprite* sprite_object_get_sprite(SpriteObject* sprite_object);
|
||||
|
||||
void sprite_object_set_focus(SpriteObject* sprite_object, bool focus);
|
||||
bool sprite_object_is_focused(SpriteObject* sprite_object);
|
||||
|
||||
#endif // SPRITE_H
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -29,15 +29,15 @@ void init()
|
||||
mmStart(MOD_MAIN_THEME, MM_PLAY_LOOP);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||