Refactor shop code to use generic Item (#536)
* Turned SpriteObject into a member of JokerObject and CardObject and expiremented with casting * Extracted shop code to use generic `SpriteObject` * Extracted shop joker generation to a function * Renamed object -> item * Added setters and getters for `SpriteObject` members and updated all accesses to use them with casting (AI used for tedious work and reviewed - model Raptor mini) * Added sprite_object_set_vx() because sprite_object_set_vy() exists and reordered the function order to have x,y parameters first, then targets * Added Item object to act as a purchasable interface for the shop - AI used (model Raptor mini) * Added -fms-extensions and switched to anonymous inheritance * Fixed anonymous inheritance for joker and added direct access for that too * fix build error from previous commit + clang-format * Fixed build errors + clang-format for real this time (I hope...) * clang-format one last time, I don't understand it anymore * clang-format is annoying * Added uses of CHECK_NULL_ARG macros * Merged item_defs.h into item.h and fixed build error from previous commit * clang-format...? * Changed sprite_object_new() into sprite_object_init() and made it accept a parameter instead of returning one to make it less awkward * Updated sprite_object_init() documentation * Updated sprite_object_destroy documentation * More clang-format * Renamed add_to_inventory to acquire and updated documentation * Added function documentations * Update documentation + swap order of consumable and playing card types * Added documentation for new files (+ small addition to button.h) * clang-format * Used typedef * A bit more documentation * Changed sho pcode to use generic Item instead of SpriteObject * clang-format + fixed NULL-check error * Revert weird clang-format...? * clang-format for real * Fixed errors from rebase on log_function_name * Fixed build errors from rebase on main * Added some more documentation about first member struct inheritance * typo fix * typo fix for real * Removed SpriteObject field getters/setters (AI used - model Raptor mini) * Renamed item_acquire -> item_on_acquired * Added item_can_acquire() * clang-format * Fixed some sprite issues but not all... * Fixed some more issues * Cleanup JokerObject some more JokerObjects in the shop * Added `item_destroy()` * Added item_set_available_to_shop, CHECK_ITEM_TYPE macros + small documentation updates * Another small JokerObject->Item replacement * Removed item_set_available_to_shop and replaced with item_roll_new() and item_dispose(), also changed "available_to_shop" semantics to "rollable" * Re-applied changes from game.c to round.c after rebase on main * Added partial implementations of item functions for playing cards * Line endings fix... * Macro renames, function documentations * Updated documentations * Apply fixes from Copilot review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fix card_object_get_buy_price type checking Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Avoid double pointer cast on dispose Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Apply suggestions from @ricfehr3's code review Co-authored-by: Rickey <ric@rf3.xyz> * Remove redundant comments * Moved error checking before joker_get_random_rarity Co-authored-by: Rickey <ric@rf3.xyz> * Fixed build error from rebase * clang-format * Added doxygen documentation for Item explaining inheritance * Removed unnecessary comment --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rickey <ric@rf3.xyz>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
Rickey
parent
369c680cb7
commit
d24b0b5619
@@ -2,6 +2,7 @@
|
||||
* @file button.h
|
||||
*
|
||||
* @brief A button structure containing the common button functionalities
|
||||
* Including highlight and pressing functionalities.
|
||||
*/
|
||||
|
||||
#ifndef BUTTON_H
|
||||
|
||||
+5
-2
@@ -2,7 +2,7 @@
|
||||
#define CARD_H
|
||||
|
||||
#include "deck_types.h"
|
||||
#include "sprite.h"
|
||||
#include "item.h"
|
||||
|
||||
#include <maxmod.h>
|
||||
#include <tonc.h>
|
||||
@@ -54,8 +54,8 @@ typedef struct Card
|
||||
|
||||
typedef struct CardObject
|
||||
{
|
||||
Item; // First member struct inheritance
|
||||
Card* card;
|
||||
SpriteObject* sprite_object;
|
||||
bool selected;
|
||||
} CardObject;
|
||||
|
||||
@@ -83,4 +83,7 @@ void card_object_set_selected(CardObject* card_object, bool selected);
|
||||
bool card_object_is_selected(CardObject* card_object);
|
||||
Sprite* card_object_get_sprite(CardObject* card_object);
|
||||
|
||||
int card_object_get_buy_price(Item* card_object);
|
||||
void card_object_dispose(Item** card_object);
|
||||
|
||||
#endif // CARD_H
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "sprite.h"
|
||||
|
||||
POOL_ENTRY(Sprite, MAX_SPRITES);
|
||||
POOL_ENTRY(SpriteObject, MAX_SPRITE_OBJECTS);
|
||||
POOL_ENTRY(Joker, MAX_ACTIVE_JOKERS);
|
||||
POOL_ENTRY(JokerObject, MAX_ACTIVE_JOKERS);
|
||||
POOL_ENTRY(Card, MAX_CARDS);
|
||||
|
||||
+3
-1
@@ -4,12 +4,13 @@
|
||||
#include "game/common_ui.h"
|
||||
#include "game_variables.h"
|
||||
#include "graphic_utils.h"
|
||||
#include "item.h"
|
||||
|
||||
#include <tonc.h>
|
||||
|
||||
#define MAX_DECK_SIZE 52
|
||||
#define MAX_JOKERS_HELD_SIZE 5 // This doesn't account for negatives right now.
|
||||
#define MAX_SHOP_JOKERS 2 // TODO: Make this dynamic and allow for other items besides jokers
|
||||
#define MAX_SHOP_ITEMS 2 // TODO: Make this dynamic
|
||||
#define MAX_SELECTION_SIZE 5
|
||||
#define FRAMES(x) (((x) + (g_game_vars.game_speed) - 1) / (g_game_vars.game_speed))
|
||||
|
||||
@@ -69,6 +70,7 @@ void game_change_state(enum GameState new_game_state);
|
||||
enum GameState game_get_state(void);
|
||||
|
||||
bool is_joker_owned(int joker_id);
|
||||
bool joker_object_can_acquire(Item* item);
|
||||
bool card_is_face(Card* card);
|
||||
void add_joker(JokerObject* joker_object);
|
||||
void remove_owned_joker(int owned_joker_idx);
|
||||
|
||||
@@ -23,14 +23,6 @@ void game_shop_reset(void);
|
||||
*/
|
||||
JokerObject* game_shop_get_description_card(void);
|
||||
|
||||
/**
|
||||
* @brief Set whether a Joker can appear in the shop.
|
||||
*
|
||||
* @param avail - true to make it available to the shop to appear in
|
||||
* false to make it unavailable.
|
||||
*/
|
||||
void game_shop_set_joker_avail(int joker_id, bool avail);
|
||||
|
||||
/**
|
||||
* @brief Change to the shop background
|
||||
*/
|
||||
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* @file item.h
|
||||
*
|
||||
* @brief The core structure for items in the shop and inventory.
|
||||
* Provides a common API for the shop and inventory to handle all types of items.
|
||||
* Uses struct inheritance so all inherited items can implement an is-a relationship with Item.
|
||||
* This means that pointers to structs that inherit Item using first member struct inheritance
|
||||
* can and should be cast to Item* so code that expects an Item* can use them.
|
||||
*/
|
||||
|
||||
#ifndef ITEM_H
|
||||
#define ITEM_H
|
||||
|
||||
#include "mgba_logger.h"
|
||||
#include "sprite.h"
|
||||
|
||||
// TODO: Merge these with GBAL_RETURN_IF_NULL macros?
|
||||
/**
|
||||
* @brief Checks if @p item is of type @p expected_type - logs error message and returns otherwise
|
||||
*
|
||||
* This version is for a function that returns a value, while
|
||||
* @ref ITEM_RETURN_IF_UNEXPECTED_TYPE_VOID is for a void function.
|
||||
*/
|
||||
#define ITEM_RETURN_IF_UNEXPECTED_TYPE_RET(item, expected_type, ret_val) \
|
||||
do \
|
||||
{ \
|
||||
if ((item)->type != expected_type) \
|
||||
{ \
|
||||
MGBA_FUNC_ERROR("Unexpected %s->type != %s", #item, #expected_type); \
|
||||
return (ret_val); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Checks if @p item is of type @p expected_type - logs error message and returns otherwise
|
||||
*
|
||||
* This version is for a void function, while @ref ITEM_RETURN_IF_UNEXPECTED_TYPE_RET is for one
|
||||
* with a return value.
|
||||
*/
|
||||
#define ITEM_RETURN_IF_UNEXPECTED_TYPE_VOID(item, expected_type) \
|
||||
do \
|
||||
{ \
|
||||
if ((item)->type != expected_type) \
|
||||
{ \
|
||||
MGBA_FUNC_ERROR("Unexpected %s->type != %s", #item, #expected_type); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
enum ItemType
|
||||
{
|
||||
ITEM_TYPE_JOKER,
|
||||
ITEM_TYPE_PLAYING_CARD,
|
||||
|
||||
// Future planned item types
|
||||
// ITEM_TYPE_CONSUMABLE, // Expand to PLANET, TAROT, and SPECTRAL?
|
||||
// ITEM_TYPE_VOUCHER,
|
||||
// ITEM_TYPE_PACK
|
||||
|
||||
ITEM_NUM_TYPES
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A generic interface for all items that can appear in the shop or be in the inventory.
|
||||
* This uses first member struct inheritance - other structs are meant to inherit it by
|
||||
* making their first member field Item.
|
||||
* Then casts from inheriting structs to Item* are allowed and intentional and this allows for
|
||||
* generic code that uses polymorphism.
|
||||
* The -fms-extensions compile flag allows for anonymous members making it behave fully
|
||||
* as inheritance. It makes all member fields be fully inherited so any struct
|
||||
* that inherits Item for example will have all its fields accessible directly,
|
||||
* e.g. `JokerObject joker_object; joker_object.type = ITEM_TYPE_JOKER`
|
||||
*/
|
||||
typedef struct Item
|
||||
{
|
||||
/**
|
||||
* @brief First member struct inheritance
|
||||
* all items that can appear in the shop are SpriteObjects.
|
||||
* Note that this is an anonymous member.
|
||||
*/
|
||||
SpriteObject;
|
||||
|
||||
/**
|
||||
* @brief The item type - used to dispatch the function implementations for inheriting types.
|
||||
*/
|
||||
enum ItemType type;
|
||||
} Item;
|
||||
|
||||
/**
|
||||
* @brief The set of functions that each item type implements.
|
||||
*/
|
||||
typedef struct ItemFuncs
|
||||
{
|
||||
/**
|
||||
* All items must implement the following since they are called by the shop and all items
|
||||
* must be capable of appearing in the shop.
|
||||
*/
|
||||
Item* (*roll_new)(void);
|
||||
int (*get_buy_price)(Item* item);
|
||||
bool (*can_acquire)(Item* item);
|
||||
void (*acquire)(Item* item);
|
||||
void (*dispose)(Item** item);
|
||||
// TODO: void (*print_description)(Item* item); // or something of the form
|
||||
|
||||
// Optional implementation functions will be added here
|
||||
} ItemFuncs;
|
||||
|
||||
/**
|
||||
* @brief Rolls a random item of type @p item_type and returns a newly created one.
|
||||
* Manages rollable items set if necessary (i.e. not rolling items already in inventory)
|
||||
* To be used when rolling new items for the shop or packs.
|
||||
*
|
||||
* Matches @ref ItemFuncs.roll_new()
|
||||
*
|
||||
* @param item_type The type of the item to roll
|
||||
*
|
||||
* @return The newly created randomly rolled item
|
||||
*/
|
||||
Item* item_roll_new(enum ItemType item_type);
|
||||
|
||||
/**
|
||||
* @brief Returns the buy price of the item.
|
||||
*
|
||||
* Matches @ref ItemFuncs.get_buy_price()
|
||||
*
|
||||
* @param item The item whose price to return.
|
||||
*
|
||||
* @return UNDEFINED in case of error, the item's buy price otherwise.
|
||||
*/
|
||||
int item_get_buy_price(Item* item);
|
||||
|
||||
/**
|
||||
* @brief Acquires the item, adding to inventory if applicable.
|
||||
* Called when it is purchased from the shop, note that it does not
|
||||
* perform the purchase operation of decrementing the player's money,
|
||||
* that should be handled by the shop code.
|
||||
* For packs this can be to just open the pack,
|
||||
* for vouchers, this will apply their effect.
|
||||
*
|
||||
* Matches @ref ItemFuncs.acquire()
|
||||
*
|
||||
* @param item The item to acquire
|
||||
*/
|
||||
void item_acquire(Item* item);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the item can be acquired, i.e. added to inventory.
|
||||
* Does not check if the player has enough money to buy the item, that is the shop's job,
|
||||
* as this will be used both when purchasing and when selecting in a pack.
|
||||
*
|
||||
* Matches @ref ItemFuncs.can_acquire()
|
||||
*
|
||||
* @param item The item to check
|
||||
*/
|
||||
bool item_can_acquire(Item* item);
|
||||
|
||||
/**
|
||||
* @brief Destroys an item, freeing underlying resources, and manages rollable items sets if needed.
|
||||
* To be used when destroying items from the inventory, shop, or packs.
|
||||
*
|
||||
* @param item A pointer to an item for destruction.
|
||||
*/
|
||||
void item_dispose(Item** item);
|
||||
|
||||
/**
|
||||
* @brief Prints the buy price under the item
|
||||
* Relies on the fact item is a SpriteObject
|
||||
*
|
||||
* @param item The item to print under
|
||||
*/
|
||||
void item_print_buy_price_under(Item* item);
|
||||
|
||||
#endif // ITEM_H
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @file item_funcs.h
|
||||
*
|
||||
* @brief An API for the item functions defined in item.h
|
||||
* Separated module from item.c/.h so item_funcs.c can include joker.h and card.h etc.
|
||||
* so the item.h doesn't depend on implementations such as jokers and cards.
|
||||
*/
|
||||
|
||||
#ifndef ITEM_FUNCS_H
|
||||
#define ITEM_FUNCS_H
|
||||
|
||||
#include "item.h"
|
||||
|
||||
/**
|
||||
* @brief Returns the function table for a given item type.
|
||||
*
|
||||
* Looks up the @ref ItemFuncs dispatch table corresponding to @p type.
|
||||
*
|
||||
* @param type The item type whose function table to retrieve.
|
||||
*
|
||||
* @return Pointer to the @ref ItemFuncs table for @p type,
|
||||
* or NULL if @p type is invalid or has no implemented functions.
|
||||
*/
|
||||
ItemFuncs* get_item_type_funcs(enum ItemType type);
|
||||
|
||||
#endif // ITEM_FUNCS_H
|
||||
+47
-2
@@ -9,7 +9,7 @@
|
||||
#include "card.h"
|
||||
#include "game.h"
|
||||
#include "graphic_utils.h"
|
||||
#include "sprite.h"
|
||||
#include "item.h"
|
||||
|
||||
#include <maxmod.h>
|
||||
|
||||
@@ -112,8 +112,8 @@ typedef struct
|
||||
|
||||
typedef struct JokerObject
|
||||
{
|
||||
Item; // First member struct inheritance
|
||||
Joker* joker;
|
||||
SpriteObject* sprite_object;
|
||||
} JokerObject;
|
||||
|
||||
typedef struct // These jokers are triggered after the played hand has finished scoring.
|
||||
@@ -197,6 +197,51 @@ JokerObject* joker_object_new(Joker* joker);
|
||||
void joker_object_destroy(JokerObject** joker_object);
|
||||
// This doesn't actually score anything, it just performs an animation and plays a sound effect
|
||||
void joker_object_shake(JokerObject* joker_object, mm_word sound_id);
|
||||
|
||||
/**
|
||||
* @brief Returns the buy price of the joker object.
|
||||
*
|
||||
* @param joker_object the joker object whose price to return.
|
||||
*
|
||||
* @return UNDEFINED in case of error, the buy price of the joker otherwise.
|
||||
*/
|
||||
int joker_object_get_buy_price(Item* joker_object);
|
||||
|
||||
// TODO: Move to an owned_jokers.c/.h file?
|
||||
/**
|
||||
* @brief Add a Joker to the list of owned Jokers and place it in the joker row.
|
||||
*
|
||||
* @param joker_object The JokerObject to add cast to Item*
|
||||
*/
|
||||
void joker_object_add_to_owned(Item* joker_object);
|
||||
|
||||
/**
|
||||
* @brief Destroy a JokerObject item, free its resources, and make it available to be rolled.
|
||||
*
|
||||
* @param joker_object Pointer to the JokerObject Item* to destroy; set to NULL.
|
||||
*/
|
||||
void joker_object_dispose(Item** joker_object);
|
||||
|
||||
/**
|
||||
* @brief Set whether a Joker is available to be rolled for the shop, packs, etc.
|
||||
*
|
||||
* @param joker_id The ID of the joker whose availability to set.
|
||||
* @param rollable true to make it rollable, false otherwise.
|
||||
*/
|
||||
void joker_set_rollable(int joker_id, bool rollable);
|
||||
|
||||
/**
|
||||
* @brief Reset rollable jokers to include all jokers in the registry.
|
||||
*/
|
||||
void joker_reset_rollable_jokers(void);
|
||||
|
||||
/**
|
||||
* @brief Roll and create a new JokerObject item.
|
||||
*
|
||||
* @return Newly created `Item*` (JokerObject) or NULL if none available.
|
||||
*/
|
||||
Item* joker_object_roll_new(void);
|
||||
|
||||
// This scores the joker and returns true if it was scored successfully
|
||||
// card_object = NULL means the joker_event does not concern a particular Card, i.e. Independend or
|
||||
// On_Blind_Selected as opposed to events that concern a particular card, i.e. On_Card_Scored or
|
||||
|
||||
+9
-8
@@ -194,23 +194,24 @@ void sprite_init(void);
|
||||
void sprite_draw(void);
|
||||
|
||||
/**
|
||||
* @brief Allocate and retrieve a pointer to a valid SpriteObject
|
||||
* @brief Initialize a SpriteObject to a default state.
|
||||
* Must be called only once per SpriteObject when it is created.
|
||||
*
|
||||
* @return A valid pointer to an newly allocated SpriteObject
|
||||
* if successful, othewise return **NULL**.
|
||||
* @param sprite_object - The SpriteObject to initialize
|
||||
*/
|
||||
SpriteObject* sprite_object_new();
|
||||
void sprite_object_init(SpriteObject* sprite_object);
|
||||
|
||||
/**
|
||||
* @brief Destroy SpriteObject
|
||||
*
|
||||
* Destroy a SpriteObject by freeing it back to the pool and releasing its
|
||||
* associated resources
|
||||
* Destroy a SpriteObject by releasing its associated resources (e.g. the sprite).
|
||||
* This invalidates the SpriteObject and it should not be used after destroyed,
|
||||
* a new one should be created instead.
|
||||
*
|
||||
* @param sprite_object pointer to a pointer of SpriteObject to destroy.
|
||||
* @param sprite_object pointer to a SpriteObject to destroy.
|
||||
* Cannot be **NULL**.
|
||||
*/
|
||||
void sprite_object_destroy(SpriteObject** sprite_object);
|
||||
void sprite_object_destroy(SpriteObject* sprite_object);
|
||||
|
||||
/**
|
||||
* @brief Register a Sprite to an associated SpriteObject
|
||||
|
||||
Reference in New Issue
Block a user