├── .gitattributes
├── .gitignore
├── README.md
├── RSDKv2
├── Animation.cs
├── ArcContainer.cs
├── BackgroundLayout.cs
├── Bytecode.cs
├── DataFile.cs
├── GameConfig.cs
├── GraphicsImage.cs
├── Object.cs
├── Palette.cs
├── PaletteColour.cs
├── Properties
│ └── AssemblyInfo.cs
├── RSDKv2.csproj
├── Reader.cs
├── SaveFiles.cs
├── Scene.cs
├── Script.cs
├── Setup.cs
├── StageConfig.cs
├── StringSet.cs
├── TextFont.cs
├── Tileconfig.cs
├── Tiles128x128.cs
├── Video.cs
├── Writer.cs
└── packages.config
├── Sonic-CD-SaveED.sln
├── Sonic-CD-SaveED
├── AboutForm.Designer.cs
├── AboutForm.cs
├── AboutForm.resx
├── App.config
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── SLWSaveForm.Designer.cs
├── SLWSaveForm.cs
├── SLWSaveForm.resx
├── Sonic-CD-SaveED.csproj
├── Steam.cs
└── sonic_CD.ico
└── packages
└── zlib.net.1.0.4.0
├── lib
└── zlib.net.dll
└── zlib.net.1.0.4.0.nupkg
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | bin/
23 | [Bb]in/
24 | [Oo]bj/
25 |
26 | # Visual Studio 2015 cache/options directory
27 | .vs/
28 |
29 | # MSTest test Results
30 | [Tt]est[Rr]esult*/
31 | [Bb]uild[Ll]og.*
32 |
33 | # NUNIT
34 | *.VisualState.xml
35 | TestResult.xml
36 |
37 | # Build Results of an ATL Project
38 | [Dd]ebugPS/
39 | [Rr]eleasePS/
40 | dlldata.c
41 |
42 | # DNX
43 | project.lock.json
44 | artifacts/
45 |
46 | *_i.c
47 | *_p.c
48 | *_i.h
49 | *.ilk
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding add-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | _NCrunch_*
108 | .*crunch*.local.xml
109 |
110 | # MightyMoose
111 | *.mm.*
112 | AutoTest.Net/
113 |
114 | # Web workbench (sass)
115 | .sass-cache/
116 |
117 | # Installshield output folder
118 | [Ee]xpress/
119 |
120 | # DocProject is a documentation generator add-in
121 | DocProject/buildhelp/
122 | DocProject/Help/*.HxT
123 | DocProject/Help/*.HxC
124 | DocProject/Help/*.hhc
125 | DocProject/Help/*.hhk
126 | DocProject/Help/*.hhp
127 | DocProject/Help/Html2
128 | DocProject/Help/html
129 |
130 | # Click-Once directory
131 | publish/
132 |
133 | # Publish Web Output
134 | *.[Pp]ublish.xml
135 | *.azurePubxml
136 | ## TODO: Comment the next line if you want to checkin your
137 | ## web deploy settings but do note that will include unencrypted
138 | ## passwords
139 | #*.pubxml
140 |
141 | *.publishproj
142 |
143 | # NuGet Packages
144 | *.nupkg
145 | # The packages folder can be ignored because of Package Restore
146 | **/packages/*
147 | # except build/, which is used as an MSBuild target.
148 | !**/packages/build/
149 | # Uncomment if necessary however generally it will be regenerated when needed
150 | #!**/packages/repositories.config
151 |
152 | # Windows Azure Build Output
153 | csx/
154 | *.build.csdef
155 |
156 | # Windows Store app package directory
157 | AppPackages/
158 |
159 | # Visual Studio cache files
160 | # files ending in .cache can be ignored
161 | *.[Cc]ache
162 | # but keep track of directories ending in .cache
163 | !*.[Cc]ache/
164 |
165 | # Others
166 | ClientBin/
167 | [Ss]tyle[Cc]op.*
168 | ~$*
169 | *~
170 | *.dbmdl
171 | *.dbproj.schemaview
172 | *.pfx
173 | *.publishsettings
174 | node_modules/
175 | orleans.codegen.cs
176 |
177 | # RIA/Silverlight projects
178 | Generated_Code/
179 |
180 | # Backup & report files from converting an old project file
181 | # to a newer Visual Studio version. Backup files are not needed,
182 | # because we have git ;-)
183 | _UpgradeReport_Files/
184 | Backup*/
185 | UpgradeLog*.XML
186 | UpgradeLog*.htm
187 |
188 | # SQL Server files
189 | *.mdf
190 | *.ldf
191 |
192 | # Business Intelligence projects
193 | *.rdl.data
194 | *.bim.layout
195 | *.bim_*.settings
196 |
197 | # Microsoft Fakes
198 | FakesAssemblies/
199 |
200 | # Node.js Tools for Visual Studio
201 | .ntvs_analysis.dat
202 |
203 | # Visual Studio 6 build log
204 | *.plg
205 |
206 | # Visual Studio 6 workspace options file
207 | *.opt
208 |
209 | # LightSwitch generated files
210 | GeneratedArtifacts/
211 | _Pvt_Extensions/
212 | ModelManifest.xml
213 |
214 | # ============================================= #
215 | # Visual Studio / MonoDevelop / Rider generated #
216 | # ============================================= #
217 | [Ee]xported[Oo]bj/
218 | /*.unityproj
219 | /*.booproj
220 | /.idea*/
221 |
222 | # ============ #
223 | # OS generated #
224 | # ============ #
225 | .DS_Store*
226 | ._*
227 | .Spotlight-V100
228 | .Trashes
229 | ehthumbs.db
230 | [Tt]humbs.db
231 | [Dd]esktop.ini
232 |
233 | # Other
234 | Ignored/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SonicCD SaveEditor - By Rubberduckycooly and Beta Angel
2 |
3 | A save file editor for Sonic CD (2011)!
4 |
5 | This program can edit all the values used by the game to save progress and settings (it does not edit time attack data!)
6 | however, some values functions are unknown, but the program can modify them regardless...
7 |
8 | My Github: you're on it lol
9 |
10 | Beta Angel's Github: https://github.com/BetaAngel
11 |
--------------------------------------------------------------------------------
/RSDKv2/Animation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RSDKv2
8 | {
9 | [Serializable]
10 | public class Animation : ICloneable
11 | {
12 | public object Clone()
13 | {
14 | return this.MemberwiseClone();
15 | }
16 | ///
17 | /// a string to be added to the start of the path
18 | ///
19 | public string PathMod
20 | {
21 | get
22 | {
23 | return "..\\sprites\\";
24 | }
25 | }
26 |
27 | ///
28 | /// if this is set then only allow one sheet (meaning it'll be used for Objects and not the player)
29 | ///
30 | public bool isObjectAni = false;
31 |
32 | ///
33 | /// a List of paths to the spritesheets, relative to "Data/Sprites"
34 | ///
35 | public List SpriteSheets = new List();
36 |
37 | ///
38 | /// a list of the hitboxes that the animations can use
39 | ///
40 | public List CollisionBoxes = new List();
41 | ///
42 | /// a list of Animations in the file
43 | ///
44 | public List Animations = new List();
45 |
46 | [Serializable]
47 | public class sprAnimation : ICloneable
48 | {
49 | public object Clone()
50 | {
51 | return this.MemberwiseClone();
52 | }
53 | [Serializable]
54 | public class sprFrame : ICloneable
55 | {
56 | public object Clone()
57 | {
58 | return this.MemberwiseClone();
59 | }
60 | public struct HitBox
61 | {
62 | public short Left, Right, Top, Bottom;
63 | }
64 |
65 | public List HitBoxes = new List();
66 | ///
67 | /// the spritesheet index
68 | ///
69 | public byte SpriteSheet = 0;
70 | ///
71 | /// the collision box
72 | ///
73 | public byte CollisionBox = 0;
74 | ///
75 | /// the delay of each frame before advancing to the next one in frames (always 256)
76 | ///
77 | public readonly short Delay = 256;
78 | ///
79 | /// the Xpos on the sheet
80 | ///
81 | public byte X = 0;
82 | ///
83 | /// the YPos on the sheet
84 | ///
85 | public byte Y = 0;
86 | ///
87 | /// the frame's width
88 | ///
89 | public byte Width = 0;
90 | ///
91 | /// the frame's height
92 | ///
93 | public byte Height = 0;
94 | ///
95 | /// the offsetX of the frame
96 | ///
97 | public SByte PivotX = 0;
98 | ///
99 | /// the offsetY of the frame
100 | ///
101 | public SByte PivotY = 0;
102 |
103 | public sprFrame()
104 | {
105 |
106 | }
107 |
108 | public sprFrame(Reader reader, Animation anim = null)
109 | {
110 | SpriteSheet = reader.ReadByte();
111 | CollisionBox = reader.ReadByte();
112 | X = reader.ReadByte();
113 | Y = reader.ReadByte();
114 | Width = reader.ReadByte();
115 | Height = reader.ReadByte();
116 | PivotX = reader.ReadSByte();
117 | PivotY = reader.ReadSByte();
118 | }
119 |
120 | public void Write(Writer writer)
121 | {
122 | writer.Write(SpriteSheet);
123 | writer.Write(CollisionBox);
124 | writer.Write(X);
125 | writer.Write(Y);
126 | writer.Write(Width);
127 | writer.Write(Height);
128 | writer.Write(PivotX);
129 | writer.Write(PivotY);
130 | }
131 |
132 | }
133 |
134 | ///
135 | /// the name of the animation
136 | ///
137 | public string AnimName;
138 | ///
139 | /// a list of frames in the animation
140 | ///
141 | public List Frames = new List();
142 | ///
143 | /// what frame to loop back from
144 | ///
145 | public byte LoopIndex;
146 | ///
147 | /// the speed multiplyer of the animation
148 | ///
149 | public byte SpeedMultiplyer;
150 | ///
151 | /// the rotation style of the animation
152 | ///
153 | public byte RotationFlags;
154 |
155 | public sprAnimation()
156 | {
157 |
158 | }
159 |
160 | public sprAnimation(Reader reader, Animation anim = null)
161 | {
162 | AnimName = reader.ReadString();
163 | short frameCount = reader.ReadByte();
164 | SpeedMultiplyer = reader.ReadByte();
165 | LoopIndex = reader.ReadByte();
166 | RotationFlags = reader.ReadByte();
167 | for (int i = 0; i < frameCount; ++i)
168 | {
169 | Frames.Add(new sprFrame(reader,anim));
170 | }
171 | }
172 |
173 | public void Write(Writer writer)
174 | {
175 | writer.Write(AnimName);
176 | writer.Write((byte)Frames.Count);
177 | writer.Write(SpeedMultiplyer);
178 | writer.Write(LoopIndex);
179 | writer.Write(RotationFlags);
180 | for (int i = 0; i < Frames.Count; ++i)
181 | {
182 | Frames[i].Write(writer);
183 | }
184 | }
185 |
186 | public void NewFrame()
187 | {
188 | Frames.Add(new sprFrame());
189 | }
190 |
191 | public void CloneFrame(int frame)
192 | {
193 | Frames.Add((sprFrame)Frames[frame].Clone());
194 | }
195 |
196 | public void DeleteFrame(int frame)
197 | {
198 | if (Frames.Count > 0)
199 | {
200 | Frames.RemoveAt(frame);
201 | }
202 | }
203 |
204 | }
205 |
206 | [Serializable]
207 | public class sprHitbox
208 | {
209 | public SByte Left, Right, Top, Bottom;
210 |
211 | public sprHitbox()
212 | {
213 |
214 | }
215 |
216 | public sprHitbox(Reader reader)
217 | {
218 | Left = reader.ReadSByte();
219 | Top = reader.ReadSByte();
220 | Right = reader.ReadSByte();
221 | Bottom = reader.ReadSByte();
222 | }
223 |
224 | public void Write(Writer writer)
225 | {
226 | writer.Write(Left);
227 | writer.Write(Top);
228 | writer.Write(Right);
229 | writer.Write(Bottom);
230 | }
231 | }
232 |
233 | public Animation()
234 | {
235 |
236 | }
237 |
238 | public Animation(Reader reader)
239 | {
240 | int spriteSheetCount = reader.ReadByte();
241 | for (int i = 0; i < spriteSheetCount; ++i)
242 | SpriteSheets.Add(reader.ReadString());
243 |
244 | var animationCount = reader.ReadInt16();
245 | for (int i = 0; i < animationCount; ++i)
246 | Animations.Add(new sprAnimation(reader));
247 |
248 | int collisionBoxCount = reader.ReadByte();
249 | for (int i = 0; i < collisionBoxCount; ++i)
250 | CollisionBoxes.Add(new sprHitbox(reader));
251 | reader.Close();
252 | }
253 |
254 | public void Write(Writer writer)
255 | {
256 | writer.Write((byte)SpriteSheets.Count);
257 | for (int i = 0; i < SpriteSheets.Count; ++i)
258 | {
259 | writer.WriteRSDKString(SpriteSheets[i]);
260 | }
261 |
262 | writer.Write((byte)Animations.Count);
263 | for (int i = 0; i < Animations.Count; ++i)
264 | {
265 | Animations[i].Write(writer);
266 | }
267 |
268 | writer.Write((byte)CollisionBoxes.Count);
269 | for (int i = 0; i < CollisionBoxes.Count; ++i)
270 | {
271 | CollisionBoxes[i].Write(writer);
272 | }
273 | writer.Close();
274 | }
275 |
276 | public void NewAnimation()
277 | {
278 | sprAnimation a = new sprAnimation();
279 | Animations.Add(a);
280 | }
281 |
282 | public void CloneAnimation(int anim)
283 | {
284 | sprAnimation a = new sprAnimation();
285 |
286 | a.AnimName = Animations[anim].AnimName;
287 | byte FrameAmount = (byte)Animations[anim].Frames.Count;
288 | a.LoopIndex = Animations[anim].LoopIndex;
289 | a.SpeedMultiplyer = Animations[anim].SpeedMultiplyer;
290 | a.RotationFlags = Animations[anim].RotationFlags;
291 |
292 | a.Frames.Clear();
293 |
294 | for (int i = 0; i < FrameAmount; i++)
295 | {
296 | a.Frames.Add((sprAnimation.sprFrame)Animations[anim].Frames[i].Clone());
297 | }
298 |
299 | Animations.Add(a);
300 | }
301 |
302 | public void DeleteAnimation(int frame)
303 | {
304 | Animations.RemoveAt(frame);
305 | }
306 |
307 | public int GetAnimByName(string name)
308 | {
309 | for (int i = 0; i < Animations.Count; i++)
310 | {
311 | if (Animations[i].AnimName == name)
312 | {
313 | return i;
314 | }
315 | }
316 | Console.WriteLine("An anim with that name didn't exist! Name = " + name);
317 | return -1;
318 | }
319 |
320 | public void DeleteEndAnimation()
321 | {
322 | Animations.RemoveAt(Animations.Count - 1);
323 | }
324 |
325 | }
326 | }
327 |
--------------------------------------------------------------------------------
/RSDKv2/ArcContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RSDKv2
8 | {
9 | public class ArcContainer
10 | {
11 |
12 | public static readonly byte[] MAGIC = new byte[] { (byte)'A', (byte)'R', (byte)'C', (byte)'L' };
13 |
14 | string FileName = "File";
15 |
16 | public ArcContainer()
17 | {
18 |
19 | }
20 |
21 | public ArcContainer(Reader reader)
22 | {
23 | FileName = System.IO.Path.GetFileNameWithoutExtension(reader.GetFilename());
24 |
25 | if (!reader.ReadBytes(4).SequenceEqual(MAGIC))
26 | {
27 | Console.WriteLine("This isn't an ARC file! aborting!");
28 | return;
29 | }
30 |
31 | ushort unknown = reader.ReadUInt16();
32 |
33 |
34 |
35 | }
36 |
37 | public void Write(Writer writer)
38 | {
39 |
40 | }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/RSDKv2/BackgroundLayout.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RSDKv2
8 | {
9 | /* Background Layout */
10 | public class BGLayout
11 | {
12 | public class ScrollInfo
13 | {
14 | ///
15 | /// how fast the line moves while the player is moving
16 | ///
17 | public byte RelativeSpeed;
18 | ///
19 | /// How fast the line moves without the player moving
20 | ///
21 | public byte ConstantSpeed;
22 | ///
23 | /// the draw order of the layer
24 | ///
25 | public byte DrawLayer;
26 | ///
27 | /// a special byte that tells the game what "behaviour" property the layer has
28 | ///
29 | public byte Behaviour;
30 |
31 | public ScrollInfo()
32 | {
33 | RelativeSpeed = 0;
34 | ConstantSpeed = 0;
35 | DrawLayer = 0;
36 | Behaviour = 0;
37 | }
38 |
39 | public ScrollInfo(byte r, byte c, byte d, byte b)
40 | {
41 | RelativeSpeed = r;
42 | ConstantSpeed = c;
43 | DrawLayer = d;
44 | Behaviour = b;
45 | }
46 |
47 | public ScrollInfo(Reader reader)
48 | {
49 | RelativeSpeed = reader.ReadByte();
50 | ConstantSpeed = reader.ReadByte();
51 | DrawLayer = reader.ReadByte();
52 | Behaviour = reader.ReadByte();
53 | }
54 |
55 | public void Write(Writer writer)
56 | {
57 | writer.Write(RelativeSpeed);
58 | writer.Write(ConstantSpeed);
59 | writer.Write(DrawLayer);
60 | writer.Write(Behaviour);
61 | }
62 |
63 | }
64 |
65 | public class BGLayer
66 | {
67 | ///
68 | /// the array of Chunks IDs for the Layer
69 | ///
70 | public ushort[][] MapLayout { get; set; }
71 |
72 | ///
73 | /// Layer Width
74 | ///
75 | public byte width = 0;
76 | ///
77 | /// Layer Height
78 | ///
79 | public byte height = 0;
80 | ///
81 | /// the draw order of the layer
82 | ///
83 | public byte DrawLayer;
84 | ///
85 | /// a special byte that tells the game what "behaviour" property the layer has
86 | ///
87 | public byte Behaviour;
88 | ///
89 | /// how fast the Layer moves while the player is moving
90 | ///
91 | public byte RelativeSpeed;
92 | ///
93 | /// how fast the layer moves while the player isn't moving
94 | ///
95 | public byte ConstantSpeed;
96 |
97 | public List LineIndexes = new List();
98 |
99 | public BGLayer()
100 | {
101 | width = height = 1;
102 | DrawLayer = Behaviour = RelativeSpeed = ConstantSpeed = 0;
103 |
104 | MapLayout = new ushort[height][];
105 | for (int m = 0; m < height; m++)
106 | {
107 | MapLayout[m] = new ushort[width];
108 | }
109 | }
110 |
111 | public BGLayer(byte w, byte h)
112 | {
113 | width = w;
114 | height = h;
115 | Behaviour = DrawLayer = RelativeSpeed = ConstantSpeed = 0;
116 |
117 | MapLayout = new ushort[height][];
118 | for (int m = 0; m < height; m++)
119 | {
120 | MapLayout[m] = new ushort[width];
121 | }
122 | }
123 |
124 | public BGLayer(Reader reader)
125 | {
126 | width = reader.ReadByte();
127 | height = reader.ReadByte();
128 | RelativeSpeed = reader.ReadByte();
129 | ConstantSpeed = reader.ReadByte();
130 | DrawLayer = reader.ReadByte();
131 | Behaviour = reader.ReadByte();
132 |
133 | int j = 0;
134 | while (j < 1)
135 | {
136 | byte b;
137 |
138 | b = reader.ReadByte();
139 |
140 | if (b == 255)
141 | {
142 | byte tmp2 = reader.ReadByte();
143 |
144 | if (tmp2 == 255)
145 | {
146 | j = 1;
147 | }
148 | else
149 | {
150 | b = reader.ReadByte();
151 | }
152 | }
153 |
154 | LineIndexes.Add(b);
155 | }
156 |
157 | byte[] buffer = new byte[2];
158 |
159 | MapLayout = new ushort[height][];
160 | for (int m = 0; m < height; m++)
161 | {
162 | MapLayout[m] = new ushort[width];
163 | }
164 | for (int y = 0; y < height; y++)
165 | {
166 | for (int x = 0; x < width; x++)
167 | {
168 | reader.Read(buffer, 0, 2); //Read size
169 | MapLayout[y][x] = (ushort)(buffer[1] + (buffer[0] << 8));
170 | }
171 | }
172 | }
173 |
174 | public void Write(Writer writer)
175 | {
176 | writer.Write(width);
177 | writer.Write(height);
178 | writer.Write(RelativeSpeed);
179 | writer.Write(ConstantSpeed);
180 | writer.Write(DrawLayer);
181 | writer.Write(Behaviour);
182 |
183 | for (int i = 0; i < LineIndexes.Count; i++)
184 | {
185 | writer.Write(LineIndexes[i]);
186 | }
187 | writer.Write(0xFF);
188 |
189 | for (int h = 0; h < height; h++)
190 | {
191 | for (int w = 0; w < width; w++)
192 | {
193 | writer.Write((byte)(MapLayout[h][w] >> 8));
194 | writer.Write((byte)(MapLayout[h][w] & 0xff));
195 | }
196 | }
197 |
198 | }
199 |
200 | }
201 |
202 | ///
203 | /// A list of Horizontal Line Scroll Values
204 | ///
205 | public List HLines = new List();
206 | ///
207 | /// A list of Vertical Line Scroll Values
208 | ///
209 | public List VLines = new List();
210 | ///
211 | /// A list of Background layers
212 | ///
213 | public List Layers = new List();
214 |
215 | public BGLayout()
216 | {
217 |
218 | }
219 |
220 | public BGLayout(string filename) : this(new Reader(filename))
221 | {
222 |
223 | }
224 |
225 | public BGLayout(System.IO.Stream stream) : this(new Reader(stream))
226 | {
227 |
228 | }
229 |
230 | public BGLayout(Reader reader)
231 | {
232 | byte LayerCount = reader.ReadByte();
233 |
234 | byte HLineCount = reader.ReadByte();
235 | byte VLineCount = reader.ReadByte();
236 |
237 | for (int i = 0; i < HLineCount; i++)
238 | {
239 | ScrollInfo p = new ScrollInfo(reader);
240 | HLines.Add(p);
241 | }
242 |
243 | for (int i = 0; i < VLineCount; i++)
244 | {
245 | ScrollInfo p = new ScrollInfo(reader);
246 | VLines.Add(p);
247 | }
248 |
249 | for (int i = 0; i < LayerCount; i++)
250 | {
251 | Layers.Add(new BGLayer(reader));
252 | }
253 |
254 | reader.Close();
255 | }
256 |
257 | public void Write(string filename)
258 | {
259 | using (Writer writer = new Writer(filename))
260 | this.Write(writer);
261 | }
262 |
263 | public void Write(System.IO.Stream stream)
264 | {
265 | using (Writer writer = new Writer(stream))
266 | this.Write(writer);
267 | }
268 |
269 | internal void Write(Writer writer)
270 | {
271 | writer.Write((byte)Layers.Count);
272 | writer.Write((byte)HLines.Count);
273 | writer.Write((byte)VLines.Count);
274 |
275 | for (int i = 0; i < HLines.Count; i++)
276 | {
277 | HLines[i].Write(writer);
278 | }
279 |
280 | for (int i = 0; i < VLines.Count; i++)
281 | {
282 | VLines[i].Write(writer);
283 | }
284 |
285 | for (int i = 0; i < Layers.Count; i++)
286 | {
287 | Layers[i].Write(writer);
288 | }
289 |
290 | writer.Close();
291 | }
292 | }
293 | }
294 |
--------------------------------------------------------------------------------
/RSDKv2/DataFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RSDKv2
8 | {
9 | public class DataFile
10 | {
11 | public class DirInfo
12 | {
13 | ///
14 | /// the directory path
15 | ///
16 | public string Directory;
17 | ///
18 | /// the file offset for the directory
19 | ///
20 | public int Address;
21 |
22 | public DirInfo()
23 | {
24 |
25 | }
26 |
27 | public DirInfo(Reader reader)
28 | {
29 | byte ss = reader.ReadByte();
30 |
31 | char buf = ',';
32 | string DecryptedString = "";
33 |
34 | for (int i = 0; i < ss; i++)
35 | {
36 | byte b = reader.ReadByte();
37 | int bufInt = (int)b;
38 |
39 | bufInt ^= 0xFF - ss;
40 |
41 | buf = (char)bufInt;
42 | DecryptedString = DecryptedString + buf;
43 | }
44 | Directory = DecryptedString;
45 | Console.WriteLine(Directory);
46 | Address = reader.ReadInt32();
47 | }
48 |
49 | public void Write(Writer writer, bool SingleFile = false)
50 | {
51 | int ss = Directory.Length;
52 | writer.Write((byte)ss);
53 |
54 | string str = Directory;
55 |
56 | for (int i = 0; i < ss; i++)
57 | {
58 | int s = str[i];
59 | writer.Write((byte)(s ^ (0xFF - ss)));
60 | }
61 |
62 | writer.Write(Address);
63 | if (SingleFile) writer.Close();
64 | }
65 |
66 | public void Write(string dataFolder)
67 | {
68 | System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(Directory);
69 | if (!di.Exists) di.Create();
70 | Writer writer = new Writer(dataFolder);
71 | writer.Write(Directory);
72 | writer.Write(Address);
73 | writer.Close();
74 | }
75 | }
76 |
77 | public class FileInfo
78 | {
79 | ///
80 | /// the filename of the file
81 | ///
82 | public string FileName;
83 | ///
84 | /// the combined filename and directory of the file
85 | ///
86 | public string FullFileName;
87 | ///
88 | /// how many bytes the file contains
89 | ///
90 | public ulong fileSize;
91 |
92 | ///
93 | /// an array of bytes in the file
94 | ///
95 | public byte[] Filedata;
96 |
97 | ///
98 | /// what directory the file is in
99 | ///
100 | public ushort DirID = 0;
101 |
102 | int decryptKeyZ;
103 | int decryptKeyIndexZ;
104 | int decryptKeyIndex2;
105 | int decryptKeyIndex1;
106 |
107 | string decryptKey1 = "4RaS9D7KaEbxcp2o5r6t";
108 | string decryptKey2 = "3tRaUxLmEaSn";
109 |
110 | public FileInfo()
111 | {
112 |
113 | }
114 |
115 | public FileInfo(Reader reader)
116 | {
117 | byte ss = reader.ReadByte();
118 |
119 | char buf = ',';
120 | string DecryptedString = "";
121 |
122 | for (int i = 0; i < ss; i++)
123 | {
124 | byte b = reader.ReadByte();
125 | int bufInt = b;
126 |
127 | bufInt ^= 0xFF;
128 |
129 | buf = (char)bufInt;
130 | DecryptedString = DecryptedString + buf;
131 | }
132 |
133 | FileName = DecryptedString;
134 |
135 | Console.WriteLine(FileName);
136 |
137 | fileSize = reader.ReadUInt32();
138 |
139 | byte[] tmp = reader.ReadBytes(fileSize);
140 | int[] outbuf = new int[fileSize];
141 |
142 | for (int i = 0; i < (int)fileSize; i++)
143 | {
144 | outbuf[i] = tmp[i];
145 | }
146 |
147 | decryptKeyZ = ((int)fileSize & 0x1fc) >> 2;
148 | decryptKeyIndex2 = (decryptKeyZ % 9) + 1;
149 | decryptKeyIndex1 = (decryptKeyZ % decryptKeyIndex2) + 1;
150 |
151 | decryptKeyIndexZ = 0;
152 |
153 | for (int i = 0; i < (int)fileSize; i++)
154 | {
155 | outbuf[i] ^= decryptKey2[decryptKeyIndex2++] ^ decryptKeyZ;
156 |
157 | if (decryptKeyIndexZ == 1) // swap nibbles
158 | outbuf[i] = (outbuf[i] >> 4) | ((outbuf[i] & 0xf) << 4);
159 |
160 | outbuf[i] ^= decryptKey1[decryptKeyIndex1++];
161 |
162 | if ((decryptKeyIndex1 <= 19) || (decryptKeyIndex2 <= 11))
163 | {
164 | if (decryptKeyIndex1 > 19)
165 | {
166 | decryptKeyIndex1 = 1;
167 | decryptKeyIndexZ ^= 1;
168 | }
169 | if (decryptKeyIndex2 > 11)
170 | {
171 | decryptKeyIndex2 = 1;
172 | decryptKeyIndexZ ^= 1;
173 | }
174 | }
175 | else
176 | {
177 | decryptKeyZ++;
178 | decryptKeyZ &= 0x7F;
179 |
180 | if (decryptKeyIndexZ != 0)
181 | {
182 | decryptKeyIndex1 = (decryptKeyZ % 12) + 6;
183 | decryptKeyIndex2 = (decryptKeyZ % 5) + 4;
184 | decryptKeyIndexZ = 0;
185 | }
186 | else
187 | {
188 | decryptKeyIndexZ = 1;
189 | decryptKeyIndex1 = (decryptKeyZ % 15) + 3;
190 | decryptKeyIndex2 = (decryptKeyZ % 7) + 1;
191 | }
192 | }
193 | }
194 | Filedata = new byte[outbuf.Length];
195 | for (int i = 0; i > 2;
227 | decryptKeyIndex2 = (decryptKeyZ % 9) + 1;
228 | decryptKeyIndex1 = (decryptKeyZ % decryptKeyIndex2) + 1;
229 |
230 | decryptKeyIndexZ = 0;
231 |
232 | int[] outbuf = new int[Filedata.Length];
233 |
234 | for (int i = 0; i < (int)fileSize; i++)
235 | {
236 | outbuf[i] = Filedata[i];
237 | }
238 |
239 | for (int i = 0; i < (int)fileSize; i++)
240 | {
241 | outbuf[i] ^= decryptKey1[decryptKeyIndex1++];
242 |
243 | if (decryptKeyIndexZ == 1) // swap nibbles
244 | outbuf[i] = (outbuf[i] >> 4) | ((outbuf[i] & 0xf) << 4);
245 |
246 | outbuf[i] ^= decryptKey2[decryptKeyIndex2++] ^ decryptKeyZ;
247 |
248 | if ((decryptKeyIndex1 <= 19) || (decryptKeyIndex2 <= 11))
249 | {
250 | if (decryptKeyIndex1 > 19)
251 | {
252 | decryptKeyIndex1 = 1;
253 | decryptKeyIndexZ ^= 1;
254 | }
255 | if (decryptKeyIndex2 > 11)
256 | {
257 | decryptKeyIndex2 = 1;
258 | decryptKeyIndexZ ^= 1;
259 | }
260 | }
261 | else
262 | {
263 | decryptKeyZ++;
264 | decryptKeyZ &= 0x7F;
265 |
266 | if (decryptKeyIndexZ != 0)
267 | {
268 | decryptKeyIndex1 = (decryptKeyZ % 12) + 6;
269 | decryptKeyIndex2 = (decryptKeyZ % 5) + 4;
270 | decryptKeyIndexZ = 0;
271 | }
272 | else
273 | {
274 | decryptKeyIndexZ = 1;
275 | decryptKeyIndex1 = (decryptKeyZ % 15) + 3;
276 | decryptKeyIndex2 = (decryptKeyZ % 7) + 1;
277 | }
278 | }
279 | }
280 |
281 | Filedata = new byte[outbuf.Length];
282 | for (int i = 0; i < outbuf.Length; i++)
283 | {
284 | Filedata[i] = (byte)outbuf[i];
285 | }
286 |
287 | writer.Write(fileSize);
288 | writer.Write(Filedata);
289 | }
290 | }
291 |
292 | public void Write(string Datadirectory)
293 | {
294 | string tmp = FullFileName.Replace(System.IO.Path.GetFileName(FullFileName), "");
295 | string fullDir = Datadirectory + "\\" + tmp;
296 | System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(fullDir);
297 | if (!di.Exists) di.Create();
298 | Writer writer = new Writer(fullDir + FileName);
299 | writer.Write(Filedata);
300 | writer.Close();
301 | }
302 | }
303 |
304 | ///
305 | /// the "offset" for file loading I think?
306 | ///
307 | public int headerSize;
308 |
309 | ///
310 | /// a list of directories for the datafile
311 | ///
312 | public List Directories = new List();
313 | ///
314 | /// the list of fileinfo data for the file
315 | ///
316 | public List Files = new List();
317 | /** Sequentially, a file description block for every file stored inside the data file. */
318 |
319 | public DataFile()
320 | { }
321 |
322 | public DataFile(string filepath) : this(new Reader(filepath))
323 | { }
324 |
325 | public DataFile(Reader reader)
326 | {
327 |
328 | headerSize = reader.ReadInt32();
329 | Console.WriteLine("Header Size = " + headerSize);
330 |
331 | int dircount = reader.ReadUInt16();
332 | Console.WriteLine("Directory Count = " + dircount);
333 |
334 | Directories = new List();
335 |
336 | for (int d = 0; d < dircount; d++)
337 | {
338 | Directories.Add(new DirInfo(reader));
339 | }
340 |
341 | for (int d = 0; d < dircount; d++)
342 | {
343 | if ((d + 1) < Directories.Count())
344 | {
345 | while (reader.Pos - headerSize < Directories[d + 1].Address && !reader.IsEof)
346 | {
347 | FileInfo f = new FileInfo(reader);
348 | f.FullFileName = Directories[d].Directory + f.FileName;
349 | Files.Add(f);
350 | }
351 | }
352 | else
353 | {
354 | while (!reader.IsEof)
355 | {
356 | FileInfo f = new FileInfo(reader);
357 | f.FullFileName = Directories[d].Directory + f.FileName;
358 | Files.Add(f);
359 | }
360 | }
361 | }
362 | }
363 |
364 | public void Write(Writer writer)
365 | {
366 |
367 | int DirHeaderSize = 0;
368 |
369 | writer.Write(DirHeaderSize);
370 |
371 | writer.Write((ushort)Directories.Count);
372 |
373 | for (int i = 0; i < Directories.Count; i++)
374 | {
375 | Directories[i].Write(writer);
376 | }
377 |
378 | DirHeaderSize = (int)writer.BaseStream.Position;
379 |
380 | var orderedFiles = Files.OrderBy(f => f.DirID).ToList();
381 |
382 | int Dir = 0;
383 |
384 | Directories[Dir].Address = 0;
385 |
386 | for (int i = 0; i < Files.Count; i++)
387 | {
388 | if (Files[i].DirID == Dir)
389 | {
390 | Files[i].Write(writer);
391 | }
392 | else
393 | {
394 | Dir++;
395 | Directories[Dir].Address = (int)writer.BaseStream.Position - DirHeaderSize;
396 | Files[i].Write(writer);
397 | }
398 | }
399 |
400 | writer.BaseStream.Position = 0;
401 |
402 | writer.Write(DirHeaderSize);
403 |
404 | writer.Write((ushort)Directories.Count);
405 |
406 | for (int i = 0; i < Directories.Count; i++)
407 | {
408 | Directories[i].Write(writer);
409 | }
410 |
411 | writer.Close();
412 | }
413 |
414 | public void WriteFile(int fileID)
415 | {
416 | Files[fileID].Write("");
417 | }
418 |
419 | public void WriteFile(string fileName, string NewFileName)
420 | {
421 | foreach (FileInfo f in Files)
422 | {
423 | if (f.FileName == fileName)
424 | {
425 | f.Write(NewFileName);
426 | }
427 | }
428 | }
429 |
430 | }
431 | }
432 |
--------------------------------------------------------------------------------
/RSDKv2/GameConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RSDKv2
8 | {
9 | public class GameConfig
10 | {
11 |
12 | public class Category
13 | {
14 | ///
15 | /// the list of stages in this category
16 | ///
17 | public List Scenes = new List();
18 |
19 | public class SceneInfo
20 | {
21 | ///
22 | /// not entirely sure
23 | ///
24 | public byte Unknown;
25 | ///
26 | /// the folder of the scene
27 | ///
28 | public string SceneFolder = "Folder";
29 | ///
30 | /// the scene's identifier (E.G Act1 or Act2)
31 | ///
32 | public string ActID = "1";
33 | ///
34 | /// the scene name (shows up on the dev menu)
35 | ///
36 | public string Name = "Scene";
37 |
38 | public SceneInfo()
39 | {
40 | SceneFolder = "Folder";
41 | ActID = "1";
42 | Name = "Stage";
43 | Unknown = 0;
44 | }
45 |
46 | public SceneInfo(Reader reader)
47 | {
48 | SceneFolder = reader.ReadRSDKString();
49 | ActID = reader.ReadRSDKString();
50 | Name = reader.ReadRSDKString();
51 | Unknown = reader.ReadByte();
52 | Console.WriteLine("Name = " + Name + " ,Act ID = " + ActID + " ,Scene Folder = " + SceneFolder, " ,Unknown = " + Unknown);
53 | }
54 |
55 | public void Write(Writer writer)
56 | {
57 | writer.WriteRSDKString(SceneFolder);
58 | writer.WriteRSDKString(ActID);
59 | writer.WriteRSDKString(Name);
60 | writer.Write(Unknown);
61 | }
62 | }
63 |
64 | public Category()
65 | {
66 |
67 | }
68 |
69 | public Category(string filename) : this(new Reader(filename))
70 | {
71 |
72 | }
73 |
74 | public Category(System.IO.Stream stream) : this(new Reader(stream))
75 | {
76 |
77 | }
78 |
79 | public Category(Reader reader)
80 | {
81 | byte SceneCount = reader.ReadByte();
82 | for (int i = 0; i < SceneCount; i++)
83 | {
84 | Scenes.Add(new SceneInfo(reader));
85 | }
86 | }
87 |
88 | public void Write(string filename)
89 | {
90 | using (Writer writer = new Writer(filename))
91 | this.Write(writer);
92 | }
93 |
94 | public void Write(System.IO.Stream stream)
95 | {
96 | using (Writer writer = new Writer(stream))
97 | this.Write(writer);
98 | }
99 |
100 | public void Write(Writer writer)
101 | {
102 | writer.Write((byte)Scenes.Count);
103 | for (int i = 0; i < Scenes.Count; i++)
104 | {
105 | Scenes[i].Write(writer);
106 | }
107 | }
108 |
109 | }
110 |
111 | public class GlobalVariable
112 | {
113 | ///
114 | /// the name of the variable
115 | ///
116 | public string Name;
117 | ///
118 | /// the variable's value
119 | ///
120 | public int Value = 0;
121 |
122 | public GlobalVariable()
123 | {
124 |
125 | }
126 |
127 | public GlobalVariable(string name)
128 | {
129 | Name = name;
130 | }
131 |
132 | public GlobalVariable(Reader reader)
133 | {
134 | Name = reader.ReadString();
135 | Console.WriteLine(Name);
136 | Value = reader.ReadInt32();
137 | }
138 |
139 | public void Write(Writer writer)
140 | {
141 | writer.WriteRSDKString(Name);
142 | writer.Write(Value);
143 | }
144 | }
145 |
146 | ///
147 | /// the game name, appears on the window
148 | ///
149 | public string GameWindowText;
150 | ///
151 | /// i have no idea
152 | ///
153 | public string DataFileName;
154 | ///
155 | /// the string the appears in the about window
156 | ///
157 | public string GameDescriptionText;
158 |
159 | ///
160 | /// a unique name for each object in the script list
161 | ///
162 | public List ObjectsNames = new List();
163 | ///
164 | /// the list of filepaths for the global objects
165 | ///
166 | public List ScriptPaths = new List();
167 | ///
168 | /// the list of global SoundFX
169 | ///
170 | public List SoundFX = new List();
171 | ///
172 | /// the list of global variable names and values
173 | ///
174 | public List GlobalVariables = new List();
175 | ///
176 | /// the list of playerdata needed for players
177 | ///
178 | public List Players = new List();
179 | ///
180 | /// the category list (stage list)
181 | ///
182 | public List Categories = new List();
183 |
184 | public GameConfig()
185 | {
186 | Categories.Add(new Category()); //Menus
187 | Categories.Add(new Category()); //Stages
188 | Categories.Add(new Category()); //Special Stages
189 | Categories.Add(new Category()); //Bonus Stages
190 | }
191 |
192 | public GameConfig(string filename) : this(new Reader(filename))
193 | {
194 |
195 | }
196 |
197 | public GameConfig(System.IO.Stream stream) : this(new Reader(stream))
198 | {
199 |
200 | }
201 |
202 | public GameConfig(Reader reader)
203 | {
204 | GameWindowText = reader.ReadRSDKString();
205 | DataFileName = reader.ReadRSDKString();
206 | GameDescriptionText = reader.ReadRSDKString();
207 |
208 | Console.WriteLine("Game Name: " + GameWindowText);
209 | Console.WriteLine("???: " + DataFileName);
210 | Console.WriteLine("Game Description: " + GameDescriptionText);
211 |
212 | this.ReadObjectData(reader);
213 |
214 | byte GlobalsAmount = reader.ReadByte();
215 |
216 | for (int i = 0; i < GlobalsAmount; i++)
217 | {
218 | GlobalVariables.Add(new GlobalVariable(reader));
219 | }
220 |
221 | this.ReadSFXData(reader);
222 |
223 | byte playerCount = reader.ReadByte();
224 | for (int i = 0; i < playerCount; i++)
225 | {
226 | Players.Add(reader.ReadRSDKString());
227 | }
228 |
229 | Categories.Add(new Category(reader)); //Menus
230 | Categories.Add(new Category(reader)); //Stages
231 | Categories.Add(new Category(reader)); //Special Stages
232 | Categories.Add(new Category(reader)); //Bonus Stages
233 |
234 | reader.Close();
235 | }
236 |
237 | public void Write(string filename)
238 | {
239 | using (Writer writer = new Writer(filename))
240 | this.Write(writer);
241 | }
242 |
243 | public void Write(System.IO.Stream stream)
244 | {
245 | using (Writer writer = new Writer(stream))
246 | this.Write(writer);
247 | }
248 |
249 | public void Write(Writer writer)
250 | {
251 | writer.WriteRSDKString(GameWindowText);
252 | writer.WriteRSDKString(DataFileName);
253 | writer.WriteRSDKString(GameDescriptionText);
254 |
255 | this.WriteObjectData(writer);
256 |
257 | writer.Write((byte)GlobalVariables.Count);
258 | for (int i = 0; i < GlobalVariables.Count; i++)
259 | {
260 | GlobalVariables[i].Write(writer);
261 | }
262 |
263 | this.WriteSFXData(writer);
264 |
265 | writer.Write((byte)Players.Count);
266 | for (int i = 0; i < Players.Count; i++)
267 | {
268 | writer.Write(Players[i]);
269 | }
270 |
271 | for (int i = 0; i < 4; i++)
272 | {
273 | Categories[i].Write(writer);
274 | }
275 |
276 | writer.Close();
277 | }
278 |
279 | internal void ReadObjectData(Reader reader)
280 | {
281 | byte objects_count = reader.ReadByte();
282 | for (int i = 0; i < objects_count; ++i)
283 | { ObjectsNames.Add(reader.ReadRSDKString());}
284 | for (int i = 0; i < objects_count; ++i)
285 | { ScriptPaths.Add(reader.ReadRSDKString()); Console.WriteLine(ScriptPaths[i]); }
286 | }
287 |
288 | internal void WriteObjectData(Writer writer)
289 | {
290 | writer.Write((byte)ObjectsNames.Count);
291 | foreach (string name in ObjectsNames)
292 | writer.WriteRSDKString(name);
293 | foreach (string name in ScriptPaths)
294 | writer.WriteRSDKString(name);
295 | }
296 |
297 | internal void ReadSFXData(Reader reader)
298 | {
299 | byte SoundFX_count = reader.ReadByte();
300 | for (int i = 0; i < SoundFX_count; ++i)
301 | { SoundFX.Add(reader.ReadString()); }
302 | }
303 |
304 | internal void WriteSFXData(Writer writer)
305 | {
306 | writer.Write((byte)SoundFX.Count);
307 | foreach (string wav in SoundFX)
308 | writer.Write(wav);
309 | }
310 |
311 | /*The Value For DevMenu is at: Line CA0, Column 0B*/
312 | public void SetDevMenu()
313 | {
314 | for (int i = 0; i < GlobalVariables.Count; i++)
315 | {
316 | if (GlobalVariables[i].Name == "Options.DevMenuFlag")
317 | {
318 | if (GlobalVariables[i].Value == 1)
319 | {
320 | GlobalVariables[i].Value = 0;
321 | Console.WriteLine("DevMenu Deactivated!");
322 | return;
323 | }
324 | else if (GlobalVariables[i].Value == 0)
325 | {
326 | GlobalVariables[i].Value = 1;
327 | Console.WriteLine("DevMenu Activated!");
328 | return;
329 | }
330 | }
331 | }
332 | }
333 |
334 | }
335 | }
336 |
--------------------------------------------------------------------------------
/RSDKv2/GraphicsImage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Drawing;
6 | using System.Drawing.Imaging;
7 |
8 | /* Yes, RSDKv2 has support for the .gfx format */
9 |
10 | namespace RSDKv2
11 | {
12 | public class GraphicsImage
13 | {
14 | ///
15 | /// the data of the image layed out in a bitmap form for easy use
16 | ///
17 | public Bitmap gfxImage;
18 | ///
19 | /// the Image's palette
20 | ///
21 | public PaletteColour[] GFXpal = new PaletteColour[255];
22 | ///
23 | /// the width of the image
24 | ///
25 | public ushort width;
26 | ///
27 | /// the height of the image
28 | ///
29 | public ushort height;
30 | ///
31 | /// the image data
32 | ///
33 | public byte[] data;
34 |
35 | public GraphicsImage()
36 | {
37 |
38 | }
39 |
40 | public GraphicsImage(string filename, bool dcGFX = false) : this(new Reader(filename), dcGFX)
41 | {
42 |
43 | }
44 |
45 | public GraphicsImage(System.IO.Stream stream, bool dcGFX = false) : this(new Reader(stream), dcGFX)
46 | {
47 |
48 | }
49 |
50 | public GraphicsImage(Reader reader, bool dcGFX = false)
51 | {
52 |
53 | if (dcGFX)
54 | {
55 | reader.ReadByte();
56 | }
57 |
58 | width = (ushort)(reader.ReadByte() << 8);
59 | width |= reader.ReadByte();
60 |
61 | height = (ushort)(reader.ReadByte() << 8);
62 | height |= reader.ReadByte();
63 |
64 | // Create image
65 | gfxImage = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
66 |
67 | ColorPalette cp = gfxImage.Palette;
68 |
69 | // Read & Process palette
70 | for (int i = 0; i < 255; i++)
71 | {
72 | GFXpal[i].R = reader.ReadByte();
73 | GFXpal[i].G = reader.ReadByte();
74 | GFXpal[i].B = reader.ReadByte();
75 | cp.Entries[i] = Color.FromArgb(255, GFXpal[i].R, GFXpal[i].G, GFXpal[i].B);
76 |
77 | }
78 | gfxImage.Palette = cp;
79 |
80 | //Read Image Data
81 | byte[] buf = new byte[3];
82 | bool finished = false;
83 | int cnt = 0;
84 | int loop = 0;
85 |
86 | data = new byte[(width * height) + 1];
87 |
88 | while (!finished)
89 | {
90 | buf[0] = reader.ReadByte();
91 | if (buf[0] == 255)
92 | {
93 | buf[1] = reader.ReadByte();
94 | if (buf[1] == 255)
95 | {
96 | finished = true;
97 | break;
98 | }
99 | else
100 | {
101 | buf[2] = reader.ReadByte();
102 | loop = 0;
103 |
104 | // Repeat value needs to decreased by one to decode
105 | // the graphics from the Dreamcast demo
106 | if (dcGFX)
107 | { buf[2]--; }
108 |
109 | while (loop < buf[2] && !reader.IsEof)
110 | {
111 | data[cnt++] = buf[1];
112 | loop++;
113 | }
114 | }
115 | }
116 | else
117 | {
118 | data[cnt++] = buf[0];
119 | }
120 | }
121 |
122 | Console.Write("file Length = " + reader.BaseStream.Length + " file pos = " + reader.Pos + " data remaining = " + (reader.BaseStream.Length - reader.Pos));
123 |
124 | // Write data to image
125 | int pixel = 0;
126 | for (int h = 0; h < height; h++)
127 | {
128 | for (int w = 0; w < width; w++)
129 | {
130 | BitmapData ImgData = gfxImage.LockBits(new Rectangle(new Point(w, h), new Size(1, 1)), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
131 | byte b = System.Runtime.InteropServices.Marshal.ReadByte(ImgData.Scan0);
132 | System.Runtime.InteropServices.Marshal.WriteByte(ImgData.Scan0, (data[pixel]));
133 | gfxImage.UnlockBits(ImgData);
134 | pixel++;
135 | }
136 | }
137 |
138 | reader.Close();
139 | }
140 |
141 | public void ReDrawImage()
142 | {
143 | gfxImage = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
144 |
145 | ColorPalette cp = gfxImage.Palette;
146 |
147 | // Read & Process palette
148 | for (int i = 0; i < 255; i++)
149 | {
150 | cp.Entries[i] = Color.FromArgb(255, GFXpal[i].R, GFXpal[i].G, GFXpal[i].B);
151 | }
152 | gfxImage.Palette = cp;
153 |
154 | // Write data to image
155 | int pixel = 0;
156 | for (int h = 0; h < height; h++)
157 | {
158 | for (int w = 0; w < width; w++)
159 | {
160 | BitmapData ImgData = gfxImage.LockBits(new Rectangle(new Point(w, h), new Size(1, 1)), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
161 | byte b = System.Runtime.InteropServices.Marshal.ReadByte(ImgData.Scan0);
162 | System.Runtime.InteropServices.Marshal.WriteByte(ImgData.Scan0, (data[pixel]));
163 | gfxImage.UnlockBits(ImgData);
164 | pixel++;
165 | }
166 | }
167 | }
168 |
169 | public void export(string exportLocation, System.Drawing.Imaging.ImageFormat format)
170 | {
171 | gfxImage.Save(exportLocation, format);
172 | }
173 |
174 | public void importFromBitmap(Bitmap IMG)
175 | {
176 | gfxImage = IMG;
177 | width = (ushort)IMG.Width;
178 | height = (ushort)IMG.Height;
179 | }
180 |
181 | public void Write(string filename, bool dcGFX = false)
182 | {
183 | using (Writer writer = new Writer(filename))
184 | this.Write(writer, dcGFX);
185 | }
186 |
187 | public void Write(System.IO.Stream stream, bool dcGFX = false)
188 | {
189 | using (Writer writer = new Writer(stream))
190 | this.Write(writer, dcGFX);
191 | }
192 |
193 | public static byte Get8bppImagePixel(Bitmap bmp, Point location)
194 | {
195 | Color pixelRGB = bmp.GetPixel(location.X, location.Y);
196 | int pixel8bpp = Array.IndexOf(bmp.Palette.Entries, pixelRGB);
197 | return (byte)pixel8bpp;
198 | }
199 |
200 | public void Write(Writer writer, bool dcGFX = false, bool raw = false)
201 | {
202 | if (gfxImage == null)
203 | throw new Exception("Image is NULL");
204 |
205 | if (gfxImage.Palette == null || gfxImage.Palette.Entries.Length == 0)
206 | throw new Exception("Only indexed images can be converted to GFX format.");
207 |
208 | if (gfxImage.Width > 65535)
209 | throw new Exception("GFX Images can't be wider than 65535 pixels");
210 |
211 | if (gfxImage.Height > 65535)
212 | throw new Exception("GFX Images can't be higher than 65535 pixels");
213 |
214 | int num_pixels = gfxImage.Width * gfxImage.Height;
215 | int[] pixels = new int[num_pixels]; //Pallete Indexes
216 |
217 | // Images can't contain index 255
218 | for (int x = 0; x < num_pixels; x++)
219 | {
220 | if (pixels[x] == 255)
221 | throw new Exception("Images to be converted to GFX format can't contain index 255.");
222 | }
223 |
224 | int pix = 0;
225 | if (raw) //get data from "data" array
226 | {
227 | for (int h = 0; h < height; h++)
228 | {
229 | for (int w = 0; w < width; w++)
230 | {
231 | pixels[pix] = data[pix];
232 | pix++;
233 | }
234 | }
235 | }
236 | else //Get Data from Bitmap Class
237 | {
238 | for (int h = 0; h < gfxImage.Height; h++)
239 | {
240 | for (int w = 0; w < gfxImage.Width; w++)
241 | {
242 | pixels[pix++] = Get8bppImagePixel(gfxImage, new Point(w, h));
243 | }
244 | }
245 | }
246 |
247 | if (dcGFX)
248 | {
249 | byte z = 0;
250 | writer.Write(z);
251 | }
252 |
253 | // Output width and height
254 | writer.Write((byte)(gfxImage.Width >> 8));
255 | writer.Write((byte)(gfxImage.Width & 0xff));
256 |
257 | writer.Write((byte)(gfxImage.Height >> 8));
258 | writer.Write((byte)(gfxImage.Height & 0xff));
259 |
260 | for (int i = 0; i < gfxImage.Palette.Entries.Length; i++)
261 | {
262 | GFXpal[i].R = gfxImage.Palette.Entries[i].R;
263 | GFXpal[i].G = gfxImage.Palette.Entries[i].G;
264 | GFXpal[i].B = gfxImage.Palette.Entries[i].B;
265 | }
266 |
267 | // Output palette
268 | for (int x = 0; x < 255; x++)
269 | {
270 | writer.Write(GFXpal[x].R);
271 | writer.Write(GFXpal[x].G);
272 | writer.Write(GFXpal[x].B);
273 | }
274 |
275 | // Output data
276 | int p = 0;
277 | int cnt = 0;
278 |
279 | for (int x = 0; x < num_pixels; x++)
280 | {
281 | if (pixels[x] != p && x > 0)
282 | {
283 | rle_write(writer, p, cnt, dcGFX);
284 | cnt = 0;
285 | }
286 | p = pixels[x];
287 | cnt++;
288 | }
289 |
290 | rle_write(writer, p, cnt, dcGFX);
291 |
292 | // End of GFX file
293 | writer.Write((byte)0xFF);
294 | writer.Write((byte)0xFF);
295 |
296 | writer.Close();
297 | }
298 |
299 | private static void rle_write(Writer file, int pixel, int count, bool dcGfx = false)
300 | {
301 | if (count <= 2)
302 | {
303 | for (int y = 0; y < count; y++)
304 | file.Write((byte)pixel);
305 | }
306 | else
307 | {
308 | while (count > 0)
309 | {
310 | file.Write((byte)0xFF);
311 |
312 | file.Write((byte)pixel);
313 |
314 | if (dcGfx)
315 | {
316 | file.Write((byte)((count > 253) ? 254 : (count + 1)));
317 | count -= 253;
318 | }
319 | else
320 | {
321 | file.Write((byte)((count > 254) ? 254 : count));
322 | count -= 254;
323 | }
324 | }
325 | }
326 | }
327 |
328 | }
329 | }
330 |
--------------------------------------------------------------------------------
/RSDKv2/Object.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RSDKv2
8 | {
9 | public class Object
10 | {
11 | ///
12 | /// the Object's Name (used for entity list)
13 | ///
14 | public string Name
15 | {
16 | get;
17 | set;
18 | }
19 | ///
20 | /// The Type of the object
21 | ///
22 | public byte type;
23 | ///
24 | /// The Object's SubType/PropertyValue
25 | ///
26 | public byte subtype;
27 | ///
28 | /// The Object's X Position
29 | ///
30 | public short xPos;
31 | ///
32 | /// The Object's Y Position
33 | ///
34 | public short yPos;
35 | ///
36 | /// how to load the "attribute"?
37 | ///
38 | public static int cur_id = 0;
39 | ///
40 | /// the Index of the object in the loaded Object List
41 | ///
42 | public int id;
43 |
44 | public Object()
45 | {
46 |
47 | }
48 |
49 | public Object(byte type, byte subtype, short xPos, short yPos) : this(type, subtype, xPos, yPos, cur_id++)
50 | {
51 | }
52 |
53 | public Object(byte type, byte subtype, short xPos, short yPos, int id)
54 | {
55 | Name = "Unknown Object";
56 | this.type = type;
57 | this.subtype = subtype;
58 | this.xPos = xPos;
59 | this.yPos = yPos;
60 | this.id = id;
61 | }
62 |
63 | public Object(byte type, byte subtype, short xPos, short yPos, int id, string name)
64 | {
65 | this.Name = name;
66 | this.type = type;
67 | this.subtype = subtype;
68 | this.xPos = xPos;
69 | this.yPos = yPos;
70 | this.id = id;
71 | }
72 |
73 | public Object(Reader reader)
74 | {
75 | cur_id++;
76 | id = cur_id;
77 |
78 | // Object type, 1 byte, unsigned
79 | type = reader.ReadByte();
80 | // Object subtype, 1 byte, unsigned
81 | subtype = reader.ReadByte();
82 |
83 | // X Position, 2 bytes, big-endian, signed
84 | xPos = (short)(reader.ReadSByte() << 8);
85 | xPos |= (short)reader.ReadByte();
86 |
87 | // Y Position, 2 bytes, big-endian, signed
88 | yPos = (short)(reader.ReadSByte() << 8);
89 | yPos |= (short)reader.ReadByte();
90 |
91 | Console.WriteLine(id + " Obj Values: Type: " + type + ", Subtype: " + subtype + ", Xpos = " + xPos + ", Ypos = " + yPos);
92 | }
93 |
94 | public void Write(Writer writer)
95 | {
96 | if (type > 255)
97 | throw new Exception("Cannot save as Type v2. Object type > 255");
98 |
99 | if (subtype > 255)
100 | throw new Exception("Cannot save as Type v2. Object subtype > 255");
101 |
102 | if (xPos < -32768 || xPos > 32767)
103 | throw new Exception("Cannot save as Type v2. Object X Position can't fit in 16-bits");
104 |
105 | if (yPos < -32768 || yPos > 32767)
106 | throw new Exception("Cannot save as Type v2. Object Y Position can't fit in 16-bits");
107 |
108 | writer.Write(type);
109 | writer.Write(subtype);
110 |
111 | writer.Write((byte)(xPos >> 8));
112 | writer.Write((byte)(xPos & 0xFF));
113 |
114 | writer.Write((byte)(yPos >> 8));
115 | writer.Write((byte)(yPos & 0xFF));
116 |
117 | Console.WriteLine(id + " Obj Values: Type: " + type + ", Subtype: " + subtype + ", Xpos = " + xPos + ", Ypos = " + yPos);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/RSDKv2/Palette.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 |
6 |
7 | namespace RSDKv2
8 | {
9 | public class Palette
10 | {
11 | ///
12 | /// how many colours for each row (always 16)
13 | ///
14 | public const int COLORS_PER_COLUMN = 0x10;
15 |
16 | ///
17 | /// an array of the colours
18 | ///
19 | public PaletteColour[][] Colors;
20 |
21 | public Palette(int pc = 2)
22 | {
23 | int palColumns = pc;
24 |
25 | Colors = new PaletteColour[palColumns][];
26 | for (int i = 0; i < palColumns; i++)
27 | {
28 | Colors[i] = new PaletteColour[COLORS_PER_COLUMN];
29 | for (int j = 0; j < COLORS_PER_COLUMN; ++j)
30 | { Colors[i][j] = new PaletteColour(); }
31 | }
32 | }
33 |
34 | public Palette(Reader r)
35 | {
36 | Read(r);
37 | }
38 |
39 | public Palette(Reader r, int palcols)
40 | {
41 | Read(r, palcols);
42 | }
43 |
44 | public void Read(Reader reader, int Columns)
45 | {
46 | int palColumns = Columns;
47 |
48 | Colors = new PaletteColour[palColumns][];
49 | for (int i = 0; i < palColumns; i++)
50 | {
51 | Colors[i] = new PaletteColour[COLORS_PER_COLUMN];
52 | for (int j = 0; j < COLORS_PER_COLUMN; ++j)
53 | { Colors[i][j] = new PaletteColour(reader); }
54 | }
55 | }
56 |
57 | public void Read(Reader reader)
58 | {
59 | int palColumns = ((int)reader.BaseStream.Length / 8) / 6;
60 |
61 | Colors = new PaletteColour[palColumns][];
62 | for (int i = 0; i < palColumns; i++)
63 | {
64 | Colors[i] = new PaletteColour[COLORS_PER_COLUMN];
65 | for (int j = 0; j < COLORS_PER_COLUMN; ++j)
66 | { Colors[i][j] = new PaletteColour(reader);}
67 | }
68 | }
69 |
70 | public void Write(string filename)
71 | {
72 | using (Writer writer = new Writer(filename))
73 | this.Write(writer);
74 | }
75 |
76 | public void Write(System.IO.Stream stream)
77 | {
78 | using (Writer writer = new Writer(stream))
79 | this.Write(writer);
80 | }
81 |
82 | internal void Write(Writer writer)
83 | {
84 | int palColumns = Colors.Length/16;
85 | Console.WriteLine(palColumns);
86 | foreach (PaletteColour[] column in Colors)
87 | if (column != null)
88 | foreach (PaletteColour color in column)
89 | { color.Write(writer);}
90 | }
91 |
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/RSDKv2/PaletteColour.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.IO;
7 |
8 | namespace RSDKv2
9 | {
10 | public class PaletteColour
11 | {
12 |
13 | ///
14 | /// Colour Red Value
15 | ///
16 | public byte R;
17 | ///
18 | /// Colour Green Value
19 | ///
20 | public byte G;
21 | ///
22 | /// Colour Blue Value
23 | ///
24 | public byte B;
25 |
26 | public PaletteColour(byte R = 0, byte G = 0, byte B = 0)
27 | {
28 | this.R = R;
29 | this.G = G;
30 | this.B = B;
31 | }
32 |
33 | internal PaletteColour(BinaryReader reader)
34 | {
35 | this.Read(reader);
36 | }
37 |
38 | internal void Read(BinaryReader reader)
39 | {
40 | R = reader.ReadByte();
41 | G = reader.ReadByte();
42 | B = reader.ReadByte();
43 | }
44 |
45 | internal void Write(BinaryWriter writer)
46 | {
47 | writer.Write(R);
48 | writer.Write(G);
49 | writer.Write(B);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/RSDKv2/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("RSDKv2")]
9 | [assembly: AssemblyDescription("A library for interacting with the RSDKv2's file formats")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Rubberduckycooly")]
12 | [assembly: AssemblyProduct("RSDKv2")]
13 | [assembly: AssemblyCopyright("Copyright © Rubberduckycooly 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b41a3858-7e66-4755-9f50-94ea021155b6")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/RSDKv2/RSDKv2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B41A3858-7E66-4755-9F50-94EA021155B6}
8 | Library
9 | Properties
10 | RSDKv2
11 | RSDKv2
12 | v4.6.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | ..\packages\zlib.net.1.0.4.0\lib\zlib.net.dll
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/RSDKv2/Reader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.IO;
7 | using zlib;
8 |
9 | namespace RSDKv2
10 | {
11 | public class Reader : BinaryReader
12 | {
13 | public Reader(Stream stream) : base(stream)
14 | {
15 | }
16 |
17 | public Reader(string file) : base(File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
18 | {
19 | }
20 |
21 | public byte[] ReadBytes(long count)
22 | {
23 | if (count < 0 || count > Int32.MaxValue)
24 | throw new ArgumentOutOfRangeException("requested " + count + " bytes, while only non-negative int32 amount of bytes possible");
25 | byte[] bytes = base.ReadBytes((int)count);
26 | if (bytes.Length < count)
27 | throw new EndOfStreamException("requested " + count + " bytes, but got only " + bytes.Length + " bytes");
28 | return bytes;
29 | }
30 |
31 | public byte[] ReadBytes(ulong count)
32 | {
33 | if (count > Int32.MaxValue)
34 | throw new ArgumentOutOfRangeException("requested " + count + " bytes, while only non-negative int32 amount of bytes possible");
35 | int cnt = (int)count;
36 | byte[] bytes = base.ReadBytes(cnt);
37 | if (bytes.Length < cnt)
38 | throw new EndOfStreamException("requested " + count + " bytes, but got only " + bytes.Length + " bytes");
39 | return bytes;
40 | }
41 |
42 | public bool IsEof
43 | {
44 | get { return BaseStream.Position >= BaseStream.Length; }
45 | }
46 |
47 | public void Seek(long position, SeekOrigin org)
48 | {
49 | BaseStream.Seek(position, org);
50 | }
51 |
52 | public long Pos
53 | {
54 | get { return BaseStream.Position; }
55 | }
56 |
57 | public long Size
58 | {
59 | get { return BaseStream.Length; }
60 | }
61 |
62 | public uint ReadUInt32BE()
63 | {
64 | byte[] bytes = ReadBytes(4);
65 | Array.Reverse(bytes);
66 | return BitConverter.ToUInt32(bytes, 0);
67 | }
68 |
69 | public string GetFilename()
70 | {
71 | var fileStream = BaseStream as FileStream;
72 | return fileStream.Name;
73 | }
74 |
75 | public string ReadRSDKString()
76 | {
77 | return new UTF8Encoding().GetString(ReadBytes(this.ReadByte()));
78 | }
79 |
80 | public string ReadRSDKUnicodeString()
81 | {
82 | return new UnicodeEncoding().GetString(ReadBytes(this.ReadUInt16() * 2));
83 | }
84 |
85 | public byte[] ReadCompressed()
86 | {
87 | uint compresed_size = this.ReadUInt32();
88 | uint uncompressed_size = this.ReadUInt32BE();
89 | using (MemoryStream outMemoryStream = new MemoryStream())
90 | using (ZOutputStream decompress = new ZOutputStream(outMemoryStream))
91 | {
92 | decompress.Write(this.ReadBytes(compresed_size - 4), 0, (int)compresed_size - 4);
93 | decompress.finish();
94 | return outMemoryStream.ToArray();
95 | }
96 | }
97 |
98 | public Reader GetCompressedStream()
99 | {
100 | return new Reader(new MemoryStream(this.ReadCompressed()));
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/RSDKv2/SaveFiles.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace RSDKv2
8 | {
9 | public class SaveFiles
10 | {
11 |
12 | public class TimeAttackStageData
13 | {
14 | public class TimeAttackData
15 | {
16 | public int Minutes;
17 | public int Seconds;
18 | public int Milliseconds;
19 |
20 | public TimeAttackData()
21 | {
22 |
23 | }
24 |
25 | public TimeAttackData(int Offset)
26 | {
27 | //SaveRAM[Offset];
28 | }
29 | }
30 |
31 | TimeAttackData[] Times = new TimeAttackData[3];
32 |
33 | public TimeAttackStageData()
34 | {
35 | Times[0] = new TimeAttackData();
36 | Times[1] = new TimeAttackData();
37 | Times[2] = new TimeAttackData();
38 | }
39 |
40 | public TimeAttackStageData(int Offset)
41 | {
42 | int BaseOffset = Offset;
43 | for (int i = Offset; Offset < BaseOffset + 3; Offset++)
44 | {
45 | Times[Offset - BaseOffset] = new TimeAttackData(Offset);
46 | }
47 | }
48 | }
49 |
50 | public static int FileSize
51 | {
52 | get
53 | {
54 | return 0x8000;
55 | }
56 | }
57 |
58 | public static int[] SaveRAM = new int[FileSize/4];
59 |
60 | public int SaveFile = 0;
61 | public int TimeAttackStage = 0;
62 | public int TimeAttackPlace = 0; //0 to 2
63 | public int SaveFilePos
64 | {
65 | get
66 | {
67 | return (SaveFile * 0x20);
68 | }
69 | }
70 |
71 | ///
72 | /// what character you are
73 | ///
74 | public int CharacterID
75 | {
76 | get
77 | {
78 | return SaveRAM[(SaveFilePos + 0x00) / 4];
79 | }
80 | set
81 | {
82 | SaveRAM[(SaveFilePos + 0x00) / 4] = value;
83 | }
84 | }
85 | ///
86 | /// how many lives you have
87 | ///
88 | public int Lives
89 | {
90 | get
91 | {
92 | return SaveRAM[(SaveFilePos + 0x04) / 4];
93 | }
94 | set
95 | {
96 | SaveRAM[(SaveFilePos + 0x04) / 4] = value;
97 | }
98 | }
99 | ///
100 | /// current score
101 | ///
102 | public int Score
103 | {
104 | get
105 | {
106 | byte[] intBytes = BitConverter.GetBytes(SaveRAM[(SaveFilePos + 0x08) / 4]);
107 | return intBytes[0] + (intBytes[1] << 8) + (intBytes[2] << 16);
108 | }
109 | set
110 | {
111 | byte[] intBytes = BitConverter.GetBytes(value);
112 | SaveRAM[(SaveFilePos + 0x08) / 4] = intBytes[0] + (intBytes[1] << 8) + (intBytes[2] << 16);
113 | }
114 | }
115 | ///
116 | /// what zone the player is upto
117 | ///
118 | public int ZoneID
119 | {
120 | get
121 | {
122 | return SaveRAM[(SaveFilePos + 0x0C) / 4];
123 | }
124 | set
125 | {
126 | SaveRAM[(SaveFilePos + 0x0C) / 4] = value;
127 | }
128 | }
129 | ///
130 | /// how many timestones are collected
131 | ///
132 | public int TimeStones
133 | {
134 | get
135 | {
136 | return SaveRAM[(SaveFilePos + 0x10) / 4];
137 | }
138 | set
139 | {
140 | SaveRAM[(SaveFilePos + 0x10) / 4] = value;
141 | }
142 | }
143 | ///
144 | /// what special stage the user is upto
145 | ///
146 | public int SpecialZoneID
147 | {
148 | get
149 | {
150 | return SaveRAM[(SaveFilePos + 0x14) / 4];
151 | }
152 | set
153 | {
154 | SaveRAM[(SaveFilePos + 0x14) / 4] = value;
155 | }
156 | }
157 | ///
158 | /// what stages have good futures
159 | ///
160 | public int GoodFutures
161 | {
162 | get
163 | {
164 | return SaveRAM[(SaveFilePos + 0x18) / 4];
165 | }
166 | set
167 | {
168 | SaveRAM[(SaveFilePos + 0x18) / 4] = value;
169 | }
170 | }
171 | ///
172 | /// how many robo machines have been broken
173 | ///
174 | public int FuturesSaved
175 | {
176 | get
177 | {
178 | byte[] intBytes = BitConverter.GetBytes(SaveRAM[(SaveFilePos + 0x1C) / 4]);
179 | return intBytes[2] + (intBytes[3] << 8);
180 | }
181 | set
182 | {
183 | SaveRAM[(SaveFilePos + 0x1C) / 4] = value;
184 | }
185 | }
186 |
187 | //Global Vars
188 | ///
189 | /// if set to 0 the engine resets everything
190 | ///
191 | public int NewSave
192 | {
193 | get
194 | {
195 | return SaveRAM[0x80 / 4];
196 | }
197 | set
198 | {
199 | SaveRAM[0x80 / 4] = value;
200 | }
201 | }
202 | ///
203 | /// how loud the music is
204 | ///
205 | public int MusVolume
206 | {
207 | get
208 | {
209 | return SaveRAM[0x84 / 4];
210 | }
211 | set
212 | {
213 | SaveRAM[0x84 / 4] = value;
214 | }
215 | }
216 | ///
217 | /// how loud the SoundFX is
218 | ///
219 | public int SFXVolume
220 | {
221 | get
222 | {
223 | return SaveRAM[0x88 / 4];
224 | }
225 | set
226 | {
227 | SaveRAM[0x88 / 4] = value;
228 | }
229 | }
230 | ///
231 | /// using CD or MD spindash style
232 | ///
233 | public int SpindashStyle
234 | {
235 | get
236 | {
237 | return SaveRAM[0x8C / 4];
238 | }
239 | set
240 | {
241 | SaveRAM[0x8C / 4] = value;
242 | }
243 | }
244 | ///
245 | /// no idea
246 | ///
247 | public int unknown3
248 | {
249 | get
250 | {
251 | return SaveRAM[0x90 / 4];
252 | }
253 | set
254 | {
255 | SaveRAM[0x90 / 4] = value;
256 | }
257 | }
258 | ///
259 | /// the screen filter
260 | ///
261 | public int Filter
262 | {
263 | get
264 | {
265 | return SaveRAM[0x94 / 4];
266 | }
267 | set
268 | {
269 | SaveRAM[0x94 / 4] = value;
270 | }
271 | }
272 | ///
273 | /// JP or US OST?
274 | ///
275 | public int OSTStyle
276 | {
277 | get
278 | {
279 | byte[] intBytes = BitConverter.GetBytes(SaveRAM[0x98 / 4]);
280 | return intBytes[0];
281 | }
282 | set
283 | {
284 | SaveRAM[0x98 / 4] = value;
285 | }
286 | }
287 | ///
288 | /// do we have tails unlocked?
289 | ///
290 | public bool TailsUnlocked
291 | {
292 | get
293 | {
294 | if (SaveRAM[0x9C / 4] == 7)
295 | {
296 | return true;
297 | }
298 | else
299 | {
300 | return false;
301 | }
302 | }
303 | set
304 | {
305 | if (value)
306 | {
307 | SaveRAM[0x9C / 4] = 7;
308 | }
309 | else
310 | {
311 | SaveRAM[0x9C / 4] = 0;
312 | }
313 | }
314 | }
315 | ///
316 | /// what zones are unlocked in time attack?
317 | ///
318 | public int TimeAttackUnlocks
319 | {
320 | get
321 | {
322 | return SaveRAM[0x9C / 4];
323 | }
324 | set
325 | {
326 | SaveRAM[0x9C / 4] = value;
327 | }
328 | }
329 |
330 |
331 | public void SetTimeStone(int pos, bool Set)
332 | {
333 | if (Set)
334 | {
335 | TimeStones |= 1 << pos;
336 | }
337 | if (!Set)
338 | {
339 | TimeStones &= ~(1 << pos);
340 | }
341 | }
342 |
343 | public SaveFiles()
344 | {
345 | SaveFile = 1;
346 | }
347 |
348 | public SaveFiles(Stream stream) : this(new Reader(stream))
349 | {
350 | }
351 |
352 | public SaveFiles(string file) : this(File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
353 | {
354 | }
355 |
356 | internal SaveFiles(Reader reader)
357 | {
358 | SaveFile = 1;
359 | for (int i = 0; i < FileSize / 4; i++)
360 | {
361 | SaveRAM[i] = reader.ReadInt32();
362 | }
363 |
364 | reader.Close();
365 | }
366 |
367 | public void Write(string filename)
368 | {
369 | using (Writer writer = new Writer(filename))
370 | this.Write(writer);
371 | }
372 |
373 | public void Write(System.IO.Stream stream)
374 | {
375 | using (Writer writer = new Writer(stream))
376 | this.Write(writer);
377 | }
378 |
379 | public void Write(Writer writer)
380 | {
381 | for (int i = 0; i < SaveRAM.Length; i++)
382 | {
383 | writer.Write(SaveRAM[i]);
384 | }
385 | writer.Close();
386 | }
387 |
388 | }
389 | }
390 |
--------------------------------------------------------------------------------
/RSDKv2/Scene.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | /*
8 | This Loader uses code from the programs: "Retro Engine Map Viewer" and TaxEd by -- and Nextvolume respectivley
9 | */
10 |
11 | namespace RSDKv2
12 | {
13 | public class Scene
14 | {
15 | ///
16 | /// the Stage Name (what the titlecard displays)
17 | ///
18 | public string Title = "Stage";
19 |
20 | ///
21 | /// the array of Chunk IDs for the stage
22 | ///
23 | public ushort[][] MapLayout;
24 |
25 | /* Values for the "Display Bytes" */
26 | ///
27 | /// Active Layer 0, does ???
28 | ///
29 | public byte ActiveLayer0 = 1; //Usually BG Layer
30 | ///
31 | /// Active Layer 0, does ???
32 | ///
33 | public byte ActiveLayer1 = 9; //Unknown
34 | ///
35 | /// Active Layer 0, does ???
36 | ///
37 | public byte ActiveLayer2 = 0; //Usually Foreground (Map) Layer
38 | ///
39 | /// Active Layer 0, does ???
40 | ///
41 | public byte ActiveLayer3 = 0; //Usually Foreground (Map) Layer
42 | ///
43 | /// The Midpoint Layer does ???
44 | ///
45 | public byte Midpoint = 3;
46 |
47 | ///
48 | /// the starting X Boundary, it's always 0 though
49 | ///
50 | public int xBoundary1
51 | {
52 | get
53 | {
54 | return 0;
55 | }
56 | }
57 | ///
58 | /// the starting Y Boundary, it's always 0 though
59 | ///
60 | public int yBoundary1
61 | {
62 | get
63 | {
64 | return 0;
65 | }
66 | }
67 | ///
68 | /// the ending X Boundary, it's the value (in pixels) for the stage width
69 | ///
70 | public int xBoundary2
71 | {
72 | get
73 | {
74 | return width << 7;
75 | }
76 | }
77 | ///
78 | /// the ending Y Boundary, it's the value (in pixels) for the stage height
79 | ///
80 | public int yBoundary2
81 | {
82 | get
83 | {
84 | return height << 7;
85 | }
86 | }
87 | ///
88 | /// The water level for the stage, by default it will be below the stage, so it's kinda useless lol
89 | ///
90 | public int WaterLevel
91 | {
92 | get
93 | {
94 | return yBoundary2 + 128;
95 | }
96 | }
97 |
98 |
99 | //Byte 5: Stage.MidPoint
100 | //if it's 0 then nothing but the objects are drawn
101 | //if its 1 or 2 the tiles on high layer are drawn on the low layer
102 | // 3 is default
103 | // 4 or above draws tiles that are on the low layer on the high layer
104 |
105 | ///
106 | /// the list of objects in the stage
107 | ///
108 | public List