Mesen-S/Core/CheatManager.cpp

141 lines
3.3 KiB
C++

#include "stdafx.h"
#include "CheatManager.h"
#include "MessageManager.h"
#include "Console.h"
#include "NotificationManager.h"
#include "../Utilities/HexUtilities.h"
CheatManager::CheatManager(Console* console)
{
_console = console;
}
void CheatManager::AddCheat(CheatCode code)
{
_cheats.push_back(code);
_cheatsByAddress.emplace(code.Address, code);
_hasCheats = true;
_bankHasCheats[code.Address >> 16] = true;
if(code.Address >= 0x7E0000 && code.Address < 0x7E2000) {
//Mirror codes for the first 2kb of workram across all workram mirrors
CheatCode mirror;
mirror.Value = code.Value;
for(int i = 0; i < 0x3F; i++) {
mirror.Address = (i << 16) | (code.Address & 0xFFFF);
AddCheat(mirror);
mirror.Address |= 0x800000;
AddCheat(mirror);
}
}
}
void CheatManager::SetCheats(vector<CheatCode> codes)
{
auto lock = _console->AcquireLock();
bool hasCheats = !_cheats.empty();
ClearCheats(false);
for(CheatCode &code : codes) {
AddCheat(code);
}
if(codes.size() > 1) {
MessageManager::DisplayMessage("Cheats", "CheatsApplied", std::to_string(codes.size()));
} else if(codes.size() == 1) {
MessageManager::DisplayMessage("Cheats", "CheatApplied");
} else if(hasCheats) {
MessageManager::DisplayMessage("Cheats", "CheatsDisabled");
}
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CheatsChanged);
}
void CheatManager::SetCheats(uint32_t codes[], uint32_t length)
{
vector<CheatCode> cheats;
cheats.reserve(length);
for(uint32_t i = 0; i < length; i++) {
CheatCode code;
code.Address = codes[i] >> 8;
code.Value = codes[i] & 0xFF;
cheats.push_back(code);
}
SetCheats(cheats);
}
void CheatManager::ClearCheats(bool showMessage)
{
auto lock = _console->AcquireLock();
bool hadCheats = !_cheats.empty();
_cheats.clear();
_cheatsByAddress.clear();
_hasCheats = false;
memset(_bankHasCheats, 0, sizeof(_bankHasCheats));
if(showMessage && hadCheats) {
MessageManager::DisplayMessage("Cheats", "CheatsDisabled");
//Used by net play
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CheatsChanged);
}
}
void CheatManager::AddStringCheat(string code)
{
static string _convertTable = "DF4709156BC8A23E";
auto lock = _console->AcquireLock();
std::transform(code.begin(), code.end(), code.begin(), ::toupper);
if(code.size() == 9 && code[4] == '-') {
uint32_t rawValue = 0;
for(int i = 0; i < (int)code.size(); i++) {
if(code[i] != '-') {
rawValue <<= 4;
size_t pos = _convertTable.find_first_of(code[i]);
if(pos == string::npos) {
//Invalid code
return;
}
rawValue |= (uint32_t)pos;
}
}
CheatCode cheat;
cheat.Address = (
((rawValue & 0x3C00) << 10) |
((rawValue & 0x3C) << 14) |
((rawValue & 0xF00000) >> 8) |
((rawValue & 0x03) << 10) |
((rawValue & 0xC000) >> 6) |
((rawValue & 0xF0000) >> 12) |
((rawValue & 0x3C0) >> 6)
);
cheat.Value = rawValue >> 24;
AddCheat(cheat);
} else if(code.size() == 8) {
for(int i = 0; i < (int)code.size(); i++) {
if((code[i] < 'A' || code[i] > 'F') && (code[i] < '0' || code[i] > '9')) {
//Invalid code
return;
}
}
uint32_t rawValue = HexUtilities::FromHex(code);
CheatCode cheat;
cheat.Address = rawValue >> 8;
cheat.Value = rawValue & 0xFF;
AddCheat(cheat);
}
}
vector<CheatCode> CheatManager::GetCheats()
{
return _cheats;
}