project64/Source/Project64-core/N64System/Enhancement/Enhancement.cpp

466 lines
12 KiB
C++

#include "stdafx.h"
#include <Project64-core/N64System/Enhancement/Enhancement.h>
#include <Project64-core/N64System/N64System.h>
#include <Project64-core/N64System/SystemGlobals.h>
#include <Project64-core/Settings/SettingType/SettingsType-GameSetting.h>
const char * CEnhancement::CheatIdent = "Cheat";
const char * CEnhancement::EnhancementIdent = "Enhancement";
#pragma warning(disable : 4996)
static std::string GenerateKeyName(const char * Name, const char * Ident, const char * PostIdent)
{
stdstr KeyName(Name);
KeyName.Replace('\\', '_');
KeyName.Replace(' ', '_');
if (KeyName.empty())
{
return "";
}
return stdstr_f("%s_%s_%s", Ident, KeyName.c_str(), PostIdent);
}
class CSettingEnhancementActive :
public CSettingTypeGame
{
public:
CSettingEnhancementActive(const char * Name, const char * Ident, bool Default) :
CSettingTypeGame("", false),
m_Default(Default)
{
m_KeyNameIdex = GenerateKeyName(Name, Ident, "Active");
}
bool Active()
{
if (m_KeyNameIdex.empty())
{
return false;
}
bool Active = false;
if (Load(0, Active))
{
return Active;
}
return m_Default;
}
void SetActive(bool Active)
{
if (m_KeyNameIdex.empty())
{
return;
}
m_SettingsIniFile->SaveNumber(SectionName(), m_KeyNameIdex.c_str(), Active ? 1 : 0);
Flush();
}
void Delete()
{
if (m_KeyNameIdex.empty())
{
return;
}
CSettingTypeApplication::Delete(0);
Flush();
}
private:
bool m_Default;
};
class CSettingEnhancementSelectedOption :
public CSettingTypeGame
{
public:
CSettingEnhancementSelectedOption(const char * Name, const char * Ident) :
CSettingTypeGame("", false)
{
m_KeyNameIdex = GenerateKeyName(Name, Ident, "Option");
}
void SetOption(uint16_t Value)
{
if (m_KeyNameIdex.empty())
{
return;
}
Save(0, (uint32_t)Value);
Flush();
}
bool SelectedValue(uint16_t & Value)
{
uint32_t StoredValue = 0;
if (!Load(0, StoredValue))
{
return false;
}
Value = (uint16_t)(StoredValue & 0xFFFF);
return true;
}
void Delete()
{
if (m_KeyNameIdex.empty())
{
return;
}
CSettingTypeGame::Delete(0);
Flush();
}
};
CEnhancement::CEnhancement(const char * Ident) :
m_Ident(Ident),
m_CodeOptionSize(0),
m_SelectedOption(0xFFFF0000),
m_OnByDefault(false),
m_Active(false),
m_OverClock(false),
m_OverClockModifier(1),
m_Valid(false)
{
}
CEnhancement::CEnhancement(const char * Ident, const char * Entry) :
m_Ident(Ident),
m_CodeOptionSize(0),
m_SelectedOption(0xFFFF0000),
m_OnByDefault(false),
m_Active(false),
m_OverClock(false),
m_OverClockModifier(1),
m_Valid(false)
{
stdstr EntryLine(Entry);
EntryLine.Replace("\r", "");
strvector Lines = EntryLine.Tokenize('\n');
if (Lines.size() == 0 || Lines[0].length() < 2 || Lines[0][0] != '$')
{
return;
}
uint32_t CurrentLine = 1;
m_Name = &(Lines[0][CurrentLine]);
m_NameAndExtension = m_Name;
// Key=value
while (CurrentLine < Lines.size())
{
const char * Pos = strchr(Lines[CurrentLine].c_str(), '=');
if (Pos == nullptr)
{
break;
}
uint32_t Line = CurrentLine;
CurrentLine += 1;
std::string Key = Lines[Line].c_str();
size_t Seperator = Pos - Lines[Line].c_str();
if (Seperator >= Key.size())
{
g_Notify->BreakPoint(__FILE__, __LINE__);
}
Key.resize(Seperator);
if (stricmp(Key.c_str(), "PluginList") == 0 || stricmp(Key.c_str(), "Plugin List") == 0)
{
strvector Plugins = stdstr(&Pos[1]).Tokenize(",");
for (size_t i = 0, n = Plugins.size(); i < n; i++)
{
m_PluginList.push_back(Plugins[i]);
}
}
else if (stricmp(Key.c_str(), "Author") == 0)
{
m_Author = &Pos[1];
}
else if (stricmp(Key.c_str(), "Note") == 0)
{
m_Note = &Pos[1];
}
else if (stricmp(Key.c_str(), "OnByDefault") == 0 || stricmp(Key.c_str(), "On By Default") == 0)
{
m_OnByDefault = Pos[1] == '1';
}
else if (stricmp(Key.c_str(), "Overclock") == 0)
{
SetOverClock(true, atoi(&Pos[1]));
}
else
{
g_Notify->BreakPoint(__FILE__, __LINE__);
}
}
// Gameshark code
while (CurrentLine < Lines.size())
{
char TempFormat[128] = { 0 };
const char * Line = Lines[CurrentLine].c_str();
size_t LineLen = strlen(Line);
if (LineLen >= (sizeof(TempFormat) / sizeof(TempFormat[0])))
{
break;
}
for (size_t i = 0, n = LineLen; i < n; i++)
{
if (isxdigit(Line[i]))
{
TempFormat[i] = 'X';
}
else if (Line[i] == ' ' || Line[i] == '?' || Line[i] == ':')
{
TempFormat[i] = Line[i];
}
else
{
TempFormat[i] = '#';
}
}
if (strcmp(TempFormat, "XXXXXXXX XXXX") != 0 &&
strcmp(TempFormat, "XXXXXXXX XX??") != 0 &&
strcmp(TempFormat, "XXXXXXXX ??XX") != 0 &&
strcmp(TempFormat, "XXXXXXXX ????") != 0 &&
strcmp(TempFormat, "XXXXXXXX XXXX:XXXX") != 0)
{
break;
}
CurrentLine += 1;
CodeEntry GSEntry;
GSEntry.Command = strtoul(Line, 0, 16);
GSEntry.Value = &Line[9];
m_Entries.push_back(GSEntry);
}
// Options
uint32_t OptionSize = 0;
while (CurrentLine < Lines.size())
{
const char * Line = Lines[CurrentLine].c_str();
size_t LineLen = strlen(Line);
if (((OptionSize != 0 && OptionSize != 2) || LineLen < 4 || Line[2] != ' ') &&
((OptionSize != 0 && OptionSize != 4) || LineLen < 6 || Line[4] != ' '))
{
break;
}
CurrentLine += 1;
if (OptionSize == 0)
{
OptionSize = Line[2] == ' ' ? 2 : 4;
}
CodeOption Option;
Option.Value = (uint16_t)strtoul(Line, 0, 16);
Option.Name = &Line[OptionSize + 1];
m_Options.push_back(Option);
}
if (CurrentLine < Lines.size())
{
g_Notify->BreakPoint(__FILE__, __LINE__);
}
m_Active = CSettingEnhancementActive(m_Name.c_str(), m_Ident.c_str(), m_OnByDefault).Active();
uint16_t SelectedValue = 0;
if (CSettingEnhancementSelectedOption(m_Name.c_str(), m_Ident.c_str()).SelectedValue(SelectedValue))
{
m_SelectedOption = SelectedValue;
}
CheckValid();
}
void CEnhancement::SetName(const char * Name)
{
std::string NewName = stdstr(Name != nullptr ? Name : "").Trim("\t ,");
if (NewName == m_Name)
{
return;
}
CSettingEnhancementActive(m_Name.c_str(), m_Ident.c_str(), m_OnByDefault).Delete();
CSettingEnhancementSelectedOption(m_Name.c_str(), m_Ident.c_str()).Delete();
m_Name = stdstr(Name != nullptr ? Name : "").Trim("\t ,");
m_NameAndExtension = m_Name;
if (m_Active != m_OnByDefault)
{
CSettingEnhancementActive(m_Name.c_str(), m_Ident.c_str(), m_OnByDefault).SetActive(m_OnByDefault);
}
if (OptionSelected())
{
CSettingEnhancementSelectedOption(m_Name.c_str(), m_Ident.c_str()).SetOption(SelectedOption());
}
CheckValid();
}
void CEnhancement::SetAuthor(const char * Author)
{
m_Author = Author != nullptr ? Author : "";
}
void CEnhancement::SetNote(const char * Note)
{
m_Note = Note != nullptr ? Note : "";
}
void CEnhancement::SetEntries(const CodeEntries & Entries)
{
m_Entries = Entries;
CheckValid();
}
void CEnhancement::SetPluginList(const PluginList & List)
{
m_PluginList = List;
}
void CEnhancement::SetOptions(const CodeOptions & Options)
{
m_Options = Options;
CheckValid();
}
void CEnhancement::SetSelectedOption(uint16_t Value)
{
if (m_Name.empty())
{
return;
}
m_SelectedOption = Value;
CheckValid();
CSettingEnhancementSelectedOption(m_Name.c_str(), m_Ident.c_str()).SetOption(Value);
}
void CEnhancement::SetActive(bool Active)
{
if (m_Name.empty())
{
return;
}
m_Active = Active;
CSettingEnhancementActive(m_Name.c_str(), m_Ident.c_str(), m_OnByDefault).SetActive(m_Active);
}
void CEnhancement::SetOnByDefault(bool OnByDefault)
{
m_OnByDefault = OnByDefault;
m_Active = CSettingEnhancementActive(m_Name.c_str(), m_Ident.c_str(), m_OnByDefault).Active();
}
void CEnhancement::SetOverClock(bool OverClock, uint32_t OverClockModifier)
{
m_OverClock = OverClock;
m_OverClockModifier = OverClockModifier;
if (m_OverClockModifier < 1)
{
m_OverClockModifier = 1;
}
if (m_OverClockModifier > 20)
{
m_OverClockModifier = 20;
}
}
void CEnhancement::CheckValid(void)
{
m_Valid = false;
m_OptionValue = "";
m_CodeOptionSize = 0;
if (m_Name.empty())
{
return;
}
std::string OptionValue;
uint32_t CodeOptionSize = 0;
for (CodeEntries::const_iterator itr = m_Entries.begin(); itr != m_Entries.end(); itr++)
{
switch (itr->Command & 0xFF000000)
{
case 0x80000000:
case 0x81000000:
case 0x88000000:
case 0x89000000:
case 0xA0000000:
case 0xA1000000:
case 0xD0000000:
case 0xD1000000:
case 0xD2000000:
case 0xD3000000:
if (strchr(itr->Value.c_str(), '?') != nullptr)
{
if (strncmp(itr->Value.c_str(), "????", 4) == 0)
{
if (!OptionValue.empty() && OptionValue != "????")
{
return;
}
OptionValue = "????";
CodeOptionSize = 4;
}
else if (itr->Value.length() == 4 && strncmp(&itr->Value.c_str()[2], "??", 2) == 0)
{
if (!OptionValue.empty() && OptionValue != "XX??")
{
return;
}
OptionValue = "XX??";
CodeOptionSize = 2;
}
else if (itr->Value.length() == 4 && strncmp(&itr->Value.c_str()[0], "??", 2) == 0)
{
if (!OptionValue.empty() && OptionValue != "??XX")
{
return;
}
OptionValue = "??XX";
CodeOptionSize = 2;
}
else
{
return;
}
}
break;
case 0x50000000:
if (strchr(itr->Value.c_str(), '?') != nullptr)
{
return;
}
break;
default:
return;
}
}
if (m_Options.size() > 0 && OptionValue.empty())
{
return;
}
m_OptionValue = OptionValue;
m_CodeOptionSize = CodeOptionSize;
m_Valid = true;
if (m_CodeOptionSize != 0)
{
std::string CheatValue = "??? - Not Set";
if (OptionSelected())
{
bool found = false;
for (size_t i = 0, n = m_Options.size(); i < n; i++)
{
if (m_Options[i].Value != SelectedOption())
{
continue;
}
CheatValue = stdstr_f("$%02X %s", m_Options[i].Value, m_Options[i].Name.c_str());
found = true;
break;
}
if (!found)
{
m_SelectedOption = 0xFFFF0000;
}
}
m_NameAndExtension = stdstr_f("%s (=>%s)", m_Name.c_str(), CheatValue.c_str());
}
}