Jump to content

[SOLVED] (FE8) Can someone confirm if this patch works?


BrightVega

Recommended Posts

It's a ASM hack found in FEuniverse by VennoBennu:

It uses weapon Ability Byte 3 0x40 (for FE7) or 0x80 (for FE8) to allow an item with a stat boost pointer to give those boosts even not equipped

I have Python2.7.6 installed and I'm trying to patch it using Camtech's Patcher as it says in the ReamMe.txt .

The folder has the required files and renamed as required for the text script to run and it does run

however in the command line when it asks for an offset to install the patch, things go wrong:

"The program will ask you twice to input an address; enter the address, without the leading 0x8000000, that you
want to place the hack at."

Well, my free space now is at "00B2BEB0" and I've tried typing:

b2beb0 -> Command Line just closes and nothing happens to ROM file

0xb2beb0 -> A "patched" file is created with no changes at all when compared in HxD and no new data at "00B2BEB0"

0x8b2beb0 -> Same as above

0x0b2beb0 -> Same as above

Opening the .dmp file in HxD it has these 2 offsets too:

"0163F0" and "016B3E" but comparing the "patched" with the unpatched files have no difference at these adresses.

So, what I am doing wrong ?

Link to comment
Share on other sites

maybe it's case-sensitive

(programming is picky at times had to ask)

Unfortunately, I've already tried with caps.

Wish I could install it manually with hex (which also tried) but i need to know what to re-point towards the hack.

In case anyone's interested: https://gyazo.com/8b44c42489e6d797f09ec2c5cac4348a

