diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c deleted file mode 100755 index e1515c4b..00000000 --- a/sysmodules/rosalina/source/menus/cheats.c +++ /dev/null @@ -1,2145 +0,0 @@ -/* - * This file is part of Luma3DS - * Copyright (C) 2016-2021 Aurora Wright, TuxSH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Additional Terms 7.b and 7.c of GPLv3 apply to this file: - * * Requiring preservation of specified reasonable legal notices or - * author attributions in that material or in the Appropriate Legal - * Notices displayed by works containing it. - * * Prohibiting misrepresentation of the origin of that material, - * or requiring that modified versions of such material be marked in - * reasonable ways as different from the original version. - */ - -#include <3ds.h> -#include -#include "menus/cheats.h" -#include "memory.h" -#include "draw.h" -#include "menu.h" -#include "utils.h" -#include "fmt.h" -#include "ifile.h" -#include "pmdbgext.h" - -#define MAKE_QWORD(hi,low) \ - ((u64) ((((u64)(hi)) << 32) | (low))) - -typedef struct CheatDescription -{ - struct { - u8 active : 1; - u8 valid : 1; - u8 hasKeyCode : 1; - u8 activeStorage : 1; - }; - char name[39]; - u32 codesCount; - u32 storage1; - u32 storage2; - u64 codes[0]; -} CheatDescription; - -typedef struct BufferedFile -{ - IFile file; - u64 curPos; - u64 maxPos; - char buffer[512]; -} BufferedFile; - -CheatDescription* cheats[1024] = { 0 }; -u8 cheatBuffer[32768] = { 0 }; -u8 cheatPage[0x1000] = { 0 }; - -typedef struct CheatState -{ - u32 index; - u32 offset1; - u32 offset2; - u32 data1; - u32 data2; - struct { - u8 activeOffset : 1; - u8 activeData : 1; - u8 conditionalMode : 3; - u8 data1Mode : 1; - u8 data2Mode : 1; - u8 floatMode : 1; - }; - u8 typeELine; - u8 typeEIdx; - - s8 loopLine; - u32 loopCount; - - u32 ifStack; - u32 storedStack; - u8 ifCount; - u8 storedIfCount; - -} CheatState; - -CheatState cheat_state = { 0 }; -u8 cheatCount = 0; -u64 cheatTitleInfo = -1ULL; -u64 cheatRngState = 0; - -static inline u32* activeOffset() -{ - return cheat_state.activeOffset ? &cheat_state.offset2 : &cheat_state.offset1; -} - -static inline u32* activeData() -{ - return cheat_state.activeData ? &cheat_state.data2 : &cheat_state.data1; -} - -static inline u32* activeStorage(CheatDescription* desc) -{ - return desc->activeStorage ? &desc->storage2 : &desc->storage1; -} - -char failureReason[64]; - -static u32 Cheat_GetRandomNumber(void) -{ - cheatRngState = 0x5D588B656C078965ULL * cheatRngState + 0x0000000000269EC3ULL; - return (u32)(cheatRngState >> 32); -} - -static bool Cheat_IsValidAddress(const Handle processHandle, u32 address, u32 size) -{ - MemInfo info; - PageInfo out; - - Result res = svcQueryDebugProcessMemory(&info, &out, processHandle, address); - if (R_SUCCEEDED(res) && info.state != MEMSTATE_FREE && info.base_addr > 0 && info.base_addr <= address && address <= info.base_addr + info.size - size) { - return true; - } - return false; -} - -static u32 ReadWriteBuffer32 = 0; -static u16 ReadWriteBuffer16 = 0; -static u8 ReadWriteBuffer8 = 0; - -static bool Cheat_Write8(const Handle processHandle, u32 offset, u8 value) -{ - u32 addr = *activeOffset() + offset; - if (addr >= 0x01E81000 && addr < 0x01E82000) - { - cheatPage[addr - 0x01E81000] = value; - return true; - } - if (Cheat_IsValidAddress(processHandle, addr, 1)) - { - *((u8*) (&ReadWriteBuffer8)) = value; - return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer8, addr, 1)); - } - return false; -} - -static bool Cheat_Write16(const Handle processHandle, u32 offset, u16 value) -{ - u32 addr = *activeOffset() + offset; - if (addr >= 0x01E81000 && addr + 1 < 0x01E82000) - { - *(u16*)(cheatPage + addr - 0x01E81000) = value; - return true; - } - if (Cheat_IsValidAddress(processHandle, addr, 2)) - { - *((u16*) (&ReadWriteBuffer16)) = value; - return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer16, addr, 2)); - } - return false; -} - -static bool Cheat_Write32(const Handle processHandle, u32 offset, u32 value) -{ - u32 addr = *activeOffset() + offset; - if (addr >= 0x01E81000 && addr + 3 < 0x01E82000) - { - *(u32*)(cheatPage + addr - 0x01E81000) = value; - return true; - } - if (Cheat_IsValidAddress(processHandle, addr, 4)) - { - *((u32*) (&ReadWriteBuffer32)) = value; - return R_SUCCEEDED(svcWriteProcessMemory(processHandle, &ReadWriteBuffer32, addr, 4)); - } - return false; -} - -static bool Cheat_Read8(const Handle processHandle, u32 offset, u8* retValue) -{ - u32 addr = *activeOffset() + offset; - if (addr >= 0x01E81000 && addr < 0x01E82000) - { - *retValue = cheatPage[addr - 0x01E81000]; - return true; - } - if (Cheat_IsValidAddress(processHandle, addr, 1)) - { - Result res = svcReadProcessMemory(&ReadWriteBuffer8, processHandle, addr, 1); - *retValue = *((u8*) (&ReadWriteBuffer8)); - return R_SUCCEEDED(res); - } - return false; -} - -static bool Cheat_Read16(const Handle processHandle, u32 offset, u16* retValue) -{ - u32 addr = *activeOffset() + offset; - if (addr >= 0x01E81000 && addr + 1 < 0x01E82000) - { - *retValue = *(u16*)(cheatPage + addr - 0x01E81000); - return true; - } - if (Cheat_IsValidAddress(processHandle, addr, 2)) - { - Result res = svcReadProcessMemory(&ReadWriteBuffer16, processHandle, addr, 2); - *retValue = *((u16*) (&ReadWriteBuffer16)); - return R_SUCCEEDED(res); - } - return false; -} - -static bool Cheat_Read32(const Handle processHandle, u32 offset, u32* retValue) -{ - u32 addr = *activeOffset() + offset; - if (addr >= 0x01E81000 && addr + 3 < 0x01E82000) - { - *retValue = *(u32*)(cheatPage + addr - 0x01E81000); - return true; - } - if (Cheat_IsValidAddress(processHandle, addr, 4)) - { - Result res = svcReadProcessMemory(&ReadWriteBuffer32, processHandle, addr, 4); - *retValue = *((u32*) (&ReadWriteBuffer32)); - return R_SUCCEEDED(res); - } - return false; -} - -static u8 typeEMapping[] = { 4 << 3, 5 << 3, 6 << 3, 7 << 3, 0 << 3, 1 << 3, 2 << 3, 3 << 3 }; - -static u8 Cheat_GetNextTypeE(const CheatDescription* cheat) -{ - - if (cheat_state.typeEIdx == 7) - { - cheat_state.typeEIdx = 0; - cheat_state.typeELine++; - } - else - { - cheat_state.typeEIdx++; - } - return (u8) ((cheat->codes[cheat_state.typeELine] >> (typeEMapping[cheat_state.typeEIdx])) & 0xFF); -} - -static u32 Cheat_ApplyCheat(const Handle processHandle, CheatDescription* const cheat) -{ - cheat_state.index = 0; - cheat_state.offset1 = 0; - cheat_state.offset2 = 0; - cheat_state.data1 = 0; - cheat_state.data2 = 0; - cheat_state.activeOffset = 0; - cheat_state.activeData = 0; - cheat_state.conditionalMode = 0; - cheat_state.data1Mode = 0; - cheat_state.data2Mode = 0; - cheat_state.floatMode = 0; - cheat_state.loopCount = 0; - cheat_state.loopLine = -1; - cheat_state.ifStack = 0; - cheat_state.storedStack = 0; - cheat_state.ifCount = 0; - cheat_state.storedIfCount = 0; - - while (cheat_state.index < cheat->codesCount) - { - bool skipExecution = (cheat_state.ifStack & 0x00000001) != 0; - u32 arg0 = (u32) ((cheat->codes[cheat_state.index] >> 32) & 0x00000000FFFFFFFFULL); - u32 arg1 = (u32) ((cheat->codes[cheat_state.index]) & 0x00000000FFFFFFFFULL); - if (arg0 == 0 && arg1 == 0) - { - return 0; - } - u32 code = ((arg0 >> 28) & 0x0F); - u32 subcode = ((arg0 >> 24) & 0x0F); - u32 codeArg = arg0 & 0x0F; - - switch (code) - { - case 0x0: - // 0 Type - // Format: 0XXXXXXX YYYYYYYY - // Description: 32bit write of YYYYYYYY to 0XXXXXXX. - if (!skipExecution) - { - if (!Cheat_Write32(processHandle, (arg0 & 0x0FFFFFFF), arg1)) return 0; - } - break; - case 0x1: - // 1 Type - // Format: 1XXXXXXX 0000YYYY - // Description: 16bit write of YYYY to 0XXXXXXX. - if (!skipExecution) - { - if (!Cheat_Write16(processHandle, (arg0 & 0x0FFFFFFF), (u16) (arg1 & 0xFFFF))) return 0; - } - break; - case 0x2: - // 2 Type - // Format: 2XXXXXXX 000000YY - // Description: 8bit write of YY to 0XXXXXXX. - if (!skipExecution) - { - if (!Cheat_Write8(processHandle, (arg0 & 0x0FFFFFFF), (u8) (arg1 & 0xFF))) return 0; - } - break; - case 0x3: - // 3 Type - // Format: 3XXXXXXXX YYYYYYYY - // Description: 32bit if less than. - // Simple: If the value at address 0XXXXXXX is less than the value YYYYYYYY. - // Example: 323D6B28 10000000 - { - bool newSkip; - u32 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value < arg1); - break; - case 0x1: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value < *activeData()); - break; - case 0x2: - newSkip = !(*activeData() < arg1); - break; - case 0x3: - newSkip = !(*activeStorage(cheat) < arg1); - break; - case 0x4: - newSkip = !(*activeData() < *activeStorage(cheat)); - break; - default: - return 0; - } - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0x4: - // 4 Type - // Format: 4XXXXXXXX YYYYYYYY - // Description: 32bit if greater than. - // Simple: If the value at address 0XXXXXXX is greater than the value YYYYYYYY. - // Example: 423D6B28 10000000 - { - bool newSkip; - u32 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value > arg1); - break; - case 0x1: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value > *activeData()); - break; - case 0x2: - newSkip = !(*activeData() > arg1); - break; - case 0x3: - newSkip = !(*activeStorage(cheat) > arg1); - break; - case 0x4: - newSkip = !(*activeData() > *activeStorage(cheat)); - break; - default: - return 0; - } - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0x5: - // 5 Type - // Format: 5XXXXXXXX YYYYYYYY - // Description: 32bit if equal to. - // Simple: If the value at address 0XXXXXXX is equal to the value YYYYYYYY. - // Example: 523D6B28 10000000 - { - bool newSkip; - u32 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value == arg1); - break; - case 0x1: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value == *activeData()); - break; - case 0x2: - newSkip = !(*activeData() == arg1); - break; - case 0x3: - newSkip = !(*activeStorage(cheat) == arg1); - break; - case 0x4: - newSkip = !(*activeData() == *activeStorage(cheat)); - break; - default: - return 0; - } - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0x6: - // 6 Type - // Format: 3XXXXXXXX YYYYYYYY - // Description: 32bit if not equal to. - // Simple: If the value at address 0XXXXXXX is not equal to the value YYYYYYYY. - // Example: 623D6B28 10000000 - { - bool newSkip; - u32 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value != arg1); - break; - case 0x1: - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !(value != *activeData()); - break; - case 0x2: - newSkip = !(*activeData() != arg1); - break; - case 0x3: - newSkip = !(*activeStorage(cheat) != arg1); - break; - case 0x4: - newSkip = !(*activeData() != *activeStorage(cheat)); - break; - default: - return 0; - } - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0x7: - // 7 Type - // Format: 7XXXXXXXX 0000YYYY - // Description: 16bit if less than. - // Simple: If the value at address 0XXXXXXX is less than the value YYYY. - // Example: 723D6B28 00005400 - { - bool newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) < (arg1 & 0xFFFF)); - break; - case 0x1: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) < (*activeData() & (~mask))); - break; - case 0x2: - newSkip = !((*activeData() & (~mask)) < (arg1 & 0xFFFF)); - break; - case 0x3: - newSkip = !((*activeStorage(cheat) & (~mask)) < (arg1 & 0xFFFF)); - break; - case 0x4: - newSkip = !((*activeData() & (~mask)) < (*activeStorage(cheat) & (~mask))); - break; - default: - return 0; - } - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0x8: - // 8 Type - // Format: 8XXXXXXXX 0000YYYY - // Description: 16bit if greater than. - // Simple: If the value at address 0XXXXXXX is greater than the value YYYY. - // Example: 823D6B28 00005400 - { - bool newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) > (arg1 & 0xFFFF)); - break; - case 0x1: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) > (*activeData() & (~mask))); - break; - case 0x2: - newSkip = !((*activeData() & (~mask)) > (arg1 & 0xFFFF)); - break; - case 0x3: - newSkip = !((*activeStorage(cheat) & (~mask)) > (arg1 & 0xFFFF)); - break; - case 0x4: - newSkip = !((*activeData() & (~mask)) > (*activeStorage(cheat) & (~mask))); - break; - default: - return 0; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0x9: - // 9 Type - // Format: 9XXXXXXXX 0000YYYY - // Description: 16bit if equal to. - // Simple: If the value at address 0XXXXXXX is equal to the value YYYY. - // Example: 923D6B28 00005400 - { - bool newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) == (arg1 & 0xFFFF)); - break; - case 0x1: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) == (*activeData() & (~mask))); - break; - case 0x2: - newSkip = !((*activeData() & (~mask)) == (arg1 & 0xFFFF)); - break; - case 0x3: - newSkip = !((*activeStorage(cheat) & (~mask)) == (arg1 & 0xFFFF)); - break; - case 0x4: - newSkip = !((*activeData() & (~mask)) == (*activeStorage(cheat) & (~mask))); - break; - default: - return 0; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0xA: - // A Type - // Format: AXXXXXXXX 0000YYYY - // Description: 16bit if not equal to. - // Simple: If the value at address 0XXXXXXX is not equal to the value YYYY. - // Example: A23D6B28 00005400 - { - bool newSkip; - u16 mask = (u16) ((arg1 >> 16) & 0xFFFF); - u16 value = 0; - switch (cheat_state.conditionalMode) - { - case 0x0: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) != (arg1 & 0xFFFF)); - break; - case 0x1: - if (!Cheat_Read16(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - newSkip = !((value & (~mask)) != (*activeData() & (~mask))); - break; - case 0x2: - newSkip = !((*activeData() & (~mask)) != (arg1 & 0xFFFF)); - break; - case 0x3: - newSkip = !((*activeStorage(cheat) & (~mask)) != (arg1 & 0xFFFF)); - break; - case 0x4: - newSkip = !((*activeData() & (~mask)) != (*activeStorage(cheat) & (~mask))); - break; - default: - return 0; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - - case 0xB: - // B Type - // Format: BXXXXXXX 00000000 - // Description: Loads offset register with value at given XXXXXXX - if (!skipExecution) - { - u32 value; - if (!Cheat_Read32(processHandle, arg0 & 0x0FFFFFFF, &value)) return 0; - *activeOffset() = value; - } - break; - case 0xC: - // C Type - // Format: C0000000 ZZZZZZZZ - // Description: Repeat following lines at specified offset. - // Simple: used to write a value to an address, and then continues to write that value Z number of times to all addresses at an offset determined by the (D6, D7, D8, or DC) type following it. - // Note: used with the D6, D7, D8, and DC types. C types can not be nested. - // Example: - - // C0000000 00000005 - // 023D6B28 0009896C - // DC000000 00000010 - // D2000000 00000000 - switch (subcode) - { - case 0x00: - cheat_state.loopLine = cheat_state.index; - cheat_state.loopCount = arg1; - cheat_state.storedStack = cheat_state.ifStack; - cheat_state.storedIfCount = cheat_state.ifCount; - break; - case 0x01: - cheat_state.loopLine = cheat_state.index; - cheat_state.loopCount = cheat_state.data1; - cheat_state.storedStack = cheat_state.ifStack; - cheat_state.storedIfCount = cheat_state.ifCount; - break; - case 0x02: - cheat_state.loopLine = cheat_state.index; - cheat_state.loopCount = cheat_state.data2; - cheat_state.storedStack = cheat_state.ifStack; - cheat_state.storedIfCount = cheat_state.ifCount; - break; - } - break; - case 0xD: - switch (subcode) - { - case 0x00: - // D0 Type - // Format: D0000000 00000000 - // Description: ends most recent conditional. - // Simple: type 3 through A are all "conditionals," the conditional most recently executed before this line will be terminated by it. - // Example: - - // 94000130 FFFB0000 - // 74000100 FF00000C - // 023D6B28 0009896C - // D0000000 00000000 - - // The 7 type line would be terminated. - if (arg1 == 0) - { - if (cheat_state.loopLine != -1) - { - if (cheat_state.ifCount > 0 && cheat_state.ifCount > cheat_state.storedIfCount) - { - cheat_state.ifStack >>= 1; - cheat_state.ifCount--; - } - else - { - - if (cheat_state.loopCount > 0) - { - cheat_state.loopCount--; - if (cheat_state.loopCount == 0) - { - cheat_state.loopLine = -1; - } - else if (cheat_state.loopLine != -1) - { - cheat_state.index = cheat_state.loopLine; - } - } - } - } - else - { - if (cheat_state.ifCount > 0) - { - cheat_state.ifStack >>= 1; - cheat_state.ifCount--; - } - } - } - // D0000000 00000001 - // Loop break - else if (!skipExecution && arg1 == 1) - { - cheat_state.loopCount = 0; - cheat_state.loopLine = -1; - cheat_state.index++; - while (cheat_state.index < cheat->codesCount) - { - u64 code = cheat->codes[cheat_state.index++]; - if (code == 0xD100000000000000ull || code == 0xD200000000000000ull) - { - break; - } - } - } - break; - case 0x01: - // D1 Type - // Format: D1000000 00000000 - // Description: ends repeat block. - // Simple: will end all conditionals within a C type code, along with the C type itself. - // Example: - - // 94000130 FFFB0000 - // C0000000 00000010 - // 8453DA0C 00000200 - // 023D6B28 0009896C - // D6000000 00000005 - // D1000000 00000000 - - // The C line, 8 line, 0 line, and D6 line would be terminated. - if (cheat_state.loopCount > 0) - { - cheat_state.ifStack = cheat_state.storedStack; - cheat_state.ifCount = cheat_state.storedIfCount; - cheat_state.loopCount--; - if (cheat_state.loopCount == 0) - { - cheat_state.loopLine = -1; - } - else - { - if (cheat_state.loopLine != -1) - { - cheat_state.index = cheat_state.loopLine; - } - } - } - break; - case 0x02: - // D2 Type - // Format: D2000000 00000000 - // Description: ends all conditionals/repeats before it and sets offset and stored to zero. - // Simple: ends all lines. - // Example: - - // 94000130 FEEF0000 - // C0000000 00000010 - // 8453DA0C 00000200 - // 023D6B28 0009896C - // D6000000 00000005 - // D2000000 00000000 - - // All lines would terminate. - if (arg1 == 0) - { - if (cheat_state.loopCount > 0) - { - cheat_state.loopCount--; - if (cheat_state.loopCount == 0) - { - *activeData() = 0; - *activeOffset() = 0; - cheat_state.loopLine = -1; - - cheat_state.ifStack = 0; - cheat_state.ifCount = 0; - } - else - { - if (cheat_state.loopLine != -1) - { - cheat_state.index = cheat_state.loopLine; - } - } - } - else - { - *activeData() = 0; - *activeOffset() = 0; - cheat_state.ifStack = 0; - cheat_state.ifCount = 0; - } - } - // D2000000 00000001 - // Return - else if (!skipExecution && arg1 == 1) - { - cheat_state.index = cheat->codesCount; - } - break; - case 0x03: - // D3 Type - // Format: D3000000 XXXXXXXX - // Description: sets offset. - // Simple: loads the address X so that lines after can modify the value at address X. - // Note: used with the D4, D5, D6, D7, D8, and DC types. - // Example: D3000000 023D6B28 - if (!skipExecution) - { - if (codeArg == 0) - { - cheat_state.offset1 = arg1; - } - else if (codeArg == 1) - { - cheat_state.offset2 = arg1; - } - } - break; - case 0x04: - // D4 Type - // Format: D4000000 YYYYYYYY - // Description: adds to the stored address' value. - // Simple: adds to the value at the address defined by lines D3, D9, DA, and DB. - // Note: used with the D3, D9, DA, DB, DC types. - // Example: D4000000 00000025 - if (!skipExecution) - { - if (codeArg == 0) - { - *activeData() += arg1; - } - else if (codeArg == 1) - { - cheat_state.data1 += arg1 + cheat_state.data2; - } - else if (codeArg == 2) - { - cheat_state.data2 += arg1 + cheat_state.data1; - } - } - break; - case 0x05: - // D5 Type - // Format: D5000000 YYYYYYYY - // Description: sets the stored address' value. - // Simple: makes the value at the address defined by lines D3, D9, DA, and DB to YYYYYYYY. - // Note: used with the D3, D9, DA, DB, and DC types. - // Example: D5000000 34540099 - if (!skipExecution) - { - if (codeArg == 0) - { - *activeData() = arg1; - } - else if (codeArg == 1) - { - cheat_state.data1 = arg1; - } - else if (codeArg == 2) - { - cheat_state.data2 = arg1; - } - } - break; - case 0x06: - // D6 Type - // Format: D6000000 XXXXXXXX - // Description: 32bit store and increment by 4. - // Simple: stores the value at address XXXXXXXX and to addresses in increments of 4. - // Note: used with the C, D3, and D9 types. - // Example: D3000000 023D6B28 - if (!skipExecution) - { - if (codeArg == 0) - { - if (!Cheat_Write32(processHandle, arg1, *activeData())) return 0; - *activeOffset() += 4; - } - else if (codeArg == 1) - { - if (!Cheat_Write32(processHandle, arg1, cheat_state.data1)) return 0; - *activeOffset() += 4; - } - else if (codeArg == 2) - { - if (!Cheat_Write32(processHandle, arg1, cheat_state.data2)) return 0; - *activeOffset() += 4; - } - } - break; - case 0x07: - // D7 Type - // Format: D7000000 XXXXXXXX - // Description: 16bit store and increment by 2. - // Simple: stores 2 bytes of the value at address XXXXXXXX and to addresses in increments of 2. - // Note: used with the C, D3, and DA types. - // Example: D7000000 023D6B28 - if (!skipExecution) - { - if (codeArg == 0) - { - if (!Cheat_Write16(processHandle, arg1, (u16) (*activeData() & 0xFFFF))) return 0; - *activeOffset() += 2; - } - else if (codeArg == 1) - { - if (!Cheat_Write16(processHandle, arg1, (u16) (cheat_state.data1 & 0xFFFF))) return 0; - *activeOffset() += 2; - } - else if (codeArg == 2) - { - if (!Cheat_Write16(processHandle, arg1, (u16) (cheat_state.data2 & 0xFFFF))) return 0; - *activeOffset() += 2; - } - } - break; - case 0x08: - // D8 Type - // Format: D8000000 XXXXXXXX - // Description: 8bit store and increment by 1. - // Simple: stores 1 byte of the value at address XXXXXXXX and to addresses in increments of 1. - // Note: used with the C, D3, and DB types. - // Example: D8000000 023D6B28 - if (!skipExecution) - { - if (codeArg == 0) - { - if (!Cheat_Write8(processHandle, arg1, (u8) (*activeData() & 0xFF))) return 0; - *activeOffset() += 1; - } - else if (codeArg == 1) - { - if (!Cheat_Write8(processHandle, arg1, (u8) (cheat_state.data1 & 0xFF))) return 0; - *activeOffset() += 1; - } - else if (codeArg == 2) - { - if (!Cheat_Write8(processHandle, arg1, (u8) (cheat_state.data2 & 0xFF))) return 0; - *activeOffset() += 1; - } - } - break; - case 0x09: - // D9 Type - // Format: D9000000 XXXXXXXX - // Description: 32bit load. - // Simple: loads the value from address X. - // Note: used with the D5 and D6 types. - // Example: D9000000 023D6B28 - if (!skipExecution) - { - if (codeArg == 0) - { - u32 value = 0; - if (!Cheat_Read32(processHandle, arg1, &value)) return 0; - *activeData() = value; - } - else if (codeArg == 1) - { - u32 value = 0; - if (!Cheat_Read32(processHandle, arg1, &value)) return 0; - cheat_state.data1 = value; - } - else if (codeArg == 2) - { - u32 value = 0; - if (!Cheat_Read32(processHandle, arg1, &value)) return 0; - cheat_state.data2 = value; - } - } - break; - case 0x0A: - // DA Type - // Format: DA000000 XXXXXXXX - // Description: 16bit load. - // Simple: loads 2 bytes from address X. - // Note: used with the D5 and D7 types. - // Example: DA000000 023D6B28 - if (!skipExecution) - { - if (codeArg == 0) - { - u16 value = 0; - if (!Cheat_Read16(processHandle, arg1, &value)) return 0; - *activeData() = value; - } - else if (codeArg == 1) - { - u16 value = 0; - if (!Cheat_Read16(processHandle, arg1, &value)) return 0; - cheat_state.data1 = value; - } - else if (codeArg == 2) - { - u16 value = 0; - if (!Cheat_Read16(processHandle, arg1, &value)) return 0; - cheat_state.data2 = value; - } - } - break; - case 0x0B: - // DB Type - // Format: DB000000 XXXXXXXX - // Description: 8bit load. - // Simple: loads 1 byte from address X. - // Note: used with the D5 and D8 types. - // Example: DB000000 023D6B28 - if (!skipExecution) - { - if (codeArg == 0) - { - u8 value = 0; - if (!Cheat_Read8(processHandle, arg1, &value)) return 0; - *activeData() = value; - } - else if (codeArg == 1) - { - u8 value = 0; - if (!Cheat_Read8(processHandle, arg1, &value)) return 0; - cheat_state.data1 = value; - } - else if (codeArg == 2) - { - u8 value = 0; - if (!Cheat_Read8(processHandle, arg1, &value)) return 0; - cheat_state.data2 = value; - } - } - break; - case 0x0C: - // DC Type - // Format: DC000000 VVVVVVVV - // Description: 32bit store and increment by V. - // Simple: stores the value at address(es) before it and to addresses in increments of V. - // Note: used with the C, D3, D5, D9, D8, DB types. - // Example: DC000000 00000100 - if (!skipExecution) - { - *activeOffset() += arg1; - } - break; - case 0x0D: - // DD Type - { - bool newSkip = !(arg1 == 0 || (HID_PAD & arg1) == arg1); - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0;; - cheat_state.ifCount++; - } - break; - case 0x0E: - // Touchpad conditional - // DE000000 AAAABBBB: AAAA >= X position >= BBBB - // DE000001 AAAABBBB: AAAA >= Y position >= BBBB - { - bool newSkip; - u32 highBound = arg1 >> 16; - u32 lowBound = arg1 & 0xFFFF; - touchPosition touch; - hidTouchRead(&touch); - if (codeArg == 0) - { - newSkip = !(lowBound <= touch.px && highBound >= touch.px); - } - else if (codeArg == 1) - { - newSkip = !(lowBound <= touch.py && highBound >= touch.py); - } - else - { - return 0; - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - break; - case 0x0F: - { - switch (codeArg) - { - case 0x00: - { - if (arg1 & 0x00010000) - { - if (arg1 & 0x1) - { - cheat_state.offset2 = cheat_state.offset1; - } - else - { - cheat_state.offset1 = cheat_state.offset2; - } - } - else if (arg1 & 0x00020000) - { - if (arg1 & 0x1) - { - cheat_state.data2 = cheat_state.offset2; - } - else - { - cheat_state.data1 = cheat_state.offset1; - } - } - else - { - cheat_state.activeOffset = arg1 & 0x1; - } - } - break; - case 0x01: - { - if (arg1 & 0x00010000) - { - if (arg1 & 0x1) - { - cheat_state.data2 = cheat_state.data1; - } - else - { - cheat_state.data1 = cheat_state.data2; - } - } - else if (arg1 & 0x00020000) - { - if (arg1 & 0x1) - { - cheat_state.offset2 = cheat_state.data2; - } - else - { - cheat_state.offset1 = cheat_state.data1; - } - } - else - { - cheat_state.activeData = arg1 & 0x1; - } - } - break; - case 0x02: - { - if (arg1 & 0x00010000) - { - if (arg1 & 0x1) - { - cheat_state.data2 = cheat->storage2; - } - else - { - cheat_state.data1 = cheat->storage1; - } - } - else if (arg1 & 0x00020000) - { - if (arg1 & 0x1) - { - cheat->storage2 = cheat_state.data2; - } - else - { - cheat->storage1 = cheat_state.data1; - } - } - else - { - cheat->activeStorage = arg1 & 0x1; - } - } - break; - case 0x0E: - { - if (cheat_state.activeData) - { - switch (arg1) - { - case 0x0: - { - cheat_state.data2Mode = 0; - } - break; - case 0x1: - { - cheat_state.data2Mode = 1; - } - break; - case 0x10: - { - cheat_state.data2Mode = 0; - float val; - memcpy(&val, &cheat_state.data2, sizeof(float)); - cheat_state.data2 = val; - } - break; - case 0x11: - { - cheat_state.data2Mode = 1; - float val = cheat_state.data2; - memcpy(&cheat_state.data2, &val, sizeof(float)); - } - break; - default: - return 0; - } - } - else - { - switch (arg1) - { - case 0x0: - { - cheat_state.data1Mode = 0; - } - break; - case 0x1: - { - cheat_state.data1Mode = 1; - } - break; - case 0x10: - { - cheat_state.data1Mode = 0; - float val; - memcpy(&val, &cheat_state.data1, sizeof(float)); - cheat_state.data1 = val; - } - break; - case 0x11: - { - cheat_state.data1Mode = 1; - float val = cheat_state.data1; - memcpy(&cheat_state.data1, &val, sizeof(float)); - } - break; - default: - return 0; - } - } - } - break; - case 0x0F: - { - if (arg1 < 5) - { - cheat_state.conditionalMode = (u8)arg1; - } - else - { - return 0; - } - } - break; - default: - return 0; - } - } - break; - default: - return 0; - } - break; - case 0xE: - // E Type - // Format: - // EXXXXXXX UUUUUUUU - // YYYYYYYY YYYYYYYY - - // Description: writes Y to X for U bytes. - - { - u32 beginOffset = (arg0 & 0x0FFFFFFF); - u32 count = arg1; - cheat_state.typeELine = cheat_state.index; - cheat_state.typeEIdx = 7; - for (u32 i = 0; i < count; i++) - { - u8 byte = Cheat_GetNextTypeE(cheat); - if (!skipExecution) - { - if (!Cheat_Write8(processHandle, beginOffset + i, byte)) return 0; - } - } - cheat_state.index = cheat_state.typeELine; - } - break; - case 0xF: - { - if (arg0 == 0xF0F00000) - { - // I have no clue how to implement this, or if it's even possible. Needs research. - return 0; - } - else - { - switch (subcode) - { - case 0x0: - { - if(!skipExecution) - { - cheat_state.floatMode = arg1 & 0x1; - } - } - break; - case 0x1: - { - if (!skipExecution) - { - if (cheat_state.floatMode) - { - float flarg1; - memcpy(&flarg1, &arg1, sizeof(float)); - u32 tmp; - if (!Cheat_Read32(processHandle, arg0 & 0x00FFFFFF, &tmp)) - { - return 0; - } - float value; - memcpy(&value, &tmp, sizeof(float)); - value += flarg1; - memcpy(&tmp, &value, sizeof(u32)); - if (!Cheat_Write32(processHandle, arg0 & 0x00FFFFFF, tmp)) - { - return 0; - } - } - else - { - u32 tmp; - if (!Cheat_Read32(processHandle, arg0 & 0x00FFFFFF, &tmp)) - { - return 0; - } - tmp += arg1; - if (!Cheat_Write32(processHandle, arg0 & 0x00FFFFFF, tmp)) - { - return 0; - } - } - } - } - break; - case 0x2: - { - if (!skipExecution) - { - if (cheat_state.floatMode) - { - float flarg1; - memcpy(&flarg1, &arg1, sizeof(float)); - u32 tmp; - if (!Cheat_Read32(processHandle, arg0 & 0x00FFFFFF, &tmp)) - { - return 0; - } - float value; - memcpy(&value, &tmp, sizeof(float)); - value *= flarg1; - memcpy(&tmp, &value, sizeof(u32)); - if (!Cheat_Write32(processHandle, arg0 & 0x00FFFFFF, tmp)) - { - return 0; - } - } - else - { - u32 tmp; - if (!Cheat_Read32(processHandle, arg0 & 0x00FFFFFF, &tmp)) - { - return 0; - } - tmp *= arg1; - if (!Cheat_Write32(processHandle, arg0 & 0x00FFFFFF, tmp)) - { - return 0; - } - } - } - } - break; - case 0x3: - { - if (!skipExecution) - { - if (cheat_state.floatMode) - { - float flarg1; - memcpy(&flarg1, &arg1, sizeof(float)); - u32 tmp; - if (!Cheat_Read32(processHandle, arg0 & 0x00FFFFFF, &tmp)) - { - return 0; - } - float value; - memcpy(&value, &tmp, sizeof(float)); - value /= flarg1; - memcpy(&tmp, &value, sizeof(u32)); - if (!Cheat_Write32(processHandle, arg0 & 0x00FFFFFF, tmp)) - { - return 0; - } - } - else - { - u32 tmp; - if (!Cheat_Read32(processHandle, arg0 & 0x00FFFFFF, &tmp)) - { - return 0; - } - tmp /= arg1; - if (!Cheat_Write32(processHandle, arg0 & 0x00FFFFFF, tmp)) - { - return 0; - } - } - } - } - break; - case 0x4: - { - if (!skipExecution) - { - if (cheat_state.data1Mode) - { - float flarg1; - memcpy(&flarg1, &arg1, sizeof(float)); - float value; - memcpy(&value, activeData(), sizeof(float)); - value *= flarg1; - memcpy(activeData(), &value, sizeof(float)); - } - else - { - *activeData() *= arg1; - } - } - } - break; - case 0x5: - { - if (!skipExecution) - { - if (cheat_state.data1Mode) - { - float flarg1; - memcpy(&flarg1, &arg1, sizeof(float)); - float value; - memcpy(&value, activeData(), sizeof(float)); - value /= flarg1; - memcpy(activeData(), &value, sizeof(float)); - } - else - { - *activeData() /= arg1; - } - } - } - break; - case 0x6: - { - if (!skipExecution) - { - *activeData() &= arg1; - } - } - break; - case 0x7: - { - if (!skipExecution) - { - *activeData() |= arg1; - } - } - break; - case 0x8: - { - if (!skipExecution) - { - *activeData() ^= arg1; - } - } - break; - case 0x9: - { - if (!skipExecution) - { - *activeData() = ~*activeData(); - } - } - break; - case 0xA: - { - if (!skipExecution) - { - *activeData() <<= arg1; - } - } - break; - case 0xB: - { - if (!skipExecution) - { - *activeData() >>= arg1; - } - } - break; - case 0xC: - { - if (!skipExecution) - { - u8 origActiveOffset = cheat_state.activeOffset; - for (size_t i = 0; i < arg1; i++) - { - u8 data; - cheat_state.activeOffset = 1; - if (!Cheat_Read8(processHandle, 0, &data)) - { - return 0; - } - cheat_state.activeOffset = 0; - if (!Cheat_Write8(processHandle, 0, data)) - { - return 0; - } - } - cheat_state.activeOffset = origActiveOffset; - } - } - break; - // Search for pattern - case 0xE: - { - u32 searchSize = arg0 & 0xFFFF; - if (searchSize <= arg1 && searchSize + cheat_state.index < cheat->codesCount) - { - bool newSkip = true; - if (!skipExecution) // Don't do an expensive operation if we don't have to - { - u8* searchData = (u8*)(cheat->codes + cheat_state.index + 1); - cheat_state.index += searchSize / 8; - if (searchSize & 0x7) - { - cheat_state.index++; - } - for (size_t i = 0; i < arg1 - searchSize; i++) - { - u8 curVal; - newSkip = false; - for (size_t j = 0; j < searchSize; j++) - { - if (!Cheat_Read8(processHandle, i + j, &curVal)) - { - return 0; - } - if (curVal != searchData[j]) - { - newSkip = 1; - break; - } - } - if (!newSkip) - { - break; - } - } - } - - cheat_state.ifStack <<= 1; - cheat_state.ifStack |= (newSkip || skipExecution) ? 1 : 0; - cheat_state.ifCount++; - } - else - { - return 0; - } - } - break; - case 0xF: - { - if (!skipExecution) - { - u32 range = arg1 - (arg0 & 0xFFFFFF); - u32 number = Cheat_GetRandomNumber() % range; - *activeData() = (arg0 & 0xFFFFFF) + number; - } - } - break; - default: - return 0; - } - } - } - break; - // This should now not be possible - default: - return 0; - } - cheat_state.index++; - } - return 1; -} - -static void Cheat_EatEvents(Handle debug) -{ - DebugEventInfo info; - Result r; - - while(true) - { - if((r = svcGetProcessDebugEvent(&info, debug)) != 0) - { - if(r == (s32)(0xd8402009)) - { - break; - } - } - svcContinueDebugEvent(debug, 3); - } -} - -static Result Cheat_MapMemoryAndApplyCheat(u32 pid, CheatDescription* const cheat) -{ - Handle processHandle; - Handle debugHandle; - Result res; - res = svcOpenProcess(&processHandle, pid); - if (R_SUCCEEDED(res)) - { - res = svcDebugActiveProcess(&debugHandle, pid); - if (R_SUCCEEDED(res)) - { - Cheat_EatEvents(debugHandle); - cheat->valid = Cheat_ApplyCheat(debugHandle, cheat); - - svcCloseHandle(debugHandle); - svcCloseHandle(processHandle); - cheat->active = 1; - } - else - { - sprintf(failureReason, "Debug process failed"); - svcCloseHandle(processHandle); - } - } - else - { - sprintf(failureReason, "Open process failed"); - } - return res; -} - -static CheatDescription* Cheat_AllocCheat() -{ - CheatDescription* cheat; - if (cheatCount == 0) - { - cheat = (CheatDescription*) cheatBuffer; - } - else - { - CheatDescription* prev = cheats[cheatCount - 1]; - cheat = (CheatDescription *) ((u8*) (prev) + sizeof(CheatDescription) + sizeof(u64) * (prev->codesCount)); - } - cheat->active = 0; - cheat->valid = 1; - cheat->codesCount = 0; - cheat->hasKeyCode = 0; - cheat->storage1 = 0; - cheat->storage2 = 0; - cheat->name[0] = '\0'; - - cheats[cheatCount] = cheat; - cheatCount++; - return cheat; -} - -static void Cheat_AddCode(CheatDescription* cheat, u64 code) -{ - if (cheat) - { - cheat->codes[cheat->codesCount] = code; - (cheat->codesCount)++; - } -} - -static Result BufferedFile_Open(BufferedFile* file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags) -{ - Result res = 0; - memset(file->buffer, '\0', sizeof(file->buffer)); - res = IFile_Open(&file->file, archiveId, archivePath, filePath, flags); - if (R_SUCCEEDED(res)) - { - file->curPos = 0; - res = IFile_Read(&file->file, &file->maxPos, file->buffer, sizeof(file->buffer)); - } - return res; -} - -static Result BufferedFile_Read(BufferedFile* file, u64* totalRead, void* buffer, u32 len) -{ - Result res = 0; - if (len == 0) - { - *totalRead = 0; - return 0; - } - else if (file->curPos + len < file->maxPos) - { - memcpy(buffer, file->buffer + file->curPos, len); - file->curPos += len; - *totalRead = len; - } - else - { - *totalRead = 0; - while(R_SUCCEEDED(res) && file->maxPos != 0 && *totalRead < len) - { - u32 toRead = file->maxPos - file->curPos < len - *totalRead ? file->maxPos - file->curPos : len - *totalRead; - memcpy(buffer + *totalRead, file->buffer + file->curPos, toRead); - *totalRead += toRead; - file->curPos += toRead; - if (file->curPos >= file->maxPos) - { - res = IFile_Read(&file->file, &file->maxPos, file->buffer, sizeof(file->buffer)); - file->curPos = 0; - } - } - } - return res; -} - -static Result Cheat_ReadLine(BufferedFile* file, char* line, u32 lineSize) -{ - Result res = 0; - - u32 idx = 0; - u64 total = 0; - bool lastWasCarriageReturn = false; - while (R_SUCCEEDED(res) && idx < lineSize) - { - res = BufferedFile_Read(file, &total, line + idx, 1); - if (total == 0) - { - line[idx] = '\0'; - return -1; - } - if (R_SUCCEEDED(res)) - { - if (line[idx] == '\r') - { - lastWasCarriageReturn = true; - } - else if (line[idx] == '\n') - { - if (lastWasCarriageReturn) - { - line[--idx] = '\0'; - return idx; - } - else - { - line[idx] = '\0'; - return idx; - } - } - else if (line[idx] == '\0') - { - return -1; - } - else - { - lastWasCarriageReturn = false; - } - idx++; - } - } - return res; -} - -static bool Cheat_IsCodeLine(const char *line) -{ - s32 len = strnlen(line, 1023); - if (len != 17) - { - return false; - } - if (line[8] != ' ') - { - return false; - } - - int i; - for (i = 0; i < 8; i++) - { - char c = line[i]; - if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'))) - { - return false; - } - } - - for (i = 9; i < 17; i++) - { - char c = line[i]; - if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'))) - { - return false; - } - } - - return true; -} - -static u64 Cheat_GetCode(const char *line) -{ - u64 tmp = 0; - int i; - for (i = 0; i < 8; i++) - { - char c = line[i]; - u8 code = 0; - if ('0' <= c && c <= '9') - { - code = c - '0'; - } - if ('A' <= c && c <= 'F') - { - code = c - 'A' + 10; - } - if ('a' <= c && c <= 'f') - { - code = c - 'a' + 10; - } - tmp <<= 4; - tmp |= (code & 0xF); - } - - for (i = 9; i < 17; i++) - { - char c = line[i]; - u8 code = 0; - if ('0' <= c && c <= '9') - { - code = c - '0'; - } - if ('A' <= c && c <= 'F') - { - code = c - 'A' + 10; - } - if ('a' <= c && c <= 'f') - { - code = c - 'a' + 10; - } - tmp <<= 4; - tmp |= (code & 0xF); - } - - return tmp; -} - -static char* stripWhitespace(char* in) -{ - char* ret = in; - while (*ret == ' ' || *ret == '\t') - { - ret++; - } - int back = strlen(ret) - 1; - while (back > 0 && (ret[back] == ' ' || ret[back] == '\t')) - { - back--; - } - ret[back+1] = '\0'; - return ret; -} - -static void Cheat_LoadCheatsIntoMemory(u64 titleId) -{ - cheatCount = 0; - cheatTitleInfo = titleId; - - char path[64] = { 0 }; - sprintf(path, "/luma/titles/%016llX/cheats.txt", titleId); - - BufferedFile file; - - if (R_FAILED(BufferedFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, path), FS_OPEN_READ))) - { - // OK, let's try another source - sprintf(path, "/cheats/%016llX.txt", titleId); - if (R_FAILED(BufferedFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, path), FS_OPEN_READ))) return; - }; - - char line[1024] = { 0 }; - Result res = 0; - CheatDescription* cheat = 0; - u32 cheatSize = 0; - do - { - res = Cheat_ReadLine(&file, line, 1024); - // -1 is special; it can't be a normal result because of how results are constructed - // So let's just use it as a signal that this is the final line of a file - if (R_SUCCEEDED(res) || res == -1) - { - char* strippedLine = stripWhitespace(line); - s32 lineLen = strnlen(strippedLine, 1023); - if (!lineLen) - { - continue; - } - if (strippedLine[0] == '#') - { - continue; - } - if (Cheat_IsCodeLine(strippedLine)) - { - if (cheatSize + sizeof(u64) >= sizeof(cheatBuffer)) - { - cheatCount--; - break; - } - if (cheat) - { - u64 tmp = Cheat_GetCode(strippedLine); - Cheat_AddCode(cheat, tmp); - cheatSize += sizeof(u64); - if (((tmp >> 32) & 0xFFFFFFFF) == 0xDD000000) - { - cheat->hasKeyCode = 1; - } - } - } - else - { - if (!cheat || cheat->codesCount > 0) - { - if (cheatSize + sizeof(CheatDescription) >= sizeof(cheatBuffer)) - { - break; - } - cheat = Cheat_AllocCheat(); - cheatSize += sizeof(CheatDescription); - } - strncpy(cheat->name, line, 38); - cheat->name[38] = '\0'; - } - } - } while (R_SUCCEEDED(res) && cheatSize < sizeof(cheatBuffer)); - - IFile_Close(&file.file); - - if ((cheatCount > 0) && (cheats[cheatCount - 1]->codesCount == 0)) - { - cheatCount--; // Remove last empty cheat - } - - memset(cheatPage, 0, 0x1000); -} - -static u32 Cheat_GetCurrentProcessAndTitleId(u64* titleId) -{ - FS_ProgramInfo programInfo; - u32 pid; - u32 launchFlags; - Result res = PMDBG_GetCurrentAppInfo(&programInfo, &pid, &launchFlags); - if (R_FAILED(res)) { - *titleId = 0; - return 0xFFFFFFFF; - } - - *titleId = programInfo.programId; - return pid; -} - -void Cheat_SeedRng(u64 seed) -{ - cheatRngState = seed; -} - -void Cheat_ApplyCheats(void) -{ - if (!cheatCount) - { - return; - } - - u64 titleId = 0; - u32 pid = Cheat_GetCurrentProcessAndTitleId(&titleId); - - if (!titleId) - { - cheatCount = 0; - return; - } - - if (titleId != cheatTitleInfo) - { - cheatCount = 0; - return; - } - - for (int i = 0; i < cheatCount; i++) - { - if (cheats[i]->active) - { - Cheat_MapMemoryAndApplyCheat(pid, cheats[i]); - } - } -} - -void RosalinaMenu_Cheats(void) -{ - u64 titleId = 0; - u32 pid = Cheat_GetCurrentProcessAndTitleId(&titleId); - - if (titleId != 0) - { - if (cheatTitleInfo != titleId || cheatCount == 0) - { - Cheat_LoadCheatsIntoMemory(titleId); - } - } - - Draw_Lock(); - Draw_ClearFramebuffer(); - Draw_FlushFramebuffer(); - Draw_Unlock(); - - if (titleId == 0 || cheatCount == 0) - { - do - { - Draw_Lock(); - Draw_DrawString(10, 10, COLOR_TITLE, "Cheats"); - if (titleId == 0) - { - Draw_DrawString(10, 30, COLOR_WHITE, "No suitable title found"); - } - else - { - Draw_DrawFormattedString(10, 30, COLOR_WHITE, "No cheats found for title %016llX", titleId); - } - - Draw_FlushFramebuffer(); - Draw_Unlock(); - } while (!(waitInput() & KEY_B) && !menuShouldExit); - } - else - { - s32 selected = 0, page = 0, pagePrev = 0; - - Result r = 0; - do - { - Draw_Lock(); - if (page != pagePrev || R_FAILED(r)) - { - Draw_ClearFramebuffer(); - } - if (R_SUCCEEDED(r)) - { - Draw_DrawFormattedString(10, 10, COLOR_TITLE, "Cheat list"); - - for (s32 i = 0; i < CHEATS_PER_MENU_PAGE && page * CHEATS_PER_MENU_PAGE + i < cheatCount; i++) - { - char buf[65] = { 0 }; - s32 j = page * CHEATS_PER_MENU_PAGE + i; - const char * checkbox = (cheats[j]->active ? "(x) " : "( ) "); - const char * keyAct = (cheats[j]->hasKeyCode ? "*" : " "); - sprintf(buf, "%s%s%s", checkbox, keyAct, cheats[j]->name); - - Draw_DrawString(30, 30 + i * SPACING_Y, cheats[j]->valid ? COLOR_WHITE : COLOR_RED, buf); - Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, j == selected ? '>' : ' '); - } - } - else - { - Draw_DrawFormattedString(10, 10, COLOR_TITLE, "ERROR: %08lx", r); - Draw_DrawFormattedString(10, 30, COLOR_RED, failureReason); - } - Draw_FlushFramebuffer(); - Draw_Unlock(); - - if (menuShouldExit) break; - - u32 pressed; - do - { - pressed = waitInputWithTimeout(50); - if (pressed != 0) break; - } while (pressed == 0 && !menuShouldExit); - - if (pressed & KEY_B) - break; - else if ((pressed & KEY_A) && R_SUCCEEDED(r)) - { - if (cheats[selected]->active) - { - cheats[selected]->active = 0; - } - else - { - r = Cheat_MapMemoryAndApplyCheat(pid, cheats[selected]); - } - } - else if (pressed & KEY_DOWN) - selected++; - else if (pressed & KEY_UP) - selected--; - else if (pressed & KEY_LEFT) - selected -= CHEATS_PER_MENU_PAGE; - else if (pressed & KEY_RIGHT) - { - if (selected + CHEATS_PER_MENU_PAGE < cheatCount) - selected += CHEATS_PER_MENU_PAGE; - else if ((cheatCount - 1) / CHEATS_PER_MENU_PAGE == page) - selected %= CHEATS_PER_MENU_PAGE; - else selected = cheatCount - 1; - } - - if (selected < 0) - selected = cheatCount - 1; - else if (selected >= cheatCount) selected = 0; - - pagePrev = page; - page = selected / CHEATS_PER_MENU_PAGE; - } while (!menuShouldExit); - } - -}