Banner
Views: 236,434,994
Time: 2013-05-23 03:27:19 PM
24 users online: o 1UPdudes, Alcaro, o AnybodyAgrees, chineesmw, Davichii, Dylancd5010, Flame8765, FlyHorn, HyperMario, Incognito, Ivan Sword54, Koopster, LX5, MarioBros980, o mariocool1999, Masterlink, NEX and GBX, Ragey, o Richard Nixon, ShUriK KiD, Sokobansolver, supernova38, o Undy, X-cniS - Guests: 30 - Bots: 6Users: 22,871 (1,275 active)
Latest: julian2908
Tip: If you edit level 0, make sure you also edit level 100. Both of them are used for the bonus game.
SMW/ROMhacking tool related code library
Forum Index - Hobbies - Computers & Technology - SMW/ROMhacking tool related code library
Pages: « 1 2 »
I decided to post a couple core functions from Xkas GUI here for good measure.

RemoveCommentsAndTrim

trims up an ASM patch so it can be more easily processed

Code
private string[] removeCommentsAndTrim(string[] input) { for (int i = 0; i < input.Length; i++) { if (input[i].Contains(";")) { input[i] = input[i].Substring(0, input[i ].IndexOf(";")); } if (input[i].Contains("//")) { input[i] = input[i].Substring(0, input[i].IndexOf("//")); } input[i] = input[i].Trim(); } return input; }


CountBytes

Counts the bytes in an ASM patch, starting at a given line and ending at the next ORG or the end of the file

