mirror of
https://github.com/LNH-team/pico-launcher.git
synced 2026-06-02 09:06:54 +02:00
Add cheat documentation, enable input repeat for L and R, show cheat category name
This commit is contained in:
@@ -15,6 +15,7 @@ This repository contains Pico Launcher, which is a front-end for [Pico Loader](h
|
|||||||
- [Covers](docs/Covers.md)
|
- [Covers](docs/Covers.md)
|
||||||
- [Material Design 3 and custom themes](docs/Themes.md)
|
- [Material Design 3 and custom themes](docs/Themes.md)
|
||||||
- Support for background music (see [Themes](docs/Themes.md))
|
- Support for background music (see [Themes](docs/Themes.md))
|
||||||
|
- Support for cheats (See [Cheats](docs/Cheats.md))
|
||||||
|
|
||||||
General usage documentation can be found here: [Usage](docs/Usage.md).
|
General usage documentation can be found here: [Usage](docs/Usage.md).
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ App::App(IAppSettingsService& appSettingsService, IBgmService& bgmService)
|
|||||||
, _bgmService(bgmService)
|
, _bgmService(bgmService)
|
||||||
, _inputProvider(&_inputSource)
|
, _inputProvider(&_inputSource)
|
||||||
, _inputRepeater(&_inputProvider,
|
, _inputRepeater(&_inputProvider,
|
||||||
InputKey::DpadLeft | InputKey::DpadRight | InputKey::DpadUp | InputKey::DpadDown,
|
InputKey::DpadLeft | InputKey::DpadRight | InputKey::DpadUp | InputKey::DpadDown | InputKey::L | InputKey::R,
|
||||||
25, 8)
|
25, 8)
|
||||||
, _romBrowserController(&appSettingsService, &_ioTaskQueue, &_bgTaskQueue)
|
, _romBrowserController(&appSettingsService, &_ioTaskQueue, &_bgTaskQueue)
|
||||||
, _displaySettingsBottomSheetViewModel(&_romBrowserController)
|
, _displaySettingsBottomSheetViewModel(&_romBrowserController)
|
||||||
|
|||||||
@@ -1,27 +1,48 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "CheatTreeItem.h"
|
|
||||||
|
|
||||||
class Cheat : public CheatTreeItem
|
/// @brief Class representing a single cheat.
|
||||||
|
class Cheat
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Cheat()
|
Cheat() { }
|
||||||
: _cheatData(nullptr), _cheatDataLength(0) { }
|
|
||||||
|
|
||||||
Cheat(const char* name, const char* description, u32* flagsPointer, const void* cheatData, u32 cheatDataLength)
|
Cheat(const char* name, const char* description, u32* flagsPointer, const void* cheatData, u32 cheatDataLength)
|
||||||
: CheatTreeItem(name, description), _flagsPointer(flagsPointer)
|
: _name(name), _description(description), _flagsPointer(flagsPointer)
|
||||||
, _cheatData(cheatData), _cheatDataLength(cheatDataLength) { }
|
, _cheatData(cheatData), _cheatDataLength(cheatDataLength) { }
|
||||||
|
|
||||||
|
/// @brief Gets the name of this cheat.
|
||||||
|
/// @return A pointer to the name of this cheat.
|
||||||
|
const char* GetName() const
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Gets the description of this cheat.
|
||||||
|
/// @return A pointer to the description of this cheat.
|
||||||
|
const char* GetDescription() const
|
||||||
|
{
|
||||||
|
return _description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Gets a pointer to the data of this cheat.
|
||||||
|
/// @param cheatDataLength The length of the cheat data is returned in this reference.
|
||||||
|
/// @return A pointer to the cheat data.
|
||||||
|
/// This pointer is only valid for the lifetime of the \see GameCheats instance this cheat belongs to.
|
||||||
const void* GetCheatData(u32& cheatDataLength) const
|
const void* GetCheatData(u32& cheatDataLength) const
|
||||||
{
|
{
|
||||||
cheatDataLength = _cheatDataLength;
|
cheatDataLength = _cheatDataLength;
|
||||||
return _cheatData;
|
return _cheatData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Gets whether this cheat is active (enabled) or not.
|
||||||
|
/// @return \c true when this cheat is active, or \c false when not active.
|
||||||
bool GetIsCheatActive() const
|
bool GetIsCheatActive() const
|
||||||
{
|
{
|
||||||
return ((*_flagsPointer >> 24) & 1) == 1;
|
return ((*_flagsPointer >> 24) & 1) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Sets whether this cheat is active (enabled) or not.
|
||||||
|
/// @param isCheatActive \c true to enable this cheat, or \c false to disable this cheat.
|
||||||
void SetIsCheatActive(bool isCheatActive) const
|
void SetIsCheatActive(bool isCheatActive) const
|
||||||
{
|
{
|
||||||
u32 flags = *_flagsPointer;
|
u32 flags = *_flagsPointer;
|
||||||
@@ -34,7 +55,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32* _flagsPointer;
|
const char* _name = nullptr;
|
||||||
const void* _cheatData;
|
const char* _description = nullptr;
|
||||||
u32 _cheatDataLength;
|
u32* _flagsPointer = nullptr;
|
||||||
|
const void* _cheatData = nullptr;
|
||||||
|
u32 _cheatDataLength = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "CheatTreeItem.h"
|
|
||||||
#include "Cheat.h"
|
|
||||||
#include "ICheatCategory.h"
|
#include "ICheatCategory.h"
|
||||||
|
|
||||||
class CheatCategory : public CheatTreeItem, public ICheatCategory
|
/// @brief Class representing a cheat category, containing sub-categories and cheats.
|
||||||
|
class CheatCategory : public ICheatCategory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CheatCategory()
|
CheatCategory() { }
|
||||||
: _isMaxOneCheatActive(false), _subCategories(nullptr), _numberOfSubCategories(0)
|
|
||||||
, _cheats(nullptr), _numberOfCheats(0) { }
|
|
||||||
|
|
||||||
CheatCategory(const char* name, const char* description, bool isMaxOneCheatActive,
|
CheatCategory(const char* name, const char* description, bool isMaxOneCheatActive,
|
||||||
CheatCategory* subCategories, u32 numberOfSubCategories, Cheat* cheats, u32 numberOfCheats)
|
CheatCategory* subCategories, u32 numberOfSubCategories, Cheat* cheats, u32 numberOfCheats)
|
||||||
: CheatTreeItem(name, description), _isMaxOneCheatActive(isMaxOneCheatActive)
|
: _name(name), _description(description), _isMaxOneCheatActive(isMaxOneCheatActive)
|
||||||
, _subCategories(subCategories), _numberOfSubCategories(numberOfSubCategories)
|
, _subCategories(subCategories), _numberOfSubCategories(numberOfSubCategories)
|
||||||
, _cheats(cheats), _numberOfCheats(numberOfCheats) { }
|
, _cheats(cheats), _numberOfCheats(numberOfCheats) { }
|
||||||
|
|
||||||
@@ -56,6 +53,18 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* GetName() const override
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Gets the description of this cheat category.
|
||||||
|
/// @return A pointer to the description of this cheat category.
|
||||||
|
const char* GetDescription() const
|
||||||
|
{
|
||||||
|
return _description;
|
||||||
|
}
|
||||||
|
|
||||||
bool GetIsMaxOneCheatActive() const override
|
bool GetIsMaxOneCheatActive() const override
|
||||||
{
|
{
|
||||||
return _isMaxOneCheatActive;
|
return _isMaxOneCheatActive;
|
||||||
@@ -74,9 +83,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _isMaxOneCheatActive;
|
const char* _name = nullptr;
|
||||||
CheatCategory* _subCategories;
|
const char* _description = nullptr;
|
||||||
u32 _numberOfSubCategories;
|
bool _isMaxOneCheatActive = false;
|
||||||
Cheat* _cheats;
|
CheatCategory* _subCategories = nullptr;
|
||||||
u32 _numberOfCheats;
|
u32 _numberOfSubCategories = 0;
|
||||||
|
Cheat* _cheats = nullptr;
|
||||||
|
u32 _numberOfCheats = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class CheatTreeItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const char* GetName() const
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* GetDescription() const
|
|
||||||
{
|
|
||||||
return _description;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const char* _name;
|
|
||||||
const char* _description;
|
|
||||||
|
|
||||||
CheatTreeItem()
|
|
||||||
: _name(nullptr), _description(nullptr) { }
|
|
||||||
|
|
||||||
CheatTreeItem(const char* name, const char* description)
|
|
||||||
: _name(name), _description(description) { }
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "ICheatRepository.h"
|
#include "ICheatRepository.h"
|
||||||
|
|
||||||
|
/// @brief Class implementing an empty cheat repository.
|
||||||
class EmptyCheatRepository : public ICheatRepository
|
class EmptyCheatRepository : public ICheatRepository
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "CheatCategory.h"
|
#include "CheatCategory.h"
|
||||||
#include "ICheatCategory.h"
|
#include "ICheatCategory.h"
|
||||||
|
|
||||||
|
/// @brief Class holding the cheats for a game.
|
||||||
class GameCheats : public ICheatCategory
|
class GameCheats : public ICheatCategory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -24,16 +25,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Gets the name of the game.
|
||||||
|
/// @return A pointer to the name of the game.
|
||||||
const char* GetGameName() const
|
const char* GetGameName() const
|
||||||
{
|
{
|
||||||
return _gameName;
|
return _gameName;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetIsMaxOneCheatActive() const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CheatCategory* GetCategories(u32& numberOfCategories) const override
|
const CheatCategory* GetCategories(u32& numberOfCategories) const override
|
||||||
{
|
{
|
||||||
numberOfCategories = _numberOfCategories;
|
numberOfCategories = _numberOfCategories;
|
||||||
@@ -46,6 +44,9 @@ public:
|
|||||||
return _cheats;
|
return _cheats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Gets a pointer to the cheat data.
|
||||||
|
/// @param cheatDataLength The length of the cheat data is returned in this reference.
|
||||||
|
/// @return A pointer to the cheat data. This pointer is only valid for the lifetime of this \see GameCheats instance.
|
||||||
u8* GetCheatData(u32& cheatDataLength) const
|
u8* GetCheatData(u32& cheatDataLength) const
|
||||||
{
|
{
|
||||||
cheatDataLength = _cheatDataLength;
|
cheatDataLength = _cheatDataLength;
|
||||||
@@ -66,4 +67,15 @@ private:
|
|||||||
u32 _numberOfCategories;
|
u32 _numberOfCategories;
|
||||||
Cheat* _cheats;
|
Cheat* _cheats;
|
||||||
u32 _numberOfCheats;
|
u32 _numberOfCheats;
|
||||||
|
|
||||||
|
// From ICheatCategory
|
||||||
|
const char* GetName() const override
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetIsMaxOneCheatActive() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,13 +3,28 @@
|
|||||||
class CheatCategory;
|
class CheatCategory;
|
||||||
class Cheat;
|
class Cheat;
|
||||||
|
|
||||||
|
/// @brief Interface for a collection of cheats.
|
||||||
class ICheatCategory
|
class ICheatCategory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ICheatCategory() = default;
|
virtual ~ICheatCategory() = default;
|
||||||
|
|
||||||
|
/// @brief Gets the name of this category.
|
||||||
|
/// @return The name of this category.
|
||||||
|
virtual const char* GetName() const = 0;
|
||||||
|
|
||||||
|
/// @brief Indicates if only one cheat in this category is allowed to be on or not.
|
||||||
|
/// @return \c true when only one cheat is allowed to be active in this category, or \c false otherwise.
|
||||||
virtual bool GetIsMaxOneCheatActive() const = 0;
|
virtual bool GetIsMaxOneCheatActive() const = 0;
|
||||||
|
|
||||||
|
/// @brief Gets the sub-categories of this category.
|
||||||
|
/// @param numberOfCategories The number of categories is returned through this reference.
|
||||||
|
/// @return A pointer to an array of categories. This may be \c nullptr when \p numberOfCategories is 0.
|
||||||
virtual const CheatCategory* GetCategories(u32& numberOfCategories) const;
|
virtual const CheatCategory* GetCategories(u32& numberOfCategories) const;
|
||||||
|
|
||||||
|
/// @brief Gets the cheats in this category.
|
||||||
|
/// @param numberOfCheats The number of cheats is returned through this reference.
|
||||||
|
/// @return A pointer to an array of cheats. This may be \c nullptr when \p numberOfCheats is 0.
|
||||||
virtual const Cheat* GetCheats(u32& numberOfCheats) const;
|
virtual const Cheat* GetCheats(u32& numberOfCheats) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -2,12 +2,19 @@
|
|||||||
#include "GameCheats.h"
|
#include "GameCheats.h"
|
||||||
#include "fat/FastFileRef.h"
|
#include "fat/FastFileRef.h"
|
||||||
|
|
||||||
|
/// @brief Interface for a repository providing access to cheats.
|
||||||
class ICheatRepository
|
class ICheatRepository
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~ICheatRepository() { }
|
virtual ~ICheatRepository() { }
|
||||||
|
|
||||||
|
/// @brief Gets the available cheats for the given \p romFile.
|
||||||
|
/// @param romFile Reference to the rom file.
|
||||||
|
/// @return A unique pointer to the found cheats, or an empty unique pointer when no cheats were found.
|
||||||
virtual std::unique_ptr<GameCheats> GetCheatsForGame(const FastFileRef& romFile) const = 0;
|
virtual std::unique_ptr<GameCheats> GetCheatsForGame(const FastFileRef& romFile) const = 0;
|
||||||
|
|
||||||
|
/// @brief Writes the enable/disabled status of the given \p cheats.
|
||||||
|
/// @param cheats The cheats to update.
|
||||||
virtual void UpdateEnabledCheatsForGame(const std::unique_ptr<GameCheats>& cheats) const = 0;
|
virtual void UpdateEnabledCheatsForGame(const std::unique_ptr<GameCheats>& cheats) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -3,9 +3,13 @@
|
|||||||
#include "GameCheats.h"
|
#include "GameCheats.h"
|
||||||
#include "picoLoader7.h"
|
#include "picoLoader7.h"
|
||||||
|
|
||||||
|
/// @brief Factory for creating Pico Loader compatible cheat data.
|
||||||
class PicoLoaderCheatDataFactory
|
class PicoLoaderCheatDataFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// @brief Converts the given \p gameCheats to Pico Loader format. Only the enabled cheats will be included.
|
||||||
|
/// @param gameCheats The cheats to convert.
|
||||||
|
/// @return Pointer to the created cheat data.
|
||||||
pload_cheats_t* CreateCheatData(const std::unique_ptr<GameCheats>& gameCheats) const;
|
pload_cheats_t* CreateCheatData(const std::unique_ptr<GameCheats>& gameCheats) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/// @brief Struct representing an index entry of usrcheat.dat.
|
||||||
struct usr_cheat_index_entry_t
|
struct usr_cheat_index_entry_t
|
||||||
{
|
{
|
||||||
u32 gameCode;
|
u32 gameCode;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "ICheatRepository.h"
|
#include "ICheatRepository.h"
|
||||||
#include "UsrCheatDat.h"
|
#include "UsrCheatDat.h"
|
||||||
|
|
||||||
|
/// @brief Class implementing a cheat repository for usrcheat.dat.
|
||||||
class UsrCheatRepository : public ICheatRepository
|
class UsrCheatRepository : public ICheatRepository
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -2,8 +2,12 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include "UsrCheatRepository.h"
|
#include "UsrCheatRepository.h"
|
||||||
|
|
||||||
|
/// @brief Factory for constructing a \see UsrCheatRepository for a usrcheat.dat file.
|
||||||
class UsrCheatRepositoryFactory
|
class UsrCheatRepositoryFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// @brief Constructs a \see UsrCheatRepository for the given \p usrCheatDatPath.
|
||||||
|
/// @param usrCheatDatPath The path to the usrcheat.dat file.
|
||||||
|
/// @return A unique pointer to the constructed repository, or an empty unique pointer when construction failed.
|
||||||
std::unique_ptr<UsrCheatRepository> FromUsrCheatDat(const TCHAR* usrCheatDatPath);
|
std::unique_ptr<UsrCheatRepository> FromUsrCheatDat(const TCHAR* usrCheatDatPath);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ CheatsViewModel::CheatsViewModel(const FileInfo& romFileInfo, IRomBrowserControl
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatsViewModel::ItemActivated()
|
void CheatsViewModel::ActivateSelectedItem()
|
||||||
{
|
{
|
||||||
auto cheatCategory = GetCurrentCheatCategory();
|
auto cheatCategory = GetCurrentCheatCategory();
|
||||||
u32 numberOfCategories = 0;
|
u32 numberOfCategories = 0;
|
||||||
@@ -58,21 +58,25 @@ void CheatsViewModel::ItemActivated()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatsViewModel::Back()
|
bool CheatsViewModel::NavigateUp()
|
||||||
{
|
{
|
||||||
if (_categoryStackLevel == 0)
|
if (_categoryStackLevel == 0)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_selectedItem = _categoryStack[_categoryStackLevel].index;
|
_selectedItem = _categoryStack[_categoryStackLevel].index;
|
||||||
_categoryStack[_categoryStackLevel--] = { nullptr, 0 };
|
_categoryStack[_categoryStackLevel--] = { nullptr, 0 };
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatsViewModel::Close()
|
void CheatsViewModel::Close()
|
||||||
{
|
{
|
||||||
|
_categoryStack.fill({ nullptr, 0 });
|
||||||
|
|
||||||
if (_changed)
|
if (_changed)
|
||||||
{
|
{
|
||||||
// Save which cheats are enabled/disabled
|
// Save which cheats are enabled/disabled
|
||||||
|
|||||||
@@ -10,26 +10,57 @@
|
|||||||
class CheatsViewModel
|
class CheatsViewModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// @brief Enum representing the state of the cheats panel.
|
||||||
enum class State
|
enum class State
|
||||||
{
|
{
|
||||||
|
/// @brief Cheats are being loaded.
|
||||||
Loading,
|
Loading,
|
||||||
|
|
||||||
|
/// @brief No cheats were found.
|
||||||
NoCheats,
|
NoCheats,
|
||||||
|
|
||||||
|
/// @brief Cheats are being displayed.
|
||||||
DisplayCheats
|
DisplayCheats
|
||||||
};
|
};
|
||||||
|
|
||||||
CheatsViewModel(const FileInfo& romFileInfo, IRomBrowserController* romBrowserController);
|
CheatsViewModel(const FileInfo& romFileInfo, IRomBrowserController* romBrowserController);
|
||||||
|
|
||||||
void ItemActivated();
|
/// @brief Activates the selected cheat or category.
|
||||||
void Back();
|
void ActivateSelectedItem();
|
||||||
|
|
||||||
|
/// @brief Navigates up in the cheat hierachy, or closes the cheats panel when at the root.
|
||||||
|
/// @return \c true when navigation happened in the cheats tree, or \c false when the cheats panel was closed.
|
||||||
|
bool NavigateUp();
|
||||||
|
|
||||||
|
/// @brief Closes the cheats panel.
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
|
/// @brief Disables all cheats.
|
||||||
void DisableAllCheats();
|
void DisableAllCheats();
|
||||||
|
|
||||||
|
/// @brief Gets the current state of the cheats panel.
|
||||||
|
/// @return The current state of the cheats panel.
|
||||||
State GetState() const { return _state; }
|
State GetState() const { return _state; }
|
||||||
|
|
||||||
|
/// @brief Gets the current cheat category.
|
||||||
|
/// @return The current cheat category.
|
||||||
const ICheatCategory* GetCurrentCheatCategory() const { return _categoryStack[_categoryStackLevel].cheatCategory; }
|
const ICheatCategory* GetCurrentCheatCategory() const { return _categoryStack[_categoryStackLevel].cheatCategory; }
|
||||||
|
|
||||||
|
/// @brief Gets the index of the selected item.
|
||||||
|
/// @return The index of the selected item.
|
||||||
constexpr int GetSelectedItem() const { return _selectedItem; }
|
constexpr int GetSelectedItem() const { return _selectedItem; }
|
||||||
|
|
||||||
|
/// @brief Sets the index of the selected item.
|
||||||
|
/// @param selectedItem The index of the selected item to set.
|
||||||
void SetSelectedItem(int selectedItem) { _selectedItem = selectedItem; }
|
void SetSelectedItem(int selectedItem) { _selectedItem = selectedItem; }
|
||||||
|
|
||||||
|
/// @brief Returns whether the category name should be displayed.
|
||||||
|
/// @return \c true when the category name should be displayed, or \c false otherwise.
|
||||||
|
bool ShouldShowCategoryName() const
|
||||||
|
{
|
||||||
|
return _categoryStackLevel > 0;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CategoryStackEntry
|
struct CategoryStackEntry
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
class MaterialColorScheme;
|
class MaterialColorScheme;
|
||||||
class IFontRepository;
|
class IFontRepository;
|
||||||
|
|
||||||
|
/// @brief List item view for the cheats panel, representing a single cheat or cheat category.
|
||||||
class CheatListItemView : public ViewContainer
|
class CheatListItemView : public ViewContainer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "cheats/Cheat.h"
|
#include "cheats/Cheat.h"
|
||||||
#include "CheatListItemView.h"
|
#include "CheatListItemView.h"
|
||||||
|
|
||||||
|
/// @brief Recycler adapter for cheats.
|
||||||
class CheatsAdapter : public RecyclerAdapter
|
class CheatsAdapter : public RecyclerAdapter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
#define TITLE_LABEL_X 20
|
#define TITLE_LABEL_X 20
|
||||||
#define TITLE_LABEL_Y 16
|
#define TITLE_LABEL_Y 16
|
||||||
|
|
||||||
|
#define CATEGORY_NAME_LABEL_X (TITLE_LABEL_X + 43)
|
||||||
|
#define CATEGORY_NAME_LABEL_Y (TITLE_LABEL_Y + 1)
|
||||||
|
|
||||||
#define NO_CHEATS_FOUND_LABEL_X 20
|
#define NO_CHEATS_FOUND_LABEL_X 20
|
||||||
#define NO_CHEATS_FOUND_LABEL_Y 36
|
#define NO_CHEATS_FOUND_LABEL_Y 36
|
||||||
|
|
||||||
@@ -32,7 +35,7 @@ CheatsBottomSheetView::CheatsBottomSheetView(std::unique_ptr<CheatsViewModel> vi
|
|||||||
FocusManager* focusManager)
|
FocusManager* focusManager)
|
||||||
: _viewModel(std::move(viewModel))
|
: _viewModel(std::move(viewModel))
|
||||||
, _titleLabel(64, 16, 25, fontRepository->GetFont(FontType::Medium11))
|
, _titleLabel(64, 16, 25, fontRepository->GetFont(FontType::Medium11))
|
||||||
, _noCheatsFoundLabel(96, 16, 25, fontRepository->GetFont(FontType::Regular10))
|
, _secondaryLabel(177, 16, 64, fontRepository->GetFont(FontType::Regular10))
|
||||||
, _descriptionLabel(224, 16, 256, fontRepository->GetFont(FontType::Medium7_5))
|
, _descriptionLabel(224, 16, 256, fontRepository->GetFont(FontType::Medium7_5))
|
||||||
, _cheatListRecycler(std::make_unique<RecyclerView>(
|
, _cheatListRecycler(std::make_unique<RecyclerView>(
|
||||||
LIST_X, LIST_Y, LIST_WIDTH, LIST_HEIGHT, RecyclerView::Mode::VerticalList))
|
LIST_X, LIST_Y, LIST_WIDTH, LIST_HEIGHT, RecyclerView::Mode::VerticalList))
|
||||||
@@ -41,11 +44,12 @@ CheatsBottomSheetView::CheatsBottomSheetView(std::unique_ptr<CheatsViewModel> vi
|
|||||||
, _focusManager(focusManager)
|
, _focusManager(focusManager)
|
||||||
{
|
{
|
||||||
_titleLabel.SetText(u"Cheats");
|
_titleLabel.SetText(u"Cheats");
|
||||||
_noCheatsFoundLabel.SetText(u"No cheats found.");
|
_secondaryLabel.SetText(u"No cheats found.");
|
||||||
|
_secondaryLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis);
|
||||||
_descriptionLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Marquee);
|
_descriptionLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Marquee);
|
||||||
_descriptionLabel.SetText("");
|
_descriptionLabel.SetText("");
|
||||||
AddChildTail(&_titleLabel);
|
AddChildTail(&_titleLabel);
|
||||||
AddChildTail(&_noCheatsFoundLabel);
|
AddChildTail(&_secondaryLabel);
|
||||||
AddChildTail(&_descriptionLabel);
|
AddChildTail(&_descriptionLabel);
|
||||||
AddChildTail(_cheatListRecycler.get());
|
AddChildTail(_cheatListRecycler.get());
|
||||||
}
|
}
|
||||||
@@ -80,7 +84,14 @@ void CheatsBottomSheetView::InitVram(const VramContext& vramContext)
|
|||||||
void CheatsBottomSheetView::Update()
|
void CheatsBottomSheetView::Update()
|
||||||
{
|
{
|
||||||
_titleLabel.SetPosition(TITLE_LABEL_X, _position.y + TITLE_LABEL_Y);
|
_titleLabel.SetPosition(TITLE_LABEL_X, _position.y + TITLE_LABEL_Y);
|
||||||
_noCheatsFoundLabel.SetPosition(NO_CHEATS_FOUND_LABEL_X, _position.y + NO_CHEATS_FOUND_LABEL_Y);
|
if (_viewModel->GetState() == CheatsViewModel::State::DisplayCheats)
|
||||||
|
{
|
||||||
|
_secondaryLabel.SetPosition(CATEGORY_NAME_LABEL_X, _position.y + CATEGORY_NAME_LABEL_Y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_secondaryLabel.SetPosition(NO_CHEATS_FOUND_LABEL_X, _position.y + NO_CHEATS_FOUND_LABEL_Y);
|
||||||
|
}
|
||||||
_descriptionLabel.SetPosition(DESCRIPTION_LABEL_X, _position.y + DESCRIPTION_LABEL_Y);
|
_descriptionLabel.SetPosition(DESCRIPTION_LABEL_X, _position.y + DESCRIPTION_LABEL_Y);
|
||||||
_cheatListRecycler->SetPosition(LIST_X, _position.y + LIST_Y);
|
_cheatListRecycler->SetPosition(LIST_X, _position.y + LIST_Y);
|
||||||
if (_viewModel->GetState() == CheatsViewModel::State::DisplayCheats)
|
if (_viewModel->GetState() == CheatsViewModel::State::DisplayCheats)
|
||||||
@@ -168,11 +179,12 @@ void CheatsBottomSheetView::Draw(GraphicsContext& graphicsContext)
|
|||||||
_titleLabel.SetForegroundColor(_materialColorScheme->onSurface);
|
_titleLabel.SetForegroundColor(_materialColorScheme->onSurface);
|
||||||
_titleLabel.Draw(graphicsContext);
|
_titleLabel.Draw(graphicsContext);
|
||||||
|
|
||||||
if (_viewModel->GetState() == CheatsViewModel::State::NoCheats)
|
if (_viewModel->GetState() == CheatsViewModel::State::NoCheats ||
|
||||||
|
_viewModel->ShouldShowCategoryName())
|
||||||
{
|
{
|
||||||
_noCheatsFoundLabel.SetBackgroundColor(backColor);
|
_secondaryLabel.SetBackgroundColor(backColor);
|
||||||
_noCheatsFoundLabel.SetForegroundColor(_materialColorScheme->onSurface);
|
_secondaryLabel.SetForegroundColor(_materialColorScheme->onSurfaceVariant);
|
||||||
_noCheatsFoundLabel.Draw(graphicsContext);
|
_secondaryLabel.Draw(graphicsContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
_descriptionLabel.SetBackgroundColor(backColor);
|
_descriptionLabel.SetBackgroundColor(backColor);
|
||||||
@@ -190,9 +202,10 @@ bool CheatsBottomSheetView::HandleInput(const InputProvider& inputProvider, Focu
|
|||||||
if (focusManager.IsFocusInside(_cheatListRecycler.get()))
|
if (focusManager.IsFocusInside(_cheatListRecycler.get()))
|
||||||
{
|
{
|
||||||
auto oldCategory = _viewModel->GetCurrentCheatCategory();
|
auto oldCategory = _viewModel->GetCurrentCheatCategory();
|
||||||
_viewModel->ItemActivated();
|
_viewModel->ActivateSelectedItem();
|
||||||
if (oldCategory != _viewModel->GetCurrentCheatCategory())
|
if (oldCategory != _viewModel->GetCurrentCheatCategory())
|
||||||
{
|
{
|
||||||
|
_secondaryLabel.SetText(_viewModel->GetCurrentCheatCategory()->GetName());
|
||||||
UpdateCheatList();
|
UpdateCheatList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,8 +215,8 @@ bool CheatsBottomSheetView::HandleInput(const InputProvider& inputProvider, Focu
|
|||||||
else if (inputProvider.Triggered(InputKey::B))
|
else if (inputProvider.Triggered(InputKey::B))
|
||||||
{
|
{
|
||||||
auto oldCategory = _viewModel->GetCurrentCheatCategory();
|
auto oldCategory = _viewModel->GetCurrentCheatCategory();
|
||||||
_viewModel->Back();
|
if (_viewModel->NavigateUp() &&
|
||||||
if (oldCategory != _viewModel->GetCurrentCheatCategory())
|
oldCategory != _viewModel->GetCurrentCheatCategory())
|
||||||
{
|
{
|
||||||
UpdateCheatList();
|
UpdateCheatList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class MaterialColorScheme;
|
|||||||
class IFontRepository;
|
class IFontRepository;
|
||||||
class IVramManager;
|
class IVramManager;
|
||||||
|
|
||||||
|
/// @brief Bottom sheet for browsing and enabling/disabling cheats.
|
||||||
class CheatsBottomSheetView : public BottomSheetView
|
class CheatsBottomSheetView : public BottomSheetView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -40,7 +41,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::unique_ptr<CheatsViewModel> _viewModel;
|
std::unique_ptr<CheatsViewModel> _viewModel;
|
||||||
Label2DView _titleLabel;
|
Label2DView _titleLabel;
|
||||||
Label2DView _noCheatsFoundLabel;
|
Label2DView _secondaryLabel;
|
||||||
Label2DView _descriptionLabel;
|
Label2DView _descriptionLabel;
|
||||||
std::unique_ptr<RecyclerView> _cheatListRecycler;
|
std::unique_ptr<RecyclerView> _cheatListRecycler;
|
||||||
CheatsAdapter* _cheatsAdapter = nullptr;
|
CheatsAdapter* _cheatsAdapter = nullptr;
|
||||||
|
|||||||
15
docs/Cheats.md
Normal file
15
docs/Cheats.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Cheats
|
||||||
|
Pico Launcher supports cheats from a `usrcheat.dat` file placed at `/_pico/usrcheat.dat`. The file stores the cheat codes, as well as which cheats are enabled. When a game is started which has cheats enabled, the enabled cheats are passed to Pico Loader.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
To display the available cheats highlight a game in the rom browser and press Y to access the cheats panel.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Controls
|
||||||
|
- DPAD up/down: Scroll through the list of cheats.
|
||||||
|
- L and R: Scroll quickly when there are many cheats.
|
||||||
|
- A: Toggle a cheat on/off, or go into a cheat category.
|
||||||
|
- B: Go up in the cheat hierarchy, or close the cheats panel when at the root.
|
||||||
|
- Y: Close the cheats panel.
|
||||||
|
- X: Disable all cheats.
|
||||||
@@ -12,6 +12,7 @@ From here you can browse your SD card to launch homebrew and games.
|
|||||||
- A: Open a folder, or to launch a homebrew or game.
|
- A: Open a folder, or to launch a homebrew or game.
|
||||||
- B: Go to the parent folder or close a menu.
|
- B: Go to the parent folder or close a menu.
|
||||||
- L and R: Scroll quickly when there are many items in a folder.
|
- L and R: Scroll quickly when there are many items in a folder.
|
||||||
|
- Y: Open the cheats panel (see [Cheats](Cheats.md)).
|
||||||
|
|
||||||
The back arrow on the top left of the bottom screen can also be used to go up to the parent folder.
|
The back arrow on the top left of the bottom screen can also be used to go up to the parent folder.
|
||||||
|
|
||||||
|
|||||||
BIN
docs/images/Cheats.png
Normal file
BIN
docs/images/Cheats.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
Reference in New Issue
Block a user