public Feature_Force_Load_Level() { // Retrieves all of the available possible levels that could be loaded, as well as their individual Stage IDs. Get_All_Levels(); /// <summary> /// x86 Mnemonics which dynamically load the appropriate blending address based on the currently controlling character. /// </summary> string[] Menu_Enter_Hook_ASM_Mnemonics = new string[] { "use32", "mov eax,[edi+0x58]", "push dword 0x40578D", "ret" }; // Get Assembly Code for the Mnemonics byte[] Menu_Enter_Hook_ASM_Bytes = Program.Sonic_Heroes_Networking_Client.SendData_Alternate(Message_Type.Client_Call_Assemble_x86_Mnemonics, Serialize_x86_ASM_Mnemonics(Menu_Enter_Hook_ASM_Mnemonics), true); // Set Hook - Hooked at random address triggered post loading of main menu. Menu_Enter_Hook_ASM = new SonicHeroes.Hooking.ASM_Hook((IntPtr)0x405785, Menu_Enter_Hook_ASM_Bytes, 8, Program.Sonic_Heroes_Networking_Client, true); // Activate Hook Such that Menu_Enter_Hook Picks up the New Bytes. Menu_Enter_Hook_ASM.Activate(); // Set Hook - Hooked at random address triggered post loading of main menu. Menu_Enter_Hook = new SonicHeroes.Hooking.Injection((IntPtr)0x405785, (Force_Level_Load_Hook)Force_Load_Level_Method, 8, Program.Sonic_Heroes_Networking_Client, false); // Deactivate Hook. Menu_Enter_Hook_ASM.Deactivate(); // At startup set initial teams to be Team Sonic for P1 and disable others Program.Sonic_Heroes_Process.WriteMemory((IntPtr)0x8D6920, new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); }
/// <summary> /// Sets up TrickScore X & Y Positions to become available configurable as Memory addresses rather than hardcoded. /// </summary> private void Setup_TrickScore_XYPosition() { // Get bytes for new location of X & Y Trick Score Positions ADDRESS_TRICKSCORE_HUD_XPOSITION = (int)Program.Sonic_Heroes_Process.AllocateMemory(4); ADDRESS_TRICKSCORE_HUD_YPOSITION = (int)Program.Sonic_Heroes_Process.AllocateMemory(4); // Write Default Values to Addresses float DefaultX = 0.06562499702F; float DefaultY = 0.7333300114F; // Write Defaults to memory. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)ADDRESS_TRICKSCORE_HUD_XPOSITION, BitConverter.GetBytes(DefaultX)); Program.Sonic_Heroes_Process.WriteMemory((IntPtr)ADDRESS_TRICKSCORE_HUD_YPOSITION, BitConverter.GetBytes(DefaultY)); // Assemble code to Move X & Y Trick Source Location from Memory rather than hardcoding.. string[] Get_From_New_XLocation = new string[] { "use32", "push edi", "push esi", "mov esi, " + "[" + ADDRESS_TRICKSCORE_HUD_XPOSITION + "]", "mov edi, " + "[" + ADDRESS_TRICKSCORE_HUD_YPOSITION + "]", "mov dword [esp+0x20], esi", "mov dword [esp+0x24], edi", "pop esi", "pop edi", }; // Get Assembly Code for the Mnemonics byte[] Get_From_NewX = Program.Sonic_Heroes_Networking_Client.SendData_Alternate(Message_Type.Client_Call_Assemble_x86_Mnemonics, Serialize_x86_ASM_Mnemonics(Get_From_New_XLocation), true); // Overwrite old instructions scoreInjection = new SonicHeroes.Hooking.ASM_Hook((IntPtr)0x5B499C, Get_From_NewX, 20, Program.Sonic_Heroes_Networking_Client, true); scoreInjection.Activate(); }
/// <summary> /// Attempts to forcefully load a level into the current game. /// </summary> public void Force_Load_Level() { // Write requested stage to memory. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)SonicHeroesVariables.Stage_CurrentStage.PlayerStageIDToLoad, BitConverter.GetBytes(Stage_Entry_List[Stage_Enum_Index].Stage_ID)); Program.Sonic_Heroes_Process.WriteMemory((IntPtr)SonicHeroesVariables.Stage_CurrentStage.PlayerStageChoiceMainMenu, BitConverter.GetBytes(Stage_Entry_List[Stage_Enum_Index].Stage_ID)); // Check if in level. byte In_Level = Program.Sonic_Heroes_Process.ReadMemory <byte>((IntPtr)SonicHeroes.Variables.SonicHeroesVariables.Game_CurrentState.CurrentlyInLevel, 1); if (In_Level == 1) { // Secretly put us back in the main menu if we are in a stage. Invoke_External_Class.Exit_Stage_X(); Menu_Enter_Hook_ASM.Activate(); Menu_Enter_Hook.Activate(); } else { Force_Load_Level_Method(); } }