Code
private int countbytes(string asmpath, int startline) { int n = 0; string[] a = File.ReadAllLines(asmpath); a = removeCommentsAndTrim(a); for (int i = startline; i < a.Length && !a[ i].ToLowerInvariant().Contains("org"); i++) { a[i] = a[i].ToLowerInvariant(); if (a[i].Contains(":")) continue; if (a[i].ToLowerInvariant().Contains("incbin")) { n += File.ReadAllBytes(asmpath.Substring(0, asmpath.LastIndexOf("\\") + 1) + a[i].Substring(7)).Length; continue; } if (a[i].ToLowerInvariant().Contains("incsrc")) { n += countbytes(asmpath.Substring (0, asmpath.LastIndexOf("\\") + 1) + a[i].Substring(7), 0); continue; // 1 2 /2 /1 } int fair = 0; for (int j = 0; j < a[i].Length; j++) { if (a[i].Substring(j, 1).IndexOfAny(letters) != -1) { fair++; if (fair >= 3) { fair = 0; n++; } } else fair = 0; } fair = 0; for (int j = 0; j < a[i ].Length; j++) { if (a[i].Substring(j, 1).IndexOfAny(hex) != -1) { fair++; if (fair >= 2) { fair = 0; n++; } } else fair = 0; } } return n; }


GetFreeSpace

Searches for a given number of unprotected bytes in a ROM, starting in bank 10. Returns "not" if there isn't a string of free bytes long enough, "exp" if the ROM hasn't been expanded, or returns the hex address of the freespace.

Code
private string getfreespace(string rompath, int bytesneeded) { byte[] rombyte = File.ReadAllBytes(rompath); if (rombyte.Length < 513 * 1024) return "exp"; int header = 0; if (rombyte[11] == 0 && rombyte[12] == 0 && rombyte[13] == 0) header = 0x200; int freebytes = 0; int freespace = 0x80000 + header; for (int i = freespace; i < rombyte.Length; i++) { if (rombyte[i] == 0x53) { if (rombyte[i + 1] == 0x54) { if (rombyte[i + 2] == 0x41) { if ((rombyte[i + 3] == 0x52) || (((i - header) & 0x77FFF) | 0x8000) == 0x8000) { if (freebytes >= bytesneeded) { rombyte[freespace] = 0x52; rombyte[freespace + 1] = 0x41; rombyte[freespace + 2] = 0x54; rombyte[freespace + 3] = 0x53; rombyte[freespace + 4] = (byte)(bytesneeded & 0xFF); rombyte[freespace + 5] = (byte)(bytesneeded >> 8 & 0xFF); rombyte[freespace + 6] = (byte)(bytesneeded ^ 0xFFFF & 0xFF); rombyte[freespace + 7] = (byte)(bytesneeded ^ 0xFFFF >> 8 & 0xFF); File.WriteAllBytes(rompath, rombyte); string freestring = String.Format("{0:X}", PCSNES(freespace, header)); while (freestring.Length < 6) { freestring = "0" + freestring; } return freestring; } freebytes = 0; i += 5 + rombyte[i + 4] + (rombyte[i + 5] * 0x100); freespace = i; } } } } freebytes++; } if (freespace >= bytesneeded) { rombyte[freespace] = 0x52; rombyte[freespace + 1] = 0x41; rombyte[freespace + 2] = 0x54; rombyte[freespace + 3] = 0x53; rombyte[freespace + 4] = (byte)(bytesneeded & 0xFF); rombyte[freespace + 5] = (byte)(bytesneeded >> 8 & 0xFF); rombyte[freespace + 6] = (byte)(bytesneeded ^ 0xFFFF & 0xFF); rombyte[freespace + 7] = (byte)(bytesneeded ^ 0xFFFF >> 8 & 0xFF); File.WriteAllBytes(rompath, rombyte); string freestring = String.Format("{0:X}", PCSNES(freespace, header)); while (freestring.Length < 6) { freestring = "0" + freestring; } return freestring; } return "not"; }


mRecreateResourses

A great code I found somewhere on the internet. It re-creates a given resource in the folder of the tool.

Code
private void mRecreateResource(string filename) { // Get Current Assembly refrence Assembly currentAssembly = Assembly.GetExecutingAssembly(); // Get all imbedded resources string[] arrResources = currentAssembly.GetManifestResourceNames(); foreach (string resourceName in arrResources) { if (resourceName == filename) { //Name of the file saved on disk string saveAsName = AppDomain.CurrentDomain.BaseDirectory + filename; FileInfo fileInfoOutputFile = new FileInfo(saveAsName); //CHECK IF FILE EXISTS AND DO SOMETHING DEPENDING ON YOUR NEEDS if (fileInfoOutputFile.Exists) { File.Delete(fileInfoOutputFile.ToString()); } //OPEN NEWLY CREATING FILE FOR WRITTING FileStream streamToOutputFile = fileInfoOutputFile.OpenWrite(); //GET THE STREAM TO THE RESOURCES Stream streamToResourceFile = currentAssembly.GetManifestResourceStream(resourceName); //--------------------------------- //SAVE TO DISK OPERATION //--------------------------------- const int size = 4096; byte[] bytes = new byte[4096]; int numBytes; while ((numBytes = streamToResourceFile.Read(bytes, 0, size)) > 0) { streamToOutputFile.Write(bytes, 0, numBytes); } streamToOutputFile.Close(); streamToResourceFile.Close(); }//end_if }//end_foreach }


...yep, that's about all for now.

One thing I am constantly annoyed at about SMWC is that if I try to index an array with int i, SMWC reads it as an italics tag.

Ersan to the rescue with &#91;!
Last edited on 2009-12-21 01:02:31 PM by Noobish Noobsicle.
Here is a small code I wrote in C# for a 'layer 3 palette editor', to get the current palette and color number on a 16x16 color palette grid. (Actually it was meant for a NES palette editor but both of their palettes pretty much behave the same)

Code
int paletteNumber = (((e.X >> 4) / 4) + ((e.Y >> 4) * 4)); int colorNumber = ((e.X >> 4) & 0x03);

This can be used in a mouseover event.

Example values (numbers and borders put by me):
I don't really have anything useful to share, but I do have a (not very efficient, but absolute) algorithm for converting hex to dec for C. This is for a two-character hex number, which you put in the argument.

COPYPASTA!

Code
int hexadecimaltc(char value[2]) //Two-character hexadecimal converter. Converts from hex to dec. { int num; //The number you get after the process is done. int temp; //A temporary controller for the number you add to num. if (value[0] == '0'){ temp = 0; } if (value[0] == '1'){ temp = 1; } if (value[0] == '2'){ temp = 2; } if (value[0] == '3'){ temp = 3; } if (value[0] == '4'){ temp = 4; } if (value[0] == '5'){ temp = 5; } if (value[0] == '6'){ temp = 6; } if (value[0] == '7'){ temp = 7; } if (value[0] == '8'){ temp = 8; } if (value[0] == '9'){ temp = 9; } if (value[0] == 'A' || value[0] == 'a'){ temp = 10; } if (value[0] == 'B' || value[0] == 'b'){ temp = 11; } if (value[0] == 'C' || value[0] == 'c'){ temp = 12; } if (value[0] == 'D' || value[0] == 'd'){ temp = 13; } if (value[0] == 'E' || value[0] == 'e'){ temp = 14; } if (value[0] == 'F' || value[0] == 'f'){ temp = 15; } num = 16 * temp; if (value[1] == '0'){ temp = 0; } if (value[1] == '1'){ temp = 1; } if (value[1] == '2'){ temp = 2; } if (value[1] == '3'){ temp = 3; } if (value[1] == '4'){ temp = 4; } if (value[1] == '5'){ temp = 5; } if (value[1] == '6'){ temp = 6; } if (value[1] == '7'){ temp = 7; } if (value[1] == '8'){ temp = 8; } if (value[1] == '9'){ temp = 9; } if (value[1] == 'A' || value[1] == 'a'){ temp = 10; } if (value[1] == 'B' || value[1] == 'b'){ temp = 11; } if (value[1] == 'C' || value[1] == 'c'){ temp = 12; } if (value[1] == 'D' || value[1] == 'd'){ temp = 13; } if (value[1] == 'E' || value[1] == 'e'){ temp = 14; } if (value[1] == 'F' || value[1] == 'f'){ temp = 15; } num = num + temp; return num; }
Or you could use the strtol() function? (It is located in stdlib.h)
Code
#include <iostream> [...] cout << dec << 0xff << endl
Results in 255.
Originally posted by Yakov
Code
#include <iostream> [...] cout << dec << 0xff << endl
Results in 255.


strtol is used when the given number is coming from a string. When it comes to inputting number from a programmers perspective like you did will usually result in a decimal output. The only exception to that would be using output modifiers on the iostream(or print style functions of C).
Originally posted by p4plus2
Or you could use the strtol() function? (It is located in stdlib.h)


What's that? I need something to convert decimal to hex anyway, and I don't know how %x works.
Originally posted by mszegedy
Originally posted by p4plus2
Or you could use the strtol() function? (It is located in stdlib.h)


What's that? I need something to convert decimal to hex anyway, and I don't know how %x works.


It will take a char array input and will return a long int.
Code
long int strtol(const char *start, char **end, int base);


More information can be found here:
http://www.cplusplus.com/reference/clibrary/cstdlib/strtol/

Also, %x works like this:
Code
printf("hex: %x", 100);
Originally posted by x-treme
Sorry for the bump, but what is the code for patch a ips patch in VB2008?


Code
Dim romstream As New FileStream(romname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite) Dim ipsstream As New FileStream(patchname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite) Dim lint As Integer = CInt(ipsstream.Length) Dim ipsbyte As Byte() = New Byte(ipsstream.Length - 1) {} Dim rombyte As Byte() = New Byte(romstream.Length - 1) {} Dim romresult As IAsyncResult Dim ipsresult As IAsyncResult = ipsstream.BeginRead(ipsbyte, 0, lint, Nothing, Nothing) ipsstream.EndRead(ipsresult) Dim ipson As Integer = 5 Dim totalrepeats As Integer = 0 Dim offset As Integer = 0 Dim keepgoing As Boolean = True '''///////////////End Init code '''///////////////Start main code While keepgoing = True offset = ipsbyte(ipson) * &H10000 + ipsbyte(ipson + 1) * &H100 + ipsbyte(ipson + 2) ipson += 1 ipson += 1 ipson += 1 '''//////////split between repeating byte mode and standard mode If ipsbyte(ipson) * 256 + ipsbyte(ipson + 1) = 0 Then '''/////////repeating byte mode ipson += 1 ipson += 1 totalrepeats = ipsbyte(ipson) * 256 + ipsbyte(ipson + 1) ipson += 1 ipson += 1 Dim repeatbyte As Byte() = New Byte(totalrepeats - 1) {} For ontime As Integer = 0 To totalrepeats - 1 repeatbyte(ontime) = ipsbyte(ipson) Next romstream.Seek(offset, SeekOrigin.Begin) romresult = romstream.BeginWrite(repeatbyte, 0, totalrepeats, Nothing, Nothing) romstream.EndWrite(romresult) ipson += 1 Else '''/////////standard mode totalrepeats = ipsbyte(ipson) * 256 + ipsbyte(ipson + 1) ipson += 1 ipson += 1 romstream.Seek(offset, SeekOrigin.Begin) romresult = romstream.BeginWrite(ipsbyte, ipson, totalrepeats, Nothing, Nothing) romstream.EndWrite(romresult) ipson = ipson + totalrepeats End If '''//////////Test For "EOF" If ipsbyte(ipson) = 69 AndAlso ipsbyte(ipson + 1) = 79 AndAlso ipsbyte(ipson + 2) = 70 Then keepgoing = False End If End While romstream.Close() ipsstream.Close()

Sorry for bumping the tread but since its sticked.....
Last edited on 2011-07-13 01:33:39 PM by MarioErmando.
Some generic snes functions in Python, suggested by imamelia:

Code
def addresstostring(address, endianness = "little"): return "".join([hex(ord(x))[2:] if len(hex(ord(x))[2:]) == 2 else "0"+hex(ord(x))[2:] for x in (address[::-1] if endianness == "little" else address)])

Takes in an address in little endian (or big endian if you specify anything else but "little" for the endianness parameter) and returns it as a formatted string (e.g. "\x00\x00\x08" will become "080000")

Code
def LoRomtoPC(address,header=False): return (((address & 0x7f0000) >> 1) | (address & 0x7fff)) + header*0x200 def HiRomtoPC(address,header=False): return (address & 0x3fffff) + header*0x200 def PCtoLoRom(address,header=False): address = address-(header*0x200) return ((address & 0x7F8000) << 1) + 0x8000 + (address & 0x7FFF) def PCtoHiRom(address,header=False): return 0xC00000 + ((address - header*0x200)&0x3FFFFF)


Pretty self explanatory, just the snes/PC conversion routines

Code
import re class FreeSpace(object): def __init__(self,start,length): self.start = start self.LoRom = PCtoLoRom(start) self.HiRom = PCtoHiRom(start) self.length = length def __str__(self): return "<FreeSpace object, start= {0} , length= {1} >".format(hex(self.start),hex(self.length)) def FindFreespace(data,size=1,zeros=False): matches = re.finditer("STAR(....)",data,re.S) count, RATs, addresses, lastRAT = 0,[],[],(0,0) for match in matches: length = int(addresstostring(match.groups()[0][0:2]),16) if length^0xFFFF == int(addresstostring(match.groups()[0][2:]),16) and \ match.start() + 8 + length >= lastRAT[1]: RATs.append((match.start(),match.start()+8+length)) lastRAT = (match.start(),match.start()+8+length) if zeros: for RAT in zip([(0,0)]+RATs,RATs+[(len(data),len(data))]): if RAT[0][1]+1 < RAT[1][0]: matches=re.finditer("".join(["\x00" for x in xrange(size)])+"\x00*",data[RAT[0][1]+1:RAT[1][0]]) for match in matches: freespace = FreeSpace(RAT[0][1]+1+match.start(),match.end()-match.start()) addresses.append(freespace) else: for RAT in zip([(0,0)]+RATs,RATs+[(len(data),len(data))]): if RAT[0][1]+1 < RAT[1][0]: freespace = FreeSpace(RAT[0][1]+1, RAT[1][0]-RAT[0][1]) if freespace.length >= size: addresses.append(freespace) return addresses

First one is a class, it's not necessary (I could just use a tuple) but it's nicer to be able to call freespace.start than having to do freespace[0].

Following that is a freespace finder. It takes in the ROM data, how many bytes of freespace it should look for, and whether it should look for zeros or just space between RATs, and it returns a list of "FreeSpace" objects that represent areas of freespace in the ROM. And, just for fun, here's the 8 line version (Pastebinned because otherwise it creates massive table stretch) Beat that p4plus2 :P

Code
def FindFreespaceByBanks(data,size=1,zeros=False): freespaces = FindFreespace(data,size,zeros) bankfreespaces = [[] for x in xrange(len(data)//0x8000)] for freespace in freespaces: banknum = freespace.start//0x8000 posinbank = freespace.start%0x8000 if posinbank + freespace.length > 0x8000: tempfreespaces = [] length = freespace.length newfreespace = FreeSpace(freespace.start,0x8000-posinbank) bankfreespaces[banknum].append(newfreespace) tempfreespaces.append(newfreespace) length -= 0x8000-posinbank banknum += 1 while length > 0x8000: newfreespace = FreeSpace(0x8000*banknum,0x8000) bankfreespaces[banknum].append(newfreespace) tempfreespaces.append(newfreespace) length -= 0x8000 banknum += 1 newfreespace = FreeSpace(0x8000*banknum,length) bankfreespaces[banknum].append(newfreespace) tempfreespaces.append(newfreespace) else: bankfreespaces[banknum].append(freespace) return bankfreespaces

This is a convenience wrapper around the freespace finding function. Essentially it just takes the freespace and splits it up into banks, it takes the same parameters as the freespace function and returns a list of lists of freepsace objects. Each item in the list corresponds to a bank, so if you wanted, e.g., all freespace within bank ten, you would just grab the tenth item in the list and it would be a list of freespace objects that correspond to the freespace found in bank 10.

These are all available as a module, plus a slogger clone to give an idea of how to use them, from here. Not that really anyone else uses python, but now it's out there if anyone needs it.
Now we just need a convenience wrapper for the convenience wrapper. As much as I appreciate you making these, I still don't see why you had to do the function that way and not just have one that finds the first available area of freespace given a file handle and size (and not letting it cross a bank boundary, of course). That just seems to be needlessly complicating things, if you ask me.
Last edited on 2011-09-05 11:33:45 AM by imamelia.
Originally posted by imamelia
I still don't see why you had to do the function that way and not just have one that finds the first available area of freespace given a file handle and size (and not letting it cross a bank boundary, of course). That just seems to be needlessly complicating things, if you ask me.

It's slow to look for freespace every single time. This way, it would take a minimal amount of coding on your part to vastly speed up the searching. However, I added a little function anyways that takes what is returned by "FindFreespaceByBanks" function, a length, and whether or not the freespace should be updated (True by default) and returns a freespace object for you, updating the one in the list so that it will take into account the code you are inserting (Eww, side effect). This also included changing the freespace object, but merely for convenience:

Code
class FreeSpace(object): def __init__(self,start,length): self.start = start self.LoRom = PCtoLoRom(start) self.HiRom = PCtoHiRom(start) self.length = length def UpdateAddress(self,length): self.length -= length self.start += length self.LoRom = PCtoLoRom(self.start) self.HiRom = PCtoHiRom(self.start) def __str__(self): return "<FreeSpace object, start= {0} , length= {1} >".format(hex(self.start),hex(self.length)) def GetFirstFreespace(banks,length, update = True): for freespaces in banks: for freespace in freespaces: if freespace.length >= length: tmpfreespace = FreeSpace(freespace.start,freespace.length) if update: freespace.UpdateAddress(length) return tmpfreespace return None


I've updated the download for snesproc to add these.

Possible usage would look like this:

Code
import snesproc file1 = open("ROM.smc",'rb') data = file1.read() file1.close() if len(data)%1024: data=data[0x200:] freespaces = snesproc.FindFreespaceByBanks(data,1,True) print snesproc.GetFirstFreespace(freespaces[0x10:],0x343)


I don't know if I mentioned, but these all require the ROM to be non headered.
This method of converting between 8-bit colour channels and 5-bit colour channels is far more accurate than simple bit-shifts.

Code
byte Convert8BitTo5Bit(byte value) { return (byte)((value * (31.0 / 255.0) + 0.5); } byte Convert5BitTo8Bit(byte value) { return (byte)(((value & 31) * (255.0 / 31.0) + 0.5); }


Alternatively, if you want to use bit shifts to convert a 5-bit channel value to an 8-bit channel value, the following code shows the most accurate way to do this.

Code
byte Convert5BitTo8Bit(byte value) { return (byte)(((value & 31) << 3) | ((value & 31) >> 2)); }


Of 32 possible values, 4 are off by 1.
using floating point casting is an amazingly inefficient method.
Originally posted by spel werdz rite
using floating point casting is an amazingly inefficient method.

I tried it in .NET before. I did 1 billion 500 million conversions from a 5-bit channel to an 8-bit channel.
e: 1 billion values takes too long for my results; must have been 500 million values instead.

The "bitbashing" method I showed took ~4 ~3.687 seconds to compute.
Using floating point method took ~6 ~5.618 seconds to compute.

If you want to see what's really inefficient, using Math.Round instead of the method I showed, the floating point method took ~12 ~18.339 seconds to compute.
Using Convert.ToByte took ~42 seconds to compute. Holy crap, now THAT's inefficient.
e: Did it again, got ~13.569 seconds with 500 million values. How odd.

If the floating point method taking 50% longer is a problem, just use the bitbashing method I demonstrated. It is far superior to simple bit shifting (AKA "dumb conversion").

e: A precomputed lookup table works fine, too. After all, when converting a 5-bit channel to an 8-bit channel, a lookup table would only be 32 bytes.

Using the lookup table took ~3.390 for the same 500 million values.
Last edited on 2011-12-17 01:19:40 PM by ShadowFan-X.
Lua: load ROM into a table

Code
-- Prompt user for ROM name. local file, fileName, bytes while not fileOpen do io.write("Enter ROM name:\n") fileName = io.read() file = io.open(fileName, "rb") if not file then print("Error opening file\n") else fileOpen = true end end -- Now, split file into a table. local romBuffer = {} while true do local bytes = file:read(1) if not bytes then break end romBuffer[#romBuffer + 1] = bytes end


The ROM is loaded byte by byte into romBuffer table.
Now we can test out this code by printing some bytes from ROM:

Code
for i = 1, 1000 do io.write(string.format("%02X ", string.byte( romBuffer[ i ] ))) if i % 8 == 0 then io.write("\n") end end


I hope this is helpful for those who use Lua. It's very simple and quick, but maybe the code could be optimized more. ;)
Here's a class, written in Java, that converts a 4BPP .bin file back and forth between a more useful format:

Code
public class DataConverter { /** * Converts data from the SNES 4BPP format to a packed array of palette values. * * @param data data to convert * @return converted array */ public static byte[] fromSNES4BPP(byte[] data) { byte[] tileData = new byte[data.length*2]; for (int i = 0; i < tileData.length; i++) { int tile = i / 64; int row = (i % 64) / 8; int col = i % 8; byte value = 0; value |= getBit(data[0 + tile*32 + row*2], (byte) 7 - col); value |= getBit(data[1 + tile*32 + row*2], (byte) 7 - col) << 1; value |= getBit(data[16 + tile*32 + row*2], (byte) 7 - col) << 2; value |= getBit(data[17 + tile*32 + row*2], (byte) 7 - col) << 3; tileData[i] = value; } return tileData; } /** * Converts data from a packed array of palette values to the SNES 4BPP format. * * @param data data to convert * @return converted array */ public static byte[] toSNES4BPP(byte[] tileData) { byte[] data = new byte[tileData.length/2]; for (int i = 0; i < tileData.length; i++) { int tile = i / 64; int row = (i % 64) / 8; int col = i % 8; data[0 + tile*32 + row*2] |= getBit(tileData[i], 0) << 7 - col; data[1 + tile*32 + row*2] |= getBit(tileData[i], 1) << 7 - col; data[16 + tile*32 + row*2] |= getBit(tileData[i], 2) << 7 - col; data[17 + tile*32 + row*2] |= getBit(tileData[i], 3) << 7 - col; } return data; } /** * Gets the value of a bit in a byte. * * @param value byte value to check * @param bit which bit to check * @return either 0 or 1 */ public static byte getBit(byte value, int bit) { return (byte) (value >>> bit & 0x1); } }


The converted array contains nothing more than a series of palette values, from 0x0 to 0xF. While this is Java code, it could easily be converted to other languages.
Note that this comes from my tile editor, SNESTile, and a prettier version of this class can be found here.
Pages: « 1 2 »
Forum Index - Hobbies - Computers & Technology - SMW/ROMhacking tool related code library

The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.

Copyright © 2005 - 2013 - SMW Central
Legal Information - Link To Us


Total queries: 29

Menu