Reorganise repository and rename globals to setup
This commit is contained in:
parent
66e581a77c
commit
0994436231
37
Makefile
37
Makefile
|
|
@ -59,16 +59,16 @@ E_SETUP_BIN_FILES := $(patsubst src/setup/%.c, $(E_DIR)/files/setup/U%.bin, $(SE
|
|||
B_SETUP_BINZ_FILES := $(patsubst src/setup/%.c, $(B_DIR)/files/U%Z, $(SETUP_C_FILES))
|
||||
E_SETUP_BINZ_FILES := $(patsubst src/setup/%.c, $(E_DIR)/files/U%Z, $(SETUP_C_FILES))
|
||||
|
||||
setup: $(B_SETUP_BINZ_FILES)
|
||||
stagesetup: $(B_SETUP_BINZ_FILES)
|
||||
|
||||
$(B_DIR)/files/setup/%.o: src/setup/%.c $(SETUP_H_FILES)
|
||||
mkdir -p $(B_DIR)/files/setup
|
||||
$(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc -c $(CFLAGS) -o $@ -O2 $<
|
||||
|
||||
$(B_DIR)/files/setup/%.elf: $(B_DIR)/files/setup/%.o
|
||||
cp $< build/setup.tmp.o
|
||||
$(TOOLCHAIN)-ld -T setup.ld -o $@
|
||||
rm -f build/setup.tmp.o
|
||||
cp $< build/zero.tmp.o
|
||||
$(TOOLCHAIN)-ld -T ld/zero.ld -o $@
|
||||
rm -f build/zero.tmp.o
|
||||
|
||||
$(B_DIR)/files/setup/U%.bin: $(B_DIR)/files/setup/%.elf
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
|
@ -95,9 +95,9 @@ $(B_DIR)/files/lang/%.o: src/lang/%.c
|
|||
$(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc -c $(CFLAGS) -o $@ -O2 $<
|
||||
|
||||
$(B_DIR)/files/lang/%.elf: $(B_DIR)/files/lang/%.o
|
||||
cp $< build/setup.tmp.o
|
||||
$(TOOLCHAIN)-ld -T setup.ld -o $@
|
||||
rm -f build/setup.tmp.o
|
||||
cp $< build/zero.tmp.o
|
||||
$(TOOLCHAIN)-ld -T ld/zero.ld -o $@
|
||||
rm -f build/zero.tmp.o
|
||||
|
||||
$(B_DIR)/files/lang/L%.bin: $(B_DIR)/files/lang/%.elf
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
|
@ -115,20 +115,21 @@ $(B_DIR)/files/L%Z: $(B_DIR)/files/lang/L%.bin
|
|||
tools/rarezip $< > $@
|
||||
|
||||
################################################################################
|
||||
# Globals file
|
||||
# Game setup file
|
||||
|
||||
globals: $(B_DIR)/Uglobals
|
||||
setup: $(B_DIR)/ucode/setup.bin
|
||||
|
||||
$(B_DIR)/globals.o: src/globals.c $(SETUP_H_FILES)
|
||||
$(B_DIR)/setup.o: src/setup.c $(SETUP_H_FILES)
|
||||
mkdir -p $(B_DIR)
|
||||
$(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc -c $(CFLAGS) -o $@ -O2 $<
|
||||
|
||||
$(B_DIR)/globals.elf: $(B_DIR)/globals.o
|
||||
cp $< build/globals.tmp.o
|
||||
$(TOOLCHAIN)-ld -e 0x80059fe0 -T globals.ld -o $@
|
||||
rm -f build/globals.tmp.o
|
||||
$(B_DIR)/setup.elf: $(B_DIR)/setup.o
|
||||
cp $< build/setup.tmp.o
|
||||
$(TOOLCHAIN)-ld -e 0x80059fe0 -T ld/setup.ld -o $@
|
||||
rm -f build/setup.tmp.o
|
||||
|
||||
$(B_DIR)/Uglobals: $(B_DIR)/globals.elf
|
||||
$(B_DIR)/ucode/setup.bin: $(B_DIR)/setup.elf
|
||||
mkdir -p $(B_DIR)/ucode
|
||||
$(TOOLCHAIN)-objcopy $< $@ -O binary
|
||||
|
||||
################################################################################
|
||||
|
|
@ -165,7 +166,7 @@ test: $(B_SETUP_BINZ_FILES) $(B_LANG_BINZ_FILES)
|
|||
--exclude=bgdata \
|
||||
--exclude=ob \
|
||||
$(E_DIR)/files $(B_DIR)/files
|
||||
@diff -q $(E_DIR)/Uglobals $(B_DIR)/Uglobals
|
||||
@diff -q $(E_DIR)/ucode/setup.bin $(B_DIR)/ucode/setup.bin
|
||||
|
||||
testall:
|
||||
REGION=ntsc RELEASE=final make test
|
||||
|
|
@ -178,9 +179,9 @@ testall:
|
|||
################################################################################
|
||||
# Miscellaneous
|
||||
|
||||
all: setup lang globals
|
||||
all: setup lang stagesetup
|
||||
|
||||
rom: $(B_SETUP_BINZ_FILES) $(B_DIR)/Uglobals
|
||||
rom: $(B_SETUP_BINZ_FILES) $(B_DIR)/ucode/setup.bin
|
||||
tools/inject pd.$(ROMID).z64
|
||||
|
||||
clean:
|
||||
|
|
|
|||
72
README.md
72
README.md
|
|
@ -1,10 +1,27 @@
|
|||
# Perfect Dark Decompilation (WIP)
|
||||
|
||||
This repository contains a work-in-progress decompilation of Perfect Dark for the Nintendo 64. So far only the stage setup files and lang files are decompiled.
|
||||
This repository contains a work-in-progress decompilation of Perfect Dark for the Nintendo 64.
|
||||
|
||||
## I have no idea what you're talking about
|
||||
## Roadmap
|
||||
|
||||
Go have a look at the level scripts in the src/setup directory. Here's a mapping table for your convenience:
|
||||
| Section | Progress |
|
||||
| --------------- | ----------------------------------------- |
|
||||
| 0x40 rspboot | Won't disassemble as source is likely ASM |
|
||||
| 0x1000 boot | Not started |
|
||||
| 0x3050 library | Not started |
|
||||
| 0x39850 setup | About 50% identified |
|
||||
| 0x4e850 rarezip | 2/8 functions done |
|
||||
| 0x5032e game | Not started |
|
||||
| Lang files | Done |
|
||||
| Setup files | Done |
|
||||
| Prop files | Not started |
|
||||
| Character files | Not started |
|
||||
| Gun files | Not started |
|
||||
| BG files | Not started |
|
||||
| Pad files | Not started |
|
||||
| Tile files | Not started |
|
||||
|
||||
If you want to browse the stage setup files, use this table to find the filename:
|
||||
|
||||
| Stage | File |
|
||||
| ---------------- | ------------------------------------ |
|
||||
|
|
@ -30,17 +47,11 @@ Go have a look at the level scripts in the src/setup directory. Here's a mapping
|
|||
| WAR! | [setupstat.c](src/setup/setupstat.c) |
|
||||
| The Duel | [setupate.c](src/setup/setupate.c) |
|
||||
| CI Training | [setupdish.c](src/setup/setupdish.c) |
|
||||
| Global Functions | [globals.c](src/globals.c) |
|
||||
| Common Functions | [setup.c](src/setup.c) |
|
||||
|
||||
There is also a stagetable.txt in the repository root which includes multiplayer stages.
|
||||
|
||||
## What can I do with this?
|
||||
|
||||
You can read and modify the level scripting easily, then recompile it into a playable ROM file. Assuming you have a ROM already of course (it's not included in the repo). The only supported version is the NTSC 8.7 final version. Other versions will be supported eventually.
|
||||
|
||||
You can use this to make mods without having to deal with the GE Setup Editor's interface. Or you can use it for practicing speedruns (eg. start a level at a particular location with particular objectives completed). Or you could make ROMs to help figure out how certain commands work.
|
||||
|
||||
## Okay, how? Show me how to make an edit
|
||||
## Compiling
|
||||
|
||||
Install the following:
|
||||
|
||||
|
|
@ -51,43 +62,10 @@ Install the following:
|
|||
Then:
|
||||
|
||||
1. Save your existing ROM file into the root of the repository with the name `pd.ntsc-final.z64`. It should not be byteswapped (the first four bytes should be `0x80371240`).
|
||||
2. Edit a setup file. Open up `src/setup/setupame.c` (Defection), find the symbol `func0422_intro` and add `explosions_around_chr(CHR_JOANNA)` as the first statement.
|
||||
2. Run `make extract`. This will create an `extracted/ntsc-final` containing assets from your ROM.
|
||||
3. Make edits to the C files in the `src` directory if desired.
|
||||
3. Run `make rom`. This will create a ROM file at `build/ntsc-final/pd.z64`.
|
||||
4. Play the ROM.
|
||||
5. Start Defection, watch the intro and admire Joanna jumping from the dropship into a sea of explosions to her fiery death.
|
||||
|
||||
## Where's the list of commands? Is there a reference?
|
||||
|
||||
See `src/include/commands.h` and `src/include/constants.h` for a start.
|
||||
|
||||
## Whats with all this beginloop and endloop stuff?
|
||||
|
||||
All scripting is a series of labels and gotos. To give some structure to the code, I made a macro called `beginloop` that replaces a `label` + `yield`, and a macro called `endloop` that replaces a `goto_first` when used in this context. Most loops use the label and yield consecutively which allows this to work.
|
||||
|
||||
I don't think Rare had constructs like this though. There's a few rare places where yields are done at the end of the loop, and some where there's a dprint (comment) between the label and yield. In these cases my macros can't and aren't used.
|
||||
|
||||
I also added a `reloop` macro, which is selectively used to replace a `goto_first` within a loop. It's basically a `continue` statement for those familiar with programming.
|
||||
|
||||
## Can I edit global functions?
|
||||
|
||||
Well, yes but no. They won't be injected into the ROM because I'm lazy and haven't written code to do that. The stage files will though.
|
||||
|
||||
The global functions are at src/globals.c.
|
||||
|
||||
## How much stuff can I add before I run out of space?
|
||||
|
||||
Lots. If all the usual file space is exhaused, there's about 300KB of unused ROM space from other locations which will also be used. Considering each command averages only a couple of bytes, you're looking at about 10,000 to 100,000 commands you can add before you run out.
|
||||
|
||||
## How do I know the built files are matching?
|
||||
|
||||
1. With your ROM in place from earlier, run `make extract`. This will create an `extracted/ntsc-final` directory and populate it with the binaries from your ROM.
|
||||
2. Without making any modifications to the setup files, run `make` to build them as usual. These will be compiled at `build/ntsc-final/files`.
|
||||
3. Run `make test`. This will compare the setup binaries in `extracted` with the ones in `build`. If you get no output then they're matching. Try making a change to a file and repeat the `make` and `make test` steps again to see it identify the mismatching files.
|
||||
|
||||
## I want to see support for PAL, JAP and other versions
|
||||
|
||||
It's next on my to do list.
|
||||
|
||||
## Can you do the same for GoldenEye?
|
||||
|
||||
I might do, but my focus is on PD for now.
|
||||
Run `make` followed by `make test`. If `make test` produces no output then everything is matching.
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ OUTPUT_ARCH (mips)
|
|||
|
||||
SECTIONS
|
||||
{
|
||||
.data 0x80059fe0 : AT(0x0000) {
|
||||
build/globals.tmp.o (.data);
|
||||
.text 0x70200000 : AT(0x0000) {
|
||||
build/rarezip.tmp.o (.text);
|
||||
build/rarezip.tmp.o (.data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/DISCARD/ : {
|
||||
* (.MIPS.abiflags);
|
||||
* (.options);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*OUTPUT_FORMAT ("elf32-bigmips")*/
|
||||
OUTPUT_ARCH (mips)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.data 0x80059fe0 : AT(0x0000) {
|
||||
build/setup.tmp.o (.data);
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
* (.MIPS.abiflags);
|
||||
* (.options);
|
||||
* (.gnu.attributes);
|
||||
* (.pdr);
|
||||
* (.mdebug);
|
||||
* (.gptab.bss);
|
||||
* (.gptab.data);
|
||||
* (.reginfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*OUTPUT_FORMAT ("elf32-bigmips")*/
|
||||
OUTPUT_ARCH (mips)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.data 0x00000000 : AT(0x0000) {
|
||||
build/zero.tmp.o (.data);
|
||||
}
|
||||
|
||||
.rodata : AT(SIZEOF(.data)) {
|
||||
build/zero.tmp.o (.rodata);
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
* (.MIPS.abiflags);
|
||||
* (.options);
|
||||
* (.gnu.attributes);
|
||||
* (.pdr);
|
||||
* (.mdebug);
|
||||
* (.gptab.bss);
|
||||
* (.gptab.data);
|
||||
* (.reginfo);
|
||||
}
|
||||
}
|
||||
35
setup.ld
35
setup.ld
|
|
@ -1,35 +0,0 @@
|
|||
/*OUTPUT_FORMAT ("elf32-bigmips")*/
|
||||
OUTPUT_ARCH (mips)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_LnameXDataStart = ADDR(.data);
|
||||
_LnameXDataRomStart = 0x0000;
|
||||
.data 0x00000000 : AT(0x0000) {
|
||||
build/setup.tmp.o (.data);
|
||||
}
|
||||
_LnameXDataEnd = ADDR(.data) + SIZEOF(.data);
|
||||
_LnameXDataRomEnd = 0x0000 + SIZEOF(.data);
|
||||
|
||||
|
||||
|
||||
_LnameXRODataStart = ADDR(.rodata);
|
||||
_LnameXRODataRomStart = _LnameXDataRomEnd;
|
||||
.rodata : AT(_LnameXDataRomEnd) {
|
||||
build/setup.tmp.o (.rodata);
|
||||
}
|
||||
_LnameXRODataEnd = ADDR( .rodata) + SIZEOF( .rodata);
|
||||
_LnameXRODataRomEnd = _LnameXDataRomEnd + SIZEOF( .rodata);
|
||||
|
||||
/DISCARD/ : {
|
||||
* (.MIPS.abiflags);
|
||||
* (.options);
|
||||
* (.gnu.attributes);
|
||||
* (.pdr);
|
||||
* (.mdebug);
|
||||
* (.gptab.bss);
|
||||
* (.gptab.data);
|
||||
* (.reginfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ class Extractor:
|
|||
self.rom = fd.read()
|
||||
fd.close()
|
||||
|
||||
self.globals = self.decompress(self.rom[self.val('globals'):])
|
||||
self.setup = self.decompress(self.rom[self.val('setup'):])
|
||||
self.extract_all()
|
||||
|
||||
def extract_all(self):
|
||||
|
|
@ -110,7 +110,7 @@ class Extractor:
|
|||
i = self.val('files')
|
||||
offsets = []
|
||||
while True:
|
||||
offset = int.from_bytes(self.globals[i:i+4], 'big')
|
||||
offset = int.from_bytes(self.setup[i:i+4], 'big')
|
||||
if offset == 0 and len(offsets):
|
||||
return offsets
|
||||
offsets.append(offset)
|
||||
|
|
@ -143,7 +143,7 @@ class Extractor:
|
|||
#
|
||||
|
||||
def extract_globals(self):
|
||||
self.write('Uglobals', self.globals)
|
||||
self.write('ucode/setup.bin', self.setup)
|
||||
|
||||
#
|
||||
# Textures
|
||||
|
|
@ -208,37 +208,37 @@ class Extractor:
|
|||
'ntsc-final': {
|
||||
'game': 0x4fc40,
|
||||
'files': 0x28080,
|
||||
'globals': 0x39850,
|
||||
'setup': 0x39850,
|
||||
'sfxctl': 0x80a250,
|
||||
},
|
||||
'ntsc-1.0': {
|
||||
'game': 0x4fc40,
|
||||
'files': 0x28080,
|
||||
'globals': 0x39850,
|
||||
'setup': 0x39850,
|
||||
'sfxctl': 0x80a250,
|
||||
},
|
||||
'ntsc-beta': {
|
||||
'game': 0x43c40,
|
||||
'files': 0x29160,
|
||||
'globals': 0x30850,
|
||||
'setup': 0x30850,
|
||||
'sfxctl': 0x7be940,
|
||||
},
|
||||
'pal-final': {
|
||||
'game': 0x4fc40,
|
||||
'files': 0x28910,
|
||||
'globals': 0x39850,
|
||||
'setup': 0x39850,
|
||||
'sfxctl': 0x7f87e0,
|
||||
},
|
||||
'pal-beta': {
|
||||
'game': 0x4fc40,
|
||||
'files': 0x29b90,
|
||||
'globals': 0x39850,
|
||||
'setup': 0x39850,
|
||||
'sfxctl': 0x7f87e0,
|
||||
},
|
||||
'jap-final': {
|
||||
'game': 0x4fc40,
|
||||
'files': 0x28800,
|
||||
'globals': 0x39850,
|
||||
'setup': 0x39850,
|
||||
'sfxctl': 0x7fc670,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
10
tools/inject
10
tools/inject
|
|
@ -34,19 +34,19 @@ class Injector:
|
|||
self.rompart3 = rombuffer[0x001a15c0:0x00ed83a0]
|
||||
self.rompart4 = rombuffer[0x01d5ca00:]
|
||||
|
||||
fp = open('build/ntsc-final/Uglobals', 'rb')
|
||||
globals = fp.read()
|
||||
fp = open('build/ntsc-final/ucode/setup.bin', 'rb')
|
||||
setup = fp.read()
|
||||
fp.close()
|
||||
|
||||
self.globaltop = globals[0:0x28080]
|
||||
self.globalbot = globals[0x2a000:]
|
||||
self.globaltop = setup[0:0x28080]
|
||||
self.globalbot = setup[0x2a000:]
|
||||
|
||||
self.files = []
|
||||
i = 0
|
||||
|
||||
while i <= 0x7dd:
|
||||
romnameaddr = int.from_bytes(rombuffer[0x01d5ca00 + i * 4:0x01d5ca00 + i * 4 + 4], 'big') + 0x01d5ca00
|
||||
romdataaddr = int.from_bytes(globals[0x28080 + i * 4:0x28080 + i * 4 + 4], 'big')
|
||||
romdataaddr = int.from_bytes(setup[0x28080 + i * 4:0x28080 + i * 4 + 4], 'big')
|
||||
|
||||
name = ''
|
||||
while rombuffer[romnameaddr] != 0:
|
||||
|
|
|
|||
Loading…
Reference in New Issue