mirror of
https://github.com/risingPhil/PokeMe64.git
synced 2026-09-11 02:05:11 -05:00
Work on adding a PokeShop (incomplete, WIP, untested)
This commit is the start of the work to add a Pokéshop, which would let you buy starters or version exclusives for in-game money. But it's far from complete. This commit lays some of the groundwork, but can't even get compiled yet.
This commit is contained in:
57
include/scenes/PokeShopScene.h
Normal file
57
include/scenes/PokeShopScene.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef _POKESHOPSCENE_H
|
||||
#define _POKESHOPSCENE_H
|
||||
|
||||
#include "scenes/MenuScene.h"
|
||||
#include "transferpak/TransferPakRomReader.h"
|
||||
#include "transferpak/TransferPakSaveManager.h"
|
||||
#include "gen1/Gen1GameReader.h"
|
||||
#include "gen2/Gen2GameReader.h"
|
||||
#include "widget/PokeShopMenuItemWidget.h"
|
||||
|
||||
/**
|
||||
* @brief This scene implementation gives you a list of pokémon you
|
||||
* can buy from the PokéShop and inject into your cartridge save by selecting one
|
||||
*/
|
||||
class PokeShopScene : public MenuScene
|
||||
{
|
||||
public:
|
||||
PokeShopScene(SceneDependencies& deps, void* context);
|
||||
virtual ~PokeShopScene();
|
||||
|
||||
void init() override;
|
||||
void destroy() override;
|
||||
|
||||
bool handleUserInput(joypad_port_t port, const joypad_inputs_t& inputs) override;
|
||||
|
||||
/**
|
||||
* This function will start the pokémon injection. and show a non-skippable "saving" dialog
|
||||
* The actual injection will be done on the next handleUserInput() call.
|
||||
* That will ensure that at least 1 render() call has been handled before we start doing the work
|
||||
*/
|
||||
void triggerPokemonInjection(const void* data);
|
||||
|
||||
/**
|
||||
* @brief The core functionality of this class: it will inject the selected pokémon into your cartridge save.
|
||||
*
|
||||
* @param data a pointer to the Gen1DistributionPokemon or Gen2DistributionPokemon instance you want to inject.
|
||||
*/
|
||||
void injectPokemon(const void* data);
|
||||
|
||||
void onDialogDone() override;
|
||||
protected:
|
||||
void setupMenu() override;
|
||||
private:
|
||||
void loadShopList();
|
||||
|
||||
TransferPakRomReader romReader_;
|
||||
TransferPakSaveManager saveManager_;
|
||||
Gen1GameReader gen1Reader_;
|
||||
Gen2GameReader gen2Reader_;
|
||||
PokemonPartyIconFactory iconFactory_;
|
||||
ListItemFiller<VerticalList, PokeShopMenuItemData, PokeShopMenuItem, PokeShopMenuItemStyle> customListFiller_;
|
||||
DialogData diag_;
|
||||
sprite_t* iconBackgroundSprite_;
|
||||
const void* pokeToInject_;
|
||||
};
|
||||
|
||||
#endif
|
||||
110
include/widget/PokeShopMenuItemWidget.h
Normal file
110
include/widget/PokeShopMenuItemWidget.h
Normal file
@@ -0,0 +1,110 @@
|
||||
#ifndef _POKESHOPMENUITEMWIDGET_H
|
||||
#define _POKESHOPMENUITEMWIDGET_H
|
||||
|
||||
#include "widget/PokemonPartyIconWidget.h"
|
||||
#include "widget/MenuItemWidget.h"
|
||||
|
||||
typedef struct PokeShopMenuItemStyle
|
||||
{
|
||||
/**
|
||||
* width and height for the MenuItemWidget
|
||||
*/
|
||||
Dimensions size;
|
||||
struct {
|
||||
/**
|
||||
* (optional) background sprite
|
||||
*/
|
||||
sprite_t* sprite;
|
||||
/*
|
||||
* RenderSettings that influence how the backgroundSprite is
|
||||
* being rendered
|
||||
*/
|
||||
SpriteRenderSettings spriteSettings;
|
||||
} background;
|
||||
|
||||
struct {
|
||||
PokemonPartyIconWidgetStyle style;
|
||||
Rectangle bounds;
|
||||
} icon;
|
||||
|
||||
struct {
|
||||
/**
|
||||
* These are the text settings for when the MenuItemWidget is NOT focused by the user
|
||||
*/
|
||||
TextRenderSettings labelNotFocused;
|
||||
/**
|
||||
* These are the text render settings for when the MenuItemWidget is focused by the user
|
||||
*/
|
||||
TextRenderSettings labelFocused;
|
||||
/**
|
||||
* @brief the bounds for the price label
|
||||
*/
|
||||
Rectangle bounds;
|
||||
} title;
|
||||
|
||||
struct {
|
||||
/**
|
||||
* These are the text settings for when the MenuItemWidget is NOT focused by the user
|
||||
*/
|
||||
TextRenderSettings labelNotFocused;
|
||||
/**
|
||||
* These are the text render settings for when the MenuItemWidget is focused by the user
|
||||
*/
|
||||
TextRenderSettings labelFocused;
|
||||
/**
|
||||
* @brief the bounds for the price label
|
||||
*/
|
||||
Rectangle bounds;
|
||||
} price;
|
||||
} PokeShopMenuItemStyle;
|
||||
|
||||
typedef struct PokeShopMenuItemData : public MenuItemData
|
||||
{
|
||||
PokemonPartyIconWidgetData iconData;
|
||||
uint32_t price;
|
||||
} PokeShopMenuItemData;
|
||||
|
||||
/**
|
||||
* @brief This is a custom MenuItem widget to display distribution event pokemon in a vertical list menu.
|
||||
*/
|
||||
class PokeShopMenuItem : public IWidget
|
||||
{
|
||||
public:
|
||||
PokeShopMenuItem();
|
||||
virtual ~PokeShopMenuItem();
|
||||
|
||||
const PokeShopMenuItemData& getData() const;
|
||||
|
||||
void setData(const PokeShopMenuItemData& data);
|
||||
void setStyle(const PokeShopMenuItemStyle& style);
|
||||
|
||||
bool isFocused() const override;
|
||||
void setFocused(bool isFocused) override;
|
||||
|
||||
bool isVisible() const override;
|
||||
void setVisible(bool visible) override;
|
||||
|
||||
Rectangle getBounds() const override;
|
||||
void setBounds(const Rectangle& bounds) override;
|
||||
|
||||
Dimensions getSize() const override;
|
||||
|
||||
bool handleUserInput(const joypad_inputs_t& userInput) override;
|
||||
|
||||
void render(RDPQGraphics& gfx, const Rectangle& parentBounds) override;
|
||||
protected:
|
||||
/**
|
||||
* Executes the onConfirmAction callback (if any)
|
||||
*/
|
||||
bool execute();
|
||||
private:
|
||||
PokemonPartyIconWidget partyIconWidget_;
|
||||
PokeShopMenuItemStyle style_;
|
||||
PokeShopMenuItemData data_;
|
||||
char priceText_[10];
|
||||
bool focused_;
|
||||
bool visible_;
|
||||
bool aButtonPressed_;
|
||||
};
|
||||
|
||||
#endif
|
||||
39
src/scenes/PokeShopScene.cpp
Normal file
39
src/scenes/PokeShopScene.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "scenes/PokeShopScene.h"
|
||||
#include "scenes/SceneManager.h"
|
||||
#include "scenes/StatsScene.h"
|
||||
#include "transferpak/TransferPakManager.h"
|
||||
|
||||
static const Rectangle menuListBounds = {20, 20, 280, 0};
|
||||
static const Rectangle imgScrollArrowUpBounds = {.x = 154, .y = 14, .width = 11, .height = 6};
|
||||
static const Rectangle imgScrollArrowDownBounds = {.x = 154, .y = 220, .width = 11, .height = 6};
|
||||
|
||||
static void injectDistributionPokemon(void* context, const void* data)
|
||||
{
|
||||
auto scene = static_cast<PokeShopScene*>(context);
|
||||
scene->triggerPokemonInjection(data);
|
||||
}
|
||||
|
||||
PokeShopScene::PokeShopScene(SceneDependencies& deps, void* context)
|
||||
: MenuScene(deps, context)
|
||||
, romReader_(deps.tpakManager)
|
||||
, saveManager_(deps.tpakManager)
|
||||
, gen1Reader_(romReader_, saveManager_, static_cast<Gen1GameType>(deps.specificGenVersion), static_cast<Gen1LocalizationLanguage>(deps.localization))
|
||||
, gen2Reader_(romReader_, saveManager_, static_cast<Gen2GameType>(deps.specificGenVersion), static_cast<Gen2LocalizationLanguage>(deps.localization))
|
||||
, iconFactory_(romReader_)
|
||||
, customListFiller_(menuList_)
|
||||
, diag_()
|
||||
, iconBackgroundSprite_(nullptr)
|
||||
, pokeToInject_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
PokeShopScene::~PokeShopScene()
|
||||
{
|
||||
}
|
||||
|
||||
void PokeShopScene::init()
|
||||
{
|
||||
iconBackgroundSprite_ = sprite_load("rom://bg-party-icon.sprite");
|
||||
loadShopList();
|
||||
MenuScene::init();
|
||||
}
|
||||
129
src/widget/PokeShopMenuItemWidget.cpp
Normal file
129
src/widget/PokeShopMenuItemWidget.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "widget/PokeShopMenuItemWidget.h"
|
||||
|
||||
PokeShopMenuItem::PokeShopMenuItem()
|
||||
: partyIconWidget_()
|
||||
, style_({0})
|
||||
, data_()
|
||||
, priceText_({0})
|
||||
, focused_(false)
|
||||
, visible_(true)
|
||||
, aButtonPressed_(false)
|
||||
{
|
||||
}
|
||||
|
||||
PokeShopMenuItem::~PokeShopMenuItem()
|
||||
{
|
||||
}
|
||||
|
||||
const PokeShopMenuItemData& PokeShopMenuItem::getData() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
void PokeShopMenuItem::setData(const PokeShopMenuItemData& data)
|
||||
{
|
||||
data_ = data;
|
||||
|
||||
snprintf(priceText_, sizeof(priceText_), "$%u", data.price);
|
||||
partyIconWidget_.setData(data.iconData);
|
||||
}
|
||||
|
||||
void PokeShopMenuItem::setStyle(const PokeShopMenuItemStyle& style)
|
||||
{
|
||||
style_ = style;
|
||||
|
||||
partyIconWidget_.setBounds(style.icon.bounds);
|
||||
partyIconWidget_.setStyle(style.icon.style);
|
||||
}
|
||||
|
||||
bool PokeShopMenuItem::isFocused() const
|
||||
{
|
||||
return focused_;
|
||||
}
|
||||
|
||||
void PokeShopMenuItem::setFocused(bool isFocused)
|
||||
{
|
||||
focused_ = isFocused;
|
||||
partyIconWidget_.setFocused(isFocused);
|
||||
}
|
||||
|
||||
bool PokeShopMenuItem::isVisible() const
|
||||
{
|
||||
return visible_;
|
||||
}
|
||||
|
||||
void PokeShopMenuItem::setVisible(bool visible)
|
||||
{
|
||||
visible_ = visible;
|
||||
}
|
||||
|
||||
Rectangle PokeShopMenuItem::getBounds() const
|
||||
{
|
||||
return Rectangle{.x = 0, .y = 0, .width = style_.size.width, .height = style_.size.height};
|
||||
}
|
||||
|
||||
void PokeShopMenuItem::setBounds(const Rectangle& bounds)
|
||||
{
|
||||
// Not relevant: the actual bounds are passed from the VerticalList widget
|
||||
}
|
||||
|
||||
Dimensions PokeShopMenuItem::getSize() const
|
||||
{
|
||||
return style_.size;
|
||||
}
|
||||
|
||||
bool PokeShopMenuItem::handleUserInput(const joypad_inputs_t& userInput)
|
||||
{
|
||||
// We only care about the A-button press/release for this widget
|
||||
if(userInput.btn.a)
|
||||
{
|
||||
aButtonPressed_ = true;
|
||||
return true;
|
||||
}
|
||||
else if(aButtonPressed_)
|
||||
{
|
||||
aButtonPressed_ = false;
|
||||
return execute();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PokeShopMenuItem::render(RDPQGraphics& gfx, const Rectangle& parentBounds)
|
||||
{
|
||||
if(!visible_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const Rectangle myBounds = {.x = parentBounds.x, .y = parentBounds.y, .width = style_.size.width, .height = style_.size.height};
|
||||
if(style_.background.sprite)
|
||||
{
|
||||
gfx.drawSprite(myBounds, style_.background.sprite, style_.background.spriteSettings);
|
||||
}
|
||||
|
||||
partyIconWidget_.render(gfx, myBounds);
|
||||
|
||||
const Rectangle titleBounds = { myBounds.x + style_.title.bounds.x,
|
||||
myBounds.y + style_.title.bounds.y,
|
||||
style_.title.bounds.width,
|
||||
style_.title.bounds.height };
|
||||
|
||||
gfx.drawText(titleBounds, data_.title, (focused_) ? style_.title.labelFocused : style_.title.labelNotFocused);
|
||||
|
||||
const Rectangle priceBounds = { myBounds.x + style_.price.bounds.x,
|
||||
myBounds.y + style_.price.bounds.y,
|
||||
style_.price.bounds.width,
|
||||
style_.price.bounds.height };
|
||||
|
||||
gfx.drawText(priceBounds, priceText_, (focused_) ? style_.price.labelFocused : style_.price.labelNotFocused);
|
||||
}
|
||||
|
||||
bool PokeShopMenuItem::execute()
|
||||
{
|
||||
if(data_.onConfirmAction)
|
||||
{
|
||||
data_.onConfirmAction(data_.context, data_.itemParam);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user