Added the ability to discard cards in a hand and other various changes.
This commit is contained in:
+203
-36
@@ -8,6 +8,7 @@
|
||||
|
||||
#define MAX_HAND_SIZE 16
|
||||
#define MAX_DECK_SIZE 52
|
||||
#define MAX_SELECTION_SIZE 5
|
||||
|
||||
// Card sprites lookup table. First index is the suit, second index is the rank. The value is the tile index.
|
||||
const static u16 card_sprite_lut[4][13] = {
|
||||
@@ -17,13 +18,20 @@ const static u16 card_sprite_lut[4][13] = {
|
||||
{624, 640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816}
|
||||
};
|
||||
|
||||
static enum HandState hand_state = HAND_DRAW;
|
||||
|
||||
static CardObject *played[MAX_SELECTION_SIZE] = {NULL};
|
||||
static CardObject *hand[MAX_HAND_SIZE] = {NULL};
|
||||
static Card *deck[MAX_DECK_SIZE] = {NULL};
|
||||
|
||||
static int deck_top = -1;
|
||||
static int played_top = -1;
|
||||
static int hand_top = -1;
|
||||
static int deck_top = -1;
|
||||
|
||||
static int hand_size = 8; // Default hand size is 8
|
||||
static int cards_drawn = 0;
|
||||
static int hand_selections = 0;
|
||||
|
||||
static int hand_size = 8;
|
||||
static int card_focused = 0;
|
||||
|
||||
static bool sort_by_suit = false;
|
||||
@@ -62,7 +70,7 @@ static inline void sort_cards()
|
||||
}
|
||||
}
|
||||
|
||||
// Update the sprites in the hand by destroying them and creating new ones in the correct order.
|
||||
// Update the sprites in the hand by destroying them and creating new ones in the correct order
|
||||
// (This is feels like a diabolical solution but like literally how else would you do this)
|
||||
for (int i = 0; i <= hand_top; i++)
|
||||
{
|
||||
@@ -77,18 +85,32 @@ static inline void sort_cards()
|
||||
if (hand[i] != NULL)
|
||||
{
|
||||
hand[i]->sprite = sprite_new(ATTR0_SQUARE | ATTR0_4BPP | ATTR0_AFF, ATTR1_SIZE_32, card_sprite_lut[hand[i]->card->suit][hand[i]->card->rank], 0, i);
|
||||
sprite_position(hand[i]->sprite, fx2int(hand[i]->x), fx2int(hand[i]->y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deck private functions
|
||||
void deck_push(Card *card)
|
||||
// Played stack
|
||||
inline void played_push(CardObject *card_object)
|
||||
{
|
||||
if (played_top >= MAX_SELECTION_SIZE - 1) return;
|
||||
played[++played_top] = card_object;
|
||||
}
|
||||
|
||||
inline CardObject *played_pop()
|
||||
{
|
||||
if (played_top < 0) return NULL;
|
||||
return played[played_top--];
|
||||
}
|
||||
|
||||
// Deck stack
|
||||
inline void deck_push(Card *card)
|
||||
{
|
||||
if (deck_top >= MAX_DECK_SIZE - 1) return;
|
||||
deck[++deck_top] = card;
|
||||
}
|
||||
|
||||
Card *deck_pop()
|
||||
inline Card *deck_pop()
|
||||
{
|
||||
if (deck_top < 0) return NULL;
|
||||
return deck[deck_top--];
|
||||
@@ -131,8 +153,8 @@ CardObject *card_object_new(Card *card)
|
||||
void card_object_destroy(CardObject **card_object)
|
||||
{
|
||||
if (*card_object == NULL) return;
|
||||
card_destroy(&(*card_object)->card);
|
||||
sprite_destroy(&(*card_object)->sprite);
|
||||
card_destroy(&(*card_object)->card);
|
||||
free(*card_object);
|
||||
*card_object = NULL;
|
||||
}
|
||||
@@ -142,9 +164,9 @@ void card_draw()
|
||||
if (deck_top < 0 || hand_top >= hand_size - 1 || hand_top >= MAX_HAND_SIZE - 1) return;
|
||||
|
||||
CardObject *card_object = card_object_new(deck_pop());
|
||||
|
||||
static const FIXED deck_x = 208 << FIX_SHIFT;
|
||||
static const FIXED deck_y = 110 << FIX_SHIFT;
|
||||
|
||||
const FIXED deck_x = int2fx(208);
|
||||
const FIXED deck_y = int2fx(110);
|
||||
|
||||
card_object->x = deck_x;
|
||||
card_object->y = deck_y;
|
||||
@@ -154,8 +176,8 @@ void card_draw()
|
||||
// Sort the hand after drawing a card
|
||||
sort_cards();
|
||||
|
||||
static mm_sound_effect sfx_draw = {{ SFX_DRAW }, (int)(1.0f * (1<<10)), 0, 255, 128,};
|
||||
|
||||
const int pitch_lut[MAX_HAND_SIZE] = {1024, 1048, 1072, 1096, 1120, 1144, 1168, 1192, 1216, 1240, 1264, 1288, 1312, 1336, 1360, 1384};
|
||||
mm_sound_effect sfx_draw = {{SFX_CARD_DRAW}, pitch_lut[cards_drawn], 0, 255, 128,};
|
||||
mmEffectEx(&sfx_draw);
|
||||
}
|
||||
|
||||
@@ -184,40 +206,132 @@ void card_init()
|
||||
|
||||
void card_update() // This whole function is currently pretty unoptimized due to the fixed point math, but that can be fixed later with a LUT
|
||||
{
|
||||
const int update_frame = 10; // This is the number of frames between each card event
|
||||
|
||||
static int timer = 0;
|
||||
if (hand_state == HAND_DRAW && cards_drawn < hand_size)
|
||||
{
|
||||
if (timer % update_frame == 0) // Draw a card every 10 frames
|
||||
{
|
||||
cards_drawn++;
|
||||
card_draw();
|
||||
}
|
||||
timer++;
|
||||
}
|
||||
else if (hand_state == HAND_DRAW)
|
||||
{
|
||||
hand_state = HAND_SELECT; // Change the hand state to select after drawing all the cards
|
||||
cards_drawn = 0;
|
||||
timer = 0;
|
||||
}
|
||||
|
||||
bool discarded_card = false;
|
||||
|
||||
for (int i = 0; i < MAX_HAND_SIZE; i++)
|
||||
{
|
||||
if (hand[i] != NULL)
|
||||
{
|
||||
static const int spacing_lut[MAX_HAND_SIZE] = {28, 28, 28, 28, 27, 21, 18, 15, 13, 12, 10, 9, 9, 8, 8, 7}; // This is a stupid way to do this but I don't care
|
||||
static const FIXED hand_x = 120 << FIX_SHIFT;
|
||||
static const FIXED hand_y = 90 << FIX_SHIFT;
|
||||
const int spacing_lut[MAX_HAND_SIZE] = {28, 28, 28, 28, 27, 21, 18, 15, 13, 12, 10, 9, 9, 8, 8, 7}; // This is a stupid way to do this but I don't care
|
||||
|
||||
FIXED hand_x = int2fx(120);
|
||||
FIXED hand_y = int2fx(90);
|
||||
|
||||
FIXED hand_y_offset = hand_y;
|
||||
switch (hand_state)
|
||||
{
|
||||
case HAND_DRAW:
|
||||
hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top];
|
||||
break;
|
||||
case HAND_SELECT:
|
||||
if (i == card_focused && !hand[i]->selected)
|
||||
{
|
||||
hand_y -= (10 << FIX_SHIFT);
|
||||
}
|
||||
else if (i != card_focused && hand[i]->selected)
|
||||
{
|
||||
hand_y -= (15 << FIX_SHIFT);
|
||||
}
|
||||
else if (i == card_focused && hand[i]->selected)
|
||||
{
|
||||
hand_y -= (20 << FIX_SHIFT);
|
||||
}
|
||||
|
||||
if (i == card_focused && !hand[i]->selected)
|
||||
{
|
||||
hand_y_offset -= (10 << FIX_SHIFT);
|
||||
}
|
||||
else if (i != card_focused && hand[i]->selected)
|
||||
{
|
||||
hand_y_offset -= (15 << FIX_SHIFT);
|
||||
}
|
||||
else if (i == card_focused && hand[i]->selected)
|
||||
{
|
||||
hand_y_offset -= (20 << FIX_SHIFT);
|
||||
if (i != card_focused && hand[i]->y > hand_y)
|
||||
{
|
||||
hand[i]->y = hand_y;
|
||||
hand[i]->vy = 0;
|
||||
}
|
||||
|
||||
hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top]; // TODO: Change this later to reference a 2D LUT of positions
|
||||
break;
|
||||
case HAND_DISCARD: // TODO: Add sound
|
||||
static bool sound_played = false;
|
||||
|
||||
if (hand[i]->selected)
|
||||
{
|
||||
if (!discarded_card)
|
||||
{
|
||||
hand_x = int2fx(240);
|
||||
hand_y = int2fx(70);
|
||||
|
||||
if (hand[i]->x >= hand_x)
|
||||
{
|
||||
card_object_destroy(&hand[i]);
|
||||
sort_cards();
|
||||
|
||||
hand_top--;
|
||||
cards_drawn++; // This technically isn't drawing cards, I'm just reusing the variable
|
||||
sound_played = false;
|
||||
}
|
||||
|
||||
if (!sound_played)
|
||||
{
|
||||
const int pitch_lut[MAX_SELECTION_SIZE] = {1024, 960, 896, 832, 768};
|
||||
mm_sound_effect sfx_draw = {{SFX_CARD_DRAW}, pitch_lut[cards_drawn], 0, 255, 128,};
|
||||
mmEffectEx(&sfx_draw);
|
||||
sound_played = true;
|
||||
}
|
||||
|
||||
discarded_card = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hand_y -= (15 << FIX_SHIFT);
|
||||
hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hand_x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top];
|
||||
}
|
||||
|
||||
if (i == hand_top && discarded_card == false)
|
||||
{
|
||||
hand_state = HAND_DRAW;
|
||||
sound_played = false;
|
||||
cards_drawn = 0;
|
||||
hand_selections = 0;
|
||||
timer = 0;
|
||||
}
|
||||
|
||||
timer++;
|
||||
break;
|
||||
case HAND_PLAY:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
hand[i]->vx += (hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top] - hand[i]->x) / 8; // TODO: Change this later to reference a 2D LUT of positions
|
||||
hand[i]->vy += (hand_y_offset - hand[i]->y) / 8;
|
||||
hand[i]->vx += (hand_x - hand[i]->x) / 8;
|
||||
hand[i]->vy += (hand_y - hand[i]->y) / 8;
|
||||
|
||||
// set velocity to 0 if it's close enough to the target
|
||||
if (hand[i]->vx < float2fx(0.01f) && hand[i]->vx > float2fx(-0.01f) && hand[i]->vy < float2fx(0.01f) && hand[i]->vy > float2fx(-0.01f))
|
||||
const float epsilon = float2fx(0.01f);
|
||||
if (hand[i]->vx < epsilon && hand[i]->vx > -epsilon && hand[i]->vy < epsilon && hand[i]->vy > -epsilon)
|
||||
{
|
||||
hand[i]->vx = 0;
|
||||
hand[i]->vy = 0;
|
||||
|
||||
hand[i]->x = hand_x + (int2fx(i) - int2fx(hand_top) / 2) * -spacing_lut[hand_top];
|
||||
hand[i]->y = hand_y_offset;
|
||||
hand[i]->x = hand_x;
|
||||
hand[i]->y = hand_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -227,7 +341,7 @@ void card_update() // This whole function is currently pretty unoptimized due to
|
||||
hand[i]->x += hand[i]->vx;
|
||||
hand[i]->y += hand[i]->vy;
|
||||
}
|
||||
|
||||
|
||||
obj_aff_rotate(hand[i]->sprite->aff, -hand[i]->vx);
|
||||
sprite_position(hand[i]->sprite, fx2int(hand[i]->x), fx2int(hand[i]->y));
|
||||
}
|
||||
@@ -235,20 +349,73 @@ void card_update() // This whole function is currently pretty unoptimized due to
|
||||
}
|
||||
|
||||
// Hand functions
|
||||
void hand_index(int index)
|
||||
void hand_set_focus(int index)
|
||||
{
|
||||
if (index < 0 || index > hand_top) return;
|
||||
card_focused = index;
|
||||
|
||||
mm_sound_effect sfx_focus = {{SFX_CARD_FOCUS}, 1024 + rand() % 512, 0, 255, 128,};
|
||||
mmEffectEx(&sfx_focus);
|
||||
}
|
||||
|
||||
int hand_get_focus()
|
||||
{
|
||||
return card_focused;
|
||||
}
|
||||
|
||||
void hand_select()
|
||||
{
|
||||
if (hand[card_focused] == NULL) return;
|
||||
hand[card_focused]->selected = !hand[card_focused]->selected;
|
||||
if (hand_state != HAND_SELECT || hand[card_focused] == NULL) return;
|
||||
|
||||
if (hand[card_focused]->selected)
|
||||
{
|
||||
hand[card_focused]->selected = false;
|
||||
hand_selections--;
|
||||
|
||||
mm_sound_effect sfx_select = {{SFX_CARD_SELECT}, 1024, 0, 255, 128,};
|
||||
mmEffectEx(&sfx_select);
|
||||
}
|
||||
else if (hand_selections < MAX_SELECTION_SIZE)
|
||||
{
|
||||
hand[card_focused]->selected = true;
|
||||
hand_selections++;
|
||||
|
||||
mm_sound_effect sfx_deselect = {{SFX_CARD_DESELECT}, 1024, 0, 255, 128,};
|
||||
mmEffectEx(&sfx_deselect);
|
||||
}
|
||||
}
|
||||
|
||||
void hand_change_sort()
|
||||
{
|
||||
sort_by_suit = !sort_by_suit;
|
||||
sort_cards();
|
||||
}
|
||||
|
||||
void hand_discard()
|
||||
{
|
||||
if (hand_state != HAND_SELECT) return;
|
||||
hand_state = HAND_DISCARD;
|
||||
card_focused = 0;
|
||||
}
|
||||
|
||||
int hand_get_size()
|
||||
{
|
||||
return hand_top + 1;
|
||||
}
|
||||
|
||||
int hand_get_max_size()
|
||||
{
|
||||
return hand_size;
|
||||
}
|
||||
|
||||
// Deck functions
|
||||
|
||||
int deck_get_size()
|
||||
{
|
||||
return deck_top + 1;
|
||||
}
|
||||
|
||||
int deck_get_max_size()
|
||||
{
|
||||
return MAX_DECK_SIZE; // This shouldn't be the array max size, it should be the total amount of cards that you have but I can't do that until I implement a way for discarded cards to still be stored in ram
|
||||
}
|
||||
+13
-15
@@ -3,6 +3,7 @@
|
||||
#include <maxmod.h>
|
||||
#include <tonc.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sprite.h"
|
||||
#include "card.h"
|
||||
@@ -14,24 +15,13 @@ void game_init()
|
||||
|
||||
void game_update()
|
||||
{
|
||||
static int timer = 0;
|
||||
timer++;
|
||||
|
||||
if (timer % 12 == 0)
|
||||
{
|
||||
card_draw();
|
||||
}
|
||||
|
||||
static int hand_index_selected = 0;
|
||||
if (key_hit(KEY_LEFT))
|
||||
{
|
||||
hand_index_selected++;
|
||||
hand_index(hand_index_selected);
|
||||
hand_set_focus(hand_get_focus() + 1); // The reason why this adds 1 is because the hand is drawn from right to left. There is no particular reason for this, it's just how I did it.
|
||||
}
|
||||
if (key_hit(KEY_RIGHT))
|
||||
else if (key_hit(KEY_RIGHT))
|
||||
{
|
||||
hand_index_selected--;
|
||||
hand_index(hand_index_selected);
|
||||
hand_set_focus(hand_get_focus() - 1);
|
||||
}
|
||||
|
||||
if (key_hit(KEY_A))
|
||||
@@ -39,8 +29,16 @@ void game_update()
|
||||
hand_select();
|
||||
}
|
||||
|
||||
if (key_hit(KEY_SELECT))
|
||||
if (key_hit(KEY_B))
|
||||
{
|
||||
hand_change_sort();
|
||||
}
|
||||
|
||||
if (key_hit(KEY_SELECT))
|
||||
{
|
||||
hand_discard();
|
||||
}
|
||||
|
||||
tte_printf("#{es; P:128,130}%d/%d", hand_get_size(), hand_get_max_size());
|
||||
tte_printf("#{P:200,155}%d/%d", deck_get_size(), deck_get_max_size());
|
||||
}
|
||||
+9
-5
@@ -1,6 +1,5 @@
|
||||
#include <tonc.h>
|
||||
#include <maxmod.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sprite.h"
|
||||
@@ -17,16 +16,21 @@
|
||||
|
||||
void init()
|
||||
{
|
||||
// Initialize Maxmod
|
||||
irq_init(NULL);
|
||||
irq_add(II_VBLANK, mmVBlank);
|
||||
|
||||
mmInitDefault((mm_addr)soundbank_bin, 8);
|
||||
// Initialize maxmod
|
||||
mmInitDefault((mm_addr)soundbank_bin, 12);
|
||||
mmStart(MOD_MAIN_THEME, MM_PLAY_LOOP);
|
||||
|
||||
// Initialize text engine
|
||||
tte_init_se(1, BG_CBB(1) | BG_SBB(31) | BG_8BPP, 0, CLR_WHITE, 11, NULL, NULL);
|
||||
tte_init_con();
|
||||
|
||||
// Set up the video mode
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0 | DCNT_OBJ_1D | DCNT_OBJ;
|
||||
REG_BG0CNT = BG_CBB(0) | BG_SBB(30) | BG_8BPP | BG_REG_64x32;
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_OBJ;
|
||||
REG_BG0CNT = BG_PRIO(1) | BG_CBB(0) | BG_SBB(30) | BG_8BPP | BG_REG_64x32;
|
||||
REG_BG1CNT = BG_PRIO(0) | BG_CBB(1) | BG_SBB(31) | BG_8BPP;
|
||||
|
||||
// Load the tiles and palette
|
||||
memcpy(pal_bg_mem, background_gfxPal, background_gfxPalLen);
|
||||
|
||||
Reference in New Issue
Block a user