diff --git a/Includes/Address/Addresses.hpp b/Includes/Address/Addresses.hpp index 86fb5798..09d96e2c 100644 --- a/Includes/Address/Addresses.hpp +++ b/Includes/Address/Addresses.hpp @@ -3,10 +3,13 @@ #include "types.h" static const u32 ADDRESSES[][8] = { + { 0x6AF954, 0x6AEE7C, 0x6AE98C, 0x6AE98C, 0x6AE324, 0x6AE324, 0x6ADECC, 0x6ADECC }, //BADGE_AFTERWARDS + { 0x6AECA0, 0x6AE1C8, 0x6ADCD8, 0x6ADCD8, 0x6AD72C, 0x6AD72C, 0x6AD2D4, 0x6AD2D4 }, //BADGE_FIRST + { 0x19CE64, 0x19C8AC, 0x19CE84, 0x19CE84, 0x19CDC4, 0x19CDC4, 0x19CDC4, 0x19CDC4 }, //HOVERED_ITEM_NAME { 0x6BAC8C, 0x6BA13C, 0x6B9CC4, 0x6B9C9C, 0x6B95BC, 0x6B9594, 0x6B9164, 0x6B913C }, //SEED_ITEM_LEGIT { 0x4E1720, 0x4E1098, 0x4E0768, 0x4E0768, 0x4E0364, 0x4E0364, 0x4DFB3C, 0x4DFB3C }, //MOVING_FURNITURE - { 0x678AC0, 0x677FE8, 0x677AF8, 0x677AF8, 0x6775B8, 0x6775B8, 0x677160, 0x677160 }, //PICKING_UP_FURNITURE - { 0x76B880, 0x76A864, 0x76A888, 0x76A860, 0x76A020, 0x769FF8, 0x769BC8, 0x769BA0 }, //PLACING_FURNITURE1 + { 0x678AC0, 0x677FE8, 0x677AF8, 0x677AF8, 0x6775B8, 0x6775B8, 0x677160, 0x677160 }, //PICKING_UP_FURNITURE + { 0x76B880, 0x76A864, 0x76A888, 0x76A860, 0x76A020, 0x769FF8, 0x769BC8, 0x769BA0 }, //PLACING_FURNITURE1 { 0x26FED8, 0x26F91C, 0x26FED4, 0x26FED4, 0x26FDE0, 0x26FDE0, 0x26FDAC, 0x26FDAC }, //PLACING_FURNITURE2 { 0x4E78A8, 0x4E7220, 0x4E68F0, 0x4E68F0, 0x4E64EC, 0x4E64EC, 0x4E5CC4, 0x4E5CC4 }, //PLACING_FURNITURE3 { 0x3279CC, 0x3273E0, 0x326D20, 0x326D20, 0x3269AC, 0x3269AC, 0x326864, 0x326864 }, //LIGHTSWITCH_VISIBLE @@ -19,8 +22,6 @@ static const u32 ADDRESSES[][8] = { { 0x2FEA78, 0x2FE7F4, 0x2FEA0C, 0x2FEA0C, 0x2FEAAC, 0x2FEAAC, 0x2FE9E4, 0x2FE9E4 }, //GET_ITEM_NAME { 0x767028, 0x76600C, 0x766030, 0x766008, 0x7657C8, 0x7657A0, 0x765370, 0x765348 }, //DEVER5 { 0x2912B8, 0x290CFC, 0x2912B4, 0x2912B4, 0x2911B4, 0x2911B4, 0x29118C, 0x29118C }, //DISP - { 0xC, 0xC, 0xC, 0xC, 0, 0, 0, 0 }, //FIX - { 0x2C, 0x30, 0x2C, 0x30, 0x30, 0x30, 0x2C, 0x30 }, //CALC { 0x2F7384, 0x2F74C8, 0x2F73AC, 0x2F73AC, 0x2F75CC, 0x2F75CC, 0x2F7488, 0x2F7488 }, //GETROOM { 0x51C104, 0x51BA58, 0x51B14C, 0x51B14C, 0x51AA68, 0x51AA68, 0x51A3FC, 0x51A3FC }, //OFFSETPATCH { 0x51BBDC, 0x51B530, 0x51AC24, 0x51AC24, 0x51A540, 0x51A540, 0x519ED4, 0x519ED4 }, //OFFSETHOOK diff --git a/Includes/Helpers/Checks.hpp b/Includes/Helpers/Checks.hpp index dad21a10..6c7dcf3e 100644 --- a/Includes/Helpers/Checks.hpp +++ b/Includes/Helpers/Checks.hpp @@ -4,6 +4,7 @@ #include "Helpers/GameStructs.hpp" namespace CTRPluginFramework { + void CheckInvalidBadge(u32 data, u32 badge, int badgeType, u32 r3, u32 r4); void OnTitleScreen(u8 roomId, bool u0, bool u1, bool u2); void InvalidGiveItem(bool var1, Item* item, u32 data); u32 InvalidPickStop(u8 ID, Item *ItemToReplace, Item *ItemToPlace, Item *ItemToShow, u8 worldx, u8 worldy); @@ -13,7 +14,8 @@ namespace CTRPluginFramework { bool InvalidItemStop(Item* item); bool ConvertFlower(Item *item); bool IsItemReplaceable(Item *item); - void NameFunc(u32 u0, u32 u1, u32 u2); + void SetHoveredItemName(u32 r0, u32 r1, u32 r2, u32 r3); + void SetItemName(u32 u0, u32 u1, u32 u2); bool IsItemDroppable(u32 ItemData, Item *ItemID, int SecondaryItemFlag); bool IsItemPlantable(u32 ItemData, Item *ItemID); int CatalogPatch_Keyboard(u32 u0, u32 u1, u32 u2); diff --git a/Includes/cheats.hpp b/Includes/cheats.hpp index 37df7512..767780ec 100644 --- a/Includes/cheats.hpp +++ b/Includes/cheats.hpp @@ -233,6 +233,7 @@ namespace CTRPluginFramework { void DisableAllChecks(void); void DisableAllPatches(void); + void CheckInvalidBadgeEntry(MenuEntry *entry); void SeedItemLegitimacyEntry(MenuEntry *entry); void OnlineDropLagRemoverEntry(MenuEntry *entry); void ChangeRockbreakParticleEntry(MenuEntry *entry); diff --git a/Sources/Folders/AnimationCodes.cpp b/Sources/Folders/AnimationCodes.cpp index 6359d31c..0cdc4f87 100644 --- a/Sources/Folders/AnimationCodes.cpp +++ b/Sources/Folders/AnimationCodes.cpp @@ -20,33 +20,34 @@ namespace CTRPluginFramework { //Speed bool speedmode = false; - static Address playerSelect(0x305EF0); - static Address playerSelect2 = playerSelect.MoveOffset(4); + bool IsPlayerSelectEnabled = false; - void PSelector_Set(u8 pIndex) { - playerSelect.Patch(0xE3A00000 + pIndex); - playerSelect2.Patch(0xE12FFF1E); - } - - void PSelector_OFF(void) { - playerSelect.Unpatch(); - playerSelect2.Unpatch(); - } + void TogglePlayerSelect(u8 pIndex) { + static Address playerSelect(0x305EF0); + static Address playerSelect2 = playerSelect.MoveOffset(4); - bool PSelector_ON(void) { - return (*(u32 *)playerSelect.addr != playerSelect.origVal); + if (pIndex < 4) { + playerSelect.Patch(0xE3A00000 + pIndex); + playerSelect2.Patch(0xE12FFF1E); + IsPlayerSelectEnabled = true; + } + else { + playerSelect.Unpatch(); + playerSelect2.Unpatch(); + IsPlayerSelectEnabled = false; + } } //check to make player selector better void PlayerSelectCheck(void) { - if(!PSelector_ON()) { + if(!IsPlayerSelectEnabled) { return; } u8 pIndex = Game::GetOnlinePlayerIndex(); //If player is not loaded or loading screen started, switch off the code if(!PlayerClass::GetInstance()->IsLoaded() || !PlayerClass::GetInstance(pIndex)->IsLoaded() || Game::IsRoomLoading()) { - PSelector_OFF(); + TogglePlayerSelect(4); } } @@ -76,7 +77,7 @@ namespace CTRPluginFramework { int pChoice = pKB.Open(); if(pChoice >= 0) { if(pV[pChoice] != Color::Silver << "-Empty-") { - PSelector_Set(pChoice); + TogglePlayerSelect(pChoice); OSD::Notify(Utils::Format("Controlling Player: %02X Enabled!", pChoice)); } else { @@ -86,16 +87,16 @@ namespace CTRPluginFramework { } else if(entry->Hotkeys[1].IsPressed()) { - if(PSelector_ON()) { + if(IsPlayerSelectEnabled) { OSD::Notify(Utils::Format("Controlling Player: %02X Disabled!", *(u8 *)(Address(0x75F010).addr + 0x10))); - PSelector_OFF(); + TogglePlayerSelect(4); return; } OSD::Notify("Error: No Player Is Selected!", Color::Red); } if(!entry->IsActivated()) { - PSelector_OFF(); + TogglePlayerSelect(4); PluginMenu *menu = PluginMenu::GetRunningInstance(); *menu -= PlayerSelectCheck; } diff --git a/Sources/Folders/DefaultCodes/DefaultChecks.cpp b/Sources/Folders/DefaultCodes/DefaultChecks.cpp index 26eb6c95..f7f08ca9 100644 --- a/Sources/Folders/DefaultCodes/DefaultChecks.cpp +++ b/Sources/Folders/DefaultCodes/DefaultChecks.cpp @@ -28,6 +28,7 @@ namespace CTRPluginFramework { return optKb.Open(); } + static Hook CheckInvalidBadgeHook1, CheckInvalidBadgeHook2; static Hook SaveButtonCheck; static Hook CatalogPHook1, CatalogPHook2; static Hook IPHook; @@ -37,6 +38,7 @@ namespace CTRPluginFramework { static Hook IHHook; static Hook IIHook; static Hook CFHook; + static Hook HoveredNameHook; static Hook NameHook; static Hook ReplaceHook; static Hook DropHook1, DropHook2, DropHook3, DropHook4; @@ -45,6 +47,9 @@ namespace CTRPluginFramework { static Hook OnProDesignHook; void EnableAllChecks() { + SetHook(CheckInvalidBadgeHook1, Address(0x6AF954).addr, (u32)CheckInvalidBadge, USE_LR_TO_RETURN); + SetHook(CheckInvalidBadgeHook2, Address(0x6AECA0).addr, (u32)CheckInvalidBadge, USE_LR_TO_RETURN); + SetHook(SaveButtonCheck, Address(0x1A0980).addr - 0x10, (u32)IsSTARTDown, USE_LR_TO_RETURN); SetHook(CatalogPHook1, Address(0x21C408).addr, (u32)CatalogPatch_Keyboard, USE_LR_TO_RETURN); @@ -65,7 +70,8 @@ namespace CTRPluginFramework { SetHook(CFHook, Address(0x323514).addr, (u32)ConvertFlower, USE_LR_TO_RETURN); - SetHook(NameHook, Address(0x19C498).addr, (u32)NameFunc, USE_LR_TO_RETURN); + SetHook(HoveredNameHook, Address(0x19CE64).addr, (u32)SetHoveredItemName, USE_LR_TO_RETURN); + SetHook(NameHook, Address(0x19C498).addr, (u32)SetItemName, USE_LR_TO_RETURN); SetHook(ReplaceHook, Address(0x165528).addr, (u32)IsItemReplaceable, USE_LR_TO_RETURN); @@ -86,6 +92,8 @@ namespace CTRPluginFramework { } void DisableAllChecks() { + CheckInvalidBadgeHook1.Disable(); + CheckInvalidBadgeHook2.Disable(); SaveButtonCheck.Disable(); CatalogPHook1.Disable(); CatalogPHook2.Disable(); @@ -97,6 +105,7 @@ namespace CTRPluginFramework { IHHook.Disable(); IIHook.Disable(); CFHook.Disable(); + HoveredNameHook.Disable(); NameHook.Disable(); ReplaceHook.Disable(); DropHook1.Disable(); @@ -112,6 +121,22 @@ namespace CTRPluginFramework { OnProDesignHook.Disable(); } + void CheckInvalidBadgeEntry(MenuEntry *entry) { + int res = OptionKeyboard(); + if(res < 0) { + return; + } + + if (res == 0) { + CheckInvalidBadgeHook1.Enable(); + CheckInvalidBadgeHook2.Enable(); + } + else { + CheckInvalidBadgeHook1.Disable(); + CheckInvalidBadgeHook2.Disable(); + } + } + void DisableOpenSaveMenuWithStartButton(MenuEntry *entry) { int res = OptionKeyboard(); if(res < 0) { @@ -249,9 +274,11 @@ namespace CTRPluginFramework { } if (res == 0) { + HoveredNameHook.Enable(); NameHook.Enable(); } else { + HoveredNameHook.Disable(); NameHook.Disable(); } } diff --git a/Sources/Folders/InventoryCodes.cpp b/Sources/Folders/InventoryCodes.cpp index 44169dec..b5c3306b 100644 --- a/Sources/Folders/InventoryCodes.cpp +++ b/Sources/Folders/InventoryCodes.cpp @@ -348,10 +348,20 @@ namespace CTRPluginFramework { } } - void Hook_MenuPatch(void) { - Game::OpenMenu(CurrentMenu); - PluginMenu *menu = PluginMenu::GetRunningInstance(); - *menu += Callback_MenuPatch; + void Hook_MenuPatch(u32 r0, u32 r1, u32 r3) { + u8 roomId = Player::GetRoom(4); + if (roomId == 0xA1 || roomId == 0xA2 || (roomId >= 0x92 && roomId <= 0x97)) { + OSD::Notify("Custom Save Menu doesn't work in this room!", Color::Red); + + const HookContext &curr = HookContext::GetCurrent(); + static Address func = Address::decodeARMBranch(curr.targetAddress, curr.overwrittenInstr); + func.Call(r0, r1, r3); + } + else { + Game::OpenMenu(CurrentMenu); + PluginMenu *menu = PluginMenu::GetRunningInstance(); + *menu += Callback_MenuPatch; + } } //Menu Changer diff --git a/Sources/Folders/MiscCodes.cpp b/Sources/Folders/MiscCodes.cpp index 56587886..0e6355ef 100644 --- a/Sources/Folders/MiscCodes.cpp +++ b/Sources/Folders/MiscCodes.cpp @@ -225,6 +225,30 @@ namespace CTRPluginFramework { } u32 LightSwitchPatch(void) { + static const u8 r_Array[14] = { + 0x02, //Train Station + 0x26, //Town Hall + 0x30, //Police Station + 0x31, //Police Station + 0x39, //T&T Mart + 0x3A, //Super T&T + 0x3B, //TIY + 0x3F, //Able Sisters Mable & Sable + 0x41, //Nooks Homes + 0x43, //Gardening Store + 0x44, //Gardening Store + 0x48, //Shampoodle + 0x5A, //Post Office + 0x67, //Island (Might freeze?) + }; + + u8 stageID = CTRPluginFramework::Player::GetRoom(4); + for (u8 i = 0; i < 14; ++i) { + if(stageID == r_Array[i]) { + return 0; //Disable lightswitch if invalid room + } + } + return Player::IsIndoors(); } diff --git a/Sources/Helpers/Checks.cpp b/Sources/Helpers/Checks.cpp index 29c59742..abf96997 100644 --- a/Sources/Helpers/Checks.cpp +++ b/Sources/Helpers/Checks.cpp @@ -36,6 +36,17 @@ extern "C" bool __IsPlayerHouse() { } namespace CTRPluginFramework { + void CheckInvalidBadge(u32 data, u32 badge, int badgeType, u32 r3, u32 r4) { + if (badgeType > 3) { + OSD::Notify("Invalid Badge Type! Can't display badge properly.", Color::Red); + return; + } + + const HookContext &curr = HookContext::GetCurrent(); + static Address func = Address::decodeARMBranch(curr.targetAddress, curr.overwrittenInstr); + func.Call(data, badge, badgeType, r3, r4); + } + //Hook invalid pickup u32 InvalidPickStop(u8 ID, Item *ItemToReplace, Item *ItemToPlace, Item *ItemToShow, u8 worldx, u8 worldy) { if(ItemToReplace->isValid()) { @@ -129,7 +140,30 @@ namespace CTRPluginFramework { return false; } - void NameFunc(u32 r0, u32 r1, u32 r2) { + void SetHoveredItemName(u32 r0, u32 r1, u32 r2, u32 r3) { + Item itemslotid = {0x7FFE, 0}; + u8 slot = 0; + + if(Inventory::GetHoveredSlot(slot)) { + if(Inventory::ReadSlot(slot, itemslotid)) { + itemslotid.Flags = 0; + if(Game::IsOutdoorItem(itemslotid) || itemslotid.ID == 0x3729) { + std::string name = itemslotid.GetName(); + Process::Write32(r1 + 0x18, 0x000E000E); + Process::Write32(r1 + 0x1C, 0x00040000); + Process::Write32(r1 + 0x20, 0xCD030100); + + Process::WriteString(r1 + 0x24, itemslotid.isValid(false) ? name : "Invalid Item", StringFormat::Utf16); + } + } + } + + const HookContext &curr = HookContext::GetCurrent(); + static Address func = Address::decodeARMBranch(curr.targetAddress, curr.overwrittenInstr); + func.Call(r0, r1, r2, r3); + } + + void SetItemName(u32 r0, u32 r1, u32 r2) { Item itemslotid = {0x7FFE, 0}; u8 slot = 0; diff --git a/Sources/Helpers/Game.cpp b/Sources/Helpers/Game.cpp index 80ca0e25..cc8cd725 100644 --- a/Sources/Helpers/Game.cpp +++ b/Sources/Helpers/Game.cpp @@ -434,12 +434,14 @@ namespace CTRPluginFramework { //get map boolen pointer bool Game::MapBoolCheck() { - return *(bool *)Address(0x950C30).addr; + static const Address mapBool(0x950C30); + return *(bool *)mapBool.addr; } //Get online index u8 Game::GetOnlinePlayerIndex() { - return Address(0x305EF0).Call(); + static Address playerIndex(0x305EF0); + return playerIndex.Call(); } //Get actual index diff --git a/Sources/Helpers/KeepConnection.cpp b/Sources/Helpers/KeepConnection.cpp index 83d3d85a..197e71c7 100644 --- a/Sources/Helpers/KeepConnection.cpp +++ b/Sources/Helpers/KeepConnection.cpp @@ -111,9 +111,14 @@ namespace CTRPluginFramework { void PatchThreadBegin(u32 threadfunc, u32 threadargs, u32 startFunc, u32 u0) { static Address point(0x953CA0); - static Address calc(0x2C); - static u32 threadAddress = *(u32 *)(*(u32 *)(point.addr) + 0xA8 + 0x80) - calc.addr; + u8 fixOffset = 0x30; //For USAWA, EURWA, JPN, JPNWA, KORWA + if (Address::IsRegion(Address::Region::USA) || Address::IsRegion(Address::Region::EUR) + || Address::IsRegion(Address::Region::KOR)) { + fixOffset = 0x2C; + } + + static u32 threadAddress = *(u32 *)(*(u32 *)(point.addr) + 0xA8 + 0x80) - fixOffset; static u32 onlineThreadArgs[ONLINETHREADSAMOUNT] = { 0x82C0FF8, //Region Free diff --git a/Sources/Helpers/NPC.cpp b/Sources/Helpers/NPC.cpp index 2a9d4e11..44b9ca93 100644 --- a/Sources/Helpers/NPC.cpp +++ b/Sources/Helpers/NPC.cpp @@ -81,8 +81,12 @@ Gets npc data for anim mods, coord mods, etc 0xB6F9B4 static Address SetUpStack(0x3081E8); static Address SetUp(0x312610); + u8 fixOffset = 0; //No clue why, but the USA and EUR version have some formatting string parts at the beginning of the NPC race string which we need to skip - static const Address Fix(0xC); + if (Address::IsRegion(Address::Region::USA) || Address::IsRegion(Address::Region::USAWA) + || Address::IsRegion(Address::Region::EUR) || Address::IsRegion(Address::Region::EURWA)) { + fixOffset = 0xC; + } u32 Stack[44]; u32 add = SetUpStack.Call(Stack, Stack + 0x18, 0x10); @@ -97,7 +101,7 @@ Gets npc data for anim mods, coord mods, etc 0xB6F9B4 std::string NPCRace = ""; - Process::ReadString(Stack[1] + Fix.addr, NPCRace, 0x20, StringFormat::Utf16); + Process::ReadString(Stack[1] + fixOffset, NPCRace, 0x20, StringFormat::Utf16); return NPCRace.empty() ? "???" : NPCRace; } diff --git a/Sources/Item/Item.cpp b/Sources/Item/Item.cpp index 04d88881..58bda386 100644 --- a/Sources/Item/Item.cpp +++ b/Sources/Item/Item.cpp @@ -64,8 +64,15 @@ namespace CTRPluginFramework { u16 itemID = SetUpItem.Call(&ID); SetUp.Call(*(u32 *)Address(0x95EEDC).addr, add, (char *)"STR_Item_name", itemID); + u8 fixOffset = 0; + //No clue why, but the USA and EUR version have some formatting string parts at the beginning of the NPC race string which we need to skip + if (Address::IsRegion(Address::Region::USA) || Address::IsRegion(Address::Region::USAWA) + || Address::IsRegion(Address::Region::EUR) || Address::IsRegion(Address::Region::EURWA)) { + fixOffset = 0xC; + } + std::string itemName = ""; - Process::ReadString(Stack[1] + 0xC, itemName, 0x30, StringFormat::Utf16); + Process::ReadString(Stack[1] + fixOffset, itemName, 0x30, StringFormat::Utf16); if (itemName.empty()) { return "???"; @@ -92,17 +99,27 @@ namespace CTRPluginFramework { return (IS(ID, 0x2001) || IS(ID, 0x3729) || RANGE(ID, 0x334C, 0x33A2)); } + static std::string toLower(const std::string& s) { + std::string out = s; + + std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c){ + return std::tolower(c); + }); + return out; + } + bool Item::searchByKeyword(const std::string& keyword, ItemNamePack& foundItem) { ItemNamePack partialMatch; bool hasPartial = false; + std::string keyLower = toLower(keyword); + for (u16 id = 0; id < 0x372B; ++id) { Item item(id); const std::string& name = item.GetName(); + std::string nameLower = toLower(name); - size_t pos = name.find(keyword); - - if (pos != std::string::npos) { + if (nameLower.find(keyLower) != std::string::npos) { if (!hasPartial) { partialMatch = {name, id}; hasPartial = true; @@ -110,7 +127,7 @@ namespace CTRPluginFramework { } // exact match - if (name == keyword) { + if (nameLower == keyLower) { foundItem = {name, id}; return true; } @@ -125,11 +142,16 @@ namespace CTRPluginFramework { } bool Item::searchAllByKeyword(const std::string& keyword, std::vector& foundItems) { - for (u16 id = 0; id <= 0x372B; ++id) { + std::string keyLower = toLower(keyword); + + for (u16 id = 0; id <= 0x372B; ++id) { Item item(id); - if (item.GetName().find(keyword) != std::string::npos) { - foundItems.push_back(ItemNamePack{item.GetName(), id}); - } + std::string name = item.GetName(); + std::string nameLower = toLower(name); + + if (nameLower.find(keyLower) != std::string::npos) { + foundItems.push_back(ItemNamePack{name, id}); + } } return !foundItems.empty(); } diff --git a/Sources/MenuCreate.cpp b/Sources/MenuCreate.cpp index 1fad9d23..f5338218 100644 --- a/Sources/MenuCreate.cpp +++ b/Sources/MenuCreate.cpp @@ -432,6 +432,7 @@ namespace CTRPluginFramework { DEFAULTC->Append(new MenuEntry("Disable Non Seed Item Check", nullptr, DisableNonSeedItemCheckEntry, "")), DEFAULTC->Append(new MenuEntry("Patch Drop Function", nullptr, PatchDropFunctionEntry, "")), + DEFAULTC->Append(new MenuEntry("Fix Invalid Badge Crash", nullptr, CheckInvalidBadgeEntry, "")), DEFAULTC->Append(new MenuEntry("Disable Open Save Menu With Start Button", nullptr, DisableOpenSaveMenuWithStartButton, "")), DEFAULTC->Append(new MenuEntry("Disable Catalog Search Function", nullptr, DisableCatalogSearchFunction, "")), DEFAULTC->Append(new MenuEntry("Fix Invalid Pickup Crash", nullptr, FixInvalidPickupCrash, "")),