cheats: don't update the cheat list when adding one fails
The operation should fail or succeed completely. Issue #871
This commit is contained in:
parent
13428ba696
commit
8aadf5b097
358
core/cheats.cpp
358
core/cheats.cpp
|
@ -623,200 +623,206 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||||
Cheat conditionCheat;
|
Cheat conditionCheat;
|
||||||
unsigned conditionLimit = 0;
|
unsigned conditionLimit = 0;
|
||||||
|
|
||||||
for (unsigned i = 0; i < codes.size(); i++)
|
const size_t prevSize = cheats.size();
|
||||||
{
|
try {
|
||||||
if (i < conditionLimit)
|
for (unsigned i = 0; i < codes.size(); i++)
|
||||||
cheats.push_back(conditionCheat);
|
|
||||||
Cheat cheat{};
|
|
||||||
cheat.description = name;
|
|
||||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
|
||||||
switch (code)
|
|
||||||
{
|
{
|
||||||
case 0:
|
if (i < conditionLimit)
|
||||||
case 1:
|
cheats.push_back(conditionCheat);
|
||||||
case 2:
|
Cheat cheat{};
|
||||||
|
cheat.description = name;
|
||||||
|
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||||
|
switch (code)
|
||||||
{
|
{
|
||||||
// 8/16/32-bit write
|
case 0:
|
||||||
if (i + 1 >= codes.size())
|
case 1:
|
||||||
throw FlycastException("Missing value");
|
case 2:
|
||||||
cheat.type = Cheat::Type::setValue;
|
|
||||||
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
|
|
||||||
cheat.address = codes[i] & 0x00ffffff;
|
|
||||||
cheat.value = codes[++i];
|
|
||||||
cheats.push_back(cheat);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
|
|
||||||
switch (subcode)
|
|
||||||
{
|
{
|
||||||
case 0:
|
// 8/16/32-bit write
|
||||||
|
if (i + 1 >= codes.size())
|
||||||
|
throw FlycastException("Missing value");
|
||||||
|
cheat.type = Cheat::Type::setValue;
|
||||||
|
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
|
||||||
|
cheat.address = codes[i] & 0x00ffffff;
|
||||||
|
cheat.value = codes[++i];
|
||||||
|
cheats.push_back(cheat);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
|
||||||
|
switch (subcode)
|
||||||
{
|
{
|
||||||
// Group write
|
case 0:
|
||||||
int count = codes[i] & 0xffff;
|
|
||||||
if (i + count + 1 >= codes.size())
|
|
||||||
throw FlycastException("Missing values");
|
|
||||||
cheat.type = Cheat::Type::setValue;
|
|
||||||
cheat.size = 32;
|
|
||||||
cheat.address = codes[++i] & 0x00ffffff;
|
|
||||||
for (int j = 0; j < count; j++)
|
|
||||||
{
|
{
|
||||||
if (j == 1)
|
// Group write
|
||||||
cheat.description += " (cont'd)";
|
int count = codes[i] & 0xffff;
|
||||||
|
if (i + count + 1 >= codes.size())
|
||||||
|
throw FlycastException("Missing values");
|
||||||
|
cheat.type = Cheat::Type::setValue;
|
||||||
|
cheat.size = 32;
|
||||||
|
cheat.address = codes[++i] & 0x00ffffff;
|
||||||
|
for (int j = 0; j < count; j++)
|
||||||
|
{
|
||||||
|
if (j == 1)
|
||||||
|
cheat.description += " (cont'd)";
|
||||||
|
cheat.value = codes[++i];
|
||||||
|
cheats.push_back(cheat);
|
||||||
|
cheat.address += 4;
|
||||||
|
if (j < count - 1 && i < conditionLimit)
|
||||||
|
cheats.push_back(conditionCheat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
// 8-bit inc/decrement
|
||||||
|
if (i + 1 >= codes.size())
|
||||||
|
throw FlycastException("Missing value");
|
||||||
|
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||||
|
cheat.size = 8;
|
||||||
|
cheat.value = codes[i] & 0xff;
|
||||||
|
cheat.address = codes[++i] & 0x00ffffff;
|
||||||
|
cheats.push_back(cheat);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
// 16-bit inc/decrement
|
||||||
|
if (i + 1 >= codes.size())
|
||||||
|
throw FlycastException("Missing value");
|
||||||
|
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||||
|
cheat.size = 16;
|
||||||
|
cheat.value = codes[i] & 0xffff;
|
||||||
|
cheat.address = codes[++i] & 0x00ffffff;
|
||||||
|
cheats.push_back(cheat);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
{
|
||||||
|
// 32-bit inc/decrement
|
||||||
|
if (i + 2 >= codes.size())
|
||||||
|
throw FlycastException("Missing address or value");
|
||||||
|
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||||
|
cheat.size = 32;
|
||||||
|
cheat.address = codes[++i] & 0x00ffffff;
|
||||||
cheat.value = codes[++i];
|
cheat.value = codes[++i];
|
||||||
cheats.push_back(cheat);
|
cheats.push_back(cheat);
|
||||||
cheat.address += 4;
|
|
||||||
if (j < count - 1 && i < conditionLimit)
|
|
||||||
cheats.push_back(conditionCheat);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw FlycastException("Unsupported cheat type");
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
// 8-bit inc/decrement
|
|
||||||
if (i + 1 >= codes.size())
|
|
||||||
throw FlycastException("Missing value");
|
|
||||||
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
|
|
||||||
cheat.size = 8;
|
|
||||||
cheat.value = codes[i] & 0xff;
|
|
||||||
cheat.address = codes[++i] & 0x00ffffff;
|
|
||||||
cheats.push_back(cheat);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
// 16-bit inc/decrement
|
|
||||||
if (i + 1 >= codes.size())
|
|
||||||
throw FlycastException("Missing value");
|
|
||||||
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
|
|
||||||
cheat.size = 16;
|
|
||||||
cheat.value = codes[i] & 0xffff;
|
|
||||||
cheat.address = codes[++i] & 0x00ffffff;
|
|
||||||
cheats.push_back(cheat);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
{
|
|
||||||
// 32-bit inc/decrement
|
|
||||||
if (i + 2 >= codes.size())
|
|
||||||
throw FlycastException("Missing address or value");
|
|
||||||
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
|
|
||||||
cheat.size = 32;
|
|
||||||
cheat.address = codes[++i] & 0x00ffffff;
|
|
||||||
cheat.value = codes[++i];
|
|
||||||
cheats.push_back(cheat);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw FlycastException("Unsupported cheat type");
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case 4:
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
// 32-bit repeat write
|
|
||||||
if (i + 2 >= codes.size())
|
|
||||||
throw FlycastException("Missing count or value");
|
|
||||||
cheat.type = Cheat::Type::setValue;
|
|
||||||
cheat.size = 32;
|
|
||||||
cheat.address = codes[i] & 0x00ffffff;
|
|
||||||
cheat.repeatCount = codes[++i] >> 16;
|
|
||||||
cheat.repeatAddressIncrement = codes[i] & 0xffff;
|
|
||||||
cheat.value = codes[++i];
|
|
||||||
cheats.push_back(cheat);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
{
|
|
||||||
// copy bytes
|
|
||||||
if (i + 2 >= codes.size())
|
|
||||||
throw FlycastException("Missing count or destination address");
|
|
||||||
cheat.type = Cheat::Type::copy;
|
|
||||||
cheat.size = 8;
|
|
||||||
cheat.address = codes[i] & 0x00ffffff;
|
|
||||||
cheat.destAddress = codes[++i] & 0x00ffffff;
|
|
||||||
cheat.repeatCount = codes[++i];
|
|
||||||
cheats.push_back(cheat);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// TODO 7 change decryption type
|
|
||||||
// TODO 0xb delay applying codes
|
|
||||||
// TODO 0xc global enable test
|
|
||||||
case 0xd:
|
|
||||||
{
|
|
||||||
// enable next code if eq/neq/lt/gt
|
|
||||||
if (i + 1 >= codes.size())
|
|
||||||
throw FlycastException("Missing count or destination address");
|
|
||||||
cheat.size = 16;
|
|
||||||
cheat.address = codes[i] & 0x00ffffff;
|
|
||||||
switch (codes[++i] >> 16)
|
|
||||||
{
|
{
|
||||||
case 0:
|
// 32-bit repeat write
|
||||||
cheat.type = Cheat::Type::runNextIfEq;
|
if (i + 2 >= codes.size())
|
||||||
break;
|
throw FlycastException("Missing count or value");
|
||||||
case 1:
|
cheat.type = Cheat::Type::setValue;
|
||||||
cheat.type = Cheat::Type::runNextIfNeq;
|
cheat.size = 32;
|
||||||
break;
|
cheat.address = codes[i] & 0x00ffffff;
|
||||||
case 2:
|
cheat.repeatCount = codes[++i] >> 16;
|
||||||
cheat.type = Cheat::Type::runNextIfLt;
|
cheat.repeatAddressIncrement = codes[i] & 0xffff;
|
||||||
break;
|
cheat.value = codes[++i];
|
||||||
case 3:
|
cheats.push_back(cheat);
|
||||||
cheat.type = Cheat::Type::runNextIfGt;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw FlycastException("Unsupported conditional code");
|
|
||||||
}
|
}
|
||||||
cheat.value = codes[i] & 0xffff;
|
break;
|
||||||
cheats.push_back(cheat);
|
case 5:
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0xe:
|
|
||||||
{
|
|
||||||
// multiline enable codes if eq/neq/lt/gt
|
|
||||||
if (i + 1 >= codes.size())
|
|
||||||
throw FlycastException("Missing test address");
|
|
||||||
cheat.size = 16;
|
|
||||||
cheat.value = codes[i] & 0xffff;
|
|
||||||
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
|
|
||||||
switch (codes[++i] >> 24)
|
|
||||||
{
|
{
|
||||||
case 0:
|
// copy bytes
|
||||||
cheat.type = Cheat::Type::runNextIfEq;
|
if (i + 2 >= codes.size())
|
||||||
break;
|
throw FlycastException("Missing count or destination address");
|
||||||
case 1:
|
cheat.type = Cheat::Type::copy;
|
||||||
cheat.type = Cheat::Type::runNextIfNeq;
|
cheat.size = 8;
|
||||||
break;
|
cheat.address = codes[i] & 0x00ffffff;
|
||||||
case 2:
|
cheat.destAddress = codes[++i] & 0x00ffffff;
|
||||||
cheat.type = Cheat::Type::runNextIfLt;
|
cheat.repeatCount = codes[++i];
|
||||||
break;
|
cheats.push_back(cheat);
|
||||||
case 3:
|
|
||||||
cheat.type = Cheat::Type::runNextIfGt;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw FlycastException("Unsupported conditional code");
|
|
||||||
}
|
}
|
||||||
cheat.address = codes[i] & 0x00ffffff;
|
break;
|
||||||
conditionCheat = cheat;
|
// TODO 7 change decryption type
|
||||||
|
// TODO 0xb delay applying codes
|
||||||
|
// TODO 0xc global enable test
|
||||||
|
case 0xd:
|
||||||
|
{
|
||||||
|
// enable next code if eq/neq/lt/gt
|
||||||
|
if (i + 1 >= codes.size())
|
||||||
|
throw FlycastException("Missing count or destination address");
|
||||||
|
cheat.size = 16;
|
||||||
|
cheat.address = codes[i] & 0x00ffffff;
|
||||||
|
switch (codes[++i] >> 16)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
cheat.type = Cheat::Type::runNextIfEq;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cheat.type = Cheat::Type::runNextIfNeq;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cheat.type = Cheat::Type::runNextIfLt;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
cheat.type = Cheat::Type::runNextIfGt;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw FlycastException("Unsupported conditional code");
|
||||||
|
}
|
||||||
|
cheat.value = codes[i] & 0xffff;
|
||||||
|
cheats.push_back(cheat);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xe:
|
||||||
|
{
|
||||||
|
// multiline enable codes if eq/neq/lt/gt
|
||||||
|
if (i + 1 >= codes.size())
|
||||||
|
throw FlycastException("Missing test address");
|
||||||
|
cheat.size = 16;
|
||||||
|
cheat.value = codes[i] & 0xffff;
|
||||||
|
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
|
||||||
|
switch (codes[++i] >> 24)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
cheat.type = Cheat::Type::runNextIfEq;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cheat.type = Cheat::Type::runNextIfNeq;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cheat.type = Cheat::Type::runNextIfLt;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
cheat.type = Cheat::Type::runNextIfGt;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw FlycastException("Unsupported conditional code");
|
||||||
|
}
|
||||||
|
cheat.address = codes[i] & 0x00ffffff;
|
||||||
|
conditionCheat = cheat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw FlycastException("Unsupported cheat type");
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw FlycastException("Unsupported cheat type");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
setActive(!cheats.empty());
|
|
||||||
#ifndef LIBRETRO
|
#ifndef LIBRETRO
|
||||||
std::string path = cfgLoadStr("cheats", gameId, "");
|
std::string path = cfgLoadStr("cheats", gameId, "");
|
||||||
if (path == "")
|
if (path == "")
|
||||||
{
|
{
|
||||||
path = get_game_save_prefix() + ".cht";
|
path = get_game_save_prefix() + ".cht";
|
||||||
cfgSaveStr("cheats", gameId, path);
|
cfgSaveStr("cheats", gameId, path);
|
||||||
}
|
}
|
||||||
saveCheatFile(path);
|
saveCheatFile(path);
|
||||||
#endif
|
#endif
|
||||||
|
setActive(!cheats.empty());
|
||||||
|
} catch (...) {
|
||||||
|
cheats.erase(cheats.begin() + prevSize, cheats.end());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatManager::saveCheatFile(const std::string& filename)
|
void CheatManager::saveCheatFile(const std::string& filename)
|
||||||
|
|
Loading…
Reference in New Issue