├── .gitattributes ├── .gitignore ├── .gitmodules ├── CharacterSelectPlus.sln ├── CharacterSelectPlus ├── Base.cpp ├── Base.h ├── BossTitles.cpp ├── BossTitles.h ├── CharacterSelectPlus.cpp ├── CharacterSelectPlus.vcxproj ├── CharacterSelectPlus.vcxproj.filters ├── RankVoices.cpp ├── RankVoices.h ├── config.cpp ├── defs.h ├── dllmain.cpp ├── mod.h ├── old.cpp ├── sa2-util.h ├── set-file.cpp ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── util.cpp └── util.h ├── README.md └── Resources ├── PRS ├── missiontex_am.pak ├── missiontex_am2.pak ├── missiontex_c0.pak ├── missiontex_c02.pak ├── missiontex_ch.pak ├── missiontex_ch2.pak ├── missiontex_dc.pak ├── missiontex_dc2.pak ├── missiontex_me.pak ├── missiontex_me2.pak ├── missiontex_ti.pak ├── missiontex_ti2.pak └── stageMap.pak └── set ├── set0005_s.bin ├── set0005_u.bin ├── set0007_s.bin ├── set0007_u.bin ├── set0008_s.bin ├── set0008_u.bin ├── set0016_s.bin ├── set0016_u.bin ├── set0018_s.bin ├── set0018_u.bin ├── set0026_s.bin ├── set0026_u.bin ├── set0032_s.bin └── set0044_s.bin /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sa2-mod-loader"] 2 | path = sa2-mod-loader 3 | url = https://github.com/X-Hax/sa2-mod-loader 4 | [submodule "mod-loader-common"] 5 | path = mod-loader-common 6 | url = https://github.com/X-Hax/mod-loader-common 7 | -------------------------------------------------------------------------------- /CharacterSelectPlus.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29418.71 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CharacterSelectPlus", "CharacterSelectPlus\CharacterSelectPlus.vcxproj", "{D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B} = {EC0293F5-4BCF-46B2-8133-18CAEA141C5B} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmodutils", "sa2-mod-loader\libmodutils\libmodutils.vcxproj", "{83C0F6B3-2297-4A14-98D6-F9C3E99192CE}" 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModLoaderCommon", "sa2-mod-loader\mod-loader-common\ModLoaderCommon\ModLoaderCommon.vcxproj", "{EC0293F5-4BCF-46B2-8133-18CAEA141C5B}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Debug|Win32 = Debug|Win32 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|Any CPU = Release|Any CPU 22 | Release|Win32 = Release|Win32 23 | Release|x64 = Release|x64 24 | Release|x86 = Release|x86 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Debug|Any CPU.ActiveCfg = Debug|Win32 28 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Debug|Win32.ActiveCfg = Debug|Win32 29 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Debug|Win32.Build.0 = Debug|Win32 30 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Debug|x64.ActiveCfg = Debug|x64 31 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Debug|x64.Build.0 = Debug|x64 32 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Debug|x86.ActiveCfg = Debug|Win32 33 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Debug|x86.Build.0 = Debug|Win32 34 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Release|Any CPU.ActiveCfg = Release|Win32 35 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Release|Win32.ActiveCfg = Release|Win32 36 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Release|Win32.Build.0 = Release|Win32 37 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Release|x64.ActiveCfg = Release|x64 38 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Release|x64.Build.0 = Release|x64 39 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Release|x86.ActiveCfg = Release|Win32 40 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5}.Release|x86.Build.0 = Release|Win32 41 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Debug|Any CPU.ActiveCfg = Debug|Win32 42 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Debug|Win32.ActiveCfg = Debug|Win32 43 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Debug|Win32.Build.0 = Debug|Win32 44 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Debug|x64.ActiveCfg = Debug|Win32 45 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Debug|x86.ActiveCfg = Debug|Win32 46 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Debug|x86.Build.0 = Debug|Win32 47 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Release|Any CPU.ActiveCfg = Release|Win32 48 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Release|Win32.ActiveCfg = Release|Win32 49 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Release|Win32.Build.0 = Release|Win32 50 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Release|x64.ActiveCfg = Release|Win32 51 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Release|x86.ActiveCfg = Release|Win32 52 | {83C0F6B3-2297-4A14-98D6-F9C3E99192CE}.Release|x86.Build.0 = Release|Win32 53 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|Any CPU.ActiveCfg = Debug|Win32 54 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|Win32.ActiveCfg = Debug|Win32 55 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|Win32.Build.0 = Debug|Win32 56 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|x64.ActiveCfg = Debug|Win32 57 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|x86.ActiveCfg = Debug|Win32 58 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Debug|x86.Build.0 = Debug|Win32 59 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|Any CPU.ActiveCfg = Release|Win32 60 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|Win32.ActiveCfg = Release|Win32 61 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|Win32.Build.0 = Release|Win32 62 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|x64.ActiveCfg = Release|Win32 63 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|x86.ActiveCfg = Release|Win32 64 | {EC0293F5-4BCF-46B2-8133-18CAEA141C5B}.Release|x86.Build.0 = Release|Win32 65 | EndGlobalSection 66 | GlobalSection(SolutionProperties) = preSolution 67 | HideSolutionNode = FALSE 68 | EndGlobalSection 69 | GlobalSection(ExtensibilityGlobals) = postSolution 70 | SolutionGuid = {1220F2E5-23F7-481B-8FC6-B01679392B62} 71 | EndGlobalSection 72 | EndGlobal 73 | -------------------------------------------------------------------------------- /CharacterSelectPlus/Base.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "SA2ModLoader.h" 3 | #include "IniFile.hpp" 4 | #include "Base.h" 5 | #include 6 | #include 7 | #include 8 | 9 | using std::vector; 10 | using std::string; 11 | using std::unordered_map; 12 | using std::transform; 13 | 14 | static Trampoline* GoalRing_t = nullptr; 15 | 16 | #pragma region Cutscene stuff 17 | 18 | LevelCutscene* const stru_173A808 = (LevelCutscene*)0x173A808; 19 | signed int __cdecl sub_458970() 20 | { 21 | signed int v0; // ecx@3 22 | unsigned int v1; // eax@6 23 | 24 | if (MainCharObj2[0]) 25 | v0 = MainCharObj2[0]->CharID2; 26 | else 27 | v0 = -1; 28 | if (v0 >= Characters_Amy) return 0; 29 | if (AltCostume[0]) return 0; 30 | if (MainCharObj2[1] && MainCharObj2[1]->CharID2 >= Characters_Amy) return 0; 31 | if (MainCharObj2[1] && AltCostume[1]) return 0; 32 | if (*(char*)0x1DEB321 && *(char*)0x1DEB320) 33 | { 34 | v1 = 0; 35 | while (stru_173A808[v1].Level != (signed __int16)CurrentLevel 36 | || stru_173A808[v1].Character != v0) 37 | { 38 | v1++; 39 | if (v1 >= 15) 40 | return 0; 41 | } 42 | return 1; 43 | } 44 | else 45 | return 0; 46 | } 47 | 48 | #pragma endregion 49 | #pragma region Somersault fixes 50 | 51 | // Fix 1 52 | #define Texlist_SonEff 0xA08B94 53 | #define Texlist_ShadEff 0xA08D94 54 | #define Texlist_AmyEff 0xA08F94 55 | #define Texlist_MetEff 0xA0917C 56 | const int loc_75783C = 0x75783C; 57 | __declspec(naked) void __cdecl sub_757810() 58 | { 59 | __asm 60 | { 61 | mov eax, [esp + 4] 62 | mov eax, [eax]ObjectMaster.Data2 63 | movsx ecx, [eax].CharID 64 | mov edx, MainCharObj2 65 | mov edx, [edx + ecx * 4] 66 | mov ecx, 0xA0B3B8 67 | mov dl, [edx].CharID2 68 | cmp dl, Characters_Sonic 69 | jnz NotSonic 70 | mov dword ptr[ecx], Texlist_SonEff 71 | jmp loc_75783C 72 | 73 | NotSonic : 74 | cmp dl, Characters_Shadow 75 | jnz NotShadow 76 | mov dword ptr[ecx], Texlist_ShadEff 77 | jmp loc_75783C 78 | 79 | NotShadow : 80 | cmp dl, Characters_Amy 81 | jnz NotAmy 82 | mov dword ptr[ecx], Texlist_AmyEff 83 | jmp loc_75783C 84 | 85 | NotAmy : 86 | mov dword ptr[ecx], Texlist_MetEff 87 | jmp loc_75783C 88 | } 89 | } 90 | 91 | // Fix 2 92 | 93 | const int loc_759A3C = 0x759A3C; 94 | __declspec(naked) void loc_759A18() 95 | { 96 | __asm 97 | { 98 | movsx eax, [eax].CharID2 99 | mov ecx, 0x2670544 100 | mov ecx, [ecx] 101 | cmp eax, Characters_Sonic 102 | jne short NotSonic 103 | mov dword ptr[ecx + 20h], Texlist_SonEff 104 | jmp loc_759A3C 105 | 106 | NotSonic : 107 | cmp eax, Characters_Shadow 108 | jne short NotShadow 109 | mov dword ptr[ecx + 20h], Texlist_ShadEff 110 | jmp loc_759A3C 111 | 112 | NotShadow : 113 | cmp eax, Characters_Amy 114 | jne short NotAmy 115 | mov dword ptr[ecx + 20h], Texlist_AmyEff 116 | jmp loc_759A3C 117 | 118 | NotAmy : 119 | mov dword ptr[ecx + 20h], Texlist_MetEff 120 | jmp loc_759A3C 121 | } 122 | } 123 | 124 | #pragma endregion 125 | #pragma region Start Positions 126 | 127 | #pragma warning(disable : 4838) 128 | StartPosition KnucklesStart[] = { 129 | { LevelIDs_BasicTest }, 130 | { LevelIDs_PumpkinHill, 0xD000u, 0xD000u, 0xD000u, { 199, -1361, -1035 }, { 188.63f, -1361, -1045 }, { 208.3f, -1361, -1021.5f } }, 131 | { LevelIDs_AquaticMine, 0x4000, 0x4000, 0x4000, { 0, 155, -233 }, { 10, 155, -233 }, { -10, 155, -233 } }, 132 | { LevelIDs_WildCanyon, 0x4000, 0x4000, 0x4000, { 200, 100, -400 }, { 220, 65.2f, -400 }, { 180, 65.2f, -400 } }, 133 | { LevelIDs_DeathChamber, 0xA000u, 0x8000u, 0xC000u, { 870, 70, 870 }, { 0, 240, 180 }, { 180, 240, 0 } }, 134 | { LevelIDs_KingBoomBoo, 0, 0, 0, { 276, -40, 190 }, { 276, -40, 190 }, { 276, -40, 190 } }, 135 | { LevelIDs_KnucklesVsRouge, 0, 0, 0, { -20, 0, 0 }, { -20, 0, 0 }, { -20, 0, 0 } }, 136 | { LevelIDs_WildCanyon2P, 0x4000, 0x4000, 0x4000, { 200, 100, -400 }, { 220, 66, -345 }, { 180, 66, -345 } }, 137 | { LevelIDs_CannonsCoreK, 0x8000u, 0x8000u, 0x8000u, { 0, 580, 60 }, { 0, 580, 60 }, { 0, 580, 60 } }, 138 | { LevelIDs_MeteorHerd, 0x4000, 0x4000, 0x4000, { 0, -450, -1025 }, { 25, -450, -1025 }, { -25, -450, -1025 } }, 139 | { LevelIDs_DryLagoon2P, 0x4000, 0x4000, 0x4000, { 220, 210, 1350 }, { 225, 480, 1325 }, { 185, 480, 1325 } }, 140 | { LevelIDs_PoolQuest, 0x4000, 0x4000, 0x4000, { 0, 155, -233 }, { 10, 155, -233 }, { -10, 155, -233 } }, 141 | { LevelIDs_PlanetQuest, 0, 0x4000, 0x4000, { 0, 660, 0 }, { -470, 1500, -630 }, { -430, 1500, -630 } }, 142 | { LevelIDs_SecurityHall, 0xA000u, 0xA000u, 0xE000u, { 405, -830, 410 }, { 405, -830, 410 }, { -405, -830, 410 } }, 143 | { LevelIDs_EggQuarters, 0xA000u, 0xC000u, 0xC000u, { 940, -30, 940 }, { 20, 110, 40 }, { -20, 110, 40 } }, 144 | { LevelIDs_MadSpace, 0x7000, 0xC000u, 0xC000u, { 0, 660, 0 }, { 30, 630, 17 }, { 0, 630, -35 } }, 145 | { LevelIDs_DeathChamber2P, 0xA000u, 0x8000u, 0xC000u, { 870, 70, 870 }, { 0, 240, 180 }, { 180, 240, 0 } }, 146 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { 0, -400, -910 }, { -40, -400, -910 }, { 40, -400, -910 } }, 147 | { LevelIDs_Invalid } 148 | }; 149 | 150 | StartPosition MechEggmanStart[] = { 151 | { LevelIDs_BasicTest }, 152 | { LevelIDs_IronGate }, 153 | { LevelIDs_WeaponsBed, 0xC000u, 0xC000u, 0xC000u, { 0 }, { 10, 0, 0 }, { -10, 0, 0 } }, 154 | { LevelIDs_WeaponsBed2P, 0xC000u, 0xC000u, 0x4000, { 50, -170, 50 }, { 20, -170, 95 }, { 20, -170, -95 } }, 155 | { LevelIDs_TailsVsEggman1, 0xB200u, 0xB200u, 0xB200u, { 50, -170, 50 }, { 50, -170, 50 }, { 50, -170, 50 } }, 156 | { LevelIDs_SandOcean, 0xC000u, 0xC000u, 0xC000u, { 0, 80, 0 }, { 0, 80, 0 }, { 0, 80, 0 } }, 157 | { LevelIDs_EternalEngine, 0xC000u, 0xC000u, 0xC000u, { 0, 370, 0 }, { 0, 370, 0 }, { 0, 370, 0 } }, 158 | { LevelIDs_LostColony, 0xC000u, 0xC000u, 0xC000u, { 0, -175, 29 }, { 0, -175, 29 }, { 0, -175, 29 } }, 159 | { LevelIDs_TailsVsEggman2, 0xB200u, 0xB200u, 0xB200u, { 50, -50, 80 }, { 50, -50, 80 }, { 50, -50, 80 } }, 160 | { LevelIDs_MissionStreet2P, 0, 0, 0x8000u, { -520, 0, 0 }, { -520, 0, 0 }, { 0 } }, 161 | { LevelIDs_EggGolemE, 0, 0, 0, { 0, 200, 210 }, { 0, 200, 210 }, { 0, 200, 210 } }, 162 | { LevelIDs_CannonsCoreE, 0xC000u, 0xC000u, 0xC000u, { 0, 20.1f, -200 }, { 0, 20.1f, -200 }, { 0, 20.1f, -200 } }, 163 | { LevelIDs_SandOcean2P, 0, 0, 0x8000u, { -60, 35, 0 }, { -60, 35, 0 }, { 60, 35, 0 } }, 164 | { LevelIDs_CosmicWall }, 165 | { LevelIDs_DeckRace, 0xC000u, 0xC000u, 0xC000u, { 0 }, { -15, -170, 1480 }, { 15, -170, 1480 } }, 166 | { LevelIDs_LostColony2P, 0, 0, 0x8000u, { -280, 150, 280 }, { -280, 150, 280 }, { 280, 150, -280 } }, 167 | { LevelIDs_PyramidRace, 0, 0xC000u, 0xC000u, { 0 }, { -35, 10, -20 }, { 35, 10, -20 } }, 168 | { LevelIDs_HiddenBase2P, 0, 0, 0x8000u, { 60, 0, 10 }, { -60, 0, 10 }, { 60, 0, 10 } }, 169 | { LevelIDs_CosmicWall2P, 0, 0, 0x8000u, { -80, 0, 0 }, { -80, 0, 0 }, { 80, 0, 5 } }, 170 | { LevelIDs_EternalEngine2P, 0x4000, 0x4000, 0xC000u, { 0, -50, -120 }, { 0, -50, -120 }, { 0, -50, 120 } }, 171 | { LevelIDs_IronGate2P, 0, 0, 0x8000u, { 0 }, { -50, -10, -20 }, { 50, -10, -20 } }, 172 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { 0, 0, -1330 }, { -40, 0, -1330 }, { 40, 0, -1330 } }, 173 | { LevelIDs_Invalid } 174 | }; 175 | 176 | StartPosition MechTailsStart[] = { 177 | { LevelIDs_BasicTest }, 178 | { LevelIDs_PrisonLane, 0x8000u, 0x8000u, 0x8000u, { 115, 10, 4 }, { 115, 10, 4 }, { 115, 10, 4 } }, 179 | { LevelIDs_WeaponsBed, 0xC000u, 0xC000u, 0xC000u, { 0 }, { 10, 0, 0 }, { -10, 0, 0 } }, 180 | { LevelIDs_WeaponsBed2P, 0xC000u, 0xC000u, 0x4000, { 50, -170, 50 }, { 20, -170, 95 }, { 20, -170, -95 } }, 181 | { LevelIDs_MissionStreet, 0xC000u, 0xC000u, 0xC000u, { 0, 200, 0 }, { 0, 200, 0 }, { 0, 200, 0 } }, 182 | { LevelIDs_TailsVsEggman1, 0x3800, 0x3800, 0x3800, { 50, -170, -250 }, { 50, -170, -250 }, { 50, -170, -250 } }, 183 | { LevelIDs_HiddenBase, 0xC000u, 0xC000u, 0xC000u, { 0, 140, 0 }, { 0, 140, 0 }, { 0, 140, 0 } }, 184 | { LevelIDs_EternalEngine, 0xC000u, 0xC000u, 0xC000u, { 0, 370, 0 }, { 0, 370, 0 }, { 0, 370, 0 } }, 185 | { LevelIDs_TailsVsEggman2, 0x3800, 0x3800, 0x3800, { 50, -50, -80 }, { 50, -50, -80 }, { 50, -50, -80 } }, 186 | { LevelIDs_MissionStreet2P, 0x8000u, 0, 0x8000u, { 0 }, { -520, 0, 0 }, { 0 } }, 187 | { LevelIDs_CannonsCoreT, 0xC000u, 0xC000u, 0xC000u, { 0, 670, 0 }, { 0, 670, 0 }, { 0, 670, 0 } }, 188 | { LevelIDs_SandOcean2P, 0, 0, 0x8000u, { -60, 35, 0 }, { -60, 35, 0 }, { 60, 35, 0 } }, 189 | { LevelIDs_DeckRace, 0xC000u, 0xC000u, 0xC000u, { 0 }, { -15, -170, 1480 }, { 15, -170, 1480 } }, 190 | { LevelIDs_LostColony2P, 0, 0, 0x8000u, { -280, 150, 280 }, { -280, 150, 280 }, { 280, 150, -280 } }, 191 | { LevelIDs_PyramidRace, 0, 0xC000u, 0xC000u, { 0 }, { -35, 10, -20 }, { 35, 10, -20 } }, 192 | { LevelIDs_HiddenBase2P, 0, 0, 0x8000u, { 60, 0, 10 }, { -60, 0, 10 }, { 60, 0, 10 } }, 193 | { LevelIDs_EternalEngine2P, 0x4000, 0x4000, 0xC000u, { 0, -50, -120 }, { 0, -50, -120 }, { 0, -50, 120 } }, 194 | { LevelIDs_IronGate2P, 0, 0, 0x8000u, { 0 }, { -50, -10, -20 }, { 50, -10, -20 } }, 195 | { LevelIDs_CosmicWall2P, 0, 0, 0x8000u, { -80, 0, 0 }, { -80, 0, 0 }, { 80, 0, 5 } }, 196 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { 0, 0, -1330 }, { -40, 0, -1330 }, { 40, 0, -1330 } }, 197 | { LevelIDs_Invalid } 198 | }; 199 | 200 | StartPosition RougeStart[] = { 201 | { LevelIDs_BasicTest }, 202 | { LevelIDs_PumpkinHill, 0xD000u, 0xD000u, 0xD000u, { 199, -1361, -1035 }, { 188.63f, -1361, -1045 }, { 208.3f, -1361, -1021.5f } }, 203 | { LevelIDs_SecurityHall, 0xA000u, 0xA000u, 0xE000u, { 405, -830, 410 }, { 405, -830, 410 }, { -405, -830, 410 } }, 204 | { LevelIDs_DeathChamber, 0xA000u, 0x8000u, 0xC000u, { 870, 70, 870 }, { 0, 240, 180 }, { 180, 240, 0 } }, 205 | { LevelIDs_EggQuarters, 0xA000u, 0xC000u, 0xC000u, { 940, -30, 940 }, { 20, 110, 40 }, { -20, 110, 40 } }, 206 | { LevelIDs_DryLagoon, 0x4000, 0x4000, 0x4000, { 200, 65, -400 }, { 200, 65, -400 }, { 200, 65, -400 } }, 207 | { LevelIDs_WildCanyon, 0x4000, 0x4000, 0x4000, { 200, 100, -400 }, { 220, 65.2f, -400 }, { 180, 65.2f, -400 } }, 208 | { LevelIDs_KnucklesVsRouge, 0x8000u, 0x8000u, 0x8000u, { 20, 0, 0 }, { 20, 0, 0 }, { 20, 0, 0 } }, 209 | { LevelIDs_WildCanyon2P, 0x4000, 0x4000, 0x4000, { 200, 100, -400 }, { 220, 66, -345 }, { 180, 66, -345 } }, 210 | { LevelIDs_CannonsCoreR, 0xC000u, 0xC000u, 0xC000u, { 0, 480, 150 }, { 0, 480, 150 }, { 0, 480, 150 } }, 211 | { LevelIDs_MeteorHerd, 0x4000, 0x4000, 0x4000, { 0, -450, -1025 }, { 25, -450, -1025 }, { -25, -450, -1025 } }, 212 | { LevelIDs_MadSpace, 0x7000, 0xC000u, 0xC000u, { 0, 660, 0 }, { 30, 630, 17 }, { 0, 630, -35 } }, 213 | { LevelIDs_DryLagoon2P, 0x4000, 0x4000, 0x4000, { 220, 210, 1350 }, { 225, 480, 1325 }, { 185, 480, 1325 } }, 214 | { LevelIDs_PoolQuest, 0x4000, 0x4000, 0x4000, { 0, 155, -233 }, { 10, 155, -233 }, { -10, 155, -233 } }, 215 | { LevelIDs_PlanetQuest, 0, 0x4000, 0x4000, { 0, 660, 0 }, { -470, 1500, -630 }, { -430, 1500, -630 } }, 216 | { LevelIDs_DeathChamber2P, 0xA000u, 0x8000u, 0xC000u, { 870, 70, 870 }, { 0, 240, 180 }, { 180, 240, 0 } }, 217 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { 0, -400, -910 }, { -40, -400, -910 }, { 40, -400, -910 } }, 218 | { LevelIDs_Invalid } 219 | }; 220 | 221 | StartPosition ShadowStart[] = { 222 | { LevelIDs_BasicTest }, 223 | { LevelIDs_GreenForest, 0x4000, 0x4000, 0x4000, { 1.61f, 40, -416 }, { 15, 40, -416 }, { -15, 40, -416 } }, 224 | { LevelIDs_WhiteJungle, 0x4000, 0x4000, 0x4000, { 0, -85, -45 }, { 15, -85, -45 }, { -15, -85, -45 } }, 225 | { LevelIDs_SkyRail, 0x4000, 0x4000, 0x4000, { -9.5f, 800, -526.1438f }, { -9.5f, 800, -526.1438f }, { 8.7f, 800, -526.1438f } }, 226 | { LevelIDs_CityEscape, 0x4000, 0x4000, 0x4000, { 0, 300, 340 }, { 10, 300, 340 }, { -10, 300, 340 } }, 227 | { LevelIDs_MetalHarbor, 0xC000u, 0xC000u, 0xC000u, { 0, 500, 40 }, { 10, 500, 45 }, { -10, 500, 45 } }, 228 | { LevelIDs_MetalHarbor2P, 0xC000u, 0xC000u, 0xC000u, { 0, 500, 40 }, { -10, 500, 45 }, { 10, 500, 45 } }, 229 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { 103, 182, -39 }, { 103, 182, -39 }, { -103, 182, -39 } }, 230 | { LevelIDs_SonicVsShadow1, 0x8000u, 0x8000u, 0x8000u, { 60, 64, 0 }, { 60, 64, 0 }, { 60, 64, 0 } }, 231 | { LevelIDs_CrazyGadget, 0xC000u, 0xC000u, 0xC000u, { 0, 180, 340 }, { 20, 180, 340 }, { -20, 180, 340 } }, 232 | { LevelIDs_FinalHazard, 0, 0, 0, { 0, 0, -1000 }, { 0, 0, -1000 }, { 0, 0, -1000 } }, 233 | { LevelIDs_SonicVsShadow2, 0, 0, 0, { 0, 0, 15 }, { 0, 0, 15 }, { 0, 0, 15 } }, 234 | { LevelIDs_FinalRush, 0, 0, 0, { -100, 0, 0 }, { -100, 0, -25 }, { -100, 0, 25 } }, 235 | { LevelIDs_FinalChase, 0, 0x4000, 0x4000, { -223, -100, 63 }, { 3206, -4000, 2455 }, { 3176, -4000, 2455 } }, 236 | { LevelIDs_GreenHill, 0xC000u, 0xC000u, 0xC000u, { 0, 40, 0 }, { 15, 40, 0 }, { -15, 40, 0 } }, 237 | { LevelIDs_DowntownRace, 0x4000, 0x4000, 0x4000, { -2215, 4320, -4670 }, { -2235, 4320, -4670 }, { -2195, 4320, -4670 } }, 238 | { LevelIDs_GrindRace, 0, 0, 0, { 10, -445, -900 }, { 10, -795, -900 }, { -10, -795, -900 } }, 239 | { LevelIDs_Invalid } 240 | }; 241 | 242 | StartPosition SonicStart[] = { 243 | { LevelIDs_BasicTest }, 244 | { LevelIDs_GreenForest, 0x4000, 0x4000, 0x4000, { 1.61f, 40, -416 }, { 15, 40, -416 }, { -15, 40, -416 } }, 245 | { LevelIDs_SkyRail, 0x4000, 0x4000, 0x4000, { -9.5f, 800, -526.1438f }, { -9.5f, 800, -526.1438f }, { 8.7f, 800, -526.1438f } }, 246 | { LevelIDs_MetalHarbor, 0xC000u, 0xC000u, 0xC000u, { 0, 500, 40 }, { 10, 500, 45 }, { -10, 500, 45 } }, 247 | { LevelIDs_MetalHarbor2P, 0xC000u, 0xC000u, 0xC000u, { 0, 500, 40 }, { -10, 500, 45 }, { 10, 500, 45 } }, 248 | { LevelIDs_CityEscape, 0x4000, 0x4000, 0x4000, { 0, 300, 340 }, { 10, 300, 340 }, { -10, 300, 340 } }, 249 | { LevelIDs_WhiteJungle, 0x4000, 0x4000, 0x4000, { 0, -85, -45 }, { 15, -80, -45 }, { -15, -80, -45 } }, 250 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { 103, 182, -39 }, { 103, 182, -39 }, { -103, 182, -39 } }, 251 | { LevelIDs_SonicVsShadow1, 0, 0, 0, { -60, 64, 0 }, { -60, 64, 0 }, { -60, 64, 0 } }, 252 | { LevelIDs_CrazyGadget, 0xC000u, 0xC000u, 0xC000u, { 0, 180, 340 }, { 20, 180, 340 }, { -20, 180, 340 } }, 253 | { LevelIDs_PyramidCave, 0xC000u, 0xC000u, 0xC000u, { 0, 300, 0 }, { 0, 300, 0 }, { 0, 300, 0 } }, 254 | { LevelIDs_FinalRush, 0, 0, 0, { -100, 0, 0 }, { -100, 0, -25 }, { -100, 0, 25 } }, 255 | { LevelIDs_FinalChase, 0, 0x4000, 0x4000, { -223, -100, 63 }, { 3206, -4000, 2455 }, { 3176, -4000, 2455 } }, 256 | { LevelIDs_CannonsCoreS, 0xC000u, 0xC000u, 0xC000u, { 0, 45, 0 }, { 0, 45, 0 }, { 0, 45, 0 } }, 257 | { LevelIDs_EggGolemS, 0, 0, 0, { 0, 200, 210 }, { 0, 200, 210 }, { 0, 200, 210 } }, 258 | { LevelIDs_FinalHazard, 0, 0, 0, { 0, 0, 1000 }, { 0, 0, 1000 }, { 0, 0, 1000 } }, 259 | { LevelIDs_SonicVsShadow2, 0, 0, 0, { 0, 0, -15 }, { 0, 0, -15 }, { 0, 0, -15 } }, 260 | { LevelIDs_GreenHill, 0xC000u, 0xC000u, 0xC000u, { 0, 40, 0 }, { 15, 40, 0 }, { -15, 40, 0 } }, 261 | { LevelIDs_DowntownRace, 0x4000, 0x4000, 0x4000, { -2215, 4320, -4670 }, { -2235, 4320, -4670 }, { -2195, 4320, -4670 } }, 262 | { LevelIDs_GrindRace, 0, 0, 0, { 10, -445, -900 }, { 10, -795, -900 }, { -10, -795, -900 } }, 263 | { LevelIDs_Invalid } 264 | }; 265 | 266 | StartPosition SuperShadowStart[] = { 267 | { LevelIDs_BasicTest }, 268 | { LevelIDs_FinalHazard, 0, 0, 0, { 0, 0, -1000 }, { 0, 0, -1000 }, { 0, 0, -1000 } }, 269 | { LevelIDs_Invalid } 270 | }; 271 | 272 | StartPosition SuperSonicStart[] = { 273 | { LevelIDs_BasicTest }, 274 | { LevelIDs_FinalHazard, 0, 0, 0, { 0, 0, 1000 }, { 0, 0, 1000 }, { 0, 0, 1000 } }, 275 | { LevelIDs_Invalid } 276 | }; 277 | 278 | StartPosition TailsStart[] = { 279 | { LevelIDs_BasicTest }, 280 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { 0, -400, -910 }, { -40, -400, -910 }, { 40, -400, -910 } }, 281 | { LevelIDs_Invalid } 282 | }; 283 | #pragma warning(default : 4838) 284 | 285 | StartPosition* SonicStartList[] = { SonicStart, ShadowStart, MechTailsStart, MechEggmanStart, KnucklesStart, RougeStart, SuperSonicStart, SuperShadowStart, TailsStart }; 286 | StartPosition* ShadowStartList[] = { ShadowStart, SonicStart, MechEggmanStart, MechTailsStart, RougeStart, KnucklesStart, SuperShadowStart, SuperSonicStart, TailsStart }; 287 | StartPosition* MechTailsStartList[] = { MechTailsStart, MechEggmanStart, SonicStart, ShadowStart, KnucklesStart, RougeStart, SuperSonicStart, SuperShadowStart, TailsStart }; 288 | StartPosition* MechEggmanStartList[] = { MechEggmanStart, MechTailsStart, ShadowStart, SonicStart, RougeStart, KnucklesStart, SuperShadowStart, SuperSonicStart, TailsStart }; 289 | StartPosition* KnucklesStartList[] = { KnucklesStart, RougeStart, SonicStart, ShadowStart, MechTailsStart, MechEggmanStart, SuperSonicStart, SuperShadowStart, TailsStart }; 290 | StartPosition* RougeStartList[] = { RougeStart, KnucklesStart, ShadowStart, SonicStart, MechEggmanStart, MechTailsStart, SuperShadowStart, SuperSonicStart, TailsStart }; 291 | StartPosition* SuperSonicStartList[] = { SuperSonicStart, SuperShadowStart, SonicStart, ShadowStart, MechTailsStart, MechEggmanStart, KnucklesStart, RougeStart, TailsStart }; 292 | StartPosition* SuperShadowStartList[] = { SuperShadowStart, SuperSonicStart, ShadowStart, SonicStart, MechEggmanStart, MechTailsStart, RougeStart, KnucklesStart, TailsStart }; 293 | StartPosition* TailsStartList[] = { TailsStart, SonicStart, ShadowStart, MechTailsStart, MechEggmanStart, KnucklesStart, RougeStart, SuperSonicStart, SuperShadowStart }; 294 | StartPosition* EggmanStartList[] = { TailsStart, ShadowStart, SonicStart, MechEggmanStart, MechTailsStart, RougeStart, KnucklesStart, SuperShadowStart, SuperSonicStart }; 295 | 296 | int __cdecl LoadStartPosition_ri(int playerNum, NJS_VECTOR* position, Rotation* rotation) 297 | { 298 | ObjectMaster* v1; // eax@1 299 | CharObj2Base* v4; // eax@7 300 | StartPosition** list; 301 | StartPosition* v5; // eax@9 302 | int v6; // edx@25 303 | NJS_VECTOR* v8; // edx@35 304 | 305 | v1 = MainCharacter[playerNum]; 306 | if (position) 307 | { 308 | position->z = 0.0; 309 | position->y = 0.0; 310 | position->x = 0.0; 311 | } 312 | if (rotation) 313 | { 314 | rotation->z = 0; 315 | rotation->y = 0; 316 | rotation->x = 0; 317 | } 318 | if (v1) 319 | { 320 | v4 = MainCharObj2[playerNum]; 321 | if (v4) 322 | { 323 | switch (v4->CharID) 324 | { 325 | case Characters_Sonic: 326 | list = SonicStartList; 327 | break; 328 | case Characters_Shadow: 329 | list = ShadowStartList; 330 | break; 331 | case Characters_Knuckles: 332 | list = KnucklesStartList; 333 | break; 334 | case Characters_Rouge: 335 | list = RougeStartList; 336 | break; 337 | case Characters_Tails: 338 | list = TailsStartList; 339 | break; 340 | case Characters_Eggman: 341 | list = EggmanStartList; 342 | break; 343 | case Characters_MechEggman: 344 | list = MechEggmanStartList; 345 | break; 346 | case Characters_MechTails: 347 | list = MechTailsStartList; 348 | break; 349 | case Characters_SuperSonic: 350 | list = SuperSonicStartList; 351 | break; 352 | case Characters_SuperShadow: 353 | list = SuperShadowStartList; 354 | break; 355 | default: 356 | return 1; 357 | } 358 | } 359 | else 360 | return 1; 361 | if (TwoPlayerMode 362 | || (short)CurrentLevel == LevelIDs_SonicVsShadow1 363 | || (short)CurrentLevel == LevelIDs_SonicVsShadow2 364 | || (short)CurrentLevel == LevelIDs_TailsVsEggman1 365 | || (short)CurrentLevel == LevelIDs_TailsVsEggman2 366 | || (short)CurrentLevel == LevelIDs_KnucklesVsRouge) 367 | v6 = (playerNum != 0) + 1; 368 | else 369 | v6 = 0; 370 | for (int i = 0; i < (int)LengthOfArray(SonicStartList); i++) 371 | { 372 | v5 = list[i]; 373 | if (v5) 374 | { 375 | while (v5->Level != LevelIDs_Invalid) 376 | { 377 | if (v5->Level == (short)CurrentLevel) 378 | { 379 | if (rotation) 380 | rotation->y = *(&v5->Rotation1P + v6); 381 | if (position) 382 | { 383 | v8 = &(&v5->Position1P)[v6]; 384 | position->x = v8->x; 385 | position->y = v8->y; 386 | position->z = v8->z; 387 | } 388 | return 1; 389 | } 390 | ++v5; 391 | } 392 | } 393 | } 394 | return 1; 395 | } 396 | return 0; 397 | } 398 | 399 | __declspec(naked) void LoadStartPosition_r() 400 | { 401 | __asm 402 | { 403 | mov eax, [esp + 4] 404 | push eax 405 | push edi 406 | push ecx 407 | call LoadStartPosition_ri 408 | add esp, 12 409 | retn 410 | } 411 | } 412 | 413 | #pragma endregion 414 | #pragma region Start2 Positions 415 | 416 | StartPosition KnucklesStart2[] = { 417 | { LevelIDs_BasicTest }, 418 | { LevelIDs_PumpkinHill, 0xD000u, 0xD000u, 0xD000u, { 199, -1361, -1035 }, { 188.63f, -1361, -1045 }, { 208.3f, -1361, -1021.5f } }, 419 | { LevelIDs_AquaticMine, 0x4000, 0, 0, { 0, 130, -340 }, { 10, 130, -200 }, { -10, 130, -200 } }, 420 | { LevelIDs_WildCanyon, 0x4000, 0x4000, 0x4000, { 200, 856, -140 }, { 220, 856, -140 }, { 180, 856, -140 } }, 421 | { LevelIDs_DeathChamber, 0x2000, 0x2000, 0x2000, { 830, 20, 830 }, { 830, 20, 830 }, { 830, 20, 830 } }, 422 | { LevelIDs_EggQuarters, 0x2000, 0xA000u, 0xA000u, { 980, -30, 980 }, { -820, 20, 820 }, { -820, 20, 820 } }, 423 | { LevelIDs_KingBoomBoo, 0x1800, 0x1800, 0x1800, { 374, -40, -120 }, { 374, -40, -120 }, { 374, -40, -120 } }, 424 | { LevelIDs_KnucklesVsRouge, 0, 0, 0, { 0, -340, 10 }, { 0, -340, 10 }, { 0, -340, 10 } }, 425 | { LevelIDs_WildCanyon2P, 0x4000, 0xF000u, 0xF000u, { 200, 856, -140 }, { -359, 927, -44 }, { -359, 927, -44 } }, 426 | { LevelIDs_CannonsCoreK, 0, 0, 0, { -435, -175, -1735 }, { -435, -175, 1735 }, { -435, -175, 1735 } }, 427 | { LevelIDs_MeteorHerd, 0x4000, 0x4000, 0x4000, { 0, -500, -1025 }, { 25, -500, -1025 }, { -25, -500, -1025 } }, 428 | { LevelIDs_DryLagoon2P, 0x4000, 0x4000, 0x4000, { 200, 210, 1350 }, { 200, 210, 1350 }, { 200, 210, 1350 } }, 429 | { LevelIDs_PoolQuest, 0, 0, 0, { 0, 130, -200 }, { 10, 130, -200 }, { -10, 130, -200 } }, 430 | { LevelIDs_PlanetQuest, 0, 0, 0, { 0, 620, 0 }, { -432, 1640.5f, -560 }, { -432, 1640.5f, -560 } }, 431 | { LevelIDs_SecurityHall, 0xA000u, 0x6000, 0xA000u, { 405, -933, 410 }, { 217, -933, 410 }, { 217, -933, 410 } }, 432 | { LevelIDs_MadSpace, 0xF000u, 0xF000u, 0xF000u, { 0, 620, 0 }, { 0, 620, 5 }, { 0, 620, 5 } }, 433 | { LevelIDs_DeathChamber2P, 0x2000, 0x2000, 0x2000, { 830, 20, 830 }, { 830, 20, 830 }, { 830, 20, 830 } }, 434 | { LevelIDs_Invalid } 435 | }; 436 | 437 | StartPosition MechEggmanStart2[] = { 438 | { LevelIDs_BasicTest }, 439 | { LevelIDs_IronGate, 0, 0, 0, { 6150, -1521, -1230 }, { 6150, -1521, -1230 }, { 6150, -1521, -1230 } }, 440 | { LevelIDs_WeaponsBed, 0, 0, 0, { 4251, -220, -10138 }, { 4231, -220, -10138 }, { 4281, -220, -10138 } }, 441 | { LevelIDs_WeaponsBed2P, 0x4000, 0x4000, 0x4000, { 140, -170, 20 }, { 140, -170, 20 }, { 140, -170, 20 } }, 442 | { LevelIDs_TailsVsEggman1, 0x4000, 0x4000, 0x4000, { 140, -170, 20 }, { 140, -170, 20 }, { 140, -170, 20 } }, 443 | { LevelIDs_SandOcean, 0x8000u, 0x8000u, 0x8000u, { 2895, 155, -7185 }, { 2895, 155, -7185 }, { 2895, 155, -7185 } }, 444 | { LevelIDs_EternalEngine, 0xC000u, 0xC000u, 0xC000u, { 207, -1826, -9150 }, { 207, -1826, -9150 }, { 207, -1826, -9150 } }, 445 | { LevelIDs_LostColony, 0, 0, 0, { 4710, 1552, -2400 }, { 4710, 1552, -2400 }, { 4710, 1552, -2400 } }, 446 | { LevelIDs_TailsVsEggman2, 0x4000, 0x4000, 0x4000, { 0, -50, -181.5f }, { 0, -50, -181.5f }, { 0, -50, -181.5f } }, 447 | { LevelIDs_MissionStreet2P, 0xC000u, 0xC000u, 0xC000u, { 0, 0, -25 }, { 0, 0, -25 }, { 0, 0, -25 } }, 448 | { LevelIDs_SandOcean2P, 0x4000, 0x4000, 0x4000, { 17, 30, -150 }, { 17, 30, -150 }, { 17, 30, -150 } }, 449 | { LevelIDs_CannonsCoreE, 0xC000u, 0xC000u, 0xC000u, { 570, -2630, -3450 }, { 570, -2630, -3450 }, { 570, -2630, -3450 } }, 450 | { LevelIDs_EggGolemE, 0, 0, 0, { 0, 200, 220 }, { 0, 200, 220 }, { 0, 200, 220 } }, 451 | { LevelIDs_CosmicWall, 0x8000u, 0x8000u, 0x8000u, { 3550, -1600, 29690 }, { 3550, -1600, 29690 }, { 3550, -1600, 29690 } }, 452 | { LevelIDs_HiddenBase2P, 0, 0x4000, 0x4000, { 0, 0, 30 }, { -20, 0, 25 }, { -20, 0, 25 } }, 453 | { LevelIDs_IronGate2P, 0, 0xC000u, 0xC000u, { 0 }, { -30, -10, -20 }, { -30, -10, -20 } }, 454 | { LevelIDs_LostColony2P, 0, 0, 0x2000, { -150, 0, 0 }, { -150, 0, 0 }, { -280, 0, -170 } }, 455 | { LevelIDs_PyramidRace, 0, 0, 0, { 0 }, { 0, 0, -2020 }, { 0, 0, -2020 } }, 456 | { LevelIDs_DeckRace, 0xC000u, 0xC000u, 0xC000u, { 0 }, { 0, -170, -475 }, { 0, -170, -475 } }, 457 | { LevelIDs_EternalEngine2P, 0x6000, 0x6000, 0x6000, { 0, -50, -120 }, { 0, -50, -120 }, { 0, -50, 120 } }, 458 | { LevelIDs_Invalid } 459 | }; 460 | 461 | StartPosition MechTailsStart2[] = { 462 | { LevelIDs_BasicTest }, 463 | { LevelIDs_PrisonLane, 0xC000u, 0xC000u, 0xC000u, { -4440, 940, -1178 }, { -4440, 940, -1178 }, { -4440, 940, -1178 } }, 464 | { LevelIDs_WeaponsBed, 0, 0, 0, { 4251, -220, -10138 }, { 4231, -220, -10138 }, { 4281, -220, -10138 } }, 465 | { LevelIDs_WeaponsBed2P, 0xC000u, 0xC000u, 0xC000u, { 140, -170, -40 }, { 140, -170, -40 }, { 140, -170, -40 } }, 466 | { LevelIDs_MissionStreet, 0xC000u, 0xC000u, 0xC000u, { 7170, 598, -6913 }, { 7170, 598, -6913 }, { 7170, 598, -6913 } }, 467 | { LevelIDs_TailsVsEggman1, 0xC000u, 0xC000u, 0xC000u, { 140, -170, -40 }, { 140, -170, -40 }, { 140, -170, -40 } }, 468 | { LevelIDs_HiddenBase, 0x4000, 0x4000, 0x4000, { -3035, 1280, -5400 }, { -3035, 1280, -5400 }, { -3035, 1280, -5400 } }, 469 | { LevelIDs_EternalEngine, 0xC000u, 0xC000u, 0xC000u, { 207, -1826, -9150 }, { 207, -1826, -9150 }, { 207, -1826, -9150 } }, 470 | { LevelIDs_TailsVsEggman2, 0xC000u, 0xC000u, 0xC000u, { 140, -50, -40 }, { 140, -50, -40 }, { 140, -50, -40 } }, 471 | { LevelIDs_MissionStreet2P, 0x4000, 0x4000, 0x4000, { 0, 0, 25 }, { 0, 0, 25 }, { 0, 0, 25 } }, 472 | { LevelIDs_SandOcean2P, 0x4000, 0x4000, 0x4000, { 17, 30, -150 }, { 17, 30, -150 }, { 17, 30, -150 } }, 473 | { LevelIDs_CannonsCoreE, 0xC000u, 0xC000u, 0xC000u, { -1990, -1258, -2500 }, { -1990, -1258, -2500 }, { -1990, -1258, -2500 } }, 474 | { LevelIDs_HiddenBase2P, 0, 0x4000, 0x4000, { 0, 0, 30 }, { -20, 0, 25 }, { -20, 0, 25 } }, 475 | { LevelIDs_IronGate2P, 0, 0xC000u, 0xC000u, { 0 }, { -30, -10, -20 }, { -30, -10, -20 } }, 476 | { LevelIDs_LostColony2P, 0, 0, 0x2000, { -150, 0, 0 }, { -150, 0, 0 }, { -280, 0, -170 } }, 477 | { LevelIDs_PyramidRace, 0, 0, 0, { 0 }, { 0, 0, -2020 }, { 0, 0, -2020 } }, 478 | { LevelIDs_DeckRace, 0xC000u, 0xC000u, 0xC000u, { 0 }, { 0, -170, -475 }, { 0, -170, -475 } }, 479 | { LevelIDs_EternalEngine2P, 0x6000, 0x6000, 0x6000, { 0, -50, -120 }, { 0, -50, -120 }, { 0, -50, 120 } }, 480 | { LevelIDs_Invalid } 481 | }; 482 | 483 | StartPosition RougeStart2[] = { 484 | { LevelIDs_BasicTest }, 485 | { LevelIDs_PumpkinHill, 0xD000u, 0xD000u, 0xD000u, { 199, -1361, -1035 }, { 188.63f, -1361, -1045 }, { 208.3f, -1361, -1021.5f } }, 486 | { LevelIDs_SecurityHall, 0xA000u, 0x6000, 0xA000u, { 405, -933, 410 }, { 217, -933, 410 }, { 217, -933, 410 } }, 487 | { LevelIDs_DryLagoon, 0x4000, 0x4000, 0x4000, { 200, 15, -140 }, { 200, 15, -140 }, { 200, 15, -140 } }, 488 | { LevelIDs_WildCanyon, 0x4000, 0x4000, 0x4000, { 200, 856, -140 }, { 220, 856, -140 }, { 180, 856, -140 } }, 489 | { LevelIDs_DeathChamber, 0x2000, 0xE000u, 0xE000u, { 830, 20, 830 }, { 830, 20, 830 }, { 830, 20, 830 } }, 490 | { LevelIDs_EggQuarters, 0x2000, 0x2000, 0x2000, { 980, -30, 980 }, { -820, 20, 820 }, { -820, 20, 820 } }, 491 | { LevelIDs_KnucklesVsRouge, 0, 0, 0, { 10, -340, 0 }, { 10, -340, 0 }, { 10, -340, 0 } }, 492 | { LevelIDs_WildCanyon2P, 0x4000, 0xF000u, 0xF000u, { 200, 856, -400 }, { -359, 927, -44 }, { -359, 927, -44 } }, 493 | { LevelIDs_CannonsCoreR, 0x8000u, 0x8000u, 0x8000u, { 120, 20, 0 }, { 120, 20, 0 }, { 120, 20, 0 } }, 494 | { LevelIDs_FlyingDog }, 495 | { LevelIDs_MeteorHerd, 0x4000, 0x4000, 0x4000, { 0, -500, -1025 }, { 25, -500, -1025 }, { -25, -500, -1025 } }, 496 | { LevelIDs_MadSpace, 0xF000u, 0xF000u, 0xF000u, { 0, 620, 0 }, { 0, 620, 5 }, { 0, 620, 5 } }, 497 | { LevelIDs_DryLagoon2P, 0x4000, 0x4000, 0x4000, { 200, 210, 1350 }, { 200, 210, 1350 }, { 200, 210, 1350 } }, 498 | { LevelIDs_PoolQuest, 0, 0, 0, { 0, 130, -200 }, { 10, 130, -200 }, { -10, 130, -200 } }, 499 | { LevelIDs_PlanetQuest, 0, 0, 0, { 0, 620, 0 }, { -432, 1640.5f, -560 }, { -432, 1640.5f, -560 } }, 500 | { LevelIDs_DeathChamber2P, 0x2000, 0xE000u, 0xE000u, { 830, 20, 830 }, { 830, 20, 830 }, { 830, 20, 830 } }, 501 | { LevelIDs_Invalid } 502 | }; 503 | 504 | StartPosition ShadowStart2[] = { 505 | { LevelIDs_BasicTest }, 506 | { LevelIDs_GreenForest, 0x8000u, 0x8000u, 0x8000u, { 10935, -1854, 11056 }, { 10935, -1854, 11076 }, { 10935, -1854, 11066 } }, 507 | { LevelIDs_WhiteJungle, 0xC000u, 0xC000u, 0xC000u, { 13166, -3599, -5518 }, { 9135, -3154, -4930 }, { 9135, -3154, -4930 } }, 508 | { LevelIDs_SkyRail, 0x4000, 0x4000, 0x4000, { -1343.7f, -4928, 10098 }, { -1333.7f, -4928, 10098 }, { -1353.7f, -4928, 10098 } }, 509 | { LevelIDs_CityEscape, 0x4000, 0x8000u, 0x8000u, { 3955, -22175, 16130 }, { 6450, -15915, 9070 }, { 6450, -15915, 9070 } }, 510 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { -9970, -6999, -18430 }, { -9970, -6999, -18350 }, { -9970, -6999, -18350 } }, 511 | { LevelIDs_SonicVsShadow1, 0x6C00, 0x6C00, 0x6C00, { 10, -42, 0 }, { 10, -42, 0 }, { 10, -42, 0 } }, 512 | { LevelIDs_CrazyGadget, 0xC000u, 0xC000u, 0xC000u, { -8470, -1097, -2904 }, { -8470, -1097, -2904 }, { -8470, -1097, -2904 } }, 513 | { LevelIDs_HotShot }, 514 | { LevelIDs_Biolizard, 0, 0, 0, { -265, 10, 0 }, { -265, 10, 0 }, { -265, 10, 0 } }, 515 | { LevelIDs_FinalHazard, 0, 0, 0, { 0, 0, -1000 }, { 0, 0, -1000 }, { 0, 0, -1000 } }, 516 | { LevelIDs_SonicVsShadow2, 0x4000, 0x4000, 0x4000, { -292, 0, 0 }, { -292, 0, 0 }, { -292, 0, 0 } }, 517 | { LevelIDs_FinalChase, 0, 0xC000u, 0xC000u, { 122, -9960, 7627 }, { 3440, -6812, 17730 }, { 3440, -6812, 17730 } }, 518 | { LevelIDs_GreenHill, 0xC000u, 0xC000u, 0xC000u, { -1970, -1390, -6940 }, { -1970, -1390, -6940 }, { -1970, -1390, -6910 } }, 519 | { LevelIDs_FinalRush, 0, 0x4000, 0x4000, { 2530, -26495.5f, 7465 }, { 2531, -20965, 11350 }, { 2531, -20965, 11350 } }, 520 | { LevelIDs_MetalHarbor2P, 0, 0x8000u, 0x8000u, { 8854, -31, -10370 }, { 4913, -31, -10370 }, { 4913, -31, -10370 } }, 521 | { LevelIDs_GrindRace, 0x8000u, 0x8000u, 0x8000u, { 13990, -35280, 10050 }, { 13990, -35280, 10050 }, { 13990, -35280, 10050 } }, 522 | { LevelIDs_DowntownRace, 0xC000u, 0xC000u, 0xC000u, { -1540, -6060, 8800 }, { -1540, -6060, 8800 }, { -1540, -6060, 8770 } }, 523 | { LevelIDs_Invalid } 524 | }; 525 | 526 | StartPosition SonicStart2[] = { 527 | { LevelIDs_BasicTest }, 528 | { LevelIDs_GreenForest, 0x8000u, 0x8000u, 0x8000u, { 10935, -1854, 11056 }, { 10935, -1854, 11076 }, { 10935, -1854, 11066 } }, 529 | { LevelIDs_SkyRail, 0x4000, 0x4000, 0x4000, { -1343.7f, -4928, 10098 }, { -1333.7f, -4928, 10098 }, { -1353.7f, -4928, 10098 } }, 530 | { LevelIDs_MetalHarbor, 0x6000, 0, 0, { 8777, -170, -10240 }, { 8854, -170, -10241 }, { 8854, -170, -10281 } }, 531 | { LevelIDs_CityEscape, 0x4000, 0x8000u, 0x8000u, { 3955, -22175, 16130 }, { 6450, -15915, 9070 }, { 6450, -15915, 9070 } }, 532 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0xC000u, { -9970, -6999, -18430 }, { -9970, -6999, -18350 }, { -9970, -6999, -18350 } }, 533 | { LevelIDs_SonicVsShadow1, 0x800, 0x800, 0x800, { -10, -42, 0 }, { -10, -42, 0 }, { -10, -42, 0 } }, 534 | { LevelIDs_CrazyGadget, 0xC000u, 0xC000u, 0xC000u, { -8470, -1097, -2904 }, { -8470, -1097, -2904 }, { -8470, -1097, -2904 } }, 535 | { LevelIDs_PyramidCave, 0x4000, 0x4000, 0x4000, { 940, -4060, -22190 }, { 940, -4060, -22190 }, { 940, -4060, -22190 } }, 536 | { LevelIDs_FinalRush, 0, 0x4000, 0x4000, { 2530, -26495.5f, 7465 }, { 2531, -20965, 11350 }, { 2531, -20965, 11350 } }, 537 | { LevelIDs_BigFoot, 0, 0, 0, { 0, -1, 0 }, { 0, -1, 0 }, { 0, -1, 0 } }, 538 | { LevelIDs_EggGolemS, 0, 0, 0, { 0, 200, 220 }, { 0, 200, 220 }, { 0, 200, 220 } }, 539 | { LevelIDs_FinalHazard, 0, 0, 0, { 0, 0, 1000 }, { 0, 0, 1000 }, { 0, 0, 1000 } }, 540 | { LevelIDs_CannonsCoreS, 0x1000, 0x1000, 0x1000, { -1600, -5755, -9565 }, { -308, 0, 0 }, { -308, 0, 0 } }, 541 | { LevelIDs_SonicVsShadow2, 0x4000, 0x4000, 0x4000, { -308, 0, 0 }, { -308, 0, 0 }, { -308, 0, 0 } }, 542 | { LevelIDs_GreenHill, 0xC000u, 0xC000u, 0xC000u, { -1970, -1390, -6940 }, { -1970, -1390, -6940 }, { -1970, -1390, -6910 } }, 543 | { LevelIDs_DowntownRace, 0xC000u, 0xC000u, 0xC000u, { -1540, -6060, 8800 }, { -1540, -6060, 8800 }, { -1540, -6060, 8770 } }, 544 | { LevelIDs_GrindRace, 0x8000u, 0x8000u, 0x8000u, { 13990, -35280, 10050 }, { 13990, -35280, 10050 }, { 13990, -35280, 10050 } }, 545 | { LevelIDs_MetalHarbor2P, 0, 0x8000u, 0x8000u, { 8854, -31, -10370 }, { 4913, -31, -10370 }, { 4913, -31, -10370 } }, 546 | { LevelIDs_FinalChase, 0, 0xC000u, 0xC000u, { 122, -9960, 7627 }, { 3440, -6812, 17730 }, { 3440, -6812, 17730 } }, 547 | { LevelIDs_WhiteJungle, 0xC000u, 0xC000u, 0xC000u, { 13166, -3599, -5518 }, { 9135, -3154, -4930 }, { 9135, -3154, -4930 } }, 548 | { LevelIDs_Invalid } 549 | }; 550 | 551 | StartPosition SuperShadowStart2[] = { 552 | { LevelIDs_BasicTest }, 553 | { LevelIDs_FinalHazard, 0, 0, 0, { 600, -400, 200 }, { 600, -400, 200 }, { 600, -400, 200 } }, 554 | { LevelIDs_Invalid } 555 | }; 556 | 557 | StartPosition SuperSonicStart2[] = { 558 | { LevelIDs_BasicTest }, 559 | { LevelIDs_FinalHazard, 0, 0, 0, { 600, -400, 200 }, { 600, -400, 200 }, { 600, -400, 200 } }, 560 | { LevelIDs_Invalid } 561 | }; 562 | #pragma warning(default : 4838) 563 | 564 | StartPosition* SonicStartList2[] = { SonicStart2, ShadowStart2, MechTailsStart2, MechEggmanStart2, KnucklesStart2, RougeStart2, SuperSonicStart2, SuperShadowStart2 }; 565 | StartPosition* ShadowStartList2[] = { ShadowStart2, SonicStart2, MechEggmanStart2, MechTailsStart2, RougeStart2, KnucklesStart2, SuperShadowStart2, SuperSonicStart2 }; 566 | StartPosition* MechTailsStartList2[] = { MechTailsStart2, MechEggmanStart2, SonicStart2, ShadowStart2, KnucklesStart2, RougeStart2, SuperSonicStart2, SuperShadowStart2 }; 567 | StartPosition* MechEggmanStartList2[] = { MechEggmanStart2, MechTailsStart2, ShadowStart2, SonicStart2, RougeStart2, KnucklesStart2, SuperShadowStart2, SuperSonicStart2 }; 568 | StartPosition* KnucklesStartList2[] = { KnucklesStart2, RougeStart2, SonicStart2, ShadowStart2, MechTailsStart2, MechEggmanStart2, SuperSonicStart2, SuperShadowStart2 }; 569 | StartPosition* RougeStartList2[] = { RougeStart2, KnucklesStart2, ShadowStart2, SonicStart2, MechEggmanStart2, MechTailsStart2, SuperShadowStart2, SuperSonicStart2 }; 570 | StartPosition* SuperSonicStartList2[] = { SuperSonicStart2, SuperShadowStart2, SonicStart2, ShadowStart2, MechTailsStart2, MechEggmanStart2, KnucklesStart2, RougeStart2 }; 571 | StartPosition* SuperShadowStartList2[] = { SuperShadowStart2, SuperSonicStart2, MechEggmanStart2, MechTailsStart2, RougeStart2, KnucklesStart2, ShadowStart2, SonicStart2 }; 572 | 573 | #pragma endregion 574 | #pragma region End Positions 575 | 576 | #pragma warning(disable : 4838) 577 | LevelEndPosition KnucklesEnd[] = { 578 | { LevelIDs_PumpkinHill, 0x8000u, 0xC000u, 0, { 530, -986, -770 }, { -13, 34.8f, 1275 } }, 579 | { LevelIDs_AquaticMine, 0, 0, 0, { 0, 130, -365 }, { -600, 211, 443 } }, 580 | { LevelIDs_WildCanyon, 0xC000u, 0xC000u, 0, { 705, 1010, -14 }, { 1700, 0, 121 } }, 581 | { LevelIDs_DeathChamber, 0, 0xE000u, 0, { 100, 100, 180 }, { -805, -35, -805 } }, 582 | { LevelIDs_MeteorHerd, 0, 0x5200, 0, { 10, 170, 140 }, { -438, 2752, -432 } }, 583 | { LevelIDs_CannonsCoreK, 0xC000u, 0xFFFFu, 0, { 0, 660, -160 }, { 0, 580, 60 } }, 584 | { LevelIDs_Invalid }, 585 | }; 586 | 587 | LevelEndPosition MechEggmanEnd[] = { 588 | { LevelIDs_IronGate, 0x8000u, 0xC000u, 0, { 1490, -270, -1025 }, { 3184, -233, -702 } }, 589 | { LevelIDs_WeaponsBed, 0x4000, 0xFA00u, 0, { -4, -160, -40 }, { 1500, -220, -6008 } }, 590 | { LevelIDs_SandOcean, 0x4000, 0x4A00, 0, { 0, 80, 0 }, { 659, 120, -4660 } }, 591 | { LevelIDs_LostColony, 0x8000u, 0, 0, { 595, -518, -2350 }, { 2225, -308, -2400 } }, 592 | { LevelIDs_CannonsCoreE, 0, 0xFFFFu, 0, { 80, -30, -1570 }, { 0, 20, -200 } }, 593 | { LevelIDs_CosmicWall, 0x4000, 0xA000u, 0, { 6673, 4000, 11677 }, { 2753, 2583, -1045 } }, 594 | { LevelIDs_Invalid }, 595 | }; 596 | 597 | LevelEndPosition MechTailsEnd[] = { 598 | { LevelIDs_PrisonLane, 0x8000u, 0x8000u, 0, { -350, 117, 410 }, { -3129, 790, -242 } }, 599 | { LevelIDs_MissionStreet, 0x8000u, 0, 0, { 2200, 800, -3500 }, { 4065, 758, -4170 } }, 600 | { LevelIDs_HiddenBase, 0, 0x4000, 0, { -2295, 110, -2845 }, { -3525, 920, -4960 } }, 601 | { LevelIDs_EternalEngine, 0x4000, 0x4000, 0, { -2055, 936, -5825 }, { -652, 788, -4426 } }, 602 | { LevelIDs_CannonsCoreT, 0, 0xFFFFu, 0, { -1050, 638, -1540 }, { 0, 670, 0 } }, 603 | { LevelIDs_Invalid }, 604 | }; 605 | 606 | LevelEndPosition RougeEnd[] = { 607 | { LevelIDs_SecurityHall, 0, 0x4000, 0, { 100, -573, 490 }, { 0, 314.6f, 110 } }, 608 | { LevelIDs_DryLagoon, 0x8000u, 0x7000, 0, { 191, 211, 1317 }, { 1728, 0, -382 } }, 609 | { LevelIDs_EggQuarters, 0x8000u, 0x8000u, 0, { 100, 70, 1255 }, { -655, -20, 2680 } }, 610 | { LevelIDs_CannonsCoreR, 0x4000, 0xFFFFu, 0, { 80, 135, 80 }, { 0, 480, 150 } }, 611 | { LevelIDs_MadSpace, 0xEC00u, 0, 0, { 272.5f, 2358, -334.5f }, { -154, 3350, 481 } }, 612 | { LevelIDs_Invalid }, 613 | }; 614 | 615 | LevelEndPosition ShadowEnd[] = { 616 | { LevelIDs_BasicTest, 0, 0, 0, { 0 }, { 0 } }, 617 | { LevelIDs_RadicalHighway, 0xC000u, 0x8000u, 0, { -40, -400, -970 }, { -6330, -4500, -8830 } }, 618 | { LevelIDs_WhiteJungle, 0xC000u, 0xB000u, 0, { 5040, -2220, -1550 }, { 13280, -3157, -7370 } }, 619 | { LevelIDs_FinalChase, 0xC000u, 0xE000u, 0, { 3408, -6592, 16865 }, { -695, -6959.5f, 10275 } }, 620 | { LevelIDs_SkyRail, 0x8000u, 0xA000u, 0, { -2411, -1792, 4260 }, { -3457, -1047, 3001 } }, 621 | { LevelIDs_Invalid }, 622 | }; 623 | 624 | LevelEndPosition SonicEnd[] = { 625 | { LevelIDs_BasicTest }, 626 | { LevelIDs_GreenForest, 0x8000u, 0x8000u, 0, { 5858, -1812, 7541 }, { 6890, -1610, 7542 } }, 627 | { LevelIDs_MetalHarbor, 0, 0x4000, 0, { 2158, -160, -5294 }, { 1707, -170, -6583 } }, 628 | { LevelIDs_CityEscape, 0xC000u, 0x4000, 0, { -1570, -6060, 8860 }, { 7700, -13145, 5570 } }, 629 | { LevelIDs_CrazyGadget, 0xC000u, 0x8000u, 0, { -9710, -1045, -4005 }, { -8725, -537, -2905 } }, 630 | { LevelIDs_PyramidCave, 0x4000, 0, 0, { -685, -4190, -19525 }, { -2170, -3970, -21870 } }, 631 | { LevelIDs_FinalRush, 0, 0xC000u, 0, { 5776, -15687, 20080 }, { 4207, -16632, 24462 } }, 632 | { LevelIDs_CannonsCoreS, 0x4000, 0x4000, 0, { 0, -480, -1550 }, { -510, -655, -4700 } }, 633 | { LevelIDs_Invalid }, 634 | }; 635 | 636 | LevelEndPosition* SonicEndList[] = { SonicEnd, ShadowEnd, MechTailsEnd, MechEggmanEnd, KnucklesEnd, RougeEnd }; 637 | LevelEndPosition* ShadowEndList[] = { ShadowEnd, SonicEnd, MechEggmanEnd, MechTailsEnd, RougeEnd, KnucklesEnd }; 638 | LevelEndPosition* MechTailsEndList[] = { MechTailsEnd, MechEggmanEnd, SonicEnd, ShadowEnd, KnucklesEnd, RougeEnd }; 639 | LevelEndPosition* MechEggmanEndList[] = { MechEggmanEnd, MechTailsEnd, ShadowEnd, SonicEnd, RougeEnd, KnucklesEnd }; 640 | LevelEndPosition* KnucklesEndList[] = { KnucklesEnd, RougeEnd, SonicEnd, ShadowEnd, MechTailsEnd, MechEggmanEnd }; 641 | LevelEndPosition* RougeEndList[] = { RougeEnd, KnucklesEnd, ShadowEnd, SonicEnd, MechEggmanEnd, MechTailsEnd }; 642 | 643 | static const void* const sub_46DC70Ptr = (void*)0x46DC70; 644 | void sub_46DC70(int a1, NJS_VECTOR* a2, char a3) 645 | { 646 | __asm 647 | { 648 | xor eax, eax 649 | mov al, [a3] 650 | push eax 651 | mov eax, [a1] 652 | mov ecx, [a2] 653 | call sub_46DC70Ptr 654 | add esp, 4 655 | } 656 | } 657 | 658 | DataArray(char, byte_1DE4664, 0x1DE4664, 2); 659 | DataPointer(void*, off_1DE95E0, 0x1DE95E0); 660 | 661 | signed int sub_46DBD0(int a1) 662 | { 663 | CharObj2Base* v1; // eax@1 664 | signed int result; // eax@2 665 | 666 | v1 = MainCharObj2[a1]; 667 | if (v1) 668 | result = v1->CharID; 669 | else 670 | result = -1; 671 | return result; 672 | } 673 | 674 | signed int LoadEndPosition_r(int playerNum) 675 | { 676 | int v1; // edi@1 677 | __int16 v2; // bp@2 678 | int v3; // edx@12 679 | EntityData1* v4; // esi@12 680 | LevelEndPosition** list; 681 | LevelEndPosition* v5; // eax@13 682 | int v8; // edi@24 683 | int v9; // ecx@24 684 | NJS_VECTOR* v10; // eax@24 685 | float v11; // ST14_4@24 686 | 687 | v1 = playerNum; 688 | v5 = &SonicEnd[0]; 689 | if (TwoPlayerMode 690 | || (v2 = CurrentLevel, (short)CurrentLevel == LevelIDs_SonicVsShadow1) 691 | || (short)CurrentLevel == LevelIDs_SonicVsShadow2 692 | || (short)CurrentLevel == LevelIDs_TailsVsEggman1 693 | || (short)CurrentLevel == LevelIDs_TailsVsEggman2 694 | || (short)CurrentLevel == LevelIDs_KnucklesVsRouge 695 | || (short)CurrentLevel > LevelIDs_BigFoot && (short)CurrentLevel != LevelIDs_Route101280 696 | || MissionNum != 1 && MissionNum != 2) 697 | return 0; 698 | else 699 | { 700 | v3 = MissionNum == 1 ? 0 : 1; 701 | v4 = MainCharacter[playerNum]->Data1.Entity; 702 | switch (sub_46DBD0(playerNum)) 703 | { 704 | case Characters_Sonic: 705 | case Characters_Tails: 706 | case Characters_SuperSonic: 707 | list = SonicEndList; 708 | break; 709 | case Characters_Shadow: 710 | case Characters_Eggman: 711 | case Characters_SuperShadow: 712 | list = ShadowEndList; 713 | break; 714 | case Characters_Knuckles: 715 | list = KnucklesEndList; 716 | break; 717 | case Characters_Rouge: 718 | list = RougeEndList; 719 | break; 720 | case Characters_MechEggman: 721 | list = MechEggmanEndList; 722 | break; 723 | case Characters_MechTails: 724 | list = MechTailsEndList; 725 | break; 726 | default: 727 | return 0; 728 | } 729 | for (int i = 0; i < (int)LengthOfArray(SonicEndList); i++) 730 | { 731 | v5 = list[i]; 732 | while (v5->Level != LevelIDs_Invalid) 733 | { 734 | if (v5->Level == v2) 735 | goto endloop; 736 | ++v5; 737 | } 738 | } 739 | endloop: 740 | if (*(&v5->Mission2YRotation + v3) == 0xFFFF) 741 | return 0; 742 | v4->Rotation.z = 0; 743 | v4->Rotation.x = 0; 744 | v9 = *(&v5->Mission2YRotation + v3); 745 | v4->Rotation.y = v9; 746 | *((int*)*(&off_1DE95E0 + v1) + 7) = v9; 747 | v10 = (NJS_VECTOR*)((char*)&v5->Mission2Position + 12 * v3); 748 | v4->Position = *v10; 749 | v11 = v4->Position.y - 10.0f; 750 | *(float*)&MainCharObj2[v1]->SurfaceInfo.BottomSurfaceDist = v11; 751 | MainCharObj2[playerNum]->SomeVectors[0].x = 0; 752 | sub_46DC70(v1, &v4->Position, 0); 753 | v4->Collision->CollisionArray->push |= 0x70u; 754 | *(int*)&MainCharObj2[v1]->CurrentSurfaceFlags = 0; 755 | v8 = v1 & 1; 756 | if ((short)CurrentLevel == LevelIDs_LostColony) 757 | { 758 | byte_1DE4664[v8] = 5; 759 | return 1; 760 | } 761 | else 762 | { 763 | byte_1DE4664[v8] = *(char*)0x1DE4660; 764 | return 1; 765 | } 766 | } 767 | } 768 | 769 | void __cdecl SetEndLevelPosition_i(int pNum) 770 | { 771 | StartPosition** list = 0; 772 | StartPosition* v5 = 0; 773 | int v6 = 0; 774 | int v8 = 0; 775 | float posDif = 0.0f; 776 | 777 | auto player = MainCharacter[pNum]; 778 | 779 | if (!player) 780 | return; 781 | 782 | auto co2 = MainCharObj2[pNum]; 783 | auto pData = player->Data1.Entity; 784 | 785 | if (LoadEndPosition_r(pNum) != 1) 786 | { 787 | if (co2) 788 | { 789 | switch (co2->CharID) 790 | { 791 | case Characters_Sonic: 792 | case Characters_Tails: 793 | list = SonicStartList2; 794 | break; 795 | case Characters_Shadow: 796 | case Characters_Eggman: 797 | list = ShadowStartList2; 798 | break; 799 | case Characters_Knuckles: 800 | list = KnucklesStartList2; 801 | break; 802 | case Characters_Rouge: 803 | list = RougeStartList2; 804 | break; 805 | case Characters_MechEggman: 806 | list = MechEggmanStartList2; 807 | break; 808 | case Characters_MechTails: 809 | list = MechTailsStartList2; 810 | break; 811 | case Characters_SuperSonic: 812 | list = SuperSonicStartList2; 813 | break; 814 | case Characters_SuperShadow: 815 | list = SuperShadowStartList2; 816 | break; 817 | default: 818 | goto LABEL_13; 819 | } 820 | } 821 | else 822 | { 823 | LABEL_13: 824 | list = 0; 825 | } 826 | if (TwoPlayerMode 827 | || (short)CurrentLevel == LevelIDs_SonicVsShadow1 828 | || (short)CurrentLevel == LevelIDs_SonicVsShadow2 829 | || (short)CurrentLevel == LevelIDs_TailsVsEggman1 830 | || (short)CurrentLevel == LevelIDs_TailsVsEggman2 831 | || (short)CurrentLevel == LevelIDs_KnucklesVsRouge) 832 | v6 = (pNum != 0) + 1; 833 | else 834 | v6 = 0; 835 | if (list) 836 | { 837 | for (int i = 0; i < (int)LengthOfArray(SonicStartList2); i++) 838 | { 839 | v5 = list[i]; 840 | while (v5->Level != LevelIDs_Invalid) 841 | { 842 | if (v5->Level == (short)CurrentLevel) 843 | { 844 | pData->Rotation.z = 0; 845 | pData->Rotation.x = 0; 846 | v8 = *(&v5->Rotation1P + v6); 847 | pData->Rotation.y = v8; 848 | *((int*)*(&off_1DE95E0 + pNum) + 7) = v8; 849 | pData->Position = (&v5->Position1P)[v6]; 850 | posDif = pData->Position.y - 10.0f; 851 | MainCharObj2[pNum]->SurfaceInfo.BottomSurfaceDist = posDif; 852 | MainCharObj2[pNum]->SomeVectors[0].x = 0; 853 | goto LABEL_27; 854 | } 855 | ++v5; 856 | } 857 | } 858 | } 859 | 860 | pData->Rotation = { 0, 0, 0 }; 861 | pData->Position = { 0.0f, 0.0f, 0.0f }; 862 | *((int*)*(&off_1DE95E0 + pNum) + 7) = 0; 863 | LABEL_27: 864 | sub_46DC70(pNum, &pData->Position, 0); 865 | pData->Collision->CollisionArray->push |= 0x70u; 866 | MainCharObj2[pNum]->CurrentSurfaceFlags = (SurfaceFlags)0x0; 867 | 868 | if ((short)CurrentLevel == LevelIDs_RadicalHighway || (short)CurrentLevel == LevelIDs_LostColony) 869 | byte_1DE4664[pNum & 1] = 5; 870 | else 871 | byte_1DE4664[pNum & 1] = *(char*)0x1DE4660; 872 | } 873 | } 874 | 875 | __declspec(naked) void SetEndLevelPosition() 876 | { 877 | __asm 878 | { 879 | push eax 880 | call SetEndLevelPosition_i 881 | add esp, 4 882 | retn 883 | } 884 | } 885 | 886 | #pragma endregion 887 | #pragma region 2P Intro Pos 888 | 889 | #pragma warning(disable : 4838) 890 | LevelEndPosition Knuckles2PIntro[] = { 891 | { LevelIDs_PumpkinHill, 0x5800, 0x5800, 0, { -193, -742.38f, -908.24f }, { -193, -742.38f, -908.24f } }, 892 | { LevelIDs_DeathChamber, 0, 0xC000u, 0, { 0, 210, 150 }, { 150, 210, 0 } }, 893 | { LevelIDs_WildCanyon2P, 0x4000, 0x4000, 0, { 220, 65.2f, -400 }, { 180, 65.2f, -400 } }, 894 | { LevelIDs_MeteorHerd, 0, 0x8000u, 0, { 190, -340, 0 }, { -190, -340, 0 } }, 895 | { LevelIDs_DryLagoon2P, 0, 0x8000u, 0, { 40, 270, 1438 }, { 355, 270, 1438 } }, 896 | { LevelIDs_EggQuarters, 0x2000, 0x6000, 0, { -845, 20, 845 }, { 845, 20, 845 } }, 897 | { LevelIDs_SecurityHall, 0x6000, 0xB000u, 0, { 470, -573, 490 }, { -395, -416, -20 } }, 898 | { LevelIDs_PoolQuest, 0x4000, 0x4000, 0, { 10, 130, -225 }, { -10, 130, -225 } }, 899 | { LevelIDs_PlanetQuest, 0, 0, 0, { -432, 1640.5f, -560 }, { -432, 1640.5f, -560 } }, 900 | { LevelIDs_MadSpace, 0x9800u, 0x4000, 0, { 30, 620, 17 }, { 0, 620, -35 } }, 901 | { LevelIDs_DeathChamber2P, 0, 0xC000u, 0, { 0, 210, 150 }, { 150, 210, 0 } }, 902 | { LevelIDs_Invalid }, 903 | }; 904 | 905 | LevelEndPosition MechEggman2PIntro[] = { 906 | { LevelIDs_WeaponsBed2P, 0xC000u, 0xC000u, 0, { 50, -170, 50 }, { 50, -170, 50 } }, 907 | { LevelIDs_MissionStreet2P, 0, 0, 0, { -450, 0, 0 }, { -450, 0, 0 } }, 908 | { LevelIDs_SandOcean2P, 0, 0x8000u, 0, { -155, 30, -15 }, { 155, 30, -15 } }, 909 | { LevelIDs_DeckRace, 0xC000u, 0xC000u, 0, { -15, -170, 1480 }, { 15, -170, 1480 } }, 910 | { LevelIDs_PyramidRace, 0x4000, 0x4000, 0, { -35, 0, -200 }, { 35, 0, -220 } }, 911 | { LevelIDs_HiddenBase2P, 0, 0x8000u, 0, { 60, 0, 10 }, { -60, 0, 10 } }, 912 | { LevelIDs_CosmicWall2P, 0, 0x8000u, 0, { -80, 0, 0 }, { 80, 0, 0 } }, 913 | { LevelIDs_EternalEngine2P, 0x4000, 0xC000u, 0, { 0, -50, 120 }, { 0, -50, -150 } }, 914 | { LevelIDs_IronGate2P, 0, 0x8000u, 0, { -50, -10, -20 }, { 50, -10, -20 } }, 915 | { LevelIDs_LostColony2P, 0xC000u, 0, 0, { 280, 65, -110 }, { -90, 0, 0 } }, 916 | { LevelIDs_Invalid }, 917 | }; 918 | 919 | LevelEndPosition MechTails2PIntro[] = { 920 | { LevelIDs_WeaponsBed2P, 0x4000, 0x4000, 0, { 50, -170, -250 }, { 50, -170, -250 } }, 921 | { LevelIDs_MissionStreet2P, 0x8000u, 0x8000u, 0, { 0 }, { 0 } }, 922 | { LevelIDs_SandOcean2P, 0, 0x8000u, 0, { -155, 30, -15 }, { 155, 30, -15 } }, 923 | { LevelIDs_DeckRace, 0xC000u, 0xC000u, 0, { -15, -170, 1480 }, { 15, -170, 1480 } }, 924 | { LevelIDs_PyramidRace, 0x4000, 0x4000, 0, { -35, 0, -200 }, { 35, 0, -220 } }, 925 | { LevelIDs_HiddenBase2P, 0, 0x8000u, 0, { 60, 0, 10 }, { -60, 0, 10 } }, 926 | { LevelIDs_CosmicWall2P, 0, 0x8000u, 0, { -80, 0, 0 }, { 80, 0, 0 } }, 927 | { LevelIDs_EternalEngine2P, 0x4000, 0xC000u, 0, { 0, -50, 120 }, { 0, -50, -150 } }, 928 | { LevelIDs_IronGate2P, 0, 0x8000u, 0, { -50, -10, -20 }, { 50, -10, -20 } }, 929 | { LevelIDs_LostColony2P, 0xC000u, 0, 0, { 280, 65, -110 }, { -90, 0, 0 } }, 930 | { LevelIDs_Invalid }, 931 | }; 932 | 933 | LevelEndPosition Rouge2PIntro[] = { 934 | { LevelIDs_PumpkinHill, 0xC000u, 0xC000u, 0, { 0, -590, -1642 }, { 0, -590, -1642 } }, 935 | { LevelIDs_DeathChamber, 0, 0xC000u, 0, { 0, 210, 150 }, { 150, 210, 0 } }, 936 | { LevelIDs_WildCanyon2P, 0x4000, 0x4000, 0, { 220, 65.2f, -400 }, { 180, 65.2f, -400 } }, 937 | { LevelIDs_MeteorHerd, 0, 0x8000u, 0, { 190, -340, 0 }, { -190, -340, 0 } }, 938 | { LevelIDs_DryLagoon2P, 0, 0x8000u, 0, { 40, 270, 1438 }, { 355, 270, 1438 } }, 939 | { LevelIDs_EggQuarters, 0x2000, 0x6000, 0, { -845, 20, 845 }, { 845, 20, 845 } }, 940 | { LevelIDs_SecurityHall, 0x6000, 0xB000u, 0, { 470, -573, 490 }, { -395, -416, -20 } }, 941 | { LevelIDs_PoolQuest, 0x4000, 0x4000, 0, { 10, 130, -225 }, { -10, 130, -225 } }, 942 | { LevelIDs_PlanetQuest, 0, 0, 0, { -432, 1640.5f, -560 }, { -432, 1640.5f, -560 } }, 943 | { LevelIDs_MadSpace, 0x9800u, 0x4000, 0, { 30, 620, 17 }, { 0, 620, -35 } }, 944 | { LevelIDs_DeathChamber2P, 0, 0xC000u, 0, { 0, 210, 150 }, { 150, 210, 0 } }, 945 | { LevelIDs_Invalid }, 946 | }; 947 | 948 | LevelEndPosition Shadow2PIntro[] = { 949 | { LevelIDs_GreenForest, 0, 0, 0, { 1247, -955, 2920 }, { 1247, -955, 2920 } }, 950 | { LevelIDs_SkyRail, 0xED00u, 0xED00u, 0, { -297, -724.9f, 2118 }, { -297, -724.9f, 2118 } }, 951 | { LevelIDs_MetalHarbor2P, 0x4000, 0x4000, 0, { 2065, -160, -4325 }, { 2065, -160, -4325 } }, 952 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0, { 105, 200, 0 }, { -105, 200, 0 } }, 953 | { LevelIDs_GreenHill, 0x5800, 0x5800, 0, { -760, -70, -2930 }, { -760, -70, -2930 } }, 954 | { LevelIDs_CityEscape, 0x8000u, 0x8000u, 0, { 150, -2226, 4010 }, { 150, -2226, 4010 } }, 955 | { LevelIDs_FinalRush, 0, 0, 0, { -100, 0, -25 }, { -100, 0, 25 } }, 956 | { LevelIDs_FinalChase, 0x8000u, 0x4000, 0, { 3600, -4525, 4675 }, { 3600, -4525, 4675 } }, 957 | { LevelIDs_GrindRace, 0, 0, 0, { 0, -815, -910 }, { 0, -815, -910 } }, 958 | { LevelIDs_WhiteJungle, 0x4000, 0xA000u, 0, { 4205, -2126, 430 }, { 6395, -1919, -2650 } }, 959 | { LevelIDs_DowntownRace, 0xF700u, 0xB00, 0, { -2010, 4793, -5215 }, { -2010, 4793, -5110 } }, 960 | { LevelIDs_Invalid }, 961 | }; 962 | 963 | LevelEndPosition Sonic2PIntro[] = { 964 | { LevelIDs_GreenForest, 0, 0, 0, { -87, -860, 1305 }, { -87, -860, 1305 } }, 965 | { LevelIDs_SkyRail, 0x1800, 0x1800, 0, { -2548, -1762.4f, 3508 }, { -2548, -1762.4f, 3508 } }, 966 | { LevelIDs_MetalHarbor2P, 0x4000, 0x4000, 0, { 2065, -160, -4325 }, { 2065, -160, -4325 } }, 967 | { LevelIDs_RadicalHighway, 0xC000u, 0xC000u, 0, { 105, 200, 0 }, { -105, 200, 0 } }, 968 | { LevelIDs_GreenHill, 0x4000, 0x4000, 0, { -80, 70, -480 }, { -80, 70, -480 } }, 969 | { LevelIDs_CityEscape, 0xC000u, 0xC000u, 0, { 90, -2813, 5000 }, { 90, -2813, 5000 } }, 970 | { LevelIDs_FinalRush, 0, 0, 0, { -100, 0, -25 }, { -100, 0, 25 } }, 971 | { LevelIDs_FinalChase, 0x8000u, 0x4000, 0, { 3600, -4525, 4675 }, { 3600, -4525, 4675 } }, 972 | { LevelIDs_GrindRace, 0, 0, 0, { 0, -815, -910 }, { 0, -815, -910 } }, 973 | { LevelIDs_WhiteJungle, 0x4000, 0xA000u, 0, { 4205, -2126, 430 }, { 6395, -1919, -2650 } }, 974 | { LevelIDs_DowntownRace, 0xF700u, 0xB00, 0, { -2010, 4793, -5215 }, { -2010, 4793, -5110 } }, 975 | { LevelIDs_Invalid }, 976 | }; 977 | #pragma warning(default : 4838) 978 | 979 | LevelEndPosition* Sonic2PIntroList[] = { Sonic2PIntro, Shadow2PIntro, MechTails2PIntro, MechEggman2PIntro, Knuckles2PIntro, Rouge2PIntro }; 980 | LevelEndPosition* Shadow2PIntroList[] = { Shadow2PIntro, Sonic2PIntro, MechEggman2PIntro, MechTails2PIntro, Rouge2PIntro, Knuckles2PIntro }; 981 | LevelEndPosition* MechTails2PIntroList[] = { MechTails2PIntro, MechEggman2PIntro, Sonic2PIntro, Shadow2PIntro, Knuckles2PIntro, Rouge2PIntro }; 982 | LevelEndPosition* MechEggman2PIntroList[] = { MechEggman2PIntro, MechTails2PIntro, Shadow2PIntro, Sonic2PIntro, Rouge2PIntro, Knuckles2PIntro }; 983 | LevelEndPosition* Knuckles2PIntroList[] = { Knuckles2PIntro, Rouge2PIntro, Sonic2PIntro, Shadow2PIntro, MechTails2PIntro, MechEggman2PIntro }; 984 | LevelEndPosition* Rouge2PIntroList[] = { Rouge2PIntro, Knuckles2PIntro, Shadow2PIntro, Sonic2PIntro, MechEggman2PIntro, MechTails2PIntro }; 985 | 986 | void __cdecl Load2PIntroPos_ri(int playerNum) 987 | { 988 | LevelEndPosition** list = 0; 989 | LevelEndPosition* v5 = 0; 990 | bool v6 = false; 991 | NJS_VECTOR* v8 = { 0 }; 992 | int v10 = 0; 993 | char v11 = 0; 994 | NJS_VECTOR* v12 = nullptr; 995 | float v13 = 0.0f; 996 | 997 | auto pNum = playerNum; 998 | auto p = MainCharacter[playerNum]; 999 | 1000 | if (!p) 1001 | return; 1002 | 1003 | auto pData = p->Data1.Entity; 1004 | auto co2 = MainCharObj2[playerNum]; 1005 | 1006 | if (co2) 1007 | { 1008 | switch (co2->CharID) 1009 | { 1010 | case Characters_Sonic: 1011 | case Characters_Tails: 1012 | case Characters_SuperSonic: 1013 | list = Sonic2PIntroList; 1014 | break; 1015 | case Characters_Shadow: 1016 | case Characters_Eggman: 1017 | case Characters_SuperShadow: 1018 | list = Shadow2PIntroList; 1019 | break; 1020 | case Characters_Knuckles: 1021 | list = Knuckles2PIntroList; 1022 | break; 1023 | case Characters_Rouge: 1024 | list = Rouge2PIntroList; 1025 | break; 1026 | case Characters_MechEggman: 1027 | list = MechEggman2PIntroList; 1028 | break; 1029 | case Characters_MechTails: 1030 | list = MechTails2PIntroList; 1031 | break; 1032 | default: 1033 | goto LABEL_10; 1034 | } 1035 | } 1036 | else 1037 | { 1038 | LABEL_10: 1039 | list = 0; 1040 | } 1041 | v6 = pNum != 0; 1042 | if (list) 1043 | { 1044 | for (int i = 0; i < (int)LengthOfArray(Sonic2PIntroList); i++) 1045 | { 1046 | v5 = list[i]; 1047 | while (v5->Level != LevelIDs_Invalid) 1048 | { 1049 | if (v5->Level == (short)CurrentLevel) 1050 | { 1051 | pData->Rotation.y = *(&v5->Mission2YRotation + v6); 1052 | v12 = (NJS_VECTOR*)((char*)&v5->Mission2Position + 12 * v6); 1053 | pData->Position = *v12; 1054 | v8 = &pData->Position; 1055 | *((int*)*(&off_1DE95E0 + pNum) + 7) = pData->Rotation.y; 1056 | v13 = pData->Position.y - 10.0f; 1057 | MainCharObj2[pNum]->SurfaceInfo.BottomSurfaceDist = v13; 1058 | goto LABEL_16; 1059 | } 1060 | ++v5; 1061 | } 1062 | } 1063 | } 1064 | pData->Position.z = 0.0; 1065 | v8 = &pData->Position; 1066 | pData->Position = { 0.0f, 0.0f, 0.0f }; 1067 | 1068 | LABEL_16: 1069 | sub_46DC70(pNum, v8, 0); 1070 | pData->Collision->CollisionArray->push |= 0x70u; 1071 | v11 = *(char*)0x1DE4660; 1072 | *(int*)&MainCharObj2[pNum]->CurrentSurfaceFlags = 0; 1073 | byte_1DE4664[pNum & 1] = v11; 1074 | 1075 | v10 = (int)*(&off_1DE95E0 + pNum); 1076 | if (co2) 1077 | { 1078 | co2->Speed = { 0.0f, 0.0f, 0.0f }; 1079 | } 1080 | if (v10) 1081 | { 1082 | *(float*)(v10 + 8) = 0.0f; 1083 | *(float*)(v10 + 4) = 0.0f; 1084 | *(float*)v10 = 0.0f; 1085 | } 1086 | } 1087 | 1088 | __declspec(naked) void Load2PIntroPos_r() 1089 | { 1090 | __asm 1091 | { 1092 | push eax 1093 | call Load2PIntroPos_ri 1094 | add esp, 4 1095 | retn 1096 | } 1097 | } 1098 | 1099 | #pragma endregion 1100 | #pragma region 2P Race Bar 1101 | 1102 | CharObj2Base* __cdecl loc_727E5B_i(int playerNum) 1103 | { 1104 | CharObj2Base* v13 = MainCharObj2[playerNum]; 1105 | NJS_TEXLIST* v12 = 0; 1106 | if (v13) 1107 | { 1108 | switch (v13->CharID2) 1109 | { 1110 | case Characters_Sonic: 1111 | case Characters_SuperSonic: 1112 | v12 = &TexList_SonicLife; 1113 | break; 1114 | case Characters_Shadow: 1115 | case Characters_SuperShadow: 1116 | v12 = &TexList_ShadowLife; 1117 | break; 1118 | case Characters_Amy: 1119 | v12 = &TexList_AmyLife; 1120 | break; 1121 | case Characters_MetalSonic: 1122 | v12 = &TexList_MetalLife; 1123 | break; 1124 | case Characters_Tails: 1125 | case Characters_MechTails: 1126 | v12 = &TexList_TailsLife; 1127 | break; 1128 | case Characters_ChaoWalker: 1129 | v12 = &TexList_ChaoLife; 1130 | break; 1131 | case Characters_DarkChaoWalker: 1132 | v12 = &TexList_DarkChaoLife; 1133 | break; 1134 | case Characters_Knuckles: 1135 | v12 = &TexList_KnucklesLife; 1136 | break; 1137 | case Characters_Rouge: 1138 | v12 = &TexList_RougeLife; 1139 | break; 1140 | case Characters_Tikal: 1141 | v12 = &TexList_TikalLife; 1142 | break; 1143 | case Characters_Chaos: 1144 | v12 = &TexList_ChaosLife; 1145 | break; 1146 | default: 1147 | return 0; 1148 | } 1149 | (*(int**)0x2670544)[8] = (int)v12; 1150 | } 1151 | return v13; 1152 | } 1153 | 1154 | const void* const loc_727F34 = (void*)0x727F34; 1155 | const void* const loc_727EA8 = (void*)0x727EA8; 1156 | __declspec(naked) void loc_727E5B() 1157 | { 1158 | __asm 1159 | { 1160 | push esi 1161 | call loc_727E5B_i 1162 | add esp, 4 1163 | test eax, eax 1164 | jz lab 1165 | xor ecx, ecx 1166 | jmp loc_727EA8 1167 | lab : 1168 | jmp loc_727F34 1169 | } 1170 | } 1171 | 1172 | #pragma endregion 1173 | #pragma region Goal Ring 1174 | 1175 | void GoalRing_Main_r(ObjectMaster* obj) 1176 | { 1177 | EntityData1* data = obj->Data1.Entity; 1178 | 1179 | for (uint8_t i = 0; i < StageSelectLevels_Length; i++) 1180 | { 1181 | if ((CurrentLevel == StageSelectLevels[i].Level) && (StageSelectLevels[i].Character == Characters_Knuckles || StageSelectLevels[i].Character == Characters_Rouge)) 1182 | { 1183 | if (MissionNum == 1) 1184 | { 1185 | data->Rotation.x = 2; 1186 | data->Action = 1; 1187 | if (!MainCharObj1[0] || MainCharObj1[0]->Timer < 120u) 1188 | { 1189 | return; 1190 | } 1191 | } 1192 | else if (data->Rotation.x % 3 != 1) 1193 | { 1194 | return; 1195 | } 1196 | } 1197 | } 1198 | 1199 | ObjectFunc(origin, GoalRing_t->Target()); 1200 | origin(obj); 1201 | } 1202 | 1203 | #pragma endregion 1204 | #pragma region Title Card Textures 1205 | 1206 | DataPointer(NJS_TEXLIST, stru_1738D90, 0x1738D90); 1207 | DataPointer(NJS_TEXLIST, stru_1738DB0, 0x1738DB0); 1208 | void LoadTitleCardTextures() 1209 | { 1210 | const char* v15; // esi@19 1211 | char filename[24]; // [sp+Ch] [bp-20h]@27 1212 | 1213 | if (TwoPlayerMode || CurrentLevel == LevelIDs_Route101280) 1214 | { 1215 | switch (CurrentCharacter) 1216 | { 1217 | case Characters_Knuckles: 1218 | case Characters_Rouge: 1219 | v15 = "KN"; 1220 | break; 1221 | case Characters_Tails: 1222 | case Characters_Eggman: 1223 | case Characters_MechTails: 1224 | case Characters_MechEggman: 1225 | v15 = "TA"; 1226 | break; 1227 | default: 1228 | v15 = "SO"; 1229 | break; 1230 | } 1231 | } 1232 | else 1233 | { 1234 | if (CurrentLevel == LevelIDs_CannonsCoreT) 1235 | goto LABEL_26; 1236 | switch (MainCharObj2[0]->CharID2) 1237 | { 1238 | case Characters_Shadow: 1239 | case Characters_SuperShadow: 1240 | v15 = "SH"; 1241 | break; 1242 | case Characters_Eggman: 1243 | case Characters_MechEggman: 1244 | v15 = "EG"; 1245 | break; 1246 | case Characters_Tails: 1247 | case Characters_MechTails: 1248 | v15 = "TA"; 1249 | break; 1250 | case Characters_Knuckles: 1251 | v15 = "KN"; 1252 | break; 1253 | case Characters_Rouge: 1254 | v15 = "RO"; 1255 | break; 1256 | case Characters_Amy: 1257 | v15 = "AM"; 1258 | break; 1259 | case Characters_MetalSonic: 1260 | v15 = "ME"; 1261 | break; 1262 | case Characters_Tikal: 1263 | v15 = "TI"; 1264 | break; 1265 | case Characters_Chaos: 1266 | v15 = "C0"; 1267 | break; 1268 | case Characters_ChaoWalker: 1269 | v15 = "CH"; 1270 | break; 1271 | case Characters_DarkChaoWalker: 1272 | v15 = "DC"; 1273 | break; 1274 | default: 1275 | LABEL_26: 1276 | v15 = "SO"; 1277 | break; 1278 | } 1279 | } 1280 | sprintf_s(filename, "MISSIONTEX_%s", v15); 1281 | LoadTextureList(filename, &stru_1738D90); 1282 | sprintf_s(filename, "MISSIONTEX_%s2", v15); 1283 | LoadTextureList(filename, &stru_1738DB0); 1284 | } 1285 | 1286 | static const void* const loc_472B12 = (void*)0x472B12; 1287 | __declspec(naked) void loc_472A7D() 1288 | { 1289 | LoadTitleCardTextures(); 1290 | __asm jmp loc_472B12 1291 | } 1292 | 1293 | #pragma endregion 1294 | #pragma region End Level Voices 1295 | 1296 | DataArray(char, byte_174AFF5, 0x174AFF5, 2); 1297 | void PlayEndLevelVoice(int playerNum) 1298 | { 1299 | bool v3; 1300 | __int16 v6; // cx@12 1301 | CharObj2Base* v14; // edx@29 1302 | bool v15; // eax@30 1303 | int v16; // eax@42 1304 | bool v17; // eax@62 1305 | 1306 | if (!HaveChaoKey) 1307 | *(int*)AltCostume = 0; 1308 | v3 = !playerNum; 1309 | v6 = CurrentLevel; 1310 | v14 = MainCharObj2[playerNum]; 1311 | if (TwoPlayerMode) 1312 | { 1313 | v15 = byte_174AFF5[playerNum] != 1; 1314 | switch (v14->CharID2) 1315 | { 1316 | case Characters_Sonic: 1317 | if (byte_174AFF5[playerNum] == 1) 1318 | v16 = 1529; 1319 | else 1320 | v16 = (char)(MainCharObj2[v3]->CharID2 - 1) != 0 ? 1613 : 1531; 1321 | break; 1322 | case Characters_Shadow: 1323 | if (byte_174AFF5[playerNum] == 1) 1324 | v16 = MainCharObj2[v3]->CharID2 != 0 ? 1604 : 1528; 1325 | else 1326 | v16 = 1530; 1327 | break; 1328 | case Characters_Knuckles: 1329 | v16 = 2 * (v15 != 0) + 1254; 1330 | break; 1331 | case Characters_Rouge: 1332 | v16 = 2 * (v15 != 0) + 1255; 1333 | break; 1334 | case Characters_MechTails: 1335 | if (byte_174AFF5[playerNum] == 1) 1336 | v16 = 1643; 1337 | else 1338 | v16 = (((MainCharObj2[v3]->CharID2 != Characters_MechEggman) - 1) & 0xFFFFFFBA) + 1715; 1339 | break; 1340 | case Characters_MechEggman: 1341 | if (byte_174AFF5[playerNum] != 1 || *(char*)0x174AFD2) 1342 | v16 = 1644; 1343 | else 1344 | v16 = 1642; 1345 | break; 1346 | case Characters_Amy: 1347 | if (byte_174AFF5[playerNum] == 1) 1348 | { 1349 | if (RingCount[playerNum] <= 100) 1350 | v16 = 8 * (RingCount[v3] < 20) + 2670; 1351 | else 1352 | v16 = 2680; 1353 | } 1354 | else 1355 | { 1356 | if (RingCount[playerNum] <= 100) 1357 | { 1358 | v17 = RingCount[v3] < 20; 1359 | v17 = RingCount[v3] >= 20; 1360 | v16 = ((v17 - 1) & 6) + 2673; 1361 | } 1362 | else 1363 | { 1364 | v16 = 2681; 1365 | } 1366 | } 1367 | break; 1368 | case Characters_Tikal: 1369 | v16 = 2716; 1370 | break; 1371 | case Characters_Chaos: 1372 | v16 = 2687; 1373 | break; 1374 | case Characters_MetalSonic: 1375 | v16 = 2712; 1376 | break; 1377 | case Characters_ChaoWalker: 1378 | v16 = 2692; 1379 | break; 1380 | case Characters_DarkChaoWalker: 1381 | v16 = 2703; 1382 | break; 1383 | default: 1384 | return; 1385 | } 1386 | } 1387 | else 1388 | { 1389 | switch (v14->CharID2) 1390 | { 1391 | case Characters_Sonic: 1392 | switch (v6) 1393 | { 1394 | case LevelIDs_BigFoot: 1395 | v16 = 1605; 1396 | break; 1397 | case LevelIDs_SonicVsShadow1: 1398 | v16 = 1606; 1399 | break; 1400 | case LevelIDs_EggGolemS: 1401 | v16 = 1607; 1402 | break; 1403 | case LevelIDs_SonicVsShadow2: 1404 | v16 = 1608; 1405 | break; 1406 | default: 1407 | v16 = 1593; 1408 | break; 1409 | } 1410 | break; 1411 | case Characters_SuperSonic: 1412 | v16 = (((v6 == LevelIDs_FinalHazard) - 1) & 0xFFFFFFEF) + 1610; 1413 | break; 1414 | case Characters_Shadow: 1415 | switch (v6) 1416 | { 1417 | case LevelIDs_HotShot: 1418 | v16 = 1594; 1419 | break; 1420 | case LevelIDs_SonicVsShadow1: 1421 | v16 = 1596; 1422 | break; 1423 | case LevelIDs_SonicVsShadow2: 1424 | v16 = 1598; 1425 | break; 1426 | case LevelIDs_Biolizard: 1427 | v16 = 1600; 1428 | break; 1429 | default: 1430 | v16 = 1552; 1431 | break; 1432 | } 1433 | break; 1434 | case Characters_SuperShadow: 1435 | v16 = (((v6 == LevelIDs_FinalHazard) - 1) & 0xFFFFFFCE) + 1602; 1436 | break; 1437 | case Characters_Knuckles: 1438 | if (v6 == LevelIDs_KnucklesVsRouge) 1439 | v16 = 1344; 1440 | else 1441 | v16 = v6 != LevelIDs_KingBoomBoo ? 1330 : 1342; 1442 | break; 1443 | case Characters_Rouge: 1444 | if (v6 == LevelIDs_KnucklesVsRouge) 1445 | v16 = 1345; 1446 | else 1447 | v16 = v6 != LevelIDs_FlyingDog ? 1331 : 1343; 1448 | break; 1449 | case Characters_MechTails: 1450 | v16 = (((v6 == LevelIDs_TailsVsEggman1) - 1) & 0xFFFFFFF4) + 1715; 1451 | break; 1452 | case Characters_MechEggman: 1453 | v16 = (((v6 == LevelIDs_TailsVsEggman1) - 1) & 0x3A) + 1642; 1454 | break; 1455 | case Characters_Amy: 1456 | v16 = 2679; 1457 | break; 1458 | case Characters_Tikal: 1459 | v16 = 2716; 1460 | break; 1461 | case Characters_Chaos: 1462 | v16 = 2687; 1463 | break; 1464 | case Characters_MetalSonic: 1465 | v16 = 2712; 1466 | break; 1467 | case Characters_ChaoWalker: 1468 | v16 = 2692; 1469 | break; 1470 | case Characters_DarkChaoWalker: 1471 | v16 = 2703; 1472 | break; 1473 | default: 1474 | return; 1475 | } 1476 | } 1477 | PlayVoice(2, v16); 1478 | } 1479 | 1480 | static const void* const loc_43F1FC = (void*)0x43F1FC; 1481 | __declspec(naked) void loc_43EE5F() 1482 | { 1483 | __asm 1484 | { 1485 | push esi 1486 | call PlayEndLevelVoice 1487 | pop esi 1488 | jmp loc_43F1FC 1489 | } 1490 | } 1491 | 1492 | #pragma endregion 1493 | /* 1494 | #pragma region Chao World Sounds 1495 | 1496 | ThiscallFunctionPointer(void, sub_435880, (const char*), 0x435880); 1497 | void LoadChaoWorldSoundBank() 1498 | { 1499 | const char* v4; 1500 | 1501 | int v2 = MainCharObj2[0]->CharID2; 1502 | switch (v2) 1503 | { 1504 | case Characters_Amy: 1505 | case Characters_MetalSonic: 1506 | v4 = "chao_chara_sn.mlt"; 1507 | break; 1508 | case Characters_Knuckles: 1509 | case Characters_Rouge: 1510 | v4 = "chao_chara_kr.mlt"; 1511 | break; 1512 | case Characters_Tikal: 1513 | case Characters_Chaos: 1514 | v4 = "se_ch_kn_BATTLE.mlt"; 1515 | break; 1516 | case Characters_Tails: 1517 | case Characters_Eggman: 1518 | v4 = "chao_chara_te.mlt"; 1519 | break; 1520 | case Characters_MechTails: 1521 | case Characters_MechEggman: 1522 | v4 = "se_ch_wk.mlt"; 1523 | break; 1524 | case Characters_ChaoWalker: 1525 | case Characters_DarkChaoWalker: 1526 | v4 = "se_ch_wk_BATTLE.mlt"; 1527 | break; 1528 | default: 1529 | v4 = "chao_chara_ss.mlt"; 1530 | break; 1531 | } 1532 | sub_435880(v4); 1533 | } 1534 | 1535 | static const int loc_532054 = 0x532054; 1536 | __declspec(naked) void loc_532029() 1537 | { 1538 | LoadChaoWorldSoundBank(); 1539 | __asm jmp loc_532054 1540 | } 1541 | 1542 | #pragma endregion 1543 | #pragma region Chao World Voices 1544 | 1545 | static const int stru_173A0B8 = 0x173A0B8; 1546 | static const int sub_459010 = 0x459010; 1547 | static const int loc_45923B = 0x45923B; 1548 | __declspec(naked) void loc_2800440() 1549 | { 1550 | __asm 1551 | { 1552 | mov ecx, MainCharObj2 1553 | movzx ecx, [ecx].CharID2 1554 | cmp ecx, Characters_Amy 1555 | jle short loc_280045F 1556 | cmp ecx, Characters_Tikal 1557 | jz short loc_280045A 1558 | cmp ecx, Characters_Amy 1559 | jnz short loc_280045F 1560 | mov esi, stru_173A0B8 1561 | jmp short loc_280045F 1562 | ; -------------------------------------------------------------------------- - 1563 | 1564 | loc_280045A: 1565 | mov esi, (stru_173A0B8 + 20h) 1566 | 1567 | loc_280045F : 1568 | call sub_459010 1569 | jmp loc_45923B 1570 | } 1571 | } 1572 | 1573 | #pragma endregion 1574 | */ 1575 | #pragma region Upgrade Fixes 1576 | 1577 | // Knuckles Sunglasses 1578 | static const int loc_72F528 = 0x72F528; 1579 | static const int loc_72F4DB = 0x72F4DB; 1580 | static NJS_OBJECT** const KnucklesSunglassesModel = &CharacterModels[161].Model; 1581 | __declspec(naked) void KnucklesSunglassesFix() 1582 | { 1583 | __asm 1584 | { 1585 | mov eax, KnucklesSunglassesModel 1586 | mov eax, [eax] 1587 | test eax, eax 1588 | jz label 1589 | jmp loc_72F4DB 1590 | label : 1591 | jmp loc_72F528 1592 | } 1593 | } 1594 | 1595 | // Knuckles Air Necklase 1596 | static const int loc_72F564 = 0x72F564; 1597 | static const int loc_72F537 = 0x72F537; 1598 | static NJS_OBJECT** const KnucklesAirNecklaceModel = &CharacterModels[168].Model; 1599 | __declspec(naked) void KnucklesAirNecklaceFix() 1600 | { 1601 | __asm 1602 | { 1603 | mov ecx, KnucklesAirNecklaceModel 1604 | mov ecx, [ecx] 1605 | test ecx, ecx 1606 | jz label 1607 | jmp loc_72F537 1608 | label : 1609 | jmp loc_72F564 1610 | } 1611 | } 1612 | 1613 | // Eggman Laser Blaster 1614 | static const int loc_74496B = 0x74496B; 1615 | static const int loc_74491A = 0x74491A; 1616 | static NJS_OBJECT** const EggmanLaserBlasterModel = &CharacterModels[260].Model; 1617 | __declspec(naked) void EggmanLaserBlasterFix() 1618 | { 1619 | __asm 1620 | { 1621 | mov edx, EggmanLaserBlasterModel 1622 | mov edx, [edx] 1623 | test edx, edx 1624 | jz label 1625 | jmp loc_74491A 1626 | label : 1627 | jmp loc_74496B 1628 | } 1629 | } 1630 | 1631 | // Eggman Large Cannon 1632 | static const int loc_744E59 = 0x744E59; 1633 | static const int loc_744E08 = 0x744E08; 1634 | static NJS_OBJECT** const EggmanLargeCannonModel1 = &CharacterModels[262].Model; 1635 | static NJS_OBJECT** const EggmanLargeCannonModel2 = &CharacterModels[263].Model; 1636 | static const float* const flt_8AF004 = (const float*)0x8AF004; 1637 | __declspec(naked) void EggmanLargeCannonFix() 1638 | { 1639 | __asm 1640 | { 1641 | mov eax, EggmanLargeCannonModel1 1642 | mov eax, [eax] 1643 | test eax, eax 1644 | jz label 1645 | mov eax, EggmanLargeCannonModel2 1646 | mov eax, [eax] 1647 | test eax, eax 1648 | jz label 1649 | mov eax, flt_8AF004 1650 | fld[eax] 1651 | jmp loc_744E08 1652 | label : 1653 | jmp loc_744E59 1654 | } 1655 | } 1656 | 1657 | // Tails Laser Blaster 1658 | static const int loc_7481C3 = 0x7481C3; 1659 | static const int loc_74816E = 0x74816E; 1660 | static NJS_OBJECT** const TailsLaserBlasterModel = &CharacterModels[306].Model; 1661 | __declspec(naked) void TailsLaserBlasterFix() 1662 | { 1663 | __asm 1664 | { 1665 | mov edx, TailsLaserBlasterModel 1666 | mov edx, [edx] 1667 | test edx, edx 1668 | jz label 1669 | jmp loc_74816E 1670 | label : 1671 | jmp loc_7481C3 1672 | } 1673 | } 1674 | 1675 | // Tails Bazooka 1676 | static const int loc_748717 = 0x748717; 1677 | static const int loc_748620 = 0x748620; 1678 | static NJS_OBJECT** const TailsBazookaModel = &CharacterModels[309].Model; 1679 | __declspec(naked) void TailsBazookaFix() 1680 | { 1681 | __asm 1682 | { 1683 | mov esi, TailsBazookaModel 1684 | mov esi, [esi] 1685 | test esi, esi 1686 | jz label 1687 | jmp loc_748620 1688 | label : 1689 | jmp loc_748717 1690 | } 1691 | } 1692 | 1693 | #pragma endregion 1694 | 1695 | #pragma region Emerald Manager 1696 | 1697 | bool __cdecl CheckEmeraldManager() 1698 | { 1699 | if (MissionNum == 1 || MissionNum == 2) 1700 | return false; 1701 | if (*(int*)0x1AF014C) 1702 | return false; 1703 | switch ((short)CurrentLevel) 1704 | { 1705 | case LevelIDs_PumpkinHill: 1706 | case LevelIDs_AquaticMine: 1707 | case LevelIDs_SecurityHall: 1708 | case LevelIDs_WildCanyon: 1709 | case LevelIDs_DryLagoon: 1710 | case LevelIDs_DeathChamber: 1711 | case LevelIDs_EggQuarters: 1712 | case LevelIDs_MeteorHerd: 1713 | case LevelIDs_WildCanyon2P: 1714 | case LevelIDs_MadSpace: 1715 | case LevelIDs_DryLagoon2P: 1716 | case LevelIDs_PoolQuest: 1717 | case LevelIDs_PlanetQuest: 1718 | case LevelIDs_DeathChamber2P: 1719 | return true; 1720 | } 1721 | return false; 1722 | } 1723 | 1724 | static const void* const loc_73AAC2 = (void*)0x73AAC2; 1725 | __declspec(naked) void LoadEmeraldManager_r() 1726 | { 1727 | if (!CheckEmeraldManager()) 1728 | __asm retn; 1729 | __asm 1730 | { 1731 | push esi 1732 | push edi 1733 | jmp loc_73AAC2 1734 | } 1735 | } 1736 | 1737 | void LoadEmeraldManager_r_wrapper() 1738 | { 1739 | LoadEmeraldManager_r(); 1740 | } 1741 | 1742 | #pragma endregion 1743 | 1744 | Trampoline* Knuckles_LevelBounds_t = nullptr; 1745 | 1746 | static inline int Knuckles_LevelBounds_origin(EntityData1* a1, KnucklesCharObj2* a2) 1747 | { 1748 | auto target = Knuckles_LevelBounds_t->Target(); 1749 | 1750 | int result; 1751 | __asm 1752 | { 1753 | mov ecx, [a2] 1754 | mov eax, [a1] 1755 | call target 1756 | mov result, eax 1757 | } 1758 | return result; 1759 | } 1760 | 1761 | int Knuckles_LevelBounds_r(EntityData1* a1, KnucklesCharObj2* a2) 1762 | { 1763 | for (uint8_t i = 0; i < StageSelectLevels_Length; i++) 1764 | { 1765 | if ((CurrentLevel == StageSelectLevels[i].Level)) 1766 | { 1767 | if (StageSelectLevels[i].Character == Characters_Knuckles || StageSelectLevels[i].Character == Characters_Rouge) { 1768 | 1769 | return Knuckles_LevelBounds_origin(a1, a2); 1770 | } 1771 | } 1772 | } 1773 | 1774 | return 0; 1775 | } 1776 | 1777 | static void __declspec(naked) Knuckles_LevelBounds_ASM() 1778 | { 1779 | __asm 1780 | { 1781 | push ecx 1782 | push eax 1783 | call Knuckles_LevelBounds_r 1784 | add esp, 4 1785 | pop ecx 1786 | retn 1787 | } 1788 | } 1789 | 1790 | 1791 | #pragma region Animation Loaders 1792 | 1793 | void LoadAquaticMineCharAnims_r() 1794 | { 1795 | if (CurrentCharacter == Characters_Knuckles) 1796 | LoadAquaticMineCharAnims(); 1797 | else 1798 | LoadDryLagoon2PCharAnims(); 1799 | } 1800 | 1801 | void LoadDryLagoonCharAnims_r() 1802 | { 1803 | if (CurrentCharacter == Characters_Rouge) 1804 | LoadDryLagoonCharAnims(); 1805 | else 1806 | LoadDryLagoon2PCharAnims(); 1807 | } 1808 | 1809 | void LoadCannonsCoreRCharAnims_r() 1810 | { 1811 | if (CurrentCharacter == Characters_Rouge) 1812 | LoadCannonsCoreRCharAnims(); 1813 | else 1814 | LoadDryLagoon2PCharAnims(); 1815 | } 1816 | 1817 | void LoadCannonsCoreKCharAnims_r() 1818 | { 1819 | if (CurrentCharacter == Characters_Knuckles) 1820 | LoadCannonsCoreKCharAnims(); 1821 | else 1822 | LoadDryLagoon2PCharAnims(); 1823 | } 1824 | 1825 | void LoadSandOceanCharAnims_r() 1826 | { 1827 | if (CurrentCharacter == Characters_MechEggman) 1828 | LoadSandOceanCharAnims(); 1829 | else if (CurrentCharacter <= Characters_Shadow && !isSonicTrickMod()) 1830 | LoadEggGolemCharAnims(); 1831 | else 1832 | LoadSandOcean2PCharAnims(); 1833 | } 1834 | 1835 | void LoadHiddenBaseCharAnims_r() 1836 | { 1837 | if (CurrentCharacter == Characters_MechTails) 1838 | LoadHiddenBaseCharAnims(); 1839 | else if (CurrentCharacter <= Characters_Shadow && !isSonicTrickMod()) 1840 | LoadEggGolemCharAnims(); 1841 | else 1842 | LoadSandOcean2PCharAnims(); 1843 | } 1844 | 1845 | void LoadEggGolemECharAnims_r() 1846 | { 1847 | if (CurrentCharacter == Characters_MechEggman) 1848 | LoadEggGolemECharAnims(); 1849 | else 1850 | LoadSandOcean2PCharAnims(); 1851 | } 1852 | 1853 | #pragma endregion 1854 | #pragma region Animation Lists 1855 | AnimationInfo TailsAnimList2[ChaosAnimList_Length]; 1856 | AnimationInfo MechEggmanAnimList2[ChaosAnimList_Length]; 1857 | AnimationInfo MechTailsAnimList2[ChaosAnimList_Length]; 1858 | AnimationInfo ChaoWalkerAnimList2[ChaosAnimList_Length]; 1859 | AnimationInfo DarkChaoWalkerAnimList2[ChaosAnimList_Length]; 1860 | AnimationInfo EggmanAnimList2[ChaosAnimList_Length]; 1861 | AnimationInfo SonicAnimList2[ChaosAnimList_Length]; 1862 | 1863 | pair SonicAnimReplacements[] = { 1864 | { 211, 1 }, 1865 | { 212, 77 }, 1866 | { 215, 15 } 1867 | }; 1868 | 1869 | pair OthersAnimReplacements[] = { 1870 | { 76, 0 }, 1871 | { 77, 15 }, 1872 | { 185, 62 }, 1873 | { 186, 62 }, 1874 | { 187, 62 }, 1875 | { 189, 62 }, 1876 | { 190, 62 }, 1877 | { 192, 15 }, 1878 | { 193, 15 }, 1879 | { 194, 15 }, 1880 | { 195, 15 }, 1881 | { 196, 15 }, 1882 | { 197, 15 }, 1883 | { 198, 15 }, 1884 | { 211, 1 }, 1885 | { 212, 62 }, 1886 | { 215, 15 } 1887 | }; 1888 | 1889 | pair KnucklesAnimReplacements[] = { 1890 | { 190, 75 }, 1891 | { 192, 105 }, 1892 | { 193, 105 }, 1893 | { 194, 15 }, 1894 | { 195, 15 }, 1895 | { 196, 15 }, 1896 | { 197, 15 }, 1897 | { 198, 15 }, 1898 | { 211, 1 }, 1899 | { 212, 77 }, 1900 | { 215, 15 } 1901 | }; 1902 | 1903 | pair MechAnimReplacements[] = { 1904 | { 76, 0 }, 1905 | { 77, 15 }, 1906 | { 185, 75 }, 1907 | { 186, 75 }, 1908 | { 187, 75 }, 1909 | { 189, 75 }, 1910 | { 190, 75 }, 1911 | { 192, 15 }, 1912 | { 193, 15 }, 1913 | { 194, 15 }, 1914 | { 195, 15 }, 1915 | { 196, 15 }, 1916 | { 197, 15 }, 1917 | { 198, 15 }, 1918 | { 211, 1 }, 1919 | { 212, 77 }, 1920 | { 215, 15 } 1921 | }; 1922 | 1923 | pair listend = { -1, 0 }; 1924 | 1925 | void LoadAnimations(int* character, int playerNum) 1926 | { 1927 | int repcnt; 1928 | pair* replst; 1929 | switch (*character) 1930 | { 1931 | case Characters_Sonic: 1932 | default: 1933 | 1934 | LoadSonic(playerNum); 1935 | repcnt = (int)LengthOfArray(SonicAnimReplacements); 1936 | replst = SonicAnimReplacements; 1937 | break; 1938 | case Characters_Shadow: 1939 | LoadShadow(playerNum); 1940 | repcnt = (int)LengthOfArray(SonicAnimReplacements); 1941 | replst = SonicAnimReplacements; 1942 | break; 1943 | case Characters_Tails: 1944 | LoadTails(playerNum); 1945 | repcnt = (int)LengthOfArray(OthersAnimReplacements); 1946 | replst = OthersAnimReplacements; 1947 | break; 1948 | case Characters_Eggman: 1949 | LoadEggman(playerNum); 1950 | repcnt = (int)LengthOfArray(OthersAnimReplacements); 1951 | replst = OthersAnimReplacements; 1952 | break; 1953 | case Characters_Knuckles: 1954 | LoadKnuckles(playerNum); 1955 | repcnt = (int)LengthOfArray(KnucklesAnimReplacements); 1956 | replst = KnucklesAnimReplacements; 1957 | break; 1958 | case Characters_Rouge: 1959 | LoadRouge(playerNum); 1960 | repcnt = (int)LengthOfArray(KnucklesAnimReplacements) - 3; 1961 | replst = KnucklesAnimReplacements; 1962 | break; 1963 | case Characters_MechTails: 1964 | LoadMechTails(playerNum); 1965 | repcnt = (int)LengthOfArray(MechAnimReplacements); 1966 | replst = MechAnimReplacements; 1967 | break; 1968 | case Characters_MechEggman: 1969 | LoadMechEggman(playerNum); 1970 | repcnt = (int)LengthOfArray(MechAnimReplacements); 1971 | replst = MechAnimReplacements; 1972 | break; 1973 | } 1974 | InitPlayer(playerNum); 1975 | /**AnimationInfo* anilst = MainCharObj2[playerNum]->AnimInfo.Animations; 1976 | for (int i = 0; i < repcnt; i++) 1977 | if (!CharacterAnimations[anilst[replst[i].key].AnimNum].Animation) 1978 | anilst[replst[i].key] = anilst[replst[i].value];*/ 1979 | } 1980 | 1981 | template 1982 | void actionlistthing(pair* (&order)[N], void** ptr, bool skipmagichands) 1983 | { 1984 | vector> tmp; 1985 | for (size_t i = 0; i < LengthOfArray(order); i++) 1986 | { 1987 | while (order[i]->key != -1) 1988 | { 1989 | if (skipmagichands && order[i]->key == 74) 1990 | goto next; 1991 | for (size_t j = 0; j < tmp.size(); j++) 1992 | if (tmp[j].key == order[i]->key) 1993 | goto next; 1994 | tmp.emplace_back(*order[i]); 1995 | next: 1996 | ++order[i]; 1997 | } 1998 | } 1999 | tmp.emplace_back(listend); 2000 | pair* buf = new pair[tmp.size()]; 2001 | memcpy(buf, tmp.data(), tmp.size() * sizeof(pair)); 2002 | WriteData(ptr, (void*)buf); 2003 | } 2004 | 2005 | #pragma endregion 2006 | 2007 | void LoadCharacterSoundBanks_r(int curChar, MLTSoundList* mltSoundList, MLTSoundList* a1) 2008 | { 2009 | if (curChar != Characters_Tails && curChar != Characters_Eggman) 2010 | { 2011 | LoadCharacterSoundBanks(curChar, mltSoundList, a1); 2012 | return; 2013 | } 2014 | 2015 | CharacterSoundBank* SoundBank; 2016 | char i; 2017 | CharacterVoiceBank* soundBank2; 2018 | char k; 2019 | const char* v14; 2020 | 2021 | SoundBank = stru_1739F58; 2022 | 2023 | for (i = 0; i < 10; ++i) 2024 | { 2025 | if ((SoundBank->Character) == curChar) 2026 | { 2027 | break; 2028 | } 2029 | ++SoundBank; 2030 | } 2031 | if (i == 10) 2032 | { 2033 | SoundBank = stru_1739F58; 2034 | } 2035 | 2036 | soundBank2 = stru_173A018; 2037 | for (k = 0; k < 10; ++k) 2038 | { 2039 | if (soundBank2->Character == curChar) 2040 | { 2041 | break; 2042 | } 2043 | ++soundBank2; 2044 | } 2045 | if (k == 10) 2046 | { 2047 | soundBank2 = stru_173A018; 2048 | } 2049 | 2050 | v14 = SoundBank->Name; 2051 | if (v14) 2052 | { 2053 | LoadMLT(v14); 2054 | } 2055 | mltSoundList->Size = (int)SoundBank->SoundList; 2056 | sub_459010(a1, soundBank2); 2057 | } 2058 | 2059 | static void __declspec(naked) LoadCharacterSoundBanksASM() 2060 | { 2061 | __asm 2062 | { 2063 | push[esp + 08h] // a1 2064 | push[esp + 08h] // mltSoundList 2065 | push ebx // curChar 2066 | 2067 | // Call your __cdecl function here: 2068 | call LoadCharacterSoundBanks_r 2069 | 2070 | pop ebx // curChar 2071 | add esp, 4 // mltSoundList 2072 | add esp, 4 // a1 2073 | retn 2074 | } 2075 | } 2076 | 2077 | int CanGrabPiece_r(int pieceID, int pnum) 2078 | { 2079 | if (CurrentCharacter != Characters_Knuckles && CurrentCharacter != Characters_Rouge) 2080 | return 1; 2081 | 2082 | auto player = MainCharObj1[pnum]; 2083 | auto co2 = MainCharObj2[pnum]; 2084 | char action = player->Action; 2085 | int result = 0; 2086 | 2087 | if (pieceID < 4) 2088 | { 2089 | return 1; 2090 | } 2091 | if (pieceID > 6) 2092 | { 2093 | return 1; 2094 | } 2095 | 2096 | if (!player) 2097 | { 2098 | return 1; 2099 | } 2100 | 2101 | if (action == Action_DigFinish || action == Action_DigFinishOnWall) 2102 | { 2103 | return 1; 2104 | } 2105 | switch (CurrentLevel) 2106 | { 2107 | case LevelIDs_SecurityHall: 2108 | case LevelIDs_WildCanyon: 2109 | case LevelIDs_DryLagoon: 2110 | case LevelIDs_WildCanyon2P: 2111 | case LevelIDs_DryLagoon2P: 2112 | return 1; 2113 | default: 2114 | result = 0; 2115 | break; 2116 | } 2117 | return result; 2118 | } 2119 | 2120 | 2121 | static void __declspec(naked) CanGrabPieceASM() 2122 | { 2123 | __asm 2124 | { 2125 | push[esp + 04h] 2126 | push eax 2127 | call CanGrabPiece_r 2128 | add esp, 4 2129 | add esp, 4 2130 | retn 2131 | } 2132 | } 2133 | 2134 | 2135 | void WritePatches() 2136 | { 2137 | //fix Tails and Eggman mechless wrong sound bank 2138 | WriteCall((void*)0x438B37, LoadCharacterSoundBanksASM); 2139 | 2140 | unsigned __int8 twobytenop[] = { 0x66, 0x90 }; 2141 | unsigned __int8 fivebytenop[] = { 0x66, 0x90, 0x66, 0x90, 0x90 }; 2142 | unsigned __int8 shortjmp[] = { 0xEB }; 2143 | 2144 | WriteData((void*)0x459110, twobytenop); // 2P Sound Effects Patch 2145 | WriteData((void*)0x45913B, twobytenop); // 2P Voice Patch 2146 | WriteData((void*)0x44E63B, twobytenop); // Dark Chao Walker Life Icon Patch 2147 | WriteData((void*)0x4CD255, twobytenop); // Sonic's Cannon's Core Control Patch 2148 | WriteData((void*)0x724261, shortjmp); // Sonic Boss Special Patch 2149 | WriteData((void*)0x736211, shortjmp); // Knuckles Boss Special Patch 2150 | WriteData((void*)0x7374E4, shortjmp); // Dry Lagoon Turtle Grab Patch 2151 | WriteData((void*)0x749921, shortjmp); // Mech Boss Special Patch 2152 | WriteData((void*)0x741690, shortjmp); // Dark Chao Walker Fix 2153 | WriteData((void*)0x7416DC, shortjmp); // Chao Walker Fix 2154 | WriteData((void*)0x728141, fivebytenop); // Knuckles emerald manager 2155 | WriteData((void*)0x728491, fivebytenop); // Rouge emerald manager 2156 | WriteData((void*)0x7288B7, fivebytenop); // Tikal emerald manager 2157 | WriteData((void*)0x728B64, fivebytenop); // Chaos emerald manager 2158 | WriteData((void*)0x716E13, twobytenop); // Amy 2159 | WriteData((void*)0x716F2C, twobytenop); // Sonic costume 2160 | WriteData((void*)0x717373, twobytenop); // Metal Sonic 2161 | WriteData((void*)0x71748C, twobytenop); // Shadow costume 2162 | WriteData((void*)0x728123, twobytenop); // Tikal 2163 | WriteData((void*)0x728241, twobytenop); // Knuckles costume 2164 | WriteData((void*)0x728473, twobytenop); // Chaos 2165 | WriteData((void*)0x728591, twobytenop); // Rouge costume 2166 | WriteData((void*)0x740C61, twobytenop); // Dark Chao Walker 2167 | WriteData((void*)0x740D72, twobytenop); // Eggman costume 2168 | WriteData((void*)0x740EC1, twobytenop); // Chao Walker 2169 | WriteData((void*)0x740FD2, twobytenop); // Tails costume 2170 | } 2171 | 2172 | void WriteJumps() 2173 | { 2174 | WriteJump((void*)0x458970, sub_458970); // Level Cutscene Function 2175 | WriteJump((void*)0x757810, sub_757810); // Somersault Fix 1 2176 | WriteJump((void*)0x759A18, loc_759A18); // Somersault Fix 2 2177 | WriteJump((void*)LoadStartPositionPtr, LoadStartPosition_r); // LoadStartPosition replacement 2178 | WriteJump((void*)0x43DF30, SetEndLevelPosition); // End position 2179 | WriteJump((void*)Load2PIntroPos, Load2PIntroPos_r); // 2P Intro position 2180 | WriteJump((void*)0x727E5B, loc_727E5B); // 2P Race Bar 2181 | 2182 | WriteJump((void*)0x6cff40, CanGrabPieceASM); //make all knux pieces always grabbable 2183 | 2184 | WriteJump((void*)0x43C9D0, (void*)0x43CADF); // Tails/Eggman fix 2185 | WriteJump((void*)0x472A7D, loc_472A7D); // Title Card textures 2186 | WriteJump((void*)0x43EE5F, loc_43EE5F); // End Level voices 2187 | //WriteJump((void*)0x532029, loc_532029); // Chao World sounds 2188 | //WriteJump((void*)0x459236, loc_2800440); // Chao World voices 2189 | WriteJump((void*)0x72F4D6, KnucklesSunglassesFix); 2190 | WriteJump((void*)0x72F531, KnucklesAirNecklaceFix); 2191 | WriteJump((void*)0x744914, EggmanLaserBlasterFix); 2192 | WriteJump((void*)0x744E02, EggmanLargeCannonFix); 2193 | WriteJump((void*)0x748168, TailsLaserBlasterFix); 2194 | WriteJump((void*)0x74861A, TailsBazookaFix); 2195 | 2196 | WriteJump((void*)0x6c63de, (void*)0x6c6431); //fix goal ring for the hunters 2197 | } 2198 | 2199 | void InitBase() 2200 | { 2201 | WritePatches(); 2202 | WriteJumps(); 2203 | 2204 | // Fixing action Lists 2205 | pair* sonic = (pair*)0x96EC80; 2206 | pair* amy = (pair*)0x96ECD0; 2207 | pair* shadow = (pair*)0x96ED18; 2208 | pair* knuckles = (pair*)0x96ED58; 2209 | pair* tikal = (pair*)0x96EDB8; 2210 | pair* rouge = (pair*)0x96EE10; 2211 | pair* chaos = (pair*)0x96EE80; 2212 | pair* mecheggman = (pair*)0x96EED8; 2213 | pair* darkchaowalker = (pair*)0x96EF08; 2214 | pair* mechtails = (pair*)0x96EF38; 2215 | pair* chaowalker = (pair*)0x96EF68; 2216 | pair* eggman = (pair*)0x96EF98; 2217 | pair* tails = (pair*)0x96EFA8; 2218 | { 2219 | pair* order[] = { sonic, shadow, rouge, knuckles, mechtails, mecheggman }; 2220 | actionlistthing(order, (void**)0x7952E5, false); 2221 | } 2222 | { 2223 | pair* order[] = { amy, sonic, shadow, rouge, knuckles, mechtails, mecheggman }; 2224 | actionlistthing(order, (void**)0x7952EC, false); 2225 | } 2226 | { 2227 | pair* order[] = { shadow, sonic, rouge, knuckles, mechtails, mecheggman }; 2228 | actionlistthing(order, (void**)0x7952F3, false); 2229 | } 2230 | { 2231 | pair* order[] = { tails, mechtails, mecheggman, sonic, shadow, rouge, knuckles }; 2232 | actionlistthing(order, (void**)0x7952FA, true); 2233 | } 2234 | { 2235 | pair* order[] = { knuckles, rouge, sonic, shadow, mechtails, mecheggman }; 2236 | actionlistthing(order, (void**)0x795301, true); 2237 | } 2238 | { 2239 | pair* order[] = { tikal, rouge, knuckles, sonic, shadow, mechtails, mecheggman }; 2240 | actionlistthing(order, (void**)0x795308, true); 2241 | } 2242 | { 2243 | pair* order[] = { rouge, knuckles, sonic, shadow, mechtails, mecheggman }; 2244 | actionlistthing(order, (void**)0x79530F, true); 2245 | } 2246 | { 2247 | pair* order[] = { chaos, rouge, knuckles, sonic, shadow, mechtails, mecheggman }; 2248 | actionlistthing(order, (void**)0x795316, true); 2249 | } 2250 | { 2251 | pair* order[] = { eggman, mecheggman, mechtails, sonic, shadow, rouge, knuckles }; 2252 | actionlistthing(order, (void**)0x79531D, true); 2253 | } 2254 | { 2255 | pair* order[] = { mecheggman, mechtails, sonic, shadow, rouge, knuckles }; 2256 | actionlistthing(order, (void**)0x795324, true); 2257 | } 2258 | { 2259 | pair* order[] = { darkchaowalker, mecheggman, mechtails, sonic, shadow, rouge, knuckles }; 2260 | actionlistthing(order, (void**)0x79532B, true); 2261 | } 2262 | { 2263 | pair* order[] = { chaowalker, mechtails, mecheggman, sonic, shadow, rouge, knuckles }; 2264 | actionlistthing(order, (void**)0x795332, true); 2265 | } 2266 | { 2267 | pair* order[] = { mechtails, mecheggman, sonic, shadow, rouge, knuckles }; 2268 | actionlistthing(order, (void**)0x795339, true); 2269 | } 2270 | 2271 | 2272 | Knuckles_LevelBounds_t = new Trampoline((int)0x737B50, (int)0x737B5A, Knuckles_LevelBounds_ASM); 2273 | GoalRing_t = new Trampoline((int)GoalRing_Main, (int)GoalRing_Main + 0x6, GoalRing_Main_r); 2274 | 2275 | WriteCall((void*)0x4D45F0, LoadAquaticMineCharAnims_r); 2276 | WriteCall((void*)0x63D727, LoadDryLagoonCharAnims_r); 2277 | WriteCall((void*)0x4DB351, LoadCannonsCoreRCharAnims_r); 2278 | WriteCall((void*)0x65E8F1, LoadCannonsCoreKCharAnims_r); 2279 | WriteCall((void*)0x65662A, LoadSandOceanCharAnims_r); 2280 | WriteCall((void*)0x4DDE49, LoadHiddenBaseCharAnims_r); //pyramid race thing 2281 | WriteCall((void*)0x710476, LoadHiddenBaseCharAnims_r); //hidden base 2282 | WriteCall((void*)0x4A53AC, LoadEggGolemECharAnims_r); 2283 | } -------------------------------------------------------------------------------- /CharacterSelectPlus/Base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void InitBase(); 4 | void LoadEmeraldManager_r_wrapper(); 5 | template struct pair { T1 key; T2 value; }; 6 | void LoadAnimations(int* character, int playerNum); -------------------------------------------------------------------------------- /CharacterSelectPlus/BossTitles.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | enum BossTitleLetterIDs 4 | { 5 | space, 6 | _A = 1000000, 7 | _C, 8 | _D, 9 | dot, 10 | _E, 11 | _G, 12 | _H, 13 | _I, 14 | _L, 15 | _M, 16 | _N, 17 | _O, 18 | _R, 19 | _S, 20 | _T, 21 | _U, 22 | _W, 23 | _Y, 24 | _K = 1000030 25 | }; 26 | 27 | NJS_TEXNAME AmyBossTitleTexName[3]; 28 | 29 | NJS_TEXLIST AmyBossTitleTex{ arrayptrandlengthT(AmyBossTitleTexName, int) }; 30 | 31 | BossTitleLetterData AmyBossTitleLetters[] 32 | { 33 | { _A, 18, 16, 0, 32, 16, 0 }, 34 | { _M, 22, 16, 0, 32, 16, 0 }, 35 | { _Y, 16, 16, 0, 16, 16, 0 }, 36 | }; 37 | 38 | BossTitleData AmyBossTitle{ arrayptrandlengthT(AmyBossTitleLetters, short), 0xC, 0x14, 0, 0x30000, 480, &AmyBossTitleTex, 320, 240, 2, 0xFFFFFF }; 39 | 40 | NJS_TEXNAME MetalSonicBossTitleTexName[10]; 41 | 42 | NJS_TEXLIST MetalSonicBossTitleTex{ arrayptrandlengthT(MetalSonicBossTitleTexName, int) }; 43 | 44 | BossTitleLetterData MetalSonicBossTitleLetters[] 45 | { 46 | { _M, 22, 16, 0, 32, 16, 0 }, 47 | { _E, 16, 16, 0, 16, 16, 0 }, 48 | { _T, 16, 16, 0, 16, 16, 0 }, 49 | { _A, 18, 16, 0, 32, 16, 0 }, 50 | { _L, 16, 16, 0, 16, 16, 0 }, 51 | { space, 16, 16, 0, 16, 16, 0 }, 52 | { _S, 16, 16, 0, 16, 16, 0 }, 53 | { _O, 16, 16, 0, 16, 16, 0 }, 54 | { _N, 16, 16, 0, 16, 16, 0 }, 55 | { _I, 8, 16, 0, 8, 16, 0 }, 56 | { _C, 16, 16, 0, 16, 16, 0 }, 57 | }; 58 | 59 | BossTitleData MetalSonicBossTitle{ arrayptrandlengthT(MetalSonicBossTitleLetters, short), 0xC, 0x14, 0, 0x30000, 480, &MetalSonicBossTitleTex, 320, 240, 2, 0xFFFFFF }; 60 | 61 | NJS_TEXNAME TikalBossTitleTexName[5]; 62 | 63 | NJS_TEXLIST TikalBossTitleTex{ arrayptrandlengthT(TikalBossTitleTexName, int) }; 64 | 65 | BossTitleLetterData TikalBossTitleLetters[] 66 | { 67 | { _T, 16, 16, 0, 16, 16, 0 }, 68 | { _I, 8, 16, 0, 8, 16, 0 }, 69 | { _K, 16, 16, 0, 16, 16, 0 }, 70 | { _A, 18, 16, 0, 32, 16, 0 }, 71 | { _L, 16, 16, 0, 16, 16, 0 }, 72 | }; 73 | 74 | BossTitleData TikalBossTitle{ arrayptrandlengthT(TikalBossTitleLetters, short), 0xC, 0x14, 0, 0x30000, 480, &TikalBossTitleTex, 320, 240, 2, 0xFFFFFF }; 75 | 76 | NJS_TEXNAME ChaosBossTitleTexName[5]; 77 | 78 | NJS_TEXLIST ChaosBossTitleTex{ arrayptrandlengthT(ChaosBossTitleTexName, int) }; 79 | 80 | BossTitleLetterData ChaosBossTitleLetters[] 81 | { 82 | { _C, 16, 16, 0, 16, 16, 0 }, 83 | { _H, 16, 16, 0, 16, 16, 0 }, 84 | { _A, 18, 16, 0, 32, 16, 0 }, 85 | { _O, 16, 16, 0, 16, 16, 0 }, 86 | { _S, 16, 16, 0, 16, 16, 0 }, 87 | }; 88 | 89 | BossTitleData ChaosBossTitle{ arrayptrandlengthT(ChaosBossTitleLetters, short), 0xC, 0x14, 0, 0x30000, 480, &ChaosBossTitleTex, 320, 240, 2, 0xFFFFFF }; 90 | 91 | NJS_TEXNAME ChaoBossTitleTexName[4]; 92 | 93 | NJS_TEXLIST ChaoBossTitleTex{ arrayptrandlengthT(ChaoBossTitleTexName, int) }; 94 | 95 | BossTitleLetterData ChaoBossTitleLetters[] 96 | { 97 | { _C, 16, 16, 0, 16, 16, 0 }, 98 | { _H, 16, 16, 0, 16, 16, 0 }, 99 | { _A, 18, 16, 0, 32, 16, 0 }, 100 | { _O, 16, 16, 0, 16, 16, 0 }, 101 | }; 102 | 103 | BossTitleData ChaoBossTitle{ arrayptrandlengthT(ChaoBossTitleLetters, short), 0xC, 0x14, 0, 0x30000, 480, &ChaoBossTitleTex, 320, 240, 2, 0xFFFFFF }; 104 | 105 | NJS_TEXNAME DarkChaoBossTitleTexName[7]; 106 | 107 | NJS_TEXLIST DarkChaoBossTitleTex{ arrayptrandlengthT(DarkChaoBossTitleTexName, int) }; 108 | 109 | BossTitleLetterData DarkChaoBossTitleLetters[] 110 | { 111 | { _D, 16, 16, 0, 16, 16, 0 }, 112 | { _A, 18, 16, 0, 32, 16, 0 }, 113 | { _R, 16, 16, 0, 16, 16, 0 }, 114 | { _K, 16, 16, 0, 16, 16, 0 }, 115 | { space, 16, 16, 0, 16, 16, 0 }, 116 | { _C, 16, 16, 0, 16, 16, 0 }, 117 | { _H, 16, 16, 0, 16, 16, 0 }, 118 | { _A, 18, 16, 0, 32, 16, 0 }, 119 | { _O, 16, 16, 0, 16, 16, 0 }, 120 | }; 121 | 122 | BossTitleData DarkChaoBossTitle{ arrayptrandlengthT(DarkChaoBossTitleLetters, short), 0xC, 0x14, 0, 0x30000, 480, &DarkChaoBossTitleTex, 320, 240, 2, 0xFFFFFF }; 123 | 124 | void LoadBossTitle(char id) 125 | { 126 | BossTitleData* title = nullptr; 127 | switch (id) 128 | { 129 | case Characters_Sonic: 130 | title = &SonicBossTitle; 131 | break; 132 | case Characters_Shadow: 133 | title = &ShadowBossTitle; 134 | break; 135 | case Characters_Tails: 136 | case Characters_MechTails: 137 | title = &TailsBossTitle; 138 | break; 139 | case Characters_Eggman: 140 | case Characters_MechEggman: 141 | title = &EggmanBossTitle; 142 | break; 143 | case Characters_Knuckles: 144 | title = &KnucklesBossTitle; 145 | break; 146 | case Characters_Rouge: 147 | title = &RougeBossTitle; 148 | break; 149 | case Characters_Amy: 150 | title = &AmyBossTitle; 151 | break; 152 | case Characters_MetalSonic: 153 | title = &MetalSonicBossTitle; 154 | break; 155 | case Characters_Tikal: 156 | title = &TikalBossTitle; 157 | break; 158 | case Characters_Chaos: 159 | title = &ChaosBossTitle; 160 | break; 161 | case Characters_ChaoWalker: 162 | title = &ChaoBossTitle; 163 | break; 164 | case Characters_DarkChaoWalker: 165 | title = &DarkChaoBossTitle; 166 | break; 167 | } 168 | if (title) 169 | { 170 | switch (CurrentLevel) 171 | { 172 | case LevelIDs_SonicVsShadow1: 173 | case LevelIDs_TailsVsEggman1: 174 | case LevelIDs_SonicVsShadow2: 175 | title->DisplayTime = 360; 176 | break; 177 | case LevelIDs_TailsVsEggman2: 178 | case LevelIDs_KnucklesVsRouge: 179 | title->DisplayTime = 480; 180 | break; 181 | } 182 | LoadBossTitleExec(nullptr, title); 183 | } 184 | } 185 | 186 | const void* const loc_4C8142 = (void*)0x4C8142; 187 | __declspec(naked) void LoadShadow2BossTitle() 188 | { 189 | __asm 190 | { 191 | movzx eax, al 192 | push eax 193 | call LoadBossTitle 194 | pop eax 195 | jmp loc_4C8142 196 | } 197 | } 198 | 199 | const void* const loc_619D4C = (void*)0x619D4C; 200 | __declspec(naked) void LoadShadow1BossTitle() 201 | { 202 | __asm 203 | { 204 | movzx eax, al 205 | push eax 206 | call LoadBossTitle 207 | pop eax 208 | jmp loc_619D4C 209 | } 210 | } 211 | 212 | const void* const loc_6273E7 = (void*)0x6273E7; 213 | __declspec(naked) void LoadEggman1BossTitle() 214 | { 215 | __asm 216 | { 217 | movzx eax, al 218 | push eax 219 | call LoadBossTitle 220 | pop eax 221 | jmp loc_6273E7 222 | } 223 | } 224 | 225 | const void* const loc_649C91 = (void*)0x649C91; 226 | __declspec(naked) void LoadRougeBossTitle() 227 | { 228 | __asm 229 | { 230 | movzx eax, al 231 | push eax 232 | call LoadBossTitle 233 | pop eax 234 | jmp loc_649C91 235 | } 236 | } 237 | 238 | const void* const loc_662A7B = (void*)0x662A7B; 239 | __declspec(naked) void LoadEggman2BossTitle() 240 | { 241 | __asm 242 | { 243 | movzx eax, al 244 | push eax 245 | call LoadBossTitle 246 | pop eax 247 | jmp loc_662A7B 248 | } 249 | } 250 | 251 | 252 | void FreeSonicBossTitleTex(ObjectMaster* obj) 253 | { 254 | FreeTexList(SonicBossTitle.TexList); 255 | } 256 | 257 | void FreeShadowBossTitleTex(ObjectMaster* obj) 258 | { 259 | FreeTexList(ShadowBossTitle.TexList); 260 | } 261 | 262 | void FreeTailsBossTitleTex(ObjectMaster* obj) 263 | { 264 | FreeTexList(TailsBossTitle.TexList); 265 | } 266 | 267 | void FreeEggmanBossTitleTex(ObjectMaster* obj) 268 | { 269 | FreeTexList(EggmanBossTitle.TexList); 270 | } 271 | 272 | void FreeKnucklesBossTitleTex(ObjectMaster* obj) 273 | { 274 | FreeTexList(KnucklesBossTitle.TexList); 275 | } 276 | 277 | void FreeRougeBossTitleTex(ObjectMaster* obj) 278 | { 279 | FreeTexList(RougeBossTitle.TexList); 280 | } 281 | 282 | void FreeAmyBossTitleTex(ObjectMaster* obj) 283 | { 284 | FreeTexList(AmyBossTitle.TexList); 285 | } 286 | 287 | void FreeMetalSonicBossTitleTex(ObjectMaster* obj) 288 | { 289 | FreeTexList(MetalSonicBossTitle.TexList); 290 | } 291 | 292 | void FreeTikalBossTitleTex(ObjectMaster* obj) 293 | { 294 | FreeTexList(TikalBossTitle.TexList); 295 | } 296 | 297 | void FreeChaosBossTitleTex(ObjectMaster* obj) 298 | { 299 | FreeTexList(ChaosBossTitle.TexList); 300 | } 301 | 302 | void FreeChaoBossTitleTex(ObjectMaster* obj) 303 | { 304 | FreeTexList(ChaoBossTitle.TexList); 305 | } 306 | 307 | void FreeDarkChaoBossTitleTex(ObjectMaster* obj) 308 | { 309 | FreeTexList(DarkChaoBossTitle.TexList); 310 | } 311 | 312 | void LoadBossTitleTex(ObjectMaster *obj, char id) 313 | { 314 | switch (id) 315 | { 316 | case Characters_Sonic: 317 | LoadTextureList("TITLETEX_SONIC", SonicBossTitle.TexList); 318 | obj->DeleteSub = FreeSonicBossTitleTex; 319 | break; 320 | case Characters_Shadow: 321 | LoadTextureList("TITLETEX_SHADOW", ShadowBossTitle.TexList); 322 | obj->DeleteSub = FreeShadowBossTitleTex; 323 | break; 324 | case Characters_Tails: 325 | case Characters_MechTails: 326 | LoadTextureList("TITLETEX_TAILS", TailsBossTitle.TexList); 327 | obj->DeleteSub = FreeTailsBossTitleTex; 328 | break; 329 | case Characters_Eggman: 330 | case Characters_MechEggman: 331 | LoadTextureList("TITLETEX_EGGMAN", EggmanBossTitle.TexList); 332 | obj->DeleteSub = FreeEggmanBossTitleTex; 333 | break; 334 | case Characters_Knuckles: 335 | LoadTextureList("TITLETEX_KNUCKLES", KnucklesBossTitle.TexList); 336 | obj->DeleteSub = FreeKnucklesBossTitleTex; 337 | break; 338 | case Characters_Rouge: 339 | LoadTextureList("TITLETEX_ROUGE", RougeBossTitle.TexList); 340 | obj->DeleteSub = FreeRougeBossTitleTex; 341 | break; 342 | case Characters_Amy: 343 | LoadTextureList("TITLETEX_AMY", AmyBossTitle.TexList); 344 | obj->DeleteSub = FreeAmyBossTitleTex; 345 | break; 346 | case Characters_MetalSonic: 347 | LoadTextureList("TITLETEX_METALSONIC", MetalSonicBossTitle.TexList); 348 | obj->DeleteSub = FreeMetalSonicBossTitleTex; 349 | break; 350 | case Characters_Tikal: 351 | LoadTextureList("TITLETEX_TIKAL", TikalBossTitle.TexList); 352 | obj->DeleteSub = FreeTikalBossTitleTex; 353 | break; 354 | case Characters_Chaos: 355 | LoadTextureList("TITLETEX_CHAOS", ChaosBossTitle.TexList); 356 | obj->DeleteSub = FreeChaosBossTitleTex; 357 | break; 358 | case Characters_ChaoWalker: 359 | LoadTextureList("TITLETEX_CHAO", ChaoBossTitle.TexList); 360 | obj->DeleteSub = FreeChaoBossTitleTex; 361 | break; 362 | case Characters_DarkChaoWalker: 363 | LoadTextureList("TITLETEX_DARKCHAO", DarkChaoBossTitle.TexList); 364 | obj->DeleteSub = FreeDarkChaoBossTitleTex; 365 | break; 366 | } 367 | } 368 | 369 | const void* const loc_4C909C = (void*)0x4C909C; 370 | __declspec(naked) void LoadShadow2BossTitleTex() 371 | { 372 | __asm 373 | { 374 | movzx eax, al 375 | push eax 376 | push edi 377 | call LoadBossTitleTex 378 | pop edi 379 | pop eax 380 | jmp loc_4C909C 381 | } 382 | } 383 | 384 | const void* const loc_61A383 = (void*)0x61A383; 385 | __declspec(naked) void LoadShadow1BossTitleTex() 386 | { 387 | __asm 388 | { 389 | movzx eax, al 390 | push eax 391 | push edi 392 | call LoadBossTitleTex 393 | pop edi 394 | pop eax 395 | jmp loc_61A383 396 | } 397 | } 398 | 399 | const void* const loc_627D02 = (void*)0x627D02; 400 | __declspec(naked) void LoadEggman1BossTitleTex() 401 | { 402 | __asm 403 | { 404 | movzx eax, al 405 | push eax 406 | push edi 407 | call LoadBossTitleTex 408 | pop edi 409 | pop eax 410 | jmp loc_627D02 411 | } 412 | } 413 | 414 | const void* const loc_64B7A0 = (void*)0x64B7A0; 415 | __declspec(naked) void LoadRougeBossTitleTex() 416 | { 417 | __asm 418 | { 419 | movzx eax, al 420 | push eax 421 | push edi 422 | call LoadBossTitleTex 423 | pop edi 424 | pop eax 425 | jmp loc_64B7A0 426 | } 427 | } 428 | 429 | const void* const loc_6639D9 = (void*)0x6639D9; 430 | __declspec(naked) void LoadEggman2BossTitleTex() 431 | { 432 | __asm 433 | { 434 | movzx eax, al 435 | push eax 436 | push edi 437 | call LoadBossTitleTex 438 | pop edi 439 | pop eax 440 | jmp loc_6639D9 441 | } 442 | } 443 | 444 | void InitBossTitles() 445 | { 446 | WriteJump((void*)0x4C8124, LoadShadow2BossTitle); 447 | WriteJump((void*)0x4C9061, LoadShadow2BossTitleTex); 448 | WriteJump((void*)0x619D2E, LoadShadow1BossTitle); 449 | WriteJump((void*)0x61A348, LoadShadow1BossTitleTex); 450 | WriteJump((void*)0x6273C9, LoadEggman1BossTitle); 451 | WriteJump((void*)0x627CC7, LoadEggman1BossTitleTex); 452 | WriteJump((void*)0x649C73, LoadRougeBossTitle); 453 | WriteJump((void*)0x64B765, LoadRougeBossTitleTex); 454 | WriteJump((void*)0x662A5D, LoadEggman2BossTitle); 455 | WriteJump((void*)0x66399E, LoadEggman2BossTitleTex); 456 | } -------------------------------------------------------------------------------- /CharacterSelectPlus/BossTitles.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void InitBossTitles(); 4 | -------------------------------------------------------------------------------- /CharacterSelectPlus/CharacterSelectPlus.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/CharacterSelectPlus/CharacterSelectPlus.cpp -------------------------------------------------------------------------------- /CharacterSelectPlus/CharacterSelectPlus.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {D780E44E-E0A9-4C6C-8B25-23EA3005D9E5} 24 | Win32Proj 25 | CharacterSelectPlus 26 | 10.0 27 | CharacterSelectPlus 28 | 29 | 30 | 31 | DynamicLibrary 32 | true 33 | v142 34 | Unicode 35 | 36 | 37 | DynamicLibrary 38 | false 39 | v141_xp 40 | true 41 | Unicode 42 | 43 | 44 | DynamicLibrary 45 | true 46 | v142 47 | Unicode 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v142 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | $(SolutionDir)bin 77 | bin\ 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | $(SolutionDir)bin 85 | bin\ 86 | 87 | 88 | false 89 | 90 | 91 | 92 | Use 93 | Level3 94 | Disabled 95 | true 96 | WIN32;_DEBUG;CharacterSelectPlus_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 97 | true 98 | $(ProjectDir)..\sa2-mod-loader\libmodutils;$(ProjectDir)..\sa2-mod-loader\mod-loader-common\ModLoaderCommon;$(ProjectDir)..\sa2-mod-loader\SA2ModLoader\include;%(AdditionalIncludeDirectories) 99 | 100 | 101 | Windows 102 | true 103 | $(SolutionDir)bin\ModLoaderCommon.lib;$(SolutionDir)bin\libmodutils.lib;%(AdditionalDependencies) 104 | 105 | 106 | 107 | 108 | Use 109 | Level3 110 | Disabled 111 | true 112 | _DEBUG;CharacterSelectPlus_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 113 | true 114 | 115 | 116 | Windows 117 | true 118 | 119 | 120 | 121 | 122 | Use 123 | Level3 124 | MaxSpeed 125 | true 126 | true 127 | true 128 | WIN32;NDEBUG;CharacterSelectPlus_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 129 | true 130 | $(ProjectDir)..\sa2-mod-loader\libmodutils;$(ProjectDir)..\sa2-mod-loader\mod-loader-common\ModLoaderCommon;$(ProjectDir)..\sa2-mod-loader\SA2ModLoader\include;%(AdditionalIncludeDirectories) 131 | 132 | 133 | Windows 134 | true 135 | true 136 | true 137 | $(SolutionDir)bin\ModLoaderCommon.lib;$(SolutionDir)bin\libmodutils.lib;%(AdditionalDependencies) 138 | 139 | 140 | 141 | 142 | Use 143 | Level3 144 | MaxSpeed 145 | true 146 | true 147 | true 148 | NDEBUG;CharacterSelectPlus_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 149 | true 150 | 151 | 152 | 153 | 154 | Windows 155 | true 156 | true 157 | true 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | Create 180 | Create 181 | Create 182 | Create 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /CharacterSelectPlus/CharacterSelectPlus.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | 73 | 74 | Resource Files 75 | 76 | 77 | Resource Files 78 | 79 | 80 | Resource Files 81 | 82 | 83 | Resource Files 84 | 85 | 86 | Resource Files 87 | 88 | 89 | Resource Files 90 | 91 | 92 | Resource Files 93 | 94 | 95 | Resource Files 96 | 97 | 98 | Resource Files 99 | 100 | 101 | Resource Files 102 | 103 | 104 | Resource Files 105 | 106 | 107 | Resource Files 108 | 109 | 110 | Resource Files 111 | 112 | 113 | -------------------------------------------------------------------------------- /CharacterSelectPlus/RankVoices.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | void PlayRankVoice_i(int id) 4 | { 5 | int v23 = -1; 6 | switch (id) 7 | { 8 | case Characters_Sonic: 9 | case Characters_SuperSonic: 10 | v23 = SonicRankVoices[CurrentLevelRank]; 11 | break; 12 | case Characters_Shadow: 13 | case Characters_SuperShadow: 14 | v23 = ShadowRankVoices[CurrentLevelRank]; 15 | break; 16 | case Characters_Knuckles: 17 | v23 = KnucklesRankVoices[CurrentLevelRank]; 18 | break; 19 | case Characters_Rouge: 20 | v23 = RougeRankVoices[CurrentLevelRank]; 21 | break; 22 | case Characters_Tails: 23 | case Characters_MechTails: 24 | v23 = TailsRankVoices[CurrentLevelRank]; 25 | break; 26 | case Characters_Eggman: 27 | case Characters_MechEggman: 28 | v23 = EggmanRankVoices[CurrentLevelRank]; 29 | break; 30 | } 31 | if (v23 != -1) 32 | { 33 | PlayVoice(2, v23); 34 | } 35 | } 36 | 37 | const void* const loc_44FD08 = (void*)0x44FD08; 38 | __declspec(naked) void PlayRankVoice() 39 | { 40 | __asm 41 | { 42 | push eax 43 | call PlayRankVoice_i 44 | add esp, 4 45 | jmp loc_44FD08 46 | } 47 | } 48 | 49 | void InitRankVoice() 50 | { 51 | WriteJump((void*)0x44FC5E, PlayRankVoice); 52 | } -------------------------------------------------------------------------------- /CharacterSelectPlus/RankVoices.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void InitRankVoice(); 4 | -------------------------------------------------------------------------------- /CharacterSelectPlus/config.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using std::string; 7 | using std::unordered_map; 8 | bool customSet = true; 9 | 10 | 11 | #pragma region mod setting stuff 12 | 13 | static string trim(const string& s) 14 | { 15 | auto st = s.find_first_not_of(' '); 16 | if (st == string::npos) 17 | st = 0; 18 | auto ed = s.find_last_not_of(' '); 19 | if (ed == string::npos) 20 | ed = s.size() - 1; 21 | return s.substr(st, (ed + 1) - st); 22 | } 23 | 24 | static const unordered_map charnamemap = { 25 | { "sonic", Characters_Sonic }, 26 | { "shadow", Characters_Shadow }, 27 | { "tails", Characters_Tails }, 28 | { "eggman", Characters_Eggman }, 29 | { "knuckles", Characters_Knuckles }, 30 | { "rouge", Characters_Rouge }, 31 | { "mechtails", Characters_MechTails }, 32 | { "mecheggman", Characters_MechEggman }, 33 | { "amy", Characters_Sonic | altcharacter }, 34 | { "metalsonic", Characters_Shadow | altcharacter }, 35 | { "tikal", Characters_Knuckles | altcharacter }, 36 | { "chaos", Characters_Rouge | altcharacter }, 37 | { "chaowalker", Characters_MechTails | altcharacter }, 38 | { "darkchaowalker", Characters_MechEggman | altcharacter }, 39 | { "sonicalt", Characters_Sonic | altcostume }, 40 | { "shadowalt", Characters_Shadow | altcostume }, 41 | { "knucklesalt", Characters_Knuckles | altcostume }, 42 | { "rougealt", Characters_Rouge | altcostume }, 43 | { "mechtailsalt", Characters_MechTails | altcostume }, 44 | { "mecheggmanalt", Characters_MechEggman | altcostume } 45 | }; 46 | 47 | static uint8_t ParseCharacterID(const string& str, Characters def) 48 | { 49 | string s = trim(str); 50 | transform(s.begin(), s.end(), s.begin(), ::tolower); 51 | auto ch = charnamemap.find(s); 52 | if (ch != charnamemap.end()) 53 | return ch->second; 54 | return def; 55 | } 56 | 57 | const string charnames[Characters_Amy] = { "Sonic", "Shadow", "Tails", "Eggman", "Knuckles", "Rouge", "MechTails", "MechEggman" }; 58 | const string charnamesalt[Characters_Amy] = { "Amy", "MetalSonic", "Tails", "Eggman", "Tikal", "Chaos", "ChaoWalker", "DarkChaoWalker" }; 59 | 60 | #pragma endregion 61 | 62 | void init_Config(const char* path) 63 | { 64 | const IniFile* settings = new IniFile(std::string(path) + "\\config.ini"); 65 | for (int i = 0; i < Characters_Amy; i++) 66 | defaultcharacters[i] = ParseCharacterID(settings->getString("1Player", charnames[i]), (Characters)i); 67 | for (int i = 0; i < Characters_Amy; i++) 68 | defaultcharacters2p[i] = ParseCharacterID(settings->getString("2Player", charnames[i]), (Characters)i); 69 | for (int i = 0; i < Characters_Amy; i++) 70 | defaultcharacters2palt[i] = ParseCharacterID(settings->getString("2Player", charnamesalt[i]), (Characters)(i | altcharacter)); 71 | for (int i = 0; i < Characters_Amy; i++) 72 | bosscharacters[i] = ParseCharacterID(settings->getString("Boss", charnames[i]), (Characters)i); 73 | 74 | customSet = settings->getBool("Misc", "customSet", true); 75 | 76 | delete settings; 77 | 78 | } -------------------------------------------------------------------------------- /CharacterSelectPlus/defs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | This file contains definitions used by the Hex-Rays decompiler output. 4 | It has type definitions and convenience macros to make the 5 | output more readable. 6 | Copyright (c) 2007 Hex-Rays 7 | */ 8 | 9 | #if defined(__GNUC__) 10 | typedef long long ll; 11 | typedef unsigned long long ull; 12 | #define __int64 long long 13 | #define __int32 int 14 | #define __int16 short 15 | #define __int8 char 16 | #define MAKELL(num) num ## LL 17 | #define FMT_64 "ll" 18 | #elif defined(_MSC_VER) 19 | typedef __int64 ll; 20 | typedef unsigned __int64 ull; 21 | #define MAKELL(num) num ## i64 22 | #define FMT_64 "I64" 23 | #elif defined (__BORLANDC__) 24 | typedef __int64 ll; 25 | typedef unsigned __int64 ull; 26 | #define MAKELL(num) num ## i64 27 | #define FMT_64 "L" 28 | #else 29 | #error "unknown compiler" 30 | #endif 31 | typedef unsigned int uint; 32 | typedef unsigned char uchar; 33 | typedef unsigned short ushort; 34 | //typedef unsigned long ulong; 35 | 36 | typedef char int8; 37 | typedef signed char sint8; 38 | typedef unsigned char uint8; 39 | typedef short int16; 40 | typedef signed short sint16; 41 | typedef unsigned short uint16; 42 | typedef int int32; 43 | typedef signed int sint32; 44 | typedef unsigned int uint32; 45 | typedef ll int64; 46 | typedef ll sint64; 47 | typedef ull uint64; 48 | 49 | // Partially defined types: 50 | #define _BYTE uint8 51 | #define _WORD uint16 52 | #define _DWORD uint32 53 | #define _QWORD uint64 54 | #if !defined(_MSC_VER) 55 | #define _LONGLONG __int128 56 | #endif 57 | 58 | #ifndef _WINDOWS_ 59 | typedef int8 BYTE; 60 | typedef int16 WORD; 61 | typedef int32 DWORD; 62 | typedef int32 LONG; 63 | #endif 64 | typedef int64 QWORD; 65 | #ifndef __cplusplus 66 | typedef int bool; // we want to use bool in our C programs 67 | #endif 68 | 69 | // Some convenience macros to make partial accesses nicer 70 | // first unsigned macros: 71 | #define LOBYTE(x) (*((_BYTE*)&(x))) // low byte 72 | #define LOWORD(x) (*((_WORD*)&(x))) // low word 73 | #define LODWORD(x) (*((_DWORD*)&(x))) // low dword 74 | #define HIBYTE(x) (*((_BYTE*)&(x)+1)) 75 | #define HIWORD(x) (*((_WORD*)&(x)+1)) 76 | #define HIDWORD(x) (*((_DWORD*)&(x)+1)) 77 | #define BYTEn(x, n) (*((_BYTE*)&(x)+n)) 78 | #define WORDn(x, n) (*((_WORD*)&(x)+n)) 79 | #define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0) 80 | #define BYTE2(x) BYTEn(x, 2) 81 | #define BYTE3(x) BYTEn(x, 3) 82 | #define BYTE4(x) BYTEn(x, 4) 83 | #define BYTE5(x) BYTEn(x, 5) 84 | #define BYTE6(x) BYTEn(x, 6) 85 | #define BYTE7(x) BYTEn(x, 7) 86 | #define BYTE8(x) BYTEn(x, 8) 87 | #define BYTE9(x) BYTEn(x, 9) 88 | #define BYTE10(x) BYTEn(x, 10) 89 | #define BYTE11(x) BYTEn(x, 11) 90 | #define BYTE12(x) BYTEn(x, 12) 91 | #define BYTE13(x) BYTEn(x, 13) 92 | #define BYTE14(x) BYTEn(x, 14) 93 | #define BYTE15(x) BYTEn(x, 15) 94 | #define WORD1(x) WORDn(x, 1) 95 | #define WORD2(x) WORDn(x, 2) // third word of the object, unsigned 96 | #define WORD3(x) WORDn(x, 3) 97 | #define WORD4(x) WORDn(x, 4) 98 | #define WORD5(x) WORDn(x, 5) 99 | #define WORD6(x) WORDn(x, 6) 100 | #define WORD7(x) WORDn(x, 7) 101 | 102 | // now signed macros (the same but with sign extension) 103 | #define SLOBYTE(x) (*((int8*)&(x))) 104 | #define SLOWORD(x) (*((int16*)&(x))) 105 | #define SLODWORD(x) (*((int32*)&(x))) 106 | #define SHIBYTE(x) (*((int8*)&(x)+1)) 107 | #define SHIWORD(x) (*((int16*)&(x)+1)) 108 | #define SHIDWORD(x) (*((int32*)&(x)+1)) 109 | #define SBYTEn(x, n) (*((int8*)&(x)+n)) 110 | #define SWORDn(x, n) (*((int16*)&(x)+n)) 111 | #define SBYTE1(x) SBYTEn(x, 1) 112 | #define SBYTE2(x) SBYTEn(x, 2) 113 | #define SBYTE3(x) SBYTEn(x, 3) 114 | #define SBYTE4(x) SBYTEn(x, 4) 115 | #define SBYTE5(x) SBYTEn(x, 5) 116 | #define SBYTE6(x) SBYTEn(x, 6) 117 | #define SBYTE7(x) SBYTEn(x, 7) 118 | #define SBYTE8(x) SBYTEn(x, 8) 119 | #define SBYTE9(x) SBYTEn(x, 9) 120 | #define SBYTE10(x) SBYTEn(x, 10) 121 | #define SBYTE11(x) SBYTEn(x, 11) 122 | #define SBYTE12(x) SBYTEn(x, 12) 123 | #define SBYTE13(x) SBYTEn(x, 13) 124 | #define SBYTE14(x) SBYTEn(x, 14) 125 | #define SBYTE15(x) SBYTEn(x, 15) 126 | #define SWORD1(x) SWORDn(x, 1) 127 | #define SWORD2(x) SWORDn(x, 2) 128 | #define SWORD3(x) SWORDn(x, 3) 129 | #define SWORD4(x) SWORDn(x, 4) 130 | #define SWORD5(x) SWORDn(x, 5) 131 | #define SWORD6(x) SWORDn(x, 6) 132 | #define SWORD7(x) SWORDn(x, 7) 133 | 134 | 135 | // Helper functions to represent some assembly instructions. 136 | 137 | #ifdef __cplusplus 138 | 139 | // Fill memory block with an integer value 140 | inline void memset32(void *ptr, uint32 value, int count) 141 | { 142 | uint32 *p = (uint32 *)ptr; 143 | for (int i = 0; i < count; i++) 144 | *p++ = value; 145 | } 146 | 147 | // Generate a reference to pair of operands 148 | template int16 __PAIR__(int8 high, T low) { return (((int16)high) << sizeof(high) * 8) | uint8(low); } 149 | template int32 __PAIR__(int16 high, T low) { return (((int32)high) << sizeof(high) * 8) | uint16(low); } 150 | template int64 __PAIR__(int32 high, T low) { return (((int64)high) << sizeof(high) * 8) | uint32(low); } 151 | template uint16 __PAIR__(uint8 high, T low) { return (((uint16)high) << sizeof(high) * 8) | uint8(low); } 152 | template uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high) * 8) | uint16(low); } 153 | template uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high) * 8) | uint32(low); } 154 | 155 | // rotate left 156 | template T __ROL__(T value, uint count) 157 | { 158 | const uint nbits = sizeof(T) * 8; 159 | count %= nbits; 160 | 161 | T high = value >> (nbits - count); 162 | value <<= count; 163 | value |= high; 164 | return value; 165 | } 166 | 167 | // rotate right 168 | template T __ROR__(T value, uint count) 169 | { 170 | const uint nbits = sizeof(T) * 8; 171 | count %= nbits; 172 | 173 | T low = value << (nbits - count); 174 | value >>= count; 175 | value |= low; 176 | return value; 177 | } 178 | 179 | // carry flag of left shift 180 | template int8 __MKCSHL__(T value, uint count) 181 | { 182 | const uint nbits = sizeof(T) * 8; 183 | count %= nbits; 184 | 185 | return (value >> (nbits - count)) & 1; 186 | } 187 | 188 | // carry flag of right shift 189 | template int8 __MKCSHR__(T value, uint count) 190 | { 191 | return (value >> (count - 1)) & 1; 192 | } 193 | 194 | // sign flag 195 | template int8 __SETS__(T x) 196 | { 197 | if (sizeof(T) == 1) 198 | return int8(x) < 0; 199 | if (sizeof(T) == 2) 200 | return int16(x) < 0; 201 | if (sizeof(T) == 4) 202 | return int32(x) < 0; 203 | return int64(x) < 0; 204 | } 205 | 206 | // overflow flag of subtraction (x-y) 207 | template int8 __OFSUB__(T x, U y) 208 | { 209 | if (sizeof(T) < sizeof(U)) 210 | { 211 | U x2 = x; 212 | int8 sx = __SETS__(x2); 213 | return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2 - y)); 214 | } 215 | else 216 | { 217 | T y2 = y; 218 | int8 sx = __SETS__(x); 219 | return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x - y2)); 220 | } 221 | } 222 | 223 | // overflow flag of addition (x+y) 224 | template int8 __OFADD__(T x, U y) 225 | { 226 | if (sizeof(T) < sizeof(U)) 227 | { 228 | U x2 = x; 229 | int8 sx = __SETS__(x2); 230 | return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2 + y)); 231 | } 232 | else 233 | { 234 | T y2 = y; 235 | int8 sx = __SETS__(x); 236 | return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x + y2)); 237 | } 238 | } 239 | 240 | // carry flag of subtraction (x-y) 241 | template int8 __CFSUB__(T x, U y) 242 | { 243 | int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); 244 | if (size == 1) 245 | return uint8(x) < uint8(y); 246 | if (size == 2) 247 | return uint16(x) < uint16(y); 248 | if (size == 4) 249 | return uint32(x) < uint32(y); 250 | return uint64(x) < uint64(y); 251 | } 252 | 253 | // carry flag of addition (x+y) 254 | template int8 __CFADD__(T x, U y) 255 | { 256 | int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U); 257 | if (size == 1) 258 | return uint8(x) > uint8(x + y); 259 | if (size == 2) 260 | return uint16(x) > uint16(x + y); 261 | if (size == 4) 262 | return uint32(x) > uint32(x + y); 263 | return uint64(x) > uint64(x + y); 264 | } 265 | 266 | #else 267 | // The following definition is not quite correct because it always returns 268 | // uint64. The above C++ functions are good, though. 269 | #define __PAIR__(high, low) (((uint64)(high)<>y) 275 | #define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y) 276 | #define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y) 277 | #define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y) 278 | #define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y) 279 | #endif 280 | 281 | // No definition for rcl/rcr because the carry flag is unknown 282 | #define __RCL__(x, y) invalid_operation // Rotate left thru carry 283 | #define __RCR__(x, y) invalid_operation // Rotate right thru carry 284 | #define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL 285 | #define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR 286 | #define __SETP__(x, y) invalid_operation // Generate parity flag for (x-y) 287 | 288 | // In the decompilation listing there are some objects declarared as _UNKNOWN 289 | // because we could not determine their types. Since the C compiler does not 290 | // accept void item declarations, we replace them by anything of our choice, 291 | // for example a char: 292 | 293 | #define _UNKNOWN char 294 | 295 | #ifdef _MSC_VER 296 | #define snprintf _snprintf 297 | #define vsnprintf _vsnprintf 298 | #endif -------------------------------------------------------------------------------- /CharacterSelectPlus/dllmain.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/CharacterSelectPlus/dllmain.cpp -------------------------------------------------------------------------------- /CharacterSelectPlus/mod.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define altcostume 0x80u 4 | #define altcharacter 0x40 5 | #define charmask ~(altcostume|altcharacter) 6 | 7 | extern int defaultcharacters[]; 8 | extern int defaultcharacters2p[]; 9 | extern int defaultcharacters2palt[]; 10 | extern int bosscharacters[]; 11 | extern bool customSet; 12 | void init_Config(const char* path); 13 | void init_SetFiles(); -------------------------------------------------------------------------------- /CharacterSelectPlus/old.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "SA2ModLoader.h" 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | 9 | #pragma region declaring and pointing to variables 10 | DataArray(char*, Camera_Character_Data, 0x0173388C, 10); 11 | DataPointer(char, CharOrMissionSelectionMax, 0x01D1BF04); 12 | 13 | DataArray(char, CheckUnlockedChar, 0x01DEF829, 11); 14 | DataArray(int, ChaoSelectCharacterIconIDs, 0x00C75310, 6); 15 | DataPointer(float, StageSelect_MissionCharSelectLoc_X, 0x01A4A968); 16 | DataPointer(float, StageSelect_MissionCharSelectLoc_Y, 0x01A4A96C); 17 | DataPointer(float, NJS_IMAGEDATA_AlphaStrength, 0x025EFFD0); 18 | DataPointer(float, NJS_IMAGEDATA_RedStrength, 0x025EFFD4); 19 | DataPointer(float, NJS_IMAGEDATA_GreenStrength, 0x025EFFD8); 20 | DataPointer(float, NJS_IMAGEDATA_BlueStrength, 0x025EFFDC); 21 | DataArray(NJS_TEXANIM, StageMapAnims, 0x00C68C50, 104); 22 | DataArray(NJS_TEXNAME, StageMapTexNames, 0x00C68AA8, 16); 23 | DataArray(CharacterVoiceBank, stru_173A018, 0x0173A018, 10); 24 | 25 | DataPointer(int, UI_State1, 0x01D7BB14); 26 | DataPointer(int*, StageSelectFlags, 0x00C77F08); 27 | DataPointer(int, InputDown, 0x01DEFAB0); 28 | DataPointer(int, ShowButtonGuide, 0x01AEE2FC); 29 | DataPointer(int, IngameFlag, 0x01A559E8); 30 | DataPointer(char, byte_1DEB31E, 0x01DEB31E); 31 | DataPointer(short, word_1DEB31F, 0x01DEB31F); 32 | DataPointer(char, byte_1DEB321, 0x01DEB321); 33 | DataPointer(float, dword_1D7BB10, 0x01D7BB10); 34 | DataArray(int, StageUnlocked, 0x01A4A974, 1); 35 | 36 | FunctionPointer(void, DisplayMissionRanksName, (int*), 0x00676690); 37 | FunctionPointer(void, Set_NJSDATA_To, (float), 0x00433D00); 38 | FunctionPointer(int, DisplayChaoNameEmblems, (int*, float), 0x006768A0); 39 | ThiscallFunctionPointer(void, LoadSoundBank, (char*), 0x435880); 40 | FunctionPointer(void, LoadVoiceBank, (int, CharacterVoiceBank*), 0x459010); 41 | FunctionPointer(unsigned int, CheckIfCharMissionUnlocked, (), 0x00678460); 42 | FunctionPointer(void, sub_673AE0, (), 0x00673AE0); 43 | FunctionPointer(int, AdjustCharacter, (), 0x00678250); 44 | 45 | FunctionPointer(void, sub_664B60, (), 0x00664B60); 46 | 47 | 48 | //hardcoded values i guess 49 | DataPointer(float, ToCheck1, 0x01DEB6A8); 50 | DataPointer(float, ToCheck2, 0x025F0268); 51 | DataPointer(int, ToCheck3, 0x01DEB6A0); 52 | DataPointer(int, ToCheck4, 0x025F02D4); 53 | 54 | struct Vertex 55 | { 56 | float X; 57 | float Y; 58 | float Z; 59 | }; 60 | struct Vector2 61 | { 62 | float X; 63 | float Y; 64 | }; 65 | 66 | bool altCharacter; 67 | int ChaoWorldCharactersPlus[10] = { 68 | Characters::Characters_Sonic, 69 | Characters::Characters_Tails, 70 | Characters::Characters_Knuckles, 71 | Characters::Characters_Shadow, 72 | Characters::Characters_Eggman, 73 | Characters::Characters_Rouge, 74 | Characters::Characters_Sonic, 75 | Characters::Characters_Knuckles, 76 | Characters::Characters_Shadow, 77 | Characters::Characters_Rouge 78 | }; 79 | int ConvertCWCP[17] = { 80 | 0, 81 | 1, 82 | 2, 83 | 3, 84 | 4, 85 | 5, 86 | 6, 87 | 7, 88 | 0, 89 | 9, 90 | 10, 91 | 11, 92 | 1, 93 | 13, 94 | 14, 95 | 4, 96 | 5 97 | }; 98 | int ChaoSelectCharacterIconIDsPlus[10] = { 99 | 5, 100 | 6, 101 | 1, 102 | 4, 103 | 0, 104 | 3, 105 | 104, 106 | 106, 107 | 105, 108 | 107 109 | }; 110 | int StageSelectCharacterIconIDs[14] = { 111 | 5, 112 | 4, 113 | 104, 114 | 105, 115 | 1, 116 | 3, 117 | 106, 118 | 107, 119 | 6, 120 | 0, 121 | 110, 122 | 111, 123 | 108, 124 | 109 125 | }; 126 | float IconPosX[10] = { 127 | 102, 128 | 102, 129 | 102, 130 | 102, 131 | 102, 132 | 102, 133 | 302, 134 | 302, 135 | 302, 136 | 302, 137 | }; 138 | float IconPosY[10] = { 139 | 0, 140 | 0, 141 | 0, 142 | 0, 143 | 0, 144 | 0, 145 | 40, 146 | 40, 147 | 40, 148 | 40 149 | }; 150 | NJS_TEXANIM NewStageMapAnims[112]; 151 | NJS_TEXNAME NewStageMapTexNames[20]; 152 | 153 | bool SelectingStageCharacter; 154 | int SelectedStageCharacter; 155 | int StageCharacters[14] = { 156 | Characters_Sonic, 157 | Characters_Shadow, 158 | Characters_Sonic, 159 | Characters_Shadow, 160 | Characters_Knuckles, 161 | Characters_Rouge, 162 | Characters_Knuckles, 163 | Characters_Rouge, 164 | Characters_Tails, 165 | Characters_Eggman, 166 | Characters_MechTails, 167 | Characters_MechEggman, 168 | Characters_MechTails, 169 | Characters_MechEggman 170 | }; 171 | bool StageCharacterAlts[14] = { 172 | false, 173 | false, 174 | true, 175 | true, 176 | false, 177 | false, 178 | true, 179 | true, 180 | false, 181 | false, 182 | false, 183 | false, 184 | true, 185 | true, 186 | }; 187 | #pragma endregion 188 | 189 | #pragma region usercalls 190 | static const void* const CheckSelectedStageTypePtr = (void*)0x00676640; 191 | static inline void CheckSelectedStageType(int stageID, int UiSelectionID, int* output) 192 | { 193 | __asm 194 | { 195 | mov eax, [stageID] 196 | mov edx, [UiSelectionID] 197 | mov ecx, [output] 198 | call CheckSelectedStageTypePtr 199 | } 200 | } 201 | 202 | static const void* const Display_stageMapTexturePtr = (void*)0x00675C90; 203 | static inline void Display_stageMapTexture(int UIFlags, Vertex* Position, int TexID, float ESize) 204 | { 205 | __asm 206 | { 207 | push[ESize] 208 | push[TexID] 209 | mov eax, [Position] 210 | mov ecx, [UIFlags] 211 | call Display_stageMapTexturePtr 212 | } 213 | } 214 | 215 | static const void* const Display_stageMapTextureSPtr = (void*)0x00675CF0; 216 | static inline void Display_stageMapTextureS(Vertex* Position, Vector2* ESize, int TexID, int Flags) 217 | { 218 | __asm 219 | { 220 | push[Flags]; 221 | push[TexID]; 222 | mov ecx, [ESize]; 223 | mov eax, [Position]; 224 | call Display_stageMapTextureSPtr; 225 | } 226 | } 227 | 228 | static const void* const DrawTimeTextPtr = (void*)0x00674F70; 229 | static inline void DrawTimeText(Vertex* Position, int Time, float ESize) 230 | { 231 | __asm 232 | { 233 | push[ESize] 234 | mov esi, [Time] 235 | mov eax, [Position] 236 | call DrawTimeTextPtr 237 | } 238 | } 239 | 240 | static const void* const DrawScoreTextPtr = (void*)0x00675580; 241 | static inline void DrawScoreText(Vertex* Position, int number, int CharCount, float ESize) 242 | { 243 | __asm 244 | { 245 | push[ESize] 246 | push[CharCount] 247 | push[number] 248 | mov eax, [Position] 249 | call DrawScoreTextPtr 250 | } 251 | } 252 | 253 | static const void* const PlayGuideVoicePtr = (void*)0x006727E2; 254 | static inline void PlayGuideVoice(int ID) 255 | { 256 | __asm 257 | { 258 | mov eax, [ID] 259 | call PlayGuideVoicePtr 260 | } 261 | } 262 | 263 | static const void* const PlaySoundEffectPtr = (void*)0x00437260; 264 | static inline void PlaySoundEffect(int SoundID, int a2, char a3, char a4) 265 | { 266 | __asm 267 | { 268 | push[a4] 269 | push[a3] 270 | push[a2] 271 | mov esi, [SoundID] 272 | call PlaySoundEffectPtr 273 | } 274 | } 275 | 276 | static const int* const SelectNextStagePtr = (int*)0x00677BF0; 277 | static inline int SelectNextStage(int direction) 278 | { 279 | int result; 280 | __asm 281 | { 282 | mov eax, [direction] 283 | call SelectNextStagePtr 284 | mov result, eax 285 | } 286 | return result; 287 | } 288 | 289 | static const void* const sub_664DC0Ptr = (void*)0x00664DC0; 290 | static inline void sub_664DC0(int a1) 291 | { 292 | __asm 293 | { 294 | mov eax, [a1] 295 | call sub_664DC0Ptr 296 | } 297 | } 298 | #pragma endregion 299 | 300 | 301 | #pragma region mod functions 302 | //adjusting the characters to load, so that every character is loadable 303 | void __cdecl LoadCharactersPlus() 304 | { 305 | if (!SelectingStageCharacter) 306 | { 307 | if (!TwoPlayerMode) 308 | { 309 | int ch = defaultcharacters[CurrentCharacter]; 310 | CurrentCharacter = ch & charmask; 311 | AltCostume[1] = AltCostume[0] = ch & altcostume ? 1 : 0; 312 | AltCharacter[1] = AltCharacter[0] = ch & altcharacter ? 1 : 0; 313 | } 314 | int playerNum = 0; 315 | int* character = &CurrentCharacter; 316 | int buttons = MenuButtons_Held[0]; 317 | LoopStart: 318 | if (buttons & Buttons_Left) 319 | *character = Characters_Sonic; 320 | if (buttons & Buttons_Right) 321 | *character = Characters_Shadow; 322 | if (buttons & Buttons_Down) 323 | *character = Characters_Knuckles; 324 | if (buttons & Buttons_Up) 325 | *character = Characters_Rouge; 326 | if (buttons & Buttons_R) 327 | *character = Characters_MechTails; 328 | if (buttons & Buttons_L) 329 | *character = Characters_MechEggman; 330 | if (buttons & Buttons_Y) 331 | *character = Characters_Tails; 332 | if (buttons & Buttons_X) 333 | *character = Characters_Eggman; 334 | if (buttons & Buttons_B) 335 | AltCharacter[playerNum] ^= 1; 336 | if (buttons & Buttons_A) 337 | AltCostume[playerNum] ^= 1; 338 | int repcnt; 339 | pair* replst; 340 | switch (*character) 341 | { 342 | case Characters_Sonic: 343 | LoadSonic(playerNum); 344 | repcnt = (int)LengthOfArray(SonicAnimReplacements); 345 | replst = SonicAnimReplacements; 346 | break; 347 | case Characters_Shadow: 348 | LoadShadow(playerNum); 349 | repcnt = (int)LengthOfArray(SonicAnimReplacements); 350 | replst = SonicAnimReplacements; 351 | break; 352 | case Characters_Tails: 353 | LoadTails(playerNum); 354 | repcnt = (int)LengthOfArray(OthersAnimReplacements); 355 | replst = OthersAnimReplacements; 356 | break; 357 | case Characters_Eggman: 358 | LoadEggman(playerNum); 359 | repcnt = (int)LengthOfArray(OthersAnimReplacements); 360 | replst = OthersAnimReplacements; 361 | break; 362 | case Characters_Knuckles: 363 | LoadKnuckles(playerNum); 364 | repcnt = (int)LengthOfArray(KnucklesAnimReplacements); 365 | replst = KnucklesAnimReplacements; 366 | break; 367 | case Characters_Rouge: 368 | LoadRouge(playerNum); 369 | repcnt = (int)LengthOfArray(KnucklesAnimReplacements) - 3; 370 | replst = KnucklesAnimReplacements; 371 | break; 372 | case Characters_MechTails: 373 | LoadMechTails(playerNum); 374 | repcnt = (int)LengthOfArray(MechAnimReplacements); 375 | replst = MechAnimReplacements; 376 | break; 377 | case Characters_MechEggman: 378 | LoadMechEggman(playerNum); 379 | repcnt = (int)LengthOfArray(MechAnimReplacements); 380 | replst = MechAnimReplacements; 381 | break; 382 | } 383 | InitPlayer(playerNum); 384 | AnimationInfo* anilst = MainCharObj2[playerNum]->AnimInfo.Animations; 385 | for (int i = 0; i < repcnt; i++) 386 | if (!CharacterAnimations[anilst[replst[i].key].AnimNum].Animation) 387 | anilst[replst[i].key] = anilst[replst[i].value]; 388 | if (playerNum == 1) 389 | goto end; 390 | playerNum++; 391 | buttons = MenuButtons_Held[1]; 392 | if (buttons & Buttons_Start) 393 | CurrentCharacter2P = CurrentCharacter ^ 1; 394 | else if (!TwoPlayerMode) 395 | goto end; 396 | character = &CurrentCharacter2P; 397 | goto LoopStart; 398 | end: 399 | LoadEmeraldManager_r(); 400 | } 401 | else 402 | { 403 | int repcnt; 404 | pair* replst; 405 | switch (SelectedStageCharacter) 406 | { 407 | case Characters_Sonic: 408 | CurrentCharacter = Characters_Sonic; 409 | if (!altCharacter) 410 | LoadSonic(0); 411 | else LoadAmy(0); 412 | repcnt = (int)LengthOfArray(SonicAnimReplacements); 413 | replst = SonicAnimReplacements; 414 | break; 415 | case Characters_Shadow: 416 | CurrentCharacter = Characters_Shadow; 417 | if (!altCharacter) 418 | LoadShadow(0); 419 | else LoadMetalSonic(0); 420 | repcnt = (int)LengthOfArray(SonicAnimReplacements); 421 | replst = SonicAnimReplacements; 422 | break; 423 | case Characters::Characters_Knuckles: 424 | CurrentCharacter = Characters_Knuckles; 425 | if (!altCharacter) 426 | LoadKnuckles(0); 427 | else LoadTikal(0); 428 | repcnt = (int)LengthOfArray(KnucklesAnimReplacements); 429 | replst = KnucklesAnimReplacements; 430 | break; 431 | case Characters::Characters_Rouge: 432 | CurrentCharacter = Characters_Rouge; 433 | if (!altCharacter) 434 | LoadRouge(0); 435 | else LoadChaos(0); 436 | repcnt = (int)LengthOfArray(KnucklesAnimReplacements) - 3; 437 | replst = KnucklesAnimReplacements; 438 | break; 439 | case Characters::Characters_Tails: 440 | CurrentCharacter = Characters_Tails; 441 | LoadTails(0); 442 | repcnt = (int)LengthOfArray(OthersAnimReplacements); 443 | replst = OthersAnimReplacements; 444 | break; 445 | case Characters::Characters_Eggman: 446 | CurrentCharacter = Characters_Eggman; 447 | LoadEggman(0); 448 | repcnt = (int)LengthOfArray(OthersAnimReplacements); 449 | replst = OthersAnimReplacements; 450 | break; 451 | case Characters::Characters_MechEggman: 452 | CurrentCharacter = Characters_MechEggman; 453 | if (!altCharacter) 454 | LoadMechEggman(0); 455 | else LoadDarkChaoWalker(0); 456 | repcnt = (int)LengthOfArray(MechAnimReplacements); 457 | replst = MechAnimReplacements; 458 | break; 459 | case Characters::Characters_MechTails: 460 | CurrentCharacter = Characters_MechTails; 461 | if (!altCharacter) 462 | LoadMechTails(0); 463 | else LoadChaoWalker(0); 464 | repcnt = (int)LengthOfArray(MechAnimReplacements); 465 | replst = MechAnimReplacements; 466 | break; 467 | default: 468 | break; 469 | } 470 | SelectingStageCharacter = false; 471 | SelectedStageCharacter = 0; 472 | InitPlayer(0); 473 | AnimationInfo* anilst = MainCharObj2[0]->AnimInfo.Animations; 474 | for (int i = 0; i < repcnt; i++) 475 | if (!CharacterAnimations[anilst[replst[i].key].AnimNum].Animation) 476 | anilst[replst[i].key] = anilst[replst[i].value]; 477 | 478 | LoadEmeraldManager_r(); 479 | } 480 | } 481 | 482 | //changing the layout of the character select menu 483 | void DisplaySelectMissionCharMenu() 484 | { 485 | 486 | int selectedLevel; 487 | int selectedStageInfo[3]; 488 | int langIsJap; 489 | 490 | Vertex position; 491 | Vertex Location_SelectionBorder; 492 | //variables declaration ends here 493 | 494 | selectedLevel = StageSelectLevels[StageSelectLevelSelection].Level; 495 | if (selectedLevel == LevelIDs::LevelIDs_GreenHill && !SelectingStageCharacter) 496 | return; 497 | CheckSelectedStageType(selectedLevel, StageSelectLevelSelection, selectedStageInfo); 498 | 499 | if (TextLanguage != 0) 500 | langIsJap = 4; 501 | else langIsJap = 0; 502 | 503 | position.X = StageSelect_MissionCharSelectLoc_X - 128; 504 | position.Y = StageSelect_MissionCharSelectLoc_Y - 64; 505 | position.Z = -95; 506 | 507 | ToCheck1 = ToCheck4; 508 | ToCheck3 = ToCheck4; 509 | NJS_IMAGEDATA_AlphaStrength = 0.5; 510 | NJS_IMAGEDATA_RedStrength = 0.5; 511 | NJS_IMAGEDATA_GreenStrength = 0.5; 512 | NJS_IMAGEDATA_BlueStrength = 0.5; 513 | 514 | if (SelectingStageCharacter) 515 | { 516 | 517 | Vertex BoxPosition; 518 | BoxPosition.X = StageSelect_MissionCharSelectLoc_X; 519 | BoxPosition.Y = StageSelect_MissionCharSelectLoc_Y; 520 | BoxPosition.Z = -95; 521 | if (selectedLevel != LevelIDs_GreenHill) 522 | Display_stageMapTexture(34, &BoxPosition, 91, 1); 523 | 524 | BoxPosition.Y += 130; 525 | Vector2 BoxSize; 526 | BoxSize.X = 1.2; 527 | BoxSize.Y = 0.9; 528 | Display_stageMapTextureS(&BoxPosition, &BoxSize, 91, 34); 529 | if (selectedLevel == LevelIDs_GreenHill) 530 | goto SelectChar; 531 | } 532 | else if (selectedStageInfo[0]) 533 | { 534 | if (selectedStageInfo[0] == 1) 535 | Display_stageMapTexture(34, &position, 92, 1); 536 | else Display_stageMapTexture(34, &position, 93, 1); 537 | } 538 | else 539 | { 540 | int t; 541 | switch (SelectedMissionCharacter) 542 | { 543 | case 0: 544 | case 3: 545 | case 4: 546 | t = 93; 547 | break; 548 | default: 549 | t = 92; 550 | break; 551 | } 552 | Display_stageMapTexture(34, &position, t, 1); 553 | } 554 | 555 | ToCheck2 = ToCheck1; 556 | ToCheck4 = ToCheck3; 557 | NJS_IMAGEDATA_AlphaStrength = 0.0; 558 | NJS_IMAGEDATA_RedStrength = 0.0; 559 | NJS_IMAGEDATA_GreenStrength = 0.0; 560 | NJS_IMAGEDATA_BlueStrength = 0.0; 561 | 562 | position.X += 55.0; 563 | position.Y += 140.0; 564 | position.Z += 1.0; 565 | 566 | switch (selectedStageInfo[0]) 567 | { 568 | case 0: 569 | CharOrMissionSelectionMax = 5; 570 | DisplayMissionRanksName(selectedStageInfo); 571 | 572 | Location_SelectionBorder.X = SelectedMissionCharacter * 50.0 + StageSelect_MissionCharSelectLoc_X - 101.0; 573 | Location_SelectionBorder.Y = StageSelect_MissionCharSelectLoc_Y + 29.0; 574 | Location_SelectionBorder.Z = -80; 575 | Display_stageMapTexture(32, &Location_SelectionBorder, 90, 0.7); 576 | if (!SelectedMissionCharacter || SelectedMissionCharacter > 2 && SelectedMissionCharacter <= 4) 577 | { 578 | if (SelectingStageCharacter) 579 | goto SelectChar; 580 | altCharacter = false; 581 | for (int i = 0; i < 4; i++) 582 | { 583 | Display_stageMapTexture(32, &position, langIsJap + 94 + i, 1.0); 584 | position.X += 115.0; 585 | Display_stageMapTexture(32, &position, 89, 1.0); 586 | position.X -= 115.0; 587 | position.Y += 20.0; 588 | } 589 | 590 | Set_NJSDATA_To(1); 591 | 592 | position.X += 68.0; 593 | position.Y -= 79.0; 594 | position.Z += 1.0; 595 | DrawTimeText(&position, (int)(selectedStageInfo[1] + 36 * SelectedMissionCharacter + 24), 0.6); 596 | 597 | 598 | position.X += 97.0; 599 | position.Y += 20.0; 600 | DrawScoreText(&position, *(unsigned short*)(selectedStageInfo[1] + 36 * SelectedMissionCharacter + 16), 7, 0.6); // best ring 601 | 602 | position.Y += 20.0; 603 | DrawScoreText(&position, *(unsigned short*)(selectedStageInfo[1] + 36 * SelectedMissionCharacter + 20), 7, 0.6); // best score 604 | 605 | position.Y += 20.0; 606 | DrawScoreText(&position, *(unsigned short*)(selectedStageInfo[1] + 2 * SelectedMissionCharacter + 6), 7, 0.6); // no. of plays 607 | return; 608 | } 609 | LABEL_1: 610 | if (SelectingStageCharacter) 611 | goto SelectChar; 612 | altCharacter = false; 613 | for (int i = 0; i < 2; i++) 614 | { 615 | Display_stageMapTexture(32, &position, langIsJap + 94 + (i * 3), 1.0); 616 | position.X += 115.0; 617 | Display_stageMapTexture(32, &position, 89, 1.0); 618 | position.X -= 115.0; 619 | position.Y += 20.0; 620 | } 621 | 622 | Set_NJSDATA_To(1); 623 | 624 | position.X += 68.0; 625 | position.Y -= 39.0; 626 | position.Z += 1.0; 627 | 628 | DrawTimeText(&position, (int)(selectedStageInfo[1] + 36 * SelectedMissionCharacter + 24), 0.6); 629 | 630 | position.X += 97.0; 631 | position.Y += 20.0; 632 | DrawScoreText(&position, *(unsigned short*)(selectedStageInfo[1] + 2 * SelectedMissionCharacter + 6), 7, 0.6); //no. of plays 633 | 634 | return; 635 | SelectChar: 636 | for (int i = 0; i < 14; i++) 637 | { 638 | position.X = (std::floor(i / 2)) * 40.0 + StageSelect_MissionCharSelectLoc_X - 120; 639 | position.Y = StageSelect_MissionCharSelectLoc_Y + ((i % 2 == 0) ? 110 : 150); 640 | position.Z = -90; 641 | 642 | ToCheck1 = ToCheck2; 643 | ToCheck3 = ToCheck4; 644 | NJS_IMAGEDATA_AlphaStrength = 1; 645 | NJS_IMAGEDATA_RedStrength = 1; 646 | NJS_IMAGEDATA_GreenStrength = 1; 647 | NJS_IMAGEDATA_BlueStrength = 1; 648 | 649 | Display_stageMapTexture(34, &position, StageSelectCharacterIconIDs[i], 0.6); 650 | 651 | if (i == SelectedStageCharacter) 652 | { 653 | ToCheck1 = ToCheck2; 654 | ToCheck3 = ToCheck4; 655 | NJS_IMAGEDATA_AlphaStrength = 1; 656 | NJS_IMAGEDATA_RedStrength = 1; 657 | NJS_IMAGEDATA_GreenStrength = 1; 658 | NJS_IMAGEDATA_BlueStrength = 1; 659 | 660 | Display_stageMapTexture(32, &position, 90, 0.6); 661 | } 662 | } 663 | return; 664 | case 1: 665 | CharOrMissionSelectionMax = 5; 666 | DisplayMissionRanksName(selectedStageInfo); 667 | 668 | Location_SelectionBorder.X = SelectedMissionCharacter * 50.0 + StageSelect_MissionCharSelectLoc_X - 101.0; 669 | Location_SelectionBorder.Y = StageSelect_MissionCharSelectLoc_Y + 29.0; 670 | Location_SelectionBorder.Z = -80; 671 | Display_stageMapTexture(32, &Location_SelectionBorder, 90, 0.7); 672 | 673 | goto LABEL_1; 674 | case 2: 675 | CharOrMissionSelectionMax = 10; 676 | DisplayChaoNameEmblems(selectedStageInfo, 90.0); 677 | altCharacter = (SelectedMissionCharacter > 5); 678 | 679 | for (int i = 0; i < 10; i++) 680 | { 681 | position.X = i * 40.0 + StageSelect_MissionCharSelectLoc_X - IconPosX[i]; 682 | position.Y = StageSelect_MissionCharSelectLoc_Y + IconPosY[i]; 683 | position.Z = -90; 684 | 685 | float IconAlpha; 686 | if (CheckUnlockedChar[ConvertCWCP[ChaoWorldCharactersPlus[i]]] == 0) 687 | IconAlpha = 0.5; 688 | else IconAlpha = 1; 689 | 690 | ToCheck1 = ToCheck2; 691 | ToCheck3 = ToCheck4; 692 | NJS_IMAGEDATA_AlphaStrength = 1; 693 | NJS_IMAGEDATA_RedStrength = 1; 694 | NJS_IMAGEDATA_GreenStrength = 1; 695 | NJS_IMAGEDATA_BlueStrength = 1; 696 | 697 | Display_stageMapTexture(34, &position, ChaoSelectCharacterIconIDsPlus[i], 0.6); 698 | if (SelectedMissionCharacter == i) 699 | { 700 | ToCheck1 = ToCheck2; 701 | ToCheck3 = ToCheck4; 702 | NJS_IMAGEDATA_AlphaStrength = 1.0; 703 | NJS_IMAGEDATA_RedStrength = 1.0; 704 | NJS_IMAGEDATA_GreenStrength = 1.0; 705 | NJS_IMAGEDATA_BlueStrength = 1.0; 706 | 707 | Display_stageMapTexture(32, &position, 90, 0.6); 708 | } 709 | } 710 | break; 711 | } 712 | 713 | } 714 | __declspec(naked) void DisplaySelectMissionCharMenu_Wrapper() 715 | { 716 | __asm 717 | { 718 | push esi 719 | push ebx 720 | push edi 721 | push ecx 722 | call DisplaySelectMissionCharMenu 723 | pop ecx 724 | pop edi 725 | pop ebx 726 | pop esi 727 | ret 728 | } 729 | } 730 | 731 | //changing Input Handler 732 | signed int HandleStageSelectInputPlus() 733 | { 734 | int SelectDirection; 735 | int selectedLevel; 736 | int selectedStageInfo[3]; 737 | 738 | selectedLevel = StageSelectLevels[StageSelectLevelSelection].Level; 739 | CheckSelectedStageType(selectedLevel, StageSelectLevelSelection, selectedStageInfo); 740 | 741 | switch (UI_State1) 742 | { 743 | case 0: // initializing Menu 744 | *StageSelectFlags = 1; // enable stage select ui 745 | StageSelectFlags[4] = 1; // Enable stage select background 746 | UI_State1 = 1; 747 | return 0; 748 | case 1: 749 | if (StageSelectFlags[2]) // check if textures are loaded 750 | return 0; 751 | UI_State1 = 2; // enable stage selection 752 | StageSelectFlags[9] = 1; 753 | StageSelectFlags[10] = 1; // display the selected level 754 | StageSelectFlags[13] = 1; // display the ranks box 755 | StageSelectFlags[14] = 1; 756 | PlayGuideVoice(3); // plays the "select a stage" text 757 | return 0; 758 | case 2: // Select Level 759 | if (StageSelectFlags[6]) 760 | return 0; 761 | if (InputDown & 2) // on back 762 | { 763 | *StageSelectFlags = 0; // disables the stage select menu 764 | StageSelectFlags[1] = 0; 765 | ShowButtonGuide = 0; 766 | UI_State1 = 4; //goes into loading state, to close the menu 767 | PlaySoundEffect(0x8009, 0, 0, 0); 768 | return 0; 769 | } 770 | if (InputDown & 0xC) // on start or jump 771 | { 772 | if (!StageUnlocked[StageSelectLevelSelection]) 773 | { 774 | PlaySoundEffect(0x800A, 0, 0, 0); 775 | return 0; 776 | } 777 | PlaySoundEffect(0x8001, 0, 0, 0); 778 | if (StageSelectLevels[StageSelectLevelSelection].Level == LevelIDs_GreenHill) // if level is green hill 779 | { 780 | StageSelectFlags[13] = 0; // hide the ranks box 781 | StageSelectFlags[10] = 0; // hide the selected level 782 | StageSelectFlags[21] = 1; // display the character select screen 783 | StageSelectFlags[22] = 1; // display "Select your character" from the top of the screen 784 | UI_State1 = 3; //goes into the mission select screen 785 | SelectingStageCharacter = true; 786 | PlayGuideVoice(2); 787 | /* 788 | sub_673AE0(); //seems to reset loads of flags, probably because we are leaving the menu at this point 789 | IngameFlag = 3; //flags the game as "In level" 790 | *StageSelectFlags = 0; // disables the stage select menu 791 | StageSelectFlags[1] = 0; 792 | ShowButtonGuide = 0; //hides the button guide at the bottom of the screen 793 | UI_State1 = 5; // gets into closing state 794 | } 795 | else 796 | { 797 | StageSelectFlags[13] = 0; // hide the ranks box 798 | StageSelectFlags[10] = 0; // hide the selected level 799 | StageSelectFlags[21] = 1; // display the character select screen 800 | StageSelectFlags[22] = 1; // display "Select your character" from the top of the screen 801 | SelectedMissionCharacter = 0; // set the selected mission to 0 802 | UI_State1 = 3; //goes into the mission select screen 803 | if (StageSelectLevels[StageSelectLevelSelection].Level == LevelIDs_ChaoWorld) 804 | PlayGuideVoice(2); // plays the "select your character" text 805 | } 806 | } 807 | if (InputDown & 0x10) // on up 808 | SelectDirection = 1; 809 | else if (InputDown & 0x20) // on down 810 | SelectDirection = 2; 811 | else if (InputDown & 0x40) // on left 812 | SelectDirection = 3; 813 | else if (InputDown & 0x80) // on right 814 | SelectDirection = 4; 815 | if (SelectDirection); 816 | if (SelectNextStage(SelectDirection - 1)) // if a new stage was selected, play a sound 817 | PlaySoundEffect(0x8000, 0, 0, 0); 818 | return 0; 819 | case 3: // Select Mission or Character 820 | if (InputDown & 2) // on back 821 | { 822 | if (SelectingStageCharacter) 823 | { 824 | SelectingStageCharacter = false; 825 | if (StageSelectLevels[StageSelectLevelSelection].Level == LevelIDs_GreenHill) // if level is green hill 826 | { 827 | StageSelectFlags[13] = 1; 828 | StageSelectFlags[10] = 1; 829 | StageSelectFlags[21] = 0; 830 | StageSelectFlags[22] = 0; 831 | UI_State1 = 2; 832 | SelectedMissionCharacter = 0; 833 | } 834 | } 835 | else 836 | { 837 | UI_State1 = 2; // set ui stae back to 2 (level select) 838 | StageSelectFlags[13] = 1; // display the ranks box again 839 | StageSelectFlags[10] = 1; // display the selected level again 840 | StageSelectFlags[21] = 0; // hide the character select screen 841 | StageSelectFlags[22] = 0; // remove "Select your character" from the top of the screen 842 | SelectedMissionCharacter = 0; // set the selected mission to 0 843 | } 844 | PlaySoundEffect(0x8009, 0, 0, 0); 845 | return 0; 846 | } 847 | if (InputDown & 0xC) 848 | { 849 | if (!SelectingStageCharacter && !selectedStageInfo[0]) 850 | { 851 | unsigned int CharMissionUnlocked = CheckIfCharMissionUnlocked(); 852 | if (CharMissionUnlocked) 853 | { 854 | if (CharMissionUnlocked < 4) 855 | { 856 | PlaySoundEffect(0x8001, 0, 0, 0); 857 | SelectingStageCharacter = true; 858 | switch (StageSelectLevels[StageSelectLevelSelection].Character) 859 | { 860 | case Characters_MechTails: 861 | case Characters_MechEggman: 862 | SelectedStageCharacter = StageSelectLevels[StageSelectLevelSelection].Character + 4; 863 | break; 864 | default: 865 | SelectedStageCharacter = StageSelectLevels[StageSelectLevelSelection].Character; 866 | break; 867 | } 868 | PlayGuideVoice(2); 869 | } 870 | } 871 | else PlaySoundEffect(0x800A, 0, 0, 0); 872 | } 873 | else 874 | { 875 | if (!selectedStageInfo[0]) 876 | { 877 | altCharacter = StageCharacterAlts[SelectedStageCharacter]; 878 | SelectedStageCharacter = StageCharacters[SelectedStageCharacter]; 879 | } 880 | if (selectedStageInfo[0] == 2) 881 | { 882 | SelectedStageCharacter = ChaoWorldCharactersPlus[SelectedMissionCharacter]; 883 | SelectingStageCharacter = true; 884 | } 885 | PlaySoundEffect(0x8001, 0, 0, 0); 886 | sub_673AE0(); //seems to reset loads of flags, probably because we are leaving the menu at this point 887 | IngameFlag = 3; 888 | *StageSelectFlags = 0; 889 | StageSelectFlags[1] = 0; 890 | StageSelectFlags[22] = 0; 891 | ShowButtonGuide = 0; //hides the button guide at the bottom of the screen 892 | UI_State1 = 5; 893 | } 894 | return 0; 895 | } 896 | if (StageSelectLevels[StageSelectLevelSelection].Level == LevelIDs_ChaoWorld) 897 | { 898 | if (InputDown & 0x40) // on left 899 | { 900 | switch (SelectedMissionCharacter) 901 | { 902 | case 0: 903 | SelectedMissionCharacter = 5; 904 | goto PlaySound1; 905 | case 6: 906 | SelectedMissionCharacter = 9; 907 | goto PlaySound1; 908 | default: 909 | SelectedMissionCharacter--; 910 | PlaySound1: 911 | PlaySoundEffect(0x8000, 0, 0, 0); 912 | break; 913 | } 914 | } 915 | else if (InputDown & 0x80) // on right 916 | { 917 | switch (SelectedMissionCharacter) 918 | { 919 | case 5: 920 | SelectedMissionCharacter = 0; 921 | goto PlaySound2; 922 | case 9: 923 | SelectedMissionCharacter = 6; 924 | goto PlaySound2; 925 | default: 926 | SelectedMissionCharacter++; 927 | PlaySound2: 928 | PlaySoundEffect(0x8000, 0, 0, 0); 929 | break; 930 | } 931 | } 932 | else if (InputDown & 0x10) // on up 933 | { 934 | if (SelectedMissionCharacter > 5) 935 | { 936 | SelectedMissionCharacter -= 5; 937 | PlaySoundEffect(0x8000, 0, 0, 0); 938 | } 939 | } 940 | else if (InputDown & 0x20) // on down 941 | { 942 | if (SelectedMissionCharacter > 0 && SelectedMissionCharacter < 5) 943 | { 944 | SelectedMissionCharacter += 5; 945 | PlaySoundEffect(0x8000, 0, 0, 0); 946 | } 947 | } 948 | } 949 | else 950 | { 951 | if (!SelectingStageCharacter) 952 | { 953 | if (InputDown & 0x40) // on left 954 | { 955 | if (SelectedMissionCharacter > 0) 956 | { 957 | SelectedMissionCharacter--; 958 | PlaySoundEffect(0x8000, 0, 0, 0); 959 | } 960 | } 961 | else if (InputDown & 0x80) // on right 962 | { 963 | if (SelectedMissionCharacter < CharOrMissionSelectionMax - 1) 964 | { 965 | SelectedMissionCharacter++; 966 | PlaySoundEffect(0x8000, 0, 0, 0); 967 | } 968 | } 969 | } 970 | else 971 | { 972 | if (InputDown & 0x40) // on left 973 | { 974 | if (SelectedStageCharacter < 2) 975 | SelectedStageCharacter += 12; 976 | else SelectedStageCharacter -= 2; 977 | PlaySoundEffect(0x8000, 0, 0, 0); 978 | } 979 | else if (InputDown & 0x80) // on right 980 | { 981 | if (SelectedStageCharacter > 11) 982 | SelectedStageCharacter -= 12; 983 | else SelectedStageCharacter += 2; 984 | PlaySoundEffect(0x8000, 0, 0, 0); 985 | } 986 | else if (InputDown & 0x10) // on up 987 | { 988 | if (SelectedStageCharacter % 2 != 0) 989 | SelectedStageCharacter--; 990 | PlaySoundEffect(0x8000, 0, 0, 0); 991 | } 992 | else if (InputDown & 0x20) // on down 993 | { 994 | if (SelectedStageCharacter % 2 == 0) 995 | SelectedStageCharacter++; 996 | PlaySoundEffect(0x8000, 0, 0, 0); 997 | } 998 | } 999 | } 1000 | return 0; 1001 | case 4: 1002 | if (!StageSelectFlags[2]) 1003 | { 1004 | sub_664B60(); 1005 | sub_664DC0(0); 1006 | (*((unsigned int*) & (dword_1D7BB10))) = 1; 1007 | } 1008 | return 0; 1009 | case 5: 1010 | if (StageSelectFlags[2] || AdjustCharacter() > 3) 1011 | return 0; 1012 | 1013 | byte_1DEB31E = 0; 1014 | word_1DEB31F = 0; 1015 | byte_1DEB321 = 1; 1016 | return 1; 1017 | default: 1018 | return 0; 1019 | } 1020 | } 1021 | 1022 | // fixing the sound loading 1023 | void LoadChaoWorldSoundBank() 1024 | { 1025 | char* v4; 1026 | int v2 = CurrentCharacter; 1027 | if (altCharacter) 1028 | { 1029 | switch (CurrentCharacter) 1030 | { 1031 | case 0: 1032 | v2 = Characters::Characters_Amy; 1033 | break; 1034 | case 1: 1035 | v2 = Characters::Characters_MetalSonic; 1036 | break; 1037 | case 4: 1038 | v2 = Characters::Characters_Tikal; 1039 | break; 1040 | case 5: 1041 | v2 = Characters::Characters_Chaos; 1042 | break; 1043 | default: 1044 | break; 1045 | } 1046 | } 1047 | 1048 | switch (v2) 1049 | { 1050 | case Characters_Sonic: 1051 | case Characters_Shadow: 1052 | case Characters_Amy: 1053 | case Characters_MetalSonic: 1054 | v4 = (char*)"chao_chara_ss.mlt"; 1055 | break; 1056 | case Characters_Knuckles: 1057 | case Characters_Rouge: 1058 | v4 = (char*)"chao_chara_kr.mlt"; 1059 | break; 1060 | case Characters_Tikal: 1061 | case Characters_Chaos: 1062 | v4 = (char*)"se_ch_kn_BATTLE.mlt"; 1063 | break; 1064 | case Characters_Tails: 1065 | case Characters_Eggman: 1066 | v4 = (char*)"chao_chara_te.mlt"; 1067 | break; 1068 | case Characters_MechTails: 1069 | case Characters_MechEggman: 1070 | v4 = (char*)"se_ch_wk.mlt"; 1071 | break; 1072 | case Characters_ChaoWalker: 1073 | case Characters_DarkChaoWalker: 1074 | v4 = (char*)"se_ch_wk_BATTLE.mlt"; 1075 | break; 1076 | default: 1077 | v4 = (char*)"chao_chara_ss.mlt"; 1078 | break; 1079 | } 1080 | LoadSoundBank(v4); 1081 | } 1082 | 1083 | static const int return1 = 0x532054; 1084 | __declspec(naked) void loc_532029() 1085 | { 1086 | LoadChaoWorldSoundBank(); 1087 | __asm jmp return1 1088 | } 1089 | 1090 | static const int MultiPlayerVoiceBank = 0x173A0B8; 1091 | static const int return2 = 0x45923B; 1092 | __declspec(naked) void loc_2800440() 1093 | { 1094 | __asm 1095 | { 1096 | mov ecx, CurrentCharacter 1097 | mov ecx, [ecx] 1098 | cmp altCharacter, 0 1099 | je done 1100 | cmp ecx, Characters_Sonic 1101 | jne notAmy 1102 | mov ecx, Characters_Amy 1103 | mov esi, 173A0B8h // these addresses are for the multiplayerVoiceBank, but it doesnt work if use the variable for some reason, so i use the addresses directly 1104 | jmp done 1105 | notAmy : 1106 | cmp ecx, Characters_Shadow 1107 | jne notMetal 1108 | mov ecx, Characters_MetalSonic 1109 | mov esi, 173A0B8h + 10h 1110 | jmp done 1111 | notMetal : 1112 | cmp ecx, Characters_Knuckles 1113 | jne notKnuckles 1114 | mov ecx, Characters_Tikal 1115 | mov esi, 173A0B8h + 20h 1116 | jmp done 1117 | notKnuckles : 1118 | cmp ecx, Characters_Rouge 1119 | jne done 1120 | mov ecx, Characters_Chaos 1121 | mov esi, 173A0B8h + 30h 1122 | 1123 | done : 1124 | call LoadVoiceBank 1125 | jmp return2 1126 | } 1127 | } 1128 | #pragma endregion 1129 | /* 1130 | extern "C" 1131 | { 1132 | //inserting the mods 1133 | __declspec(dllexport) void Init(const char* path, const HelperFunctions& helperFunctions) 1134 | { 1135 | #pragma region SA2CharSel stuff 1136 | AnimationInfo* buf = TailsAnimList2; 1137 | WriteData((AnimationInfo**)0x74CFD7, buf); 1138 | memcpy(TailsAnimList2, TailsAnimList, TailsAnimList_Length * sizeof(AnimationInfo)); 1139 | 1140 | buf = MechEggmanAnimList2; 1141 | WriteData((AnimationInfo**)0x740D50, buf); 1142 | memcpy(MechEggmanAnimList2, MechEggmanAnimList, MechEggmanAnimList_Length * sizeof(AnimationInfo)); 1143 | 1144 | buf = MechTailsAnimList2; 1145 | WriteData((AnimationInfo**)0x740FB0, buf); 1146 | memcpy(MechTailsAnimList2, MechTailsAnimList, MechTailsAnimList_Length * sizeof(AnimationInfo)); 1147 | 1148 | buf = ChaoWalkerAnimList2; 1149 | WriteData((AnimationInfo**)0x7411DC, buf); 1150 | memcpy(ChaoWalkerAnimList2, ChaoWalkerAnimList, ChaoWalkerAnimList_Length * sizeof(AnimationInfo)); 1151 | 1152 | buf = DarkChaoWalkerAnimList2; 1153 | WriteData((AnimationInfo**)0x7413BC, buf); 1154 | memcpy(DarkChaoWalkerAnimList2, DarkChaoWalkerAnimList, DarkChaoWalkerAnimList_Length * sizeof(AnimationInfo)); 1155 | 1156 | buf = EggmanAnimList2; 1157 | WriteData((AnimationInfo**)0x73C2F2, buf); 1158 | memcpy(EggmanAnimList2, EggmanAnimList, EggmanAnimList_Length * sizeof(AnimationInfo)); 1159 | 1160 | buf = SonicAnimList2; 1161 | WriteData((AnimationInfo**)0x716F0A, buf); 1162 | memcpy(SonicAnimList2, SonicAnimList, SonicAnimList_Length * sizeof(AnimationInfo)); 1163 | 1164 | pair* sonic = (pair*)0x96EC80; 1165 | pair* amy = (pair*)0x96ECD0; 1166 | pair* shadow = (pair*)0x96ED18; 1167 | pair* knuckles = (pair*)0x96ED58; 1168 | pair* tikal = (pair*)0x96EDB8; 1169 | pair* rouge = (pair*)0x96EE10; 1170 | pair* chaos = (pair*)0x96EE80; 1171 | pair* mecheggman = (pair*)0x96EED8; 1172 | pair* darkchaowalker = (pair*)0x96EF08; 1173 | pair* mechtails = (pair*)0x96EF38; 1174 | pair* chaowalker = (pair*)0x96EF68; 1175 | pair* eggman = (pair*)0x96EF98; 1176 | pair* tails = (pair*)0x96EFA8; 1177 | { 1178 | pair* order[] = { sonic, shadow, rouge, knuckles, mechtails, mecheggman }; 1179 | actionlistthing(order, (void**)0x7952E5, false); 1180 | } 1181 | { 1182 | pair* order[] = { amy, sonic, shadow, rouge, knuckles, mechtails, mecheggman }; 1183 | actionlistthing(order, (void**)0x7952EC, false); 1184 | } 1185 | { 1186 | pair* order[] = { shadow, sonic, rouge, knuckles, mechtails, mecheggman }; 1187 | actionlistthing(order, (void**)0x7952F3, false); 1188 | } 1189 | { 1190 | pair* order[] = { tails, mechtails, mecheggman, sonic, shadow, rouge, knuckles }; 1191 | actionlistthing(order, (void**)0x7952FA, true); 1192 | } 1193 | { 1194 | pair* order[] = { knuckles, rouge, sonic, shadow, mechtails, mecheggman }; 1195 | actionlistthing(order, (void**)0x795301, true); 1196 | } 1197 | { 1198 | pair* order[] = { tikal, rouge, knuckles, sonic, shadow, mechtails, mecheggman }; 1199 | actionlistthing(order, (void**)0x795308, true); 1200 | } 1201 | { 1202 | pair* order[] = { rouge, knuckles, sonic, shadow, mechtails, mecheggman }; 1203 | actionlistthing(order, (void**)0x79530F, true); 1204 | } 1205 | { 1206 | pair* order[] = { chaos, rouge, knuckles, sonic, shadow, mechtails, mecheggman }; 1207 | actionlistthing(order, (void**)0x795316, true); 1208 | } 1209 | { 1210 | pair* order[] = { eggman, mecheggman, mechtails, sonic, shadow, rouge, knuckles }; 1211 | actionlistthing(order, (void**)0x79531D, true); 1212 | } 1213 | { 1214 | pair* order[] = { mecheggman, mechtails, sonic, shadow, rouge, knuckles }; 1215 | actionlistthing(order, (void**)0x795324, true); 1216 | } 1217 | { 1218 | pair* order[] = { darkchaowalker, mecheggman, mechtails, sonic, shadow, rouge, knuckles }; 1219 | actionlistthing(order, (void**)0x79532B, true); 1220 | } 1221 | { 1222 | pair* order[] = { chaowalker, mechtails, mecheggman, sonic, shadow, rouge, knuckles }; 1223 | actionlistthing(order, (void**)0x795332, true); 1224 | } 1225 | { 1226 | pair* order[] = { mechtails, mecheggman, sonic, shadow, rouge, knuckles }; 1227 | actionlistthing(order, (void**)0x795339, true); 1228 | } 1229 | 1230 | WriteCall((void*)0x729D16, Knuckles_LevelBounds_r); 1231 | WriteCall((void*)0x729DC5, Knuckles_LevelBounds_r); 1232 | WriteCall((void*)0x72B0F1, Knuckles_LevelBounds_r); 1233 | WriteCall((void*)0x72B2E8, Knuckles_LevelBounds_r); 1234 | WriteCall((void*)0x4D45F0, LoadAquaticMineCharAnims_r); 1235 | WriteCall((void*)0x63D727, LoadDryLagoonCharAnims_r); 1236 | WriteCall((void*)0x4DB351, LoadCannonsCoreRCharAnims_r); 1237 | WriteCall((void*)0x65E8F1, LoadCannonsCoreKCharAnims_r); 1238 | WriteCall((void*)0x65662A, LoadSandOceanCharAnims_r); 1239 | WriteCall((void*)0x4DDE49, LoadHiddenBaseCharAnims_r); 1240 | WriteCall((void*)0x4A53AC, LoadEggGolemECharAnims_r); 1241 | 1242 | const IniFile* settings = new IniFile(std::string(path) + "\\config.ini"); 1243 | for (int i = 0; i < Characters_Amy; i++) 1244 | defaultcharacters[i] = ParseCharacterID(settings->getString("1Player", charnames[i]), (Characters)i); 1245 | delete settings; 1246 | #pragma endregion 1247 | 1248 | std::memcpy(NewStageMapAnims, StageMapAnims, sizeof(NJS_TEXANIM) * 104); // copy the texanims 1249 | //std::memcpy() 1250 | NewStageMapAnims[104] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 16, 0 }; // add the new textures 1251 | NewStageMapAnims[105] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 17, 0 }; 1252 | NewStageMapAnims[106] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 18, 0 }; 1253 | NewStageMapAnims[107] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 19, 0 }; 1254 | NewStageMapAnims[108] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 20, 0 }; 1255 | NewStageMapAnims[109] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 21, 0 }; 1256 | NewStageMapAnims[110] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 22, 0 }; 1257 | NewStageMapAnims[111] = { 0x3B, 0x3B, 0, 0, 8, 8, 0x0F4, 0x0F4, 23, 0 }; 1258 | 1259 | WriteData((int*)0x00675CBB, (int)&NewStageMapAnims); // re-assign the texanims 1260 | WriteData((int*)0x00675D20, (int)&NewStageMapAnims); 1261 | WriteData((int*)0x006765F6, (int)&NewStageMapAnims); 1262 | WriteData((int*)0x006766B2, (int)&NewStageMapAnims); 1263 | WriteData((int*)0x006769B5, (int)&NewStageMapAnims); 1264 | WriteData((int*)0x00676A0E, (int)&NewStageMapAnims); 1265 | WriteData((int*)0x00677A53, (int)&NewStageMapAnims->cx); 1266 | WriteData((int*)0x00677A8B, (int)&NewStageMapAnims[112].cx); 1267 | WriteData((int*)0x00677A8B, (int)&NewStageMapAnims[112].cx); 1268 | WriteData((int*)0x00C68B6C, 0x18); // raise spritecount to 24 1269 | WriteCall((int*)0x0067792F, DisplaySelectMissionCharMenu_Wrapper); 1270 | 1271 | WriteJump((void*)0x0043D630, LoadCharactersPlus); 1272 | WriteData((int*)0x006784A0, (int)&ChaoWorldCharactersPlus); 1273 | WriteData((int*)0x006782A6, (int)&ChaoWorldCharactersPlus); 1274 | WriteJump((void*)0x532029, loc_532029); 1275 | WriteJump((void*)0x459236, loc_2800440); 1276 | WriteData((int*)0x01739FD4, 0x008B9428); 1277 | WriteData((int*)0x01739FE0, 0x008B9428); 1278 | 1279 | WriteCall((int*)0x006662AD, HandleStageSelectInputPlus); 1280 | } 1281 | 1282 | unsigned __int8 twobytenop[] = { 0x66, 0x90 }; 1283 | unsigned __int8 fivebytenop[] = { 0x66, 0x90, 0x66, 0x90, 0x90 }; 1284 | unsigned __int8 shortjmp[] = { 0xEB }; 1285 | 1286 | PatchInfo patches[] = { 1287 | patchdecl(0x44E63B, twobytenop), // Dark Chao Walker Life Icon Patch 1288 | patchdecl(0x459110, twobytenop), // 2P Sound Effects Patch 1289 | patchdecl(0x45913B, twobytenop), // 2P Voice Patch 1290 | patchdecl(0x4CD255, twobytenop), // Sonic's Cannon's Core Control Patch 1291 | patchdecl(0x724261, shortjmp), // Sonic Boss Special Patch 1292 | patchdecl(0x736211, shortjmp), // Knuckles Boss Special Patch 1293 | patchdecl(0x7374E4, shortjmp), // Dry Lagoon Turtle Grab Patch 1294 | patchdecl(0x749921, shortjmp), // Mech Boss Special Patch 1295 | patchdecl(0x741690, shortjmp), // Dark Chao Walker Fix 1296 | patchdecl(0x7416DC, shortjmp), // Chao Walker Fix 1297 | patchdecl(0x728141, fivebytenop), // Knuckles emerald manager 1298 | patchdecl(0x728491, fivebytenop), // Rouge emerald manager 1299 | patchdecl(0x7288B7, fivebytenop), // Tikal emerald manager 1300 | patchdecl(0x728B64, fivebytenop), // Chaos emerald manager 1301 | patchdecl(0x716E13, twobytenop), // Amy 1302 | patchdecl(0x716F2C, twobytenop), // Sonic costume 1303 | patchdecl(0x717373, twobytenop), // Metal Sonic 1304 | patchdecl(0x71748C, twobytenop), // Shadow costume 1305 | patchdecl(0x728123, twobytenop), // Tikal 1306 | patchdecl(0x728241, twobytenop), // Knuckles costume 1307 | patchdecl(0x728473, twobytenop), // Chaos 1308 | patchdecl(0x728591, twobytenop), // Rouge costume 1309 | patchdecl(0x740C61, twobytenop), // Dark Chao Walker 1310 | patchdecl(0x740D72, twobytenop), // Eggman costume 1311 | patchdecl(0x740EC1, twobytenop), // Chao Walker 1312 | patchdecl(0x740FD2, twobytenop) // Tails costume 1313 | }; 1314 | 1315 | __declspec(dllexport) PatchList Patches = { arrayptrandlength(patches) }; 1316 | 1317 | PointerInfo jumps[] = { 1318 | ptrdecl(0x458970, sub_458970), // Level Cutscene Function 1319 | // ptrdecl(LoadCharacters, LoadCharacters_r), // LoadCharacters replacement 1320 | ptrdecl(0x757810, sub_757810), // Somersault Fix 1 1321 | ptrdecl(0x759A18, loc_759A18), // Somersault Fix 2 1322 | ptrdecl(LoadStartPositionPtr, LoadStartPosition_r), // LoadStartPosition replacement 1323 | ptrdecl(0x43DF30, sub_43DF30), // End position 1324 | ptrdecl(Load2PIntroPos, Load2PIntroPos_r), // 2P Intro position 1325 | ptrdecl(0x6193D0, sub_6193D0), // Sonic vs Shadow 1 1326 | ptrdecl(0x4C7100, sub_4C7100), // Sonic vs Shadow 2 1327 | ptrdecl(0x648690, sub_648690), // Knuckles vs Rouge 1328 | ptrdecl(0x626680, sub_626680), // Tails vs Eggman 1 1329 | ptrdecl(0x661CF0, sub_661CF0), // Tails vs Eggman 2 1330 | ptrdecl(0x727E5B, loc_727E5B), // 2P Race Bar 1331 | ptrdecl(0x6C63E7, loc_6C63E7), // Goal Ring 1332 | ptrdecl(0x43C9D0, 0x43CADF), // Tails/Eggman fix 1333 | ptrdecl(0x472A7D, loc_472A7D), // Title Card textures 1334 | ptrdecl(0x43EE5F, loc_43EE5F), // End Level voices 1335 | ptrdecl(0x72F4D6, KnucklesSunglassesFix), 1336 | ptrdecl(0x72F531, KnucklesAirNecklaceFix), 1337 | ptrdecl(0x744914, EggmanLaserBlasterFix), 1338 | ptrdecl(0x744E02, EggmanLargeCannonFix), 1339 | ptrdecl(0x748168, TailsLaserBlasterFix), 1340 | ptrdecl(0x74861A, TailsBazookaFix), 1341 | //ptrdecl(0x4EB2B0, InitSplitscreenPlus) 1342 | }; 1343 | 1344 | __declspec(dllexport) PointerList Jumps = { arrayptrandlength(jumps) }; 1345 | 1346 | __declspec(dllexport) ModInfo SA2ModInfo = { ModLoaderVer }; 1347 | } 1348 | */ -------------------------------------------------------------------------------- /CharacterSelectPlus/sa2-util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma region declaring and pointing to variables 4 | DataArray(char*, Camera_Character_Data, 0x0173388C, 10); 5 | DataPointer(char, CharOrMissionSelectionMax, 0x01D1BF04); 6 | 7 | DataArray(char, CheckUnlockedChar, 0x01DEF829, 11); 8 | DataArray(int, ChaoSelectCharacterIconIDs, 0x00C75310, 6); 9 | DataPointer(float, StageSelect_MissionCharSelectLoc_X, 0x01A4A968); 10 | DataPointer(float, StageSelect_MissionCharSelectLoc_Y, 0x01A4A96C); 11 | DataPointer(float, NJS_IMAGEDATA_AlphaStrength, 0x025EFFD0); 12 | DataPointer(float, NJS_IMAGEDATA_RedStrength, 0x025EFFD4); 13 | DataPointer(float, NJS_IMAGEDATA_GreenStrength, 0x025EFFD8); 14 | DataPointer(float, NJS_IMAGEDATA_BlueStrength, 0x025EFFDC); 15 | DataArray(NJS_TEXANIM, StageMapAnims, 0x00C68C50, 104); 16 | DataArray(NJS_TEXNAME, StageMapTexNames, 0x00C68AA8, 16); 17 | DataArray(CharacterVoiceBank, stru_173A018, 0x0173A018, 10); 18 | 19 | DataPointer(int, UI_State1, 0x01D7BB14); 20 | DataPointer(int*, StageSelectFlags, 0x00C77F08); 21 | DataPointer(int, InputDown, 0x01DEFAB0); 22 | DataPointer(int, ShowButtonGuide, 0x01AEE2FC); 23 | DataPointer(int, IngameFlag, 0x01A559E8); 24 | DataPointer(char, byte_1DEB31E, 0x01DEB31E); 25 | DataPointer(short, word_1DEB31F, 0x01DEB31F); 26 | DataPointer(char, byte_1DEB321, 0x01DEB321); 27 | DataPointer(float, dword_1D7BB10, 0x01D7BB10); 28 | DataArray(int, StageUnlocked, 0x01A4A974, 1); 29 | 30 | FunctionPointer(void, DisplayMissionRanksName, (int*), 0x00676690); 31 | FunctionPointer(void, Set_NJSDATA_To, (float), 0x00433D00); 32 | FunctionPointer(int, DisplayChaoNameEmblems, (int*, float), 0x006768A0); 33 | ThiscallFunctionPointer(void, LoadSoundBank, (char*), 0x435880); 34 | FunctionPointer(void, LoadVoiceBank, (int, CharacterVoiceBank*), 0x459010); 35 | FunctionPointer(unsigned int, CheckIfCharMissionUnlocked, (), 0x00678460); 36 | FunctionPointer(void, sub_673AE0, (), 0x00673AE0); 37 | FunctionPointer(int, AdjustCharacter, (), 0x00678250); 38 | 39 | FunctionPointer(void, sub_664B60, (), 0x00664B60); 40 | 41 | 42 | //hardcoded values i guess 43 | DataPointer(float, ToCheck1, 0x01DEB6A8); 44 | DataPointer(float, ToCheck2, 0x025F0268); 45 | DataPointer(int, ToCheck3, 0x01DEB6A0); 46 | DataPointer(int, ToCheck4, 0x025F02D4); 47 | 48 | DataArray(CharacterSoundBank, stru_1739F58, 0x1739F58, 8); 49 | 50 | DataPointer(NJS_TEXLIST, StageMap_Texlist, 0xC68B68); 51 | 52 | struct Vertex 53 | { 54 | float X; 55 | float Y; 56 | float Z; 57 | }; 58 | struct Vector2 59 | { 60 | float X; 61 | float Y; 62 | }; 63 | #pragma endregion 64 | 65 | #pragma region usercalls 66 | static const void* const CheckSelectedStageTypePtr = (void*)0x00676640; 67 | static inline void CheckSelectedStageType(int stageID, int UiSelectionID, int* output) 68 | { 69 | __asm 70 | { 71 | mov eax, [stageID] 72 | mov edx, [UiSelectionID] 73 | mov ecx, [output] 74 | call CheckSelectedStageTypePtr 75 | } 76 | } 77 | 78 | static const void* const Display_stageMapTexturePtr = (void*)0x00675C90; 79 | static inline void Display_stageMapTexture(int UIFlags, Vertex* Position, int TexID, float ESize) 80 | { 81 | __asm 82 | { 83 | push[ESize] 84 | push[TexID] 85 | mov eax, [Position] 86 | mov ecx, [UIFlags] 87 | call Display_stageMapTexturePtr 88 | add esp, 8 89 | } 90 | } 91 | 92 | static const void* const Display_stageMapTextureSPtr = (void*)0x00675CF0; 93 | static inline void Display_stageMapTextureS(Vertex* Position, Vector2* ESize, int TexID, int Flags) 94 | { 95 | __asm 96 | { 97 | push[Flags]; 98 | push[TexID]; 99 | mov ecx, [ESize]; 100 | mov eax, [Position]; 101 | call Display_stageMapTextureSPtr; 102 | add esp, 8 103 | } 104 | } 105 | 106 | static const void* const DrawTimeTextPtr = (void*)0x00674F70; 107 | static inline void DrawTimeText(Vertex* Position, int Time, float ESize) 108 | { 109 | __asm 110 | { 111 | push[ESize] 112 | mov esi, [Time] 113 | mov eax, [Position] 114 | call DrawTimeTextPtr 115 | add esp, 4 116 | } 117 | } 118 | 119 | static const void* const DrawScoreTextPtr = (void*)0x00675580; 120 | static inline void DrawScoreText(Vertex* Position, int number, int CharCount, float ESize) 121 | { 122 | __asm 123 | { 124 | push[ESize] 125 | push[CharCount] 126 | push[number] 127 | mov eax, [Position] 128 | call DrawScoreTextPtr 129 | add esp, 12 130 | } 131 | } 132 | 133 | static const void* const PlayGuideVoicePtr = (void*)0x006727E2; 134 | static inline void PlayGuideVoice(int ID) 135 | { 136 | __asm 137 | { 138 | mov eax, [ID] 139 | call PlayGuideVoicePtr 140 | } 141 | } 142 | 143 | 144 | static const int* const SelectNextStagePtr = (int*)0x00677BF0; 145 | static inline int SelectNextStage(int direction) 146 | { 147 | int result; 148 | __asm 149 | { 150 | mov eax, [direction] 151 | call SelectNextStagePtr 152 | mov result, eax 153 | } 154 | return result; 155 | } 156 | 157 | static const void* const sub_664DC0Ptr = (void*)0x00664DC0; 158 | static inline void sub_664DC0(int a1) 159 | { 160 | __asm 161 | { 162 | mov eax, [a1] 163 | call sub_664DC0Ptr 164 | } 165 | } 166 | 167 | //void __usercall sub_459010(MLTSoundList* a1@, CharacterVoiceBank* a2@) 168 | static const void* const sub_459010Ptr = (void*)0x459010; 169 | static inline void sub_459010(MLTSoundList* a1, CharacterVoiceBank* a2) 170 | { 171 | __asm 172 | { 173 | mov esi, [a2] 174 | mov edi, [a1] 175 | call sub_459010Ptr 176 | } 177 | } 178 | 179 | DataPointer(BossTitleData, KnucklesBossTitle, 0xDCF434); 180 | DataPointer(BossTitleData, RougeBossTitle, 0xDCF530); 181 | DataPointer(BossTitleData, TailsBossTitle, 0xEF3084); 182 | DataPointer(BossTitleData, EggmanBossTitle, 0xEF3190); 183 | DataPointer(BossTitleData, SonicBossTitle, 0x1646524); 184 | DataPointer(BossTitleData, ShadowBossTitle, 0x1647C24); 185 | 186 | #pragma endregion -------------------------------------------------------------------------------- /CharacterSelectPlus/set-file.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | static Trampoline* LoadStageSetFile_t = nullptr; 4 | 5 | static inline void* LoadStageSETFile_origin(char* filename, int buffersize) 6 | { 7 | auto target = LoadStageSetFile_t->Target(); 8 | void* result; 9 | 10 | __asm 11 | { 12 | push[buffersize] 13 | mov ecx, [filename] 14 | call target 15 | add esp, 4 16 | mov result, eax 17 | } 18 | 19 | return result; 20 | } 21 | 22 | static void* LoadStageSetFile_r(char* filename, int size) 23 | { 24 | std::string setS = "\\set\\set00"; 25 | std::string setU = setS; 26 | 27 | if (CurrentCharacter == Characters_Knuckles || CurrentCharacter == Characters_Rouge || MissionNum == 2 || MissionNum >= 4) 28 | { 29 | return LoadStageSETFile_origin(filename, size); 30 | } 31 | 32 | switch (CurrentLevel) 33 | { 34 | case LevelIDs_WildCanyon: 35 | setS += "16_s.bin"; 36 | setU += "16_u.bin"; 37 | break; 38 | case LevelIDs_PumpkinHill: 39 | setS += "05_s.bin"; 40 | setU += "05_u.bin"; 41 | break; 42 | case LevelIDs_AquaticMine: 43 | setS += "07_s.bin"; 44 | setU += "07_u.bin"; 45 | break; 46 | case LevelIDs_MeteorHerd: 47 | setS += "32_s.bin"; 48 | setU = "set0032_u.bin"; 49 | break; 50 | case LevelIDs_DryLagoon: 51 | setS += "18_s.bin"; 52 | setU += "18_u.bin"; 53 | break; 54 | case LevelIDs_EggQuarters: 55 | setS += "26_s.bin"; 56 | setU += "26_u.bin"; 57 | break; 58 | case LevelIDs_SecurityHall: 59 | setS += "08_s.bin"; 60 | setU += "08_u.bin"; 61 | break; 62 | case LevelIDs_MadSpace: 63 | setS += "44_s.bin"; 64 | setU = "set0044_u.bin"; 65 | break; 66 | default: 67 | return LoadStageSETFile_origin(filename, size); 68 | } 69 | 70 | return LoadSETFile(size, (char*)setS.c_str(), (char*)setU.c_str()); 71 | } 72 | 73 | 74 | static void __declspec(naked) LoadStageSETFileASM() 75 | { 76 | __asm 77 | { 78 | push[esp + 04h] // size 79 | push ecx // filename 80 | call LoadStageSetFile_r 81 | 82 | pop ecx // filename 83 | add esp, 4 // size 84 | retn 85 | } 86 | } 87 | 88 | void init_SetFiles() 89 | { 90 | if (!customSet) 91 | return; 92 | 93 | LoadStageSetFile_t = new Trampoline((int)0x488F60, (int)0x488F66, LoadStageSETFileASM); 94 | } -------------------------------------------------------------------------------- /CharacterSelectPlus/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/CharacterSelectPlus/stdafx.cpp -------------------------------------------------------------------------------- /CharacterSelectPlus/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/CharacterSelectPlus/stdafx.h -------------------------------------------------------------------------------- /CharacterSelectPlus/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/CharacterSelectPlus/targetver.h -------------------------------------------------------------------------------- /CharacterSelectPlus/util.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | 4 | bool isTestSpawn() { 5 | int argc = 0; 6 | LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 7 | 8 | for (int i = 1; i < argc; i++) 9 | { 10 | if (!wcscmp(argv[i], L"--level") || !wcscmp(argv[i], L"-l")) 11 | { 12 | return true; 13 | } 14 | } 15 | 16 | return false; 17 | } 18 | 19 | bool isSonicTrickMod() { 20 | HMODULE sonicMod = GetModuleHandle(L"SA2-Sonic-Tricks"); 21 | 22 | if (sonicMod) 23 | return true; 24 | 25 | return false; 26 | } -------------------------------------------------------------------------------- /CharacterSelectPlus/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool isTestSpawn(); 4 | bool isSonicTrickMod(); 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SA2CharacterSelectPlus 2 | This sonic adventure 2 mod adds in 4 new buttons in the character select menu for the chao garden, and a new menu for every stage to select 1 of 14 characters! 3 | 4 | this mod uses Mainmemory's SA2CharSelect mod code to fix loads of errors - https://github.com/MainMemory/SA2CharSel 5 | 6 | 7 | big thanks to Exant and Mainmemory, who helped me out with making this mod 8 | -------------------------------------------------------------------------------- /Resources/PRS/missiontex_am.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_am.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_am2.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_am2.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_c0.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_c0.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_c02.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_c02.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_ch.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_ch.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_ch2.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_ch2.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_dc.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_dc.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_dc2.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_dc2.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_me.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_me.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_me2.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_me2.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_ti.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_ti.pak -------------------------------------------------------------------------------- /Resources/PRS/missiontex_ti2.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/missiontex_ti2.pak -------------------------------------------------------------------------------- /Resources/PRS/stageMap.pak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/PRS/stageMap.pak -------------------------------------------------------------------------------- /Resources/set/set0005_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0005_s.bin -------------------------------------------------------------------------------- /Resources/set/set0005_u.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0005_u.bin -------------------------------------------------------------------------------- /Resources/set/set0007_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0007_s.bin -------------------------------------------------------------------------------- /Resources/set/set0007_u.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0007_u.bin -------------------------------------------------------------------------------- /Resources/set/set0008_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0008_s.bin -------------------------------------------------------------------------------- /Resources/set/set0008_u.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0008_u.bin -------------------------------------------------------------------------------- /Resources/set/set0016_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0016_s.bin -------------------------------------------------------------------------------- /Resources/set/set0016_u.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0016_u.bin -------------------------------------------------------------------------------- /Resources/set/set0018_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0018_s.bin -------------------------------------------------------------------------------- /Resources/set/set0018_u.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0018_u.bin -------------------------------------------------------------------------------- /Resources/set/set0026_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0026_s.bin -------------------------------------------------------------------------------- /Resources/set/set0026_u.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0026_u.bin -------------------------------------------------------------------------------- /Resources/set/set0032_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0032_s.bin -------------------------------------------------------------------------------- /Resources/set/set0044_s.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Justin113D/SA2CharacterSelectPlus/aebbafd7e31b295e6417723c4f1087bc3c077ff4/Resources/set/set0044_s.bin --------------------------------------------------------------------------------