(Manual conflict res) Merge branch 'main' into ttm/joker-scope-joker-1
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
#include "affine_background.h"
|
||||
#include "affine_background_gfx.h"
|
||||
|
||||
#include "graphic_utils.h"
|
||||
|
||||
BG_AFFINE bgaff;
|
||||
AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0};
|
||||
|
||||
void affine_background_init()
|
||||
{
|
||||
memcpy32_tile8_with_palette_offset((u32*)&tile8_mem[AFFINE_BG_CBB], (const u32*)affine_background_gfxTiles, affine_background_gfxTilesLen/4, AFFINE_BG_PB);
|
||||
GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap);
|
||||
affine_background_load_palette(affine_background_gfxPal);
|
||||
|
||||
bgaff = bg_aff_default;
|
||||
}
|
||||
|
||||
void affine_background_update()
|
||||
{
|
||||
static uint timer = 0;
|
||||
timer++;
|
||||
|
||||
// These values are not permament, just the current configuration for the affine background
|
||||
asx.tex_x += 5;
|
||||
asx.tex_y += 12;
|
||||
asx.sx = (lu_sin(timer * 100)) >> 8; // Scale the sine value to fit in a s16
|
||||
asx.sx += 256; // Add 256 to the sine value to make it positive
|
||||
asx.sy = (lu_sin(timer * 100 + 0x4000)) >> 8; // Scale the sine value to fit in a s16
|
||||
asx.sy += 256; // Add 256 to the sine value to make it positive
|
||||
bg_rotscale_ex(&bgaff, &asx);
|
||||
REG_BG_AFFINE[2] = bgaff;
|
||||
}
|
||||
|
||||
void affine_background_set_color(COLOR color)
|
||||
{
|
||||
memcpy16(&pal_bg_mem[AFFINE_BG_PB], affine_background_gfxPal, AFFINE_BG_PAL_LEN);
|
||||
for (int i = 0; i < AFFINE_BG_PAL_LEN; i++)
|
||||
{
|
||||
clr_rgbscale(&pal_bg_mem[AFFINE_BG_PB] + i, &pal_bg_mem[AFFINE_BG_PB] + i, 1, color);
|
||||
}
|
||||
}
|
||||
|
||||
void affine_background_load_palette(const u16 *src)
|
||||
{
|
||||
memcpy16(&pal_bg_mem[AFFINE_BG_PB], src, AFFINE_BG_PAL_LEN);
|
||||
}
|
||||
+282
-216
@@ -11,6 +11,7 @@
|
||||
#include "hand_analysis.h"
|
||||
#include "blind.h"
|
||||
#include "joker.h"
|
||||
#include "affine_background.h"
|
||||
#include "graphic_utils.h"
|
||||
#include "tonc_video.h"
|
||||
#include "audio_utils.h"
|
||||
@@ -18,9 +19,12 @@
|
||||
#include "background_gfx.h"
|
||||
#include "background_shop_gfx.h"
|
||||
#include "background_blind_select_gfx.h"
|
||||
#include "affine_background_gfx.h"
|
||||
|
||||
#include "soundbank.h"
|
||||
|
||||
#include "list.h"
|
||||
|
||||
// This seed system is temporary.
|
||||
static uint rng_seed = 2048;
|
||||
static bool seeded = false;
|
||||
@@ -148,6 +152,11 @@ int get_hand_top(void) {
|
||||
return hand_top;
|
||||
}
|
||||
|
||||
int hand_get_size(void)
|
||||
{
|
||||
return hand_top + 1;
|
||||
}
|
||||
|
||||
CardObject **get_played_array(void) {
|
||||
return played;
|
||||
}
|
||||
@@ -176,6 +185,8 @@ int get_money(void) {
|
||||
return money;
|
||||
}
|
||||
|
||||
IntList* jokers_available_to_shop; // List of joker IDs
|
||||
|
||||
// Consts
|
||||
|
||||
// Rects left top right bottom
|
||||
@@ -440,6 +451,8 @@ void change_background(int id)
|
||||
else if (current_blind == BOSS_BLIND)
|
||||
{
|
||||
main_bg_se_copy_rect(BOSS_BLIND_TITLE_SRC_RECT, TOP_LEFT_BLIND_TITLE_POINT);
|
||||
|
||||
affine_background_set_color(blind_get_color(BOSS_BLIND, BLIND_SHADOW_COLOR_INDEX));
|
||||
}
|
||||
|
||||
bg_copy_current_item_to_top_left_panel();
|
||||
@@ -861,11 +874,6 @@ void hand_change_sort()
|
||||
sort_cards();
|
||||
}
|
||||
|
||||
int hand_get_size()
|
||||
{
|
||||
return hand_top + 1;
|
||||
}
|
||||
|
||||
int hand_get_max_size()
|
||||
{
|
||||
return hand_size;
|
||||
@@ -1002,8 +1010,21 @@ void game_set_state(enum GameState new_game_state)
|
||||
game_state = new_game_state;
|
||||
}
|
||||
|
||||
void jokers_avialable_to_shop_init()
|
||||
{
|
||||
int num_defined_jokers = get_joker_registry_size();
|
||||
jokers_available_to_shop = int_list_new(num_defined_jokers);
|
||||
for (int i = 0; i < num_defined_jokers; i++)
|
||||
{
|
||||
// Add all joker IDs sequentially
|
||||
int_list_append(jokers_available_to_shop, i);
|
||||
}
|
||||
}
|
||||
|
||||
void game_init()
|
||||
{
|
||||
jokers_avialable_to_shop_init();
|
||||
|
||||
hands = max_hands;
|
||||
discards = max_discards;
|
||||
|
||||
@@ -1563,7 +1584,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection
|
||||
|
||||
FIXED played_x = int2fx(120);
|
||||
FIXED played_y = int2fx(70);
|
||||
FIXED played_scale = float2fx(1.0f);
|
||||
FIXED played_scale = FIX_ONE;
|
||||
|
||||
played_x = played_x + (int2fx(played_top - i) - int2fx(played_top) / 2) * -27;
|
||||
|
||||
@@ -1627,7 +1648,7 @@ static void played_cards_update_loop(bool* discarded_card, int* played_selection
|
||||
tte_set_special(0xD000); // Set text color to blue from background memory
|
||||
|
||||
// Write the score to a character buffer variable
|
||||
char score_buffer[5]; // Assuming the maximum score is 99, we need 4 characters (2 digits + null terminator)
|
||||
char score_buffer[INT_MAX_DIGITS + 2]; // for '+' and null terminator
|
||||
snprintf(score_buffer, sizeof(score_buffer), "+%d", card_get_value(played[j]->card));
|
||||
tte_write(score_buffer);
|
||||
|
||||
@@ -1822,41 +1843,6 @@ static void game_round_end_cashout()
|
||||
display_score(score); // Set the score display
|
||||
}
|
||||
|
||||
static void game_shop_create_items(JokerObject *shop_jokers[], bool first_time)
|
||||
{
|
||||
tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT);
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists
|
||||
}
|
||||
|
||||
u8 joker_id = random() % get_joker_registry_size();
|
||||
// TODO: don't pick a joker that we already own
|
||||
// TODO: weight the random choice by joker rarity
|
||||
|
||||
shop_jokers[i] = joker_object_new(joker_new(joker_id));
|
||||
shop_jokers[i]->sprite_object->x = int2fx(120 + i * 32);
|
||||
shop_jokers[i]->sprite_object->y = int2fx(160);
|
||||
shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x;
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(71);
|
||||
|
||||
int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE;
|
||||
int y = fx2int(shop_jokers[i]->sprite_object->ty);
|
||||
tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, shop_jokers[i]->joker->value);
|
||||
|
||||
if (first_time == false)
|
||||
{
|
||||
shop_jokers[i]->sprite_object->y = shop_jokers[i]->sprite_object->ty; // If it's not the first time, set the y position to the target position
|
||||
joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
|
||||
}
|
||||
|
||||
sprite_position(joker_object_get_sprite(shop_jokers[i]), fx2int(shop_jokers[i]->sprite_object->x), fx2int(shop_jokers[i]->sprite_object->y));
|
||||
}
|
||||
}
|
||||
|
||||
void game_playing()
|
||||
{
|
||||
// TODO: Blind rect sliding into view animation...
|
||||
@@ -1998,6 +1984,7 @@ void game_round_end()
|
||||
tte_erase_rect_wrapper(BLIND_REWARD_RECT);
|
||||
tte_erase_rect_wrapper(BLIND_REQ_TEXT_RECT);
|
||||
obj_hide(playing_blind_token->obj);
|
||||
affine_background_load_palette(affine_background_gfxPal);
|
||||
state = 5;
|
||||
timer = 0;
|
||||
}
|
||||
@@ -2158,6 +2145,245 @@ void game_round_end()
|
||||
}
|
||||
}
|
||||
|
||||
static void game_shop_create_items(JokerObject *shop_jokers[])
|
||||
{
|
||||
tte_erase_rect_wrapper(SHOP_PRICES_TEXT_RECT);
|
||||
if (int_list_get_size(jokers_available_to_shop) == 0)
|
||||
{
|
||||
// No jokers to create
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
// TODO: weight the random choice by joker rarity
|
||||
int joker_idx = random() % int_list_get_size(jokers_available_to_shop);
|
||||
int joker_id = int_list_get(jokers_available_to_shop, joker_idx);
|
||||
int_list_remove_by_idx(jokers_available_to_shop, joker_idx);
|
||||
|
||||
shop_jokers[i] = joker_object_new(joker_new(joker_id));
|
||||
shop_jokers[i]->sprite_object->x = int2fx(120 + i * 32);
|
||||
shop_jokers[i]->sprite_object->y = int2fx(160);
|
||||
shop_jokers[i]->sprite_object->tx = shop_jokers[i]->sprite_object->x;
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(71);
|
||||
|
||||
int x = fx2int(shop_jokers[i]->sprite_object->tx) + TILE_SIZE - (get_digits_even(shop_jokers[i]->joker->value) - 1) * TILE_SIZE;
|
||||
int y = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + TILE_SIZE;
|
||||
tte_printf("#{P:%d,%d; cx:0xC000}$%d", x, y, shop_jokers[i]->joker->value);
|
||||
|
||||
sprite_position(joker_object_get_sprite(shop_jokers[i]), fx2int(shop_jokers[i]->sprite_object->x), fx2int(shop_jokers[i]->sprite_object->y));
|
||||
}
|
||||
}
|
||||
|
||||
// Intro sequence (menu and shop icon coming into frame)
|
||||
static void game_shop_intro(JokerObject* shop_jokers[])
|
||||
{
|
||||
main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP);
|
||||
|
||||
if (timer == 1)
|
||||
{
|
||||
game_shop_create_items(shop_jokers);
|
||||
}
|
||||
|
||||
if (timer >= 7) // Shift the shop icon
|
||||
{
|
||||
int timer_offset = timer - 6;
|
||||
|
||||
// TODO: Extract to generic function?
|
||||
for (int y = 0; y < timer_offset; y++)
|
||||
{
|
||||
int y_from = 26 + y - timer_offset;
|
||||
int y_to = 0 + y;
|
||||
|
||||
Rect from = { 0, y_from, 8, y_from };
|
||||
BG_POINT to = { 0, y_to };
|
||||
|
||||
main_bg_se_copy_rect(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
if (timer == 12)
|
||||
{
|
||||
state = 1;
|
||||
timer = 0; // Reset the timer
|
||||
}
|
||||
}
|
||||
|
||||
static void game_shop_reroll(JokerObject** shop_jokers, int *reroll_cost)
|
||||
{
|
||||
money -= *reroll_cost;
|
||||
display_money(money); // Update the money display
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id);
|
||||
joker_object_destroy(&shop_jokers[i]); // Destroy the joker object if it exists
|
||||
}
|
||||
}
|
||||
|
||||
game_shop_create_items(shop_jokers);
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
shop_jokers[i]->sprite_object->y = shop_jokers[i]->sprite_object->ty; // Set the y position to the target position
|
||||
joker_object_shake(shop_jokers[i], UNDEFINED); // Give the joker a little wiggle animation
|
||||
}
|
||||
}
|
||||
|
||||
(*reroll_cost)++;
|
||||
tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, *reroll_cost);
|
||||
}
|
||||
|
||||
// Shop menu input and selection
|
||||
static void game_shop_process_user_input(JokerObject** shop_jokers)
|
||||
{
|
||||
static const int REROLL_BASE_COST = 5; // Base cost for rerolling the shop items
|
||||
static int reroll_cost = REROLL_BASE_COST;
|
||||
|
||||
// temp variables for future implementation
|
||||
const ushort max_items_top = MAX_SHOP_JOKERS;
|
||||
const ushort max_items_bottom = 0;
|
||||
|
||||
if (timer == 1)
|
||||
{
|
||||
tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost);
|
||||
}
|
||||
|
||||
// Shop input logic
|
||||
if (key_hit(KEY_UP))
|
||||
{
|
||||
selection_y = 0;
|
||||
|
||||
if (selection_x > max_items_top)
|
||||
{
|
||||
selection_x = max_items_top;
|
||||
}
|
||||
}
|
||||
else if (key_hit(KEY_DOWN))
|
||||
{
|
||||
selection_y = 1;
|
||||
|
||||
if (selection_x > max_items_bottom)
|
||||
{
|
||||
selection_x = max_items_bottom;
|
||||
}
|
||||
}
|
||||
else if (key_hit(KEY_LEFT))
|
||||
{
|
||||
if (selection_x > 0)
|
||||
{
|
||||
selection_x--;
|
||||
}
|
||||
}
|
||||
else if (key_hit(KEY_RIGHT))
|
||||
{
|
||||
// TODO: Don't allow cursor on sold items
|
||||
if (selection_y == 0 && selection_x < max_items_top)
|
||||
{
|
||||
selection_x++;
|
||||
}
|
||||
else if (selection_y == 1 && selection_x < max_items_bottom)
|
||||
{
|
||||
selection_x++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy16(&pal_bg_mem[7], &pal_bg_mem[3], 1);
|
||||
memcpy16(&pal_bg_mem[5], &pal_bg_mem[16], 1);
|
||||
|
||||
// Shop selection logic
|
||||
if (selection_x == 0 && selection_y == 0) // Next round button
|
||||
{
|
||||
memset16(&pal_bg_mem[5], 0xFFFF, 1);
|
||||
|
||||
if (key_hit(SELECT_CARD))
|
||||
{
|
||||
// Go to next blind selection game state
|
||||
state = 2; // Go to the outro sequence state
|
||||
timer = 0; // Reset the timer
|
||||
reroll_cost = REROLL_BASE_COST;
|
||||
|
||||
memcpy16(&pal_bg_mem[5], &pal_bg_mem[6], 1);
|
||||
|
||||
// memcpy16(&pal_bg_mem[16], &pal_bg_mem[6], 1);
|
||||
// This changes the color of the button to a dark red.
|
||||
// However, it shares a palette with the shop icon, so it will change the color of the shop icon as well.
|
||||
// And I don't care enough to fix it right now.
|
||||
}
|
||||
}
|
||||
else if (selection_x == 0 && selection_y == 1) // Reroll button
|
||||
{
|
||||
memset16(&pal_bg_mem[7], 0xFFFF, 1);
|
||||
|
||||
if (key_hit(SELECT_CARD) && money >= reroll_cost)
|
||||
{
|
||||
game_shop_reroll(shop_jokers, &reroll_cost);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++) // Item selection logic
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
if (i == selection_x - 1 && selection_y == 0)
|
||||
{
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(61);
|
||||
|
||||
if (key_hit(SELECT_CARD) && jokers_top < MAX_JOKERS_HELD_SIZE - 1 && money >= shop_jokers[i]->joker->value)
|
||||
{
|
||||
joker_push(shop_jokers[i]);
|
||||
money -= shop_jokers[i]->joker->value; // Deduct the money spent on the joker
|
||||
display_money(money); // Update the money display
|
||||
|
||||
Rect joker_price_rect;
|
||||
joker_price_rect.left = fx2int(shop_jokers[i]->sprite_object->tx);
|
||||
// 2*TILE_SIZE because the item is highlighted and raised by 1 additional tile
|
||||
joker_price_rect.top = fx2int(shop_jokers[i]->sprite_object->ty) + CARD_SPRITE_SIZE + 2*TILE_SIZE;
|
||||
joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3;
|
||||
joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE;
|
||||
|
||||
tte_erase_rect_wrapper(joker_price_rect);
|
||||
|
||||
shop_jokers[i] = NULL; // Remove the joker from the shop
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(71);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void game_shop_lights_anim_frame()
|
||||
{
|
||||
// Shift palette around the border of the shop icon
|
||||
COLOR shifted_palette[4];
|
||||
memcpy16(&shifted_palette[0], &pal_bg_mem[14], 1);
|
||||
memcpy16(&shifted_palette[1], &pal_bg_mem[17], 1);
|
||||
memcpy16(&shifted_palette[2], &pal_bg_mem[22], 1);
|
||||
memcpy16(&shifted_palette[3], &pal_bg_mem[8], 1);
|
||||
|
||||
// Circularly shift the palette
|
||||
int last = shifted_palette[3];
|
||||
|
||||
for (int i = 3; i > 0; --i)
|
||||
{
|
||||
shifted_palette[i] = shifted_palette[i - 1];
|
||||
}
|
||||
|
||||
shifted_palette[0] = last;
|
||||
|
||||
memcpy16(&pal_bg_mem[14], &shifted_palette[0], 1); // Copy the shifted palette to the next 4 slots
|
||||
memcpy16(&pal_bg_mem[17], &shifted_palette[1], 1);
|
||||
memcpy16(&pal_bg_mem[22], &shifted_palette[2], 1);
|
||||
memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1);
|
||||
}
|
||||
|
||||
|
||||
void game_shop()
|
||||
{
|
||||
change_background(BG_ID_SHOP);
|
||||
@@ -2172,187 +2398,21 @@ void game_shop()
|
||||
}
|
||||
}
|
||||
|
||||
const int reroll_base_cost = 5; // Base cost for rerolling the shop items
|
||||
static int reroll_cost = reroll_base_cost;
|
||||
|
||||
// temp variables for future implementation
|
||||
const ushort max_items_top = MAX_SHOP_JOKERS;
|
||||
const ushort max_items_bottom = 0;
|
||||
|
||||
if (timer % 20 == 0) // Shift palette around the border of the shop icon
|
||||
if (timer % 20 == 0)
|
||||
{
|
||||
COLOR shifted_palette[4];
|
||||
memcpy16(&shifted_palette[0], &pal_bg_mem[14], 1);
|
||||
memcpy16(&shifted_palette[1], &pal_bg_mem[17], 1);
|
||||
memcpy16(&shifted_palette[2], &pal_bg_mem[22], 1);
|
||||
memcpy16(&shifted_palette[3], &pal_bg_mem[8], 1);
|
||||
|
||||
// Circularly shift the palette
|
||||
int last = shifted_palette[3];
|
||||
|
||||
for (int i = 3; i > 0; --i) {
|
||||
shifted_palette[i] = shifted_palette[i - 1];
|
||||
}
|
||||
|
||||
shifted_palette[0] = last;
|
||||
|
||||
memcpy16(&pal_bg_mem[14], &shifted_palette[0], 1); // Copy the shifted palette to the next 4 slots
|
||||
memcpy16(&pal_bg_mem[17], &shifted_palette[1], 1);
|
||||
memcpy16(&pal_bg_mem[22], &shifted_palette[2], 1);
|
||||
memcpy16(&pal_bg_mem[8], &shifted_palette[3], 1);
|
||||
game_shop_lights_anim_frame();
|
||||
}
|
||||
|
||||
switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer
|
||||
{
|
||||
case 0: // Intro sequence (menu and shop icon coming into frame)
|
||||
case 0:
|
||||
{
|
||||
main_bg_se_copy_rect_1_tile_vert(POP_MENU_ANIM_RECT, SE_UP);
|
||||
|
||||
if (timer == 1)
|
||||
{
|
||||
game_shop_create_items(shop_jokers, true);
|
||||
}
|
||||
|
||||
if (timer >= 7) // Shift the shop icon
|
||||
{
|
||||
int timer_offset = timer - 6;
|
||||
|
||||
// TODO: Extract to generic function?
|
||||
for (int y = 0; y < timer_offset; y++)
|
||||
{
|
||||
int y_from = 26 + y - timer_offset;
|
||||
int y_to = 0 + y;
|
||||
|
||||
Rect from = {0, y_from, 8, y_from};
|
||||
BG_POINT to = {0, y_to};
|
||||
|
||||
main_bg_se_copy_rect(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
if (timer == 12)
|
||||
{
|
||||
state = 1;
|
||||
timer = 0; // Reset the timer
|
||||
}
|
||||
|
||||
game_shop_intro(shop_jokers);
|
||||
break;
|
||||
}
|
||||
case 1: // Shop menu input and selection
|
||||
case 1:
|
||||
{
|
||||
if (timer == 1)
|
||||
{
|
||||
tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost);
|
||||
}
|
||||
|
||||
// Shop input logic
|
||||
if (key_hit(KEY_UP))
|
||||
{
|
||||
selection_y = 0;
|
||||
|
||||
if (selection_x > max_items_top)
|
||||
{
|
||||
selection_x = max_items_top;
|
||||
}
|
||||
}
|
||||
else if (key_hit(KEY_DOWN))
|
||||
{
|
||||
selection_y = 1;
|
||||
|
||||
if (selection_x > max_items_bottom)
|
||||
{
|
||||
selection_x = max_items_bottom;
|
||||
}
|
||||
}
|
||||
else if (key_hit(KEY_LEFT))
|
||||
{
|
||||
if (selection_x > 0)
|
||||
{
|
||||
selection_x--;
|
||||
}
|
||||
}
|
||||
else if (key_hit(KEY_RIGHT))
|
||||
{
|
||||
if (selection_y == 0 && selection_x < max_items_top)
|
||||
{
|
||||
selection_x++;
|
||||
}
|
||||
else if (selection_y == 1 && selection_x < max_items_bottom)
|
||||
{
|
||||
selection_x++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy16(&pal_bg_mem[7], &pal_bg_mem[3], 1);
|
||||
memcpy16(&pal_bg_mem[5], &pal_bg_mem[16], 1);
|
||||
|
||||
// Shop selection logic
|
||||
if (selection_x == 0 && selection_y == 0)
|
||||
{
|
||||
memset16(&pal_bg_mem[5], 0xFFFF, 1);
|
||||
|
||||
if (key_hit(SELECT_CARD))
|
||||
{
|
||||
// Go to next blind selection game state
|
||||
state = 2; // Go to the outro sequence state
|
||||
timer = 0; // Reset the timer
|
||||
|
||||
memcpy16(&pal_bg_mem[5], &pal_bg_mem[6], 1);
|
||||
|
||||
// memcpy16(&pal_bg_mem[16], &pal_bg_mem[6], 1);
|
||||
// This changes the color of the button to a dark red.
|
||||
// However, it shares a palette with the shop icon, so it will change the color of the shop icon as well.
|
||||
// And I don't care enough to fix it right now.
|
||||
}
|
||||
}
|
||||
else if (selection_x == 0 && selection_y == 1)
|
||||
{
|
||||
memset16(&pal_bg_mem[7], 0xFFFF, 1);
|
||||
|
||||
if (key_hit(SELECT_CARD) && money >= reroll_cost)
|
||||
{
|
||||
money -= reroll_cost;
|
||||
display_money(money); // Update the money display
|
||||
|
||||
game_shop_create_items(shop_jokers, false);
|
||||
|
||||
reroll_cost++;
|
||||
tte_printf("#{P:%d,%d; cx:0xF000}$%d", SHOP_REROLL_RECT.left, SHOP_REROLL_RECT.top, reroll_cost);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
if (i == selection_x - 1 && selection_y == 0)
|
||||
{
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(61);
|
||||
|
||||
if (key_hit(SELECT_CARD) && jokers_top < MAX_JOKERS_HELD_SIZE - 1 && money >= shop_jokers[i]->joker->value)
|
||||
{
|
||||
joker_push(shop_jokers[i]);
|
||||
money -= shop_jokers[i]->joker->value; // Deduct the money spent on the joker
|
||||
display_money(money); // Update the money display
|
||||
|
||||
Rect joker_price_rect;
|
||||
joker_price_rect.left = fx2int(shop_jokers[i]->sprite_object->tx);
|
||||
joker_price_rect.top = fx2int(shop_jokers[i]->sprite_object->ty) + TILE_SIZE;
|
||||
joker_price_rect.right = joker_price_rect.left + TILE_SIZE * 3;
|
||||
joker_price_rect.bottom = joker_price_rect.top + TILE_SIZE;
|
||||
|
||||
tte_erase_rect_wrapper(joker_price_rect);
|
||||
|
||||
shop_jokers[i] = NULL; // Remove the joker from the shop
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shop_jokers[i]->sprite_object->ty = int2fx(71);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
game_shop_process_user_input(shop_jokers);
|
||||
break;
|
||||
}
|
||||
case 2: // Outro sequence (menu and shop icon going out of frame)
|
||||
@@ -2400,23 +2460,29 @@ void game_shop()
|
||||
}
|
||||
default:
|
||||
state = 0; // Reset the state
|
||||
reroll_cost = reroll_base_cost;
|
||||
|
||||
selection_x = 0; // Reset the selection
|
||||
selection_y = 0; // Reset the selection
|
||||
|
||||
for (int i = 0; i < MAX_SHOP_JOKERS; i++)
|
||||
{
|
||||
if (shop_jokers[i] != NULL)
|
||||
{
|
||||
// Make the joker available back to shop
|
||||
int_list_append(jokers_available_to_shop, shop_jokers[i]->joker->id);
|
||||
}
|
||||
joker_object_destroy(&shop_jokers[i]); // Destroy the joker objects
|
||||
}
|
||||
|
||||
increment_blind(BLIND_DEFEATED);
|
||||
increment_blind(BLIND_DEFEATED); // TODO: Move to game_round_end()?
|
||||
game_set_state(GAME_BLIND_SELECT); // If we reach here, we should go to the blind select state
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void game_blind_select()
|
||||
{
|
||||
switch (state) // I'm only using magic numbers here for the sake of simplicity since it's just sequential, but you can replace them with named constants or enums if it makes it clearer
|
||||
|
||||
@@ -168,3 +168,22 @@ void update_text_rect_to_right_align_num(Rect* rect, int num, int overflow_direc
|
||||
}
|
||||
}
|
||||
|
||||
void memcpy16_tile8_with_palette_offset(u16* dst, const u16* src, uint hwcount, u8 palette_offset)
|
||||
{
|
||||
const u16 offset = (((palette_offset) << 8) | (palette_offset));
|
||||
for (int i = 0; i < hwcount; i++)
|
||||
{
|
||||
// Copying u8 data twice across u16 data
|
||||
dst[i] = src[i] + offset;
|
||||
}
|
||||
}
|
||||
|
||||
void memcpy32_tile8_with_palette_offset(u32* dst, const u32* src, uint wcount, u8 palette_offset)
|
||||
{
|
||||
const u32 offset = (palette_offset << 24) | (palette_offset << 16) | (palette_offset << 8) | palette_offset;
|
||||
for (int i = 0; i < wcount; i++)
|
||||
{
|
||||
// Copying u8 data 4 times across u32 data
|
||||
dst[i] = src[i] + offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "list.h"
|
||||
#include "util.h"
|
||||
|
||||
IntList *int_list_new(int init_size) {
|
||||
IntList *list = (IntList *)malloc(sizeof(IntList));
|
||||
if (list == NULL) return NULL;
|
||||
list->_array = (int *)malloc(sizeof(int) * init_size);
|
||||
if (!list->_array)
|
||||
{
|
||||
free(list);
|
||||
return NULL;
|
||||
}
|
||||
list->size = 0;
|
||||
list->allocated_size = init_size;
|
||||
return list;
|
||||
}
|
||||
|
||||
void int_list_destroy(IntList **list) {
|
||||
if (list == NULL || *list == NULL)
|
||||
return;
|
||||
{
|
||||
free((*list)->_array);
|
||||
free(*list);
|
||||
}
|
||||
|
||||
*list = NULL;
|
||||
}
|
||||
|
||||
bool int_list_append(IntList *list, int 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);
|
||||
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) {
|
||||
if (index < 0 || index >= list->size)
|
||||
return false;
|
||||
for (int i = index; i < list->size - 1; ++i)
|
||||
{
|
||||
list->_array[i] = list->_array[i + 1];
|
||||
}
|
||||
list->size--;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_list_remove_by_value(IntList *list, int value)
|
||||
{
|
||||
for (int i = 0; i < list->size; i++)
|
||||
{
|
||||
if (list->_array[i] == value)
|
||||
{
|
||||
return int_list_remove_by_idx(list, i);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int int_list_get(IntList *list, int index)
|
||||
{
|
||||
if (index < 0 || index >= list->size)
|
||||
return 0;
|
||||
return list->_array[index];
|
||||
}
|
||||
|
||||
int int_list_get_size(IntList *list)
|
||||
{
|
||||
if (list == NULL)
|
||||
{
|
||||
return UNDEFINED;
|
||||
}
|
||||
return list->size;
|
||||
}
|
||||
+66
-28
@@ -39,16 +39,52 @@ static bool used_layers[MAX_JOKER_OBJECTS] = {false}; // Track used layers for j
|
||||
// Maps the spritesheet index to the palette bank index allocated to it.
|
||||
// Spritesheets that were not allocated are
|
||||
static int* joker_spritesheet_pb_map;
|
||||
static int joker_pb_num_sprite_users[JOKER_LAST_PB - JOKER_BASE_PB + 1] = { 0 };
|
||||
|
||||
static int get_num_spritesheets()
|
||||
{
|
||||
return (get_joker_registry_size() + NUM_JOKERS_PER_SPRITESHEET - 1) / NUM_JOKERS_PER_SPRITESHEET;
|
||||
}
|
||||
|
||||
static int joker_get_spritesheet_idx(u8 joker_id)
|
||||
|
||||
{
|
||||
return joker_id / NUM_JOKERS_PER_SPRITESHEET;
|
||||
}
|
||||
|
||||
// TODO: This should be generalized so any sprite can have dynamic swapping
|
||||
static void joker_pb_add_sprite_user(int pb)
|
||||
{
|
||||
joker_pb_num_sprite_users[pb - JOKER_BASE_PB]++;
|
||||
}
|
||||
|
||||
static void joker_pb_remove_sprite_user(int pb)
|
||||
{
|
||||
int num_sprite_users = joker_pb_num_sprite_users[pb - JOKER_BASE_PB];
|
||||
joker_pb_num_sprite_users[pb - JOKER_BASE_PB] = max(0, num_sprite_users - 1);
|
||||
}
|
||||
|
||||
static int joker_pb_get_num_sprite_users(int joker_pb)
|
||||
{
|
||||
return joker_pb_num_sprite_users[joker_pb - JOKER_BASE_PB];
|
||||
}
|
||||
|
||||
static int get_unused_joker_pb()
|
||||
{
|
||||
for (int i = 0; i < NUM_ELEM_IN_ARR(joker_pb_num_sprite_users); i++)
|
||||
{
|
||||
if (joker_pb_num_sprite_users[i] == 0)
|
||||
{
|
||||
return (i + JOKER_BASE_PB);
|
||||
}
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
static int allocate_pb_if_needed(u8 joker_id)
|
||||
{
|
||||
int joker_spritesheet_idx = joker_id / NUM_JOKERS_PER_SPRITESHEET;
|
||||
int joker_spritesheet_idx = joker_get_spritesheet_idx(joker_id);
|
||||
int joker_pb = joker_spritesheet_pb_map[joker_spritesheet_idx];
|
||||
if (joker_pb != UNDEFINED)
|
||||
{
|
||||
@@ -57,23 +93,9 @@ static int allocate_pb_if_needed(u8 joker_id)
|
||||
}
|
||||
|
||||
// Allocate a new palette
|
||||
joker_pb = int_arr_max(joker_spritesheet_pb_map, get_num_spritesheets());
|
||||
joker_pb = get_unused_joker_pb();
|
||||
|
||||
if (joker_pb == UNDEFINED)
|
||||
{
|
||||
// This is the first palette loaded
|
||||
joker_pb = JOKER_BASE_PB;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The new palette bank is a 1 increment of the last allocated one
|
||||
/* TODO: This doesn't account for removal, we need to address that,
|
||||
* track sprite usage and remove palettes for unused sprites
|
||||
*/
|
||||
joker_pb = joker_pb + 1;
|
||||
}
|
||||
|
||||
if (joker_pb == NUM_PALETTES)
|
||||
{
|
||||
// Ran out of palettes, default to base and pray
|
||||
joker_pb = JOKER_BASE_PB;
|
||||
@@ -105,6 +127,9 @@ void joker_init()
|
||||
joker_gfxTiles[6] = joker_gfx6Tiles;
|
||||
joker_gfxTiles[7] = joker_gfx7Tiles;
|
||||
joker_gfxTiles[8] = joker_gfx8Tiles;
|
||||
joker_gfxTiles[9] = joker_gfx9Tiles;
|
||||
joker_gfxTiles[10] = joker_gfx10Tiles;
|
||||
joker_gfxTiles[11] = joker_gfx11Tiles;
|
||||
|
||||
joker_gfxPal[0] = joker_gfx0Pal;
|
||||
joker_gfxPal[1] = joker_gfx1Pal;
|
||||
@@ -115,6 +140,9 @@ void joker_init()
|
||||
joker_gfxPal[6] = joker_gfx6Pal;
|
||||
joker_gfxPal[7] = joker_gfx7Pal;
|
||||
joker_gfxPal[8] = joker_gfx8Pal;
|
||||
joker_gfxPal[9] = joker_gfx9Pal;
|
||||
joker_gfxPal[10] = joker_gfx10Pal;
|
||||
joker_gfxPal[11] = joker_gfx11Pal;
|
||||
|
||||
for (int i = 0; i < num_spritesheets; i++)
|
||||
{
|
||||
@@ -131,7 +159,7 @@ Joker *joker_new(u8 id)
|
||||
|
||||
joker->id = id;
|
||||
joker->modifier = BASE_EDITION; // TODO: Make this a parameter
|
||||
joker->value = jinfo->base_value + edition_price_lut[joker->modifier]; // Base value + edition price
|
||||
joker->value = jinfo->base_value + edition_price_lut[joker->modifier];
|
||||
joker->rarity = jinfo->rarity;
|
||||
joker->processed = false;
|
||||
|
||||
@@ -174,12 +202,13 @@ JokerObject *joker_object_new(Joker *joker)
|
||||
|
||||
int tile_index = JOKER_TID + (layer * JOKER_SPRITE_OFFSET);
|
||||
|
||||
int joker_spritesheet_idx = joker->id / NUM_JOKERS_PER_SPRITESHEET;
|
||||
int joker_spritesheet_idx = joker_get_spritesheet_idx(joker->id);
|
||||
int joker_idx = joker->id % NUM_JOKERS_PER_SPRITESHEET;
|
||||
int joker_pb = allocate_pb_if_needed(joker->id);
|
||||
joker_pb_add_sprite_user(joker_pb);
|
||||
|
||||
memcpy32(&tile_mem[4][tile_index], &joker_gfxTiles[joker_spritesheet_idx][joker_idx * TILE_SIZE * JOKER_SPRITE_OFFSET], TILE_SIZE * JOKER_SPRITE_OFFSET);
|
||||
|
||||
|
||||
sprite_object_set_sprite
|
||||
(
|
||||
joker_object->sprite_object,
|
||||
@@ -200,10 +229,16 @@ JokerObject *joker_object_new(Joker *joker)
|
||||
|
||||
void joker_object_destroy(JokerObject **joker_object)
|
||||
{
|
||||
if (*joker_object == NULL) return;
|
||||
if (joker_object == NULL || *joker_object == NULL) return;
|
||||
|
||||
int layer = sprite_get_layer(joker_object_get_sprite(*joker_object)) - JOKER_STARTING_LAYER;
|
||||
used_layers[layer] = false;
|
||||
joker_pb_remove_sprite_user(sprite_get_pb(joker_object_get_sprite(*joker_object)));
|
||||
if (joker_pb_get_num_sprite_users((sprite_get_pb(joker_object_get_sprite(*joker_object)))) == 0)
|
||||
{
|
||||
joker_spritesheet_pb_map[joker_get_spritesheet_idx((*joker_object)->joker->id)] = UNDEFINED;
|
||||
}
|
||||
|
||||
sprite_object_destroy(&(*joker_object)->sprite_object); // Destroy the sprite
|
||||
joker_destroy(&(*joker_object)->joker); // Destroy the joker
|
||||
free(*joker_object);
|
||||
@@ -235,42 +270,45 @@ bool joker_object_score(JokerObject *joker_object, Card* scored_card, int *chips
|
||||
*money += joker_effect.money;
|
||||
// TODO: Retrigger
|
||||
|
||||
const int joker_score_display_offset_px = (MAX_CARD_SCORE_STR_LEN + 1)*TTE_CHAR_SIZE;
|
||||
// + 1 For space
|
||||
|
||||
int cursorPosX = fx2int(joker_object->sprite_object->x) + 8; // Offset of 16 pixels to center the text on the card
|
||||
if (joker_effect.chips > 0)
|
||||
{
|
||||
char score_buffer[12];
|
||||
char score_buffer[INT_MAX_DIGITS + 2]; // For '+' and null terminator
|
||||
tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y);
|
||||
tte_set_special(0xD000); // Blue
|
||||
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.chips);
|
||||
tte_write(score_buffer);
|
||||
cursorPosX += EFFECT_TEXT_SEPARATION_AMOUNT;
|
||||
cursorPosX += joker_score_display_offset_px;
|
||||
}
|
||||
if (joker_effect.mult > 0)
|
||||
{
|
||||
char score_buffer[12];
|
||||
char score_buffer[INT_MAX_DIGITS + 2];
|
||||
tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y);
|
||||
tte_set_special(0xE000); // Red
|
||||
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.mult);
|
||||
tte_write(score_buffer);
|
||||
cursorPosX += EFFECT_TEXT_SEPARATION_AMOUNT;
|
||||
cursorPosX += joker_score_display_offset_px;
|
||||
}
|
||||
if (joker_effect.xmult > 0)
|
||||
{
|
||||
char score_buffer[12];
|
||||
char score_buffer[INT_MAX_DIGITS + 2];
|
||||
tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y);
|
||||
tte_set_special(0xE000); // Red
|
||||
snprintf(score_buffer, sizeof(score_buffer), "X%d", joker_effect.xmult);
|
||||
tte_write(score_buffer);
|
||||
cursorPosX += EFFECT_TEXT_SEPARATION_AMOUNT;
|
||||
cursorPosX += joker_score_display_offset_px;
|
||||
}
|
||||
if (joker_effect.money > 0)
|
||||
{
|
||||
char score_buffer[12];
|
||||
char score_buffer[INT_MAX_DIGITS + 2];
|
||||
tte_set_pos(cursorPosX, JOKER_SCORE_TEXT_Y);
|
||||
tte_set_special(0xC000); // Yellow
|
||||
snprintf(score_buffer, sizeof(score_buffer), "+%d", joker_effect.money);
|
||||
tte_write(score_buffer);
|
||||
cursorPosX += EFFECT_TEXT_SEPARATION_AMOUNT;
|
||||
cursorPosX += joker_score_display_offset_px;
|
||||
}
|
||||
|
||||
joker_object->joker->processed = true; // Mark the joker as processed
|
||||
|
||||
+13
-8
@@ -1,3 +1,4 @@
|
||||
#include "game.h"
|
||||
#include "joker.h"
|
||||
#include "util.h"
|
||||
#include "hand_analysis.h"
|
||||
@@ -178,7 +179,8 @@ static JokerEffect half_joker_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
|
||||
|
||||
if (get_played_top() + 1 <= 3) // game.c has hand_get_size() but it's not accesible here
|
||||
int played_size = get_played_top() + 1;
|
||||
if (played_size <= 3)
|
||||
effect.mult = 20;
|
||||
|
||||
return effect;
|
||||
@@ -190,12 +192,13 @@ static JokerEffect joker_stencil_effect(Joker *joker, Card *scored_card) {
|
||||
return effect; // if card != null, we are not at the end-phase of scoring yet
|
||||
|
||||
// +1 xmult per empty joker slot...
|
||||
int jokers_top = get_jokers_top();
|
||||
effect.xmult = (MAX_JOKERS_HELD_SIZE-1) - jokers_top;
|
||||
int num_jokers = get_jokers_top() + 1;
|
||||
|
||||
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 < jokers_top; i++ )
|
||||
for (int i = 0; i < num_jokers; i++ )
|
||||
{
|
||||
if (jokers[i]->joker->id == JOKER_STENCIL_ID)
|
||||
effect.xmult++;
|
||||
@@ -271,8 +274,8 @@ static JokerEffect blackboard_joker_effect(Joker *joker, Card *scored_card) {
|
||||
|
||||
bool all_cards_are_spades_or_clubs = true;
|
||||
CardObject** hand = get_hand_array();
|
||||
int hand_top = get_hand_top();
|
||||
for (int i = 0; i < hand_top; i++ )
|
||||
int hand_size = hand_get_size();
|
||||
for (int i = 0; i < hand_size; i++ )
|
||||
{
|
||||
u8 suit = hand[i]->card->suit;
|
||||
if (suit == HEARTS || suit == DIAMONDS) {
|
||||
@@ -470,11 +473,12 @@ const JokerInfo joker_registry[] = {
|
||||
{ COMMON_JOKER, 4, crafty_joker_effect },
|
||||
{ COMMON_JOKER, 5, half_joker_effect },
|
||||
{ UNCOMMON_JOKER, 8, joker_stencil_effect },
|
||||
{ COMMON_JOKER, 4, misprint_joker_effect },
|
||||
{ COMMON_JOKER, 5, banner_joker_effect },
|
||||
{ COMMON_JOKER, 4, walkie_talkie_joker_effect },
|
||||
{ UNCOMMON_JOKER, 8, fibonnaci_joker_effect },
|
||||
{ COMMON_JOKER, 5, banner_joker_effect },
|
||||
{ UNCOMMON_JOKER, 6, blackboard_joker_effect },
|
||||
{ COMMON_JOKER, 5, mystic_summit_joker_effect },
|
||||
{ COMMON_JOKER, 4, misprint_joker_effect },
|
||||
{ UNCOMMON_JOKER, 6, blackboard_joker_effect },
|
||||
{ COMMON_JOKER, 5, blue_joker_effect },
|
||||
{ COMMON_JOKER, 5, raised_fist_joker_effect },
|
||||
@@ -487,6 +491,7 @@ const JokerInfo joker_registry[] = {
|
||||
{ COMMON_JOKER, 4, smiley_face_joker_effect },
|
||||
{ COMMON_JOKER, 4, even_steven_joker_effect },
|
||||
{ COMMON_JOKER, 4, odd_todd_joker_effect },
|
||||
|
||||
};
|
||||
|
||||
static const size_t joker_registry_size = NUM_ELEM_IN_ARR(joker_registry);
|
||||
|
||||
+4
-43
@@ -7,6 +7,7 @@
|
||||
#include "game.h"
|
||||
#include "blind.h"
|
||||
#include "joker.h"
|
||||
#include "affine_background.h"
|
||||
#include "graphic_utils.h"
|
||||
|
||||
// Graphics
|
||||
@@ -17,29 +18,6 @@
|
||||
#include "soundbank.h"
|
||||
#include "soundbank_bin.h"
|
||||
|
||||
#define MAP_AFF_SIZE 0x0100
|
||||
BG_AFFINE bgaff;
|
||||
AFF_SRC_EX asx = {32<<8, 64<<8, 120, 80, 0x0100, 0x0100, 0};
|
||||
|
||||
|
||||
void init_map() // Temp function derived from libtonc example
|
||||
{
|
||||
// Grit is fucking garbage and doesn't allow you to have a palette offset, they all get loaded at 0x0000. I have to manually change each tile's palette bank
|
||||
|
||||
unsigned int correctedTiles[affine_background_gfxTilesLen / 4];
|
||||
for (int i = 0; i < affine_background_gfxTilesLen / 4; i++)
|
||||
{
|
||||
correctedTiles[i] = affine_background_gfxTiles[i] | 0xF0F0F0F0; // I brute forced this. I have no idea how this would and does work, but it does. We'll just leave this here for now.
|
||||
// Actually for future reference, each number seems to equate to an XY on the palette, so 0xF0F0F0F0 would just push everything down 15 colors, since the second number isn't set.
|
||||
}
|
||||
|
||||
memcpy(&tile8_mem[AFFINE_BG_CBB], correctedTiles, affine_background_gfxTilesLen);
|
||||
GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap);
|
||||
memcpy16(&pal_bg_mem[16 * 15], affine_background_gfxPal, 5);
|
||||
|
||||
bgaff = bg_aff_default;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
irq_init(NULL);
|
||||
@@ -66,7 +44,7 @@ void init()
|
||||
// BG1 is the main background layer
|
||||
REG_BG1CNT = BG_PRIO(1) | BG_CBB(MAIN_BG_CBB) | BG_SBB(MAIN_BG_SBB) | BG_8BPP;
|
||||
// BG2 is the affine background layer
|
||||
REG_BG2CNT = BG_PRIO(2) | BG_CBB(AFFINE_BG_CBB) | BG_SBB(AFFINE_BG_CBB) | BG_8BPP | BG_WRAP | BG_AFF_32x32;
|
||||
REG_BG2CNT = BG_PRIO(2) | BG_CBB(AFFINE_BG_CBB) | BG_SBB(AFFINE_BG_SBB) | BG_8BPP | BG_WRAP | BG_AFF_32x32;
|
||||
|
||||
int win1_left = 72;
|
||||
int win1_top = 44;
|
||||
@@ -93,9 +71,8 @@ void init()
|
||||
|
||||
REG_DISPCNT = DCNT_MODE1 | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_OBJ | DCNT_WIN0 | DCNT_WIN1;
|
||||
|
||||
init_map(); // Initialize the map for the background
|
||||
|
||||
// Initialize subsystems
|
||||
affine_background_init();
|
||||
sprite_init();
|
||||
card_init();
|
||||
blind_init();
|
||||
@@ -103,24 +80,9 @@ void init()
|
||||
game_init();
|
||||
}
|
||||
|
||||
void background_update() // This needs to be called before update() and draw() because setting REG_BG_AFFINE during an HBlank can cause issues
|
||||
{
|
||||
static uint timer = 0;
|
||||
timer++;
|
||||
|
||||
// These values are not permament, just the current configuration for the affine background
|
||||
asx.tex_x += 5;
|
||||
asx.tex_y += 12;
|
||||
asx.sx = (lu_sin(timer * 100)) >> 8; // Scale the sine value to fit in a s16
|
||||
asx.sx += 256; // Add 256 to the sine value to make it positive
|
||||
asx.sy = (lu_sin(timer * 100 + 0x4000)) >> 8; // Scale the sine value to fit in a s16
|
||||
asx.sy += 256; // Add 256 to the sine value to make it positive
|
||||
bg_rotscale_ex(&bgaff, &asx);
|
||||
REG_BG_AFFINE[2]= bgaff;
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
affine_background_update();
|
||||
game_update();
|
||||
}
|
||||
|
||||
@@ -138,7 +100,6 @@ int main()
|
||||
VBlankIntrWait();
|
||||
mmFrame();
|
||||
key_poll();
|
||||
background_update();
|
||||
update();
|
||||
draw();
|
||||
}
|
||||
|
||||
+17
-8
@@ -1,5 +1,6 @@
|
||||
#include "sprite.h"
|
||||
#include "util.h"
|
||||
#include "audio_utils.h"
|
||||
|
||||
#include <tonc.h>
|
||||
#include <stdlib.h>
|
||||
@@ -100,6 +101,15 @@ void sprite_draw()
|
||||
oam_copy(oam_mem, obj_buffer, MAX_SPRITES);
|
||||
}
|
||||
|
||||
int sprite_get_pb(const Sprite *sprite)
|
||||
{
|
||||
if (sprite == NULL)
|
||||
{
|
||||
return UNDEFINED;
|
||||
}
|
||||
return (sprite->obj->attr2 & ATTR2_PALBANK_MASK) >> ATTR2_PALBANK_SHIFT;
|
||||
}
|
||||
|
||||
// SpriteObject methods
|
||||
SpriteObject* sprite_object_new()
|
||||
{
|
||||
@@ -135,9 +145,9 @@ void sprite_object_reset_transform(SpriteObject* sprite_object)
|
||||
sprite_object->y = 0;
|
||||
sprite_object->vx = 0;
|
||||
sprite_object->vy = 0;
|
||||
sprite_object->tscale = float2fx(1.0f); // Target scale
|
||||
sprite_object->scale = float2fx(1.0f);
|
||||
sprite_object->vscale = float2fx(0.0f);
|
||||
sprite_object->tscale = FIX_ONE; // Target scale
|
||||
sprite_object->scale = FIX_ONE;
|
||||
sprite_object->vscale = 0;
|
||||
sprite_object->trotation = 0; // Target rotation
|
||||
sprite_object->rotation = 0;
|
||||
sprite_object->vrotation = 0;
|
||||
@@ -153,7 +163,7 @@ void sprite_object_update(SpriteObject* sprite_object)
|
||||
sprite_object->vrotation += (sprite_object->trotation - sprite_object->rotation) / 8; // Rotate the card when it's played
|
||||
|
||||
// set velocity to 0 if it's close enough to the target
|
||||
const float epsilon = float2fx(0.01f);
|
||||
const FIXED epsilon = float2fx(0.01f);
|
||||
if (sprite_object->vx < epsilon && sprite_object->vx > -epsilon && sprite_object->vy < epsilon && sprite_object->vy > -epsilon)
|
||||
{
|
||||
sprite_object->vx = 0;
|
||||
@@ -201,13 +211,12 @@ void sprite_object_update(SpriteObject* sprite_object)
|
||||
|
||||
void sprite_object_shake(SpriteObject* sprite_object, mm_word sound_id)
|
||||
{
|
||||
sprite_object->vscale = float2fx(0.3f); // Scale down the card when it's scored
|
||||
sprite_object->vrotation = float2fx(8.0f); // Rotate the card when it's scored
|
||||
sprite_object->vscale = float2fx(0.3f);
|
||||
sprite_object->vrotation = float2fx(8.0f); //Rotate the card when it's scored
|
||||
|
||||
if (sound_id == UNDEFINED) return; // If no sound ID is provided, do nothing
|
||||
|
||||
mm_sound_effect sfx_select = { {sound_id}, 1024, 0, 255, 128, };
|
||||
mmEffectEx(&sfx_select);
|
||||
play_sfx(sound_id, MM_BASE_PITCH_RATE);
|
||||
}
|
||||
|
||||
void sprite_object_set_selected(SpriteObject* sprite_object, bool selected)
|
||||
|
||||
Reference in New Issue
Block a user