/// <summary> /// Toggles party mode status, adds/removes an overlay covering the screen which will rotate all of the colours. /// </summary> public void Toggle_Party_Mode() { if (PartyModeEnabled) { // Remove the additional function pointer assigned to the delegate to render the box during the game menu editing. Program.Sonic_Heroes_Overlay.direct2DRenderMethod -= Draw_Overlay; PartyModeEnabled = false; } else { // Add a function pointer to the delegate delegate to render the box during the game menu editing. Program.Sonic_Heroes_Overlay.direct2DRenderMethod += Draw_Overlay; // Play the song "Diamond in The Sky" Invoke_External_Class.Play_Song(Pointer_DiamondInTheSky); // Disable The Character voices if they are enabled. if (Program.Feature_Toggle_Character_Chatter_X.Get_CharacterChatter()) { Program.Feature_Toggle_Character_Chatter_X.Toggle_CharacterChatter(); } if (Program.Feature_Toggle_Character_Chatter_X.Get_VoiceComments()) { Program.Feature_Toggle_Character_Chatter_X.Toggle_CharacterCommentChatter(); } // Go Go Go RGB Program.Feature_Cycle_RGB_Colours_X.Toggle_HUE_Cycle_All_Combined(); PartyModeEnabled = true; } }
/// <summary> /// Loads the AFS file, effectively swapping the voices. /// </summary> private void Load_AFS_File(int AFS_Pointer) { // Backup the conditional jump preventing from reloading of AFS file. byte[] OriginalCheck = Program.Sonic_Heroes_Process.ReadMemory((IntPtr)AFS_NO_RELOAD_JUMP_STATEMENT, 2); // NOP the jump which checks/verifies the AFS reloading. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)AFS_NO_RELOAD_JUMP_STATEMENT, new byte[] { 0x90, 0x90 }); // Writes the current offset to the new AFS file name into memory. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)AFS_FILE_NAME_OFFSET_LOCATION_MEMORY, BitConverter.GetBytes(AFS_Pointer)); // Reads the current song name string for backup purposes. int String_Length = 0; while ((Program.Sonic_Heroes_Process.ReadMemory <byte>((IntPtr)ADX_CURRENT_SONG_NAME_MEMORY + String_Length, 1)) != 0) { String_Length += 1; } string Original_Song_Name = Encoding.ASCII.GetString(Program.Sonic_Heroes_Process.ReadMemory((IntPtr)0xA6DB8A, String_Length)); // Load the currently set AFS File. Invoke_External_Class.Load_AFS_Language_File(); // Rewrite the song name string in memory after it being wiped by the AFS loading function. List <byte> Original_Song_Bytes = Encoding.ASCII.GetBytes(Original_Song_Name).ToList(); Original_Song_Bytes.Add(0x00); // Just in case, add additional null terminator. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)ADX_CURRENT_SONG_NAME_MEMORY, Original_Song_Bytes.ToArray()); // Restart the last playing music track. Invoke_External_Class.Play_Song(ADX_CURRENT_SONG_NAME_MEMORY); // Restore the original check if an AFS file is already loaded. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)AFS_NO_RELOAD_JUMP_STATEMENT, OriginalCheck); }
/// <summary> /// Hit the payload. /// </summary> private void Payload_II() { if (!Emerald_Coast_Trigger_Activated) { // Secretly put us back in the main menu if we are in a stage. Invoke_External_Class.Exit_Stage_X(); Emerald_Coast_Trigger_Activated = true; } }
/// <summary> /// Plays ADX which contains in its name the passed in string. Calls C++ Function with our own pointer to the music track. /// </summary> public void Play_ADX_Track(string ADXName) { for (int x = 0; x < BGM_List.Count; x++) { if (BGM_List[x].Song_Name.Contains(ADXName)) { Invoke_External_Class.Play_Song(BGM_List[x].Song_Pointer); break; } } }
/// <summary> /// Draws the overlay if necessary, i.e. if character is in a level. /// </summary> /// <param name="DirectX_Graphics_Window"></param> private void Draw_Overlay(WindowRenderTarget DirectX_Graphics_Window) { // Get Information of whether the overlay should be shown. byte Is_Currently_In_Level = Program.Sonic_Heroes_Process.ReadMemory <byte>((IntPtr)SonicHeroesVariables.Game_CurrentState.CurrentlyInLevel, 1); // If the player is in a stage. if (Is_Currently_In_Level == 1) { Draw_Window(DirectX_Graphics_Window); Invoke_External_Class.Play_Song(Pointer_DiamondInTheSky); } }
/// <summary> /// Plays the passed in set combination of "Sound Bank" and "Sound ID" /// </summary> private void Play_Sound_Bank_Internal(int BankID, int BankNumber) { // Standard protection from any game function calling shenanigans. // The way the game reads sound effects from the passed in register is... weird to say the least. try { // Convert the Sound Bank ID into Hexadecimal. string Sound_Bank_Hex = String.Format("{0:X2}", BankID); // Convert the Sound ID in the bank to Hexadecimal. string Sound_Bank_ID_Hex = String.Format("{0:X2}", BankNumber); // Bytes to be pushed onto the register as a method operand. string Bytes_To_Push; // If we are playing from Bank0, set the Bank ID to E0 (This is weird, lol), else reverse sound bank ID. if (Sound_Bank_Hex == "00") { Bytes_To_Push = "E0" + Sound_Bank_ID_Hex; } else { Bytes_To_Push = Sound_Bank_Hex.Reverse_String() + Sound_Bank_ID_Hex; } // If we are not in a level and want to use Bank5, do nothing, it is not loaded. if (Bytes_To_Push.StartsWith("50") && Program.Sonic_Heroes_Process.ReadMemory <byte>((IntPtr)SonicHeroesVariables.Game_CurrentState.CurrentlyInLevel, 1) == 0) { } else { // Convert Hex String to Raw Hex. int Sound_Parameter = Int32.Parse(Bytes_To_Push, System.Globalization.NumberStyles.HexNumber); // Read unknown pointer. int Sound_Pointer = Program.Sonic_Heroes_Process.ReadMemory <int>((IntPtr)0x00A2F8B0, 4); // Play the Sound! Invoke_External_Class.Play_Sound(Sound_Parameter, Sound_Pointer, 1, 1); } } catch { } }
/// <summary> /// Loads a level with a specified ID into the game. /// </summary> public void Load_Level_ID(int LevelID) { // Write Passed in Level ID Program.Sonic_Heroes_Process.WriteMemory((IntPtr)SonicHeroesVariables.Stage_CurrentStage.PlayerStageIDToLoad, BitConverter.GetBytes(LevelID)); Program.Sonic_Heroes_Process.WriteMemory((IntPtr)SonicHeroesVariables.Stage_CurrentStage.PlayerStageChoiceMainMenu, BitConverter.GetBytes(LevelID)); // 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(); } }
/// <summary> /// Loads the currently set bank file at Tsonic_win.EXE+3873BC to act as character voices. /// </summary> private void Reload_Bank3_II() { // In the case the game function returns an unexpected value (it shouldn't). try { // Remove the onframe safety toggle. Program.Sonic_Heroes_Overlay.direct2DOnframeDelegate -= Reload_Bank3_II; // Convert desired track name to list of bytes. List <byte> TrackNameASCII = Encoding.ASCII.GetBytes("sound\\" + Get_Current_Bank3_PAC_Name()).ToList(); // Add null terminator TrackNameASCII.Add(0x00); // Write bank name to memory. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)FILE_BANK3_LOCATION_MEMORY, TrackNameASCII.ToArray()); // Backup and remove check preventing a file to be loaded again. byte[] Backup_Array = Program.Sonic_Heroes_Process.ReadMemory((IntPtr)BRANCH_CHECK_DO_NOT_RELOAD_FILES, 6); // Remove the ASM check which prevents the game from reloading the Bank3 file. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)BRANCH_CHECK_DO_NOT_RELOAD_FILES, new byte[] { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }); // Retrieve the this* pointer that is to be passed to the method. int ProgramX = Program.Sonic_Heroes_Process.ReadMemory <int>((IntPtr)0x00A2F8B0, 4); // Load the sound bank into bank3 using C++ P/Invoke and Inline Assembly. Invoke_External_Class.Reload_Bank3(ProgramX); // Restore file reload branch instruction. Program.Sonic_Heroes_Process.WriteMemory((IntPtr)BRANCH_CHECK_DO_NOT_RELOAD_FILES, Backup_Array); } catch (Exception Ex) { // Send details of exception to the mod loader server. Program.Sonic_Heroes_Networking_Client.SendData_Alternate(Message_Type.Client_Call_Send_Message, Encoding.ASCII.GetBytes("[DEBUG] " + Program.Mod_Name + " | Reload Bank3 Function, Bank Utilities Class, Exception Thrown: " + Ex.Message), false); } }
/// <summary> /// Plays the currently selected ADX track. Calls C++ Function with our own pointer to the music track. /// </summary> public void Play_ADX_Track() { Invoke_External_Class.Play_Song(BGM_List[Current_ADX_Track].Song_Pointer); }
static void Main() { try { // Set Culture System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US"); ////////////// MOD LOADER DLL SKELETON CODE /////////////////////////////////////////////////////////////////////////////////////////////////// AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(SonicHeroes.Misc.SonicHeroes_Miscallenous.CurrentDomain_SetAssemblyResolve); Sonic_Heroes_Networking_Client.SetupClient(IPAddress.Loopback); /// Set up networking with the Sonic Heroes Mod Loader. byte[] Response = Sonic_Heroes_Networking_Client.SendData_Alternate(Message_Type.Client_Call_Send_Message, Encoding.ASCII.GetBytes(Mod_Name + " | Loading... OK!"), true); /// Say to the Mod Loader that we have loaded so the end user can know. Sonic_Heroes_Process = Process.GetCurrentProcess(); /// We will use this for reading and writing memory. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Enable Aero Glass if Disabled // Check to see if composition is Enabled if (!Invoke_External_Class.DwmIsCompositionEnabled()) { Invoke_External_Class.DwmEnableComposition(true); } // Sets up DirectX & Direct2D Sonic_Heroes_Overlay = new SonicHeroes.Overlay.Overlay_External_Direct2D(); Sonic_Heroes_Overlay.Initialize_DirectX(); Sonic_Heroes_Overlay.direct2DRenderMethod = Draw_DirectX; Windows_Form_Thread = new Thread(() => { while (true) { Application.Run(Sonic_Heroes_Overlay.overlayWinForm); } }); Windows_Form_Thread.Start(); // Get Original OnFrame Controller Poll Instruction (Used for Controller Disabling) Original_Controller_Call_OnFrame = Sonic_Heroes_Process.ReadMemory((IntPtr)SonicHeroes_Functions.Controller_Polling_Functions.Master_Function_Control_OnFrame_Call, 5); // Initialize Controller Controller_Manager = new DirectInput_Joystick_Manager(); // Initialize Thread to Update Controller Inputs. Heroes_Controller_Update_Thread = new Thread(() => { while (true) { Controller_Poll_Method(); Thread.Sleep(16); } } ); // Initialize Thread to Update GUI Heroes_GUI_Update_Thread = new Thread(() => { while (true) { DirectX_Render_Method(); Thread.Sleep(16); } }); // Run the Two Individual Threads Heroes_GUI_Update_Thread.Start(); Heroes_Controller_Update_Thread.Start(); // Initialize Features Feature_PAC_Clip_Player_X = new Feature_PAC_Utilities(); Feature_Force_Load_Level_X = new Feature_Force_Load_Level(); Feature_ADX_Player_X = new Feature_ADX_Utilities(); Feature_AFS_Utilities_X = new Feature_AFS_Utilities(); Feature_Toggle_Character_Chatter_X = new Feature_Toggle_Character_Chatter(); Feature_Toggle_Music_OnPause_X = new Feature_Toggle_Music_OnPause(); Feature_Physics_Swapper_X = new Feature_Physics_Swap(); Feature_Magnetic_Barrier_X = new Feature_Magnetic_Barrier(); Feature_Party_Mode_X = new Feature_Party_Mode(); Feature_Toggle_Moveset_Restrictions_X = new Feature_Toggle_Moveset_Restrictions(); Feature_Invisibility_Fixes_X = new Feature_Invisbility_Fixes(); Feature_Cycle_RGB_Colours_X = new Feature_Cycle_RGB_Colours(); Feature_Minimal_HUD_X = new Feature_Minimal_HUD(); Feature_Trail_Editor_X = new Feature_Trail_Editor(); Feature_Toggle_Super_Metal_Characters_X = new Feature_Toggle_Super_Metal_Characters(); Feature_Position_XYZ_Window_X = new Feature_Position_XYZ_Window(); Feature_Enhanced_Debug_Movement_Mode_X = new Feature_Enhanced_Debug_Movement_Mode(); Feature_Set_Editor_X = new Feature_SET_Editor(); Feature_Enhanced_FOV_Fix_X = new Feature_Enhanced_FOV_Fix(); Feature_Enhanced_FOV_Fix_X.Button_Set_FOV_Aspect_Ratio_Fix(); // Initialize Menus Menu_Main = new Menu_Main_Menu(); Menu_Sound_Test = new Menu_Sound_Test(); Menu_Graphics_Tweaks = new Menu_Graphics_Tweaks(); Menu_Trail_Editor = new Menu_Trail_Editor(); Menu_Miscallenous = new Menu_Misc_Menu(); Menu_Moveset_Tweaks = new Menu_Moveset_Tweaks(); Menu_Experiments = new Menu_Experiments(); Menu_Gameplay_Items = new Menu_Gameplay_Items(); Menu_Physics_Swapper = new Menu_Physics_Swapper(); Menu_Debug_Stuff = new Menu_Debug_Stuff(); Menu_HUD_Adjustments = new Menu_HUD_Adjustments(); // Set the current startup menu. Current_Menu = Menu_Main; // Load Station Square Feature_Toggle_Character_Chatter_X.Toggle_CharacterChatter(); Feature_Toggle_Character_Chatter_X.Toggle_CharacterCommentChatter(); } catch (Exception Ex) { Sonic_Heroes_Networking_Client.SendData_Alternate(Message_Type.Client_Call_Send_Message, Encoding.ASCII.GetBytes(Mod_Name + " Failed To Load: " + Ex.Message + " | " + Ex.StackTrace), false); } }