├── .clang-format
├── .github
└── workflows
│ └── build_psvita.yml
├── .gitignore
├── Makefile
├── README.md
├── RSDKv4.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── WorkspaceSettings.xcsettings
│ └── xcuserdata
│ │ └── rubberduckycooly.xcuserdatad
│ │ └── WorkspaceSettings.xcsettings
└── xcshareddata
│ └── xcschemes
│ └── RSDKv4.xcscheme
├── Sonic1.Vita
├── CMakeLists.txt
├── build-internal.sh
├── build.sh
└── sce_sys
│ └── livearea
│ └── contents
│ └── template.xml
├── 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
├── Sonic2.Vita
├── CMakeLists.txt
├── build-internal.sh
├── build.sh
└── sce_sys
│ └── livearea
│ └── contents
│ └── template.xml
├── 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
/.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 |
--------------------------------------------------------------------------------
/.github/workflows/build_psvita.yml:
--------------------------------------------------------------------------------
1 | name: Build Sonic 1 and 2 for PS Vita
2 | on:
3 | push:
4 | branches:
5 | - master
6 | - main
7 | - psvita
8 |
9 | jobs:
10 | sonic1-psvita:
11 | runs-on: ubuntu-latest
12 | container: vitasdk/vitasdk:latest
13 | steps:
14 | - name: Checkout repository
15 | uses: actions/checkout@v2
16 | - name: Install dependencies
17 | run: apk add --no-cache make cmake
18 | - name: Build Sonic 1
19 | run: |
20 | cd Sonic1.Vita
21 | cmake .
22 | make -j$(nproc)
23 | - name: Upload VPK
24 | uses: actions/upload-artifact@v2
25 | with:
26 | name: Sonic1-vita
27 | path: Sonic1.Vita/Sonic1.vpk
28 | if-no-files-found: error
29 | sonic2-psvita:
30 | runs-on: ubuntu-latest
31 | container: vitasdk/vitasdk:latest
32 | steps:
33 | - name: Checkout repository
34 | uses: actions/checkout@v2
35 | - name: Install dependencies
36 | run: apk add --no-cache make cmake
37 | - name: Build Sonic 2
38 | run: |
39 | cd Sonic2.Vita
40 | cmake .
41 | make -j$(nproc)
42 | - name: Upload VPK
43 | uses: actions/upload-artifact@v2
44 | with:
45 | name: sonic2-vita
46 | path: Sonic2.Vita/Sonic2.vpk
47 | if-no-files-found: error
48 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # VitaSDK artifacts
5 | dependencies/vita
6 | *.self*
7 | *.vpk*
8 | *.velf
9 |
10 | # CMake artifacts
11 | CMakeFiles/
12 | cmake_install.cmake
13 | CMakeCache.txt
14 | Sonic1.Vita/Makefile
15 | Sonic2.Vita/Makefile
16 |
17 | # User-specific files
18 | *.suo
19 | *.user
20 | *.userosscache
21 | *.sln.docstates
22 |
23 | # User-specific files (MonoDevelop/Xamarin Studio)
24 | *.userprefs
25 |
26 | # Build results
27 | [Dd]ebug/
28 | [Dd]ebugPublic/
29 | [Rr]elease/
30 | [Rr]eleases/
31 | [Bb]uild/
32 | x64/
33 | x86/
34 | bld/
35 | bin/
36 | [Bb]in/
37 | [Oo]bj/
38 |
39 | #dependencies
40 | [Dd]ependencies/windows/*
41 | [Dd]ependencies/mac/*
42 | [Dd]ependencies/all/*
43 | ![Dd]ependencies/all/dependencies.txt
44 |
45 | #OSX files
46 | *.DS_Store
47 | .DS_Store
48 | *.xactivitylog
49 | *.xcuserstate
50 | *.dia
51 | *.xbuild
52 | *.db
53 | *.plist
54 | *.idx
55 | *.pcm
56 | *.timestamp
57 | *.xcbkptlist
58 |
59 | # Visual Studio 2015 cache/options directory
60 | .vs/
61 | .vscode/
62 |
63 | # MSTest test Results
64 | [Tt]est[Rr]esult*/
65 | [Bb]uild[Ll]og.*
66 |
67 | # NUNIT
68 | *.VisualState.xml
69 | TestResult.xml
70 |
71 | # Build Results of an ATL Project
72 | [Dd]ebugPS/
73 | [Rr]eleasePS/
74 | dlldata.c
75 |
76 | # DNX
77 | project.lock.json
78 | artifacts/
79 |
80 | *_i.c
81 | *_p.c
82 | *_i.h
83 | *.ilk
84 | *.meta
85 | *.obj
86 | *.pch
87 | *.pdb
88 | *.pgc
89 | *.pgd
90 | *.rsp
91 | *.sbr
92 | *.tlb
93 | *.tli
94 | *.tlh
95 | *.tmp
96 | *.tmp_proj
97 | *.log
98 | *.vspscc
99 | *.vssscc
100 | .builds
101 | *.pidb
102 | *.svclog
103 | *.scc
104 |
105 | # Chutzpah Test files
106 | _Chutzpah*
107 |
108 | # Visual C++ cache files
109 | ipch/
110 | *.aps
111 | *.ncb
112 | *.opensdf
113 | *.sdf
114 | *.cachefile
115 |
116 | # Visual Studio profiler
117 | *.psess
118 | *.vsp
119 | *.vspx
120 |
121 | # TFS 2012 Local Workspace
122 | $tf/
123 |
124 | # Guidance Automation Toolkit
125 | *.gpState
126 |
127 | # ReSharper is a .NET coding add-in
128 | _ReSharper*/
129 | *.[Rr]e[Ss]harper
130 | *.DotSettings.user
131 |
132 | # JustCode is a .NET coding add-in
133 | .JustCode
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # NCrunch
142 | _NCrunch_*
143 | .*crunch*.local.xml
144 |
145 | # MightyMoose
146 | *.mm.*
147 | AutoTest.Net/
148 |
149 | # Web workbench (sass)
150 | .sass-cache/
151 |
152 | # Installshield output folder
153 | [Ee]xpress/
154 |
155 | # DocProject is a documentation generator add-in
156 | DocProject/buildhelp/
157 | DocProject/Help/*.HxT
158 | DocProject/Help/*.HxC
159 | DocProject/Help/*.hhc
160 | DocProject/Help/*.hhk
161 | DocProject/Help/*.hhp
162 | DocProject/Help/Html2
163 | DocProject/Help/html
164 |
165 | # Click-Once directory
166 | publish/
167 |
168 | # Publish Web Output
169 | *.[Pp]ublish.xml
170 | *.azurePubxml
171 | ## TODO: Comment the next line if you want to checkin your
172 | ## web deploy settings but do note that will include unencrypted
173 | ## passwords
174 | #*.pubxml
175 |
176 | *.publishproj
177 |
178 | # NuGet Packages
179 | *.nupkg
180 | # The packages folder can be ignored because of Package Restore
181 | **/packages/*
182 | # except build/, which is used as an MSBuild target.
183 | !**/packages/build/
184 | # Uncomment if necessary however generally it will be regenerated when needed
185 | #!**/packages/repositories.config
186 |
187 | # Windows Azure Build Output
188 | csx/
189 | *.build.csdef
190 |
191 | # Windows Store app package directory
192 | AppPackages/
193 |
194 | # Visual Studio cache files
195 | # files ending in .cache can be ignored
196 | *.[Cc]ache
197 | # but keep track of directories ending in .cache
198 | !*.[Cc]ache/
199 |
200 | # Others
201 | ClientBin/
202 | [Ss]tyle[Cc]op.*
203 | ~$*
204 | *~
205 | *.dbmdl
206 | *.dbproj.schemaview
207 | *.pfx
208 | *.publishsettings
209 | node_modules/
210 | orleans.codegen.cs
211 |
212 | # RIA/Silverlight projects
213 | Generated_Code/
214 |
215 | # Backup & report files from converting an old project file
216 | # to a newer Visual Studio version. Backup files are not needed,
217 | # because we have git ;-)
218 | _UpgradeReport_Files/
219 | Backup*/
220 | UpgradeLog*.XML
221 | UpgradeLog*.htm
222 |
223 | # SQL Server files
224 | *.mdf
225 | *.ldf
226 |
227 | # Business Intelligence projects
228 | *.rdl.data
229 | *.bim.layout
230 | *.bim_*.settings
231 |
232 | # Microsoft Fakes
233 | FakesAssemblies/
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 |
238 | # Visual Studio 6 build log
239 | *.plg
240 |
241 | # Visual Studio 6 workspace options file
242 | *.opt
243 |
244 | # LightSwitch generated files
245 | GeneratedArtifacts/
246 | _Pvt_Extensions/
247 | ModelManifest.xml
248 |
249 | Ignored/
250 |
251 | # Compiled object files
252 | objects/
253 |
--------------------------------------------------------------------------------
/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: bin/sonic2013
38 | install -Dp -m755 bin/sonic2013 $(prefix)/bin/sonic2013
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sonic 1/2 2013 Decompilation
2 | A Full Decompilation of Sonic 1 & 2 (2013)
3 |
4 | # **SUPPORT THE OFFICIAL RELEASE OF SONIC 1 & SONIC 2**
5 | + Without assets from the official releases this decompilation will not run.
6 | + Video tutorial on how to find your legally obtained data.rsdk file: https://www.youtube.com/watch?v=gzIfRW91IxE
7 |
8 | + You can get the official release of sonic 1 & sonic 2 from:
9 | * [Sonic 1 (iOS, Via the App Store)](https://apps.apple.com/au/app/sonic-the-hedgehog-classic/id316050001)
10 | * [Sonic 2 (iOS, Via the App Store)](https://apps.apple.com/au/app/sonic-the-hedgehog-2-classic/id347415188)
11 | * [Sonic 1 (Android, Via Google Play)](https://play.google.com/store/apps/details?id=com.sega.sonic1px&hl=en_AU&gl=US)
12 | * [Sonic 2 (Android, Via Google Play)](https://play.google.com/store/apps/details?id=com.sega.sonic2.runner&hl=en_AU&gl=US)
13 | * [Sonic 1 (Android, Via Amazon)](https://www.amazon.com.au/Sega-of-America-Sonic-Hedgehog/dp/B00D74DVKM)
14 | * [Sonic 2 (Android, Via Amazon)](https://www.amazon.com.au/Sega-of-America-Sonic-Hedgehog/dp/B00HAPRVWS)
15 |
16 | Even if your platform isn't supported by the official releases, buy it for the assets (you don't need to run the official release, you just need the game assets)
17 |
18 | If you want to transfer your save from the **Android pre-forever versions,** you can go to `Android/data/com.sega.sonic1 or 2/SGame.bin` and copy it to the `SData.bin` in the EXE folder.
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 | * a mac build of v1.0.0 by sappharad can be found [here](https://github.com/Sappharad/Sonic-1-2-2013-Decompilation/releases/tag/1.0.0mac)
41 |
42 | ## Switch:
43 | * head on over to [heyjoeway's fork](https://github.com/heyjoeway/Sonic-1-2-2013-Decompilation) and follow the installation instructions in the readme
44 |
45 | ## Other platforms:
46 | 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.
47 | 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
48 |
49 | # FAQ
50 | ### Q: The screen is tearing, how do I fix it?
51 | A: Try turning on vsync, that worked for me (tested on mac)
52 |
53 | ### Q: I found a bug/I have a feature request!
54 | A: Submit an issue in the issues tab and I'll fix/add (if possible) it as soon as I can
55 |
56 | ### Q: Will you do a decompilation for Sonic CD (2011)?
57 | A: I already have! you can find it [here](https://github.com/Rubberduckycooly/Sonic-CD-11-Decompilation)!
58 |
59 | ### Q: Will you do a decompilation for Sonic Mania?
60 | 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
61 |
62 | # Special Thanks
63 | * [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
64 | * 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
65 |
66 | # Contact:
67 | you can join the [Retro Engine Modding Discord Server](https://dc.railgun.works/retroengine) for any extra questions you may need to know about the decompilation or modding it
68 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/Sonic1.Vita/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | ## This file is a quick tutorial on writing CMakeLists for targeting the Vita
2 | cmake_minimum_required(VERSION 2.8)
3 |
4 | ## This includes the Vita toolchain, must go before project definition
5 | # It is a convenience so you do not have to type
6 | # -DCMAKE_TOOLCHAIN_FILE=$VITASDK/share/vita.toolchain.cmake for cmake. It is
7 | # highly recommended that you include this block for all projects.
8 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
9 | if(DEFINED ENV{VITASDK})
10 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
11 | else()
12 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
13 | endif()
14 | endif()
15 |
16 | ## Define project parameters here
17 | # Name of the project
18 | project(Sonic1)
19 | # This line adds Vita helper macros, must go after project definition in order
20 | # to build Vita specific artifacts (self/vpk).
21 | include("${VITASDK}/share/vita.cmake" REQUIRED)
22 |
23 | ## Configuration options for this app
24 | # Display name (under bubble in LiveArea)
25 | set(VITA_APP_NAME "Sonic 1")
26 | # Unique ID must be exactly 9 characters. Recommended: XXXXYYYYY where X =
27 | # unique string of developer and Y = a unique number for this app
28 | set(VITA_TITLEID "RSDK00002")
29 | # Optional version string to show in LiveArea's more info screen
30 | set(VITA_VERSION "01.00")
31 |
32 | ## Flags and includes for building
33 | # Note that we make sure not to overwrite previous flags
34 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -fsigned-char -fno-lto")
35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3 -fsigned-char -fno-lto -fno-rtti -fno-exceptions")
36 | # Optional. You can specify more param.sfo flags this way.
37 | set(VITA_MKSFOEX_FLAGS "${VITA_MKSFOEX_FLAGS} -d PARENTAL_LEVEL=1")
38 |
39 | add_definitions(-DRETRO_GAME_SONIC=1)
40 |
41 | # Add any additional include paths here
42 | include_directories(
43 | /home/user/vitasdk/arm-vita-eabi/include
44 | )
45 |
46 | # Add any additional library paths here
47 | # ${CMAKE_CURRENT_BINARY_DIR} lets you use any library currently being built
48 | link_directories(
49 | ${CMAKE_CURRENT_BINARY_DIR}
50 | )
51 |
52 | ## Build and link
53 | # Add all the files needed to compile here
54 | add_executable(${PROJECT_NAME}
55 | ../Sonic12Decomp/Animation.cpp
56 | ../Sonic12Decomp/Audio.cpp
57 | ../Sonic12Decomp/Collision.cpp
58 | ../Sonic12Decomp/Debug.cpp
59 | ../Sonic12Decomp/Drawing.cpp
60 | ../Sonic12Decomp/Ini.cpp
61 | ../Sonic12Decomp/Input.cpp
62 | ../Sonic12Decomp/main.cpp
63 | ../Sonic12Decomp/Math.cpp
64 | ../Sonic12Decomp/Network.cpp
65 | ../Sonic12Decomp/Object.cpp
66 | ../Sonic12Decomp/Palette.cpp
67 | ../Sonic12Decomp/PauseMenu.cpp
68 | ../Sonic12Decomp/Reader.cpp
69 | ../Sonic12Decomp/RetroEngine.cpp
70 | ../Sonic12Decomp/RetroGameLoop.cpp
71 | ../Sonic12Decomp/Scene.cpp
72 | ../Sonic12Decomp/Scene3D.cpp
73 | ../Sonic12Decomp/Script.cpp
74 | ../Sonic12Decomp/Sprite.cpp
75 | ../Sonic12Decomp/String.cpp
76 | ../Sonic12Decomp/Text.cpp
77 | ../Sonic12Decomp/Userdata.cpp
78 | )
79 |
80 | # Library to link to (drop the -l prefix). This will mostly be stubs.
81 | target_link_libraries(${PROJECT_NAME}
82 | SDL2
83 | vita2d
84 | vorbisfile
85 | vorbis
86 | ogg
87 | pthread
88 | SceDisplay_stub
89 | SceAudio_stub
90 | SceCtrl_stub
91 | SceSysmodule_stub
92 | SceGxm_stub
93 | SceCommonDialog_stub
94 | SceAppMgr_stub
95 | SceTouch_stub
96 | SceHid_stub
97 | SceAudio_stub
98 | SceMotion_stub
99 | m
100 | )
101 |
102 | ## Create Vita files
103 | vita_create_self(${PROJECT_NAME}.self ${PROJECT_NAME})
104 | # The FILE directive lets you add additional files to the VPK, the syntax is
105 | # FILE src_path dst_path_in_vpk. In this case, we add the LiveArea paths.
106 | vita_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} ${PROJECT_NAME}.self
107 | VERSION ${VITA_VERSION}
108 | NAME ${VITA_APP_NAME}
109 | # FILE sce_sys/icon0.png sce_sys/icon0.png
110 | # FILE sce_sys/livearea/contents/bg.png sce_sys/livearea/contents/bg.png
111 | # FILE sce_sys/livearea/contents/startup.png sce_sys/livearea/contents/startup.png
112 | FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml
113 | )
114 |
--------------------------------------------------------------------------------
/Sonic1.Vita/build-internal.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | apk add --no-cache make cmake
3 | cmake . && \
4 | make -j$(nproc)
5 | rm Sonic1 # this is not ignored by .gitignore
6 |
--------------------------------------------------------------------------------
/Sonic1.Vita/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo docker run \
3 | --rm \
4 | -v $PWD/..:/work \
5 | -w /work/Sonic1.Vita \
6 | vitasdk/vitasdk \
7 | /bin/sh -C "./build-internal.sh"
8 |
--------------------------------------------------------------------------------
/Sonic1.Vita/sce_sys/livearea/contents/template.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bg.png
6 |
7 |
8 |
9 | startup.png
10 |
11 |
12 |
--------------------------------------------------------------------------------
/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 (0x8) //4 in the original, 8 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 | void SetSfxName(const char *sfxName, int sfxID);
151 |
152 | //Helper Func
153 | inline bool PlaySFXByName(const char* sfx, sbyte loopCnt) {
154 | for (int s = 0; s < globalSFXCount + stageSFXCount; ++s) {
155 | if (StrComp(sfxNames[s], sfx)) {
156 | PlaySfx(s, loopCnt);
157 | return true;
158 | }
159 | }
160 | return false;
161 | }
162 |
163 | inline void SetMusicVolume(int volume)
164 | {
165 | if (volume < 0)
166 | volume = 0;
167 | if (volume > MAX_VOLUME)
168 | volume = MAX_VOLUME;
169 | masterVolume = volume;
170 | }
171 |
172 | inline void SetGameVolumes(int bgmVolume, int sfxVolume) {
173 | //musicVolumeSetting = bgmVolume;
174 | SetMusicVolume(masterVolume);
175 | //sfxVolumeSetting = ((sfxVolume << 7) / 100);
176 | }
177 |
178 | inline void PauseSound()
179 | {
180 | if (musicStatus == MUSIC_PLAYING)
181 | musicStatus = MUSIC_PAUSED;
182 | }
183 |
184 | inline void ResumeSound()
185 | {
186 | if (musicStatus == MUSIC_PAUSED)
187 | musicStatus = MUSIC_PLAYING;
188 | }
189 |
190 |
191 | inline void StopAllSfx()
192 | {
193 | #if RETRO_USING_SDL
194 | SDL_LockAudio();
195 | #endif
196 | for (int i = 0; i < CHANNEL_COUNT; ++i) sfxChannels[i].sfxID = -1;
197 | #if RETRO_USING_SDL
198 | SDL_UnlockAudio();
199 | #endif
200 | }
201 | inline void ReleaseGlobalSfx()
202 | {
203 | for (int i = globalSFXCount; i >= 0; --i) {
204 | if (sfxList[i].loaded) {
205 | StrCopy(sfxList[i].name, "");
206 | StrCopy(sfxNames[i], "");
207 | free(sfxList[i].buffer);
208 | sfxList[i].length = 0;
209 | sfxList[i].loaded = false;
210 | }
211 | }
212 | globalSFXCount = 0;
213 | }
214 | inline void ReleaseStageSfx()
215 | {
216 | for (int i = stageSFXCount + globalSFXCount; i >= globalSFXCount; --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 | stageSFXCount = 0;
226 | }
227 |
228 | inline void ReleaseAudioDevice()
229 | {
230 | StopMusic();
231 | StopAllSfx();
232 | ReleaseStageSfx();
233 | ReleaseGlobalSfx();
234 | }
235 |
236 | #endif // !AUDIO_H
237 |
--------------------------------------------------------------------------------
/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 | extern bool endLine;
5 | inline void printLog(const char *msg, ...)
6 | {
7 | #ifndef RETRO_DISABLE_LOG
8 | if (engineDebugMode) {
9 | char buffer[0x100];
10 |
11 | // make the full string
12 | va_list args;
13 | va_start(args, msg);
14 | vsprintf(buffer, msg, args);
15 | if (endLine) {
16 | printf("%s\n", buffer);
17 | sprintf(buffer, "%s\n", buffer);
18 | }
19 | else {
20 | printf("%s", buffer);
21 | sprintf(buffer, "%s", buffer);
22 | }
23 |
24 | char pathBuffer[0x100];
25 | #if RETRO_PLATFORM == RETRO_OSX
26 | if (!usingCWD)
27 | sprintf(pathBuffer, "%s/log.txt", getResourcesPath());
28 | else
29 | sprintf(pathBuffer, "log.txt");
30 | #else
31 | sprintf(pathBuffer, BASE_PATH "log.txt");
32 | #endif
33 | FileIO *file = fOpen(pathBuffer, "a");
34 | if (file) {
35 | fWrite(&buffer, 1, StrLength(buffer), file);
36 | fClose(file);
37 | }
38 | }
39 | #endif
40 | }
41 |
42 | inline void printLog(const ushort *msg)
43 | {
44 | #ifndef RETRO_DISABLE_LOG
45 | if (engineDebugMode) {
46 | int mPos = 0;
47 | while (msg[mPos]) {
48 | printf("%lc", (wint_t)msg[mPos]);
49 | mPos++;
50 | }
51 | if (endLine)
52 | printf("\n");
53 |
54 | char pathBuffer[0x100];
55 | #if RETRO_PLATFORM == RETRO_OSX
56 | if (!usingCWD)
57 | sprintf(pathBuffer, "%s/log.txt", getResourcesPath());
58 | else
59 | sprintf(pathBuffer, "log.txt");
60 | #else
61 | sprintf(pathBuffer, BASE_PATH "log.txt");
62 | #endif
63 | mPos = 0;
64 | FileIO *file = fOpen(pathBuffer, "a");
65 | if (file) {
66 | while (msg[mPos]) {
67 | fWrite(&msg[mPos], 2, 1, file);
68 | mPos++;
69 | }
70 |
71 | ushort el = '\n';
72 | if (endLine)
73 | fWrite(&el, 2, 1, file);
74 | fClose(file);
75 | }
76 | }
77 | #endif
78 | }
79 |
80 | enum DevMenuMenus {
81 | DEVMENU_MAIN,
82 | DEVMENU_PLAYERSEL,
83 | DEVMENU_STAGELISTSEL,
84 | DEVMENU_STAGESEL,
85 | DEVMENU_SCRIPTERROR,
86 | };
87 |
88 | enum StartMenuMenus {
89 | STARTMENU_MAIN = 5,
90 | STARTMENU_SAVESEL,
91 | STARTMENU_PLAYERSEL,
92 | STARTMENU_GAMEOPTS,
93 | STARTMENU_TASTAGESEL,
94 | STARTMENU_TACONFIRMSEL,
95 | STARTMENU_ACHIEVEMENTS,
96 | STARTMENU_LEADERBOARDS,
97 | };
98 |
99 | void initDevMenu();
100 | void initErrorMessage();
101 | void processStageSelect();
102 |
103 | // added due to lack of normal main menu
104 | void initStartMenu(int mode);
105 | void processStartMenu();
106 | void setTextMenu(int mode);
107 |
108 | #endif //! DEBUG_H
109 |
--------------------------------------------------------------------------------
/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 |
6 | IniParser::IniParser(const char *filename)
7 | {
8 | memset(items, 0, 0x80 * sizeof(ConfigItem));
9 | char buf[0x100];
10 | char section[0x40];
11 | bool hasSection = false;
12 | char key[0x40];
13 | char value[0x100];
14 |
15 | count = 0;
16 |
17 | char pathBuffer[0x80];
18 |
19 | #if RETRO_PLATFORM == RETRO_OSX
20 | if (!usingCWD)
21 | sprintf(pathBuffer, "%s/%s", getResourcesPath(), filename);
22 | else
23 | sprintf(pathBuffer, "%s", filename);
24 | #else
25 | sprintf(pathBuffer, "%s", filename);
26 | #endif
27 |
28 | FileIO *f;
29 | if ((f = fOpen(pathBuffer, "r")) == NULL) {
30 | printLog("ERROR: Couldn't open file '%s'!", filename);
31 | return;
32 | }
33 |
34 | while (true) {
35 | bool flag = false;
36 | int ret = 0;
37 | int strLen = 0;
38 | while (true) {
39 | ret = (int)fRead(&buf[strLen++], sizeof(byte), 1, f);
40 | flag = ret == 0;
41 | if (ret == 0)
42 | break;
43 | if (buf[strLen - 1] == '\n')
44 | break;
45 | }
46 | buf[strLen] = 0;
47 | if (buf[0] == '#')
48 | continue;
49 |
50 | if (sscanf(buf, "[%[^][]]", section) == 1) {
51 | hasSection = true;
52 | }
53 | else if (sscanf(buf, "%[^ =]= %s", key, value) == 2 || sscanf(buf, "%[^ =]=%s", key, value) == 2
54 | || sscanf(buf, "%[^ =] = %s", key, value) == 2 || sscanf(buf, "%[^ =] =%s", key, value) == 2) {
55 | if (hasSection)
56 | sprintf(items[count].section, "%s", section);
57 |
58 | sprintf(items[count].key, "%s", key);
59 | sprintf(items[count].value, "%s", value);
60 | items[count].hasSection = hasSection;
61 | count++;
62 | }
63 | if (flag)
64 | break;
65 | }
66 |
67 | fClose(f);
68 | }
69 |
70 | int IniParser::GetString(const char *section, const char *key, char *dest)
71 | {
72 | if (count == 0)
73 | return 0;
74 |
75 | for (int x = 0; x < count; x++) {
76 | if (!strcmp(section, items[x].section)) {
77 | if (!strcmp(key, items[x].key)) {
78 | strcpy(dest, items[x].value);
79 | return 1;
80 | }
81 | }
82 | }
83 |
84 | return 0;
85 | }
86 | int IniParser::GetInteger(const char *section, const char *key, int *dest)
87 | {
88 | if (count == 0)
89 | return 0;
90 |
91 | for (int x = 0; x < count; x++) {
92 | if (!strcmp(section, items[x].section)) {
93 | if (!strcmp(key, items[x].key)) {
94 | *dest = atoi(items[x].value);
95 | return 1;
96 | }
97 | }
98 | }
99 |
100 | return 0;
101 | }
102 | int IniParser::GetFloat(const char *section, const char *key, float *dest)
103 | {
104 | if (count == 0)
105 | return 0;
106 |
107 | for (int x = 0; x < count; x++) {
108 | if (!strcmp(section, items[x].section)) {
109 | if (!strcmp(key, items[x].key)) {
110 | *dest = atof(items[x].value);
111 | return 1;
112 | }
113 | }
114 | }
115 |
116 | return 0.0f;
117 | }
118 | int IniParser::GetBool(const char *section, const char *key, bool *dest)
119 | {
120 | if (count == 0)
121 | return 0;
122 |
123 | for (int x = 0; x < count; x++) {
124 | if (!strcmp(section, items[x].section)) {
125 | if (!strcmp(key, items[x].key)) {
126 | *dest = !strcmp(items[x].value, "true") || !strcmp(items[x].value, "1");
127 | return 1;
128 | }
129 | }
130 | }
131 |
132 | return 0;
133 | }
134 |
135 | int IniParser::SetString(const char *section, const char *key, char *value)
136 | {
137 | int where = -1;
138 | for (int x = 0; x < count; x++) {
139 | if (strcmp(section, items[x].section) == 0) {
140 | if (strcmp(key, items[x].key) == 0) {
141 | where = x;
142 | break;
143 | }
144 | }
145 | }
146 | if (where < 0)
147 | where = count++;
148 |
149 | strcpy(items[where].section, section);
150 | strcpy(items[where].key, key);
151 | strcpy(items[where].value, value);
152 | items[where].type = INI_ITEM_STRING;
153 | return 1;
154 | }
155 | int IniParser::SetInteger(const char *section, const char *key, int value)
156 | {
157 | int where = -1;
158 | for (int x = 0; x < count; x++) {
159 | if (strcmp(section, items[x].section) == 0) {
160 | if (strcmp(key, items[x].key) == 0) {
161 | where = x;
162 | break;
163 | }
164 | }
165 | }
166 | if (where < 0)
167 | where = count++;
168 |
169 | strcpy(items[where].section, section);
170 | strcpy(items[where].key, key);
171 | sprintf(items[where].value, "%d", value);
172 | items[where].type = INI_ITEM_INT;
173 | return 1;
174 | }
175 | int IniParser::SetFloat(const char *section, const char *key, float value)
176 | {
177 | int where = -1;
178 | for (int x = 0; x < count; x++) {
179 | if (strcmp(section, items[x].section) == 0) {
180 | if (strcmp(key, items[x].key) == 0) {
181 | where = x;
182 | break;
183 | }
184 | }
185 | }
186 | if (where < 0)
187 | where = count++;
188 |
189 | strcpy(items[where].section, section);
190 | strcpy(items[where].key, key);
191 | sprintf(items[where].value, "%f", value);
192 | items[where].type = INI_ITEM_FLOAT;
193 | return 1;
194 | }
195 | int IniParser::SetBool(const char *section, const char *key, bool value)
196 | {
197 | int where = -1;
198 | for (int x = 0; x < count; x++) {
199 | if (strcmp(section, items[x].section) == 0) {
200 | if (strcmp(key, items[x].key) == 0) {
201 | where = x;
202 | break;
203 | }
204 | }
205 | }
206 | if (where < 0)
207 | where = count++;
208 |
209 | strcpy(items[where].section, section);
210 | strcpy(items[where].key, key);
211 | sprintf(items[where].value, "%s", value ? "true" : "false");
212 | items[where].type = INI_ITEM_BOOL;
213 | return 1;
214 | }
215 | int IniParser::SetComment(const char *section, const char *key, const char *comment)
216 | {
217 | int where = -1;
218 | for (int x = 0; x < count; x++) {
219 | if (strcmp(section, items[x].section) == 0) {
220 | if (strcmp(key, items[x].key) == 0) {
221 | where = x;
222 | break;
223 | }
224 | }
225 | }
226 | if (where < 0)
227 | where = count++;
228 |
229 | strcpy(items[where].section, section);
230 | strcpy(items[where].key, key);
231 | sprintf(items[where].value, "%s", comment);
232 | items[where].type = INI_ITEM_COMMENT;
233 | return 1;
234 | }
235 |
236 | void IniParser::Write(const char *filename)
237 | {
238 | char pathBuffer[0x80];
239 |
240 | #if RETRO_PLATFORM == RETRO_OSX
241 | if (!usingCWD)
242 | sprintf(pathBuffer, "%s/%s", getResourcesPath(), filename);
243 | else
244 | sprintf(pathBuffer, "%s", filename);
245 | #else
246 | sprintf(pathBuffer, "%s", filename);
247 | #endif
248 |
249 | FileIO *f;
250 | if ((f = fOpen(pathBuffer, "w")) == NULL) {
251 | printLog("ERROR: Couldn't open file '%s' for writing!", filename);
252 | return;
253 | }
254 |
255 | char sections[10][60];
256 | char past[60];
257 | int c = 0;
258 | sprintf(past, "");
259 | for (int i = 0; i < count; ++i) {
260 | if (std::find(std::begin(sections), std::end(sections), items[i].section) == std::end(sections) && strcmp(past, items[i].section) != 0) {
261 | sprintf(past, "%s", items[i].section);
262 | sprintf(sections[c], "%s", items[i].section);
263 | c++;
264 | }
265 | }
266 |
267 | if (c >= 1) {
268 | if (strcmp(sections[0], sections[c - 1]) == 0)
269 | c--;
270 | }
271 |
272 | char buffer[0x100];
273 | for (int s = 0; s < c; ++s) {
274 | sprintf(buffer, "[%s]\n", sections[s]);
275 | fWrite(&buffer, 1, StrLength(buffer), f);
276 | for (int i = 0; i < count; ++i) {
277 | if (strcmp(sections[s], items[i].section) == 0) {
278 | switch (items[i].type) {
279 | default:
280 | case INI_ITEM_STRING:
281 | case INI_ITEM_INT:
282 | case INI_ITEM_FLOAT:
283 | case INI_ITEM_BOOL:
284 | sprintf(buffer, "%s=%s\n", items[i].key, items[i].value);
285 | fWrite(&buffer, 1, StrLength(buffer), f);
286 | break;
287 | case INI_ITEM_COMMENT:
288 | sprintf(buffer, "; %s\n", items[i].value);
289 | fWrite(&buffer, 1, StrLength(buffer), f);
290 | break;
291 | }
292 | }
293 | }
294 |
295 | if (s + 1 < c) {
296 | sprintf(buffer, "\n");
297 | fWrite(&buffer, StrLength(buffer), 1, f);
298 | }
299 | }
300 |
301 | fClose(f);
302 | }
303 |
--------------------------------------------------------------------------------
/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: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) < -LSTICK_DEADZONE;
51 | case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) > LSTICK_DEADZONE;
52 | case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) < -LSTICK_DEADZONE;
53 | case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) > LSTICK_DEADZONE;
54 | }
55 | }
56 |
57 | switch (buttonID) {
58 | default: break;
59 | case SDL_CONTROLLER_BUTTON_ZL: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > LTRIGGER_DEADZONE;
60 | case SDL_CONTROLLER_BUTTON_ZR: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > RTRIGGER_DEADZONE;
61 | case SDL_CONTROLLER_BUTTON_LSTICK_UP: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) < -LSTICK_DEADZONE;
62 | case SDL_CONTROLLER_BUTTON_LSTICK_DOWN: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) > LSTICK_DEADZONE;
63 | case SDL_CONTROLLER_BUTTON_LSTICK_LEFT: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) < -LSTICK_DEADZONE;
64 | case SDL_CONTROLLER_BUTTON_LSTICK_RIGHT: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) > LSTICK_DEADZONE;
65 | case SDL_CONTROLLER_BUTTON_RSTICK_UP: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) < -RSTICK_DEADZONE;
66 | case SDL_CONTROLLER_BUTTON_RSTICK_DOWN: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) > RSTICK_DEADZONE;
67 | case SDL_CONTROLLER_BUTTON_RSTICK_LEFT: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) < -RSTICK_DEADZONE;
68 | case SDL_CONTROLLER_BUTTON_RSTICK_RIGHT: return SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) > RSTICK_DEADZONE;
69 | }
70 |
71 | return false;
72 | }
73 | #endif
74 |
75 | void ProcessInput()
76 | {
77 | #if RETRO_USING_SDL
78 | int length = 0;
79 | const byte *keyState = SDL_GetKeyboardState(&length);
80 |
81 | if (inputType == 0) {
82 | for (int i = 0; i < 8; i++) {
83 | if (keyState[inputDevice[i].keyMappings]) {
84 | inputDevice[i].setHeld();
85 | inputDevice[8].setHeld();
86 | continue;
87 | }
88 | else if (inputDevice[i].hold)
89 | inputDevice[i].setReleased();
90 | }
91 | }
92 | else if (inputType == 1) {
93 | for (int i = 0; i < 8; i++) {
94 | if (getControllerButton(inputDevice[i].contMappings)) {
95 | inputDevice[i].setHeld();
96 | inputDevice[8].setHeld();
97 | continue;
98 | }
99 | else if (inputDevice[i].hold)
100 | inputDevice[i].setReleased();
101 | }
102 | }
103 |
104 | if (keyState[inputDevice[0].keyMappings] || keyState[inputDevice[1].keyMappings] || keyState[inputDevice[2].keyMappings]
105 | || keyState[inputDevice[3].keyMappings] || keyState[inputDevice[4].keyMappings] || keyState[inputDevice[5].keyMappings]
106 | || keyState[inputDevice[6].keyMappings] || keyState[inputDevice[7].keyMappings]) {
107 | inputType = 0;
108 | }
109 | else if (inputType == 0)
110 | inputDevice[8].setReleased();
111 |
112 | if (getControllerButton(SDL_CONTROLLER_BUTTON_A) || getControllerButton(SDL_CONTROLLER_BUTTON_B) || getControllerButton(SDL_CONTROLLER_BUTTON_X)
113 | || getControllerButton(SDL_CONTROLLER_BUTTON_Y) || getControllerButton(SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
114 | || getControllerButton(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) || getControllerButton(SDL_CONTROLLER_BUTTON_ZL)
115 | || getControllerButton(SDL_CONTROLLER_BUTTON_ZR) || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_UP)
116 | || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_DOWN) || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_LEFT)
117 | || getControllerButton(SDL_CONTROLLER_BUTTON_DPAD_RIGHT) || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_UP)
118 | || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_DOWN) || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_LEFT)
119 | || getControllerButton(SDL_CONTROLLER_BUTTON_LSTICK_RIGHT) || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_UP)
120 | || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_DOWN) || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_LEFT)
121 | || getControllerButton(SDL_CONTROLLER_BUTTON_RSTICK_RIGHT) || getControllerButton(SDL_CONTROLLER_BUTTON_START)) {
122 | inputType = 1;
123 | }
124 | else if (inputType == 1)
125 | inputDevice[8].setReleased();
126 | #endif
127 | }
128 |
129 | void CheckKeyPress(InputData *input, byte flags)
130 | {
131 | if (flags & 0x1)
132 | input->up = inputDevice[0].press;
133 | if (flags & 0x2)
134 | input->down = inputDevice[1].press;
135 | if (flags & 0x4)
136 | input->left = inputDevice[2].press;
137 | if (flags & 0x8)
138 | input->right = inputDevice[3].press;
139 | if (flags & 0x10)
140 | input->A = inputDevice[4].press;
141 | if (flags & 0x20)
142 | input->B = inputDevice[5].press;
143 | if (flags & 0x40)
144 | input->C = inputDevice[6].press;
145 | if (flags & 0x80)
146 | input->start = inputDevice[7].press;
147 | if (flags & 0x80)
148 | anyPress = inputDevice[8].press;
149 | }
150 |
151 | void CheckKeyDown(InputData *input, byte flags)
152 | {
153 | if (flags & 0x1)
154 | input->up = inputDevice[0].hold;
155 | if (flags & 0x2)
156 | input->down = inputDevice[1].hold;
157 | if (flags & 0x4)
158 | input->left = inputDevice[2].hold;
159 | if (flags & 0x8)
160 | input->right = inputDevice[3].hold;
161 | if (flags & 0x10)
162 | input->A = inputDevice[4].hold;
163 | if (flags & 0x20)
164 | input->B = inputDevice[5].hold;
165 | if (flags & 0x40)
166 | input->C = inputDevice[6].hold;
167 | if (flags & 0x80)
168 | input->start = inputDevice[7].hold;
169 | // if (flags & 0x80)
170 | // anyHold = inputDevice[8].hold;
171 | }
--------------------------------------------------------------------------------
/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 | #ifndef M_PI
5 | #define M_PI 3.14159265358979323846264338327950288
6 | #endif
7 |
8 | int sinValM7[512];
9 | int cosValM7[512];
10 |
11 | int sinVal512[512];
12 | int cosVal512[512];
13 |
14 | int sinVal256[256];
15 | int cosVal256[256];
16 |
17 | byte atanVal256[0x100 * 0x100];
18 |
19 | void CalculateTrigAngles()
20 | {
21 | for (int i = 0; i < 0x200; ++i) {
22 | float val = sin(((float)i / 256.0) * M_PI);
23 | sinValM7[i] = (val * 4096.0);
24 | val = cos(((float)i / 256.0) * M_PI);
25 | cosValM7[i] = (val * 4096.0);
26 | }
27 |
28 | cosValM7[0] = 4096;
29 | cosValM7[128] = 0;
30 | cosValM7[256] = -4096;
31 | cosValM7[384] = 0;
32 | sinValM7[0] = 0;
33 | sinValM7[128] = 4096;
34 | sinValM7[256] = 0;
35 | sinValM7[384] = -4096;
36 |
37 | for (int i = 0; i < 0x200; ++i) {
38 | float val = sinf(((float)i / 256) * M_PI);
39 | sinVal512[i] = (signed int)(val * 512.0);
40 | val = cosf(((float)i / 256) * M_PI);
41 | cosVal512[i] = (signed int)(val * 512.0);
42 | }
43 |
44 | cosVal512[0] = 0x200;
45 | cosVal512[128] = 0;
46 | cosVal512[256] = -0x200;
47 | cosVal512[384] = 0;
48 | sinVal512[0] = 0;
49 | sinVal512[128] = 0x200;
50 | sinVal512[256] = 0;
51 | sinVal512[384] = -0x200;
52 |
53 | for (int i = 0; i < 0x100; i++) {
54 | sinVal256[i] = (sinVal512[i * 2] >> 1);
55 | cosVal256[i] = (cosVal512[i * 2] >> 1);
56 | }
57 |
58 | for (int Y = 0; Y < 0x100; ++Y) {
59 | byte *ATan = (byte *)&atanVal256[Y];
60 | for (int X = 0; X < 0x100; ++X) {
61 | float angle = atan2f(Y, X);
62 | *ATan = (signed int)(angle * 40.743664f);
63 | ATan += 0x100;
64 | }
65 | }
66 | }
67 |
68 | byte ArcTanLookup(int X, int Y)
69 | {
70 | int x = 0;
71 | int y = 0;
72 |
73 | x = abs(X);
74 | y = abs(Y);
75 |
76 | if (x <= y) {
77 | while (y > 0xFF) {
78 | x >>= 4;
79 | y >>= 4;
80 | }
81 | }
82 | else {
83 | while (x > 0xFF) {
84 | x >>= 4;
85 | y >>= 4;
86 | }
87 | }
88 | if (X <= 0) {
89 | if (Y <= 0)
90 | return atanVal256[(x << 8) + y] + -0x80;
91 | else
92 | return -0x80 - atanVal256[(x << 8) + y];
93 | }
94 | else if (Y <= 0)
95 | return -atanVal256[(x << 8) + y];
96 | else
97 | return atanVal256[(x << 8) + y];
98 | }
99 |
100 | int64_t pow(int base, int exponent) {
101 | if (!exponent) return 1;
102 | int64_t result = base;
103 | for (int i = 1; i < exponent; i++) result *= base;
104 | return result;
105 | }
106 |
--------------------------------------------------------------------------------
/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 | void SetObjectTypeName(const char *objectName, int objectID);
132 |
133 | extern int playerListPos;
134 |
135 | void ProcessPlayerControl(Entity *player);
136 |
137 | void InitNativeObjectSystem();
138 | NativeEntity *CreateNativeObject(void (*objCreate)(void *objPtr), void (*objMain)(void *objPtr));
139 | void RemoveNativeObject(NativeEntityBase *NativeEntry);
140 | void ProcessNativeObjects();
141 | inline void BackupNativeObjects() {
142 | memcpy(backupEntityList, activeEntityList, sizeof(int) * NATIVEENTITY_COUNT);
143 | memcpy(objectEntityBackup, objectEntityBank, sizeof(NativeEntity) * NATIVEENTITY_COUNT);
144 | nativeEntityCountBackup = nativeEntityCount;
145 | }
146 | inline void BackupNativeObjectsSettings() {
147 | memcpy(backupEntityListS, activeEntityList, sizeof(int) * NATIVEENTITY_COUNT);
148 | memcpy(objectEntityBackupS, objectEntityBank, sizeof(NativeEntity) * NATIVEENTITY_COUNT);
149 | nativeEntityCountBackupS = nativeEntityCount;
150 | }
151 | inline void RestoreNativeObjects()
152 | {
153 | memcpy(activeEntityList, backupEntityList, sizeof(int) * NATIVEENTITY_COUNT);
154 | nativeEntityCount = nativeEntityCountBackup;
155 | memcpy(objectEntityBank, objectEntityBackup, sizeof(NativeEntity) * NATIVEENTITY_COUNT);
156 |
157 | //ptr = CreateNativeObject(FadeScreen_Create, FadeScreen_Main);
158 | //ptr + 16 = 0;
159 | }
160 | inline void RestoreNativeObjectsNoFade()
161 | {
162 | memcpy(activeEntityList, backupEntityList, sizeof(int) * NATIVEENTITY_COUNT);
163 | nativeEntityCount = nativeEntityCountBackup;
164 | memcpy(objectEntityBank, objectEntityBackup, sizeof(NativeEntity) * NATIVEENTITY_COUNT);
165 | }
166 | inline void RestoreNativeObjectsSettings()
167 | {
168 | memcpy(activeEntityList, backupEntityListS, sizeof(int) * NATIVEENTITY_COUNT);
169 | nativeEntityCount = nativeEntityCountBackupS;
170 | memcpy(objectEntityBank, objectEntityBackupS, sizeof(NativeEntity) * NATIVEENTITY_COUNT);
171 | }
172 | inline void GetNativeObject(NativeEntity *obj, void (*newCreate)(void *objPtr), void (*newMain)(void *objPtr))
173 | {
174 | int slotID = obj->slotID;
175 | int objID = obj->objectID;
176 | memset(&objectEntityBank[slotID], 0, sizeof(NativeEntity));
177 | obj->slotID = slotID;
178 | obj->mainPtr = newMain;
179 | obj->createPtr = newCreate;
180 | obj->objectID = objID;
181 | if (obj->createPtr)
182 | obj->createPtr(obj);
183 | }
184 | inline NativeEntity *GetNativeObject(uint objID)
185 | {
186 | if (objID > 0xFF)
187 | return nullptr;
188 | else
189 | return &objectEntityBank[objID];
190 | }
191 | inline void ClearNativeObjects() {
192 | nativeEntityCount = 0;
193 | memset(objectEntityBank, 0, sizeof(NativeEntity) * NATIVEENTITY_COUNT);
194 | }
195 |
196 | #endif // !OBJECT_H
197 |
--------------------------------------------------------------------------------
/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].r * blendAmount + blendA * fullPalette32[srcPaletteA][l].r) >> 8),
72 | (byte)((ushort)(fullPalette32[srcPaletteB][l].g * blendAmount + blendA * fullPalette32[srcPaletteA][l].g) >> 8),
73 | (byte)((ushort)(fullPalette32[srcPaletteB][l].b * blendAmount + blendA * fullPalette32[srcPaletteA][l].b) >> 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) gfxLineBuffer[startLine % SCREEN_YSIZE] = 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 | // typedef unsigned long long ulong;
21 |
22 | #define RETRO_USE_NETWORKING (0)
23 | #if !RETRO_USE_NETWORKING
24 | #define NETWORK_H // easy way to fuck over network header LOL
25 | #endif
26 |
27 | // Platforms (RSDKv4 only defines these 7 (I assume), but feel free to add your own custom platform define for easier platform code changes)
28 | #define RETRO_WIN (0)
29 | #define RETRO_OSX (1)
30 | #define RETRO_XBOX_360 (2)
31 | #define RETRO_PS3 (3)
32 | #define RETRO_iOS (4)
33 | #define RETRO_ANDROID (5)
34 | #define RETRO_WP7 (6)
35 | // Custom Platforms start here
36 | #define RETRO_VITA (7)
37 |
38 | // Platform types (Game manages platform-specific code such as HUD position using this rather than the above)
39 | #define RETRO_STANDARD (0)
40 | #define RETRO_MOBILE (1)
41 |
42 | #if defined _WIN32
43 | #define RETRO_PLATFORM (RETRO_WIN)
44 | #define RETRO_PLATTYPE (RETRO_STANDARD)
45 | #elif defined __APPLE__
46 | #if __IPHONEOS__
47 | #define RETRO_PLATTYPE (RETRO_iOS)
48 | #define RETRO_PLATTYPE (RETRO_MOBILE)
49 | #else
50 | #define RETRO_PLATFORM (RETRO_OSX)
51 | #define RETRO_PLATTYPE (RETRO_STANDARD)
52 | #endif
53 | #elif defined __vita__
54 | #define RETRO_PLATFORM (RETRO_VITA)
55 | #define RETRO_PLATTYPE (RETRO_STANDARD)
56 | #else
57 | #define RETRO_PLATFORM (RETRO_WIN)
58 | #define RETRO_PLATTYPE (RETRO_STANDARD)
59 | #endif
60 |
61 | #if RETRO_PLATFORM == RETRO_VITA
62 | #if RETRO_GAME_SONIC == 1
63 | #define BASE_PATH "ux0:data/Sonic1/"
64 | #elif RETRO_GAME_SONIC == 2
65 | #define BASE_PATH "ux0:data/Sonic2/"
66 | #else
67 | #error "RETRO_GAME_SONIC not defined"
68 | #endif
69 | #define DEFAULT_SCREEN_XSIZE 480
70 | #define DEFAULT_FULLSCREEN false
71 | #define SCREEN_YSIZE (272)
72 | #else
73 | #define BASE_PATH ""
74 | #define DEFAULT_SCREEN_XSIZE 424
75 | #define DEFAULT_FULLSCREEN false
76 | #define SCREEN_YSIZE (240)
77 | #define RETRO_USING_MOUSE
78 | #define RETRO_USING_TOUCH
79 | #endif
80 |
81 | #if RETRO_PLATFORM == RETRO_WINDOWS || RETRO_PLATFORM == RETRO_OSX || RETRO_PLATFORM == RETRO_VITA
82 | #define RETRO_USING_SDL (1)
83 | #else // Since its an else & not an elif these platforms probably aren't supported yet
84 | #define RETRO_USING_SDL (0)
85 | #endif
86 |
87 | #define RETRO_GAME_STANDARD (0)
88 | #define RETRO_GAME_MOBILE (1)
89 |
90 | #if RETRO_PLATFORM == RETRO_iOS || RETRO_PLATFORM == RETRO_ANDROID || RETRO_PLATFORM == RETRO_WP7
91 | #define RETRO_GAMEPLATFORM (RETRO_GAME_MOBILE)
92 | #else
93 | #define RETRO_GAMEPLATFORM (RETRO_GAME_STANDARD)
94 | #endif
95 |
96 | #define RETRO_SW_RENDER (0)
97 | #define RETRO_HW_RENDER (1)
98 | #define RETRO_RENDERTYPE (RETRO_SW_RENDER)
99 |
100 | #define RETRO_USE_HAPTICS (1)
101 |
102 | enum RetroLanguages {
103 | RETRO_EN = 0,
104 | RETRO_FR = 1,
105 | RETRO_IT = 2,
106 | RETRO_DE = 3,
107 | RETRO_ES = 4,
108 | RETRO_JP = 5,
109 | RETRO_PT = 6,
110 | RETRO_RU = 7,
111 | RETRO_KO = 8,
112 | RETRO_ZH = 9,
113 | RETRO_ZS = 10,
114 | };
115 |
116 | enum RetroStates {
117 | ENGINE_DEVMENU = 0,
118 | ENGINE_MAINGAME = 1,
119 | ENGINE_INITDEVMENU = 2,
120 | ENGINE_WAIT = 3,
121 | ENGINE_SCRIPTERROR = 4,
122 | ENGINE_INITPAUSE = 5,
123 | ENGINE_EXITPAUSE = 6,
124 | ENGINE_ENDGAME = 7,
125 | ENGINE_RESETGAME = 8,
126 |
127 | // Custom GameModes (required to make some features work
128 | ENGINE_CONNECT2PVS = 0x80,
129 | };
130 |
131 | enum RetroGameType {
132 | GAME_UNKNOWN = 0,
133 | GAME_SONIC1 = 1,
134 | GAME_SONIC2 = 2,
135 | };
136 |
137 | // General Defines
138 | #define SCREEN_CENTERY (SCREEN_YSIZE / 2)
139 |
140 | #if RETRO_PLATFORM == RETRO_WIN
141 | #include
142 | #include
143 | #elif RETRO_PLATFORM == RETRO_OSX
144 | #include
145 | #include
146 |
147 | #include "cocoaHelpers.hpp"
148 |
149 | #elif RETRO_USING_SDL
150 | #include
151 | #include
152 |
153 | #else
154 |
155 | #endif
156 |
157 | extern bool usingCWD;
158 | extern bool engineDebugMode;
159 |
160 | // Utils
161 | #include "Ini.hpp"
162 | #include "Network.hpp"
163 |
164 | #include "Math.hpp"
165 | #include "Reader.hpp"
166 | #include "String.hpp"
167 | #include "Animation.hpp"
168 | #include "Audio.hpp"
169 | #include "Input.hpp"
170 | #include "Object.hpp"
171 | #include "Palette.hpp"
172 | #include "Drawing.hpp"
173 | #include "Scene3D.hpp"
174 | #include "Collision.hpp"
175 | #include "Scene.hpp"
176 | #include "Script.hpp"
177 | #include "Sprite.hpp"
178 | #include "Text.hpp"
179 | #include "Userdata.hpp"
180 | #include "Debug.hpp"
181 |
182 | // Native Entities
183 | #include "PauseMenu.hpp"
184 | #include "RetroGameLoop.hpp"
185 |
186 | class RetroEngine
187 | {
188 | public:
189 | bool usingDataFile = false;
190 | bool usingBytecode = false;
191 |
192 | char *dataFile = new char[0x80];
193 |
194 | bool initialised = false;
195 | bool running = false;
196 |
197 | int gameMode = 1;
198 | int language = RETRO_EN;
199 | int message = 0;
200 |
201 | bool trialMode = false;
202 | bool onlineActive = true;
203 | bool hapticsEnabled = true;
204 |
205 | int frameSkipSetting = 0;
206 | int frameSkipTimer = 0;
207 |
208 | // Ported from RSDKv5
209 | bool devMenu = false;
210 | int startList = -1;
211 | int startStage = -1;
212 | int startPlayer = -1;
213 | int startSave = -1;
214 | int gameSpeed = 1;
215 | int fastForwardSpeed = 8;
216 | bool masterPaused = false;
217 | bool frameStep = false;
218 |
219 | bool showPaletteOverlay = false;
220 | bool useHQModes = true;
221 |
222 | void Init();
223 | void Run();
224 |
225 | bool LoadGameConfig(const char *Filepath);
226 |
227 | int callbackMessage = 0;
228 | int prevMessage = 0;
229 | int waitValue = 0;
230 | void Callback(int callbackID);
231 |
232 | bool finishedStartMenu = false;
233 |
234 | char gameWindowText[0x40];
235 | char gameDescriptionText[0x100];
236 | const char *gameVersion = "1.1.0";
237 | #if RETRO_GAMEPLATFORM == RETRO_GAME_STANDARD
238 | const char *gamePlatform = "STANDARD";
239 | #elif RETRO_GAMEPLATFORM == RETRO_GAME_MOBILE
240 | const char *gamePlatform = "MOBILE";
241 | #endif
242 |
243 | #if RETRO_RENDERTYPE == RETRO_SW_RENDER
244 | const char *gameRenderType = "SW_RENDERING";
245 | #elif RETRO_RENDERTYPE == RETRO_HW_RENDER
246 | const char *gameRenderType = "HW_RENDERING";
247 | #endif
248 |
249 | #if RETRO_USE_HAPTICS
250 | const char *gameHapticSetting = "USE_F_FEEDBACK"; // None is default, but people with controllers exist
251 | #else
252 | const char *gameHapticSetting = "NO_F_FEEDBACK";
253 | #endif
254 |
255 | byte gameType = GAME_UNKNOWN;
256 |
257 | ushort *frameBuffer = nullptr;
258 | ushort *frameBuffer2x = nullptr;
259 |
260 | bool isFullScreen = false;
261 |
262 | bool startFullScreen = false; // if should start as fullscreen
263 | bool borderless = false;
264 | bool vsync = false;
265 | int windowScale = 2;
266 | int refreshRate = 60; // user-picked screen update rate
267 | int screenRefreshRate = 60; // hardware screen update rate
268 | int targetRefreshRate = 60; // game logic update rate
269 |
270 | uint frameCount = 0; // frames since scene load
271 | int renderFrameIndex = 0;
272 | int skipFrameIndex = 0;
273 |
274 | #if RETRO_USING_SDL
275 | SDL_Window *window = nullptr;
276 | SDL_Renderer *renderer = nullptr;
277 | SDL_Texture *screenBuffer = nullptr;
278 | SDL_Texture *screenBuffer2x = nullptr;
279 |
280 | SDL_Event sdlEvents;
281 | #endif
282 | };
283 |
284 | extern RetroEngine Engine;
285 | #endif // !RETROENGINE_H
286 |
--------------------------------------------------------------------------------
/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 && nativeEntityCount > 1) // 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 | printLog("GameMode '%d' Called", Engine.gameMode);
69 | activeStageList = 0;
70 | stageListPosition = 0;
71 | stageMode = STAGEMODE_LOAD;
72 | Engine.gameMode = ENGINE_MAINGAME;
73 | break;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/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
135 |
--------------------------------------------------------------------------------
/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 | }
425 |
--------------------------------------------------------------------------------
/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 | #define USE_STDLIB
10 |
11 | extern ushort *strPressStart;
12 | extern ushort *strTouchToStart;
13 | extern ushort *strStartGame;
14 | extern ushort *strTimeAttack;
15 | extern ushort *strAchievements;
16 | extern ushort *strLeaderboards;
17 | extern ushort *strHelpAndOptions;
18 | extern ushort *strSoundTest;
19 | extern ushort *str2PlayerVS;
20 | extern ushort *strSaveSelect;
21 | extern ushort *strPlayerSelect;
22 | extern ushort *strNoSave;
23 | extern ushort *strNewGame;
24 | extern ushort *strDelete;
25 | extern ushort *strDeleteMessage;
26 | extern ushort *strYes;
27 | extern ushort *strNo;
28 | extern ushort *strSonic;
29 | extern ushort *strTails;
30 | extern ushort *strKnuckles;
31 | extern ushort *strPause;
32 | extern ushort *strContinue;
33 | extern ushort *strRestart;
34 | extern ushort *strExit;
35 | extern ushort *strDevMenu;
36 | extern ushort *strRestartMessage;
37 | extern ushort *strExitMessage;
38 | extern ushort *strNSRestartMessage;
39 | extern ushort *strNSExitMessage;
40 | extern ushort *strExitGame;
41 | extern ushort *strNetworkMessage;
42 | extern ushort *strStageList[8];
43 | extern ushort *strSaveStageList[26];
44 | extern ushort *strNewBestTime;
45 | extern ushort *strRecords;
46 | extern ushort *strNextAct;
47 | extern ushort *strPlay;
48 | extern ushort *strTotalTime;
49 | extern ushort *strInstructions;
50 | extern ushort *strSettings;
51 | extern ushort *strStaffCredits;
52 | extern ushort *strAbout;
53 | extern ushort *strMusic;
54 | extern ushort *strSoundFX;
55 | extern ushort *strSpindash;
56 | extern ushort *strBoxArt;
57 | extern ushort *strControls;
58 | extern ushort *strOn;
59 | extern ushort *strOff;
60 | extern ushort *strCustomizeDPad;
61 | extern ushort *strDPadSize;
62 | extern ushort *strDPadOpacity;
63 | extern ushort *strHelpText1;
64 | extern ushort *strHelpText2;
65 | extern ushort *strHelpText3;
66 | extern ushort *strHelpText4;
67 | extern ushort *strHelpText5;
68 | extern ushort *strVersionName;
69 | extern ushort *strPrivacy;
70 | extern ushort *strTerms;
71 |
72 | extern int stageStrCount;
73 |
74 | extern ushort stringStorage[STRSTORAGE_SIZE][STRING_SIZE];
75 | extern int stringStorePos;
76 |
77 | extern int creditsListSize;
78 | extern const ushort *strCreditsList[CREDITS_LIST_SIZE];
79 | extern byte creditsType[CREDITS_LIST_SIZE];
80 | extern float creditsAdvanceY[CREDITS_LIST_SIZE];
81 |
82 | inline void StrCopy(char *dest, const char *src)
83 | {
84 | #ifdef USE_STDLIB
85 | strcpy(dest, src);
86 |
87 | #else
88 | int i = 0;
89 |
90 | for (; src[i]; ++i) dest[i] = src[i];
91 |
92 | dest[i] = 0;
93 |
94 | #endif
95 | }
96 |
97 | inline void StrAdd(char *dest, const char *src)
98 | {
99 | int destStrPos = 0;
100 | int srcStrPos = 0;
101 | while (dest[destStrPos]) ++destStrPos;
102 | while (true) {
103 | if (!src[srcStrPos]) {
104 | break;
105 | }
106 | dest[destStrPos++] = src[srcStrPos++];
107 | }
108 | dest[destStrPos] = 0;
109 | }
110 |
111 | inline bool StrComp(const char *stringA, const char *stringB)
112 | {
113 | bool match = true;
114 | bool finished = false;
115 | while (!finished) {
116 | if (*stringA == *stringB || *stringA == *stringB + ' ' || *stringA == *stringB - ' ') {
117 | if (*stringA) {
118 | ++stringA;
119 | ++stringB;
120 | }
121 | else {
122 | finished = true;
123 | }
124 | }
125 | else {
126 | match = false;
127 | finished = true;
128 | }
129 | }
130 | return match;
131 | }
132 |
133 | inline int StrLength(const char *string)
134 | {
135 | #ifdef USE_STDLIB
136 | return strlen(string);
137 |
138 | #else
139 | int len = 0;
140 | for (len = 0; string[len]; len++)
141 | ;
142 | return len;
143 |
144 | #endif
145 | }
146 | int FindStringToken(const char *string, const char *token, char stopID);
147 |
148 | inline void StrCopyW(ushort *dest, const ushort *src)
149 | {
150 | int i = 0;
151 |
152 | for (; src[i]; ++i) dest[i] = src[i];
153 |
154 | dest[i] = 0;
155 | }
156 |
157 |
158 | inline void StrAddW(ushort *dest, const ushort *src)
159 | {
160 | int destStrPos = 0;
161 | int srcStrPos = 0;
162 | while (dest[destStrPos]) ++destStrPos;
163 | while (true) {
164 | if (!src[srcStrPos]) {
165 | break;
166 | }
167 | dest[destStrPos++] = src[srcStrPos++];
168 | }
169 | dest[destStrPos] = 0;
170 | }
171 | inline void StrCopyW(ushort *dest, const char *src)
172 | {
173 | int i = 0;
174 |
175 | for (; src[i]; ++i) dest[i] = src[i];
176 |
177 | dest[i] = 0;
178 | }
179 |
180 | inline void StrAddW(ushort *dest, const char *src)
181 | {
182 | int destStrPos = 0;
183 | int srcStrPos = 0;
184 | while (dest[destStrPos]) ++destStrPos;
185 | while (true) {
186 | if (!src[srcStrPos]) {
187 | break;
188 | }
189 | dest[destStrPos++] = src[srcStrPos++];
190 | }
191 | dest[destStrPos] = 0;
192 | }
193 |
194 | inline bool StrCompW(const ushort *stringA, const ushort *stringB)
195 | {
196 | bool match = true;
197 | bool finished = false;
198 | while (!finished) {
199 | if (*stringA == *stringB || *stringA == *stringB + ' ' || *stringA == *stringB - ' ') {
200 | if (*stringA) {
201 | ++stringA;
202 | ++stringB;
203 | }
204 | else {
205 | finished = true;
206 | }
207 | }
208 | else {
209 | match = false;
210 | finished = true;
211 | }
212 | }
213 | return match;
214 | }
215 |
216 | inline bool StrCompW(const ushort *stringA, const char *stringB)
217 | {
218 | bool match = true;
219 | bool finished = false;
220 | while (!finished) {
221 | if (*stringA == *stringB || *stringA == *stringB + ' ' || *stringA == *stringB - ' ') {
222 | if (*stringA) {
223 | ++stringA;
224 | ++stringB;
225 | }
226 | else {
227 | finished = true;
228 | }
229 | }
230 | else {
231 | match = false;
232 | finished = true;
233 | }
234 | }
235 | return match;
236 | }
237 |
238 | inline int StrLengthW(const ushort *string)
239 | {
240 | int len = 0;
241 | for (len = 0; string[len]; len++)
242 | ;
243 | return len;
244 | }
245 |
246 | int FindStringTokenUnicode(const ushort *string, const ushort *token, char stopID);
247 |
248 | inline void StringLowerCase(char *dest, const char *src)
249 | {
250 | int destPos = 0;
251 | int curChar = *src;
252 | if (*src) {
253 | int srcPos = 0;
254 | do {
255 | while (curChar - 'A' <= 0x19u) {
256 | destPos = srcPos;
257 | dest[destPos] = curChar + ' ';
258 | curChar = src[++srcPos];
259 | if (!curChar) {
260 | dest[++destPos] = 0;
261 | return;
262 | }
263 | }
264 | destPos = srcPos;
265 | dest[destPos] = curChar;
266 | curChar = src[++srcPos];
267 | } while (curChar);
268 | }
269 | dest[++destPos] = 0;
270 | }
271 |
272 | inline void StringUpperCase(char *dest, const char *src)
273 | {
274 | int destPos = 0;
275 | int curChar = *src;
276 | if (*src) {
277 | int srcPos = 0;
278 | do {
279 | while (curChar - 'a' <= 0x19u) {
280 | destPos = srcPos;
281 | dest[destPos] = curChar - ' ';
282 | curChar = src[++srcPos];
283 | if (!curChar) {
284 | dest[++destPos] = 0;
285 | return;
286 | }
287 | }
288 | destPos = srcPos;
289 | dest[destPos] = curChar;
290 | curChar = src[++srcPos];
291 | } while (curChar);
292 | }
293 | dest[++destPos] = 0;
294 | }
295 |
296 | void ConvertIntegerToString(char *text, int value);
297 |
298 | void GenerateMD5FromString(const char *string, int len, byte *buffer);
299 |
300 | void InitLocalizedStrings();
301 | ushort *ReadLocalizedString(const char *stringName, const char *language, const char *filePath);
302 |
303 | inline void ReadStringLine(char *text)
304 | {
305 | char curChar = 0;
306 |
307 | int textPos = 0;
308 | while (true) {
309 | FileRead(&curChar, 1);
310 | if (curChar == '\t' || curChar == ' ')
311 | break;
312 | if (curChar == '\r' || curChar == '\n')
313 | break;
314 | if (curChar != ';')
315 | text[textPos++] = curChar;
316 |
317 | if (ReachedEndOfFile()) {
318 | text[textPos] = 0;
319 | return;
320 | }
321 | }
322 | if (curChar != '\n' && curChar != '\r') {
323 | if (ReachedEndOfFile()) {
324 | text[textPos] = 0;
325 | return;
326 | }
327 | }
328 |
329 | text[textPos] = 0;
330 | if (ReachedEndOfFile())
331 | text[textPos] = 0;
332 | }
333 |
334 | inline void ReadStringLineUnicode(ushort *text)
335 | {
336 | int curChar = 0;
337 | byte fileBuffer[2];
338 |
339 | int textPos = 0;
340 | while (true) {
341 | FileRead(fileBuffer, 2);
342 | curChar = fileBuffer[0] + (fileBuffer[1] << 8);
343 | if (curChar != ' ' && curChar != '\t') {
344 | if (curChar == '\r') {
345 | int pos = (int)GetFilePosition();
346 | FileRead(fileBuffer, 2);
347 | curChar = fileBuffer[0] + (fileBuffer[1] << 8);
348 | if (curChar == '\n')
349 | break;
350 | SetFilePosition(pos);
351 | }
352 | if (curChar != ';')
353 | text[textPos++] = curChar;
354 | }
355 | else if (curChar == '\n' || curChar == '\r')
356 | break;
357 |
358 | if (ReachedEndOfFile()) {
359 | text[textPos] = 0;
360 | return;
361 | }
362 | }
363 | text[textPos] = 0;
364 | if (ReachedEndOfFile())
365 | text[textPos] = 0;
366 | }
367 |
368 | void ReadCreditsList(const char *filePath);
369 | inline void ReadCreditsLine(char *line)
370 | {
371 | byte fileBuffer = 0;
372 |
373 | int strPos = 0;
374 | while (true) {
375 | FileRead(&fileBuffer, 1);
376 | if (fileBuffer == '\r')
377 | break;
378 | line[strPos++] = fileBuffer;
379 | if (ReachedEndOfFile()) {
380 | line[strPos] = 0;
381 | return;
382 | }
383 | }
384 | FileRead(&fileBuffer, 1);
385 | line[strPos] = 0;
386 | if (ReachedEndOfFile()) {
387 | line[strPos] = 0;
388 | return;
389 | }
390 | }
391 |
392 | #endif // !STRING_H
393 |
--------------------------------------------------------------------------------
/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 | int textLength = StrLength(text);
47 | for (int i = 0; i < textLength;) {
48 | if (text[i] != '\0') {
49 | menu->textData[menu->textDataPos++] = text[i];
50 | menu->entrySize[menu->rowCount]++;
51 | ++i;
52 | }
53 | else {
54 | break;
55 | }
56 | }
57 | menu->rowCount++;
58 | }
59 | void AddTextMenuEntryW(TextMenu *menu, const ushort *text)
60 | {
61 | menu->entryStart[menu->rowCount] = menu->textDataPos;
62 | menu->entrySize[menu->rowCount] = 0;
63 | int textLength = StrLengthW(text);
64 | for (int i = 0; i < textLength;) {
65 | if (text[i] != '\0') {
66 | menu->textData[menu->textDataPos++] = text[i];
67 | menu->entrySize[menu->rowCount]++;
68 | ++i;
69 | }
70 | else {
71 | break;
72 | }
73 | }
74 | menu->rowCount++;
75 | }
76 | void SetTextMenuEntry(TextMenu *menu, const char *text, int rowID)
77 | {
78 | menu->entryStart[rowID] = menu->textDataPos;
79 | menu->entrySize[rowID] = 0;
80 | int textLength = StrLength(text);
81 | for (int i = 0; i < textLength;) {
82 | if (text[i] != '\0') {
83 | menu->textData[menu->textDataPos++] = text[i];
84 | menu->entrySize[rowID]++;
85 | ++i;
86 | }
87 | else {
88 | break;
89 | }
90 | }
91 | }
92 | void SetTextMenuEntryW(TextMenu *menu, const ushort *text, int rowID)
93 | {
94 | menu->entryStart[rowID] = menu->textDataPos;
95 | menu->entrySize[rowID] = 0;
96 | int textLength = StrLengthW(text);
97 | for (int i = 0; i < textLength;) {
98 | if (text[i] != '\0') {
99 | menu->textData[menu->textDataPos++] = text[i];
100 | menu->entrySize[rowID]++;
101 | ++i;
102 | }
103 | else {
104 | break;
105 | }
106 | }
107 | }
108 | void EditTextMenuEntry(TextMenu *menu, const char *text, int rowID)
109 | {
110 | int entryPos = menu->entryStart[rowID];
111 | menu->entrySize[rowID] = 0;
112 | int textLength = StrLength(text);
113 | for (int i = 0; i < textLength;) {
114 | if (text[i] != '\0') {
115 | menu->textData[entryPos++] = text[i];
116 | menu->entrySize[rowID]++;
117 | ++i;
118 | }
119 | else {
120 | break;
121 | }
122 | }
123 | }
124 | void LoadConfigListText(TextMenu *menu, int listNo)
125 | {
126 | FileInfo info;
127 | char strBuf[0x100];
128 | int fileBuffer = 0;
129 | int count = 0;
130 | int strLen = 0;
131 | if (LoadFile("Data/Game/GameConfig.bin", &info)) {
132 | // Name
133 | FileRead(&strLen, 1);
134 | FileRead(&strBuf, strLen);
135 | strBuf[strLen] = 0;
136 |
137 | // About
138 | FileRead(&strLen, 1);
139 | FileRead(&strBuf, strLen);
140 | strBuf[strLen] = 0;
141 |
142 | byte buf[3];
143 | for (int c = 0; c < 0x60; ++c) FileRead(buf, 3);
144 |
145 | // Object Names
146 | FileRead(&count, 1);
147 | for (int o = 0; o < count; ++o) {
148 | FileRead(&strLen, 1);
149 | FileRead(&strBuf, strLen);
150 | strBuf[strLen] = 0;
151 | }
152 |
153 | // Script Paths
154 | for (int s = 0; s < count; ++s) {
155 | FileRead(&strLen, 1);
156 | FileRead(&strBuf, strLen);
157 | strBuf[strLen] = 0;
158 | }
159 |
160 | // Variables
161 | FileRead(&count, 1);
162 | for (int v = 0; v < count; ++v) {
163 | //Var Name
164 | FileRead(&strLen, 1);
165 | FileRead(&strBuf, strLen);
166 | strBuf[strLen] = 0;
167 |
168 | //Var Value
169 | FileRead(&fileBuffer, 1);
170 | FileRead(&fileBuffer, 1);
171 | FileRead(&fileBuffer, 1);
172 | FileRead(&fileBuffer, 1);
173 | }
174 |
175 | // SFX Names
176 | FileRead(&count, 1);
177 | for (int s = 0; s < count; ++s) {
178 | FileRead(&strLen, 1);
179 | FileRead(&strBuf, strLen);
180 | strBuf[strLen] = 0;
181 | }
182 | // SFX Paths
183 | for (int s = 0; s < count; ++s) {
184 | FileRead(&strLen, 1);
185 | FileRead(&strBuf, strLen);
186 | strBuf[strLen] = 0;
187 | }
188 |
189 | // Players
190 | FileRead(&count, 1);
191 | for (int p = 0; p < count; ++p) {
192 | FileRead(&strLen, 1);
193 | FileRead(&strBuf, strLen);
194 | strBuf[strLen] = '\0';
195 |
196 | if (listNo == 0) { // Player List
197 | AddTextMenuEntry(menu, strBuf);
198 | StrCopy(playerListText[p], strBuf);
199 | }
200 | }
201 |
202 | // Categories
203 | for (int c = 1; c <= 4; ++c) {
204 | int stageCnt = 0;
205 | FileRead(&stageCnt, 1);
206 | for (int s = 0; s < stageCnt; ++s) {
207 | //Stage Folder
208 | FileRead(&strLen, 1);
209 | FileRead(&strBuf, strLen);
210 | strBuf[strLen] = 0;
211 |
212 | //Stage ID
213 | FileRead(&strLen, 1);
214 | FileRead(&strBuf, strLen);
215 | strBuf[strLen] = 0;
216 |
217 | //Stage Name
218 | FileRead(&strLen, 1);
219 | FileRead(&strBuf, strLen);
220 | strBuf[strLen] = '\0';
221 |
222 | //IsHighlighted
223 | FileRead(&fileBuffer, 1);
224 | if (listNo == c) {
225 | menu->entryHighlight[s] = fileBuffer;
226 | AddTextMenuEntry(menu, strBuf);
227 | }
228 | }
229 | }
230 | CloseFile();
231 | }
232 | }
--------------------------------------------------------------------------------
/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 | {
80 | if (nativeFunctionCount > 0xF)
81 | return;
82 | SetGlobalVariableByName(name, nativeFunctionCount);
83 | nativeFunction[nativeFunctionCount++] = funcPtr;
84 | }
85 |
86 | inline bool ReadSaveRAMData()
87 | {
88 | char buffer[0x100];
89 | #if RETRO_PLATFORM == RETRO_OSX
90 | if (!usingCWD)
91 | sprintf(buffer, "%s/SData.bin", getResourcesPath());
92 | else
93 | sprintf(buffer, "%sSData.bin", gamePath);
94 | #else
95 | sprintf(buffer, "%sSData.bin", gamePath);
96 | #endif
97 | FileIO *saveFile = fOpen(buffer, "rb");
98 | if (!saveFile)
99 | return false;
100 | fRead(saveRAM, 4u, SAVEDATA_MAX, saveFile);
101 | fClose(saveFile);
102 | return true;
103 | }
104 |
105 | inline bool WriteSaveRAMData()
106 | {
107 | char buffer[0x100];
108 | #if RETRO_PLATFORM == RETRO_OSX
109 | if (!usingCWD)
110 | sprintf(buffer, "%s/SData.bin", getResourcesPath());
111 | else
112 | sprintf(buffer, "%sSData.bin", gamePath);
113 | #else
114 | sprintf(buffer, "%sSData.bin", gamePath);
115 | #endif
116 |
117 | FileIO *saveFile = fOpen(buffer, "wb");
118 | if (!saveFile)
119 | return false;
120 | fWrite(saveRAM, 4u, SAVEDATA_MAX, saveFile);
121 | fClose(saveFile);
122 | return true;
123 | }
124 |
125 | void InitUserdata();
126 | void writeSettings();
127 | void ReadUserdata();
128 | void WriteUserdata();
129 |
130 | void AwardAchievement(int id, int status);
131 |
132 | int SetAchievement(int achievementID, void *achDone);
133 | int SetLeaderboard(int leaderboardID, void *res);
134 | inline void LoadAchievementsMenu() { ReadUserdata(); }
135 | inline void LoadLeaderboardsMenu() { ReadUserdata(); }
136 |
137 | int Connect2PVS(int a1, void *a2);
138 | int Disconnect2PVS(int a1, void *a2);
139 | int SendEntity(int a1, void *a2);
140 | int SendValue(int a1, void *a2);
141 | int ReceiveEntity(int a1, void *a2);
142 | int ReceiveValue(int a1, void *a2);
143 | int TransmitGlobal(int a1, void *a2);
144 |
145 | void receive2PVSData(MultiplayerData *data);
146 | void receive2PVSMatchCode(int code);
147 |
148 | int ShowPromoPopup(int a1, void *a2);
149 |
150 | #endif //! USERDATA_H
151 |
--------------------------------------------------------------------------------
/Sonic12Decomp/main.cpp:
--------------------------------------------------------------------------------
1 | #include "RetroEngine.hpp"
2 |
3 | int main(int argc, char *argv[])
4 | {
5 | for (int i = 0; i < argc; ++i) {
6 | if (StrComp(argv[i], "UsingCWD"))
7 | usingCWD = true;
8 | }
9 |
10 | Engine.Init();
11 | controllerInit(0);
12 | Engine.Run();
13 |
14 | return 0;
15 | }
16 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/Sonic2.Vita/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | ## This file is a quick tutorial on writing CMakeLists for targeting the Vita
2 | cmake_minimum_required(VERSION 2.8)
3 |
4 | ## This includes the Vita toolchain, must go before project definition
5 | # It is a convenience so you do not have to type
6 | # -DCMAKE_TOOLCHAIN_FILE=$VITASDK/share/vita.toolchain.cmake for cmake. It is
7 | # highly recommended that you include this block for all projects.
8 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
9 | if(DEFINED ENV{VITASDK})
10 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
11 | else()
12 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
13 | endif()
14 | endif()
15 |
16 | ## Define project parameters here
17 | # Name of the project
18 | project(Sonic2)
19 | # This line adds Vita helper macros, must go after project definition in order
20 | # to build Vita specific artifacts (self/vpk).
21 | include("${VITASDK}/share/vita.cmake" REQUIRED)
22 |
23 | ## Configuration options for this app
24 | # Display name (under bubble in LiveArea)
25 | set(VITA_APP_NAME "Sonic 2")
26 | # Unique ID must be exactly 9 characters. Recommended: XXXXYYYYY where X =
27 | # unique string of developer and Y = a unique number for this app
28 | set(VITA_TITLEID "RSDK00003")
29 | # Optional version string to show in LiveArea's more info screen
30 | set(VITA_VERSION "01.00")
31 |
32 | ## Flags and includes for building
33 | # Note that we make sure not to overwrite previous flags
34 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -fsigned-char -fno-lto")
35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3 -fsigned-char -fno-lto -fno-rtti -fno-exceptions")
36 | # Optional. You can specify more param.sfo flags this way.
37 | set(VITA_MKSFOEX_FLAGS "${VITA_MKSFOEX_FLAGS} -d PARENTAL_LEVEL=1")
38 |
39 | add_definitions(-DRETRO_GAME_SONIC=2)
40 |
41 | # Add any additional include paths here
42 | include_directories(
43 | /home/user/vitasdk/arm-vita-eabi/include
44 | )
45 |
46 | # Add any additional library paths here
47 | # ${CMAKE_CURRENT_BINARY_DIR} lets you use any library currently being built
48 | link_directories(
49 | ${CMAKE_CURRENT_BINARY_DIR}
50 | )
51 |
52 | ## Build and link
53 | # Add all the files needed to compile here
54 | add_executable(${PROJECT_NAME}
55 | ../Sonic12Decomp/Animation.cpp
56 | ../Sonic12Decomp/Audio.cpp
57 | ../Sonic12Decomp/Collision.cpp
58 | ../Sonic12Decomp/Debug.cpp
59 | ../Sonic12Decomp/Drawing.cpp
60 | ../Sonic12Decomp/Ini.cpp
61 | ../Sonic12Decomp/Input.cpp
62 | ../Sonic12Decomp/main.cpp
63 | ../Sonic12Decomp/Math.cpp
64 | ../Sonic12Decomp/Network.cpp
65 | ../Sonic12Decomp/Object.cpp
66 | ../Sonic12Decomp/Palette.cpp
67 | ../Sonic12Decomp/PauseMenu.cpp
68 | ../Sonic12Decomp/Reader.cpp
69 | ../Sonic12Decomp/RetroEngine.cpp
70 | ../Sonic12Decomp/RetroGameLoop.cpp
71 | ../Sonic12Decomp/Scene.cpp
72 | ../Sonic12Decomp/Scene3D.cpp
73 | ../Sonic12Decomp/Script.cpp
74 | ../Sonic12Decomp/Sprite.cpp
75 | ../Sonic12Decomp/String.cpp
76 | ../Sonic12Decomp/Text.cpp
77 | ../Sonic12Decomp/Userdata.cpp
78 | )
79 |
80 | # Library to link to (drop the -l prefix). This will mostly be stubs.
81 | target_link_libraries(${PROJECT_NAME}
82 | SDL2
83 | vita2d
84 | vorbisfile
85 | vorbis
86 | ogg
87 | pthread
88 | SceDisplay_stub
89 | SceAudio_stub
90 | SceCtrl_stub
91 | SceSysmodule_stub
92 | SceGxm_stub
93 | SceCommonDialog_stub
94 | SceAppMgr_stub
95 | SceTouch_stub
96 | SceHid_stub
97 | SceAudio_stub
98 | SceMotion_stub
99 | m
100 | )
101 |
102 | ## Create Vita files
103 | vita_create_self(${PROJECT_NAME}.self ${PROJECT_NAME})
104 | # The FILE directive lets you add additional files to the VPK, the syntax is
105 | # FILE src_path dst_path_in_vpk. In this case, we add the LiveArea paths.
106 | vita_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} ${PROJECT_NAME}.self
107 | VERSION ${VITA_VERSION}
108 | NAME ${VITA_APP_NAME}
109 | # FILE sce_sys/icon0.png sce_sys/icon0.png
110 | # FILE sce_sys/livearea/contents/bg.png sce_sys/livearea/contents/bg.png
111 | # FILE sce_sys/livearea/contents/startup.png sce_sys/livearea/contents/startup.png
112 | FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml
113 | )
114 |
--------------------------------------------------------------------------------
/Sonic2.Vita/build-internal.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | apk add --no-cache make cmake
3 | cmake . && \
4 | make -j$(nproc)
5 | rm Sonic2 # this is not ignored by .gitignore
6 |
--------------------------------------------------------------------------------
/Sonic2.Vita/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo docker run \
3 | --rm \
4 | -v $PWD/..:/work \
5 | -w /work/Sonic2.Vita \
6 | vitasdk/vitasdk \
7 | /bin/sh -C "./build-internal.sh"
8 |
--------------------------------------------------------------------------------
/Sonic2.Vita/sce_sys/livearea/contents/template.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bg.png
6 |
7 |
8 |
9 | startup.png
10 |
11 |
12 |
--------------------------------------------------------------------------------
/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)
--------------------------------------------------------------------------------