├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── Makefile ├── README.md ├── RSDKv4.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── WorkspaceSettings.xcsettings │ └── xcuserdata │ │ └── rubberduckycooly.xcuserdatad │ │ └── WorkspaceSettings.xcsettings └── xcshareddata │ └── xcschemes │ └── RSDKv4.xcscheme ├── Sonic12Decomp.sln ├── Sonic12Decomp ├── Animation.cpp ├── Animation.hpp ├── Audio.cpp ├── Audio.hpp ├── Collision.cpp ├── Collision.hpp ├── Debug.cpp ├── Debug.hpp ├── Drawing.cpp ├── Drawing.hpp ├── Ini.cpp ├── Ini.hpp ├── Input.cpp ├── Input.hpp ├── Math.cpp ├── Math.hpp ├── Network.cpp ├── Network.hpp ├── Object.cpp ├── Object.hpp ├── Palette.cpp ├── Palette.hpp ├── PauseMenu.cpp ├── PauseMenu.hpp ├── Reader.cpp ├── Reader.hpp ├── RetroEngine.cpp ├── RetroEngine.hpp ├── RetroGameLoop.cpp ├── RetroGameLoop.hpp ├── Scene.cpp ├── Scene.hpp ├── Scene3D.cpp ├── Scene3D.hpp ├── Script.cpp ├── Script.hpp ├── Sonic12Decomp.rc ├── Sonic12Decomp.vcxproj ├── Sonic12Decomp.vcxproj.filters ├── Sprite.cpp ├── Sprite.hpp ├── String.cpp ├── String.hpp ├── Text.cpp ├── Text.hpp ├── Userdata.cpp ├── Userdata.hpp ├── main.cpp └── resource.h ├── dependencies ├── all │ └── dependencies.txt ├── mac │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── cocoaHelpers.hpp │ ├── cocoaHelpers.mm │ └── dependencies.txt └── windows │ └── dependencies.txt ├── networking_code_proto.py ├── sonic1_livearea ├── icon0.png ├── livearea │ └── contents │ │ ├── bg0.png │ │ ├── startup.png │ │ └── template.xml └── pic0.png └── sonic2_livearea ├── icon0.png ├── livearea └── contents │ ├── bg0.png │ ├── startup.png │ └── template.xml └── pic0.png /.clang-format: -------------------------------------------------------------------------------- 1 | IndentWidth: 4 2 | Language: Cpp 3 | AlignAfterOpenBracket: Align 4 | SortIncludes: false 5 | ColumnLimit: 150 6 | PointerAlignment: Right 7 | AccessModifierOffset: -4 8 | AllowShortFunctionsOnASingleLine: All 9 | AllowShortCaseLabelsOnASingleLine: true 10 | #AllowShortLambdasOnASingleLine: All 11 | AllowShortLoopsOnASingleLine: true 12 | BinPackArguments: true 13 | BinPackParameters: true 14 | SpaceAfterCStyleCast: false 15 | BreakBeforeBraces: Attach 16 | BreakBeforeTernaryOperators: true 17 | BreakBeforeBinaryOperators: NonAssignment 18 | Cpp11BracedListStyle: false 19 | IndentCaseLabels: true 20 | AlignTrailingComments: true 21 | AlignOperands: true 22 | AlignConsecutiveAssignments: true 23 | AlignConsecutiveDeclarations: false 24 | AlignConsecutiveMacros: true 25 | UseTab: Never 26 | BreakBeforeBraces: Custom 27 | BraceWrapping: 28 | AfterClass: true 29 | AfterControlStatement: false 30 | AfterEnum: false 31 | AfterFunction: true 32 | AfterNamespace: true 33 | AfterObjCDeclaration: false 34 | AfterStruct: false 35 | AfterUnion: false 36 | BeforeCatch: false 37 | BeforeElse: true 38 | IndentBraces: false 39 | -------------------------------------------------------------------------------- /.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 | [Bb]uild/ 19 | x64/ 20 | x86/ 21 | bld/ 22 | bin/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | 26 | #dependencies 27 | [Dd]ependencies/windows/* 28 | [Dd]ependencies/mac/* 29 | [Dd]ependencies/all/* 30 | ![Dd]ependencies/all/dependencies.txt 31 | 32 | #OSX files 33 | *.DS_Store 34 | .DS_Store 35 | *.xactivitylog 36 | *.xcuserstate 37 | *.dia 38 | *.xbuild 39 | *.db 40 | *.plist 41 | *.idx 42 | *.pcm 43 | *.timestamp 44 | *.xcbkptlist 45 | 46 | # Visual Studio 2015 cache/options directory 47 | .vs/ 48 | .vscode/ 49 | 50 | # MSTest test Results 51 | [Tt]est[Rr]esult*/ 52 | [Bb]uild[Ll]og.* 53 | 54 | # NUNIT 55 | *.VisualState.xml 56 | TestResult.xml 57 | 58 | # Build Results of an ATL Project 59 | [Dd]ebugPS/ 60 | [Rr]eleasePS/ 61 | dlldata.c 62 | 63 | # DNX 64 | project.lock.json 65 | artifacts/ 66 | 67 | *_i.c 68 | *_p.c 69 | *_i.h 70 | *.ilk 71 | *.meta 72 | *.obj 73 | *.pch 74 | *.pdb 75 | *.pgc 76 | *.pgd 77 | *.rsp 78 | *.sbr 79 | *.tlb 80 | *.tli 81 | *.tlh 82 | *.tmp 83 | *.tmp_proj 84 | *.log 85 | *.vspscc 86 | *.vssscc 87 | .builds 88 | *.pidb 89 | *.svclog 90 | *.scc 91 | 92 | # Chutzpah Test files 93 | _Chutzpah* 94 | 95 | # Visual C++ cache files 96 | ipch/ 97 | *.aps 98 | *.ncb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | 108 | # TFS 2012 Local Workspace 109 | $tf/ 110 | 111 | # Guidance Automation Toolkit 112 | *.gpState 113 | 114 | # ReSharper is a .NET coding add-in 115 | _ReSharper*/ 116 | *.[Rr]e[Ss]harper 117 | *.DotSettings.user 118 | 119 | # JustCode is a .NET coding add-in 120 | .JustCode 121 | 122 | # TeamCity is a build add-in 123 | _TeamCity* 124 | 125 | # DotCover is a Code Coverage Tool 126 | *.dotCover 127 | 128 | # NCrunch 129 | _NCrunch_* 130 | .*crunch*.local.xml 131 | 132 | # MightyMoose 133 | *.mm.* 134 | AutoTest.Net/ 135 | 136 | # Web workbench (sass) 137 | .sass-cache/ 138 | 139 | # Installshield output folder 140 | [Ee]xpress/ 141 | 142 | # DocProject is a documentation generator add-in 143 | DocProject/buildhelp/ 144 | DocProject/Help/*.HxT 145 | DocProject/Help/*.HxC 146 | DocProject/Help/*.hhc 147 | DocProject/Help/*.hhk 148 | DocProject/Help/*.hhp 149 | DocProject/Help/Html2 150 | DocProject/Help/html 151 | 152 | # Click-Once directory 153 | publish/ 154 | 155 | # Publish Web Output 156 | *.[Pp]ublish.xml 157 | *.azurePubxml 158 | ## TODO: Comment the next line if you want to checkin your 159 | ## web deploy settings but do note that will include unencrypted 160 | ## passwords 161 | #*.pubxml 162 | 163 | *.publishproj 164 | 165 | # NuGet Packages 166 | *.nupkg 167 | # The packages folder can be ignored because of Package Restore 168 | **/packages/* 169 | # except build/, which is used as an MSBuild target. 170 | !**/packages/build/ 171 | # Uncomment if necessary however generally it will be regenerated when needed 172 | #!**/packages/repositories.config 173 | 174 | # Windows Azure Build Output 175 | csx/ 176 | *.build.csdef 177 | 178 | # Windows Store app package directory 179 | AppPackages/ 180 | 181 | # Visual Studio cache files 182 | # files ending in .cache can be ignored 183 | *.[Cc]ache 184 | # but keep track of directories ending in .cache 185 | !*.[Cc]ache/ 186 | 187 | # Others 188 | ClientBin/ 189 | [Ss]tyle[Cc]op.* 190 | ~$* 191 | *~ 192 | *.dbmdl 193 | *.dbproj.schemaview 194 | *.pfx 195 | *.publishsettings 196 | node_modules/ 197 | orleans.codegen.cs 198 | 199 | # RIA/Silverlight projects 200 | Generated_Code/ 201 | 202 | # Backup & report files from converting an old project file 203 | # to a newer Visual Studio version. Backup files are not needed, 204 | # because we have git ;-) 205 | _UpgradeReport_Files/ 206 | Backup*/ 207 | UpgradeLog*.XML 208 | UpgradeLog*.htm 209 | 210 | # SQL Server files 211 | *.mdf 212 | *.ldf 213 | 214 | # Business Intelligence projects 215 | *.rdl.data 216 | *.bim.layout 217 | *.bim_*.settings 218 | 219 | # Microsoft Fakes 220 | FakesAssemblies/ 221 | 222 | # Node.js Tools for Visual Studio 223 | .ntvs_analysis.dat 224 | 225 | # Visual Studio 6 build log 226 | *.plg 227 | 228 | # Visual Studio 6 workspace options file 229 | *.opt 230 | 231 | # LightSwitch generated files 232 | GeneratedArtifacts/ 233 | _Pvt_Extensions/ 234 | ModelManifest.xml 235 | 236 | Ignored/ 237 | 238 | # Compiled object files 239 | objects/ 240 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 4 | if(DEFINED ENV{DOLCESDK}) 5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{DOLCESDK}/share/dolce.toolchain.cmake" CACHE PATH "toolchain file") 6 | else() 7 | message(FATAL_ERROR "Please define DOLCESDK to point to your SDK path!") 8 | endif() 9 | endif() 10 | 11 | include("${DOLCESDK}/share/dolce.cmake" REQUIRED) 12 | 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -Wall") 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -std=c++11") 15 | set(DOLCE_MKSFOEX_FLAGS "${DOLCE_MKSFOEX_FLAGS} -d PARENTAL_LEVEL=1") 16 | 17 | project(Sonic12-Vita) 18 | 19 | include_directories( 20 | "Sonic12Decomp" 21 | ) 22 | 23 | # Build self 24 | 25 | set(ELF "sonic1.elf") 26 | set(SELF "sonic1.self") 27 | 28 | file(GLOB_RECURSE sonic_SRC 29 | Sonic12Decomp/*.cpp 30 | ) 31 | 32 | add_executable("${ELF}" 33 | ${sonic_SRC} 34 | ) 35 | 36 | target_compile_definitions("${ELF}" PUBLIC -DBASE_PATH="ux0:data/Sonic1/") 37 | 38 | target_link_libraries("${ELF}" 39 | SDL2 40 | SDL2_image 41 | pib 42 | vorbisfile 43 | vorbis 44 | ogg 45 | mpg123 46 | FLAC 47 | mikmod 48 | opus 49 | freetype 50 | jpeg 51 | png 52 | theora 53 | SceMotion_stub 54 | SceCommonDialog_stub 55 | SceHid_stub 56 | SceGxm_stub 57 | SceAudio_stub 58 | ScePower_stub 59 | SceDisplayUser_stub 60 | SceDisplay_stub 61 | SceCtrl_stub 62 | SceTouch_stub 63 | SceIofilemgr_stub 64 | SceSsl_stub 65 | SceSysmodule_stub 66 | pthread 67 | ${SDL2_LIBRARIES} 68 | gcc 69 | g 70 | m 71 | ) 72 | 73 | dolce_create_self("${SELF}" 74 | "${ELF}" 75 | ) 76 | 77 | # Build VPK 78 | 79 | set(VPK "Sonic1.vpk") 80 | set(TITLE_NAME "Sonic 1") 81 | set(TITLE_ID "SONIC0001") 82 | set(TITLE_VER "01.10") 83 | 84 | dolce_create_vpk("${VPK}" "${TITLE_ID}" "${SELF}" 85 | NAME "${TITLE_NAME}" 86 | VERSION "${TITLE_VER}" 87 | FILE sonic1_livearea sce_sys 88 | ) 89 | 90 | # Build self 91 | 92 | set(ELF2 "sonic2.elf") 93 | set(SELF2 "sonic2.self") 94 | 95 | file(GLOB_RECURSE sonic_SRC2 96 | Sonic12Decomp/*.cpp 97 | ) 98 | 99 | add_executable("${ELF2}" 100 | ${sonic_SRC2} 101 | ) 102 | 103 | target_compile_definitions("${ELF2}" PUBLIC -DBASE_PATH="ux0:data/Sonic2/") 104 | 105 | target_link_libraries("${ELF2}" 106 | SDL2 107 | SDL2_image 108 | pib 109 | vorbisfile 110 | vorbis 111 | ogg 112 | mpg123 113 | FLAC 114 | mikmod 115 | opus 116 | freetype 117 | jpeg 118 | png 119 | theora 120 | SceMotion_stub 121 | SceCommonDialog_stub 122 | SceHid_stub 123 | SceGxm_stub 124 | SceAudio_stub 125 | ScePower_stub 126 | SceDisplayUser_stub 127 | SceDisplay_stub 128 | SceCtrl_stub 129 | SceTouch_stub 130 | SceIofilemgr_stub 131 | SceSsl_stub 132 | SceSysmodule_stub 133 | pthread 134 | ${SDL2_LIBRARIES} 135 | gcc 136 | g 137 | m 138 | ) 139 | 140 | dolce_create_self("${SELF2}" 141 | "${ELF2}" 142 | ) 143 | 144 | # Build VPK 145 | 146 | set(VPK2 "Sonic2.vpk") 147 | set(TITLE_NAME2 "Sonic 2") 148 | set(TITLE_ID2 "SONIC0002") 149 | set(TITLE_VER2 "01.10") 150 | 151 | dolce_create_vpk("${VPK2}" "${TITLE_ID2}" "${SELF2}" 152 | NAME "${TITLE_NAME2}" 153 | VERSION "${TITLE_VER2}" 154 | FILE sonic2_livearea sce_sys 155 | ) -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS_ALL = $(shell pkg-config --cflags sdl2 vorbisfile vorbis) $(CXXFLAGS) 2 | LDFLAGS_ALL = $(LDFLAGS) 3 | LIBS_ALL = $(shell pkg-config --libs sdl2 vorbisfile vorbis) -pthread $(LIBS) 4 | 5 | SOURCES = Sonic12Decomp/Animation.cpp \ 6 | Sonic12Decomp/Audio.cpp \ 7 | Sonic12Decomp/Collision.cpp \ 8 | Sonic12Decomp/Debug.cpp \ 9 | Sonic12Decomp/Drawing.cpp \ 10 | Sonic12Decomp/Ini.cpp \ 11 | Sonic12Decomp/Input.cpp \ 12 | Sonic12Decomp/main.cpp \ 13 | Sonic12Decomp/Math.cpp \ 14 | Sonic12Decomp/Network.cpp \ 15 | Sonic12Decomp/Object.cpp \ 16 | Sonic12Decomp/Palette.cpp \ 17 | Sonic12Decomp/PauseMenu.cpp \ 18 | Sonic12Decomp/Reader.cpp \ 19 | Sonic12Decomp/RetroEngine.cpp \ 20 | Sonic12Decomp/RetroGameLoop.cpp \ 21 | Sonic12Decomp/Scene.cpp \ 22 | Sonic12Decomp/Scene3D.cpp \ 23 | Sonic12Decomp/Script.cpp \ 24 | Sonic12Decomp/Sprite.cpp \ 25 | Sonic12Decomp/String.cpp \ 26 | Sonic12Decomp/Text.cpp \ 27 | Sonic12Decomp/Userdata.cpp \ 28 | 29 | objects/%.o: % 30 | mkdir -p $(@D) 31 | $(CXX) $(CXXFLAGS_ALL) $^ -o $@ -c 32 | 33 | bin/sonic2013: $(SOURCES:%=objects/%.o) 34 | mkdir -p $(@D) 35 | $(CXX) $(CXXFLAGS_ALL) $(LDFLAGS_ALL) $^ -o $@ $(LIBS_ALL) 36 | 37 | install: sonic2013 38 | install -Dp -m755 bin/sonic2013 $(prefix)/bin/sonic2013 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Livearea Assets for Vita Port made by [Danhanado](https://twitter.com/DanMcL1) 2 | 3 | 4 | # Sonic 1/2 2013 Decompilation 5 | A Full Decompilation of Sonic 1 & 2 (2013) 6 | 7 | # **SUPPORT THE OFFICIAL RELEASE OF SONIC 1 & SONIC 2** 8 | + Without assets from the official releases this decompilation will not run. 9 | 10 | + You can get the official release of sonic 1 & sonic 2 from: 11 | * [Sonic 1 (iOS, Via the App Store)](https://apps.apple.com/au/app/sonic-the-hedgehog-classic/id316050001) 12 | * [Sonic 2 (iOS, Via the App Store)](https://apps.apple.com/au/app/sonic-the-hedgehog-2-classic/id347415188) 13 | * [Sonic 1 (Android, Via Google Play)](https://play.google.com/store/apps/details?id=com.sega.sonic1px&hl=en_AU&gl=US) 14 | * [Sonic 2 (Android, Via Google Play)](https://play.google.com/store/apps/details?id=com.sega.sonic2.runner&hl=en_AU&gl=US) 15 | * [Sonic 1 (Android, Via Amazon)](https://www.amazon.com.au/Sega-of-America-Sonic-Hedgehog/dp/B00D74DVKM) 16 | * [Sonic 2 (Android, Via Amazon)](https://www.amazon.com.au/Sega-of-America-Sonic-Hedgehog/dp/B00HAPRVWS) 17 | 18 | even if your platform isn't supported by the official releases, buy it for the assets (you dont need to run the official release, you just need the game assets) 19 | 20 | # Additional Tweaks 21 | * added a built in script compiler, similar to CD, but tweaked up to match the new syntax for the scripts used in RSDKv4 22 | * There is now a settings.ini file that the game uses to load all settings, similar to Sonic Mania 23 | * Dev menu can now be accessed from anywhere by pressing the `ESC` key if enabled in the config 24 | * The `f12` pause, `f11` step over & fast forward debug features from sonic mania have all be ported and are enabled if devMenu is enabled in the config 25 | * If `devMenu` is enabled in the config, pressing `f10` will activate a palette overlay that shows the game's 8 internal palettes in real time 26 | 27 | # TODOs: 28 | * the "native object" system has been implimented, but the objects (aside from RetroGameLoop and a temporary pause menu) and the proper HW rendering system have yet to be added 29 | * probably some more bug fixes, because there always are a few stragglers 30 | * create a `cmakelists.txt` file for windows compiling so builds can be added automatically via git actions 31 | * S2 networking code, we attempted to write code to handle the 2PVS mode in S2 but we couldn't finish for many reasons, we did leave our WIP code in the game, so if you think you could do it by all means give it a shot! 32 | 33 | # How to build: 34 | ## Windows: 35 | * Clone the repo, then follow the instructions in the [depencencies readme for windows](./dependencies/windows/dependencies.txt) to setup dependencies, then build via the visual studio solution 36 | * or grab a prebuilt executable from the releases section 37 | 38 | ## Mac: 39 | * Clone the repo, then follow the instructions in the [depencencies readme for mac](./dependencies/mac/dependencies.txt) to setup dependencies, then build via the xcode project 40 | * note: a proper mac release is being worked on, and hopefully will be released soon 41 | 42 | ## Other platforms: 43 | Currently the only supported platforms are the ones listed above, however the backend uses libogg, libvorbis & SDL2 to power it, so the codebase is very multiplatform. 44 | if you've cloned this repo and ported it to a platform not on the list or made some changes you'd like to see added to this repo, submit a pull request and it'll most likely be added 45 | 46 | # FAQ 47 | ### Q: The screen is tearing, how do I fix it? 48 | A: Try turning on vsync, that worked for me (tested on mac) 49 | 50 | ### Q: I found a bug/I have a feature request! 51 | A: Submit an issue in the issues tab and I'll fix/add (if possible) it as soon as I can 52 | 53 | ### Q: Will you do a decompilation for Sonic CD (2011)? 54 | A: I already have! you can find it [here](https://github.com/Rubberduckycooly/Sonic-CD-11-Decompilation)! 55 | 56 | ### Q: Will you do a decompilation for Sonic Mania? 57 | A: No. Sonic Mania is a ton bigger and requires that I'd decompile not only how the (far more complex) RSDKv5 works, but also all _600_+ objects work 58 | 59 | # Special Thanks 60 | * [RMGRich](https://github.com/MGRich): for helping me fix bugs, tweaking up my sometimes sloppy code and generally being really helpful and fun to work with on this project 61 | * Everyone in the [Retro Engine Modding Server](https://dc.railgun.works/retroengine): for being supportive of me and for giving me a place to show off these things that I've found 62 | 63 | # Background: 64 | in 2018 I started researching Christan Whitehead's 'Retro Engine' as a side project since I was bored, I started with Sonic CD (RSDKv3) since it was the most well known version that hadn't had much support, since at that time Sonic Mania's (RSDKv5) modding scene was already thriving, and eventually I expanded my range to Retro-Sonic (Retro-Sonic Engine), Sonic Nexus (RSDKv1) & Sonic 1/2 (RSDKv4), since then I have worked during spare moments to document and reverse all that I can of all versions of RSDK as it was just interesting to see how things worked under the hood or how features evolved and changed over time. Fast forward to 2020 and [Sappharad](https://github.com/Sappharad) shows me his decompilation of Sonic CD based on the windows phone 7 port since they'd seen my other github repositories relating to RSDK reversing. After seeing their decompilation I had the idea to start my own Sonic CD decompilation based on the PC port, with improvements and tweaks android port, though I didn't have much time to get around to it, so the project was shelved until I had more time to work on it. in mid-december 2020, I remembered the sonic CD decompilation that I started and finally had the time to work on it more, so after around 2 weeks of on/off working the decompilation was finally in a solid working state, though I continued tweaking it for another few weeks just to iron out all the glitches and bugs that I found. in early january 2021 it was released to almost universal praise, and since I enjoyed working on that I decided I would try to make a decompilation of RSDKv4 (Sonic 1/Sonic 2), since the engine was similar enough to v3's that I could translate much of the core over from the v3 decompilation, which I was sucessfully able to do. a few days into working on the v4 decompilation I asked [RMGRich](https://github.com/MGRich) if they wanted to help work on this with me since there's a lot about v4 that hasn't been very documented that I'd have to figure out, they accepted and over the first half of january 2021 we got to work in finishing the decompilation 65 | 66 | # Contact: 67 | Here's some other platforms I'm more active on if more specific questions need to be asked or you just wanna check out other stuff I do 68 | - [Twitter](https://twitter.com/Rubberduckcooly) 69 | - Discord: Rubberduckycooly#6438 70 | -------------------------------------------------------------------------------- /RSDKv4.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RSDKv4.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /RSDKv4.xcodeproj/project.xcworkspace/xcuserdata/rubberduckycooly.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildLocationStyle 6 | CustomLocation 7 | CustomBuildIntermediatesPath 8 | build/mac/intermediates.noindex 9 | CustomBuildLocationType 10 | RelativeToWorkspace 11 | CustomBuildProductsPath 12 | build/mac/ 13 | DerivedDataLocationStyle 14 | Default 15 | IssueFilterStyle 16 | ShowActiveSchemeOnly 17 | LiveSourceIssuesEnabled 18 | 19 | ShowSharedSchemesAutomaticallyEnabled 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /RSDKv4.xcodeproj/xcshareddata/xcschemes/RSDKv4.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 66 | 68 | 74 | 75 | 76 | 77 | 79 | 80 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /Sonic12Decomp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29806.167 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sonic12Decomp", "Sonic12Decomp\Sonic12Decomp.vcxproj", "{BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Debug|x64.ActiveCfg = Debug|x64 17 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Debug|x64.Build.0 = Debug|x64 18 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Debug|x86.Build.0 = Debug|Win32 20 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Release|x64.ActiveCfg = Release|x64 21 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Release|x64.Build.0 = Release|x64 22 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Release|x86.ActiveCfg = Release|Win32 23 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {CEEC6B21-D41E-4C5C-8B97-9FAAD7974615} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Sonic12Decomp/Animation.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | AnimationFile animationFileList[ANIFILE_COUNT]; 4 | int animationFileCount = 0; 5 | 6 | SpriteFrame scriptFrames[SPRITEFRAME_COUNT]; 7 | int scriptFrameCount = 0; 8 | 9 | SpriteFrame animFrames[SPRITEFRAME_COUNT]; 10 | int animFrameCount = 0; 11 | SpriteAnimation animationList[ANIMATION_COUNT]; 12 | int animationCount = 0; 13 | Hitbox hitboxList[HITBOX_COUNT]; 14 | int hitboxCount = 0; 15 | 16 | void LoadAnimationFile(char *filePath) 17 | { 18 | FileInfo info; 19 | if (LoadFile(filePath, &info)) { 20 | int fileBuffer = 0; 21 | char strBuf[0x21]; 22 | byte sheetIDs[0x18]; 23 | sheetIDs[0] = 0; 24 | 25 | int sheetCount = 0; 26 | FileRead(&sheetCount, 1); // Sheet Count 27 | 28 | for (int s = 0; s < sheetCount; ++s) { 29 | FileRead(&fileBuffer, 1); 30 | if (fileBuffer) { 31 | int i = 0; 32 | for (; i < fileBuffer; ++i) FileRead(&strBuf[i], 1); 33 | strBuf[i] = 0; 34 | GetFileInfo(&info); 35 | CloseFile(); 36 | sheetIDs[s] = AddGraphicsFile(strBuf); 37 | SetFileInfo(&info); 38 | } 39 | } 40 | 41 | int animCount = 0; 42 | FileRead(&animCount, 1); 43 | AnimationFile *animFile = &animationFileList[animationFileCount]; 44 | animFile->animCount = animCount; 45 | animFile->aniListOffset = animationCount; 46 | 47 | for (int a = 0; a < animCount; ++a) { 48 | SpriteAnimation *anim = &animationList[animationCount++]; 49 | anim->frameListOffset = animFrameCount; 50 | FileRead(&fileBuffer, 1); 51 | FileRead(anim->name, fileBuffer); 52 | anim->name[fileBuffer] = 0; 53 | FileRead(&anim->frameCount, 1); 54 | FileRead(&anim->speed, 1); 55 | FileRead(&anim->loopPoint, 1); 56 | FileRead(&anim->rotationFlag, 1); 57 | 58 | for (int j = 0; j < anim->frameCount; ++j) { 59 | SpriteFrame *frame = &animFrames[animFrameCount++]; 60 | FileRead(&frame->sheetID, 1); 61 | frame->sheetID = sheetIDs[frame->sheetID]; 62 | FileRead(&frame->hitboxID, 1); 63 | FileRead(&frame->sprX, 1); 64 | FileRead(&frame->sprY, 1); 65 | FileRead(&frame->width, 1); 66 | FileRead(&frame->height, 1); 67 | 68 | sbyte buffer = 0; 69 | FileRead(&buffer, 1); 70 | frame->pivotX = buffer; 71 | FileRead(&buffer, 1); 72 | frame->pivotY = buffer; 73 | } 74 | // 90 Degree (Extra rotation Frames) rotation 75 | if (anim->rotationFlag == ROTFLAG_STATICFRAMES) 76 | anim->frameCount >>= 1; 77 | } 78 | 79 | animFile->hitboxListOffset = hitboxCount; 80 | FileRead(&fileBuffer, 1); 81 | for (int i = 0; i < fileBuffer; ++i) { 82 | Hitbox *hitbox = &hitboxList[hitboxCount++]; 83 | for (int d = 0; d < HITBOX_DIR_COUNT; ++d) { 84 | FileRead(&hitbox->left[d], 1); 85 | FileRead(&hitbox->top[d], 1); 86 | FileRead(&hitbox->right[d], 1); 87 | FileRead(&hitbox->bottom[d], 1); 88 | } 89 | } 90 | 91 | CloseFile(); 92 | } 93 | } 94 | void ClearAnimationData() 95 | { 96 | for (int f = 0; f < SPRITEFRAME_COUNT; ++f) MEM_ZERO(scriptFrames[f]); 97 | for (int f = 0; f < SPRITEFRAME_COUNT; ++f) MEM_ZERO(animFrames[f]); 98 | for (int h = 0; h < HITBOX_COUNT; ++h) MEM_ZERO(hitboxList[h]); 99 | for (int a = 0; a < ANIMATION_COUNT; ++a) MEM_ZERO(animationList[a]); 100 | for (int a = 0; a < ANIFILE_COUNT; ++a) MEM_ZERO(animationFileList[a]); 101 | 102 | scriptFrameCount = 0; 103 | animFrameCount = 0; 104 | animationCount = 0; 105 | animationFileCount = 0; 106 | hitboxCount = 0; 107 | 108 | //Used for pause menu 109 | LoadGIFFile("Data/Game/SystemText.gif", SURFACE_MAX - 1); 110 | StrCopy(gfxSurface[SURFACE_MAX - 1].fileName, "Data/Game/SystemText.gif"); 111 | } 112 | 113 | AnimationFile *AddAnimationFile(char *filePath) 114 | { 115 | char path[0x80]; 116 | StrCopy(path, "Data/Animations/"); 117 | StrAdd(path, filePath); 118 | 119 | for (int a = 0; a < 0x100; ++a) { 120 | if (StrLength(animationFileList[a].fileName) <= 0) { 121 | StrCopy(animationFileList[a].fileName, filePath); 122 | LoadAnimationFile(path); 123 | ++animationFileCount; 124 | return &animationFileList[a]; 125 | } 126 | if (StrComp(animationFileList[a].fileName, filePath)) 127 | return &animationFileList[a]; 128 | } 129 | return NULL; 130 | } 131 | 132 | void ProcessObjectAnimation(void *objScr, void *ent) 133 | { 134 | ObjectScript *objectScript = (ObjectScript *)objScr; 135 | Entity *entity = (Entity *)ent; 136 | SpriteAnimation *sprAnim = &animationList[objectScript->animFile->aniListOffset + entity->animation]; 137 | 138 | if (entity->animationSpeed <= 0) { 139 | entity->animationTimer += sprAnim->speed; 140 | } 141 | else { 142 | if (entity->animationSpeed > 0xF0) 143 | entity->animationSpeed = 0xF0; 144 | entity->animationTimer += entity->animationSpeed; 145 | } 146 | if (entity->animation != entity->prevAnimation) { 147 | entity->prevAnimation = entity->animation; 148 | entity->frame = 0; 149 | entity->animationTimer = 0; 150 | entity->animationSpeed = 0; 151 | } 152 | if (entity->animationTimer > 0xEF) { 153 | entity->animationTimer -= 0xF0; 154 | ++entity->frame; 155 | } 156 | 157 | if (entity->frame >= sprAnim->frameCount) 158 | entity->frame = sprAnim->loopPoint; 159 | } -------------------------------------------------------------------------------- /Sonic12Decomp/Animation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ANIMATION_H 2 | #define ANIMATION_H 3 | 4 | #define ANIFILE_COUNT (0x100) 5 | #define ANIMATION_COUNT (0x400) 6 | #define SPRITEFRAME_COUNT (0x1000) 7 | 8 | #define HITBOX_COUNT (0x20) 9 | #define HITBOX_DIR_COUNT (0x8) 10 | 11 | enum AnimrotationFlags { ROTFLAG_NONE, ROTFLAG_FULL, ROTFLAG_45DEG, ROTFLAG_STATICFRAMES }; 12 | 13 | struct AnimationFile 14 | { 15 | char fileName[0x20]; 16 | int animCount; 17 | int aniListOffset; 18 | int hitboxListOffset; 19 | }; 20 | 21 | struct SpriteAnimation { 22 | char name[16]; 23 | byte frameCount; 24 | byte speed; 25 | byte loopPoint; 26 | byte rotationFlag; 27 | int frameListOffset; 28 | }; 29 | 30 | struct SpriteFrame { 31 | int sprX; 32 | int sprY; 33 | int width; 34 | int height; 35 | int pivotX; 36 | int pivotY; 37 | byte sheetID; 38 | byte hitboxID; 39 | }; 40 | 41 | struct Hitbox { 42 | sbyte left[HITBOX_DIR_COUNT]; 43 | sbyte top[HITBOX_DIR_COUNT]; 44 | sbyte right[HITBOX_DIR_COUNT]; 45 | sbyte bottom[HITBOX_DIR_COUNT]; 46 | }; 47 | 48 | extern AnimationFile animationFileList[ANIFILE_COUNT]; 49 | extern int animationFileCount; 50 | 51 | extern SpriteFrame scriptFrames[SPRITEFRAME_COUNT]; 52 | extern int scriptFrameCount; 53 | 54 | extern SpriteFrame animFrames[SPRITEFRAME_COUNT]; 55 | extern int animFrameCount; 56 | extern SpriteAnimation animationList[ANIMATION_COUNT]; 57 | extern int animationCount; 58 | extern Hitbox hitboxList[HITBOX_COUNT]; 59 | extern int hitboxCount; 60 | 61 | void LoadAnimationFile(char *FilePath); 62 | void ClearAnimationData(); 63 | 64 | AnimationFile *AddAnimationFile(char *FilePath); 65 | 66 | inline AnimationFile *GetDefaultAnimationRef() { return &animationFileList[0]; } 67 | 68 | void ProcessObjectAnimation(void *objScr, void *ent); 69 | 70 | #endif // !ANIMATION_H 71 | -------------------------------------------------------------------------------- /Sonic12Decomp/Audio.hpp: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_H 2 | #define AUDIO_H 3 | 4 | #define TRACK_COUNT (0x10) 5 | #define SFX_COUNT (0x100) 6 | #define CHANNEL_COUNT (0x10) //4 in the original, 16 for convenience 7 | 8 | #define MAX_VOLUME (100) 9 | 10 | struct TrackInfo { 11 | char fileName[0x40]; 12 | bool trackLoop; 13 | uint loopPoint; 14 | }; 15 | 16 | struct MusicPlaybackInfo { 17 | #if RETRO_USING_SDL 18 | OggVorbis_File vorbisFile; 19 | int vorbBitstream; 20 | SDL_AudioStream *stream; 21 | Sint16 *buffer; 22 | #endif 23 | FileInfo fileInfo; 24 | bool trackLoop; 25 | uint loopPoint; 26 | bool loaded; 27 | }; 28 | 29 | struct SFXInfo { 30 | char name[0x40]; 31 | Sint16 *buffer; 32 | size_t length; 33 | bool loaded; 34 | }; 35 | 36 | struct ChannelInfo { 37 | size_t sampleLength; 38 | Sint16 *samplePtr; 39 | int sfxID; 40 | byte loopSFX; 41 | sbyte pan; 42 | }; 43 | 44 | enum MusicStatuses { 45 | MUSIC_STOPPED = 0, 46 | MUSIC_PLAYING = 1, 47 | MUSIC_PAUSED = 2, 48 | MUSIC_LOADING = 3, 49 | MUSIC_READY = 4, 50 | }; 51 | 52 | extern int globalSFXCount; 53 | extern int stageSFXCount; 54 | 55 | extern int masterVolume; 56 | extern int trackID; 57 | extern int sfxVolume; 58 | extern int bgmVolume; 59 | extern bool audioEnabled; 60 | 61 | extern bool musicEnabled; 62 | extern int musicStatus; 63 | extern int musicStartPos; 64 | extern int musicRatio; 65 | extern TrackInfo musicTracks[TRACK_COUNT]; 66 | 67 | extern SFXInfo sfxList[SFX_COUNT]; 68 | extern char sfxNames[SFX_COUNT][0x40]; 69 | 70 | extern ChannelInfo sfxChannels[CHANNEL_COUNT]; 71 | 72 | extern MusicPlaybackInfo musInfo; 73 | 74 | #if RETRO_USING_SDL 75 | extern SDL_AudioSpec audioDeviceFormat; 76 | #endif 77 | 78 | int InitAudioPlayback(); 79 | 80 | #if RETRO_USING_SDL 81 | void ProcessMusicStream(Sint32 *stream, size_t bytes_wanted); 82 | void ProcessAudioPlayback(void *data, Uint8 *stream, int len); 83 | void ProcessAudioMixing(Sint32 *dst, const Sint16 *src, int len, int volume, sbyte pan); 84 | 85 | 86 | inline void freeMusInfo() 87 | { 88 | if (musInfo.loaded) { 89 | SDL_LockAudio(); 90 | 91 | if (musInfo.buffer) 92 | delete[] musInfo.buffer; 93 | if (musInfo.stream) 94 | SDL_FreeAudioStream(musInfo.stream); 95 | ov_clear(&musInfo.vorbisFile); 96 | musInfo.buffer = nullptr; 97 | musInfo.stream = nullptr; 98 | musInfo.trackLoop = false; 99 | musInfo.loopPoint = 0; 100 | musInfo.loaded = false; 101 | 102 | SDL_UnlockAudio(); 103 | } 104 | } 105 | #else 106 | void ProcessMusicStream() {} 107 | void ProcessAudioPlayback() {} 108 | void ProcessAudioMixing() {} 109 | 110 | inline void freeMusInfo() 111 | { 112 | if (musInfo.loaded) { 113 | if (musInfo.musicFile) 114 | delete[] musInfo.musicFile; 115 | musInfo.musicFile = nullptr; 116 | musInfo.buffer = nullptr; 117 | musInfo.stream = nullptr; 118 | musInfo.pos = 0; 119 | musInfo.len = 0; 120 | musInfo.currentTrack = nullptr; 121 | musInfo.loaded = false; 122 | } 123 | } 124 | #endif 125 | 126 | void SetMusicTrack(const char *filePath, byte trackID, bool loop, uint loopPoint); 127 | void SwapMusicTrack(const char *filePath, byte trackID, uint loopPoint, uint ratio); 128 | bool PlayMusic(int track, int musStartPos); 129 | inline void StopMusic() 130 | { 131 | musicStatus = MUSIC_STOPPED; 132 | SDL_LockAudio(); 133 | freeMusInfo(); 134 | SDL_UnlockAudio(); 135 | } 136 | 137 | void LoadSfx(char *filePath, byte sfxID); 138 | void PlaySfx(int sfx, bool loop); 139 | inline void StopSfx(int sfx) 140 | { 141 | for (int i = 0; i < CHANNEL_COUNT; ++i) { 142 | if (sfxChannels[i].sfxID == sfx) { 143 | MEM_ZERO(sfxChannels[i]); 144 | sfxChannels[i].sfxID = -1; 145 | } 146 | } 147 | } 148 | void SetSfxAttributes(int sfx, int loopCount, sbyte pan); 149 | 150 | #if !RSDK_DEBUG 151 | inline void SetSfxName(const char* sfxName, int sfxID) { 152 | int sfxNameID = 0; 153 | int soundNameID = 0; 154 | while (sfxName[sfxNameID]) { 155 | if (sfxName[sfxNameID] != ' ') 156 | sfxNames[sfxID][soundNameID++] = sfxName[sfxNameID]; 157 | ++sfxNameID; 158 | } 159 | sfxNames[sfxID][soundNameID] = 0; 160 | } 161 | #else 162 | void SetSfxName(const char *sfxName, int sfxID); 163 | #endif 164 | 165 | //Helper Func 166 | inline bool PlaySFXByName(const char* sfx, sbyte loopCnt) { 167 | for (int s = 0; s < globalSFXCount + stageSFXCount; ++s) { 168 | if (StrComp(sfxNames[s], sfx)) { 169 | PlaySfx(s, loopCnt); 170 | return true; 171 | } 172 | } 173 | return false; 174 | } 175 | 176 | inline void SetMusicVolume(int volume) 177 | { 178 | if (volume < 0) 179 | volume = 0; 180 | if (volume > MAX_VOLUME) 181 | volume = MAX_VOLUME; 182 | masterVolume = volume; 183 | } 184 | 185 | inline void SetGameVolumes(int bgmVolume, int sfxVolume) { 186 | //musicVolumeSetting = bgmVolume; 187 | SetMusicVolume(masterVolume); 188 | //sfxVolumeSetting = ((sfxVolume << 7) / 100); 189 | } 190 | 191 | inline void PauseSound() 192 | { 193 | if (musicStatus == MUSIC_PLAYING) 194 | musicStatus = MUSIC_PAUSED; 195 | } 196 | 197 | inline void ResumeSound() 198 | { 199 | if (musicStatus == MUSIC_PAUSED) 200 | musicStatus = MUSIC_PLAYING; 201 | } 202 | 203 | 204 | inline void StopAllSfx() 205 | { 206 | #if RETRO_USING_SDL 207 | SDL_LockAudio(); 208 | #endif 209 | for (int i = 0; i < CHANNEL_COUNT; ++i) sfxChannels[i].sfxID = -1; 210 | #if RETRO_USING_SDL 211 | SDL_UnlockAudio(); 212 | #endif 213 | } 214 | inline void ReleaseGlobalSfx() 215 | { 216 | for (int i = globalSFXCount; i >= 0; --i) { 217 | if (sfxList[i].loaded) { 218 | StrCopy(sfxList[i].name, ""); 219 | StrCopy(sfxNames[i], ""); 220 | free(sfxList[i].buffer); 221 | sfxList[i].length = 0; 222 | sfxList[i].loaded = false; 223 | } 224 | } 225 | globalSFXCount = 0; 226 | } 227 | inline void ReleaseStageSfx() 228 | { 229 | for (int i = stageSFXCount + globalSFXCount; i >= globalSFXCount; --i) { 230 | if (sfxList[i].loaded) { 231 | StrCopy(sfxList[i].name, ""); 232 | StrCopy(sfxNames[i], ""); 233 | free(sfxList[i].buffer); 234 | sfxList[i].length = 0; 235 | sfxList[i].loaded = false; 236 | } 237 | } 238 | stageSFXCount = 0; 239 | } 240 | 241 | inline void ReleaseAudioDevice() 242 | { 243 | StopMusic(); 244 | StopAllSfx(); 245 | ReleaseStageSfx(); 246 | ReleaseGlobalSfx(); 247 | } 248 | 249 | #endif // !AUDIO_H 250 | -------------------------------------------------------------------------------- /Sonic12Decomp/Collision.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COLLISION_H 2 | #define COLLISION_H 3 | 4 | enum CollisionSidess { 5 | CSIDE_FLOOR = 0, 6 | CSIDE_LWALL = 1, 7 | CSIDE_RWALL = 2, 8 | CSIDE_ROOF = 3, 9 | }; 10 | 11 | enum CollisionModes { 12 | CMODE_FLOOR = 0, 13 | CMODE_LWALL = 1, 14 | CMODE_ROOF = 2, 15 | CMODE_RWALL = 3, 16 | }; 17 | 18 | enum CollisionSolidity { 19 | SOLID_ALL = 0, 20 | SOLID_TOP = 1, 21 | SOLID_LRB = 2, 22 | SOLID_NONE = 3, 23 | SOLID_TOP_NOGRIP = 4, 24 | }; 25 | 26 | enum ObjectCollisionTypes { 27 | C_TOUCH = 0, 28 | C_BOX = 1, 29 | C_BOX2 = 2, 30 | C_PLATFORM = 3, 31 | }; 32 | 33 | struct CollisionSensor 34 | { 35 | int XPos; 36 | int YPos; 37 | int angle; 38 | bool collided; 39 | }; 40 | 41 | extern int collisionLeft; 42 | extern int collisionTop; 43 | extern int collisionRight; 44 | extern int collisionBottom; 45 | 46 | extern int collisionTolerance; 47 | 48 | extern CollisionSensor sensors[7]; 49 | 50 | void FindFloorPosition(Entity *player, CollisionSensor *sensor, int startYPos); 51 | void FindLWallPosition(Entity *player, CollisionSensor *sensor, int startXPos); 52 | void FindRoofPosition(Entity *player, CollisionSensor *sensor, int startYPos); 53 | void FindRWallPosition(Entity *player, CollisionSensor *sensor, int startXPos); 54 | void FloorCollision(Entity *player, CollisionSensor *sensor); 55 | void LWallCollision(Entity *player, CollisionSensor *sensor); 56 | void RoofCollision(Entity *player, CollisionSensor *sensor); 57 | void RWallCollision(Entity *player, CollisionSensor *sensor); 58 | void SetPathGripSensors(Entity *player); 59 | 60 | void ProcessPathGrip(Entity *player); 61 | void ProcessAirCollision(Entity *player); 62 | 63 | void ProcessPlayerTileCollisions(Entity *player); 64 | 65 | void TouchCollision(Entity *thisEntity, int thisLeft, int thisTop, int thisRight, int thisBottom, Entity *otherEntity, int otherLeft, int otherTop, 66 | int otherRight, int otherBottom); 67 | void BoxCollision(Entity *thisEntity, int thisLeft, int thisTop, int thisRight, int thisBottom, Entity *otherEntity, int otherLeft, int otherTop, 68 | int otherRight, int otherBottom); // Standard 69 | void BoxCollision2(Entity *thisEntity, int thisLeft, int thisTop, int thisRight, int thisBottom, Entity *otherEntity, int otherLeft, int otherTop, 70 | int otherRight, int otherBottom); // Updated (?) 71 | void PlatformCollision(Entity *thisEntity, int thisLeft, int thisTop, int thisRight, int thisBottom, Entity *otherEntity, int otherLeft, int otherTop, 72 | int otherRight, int otherBottom); 73 | 74 | void ObjectFloorCollision(int xOffset, int yOffset, int cPath); 75 | void ObjectLWallCollision(int xOffset, int yOffset, int cPath); 76 | void ObjectRoofCollision(int xOffset, int yOffset, int cPath); 77 | void ObjectRWallCollision(int xOffset, int yOffset, int cPath); 78 | 79 | void ObjectFloorGrip(int xOffset, int yOffset, int cPath); 80 | void ObjectLWallGrip(int xOffset, int yOffset, int cPath); 81 | void ObjectRoofGrip(int xOffset, int yOffset, int cPath); 82 | void ObjectRWallGrip(int xOffset, int yOffset, int cPath); 83 | 84 | #endif // !COLLISION_H 85 | -------------------------------------------------------------------------------- /Sonic12Decomp/Debug.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H 2 | #define DEBUG_H 3 | 4 | #if RSDK_DEBUG 5 | extern bool endLine; 6 | inline void printLog(const char *msg, ...) 7 | { 8 | char buffer[0x100]; 9 | 10 | // make the full string 11 | va_list args; 12 | va_start(args, msg); 13 | vsprintf(buffer, msg, args); 14 | if (endLine) { 15 | printf("%s\n", buffer); 16 | sprintf(buffer, "%s\n", buffer); 17 | } 18 | else { 19 | printf("%s", buffer); 20 | sprintf(buffer, "%s", buffer); 21 | } 22 | 23 | char pathBuffer[0x100]; 24 | #if RETRO_PLATFORM == RETRO_OSX 25 | if (!usingCWD) 26 | sprintf(pathBuffer, "%s/log.txt", getResourcesPath()); 27 | else 28 | sprintf(pathBuffer, "log.txt"); 29 | #else 30 | sprintf(pathBuffer, BASE_PATH "log.txt"); 31 | #endif 32 | FileIO *file = fOpen(pathBuffer, "a"); 33 | if (file) { 34 | fWrite(&buffer, 1, StrLength(buffer), file); 35 | fClose(file); 36 | } 37 | } 38 | 39 | inline void printLog(const ushort *msg) 40 | { 41 | int mPos = 0; 42 | while (msg[mPos]) { 43 | printf("%lc", (wint_t)msg[mPos]); 44 | mPos++; 45 | } 46 | if (endLine) 47 | printf("\n"); 48 | 49 | char pathBuffer[0x100]; 50 | #if RETRO_PLATFORM == RETRO_OSX 51 | if (!usingCWD) 52 | sprintf(pathBuffer, "%s/log.txt", getResourcesPath()); 53 | else 54 | sprintf(pathBuffer, "log.txt"); 55 | #else 56 | sprintf(pathBuffer, BASE_PATH "log.txt"); 57 | #endif 58 | mPos = 0; 59 | FileIO *file = fOpen(pathBuffer, "a"); 60 | if (file) { 61 | while (msg[mPos]) { 62 | fWrite(&msg[mPos], 2, 1, file); 63 | mPos++; 64 | } 65 | 66 | ushort el = '\n'; 67 | if (endLine) 68 | fWrite(&el, 2, 1, file); 69 | fClose(file); 70 | } 71 | } 72 | 73 | #endif 74 | 75 | enum DevMenuMenus { 76 | DEVMENU_MAIN, 77 | DEVMENU_PLAYERSEL, 78 | DEVMENU_STAGELISTSEL, 79 | DEVMENU_STAGESEL, 80 | DEVMENU_SCRIPTERROR, 81 | }; 82 | 83 | enum StartMenuMenus { 84 | STARTMENU_MAIN = 5, 85 | STARTMENU_SAVESEL, 86 | STARTMENU_PLAYERSEL, 87 | STARTMENU_GAMEOPTS, 88 | STARTMENU_TASTAGESEL, 89 | STARTMENU_TACONFIRMSEL, 90 | STARTMENU_ACHIEVEMENTS, 91 | STARTMENU_LEADERBOARDS, 92 | }; 93 | 94 | void initDevMenu(); 95 | void initErrorMessage(); 96 | void processStageSelect(); 97 | 98 | // added due to lack of normal main menu 99 | void initStartMenu(int mode); 100 | void processStartMenu(); 101 | void setTextMenu(int mode); 102 | 103 | #endif //!DEBUG_H 104 | -------------------------------------------------------------------------------- /Sonic12Decomp/Drawing.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DRAWING_H 2 | #define DRAWING_H 3 | 4 | #define SPRITESHEETS_MAX (16) 5 | #define SURFACE_MAX (24) 6 | #define GFXDATA_MAX (0x200000) 7 | 8 | #define BLENDTABLE_YSIZE (0x100) 9 | #define BLENDTABLE_XSIZE (0x20) 10 | #define BLENDTABLE_SIZE (BLENDTABLE_XSIZE * BLENDTABLE_YSIZE) 11 | #define TINTTABLE_SIZE (0x1000) 12 | 13 | #define DRAWLAYER_COUNT (0x7) 14 | 15 | enum FlipFlags { FLIP_NONE, FLIP_X, FLIP_Y, FLIP_XY }; 16 | enum InkFlags { INK_NONE, INK_BLEND, INK_ALPHA, INK_ADD, INK_SUB }; 17 | enum DrawFXFlags { FX_SCALE, FX_ROTATE, FX_ROTOZOOM, FX_INK, FX_TINT, FX_FLIP }; 18 | 19 | struct DrawListEntry 20 | { 21 | int entityRefs[ENTITY_COUNT]; 22 | int listSize; 23 | }; 24 | 25 | struct GFXSurface 26 | { 27 | char fileName[0x40]; 28 | int height; 29 | int width; 30 | int widthShift; 31 | int depth; 32 | int dataPosition; 33 | }; 34 | 35 | extern short blendLookupTable[BLENDTABLE_SIZE]; 36 | extern short subtractLookupTable[BLENDTABLE_SIZE]; 37 | extern short tintLookupTable[TINTTABLE_SIZE]; 38 | 39 | extern int SCREEN_XSIZE; 40 | extern int SCREEN_CENTERX; 41 | 42 | extern DrawListEntry drawListEntries[DRAWLAYER_COUNT]; 43 | 44 | extern int gfxDataPosition; 45 | extern GFXSurface gfxSurface[SURFACE_MAX]; 46 | extern byte graphicData[GFXDATA_MAX]; 47 | 48 | int InitRenderDevice(); 49 | void RenderRenderDevice(); 50 | void ReleaseRenderDevice(); 51 | 52 | void GenerateBlendLookupTable(); 53 | 54 | inline void ClearGraphicsData() 55 | { 56 | for (int i = 0; i < SURFACE_MAX; ++i) StrCopy(gfxSurface[i].fileName, ""); 57 | gfxDataPosition = 0; 58 | } 59 | void ClearScreen(byte index); 60 | 61 | void SetScreenSize(int width, int height); 62 | 63 | // Layer Drawing 64 | void DrawObjectList(int layer); 65 | void DrawStageGFX(); 66 | 67 | // TileLayer Drawing 68 | void DrawHLineScrollLayer(int layerID); 69 | void DrawVLineScrollLayer(int layerID); 70 | void Draw3DFloorLayer(int layerID); 71 | void Draw3DSkyLayer(int layerID); 72 | 73 | // Shape Drawing 74 | void DrawRectangle(int XPos, int YPos, int width, int height, int R, int G, int B, int A); 75 | void SetFadeHQ(int R, int G, int B, int A); 76 | void DrawTintRectangle(int XPos, int YPos, int width, int height); 77 | void DrawScaledTintMask(int direction, int XPos, int YPos, int pivotX, int pivotY, int scaleX, 78 | int scaleY, int width, int height, int sprX, int sprY, int sheetID); 79 | 80 | // Sprite Drawing 81 | void DrawSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int sheetID); 82 | void DrawSpriteFlipped(int XPos, int YPos, int width, int height, int sprX, int sprY, int direction, 83 | int sheetID); 84 | void DrawSpriteScaled(int direction, int XPos, int YPos, int pivotX, int pivotY, int scaleX, int scaleY, 85 | int width, int height, int sprX, int sprY, int sheetID); 86 | void DrawSpriteRotated(int direction, int XPos, int YPos, int pivotX, int pivotY, int sprX, int sprY, 87 | int width, int height, int rotation, int sheetID); 88 | void DrawSpriteRotozoom(int direction, int XPos, int YPos, int pivotX, int pivotY, int sprX, int sprY, 89 | int width, int height, int rotation, int scale, int sheetID); 90 | 91 | void DrawBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int sheetID); 92 | void DrawAlphaBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int alpha, 93 | int sheetID); 94 | void DrawAdditiveBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int alpha, 95 | int sheetID); 96 | void DrawSubtractiveBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, 97 | int alpha, int sheetID); 98 | 99 | void DrawObjectAnimation(void *objScr, void *ent, int XPos, int YPos); 100 | 101 | void DrawFace(void *v, uint colour); 102 | void DrawFadedFace(void *v, uint colour, uint fogColour, int alpha); 103 | void DrawTexturedFace(void *v, byte sheetID); 104 | void DrawTexturedFace2(void *v, byte sheetID); 105 | 106 | void DrawBitmapText(void *menu, int XPos, int YPos, int scale, int spacing, int rowStart, int rowCount); 107 | 108 | void DrawTextMenu(void *menu, int XPos, int YPos); 109 | void DrawTextMenuEntry(void *menu, int rowID, int XPos, int YPos, int textHighlight); 110 | void DrawStageTextEntry(void *menu, int rowID, int XPos, int YPos, int textHighlight); 111 | void DrawBlendedTextMenuEntry(void *menu, int rowID, int XPos, int YPos, int textHighlight); 112 | 113 | #endif // !DRAWING_H 114 | -------------------------------------------------------------------------------- /Sonic12Decomp/Ini.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | IniParser::IniParser(const char *filename) 8 | { 9 | memset(items, 0, 0x80 * sizeof(ConfigItem)); 10 | char buf[0x100]; 11 | char section[0x40]; 12 | bool hasSection = false; 13 | char key[0x40]; 14 | char value[0x100]; 15 | 16 | count = 0; 17 | 18 | char pathBuffer[0x80]; 19 | 20 | #if RETRO_PLATFORM == RETRO_OSX 21 | if (!usingCWD) 22 | sprintf(pathBuffer, "%s/%s", getResourcesPath(), filename); 23 | else 24 | sprintf(pathBuffer, "%s", filename); 25 | #else 26 | sprintf(pathBuffer, "%s", filename); 27 | #endif 28 | 29 | FileIO *f; 30 | if ((f = fOpen(pathBuffer, "r")) == NULL) { 31 | #if RSDK_DEBUG 32 | printLog("ERROR: Couldn't open file '%s'!", filename); 33 | #endif 34 | return; 35 | } 36 | 37 | while (true) { 38 | bool flag = false; 39 | int ret = 0; 40 | int strLen = 0; 41 | while (true) { 42 | ret = (int)fRead(&buf[strLen++], sizeof(byte), 1, f); 43 | flag = ret == 0; 44 | if (ret == 0) 45 | break; 46 | if (buf[strLen - 1] == '\n') 47 | break; 48 | } 49 | buf[strLen] = 0; 50 | if (buf[0] == '#') 51 | continue; 52 | 53 | if (sscanf(buf, "[%[^][]]", section) == 1) { 54 | hasSection = true; 55 | } 56 | else if (sscanf(buf, "%[^ =]= %s", key, value) == 2 || sscanf(buf, "%[^ =]=%s", key, value) == 2 57 | || sscanf(buf, "%[^ =] = %s", key, value) == 2 || sscanf(buf, "%[^ =] =%s", key, value) == 2) { 58 | if (hasSection) 59 | sprintf(items[count].section, "%s", section); 60 | 61 | sprintf(items[count].key, "%s", key); 62 | sprintf(items[count].value, "%s", value); 63 | items[count].hasSection = hasSection; 64 | count++; 65 | } 66 | if (flag) 67 | break; 68 | } 69 | 70 | fClose(f); 71 | } 72 | 73 | int IniParser::GetString(const char *section, const char *key, char *dest) 74 | { 75 | if (count == 0) 76 | return 0; 77 | 78 | for (int x = 0; x < count; x++) { 79 | if (!strcmp(section, items[x].section)) { 80 | if (!strcmp(key, items[x].key)) { 81 | strcpy(dest, items[x].value); 82 | return 1; 83 | } 84 | } 85 | } 86 | 87 | return 0; 88 | } 89 | int IniParser::GetInteger(const char *section, const char *key, int *dest) 90 | { 91 | if (count == 0) 92 | return 0; 93 | 94 | for (int x = 0; x < count; x++) { 95 | if (!strcmp(section, items[x].section)) { 96 | if (!strcmp(key, items[x].key)) { 97 | *dest = atoi(items[x].value); 98 | return 1; 99 | } 100 | } 101 | } 102 | 103 | return 0; 104 | } 105 | int IniParser::GetFloat(const char *section, const char *key, float *dest) 106 | { 107 | if (count == 0) 108 | return 0; 109 | 110 | for (int x = 0; x < count; x++) { 111 | if (!strcmp(section, items[x].section)) { 112 | if (!strcmp(key, items[x].key)) { 113 | *dest = atof(items[x].value); 114 | return 1; 115 | } 116 | } 117 | } 118 | 119 | return 0.0f; 120 | } 121 | int IniParser::GetBool(const char *section, const char *key, bool *dest) 122 | { 123 | if (count == 0) 124 | return 0; 125 | 126 | for (int x = 0; x < count; x++) { 127 | if (!strcmp(section, items[x].section)) { 128 | if (!strcmp(key, items[x].key)) { 129 | *dest = !strcmp(items[x].value, "true") || !strcmp(items[x].value, "1"); 130 | return 1; 131 | } 132 | } 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | int IniParser::SetString(const char *section, const char *key, char *value) 139 | { 140 | int where = -1; 141 | for (int x = 0; x < count; x++) { 142 | if (strcmp(section, items[x].section) == 0) { 143 | if (strcmp(key, items[x].key) == 0) { 144 | where = x; 145 | break; 146 | } 147 | } 148 | } 149 | if (where < 0) 150 | where = count++; 151 | 152 | strcpy(items[where].section, section); 153 | strcpy(items[where].key, key); 154 | strcpy(items[where].value, value); 155 | items[where].type = INI_ITEM_STRING; 156 | return 1; 157 | } 158 | int IniParser::SetInteger(const char *section, const char *key, int value) 159 | { 160 | int where = -1; 161 | for (int x = 0; x < count; x++) { 162 | if (strcmp(section, items[x].section) == 0) { 163 | if (strcmp(key, items[x].key) == 0) { 164 | where = x; 165 | break; 166 | } 167 | } 168 | } 169 | if (where < 0) 170 | where = count++; 171 | 172 | strcpy(items[where].section, section); 173 | strcpy(items[where].key, key); 174 | sprintf(items[where].value, "%d", value); 175 | items[where].type = INI_ITEM_INT; 176 | return 1; 177 | } 178 | int IniParser::SetFloat(const char *section, const char *key, float value) 179 | { 180 | int where = -1; 181 | for (int x = 0; x < count; x++) { 182 | if (strcmp(section, items[x].section) == 0) { 183 | if (strcmp(key, items[x].key) == 0) { 184 | where = x; 185 | break; 186 | } 187 | } 188 | } 189 | if (where < 0) 190 | where = count++; 191 | 192 | strcpy(items[where].section, section); 193 | strcpy(items[where].key, key); 194 | sprintf(items[where].value, "%f", value); 195 | items[where].type = INI_ITEM_FLOAT; 196 | return 1; 197 | } 198 | int IniParser::SetBool(const char *section, const char *key, bool value) 199 | { 200 | int where = -1; 201 | for (int x = 0; x < count; x++) { 202 | if (strcmp(section, items[x].section) == 0) { 203 | if (strcmp(key, items[x].key) == 0) { 204 | where = x; 205 | break; 206 | } 207 | } 208 | } 209 | if (where < 0) 210 | where = count++; 211 | 212 | strcpy(items[where].section, section); 213 | strcpy(items[where].key, key); 214 | sprintf(items[where].value, "%s", value ? "true" : "false"); 215 | items[where].type = INI_ITEM_BOOL; 216 | return 1; 217 | } 218 | int IniParser::SetComment(const char *section, const char *key, const char *comment) 219 | { 220 | int where = -1; 221 | for (int x = 0; x < count; x++) { 222 | if (strcmp(section, items[x].section) == 0) { 223 | if (strcmp(key, items[x].key) == 0) { 224 | where = x; 225 | break; 226 | } 227 | } 228 | } 229 | if (where < 0) 230 | where = count++; 231 | 232 | strcpy(items[where].section, section); 233 | strcpy(items[where].key, key); 234 | sprintf(items[where].value, "%s", comment); 235 | items[where].type = INI_ITEM_COMMENT; 236 | return 1; 237 | } 238 | 239 | void IniParser::Write(const char *filename) 240 | { 241 | char pathBuffer[0x80]; 242 | 243 | #if RETRO_PLATFORM == RETRO_OSX 244 | if (!usingCWD) 245 | sprintf(pathBuffer, "%s/%s", getResourcesPath(), filename); 246 | else 247 | sprintf(pathBuffer, "%s", filename); 248 | #else 249 | sprintf(pathBuffer, "%s", filename); 250 | #endif 251 | 252 | FileIO *f; 253 | if ((f = fOpen(pathBuffer, "w")) == NULL) { 254 | #if RSDK_DEBUG 255 | printLog("ERROR: Couldn't open file '%s' for writing!", filename); 256 | #endif 257 | return; 258 | } 259 | 260 | char sections[10][60]; 261 | char past[60]; 262 | int c = 0; 263 | sprintf(past, ""); 264 | for (int i = 0; i < count; ++i) { 265 | if (std::find(std::begin(sections), std::end(sections), items[i].section) == std::end(sections) && strcmp(past, items[i].section) != 0) { 266 | sprintf(past, "%s", items[i].section); 267 | sprintf(sections[c], "%s", items[i].section); 268 | c++; 269 | } 270 | } 271 | 272 | if (c >= 1) { 273 | if (strcmp(sections[0], sections[c - 1]) == 0) 274 | c--; 275 | } 276 | 277 | char buffer[0x100]; 278 | for (int s = 0; s < c; ++s) { 279 | sprintf(buffer, "[%s]\n", sections[s]); 280 | fWrite(&buffer, 1, StrLength(buffer), f); 281 | for (int i = 0; i < count; ++i) { 282 | if (strcmp(sections[s], items[i].section) == 0) { 283 | switch (items[i].type) { 284 | default: 285 | case INI_ITEM_STRING: 286 | case INI_ITEM_INT: 287 | case INI_ITEM_FLOAT: 288 | case INI_ITEM_BOOL: 289 | sprintf(buffer, "%s=%s\n", items[i].key, items[i].value); 290 | fWrite(&buffer, 1, StrLength(buffer), f); 291 | break; 292 | case INI_ITEM_COMMENT: 293 | sprintf(buffer, "; %s\n", items[i].value); 294 | fWrite(&buffer, 1, StrLength(buffer), f); 295 | break; 296 | } 297 | } 298 | } 299 | 300 | if (s + 1 < c) { 301 | sprintf(buffer, "\n"); 302 | fWrite(&buffer, StrLength(buffer), 1, f); 303 | } 304 | } 305 | 306 | fClose(f); 307 | } 308 | -------------------------------------------------------------------------------- /Sonic12Decomp/Ini.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INI_H 2 | #define INI_H 3 | 4 | class IniParser 5 | { 6 | public: 7 | enum ItemType { 8 | INI_ITEM_STRING, 9 | INI_ITEM_INT, 10 | INI_ITEM_FLOAT, 11 | INI_ITEM_BOOL, 12 | INI_ITEM_COMMENT, 13 | }; 14 | 15 | struct ConfigItem { 16 | ConfigItem() 17 | { 18 | sprintf(section, ""); 19 | sprintf(key, ""); 20 | sprintf(value, ""); 21 | hasSection = false; 22 | type = INI_ITEM_STRING; 23 | } 24 | char section[0x20]; 25 | bool hasSection = false; 26 | char key[0x40]; 27 | char value[0x100]; 28 | byte type = INI_ITEM_STRING; 29 | }; 30 | 31 | IniParser() { memset(items, 0, 0x80 * sizeof(ConfigItem)); } 32 | IniParser(const char *filename); 33 | 34 | int GetString(const char *section, const char *key, char *dest); 35 | int GetInteger(const char *section, const char *key, int *dest); 36 | int GetFloat(const char *section, const char *key, float *dest); 37 | int GetBool(const char *section, const char *key, bool *dest); 38 | int SetString(const char *section, const char *key, char *value); 39 | int SetInteger(const char *section, const char *key, int value); 40 | int SetFloat(const char *section, const char *key, float value); 41 | int SetBool(const char *section, const char *key, bool value); 42 | int SetComment(const char *section, const char *key, const char *comment); 43 | void Write(const char *filename); 44 | 45 | ConfigItem items[0x80]; 46 | 47 | int count = 0; 48 | }; 49 | #endif // !INI_H 50 | -------------------------------------------------------------------------------- /Sonic12Decomp/Input.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | InputData keyPress = InputData(); 4 | InputData keyDown = InputData(); 5 | 6 | bool anyPress = false; 7 | 8 | int touchDown[8]; 9 | int touchX[8]; 10 | int touchY[8]; 11 | int touchID[8]; 12 | int touches = 0; 13 | 14 | InputButton inputDevice[9]; 15 | int inputType = 0; 16 | 17 | int LSTICK_DEADZONE = 20000; 18 | int RSTICK_DEADZONE = 20000; 19 | int LTRIGGER_DEADZONE = 20000; 20 | int RTRIGGER_DEADZONE = 20000; 21 | 22 | #if RETRO_USING_SDL 23 | SDL_GameController *controller; 24 | #endif 25 | 26 | // Easier this way 27 | enum ExtraSDLButtons { 28 | SDL_CONTROLLER_BUTTON_ZL = SDL_CONTROLLER_BUTTON_MAX + 1, 29 | SDL_CONTROLLER_BUTTON_ZR, 30 | SDL_CONTROLLER_BUTTON_LSTICK_UP, 31 | SDL_CONTROLLER_BUTTON_LSTICK_DOWN, 32 | SDL_CONTROLLER_BUTTON_LSTICK_LEFT, 33 | SDL_CONTROLLER_BUTTON_LSTICK_RIGHT, 34 | SDL_CONTROLLER_BUTTON_RSTICK_UP, 35 | SDL_CONTROLLER_BUTTON_RSTICK_DOWN, 36 | SDL_CONTROLLER_BUTTON_RSTICK_LEFT, 37 | SDL_CONTROLLER_BUTTON_RSTICK_RIGHT, 38 | SDL_CONTROLLER_BUTTON_MAX_EXTRA, 39 | }; 40 | 41 | #if RETRO_USING_SDL 42 | bool getControllerButton(byte buttonID) 43 | { 44 | if (SDL_GameControllerGetButton(controller, (SDL_GameControllerButton)buttonID)) { 45 | return true; 46 | } 47 | else { 48 | switch (buttonID) { 49 | default: break; 50 | case SDL_CONTROLLER_BUTTON_DPAD_UP: 51 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) < -LSTICK_DEADZONE; 52 | case SDL_CONTROLLER_BUTTON_DPAD_DOWN: 53 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) > LSTICK_DEADZONE; 54 | case SDL_CONTROLLER_BUTTON_DPAD_LEFT: 55 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) < -LSTICK_DEADZONE; 56 | case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: 57 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) > LSTICK_DEADZONE; 58 | } 59 | } 60 | 61 | switch (buttonID) { 62 | default: break; 63 | case SDL_CONTROLLER_BUTTON_ZL: 64 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > LTRIGGER_DEADZONE; 65 | case SDL_CONTROLLER_BUTTON_ZR: 66 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > RTRIGGER_DEADZONE; 67 | case SDL_CONTROLLER_BUTTON_LSTICK_UP: 68 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) < -LSTICK_DEADZONE; 69 | case SDL_CONTROLLER_BUTTON_LSTICK_DOWN: 70 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) > LSTICK_DEADZONE; 71 | case SDL_CONTROLLER_BUTTON_LSTICK_LEFT: 72 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) < -LSTICK_DEADZONE; 73 | case SDL_CONTROLLER_BUTTON_LSTICK_RIGHT: 74 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) > LSTICK_DEADZONE; 75 | case SDL_CONTROLLER_BUTTON_RSTICK_UP: 76 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) < -RSTICK_DEADZONE; 77 | case SDL_CONTROLLER_BUTTON_RSTICK_DOWN: 78 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) > RSTICK_DEADZONE; 79 | case SDL_CONTROLLER_BUTTON_RSTICK_LEFT: 80 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) < -RSTICK_DEADZONE; 81 | case SDL_CONTROLLER_BUTTON_RSTICK_RIGHT: 82 | return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) > RSTICK_DEADZONE; 83 | } 84 | 85 | return false; 86 | } 87 | #endif 88 | 89 | void ProcessInput() 90 | { 91 | #if RETRO_USING_SDL 92 | int length = 0; 93 | const byte *keyState = SDL_GetKeyboardState(&length); 94 | 95 | if (inputType == 0) { 96 | for (int i = 0; i < 8; i++) { 97 | if (keyState[inputDevice[i].keyMappings]) { 98 | inputDevice[i].setHeld(); 99 | inputDevice[8].setHeld(); 100 | continue; 101 | } 102 | else if (inputDevice[i].hold) 103 | inputDevice[i].setReleased(); 104 | } 105 | } 106 | else if (inputType == 1) { 107 | for (int i = 0; i < 8; i++) { 108 | if (getControllerButton(inputDevice[i].contMappings)) { 109 | inputDevice[i].setHeld(); 110 | inputDevice[8].setHeld(); 111 | continue; 112 | } 113 | else if (inputDevice[i].hold) 114 | inputDevice[i].setReleased(); 115 | } 116 | } 117 | 118 | if (keyState[inputDevice[0].keyMappings] || keyState[inputDevice[1].keyMappings] || keyState[inputDevice[2].keyMappings] 119 | || keyState[inputDevice[3].keyMappings] || keyState[inputDevice[4].keyMappings] || keyState[inputDevice[5].keyMappings] 120 | || keyState[inputDevice[6].keyMappings] || keyState[inputDevice[7].keyMappings]) { 121 | inputType = 0; 122 | } 123 | else if (inputType == 0) 124 | inputDevice[8].setReleased(); 125 | 126 | if (getControllerButton(SDL_CONTROLLER_BUTTON_A) || getControllerButton(SDL_CONTROLLER_BUTTON_B) || getControllerButton(SDL_CONTROLLER_BUTTON_X) 127 | || getControllerButton(SDL_CONTROLLER_BUTTON_Y) || getControllerButton(SDL_CONTROLLER_BUTTON_LEFTSHOULDER) 128 | || getControllerButton(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) || getControllerButton(SDL_CONTROLLER_BUTTON_ZL) 129 | || getControllerButton(SDL_CONTROLLER_BUTTON_ZR) || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_UP) 130 | || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_DOWN) || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_LEFT) 131 | || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_RIGHT) || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_UP) 132 | || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_DOWN) || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_LEFT) 133 | || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_RIGHT) || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_UP) 134 | || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_DOWN) || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_LEFT) 135 | || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_RIGHT) || getControllerButton(SDL_CONTROLLER_BUTTON_START)) { 136 | inputType = 1; 137 | } 138 | else if (inputType == 1) 139 | inputDevice[8].setReleased(); 140 | #endif 141 | } 142 | 143 | void CheckKeyPress(InputData *input, byte flags) 144 | { 145 | if (flags & 0x1) 146 | input->up = inputDevice[0].press; 147 | if (flags & 0x2) 148 | input->down = inputDevice[1].press; 149 | if (flags & 0x4) 150 | input->left = inputDevice[2].press; 151 | if (flags & 0x8) 152 | input->right = inputDevice[3].press; 153 | if (flags & 0x10) 154 | input->A = inputDevice[4].press; 155 | if (flags & 0x20) 156 | input->B = inputDevice[5].press; 157 | if (flags & 0x40) 158 | input->C = inputDevice[6].press; 159 | if (flags & 0x80) 160 | input->start = inputDevice[7].press; 161 | if (flags & 0x80) 162 | anyPress = inputDevice[8].press; 163 | } 164 | 165 | void CheckKeyDown(InputData *input, byte flags) 166 | { 167 | if (flags & 0x1) 168 | input->up = inputDevice[0].hold; 169 | if (flags & 0x2) 170 | input->down = inputDevice[1].hold; 171 | if (flags & 0x4) 172 | input->left = inputDevice[2].hold; 173 | if (flags & 0x8) 174 | input->right = inputDevice[3].hold; 175 | if (flags & 0x10) 176 | input->A = inputDevice[4].hold; 177 | if (flags & 0x20) 178 | input->B = inputDevice[5].hold; 179 | if (flags & 0x40) 180 | input->C = inputDevice[6].hold; 181 | if (flags & 0x80) 182 | input->start = inputDevice[7].hold; 183 | //if (flags & 0x80) 184 | // anyHold = inputDevice[8].hold; 185 | } -------------------------------------------------------------------------------- /Sonic12Decomp/Input.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_H 2 | #define INPUT_H 3 | 4 | struct InputData { 5 | bool up; 6 | bool down; 7 | bool left; 8 | bool right; 9 | bool A; 10 | bool B; 11 | bool C; 12 | bool start; 13 | }; 14 | 15 | struct InputButton { 16 | bool press, hold; 17 | int keyMappings, contMappings; 18 | 19 | inline void setHeld() 20 | { 21 | press = !hold; 22 | hold = true; 23 | } 24 | inline void setReleased() 25 | { 26 | press = false; 27 | hold = false; 28 | } 29 | 30 | inline bool down() { return (press || hold); } 31 | }; 32 | 33 | extern InputData keyPress; 34 | extern InputData keyDown; 35 | 36 | extern bool anyPress; 37 | 38 | extern int touchDown[8]; 39 | extern int touchX[8]; 40 | extern int touchY[8]; 41 | extern int touchID[8]; 42 | extern int touches; 43 | 44 | extern InputButton inputDevice[9]; 45 | extern int inputType; 46 | 47 | extern int LSTICK_DEADZONE; 48 | extern int RSTICK_DEADZONE; 49 | extern int LTRIGGER_DEADZONE; 50 | extern int RTRIGGER_DEADZONE; 51 | 52 | #if RETRO_USING_SDL 53 | extern SDL_GameController *controller; 54 | 55 | inline void controllerInit(byte controllerID) 56 | { 57 | inputType = 1; 58 | controller = SDL_GameControllerOpen(controllerID); 59 | }; 60 | 61 | inline void controllerClose(byte controllerID) 62 | { 63 | if (controllerID >= 2) 64 | return; 65 | inputType = 0; 66 | } 67 | #endif 68 | 69 | void ProcessInput(); 70 | 71 | void CheckKeyPress(InputData *input, byte Flags); 72 | void CheckKeyDown(InputData *input, byte Flags); 73 | 74 | #endif // !INPUT_H 75 | -------------------------------------------------------------------------------- /Sonic12Decomp/Math.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | #include 3 | 4 | #ifdef __vita__ 5 | #define M_PI 3.14159265358979323846 6 | #endif 7 | 8 | 9 | int sinValM7[512]; 10 | int cosValM7[512]; 11 | 12 | int sinVal512[512]; 13 | int cosVal512[512]; 14 | 15 | int sinVal256[256]; 16 | int cosVal256[256]; 17 | 18 | byte atanVal256[0x100 * 0x100]; 19 | 20 | void CalculateTrigAngles() 21 | { 22 | for (int i = 0; i < 0x200; ++i) { 23 | float val = sin(((float)i / 256.0) * M_PI); 24 | sinValM7[i] = (val * 4096.0); 25 | val = cos(((float)i / 256.0) * M_PI); 26 | cosValM7[i] = (val * 4096.0); 27 | } 28 | 29 | cosValM7[0] = 4096; 30 | cosValM7[128] = 0; 31 | cosValM7[256] = -4096; 32 | cosValM7[384] = 0; 33 | sinValM7[0] = 0; 34 | sinValM7[128] = 4096; 35 | sinValM7[256] = 0; 36 | sinValM7[384] = -4096; 37 | 38 | for (int i = 0; i < 0x200; ++i) { 39 | float val = sinf(((float)i / 256) * M_PI); 40 | sinVal512[i] = (signed int)(val * 512.0); 41 | val = cosf(((float)i / 256) * M_PI); 42 | cosVal512[i] = (signed int)(val * 512.0); 43 | } 44 | 45 | cosVal512[0] = 0x200; 46 | cosVal512[128] = 0; 47 | cosVal512[256] = -0x200; 48 | cosVal512[384] = 0; 49 | sinVal512[0] = 0; 50 | sinVal512[128] = 0x200; 51 | sinVal512[256] = 0; 52 | sinVal512[384] = -0x200; 53 | 54 | for (int i = 0; i < 0x100; i++) { 55 | sinVal256[i] = (sinVal512[i * 2] >> 1); 56 | cosVal256[i] = (cosVal512[i * 2] >> 1); 57 | } 58 | 59 | for (int Y = 0; Y < 0x100; ++Y) { 60 | byte *ATan = (byte *)&atanVal256[Y]; 61 | for (int X = 0; X < 0x100; ++X) { 62 | float angle = atan2f(Y, X); 63 | *ATan = (signed int)(angle * 40.743664f); 64 | ATan += 0x100; 65 | } 66 | } 67 | } 68 | 69 | byte ArcTanLookup(int X, int Y) 70 | { 71 | int x = 0; 72 | int y = 0; 73 | 74 | x = abs(X); 75 | y = abs(Y); 76 | 77 | if (x <= y) { 78 | while (y > 0xFF) { 79 | x >>= 4; 80 | y >>= 4; 81 | } 82 | } 83 | else { 84 | while (x > 0xFF) { 85 | x >>= 4; 86 | y >>= 4; 87 | } 88 | } 89 | if (X <= 0) { 90 | if (Y <= 0) 91 | return atanVal256[(x << 8) + y] + -0x80; 92 | else 93 | return -0x80 - atanVal256[(x << 8) + y]; 94 | } 95 | else if (Y <= 0) 96 | return -atanVal256[(x << 8) + y]; 97 | else 98 | return atanVal256[(x << 8) + y]; 99 | } 100 | 101 | int64_t pow(int base, int exponent) { 102 | if (!exponent) return 1; 103 | int64_t result = base; 104 | for (int i = 1; i < exponent; i++) result *= base; 105 | return result; 106 | } 107 | -------------------------------------------------------------------------------- /Sonic12Decomp/Math.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MATH_H 2 | #define MATH_H 3 | 4 | //#define M_PI (3.1415927) 5 | 6 | #define MEM_ZERO(x) memset(&(x), 0, sizeof((x))) 7 | #define MEM_ZEROP(x) memset((x), 0, sizeof(*(x))) 8 | 9 | extern int sinValM7[0x200]; 10 | extern int cosValM7[0x200]; 11 | 12 | extern int sinVal512[0x200]; 13 | extern int cosVal512[0x200]; 14 | 15 | extern int sinVal256[0x100]; 16 | extern int cosVal256[0x100]; 17 | 18 | extern byte atanVal256[0x100 * 0x100]; 19 | 20 | // Setup Angles 21 | void CalculateTrigAngles(); 22 | 23 | inline int sin512(int angle) { 24 | if (angle < 0) 25 | angle = 0x200 - angle; 26 | angle &= 0x1FF; 27 | return sinVal512[angle]; 28 | } 29 | 30 | inline int cos512(int angle) 31 | { 32 | if (angle < 0) 33 | angle = 0x200 - angle; 34 | angle &= 0x1FF; 35 | return cosVal512[angle]; 36 | } 37 | 38 | inline int sin256(int angle) 39 | { 40 | if (angle < 0) 41 | angle = 0x100 - angle; 42 | angle &= 0xFF; 43 | return sinVal256[angle]; 44 | } 45 | 46 | inline int cos256(int angle) 47 | { 48 | if (angle < 0) 49 | angle = 0x100 - angle; 50 | angle &= 0xFF; 51 | return cosVal256[angle]; 52 | } 53 | 54 | // Get Arc Tan value 55 | byte ArcTanLookup(int X, int Y); 56 | 57 | int64_t pow(int base, int exponent); 58 | 59 | #endif // !MATH_H 60 | -------------------------------------------------------------------------------- /Sonic12Decomp/Network.cpp: -------------------------------------------------------------------------------- 1 | //here lies Network.cpp 2 | //check RetroEngine.cpp:215ish for more info (RetroEngine::Init) 3 | 4 | #if RETRO_USE_NETWORKING 5 | #include "RetroEngine.hpp" 6 | 7 | #if RETRO_PLATFORM == RETRO_WIN && _MSC_VER 8 | #include //gives it a macro it wants, will make a note otherwise 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | inline uint64_t GETBIT(uint64_t i, int n) { return (i & (1LL << n)) >> n; }; 17 | 18 | using namespace asio; 19 | using ip::tcp; 20 | using ip::udp; 21 | using std::string; 22 | using std::cout; 23 | using std::endl; 24 | 25 | const char *pattern = "AABAABC"; 26 | #define PLEN (7) 27 | 28 | char index[36]; 29 | void buildNetworkIndex() { 30 | for (byte i = 0; i < 26; ++i) index[i] = i + 'A'; 31 | for (byte i = 0; i < 10; ++i) index[i + 26] = i + '0'; 32 | } 33 | 34 | udp::socket* udpSocket = nullptr; 35 | udp::endpoint otherEndpoint; 36 | CodeData datas[2]; //0 is my end 37 | std::thread runner; 38 | 39 | string connectedIP; 40 | 41 | string generateCode(ushort port, int gameLength, int itemMode) 42 | { 43 | uint64_t code = 0; 44 | uint ip; 45 | if (getIP(&ip)) 46 | return string(); 47 | datas[0].ip = ip; 48 | datas[0].port = port; 49 | datas[0].gameLength = gameLength; 50 | datas[0].itemMode = itemMode; 51 | datas[0].player = playerListPos; 52 | short gamecode = gameLength | (itemMode << 4) | (playerListPos << 6); 53 | int ipc = 0, pc = 0, gc = 0; 54 | for (uint64_t i = 0; i < PLEN * 8; i++) { 55 | std::cout << code << ' ' << i << std::endl; 56 | char c = pattern[i % PLEN]; 57 | switch (c) { 58 | case 'A': code |= GETBIT(ip, ipc++) << i; break; 59 | case 'B': code |= GETBIT(port, pc++) << i; break; 60 | case 'C': code |= GETBIT(gamecode, gc++) << i; break; 61 | } 62 | } 63 | int i = 0; 64 | while (code >= (uint64_t)pow(36, i + 1)) i++; 65 | std::ostringstream out; 66 | while (code) { 67 | out << index[code / (uint64_t)pow(36, i)]; 68 | code %= pow(36, i--); 69 | } 70 | datas[0].codeString = out.str().c_str(); 71 | return out.str(); 72 | } 73 | 74 | CodeData parseCode(const string code) 75 | { 76 | uint64_t out = 0; 77 | int i = 0; 78 | for (auto rit = code.rbegin(); rit != code.rend(); ++rit) { 79 | char c = *rit, mult; 80 | if (c <= '9') 81 | mult = c - '0' + 26; 82 | else mult = c - 'A'; 83 | out += mult * (uint64_t)pow(36, i++); 84 | } 85 | int bitlen = floor(log2(out) + 1); 86 | CodeData ret; 87 | MEM_ZERO(ret); 88 | short gamecode = 0; 89 | int ipc = 0, pc = 0, gc = 0; 90 | for (int i = 0; i < bitlen; ++i) { 91 | char c = pattern[i % PLEN]; 92 | auto bit = GETBIT(out, i); 93 | switch (c) { 94 | case 'A': ret.ip |= bit << ipc++; break; 95 | case 'B': ret.port |= bit << pc++; break; 96 | case 'C': gamecode |= bit << gc++; break; 97 | } 98 | } 99 | ret.gameLength = gamecode & 0b1111; 100 | ret.itemMode = (gamecode >> 4) & 0b11; 101 | ret.player = (gamecode >> 6) & 0b11; 102 | //ret.ip = 127 | 1 << 24; 103 | std::ostringstream ip; 104 | ip << (ret.ip & 0xFF) << '.' 105 | << ((ret.ip >> 8) & 0xFF) << '.' 106 | << ((ret.ip >> 16) & 0xFF) << '.' 107 | << ((ret.ip >> 24) & 0xFF); 108 | ret.ipString = ip.str(); 109 | ret.codeString = code.c_str(); //make a copy i guess 110 | return ret; 111 | } 112 | 113 | int getIP(uint *ip) 114 | { 115 | string ips; 116 | try { 117 | io_service io_service; 118 | tcp::resolver resolver(io_service); 119 | tcp::resolver::query query("api.ipify.org", "http"); 120 | tcp::resolver::iterator endpoint_iterator = resolver.resolve(query), end; 121 | tcp::socket socket(io_service); 122 | 123 | error_code ec = error::not_connected; 124 | while (ec && endpoint_iterator != end) { 125 | socket.close(); 126 | socket.connect(*endpoint_iterator++, ec); 127 | } 128 | if (ec) 129 | return ec.value(); 130 | // form the HTTP request 131 | streambuf request; 132 | std::ostream request_stream(&request); 133 | request_stream << "GET / HTTP/1.0\r\n"; 134 | request_stream << "Host: api.ipify.org\r\n\r\n"; 135 | // send it 136 | write(socket, request, ec); 137 | if (ec) 138 | return ec.value(); 139 | // read the status code and HTTP code 140 | streambuf response; 141 | read_until(socket, response, "\r\n", ec); 142 | if (ec) 143 | return ec.value(); 144 | // is our response valid? 145 | std::istream response_stream(&response); 146 | string http_version; 147 | response_stream >> http_version; 148 | unsigned int status_code; 149 | response_stream >> status_code; 150 | string status_message; 151 | std::getline(response_stream, status_message); 152 | if (!response_stream || http_version.substr(0, 5) != "HTTP/") 153 | return 1; // invalid response 154 | if (status_code != 200) 155 | return status_code; // not OK 156 | // read the header 157 | std::string header; 158 | while (std::getline(response_stream, header) && header != "\r") { 159 | } 160 | // finally, read the IP address 161 | std::ostringstream output; 162 | if (response.size() > 0) 163 | output << &response; 164 | while (read(socket, response, transfer_at_least(1), ec)) output << &response; 165 | // output is now our ip address. 166 | // we can now exit the clause, but make sure we know our IP! 167 | ips = output.str(); 168 | } catch (std::exception &e) { 169 | return 1; // any exceptions we just retun 1 170 | } 171 | std::istringstream ipstream(ips); 172 | char buf; 173 | *ip = 0; 174 | // fill the bytes in properly. 175 | for (int i = 0; i < 4; i++) { 176 | int read; 177 | ipstream >> read >> buf; 178 | *ip |= (read << (i * 8)); 179 | } 180 | return 0; 181 | } 182 | 183 | void runServer(ushort); 184 | void runClient(CodeData); 185 | 186 | void initServer(ushort port) { 187 | runner = std::thread(runServer, port); 188 | } 189 | void initClient(CodeData data) { 190 | runner = std::thread(runClient, data); 191 | } 192 | 193 | void stopNetworking() { 194 | error_code ignored; 195 | udpSocket->close(ignored); //this should error the running loop 196 | runner.detach(); 197 | } 198 | 199 | void runServer(ushort port) { 200 | io_context io_context; 201 | MEM_ZERO(datas[1]); 202 | udpSocket = new udp::socket(io_context, udp::endpoint(udp::v4(), port)); 203 | while (udpSocket->is_open()) { 204 | udp::endpoint remote_endpoint; 205 | error_code ignored; 206 | char recv_buf[0x1000]; 207 | MEM_ZEROP(recv_buf); 208 | cout << "waiting for bytes" << endl; 209 | try { 210 | udpSocket->receive_from(buffer(recv_buf), remote_endpoint, 0); 211 | } 212 | catch (std::exception &e) { 213 | recv_buf[0] = 0x82; //error on the socket end, terminate immediately 214 | } 215 | cout << "recieved " << +recv_buf[0] << " from " << remote_endpoint.address().to_v4().to_string() << ":" << remote_endpoint.port() << endl; 216 | if (datas[1].ip && datas[1].ipString.compare(remote_endpoint.address().to_v4().to_string())) { 217 | sendData(0x80, 0, nullptr, &remote_endpoint); //you're not who we're looking for 218 | continue; 219 | } 220 | sbyte flag = recv_buf[0] & 0x7F, error = recv_buf[0] & 0x80; 221 | ushort datalen = *(short*)(recv_buf + 1); 222 | if (error) { 223 | udpSocket->close(ignored); 224 | receive2PVSMatchCode(1); 225 | break; //if, at ANY point, it no longer succeeds, break the whole loop 226 | } 227 | switch (flag) { 228 | default: continue; 229 | case 0x00: { //game code, this aint our business at this point 230 | receive2PVSData((MultiplayerData*)(recv_buf + 3)); 231 | break; 232 | } 233 | case 0x01: { //first response, "introduce ourselves", make sure the code's correct 234 | string code((char*)(recv_buf + 3), datalen); 235 | if (code.compare(datas[0].codeString)) { 236 | sendData(0x81, 0, nullptr, &remote_endpoint); //incorrect code 237 | continue; 238 | } 239 | otherEndpoint = remote_endpoint; //friend!!!!! 240 | sendData(0x41, 0, nullptr); 241 | break; 242 | } 243 | case 0x02: { //after first client response, this has the code. after this one server starts 244 | datas[1] = parseCode(string((char*)(recv_buf + 3), datalen)); 245 | receive2PVSMatchCode((datas[1].gameLength << 4) + (datas[1].itemMode << 8) + (datas[1].player << 12)); 246 | break; 247 | } 248 | } 249 | } 250 | } 251 | void runClient(CodeData data) { 252 | io_context io_context; 253 | datas[1] = data; 254 | otherEndpoint = udp::endpoint(ip::address_v4(data.ip), data.port); 255 | udpSocket = new udp::socket(io_context, otherEndpoint); 256 | udpSocket->connect(otherEndpoint); 257 | sendData(0x01, datas[1].codeString.length(), (void*)datas[1].codeString.c_str()); 258 | while (udpSocket->is_open()) { 259 | udp::endpoint remote_endpoint; 260 | error_code ignored; 261 | char recv_buf[0x1000]; 262 | MEM_ZEROP(recv_buf); 263 | cout << "waiting for bytes" << endl; 264 | udpSocket->receive_from(buffer(recv_buf), remote_endpoint, 0, ignored); 265 | cout << "recieved " << +recv_buf[0] << " from " << remote_endpoint.address().to_v4().to_string() << ":" << remote_endpoint.port() << endl; 266 | if (datas[1].port != remote_endpoint.port() || datas[1].ipString.compare(remote_endpoint.address().to_v4().to_string())) { 267 | sendData(0x80, 0, nullptr, &remote_endpoint); //you're not who we're looking for 268 | continue; 269 | } 270 | sbyte flag = recv_buf[0] & 0x7F, error = recv_buf[0] & 0x80; 271 | ushort datalen = *(short*)(recv_buf + 1); 272 | if (error) { 273 | udpSocket->close(ignored); 274 | receive2PVSMatchCode(1); 275 | break; //if, at ANY point, it no longer succeeds, break the whole loop 276 | } 277 | switch (flag) { 278 | case 0x00: { //game code, this aint our business at this point 279 | receive2PVSData((MultiplayerData*)(recv_buf + 3)); 280 | break; 281 | } 282 | case 0x41: { //after first response from the server, "send me your code." we start after waiting a little bit 283 | sendData(0x02, datas[0].codeString.length(), (void*)datas[0].codeString.c_str()); 284 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 285 | receive2PVSMatchCode((datas[1].gameLength << 4) + (datas[1].itemMode << 8) + (datas[1].player << 12)); 286 | break; 287 | } 288 | } 289 | } 290 | } 291 | 292 | int sendData(byte flag, ushort datalen, void* data, void *endpoint) { 293 | if (!udpSocket || !udpSocket->is_open()) return 1; //if socket doesn't exist 294 | if (!endpoint) endpoint = &otherEndpoint; //set the default endpoint 295 | error_code ec; 296 | char sendbuf[0x1000]; 297 | MEM_ZEROP(sendbuf); 298 | *sendbuf = flag; 299 | *(sendbuf + 1) = datalen; 300 | memcpy(sendbuf + 3, data, datalen); //fill our sendbuffer 301 | udpSocket->send_to(buffer(sendbuf), *(udp::endpoint*)endpoint, 0, ec); //send it over 302 | if (ec) return ec.value(); 303 | cout << "sent " << +flag << " to " << (*(udp::endpoint*)endpoint).address().to_v4().to_string() << endl; 304 | return 0; 305 | } 306 | #endif -------------------------------------------------------------------------------- /Sonic12Decomp/Network.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NETWORK_H 2 | #define NETWORK_H 3 | #include 4 | 5 | struct CodeData { 6 | uint ip; 7 | ushort port; 8 | int gameLength; 9 | int itemMode; 10 | int player; 11 | std::string ipString; 12 | std::string codeString; 13 | }; 14 | void buildNetworkIndex(); 15 | 16 | /* generates the code based on IP, port, gameLength, itemMode, and playerListPos. 17 | the other user inputs this code to connect */ 18 | std::string generateCode(ushort port, int gameLength, int itemMode); 19 | 20 | /* parses the code given and returns a CodeData. 21 | we can use this to get the IP and port and set our other variables later on */ 22 | CodeData parseCode(const std::string code); 23 | 24 | /* returns 1 or more on error 25 | this also ensures the user is connected to the internet */ 26 | int getIP(uint* ip); 27 | 28 | void initServer(ushort port); 29 | void initClient(CodeData data); 30 | int sendData(byte flag, ushort datalen, void* data, void* endpoint = nullptr); 31 | 32 | #endif -------------------------------------------------------------------------------- /Sonic12Decomp/Object.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OBJECT_H 2 | #define OBJECT_H 3 | 4 | #define NATIVEENTITY_COUNT (0x100) 5 | 6 | #define ENTITY_COUNT (0x4A0) 7 | #define TEMPENTITY_START (ENTITY_COUNT - 0x80) 8 | #define OBJECT_COUNT (0x100) 9 | #define TYPEGROUP_COUNT (0x103) 10 | 11 | struct TypeGroupList { 12 | int entityRefs[ENTITY_COUNT]; 13 | int listSize; 14 | }; 15 | 16 | struct Entity { 17 | int XPos; 18 | int YPos; 19 | int XVelocity; 20 | int YVelocity; 21 | int speed; 22 | int values[48]; 23 | int state; 24 | int angle; 25 | int scale; 26 | int rotation; 27 | int alpha; 28 | int animationTimer; 29 | int animationSpeed; 30 | int camOffsetX; 31 | int lookPos; 32 | ushort typeGroup; 33 | byte type; 34 | byte propertyValue; 35 | byte priority; 36 | sbyte drawOrder; 37 | byte direction; 38 | byte inkEffect; 39 | byte animation; 40 | byte prevAnimation; 41 | byte frame; 42 | byte collisionMode; 43 | byte collisionPlane; 44 | sbyte controlMode; 45 | byte controlLock; 46 | byte pushing; 47 | byte visible; 48 | byte tileCollisions; 49 | byte objectInteractions; 50 | byte gravity; 51 | byte left; 52 | byte right; 53 | byte up; 54 | byte down; 55 | byte jumpPress; 56 | byte jumpHold; 57 | byte trackScroll; 58 | byte flailing[5]; 59 | }; 60 | 61 | struct NativeEntityBase { 62 | void (*createPtr)(void *objPtr); 63 | void (*mainPtr)(void *objPtr); 64 | int slotID; 65 | int objectID; 66 | }; 67 | 68 | struct NativeEntity { 69 | void (*createPtr)(void *objPtr); 70 | void (*mainPtr)(void *objPtr); 71 | int slotID; 72 | int objectID; 73 | byte extra[0x400]; 74 | }; 75 | 76 | enum ObjectTypes { 77 | OBJ_TYPE_BLANKOBJECT = 0 //0 is always blank obj 78 | }; 79 | 80 | enum ObjectPriority { 81 | PRIORITY_ACTIVE_BOUNDS, 82 | PRIORITY_ACTIVE, 83 | PRIORITY_ACTIVE_PAUSED, 84 | PRIORITY_ACTIVE_XBOUNDS, 85 | PRIORITY_ACTIVE_XBOUNDS_REMOVE, 86 | PRIORITY_INACTIVE, 87 | PRIORITY_ACTIVE_BOUNDS_SMALL, 88 | PRIORITY_ACTIVE2 89 | }; 90 | 91 | //Native Objects 92 | extern int nativeEntityPos; 93 | 94 | extern int activeEntityList[NATIVEENTITY_COUNT]; 95 | extern int objectRemoveFlag[NATIVEENTITY_COUNT]; 96 | extern NativeEntity objectEntityBank[NATIVEENTITY_COUNT]; 97 | extern int nativeEntityCount; 98 | 99 | extern int nativeEntityCountBackup; 100 | extern int backupEntityList[NATIVEENTITY_COUNT]; 101 | extern NativeEntity objectEntityBackup[NATIVEENTITY_COUNT]; 102 | 103 | extern int nativeEntityCountBackupS; 104 | extern int backupEntityListS[NATIVEENTITY_COUNT]; 105 | extern NativeEntity objectEntityBackupS[NATIVEENTITY_COUNT]; 106 | 107 | //Game Objects 108 | extern int objectEntityPos; 109 | extern int curObjectType; 110 | extern Entity objectEntityList[ENTITY_COUNT]; 111 | extern int processObjectFlag[ENTITY_COUNT]; 112 | extern TypeGroupList objectTypeGroupList[TYPEGROUP_COUNT]; 113 | 114 | extern char typeNames[OBJECT_COUNT][0x40]; 115 | 116 | extern int OBJECT_BORDER_X1; 117 | extern int OBJECT_BORDER_X2; 118 | extern int OBJECT_BORDER_X3; 119 | extern int OBJECT_BORDER_X4; 120 | extern const int OBJECT_BORDER_Y1; 121 | extern const int OBJECT_BORDER_Y2; 122 | extern const int OBJECT_BORDER_Y3; 123 | extern const int OBJECT_BORDER_Y4; 124 | 125 | void ProcessStartupObjects(); 126 | void ProcessObjects(); 127 | void ProcessPausedObjects(); 128 | void ProcessFrozenObjects(); 129 | void Process2PObjects(); 130 | 131 | #if !RSDK_DEBUG 132 | inline void SetObjectTypeName(const char *objectName, int objectID) 133 | { 134 | int objNameID = 0; 135 | int typeNameID = 0; 136 | while (objectName[objNameID]) { 137 | if (objectName[objNameID] != ' ') 138 | typeNames[objectID][typeNameID++] = objectName[objNameID]; 139 | ++objNameID; 140 | } 141 | typeNames[objectID][typeNameID] = 0; 142 | } 143 | #else 144 | void SetObjectTypeName(const char *objectName, int objectID); 145 | #endif 146 | 147 | extern int playerListPos; 148 | 149 | void ProcessPlayerControl(Entity *player); 150 | 151 | void InitNativeObjectSystem(); 152 | NativeEntity *CreateNativeObject(void (*objCreate)(void *objPtr), void (*objMain)(void *objPtr)); 153 | void RemoveNativeObject(NativeEntityBase *NativeEntry); 154 | void ProcessNativeObjects(); 155 | inline void BackupNativeObjects() { 156 | memcpy(backupEntityList, activeEntityList, sizeof(int) * NATIVEENTITY_COUNT); 157 | memcpy(objectEntityBackup, objectEntityBank, sizeof(NativeEntity) * NATIVEENTITY_COUNT); 158 | nativeEntityCountBackup = nativeEntityCount; 159 | } 160 | inline void BackupNativeObjectsSettings() { 161 | memcpy(backupEntityListS, activeEntityList, sizeof(int) * NATIVEENTITY_COUNT); 162 | memcpy(objectEntityBackupS, objectEntityBank, sizeof(NativeEntity) * NATIVEENTITY_COUNT); 163 | nativeEntityCountBackupS = nativeEntityCount; 164 | } 165 | inline void RestoreNativeObjects() 166 | { 167 | memcpy(activeEntityList, backupEntityList, sizeof(int) * NATIVEENTITY_COUNT); 168 | nativeEntityCount = nativeEntityCountBackup; 169 | memcpy(objectEntityBank, objectEntityBackup, sizeof(NativeEntity) * NATIVEENTITY_COUNT); 170 | 171 | //ptr = CreateNativeObject(FadeScreen_Create, FadeScreen_Main); 172 | //ptr + 16 = 0; 173 | } 174 | inline void RestoreNativeObjectsNoFade() 175 | { 176 | memcpy(activeEntityList, backupEntityList, sizeof(int) * NATIVEENTITY_COUNT); 177 | nativeEntityCount = nativeEntityCountBackup; 178 | memcpy(objectEntityBank, objectEntityBackup, sizeof(NativeEntity) * NATIVEENTITY_COUNT); 179 | } 180 | inline void RestoreNativeObjectsSettings() 181 | { 182 | memcpy(activeEntityList, backupEntityListS, sizeof(int) * NATIVEENTITY_COUNT); 183 | nativeEntityCount = nativeEntityCountBackupS; 184 | memcpy(objectEntityBank, objectEntityBackupS, sizeof(NativeEntity) * NATIVEENTITY_COUNT); 185 | } 186 | inline void GetNativeObject(NativeEntity *obj, void (*newCreate)(void *objPtr), void (*newMain)(void *objPtr)) 187 | { 188 | int slotID = obj->slotID; 189 | int objID = obj->objectID; 190 | memset(&objectEntityBank[slotID], 0, sizeof(NativeEntity)); 191 | obj->slotID = slotID; 192 | obj->mainPtr = newMain; 193 | obj->createPtr = newCreate; 194 | obj->objectID = objID; 195 | if (obj->createPtr) 196 | obj->createPtr(obj); 197 | } 198 | inline NativeEntity *GetNativeObject(uint objID) 199 | { 200 | if (objID > 0xFF) 201 | return nullptr; 202 | else 203 | return &objectEntityBank[objID]; 204 | } 205 | inline void ClearNativeObjects() { 206 | nativeEntityCount = 0; 207 | memset(objectEntityBank, 0, sizeof(NativeEntity) * NATIVEENTITY_COUNT); 208 | } 209 | 210 | #endif // !OBJECT_H 211 | -------------------------------------------------------------------------------- /Sonic12Decomp/Palette.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | // Palettes (as RGB888 Colours) 4 | PaletteEntry fullPalette32[PALETTE_COUNT][PALETTE_SIZE]; 5 | PaletteEntry *activePalette32 = fullPalette32[0]; 6 | 7 | // Palettes (as RGB565 Colours) 8 | ushort fullPalette[PALETTE_COUNT][PALETTE_SIZE]; 9 | ushort *activePalette = fullPalette[0]; // Ptr to the 256 colour set thats active 10 | 11 | byte gfxLineBuffer[SCREEN_YSIZE]; // Pointers to active palette 12 | 13 | int fadeMode = 0; 14 | byte fadeA = 0; 15 | byte fadeR = 0; 16 | byte fadeG = 0; 17 | byte fadeB = 0; 18 | 19 | void LoadPalette(const char *filePath, int paletteID, int startPaletteIndex, int startIndex, int endIndex) 20 | { 21 | FileInfo info; 22 | char fullPath[0x80]; 23 | 24 | StrCopy(fullPath, "Data/Palettes/"); 25 | StrAdd(fullPath, filePath); 26 | 27 | if (LoadFile(fullPath, &info)) { 28 | SetFilePosition(3 * startIndex); 29 | if (paletteID >= PALETTE_COUNT || paletteID < 0) 30 | paletteID = 0; 31 | 32 | byte colour[3]; 33 | if (paletteID) { 34 | for (int i = startIndex; i < endIndex; ++i) { 35 | FileRead(&colour, 3); 36 | SetPaletteEntry(paletteID, startPaletteIndex++, colour[0], colour[1], colour[2]); 37 | } 38 | } 39 | else { 40 | for (int i = startIndex; i < endIndex; ++i) { 41 | FileRead(&colour, 3); 42 | SetPaletteEntry(-1, startPaletteIndex++, colour[0], colour[1], colour[2]); 43 | } 44 | } 45 | CloseFile(); 46 | } 47 | } 48 | 49 | void SetPaletteFade(byte destPaletteID, byte srcPaletteA, byte srcPaletteB, ushort blendAmount, int startIndex, 50 | int endIndex) 51 | { 52 | if (destPaletteID >= PALETTE_COUNT || srcPaletteA >= PALETTE_COUNT || srcPaletteB >= PALETTE_COUNT) 53 | return; 54 | 55 | if (blendAmount > 0xFF) { 56 | blendAmount = 0xFF; 57 | } 58 | else { 59 | blendAmount = 0; 60 | } 61 | if (endIndex > 0x100) 62 | endIndex = 0x100; 63 | 64 | if (startIndex < endIndex) { 65 | uint blendA = 0xFF - blendAmount; 66 | ushort *dst = &fullPalette[destPaletteID][startIndex]; 67 | ushort *srcA = &fullPalette[srcPaletteA][startIndex]; 68 | ushort *srcB = &fullPalette[srcPaletteB][startIndex]; 69 | 70 | for (int l = startIndex; l < endIndex; ++l) { 71 | *dst = RGB888_TO_RGB565((byte)((ushort)(fullPalette32[srcPaletteB][l].b * blendAmount + blendA * fullPalette32[srcPaletteA][l].b) >> 8), 72 | (byte)((ushort)(fullPalette32[srcPaletteB][l].g * blendAmount + blendA * fullPalette32[srcPaletteA][l].g) >> 8), 73 | (byte)((ushort)(fullPalette32[srcPaletteB][l].r * blendAmount + blendA * fullPalette32[srcPaletteA][l].r) >> 8)); 74 | ++srcA; 75 | ++srcB; 76 | ++dst; 77 | } 78 | 79 | 80 | } 81 | } -------------------------------------------------------------------------------- /Sonic12Decomp/Palette.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PALETTE_H 2 | #define PALETTE_H 3 | 4 | #define PALETTE_COUNT (0x8) 5 | #define PALETTE_SIZE (0x100) 6 | 7 | struct PaletteEntry { 8 | byte r; 9 | byte g; 10 | byte b; 11 | }; 12 | 13 | // Palettes (as RGB565 Colours) 14 | extern PaletteEntry fullPalette32[PALETTE_COUNT][PALETTE_SIZE]; 15 | extern ushort fullPalette[PALETTE_COUNT][PALETTE_SIZE]; 16 | extern ushort *activePalette; // Ptr to the 256 colour set thats active 17 | extern PaletteEntry *activePalette32; 18 | 19 | extern byte gfxLineBuffer[SCREEN_YSIZE]; // Pointers to active palette 20 | 21 | extern int fadeMode; 22 | extern byte fadeA; 23 | extern byte fadeR; 24 | extern byte fadeG; 25 | extern byte fadeB; 26 | 27 | extern int paletteMode; 28 | 29 | #define RGB888_TO_RGB5551(r, g, b) (2 * ((b) >> 3) | ((g) >> 3 << 6) | ((r) >> 3 << 11) | 1) // used in mobile vers 30 | #define RGB888_TO_RGB565(r, g, b) ((b) >> 3) | (((g) >> 2) << 5) | (((r) >> 3) << 11) // used in pc vers 31 | 32 | void LoadPalette(const char *filePath, int paletteID, int startPaletteIndex, int startIndex, int endIndex); 33 | 34 | inline void SetActivePalette(byte newActivePal, int startLine, int endLine) 35 | { 36 | if (newActivePal < PALETTE_COUNT) 37 | while (startLine++ < endLine && startLine < SCREEN_YSIZE) gfxLineBuffer[startLine] = newActivePal; 38 | 39 | activePalette = fullPalette[gfxLineBuffer[0]]; 40 | activePalette32 = fullPalette32[gfxLineBuffer[0]]; 41 | } 42 | 43 | inline void SetPaletteEntry(byte paletteIndex, byte index, byte r, byte g, byte b) 44 | { 45 | if (paletteIndex != 0xFF) { 46 | fullPalette[paletteIndex][index] = RGB888_TO_RGB565(r, g, b); 47 | fullPalette32[paletteIndex][index].r = r; 48 | fullPalette32[paletteIndex][index].g = g; 49 | fullPalette32[paletteIndex][index].b = b; 50 | } 51 | else { 52 | activePalette[index] = RGB888_TO_RGB565(r, g, b); 53 | activePalette32[index].r = r; 54 | activePalette32[index].g = g; 55 | activePalette32[index].b = b; 56 | } 57 | } 58 | 59 | inline void SetPaletteEntryPacked(byte paletteIndex, byte index, uint colour) 60 | { 61 | fullPalette[paletteIndex][index] = RGB888_TO_RGB565((byte)(colour >> 16), (byte)(colour >> 8), (byte)(colour >> 0)); 62 | fullPalette32[paletteIndex][index].r = (byte)(colour >> 16); 63 | fullPalette32[paletteIndex][index].g = (byte)(colour >> 8); 64 | fullPalette32[paletteIndex][index].b = (byte)(colour >> 0); 65 | } 66 | 67 | inline uint GetPaletteEntryPacked(byte paletteIndex, byte index) 68 | { 69 | PaletteEntry clr = fullPalette32[paletteIndex][index]; 70 | return (clr.r << 16) | (clr.g << 8) | (clr.b); 71 | } 72 | 73 | inline void CopyPalette(byte sourcePalette, byte srcPaletteStart, byte destinationPalette, byte destPaletteStart, byte count) 74 | { 75 | if (sourcePalette < PALETTE_COUNT && destinationPalette < PALETTE_COUNT) { 76 | for (int i = 0; i < count; ++i) { 77 | fullPalette[destinationPalette][srcPaletteStart + i] = fullPalette[sourcePalette][destPaletteStart + i]; 78 | fullPalette32[destinationPalette][srcPaletteStart + i] = fullPalette32[sourcePalette][destPaletteStart + i]; 79 | } 80 | } 81 | } 82 | 83 | inline void RotatePalette(int palID, byte startIndex, byte endIndex, bool right) 84 | { 85 | if (right) { 86 | ushort startClr = fullPalette[palID][endIndex]; 87 | PaletteEntry startClr32 = fullPalette32[palID][startIndex]; 88 | for (int i = endIndex; i > startIndex; --i) { 89 | fullPalette[palID][i] = fullPalette[palID][i - 1]; 90 | fullPalette32[palID][i] = fullPalette32[palID][i - 1]; 91 | } 92 | fullPalette[palID][startIndex] = startClr; 93 | fullPalette32[palID][endIndex] = startClr32; 94 | } 95 | else { 96 | ushort startClr = fullPalette[palID][startIndex]; 97 | PaletteEntry startClr32 = fullPalette32[palID][startIndex]; 98 | for (int i = startIndex; i < endIndex; ++i) { 99 | fullPalette[palID][i] = fullPalette[palID][i + 1]; 100 | fullPalette32[palID][i] = fullPalette32[palID][i + 1]; 101 | } 102 | fullPalette[palID][endIndex] = startClr; 103 | fullPalette32[palID][endIndex] = startClr32; 104 | } 105 | } 106 | 107 | inline void SetFade(byte R, byte G, byte B, ushort A) 108 | { 109 | fadeMode = 1; 110 | fadeR = R; 111 | fadeG = G; 112 | fadeB = B; 113 | fadeA = A > 0xFF ? 0xFF : A; 114 | } 115 | void SetPaletteFade(byte destPaletteID, byte srcPaletteA, byte srcPaletteB, ushort blendAmount, int startIndex, int endIndex); 116 | 117 | #endif // !PALETTE_H 118 | -------------------------------------------------------------------------------- /Sonic12Decomp/PauseMenu.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | TextMenu pauseTextMenu; 4 | 5 | void PauseMenu_Create(void *objPtr) 6 | { 7 | NativeEntity_PauseMenu *pauseMenu = (NativeEntity_PauseMenu *)objPtr; 8 | pauseMenu->state = 0; 9 | pauseMenu->timer = 0; 10 | pauseMenu->selectedOption = 0; 11 | pauseMenu->barPos = SCREEN_XSIZE + 64; 12 | pauseMenu->menu = &pauseTextMenu; 13 | MEM_ZEROP(pauseMenu->menu); 14 | 15 | AddTextMenuEntry(pauseMenu->menu, "RESUME"); 16 | AddTextMenuEntry(pauseMenu->menu, ""); 17 | AddTextMenuEntry(pauseMenu->menu, ""); 18 | AddTextMenuEntry(pauseMenu->menu, ""); 19 | AddTextMenuEntry(pauseMenu->menu, "RESTART"); 20 | AddTextMenuEntry(pauseMenu->menu, ""); 21 | AddTextMenuEntry(pauseMenu->menu, ""); 22 | AddTextMenuEntry(pauseMenu->menu, ""); 23 | AddTextMenuEntry(pauseMenu->menu, "EXIT"); 24 | if (Engine.devMenu) { 25 | AddTextMenuEntry(pauseMenu->menu, ""); 26 | AddTextMenuEntry(pauseMenu->menu, ""); 27 | AddTextMenuEntry(pauseMenu->menu, ""); 28 | AddTextMenuEntry(pauseMenu->menu, "DEV MENU"); 29 | } 30 | pauseMenu->menu->alignment = MENU_ALIGN_CENTER; 31 | pauseMenu->menu->selectionCount = Engine.devMenu ? 3 : 2; 32 | pauseMenu->menu->selection1 = 0; 33 | pauseMenu->menu->selection2 = 0; 34 | pauseMenu->lastSurfaceNo = textMenuSurfaceNo; 35 | textMenuSurfaceNo = SURFACE_MAX - 1; 36 | 37 | SetPaletteEntryPacked(7, 0x08, GetPaletteEntryPacked(0, 8)); 38 | SetPaletteEntryPacked(7, 0xFF, 0xFFFFFF); 39 | } 40 | void PauseMenu_Main(void *objPtr) 41 | { 42 | CheckKeyDown(&keyDown, 0xFF); 43 | CheckKeyPress(&keyPress, 0xFF); 44 | 45 | NativeEntity_PauseMenu *pauseMenu = (NativeEntity_PauseMenu *)objPtr; 46 | 47 | switch (pauseMenu->state) { 48 | case 0: 49 | // wait 50 | pauseMenu->barPos -= 16; 51 | if (pauseMenu->barPos + 64 < SCREEN_XSIZE) { 52 | pauseMenu->state++; 53 | } 54 | break; 55 | case 1: 56 | if (keyPress.up) { 57 | if (pauseMenu->selectedOption - 1 < 0) { 58 | if (!Engine.devMenu) 59 | pauseMenu->selectedOption = 3; 60 | else 61 | pauseMenu->selectedOption = 4; 62 | } 63 | --pauseMenu->selectedOption; 64 | PlaySFXByName("MenuMove", 0); 65 | } 66 | else if (keyPress.down) { 67 | if (!Engine.devMenu) 68 | pauseMenu->selectedOption = ++pauseMenu->selectedOption % 3; 69 | else 70 | pauseMenu->selectedOption = ++pauseMenu->selectedOption % 4; 71 | PlaySFXByName("MenuMove", 0); 72 | } 73 | 74 | pauseMenu->menu->selection1 = pauseMenu->selectedOption * 4; 75 | 76 | if (keyPress.A || keyPress.start) { 77 | switch (pauseMenu->selectedOption) { 78 | case 0: { 79 | Engine.gameMode = ENGINE_EXITPAUSE; 80 | pauseMenu->state = 2; 81 | break; 82 | } 83 | case 1: { 84 | pauseMenu->state = 3; 85 | break; 86 | } 87 | case 2: { 88 | pauseMenu->state = 4; 89 | break; 90 | } 91 | case 3: { 92 | pauseMenu->state = 5; 93 | break; 94 | } 95 | } 96 | PlaySFXByName("MenuSelect", 0); 97 | } 98 | else if (keyPress.B) { 99 | Engine.gameMode = ENGINE_EXITPAUSE; 100 | PlaySFXByName("MenuBack", 0); 101 | pauseMenu->state = 6; 102 | } 103 | break; 104 | case 2: 105 | case 6: 106 | pauseMenu->barPos += 16; 107 | if (pauseMenu->barPos > SCREEN_XSIZE + 64) { 108 | textMenuSurfaceNo = pauseMenu->lastSurfaceNo; 109 | RemoveNativeObject(pauseMenu); 110 | return; 111 | } 112 | break; 113 | case 3: 114 | case 4: 115 | case 5: 116 | // wait (again) 117 | pauseMenu->barPos -= 16; 118 | if (pauseMenu->barPos + 64 < 0) { 119 | switch (pauseMenu->state) { 120 | default: break; 121 | case 3: 122 | stageMode = STAGEMODE_LOAD; 123 | Engine.gameMode = ENGINE_MAINGAME; 124 | break; 125 | case 4: initStartMenu(0); break; 126 | case 5: 127 | Engine.gameMode = ENGINE_DEVMENU; 128 | initDevMenu(); 129 | break; 130 | } 131 | textMenuSurfaceNo = pauseMenu->lastSurfaceNo; 132 | RemoveNativeObject(pauseMenu); 133 | return; 134 | } 135 | break; 136 | } 137 | 138 | if (pauseMenu->menu) { 139 | SetActivePalette(7, 0, SCREEN_YSIZE); 140 | 141 | DrawRectangle(pauseMenu->barPos, 0, SCREEN_XSIZE - pauseMenu->barPos, SCREEN_YSIZE, 0, 0, 0, 0xFF); 142 | DrawTextMenu(pauseMenu->menu, pauseMenu->barPos + 0x28, SCREEN_CENTERY - 0x30); 143 | 144 | SetActivePalette(0, 0, SCREEN_YSIZE); 145 | } 146 | } -------------------------------------------------------------------------------- /Sonic12Decomp/PauseMenu.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NATIVE_PAUSEMENU_H 2 | #define NATIVE_PAUSEMENU_H 3 | 4 | struct NativeEntity_PauseMenu : NativeEntityBase { 5 | byte state; 6 | int timer; 7 | int barPos; 8 | byte selectedOption; 9 | TextMenu *menu; 10 | 11 | int lastSurfaceNo; 12 | }; 13 | 14 | void PauseMenu_Create(void *objPtr); 15 | void PauseMenu_Main(void *objPtr); 16 | 17 | #endif // NATIVE_PAUSEMENU_H -------------------------------------------------------------------------------- /Sonic12Decomp/Reader.hpp: -------------------------------------------------------------------------------- 1 | #ifndef READER_H 2 | #define READER_H 3 | 4 | #if RETRO_USING_SDL 5 | #define FileIO SDL_RWops 6 | #define fOpen(path, mode) SDL_RWFromFile(path, mode) 7 | #define fRead(buffer, elementSize, elementCount, file) SDL_RWread(file, buffer, elementSize, elementCount) 8 | #define fSeek(file, offset, whence) SDL_RWseek(file, offset, whence) 9 | #define fTell(file) SDL_RWtell(file) 10 | #define fClose(file) SDL_RWclose(file) 11 | #define fWrite(buffer, elementSize, elementCount, file) SDL_RWwrite(file, buffer, elementSize, elementCount) 12 | #else 13 | #define FileIO FILE 14 | #define fOpen(path, mode) fopen(path, mode) 15 | #define fRead(buffer, elementSize, elementCount, file) fread(buffer, elementSize, elementCount, file) 16 | #define fSeek(file, offset, whence) fseek(file, offset, whence) 17 | #define fTell(file) ftell(file) 18 | #define fClose(file) fclose(file) 19 | #define fWrite(buffer, elementSize, elementCount, file) fwrite(buffer, elementSize, elementCount, file) 20 | #endif 21 | 22 | struct FileInfo { 23 | char fileName[0x100]; 24 | int fileSize; 25 | int vfileSize; 26 | int readPos; 27 | int bufferPosition; 28 | int virtualFileOffset; 29 | byte eStringPosA; 30 | byte eStringPosB; 31 | byte eStringNo; 32 | byte eNybbleSwap; 33 | bool useEncryption; 34 | byte encryptionStringA[0x10]; 35 | byte encryptionStringB[0x10]; 36 | FileIO *cFileHandle; 37 | }; 38 | 39 | struct RSDKFileInfo { 40 | byte hash[0x10]; 41 | int offset; 42 | int filesize; 43 | bool encrypted; 44 | int fileID; 45 | }; 46 | 47 | struct RSDKContainer { 48 | RSDKFileInfo files[0x400]; 49 | int fileCount; 50 | }; 51 | 52 | extern RSDKContainer rsdkContainer; 53 | extern char rsdkName[0x400]; 54 | 55 | extern char fileName[0x100]; 56 | extern byte fileBuffer[0x2000]; 57 | extern int fileSize; 58 | extern int vFileSize; 59 | extern int readPos; 60 | extern int readSize; 61 | extern int bufferPosition; 62 | extern int virtualFileOffset; 63 | extern bool useEncryption; 64 | extern byte eStringPosA; 65 | extern byte eStringPosB; 66 | extern byte eStringNo; 67 | extern byte eNybbleSwap; 68 | extern byte encryptionStringA[0x10]; 69 | extern byte encryptionStringB[0x10]; 70 | 71 | extern FileIO *cFileHandle; 72 | 73 | inline void CopyFilePath(char *dest, const char *src) 74 | { 75 | strcpy(dest, src); 76 | for (int i = 0;; ++i) { 77 | if (i >= strlen(dest)) { 78 | break; 79 | } 80 | 81 | if (dest[i] == '/') 82 | dest[i] = '\\'; 83 | } 84 | } 85 | bool CheckRSDKFile(const char *filePath); 86 | 87 | bool LoadFile(const char *filePath, FileInfo *fileInfo); 88 | inline bool CloseFile() 89 | { 90 | int result = 0; 91 | if (cFileHandle) 92 | result = fClose(cFileHandle); 93 | 94 | cFileHandle = NULL; 95 | return result; 96 | } 97 | 98 | void GenerateELoadKeys(uint key1, uint key2); 99 | 100 | void FileRead(void *dest, int size); 101 | 102 | inline size_t FillFileBuffer() 103 | { 104 | if (readPos + 0x2000 <= fileSize) 105 | readSize = 0x2000; 106 | else 107 | readSize = fileSize - readPos; 108 | 109 | size_t result = fRead(fileBuffer, 1u, readSize, cFileHandle); 110 | readPos += readSize; 111 | bufferPosition = 0; 112 | return result; 113 | } 114 | 115 | void GetFileInfo(FileInfo *fileInfo); 116 | void SetFileInfo(FileInfo *fileInfo); 117 | size_t GetFilePosition(); 118 | void SetFilePosition(int newPos); 119 | bool ReachedEndOfFile(); 120 | 121 | 122 | size_t FileRead2(FileInfo *info, void *dest, int size); // For Music Streaming 123 | inline bool CloseFile2(FileInfo *info) 124 | { 125 | int result = 0; 126 | if (info->cFileHandle) 127 | result = fClose(info->cFileHandle); 128 | 129 | info->cFileHandle = NULL; 130 | return result; 131 | } 132 | size_t GetFilePosition2(FileInfo *info); 133 | void SetFilePosition2(FileInfo *info, int newPos); 134 | 135 | #endif // !READER_H 136 | -------------------------------------------------------------------------------- /Sonic12Decomp/RetroEngine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RETROENGINE_H 2 | #define RETROENGINE_H 3 | 4 | // Disables POSIX use c++ name blah blah stuff 5 | #pragma warning(disable : 4996) 6 | 7 | // ================ 8 | // STANDARD LIBS 9 | // ================ 10 | #include 11 | #include 12 | 13 | // ================ 14 | // STANDARD TYPES 15 | // ================ 16 | typedef unsigned char byte; 17 | typedef signed char sbyte; 18 | typedef unsigned short ushort; 19 | typedef unsigned int uint; 20 | #ifndef __vita__ 21 | typedef unsigned long long ulong; 22 | #endif 23 | 24 | #define RSDK_DEBUG (1) 25 | 26 | #define RETRO_USE_NETWORKING (0) 27 | #if !RETRO_USE_NETWORKING 28 | #define NETWORK_H //easy way to fuck over network header LOL 29 | #endif 30 | 31 | // Platforms (RSDKv4 only defines these 7 (I assume), but feel free to add your own custom platform define for easier platform code changes) 32 | #define RETRO_WIN (0) 33 | #define RETRO_OSX (1) 34 | #define RETRO_XBOX_360 (2) 35 | #define RETRO_PS3 (3) 36 | #define RETRO_iOS (4) 37 | #define RETRO_ANDROID (5) 38 | #define RETRO_WP7 (6) 39 | #define RETRO_VITA (7) 40 | // Custom Platforms start here 41 | 42 | // Platform types (Game manages platform-specific code such as HUD position using this rather than the above) 43 | #define RETRO_STANDARD (0) 44 | #define RETRO_MOBILE (1) 45 | 46 | #if defined _WIN32 47 | #define RETRO_PLATFORM (RETRO_WIN) 48 | #define RETRO_PLATTYPE (RETRO_STANDARD) 49 | #elif defined __APPLE__ 50 | #if __IPHONEOS__ 51 | #define RETRO_PLATTYPE (RETRO_iOS) 52 | #define RETRO_PLATTYPE (RETRO_MOBILE) 53 | #else 54 | #define RETRO_PLATFORM (RETRO_OSX) 55 | #define RETRO_PLATTYPE (RETRO_STANDARD) 56 | #endif 57 | #elif defined __vita__ 58 | #define RETRO_PLATFORM (RETRO_VITA) 59 | #define RETRO_PLATTYPE (RETRO_STANDARD) 60 | #else 61 | #define RETRO_PLATFORM (RETRO_WIN) 62 | #define RETRO_PLATTYPE (RETRO_STANDARD) 63 | #endif 64 | 65 | #define DEFAULT_SCREEN_XSIZE 424 66 | #define DEFAULT_FULLSCREEN false 67 | 68 | #ifndef BASE_PATH 69 | #define BASE_PATH "" 70 | #endif 71 | 72 | #if RETRO_PLATFORM == RETRO_WINDOWS || RETRO_PLATFORM == RETRO_OSX || RETRO_PLATFORM == RETRO_VITA 73 | #define RETRO_USING_SDL (1) 74 | #else //Since its an else & not an elif these platforms probably aren't supported yet 75 | #define RETRO_USING_SDL (0) 76 | #endif 77 | 78 | #define RETRO_GAME_STANDARD (0) 79 | #define RETRO_GAME_MOBILE (1) 80 | 81 | #if RETRO_PLATFORM == RETRO_iOS || RETRO_PLATFORM == RETRO_ANDROID || RETRO_PLATFORM == RETRO_WP7 82 | #define RETRO_GAMEPLATFORM (RETRO_GAME_MOBILE) 83 | #else 84 | #define RETRO_GAMEPLATFORM (RETRO_GAME_STANDARD) 85 | #endif 86 | 87 | #define RETRO_SW_RENDER (0) 88 | #define RETRO_HW_RENDER (1) 89 | #define RETRO_RENDERTYPE (RETRO_SW_RENDER) 90 | 91 | #define RETRO_USE_HAPTICS (1) 92 | 93 | enum RetroLanguages { 94 | RETRO_EN = 0, 95 | RETRO_FR = 1, 96 | RETRO_IT = 2, 97 | RETRO_DE = 3, 98 | RETRO_ES = 4, 99 | RETRO_JP = 5, 100 | RETRO_PT = 6, 101 | RETRO_RU = 7, 102 | RETRO_KO = 8, 103 | RETRO_ZH = 9, 104 | RETRO_ZS = 10, 105 | }; 106 | 107 | enum RetroStates { 108 | ENGINE_DEVMENU = 0, 109 | ENGINE_MAINGAME = 1, 110 | ENGINE_INITDEVMENU = 2, 111 | ENGINE_WAIT = 3, 112 | ENGINE_SCRIPTERROR = 4, 113 | ENGINE_INITPAUSE = 5, 114 | ENGINE_EXITPAUSE = 6, 115 | ENGINE_ENDGAME = 7, 116 | ENGINE_RESETGAME = 8, 117 | 118 | // Custom GameModes (required to make some features work 119 | ENGINE_CONNECT2PVS = 0x80, 120 | }; 121 | 122 | enum RetroGameType { 123 | GAME_UNKNOWN = 0, 124 | GAME_SONIC1 = 1, 125 | GAME_SONIC2 = 2, 126 | }; 127 | 128 | // General Defines 129 | #define SCREEN_YSIZE (240) 130 | #define SCREEN_CENTERY (SCREEN_YSIZE / 2) 131 | 132 | #if RETRO_PLATFORM == RETRO_WIN 133 | #include 134 | #include 135 | #elif RETRO_PLATFORM == RETRO_OSX 136 | #include 137 | #include 138 | 139 | #include "cocoaHelpers.hpp" 140 | #elif RETRO_PLATFORM == RETRO_VITA 141 | #include 142 | #include 143 | #endif 144 | 145 | extern bool usingCWD; 146 | 147 | //Utils 148 | #include "Ini.hpp" 149 | #include "Network.hpp" 150 | 151 | #include "Math.hpp" 152 | #include "Reader.hpp" 153 | #include "String.hpp" 154 | #include "Animation.hpp" 155 | #include "Audio.hpp" 156 | #include "Input.hpp" 157 | #include "Object.hpp" 158 | #include "Palette.hpp" 159 | #include "Drawing.hpp" 160 | #include "Scene3D.hpp" 161 | #include "Collision.hpp" 162 | #include "Scene.hpp" 163 | #include "Script.hpp" 164 | #include "Sprite.hpp" 165 | #include "Text.hpp" 166 | #include "Userdata.hpp" 167 | #include "Debug.hpp" 168 | 169 | //Native Entities 170 | #include "PauseMenu.hpp" 171 | #include "RetroGameLoop.hpp" 172 | 173 | class RetroEngine 174 | { 175 | public: 176 | bool usingDataFile = false; 177 | bool usingBytecode = false; 178 | 179 | bool initialised = false; 180 | bool running = false; 181 | 182 | int gameMode = 1; 183 | int language = RETRO_EN; 184 | int message = 0; 185 | 186 | bool trialMode = false; 187 | bool onlineActive = true; 188 | bool hapticsEnabled = true; 189 | 190 | int frameSkipSetting = 0; 191 | int frameSkipTimer = 0; 192 | 193 | 194 | // Ported from RSDKv5 195 | bool devMenu = false; 196 | int startList = 0; 197 | int startStage = 0; 198 | int gameSpeed = 1; 199 | int fastForwardSpeed = 8; 200 | bool masterPaused = false; 201 | bool frameStep = false; 202 | 203 | bool showPaletteOverlay = false; 204 | bool useHQModes = true; 205 | 206 | void Init(); 207 | void Run(); 208 | 209 | bool LoadGameConfig(const char *Filepath); 210 | 211 | int callbackMessage = 0; 212 | int prevMessage = 0; 213 | int waitValue = 0; 214 | void Callback(int callbackID); 215 | 216 | bool finishedStartMenu = false; 217 | 218 | char gameWindowText[0x40]; 219 | char gameDescriptionText[0x100]; 220 | const char *gameVersion = "1.1.0"; 221 | #if RETRO_GAMEPLATFORM == RETRO_GAME_STANDARD 222 | const char *gamePlatform = "STANDARD"; // "STANDARD" 223 | #elif RETRO_GAMEPLATFORM == RETRO_GAME_MOBILE 224 | const char *gamePlatform = "MOBILE"; // "MOBILE" 225 | #endif 226 | 227 | #if RETRO_RENDERTYPE == RETRO_SW_RENDER 228 | const char *gameRenderType = "SW_RENDERING"; //"SW_RENDERING" 229 | #elif RETRO_RENDERTYPE == RETRO_HW_RENDER 230 | const char *gameRenderType = "HW_RENDERING"; // "HW_RENDERING" 231 | #endif 232 | 233 | #if RETRO_USE_HAPTICS 234 | const char *gameHapticSetting = "USE_F_FEEDBACK"; //"USE_F_FEEDBACK"; // None is default, but people with controllers exist 235 | #else 236 | const char *gameHapticSetting = "NO_F_FEEDBACK"; //"NO_F_FEEDBACK"; 237 | #endif 238 | 239 | byte gameType = GAME_UNKNOWN; 240 | 241 | ushort *frameBuffer = nullptr; 242 | ushort *frameBuffer2x = nullptr; 243 | 244 | bool isFullScreen = false; 245 | 246 | bool startFullScreen = false; // if should start as fullscreen 247 | bool borderless = false; 248 | bool vsync = false; 249 | int windowScale = 2; 250 | int refreshRate = 60; // user-picked screen update rate 251 | int screenRefreshRate = 60; // hardware screen update rate 252 | int targetRefreshRate = 60; // game logic update rate 253 | 254 | uint frameCount = 0; // frames since scene load 255 | int renderFrameIndex = 0; 256 | int skipFrameIndex = 0; 257 | 258 | #if RETRO_USING_SDL 259 | SDL_Window *window = nullptr; 260 | SDL_Renderer *renderer = nullptr; 261 | SDL_Texture *screenBuffer = nullptr; 262 | SDL_Texture *screenBuffer2x = nullptr; 263 | 264 | SDL_Event sdlEvents; 265 | #endif 266 | }; 267 | 268 | extern RetroEngine Engine; 269 | #endif // !RETROENGINE_H 270 | -------------------------------------------------------------------------------- /Sonic12Decomp/RetroGameLoop.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | void RetroGameLoop_Create(void *objPtr) { 4 | NativeEntity_RetroGameLoop *entity = (NativeEntity_RetroGameLoop *)objPtr; 5 | entity->pauseMenu = nullptr; 6 | } 7 | void RetroGameLoop_Main(void *objPtr) 8 | { 9 | NativeEntity_RetroGameLoop *entity = (NativeEntity_RetroGameLoop *)objPtr; 10 | 11 | switch (Engine.gameMode) { 12 | case ENGINE_DEVMENU: 13 | if (entity->pauseMenu) //dumb fix but yknow how it is 14 | RemoveNativeObject(entity->pauseMenu); 15 | entity->pauseMenu = nullptr; 16 | 17 | processStageSelect(); break; 18 | case ENGINE_MAINGAME: 19 | if (Engine.finishedStartMenu) 20 | ProcessStage(); 21 | else 22 | processStartMenu(); 23 | break; 24 | case ENGINE_INITDEVMENU: 25 | Engine.LoadGameConfig("Data/Game/GameConfig.bin"); 26 | initDevMenu(); 27 | ResetCurrentStageFolder(); 28 | break; 29 | case ENGINE_WAIT: break; 30 | case ENGINE_SCRIPTERROR: 31 | Engine.LoadGameConfig("Data/Game/GameConfig.bin"); 32 | initErrorMessage(); 33 | ResetCurrentStageFolder(); 34 | break; 35 | case ENGINE_INITPAUSE: 36 | PauseSound(); 37 | //ClearNativeObjects(); 38 | Engine.gameMode = ENGINE_WAIT; //temp (maybe?) so pause menu renders on top 39 | // CreateNativeObject(MenuBG_Create, MenuBG_Main); // temp until/if nativeObjs are fully complete 40 | if (entity->pauseMenu && nativeEntityCount > 1) 41 | RemoveNativeObject(entity->pauseMenu); 42 | entity->pauseMenu = (NativeEntity_PauseMenu*)CreateNativeObject(PauseMenu_Create, PauseMenu_Main); 43 | break; 44 | case ENGINE_EXITPAUSE: 45 | Engine.gameMode = ENGINE_MAINGAME; 46 | ResumeSound(); 47 | if (entity->pauseMenu) 48 | RemoveNativeObject(entity->pauseMenu); 49 | entity->pauseMenu = nullptr; 50 | break; 51 | case ENGINE_ENDGAME: 52 | ClearScreen(1); 53 | //RestoreNativeObjects(); 54 | Engine.LoadGameConfig("Data/Game/GameConfig.bin"); 55 | activeStageList = 0; 56 | stageListPosition = 0; 57 | initStartMenu(0); 58 | break; 59 | case ENGINE_RESETGAME: //Also called when 2P VS disconnects 60 | ClearScreen(1); 61 | //RestoreNativeObjects(); 62 | initStartMenu(1); 63 | break; 64 | case ENGINE_CONNECT2PVS: 65 | //connect screen goes here 66 | break; 67 | default: 68 | #if RSDK_DEBUG 69 | printLog("GameMode '%d' Called", Engine.gameMode); 70 | #endif 71 | activeStageList = 0; 72 | stageListPosition = 0; 73 | stageMode = STAGEMODE_LOAD; 74 | Engine.gameMode = ENGINE_MAINGAME; 75 | break; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sonic12Decomp/RetroGameLoop.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NATIVE_RETROGAMELOOP_H 2 | #define NATIVE_RETROGAMELOOP_H 3 | 4 | struct NativeEntity_RetroGameLoop : NativeEntityBase { 5 | //Nothin lol 6 | NativeEntity_PauseMenu *pauseMenu; 7 | }; 8 | 9 | void RetroGameLoop_Create(void *objPtr); 10 | void RetroGameLoop_Main(void *objPtr); 11 | 12 | #endif // !NATIVE_RETROGAMELOOP_H 13 | -------------------------------------------------------------------------------- /Sonic12Decomp/Scene.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_H 2 | #define SCENE_H 3 | 4 | #define LAYER_COUNT (9) 5 | #define DEFORM_STORE (0x100) 6 | #define DEFORM_SIZE (320) 7 | #define DEFORM_COUNT (DEFORM_STORE + DEFORM_SIZE) 8 | #define PARALLAX_COUNT (0x100) 9 | 10 | #define TILE_COUNT (0x400) 11 | #define TILE_SIZE (0x10) 12 | #define CHUNK_SIZE (0x80) 13 | #define TILE_DATASIZE (TILE_SIZE * TILE_SIZE) 14 | #define TILESET_SIZE (TILE_COUNT * TILE_DATASIZE) 15 | 16 | #define TILELAYER_CHUNK_W (0x100) 17 | #define TILELAYER_CHUNK_H (0x100) 18 | #define TILELAYER_CHUNK_MAX (TILELAYER_CHUNK_W * TILELAYER_CHUNK_H) 19 | #define TILELAYER_SCROLL_MAX (TILELAYER_CHUNK_H * CHUNK_SIZE) 20 | 21 | #define CHUNKTILE_COUNT (0x200 * (8 * 8)) 22 | 23 | #define CPATH_COUNT (2) 24 | 25 | enum StageListNames { 26 | STAGELIST_PRESENTATION = 0, 27 | STAGELIST_REGULAR = 1, 28 | STAGELIST_BONUS = 2, 29 | STAGELIST_SPECIAL = 3, 30 | STAGELIST_MAX, //StageList size 31 | }; 32 | 33 | enum TileLayerTypes { 34 | LAYER_NOSCROLL = 0, 35 | LAYER_HSCROLL = 1, 36 | LAYER_VSCROLL = 2, 37 | LAYER_3DFLOOR = 3, 38 | LAYER_3DSKY = 4, 39 | }; 40 | 41 | enum StageModes { 42 | STAGEMODE_LOAD = 0, 43 | STAGEMODE_NORMAL = 1, 44 | STAGEMODE_PAUSED = 2, 45 | STAGEMODE_FROZEN = 3, 46 | STAGEMODE_2P = 4, 47 | STAGEMODE_STEPOVER = 5, 48 | STAGEMODE_PAUSED_STEPOVER = 6, 49 | STAGEMODE_FROZEN_PAUSED = 7, 50 | STAGEMODE_2P_PAUSED = 8 51 | }; 52 | 53 | enum TileInfo { 54 | TILEINFO_INDEX = 0, 55 | TILEINFO_DIRECTION = 1, 56 | TILEINFO_VISUALPLANE = 2, 57 | TILEINFO_SOLIDITYA = 3, 58 | TILEINFO_SOLIDITYB = 4, 59 | TILEINFO_FLAGSA = 5, 60 | TILEINFO_ANGLEA = 6, 61 | TILEINFO_FLAGSB = 7, 62 | TILEINFO_ANGLEB = 8, 63 | }; 64 | 65 | enum DeformationModes { 66 | DEFORM_FG = 0, 67 | DEFORM_FG_WATER = 1, 68 | DEFORM_BG = 2, 69 | DEFORM_BG_WATER = 3, 70 | }; 71 | 72 | struct SceneInfo { 73 | char name[0x40]; 74 | char folder[0x40]; 75 | char id[0x40]; 76 | bool highlighted; 77 | }; 78 | 79 | struct CollisionMasks { 80 | sbyte floorMasks[TILE_COUNT * TILE_SIZE]; 81 | sbyte lWallMasks[TILE_COUNT * TILE_SIZE]; 82 | sbyte rWallMasks[TILE_COUNT * TILE_SIZE]; 83 | sbyte roofMasks[TILE_COUNT * TILE_SIZE]; 84 | uint angles[TILE_COUNT]; 85 | byte flags[TILE_COUNT]; 86 | }; 87 | 88 | struct TileLayer { 89 | ushort tiles[TILELAYER_CHUNK_MAX]; 90 | byte lineScroll[TILELAYER_SCROLL_MAX]; 91 | int parallaxFactor; 92 | int scrollSpeed; 93 | int scrollPos; 94 | int angle; 95 | int XPos; 96 | int YPos; 97 | int ZPos; 98 | int deformationOffset; 99 | int deformationOffsetW; 100 | byte type; 101 | byte width; 102 | byte height; 103 | }; 104 | 105 | struct LineScroll { 106 | int parallaxFactor[PARALLAX_COUNT]; 107 | int scrollSpeed[PARALLAX_COUNT]; 108 | int scrollPos[PARALLAX_COUNT]; 109 | int tilePos[PARALLAX_COUNT]; 110 | int deform[PARALLAX_COUNT]; 111 | byte entryCount; 112 | }; 113 | 114 | struct Tiles128x128 { 115 | int gfxDataPos[CHUNKTILE_COUNT]; 116 | ushort tileIndex[CHUNKTILE_COUNT]; 117 | byte direction[CHUNKTILE_COUNT]; 118 | byte visualPlane[CHUNKTILE_COUNT]; 119 | byte collisionFlags[CPATH_COUNT][CHUNKTILE_COUNT]; 120 | }; 121 | 122 | extern int stageListCount[STAGELIST_MAX]; 123 | extern char stageListNames[STAGELIST_MAX][0x20]; 124 | extern SceneInfo stageList[STAGELIST_MAX][0x100]; 125 | 126 | extern int stageMode; 127 | 128 | extern int cameraTarget; 129 | extern int cameraStyle; 130 | extern int cameraEnabled; 131 | extern int cameraAdjustY; 132 | extern int xScrollOffset; 133 | extern int yScrollOffset; 134 | extern int cameraXPos; 135 | extern int cameraYPos; 136 | extern int cameraShift; 137 | extern int cameraLockedY; 138 | extern int cameraShakeX; 139 | extern int cameraShakeY; 140 | extern int cameraLag; 141 | extern int cameraLagStyle; 142 | 143 | extern int curXBoundary1; 144 | extern int newXBoundary1; 145 | extern int curYBoundary1; 146 | extern int newYBoundary1; 147 | extern int curXBoundary2; 148 | extern int curYBoundary2; 149 | extern int waterLevel; 150 | extern int waterDrawPos; 151 | extern int newXBoundary2; 152 | extern int newYBoundary2; 153 | 154 | extern int SCREEN_SCROLL_LEFT; 155 | extern int SCREEN_SCROLL_RIGHT; 156 | #define SCREEN_SCROLL_UP ((SCREEN_YSIZE / 2) - 16) 157 | #define SCREEN_SCROLL_DOWN ((SCREEN_YSIZE / 2) + 16) 158 | 159 | extern int lastXSize; 160 | extern int lastYSize; 161 | 162 | extern bool pauseEnabled; 163 | extern bool timeEnabled; 164 | extern bool debugMode; 165 | extern int frameCounter; 166 | extern int stageMilliseconds; 167 | extern int stageSeconds; 168 | extern int stageMinutes; 169 | 170 | // Category and Scene IDs 171 | extern int activeStageList; 172 | extern int stageListPosition; 173 | extern char currentStageFolder[0x100]; 174 | extern int actID; 175 | 176 | extern char titleCardText[0x100]; 177 | extern byte titleCardWord2; 178 | 179 | extern byte activeTileLayers[4]; 180 | extern byte tLayerMidPoint; 181 | extern TileLayer stageLayouts[LAYER_COUNT]; 182 | 183 | extern int bgDeformationData0[DEFORM_COUNT]; 184 | extern int bgDeformationData1[DEFORM_COUNT]; 185 | extern int bgDeformationData2[DEFORM_COUNT]; 186 | extern int bgDeformationData3[DEFORM_COUNT]; 187 | 188 | extern LineScroll hParallax; 189 | extern LineScroll vParallax; 190 | 191 | extern Tiles128x128 tiles128x128; 192 | extern CollisionMasks collisionMasks[2]; 193 | 194 | extern byte tilesetGFXData[TILESET_SIZE]; 195 | 196 | extern ushort tile3DFloorBuffer[0x13334]; 197 | extern bool drawStageGFXHQ; 198 | 199 | void InitFirstStage(); 200 | void InitStartingStage(int list, int stage, int player); 201 | void ProcessStage(); 202 | 203 | void ProcessParallaxAutoScroll(); 204 | 205 | void ResetBackgroundSettings(); 206 | inline void ResetCurrentStageFolder() { strcpy(currentStageFolder, ""); } 207 | inline bool CheckCurrentStageFolder(int stage) 208 | { 209 | if (strcmp(currentStageFolder, stageList[activeStageList][stage].folder) == 0) { 210 | return true; 211 | } 212 | else { 213 | strcpy(currentStageFolder, stageList[activeStageList][stage].folder); 214 | return false; 215 | } 216 | } 217 | 218 | void LoadStageFiles(); 219 | int LoadActFile(const char *ext, int stageID, FileInfo *info); 220 | int LoadStageFile(const char *filePath, int stageID, FileInfo *info); 221 | 222 | void LoadActLayout(); 223 | void LoadStageBackground(); 224 | void LoadStageChunks(); 225 | void LoadStageCollisions(); 226 | void LoadStageGIFFile(int stageID); 227 | 228 | inline void Init3DFloorBuffer(int layerID) 229 | { 230 | for (int y = 0; y < TILELAYER_CHUNK_H; ++y) { 231 | for (int x = 0; x < TILELAYER_CHUNK_W; ++x) { 232 | int c = stageLayouts[layerID].tiles[(x >> 3) + (y >> 3 << 8)] << 6; 233 | int tx = x & 7; 234 | tile3DFloorBuffer[x + (y << 8)] = c + tx + ((y & 7) << 3); 235 | } 236 | } 237 | } 238 | 239 | inline void Copy16x16Tile(ushort dest, ushort src) 240 | { 241 | byte *destPtr = &tilesetGFXData[TILELAYER_CHUNK_W * dest]; 242 | byte *srcPtr = &tilesetGFXData[TILELAYER_CHUNK_W * src]; 243 | int cnt = TILE_DATASIZE; 244 | while (cnt--) *destPtr++ = *srcPtr++; 245 | } 246 | 247 | void SetLayerDeformation(int deformID, int deformationA, int deformationB, int deformType, int deformOffset, int deformCount); 248 | 249 | void SetPlayerScreenPosition(Entity *target); 250 | void SetPlayerScreenPositionCDStyle(Entity *target); 251 | void SetPlayerHLockedScreenPosition(Entity *target); 252 | void SetPlayerLockedScreenPosition(Entity *target); 253 | void SetPlayerScreenPositionFixed(Entity *target); 254 | 255 | #endif // !SCENE_H 256 | -------------------------------------------------------------------------------- /Sonic12Decomp/Scene3D.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DRAWING3D_H 2 | #define DRAWING3D_H 3 | 4 | #define VERTEXBUFFER_SIZE (0x1000) 5 | #define FACEBUFFER_SIZE (0x400) 6 | 7 | enum FaceFlags { 8 | FACE_FLAG_TEXTURED_3D = 0, 9 | FACE_FLAG_TEXTURED_2D = 1, 10 | FACE_FLAG_COLOURED_3D = 2, 11 | FACE_FLAG_COLOURED_2D = 3, 12 | FACE_FLAG_FADED = 4, 13 | FACE_FLAG_TEXTURED_C = 5, 14 | FACE_FLAG_TEXTURED_D = 6, 15 | FACE_FLAG_3DSPRITE = 7 16 | }; 17 | 18 | enum MatrixTypes { 19 | MAT_WORLD = 0, 20 | MAT_VIEW = 1, 21 | MAT_TEMP = 2, 22 | }; 23 | 24 | struct Matrix { 25 | int values[4][4]; 26 | }; 27 | 28 | struct Vertex { 29 | int x; 30 | int y; 31 | int z; 32 | int u; 33 | int v; 34 | }; 35 | 36 | struct Face { 37 | int a; 38 | int b; 39 | int c; 40 | int d; 41 | uint colour; 42 | int flag; 43 | }; 44 | 45 | struct DrawListEntry3D { 46 | int faceID; 47 | int depth; 48 | }; 49 | 50 | extern int vertexCount; 51 | extern int faceCount; 52 | 53 | extern Matrix matFinal; 54 | extern Matrix matWorld; 55 | extern Matrix matView; 56 | extern Matrix matTemp; 57 | 58 | extern Face faceBuffer[FACEBUFFER_SIZE]; 59 | extern Vertex vertexBuffer[VERTEXBUFFER_SIZE]; 60 | extern Vertex vertexBufferT[VERTEXBUFFER_SIZE]; 61 | 62 | extern DrawListEntry3D drawList3D[FACEBUFFER_SIZE]; 63 | 64 | extern int projectionX; 65 | extern int projectionY; 66 | extern int fogColour; 67 | extern int fogStrength; 68 | 69 | extern int faceLineStart[SCREEN_YSIZE]; 70 | extern int faceLineEnd[SCREEN_YSIZE]; 71 | extern int faceLineStartU[SCREEN_YSIZE]; 72 | extern int faceLineEndU[SCREEN_YSIZE]; 73 | extern int faceLineStartV[SCREEN_YSIZE]; 74 | extern int faceLineEndV[SCREEN_YSIZE]; 75 | 76 | void setIdentityMatrix(Matrix *matrix); 77 | void matrixMultiply(Matrix *matrixA, Matrix *matrixB); 78 | void matrixTranslateXYZ(Matrix *Matrix, int XPos, int YPos, int ZPos); 79 | void matrixScaleXYZ(Matrix *matrix, int scaleX, int scaleY, int scaleZ); 80 | void matrixRotateX(Matrix *matrix, int rotationX); 81 | void matrixRotateY(Matrix *matrix, int rotationY); 82 | void matrixRotateZ(Matrix *matrix, int rotationZ); 83 | void matrixRotateXYZ(Matrix *matrix, short rotationX, short rotationY, short rotationZ); 84 | void matrixInverse(Matrix *matrix); 85 | void transformVertexBuffer(); 86 | void transformVertices(Matrix *matrix, int startIndex, int endIndex); 87 | void sort3DDrawList(); 88 | void draw3DScene(int spriteSheetID); 89 | 90 | void processScanEdge(Vertex *vertA, Vertex *vertB); 91 | void processScanEdgeUV(Vertex *vertA, Vertex *vertB); 92 | 93 | #endif // !DRAWING3D_H 94 | -------------------------------------------------------------------------------- /Sonic12Decomp/Script.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SCRIPT_H 2 | #define SCRIPT_H 3 | 4 | #define SCRIPTDATA_COUNT (0x100000) 5 | #define JUMPTABLE_COUNT (0x10000) 6 | #define FUNCTION_COUNT (0x200) 7 | 8 | #define JUMPSTACK_COUNT (0x400) 9 | #define FUNCSTACK_COUNT (0x400) 10 | #define FORSTACK_COUNT (0x400) 11 | 12 | struct ScriptPtr { 13 | int scriptCodePtr; 14 | int jumpTablePtr; 15 | }; 16 | 17 | struct ObjectScript { 18 | int frameCount; 19 | int spriteSheetID; 20 | ScriptPtr eventMain; 21 | ScriptPtr eventDraw; 22 | ScriptPtr eventStartup; 23 | int frameListOffset; 24 | AnimationFile* animFile; 25 | }; 26 | 27 | struct ScriptEngine { 28 | int operands[0x10]; 29 | int tempValue[8]; 30 | int arrayPosition[9]; 31 | // int currentPlayer; // ArrayPos[6] 32 | // int playerCount; // ArrayPos[7] 33 | // int tempObjectPos; // ArrayPos[8] 34 | int checkResult; 35 | }; 36 | 37 | #define TABLE_COUNT (0x200) 38 | #define TABLE_ENTRY_COUNT (0x400) 39 | 40 | struct StaticInfo { 41 | StaticInfo() 42 | { 43 | StrCopy(name, ""); 44 | value = 0; 45 | dataPos = SCRIPTDATA_COUNT - 1; 46 | } 47 | StaticInfo(const char *aliasName, int val) 48 | { 49 | StrCopy(name, aliasName); 50 | value = val; 51 | dataPos = SCRIPTDATA_COUNT - 1; 52 | } 53 | 54 | char name[0x20]; 55 | int value; 56 | int dataPos; 57 | }; 58 | 59 | struct TableInfo { 60 | TableInfo() 61 | { 62 | StrCopy(name, ""); 63 | valueCount = 0; 64 | dataPos = SCRIPTDATA_COUNT - 1; 65 | } 66 | TableInfo(const char *aliasName, int valCnt) 67 | { 68 | StrCopy(name, aliasName); 69 | valueCount = valCnt; 70 | dataPos = SCRIPTDATA_COUNT - 1; 71 | } 72 | 73 | char name[0x20]; 74 | int valueCount; 75 | StaticInfo values[TABLE_ENTRY_COUNT]; 76 | int dataPos; 77 | }; 78 | 79 | enum ScriptSubs { EVENT_MAIN = 0, EVENT_DRAW = 1, EVENT_SETUP = 2 }; 80 | 81 | extern ObjectScript objectScriptList[OBJECT_COUNT]; 82 | extern ScriptPtr functionScriptList[FUNCTION_COUNT]; 83 | 84 | extern int scriptData[SCRIPTDATA_COUNT]; 85 | extern int jumpTableData[JUMPTABLE_COUNT]; 86 | 87 | extern int jumpTableStack[JUMPSTACK_COUNT]; 88 | extern int functionStack[FUNCSTACK_COUNT]; 89 | extern int foreachStack[FORSTACK_COUNT]; 90 | 91 | extern int scriptCodePos; //Bytecode reading offset 92 | extern int jumpTablePos; //Bytecode reading offset 93 | extern int jumpTableStackPos; 94 | extern int functionStackPos; 95 | extern int foreachStackPos; 96 | 97 | extern ScriptEngine scriptEng; 98 | extern char scriptText[0x4000]; 99 | 100 | extern int scriptDataPos; 101 | extern int scriptDataOffset; 102 | extern int jumpTableDataPos; 103 | extern int jumpTableDataOffset; 104 | 105 | extern int scriptFunctionCount; 106 | extern char scriptFunctionNames[FUNCTION_COUNT][0x20]; 107 | 108 | extern int lineID; 109 | 110 | void CheckAliasText(char *text); 111 | void CheckStaticText(char *text); 112 | TableInfo *CheckTableText(char *text); 113 | void ConvertArithmaticSyntax(char *text); 114 | void ConvertIfWhileStatement(char *text); 115 | void ConvertForeachStatement(char *text); 116 | bool ConvertSwitchStatement(char *text); 117 | void ConvertFunctionText(char *text); 118 | void CheckCaseNumber(char *text); 119 | bool ReadSwitchCase(char *text); 120 | void ReadTableValues(char *text); 121 | void AppendIntegerToString(char *text, int value); 122 | void AppendIntegerToStringW(ushort *text, int value); 123 | bool ConvertStringToInteger(const char *text, int *value); 124 | void CopyAliasStr(char *dest, char *text, bool arrayIndex); 125 | bool CheckOpcodeType(char *text); // Never actually used 126 | 127 | void ParseScriptFile(char *scriptName, int scriptID); 128 | void LoadBytecode(int stageListID, int scriptID); 129 | 130 | void ProcessScript(int scriptCodePtr, int jumpTablePtr, byte scriptSub); 131 | 132 | void ClearScriptData(void); 133 | 134 | #endif // !SCRIPT_H -------------------------------------------------------------------------------- /Sonic12Decomp/Sonic12Decomp.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "winres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United Kingdom) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | #endif // English (United Kingdom) resources 48 | ///////////////////////////////////////////////////////////////////////////// 49 | 50 | 51 | ///////////////////////////////////////////////////////////////////////////// 52 | // English (Australia) resources 53 | 54 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) 55 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS 56 | #pragma code_page(1252) 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | VS_VERSION_INFO VERSIONINFO 64 | FILEVERSION 1,0,0,0 65 | PRODUCTVERSION 1,0,0,0 66 | FILEFLAGSMASK 0x3fL 67 | #ifdef _DEBUG 68 | FILEFLAGS 0x1L 69 | #else 70 | FILEFLAGS 0x0L 71 | #endif 72 | FILEOS 0x40004L 73 | FILETYPE 0x1L 74 | FILESUBTYPE 0x0L 75 | BEGIN 76 | BLOCK "StringFileInfo" 77 | BEGIN 78 | BLOCK "0c0904b0" 79 | BEGIN 80 | VALUE "CompanyName", "RSDKv4/Sonic 1/2 (2013) By Christian 'The Taxman' Whitehead & Simon 'Stealth' Thomley, Decompilation By Rubberduckycooly/RMGRich" 81 | VALUE "FileDescription", "RSDKv4" 82 | VALUE "FileVersion", "1.0.0" 83 | VALUE "InternalName", "RSDKv4.exe" 84 | VALUE "OriginalFilename", "RSDKv4.exe" 85 | VALUE "ProductName", "RSDKv4" 86 | VALUE "ProductVersion", "1.0.0" 87 | END 88 | END 89 | BLOCK "VarFileInfo" 90 | BEGIN 91 | VALUE "Translation", 0xc09, 1200 92 | END 93 | END 94 | 95 | #endif // English (Australia) resources 96 | ///////////////////////////////////////////////////////////////////////////// 97 | 98 | 99 | 100 | #ifndef APSTUDIO_INVOKED 101 | ///////////////////////////////////////////////////////////////////////////// 102 | // 103 | // Generated from the TEXTINCLUDE 3 resource. 104 | // 105 | 106 | 107 | ///////////////////////////////////////////////////////////////////////////// 108 | #endif // not APSTUDIO_INVOKED 109 | 110 | -------------------------------------------------------------------------------- /Sonic12Decomp/Sonic12Decomp.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 | 16.0 23 | {BD4A4266-8ED9-491E-B4CC-3F63F0D39C1B} 24 | Win32Proj 25 | Sonic12Decomp 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)build\$(Platform)\$(Configuration)\ 76 | RSDKv4 77 | $(Platform)\$(Configuration)\ 78 | 79 | 80 | true 81 | $(SolutionDir)build\$(Platform)\$(Configuration)\ 82 | RSDKv4_64 83 | 84 | 85 | false 86 | $(SolutionDir)build\$(Platform)\$(Configuration)\ 87 | RSDKv4 88 | $(Platform)\$(Configuration)\ 89 | 90 | 91 | false 92 | $(SolutionDir)build\$(Platform)\$(Configuration)\ 93 | RSDKv4_64 94 | 95 | 96 | 97 | NotUsing 98 | Level1 99 | true 100 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 101 | true 102 | $(SolutionDir)dependencies/windows/SDL2/include/;$(SolutionDir)dependencies/windows/libogg/include/;$(SolutionDir)dependencies/windows/libvorbis/include/;$(SolutionDir)dependencies/windows/libtheora/include/;$(SolutionDir)dependencies/all/asio/include;%(AdditionalIncludeDirectories) 103 | 104 | 105 | Console 106 | true 107 | $(SolutionDir)dependencies/windows/SDL2/lib/$(PlatformTargetAsMSBuildArchitecture)/;$(SolutionDir)dependencies/windows/libvorbis/win32/VS2010/$(Platform)/$(Configuration)/;$(SolutionDir)dependencies/windows/libogg/win32/VS2015/$(Platform)/$(Configuration)/ 108 | SDL2.lib;SDL2main.lib;libogg.lib;libvorbis_static.lib;libvorbisfile_static.lib;Shell32.lib 109 | 110 | 111 | copy /Y "$(SolutionDir)dependencies\windows\SDL2\lib\$(PlatformTargetAsMSBuildArchitecture)\SDL2.dll" "$(OutDir)" 112 | 113 | 114 | copying SDL2 library DLL to the build directory. build should fail if it's not found 115 | 116 | 117 | 118 | 119 | NotUsing 120 | Level1 121 | true 122 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | true 124 | $(SolutionDir)dependencies/windows/SDL2/include/;$(SolutionDir)dependencies/windows/libogg/include/;$(SolutionDir)dependencies/windows/libvorbis/include/;$(SolutionDir)dependencies/windows/libtheora/include/;$(SolutionDir)dependencies/all/asio/include;%(AdditionalIncludeDirectories) 125 | 126 | 127 | Console 128 | true 129 | $(SolutionDir)dependencies/windows/SDL2/lib/$(PlatformTargetAsMSBuildArchitecture)/;$(SolutionDir)dependencies/windows/libvorbis/win32/VS2010/$(Platform)/$(Configuration)/;$(SolutionDir)dependencies/windows/libogg/win32/VS2015/$(Platform)/$(Configuration)/ 130 | SDL2.lib;SDL2main.lib;libogg.lib;libvorbis_static.lib;libvorbisfile_static.lib;Shell32.lib 131 | 132 | 133 | copy /Y "$(SolutionDir)dependencies\windows\SDL2\lib\$(PlatformTargetAsMSBuildArchitecture)\SDL2.dll" "$(OutDir)" 134 | 135 | 136 | copying SDL2 library DLL to the build directory. build should fail if it's not found 137 | 138 | 139 | 140 | 141 | NotUsing 142 | Level1 143 | true 144 | true 145 | true 146 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 147 | true 148 | $(SolutionDir)dependencies/windows/SDL2/include/;$(SolutionDir)dependencies/windows/libogg/include/;$(SolutionDir)dependencies/windows/libvorbis/include/;$(SolutionDir)dependencies/windows/libtheora/include/;$(SolutionDir)dependencies/all/asio/include;%(AdditionalIncludeDirectories) 149 | 150 | 151 | Console 152 | true 153 | true 154 | true 155 | $(SolutionDir)dependencies/windows/SDL2/lib/$(PlatformTargetAsMSBuildArchitecture)/;$(SolutionDir)dependencies/windows/libvorbis/win32/VS2010/$(Platform)/$(Configuration)/;$(SolutionDir)dependencies/windows/libogg/win32/VS2015/$(Platform)/$(Configuration)/ 156 | SDL2.lib;SDL2main.lib;libogg.lib;libvorbis_static.lib;libvorbisfile_static.lib;Shell32.lib 157 | 158 | 159 | copy /Y "$(SolutionDir)dependencies\windows\SDL2\lib\$(PlatformTargetAsMSBuildArchitecture)\SDL2.dll" "$(OutDir)" 160 | 161 | 162 | copying SDL2 library DLL to the build directory. build should fail if it's not found 163 | 164 | 165 | 166 | 167 | NotUsing 168 | Level1 169 | true 170 | true 171 | true 172 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 173 | true 174 | $(SolutionDir)dependencies/windows/SDL2/include/;$(SolutionDir)dependencies/windows/libogg/include/;$(SolutionDir)dependencies/windows/libvorbis/include/;$(SolutionDir)dependencies/windows/libtheora/include/;$(SolutionDir)dependencies/all/asio/include;%(AdditionalIncludeDirectories) 175 | 176 | 177 | Console 178 | true 179 | true 180 | true 181 | $(SolutionDir)dependencies/windows/SDL2/lib/$(PlatformTargetAsMSBuildArchitecture)/;$(SolutionDir)dependencies/windows/libvorbis/win32/VS2010/$(Platform)/$(Configuration)/;$(SolutionDir)dependencies/windows/libogg/win32/VS2015/$(Platform)/$(Configuration)/ 182 | SDL2.lib;SDL2main.lib;libogg.lib;libvorbis_static.lib;libvorbisfile_static.lib;Shell32.lib 183 | 184 | 185 | copy /Y "$(SolutionDir)dependencies\windows\SDL2\lib\$(PlatformTargetAsMSBuildArchitecture)\SDL2.dll" "$(OutDir)" 186 | 187 | 188 | copying SDL2 library DLL to the build directory. build should fail if it's not found 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /Sonic12Decomp/Sonic12Decomp.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 | {1890ac66-74c7-48ee-b3f4-2b4280f370b4} 18 | 19 | 20 | {65197e20-a952-4014-93ca-c21e07885ac7} 21 | 22 | 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 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | Header Files 62 | 63 | 64 | Header Files 65 | 66 | 67 | Header Files 68 | 69 | 70 | Header Files 71 | 72 | 73 | Header Files 74 | 75 | 76 | Header Files 77 | 78 | 79 | Header Files 80 | 81 | 82 | Header Files 83 | 84 | 85 | Header Files\nativeEntities 86 | 87 | 88 | Header Files\nativeEntities 89 | 90 | 91 | Header Files 92 | 93 | 94 | 95 | 96 | Source Files 97 | 98 | 99 | Source Files 100 | 101 | 102 | Source Files 103 | 104 | 105 | Source Files 106 | 107 | 108 | Source Files 109 | 110 | 111 | Source Files 112 | 113 | 114 | Source Files 115 | 116 | 117 | Source Files 118 | 119 | 120 | Source Files 121 | 122 | 123 | Source Files 124 | 125 | 126 | Source Files 127 | 128 | 129 | Source Files 130 | 131 | 132 | Source Files 133 | 134 | 135 | Source Files 136 | 137 | 138 | Source Files 139 | 140 | 141 | Source Files 142 | 143 | 144 | Source Files 145 | 146 | 147 | Source Files 148 | 149 | 150 | Source Files 151 | 152 | 153 | Source Files 154 | 155 | 156 | Source Files\nativeEntities 157 | 158 | 159 | Source Files\nativeEntities 160 | 161 | 162 | Source Files 163 | 164 | 165 | 166 | 167 | Resource Files 168 | 169 | 170 | -------------------------------------------------------------------------------- /Sonic12Decomp/Sprite.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | struct GifDecoder { 4 | int depth; 5 | int clearCode; 6 | int eofCode; 7 | int runningCode; 8 | int runningBits; 9 | int prevCode; 10 | int currentCode; 11 | int maxCodePlusOne; 12 | int stackPtr; 13 | int shiftState; 14 | int fileState; 15 | int position; 16 | int bufferSize; 17 | uint shiftData; 18 | uint pixelCount; 19 | byte buffer[256]; 20 | byte stack[4096]; 21 | byte suffix[4096]; 22 | uint prefix[4096]; 23 | }; 24 | 25 | const int LOADING_IMAGE = 0; 26 | const int LOAD_COMPLETE = 1; 27 | const int LZ_MAX_CODE = 4095; 28 | const int LZ_BITS = 12; 29 | const int FIRST_CODE = 4097; 30 | const int NO_SUCH_CODE = 4098; 31 | 32 | struct GifDecoder gifDecoder; 33 | int codeMasks[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095 }; 34 | 35 | int ReadGifCode(void); 36 | byte ReadGifByte(void); 37 | byte TraceGifPrefix(uint *prefix, int code, int clearCode); 38 | 39 | void InitGifDecoder() 40 | { 41 | int val = 0; 42 | FileRead(&val, 1); 43 | gifDecoder.fileState = LOADING_IMAGE; 44 | gifDecoder.position = 0; 45 | gifDecoder.bufferSize = 0; 46 | gifDecoder.buffer[0] = 0; 47 | gifDecoder.depth = val; 48 | gifDecoder.clearCode = 1 << val; 49 | gifDecoder.eofCode = gifDecoder.clearCode + 1; 50 | gifDecoder.runningCode = gifDecoder.eofCode + 1; 51 | gifDecoder.runningBits = val + 1; 52 | gifDecoder.maxCodePlusOne = 1 << gifDecoder.runningBits; 53 | gifDecoder.stackPtr = 0; 54 | gifDecoder.prevCode = NO_SUCH_CODE; 55 | gifDecoder.shiftState = 0; 56 | gifDecoder.shiftData = 0u; 57 | for (int i = 0; i <= LZ_MAX_CODE; ++i) gifDecoder.prefix[i] = (byte)NO_SUCH_CODE; 58 | } 59 | void ReadGifLine(byte *line, int length, int offset) 60 | { 61 | int i = 0; 62 | int stackPtr = gifDecoder.stackPtr; 63 | int eofCode = gifDecoder.eofCode; 64 | int clearCode = gifDecoder.clearCode; 65 | int prevCode = gifDecoder.prevCode; 66 | if (stackPtr != 0) { 67 | while (stackPtr != 0) { 68 | if (i >= length) { 69 | break; 70 | } 71 | line[offset++] = gifDecoder.stack[--stackPtr]; 72 | i++; 73 | } 74 | } 75 | while (i < length) { 76 | int gifCode = ReadGifCode(); 77 | if (gifCode == eofCode) { 78 | if (i != length - 1 | gifDecoder.pixelCount != 0u) { 79 | return; 80 | } 81 | i++; 82 | } 83 | else { 84 | if (gifCode == clearCode) { 85 | for (int j = 0; j <= LZ_MAX_CODE; j++) { 86 | gifDecoder.prefix[j] = NO_SUCH_CODE; 87 | } 88 | gifDecoder.runningCode = gifDecoder.eofCode + 1; 89 | gifDecoder.runningBits = gifDecoder.depth + 1; 90 | gifDecoder.maxCodePlusOne = 1 << gifDecoder.runningBits; 91 | prevCode = (gifDecoder.prevCode = NO_SUCH_CODE); 92 | } 93 | else { 94 | if (gifCode < clearCode) { 95 | line[offset] = (byte)gifCode; 96 | offset++; 97 | i++; 98 | } 99 | else { 100 | if (gifCode<0 | gifCode> LZ_MAX_CODE) { 101 | return; 102 | } 103 | int code; 104 | if (gifDecoder.prefix[gifCode] == NO_SUCH_CODE) { 105 | if (gifCode != gifDecoder.runningCode - 2) { 106 | return; 107 | } 108 | code = prevCode; 109 | gifDecoder.suffix[gifDecoder.runningCode - 2] = 110 | (gifDecoder.stack[stackPtr++] = TraceGifPrefix(gifDecoder.prefix, prevCode, clearCode)); 111 | } 112 | else { 113 | code = gifCode; 114 | } 115 | int c = 0; 116 | while (c++ <= LZ_MAX_CODE && code > clearCode && code <= LZ_MAX_CODE) { 117 | gifDecoder.stack[stackPtr++] = gifDecoder.suffix[code]; 118 | code = gifDecoder.prefix[code]; 119 | } 120 | if (c >= LZ_MAX_CODE | code > LZ_MAX_CODE) { 121 | return; 122 | } 123 | gifDecoder.stack[stackPtr++] = (byte)code; 124 | while (stackPtr != 0 && i++ < length) { 125 | line[offset++] = gifDecoder.stack[--stackPtr]; 126 | } 127 | } 128 | if (prevCode != NO_SUCH_CODE) { 129 | if (gifDecoder.runningCode<2 | gifDecoder.runningCode> FIRST_CODE) { 130 | return; 131 | } 132 | gifDecoder.prefix[gifDecoder.runningCode - 2] = prevCode; 133 | if (gifCode == gifDecoder.runningCode - 2) { 134 | gifDecoder.suffix[gifDecoder.runningCode - 2] = TraceGifPrefix(gifDecoder.prefix, prevCode, clearCode); 135 | } 136 | else { 137 | gifDecoder.suffix[gifDecoder.runningCode - 2] = TraceGifPrefix(gifDecoder.prefix, gifCode, clearCode); 138 | } 139 | } 140 | prevCode = gifCode; 141 | } 142 | } 143 | } 144 | gifDecoder.prevCode = prevCode; 145 | gifDecoder.stackPtr = stackPtr; 146 | } 147 | 148 | int ReadGifCode() 149 | { 150 | while (gifDecoder.shiftState < gifDecoder.runningBits) { 151 | byte b = ReadGifByte(); 152 | gifDecoder.shiftData |= (uint)((uint)b << gifDecoder.shiftState); 153 | gifDecoder.shiftState += 8; 154 | } 155 | int result = (int)((unsigned long)gifDecoder.shiftData & (unsigned long)(codeMasks[gifDecoder.runningBits])); 156 | gifDecoder.shiftData >>= gifDecoder.runningBits; 157 | gifDecoder.shiftState -= gifDecoder.runningBits; 158 | if (++gifDecoder.runningCode > gifDecoder.maxCodePlusOne && gifDecoder.runningBits < LZ_BITS) { 159 | gifDecoder.maxCodePlusOne <<= 1; 160 | gifDecoder.runningBits++; 161 | } 162 | return result; 163 | } 164 | 165 | byte ReadGifByte() 166 | { 167 | byte c = '\0'; 168 | if (gifDecoder.fileState == LOAD_COMPLETE) 169 | return c; 170 | 171 | byte b; 172 | if (gifDecoder.position == gifDecoder.bufferSize) { 173 | FileRead(&b, 1); 174 | gifDecoder.bufferSize = (int)b; 175 | if (gifDecoder.bufferSize == 0) { 176 | gifDecoder.fileState = LOAD_COMPLETE; 177 | return c; 178 | } 179 | FileRead(gifDecoder.buffer, gifDecoder.bufferSize); 180 | b = gifDecoder.buffer[0]; 181 | gifDecoder.position = 1; 182 | } 183 | else { 184 | b = gifDecoder.buffer[gifDecoder.position++]; 185 | } 186 | return b; 187 | } 188 | 189 | byte TraceGifPrefix(uint *prefix, int code, int clearCode) 190 | { 191 | int i = 0; 192 | while (code > clearCode && i++ <= LZ_MAX_CODE) code = prefix[code]; 193 | 194 | return code; 195 | } 196 | void ReadGifPictureData(int width, int height, bool interlaced, byte *gfxData, int offset) 197 | { 198 | int array[] = { 0, 4, 2, 1 }; 199 | int array2[] = { 8, 8, 4, 2 }; 200 | InitGifDecoder(); 201 | if (interlaced) { 202 | for (int i = 0; i < 4; ++i) { 203 | for (int j = array[i]; j < height; j += array2[i]) { 204 | ReadGifLine(gfxData, width, j * width + offset); 205 | } 206 | } 207 | return; 208 | } 209 | for (int h = 0; h < height; ++h) ReadGifLine(gfxData, width, h * width + offset); 210 | } 211 | 212 | int AddGraphicsFile(const char *filePath) 213 | { 214 | char sheetPath[0x100]; 215 | 216 | StrCopy(sheetPath, "Data/Sprites/"); 217 | StrAdd(sheetPath, filePath); 218 | int sheetID = 0; 219 | while (StrLength(gfxSurface[sheetID].fileName) > 0) { 220 | if (StrComp(gfxSurface[sheetID].fileName, sheetPath)) 221 | return sheetID; 222 | if (++sheetID == SURFACE_MAX) // Max Sheet cnt 223 | return 0; 224 | } 225 | byte fileExtension = (byte)sheetPath[(StrLength(sheetPath) - 1) & 0xFF]; 226 | switch (fileExtension) { 227 | case 'f': LoadGIFFile(sheetPath, sheetID); break; 228 | case 'p': LoadBMPFile(sheetPath, sheetID); break; 229 | case 'r': LoadPVRFile(sheetPath, sheetID); break; 230 | } 231 | 232 | return sheetID; 233 | } 234 | void RemoveGraphicsFile(const char *filePath, int sheetID) 235 | { 236 | if (sheetID < 0) { 237 | for (int i = 0; i < SURFACE_MAX; ++i) { 238 | if (StrLength(gfxSurface[i].fileName) > 0 && StrComp(gfxSurface[i].fileName, filePath)) 239 | sheetID = i; 240 | } 241 | } 242 | 243 | if (sheetID >= 0 && StrLength(gfxSurface[sheetID].fileName)) { 244 | StrCopy(gfxSurface[sheetID].fileName, ""); 245 | int dataPosStart = gfxSurface[sheetID].dataPosition; 246 | int dataPosEnd = gfxSurface[sheetID].dataPosition + gfxSurface[sheetID].height * gfxSurface[sheetID].width; 247 | for (int i = 0x200000 - dataPosEnd; i > 0; --i) graphicData[dataPosStart++] = graphicData[dataPosEnd++]; 248 | gfxDataPosition -= gfxSurface[sheetID].height * gfxSurface[sheetID].width; 249 | for (int i = 0; i < SURFACE_MAX; ++i) { 250 | if (gfxSurface[i].dataPosition > gfxSurface[sheetID].dataPosition) 251 | gfxSurface[i].dataPosition -= gfxSurface[sheetID].height * gfxSurface[sheetID].width; 252 | } 253 | } 254 | } 255 | 256 | int LoadBMPFile(const char *filePath, byte sheetID) 257 | { 258 | FileInfo info; 259 | if (LoadFile(filePath, &info)) { 260 | GFXSurface *surface = &gfxSurface[sheetID]; 261 | StrCopy(surface->fileName, filePath); 262 | 263 | int fileBuffer = 0; 264 | 265 | SetFilePosition(18); 266 | FileRead(&fileBuffer, 1); 267 | surface->width = fileBuffer; 268 | FileRead(&fileBuffer, 1); 269 | surface->width += fileBuffer << 8; 270 | FileRead(&fileBuffer, 1); 271 | surface->width += fileBuffer << 16; 272 | FileRead(&fileBuffer, 1); 273 | surface->width += fileBuffer << 24; 274 | 275 | FileRead(&fileBuffer, 1); 276 | surface->height = fileBuffer; 277 | FileRead(&fileBuffer, 1); 278 | surface->height += fileBuffer << 8; 279 | FileRead(&fileBuffer, 1); 280 | surface->height += fileBuffer << 16; 281 | FileRead(&fileBuffer, 1); 282 | surface->height += fileBuffer << 24; 283 | 284 | SetFilePosition(info.vfileSize - surface->height * surface->width); 285 | surface->dataPosition = gfxDataPosition; 286 | byte *gfxData = &graphicData[surface->dataPosition + surface->width * (surface->height - 1)]; 287 | for (int y = 0; y < surface->height; ++y) { 288 | for (int x = 0; x < surface->width; ++x) { 289 | FileRead(&fileBuffer, 1); 290 | *gfxData++ = fileBuffer; 291 | } 292 | gfxData -= 2 * surface->width; 293 | } 294 | gfxDataPosition += surface->height * surface->width; 295 | 296 | surface->widthShift = 0; 297 | int w = surface->width; 298 | while (w > 1) { 299 | w >>= 1; 300 | ++surface->widthShift; 301 | } 302 | if (gfxDataPosition >= 0x400000) 303 | gfxDataPosition = 0; 304 | 305 | CloseFile(); 306 | return true; 307 | } 308 | return false; 309 | } 310 | int LoadGIFFile(const char *filePath, byte sheetID) 311 | { 312 | FileInfo info; 313 | if (LoadFile(filePath, &info)) { 314 | GFXSurface *surface = &gfxSurface[sheetID]; 315 | StrCopy(surface->fileName, filePath); 316 | 317 | int fileBuffer = 0; 318 | 319 | SetFilePosition(6); // GIF89a 320 | FileRead(&fileBuffer, 1); 321 | surface->width = fileBuffer; 322 | FileRead(&fileBuffer, 1); 323 | surface->width += (fileBuffer << 8); 324 | FileRead(&fileBuffer, 1); 325 | surface->height = fileBuffer; 326 | FileRead(&fileBuffer, 1); 327 | surface->height += (fileBuffer << 8); 328 | 329 | FileRead(&fileBuffer, 1); // Palette Size (thrown away) :/ 330 | FileRead(&fileBuffer, 1); // BG Colour index (thrown away) 331 | FileRead(&fileBuffer, 1); // idk actually (still thrown away) 332 | 333 | int c = 0; 334 | byte clr[3]; 335 | do { 336 | ++c; 337 | FileRead(clr, 3); 338 | } while (c != 0x100); 339 | 340 | FileRead(&fileBuffer, 1); 341 | while (fileBuffer != ',') FileRead(&fileBuffer, 1); // gif image start identifier 342 | 343 | FileRead(&fileBuffer, 2); 344 | FileRead(&fileBuffer, 2); 345 | FileRead(&fileBuffer, 2); 346 | FileRead(&fileBuffer, 2); 347 | FileRead(&fileBuffer, 1); 348 | bool interlaced = (fileBuffer & 0x40) >> 6; 349 | if (fileBuffer >> 7 == 1) { 350 | int c = 128; 351 | do { 352 | ++c; 353 | FileRead(clr, 3); 354 | } while (c != 256); 355 | } 356 | 357 | surface->dataPosition = gfxDataPosition; 358 | surface->widthShift = 0; 359 | int w = surface->width; 360 | while (w > 1) { 361 | w >>= 1; 362 | ++surface->widthShift; 363 | } 364 | 365 | gfxDataPosition += surface->width * surface->height; 366 | if (gfxDataPosition <= 0x3FFFFF) 367 | ReadGifPictureData(surface->width, surface->height, interlaced, graphicData, surface->dataPosition); 368 | else 369 | gfxDataPosition = 0; 370 | 371 | CloseFile(); 372 | return true; 373 | } 374 | return false; 375 | } 376 | int LoadPVRFile(const char *filePath, byte sheetID) 377 | { 378 | // ONLY READS "PVRTC 2bpp RGB" PVR FILES 379 | FileInfo info; 380 | if (LoadFile(filePath, &info)) { 381 | GFXSurface *surface = &gfxSurface[sheetID]; 382 | StrCopy(surface->fileName, filePath); 383 | 384 | byte fileBuffer[2]; 385 | 386 | SetFilePosition(28); 387 | FileRead(fileBuffer, 1); 388 | int width = fileBuffer[0]; 389 | FileRead(fileBuffer, 1); 390 | width += fileBuffer[0] << 8; 391 | FileRead(fileBuffer, 1); 392 | int height = fileBuffer[0]; 393 | FileRead(fileBuffer, 1); 394 | height = fileBuffer[0] << 8; 395 | 396 | surface->width = width; 397 | surface->height = height; 398 | surface->dataPosition = gfxDataPosition; 399 | gfxDataPosition += surface->width * surface->height; 400 | 401 | surface->widthShift = 0; 402 | int w = surface->width; 403 | while (w > 1) { 404 | w >>= 1; 405 | ++surface->widthShift; 406 | } 407 | 408 | return false; // yeah I have no clue how to handle this, cd lite has this be loaded every frame on framebuffer update and does it that way 409 | 410 | ushort *buffer = NULL; 411 | for (int h = 0; h < height; ++h) { 412 | for (int w = 0; w < width; ++w) { 413 | FileRead(fileBuffer, 2); 414 | buffer[w] = 2 * (fileBuffer[0] + (fileBuffer[1] << 8)) | 1; 415 | } 416 | buffer += width; 417 | } 418 | buffer += 0x400 - width; 419 | 420 | CloseFile(); 421 | return true; 422 | } 423 | return false; 424 | } -------------------------------------------------------------------------------- /Sonic12Decomp/Sprite.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SPRITE_H 2 | #define SPRITE_H 3 | 4 | int AddGraphicsFile(const char *filePath); 5 | void RemoveGraphicsFile(const char *filePath, int sheetID); 6 | 7 | int LoadBMPFile(const char *filePath, byte sheetID); 8 | int LoadGIFFile(const char *filePath, byte sheetID); 9 | int LoadPVRFile(const char *filePath, byte sheetID); 10 | 11 | void ReadGifPictureData(int width, int height, bool interlaced, byte *gfxData, int offset); 12 | 13 | #endif // !SPRITE_H 14 | -------------------------------------------------------------------------------- /Sonic12Decomp/String.hpp: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H 2 | #define STRING_H 3 | 4 | #define STRSTORAGE_SIZE (1000) 5 | #define STRING_SIZE (0x200) 6 | 7 | #define CREDITS_LIST_SIZE (0x200) 8 | 9 | extern ushort *strPressStart; 10 | extern ushort *strTouchToStart; 11 | extern ushort *strStartGame; 12 | extern ushort *strTimeAttack; 13 | extern ushort *strAchievements; 14 | extern ushort *strLeaderboards; 15 | extern ushort *strHelpAndOptions; 16 | extern ushort *strSoundTest; 17 | extern ushort *str2PlayerVS; 18 | extern ushort *strSaveSelect; 19 | extern ushort *strPlayerSelect; 20 | extern ushort *strNoSave; 21 | extern ushort *strNewGame; 22 | extern ushort *strDelete; 23 | extern ushort *strDeleteMessage; 24 | extern ushort *strYes; 25 | extern ushort *strNo; 26 | extern ushort *strSonic; 27 | extern ushort *strTails; 28 | extern ushort *strKnuckles; 29 | extern ushort *strPause; 30 | extern ushort *strContinue; 31 | extern ushort *strRestart; 32 | extern ushort *strExit; 33 | extern ushort *strDevMenu; 34 | extern ushort *strRestartMessage; 35 | extern ushort *strExitMessage; 36 | extern ushort *strNSRestartMessage; 37 | extern ushort *strNSExitMessage; 38 | extern ushort *strExitGame; 39 | extern ushort *strNetworkMessage; 40 | extern ushort *strStageList[8]; 41 | extern ushort *strSaveStageList[26]; 42 | extern ushort *strNewBestTime; 43 | extern ushort *strRecords; 44 | extern ushort *strNextAct; 45 | extern ushort *strPlay; 46 | extern ushort *strTotalTime; 47 | extern ushort *strInstructions; 48 | extern ushort *strSettings; 49 | extern ushort *strStaffCredits; 50 | extern ushort *strAbout; 51 | extern ushort *strMusic; 52 | extern ushort *strSoundFX; 53 | extern ushort *strSpindash; 54 | extern ushort *strBoxArt; 55 | extern ushort *strControls; 56 | extern ushort *strOn; 57 | extern ushort *strOff; 58 | extern ushort *strCustomizeDPad; 59 | extern ushort *strDPadSize; 60 | extern ushort *strDPadOpacity; 61 | extern ushort *strHelpText1; 62 | extern ushort *strHelpText2; 63 | extern ushort *strHelpText3; 64 | extern ushort *strHelpText4; 65 | extern ushort *strHelpText5; 66 | extern ushort *strVersionName; 67 | extern ushort *strPrivacy; 68 | extern ushort *strTerms; 69 | 70 | extern int stageStrCount; 71 | 72 | extern ushort stringStorage[STRSTORAGE_SIZE][STRING_SIZE]; 73 | extern int stringStorePos; 74 | 75 | extern int creditsListSize; 76 | extern const ushort *strCreditsList[CREDITS_LIST_SIZE]; 77 | extern byte creditsType[CREDITS_LIST_SIZE]; 78 | extern float creditsAdvanceY[CREDITS_LIST_SIZE]; 79 | 80 | inline void StrCopy(char *dest, const char *src) 81 | { 82 | int i = 0; 83 | 84 | for (; src[i]; ++i) dest[i] = src[i]; 85 | 86 | dest[i] = 0; 87 | } 88 | 89 | inline void StrAdd(char *dest, const char *src) 90 | { 91 | int destStrPos = 0; 92 | int srcStrPos = 0; 93 | while (dest[destStrPos]) ++destStrPos; 94 | while (true) { 95 | if (!src[srcStrPos]) { 96 | break; 97 | } 98 | dest[destStrPos++] = src[srcStrPos++]; 99 | } 100 | dest[destStrPos] = 0; 101 | } 102 | 103 | inline bool StrComp(const char *stringA, const char *stringB) 104 | { 105 | bool match = true; 106 | bool finished = false; 107 | while (!finished) { 108 | if (*stringA == *stringB || *stringA == *stringB + ' ' || *stringA == *stringB - ' ') { 109 | if (*stringA) { 110 | ++stringA; 111 | ++stringB; 112 | } 113 | else { 114 | finished = true; 115 | } 116 | } 117 | else { 118 | match = false; 119 | finished = true; 120 | } 121 | } 122 | return match; 123 | } 124 | 125 | inline int StrLength(const char *string) 126 | { 127 | int len = 0; 128 | for (len = 0; string[len]; len++) 129 | ; 130 | return len; 131 | } 132 | int FindStringToken(const char *string, const char *token, char stopID); 133 | 134 | inline void StrCopyW(ushort *dest, const ushort *src) 135 | { 136 | int i = 0; 137 | 138 | for (; src[i]; ++i) dest[i] = src[i]; 139 | 140 | dest[i] = 0; 141 | } 142 | 143 | 144 | inline void StrAddW(ushort *dest, const ushort *src) 145 | { 146 | int destStrPos = 0; 147 | int srcStrPos = 0; 148 | while (dest[destStrPos]) ++destStrPos; 149 | while (true) { 150 | if (!src[srcStrPos]) { 151 | break; 152 | } 153 | dest[destStrPos++] = src[srcStrPos++]; 154 | } 155 | dest[destStrPos] = 0; 156 | } 157 | inline void StrCopyW(ushort *dest, const char *src) 158 | { 159 | int i = 0; 160 | 161 | for (; src[i]; ++i) dest[i] = src[i]; 162 | 163 | dest[i] = 0; 164 | } 165 | 166 | inline void StrAddW(ushort *dest, const char *src) 167 | { 168 | int destStrPos = 0; 169 | int srcStrPos = 0; 170 | while (dest[destStrPos]) ++destStrPos; 171 | while (true) { 172 | if (!src[srcStrPos]) { 173 | break; 174 | } 175 | dest[destStrPos++] = src[srcStrPos++]; 176 | } 177 | dest[destStrPos] = 0; 178 | } 179 | 180 | inline bool StrCompW(const ushort *stringA, const ushort *stringB) 181 | { 182 | bool match = true; 183 | bool finished = false; 184 | while (!finished) { 185 | if (*stringA == *stringB || *stringA == *stringB + ' ' || *stringA == *stringB - ' ') { 186 | if (*stringA) { 187 | ++stringA; 188 | ++stringB; 189 | } 190 | else { 191 | finished = true; 192 | } 193 | } 194 | else { 195 | match = false; 196 | finished = true; 197 | } 198 | } 199 | return match; 200 | } 201 | 202 | inline bool StrCompW(const ushort *stringA, const char *stringB) 203 | { 204 | bool match = true; 205 | bool finished = false; 206 | while (!finished) { 207 | if (*stringA == *stringB || *stringA == *stringB + ' ' || *stringA == *stringB - ' ') { 208 | if (*stringA) { 209 | ++stringA; 210 | ++stringB; 211 | } 212 | else { 213 | finished = true; 214 | } 215 | } 216 | else { 217 | match = false; 218 | finished = true; 219 | } 220 | } 221 | return match; 222 | } 223 | 224 | inline int StrLengthW(const ushort *string) 225 | { 226 | int len = 0; 227 | for (len = 0; string[len]; len++) 228 | ; 229 | return len; 230 | } 231 | 232 | int FindStringTokenUnicode(const ushort *string, const ushort *token, char stopID); 233 | 234 | inline void StringLowerCase(char *dest, const char *src) 235 | { 236 | int destPos = 0; 237 | int curChar = *src; 238 | if (*src) { 239 | int srcPos = 0; 240 | do { 241 | while (curChar - 'A' <= 0x19u) { 242 | destPos = srcPos; 243 | dest[destPos] = curChar + ' '; 244 | curChar = src[++srcPos]; 245 | if (!curChar) { 246 | dest[++destPos] = 0; 247 | return; 248 | } 249 | } 250 | destPos = srcPos; 251 | dest[destPos] = curChar; 252 | curChar = src[++srcPos]; 253 | } while (curChar); 254 | } 255 | dest[++destPos] = 0; 256 | } 257 | 258 | inline void StringUpperCase(char *dest, const char *src) 259 | { 260 | int destPos = 0; 261 | int curChar = *src; 262 | if (*src) { 263 | int srcPos = 0; 264 | do { 265 | while (curChar - 'a' <= 0x19u) { 266 | destPos = srcPos; 267 | dest[destPos] = curChar - ' '; 268 | curChar = src[++srcPos]; 269 | if (!curChar) { 270 | dest[++destPos] = 0; 271 | return; 272 | } 273 | } 274 | destPos = srcPos; 275 | dest[destPos] = curChar; 276 | curChar = src[++srcPos]; 277 | } while (curChar); 278 | } 279 | dest[++destPos] = 0; 280 | } 281 | 282 | void ConvertIntegerToString(char *text, int value); 283 | 284 | void GenerateMD5FromString(const char *string, int len, byte *buffer); 285 | 286 | void InitLocalizedStrings(); 287 | ushort *ReadLocalizedString(const char *stringName, const char *language, const char *filePath); 288 | 289 | inline void ReadStringLine(char *text) 290 | { 291 | char curChar = 0; 292 | 293 | int textPos = 0; 294 | while (true) { 295 | FileRead(&curChar, 1); 296 | if (curChar == '\t' || curChar == ' ') 297 | break; 298 | if (curChar == '\r' || curChar == '\n') 299 | break; 300 | if (curChar != ';') 301 | text[textPos++] = curChar; 302 | 303 | if (ReachedEndOfFile()) { 304 | text[textPos] = 0; 305 | return; 306 | } 307 | } 308 | if (curChar != '\n' && curChar != '\r') { 309 | if (ReachedEndOfFile()) { 310 | text[textPos] = 0; 311 | return; 312 | } 313 | } 314 | 315 | text[textPos] = 0; 316 | if (ReachedEndOfFile()) 317 | text[textPos] = 0; 318 | } 319 | 320 | inline void ReadStringLineUnicode(ushort *text) 321 | { 322 | int curChar = 0; 323 | byte fileBuffer[2]; 324 | 325 | int textPos = 0; 326 | while (true) { 327 | FileRead(fileBuffer, 2); 328 | curChar = fileBuffer[0] + (fileBuffer[1] << 8); 329 | if (curChar != ' ' && curChar != '\t') { 330 | if (curChar == '\r') { 331 | int pos = (int)GetFilePosition(); 332 | FileRead(fileBuffer, 2); 333 | curChar = fileBuffer[0] + (fileBuffer[1] << 8); 334 | if (curChar == '\n') 335 | break; 336 | SetFilePosition(pos); 337 | } 338 | if (curChar != ';') 339 | text[textPos++] = curChar; 340 | } 341 | else if (curChar == '\n' || curChar == '\r') 342 | break; 343 | 344 | if (ReachedEndOfFile()) { 345 | text[textPos] = 0; 346 | return; 347 | } 348 | } 349 | text[textPos] = 0; 350 | if (ReachedEndOfFile()) 351 | text[textPos] = 0; 352 | } 353 | 354 | void ReadCreditsList(const char *filePath); 355 | inline void ReadCreditsLine(char *line) 356 | { 357 | byte fileBuffer = 0; 358 | 359 | int strPos = 0; 360 | while (true) { 361 | FileRead(&fileBuffer, 1); 362 | if (fileBuffer == '\r') 363 | break; 364 | line[strPos++] = fileBuffer; 365 | if (ReachedEndOfFile()) { 366 | line[strPos] = 0; 367 | return; 368 | } 369 | } 370 | FileRead(&fileBuffer, 1); 371 | line[strPos] = 0; 372 | if (ReachedEndOfFile()) { 373 | line[strPos] = 0; 374 | return; 375 | } 376 | } 377 | 378 | #endif // !STRING_H 379 | -------------------------------------------------------------------------------- /Sonic12Decomp/Text.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | TextMenu gameMenu[TEXTMENU_COUNT]; 4 | int textMenuSurfaceNo = 0; 5 | 6 | char playerListText[0x80][0x20]; 7 | 8 | void LoadTextFile(TextMenu *menu, const char *filePath) 9 | { 10 | FileInfo info; 11 | byte fileBuffer = 0; 12 | if (LoadFile(filePath, &info)) { 13 | menu->textDataPos = 0; 14 | menu->rowCount = 0; 15 | menu->entryStart[menu->rowCount] = menu->textDataPos; 16 | menu->entrySize[menu->rowCount] = 0; 17 | 18 | while (menu->textDataPos < TEXTDATA_COUNT && !ReachedEndOfFile()) { 19 | FileRead(&fileBuffer, 1); 20 | if (fileBuffer != '\n') { 21 | if (fileBuffer == '\r') { 22 | menu->rowCount++; 23 | menu->entryStart[menu->rowCount] = menu->textDataPos; 24 | menu->entrySize[menu->rowCount] = 0; 25 | } 26 | else { 27 | menu->textData[menu->textDataPos++] = fileBuffer; 28 | menu->entrySize[menu->rowCount]++; 29 | } 30 | } 31 | } 32 | 33 | menu->rowCount++; 34 | CloseFile(); 35 | } 36 | } 37 | void SetupTextMenu(TextMenu *menu, int rowCount) 38 | { 39 | menu->textDataPos = 0; 40 | menu->rowCount = rowCount; 41 | } 42 | void AddTextMenuEntry(TextMenu *menu, const char *text) 43 | { 44 | menu->entryStart[menu->rowCount] = menu->textDataPos; 45 | menu->entrySize[menu->rowCount] = 0; 46 | for (int i = 0; i < StrLength(text);) { 47 | if (text[i] != '\0') { 48 | menu->textData[menu->textDataPos++] = text[i]; 49 | menu->entrySize[menu->rowCount]++; 50 | ++i; 51 | } 52 | else { 53 | break; 54 | } 55 | } 56 | menu->rowCount++; 57 | } 58 | void AddTextMenuEntryW(TextMenu *menu, const ushort *text) 59 | { 60 | menu->entryStart[menu->rowCount] = menu->textDataPos; 61 | menu->entrySize[menu->rowCount] = 0; 62 | for (int i = 0; i < StrLengthW(text);) { 63 | if (text[i] != '\0') { 64 | menu->textData[menu->textDataPos++] = text[i]; 65 | menu->entrySize[menu->rowCount]++; 66 | ++i; 67 | } 68 | else { 69 | break; 70 | } 71 | } 72 | menu->rowCount++; 73 | } 74 | void SetTextMenuEntry(TextMenu *menu, const char *text, int rowID) 75 | { 76 | menu->entryStart[rowID] = menu->textDataPos; 77 | menu->entrySize[rowID] = 0; 78 | for (int i = 0; i < StrLength(text);) { 79 | if (text[i] != '\0') { 80 | menu->textData[menu->textDataPos++] = text[i]; 81 | menu->entrySize[rowID]++; 82 | ++i; 83 | } 84 | else { 85 | break; 86 | } 87 | } 88 | } 89 | void SetTextMenuEntryW(TextMenu *menu, const ushort *text, int rowID) 90 | { 91 | menu->entryStart[rowID] = menu->textDataPos; 92 | menu->entrySize[rowID] = 0; 93 | for (int i = 0; i < StrLengthW(text);) { 94 | if (text[i] != '\0') { 95 | menu->textData[menu->textDataPos++] = text[i]; 96 | menu->entrySize[rowID]++; 97 | ++i; 98 | } 99 | else { 100 | break; 101 | } 102 | } 103 | } 104 | void EditTextMenuEntry(TextMenu *menu, const char *text, int rowID) 105 | { 106 | int entryPos = menu->entryStart[rowID]; 107 | menu->entrySize[rowID] = 0; 108 | for (int i = 0; i < StrLength(text);) { 109 | if (text[i] != '\0') { 110 | menu->textData[entryPos++] = text[i]; 111 | menu->entrySize[rowID]++; 112 | ++i; 113 | } 114 | else { 115 | break; 116 | } 117 | } 118 | } 119 | void LoadConfigListText(TextMenu *menu, int listNo) 120 | { 121 | FileInfo info; 122 | char strBuf[0x100]; 123 | int fileBuffer = 0; 124 | int count = 0; 125 | int strLen = 0; 126 | if (LoadFile("Data/Game/GameConfig.bin", &info)) { 127 | // Name 128 | FileRead(&strLen, 1); 129 | FileRead(&strBuf, strLen); 130 | strBuf[strLen] = 0; 131 | 132 | // About 133 | FileRead(&strLen, 1); 134 | FileRead(&strBuf, strLen); 135 | strBuf[strLen] = 0; 136 | 137 | byte buf[3]; 138 | for (int c = 0; c < 0x60; ++c) FileRead(buf, 3); 139 | 140 | // Object Names 141 | FileRead(&count, 1); 142 | for (int o = 0; o < count; ++o) { 143 | FileRead(&strLen, 1); 144 | FileRead(&strBuf, strLen); 145 | strBuf[strLen] = 0; 146 | } 147 | 148 | // Script Paths 149 | for (int s = 0; s < count; ++s) { 150 | FileRead(&strLen, 1); 151 | FileRead(&strBuf, strLen); 152 | strBuf[strLen] = 0; 153 | } 154 | 155 | // Variables 156 | FileRead(&count, 1); 157 | for (int v = 0; v < count; ++v) { 158 | //Var Name 159 | FileRead(&strLen, 1); 160 | FileRead(&strBuf, strLen); 161 | strBuf[strLen] = 0; 162 | 163 | //Var Value 164 | FileRead(&fileBuffer, 1); 165 | FileRead(&fileBuffer, 1); 166 | FileRead(&fileBuffer, 1); 167 | FileRead(&fileBuffer, 1); 168 | } 169 | 170 | // SFX Names 171 | FileRead(&count, 1); 172 | for (int s = 0; s < count; ++s) { 173 | FileRead(&strLen, 1); 174 | FileRead(&strBuf, strLen); 175 | strBuf[strLen] = 0; 176 | } 177 | // SFX Paths 178 | for (int s = 0; s < count; ++s) { 179 | FileRead(&strLen, 1); 180 | FileRead(&strBuf, strLen); 181 | strBuf[strLen] = 0; 182 | } 183 | 184 | // Players 185 | FileRead(&count, 1); 186 | for (int p = 0; p < count; ++p) { 187 | FileRead(&strLen, 1); 188 | FileRead(&strBuf, strLen); 189 | strBuf[strLen] = '\0'; 190 | 191 | if (listNo == 0) { // Player List 192 | AddTextMenuEntry(menu, strBuf); 193 | StrCopy(playerListText[p], strBuf); 194 | } 195 | } 196 | 197 | // Categories 198 | for (int c = 1; c <= 4; ++c) { 199 | int stageCnt = 0; 200 | FileRead(&stageCnt, 1); 201 | for (int s = 0; s < stageCnt; ++s) { 202 | //Stage Folder 203 | FileRead(&strLen, 1); 204 | FileRead(&strBuf, strLen); 205 | strBuf[strLen] = 0; 206 | 207 | //Stage ID 208 | FileRead(&strLen, 1); 209 | FileRead(&strBuf, strLen); 210 | strBuf[strLen] = 0; 211 | 212 | //Stage Name 213 | FileRead(&strLen, 1); 214 | FileRead(&strBuf, strLen); 215 | strBuf[strLen] = '\0'; 216 | 217 | //IsHighlighted 218 | FileRead(&fileBuffer, 1); 219 | if (listNo == c) { 220 | menu->entryHighlight[s] = fileBuffer; 221 | AddTextMenuEntry(menu, strBuf); 222 | } 223 | } 224 | } 225 | CloseFile(); 226 | } 227 | } -------------------------------------------------------------------------------- /Sonic12Decomp/Text.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TEXTSYSTEM_H 2 | #define TEXTSYSTEM_H 3 | 4 | #define TEXTDATA_COUNT (0x2800) 5 | #define TEXTENTRY_COUNT (0x200) 6 | #define TEXTMENU_COUNT (0x2) 7 | 8 | enum TextInfoTypes { TEXTINFO_TEXTDATA = 0, TEXTINFO_TEXTSIZE = 1, TEXTINFO_ROWCOUNT = 2 }; 9 | 10 | struct TextMenu { 11 | ushort textData[TEXTDATA_COUNT]; 12 | int entryStart[TEXTENTRY_COUNT]; 13 | int entrySize[TEXTENTRY_COUNT]; 14 | byte entryHighlight[TEXTENTRY_COUNT]; 15 | int textDataPos; 16 | int selection1; 17 | int selection2; 18 | ushort rowCount; 19 | ushort visibleRowCount; 20 | ushort visibleRowOffset; 21 | byte alignment; 22 | byte selectionCount; 23 | sbyte timer; 24 | }; 25 | 26 | enum TextMenuAlignments { 27 | MENU_ALIGN_LEFT, 28 | MENU_ALIGN_RIGHT, 29 | MENU_ALIGN_CENTER, 30 | }; 31 | 32 | extern TextMenu gameMenu[TEXTMENU_COUNT]; 33 | extern int textMenuSurfaceNo; 34 | 35 | extern char playerListText[0x80][0x20]; 36 | 37 | void LoadTextFile(TextMenu *menu, const char *filePath); 38 | void LoadConfigListText(TextMenu *menu, int listNo); 39 | 40 | void SetupTextMenu(TextMenu *menu, int rowCount); 41 | void AddTextMenuEntry(TextMenu *menu, const char *text); 42 | void AddTextMenuEntryW(TextMenu *menu, const ushort *text); 43 | void SetTextMenuEntry(TextMenu *menu, const char *text, int rowID); 44 | void SetTextMenuEntryW(TextMenu *menu, const ushort *text, int rowID); 45 | void EditTextMenuEntry(TextMenu *menu, const char *text, int rowID); 46 | 47 | #endif // !TEXTSYSTEM_H 48 | -------------------------------------------------------------------------------- /Sonic12Decomp/Userdata.hpp: -------------------------------------------------------------------------------- 1 | #ifndef USERDATA_H 2 | #define USERDATA_H 3 | 4 | #define GLOBALVAR_COUNT (0x100) 5 | 6 | #define ACHIEVEMENT_MAX (0x40) 7 | #define LEADERBOARD_MAX (0x80) 8 | 9 | #define SAVEDATA_MAX (0x2000) 10 | 11 | enum OnlineMenuTypes { 12 | ONLINEMENU_ACHIEVEMENTS = 0, 13 | ONLINEMENU_LEADERBOARDS = 1, 14 | }; 15 | 16 | struct Achievement { 17 | char name[0x40]; 18 | int status; 19 | }; 20 | 21 | struct LeaderboardEntry { 22 | int status; 23 | }; 24 | 25 | struct MultiplayerData { 26 | int type; 27 | int data[0x1FF]; 28 | }; 29 | 30 | extern int(*nativeFunction[16])(int, void *); 31 | extern int nativeFunctionCount; 32 | 33 | extern int globalVariablesCount; 34 | extern int globalVariables[GLOBALVAR_COUNT]; 35 | extern char globalVariableNames[GLOBALVAR_COUNT][0x20]; 36 | 37 | extern char gamePath[0x100]; 38 | extern int saveRAM[SAVEDATA_MAX]; 39 | extern Achievement achievements[ACHIEVEMENT_MAX]; 40 | extern LeaderboardEntry leaderboard[LEADERBOARD_MAX]; 41 | 42 | extern MultiplayerData multiplayerDataIN; 43 | extern MultiplayerData multiplayerDataOUT; 44 | extern int matchValueData[0x100]; 45 | extern int matchValueReadPos; 46 | extern int matchValueWritePos; 47 | 48 | extern int sendDataMethod; 49 | extern int sendCounter; 50 | 51 | inline int GetGlobalVariableByName(const char *name) 52 | { 53 | for (int v = 0; v < globalVariablesCount; ++v) { 54 | if (StrComp(name, globalVariableNames[v])) 55 | return globalVariables[v]; 56 | } 57 | return 0; 58 | } 59 | 60 | inline void SetGlobalVariableByName(const char *name, int value) 61 | { 62 | for (int v = 0; v < globalVariablesCount; ++v) { 63 | if (StrComp(name, globalVariableNames[v])) { 64 | globalVariables[v] = value; 65 | break; 66 | } 67 | } 68 | } 69 | inline int GetGlobalVariableID(const char *name) 70 | { 71 | for (int v = 0; v < globalVariablesCount; ++v) { 72 | if (StrComp(name, globalVariableNames[v])) 73 | return v; 74 | } 75 | return 0; 76 | } 77 | 78 | inline void AddNativeFunction(const char* name, int (*funcPtr)(int, void*)) { 79 | if (nativeFunctionCount > 0xF) 80 | return; 81 | SetGlobalVariableByName(name, nativeFunctionCount); 82 | nativeFunction[nativeFunctionCount++] = funcPtr; 83 | } 84 | 85 | inline bool ReadSaveRAMData() 86 | { 87 | char buffer[0x100]; 88 | #if RETRO_PLATFORM == RETRO_OSX 89 | if (!usingCWD) 90 | sprintf(buffer, "%s/SData.bin", getResourcesPath()); 91 | else 92 | sprintf(buffer, "%sSData.bin", gamePath); 93 | #else 94 | sprintf(buffer, "%sSData.bin", gamePath); 95 | #endif 96 | FileIO *saveFile = fOpen(buffer, "rb"); 97 | if (!saveFile) 98 | return false; 99 | fRead(saveRAM, 4u, SAVEDATA_MAX, saveFile); 100 | fClose(saveFile); 101 | return true; 102 | } 103 | 104 | inline bool WriteSaveRAMData() 105 | { 106 | char buffer[0x100]; 107 | #if RETRO_PLATFORM == RETRO_OSX 108 | if (!usingCWD) 109 | sprintf(buffer, "%s/SData.bin", getResourcesPath()); 110 | else 111 | sprintf(buffer, "%sSData.bin", gamePath); 112 | #else 113 | sprintf(buffer, "%sSData.bin", gamePath); 114 | #endif 115 | 116 | FileIO *saveFile = fOpen(buffer, "wb"); 117 | if (!saveFile) 118 | return false; 119 | fWrite(saveRAM, 4u, SAVEDATA_MAX, saveFile); 120 | fClose(saveFile); 121 | return true; 122 | } 123 | 124 | void InitUserdata(); 125 | void writeSettings(); 126 | void ReadUserdata(); 127 | void WriteUserdata(); 128 | 129 | void AwardAchievement(int id, int status); 130 | 131 | int SetAchievement(int achievementID, void* achDone); 132 | int SetLeaderboard(int leaderboardID, void *res); 133 | inline void LoadAchievementsMenu() { ReadUserdata(); } 134 | inline void LoadLeaderboardsMenu() { ReadUserdata(); } 135 | 136 | int Connect2PVS(int a1, void *a2); 137 | int Disconnect2PVS(int a1, void *a2); 138 | int SendEntity(int a1, void *a2); 139 | int SendValue(int a1, void *a2); 140 | int ReceiveEntity(int a1, void *a2); 141 | int ReceiveValue(int a1, void *a2); 142 | int TransmitGlobal(int a1, void *a2); 143 | 144 | void receive2PVSData(MultiplayerData *data); 145 | void receive2PVSMatchCode(int code); 146 | 147 | int ShowPromoPopup(int a1, void *a2); 148 | 149 | #endif //!USERDATA_H 150 | -------------------------------------------------------------------------------- /Sonic12Decomp/main.cpp: -------------------------------------------------------------------------------- 1 | #include "RetroEngine.hpp" 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | #if RETRO_PLATFORM != RETRO_VITA 6 | for (int i = 0; i < argc; ++i) { 7 | if (StrComp(argv[i], "UsingCWD")) 8 | usingCWD = true; 9 | } 10 | #endif 11 | 12 | Engine.Init(); 13 | Engine.Run(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /Sonic12Decomp/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Sonic12Decomp.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 102 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1001 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /dependencies/all/dependencies.txt: -------------------------------------------------------------------------------- 1 | IF YOU WANT TO DO NETWORKING: 2 | download asio from https://think-async.com/Asio/ and extract it into ./asio/ -------------------------------------------------------------------------------- /dependencies/mac/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /dependencies/mac/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /dependencies/mac/cocoaHelpers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COCOA_HELPERS_H 2 | #define COCOA_HELPERS_H 3 | 4 | const char* getResourcesPath(void); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /dependencies/mac/cocoaHelpers.mm: -------------------------------------------------------------------------------- 1 | #ifdef __APPLE__ 2 | #include "cocoaHelpers.hpp" 3 | 4 | #import 5 | 6 | const char* getResourcesPath(void) 7 | { 8 | @autoreleasepool 9 | { 10 | NSString* resource_path = [[NSBundle mainBundle] resourcePath]; 11 | 12 | return (char*)[resource_path UTF8String]; 13 | } 14 | } 15 | #endif 16 | -------------------------------------------------------------------------------- /dependencies/mac/dependencies.txt: -------------------------------------------------------------------------------- 1 | SDL2: https://www.libsdl.org/download-2.0.php 2 | just download the appropriate development library for your compiler and place it in "./SDL2/" 3 | 4 | libogg: https://xiph.org/downloads/ (libogg) 5 | download the libogg .zip file and unzip it in "./libogg/", then build the library as a framework, and include it in the xcode proj 6 | 7 | libvorbis: https://xiph.org/downloads/ (libvorbis) 8 | download the libogg .zip file and unzip it in "./libvorbis/", then build the library as a framework, and include it in the xcode proj -------------------------------------------------------------------------------- /dependencies/windows/dependencies.txt: -------------------------------------------------------------------------------- 1 | SDL2: https://www.libsdl.org/download-2.0.php 2 | download the appropriate development library for your compiler and unzip it in "./SDL2/" 3 | 4 | libogg: https://xiph.org/downloads/ (libogg) 5 | download libogg and unzip it in "./libogg/", then build the static library 6 | 7 | libvorbis: https://xiph.org/downloads/ (libvorbis) 8 | download libvorbis and unzip it in "./libvorbis/", then build the VS2010 static library (win32/VS2010/vorbis_static.sln) -------------------------------------------------------------------------------- /networking_code_proto.py: -------------------------------------------------------------------------------- 1 | from requests import get 2 | from io import BytesIO, StringIO 3 | from string import ascii_lowercase, ascii_uppercase, punctuation, digits 4 | from math import floor, log2 5 | 6 | index = ascii_uppercase + digits 7 | #use this for base 8 | 9 | 10 | ip = get('https://api.ipify.org').text 11 | #ip = "255.255.255.255" 12 | print("IP ", ip) 13 | 14 | ipbytes = tuple(int(x) for x in ip.split('.')) 15 | ipcode = 0 16 | for i in range(4): #TODO: should this be reverse? 17 | ipcode |= ipbytes[i] << (i * 8) 18 | print("IPC", bin(ipcode), ipcode) 19 | portcode = 300 20 | print("PRT", bin(portcode), portcode) 21 | 22 | gameinfo = (10, 3, 2) #len, itembox, player 23 | gamecode = gameinfo[0] | (gameinfo[1] << 4) | (gameinfo[2] << 6) 24 | print("GME", bin(gamecode), gamecode) 25 | 26 | def getbit(i, n): 27 | return (i & (1 << n)) >> n 28 | 29 | pattern = "AABAABC" 30 | pout = 0b0 31 | 32 | 33 | ipc = 0; pc = 0; gc = 0 34 | 35 | for i in range(len(pattern) * 8): #pattern length 36 | #we can check what's at the pattern and build/read from it 37 | #we can set this up similarly in C++ with a const char* 38 | print(pout, i) 39 | c = pattern[i % (len(pattern))] 40 | if c == "A": 41 | pout |= (getbit(ipcode, ipc) << i) 42 | ipc += 1 43 | elif c == 'B': 44 | pout |= (getbit(portcode, pc) << i) 45 | pc += 1 46 | else: 47 | pout |= (getbit(gamecode, gc) << i) 48 | gc += 1 49 | print(bin(pout)) 50 | 51 | #calculate code 52 | out = [] 53 | iter = pout 54 | i = 0 55 | 56 | base = len(index) 57 | 58 | while True: 59 | if iter < (base ** (i + 1)): break 60 | i += 1 61 | while iter: 62 | out.append(iter // (base ** i)) 63 | iter %= base ** i 64 | i -= 1 65 | code = ''.join(index[x] for x in out) 66 | print(code, len(code)) 67 | #BEGIN REVERSE 68 | #get int from code 69 | past = out 70 | out = 0 71 | i = 0 72 | for x in reversed(code): 73 | out += index.index(x) * base**i 74 | i += 1 75 | print(bin(out)) 76 | #discect bits 77 | #python OFFERS a bit length function, but since we're moving this to c++, im fucking killing you 78 | ipc = 0; pc = 0; gc = 0 79 | ipcode = 0; portcode = 0; gamecode = 0 80 | for i in range(floor(log2(out)) + 1): 81 | bit = getbit(out, i) 82 | c = pattern[i % len(pattern)] #the pattern is reversed cause of how we write 83 | if c == "A": 84 | ipcode |= bit << ipc 85 | ipc += 1 86 | elif c == "B": 87 | portcode |= bit << pc 88 | pc += 1 89 | else: 90 | gamecode |= bit << gc 91 | gc += 1 92 | ipbytes = [0, 0, 0, 0] 93 | for i in range(4): 94 | ipbytes[i] = (ipcode >> (i * 8)) & 0xFF 95 | ip = f"{ipbytes[0]}.{ipbytes[1]}.{ipbytes[2]}.{ipbytes[3]}" 96 | print("IP ", ip) 97 | print("IPC", bin(ipcode), ipcode) 98 | print("PRT", bin(portcode), portcode) 99 | print("GME", bin(gamecode), gamecode) -------------------------------------------------------------------------------- /sonic1_livearea/icon0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic1_livearea/icon0.png -------------------------------------------------------------------------------- /sonic1_livearea/livearea/contents/bg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic1_livearea/livearea/contents/bg0.png -------------------------------------------------------------------------------- /sonic1_livearea/livearea/contents/startup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic1_livearea/livearea/contents/startup.png -------------------------------------------------------------------------------- /sonic1_livearea/livearea/contents/template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | bg0.png 7 | 8 | 9 | 10 | startup.png 11 | 12 | 13 | -------------------------------------------------------------------------------- /sonic1_livearea/pic0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic1_livearea/pic0.png -------------------------------------------------------------------------------- /sonic2_livearea/icon0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic2_livearea/icon0.png -------------------------------------------------------------------------------- /sonic2_livearea/livearea/contents/bg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic2_livearea/livearea/contents/bg0.png -------------------------------------------------------------------------------- /sonic2_livearea/livearea/contents/startup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic2_livearea/livearea/contents/startup.png -------------------------------------------------------------------------------- /sonic2_livearea/livearea/contents/template.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | bg0.png 7 | 8 | 9 | 10 | startup.png 11 | 12 | 13 | -------------------------------------------------------------------------------- /sonic2_livearea/pic0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SonicMastr/Sonic-1-2-Vita/ffdf2b562ba00f4287c33b9e93a319a29e4e4e32/sonic2_livearea/pic0.png --------------------------------------------------------------------------------