(yeah the item table is still at reversed 10 9B 80 08. Haven't moved it)

Or might want to see this:

https://gyazo.com/56487e89da265d2d572793d3881e6426

Link to comment
Share on other sites

Solved the problem by manually installing the patch. Kudos to Cam's Command Line for hinting how:

- Open the "implementation.dmp" in HxD and on the first line you will see "F0 63 01 08" which is the 0163F0 offset.

The "44 01" on the same first line is the size of the data we need for 0163F0.

- Highlight everything from the start of offset 10 (2nd line) until you highlight 144 (in hex) bytes of data.

The last 4 bytes will end in "10 9B 80 08" which is the offset of the default Item Table (809B10).

! If you have repointed the item table, change this number to your new offset !

- The second last 4 bytes in the above data (before "10 9B 80 08") are some annoying "EE EE EE EE".

Change those to some free space in your ROM and write the offset reversed+1

(My free space was at 00B2BEA0 and adding +1 is "00B2BEA1" , so I wrote: "A1 BE B2 08" )

- Copy the above 144 bytes of data, go to 0163F0 in your ROM, and Paste-Write the new data.

~~~~~

- Right after the above "10 9B 80 08" (in the implementation.dmp) is "3E 6B 01 08" which is the next offset (016B3E) we need.

- In offset 160, copy the first 8 bytes (00 06 33 1C 00 28 01 D0), go to 016B3E in your ROM and Paste-Write it.

~~~~~

- Offset 170 starts with "44" which means we need 44 bytes of data. Copy everything from 175 untill the end.

(00 B5 F0 B4...~...10 9B 80 08)

! Again, the last 4 bytes are the default Item Table. If you changed its location, change those 4 sets of numbers !

- Remember the "EE EE EE EE" that we changed with the free space?

Paste-Write the above data into the free space we specified. (In 00B2BEA0 in this example)

Done.

Link to comment
Share on other sites

okay i am about 95% convinced that you're somehow not using the patcher right because the script works for me

can you screen exactly what your folder looks like before and after running the patcher, and screen the output of the program while it's running

e:

yes i'm annoyed because nobody has ever reported an issue with this before beyond the interface being clunky and bad (what else is new) and this patch has been in existence long enough that i don't think it's a problem on venno's end

which means that there's either a bug in my software or it's user error

Link to comment
Share on other sites

I've used cam's patcher before without issue

P.S. BrightVega, if you find a patch on another website, it would probably pay to ask your questions there, where the creator of the patch is likely to be more active.

Link to comment
Share on other sites

Items in folder before: (implementation.dmp_2 is the one I manually modified today)

https://gyazo.com/69d7229a89f831bab87294ae7c1bd25b

Items in folder after: (the patched one is a dummy with no changes at all)

https://gyazo.com/d5e5bec19ee362b657df1739cca5d751

Run pic:

https://gyazo.com/56487e89da265d2d572793d3881e6426

(same for every input; after 3 repeats, it just creates a dummy patched file.

When inserting an offset without even the "0x" it just closes with nothing happening)

this patch has been in existence long enough that i don't think it's a problem on venno's end

It's not just this patch of his with issues.

All of his recent versions of "weapon rank bonus" (4 months old) are malfunctioning by adding +200 to all stats

and the .nmm modules on the same pack affect wrong areas of the ROM, crashing it, or don't open up and crash Nightmare.

The older versions of "WRB" posted here on Serenes 1 year ago, work fine

except the .nmm modules again (which don't open again)

Also while the patch is old, their links have been used only 14 times (with 4 being mine; downloaded it 4 times).

I think the problem is with the offsets within the patches as when manually inserted, they work

(same for both the "passive boost" and "WRB").

I've used cam's patcher before without issue

P.S. BrightVega, if you find a patch on another website, it would probably pay to ask your questions there, where the creator of the patch is likely to be more active.

I've already tried with PM but said user is offline for about a month.

(And this place is more popular (?))

Link to comment
Share on other sites

show me the output of the program after you enter the numbers

it shouldn't be closing

again consider that you are the first person to report an issue with this program literally since release 3-4 years ago

e:

i also question the value of asking for help with a patch somewhere other than the place you found it

Link to comment
Share on other sites

There, with a clean ROM:

https://gyazo.com/3b83e4ce0abe18bb769dd38d179aaa9d

Once i press "Enter" after the 3rd offset input, for 0.2 secs it writes "incorrect number of arguments", closes and creates a "patched_fe8.gba" file

without anything changing.

And as i said about the wrong "b2beb0" without the "0x", after typing it for the first time in the first input,

for 0.2 secs a wall of text appears and it automatically closes.

Can't take a picture of that.

i also question the value of asking for help with a patch somewhere other than the place you found it

Perhaps yeah, but now this can appear in the "Resources" board for more people to find and utilize.

I can't just wait or demand for the patch-creator to log in

and personally i lost 5 evenings just for this to find an alternative.

So even if this is the wrong place, the result makes the try worth it.

And I'm not attacking your patcher, since it was your patcher that helped me to understand the hex data

by showing me the adresses and data size.

Link to comment
Share on other sites

The Script.txt :

open fe8.gba
load Implementation.dmp
process
patch
link 0x16528 0 1
close fe8_patched.gba
quit

The text of run.py:

# code by Cameron "CT075" Wong

# "run.py"
# The main body of the application. Contains all code for user interfacing
# as well as basic code for handling files as necessary.

# XXX - Refactor entire code structure such that user input into the client
# and user input as part of a command (ie when creating a linker file) are
# kept in completely different modules.

# TODO: add an actual welcome message

import sys, os

# I really shouldn't be using import * but it's just so convenient
from dataOps import *
from cli import command, execCmd, doc, _handleLineWrap

# Global strings
WELCOME = """Assembly Patcher v2.0, by CT075

Type 'help' to see available commands."""

ERROR_MSG = """
***BUG SPLAT***

It looks like you've encountered an internal error. Good for you!
Unfortunately, the root cause of the error is probably Cam being
terrible at programming, and so you must wait until Cam fixes the
error before you can progress. However, it could potentially speed
up the process considerably if you send him an error report so he
can start looking!"""

# Global variables handling the application state

# It might be neater to have an overall "state" object that handles all of these
open_ROM = []
open_ROM_name = ""

open_patch = {}
open_patch_name = ""

open_bin = []

DEBUG = False

# File IO handling operations

def saveFile(path, data):
with open(path, 'wb') as f:
f.write(data)
return True

# array is imported implicitly via dataOps.py
def loadBinary(path):
with open(path, 'rb') as f:
return array.__new__(array, 'B', f.read())

# Methods for handling user input

# Handle the actual input
def processCmd(cmd):
if not cmd: return
cmd = cmd.lower()
line = cmd.split()
command = line[0]
args = line[1:]
execCmd(command, *args)

# User commands

# Patch file
@command('patch')
def patch():
global open_ROM, open_patch
processPatch()
open_ROM = applyPatch(open_patch, open_ROM)

# Open ROM
@command('open')
def openROM(path):
""" Usage: open filename

Loads ROM data from the file specified. Make sure that only one
program is editing the same file at once!"""
global open_ROM, open_ROM_name
try:
open_ROM = loadBinary(path)
open_ROM_name = path
except IOError as e:
print('Error reading one or more of the files:\n' + str(e))
return False
except:
print(ERROR_MSG)
return False
else:
print("Loaded ROM from file.")
return True

# Load patch
@command('load')
def loadPatch(path):
# I could probably just process the patch right here but...
""" Usage: load filename

Loads data from the file specified and stores it in the cache as raw
binary data. This is implicitly called when using 'process' with a
given filename, but they are separate functions to avoid any potential
for multiple errors to pile up at once."""
global open_bin, open_patch, open_patch_name
try:
open_bin = loadBinary(path)
open_patch_name = path
open_patch = []
except IOError as e:
print('Error reading one or more of the files:\n' + str(e))
return False
except:
print(ERROR_MSG)
return False
else:
print("Loaded patch.")
return True

@command('process')
def processPatch(path = None):
""" Usage: process [filename]

Processes a loaded patch into a format usable by the patcher. If a
filename is specified, the data from that file will be used. Otherwise,
the binary data currently loaded in the cache will be processed."""
global open_bin, open_patch, open_patch_name
# operation has debug properties
global DEBUG
if path is not None:
if not loadPatch(path):
return False
data = open_bin
if not data:
print("Error: No patch data loaded.")
return False
open_patch = processPatchData(data, DEBUG)
if not open_patch:
# probably should actually raise an exception
print("Error: Patch not formatted properly.")
return False

@command('close')
def closeROM(path = None):
""" Usage: close [filename]

Closes the currently open ROM by saving the data into the path given.
After closing, a ROM must be re-opened before further patching can be
done. If no filename is specified, the ROM will be saved with the
path used to open the file with a '_patched' on the end."""
global open_ROM, open_ROM_name
# If either open_ROM or open_ROM_name is blank, we can't close.
if not open_ROM or not open_ROM_name:
print("No ROM open!")
return True
if path is None:
path = open_ROM_name
path, ext = os.path.splitext(path)
path += '_patched' + ext
try:
saveFile(path, open_ROM)
open_ROM_name = ""
open_ROM = []
return True
except IOError as e:
print('Error writing to output file:\n', str(e))
return False
except:
print(ERROR_MSG)
return False

@command('save')
def savePatch(path = None):
""" Usage: save filename

Saves the currently processed patch data into a .bin file that contains
all the necessary data to be quickly reused. It will also be formatted
in a way that is compatible with the old Assembly Patcher. Unfortunately,
a .bin created this way must be processed again for each new session of
the patcher, this functionality is planned to be implemented in version
2.2.x. A file name must be specified.

Cached patches may be used again after saving."""
global open_patch, open_patch_name
# If either open_patch or open_patch_name are empty, we can't patch!
if not open_patch or not open_patch_name:
# I could use the 'a if condition else b' format here, but that makes
# the line length get really really long and that is undesirable.
if open_bin:
print("Patch must be processed before saving!")
else:
print("No patch open!")
return True
if path is None:
print("Filename must be specified.")
return True

# XXX: This is a lot of duplicated code from the 'close' function, maybe
# it might be a good idea to just fold this logic into the saveFile method
# Maybe not, though, as the 'close' function also needs to clear open_ROM
# and open_ROM_name upon completed save.
try:
saveFile(path + '.bin', format(open_patch))
return True
except IOError as e:
print('Error writing to output file:\n', str(e))
return False
except:
print(ERROR_MSG)
return False

# Auto-create linker
# This is just a stand-in solution until I can come up with something better.
@command('link', True)
def link(offset, handle, register = 0):
""" Usage: link offset handle [link_register]

Automatically creates and applies a "linker" patch that links to the
routine at the given handle. The data for this patch will be written
to the offset given at "offset". If a register number is given (must
be 0-7), that register will be clobbered and used as the branch
register."""
# Convert string inputs to integers
global open_ROM
if handle != '_':
handle = parseInt(handle)
offset, register = list(map(parseInt, (offset, register)))
# This dictionary is the patch
data = { offset : genLinkCode(handle, register) }
print('Link creation success.')
if DEBUG: print(data)
# auto-apply the patch
open_ROM = applyPatch(data, open_ROM)
return True

@command('halp', True)
def halp(*args, **kwargs):
"""Usage: halp me pls cam halp pls"""
print("That would be cheating!")

@command('help')
def help(cmd = None):
"""You're a clever one, aren't you?"""
if cmd is None:
# This helptext setup is probably needlessly complex
global open_patch_name, open_ROM_name, open_patch
ROMstr = ''
patchstr = ''
canProcess = bool(open_patch_name) and not bool(open_patch)
canSave = bool(open_patch)
# The following two references to open_ROM_name should really be references to
# open_ROM instead, but for the most part there is no situation in which
# open_ROM_name would be set and open_ROM wouldn't (and vice versa)
canPatch = bool(open_patch) and bool(open_ROM_name)
canClose = bool(open_ROM_name)

# The help text is based on a number of factors, so we have to check them all.
if open_ROM_name:
ROMstr = 'The currently open ROM is %s.' % open_ROM_name
else:
ROMstr = 'There is currently no opened ROM.'
if open_patch_name:
patchstr = 'The currently open patch is %s.' % open_patch_name
else:
patchstr = 'There is currently no opened patch.'

helpText = ("{0} {1} You may 'open' a ROM, 'load' a patch, {2}{3}{4}{5}or "
"'quit' the program.")

# brace yourself
helpText = _handleLineWrap(
helpText.format(
ROMstr, patchstr,
"'process' patch data, " if canProcess else "",
"'save' a processed patch, " if canSave else "",
"'patch' a loaded ROM, " if canPatch else "",
"'close' (save) the current ROM, " if canClose else ""
)
)
print(helpText)
global DEBUG
if DEBUG:
print('\nDebug mode is active.')
elif cmd == "me":
print("Help you? You're supposed to be a self-sufficient hacker!")
else:
print(doc(cmd))

# Using a garbage word so people won't stumble on this at random
@command('asdf', True)
def debugOn(arg = None, *args):
"""If you know to use this option you know full well what it does."""
if arg is not None:
print("Command 'asdf' not found.")
global DEBUG
DEBUG = not DEBUG
print('Debug mode ' + ('activated' if DEBUG else 'deactivated'))

# Debug-only commands
@command('data')
def displayPatchData(patch = None):
global DEBUG
if not DEBUG:
print("Please activate debug mode for access to this command.")
return False
if patch is None:
global open_patch
patch = open_patch
if not patch:
print('No patch loaded')
return False
for address in patch:
print('Offset %s: ' % hex(address))
print(_handleLineWrap(str(list(map(hex, patch[address])))))

# Main method
def main(args):
print(WELCOME)
if (len(args) > 1):
os.chdir(os.path.dirname(args[0]))
from cli import runScript as run
run(args[1])
while True:
user_input = input('>>> ')
processCmd(user_input)
print('')
return True

# Ensures code doesn't get run if this is being imported
if __name__ == '__main__':
main(sys.argv)

I think (can't really remember) it was your version3 patcher

if that's relevant.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...