From 9aa70c4fa9537d46c1fc0bcd889592f8065306f2 Mon Sep 17 00:00:00 2001 From: beirich Date: Fri, 16 Sep 2011 04:59:59 +0000 Subject: [PATCH] Much improved pce-cd savestateyfulness Cleanup and stateyness of SCSI bus still in progress; states not done yet --- BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs | 5 + BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs | 208 +++++++++++++++--- .../Consoles/PC Engine/PCEngine.cs | 26 ++- .../Consoles/PC Engine/TurboCD.cs | 49 +---- BizHawk.Emulation/Sound/CDAudio.cs | 4 + 5 files changed, 212 insertions(+), 80 deletions(-) diff --git a/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs b/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs index ae682442d2..9ff78b0be6 100644 --- a/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs +++ b/BizHawk.Emulation/CPUs/HuC6280/HuC6280.cs @@ -76,6 +76,7 @@ namespace BizHawk.Emulation.CPUs.H6280 writer.Write("MPR "); MPR.SaveAsHex(writer); writer.WriteLine("IRQ1Assert {0}", IRQ1Assert); + writer.WriteLine("IRQ2Assert {0}", IRQ2Assert); writer.WriteLine("TimerAssert {0}", TimerAssert); writer.WriteLine("IRQControlByte {0:X2}", IRQControlByte); writer.WriteLine("IRQNextControlByte {0:X2}", IRQNextControlByte); @@ -117,6 +118,8 @@ namespace BizHawk.Emulation.CPUs.H6280 MPR.ReadFromHex(args[1]); else if (args[0] == "IRQ1Assert") IRQ1Assert = bool.Parse(args[1]); + else if (args[0] == "IRQ2Assert") + IRQ2Assert = bool.Parse(args[1]); else if (args[0] == "TimerAssert") TimerAssert = bool.Parse(args[1]); else if (args[0] == "IRQControlByte") @@ -162,6 +165,7 @@ namespace BizHawk.Emulation.CPUs.H6280 writer.Write(S); writer.Write(MPR); writer.Write(IRQ1Assert); + writer.Write(IRQ2Assert); writer.Write(TimerAssert); writer.Write(IRQControlByte); writer.Write(IRQNextControlByte); @@ -191,6 +195,7 @@ namespace BizHawk.Emulation.CPUs.H6280 S = reader.ReadByte(); MPR = reader.ReadBytes(8); IRQ1Assert = reader.ReadBoolean(); + IRQ2Assert = reader.ReadBoolean(); TimerAssert = reader.ReadBoolean(); IRQControlByte = reader.ReadByte(); IRQNextControlByte = reader.ReadByte(); diff --git a/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs b/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs index f2fe269ef9..914af7f531 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/ADPCM.cs @@ -1,10 +1,18 @@ using System; using BizHawk.Emulation.Sound; +using System.IO; +using System.Globalization; namespace BizHawk.Emulation.Consoles.TurboGrafx { public sealed class ADPCM : ISoundProvider { + ScsiCDBus SCSI; + PCEngine pce; + MetaspuSoundProvider SoundProvider = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V); + + // *************************************************************************** + public ushort IOAddress; public ushort ReadAddress; public ushort WriteAddress; @@ -15,11 +23,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx public bool ReadPending, WritePending; public byte[] RAM = new byte[0x10000]; - - ScsiCDBus SCSI; - PCEngine pce; - MetaspuSoundProvider SoundProvider = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V); - + // *************************************************************************** public bool AdpcmIsPlaying { get; private set; } @@ -29,21 +33,12 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx public bool AdpcmBusyReading { get { return ReadPending; } } public bool AdpcmCdDmaRequested { get { return (Port180B & 3) != 0; } } + // *************************************************************************** + public byte Port180A { - set - { - WriteBuffer = value; - WriteTimer = 24; - WritePending = true; - } - - get - { - ReadPending = true; - ReadTimer = 24; - return ReadBuffer; - } + set { WritePending = true; WriteTimer = 24; WriteBuffer = value; } + get { ReadPending = true; ReadTimer = 24; return ReadBuffer; } } public byte Port180B; @@ -58,7 +53,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx port180E = value; float khz = 32 / (16 - (Port180E & 0x0F)); destSamplesPerSourceSample = 44.1f / khz; - } } @@ -189,6 +183,13 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx // Playback Functions // *************************************************************************** + float Playback44khzTimer; + int playingSample; + float nextSampleTimer; + float destSamplesPerSourceSample; + bool nibble; + int magnitude; + static readonly int[] StepSize = { 0x0002, 0x0006, 0x000A, 0x000E, 0x0012, 0x0016, 0x001A, 0x001E, @@ -244,13 +245,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx static readonly int[] StepFactor = { -1, -1, -1, -1, 2, 4, 6, 8 }; - float Playback44khzTimer; - int playingSample; - float nextSampleTimer = 0; - float destSamplesPerSourceSample; - bool nibble; - int magnitude; - int AddClamped(int num1, int num2, int min, int max) { int result = num1 + num2; @@ -325,5 +319,165 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx } public int MaxVolume { get; set; } + + // *************************************************************************** + + public void SaveStateBinary(BinaryWriter writer) + { + writer.Write(RAM); + writer.Write(IOAddress); + writer.Write(AdpcmLength); + writer.Write(ReadAddress); + writer.Write((byte)ReadTimer); + writer.Write(ReadBuffer); + writer.Write(ReadPending); + writer.Write(WriteAddress); + writer.Write((byte)WriteTimer); + writer.Write(WriteBuffer); + writer.Write(WritePending); + + writer.Write(Port180B); + writer.Write(Port180D); + writer.Write(Port180E); + + writer.Write(AdpcmIsPlaying); + writer.Write(HalfReached); + writer.Write(EndReached); + + writer.Write(Playback44khzTimer); + writer.Write((ushort)playingSample); + writer.Write(nextSampleTimer); + writer.Write(nibble); + writer.Write((byte)magnitude); + } + + public void LoadStateBinary(BinaryReader reader) + { + RAM = reader.ReadBytes(0x10000); + IOAddress = reader.ReadUInt16(); + AdpcmLength = reader.ReadUInt16(); + ReadAddress = reader.ReadUInt16(); + ReadTimer = reader.ReadByte(); + ReadBuffer = reader.ReadByte(); + ReadPending = reader.ReadBoolean(); + WriteAddress = reader.ReadUInt16(); + WriteTimer = reader.ReadByte(); + WriteBuffer = reader.ReadByte(); + WritePending = reader.ReadBoolean(); + + Port180B = reader.ReadByte(); + Port180D = reader.ReadByte(); + Port180E = reader.ReadByte(); + + AdpcmIsPlaying = reader.ReadBoolean(); + HalfReached = reader.ReadBoolean(); + EndReached = reader.ReadBoolean(); + + Playback44khzTimer = reader.ReadSingle(); + playingSample = reader.ReadUInt16(); + nextSampleTimer = reader.ReadSingle(); + nibble = reader.ReadBoolean(); + magnitude = reader.ReadByte(); + + pce.IntADPCM = HalfReached; + pce.IntStop = EndReached; + pce.RefreshIRQ2(); + } + + public void SaveStateText(TextWriter writer) + { + writer.WriteLine("[ADPCM]"); + writer.Write("RAM "); + RAM.SaveAsHex(writer); + writer.WriteLine("IOAddress {0:X4}", IOAddress); + writer.WriteLine("AdpcmLength {0:X4}", AdpcmLength); + writer.WriteLine("ReadAddress {0:X4}", ReadAddress); + writer.WriteLine("ReadTimer {0}", ReadTimer); + writer.WriteLine("ReadBuffer {0:X2}", ReadBuffer); + writer.WriteLine("ReadPending {0}", ReadPending); + writer.WriteLine("WriteAddress {0:X4}", WriteAddress); + writer.WriteLine("WriteTimer {0}", WriteTimer); + writer.WriteLine("WriteBuffer {0:X2}", WriteBuffer); + writer.WriteLine("WritePending {0}", WritePending); + + writer.WriteLine("Port180B {0:X2}", Port180B); + writer.WriteLine("Port180D {0:X2}", Port180D); + writer.WriteLine("Port180E {0:X2}", Port180E); + + writer.WriteLine("AdpcmIsPlaying {0}", AdpcmIsPlaying); + writer.WriteLine("HalfReached {0}", HalfReached); + writer.WriteLine("EndReached {0}", EndReached); + + writer.WriteLine("Playback44khzTimer {0}", Playback44khzTimer); + writer.WriteLine("PlayingSample {0:X4}", playingSample); + writer.WriteLine("NextSampleTimer {0}", nextSampleTimer); + writer.WriteLine("FirstNibble {0}", nibble); + writer.WriteLine("Magnitude {0}", magnitude); + writer.WriteLine("[/ADPCM]\n"); + } + + public void LoadStateText(TextReader reader) + { + while (true) + { + string[] args = reader.ReadLine().Split(' '); + if (args[0].Trim() == "") continue; + if (args[0] == "[/ADPCM]") break; + if (args[0] == "RAM") + RAM.ReadFromHex(args[1]); + else if (args[0] == "IOAddress") + IOAddress = ushort.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "AdpcmLength") + AdpcmLength = ushort.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "ReadAddress") + ReadAddress = ushort.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "ReadTimer") + ReadTimer = int.Parse(args[1]); + else if (args[0] == "ReadBuffer") + ReadBuffer = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "ReadPending") + ReadPending = bool.Parse(args[1]); + else if (args[0] == "WriteAddress") + WriteAddress = ushort.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "WriteTimer") + WriteTimer = int.Parse(args[1]); + else if (args[0] == "WriteBuffer") + WriteBuffer = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "WritePending") + WritePending = bool.Parse(args[1]); + + else if (args[0] == "Port180B") + Port180B = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "Port180D") + Port180D = byte.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "Port180E") + Port180E = byte.Parse(args[1], NumberStyles.HexNumber); + + else if (args[0] == "AdpcmIsPlaying") + AdpcmIsPlaying = bool.Parse(args[1]); + else if (args[0] == "HalfReached") + HalfReached = bool.Parse(args[1]); + else if (args[0] == "EndReached") + EndReached = bool.Parse(args[1]); + + else if (args[0] == "Playback44khzTimer") + Playback44khzTimer = float.Parse(args[1]); + else if (args[0] == "PlayingSample") + playingSample = ushort.Parse(args[1], NumberStyles.HexNumber); + else if (args[0] == "NextSampleTimer") + nextSampleTimer = float.Parse(args[1]); + else if (args[0] == "FirstNibble") + nibble = bool.Parse(args[1]); + else if (args[0] == "Magnitude") + magnitude = int.Parse(args[1]); + + else + Console.WriteLine("Skipping unrecognized identifier " + args[0]); + } + + pce.IntADPCM = HalfReached; + pce.IntStop = EndReached; + pce.RefreshIRQ2(); + } } -} \ No newline at end of file +} diff --git a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs index 06d3e17ff6..77bf1b5c71 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs @@ -264,6 +264,8 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx public bool SaveRamModified { get; set; } + // TODO: properly savestate SCSI + public void SaveStateText(TextWriter writer) { writer.WriteLine("[PCEngine]"); @@ -274,8 +276,8 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx writer.Write("PopulousRAM "); PopulousRAM.SaveAsHex(writer); } - writer.WriteLine("Frame " + Frame); - writer.WriteLine("Lag " + _lagcount); + writer.WriteLine("Frame {0}", Frame); + writer.WriteLine("Lag {0}", _lagcount); if (Cpu.ReadMemory21 == ReadMemorySF2) writer.WriteLine("SF2MapperLatch " + SF2MapperLatch); writer.WriteLine("IOBuffer {0:X2}", IOBuffer); @@ -307,8 +309,9 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx writer.Write("SuperRAM "); SuperRam.SaveAsHex(writer); } -writer.Write("ADPCM_TEMP "); -ADPCM.RAM.SaveAsHex(writer); + + writer.WriteLine(); + ADPCM.SaveStateText(writer); } writer.WriteLine("[/PCEngine]"); } @@ -335,8 +338,6 @@ ADPCM.RAM.SaveAsHex(writer); CDRam.ReadFromHex(args[1]); else if (args[0] == "SuperRAM") SuperRam.ReadFromHex(args[1]); -else if (args[0] == "ADPCM_TEMP") -ADPCM.RAM.ReadFromHex(args[1]); else if (args[0] == "PopulousRAM" && PopulousRAM != null) PopulousRAM.ReadFromHex(args[1]); else if (args[0] == "[HuC6280]") @@ -353,6 +354,8 @@ ADPCM.RAM.ReadFromHex(args[1]); VDC2.LoadStateText(reader, 2); else if (args[0] == "[CDAudio]") CDAudio.LoadStateText(reader); + else if (args[0] == "[ADPCM]") + ADPCM.LoadStateText(reader); else Console.WriteLine("Skipping unrecognized identifier " + args[0]); } @@ -363,6 +366,8 @@ ADPCM.RAM.ReadFromHex(args[1]); if (SuperGrafx == false) { writer.Write(Ram); + writer.Write(CdIoPorts); + RefreshIRQ2(); if (BRAM != null) writer.Write(BRAM); if (PopulousRAM != null) @@ -372,7 +377,7 @@ ADPCM.RAM.ReadFromHex(args[1]); if (TurboCD) { writer.Write(CDRam); - writer.Write(ADPCM.RAM); + ADPCM.SaveStateBinary(writer); } writer.Write(Frame); writer.Write(_lagcount); @@ -405,6 +410,7 @@ ADPCM.RAM.ReadFromHex(args[1]); if (SuperGrafx == false) { Ram = reader.ReadBytes(0x2000); + CdIoPorts = reader.ReadBytes(16); if (BRAM != null) BRAM = reader.ReadBytes(0x800); if (PopulousRAM != null) @@ -414,7 +420,7 @@ ADPCM.RAM.ReadFromHex(args[1]); if (TurboCD) { CDRam = reader.ReadBytes(0x10000); - ADPCM.RAM = reader.ReadBytes(0x10000); + ADPCM.LoadStateBinary(reader); } Frame = reader.ReadInt32(); _lagcount = reader.ReadInt32(); @@ -444,12 +450,12 @@ ADPCM.RAM.ReadFromHex(args[1]); public byte[] SaveStateBinary() { - int buflen = 75870; + int buflen = 75887; if (SuperGrafx) buflen += 90698; if (BramEnabled) buflen += 2048; if (PopulousRAM != null) buflen += 0x8000; if (SuperRam != null) buflen += 0x30000; - if (TurboCD) buflen += 0x20000 + 30; + if (TurboCD) buflen += 0x20000 + 62; //Console.WriteLine("LENGTH1 " + buflen); var buf = new byte[buflen]; diff --git a/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs b/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs index 4b864bb7de..c80a85e2ce 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/TurboCD.cs @@ -6,9 +6,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx { public static byte[] CdIoPorts = new byte[16]; - public byte IRQ2Control { get { return CdIoPorts[2]; } set { CdIoPorts[2] = value; } } - public byte IRQ2Monitor { get { return CdIoPorts[3]; } set { CdIoPorts[3] = value; } } - public bool IntADPCM // INTA { get { return (CdIoPorts[3] & 0x04) != 0; } @@ -35,17 +32,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx set { CdIoPorts[3] = (byte)((CdIoPorts[3] & ~0x40) | (value ? 0x40 : 0x00)); } } - public byte Port1803 - { - get { return CdIoPorts[3]; } - set - { - if (value != CdIoPorts[3]) - Console.WriteLine("UPDATE 1803: From {0:X2} to {1:X2}", CdIoPorts[3], value); - CdIoPorts[3] = value; - } - } - void SetCDAudioCallback() { CDAudio.CallbackAction = () => @@ -58,27 +44,21 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx void WriteCD(int addr, byte value) { - //Log.Error("CD","Write: {0:X4} {1:X2} (PC={2:X4})", addr & 0x1FFF, value, Cpu.PC); switch (addr & 0x1FFF) { case 0x1800: // SCSI Drive Control Line CdIoPorts[0] = value; - // Console.WriteLine("Write to CDC Status [0] {0:X2}", value); - SCSI.SEL = true; SCSI.Think(); SCSI.SEL = false; SCSI.Think(); - // this probably does some things - // possibly clear irq line or trigger or who knows break; case 0x1801: // CDC Command CdIoPorts[1] = value; SCSI.DataBits = value; SCSI.Think(); -// Console.WriteLine("Write to CDC Command [1] {0:X2}", value); break; case 0x1802: // ACK and Interrupt Control @@ -103,7 +83,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx SCSI.Think(); if (SCSI.RST) { - Port1803 &= 0x8F; // Clear interrupt control bits + CdIoPorts[3] &= 0x8F; // Clear interrupt control bits RefreshIRQ2(); } break; @@ -126,7 +106,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx Console.WriteLine("doing silly thing"); ADPCM.AdpcmLength = ADPCM.IOAddress; } - //Log.Error("CD", "adpcm address = {0:X4}", ADPCM.adpcm_io_address); break; case 0x1809: // ADPCM address MSB @@ -137,7 +116,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx Console.WriteLine("doing silly thing"); ADPCM.AdpcmLength = ADPCM.IOAddress; } - //Log.Error("CD", "adpcm address = {0:X4}", ADPCM.adpcm_io_address); break; case 0x180A: // ADPCM Memory Read/Write Port @@ -146,7 +124,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx case 0x180B: // ADPCM DMA Control ADPCM.Port180B = value; - //Log.Error("CD", "Write to ADPCM DMA Control [B] {0:X2}", value); if (ADPCM.AdpcmCdDmaRequested) Console.WriteLine(" ADPCM DMA REQUESTED"); break; @@ -157,14 +134,11 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx case 0x180E: // ADPCM Playback Rate ADPCM.Port180E = value; - //Log.Error("CD", "Write to ADPCM Sample Rate [E] {0:X2}", value); break; case 0x180F: // Audio Fade Timer CdIoPorts[0x0F] = value; - //Log.Error("CD", "Write to CD Audio fade timer [F] {0:X2}", value); // TODO ADPCM fades/vol control also. - switch (value) { case 0: @@ -204,46 +178,39 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx if (SCSI.MSG) returnValue |= 0x20; if (SCSI.REQ) returnValue |= 0x40; if (SCSI.BSY) returnValue |= 0x80; - //Log.Error("CD", "Read: 1800 {0:X2} (PC={1:X4})", returnValue, Cpu.PC); return returnValue; case 0x1801: // Read data bus - //Log.Error("CD", "Read: 1801 {0:X2} (PC={1:X4})", SCSI.DataBits, Cpu.PC); return SCSI.DataBits; case 0x1802: // ADPCM / CD Control - //Log.Error("CD", "Read: 1802 {0:X2} (PC={1:X4})", CdIoPorts[2], Cpu.PC); return CdIoPorts[2]; case 0x1803: // BRAM Lock if (BramEnabled) BramLocked = true; - - //Log.Error("CD", "Read: 1803 {0:X2} (PC={1:X4})", CdIoPorts[3], Cpu.PC); - returnValue = Port1803; + + returnValue = CdIoPorts[3]; CdIoPorts[3] ^= 2; return returnValue; case 0x1804: // CD Reset - //Log.Error("CD", "Read: 1804 {0:X2} (PC={1:X4})", CdIoPorts[4], Cpu.PC); return CdIoPorts[4]; case 0x1805: // CD audio data Low - if ((Port1803 & 0x2) == 0) + if ((CdIoPorts[3] & 0x2) == 0) sample = CDAudio.VolumeLeft; else sample = CDAudio.VolumeRight; return (byte) sample; case 0x1806: // CD audio data High - if ((Port1803 & 0x2) == 0) + if ((CdIoPorts[3] & 0x2) == 0) sample = CDAudio.VolumeLeft; else sample = CDAudio.VolumeRight; return (byte) (sample >> 8); - // wow, nothing ever reads 1807 yet - case 0x1808: // Auto Handshake Data Input returnValue = SCSI.DataBits; if (SCSI.REQ && SCSI.IO && !SCSI.CD) @@ -258,7 +225,6 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx return ADPCM.Port180A; case 0x180B: // ADPCM Data Transfer Control - //Log.Error("CD", "Read ADPCM Data Transfer Control"); return ADPCM.Port180B; case 0x180C: // ADPCM Status @@ -271,17 +237,14 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx returnValue |= 0x04; if (ADPCM.AdpcmBusyReading) returnValue |= 0x80; - //Log.Error("CD", "Read ADPCM Status {0:X2}", returnValue); return returnValue; case 0x180D: // ADPCM Play Control - //Log.Error("CD", "Read ADPCM Play Control"); return CdIoPorts[0x0D]; case 0x180F: // Audio Fade Timer - //Log.Error("CD", "Read: 180F {0:X2} (PC={1:X4})", CdIoPorts[0xF], Cpu.PC); return CdIoPorts[0x0F]; // These are some retarded version check @@ -300,7 +263,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx public void RefreshIRQ2() { - int mask = CdIoPorts[2] & Port1803 & 0x7C; + int mask = CdIoPorts[2] & CdIoPorts[3] & 0x7C; Cpu.IRQ2Assert = (mask != 0); } } diff --git a/BizHawk.Emulation/Sound/CDAudio.cs b/BizHawk.Emulation/Sound/CDAudio.cs index 48ef25f629..7bcd936f6d 100644 --- a/BizHawk.Emulation/Sound/CDAudio.cs +++ b/BizHawk.Emulation/Sound/CDAudio.cs @@ -261,6 +261,10 @@ namespace BizHawk.Emulation.Sound CurrentSector = int.Parse(args[1]); else if (args[0] == "SectorOffset") SectorOffset = int.Parse(args[1]); + else if (args[0] == "FadeOutOverFrames") + FadeOutOverFrames = int.Parse(args[1]); + else if (args[0] == "FadeOutFramesRemaining") + FadeOutFramesRemaining = int.Parse(args[1]); else Console.WriteLine("Skipping unrecognized identifier " + args[0]);