Pull to refresh

Comments 7

Если вы хотите поразвлекаться, создавая случайные глюки в ваших любимых играх для Dendy, могу предложить вам небольшую программу на C#, которая предназначена именно для этого. Программа учитывает особенности формата iNES и вносит случайные изменения только в программный код.

Для использования нужно запускать в консоли команды вида: mutator in.nes out.nes keyword 100, где keyword используется как randseed (то есть для одного и того же слова будет один и тот же набор случайных мутаций), а число задаёт количество мутаций (конкретно сколько байт будет испорчено).

Программа для создания мутаций
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

class NesFile
{
	public string FileName;

	public byte[] Header;
	public byte[] Trainer;
	public List<byte[]> PRG;
	public List<byte[]> CHR;
	public byte[] Attach;

	public NesFile(string filename)
	{
		FileName = filename;

		var ROM = File.ReadAllBytes(FileName);
		if (ROM[0] != 'N' || ROM[1] != 'E' || ROM[2] != 'S' || ROM[3] != 0x1A)
		{
			throw new Exception("Invalid iNES header");
		}

		Header = new byte[16];
		Array.Copy(ROM, 0, Header, 0, 16);
		var offset = 16;

		if ((Header[6] & 0x04) != 0)
		{
			Trainer = new byte[512];
			Array.Copy(ROM, offset, Trainer, 0, Trainer.Length);
			offset += Trainer.Length;
		}

		PRG = new List<byte[]>();
		for (var i = 0; i < Header[4]; i++)
		{
			PRG.Add(new byte[16384]);
			Array.Copy(ROM, offset, PRG[i], 0, PRG[i].Length);
			offset += PRG[i].Length;
		}

		CHR = new List<byte[]>();
		for (var i = 0; i < Header[5]; i++)
		{
			CHR.Add(new byte[8192]);
			Array.Copy(ROM, offset, CHR[i], 0, CHR[i].Length);
			offset += CHR[i].Length;
		}

		if (ROM.Length > offset)
		{
			Attach = new byte[ROM.Length - offset];
			Array.Copy(ROM, offset, Attach, 0, Attach.Length);
		}
	}

	public void PrepareHeader()
	{
		Header[4] = (byte)PRG.Count;
		Header[5] = (byte)CHR.Count;
	}

	public void Save(string filename = null)
	{
		PrepareHeader();

		if (filename != null)
		{
			FileName = filename;
		}

		using (var fs = File.OpenWrite(FileName))
		{
			fs.Write(Header, 0, Header.Length);

			if (Trainer != null)
			{
				fs.Write(Trainer, 0, Trainer.Length);
			}

			for (var i = 0; i < PRG.Count; i++)
			{
				fs.Write(PRG[i], 0, PRG[0].Length);
			}

			for (var i = 0; i < CHR.Count; i++)
			{
				fs.Write(CHR[i], 0, CHR[0].Length);
			}

			if (Attach != null)
			{
				fs.Write(Attach, 0, Attach.Length);
			}
		}
	}
}

class Mutagen
{
	static void Main(string[] args)
	{
		if (args.Length < 4) return;
		var nes = new NesFile(args[0]);
		var rnd = new Random(args[2].GetHashCode());
		var crb = Int32.Parse(args[3]);
		for (int i = 0; i < crb; i++)
		{
			var prg = rnd.Next(nes.PRG.Count);
			var pos = rnd.Next(nes.PRG[prg].Length);
			var shift = rnd.Next(-2, +2);
			int value = nes.PRG[prg][pos] + shift;
			nes.PRG[prg][pos] = (byte)(value & 0xFF);
		}
		nes.Save(args[1]);
	}
}
UFO just landed and posted this here
Всё же «ампутация», на мой взгляд, больше подходит к отрезанию каких-то внешних вещей, не относящихся непосредственно к коду. В статье выше упоминается удаление некоторых тайлов в CHR ROM для того, чтобы сделать нарисованные ими элементы невидимыми.
Ежели у Вас селекция, то у нас — ампутация.
Не понял, почему вы говорите, что у меня селекция. Я сам занимался именно реверс-инжинирингом оригинальной менюшки, и в статье об этом сказано. Поскольку кода было немного (всего 16 килобайт), получилось разобраться в её работе на 100%, и на её основе сделать демку.
UFO just landed and posted this here
Как же теперь легко будет матери объяснить пользу ГМО. Спасибо.
Заходил несколько дней назад к вам на сайт, увидел обновление к Unchained Nostalgia, думаю, наверняка скоро и интересная статья появится, и вот она!

Есть какие-то предположения, сколько потребовалось проб и ошибок для создания такого хака? Это все, полагаю, вручную проверялось?
Сколько именно времени ушло на создание хака — не знаю. Но его автор выкладывает и другие подобные хаки. Например, вот пачка странных хаков игры Battle City. На мой вопрос автор этого хака ответил лаконично:
Как делал? Просто, но долго. Корруптором.
Потом в процессе разговора он уточнил суть используемого им метода:
Но не всегда случайные и не всегда случайным образом. Можно определённые на определённые. Но если ты не знаешь АСМ, дебаггеры и т.д., то только так.
Видимо, «случайные» правки всё же как-то были приправлены интуицией. Как видно, использованная программа позволяет задавать некоторые правила для «мутаций»:
image

Я сам в детстве (15 лет назад) просто исправляя в HEX-редакторе байты, которые мне просто «не нравились», умудрился снять требование регистрации в одной из вариаций игры «О, счастливчик!» (я писал свой вариант этой игры, и взламывал «конкурента», который тоже был написан школьником). Просто очень сильно повезло. Плюс много терпения и сотни перезапусков с разными исправлениями :)
Sign up to leave a comment.

Articles

Change theme settings