Skip to content

Commit

Permalink
Implementing initial support for Chaotix object format.
Browse files Browse the repository at this point in the history
  • Loading branch information
MainMemory committed Jan 30, 2015
1 parent ace5eba commit bc1ec8e
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 39 deletions.
14 changes: 10 additions & 4 deletions SonED2ProjectConverter/Program.cs
Expand Up @@ -14,8 +14,8 @@ class Program
{
static void Main(string[] args)
{
try
{
//try
//{
string folder;
if (args.Length > 0)
{
Expand Down Expand Up @@ -179,6 +179,8 @@ static void Main(string[] args)
case 2:
info.LayoutFormat = EngineVersion.S3K;
break;
default:
throw new ArgumentOutOfRangeException("Unsupported layout format.");
}
info.LayoutCompression = compressionTypes[int.Parse(data[linenum++], NumberStyles.Integer, NumberFormatInfo.InvariantInfo)];
switch (info.LayoutFormat)
Expand Down Expand Up @@ -225,6 +227,10 @@ static void Main(string[] args)
info.ObjectFormat = EngineVersion.S3K;
info.Objects = data[linenum++];
break;
case 5:
info.ObjectFormat = EngineVersion.Chaotix;
info.Objects = data[linenum++];
break;
}
switch (int.Parse(data[linenum++], NumberStyles.Integer, NumberFormatInfo.InvariantInfo))
{
Expand Down Expand Up @@ -324,12 +330,12 @@ static void Main(string[] args)
if (output.EngineVersion == EngineVersion.Invalid)
output.EngineVersion = EngineVersion.S1;
output.Save(Path.Combine(outdir, "SonLVL.ini"));
}
/*}
catch (Exception ex)
{
File.WriteAllText("SonED2ProjectConverter.log", ex.ToString());
throw;
}
}*/
}

static readonly Dictionary<int, CompressionType> compressionTypes = new Dictionary<int, CompressionType>()
Expand Down
51 changes: 31 additions & 20 deletions SonLVL/MainForm.cs
Expand Up @@ -1654,14 +1654,16 @@ private void objectPanel_KeyDown(object sender, KeyEventArgs e)
if (!loaded) return;
if (!e.Control)
{
foreach (Entry item in SelectedItems)
foreach (ObjectEntry item in SelectedItems.OfType<ObjectEntry>())
{
if (item is ObjectEntry)
unchecked
{
ObjectEntry oi = item as ObjectEntry;
oi.SubType = (byte)(oi.SubType == 0 ? 255 : oi.SubType - 1);
oi.UpdateSprite();
if (item is ChaotixObjectEntry)
--((ChaotixObjectEntry)item).FullSubType;
else
--item.SubType;
}
item.UpdateSprite();
}
DrawLevel();
}
Expand All @@ -1683,14 +1685,13 @@ private void objectPanel_KeyDown(object sender, KeyEventArgs e)
}
else
{
foreach (Entry item in SelectedItems)
foreach (ObjectEntry item in SelectedItems.OfType<ObjectEntry>())
{
if (item is ObjectEntry)
{
ObjectEntry oi = item as ObjectEntry;
oi.SubType = (byte)(oi.SubType == 255 ? 0 : oi.SubType + 1);
oi.UpdateSprite();
}
if (item is ChaotixObjectEntry)
++((ChaotixObjectEntry)item).FullSubType;
else
++item.SubType;
item.UpdateSprite();
}
DrawLevel();
}
Expand Down Expand Up @@ -1950,13 +1951,18 @@ private void objectPanel_MouseDown(object sender, MouseEventArgs e)
{
if (ModifierKeys != Keys.Control || LevelData.Bumpers == null)
{
if (LevelData.Level.ObjectFormat == EngineVersion.Chaotix)
ObjectSelect.numericUpDown2.Maximum = 0x1FFF;
else
ObjectSelect.numericUpDown2.Maximum = 0xFF;
if (ObjectSelect.ShowDialog(this) == DialogResult.OK)
{
byte ID = (byte)ObjectSelect.numericUpDown1.Value;
byte sub = (byte)ObjectSelect.numericUpDown2.Value;
ObjectEntry ent = LevelData.CreateObject(ID);
ObjectEntry ent = LevelData.CreateObject((byte)ObjectSelect.numericUpDown1.Value);
LevelData.Objects.Add(ent);
ent.SubType = sub;
if (ent is ChaotixObjectEntry)
((ChaotixObjectEntry)ent).FullSubType = (ushort)ObjectSelect.numericUpDown2.Value;
else
ent.SubType = (byte)ObjectSelect.numericUpDown2.Value;
ent.X = (ushort)gridx;
ent.Y = (ushort)gridy;
if (ent is SCDObjectEntry)
Expand Down Expand Up @@ -2612,13 +2618,18 @@ private void panel_Resize(object sender, EventArgs e)
Point menuLoc;
private void addObjectToolStripMenuItem_Click(object sender, EventArgs e)
{
if (LevelData.Level.ObjectFormat == EngineVersion.Chaotix)
ObjectSelect.numericUpDown2.Maximum = 0x1FFF;
else
ObjectSelect.numericUpDown2.Maximum = 0xFF;
if (ObjectSelect.ShowDialog(this) == DialogResult.OK)
{
byte ID = (byte)ObjectSelect.numericUpDown1.Value;
byte sub = (byte)ObjectSelect.numericUpDown2.Value;
ObjectEntry ent = LevelData.CreateObject(ID);
ObjectEntry ent = LevelData.CreateObject((byte)ObjectSelect.numericUpDown1.Value);
LevelData.Objects.Add(ent);
ent.SubType = sub;
if (ent is ChaotixObjectEntry)
((ChaotixObjectEntry)ent).FullSubType = (ushort)ObjectSelect.numericUpDown2.Value;
else
ent.SubType = (byte)ObjectSelect.numericUpDown2.Value;
double gs = 1 << ObjGrid;
ent.X = (ushort)(Math.Round((menuLoc.X * ZoomLevel + hScrollBar1.Value) / gs, MidpointRounding.AwayFromZero) * gs);
ent.Y = (ushort)(Math.Round((menuLoc.Y * ZoomLevel + vScrollBar1.Value) / gs, MidpointRounding.AwayFromZero) * gs);
Expand Down
92 changes: 90 additions & 2 deletions SonLVLAPI/DataTypes.cs
Expand Up @@ -723,7 +723,7 @@ public virtual string _ID
[Description("The subtype of the object.")]
[DisplayName("Subtype")]
[Editor(typeof(SubTypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
public string _SubType
public virtual string _SubType
{
get
{
Expand Down Expand Up @@ -1167,7 +1167,95 @@ public override void FromBytes(byte[] bytes)
}
}

[Serializable]
[DefaultProperty("ID")]
[Serializable]
public class ChaotixObjectEntry : ObjectEntry
{
public override byte SubType
{
get
{
return (byte)fullSubType;
}
set
{
fullSubType = value;
}
}

private ushort fullSubType;
public ushort FullSubType
{
get { return fullSubType; }
set { fullSubType = (ushort)(value & 0x1FFF); }
}

[DefaultValue("00")]
[Description("The subtype of the object.")]
[DisplayName("Subtype")]
[Editor(typeof(SubTypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
public override string _SubType
{
get { return FullSubType.ToString("X4"); }
set { FullSubType = byte.Parse(value, System.Globalization.NumberStyles.HexNumber); }
}
[DefaultValue(false)]
[Description("If true, the object will be loaded when it is in horizontal range of the screen, regardless of its Y position.")]
[DisplayName("Make object manager ignore Y position")]
public virtual bool SomeFlag { get; set; }

public static int Size { get { return 8; } }

public ChaotixObjectEntry() { pos = new Position(this); isLoaded = true; }

/* Format:
8 bytes per entry:
x_pos (word)
y_pos (word)
4*ID (word)
secondary subtype (byte), highest 3 bits are No-Y-Check, Y-Flip, X-Flip
subtype (byte)
*/

public ChaotixObjectEntry(byte[] file, int address)
{
byte[] bytes = new byte[Size];
Array.Copy(file, address, bytes, 0, Size);
FromBytes(bytes);
pos = new Position(this);
isLoaded = true;
}

public override byte[] GetBytes()
{
List<byte> ret = new List<byte>();
ret.AddRange(ByteConverter.GetBytes(X));
ret.AddRange(ByteConverter.GetBytes(Y));
ret.AddRange(ByteConverter.GetBytes(ID << 2));
ushort val = fullSubType;
if (XFlip) val |= 0x2000;
if (YFlip) val |= 0x4000;
if (SomeFlag) val |= 0x8000;
ret.AddRange(ByteConverter.GetBytes(val));
return ret.ToArray();
}

public override void FromBytes(byte[] bytes)
{
X = ByteConverter.ToUInt16(bytes, 0);
Y = ByteConverter.ToUInt16(bytes, 2);
ID = (byte)(ByteConverter.ToUInt16(bytes, 4) >> 2);

ushort val = ByteConverter.ToUInt16(bytes, 6);

SomeFlag = (val & 0x8000) == 0x8000;
YFlip = (val & 0x4000) == 0x4000;
XFlip = (val & 0x2000) == 0x2000;
fullSubType = (ushort)(val & 0x1FFF);
}
}

[Serializable]
public abstract class RingEntry : Entry, IComparable<RingEntry>
{
int IComparable<RingEntry>.CompareTo(RingEntry other)
Expand Down
35 changes: 22 additions & 13 deletions SonLVLAPI/LevelData.cs
Expand Up @@ -560,7 +560,14 @@ public static void LoadLevel(string levelname, bool loadGraphics)
Objects.Add(new SCDObjectEntry(tmp, oa));
}
break;
}
case EngineVersion.Chaotix:
for (int oa = 0; oa < tmp.Length; oa += ChaotixObjectEntry.Size)
{
if (ByteConverter.ToUInt16(tmp, oa) == 0xFFFF) break;
Objects.Add(new ChaotixObjectEntry(tmp, oa));
}
break;
}
if (loadGraphics)
for (int i = 0; i < Objects.Count; i++)
Objects[i].UpdateSprite();
Expand Down Expand Up @@ -905,45 +912,40 @@ public static void SaveLevel()
{
Objects.Sort();
tmp = new List<byte>();
switch (Level.ObjectFormat)
for (int oi = 0; oi < Objects.Count; oi++)
tmp.AddRange(Objects[oi].GetBytes());
switch (Level.ObjectFormat)
{
case EngineVersion.S1:
for (int oi = 0; oi < Objects.Count; oi++)
tmp.AddRange(((S1ObjectEntry)Objects[oi]).GetBytes());
tmp.AddRange(new byte[] { 0xFF, 0xFF });
while (tmp.Count % S1ObjectEntry.Size > 0)
tmp.Add(0);
break;
case EngineVersion.S2:
for (int oi = 0; oi < Objects.Count; oi++)
tmp.AddRange(((S2ObjectEntry)Objects[oi]).GetBytes());
tmp.AddRange(new byte[] { 0xFF, 0xFF });
while (tmp.Count % S2ObjectEntry.Size > 0)
tmp.Add(0);
break;
case EngineVersion.S2NA:
for (int oi = 0; oi < Objects.Count; oi++)
tmp.AddRange(((S2NAObjectEntry)Objects[oi]).GetBytes());
tmp.AddRange(new byte[] { 0xFF, 0xFF });
while (tmp.Count % S2NAObjectEntry.Size > 0)
tmp.Add(0);
break;
case EngineVersion.S3K:
case EngineVersion.SKC:
for (int oi = 0; oi < Objects.Count; oi++)
tmp.AddRange(((S3KObjectEntry)Objects[oi]).GetBytes());
tmp.AddRange(new byte[] { 0xFF, 0xFF });
while (tmp.Count % S3KObjectEntry.Size > 0)
tmp.Add(0);
break;
case EngineVersion.SCDPC:
for (int oi = 0; oi < Objects.Count; oi++)
tmp.AddRange(((SCDObjectEntry)Objects[oi]).GetBytes());
tmp.Add(0xFF);
while (tmp.Count % SCDObjectEntry.Size > 0)
tmp.Add(0xFF);
break;
}
case EngineVersion.Chaotix:
tmp.AddRange(new byte[] { 0xFF, 0xFF });
break;
}
Compression.Compress(tmp.ToArray(), Level.Objects, Level.ObjectCompression);
}
if (Level.Rings != null && RingFormat is RingLayoutFormat)
Expand Down Expand Up @@ -1296,6 +1298,9 @@ private static void InitObjectDefinitions()
case EngineVersion.SCDPC:
basetype = typeof(SCDObjectEntry);
break;
case EngineVersion.Chaotix:
basetype = typeof(ChaotixObjectEntry);
break;
default:
basetype = typeof(ObjectEntry);
break;
Expand Down Expand Up @@ -2802,6 +2807,9 @@ public static ObjectEntry CreateObject(byte ID)
case EngineVersion.SCDPC:
oe = new SCDObjectEntry() { RememberState = def.RememberState };
break;
case EngineVersion.Chaotix:
oe = new ChaotixObjectEntry();
break;
default:
oe = null;
break;
Expand Down Expand Up @@ -3201,6 +3209,7 @@ public enum EngineVersion
SCD,
SCDPC,
SKC,
Chaotix,
Custom
}

Expand Down
3 changes: 3 additions & 0 deletions SonLVLAPI/ObjectDefinition.cs
Expand Up @@ -1086,6 +1086,9 @@ private bool CheckConditions(ObjectEntry obj, XMLDef.DisplayOption option)
case EngineVersion.SCDPC:
basetype = typeof(SCDObjectEntry);
break;
case EngineVersion.Chaotix:
basetype = typeof(ChaotixObjectEntry);
break;
default:
basetype = typeof(ObjectEntry);
break;
Expand Down

0 comments on commit bc1ec8e

Please sign in to comment.