public void ImportCodes(string AFileName, bool AQuiet = false) { if (File.Exists(AFileName)) { XmlDocument lXml = new XmlDocument(); XmlNodeList lCodes = null; XmlNode lCodeNode = null; XmlAttribute lAttribute = null; lXml.Load(AFileName); lCodes = lXml.SelectNodes("//genie/.."); FModified = true; XmlNode lDeleteNode = GameNode.FirstChild; while (lDeleteNode != null) { GameNode.RemoveChild(GameNode.FirstChild); lDeleteNode = GameNode.FirstChild; } GameCodes.Clear(); string lGameFileName = Path.Combine(Path.Combine(Path.Combine(Program.BaseDirectoryExternal, "games"), FGame.Code), FGame.Code + ".nes"); foreach (XmlNode lCurCode in lCodes) { NesFile lGame = new NesFile(lGameFileName); try { lGame.PRG = GameGeniePatcherNes.Patch(lGame.PRG, lCurCode["genie"].InnerText); lCodeNode = FXml.CreateElement("gamegenie"); GameNode.AppendChild(lCodeNode); lAttribute = FXml.CreateAttribute("code"); lAttribute.Value = lCurCode["genie"].InnerText.ToUpper().Trim(); lCodeNode.Attributes.Append(lAttribute); lAttribute = FXml.CreateAttribute("description"); lAttribute.Value = lCurCode["description"].InnerText; lCodeNode.Attributes.Append(lAttribute); GameCodes.Add(new GameGenieCode(lCurCode["genie"].InnerText.ToUpper().Trim(), lCurCode["description"].InnerText)); } catch (GameGenieFormatException) { if (!AQuiet) { Tasks.MessageForm.Show(Resources.Error, string.Format(Resources.GameGenieFormatError, lCurCode["genie"].InnerText, FGame.Name), Resources.sign_error); } } catch (GameGenieNotFoundException) { if (!AQuiet) { Tasks.MessageForm.Show(Resources.Error, string.Format(Resources.GameGenieNotFound, lCurCode["genie"].InnerText, FGame.Name), Resources.sign_error); } } } } }
public void ApplyGameGenie() { if (!string.IsNullOrEmpty(GameGenie)) { bool wasCompressed = DecompressPossible().Length > 0; if (wasCompressed) { Decompress(); } var codes = GameGenie.Split(new char[] { ',', '\t', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries); var nesFiles = Directory.GetFiles(this.basePath, "*.nes", SearchOption.TopDirectoryOnly); foreach (var f in nesFiles) { var nesFile = new NesFile(f); foreach (var code in codes) { nesFile.PRG = GameGeniePatcherNes.Patch(nesFile.PRG, code.Trim()); } nesFile.Save(f); } if (wasCompressed) { Compress(); } } }
private void buttonOk_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(textBoxCode.Text.Trim())) { MessageBox.Show(this, Resources.GGCodeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (FGame != null) { NesFile lGame = new NesFile(FGame.NesPath); try { lGame.PRG = GameGenie.Patch(lGame.PRG, textBoxCode.Text); } catch (GameGenieFormatException) { MessageBox.Show(this, string.Format(Resources.GameGenieFormatError, textBoxCode.Text, FGame.Name), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } catch (GameGenieNotFoundException) { MessageBox.Show(this, string.Format(Resources.GameGenieNotFound, textBoxCode.Text, FGame.Name), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } if (string.IsNullOrEmpty(textBoxDescription.Text.Trim())) { MessageBox.Show(this, Resources.GGDescriptionEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } textBoxCode.Text = textBoxCode.Text.ToUpper().Trim(); DialogResult = System.Windows.Forms.DialogResult.OK; }
public NesGame(string gamesDirectory, string nesFileName) { var nesFile = new NesFile(nesFileName); nesFile.CorrectRom(); if (!supportedMappers.Contains(nesFile.Mapper)) { throw new Exception(string.Format(Resources.MapperNotSupported, Path.GetFileName(nesFileName), nesFile.Mapper)); } Code = string.Format("CLV-H-{0}{1}{2}{3}{4}", (char)('A' + (nesFile.CRC32 % 26)), (char)('A' + (nesFile.CRC32 >> 5) % 26), (char)('A' + ((nesFile.CRC32 >> 10) % 26)), (char)('A' + ((nesFile.CRC32 >> 15) % 26)), (char)('A' + ((nesFile.CRC32 >> 20) % 26))); GamePath = Path.Combine(gamesDirectory, Code); ConfigPath = Path.Combine(GamePath, Code + ".desktop"); Directory.CreateDirectory(GamePath); NesPath = Path.Combine(GamePath, Code + ".nes"); nesFile.Save(NesPath); Name = Path.GetFileNameWithoutExtension(nesFileName); Name = Regex.Replace(Name, @" ?\(.*?\)", string.Empty).Trim(); Name = Regex.Replace(Name, @" ?\[.*?\]", string.Empty).Trim(); Name = Name.Replace(", The", "").Replace("_", " ").Replace(" ", " ").Trim(); Players = 1; ReleaseDate = "1983-07-15"; Publisher = "Nintendo"; Args = "--guest-overscan-dimensions 0,0,9,3 --initial-fadein-durations 3,2 --volume 75 --enable-armet"; IconPath = Path.Combine(GamePath, Code + ".png"); SmallIconPath = Path.Combine(GamePath, Code + "_small.png"); SetImage(Resources.blank); Save(); }
public NesGame(string gamesDirectory, string nesFileName, bool ignoreMapper = false) { if (!Path.GetExtension(nesFileName).ToLower().Equals(".fds")) { var nesFile = new NesFile(nesFileName); nesFile.CorrectRom(); if (!supportedMappers.Contains(nesFile.Mapper) && !ignoreMapper) { throw new UnsupportedMapperException(nesFile); } var crc32 = nesFile.CRC32; Code = string.Format("CLV-H-{0}{1}{2}{3}{4}", (char)('A' + (crc32 % 26)), (char)('A' + (crc32 >> 5) % 26), (char)('A' + ((crc32 >> 10) % 26)), (char)('A' + ((crc32 >> 15) % 26)), (char)('A' + ((crc32 >> 20) % 26))); GamePath = Path.Combine(gamesDirectory, Code); ConfigPath = Path.Combine(GamePath, Code + ".desktop"); Directory.CreateDirectory(GamePath); NesPath = Path.Combine(GamePath, Code + ".nes"); nesFile.Save(NesPath); } else { var fdsData = File.ReadAllBytes(nesFileName); var crc32 = CRC32(fdsData); Code = string.Format("CLV-H-{0}{1}{2}{3}{4}", (char)('A' + (crc32 % 26)), (char)('A' + (crc32 >> 5) % 26), (char)('A' + ((crc32 >> 10) % 26)), (char)('A' + ((crc32 >> 15) % 26)), (char)('A' + ((crc32 >> 20) % 26))); GamePath = Path.Combine(gamesDirectory, Code); ConfigPath = Path.Combine(GamePath, Code + ".desktop"); Directory.CreateDirectory(GamePath); NesPath = Path.Combine(GamePath, Code + ".nes"); File.WriteAllBytes(NesPath, fdsData); } Name = Path.GetFileNameWithoutExtension(nesFileName); Name = Regex.Replace(Name, @" ?\(.*?\)", string.Empty).Trim(); Name = Regex.Replace(Name, @" ?\[.*?\]", string.Empty).Trim(); Name = Name.Replace(", The", "").Replace("_", " ").Replace(" ", " ").Trim(); Players = 1; ReleaseDate = "1983-07-15"; Publisher = "Nintendo"; Args = "--guest-overscan-dimensions 0,0,9,3 --initial-fadein-durations 3,2 --volume 75 --enable-armet"; IconPath = Path.Combine(GamePath, Code + ".png"); SmallIconPath = Path.Combine(GamePath, Code + "_small.png"); SetImage(Resources.blank); Save(); }
public void ApplyGameGenie() { if (!string.IsNullOrEmpty(GameGenie)) { var codes = GameGenie.Split(new char[] { ',', '\t', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries); var nesFile = new NesFile(NesPath); foreach (var code in codes) { nesFile.PRG = GameGeniePatcher.Patch(nesFile.PRG, code.Trim()); } nesFile.Save(NesPath); } }
public Computer(NesFile file, TextLogger logger) { if (file.Version != 0) { throw new System.Exception(string.Format("Version {0} not implemented", file.Version)); } if (file.BatteryRAM) { throw new System.Exception("Battery backed RAM not implemented"); } if (file.HasTrainer) { throw new System.Exception("Trainer not implemented"); } switch (file.Mapper) { case 0x00: // NROM //CPU $6000 -$7FFF: Family Basic only: PRG RAM, mirrored as necessary to fill entire 8 KiB window, write protectable with an external switch //CPU $8000 -$BFFF: First 16 KB of ROM. //CPU $C000 -$FFFF: Last 16 KB of ROM(NROM - 256) or mirror of $8000 -$BFFF(NROM - 128). break; default: throw new System.Exception(string.Format("Mapper {0} not implemented", file.Mapper)); } if (file.VSUnisystem) { throw new System.Exception("VSUnisystem not implemented"); } if (file.PlayChoice10) { throw new System.Exception("PlayChoice10 not implemented"); } PpuMap = new PpuMap(new Ram(0x2000), new Rom(file.chr_rom), file.VRAMLayout); Ppu = new Ppu(PpuMap); Ppu.Logger = logger; CpuMap = new CpuMap(new Ram(0x0800), new Rom(file.prg_rom), Ppu); Cpu = new Cpu(CpuMap); Cpu.Logger = logger; }
public Computer(NesFile file, TextLogger logger) { if (file.Version != 0) { throw new System.Exception(string.Format("Version {0} not implemented", file.Version)); } if(file.BatteryRAM) { throw new System.Exception("Battery backed RAM not implemented"); } if (file.HasTrainer) { throw new System.Exception("Trainer not implemented"); } switch (file.Mapper) { case 0x00: // NROM //CPU $6000 -$7FFF: Family Basic only: PRG RAM, mirrored as necessary to fill entire 8 KiB window, write protectable with an external switch //CPU $8000 -$BFFF: First 16 KB of ROM. //CPU $C000 -$FFFF: Last 16 KB of ROM(NROM - 256) or mirror of $8000 -$BFFF(NROM - 128). break; default: throw new System.Exception(string.Format("Mapper {0} not implemented", file.Mapper)); } if (file.VSUnisystem) { throw new System.Exception("VSUnisystem not implemented"); } if (file.PlayChoice10) { throw new System.Exception("PlayChoice10 not implemented"); } PpuMap = new PpuMap(new Ram(0x2000), new Rom(file.chr_rom), file.VRAMLayout); Ppu = new Ppu(PpuMap); Ppu.Logger = logger; CpuMap = new CpuMap(new Ram(0x0800), new Rom(file.prg_rom), Ppu); Cpu = new Cpu(CpuMap); Cpu.Logger = logger; }
private async void InitializeComponent() { // TODO: iOS does not support dynamically loading assemblies // so we must refer to this resource DLL statically. For // now I am doing that here. But we need a better solution!! var theme = new Avalonia.Themes.Default.DefaultTheme(); theme.TryGetResource("Button", out _); AvaloniaXamlLoader.Load(this); var file = await NesFile.FromStream(File.OpenRead("lj65.nes")).ConfigureAwait(false); _nesSystem.Cartridge.InsertNesFile(file); _nesSystem.PowerUp(); }
public void ApplyGameGenie() { if (!string.IsNullOrEmpty(GameGenie)) { var codes = GameGenie.Split(new char[] { ',', '\t', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries); var nesFiles = Directory.GetFiles(this.GamePath, "*.nes", SearchOption.TopDirectoryOnly); foreach (var f in nesFiles) { var nesFile = new NesFile(f); foreach (var code in codes) { nesFile.PRG = GameGeniePatcherNes.Patch(nesFile.PRG, code.Trim()); } nesFile.Save(f); } } }
public NesDebugger() { InitializeComponent(); if (File.Exists("nes.log")) { File.Delete("nes.log"); } File.Create("nes.log"); string src_file = "..\\..\\..\\..\\NES Test (USA).nes"; NesFile file = new NesFile(src_file); m_nes = new Computer(file, log); update(); textBoxDisassembly.Text = m_nes.Cpu.Disassemble(0x8000); }
public bool ApplyGameGenie(out byte[] gameFileData) { gameFileData = null; if (!string.IsNullOrEmpty(GameGenie)) { var codes = GameGenie.Split(new char[] { ',', '\t', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries); string gameFilePath = GameFilePath; if (gameFilePath != null) { byte[] data = GameFileData; if (data != null) { var nesFile = new NesFile(data); foreach (var code in codes) { nesFile.PRG = GameGeniePatcherNes.Patch(nesFile.PRG, code.Trim()); } gameFileData = nesFile.GetRaw(); return(true); } } } return(false); }
public NesGame(string gamesDirectory, string nesFileName, bool?ignoreMapper, ref bool?needPatch, NeedPatchDelegate needPatchCallback, Form parentForm = null, byte[] rawRomData = null) { uint crc32; if (!Path.GetExtension(nesFileName).ToLower().Equals(".fds")) { NesFile nesFile; if (rawRomData != null) { nesFile = new NesFile(rawRomData); } else { nesFile = new NesFile(nesFileName); } nesFile.CorrectRom(); crc32 = nesFile.CRC32; Code = GenerateCode(crc32); GamePath = Path.Combine(gamesDirectory, Code); Args = DefaultArgs; Type = GameType.Cartridge; NesPath = Path.Combine(GamePath, Code + ".nes"); var patchesDirectory = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "patches"); Directory.CreateDirectory(patchesDirectory); Directory.CreateDirectory(GamePath); var patches = Directory.GetFiles(patchesDirectory, string.Format("{0:X8}*.ips", crc32), SearchOption.AllDirectories); if (patches.Length > 0 && needPatch != false) { if (needPatch == true || ((needPatchCallback != null) && needPatchCallback(parentForm, Path.GetFileName(nesFileName)))) /*MessageBox.Show(parentForm, string.Format(Resources.PatchQ, Path.GetFileName(nesFileName)), Resources.PatchAvailable, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes*/ { needPatch = true; var patch = patches[0]; if (rawRomData == null) { rawRomData = File.ReadAllBytes(nesFileName); } Debug.WriteLine(string.Format("Patching {0}", nesFileName)); IpsPatcher.Patch(patch, ref rawRomData); nesFile = new NesFile(rawRomData); } else { needPatch = false; } } if (nesFile.Mapper == 71) { nesFile.Mapper = 2; // games by Codemasters/Camerica - this is UNROM clone. One exception - Fire Hawk } if (nesFile.Mapper == 88) { nesFile.Mapper = 4; // Compatible with MMC3... sometimes } if (nesFile.Mapper == 95) { nesFile.Mapper = 4; // Compatible with MMC3 } if (nesFile.Mapper == 206) { nesFile.Mapper = 4; // Compatible with MMC3 } if (!supportedMappers.Contains(nesFile.Mapper) && (ignoreMapper != true)) { Directory.Delete(GamePath, true); if (ignoreMapper != false) { throw new UnsupportedMapperException(nesFile); } else { Debug.WriteLine(string.Format("Game {0} has mapper #{1}, skipped", nesFileName, nesFile.Mapper)); return; } } if ((nesFile.Mirroring == NesFile.MirroringType.FourScreenVram) && (ignoreMapper != true)) { Directory.Delete(GamePath, true); if (ignoreMapper != false) { throw new UnsupportedFourScreenException(nesFile); } else { Debug.WriteLine(string.Format("Game {0} has four-screen mirroring, skipped", nesFileName, nesFile.Mapper)); return; } } // TODO: Make trainer check. I think that NES Mini doesn't support it. ConfigPath = Path.Combine(GamePath, Code + ".desktop"); nesFile.Save(NesPath); } else { byte[] fdsData; if (rawRomData != null) { fdsData = rawRomData; } else { fdsData = File.ReadAllBytes(nesFileName); } if (Encoding.ASCII.GetString(fdsData, 0, 3) == "FDS") // header? cut it! { var fdsDataNoHeader = new byte[fdsData.Length - 0x10]; Array.Copy(fdsData, 0x10, fdsDataNoHeader, 0, fdsDataNoHeader.Length); fdsData = fdsDataNoHeader; } crc32 = CRC32(fdsData); Code = GenerateCode(crc32); GamePath = Path.Combine(gamesDirectory, Code); Args = DefaultArgs + " --fds-auto-disk-side-switch-on-keypress"; // seems like need to make it default Type = GameType.FDS; Directory.CreateDirectory(GamePath); ConfigPath = Path.Combine(GamePath, Code + ".desktop"); NesPath = Path.Combine(GamePath, Code + ".fds"); File.WriteAllBytes(NesPath, fdsData); } Name = Path.GetFileNameWithoutExtension(nesFileName); Players = 1; ReleaseDate = DefaultReleaseDate; Publisher = DefaultPublisher; if (nesFileName.Contains("(J)")) { Region = "Japan"; } TryAutofill(crc32); Name = Regex.Replace(Name, @" ?\(.*?\)", string.Empty).Trim(); Name = Regex.Replace(Name, @" ?\[.*?\]", string.Empty).Trim(); Name = Name.Replace("_", " ").Replace(" ", " ") /*.Replace(", The", "")*/.Trim(); IconPath = Path.Combine(GamePath, Code + ".png"); SmallIconPath = Path.Combine(GamePath, Code + "_small.png"); GameGeniePath = Path.Combine(GamePath, GameGenieFileName); // Trying to find cover file Image cover = null; if (!string.IsNullOrEmpty(nesFileName)) { var imagePath = Path.Combine(Path.GetDirectoryName(nesFileName), Path.GetFileNameWithoutExtension(nesFileName) + ".png"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } imagePath = Path.Combine(Path.GetDirectoryName(nesFileName), Path.GetFileNameWithoutExtension(nesFileName) + ".jpg"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } var artDirectory = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "art"); Directory.CreateDirectory(artDirectory); imagePath = Path.Combine(artDirectory, Path.GetFileNameWithoutExtension(nesFileName) + ".png"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } imagePath = Path.Combine(artDirectory, Path.GetFileNameWithoutExtension(nesFileName) + ".jpg"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } var covers = Directory.GetFiles(artDirectory, string.Format("{0:X8}*.*", crc32), SearchOption.AllDirectories); if (covers.Length > 0) { cover = LoadBitmap(covers[0]); } } if (cover != null) { SetImage(cover, ConfigIni.EightBitPngCompression); } else { SetImage(null, ConfigIni.EightBitPngCompression); } Save(); }
public static NesGame Import(string nesFileName, bool?ignoreMapper, ref bool?needPatch, NeedPatchDelegate needPatchCallback, Form parentForm = null, byte[] rawRomData = null) { NesFile nesFile; if (rawRomData != null) { nesFile = new NesFile(rawRomData); } else { nesFile = new NesFile(nesFileName); } nesFile.CorrectRom(); var crc32 = nesFile.CRC32; var code = GenerateCode(crc32, prefixCode); var gamePath = Path.Combine(GamesDirectory, code); var nesPath = Path.Combine(gamePath, code + ".nes"); var patchesDirectory = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "patches"); Directory.CreateDirectory(patchesDirectory); Directory.CreateDirectory(gamePath); var patches = Directory.GetFiles(patchesDirectory, string.Format("{0:X8}*.ips", crc32), SearchOption.AllDirectories); if (patches.Length > 0 && needPatch != false) { if (needPatch == true || ((needPatchCallback != null) && needPatchCallback(parentForm, Path.GetFileName(nesFileName)))) /*MessageBox.Show(parentForm, string.Format(Resources.PatchQ, Path.GetFileName(nesFileName)), Resources.PatchAvailable, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes*/ { needPatch = true; var patch = patches[0]; if (rawRomData == null) { rawRomData = File.ReadAllBytes(nesFileName); } Debug.WriteLine(string.Format("Patching {0}", nesFileName)); IpsPatcher.Patch(patch, ref rawRomData); nesFile = new NesFile(rawRomData); } else { needPatch = false; } } if (nesFile.Mapper == 71) { nesFile.Mapper = 2; // games by Codemasters/Camerica - this is UNROM clone. One exception - Fire Hawk } if (nesFile.Mapper == 88) { nesFile.Mapper = 4; // Compatible with MMC3... sometimes } if (nesFile.Mapper == 95) { nesFile.Mapper = 4; // Compatible with MMC3 } if (nesFile.Mapper == 206) { nesFile.Mapper = 4; // Compatible with MMC3 } if (!supportedMappers.Contains(nesFile.Mapper) && (ignoreMapper != true)) { Directory.Delete(gamePath, true); if (ignoreMapper != false) { throw new UnsupportedMapperException(nesFile); } else { Debug.WriteLine(string.Format("Game {0} has mapper #{1}, skipped", nesFileName, nesFile.Mapper)); return(null); } } if ((nesFile.Mirroring == NesFile.MirroringType.FourScreenVram) && (ignoreMapper != true)) { Directory.Delete(gamePath, true); if (ignoreMapper != false) { throw new UnsupportedFourScreenException(nesFile); } else { Debug.WriteLine(string.Format("Game {0} has four-screen mirroring, skipped", nesFileName, nesFile.Mapper)); return(null); } } // TODO: Make trainer check. I think that NES Mini doesn't support it. nesFile.Save(nesPath); var game = new NesGame(gamePath, true); game.Name = Path.GetFileNameWithoutExtension(nesFileName); if (game.Name.Contains("(J)")) { game.region = "Japan"; } game.TryAutofill(crc32); game.Name = Regex.Replace(game.Name, @" ?\(.*?\)", string.Empty).Trim(); game.Name = Regex.Replace(game.Name, @" ?\[.*?\]", string.Empty).Trim(); game.Name = game.Name.Replace("_", " ").Replace(" ", " ") /*.Replace(", The", "")*/.Trim(); // Trying to find cover file Image cover = null; if (!string.IsNullOrEmpty(nesFileName)) { var imagePath = Path.Combine(Path.GetDirectoryName(nesFileName), Path.GetFileNameWithoutExtension(nesFileName) + ".png"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } imagePath = Path.Combine(Path.GetDirectoryName(nesFileName), Path.GetFileNameWithoutExtension(nesFileName) + ".jpg"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } var artDirectory = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "art"); Directory.CreateDirectory(artDirectory); imagePath = Path.Combine(artDirectory, Path.GetFileNameWithoutExtension(nesFileName) + ".png"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } imagePath = Path.Combine(artDirectory, Path.GetFileNameWithoutExtension(nesFileName) + ".jpg"); if (File.Exists(imagePath)) { cover = LoadBitmap(imagePath); } var covers = Directory.GetFiles(artDirectory, string.Format("{0:X8}*.*", crc32), SearchOption.AllDirectories); if (covers.Length > 0) { cover = LoadBitmap(covers[0]); } } if (cover == null) { if (game.region == "Japan") { cover = Resources.blank_jp; } else { cover = Resources.blank; } } game.Image = cover; game.Args = DefaultArgs; game.Save(); return(game); }
public static bool Patch(string inputFileName, ref byte[] rawRomData, ref char prefix, ref string application, ref string outputFileName, ref string args, ref Image cover, ref byte saveCount, ref uint crc32) { // Try to patch before mapper check, maybe it will patch mapper var patched = FindPatch(ref rawRomData, inputFileName, crc32); NesFile nesFile; try { nesFile = new NesFile(rawRomData); } catch { application = "/bin/nes"; return(true); } crc32 = nesFile.CRC32; // Also search for patch using internal CRC32 if (!patched) { if (FindPatch(ref rawRomData, inputFileName, crc32)) { nesFile = new NesFile(rawRomData); } } nesFile.CorrectRom(); if (ConfigIni.ConsoleType == MainForm.ConsoleType.NES || ConfigIni.ConsoleType == MainForm.ConsoleType.Famicom) { application = "/bin/clover-kachikachi-wr"; args = DefaultArgs; } else { application = "/bin/nes"; } //if (nesFile.Mapper == 71) nesFile.Mapper = 2; // games by Codemasters/Camerica - this is UNROM clone. One exception - Fire Hawk //if (nesFile.Mapper == 88) nesFile.Mapper = 4; // Compatible with MMC3... sometimes //if (nesFile.Mapper == 95) nesFile.Mapper = 4; // Compatible with MMC3 //if (nesFile.Mapper == 206) nesFile.Mapper = 4; // Compatible with MMC3 if (!supportedMappers.Contains(nesFile.Mapper) && (ConfigIni.ConsoleType == MainForm.ConsoleType.NES || ConfigIni.ConsoleType == MainForm.ConsoleType.Famicom) && (IgnoreMapper != true)) { if (IgnoreMapper != false) { var r = WorkerForm.MessageBoxFromThread(ParentForm, string.Format(Resources.MapperNotSupported, System.IO.Path.GetFileName(inputFileName), nesFile.Mapper), Resources.AreYouSure, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, true); if (r == DialogResult.Abort) { IgnoreMapper = true; } if (r == DialogResult.Ignore) { return(false); } } else { return(false); } } if ((nesFile.Mirroring == NesFile.MirroringType.FourScreenVram) && (ConfigIni.ConsoleType == MainForm.ConsoleType.NES || ConfigIni.ConsoleType == MainForm.ConsoleType.Famicom) && (IgnoreMapper != true)) { var r = WorkerForm.MessageBoxFromThread(ParentForm, string.Format(Resources.FourScreenNotSupported, System.IO.Path.GetFileName(inputFileName)), Resources.AreYouSure, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, true); if (r == DialogResult.Abort) { IgnoreMapper = true; } if (r == DialogResult.No) { return(false); } } // TODO: Make trainer check. I think that the NES Mini doesn't support it. rawRomData = nesFile.GetRaw(); if (inputFileName.Contains("(J)")) { cover = Resources.blank_jp; } if (nesFile.Battery) { saveCount = 3; } return(true); }
public UnsupportedMapperException(NesFile nesFile) { ROM = nesFile; }
public Game(string fileName, string menuName = null, Dictionary <uint, GameFix> fixes = null) { // Separators if (fileName == "-") { MenuName = (string.IsNullOrWhiteSpace(menuName) || menuName == "-") ? "" : menuName; FileName = ""; Flags |= GameFlags.Separator; } else { Console.WriteLine("Loading {0}...", Path.GetFileName(fileName)); FileName = fileName; if (string.IsNullOrWhiteSpace(menuName)) { // Menu name based on filename MenuName = Regex.Replace(Path.GetFileNameWithoutExtension(fileName), @"( ?\[.*?\])|( \(.\))", string.Empty).Replace("_", " ").ToUpper().Replace(", THE", "").Trim(); } else { MenuName = menuName.Trim(); if (MenuName == "?") { Flags |= GameFlags.Hidden; } } // Strip long names if (MenuName.Length > 28) { MenuName = MenuName.Substring(0, 25).Trim() + "..."; } uint crc; try { var nesFile = new NesFile(fileName); var fixResult = nesFile.CorrectRom(); if (fixResult != 0) { Console.WriteLine(" Invalid header. Fix: " + fixResult); } PRG = nesFile.PRG; PrgSize = (uint)nesFile.PRG.Count(); CHR = nesFile.CHR; ChrSize = (uint)nesFile.CHR.Count(); Battery = nesFile.Battery; Mapper = $"{nesFile.Mapper:D3}" + ((nesFile.Submapper > 0) ? $":{nesFile.Submapper}" : ""); Mirroring = nesFile.Mirroring; ContainerType = NesContainerType.iNES; if (nesFile.Trainer != null && nesFile.Trainer.Count() > 0) { throw new NotImplementedException(string.Format("{0} - trained games are not supported yet", Path.GetFileName(fileName))); } if (nesFile.Version == NesFile.iNesVersion.NES20) { PrgRamSize = nesFile.PrgRamSize + nesFile.PrgNvRamSize; ChrRamSize = nesFile.ChrRamSize + nesFile.ChrNvRamSize; } crc = nesFile.CalculateCRC32(); } catch (InvalidDataException) { var unifFile = new UnifFile(fileName); PRG = unifFile.Fields.Where(k => k.Key.StartsWith("PRG")).OrderBy(k => k.Key).SelectMany(i => i.Value); PrgSize = (uint)PRG.Count(); CHR = unifFile.Fields.Where(k => k.Key.StartsWith("CHR")).OrderBy(k => k.Key).SelectMany(i => i.Value); ChrSize = (uint)CHR.Count(); Battery = unifFile.Battery; var mapper = unifFile.Mapper; if (mapper.StartsWith("NES-") || mapper.StartsWith("UNL-") || mapper.StartsWith("HVC-") || mapper.StartsWith("BTL-") || mapper.StartsWith("BMC-")) { mapper = mapper.Substring(4); } Mapper = mapper; Mirroring = unifFile.Mirroring; ContainerType = NesContainerType.UNIF; crc = unifFile.CalculateCRC32(); } // Check for fixes database if (fixes != null) { GameFix fix = null; if (fixes.TryGetValue(crc, out fix)) { if (fix.PrgRamSize.HasValue) { PrgRamSize = fix.PrgRamSize * 1024; } if (fix.ChrRamSize.HasValue) { ChrRamSize = fix.ChrRamSize * 1024; } if (fix.Battery.HasValue) { Battery = fix.Battery.Value; } if (fix.WillNotWorkOnPal) { Flags |= GameFlags.WillNotWorkOnPal; } if (fix.WillNotWorkOnNtsc) { Flags |= GameFlags.WillNotWorkOnNtsc; } if (fix.WillNotWorkOnDendy) { Flags |= GameFlags.WillNotWorkOnDendy; } if (fix.WillNotWorkOnNewFamiclone) { Flags |= GameFlags.WillNotWorkOnNewFamiclone; } } } // External NTRAM is not supported on new famiclones if (Mirroring == NesFile.MirroringType.FourScreenVram) { Flags |= GameFlags.WillNotWorkOnNewFamiclone; } // Check for round sizes if (PrgSize > 0) { uint roundSize = 1; while (roundSize < PrgSize) { roundSize <<= 1; } if (roundSize > PrgSize) { var newPrg = new byte[roundSize]; for (uint i = PrgSize; i < roundSize; i++) { newPrg[i] = 0xFF; } Array.Copy(PRG.ToArray(), newPrg, PrgSize); PRG = newPrg; PrgSize = roundSize; } } if (ChrSize > 0) { uint roundSize = 1; while (roundSize < ChrSize) { roundSize <<= 1; } if (roundSize > ChrSize) { var newChr = new byte[roundSize]; for (uint i = ChrSize; i < roundSize; i++) { newChr[i] = 0xFF; } Array.Copy(CHR.ToArray(), newChr, ChrSize); CHR = newChr; ChrSize = roundSize; } } } }
public UnsupportedFourScreenException(NesFile nesFile) { ROM = nesFile; }
public static bool Patch(string inputFileName, ref byte[] rawRomData, ref char prefix, ref string application, ref string outputFileName, ref string args, ref Image cover, ref byte saveCount, ref uint crc32) { // Try to patch before mapper check, maybe it will patch mapper var patched = FindPatch(ref rawRomData, inputFileName, crc32); NesFile nesFile; try { nesFile = new NesFile(rawRomData); } catch { return(true); } crc32 = nesFile.CRC32; // Also search for patch using internal CRC32 if (!patched) { if (FindPatch(ref rawRomData, inputFileName, crc32)) { nesFile = new NesFile(rawRomData); } } nesFile.CorrectRom(); application = "/bin/clover-kachikachi-wr"; args = DefaultArgs; if (!supportedMappers.Contains(nesFile.Mapper) && (IgnoreMapper != true)) { if (IgnoreMapper != false) { var result = Tasks.MessageForm.Show(ParentForm, Resources.AreYouSure, string.Format(Resources.MapperNotSupported, Path.GetFileName(inputFileName), nesFile.Mapper), Resources.sign_warning, new Tasks.MessageForm.Button[] { Tasks.MessageForm.Button.YesToAll, Tasks.MessageForm.Button.Yes, Tasks.MessageForm.Button.No }, Tasks.MessageForm.DefaultButton.Button2); if (result == Tasks.MessageForm.Button.YesToAll) { IgnoreMapper = true; } if (result == Tasks.MessageForm.Button.No) { return(false); } } else { return(false); } } if ((nesFile.Mirroring == NesFile.MirroringType.FourScreenVram) && (IgnoreMapper != true)) { var result = Tasks.MessageForm.Show(ParentForm, Resources.AreYouSure, string.Format(Resources.FourScreenNotSupported, Path.GetFileName(inputFileName)), Resources.sign_warning, new Tasks.MessageForm.Button[] { Tasks.MessageForm.Button.YesToAll, Tasks.MessageForm.Button.Yes, Tasks.MessageForm.Button.No }, Tasks.MessageForm.DefaultButton.Button2); if (result == Tasks.MessageForm.Button.YesToAll) { IgnoreMapper = true; } if (result == Tasks.MessageForm.Button.No) { return(false); } } // TODO: Make trainer check. I think that the NES Mini doesn't support it. rawRomData = nesFile.GetRaw(); if (inputFileName.Contains("(J)")) { cover = Resources.blank_jp; } if (nesFile.Battery) { saveCount = 3; } return(true); }
/// <summary> /// Fix ROM header using database of popular incorrect ROMs /// </summary> /// <returns>Flags showing what has been changed</returns> public static NesFixType CorrectRom(this NesFile nes) { NesFixType fixType = NesFixType.NoFix; var crc32 = nes.CalculateCRC32(); for (int i = 0; i < correct.GetLength(0); i++) { if (crc32 == correct[i, 0]) { var mapper = correct[i, 1] & 0x3FF; var mask = ((correct[i, 1] & 0x1000) != 0) ? 0xFFF : 0xFF; var mirroring = correct[i, 2]; if ((correct[i, 1] >= 0) && (mapper >= 0) && (nes.Mapper != (mapper & mask))) { // invalid mapper nes.Mapper = (ushort)(mapper & mask); fixType |= NesFixType.Mapper; } if (mirroring >= 0) { if (mirroring == 8 && nes.Mirroring == NesFile.MirroringType.FourScreenVram) { // no four-screen nes.Mirroring = NesFile.MirroringType.Horizontal; fixType |= NesFixType.Mirroring; } NesFile.MirroringType needMirroring = NesFile.MirroringType.Unknown; switch (mirroring) { case 0: needMirroring = NesFile.MirroringType.Horizontal; break; case 1: needMirroring = NesFile.MirroringType.Vertical; break; case 2: needMirroring = NesFile.MirroringType.FourScreenVram; break; } if (needMirroring != NesFile.MirroringType.Unknown && needMirroring != nes.Mirroring) { nes.Mirroring = needMirroring; fixType |= NesFixType.Mirroring; } } if ((correct[i, 1] >= 0) && ((correct[i, 1] & 0x800) != 0) && (nes.CHR.Count() > 0)) { // no CHR nes.CHR = Array.Empty <byte>(); fixType |= NesFixType.NoChr; } } } var md5 = nes.CalculateMD5(); ulong partialmd5 = 0; for (int x = 0; x < 8; x++) { partialmd5 |= (ulong)md5[15 - x] << (x * 8); } // maybe this games uses battery saves? foreach (var sav in savie) { if (!nes.Battery && sav == partialmd5) { nes.Battery = true; fixType |= NesFixType.Battery; } } return(fixType); }
static int Main(string[] args) { var mappers = new Dictionary<byte, MapperInfo>(); mappers[0] = new MapperInfo { MapperReg = 0x00, PrgMode = 0, ChrMode = 0, WramEnabled = false }; // NROM mappers[2] = new MapperInfo { MapperReg = 0x01, PrgMode = 0, ChrMode = 0, WramEnabled = false }; // UxROM mappers[71] = new MapperInfo { MapperReg = 0x01, PrgMode = 0, ChrMode = 0, WramEnabled = false, MapperFlags = 1 }; // Codemasters mappers[3] = new MapperInfo { MapperReg = 0x02, PrgMode = 0, ChrMode = 0, WramEnabled = false }; // CNROM mappers[78] = new MapperInfo { MapperReg = 0x03, PrgMode = 0, ChrMode = 0, WramEnabled = false }; // Holy Diver mappers[97] = new MapperInfo { MapperReg = 0x04, PrgMode = 1, ChrMode = 0, WramEnabled = false }; // Irem's TAM-S1 mappers[93] = new MapperInfo { MapperReg = 0x05, PrgMode = 0, ChrMode = 0, WramEnabled = false }; // Sunsoft-2 mappers[163] = new MapperInfo { MapperReg = 0x06, PrgMode = 7, ChrMode = 0, WramEnabled = true }; // Mapper 163 (Final Fantasy & chinese shit) mappers[18] = new MapperInfo { MapperReg = 0x07, PrgMode = 4, ChrMode = 7, WramEnabled = false }; // Jaleco SS88006 mappers[7] = new MapperInfo { MapperReg = 0x08, PrgMode = 7, ChrMode = 0, WramEnabled = false }; // AxROM mappers[241] = new MapperInfo { MapperReg = 0x08, PrgMode = 7, ChrMode = 0, WramEnabled = false, MapperFlags = 1 }; // BNROM - is it just AxROM clone whith fixed mirroring? Using flag. mappers[228] = new MapperInfo { MapperReg = 0x09, PrgMode = 7, ChrMode = 0, WramEnabled = false }; // Cheetahmen 2 mappers[11] = new MapperInfo { MapperReg = 0x0A, PrgMode = 7, ChrMode = 0, WramEnabled = false }; // Color Dreams mappers[66] = new MapperInfo { MapperReg = 0x0B, PrgMode = 7, ChrMode = 0, WramEnabled = false }; // GxROM mappers[87] = new MapperInfo { MapperReg = 0x0C, PrgMode = 0, ChrMode = 0, WramEnabled = false }; // Mapper #87 mappers[90] = new MapperInfo { MapperReg = 0x0D, PrgMode = 4, ChrMode = 7, WramEnabled = false }; // Mapper #90 mappers[65] = new MapperInfo { MapperReg = 0x0E, PrgMode = 4, ChrMode = 7, WramEnabled = false }; // Mapper #65 - Irem's H3001 mappers[5] = new MapperInfo { MapperReg = 0x0F, PrgMode = 4, ChrMode = 7, WramEnabled = true }; // MMC5 mappers[1] = new MapperInfo { MapperReg = 0x10, PrgMode = 0, ChrMode = 0, WramEnabled = true }; // MMC1 mappers[9] = new MapperInfo { MapperReg = 0x11, PrgMode = 4, ChrMode = 5, WramEnabled = true }; // MMC2 mappers[10] = new MapperInfo { MapperReg = 0x11, PrgMode = 0, ChrMode = 5, WramEnabled = true, MapperFlags = 1 }; // MMC4 mappers[152] = new MapperInfo { MapperReg = 0x12, PrgMode = 0, ChrMode = 0, WramEnabled = false }; // Mapper #152 mappers[73] = new MapperInfo { MapperReg = 0x13, PrgMode = 0, ChrMode = 0, WramEnabled = true }; // VRC3 mappers[4] = new MapperInfo { MapperReg = 0x14, PrgMode = 4, ChrMode = 2, WramEnabled = true }; // MMC3 mappers[118] = new MapperInfo { MapperReg = 0x14, PrgMode = 4, ChrMode = 2, WramEnabled = true, MapperFlags = 1 }; // TxSROM (MMC3 with flag) mappers[189] = new MapperInfo { MapperReg = 0x14, PrgMode = 7, ChrMode = 2, WramEnabled = false, MapperFlags = 2 }; // Mapper #189 mappers[112] = new MapperInfo { MapperReg = 0x15, PrgMode = 4, ChrMode = 2, WramEnabled = true }; // Mapper #112 mappers[4] = new MapperInfo { MapperReg = 0x14, PrgMode = 4, ChrMode = 2, WramEnabled = true }; // MMC3 mappers[33] = new MapperInfo { MapperReg = 0x16, PrgMode = 4, ChrMode = 2, WramEnabled = true }; // Taito mappers[48] = new MapperInfo { MapperReg = 0x16, PrgMode = 4, ChrMode = 2, WramEnabled = true, MapperFlags = 1 }; // Taito mappers[21] = new MapperInfo { MapperReg = 0x18, PrgMode = 4, ChrMode = 7, WramEnabled = true, MapperFlags = 1 }; // VRC4a mappers[22] = new MapperInfo { MapperReg = 0x18, PrgMode = 4, ChrMode = 7, WramEnabled = true, MapperFlags = 1 | 2 }; // VRC2a mappers[23] = new MapperInfo { MapperReg = 0x18, PrgMode = 4, ChrMode = 7, WramEnabled = true }; // VRC2b mappers[25] = new MapperInfo { MapperReg = 0x18, PrgMode = 4, ChrMode = 7, WramEnabled = true, MapperFlags = 1 }; // VRC2c, VRC4 mappers[69] = new MapperInfo { MapperReg = 0x19, PrgMode = 4, ChrMode = 7, WramEnabled = true }; // Sunsoft FME-7 mappers[32] = new MapperInfo { MapperReg = 0x1A, PrgMode = 4, ChrMode = 7, WramEnabled = true }; // Irem's G-101 //mappers[255] = new MapperInfo { MapperReg = 0x1F, PrgMode = 7, ChrMode = 0, WramEnabled = false }; // Temp/test Console.WriteLine("COOLGIRL UNIF combiner"); Console.WriteLine("(c) Cluster, 2016"); Console.WriteLine("http://clusterrr.com"); Console.WriteLine("*****@*****.**"); Console.WriteLine(); bool needShowHelp = false; string command = null; string optionGames = null; string optionAsm = null; string optionOffsets = null; string optionReport = null; string optionLoader = null; string optionUnif = null; string optionBin = null; string optionLanguage = "eng"; bool optionNoSort = false; int optionMaxSize = 256; if (args.Length > 0) command = args[0].ToLower(); if (command != "prepare" && command != "combine") { if (!string.IsNullOrEmpty(command)) Console.WriteLine("Unknown command: " + command); needShowHelp = true; } for (int i = 1; i < args.Length; i++) { string param = args[i]; while (param.StartsWith("-")) param = param.Substring(1); string value = i < args.Length - 1 ? args[i + 1] : ""; switch (param.ToLower()) { case "games": optionGames = value; i++; break; case "asm": optionAsm = value; i++; break; case "offsets": optionOffsets = value; i++; break; case "report": optionReport = value; i++; break; case "loader": optionLoader = value; i++; break; case "unif": optionUnif = value; i++; break; case "bin": optionBin = value; i++; break; case "nosort": optionNoSort = true; break; case "maxsize": optionMaxSize = int.Parse(value); i++; break; case "language": optionLanguage = value.ToLower(); i++; break; default: Console.WriteLine("Unknown parameter: " + param); needShowHelp = true; break; } } if (command == "prepare") { if (optionGames == null) { Console.WriteLine("Missing required parameter: --games"); needShowHelp = true; } if (optionAsm == null) { Console.WriteLine("Missing required parameter: --asm"); needShowHelp = true; } if (optionOffsets == null) { Console.WriteLine("Missing required parameter: --offsets"); needShowHelp = true; } } else if (command == "combine") { if (optionLoader == null) { Console.WriteLine("Missing required parameter: --loader"); needShowHelp = true; } if (optionUnif == null && optionBin == null) { Console.WriteLine("At least one parameter required: --unif or --bin"); needShowHelp = true; } } if (needShowHelp) { Console.WriteLine(""); Console.WriteLine("--- Usage ---"); Console.WriteLine("First step:"); Console.WriteLine(" CoolgirlCombiner.exe prepare --games <games.txt> --asm <games.asm> --offsets <offsets.xml> [--report <report.txt>] [--nosort] [--maxsize sizemb] [--language <language>]"); Console.WriteLine(" {0,-20}{1}", "games", "- input plain text file with list of ROM files"); Console.WriteLine(" {0,-20}{1}", "asm", "- output file for loader"); Console.WriteLine(" {0,-20}{1}", "offsets", "- output file with offsets for every game"); Console.WriteLine(" {0,-20}{1}", "report", "- output report file (human readable)"); Console.WriteLine(" {0,-20}{1}", "nosort", "- disable automatic sort by name"); Console.WriteLine(" {0,-20}{1}", "maxsize", "- maximum size for final file (in megabytes)"); Console.WriteLine(" {0,-20}{1}", "language", "- language for system messages: \"eng\" or \"rus\""); Console.WriteLine("Second step:"); Console.WriteLine(" CoolgirlCombiner.exe combine --loader <menu.nes> --offsets <offsets.xml> [--unif <multirom.unf>] [--bin <multirom.bin>]"); Console.WriteLine(" {0,-20}{1}", "loader", "- loader (compiled using asm file generated by first step)"); Console.WriteLine(" {0,-20}{1}", "offsets", "- input file with offsets for every game (generated by first step)"); Console.WriteLine(" {0,-20}{1}", "unif", "- output UNIF file"); Console.WriteLine(" {0,-20}{1}", "bin", "- output raw binary file"); return 1; } try { if (command == "prepare") { var lines = File.ReadAllLines(optionGames); var result = new byte?[256 * 1024 * 1024]; var regs = new Dictionary<string, List<String>>(); var games = new List<Game>(); var namesIncluded = new List<String>(); // Reserved for loader for (int a = 0; a < 128 * 1024; a++) result[a] = 0xff; // Bad sector :( // for (int a = 1908 * 0x8000; a < 1908 * 0x8000 + 128 * 1024; a++) result[a] = 0xff; // Building list of ROMs foreach (var line in lines) { if (string.IsNullOrEmpty(line.Trim())) continue; if (line.StartsWith(";")) continue; int sepPos = line.TrimEnd().IndexOf('|'); string fileName; string menuName = null; if (sepPos < 0) { fileName = line.Trim(); } else { fileName = line.Substring(0, sepPos).Trim(); menuName = line.Substring(sepPos + 1).Trim(); } if (fileName.EndsWith("/") || fileName.EndsWith("\\")) { Console.WriteLine("Loading directory: {0}", fileName); var files = Directory.GetFiles(fileName, "*.nes"); foreach (var file in files) { LoadGames(games, file); } } else { LoadGames(games, fileName, menuName); } } // Removing separators if (!optionNoSort) games = new List<Game>((from game in games where !(string.IsNullOrEmpty(game.FileName) || game.FileName == "-") select game).ToArray()); // Sorting if (optionNoSort) { games = new List<Game>((from game in games where !game.ToString().StartsWith("?") select game) .Union(from game in games where game.ToString().StartsWith("?") orderby game.ToString().ToUpper() ascending select game) .ToArray()); } else { games = new List<Game>((from game in games where !game.ToString().StartsWith("?") orderby game.ToString().ToUpper() ascending select game) .Union(from game in games where game.ToString().StartsWith("?") orderby game.ToString().ToUpper() ascending select game) .ToArray()); } int hiddenCount = games.Where(game => game.ToString().StartsWith("?")).Count(); byte saveId = 0; foreach (var game in games) { if (game.ROM.Battery) { saveId++; game.SaveId = saveId; } } int usedSpace = 0; var sortedPrgs = from game in games orderby game.ROM.PRG.Length descending select game; foreach (var game in sortedPrgs) { int prgRoundSize = 1; while (prgRoundSize < game.ROM.PRG.Length) prgRoundSize *= 2; Console.WriteLine("Fitting PRG for {0} ({1}kbytes)...", game, prgRoundSize / 1024); for (int pos = 0; pos < result.Length; pos += prgRoundSize) { if (WillFit(result, pos, prgRoundSize, game.ROM.PRG)) { game.PrgPos = pos; //Array.Copy(game.ROM.PRG, 0, result, pos, game.ROM.PRG.Length); for (var i = 0; i < game.ROM.PRG.Length; i++) result[pos + i] = game.ROM.PRG[i]; usedSpace = Math.Max(usedSpace, pos + game.ROM.PRG.Length); Console.WriteLine("Address: {0:X8}", pos); break; } } if (game.PrgPos < 0) throw new Exception("Can't fit " + game); } var sortedChrs = from game in games orderby game.ROM.CHR.Length descending select game; foreach (var game in sortedChrs) { int chrSize = game.ROM.CHR.Length; if (chrSize == 0) continue; Console.WriteLine("Fitting CHR for {0} ({1}kbytes)...", game, chrSize / 1024); for (int pos = 0; pos < result.Length; pos += 0x2000) { if (WillFit(result, pos, chrSize, game.ROM.CHR)) { game.ChrPos = pos; //Array.Copy(game.ROM.CHR, 0, result, pos, game.ROM.CHR.Length); for (var i = 0; i < game.ROM.CHR.Length; i++) result[pos + i] = game.ROM.CHR[i]; usedSpace = Math.Max(usedSpace, pos + game.ROM.CHR.Length); Console.WriteLine("Address: {0:X8}", pos); break; } } if (game.ChrPos < 0) throw new Exception("Can't fit " + game.FileName); } while (usedSpace % 0x8000 != 0) usedSpace++; int romSize = usedSpace; usedSpace += 128 * 1024 * (int)Math.Ceiling(saveId / 4.0); int totalSize = 0; int maxChrSize = 0; namesIncluded.Add(string.Format("{0,-33} {1,-10} {2,-10} {3,-10} {4,0}", "Game name", "Mapper", "Save ID", "Size", "Total size")); namesIncluded.Add(string.Format("{0,-33} {1,-10} {2,-10} {3,-10} {4,0}", "------------", "-------", "-------", "-------", "--------------")); var mapperStats = new Dictionary<byte, int>(); foreach (var game in games) { if (!game.ToString().StartsWith("?")) { totalSize += game.ROM.PRG.Length; totalSize += game.ROM.CHR.Length; namesIncluded.Add(string.Format("{0,-33} {1,-10} {2,-10} {3,-10} {4,0}", FirstCharToUpper(game.ToString().Replace("_", " ").Replace("+", "")), game.ROM.Mapper, game.SaveId == 0 ? "-" : game.SaveId.ToString(), ((game.ROM.PRG.Length + game.ROM.CHR.Length) / 1024) + " KB", (totalSize / 1024) + " KB total")); if (!mapperStats.ContainsKey(game.ROM.Mapper)) mapperStats[game.ROM.Mapper] = 0; mapperStats[game.ROM.Mapper]++; } if (game.ROM.CHR.Length > maxChrSize) maxChrSize = game.ROM.CHR.Length; } namesIncluded.Add(""); namesIncluded.Add(string.Format("{0,-10} {1,0}", "Mapper", "Count")); namesIncluded.Add(string.Format("{0,-10} {1,0}", "------", "-----")); foreach (var mapper in from m in mapperStats.Keys orderby m ascending select m) { namesIncluded.Add(string.Format("{0,-10} {1,0}", mapper, mapperStats[mapper])); } namesIncluded.Add(""); namesIncluded.Add("Total games: " + (games.Count - hiddenCount)); namesIncluded.Add("Final ROM size: " + Math.Round(usedSpace / 1024.0 / 1024.0, 3) + "MB"); namesIncluded.Add("Maximum CHR size: " + maxChrSize / 1024 + "KB"); namesIncluded.Add("Battery-backed games: " + saveId); Console.WriteLine("Total games: " + (games.Count - hiddenCount)); Console.WriteLine("Final ROM size: " + Math.Round(usedSpace / 1024.0 / 1024.0, 3) + "MB"); Console.WriteLine("Maximum CHR size: " + maxChrSize / 1024 + "KB"); Console.WriteLine("Battery-backed games: " + saveId); if (optionReport != null) File.WriteAllLines(optionReport, namesIncluded.ToArray()); if (games.Count - hiddenCount == 0) throw new Exception("Games list is empty"); if (usedSpace > optionMaxSize * 1024 * 1024) throw new Exception(string.Format("ROM is too big: {0} MB", Math.Round(usedSpace / 1024.0 / 1024.0, 3))); if (games.Count > 768) throw new Exception("Too many ROMs: " + games.Count); if (saveId > 128) throw new Exception("Too many battery backed games: " + saveId); regs["reg_0"] = new List<String>(); regs["reg_1"] = new List<String>(); regs["reg_2"] = new List<String>(); regs["reg_3"] = new List<String>(); regs["reg_4"] = new List<String>(); regs["reg_5"] = new List<String>(); regs["reg_6"] = new List<String>(); regs["reg_7"] = new List<String>(); regs["chr_start_bank_h"] = new List<String>(); regs["chr_start_bank_l"] = new List<String>(); regs["chr_start_bank_s"] = new List<String>(); regs["chr_count"] = new List<String>(); regs["game_save"] = new List<String>(); regs["game_type"] = new List<String>(); regs["cursor_pos"] = new List<String>(); int c = 0; foreach (var game in games) { int prgSize = game.ROM.PRG.Length; int chrSize = game.ROM.CHR.Length; int prgPos = game.PrgPos; int chrPos = Math.Max(game.ChrPos, 0); int chrBase = (chrPos / 0x2000) >> 4; int prgBase = (prgPos / 0x2000) >> 4; int prgRoundSize = 1; while (prgRoundSize < prgSize) prgRoundSize *= 2; int chrRoundSize = 1; while (chrRoundSize < chrSize || chrRoundSize < 0x2000) chrRoundSize *= 2; MapperInfo mapperInfo; if (!mappers.TryGetValue(game.ROM.Mapper, out mapperInfo)) throw new Exception(string.Format("Unknowm mapper #{0} for {1} ", game.ROM.Mapper, game.FileName)); if (chrSize > 256 * 1024) throw new Exception(string.Format("CHR is too big in {0} ", game.FileName)); if (game.ROM.Mirroring == NesFile.MirroringType.FourScreenVram && game.ROM.CHR.Length > 256 * 1024 - 0x1000) throw new Exception(string.Format("Four-screen and such big CHR is not supported for {0} ", game.FileName)); // Some unusual games if (game.ROM.Mapper == 1) // MMC1 ? { switch (game.ROM.CRC32) { case 0xc6182024: // Romance of the 3 Kingdoms case 0x2225c20f: // Genghis Khan case 0x4642dda6: // Nobunaga's Ambition case 0x29449ba9: // "" "" (J) case 0x2b11e0b0: // "" "" (J) case 0xb8747abf: // Best Play Pro Yakyuu Special (J) case 0xc9556b36: // Final Fantasy I & II (J) [!] Console.WriteLine("WARNING! {0} uses 16KB of WRAM", game.FileName); mapperInfo.MapperFlags |= 1; // flag to support 16KB of WRAM break; } } if (game.ROM.Mapper == 4) // MMC3 ? { switch (game.ROM.CRC32) { case 0x93991433: // Low-G-Man case 0xaf65aa84: // Low-G-Man Console.WriteLine("WARNING! WRAM will be disabled for {0}", Path.GetFileName(game.FileName)); mapperInfo.WramEnabled = false; // disable WRAM break; } } switch (game.ROM.CRC32) { case 0x78b657ac: // "Armadillo (J) [!].nes" case 0xb3d92e78: // "Armadillo (J) [T+Eng1.01_Vice Translations].nes" case 0x0fe6e6a5: // "Armadillo (J) [T+Rus1.00 Chief-Net (23.05.2012)].nes" case 0xe62e3382: // "MiG 29 - Soviet Fighter (Camerica) [!].nes" case 0x1bc686a8: // "Fire Hawk (Camerica) [!].nes" Console.WriteLine("WARNING! {0} is not compatible with Dendy", Path.GetFileName(game.FileName)); game.Flags |= GameFlags.WillNotWorkOnDendy; break; } if (string.IsNullOrEmpty(game.ToString())) game.Flags = GameFlags.Separator; byte @params = 0; if (mapperInfo.WramEnabled) @params |= 1; // enable SRAM if (chrSize == 0) @params |= 2; // enable CHR write if (game.ROM.Mirroring == NesFile.MirroringType.Horizontal) @params |= 8; // default mirroring if (game.ROM.Mirroring == NesFile.MirroringType.FourScreenVram) { @params |= 32; // four screen game.Flags |= GameFlags.WillNotWorkOnNewDendy; // not external NTRAM on new famiclones :( } @params |= 0x80; // lockout regs["reg_0"].Add(string.Format("${0:X2}", ((prgPos / 0x4000) >> 8) & 0xFF)); // PRG base regs["reg_1"].Add(string.Format("${0:X2}", (prgPos / 0x4000) & 0xFF)); // PRG base regs["reg_2"].Add(string.Format("${0:X2}", (0xFF ^ (prgRoundSize / 0x4000 - 1)) & 0xFF)); // PRG mask regs["reg_3"].Add(string.Format("${0:X2}", (mapperInfo.PrgMode << 5) | 0)); // PRG mode regs["reg_4"].Add(string.Format("${0:X2}", (mapperInfo.ChrMode << 5) | (0xFF ^ (chrRoundSize / 0x2000 - 1)) & 0x1F)); // CHR mode, CHR mask regs["reg_5"].Add(string.Format("${0:X2}", (game.ROM.Battery ? 0x02 : 0x01))); // SRAM page regs["reg_6"].Add(string.Format("${0:X2}", (mapperInfo.MapperFlags << 5) | mapperInfo.MapperReg)); // Flags, mapper regs["reg_7"].Add(string.Format("${0:X2}", @params)); // Parameters regs["chr_start_bank_h"].Add(string.Format("${0:X2}", ((chrPos / 0x8000) >> 7) & 0xFF)); regs["chr_start_bank_l"].Add(string.Format("${0:X2}", ((chrPos / 0x8000) << 1) & 0xFF)); regs["chr_start_bank_s"].Add(string.Format("${0:X2}", ((chrPos % 0x8000) >> 8) | 0x80)); regs["chr_count"].Add(string.Format("${0:X2}", chrSize / 0x2000)); regs["game_save"].Add(string.Format("${0:X2}", !game.ROM.Battery ? 0 : game.SaveId)); regs["game_type"].Add(string.Format("${0:X2}", (byte)game.Flags)); regs["cursor_pos"].Add(string.Format("${0:X2}", game.ToString().Length + 4 /*+ (++c).ToString().Length*/)); } byte baseBank = 0; var asmResult = new StringBuilder(); asmResult.AppendLine("; Games database"); int regCount = 0; foreach (var reg in regs.Keys) { c = 0; foreach (var r in regs[reg]) { if (c % 256 == 0) { asmResult.AppendLine(); asmResult.AppendLine(" .bank " + (baseBank + c / 256 * 2)); asmResult.AppendLine(string.Format(" .org ${0:X4}", 0x8000 + regCount * 0x100)); asmResult.Append("loader_data_" + reg + (c == 0 ? "" : "_" + c.ToString()) + ":"); } //asmResult.AppendLine(" .db " + string.Join(", ", regs[reg])); if (c % 16 == 0) { asmResult.AppendLine(); asmResult.Append(" .db"); } asmResult.AppendFormat(((c % 16 != 0) ? "," : "") + " {0}", r); c++; } asmResult.AppendLine(); regCount++; } asmResult.AppendLine(); asmResult.AppendLine(); //asmResult.Append(" .dw"); c = 0; foreach (var game in games) { if (c % 256 == 0) { asmResult.AppendLine(); asmResult.AppendLine(" .bank " + (baseBank + c / 256 * 2)); asmResult.AppendLine(" .org $9000"); asmResult.AppendLine("game_names_list" + (c == 0 ? "" : "_" + c.ToString()) + ":"); asmResult.AppendLine(" .dw game_names" + (c == 0 ? "" : "_" + c.ToString())); asmResult.AppendLine("game_names" + (c == 0 ? "" : "_" + c.ToString()) + ":"); } //asmResult.AppendFormat(((c > 0) ? "," : "") + " game_name_" + c); asmResult.AppendLine(" .dw game_name_" + c); c++; } asmResult.AppendLine(); asmResult.AppendLine(); asmResult.AppendLine("; Game names"); c = 0; foreach (var game in games) { asmResult.AppendLine(); if (c % 256 == 0) { asmResult.AppendLine(" .bank " + (baseBank + c / 256 * 2 + 1)); if (baseBank + c / 256 * 2 + 1 >= 62) throw new Exception("Bank overflow! Too many games?"); asmResult.AppendLine(" .org $A000"); } asmResult.AppendLine("; " + game.ToString()); asmResult.AppendLine("game_name_" + c + ":"); var name = StringToTiles(string.Format(/*"{0}. "+*/"{1}", c + 1, game.ToString())); var asm = BytesToAsm(name); asmResult.Append(asm); c++; } asmResult.AppendLine(); asmResult.AppendLine(" .bank 14"); asmResult.AppendLine(" .org $C600"); asmResult.AppendLine(); asmResult.AppendLine("games_count:"); asmResult.AppendLine(" .dw " + (games.Count - hiddenCount)); asmResult.AppendLine(); asmResult.AppendLine(); asmResult.AppendLine("games_offset:"); asmResult.AppendLine(" .db " + ((games.Count - hiddenCount) > 10 ? 0 : 5 - (games.Count - hiddenCount) / 2)); asmResult.AppendLine(); asmResult.AppendLine(); asmResult.AppendLine("maximum_scroll:"); asmResult.AppendLine(" .dw " + Math.Max(0, games.Count - 11 - hiddenCount)); asmResult.AppendLine(); asmResult.AppendLine(); asmResult.AppendLine("build_info0:"); asmResult.Append(BytesToAsm(StringToTiles("FILE: " + Path.GetFileName(optionGames)))); asmResult.AppendLine("build_info2:"); asmResult.Append(BytesToAsm(StringToTiles("BUILD DATE: " + DateTime.Now.ToString("yyyy-MM-dd")))); asmResult.AppendLine("build_info3:"); asmResult.Append(BytesToAsm(StringToTiles("BUILD TIME: " + DateTime.Now.ToString("HH:mm:ss")))); asmResult.AppendLine("console_type_text:"); asmResult.Append(BytesToAsm(StringToTiles("CONSOLE TYPE:"))); asmResult.AppendLine("console_type_NTSC:"); asmResult.Append(BytesToAsm(StringToTiles("NTSC"))); asmResult.AppendLine("console_type_PAL:"); asmResult.Append(BytesToAsm(StringToTiles("PAL"))); asmResult.AppendLine("console_type_DENDY:"); asmResult.Append(BytesToAsm(StringToTiles("DENDY"))); asmResult.AppendLine("console_type_NEW:"); asmResult.Append(BytesToAsm(StringToTiles("NEW"))); asmResult.AppendLine("saving_text:"); if (optionLanguage == "rus") asmResult.Append(BytesToAsm(StringToTiles(" СОХРАНЯЕМСЯ... НЕ ВЫКЛЮЧАЙ! "))); else asmResult.Append(BytesToAsm(StringToTiles(" SAVING... KEEP POWER ON! "))); File.WriteAllText(optionAsm, asmResult.ToString()); asmResult.AppendLine("incompatible_console_text:"); if (optionLanguage == "rus") asmResult.Append(BytesToAsm(StringToTiles(" ИЗВИНИТЕ, ДАННАЯ ИГРА НЕСОВМЕСТИМА С ЭТОЙ КОНСОЛЬЮ НАЖМИТЕ ЛЮБУЮ КНОПКУ "))); else asmResult.Append(BytesToAsm(StringToTiles(" SORRY, THIS GAME IS NOT COMPATIBLE WITH THIS CONSOLE PRESS ANY BUTTON "))); asmResult.AppendLine("sram_test_ok_text:"); asmResult.Append(BytesToAsm(StringToTiles("PRG RAM TEST: OK"))); asmResult.AppendLine("sram_test_failed_text:"); asmResult.Append(BytesToAsm(StringToTiles("PRG RAM TEST: FAILED"))); asmResult.AppendLine("chr_test_ok_text:"); asmResult.Append(BytesToAsm(StringToTiles("CHR RAM TEST: OK"))); asmResult.AppendLine("chr_test_failed_text:"); asmResult.Append(BytesToAsm(StringToTiles("CHR RAM TEST: FAILED"))); File.WriteAllText(optionAsm, asmResult.ToString()); XmlWriterSettings xmlSettings = new XmlWriterSettings(); xmlSettings.Indent = true; StreamWriter str = new StreamWriter(optionOffsets); XmlWriter offsetsXml = XmlWriter.Create(str, xmlSettings); offsetsXml.WriteStartDocument(); offsetsXml.WriteStartElement("Offsets"); offsetsXml.WriteStartElement("Info"); offsetsXml.WriteElementString("Size", romSize.ToString()); offsetsXml.WriteElementString("RomCount", games.Count.ToString()); offsetsXml.WriteElementString("GamesFile", Path.GetFileName(optionGames)); offsetsXml.WriteEndElement(); offsetsXml.WriteStartElement("ROMs"); foreach (var game in games) { if (game.FileName == "-") continue; offsetsXml.WriteStartElement("ROM"); offsetsXml.WriteElementString("FileName", game.FileName); if (!game.ToString().StartsWith("?")) offsetsXml.WriteElementString("MenuName", game.ToString()); offsetsXml.WriteElementString("PrgOffset", string.Format("{0:X8}", game.PrgPos)); if (game.ROM.CHR.Length > 0) offsetsXml.WriteElementString("ChrOffset", string.Format("{0:X8}", game.ChrPos)); offsetsXml.WriteElementString("Mapper", game.ROM.Mapper.ToString()); if (game.SaveId > 0) offsetsXml.WriteElementString("SaveId", game.SaveId.ToString()); offsetsXml.WriteEndElement(); } offsetsXml.WriteEndElement(); offsetsXml.WriteEndElement(); offsetsXml.Close(); } else { using (var xmlFile = File.OpenRead(optionOffsets)) { var offsetsXml = new XPathDocument(xmlFile); XPathNavigator offsetsNavigator = offsetsXml.CreateNavigator(); XPathNodeIterator offsetsIterator = offsetsNavigator.Select("/Offsets/Info/Size"); int size = -1; while (offsetsIterator.MoveNext()) { size = offsetsIterator.Current.ValueAsInt; } //size = 64 * 1024 * 1024; if (size < 0) throw new Exception("Invalid offsets file"); var result = new byte[size]; Console.Write("Loading loader... "); var loaderFile = new NesFile(optionLoader); Array.Copy(loaderFile.PRG, 0, result, 0, loaderFile.PRG.Length); Console.WriteLine("OK."); offsetsIterator = offsetsNavigator.Select("/Offsets/ROMs/ROM"); while (offsetsIterator.MoveNext()) { var currentRom = offsetsIterator.Current; string filename = null; int prgOffset = -1; int chrOffset = -1; var descs = currentRom.SelectDescendants(XPathNodeType.Element, false); while (descs.MoveNext()) { var param = descs.Current; switch (param.Name.ToLower()) { case "filename": filename = param.Value; break; case "prgoffset": prgOffset = int.Parse(param.Value, System.Globalization.NumberStyles.HexNumber); break; case "chroffset": chrOffset = int.Parse(param.Value, System.Globalization.NumberStyles.HexNumber); break; } } if (!string.IsNullOrEmpty(filename)) { Console.Write("Loading {0}... ", filename); var nesFile = new NesFile(filename); if (prgOffset >= 0) Array.Copy(nesFile.PRG, 0, result, prgOffset, nesFile.PRG.Length); if (chrOffset >= 0) Array.Copy(nesFile.CHR, 0, result, chrOffset, nesFile.CHR.Length); Console.WriteLine("OK."); } } if (!string.IsNullOrEmpty(optionUnif)) { var u = new UnifFile(); u.Mapper = "COOLGIRL"; u.Fields["MIRR"] = new byte[] { 5 }; u.Fields["PRG0"] = result; u.Fields["BATR"] = new byte[] { 1 }; u.Version = 5; u.Save(optionUnif); uint sizeFixed = 1; while (sizeFixed < result.Length) sizeFixed <<= 1; var resultSizeFixed = new byte[sizeFixed]; Array.Copy(result, 0, resultSizeFixed, 0, result.Length); for (int i = result.Length; i < sizeFixed; i++) resultSizeFixed[i] = 0xFF; var md5 = System.Security.Cryptography.MD5.Create(); var md5hash = md5.ComputeHash(resultSizeFixed); Console.Write("ROM MD5: "); foreach (var b in md5hash) Console.Write("{0:x2}", b); Console.WriteLine(); } if (!string.IsNullOrEmpty(optionBin)) { File.WriteAllBytes(optionBin, result); } } } Console.WriteLine("Done."); } catch (Exception ex) { Console.WriteLine("Error: " + ex.Message + ex.StackTrace); return 2; } return 0; }
private void AddMenu(NesMenuCollection menuCollection, List <NesMenuCollection> allMenus = null) { if (allMenus == null) { allMenus = new List <NesMenuCollection>(); } if (!allMenus.Contains(menuCollection)) { allMenus.Add(menuCollection); } int menuIndex = allMenus.IndexOf(menuCollection); string targetDirectory; if (menuIndex == 0) { targetDirectory = gamesDirectory; } else { targetDirectory = Path.Combine(gamesDirectory, string.Format("sub{0:D3}", menuIndex)); } if (Directory.Exists(targetDirectory)) { return; } foreach (var element in menuCollection) { if (element is NesGame) { var game = element as NesGame; var gameDir = Path.Combine(targetDirectory, game.Code); Debug.WriteLine(string.Format("Processing {0}/{1}", game.Code, game.Name)); DirectoryCopy(game.GamePath, gameDir, true); if (!string.IsNullOrEmpty(game.GameGenie)) { var codes = game.GameGenie.Split(new char[] { ',', '\t', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries); var newNesFilePath = Path.Combine(gameDir, game.Code + ".nes"); try { var nesFile = new NesFile(newNesFilePath); foreach (var code in codes) { try { nesFile.PRG = GameGenie.Patch(nesFile.PRG, code.Trim()); } catch (GameGenieFormatException) { ShowError(new GameGenieFormatException(string.Format(Resources.GameGenieFormatError, code, game)), dontStop: true); } catch (GameGenieNotFoundException) { ShowError(new GameGenieNotFoundException(string.Format(Resources.GameGenieNotFound, code, game.Name)), dontStop: true); } } nesFile.Save(newNesFilePath); var ggFilePath = Path.Combine(gameDir, NesGame.GameGenieFileName); if (File.Exists(ggFilePath)) { File.Delete(ggFilePath); } } catch // in case of FDS game... just ignore { } } } if (element is NesMenuFolder) { var folder = element as NesMenuFolder; if (!allMenus.Contains(folder.Child)) { allMenus.Add(folder.Child); } int childIndex = allMenus.IndexOf(folder.Child); var folderDir = Path.Combine(targetDirectory, folder.Code); folder.Save(folderDir, childIndex); AddMenu(folder.Child, allMenus); } if (element is NesDefaultGame) { var game = element as NesDefaultGame; var gfilePath = Path.Combine(gamesDirectory, string.Format("gpath-{0}-{1}", game.Code, menuIndex)); Directory.CreateDirectory(Path.GetDirectoryName(gfilePath)); File.WriteAllText(gfilePath, menuIndex == 0 ? "." : string.Format("sub{0:D3}", menuIndex)); } } }
public static NesMiniApplication ImportNes(string nesFileName, bool?ignoreMapper, ref bool?needPatch, NeedPatchDelegate needPatchCallback = null, Form parentForm = null, byte[] rawRomData = null) { NesFile nesFile; try { if (rawRomData != null) { nesFile = new NesFile(rawRomData); } else { nesFile = new NesFile(nesFileName); } } catch { return(NesMiniApplication.Import(nesFileName, rawRomData)); } nesFile.CorrectRom(); var crc32 = nesFile.CRC32; var code = GenerateCode(crc32, Prefix); var gamePath = Path.Combine(GamesDirectory, code); var nesPath = Path.Combine(gamePath, code + ".nes"); var patchesDirectory = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "patches"); Directory.CreateDirectory(patchesDirectory); Directory.CreateDirectory(gamePath); var patches = Directory.GetFiles(patchesDirectory, string.Format("{0:X8}*.ips", crc32), SearchOption.AllDirectories); if (patches.Length > 0 && needPatch != false) { if (needPatch == true || ((needPatchCallback != null) && needPatchCallback(parentForm, Path.GetFileName(nesFileName)))) { needPatch = true; var patch = patches[0]; if (rawRomData == null) { rawRomData = File.ReadAllBytes(nesFileName); } Debug.WriteLine(string.Format("Patching {0}", nesFileName)); IpsPatcher.Patch(patch, ref rawRomData); nesFile = new NesFile(rawRomData); } else { needPatch = false; } } if (nesFile.Mapper == 71) { nesFile.Mapper = 2; // games by Codemasters/Camerica - this is UNROM clone. One exception - Fire Hawk } if (nesFile.Mapper == 88) { nesFile.Mapper = 4; // Compatible with MMC3... sometimes } if (nesFile.Mapper == 95) { nesFile.Mapper = 4; // Compatible with MMC3 } if (nesFile.Mapper == 206) { nesFile.Mapper = 4; // Compatible with MMC3 } if (!supportedMappers.Contains(nesFile.Mapper) && (ignoreMapper != true)) { Directory.Delete(gamePath, true); if (ignoreMapper != false) { throw new UnsupportedMapperException(nesFile); } else { Debug.WriteLine(string.Format("Game {0} has mapper #{1}, skipped", nesFileName, nesFile.Mapper)); return(null); } } if ((nesFile.Mirroring == NesFile.MirroringType.FourScreenVram) && (ignoreMapper != true)) { Directory.Delete(gamePath, true); if (ignoreMapper != false) { throw new UnsupportedFourScreenException(nesFile); } else { Debug.WriteLine(string.Format("Game {0} has four-screen mirroring, skipped", nesFileName, nesFile.Mapper)); return(null); } } // TODO: Make trainer check. I think that the NES Mini doesn't support it. nesFile.Save(nesPath); var game = new NesGame(gamePath, true); game.Name = Path.GetFileNameWithoutExtension(nesFileName); if (game.Name.Contains("(J)")) { game.region = "Japan"; } game.TryAutofill(crc32); game.Name = Regex.Replace(game.Name, @" ?\(.*?\)", string.Empty).Trim(); game.Name = Regex.Replace(game.Name, @" ?\[.*?\]", string.Empty).Trim(); game.Name = game.Name.Replace("_", " ").Replace(" ", " "); game.FindCover(nesFileName, (game.region == "Japan") ? Resources.blank_jp : Resources.blank_nes, crc32); game.Args = DefaultArgs; game.Save(); return(game); }
public void InsertNesFile(NesFile nesFile) { _nametableMirrorController.MirroringMode = nesFile.MirroringMode; _mapper = new Mapper0(nesFile); }
public LuaMapper() { script = new Script(); script.Globals["ReadPrg"] = script.Globals["ReadCpu"] = (Func <UInt16, int, List <byte> >) delegate(UInt16 address, int length) { if (Verbose) { Console.WriteLine("Reading {0} bytes from CPU:${1:X4}", length, address); } var result = new List <byte>(); result.AddRange(dumper.ReadCpu(address, length)); return(result); }; script.Globals["WritePrg"] = script.Globals["WriteCpu"] = (Action <UInt16, List <byte> >) delegate(UInt16 address, List <byte> data) { if (Verbose) { var a = address; foreach (var v in data) { Console.WriteLine("CPU write ${0:X2} => ${1:X4}", v, a); a++; } } dumper.WriteCpu(address, data.ToArray()); }; script.Globals["AddPrg"] = script.Globals["AddPrgResult"] = (Action <List <byte> >) delegate(List <byte> r) { resultPrg.AddRange(r); }; script.Globals["ReadAddPrg"] = script.Globals["ReadAddCpu"] = (Action <UInt16, int>) delegate(UInt16 address, int length) { if (Verbose) { Console.WriteLine("Reading {0} bytes from CPU:${1:X4}", length, address); } resultPrg.AddRange(dumper.ReadCpu(address, length)); }; script.Globals["ReadChr"] = script.Globals["ReadPpu"] = (Func <UInt16, int, List <byte> >) delegate(UInt16 address, int length) { if (Verbose) { Console.WriteLine("Reading {0} bytes from PPU:${1:X4}", length, address); } var result = new List <byte>(); result.AddRange(dumper.ReadPpu(address, length)); return(result); }; script.Globals["WriteChr"] = script.Globals["WritePpu"] = (Action <UInt16, List <byte> >) delegate(UInt16 address, List <byte> data) { if (Verbose) { var a = address; foreach (var v in data) { Console.WriteLine("PPU write ${0:X2} => ${1:X4}", v, a); a++; } } dumper.WritePpu(address, data.ToArray()); }; script.Globals["ReadAddChr"] = script.Globals["ReadAddPpu"] = (Action <UInt16, int>) delegate(UInt16 address, int length) { if (Verbose) { Console.WriteLine("Reading {0} bytes from PPU:${1:$X4}", length, address); } resultChr.AddRange(dumper.ReadPpu(address, length)); }; script.Globals["AddChr"] = script.Globals["AddChrResult"] = (Action <List <byte> >) delegate(List <byte> r) { resultChr.AddRange(r); }; script.Globals["Reset"] = (Action) delegate { if (Verbose) { Console.Write("Reset... "); } dumper.Reset(); if (Verbose) { Console.WriteLine("OK"); } }; script.Globals["WriteFile"] = (Action <string, List <byte> >) delegate(string filename, List <byte> data) { if (Verbose) { Console.Write("Writing data to \"{0}\"... ", Path.GetFileName(filename)); } File.WriteAllBytes(filename, data.ToArray()); if (Verbose) { Console.WriteLine("OK"); } }; script.Globals["WriteNes"] = (WriteNesDelegate) delegate(string filename, List <byte> prgData, List <byte> chrData, byte mapper, bool vertical) { if (Verbose) { Console.Write("Writing data to NES file \"{0}\" (mapper={1}, mirroring={2})... ", Path.GetFileName(filename), mapper, vertical ? "vertical" : "horizontal"); } var nesFile = new NesFile(); nesFile.PRG = prgData.ToArray(); nesFile.CHR = chrData.ToArray(); nesFile.Mapper = 0; nesFile.Mirroring = vertical ? NesFile.MirroringType.Vertical : NesFile.MirroringType.Horizontal; nesFile.Save(filename); if (Verbose) { Console.WriteLine("OK"); } }; script.Globals["Error"] = (Action <string>) delegate(string message) { throw new Exception(message); }; }
public Mapper0(NesFile nesFile) { _nesFile = nesFile; }