Migrate to C99 instead of C

Co-authored-by: Rémy F <yne@users.noreply.github.com>
This commit is contained in:
Snesrev
2022-08-31 21:03:04 +02:00
parent f83f949d20
commit b85e91a336
61 changed files with 770 additions and 783 deletions

9
.gitignore vendored
View File

@@ -1,5 +1,6 @@
/.vs/
/packages/
/.vscode/
.DS_Store
*.dSYM
/Debug
@@ -12,7 +13,11 @@
/tables/zelda3.sfc
/tables/zelda3.smc
/saves/*.sav
/saves/sram.dat
/saves/sram.bak
/zelda3
/.vs/
__pycache__
*.o
/*.o
/*.exe
/*.out
/snes/*.o

View File

@@ -1,22 +1,22 @@
# adapted from original README.md:
# `clang++ -I/usr/include/SDL2 -lSDL2 -O2 -ozelda3 *.cpp snes/*.cpp`
# `clang -I/usr/include/SDL2 -lSDL2 -O2 -ozelda3 *.c snes/*.c`
ifneq (,$(shell command -v clang++))
CXX = clang++
else ifneq (,$(shell command -v g++))
CXX = g++
ifneq (,$(shell which clang))
CC = clang
else ifneq (,$(shell which gcc))
CC = gcc
endif
ifneq (,$(findstring clang,$(CXX)))
ifneq (,$(findstring clang,$(CC)))
LTO = -flto=thin
else ifneq (,$(findstring g++,$(CXX)))
else ifneq (,$(findstring gcc,$(CC)))
LTO = -flto=auto
endif
override CXXFLAGS := -O2 -I/usr/include/SDL2 $(LTO) $(CXXFLAGS)
override CFLAGS := -O2 -I/usr/include/SDL2 $(LTO) $(CXXFLAGS)
override LDFLAGS := -lSDL2 $(LDFLAGS)
override OBJS = $(patsubst %.cpp,%.o,$(wildcard *.cpp snes/*.cpp))
override OBJS = $(patsubst %.c,%.o,$(wildcard *.c snes/*.c))
override BIN = zelda3
.PHONY: all clean
@@ -27,4 +27,4 @@ clean:
$(RM) $(BIN) $(OBJS)
$(BIN): $(OBJS)
$(CXX) $(CXXFLAGS) -o $(BIN) $(OBJS) $(LDFLAGS)
$(CC) $(CFLAGS) -o $(BIN) $(OBJS) $(LDFLAGS)

View File

@@ -5,28 +5,32 @@ A reimplementation of Zelda 3.
This is a reverse engineered clone of Zelda 3 - A Link to the Past.
It's around 70-80kLOC of C/C++ code, and reimplements all parts of the original game. The game is playable from start to end.
It's around 70-80kLOC of C code, and reimplements all parts of the original game. The game is playable from start to end.
You need a copy of the ROM to extract game resources (levels, images). Then once that's done, the ROM is no longer needed.
It uses the PPU and DSP implementation from LakeSnes. Additionally, it can be configured to also run the original machine code side by side. Then the RAM state is compared after each frame, to verify that the C++ implementation is correct.
It uses the PPU and DSP implementation from [LakeSnes](https://github.com/elzo-d/LakeSnes).
Additionally, it can be configured to also run the original machine code side by side. Then the RAM state is compared after each frame, to verify that the C implementation is correct.
I got much assistance from spannierism's Zelda 3 JP disassembly and the other ones that documented loads of function names and variables.
## Compiling
## Dependencies
Put the ROM in tables/zelda3.sfc. The ROM needs to be the US ROM with SHA256 hash `66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb`.
- the `libsdl2-dev` library (ubuntu: `apt install libsdl2-dev`, macOS: `brew install sdl2`). On Windows, it's installed automatically with NuGet.
- a `tables/zelda3.sfc` US ROM file (for asset extraction step only) with SHA256 hash `66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb`.
- The `pillow` and `pyyaml` python dependencies used by the assets extractor. `pip install pillow pyyaml`
## Compiling
`cd tables`
Install python dependencies: `pip install pillow` and `pip install pyyaml`
Run `python3 extract_resources.py` to extract resources from the ROM into a more human readable format.
Run `python extract_resources.py` to extract resources from the ROM into a more human readable format.
Run `python3 compile_resources.py` to produce .h files that get included by the C code.
Run `python compile_resources.py` to produce .h files that gets included by the C++ code.
### Windows
Build the .sln file with Visual Studio
First extract and compile resources, see above. Then build the .sln file with Visual Studio.
### Linux/macOS
#### Dependencies
@@ -35,20 +39,19 @@ Linux: `apt install libsdl2-dev`
macOS: `brew install sdl2`
#### Building
Make sure you are in the root directory.
First extract and compile resources, see above. Then make sure you are in the root directory.
```
clang++ `sdl2-config --cflags` -O2 -ozelda3 *.cpp snes/*.cpp `sdl2-config --libs`
clang++ `sdl2-config --cflags` -O2 -ozelda3 *.c snes/*.c `sdl2-config --libs`
```
or
`make -j$(nproc)`
## Usage and controls
The game supports snapshots. The joypad input history is also saved in the snapshot. It's thus possible to replay a playthrough in turbo mode to verify that the game behaves correctly.
The game is run with `./zelda3` and takes an optional path to the ROM-file, which will verify for each frame that the C++ code matches the original behavior.
The game is run with `./zelda3` and takes an optional path to the ROM-file, which will verify for each frame that the C code matches the original behavior.
| Button | Key |
| ------ | ----------- |

View File

@@ -102,10 +102,10 @@ static const uint8 kBombosBlasts_Tab[72] = {
};
static const uint8 kQuake_Tab1[5] = {0x17, 0x16, 0x17, 0x16, 0x10};
static const uint8 kQuakeDrawGroundBolts_Char[15] = { 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x63 };
struct QuakeItem {
typedef struct QuakeItem {
int8 x, y;
uint8 f;
};
} QuakeItem;
static const QuakeItem kQuakeItems[] = {
{0, -16, 0x00},
{0, -16, 0x01},
@@ -3273,13 +3273,13 @@ endif_7:
hookshot_effect_index = k;
}
do_draw:
static const int8 kHookShot_Move_X[4] = {0, 0, 8, -8};
static const int8 kHookShot_Move_Y[4] = {8, -9, 0, 0};
static const uint8 kHookShot_Draw_Flags[12] = {0, 0, 0xff, 0x80, 0x80, 0xff, 0x40, 0xff, 0x40, 0, 0xff, 0};
static const uint8 kHookShot_Draw_Char[12] = {9, 0xa, 0xff, 9, 0xa, 0xff, 9, 0xff, 0xa, 9, 0xff, 0xa};
Point16U info;
do_draw:
Ancilla_PrepOamCoord(k, &info);
if (ancilla_L[k])
oam_priority_value = 0x3000;
@@ -3640,8 +3640,8 @@ skipit:;
ancilla_arr3[k] = kReceiveItem_Tab4[a];
WriteTo4BPPBuffer_at_7F4000(kReceiveItem_Tab5[a]);
}
endif_12:
Point16U pt;
endif_12:
Ancilla_PrepAdjustedOamCoord(k, &pt);
Ancilla_ReceiveItem_Draw(k, pt.x, pt.y);
}
@@ -4032,9 +4032,9 @@ lbl_else:
return;
}
}
uint8 astep;
label_b:
uint8 astep;
astep = ancilla_step[k];
if (astep != 0)
@@ -4056,8 +4056,8 @@ label_b:
AncillaDraw_GTCutsceneCrystal(oam, x, y);
oam++;
}
label_a:
Point16U info;
label_a:
Ancilla_PrepAdjustedOamCoord(k, &info);
breaktowerseal_base_sparkle_x_lo[7] = info.x;

View File

@@ -1,21 +1,22 @@
#pragma once
#include "types.h"
#include "zelda_rtl.h"
#include "sprite.h"
struct CheckPlayerCollOut {
typedef struct CheckPlayerCollOut {
uint16 r4, r6;
uint16 r8, r10;
};
} CheckPlayerCollOut;
struct AncillaOamInfo {
typedef struct AncillaOamInfo {
uint8 x;
uint8 y;
uint8 flags;
};
} AncillaOamInfo;
struct AncillaRadialProjection {
typedef struct AncillaRadialProjection {
uint8 r0, r2, r4, r6;
};
} AncillaRadialProjection;
uint16 Ancilla_GetX(int k);
uint16 Ancilla_GetY(int k);

View File

@@ -1,8 +1,8 @@
#pragma once
struct AttractOamInfo {
typedef struct AttractOamInfo {
int8 x, y;
uint8 c, f, e;
};
} AttractOamInfo;
extern const uint16 kMapMode_Zooms1[224];

View File

@@ -2331,7 +2331,7 @@ void Object_Draw_DoorRight_3x4(uint16 src, int door) {
void Dungeon_OpeningLockedDoor_Combined(bool skip_anim) {
uint8 ctr = 2;
int k, dma_ptr;
int m, k, dma_ptr;
if (skip_anim) {
door_animation_step_indicator = 16;
@@ -2343,7 +2343,7 @@ void Dungeon_OpeningLockedDoor_Combined(bool skip_anim) {
if (door_animation_step_indicator != 12)
goto middle;
step12:
int m = kUpperBitmasks[dung_bg2_attr_table[dung_cur_door_pos] & 7];
m = kUpperBitmasks[dung_bg2_attr_table[dung_cur_door_pos] & 7];
dung_door_opened_incl_adjacent |= m;
dung_door_opened |= m;
ctr = 4;
@@ -2631,7 +2631,7 @@ void Dungeon_LoadRoom() { // 81873a
RoomDraw_DrawAllObjects(cur_p0); // Draw Layer 3 objects to BG2
for (dung_load_ptr_offs = 0; dung_load_ptr_offs != 0x18C; dung_load_ptr_offs += 4) {
MovableBlockData &m = movable_block_datas[dung_load_ptr_offs >> 2];
MovableBlockData m = movable_block_datas[dung_load_ptr_offs >> 2];
if (m.room == dungeon_room_index)
DrawObjects_PushableBlock(m.tilemap, dung_load_ptr_offs);
}
@@ -5174,8 +5174,9 @@ handle_62:
return;
}
if ((a & 0xf0) == 0xf0) {
int j;
handle_f0:
int j = a & 0xf;
j = a & 0xf;
a = door_type_and_slot[j] & 0xfe;
if (a != kDoorType_BreakableWall && a != 0x2A && a != 0x2E)
return;
@@ -5739,8 +5740,9 @@ uint8 OpenChestForItem(uint8 tile, int *chest_position) { // 81eb66
overworld_tileattr[pos + 1] = ptr[2];
overworld_tileattr[pos + 65] = ptr[3];
uint8 attr;
afterStoreCrap:
uint8 attr = (loc < 0x8000) ? 0x27 : 0x00;
attr = (loc < 0x8000) ? 0x27 : 0x00;
dung_bg2_attr_table[pos + 0] = attr;
dung_bg2_attr_table[pos + 64] = attr;
@@ -6131,7 +6133,7 @@ void ClearAndStripeExplodingWall(uint16 dsto) { // 81f811
if (!(dung_door_direction[dung_cur_door_idx >> 1] & 2))
r6++;
uint16 *uvdata = &uvram.t3.data[0];
uint16 *uvdata = &uvram.data[0];
for (;;) {
const uint16 *bg2 = &dung_bg2[dsto];
do {
@@ -8532,7 +8534,7 @@ void PushBlock_HandleCollision(uint8 i, uint16 x, uint16 y) { // 87efb9
bitmask_of_dragstate |= index_of_changable_dungeon_objs[i] ? 4 : 1;
if (dir & 1 ? (r8 >= r10 && (uint16)(r8 - r10) < 8) : (uint16)(r8 - r10) >= 0xfff8) {
*coord_p -= r8 - r10;
(dir & 2 ? link_x_vel : link_y_vel) -= r8 - r10;
*(dir & 2 ? &link_x_vel : &link_y_vel) -= r8 - r10;
}
}
HandleIndoorCameraAndDoors();

View File

@@ -34,21 +34,21 @@ enum {
kDoorType_ShutterTrapDL = 74,
};
struct DungPalInfo {
typedef struct DungPalInfo {
uint8 pal0;
uint8 pal1;
uint8 pal2;
uint8 pal3;
};
} DungPalInfo;
struct RoomBounds {
typedef struct RoomBounds {
union {
struct {
uint16 a0, b0, a1, b1;
};
uint16 v[4];
};
};
} RoomBounds;
#define room_bounds_y (*(RoomBounds*)(g_ram+0x600))
#define room_bounds_x (*(RoomBounds*)(g_ram+0x608))

View File

@@ -2289,7 +2289,7 @@ void Credits_HandleCameraScrollControl() { // 8eaea6
*which -= 0x10;
overworld_screen_trans_dir_bits2 |= sign8(yvel) ? 8 : 4;
}
(sign8(yvel) ? overworld_unk1_neg : overworld_unk1) = -*which;
*(sign8(yvel) ? &overworld_unk1_neg : &overworld_unk1) = -*which;
uint16 r4 = (int8)yvel, subp;
WORD(byte_7E069E[0]) = r4;
uint8 oi = BYTE(overlay_index);
@@ -2321,7 +2321,7 @@ void Credits_HandleCameraScrollControl() { // 8eaea6
*which -= 0x10;
overworld_screen_trans_dir_bits2 |= sign8(xvel) ? 2 : 1;
}
(sign8(xvel) ? overworld_unk3_neg : overworld_unk3) = -*which;
*(sign8(xvel) ? &overworld_unk3_neg : &overworld_unk3) = -*which;
uint16 r4 = (int8)xvel, subp;
WORD(byte_7E069E[1]) = r4;

View File

@@ -1,10 +1,10 @@
#pragma once
struct IntroSpriteEnt {
typedef struct IntroSpriteEnt {
int8 x, y;
uint8 charnum, flags;
uint8 ext;
};
} IntroSpriteEnt;
void Intro_SetupScreen();
void Intro_LoadTextPointersAndPalettes();

View File

@@ -8,6 +8,13 @@
#include "variables.h"
#include "hud.h"
typedef struct ItemBoxGfx {
uint16 v[4];
} ItemBoxGfx;
static void Hud_DrawItem(uint16 a, const ItemBoxGfx *src);
const uint8 kMaxBombsForLevel[] = { 10, 15, 20, 25, 30, 35, 40, 50 };
const uint8 kMaxArrowsForLevel[] = { 30, 35, 40, 45, 50, 55, 60, 70 };
static const uint8 kMaxHealthForLevel[] = { 9, 9, 9, 9, 9, 9, 9, 9, 17, 17, 17, 17, 17, 17, 17, 25, 25, 25, 25, 25, 25 };
@@ -28,7 +35,8 @@ static const uint16 kHudBottlesGfx[128] = {
0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2551, 0x2554, 0x2554, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2556, 0x255e, 0x255e, 0x2553, 0x24f5, 0x2551, 0x2554, 0x2554,
};
static const uint16 kHudItemBottles[9][4] = {
static const ItemBoxGfx kHudItemBottles[9] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2044, 0x2045, 0x2046, 0x2047},
{0x2837, 0x2838, 0x2cc3, 0x2cd3},
@@ -39,155 +47,155 @@ static const uint16 kHudItemBottles[9][4] = {
{0x2837, 0x2838, 0x2839, 0x283a},
{0x2837, 0x2838, 0x2839, 0x283a},
};
static const uint16 kHudItemBow[5][4] = {
static const ItemBoxGfx kHudItemBow[5] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x28ba, 0x28e9, 0x28e8, 0x28cb},
{0x28ba, 0x284a, 0x2849, 0x28cb},
{0x28ba, 0x28e9, 0x28e8, 0x28cb},
{0x28ba, 0x28bb, 0x24ca, 0x28cb},
};
static const uint16 kHudItemBoomerang[3][4] = {
static const ItemBoxGfx kHudItemBoomerang[3] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2cb8, 0x2cb9, 0x2cf5, 0x2cc9},
{0x24b8, 0x24b9, 0x24f5, 0x24c9},
};
static const uint16 kHudItemHookshot[2][4] = {
static const ItemBoxGfx kHudItemHookshot[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x24f5, 0x24f6, 0x24c0, 0x24f5},
};
static const uint16 kHudItemBombs[2][4] = {
static const ItemBoxGfx kHudItemBombs[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2cb2, 0x2cb3, 0x2cc2, 0x6cc2},
};
static const uint16 kHudItemMushroom[3][4] = {
static const ItemBoxGfx kHudItemMushroom[3] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2444, 0x2445, 0x2446, 0x2447},
{0x203b, 0x203c, 0x203d, 0x203e},
};
static const uint16 kHudItemFireRod[2][4] = {
static const ItemBoxGfx kHudItemFireRod[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x24b0, 0x24b1, 0x24c0, 0x24c1},
};
static const uint16 kHudItemIceRod[2][4] = {
static const ItemBoxGfx kHudItemIceRod[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2cb0, 0x2cbe, 0x2cc0, 0x2cc1},
};
static const uint16 kHudItemBombos[2][4] = {
static const ItemBoxGfx kHudItemBombos[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x287d, 0x287e, 0xe87e, 0xe87d},
};
static const uint16 kHudItemEther[2][4] = {
static const ItemBoxGfx kHudItemEther[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2876, 0x2877, 0xE877, 0xE876},
};
static const uint16 kHudItemQuake[2][4] = {
static const ItemBoxGfx kHudItemQuake[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2866, 0x2867, 0xE867, 0xE866},
};
static const uint16 kHudItemTorch[2][4] = {
static const ItemBoxGfx kHudItemTorch[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x24bc, 0x24bd, 0x24cc, 0x24cd},
};
static const uint16 kHudItemHammer[2][4] = {
static const ItemBoxGfx kHudItemHammer[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x20b6, 0x20b7, 0x20c6, 0x20c7},
};
static const uint16 kHudItemFlute[4][4] = {
static const ItemBoxGfx kHudItemFlute[4] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x20d0, 0x20d1, 0x20e0, 0x20e1},
{0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5},
{0x2cd4, 0x2cd5, 0x2ce4, 0x2ce5},
};
static const uint16 kHudItemBugNet[2][4] = {
static const ItemBoxGfx kHudItemBugNet[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x3c40, 0x3c41, 0x2842, 0x3c43},
};
static const uint16 kHudItemBookMudora[2][4] = {
static const ItemBoxGfx kHudItemBookMudora[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x3ca5, 0x3ca6, 0x3cd8, 0x3cd9},
};
static const uint16 kHudItemCaneSomaria[2][4] = {
static const ItemBoxGfx kHudItemCaneSomaria[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x24dc, 0x24dd, 0x24ec, 0x24ed},
};
static const uint16 kHudItemCaneByrna[2][4] = {
static const ItemBoxGfx kHudItemCaneByrna[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2cdc, 0x2cdd, 0x2cec, 0x2ced},
};
static const uint16 kHudItemCape[2][4] = {
static const ItemBoxGfx kHudItemCape[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x24b4, 0x24b5, 0x24c4, 0x24c5},
};
static const uint16 kHudItemMirror[4][4] = {
static const ItemBoxGfx kHudItemMirror[4] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x28de, 0x28df, 0x28ee, 0x28ef},
{0x2c62, 0x2c63, 0x2c72, 0x2c73},
{0x2886, 0x2887, 0x2888, 0x2889},
};
static const uint16 kHudItemGloves[3][4] = {
static const ItemBoxGfx kHudItemGloves[3] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2130, 0x2131, 0x2140, 0x2141},
{0x28da, 0x28db, 0x28ea, 0x28eb},
};
static const uint16 kHudItemBoots[2][4] = {
static const ItemBoxGfx kHudItemBoots[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x3429, 0x342a, 0x342b, 0x342c},
};
static const uint16 kHudItemFlippers[2][4] = {
static const ItemBoxGfx kHudItemFlippers[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2c9a, 0x2c9b, 0x2c9d, 0x2c9e},
};
static const uint16 kHudItemMoonPearl[2][4] = {
static const ItemBoxGfx kHudItemMoonPearl[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2433, 0x2434, 0x2435, 0x2436},
};
static const uint16 kHudItemEmpty[1][4] = {
static const ItemBoxGfx kHudItemEmpty[1] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
};
static const uint16 kHudItemSword[5][4] = {
static const ItemBoxGfx kHudItemSword[5] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x2c64, 0x2cce, 0x2c75, 0x3d25},
{0x2c8a, 0x2c65, 0x2474, 0x3d26},
{0x248a, 0x2465, 0x3c74, 0x2d48},
{0x288a, 0x2865, 0x2c74, 0x2d39},
};
static const uint16 kHudItemShield[4][4] = {
static const ItemBoxGfx kHudItemShield[4] = {
{0x24f5, 0x24f5, 0x24f5, 0x24f5},
{0x2cfd, 0x6cfd, 0x2cfe, 0x6cfe},
{0x34ff, 0x74ff, 0x349f, 0x749f},
{0x2880, 0x2881, 0x288d, 0x288e},
};
static const uint16 kHudItemArmor[5][4] = {
static const ItemBoxGfx kHudItemArmor[5] = {
{0x3c68, 0x7c68, 0x3c78, 0x7c78},
{0x2c68, 0x6c68, 0x2c78, 0x6c78},
{0x2468, 0x6468, 0x2478, 0x6478},
};
static const uint16 kHudItemDungeonCompass[2][4] = {
static const ItemBoxGfx kHudItemDungeonCompass[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x24bf, 0x64bf, 0x2ccf, 0x6ccf},
};
static const uint16 kHudItemPalaceItem[3][4] = {
static const ItemBoxGfx kHudItemPalaceItem[3] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x28d6, 0x68d6, 0x28e6, 0x28e7},
{0x354b, 0x354c, 0x354d, 0x354e},
};
static const uint16 kHudItemDungeonMap[2][4] = {
static const ItemBoxGfx kHudItemDungeonMap[2] = {
{0x20f5, 0x20f5, 0x20f5, 0x20f5},
{0x28de, 0x28df, 0x28ee, 0x28ef},
};
static const uint16 kHudPendants0[2][4] = {
static const ItemBoxGfx kHudPendants0[2] = {
{0x313b, 0x313c, 0x313d, 0x313e},
{0x252b, 0x252c, 0x252d, 0x252e}
};
static const uint16 kHudPendants1[2][4] = {
static const ItemBoxGfx kHudPendants1[2] = {
{0x313b, 0x313c, 0x313d, 0x313e},
{0x2d2b, 0x2d2c, 0x2d2d, 0x2d2e}
};
static const uint16 kHudPendants2[2][4] = {
static const ItemBoxGfx kHudPendants2[2] = {
{0x313b, 0x313c, 0x313d, 0x313e},
{0x3d2b, 0x3d2c, 0x3d2d, 0x3d2e}
};
static const uint16 kHudItemHeartPieces[4][4] = {
static const ItemBoxGfx kHudItemHeartPieces[4] = {
{0x2484, 0x6484, 0x2485, 0x6485},
{0x24ad, 0x6484, 0x2485, 0x6485},
{0x24ad, 0x6484, 0x24ae, 0x6485},
@@ -285,39 +293,40 @@ static const uint16 kHudTilemap[165] = {
0x207f, 0x207f, 0x2854, 0x305e, 0x6854, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f, 0x207f,
0x207f, 0x207f, 0xa850, 0x2856, 0xe850,
};
const uint16 *const kHudItemBoxGfxPtrs[] = {
kHudItemBow[0],
kHudItemBoomerang[0],
kHudItemHookshot[0],
kHudItemBombs[0],
kHudItemMushroom[0],
kHudItemFireRod[0],
kHudItemIceRod[0],
kHudItemBombos[0],
kHudItemEther[0],
kHudItemQuake[0],
kHudItemTorch[0],
kHudItemHammer[0],
kHudItemFlute[0],
kHudItemBugNet[0],
kHudItemBookMudora[0],
kHudItemBottles[0],
kHudItemCaneSomaria[0],
kHudItemCaneByrna[0],
kHudItemCape[0],
kHudItemMirror[0],
kHudItemGloves[0],
kHudItemBoots[0],
kHudItemFlippers[0],
kHudItemMoonPearl[0],
kHudItemEmpty[0],
kHudItemSword[0],
kHudItemShield[0],
kHudItemArmor[0],
kHudItemBottles[0],
kHudItemBottles[0],
kHudItemBottles[0],
kHudItemBottles[0],
static const ItemBoxGfx * const kHudItemBoxGfxPtrs[] = {
kHudItemBow,
kHudItemBoomerang,
kHudItemHookshot,
kHudItemBombs,
kHudItemMushroom,
kHudItemFireRod,
kHudItemIceRod,
kHudItemBombos,
kHudItemEther,
kHudItemQuake,
kHudItemTorch,
kHudItemHammer,
kHudItemFlute,
kHudItemBugNet,
kHudItemBookMudora,
kHudItemBottles,
kHudItemCaneSomaria,
kHudItemCaneByrna,
kHudItemCape,
kHudItemMirror,
kHudItemGloves,
kHudItemBoots,
kHudItemFlippers,
kHudItemMoonPearl,
kHudItemEmpty,
kHudItemSword,
kHudItemShield,
kHudItemArmor,
kHudItemBottles,
kHudItemBottles,
kHudItemBottles,
kHudItemBottles,
};
static const uint16 kUpdateMagicPowerTilemap[17][4] = {
{0x3cf5, 0x3cf5, 0x3cf5, 0x3cf5},
@@ -832,11 +841,11 @@ void Hud_UpdateBottleMenu() { // 8de17f
for (int x = 0; x < 8; x++)
uvram_screen.row[y].col[22 + x] = 0x24f5;
Hud_DrawItem(0x1372, kHudItemBottles[link_bottle_info[0]]);
Hud_DrawItem(0x1472, kHudItemBottles[link_bottle_info[1]]);
Hud_DrawItem(0x1572, kHudItemBottles[link_bottle_info[2]]);
Hud_DrawItem(0x1672, kHudItemBottles[link_bottle_info[3]]);
Hud_DrawItem(0x1408, kHudItemBottles[link_item_bottles ? link_bottle_info[link_item_bottles - 1] : 0]);
Hud_DrawItem(0x1372, &kHudItemBottles[link_bottle_info[0]]);
Hud_DrawItem(0x1472, &kHudItemBottles[link_bottle_info[1]]);
Hud_DrawItem(0x1572, &kHudItemBottles[link_bottle_info[2]]);
Hud_DrawItem(0x1672, &kHudItemBottles[link_bottle_info[3]]);
Hud_DrawItem(0x1408, &kHudItemBottles[link_item_bottles ? link_bottle_info[link_item_bottles - 1] : 0]);
uint16 *p = (uint16 *)&g_ram[kHudItemInVramPtr[hud_cur_item - 1]];
uvram_screen.row[6].col[25] = p[0];
@@ -902,12 +911,12 @@ void Hud_RestoreNormalMenu() { // 8de346
BYTE(nmi_load_target_addr) = 0x22;
}
void Hud_DrawItem(uint16 a, const uint16 *src) { // 8de372
static void Hud_DrawItem(uint16 a, const ItemBoxGfx *src) { // 8de372
uint16 *dst = (uint16 *)&g_ram[a];
dst[0] = src[0];
dst[1] = src[1];
dst[32] = src[2];
dst[33] = src[3];
dst[0] = src->v[0];
dst[1] = src->v[1];
dst[32] = src->v[2];
dst[33] = src->v[3];
}
void Hud_SearchForEquippedItem() { // 8de399
@@ -959,26 +968,26 @@ void Hud_DrawYButtonItems(uint16 mask) { // 8de3d9
uvram_screen.row[5].col[3] = 0x246E;
uvram_screen.row[5].col[4] = 0x246F;
Hud_DrawItem(0x11c8, kHudItemBow[link_item_bow]);
Hud_DrawItem(0x11ce, kHudItemBoomerang[link_item_boomerang]);
Hud_DrawItem(0x11d4, kHudItemHookshot[link_item_hookshot]);
Hud_DrawItem(0x11da, kHudItemBombs[link_item_bombs ? 1 : 0]);
Hud_DrawItem(0x11e0, kHudItemMushroom[link_item_mushroom]);
Hud_DrawItem(0x1288, kHudItemFireRod[link_item_fire_rod]);
Hud_DrawItem(0x128e, kHudItemIceRod[link_item_ice_rod]);
Hud_DrawItem(0x1294, kHudItemBombos[link_item_bombos_medallion]);
Hud_DrawItem(0x129a, kHudItemEther[link_item_ether_medallion]);
Hud_DrawItem(0x12a0, kHudItemQuake[link_item_quake_medallion]);
Hud_DrawItem(0x1348, kHudItemTorch[link_item_torch]);
Hud_DrawItem(0x134e, kHudItemHammer[link_item_hammer]);
Hud_DrawItem(0x1354, kHudItemFlute[link_item_flute]);
Hud_DrawItem(0x135a, kHudItemBugNet[link_item_bug_net]);
Hud_DrawItem(0x1360, kHudItemBookMudora[link_item_book_of_mudora]);
Hud_DrawItem(0x1408, kHudItemBottles[link_item_bottles ? link_bottle_info[link_item_bottles - 1] : 0]);
Hud_DrawItem(0x140e, kHudItemCaneSomaria[link_item_cane_somaria]);
Hud_DrawItem(0x1414, kHudItemCaneByrna[link_item_cane_byrna]);
Hud_DrawItem(0x141a, kHudItemCape[link_item_cape]);
Hud_DrawItem(0x1420, kHudItemMirror[link_item_mirror]);
Hud_DrawItem(0x11c8, &kHudItemBow[link_item_bow]);
Hud_DrawItem(0x11ce, &kHudItemBoomerang[link_item_boomerang]);
Hud_DrawItem(0x11d4, &kHudItemHookshot[link_item_hookshot]);
Hud_DrawItem(0x11da, &kHudItemBombs[link_item_bombs ? 1 : 0]);
Hud_DrawItem(0x11e0, &kHudItemMushroom[link_item_mushroom]);
Hud_DrawItem(0x1288, &kHudItemFireRod[link_item_fire_rod]);
Hud_DrawItem(0x128e, &kHudItemIceRod[link_item_ice_rod]);
Hud_DrawItem(0x1294, &kHudItemBombos[link_item_bombos_medallion]);
Hud_DrawItem(0x129a, &kHudItemEther[link_item_ether_medallion]);
Hud_DrawItem(0x12a0, &kHudItemQuake[link_item_quake_medallion]);
Hud_DrawItem(0x1348, &kHudItemTorch[link_item_torch]);
Hud_DrawItem(0x134e, &kHudItemHammer[link_item_hammer]);
Hud_DrawItem(0x1354, &kHudItemFlute[link_item_flute]);
Hud_DrawItem(0x135a, &kHudItemBugNet[link_item_bug_net]);
Hud_DrawItem(0x1360, &kHudItemBookMudora[link_item_book_of_mudora]);
Hud_DrawItem(0x1408, &kHudItemBottles[link_item_bottles ? link_bottle_info[link_item_bottles - 1] : 0]);
Hud_DrawItem(0x140e, &kHudItemCaneSomaria[link_item_cane_somaria]);
Hud_DrawItem(0x1414, &kHudItemCaneByrna[link_item_cane_byrna]);
Hud_DrawItem(0x141a, &kHudItemCape[link_item_cape]);
Hud_DrawItem(0x1420, &kHudItemMirror[link_item_mirror]);
}
void Hud_DrawUnknownBox(uint16 palmask) { // 8de647
@@ -1072,9 +1081,9 @@ void Hud_DrawAbilityText(uint16 palmask) { // 8de6b6
}
void Hud_DrawAbilityIcons() { // 8de7b7
Hud_DrawItem(0x16D0, kHudItemGloves[link_item_gloves]);
Hud_DrawItem(0x16C8, kHudItemBoots[link_item_boots]);
Hud_DrawItem(0x16D8, kHudItemFlippers[link_item_flippers]);
Hud_DrawItem(0x16D0, &kHudItemGloves[link_item_gloves]);
Hud_DrawItem(0x16C8, &kHudItemBoots[link_item_boots]);
Hud_DrawItem(0x16D8, &kHudItemFlippers[link_item_flippers]);
if (link_item_gloves)
Hud_DrawGlovesText(link_item_gloves != 1);
}
@@ -1100,9 +1109,9 @@ void Hud_DrawProgressIcons_Pendants() { // 8de9d3
src += 10;
}
Hud_DrawItem(0x13B2, kHudPendants0[(link_which_pendants >> 0) & 1]);
Hud_DrawItem(0x146E, kHudPendants1[(link_which_pendants >> 1) & 1]);
Hud_DrawItem(0x1476, kHudPendants2[(link_which_pendants >> 2) & 1]);
Hud_DrawItem(0x13B2, &kHudPendants0[(link_which_pendants >> 0) & 1]);
Hud_DrawItem(0x146E, &kHudPendants1[(link_which_pendants >> 1) & 1]);
Hud_DrawItem(0x1476, &kHudPendants2[(link_which_pendants >> 2) & 1]);
}
void Hud_DrawProgressIcons_Crystals() { // 8dea62
@@ -1188,7 +1197,7 @@ void Hud_DrawSelectedYButtonItem() { // 8deb3a
}
void Hud_DrawMoonPearl() { // 8dece9
Hud_DrawItem(0x16e0, kHudItemMoonPearl[link_item_moon_pearl]);
Hud_DrawItem(0x16e0, &kHudItemMoonPearl[link_item_moon_pearl]);
}
void Hud_DrawEquipment(uint16 palmask) { // 8ded29
@@ -1232,34 +1241,34 @@ void Hud_DrawEquipment(uint16 palmask) { // 8ded29
if (cur_palace_index_x2 == 0xff) {
for (int i = 0; i < 8; i++)
uvram_screen.row[26].col[22 + i] = 0x24F5;
Hud_DrawItem(0x16f2, kHudItemHeartPieces[link_heart_pieces]);
Hud_DrawItem(0x16f2, &kHudItemHeartPieces[link_heart_pieces]);
}
Hud_DrawItem(0x15ec, kHudItemSword[link_sword_type == 0xff ? 0 : link_sword_type]);
Hud_DrawItem(0x15ec, &kHudItemSword[link_sword_type == 0xff ? 0 : link_sword_type]);
}
void Hud_DrawShield() { // 8dee21
Hud_DrawItem(0x15f2, kHudItemShield[link_shield_type]);
Hud_DrawItem(0x15f2, &kHudItemShield[link_shield_type]);
}
void Hud_DrawArmor() { // 8dee3c
Hud_DrawItem(0x15f8, kHudItemArmor[link_armor]);
Hud_DrawItem(0x15f8, &kHudItemArmor[link_armor]);
}
void Hud_DrawMapAndBigKey() { // 8dee57
if (cur_palace_index_x2 != 0xff &&
(link_bigkey << (cur_palace_index_x2 >> 1)) & 0x8000) {
Hud_DrawItem(0x16F8, kHudItemPalaceItem[CheckPalaceItemPosession() + 1]);
Hud_DrawItem(0x16F8, &kHudItemPalaceItem[CheckPalaceItemPosession() + 1]);
}
if (cur_palace_index_x2 != 0xff &&
(link_dungeon_map << (cur_palace_index_x2 >> 1)) & 0x8000) {
Hud_DrawItem(0x16EC, kHudItemDungeonMap[1]);
Hud_DrawItem(0x16EC, &kHudItemDungeonMap[1]);
}
}
void Hud_DrawCompass() { // 8def39
if (cur_palace_index_x2 != 0xff &&
(link_compass << (cur_palace_index_x2 >> 1)) & 0x8000) {
Hud_DrawItem(0x16F2, kHudItemDungeonCompass[1]);
Hud_DrawItem(0x16F2, &kHudItemDungeonCompass[1]);
}
}
@@ -1284,11 +1293,11 @@ void Hud_DrawBottleMenu(uint16 palmask) { // 8def67
for (int x = 0; x < 8; x++)
uvram_screen.row[y].col[22 + x] = 0x24f5;
Hud_DrawItem(0x1372, kHudItemBottles[link_bottle_info[0]]);
Hud_DrawItem(0x1472, kHudItemBottles[link_bottle_info[1]]);
Hud_DrawItem(0x1572, kHudItemBottles[link_bottle_info[2]]);
Hud_DrawItem(0x1672, kHudItemBottles[link_bottle_info[3]]);
Hud_DrawItem(0x1408, kHudItemBottles[link_bottle_info[link_item_bottles - 1]]);
Hud_DrawItem(0x1372, &kHudItemBottles[link_bottle_info[0]]);
Hud_DrawItem(0x1472, &kHudItemBottles[link_bottle_info[1]]);
Hud_DrawItem(0x1572, &kHudItemBottles[link_bottle_info[2]]);
Hud_DrawItem(0x1672, &kHudItemBottles[link_bottle_info[3]]);
Hud_DrawItem(0x1408, &kHudItemBottles[link_bottle_info[link_item_bottles - 1]]);
uint16 *p = (uint16 *)&g_ram[kHudItemInVramPtr[hud_cur_item - 1]];
@@ -1411,7 +1420,7 @@ void Hud_UpdateItemBox() { // 8dfafd
else if (hud_cur_item == 16)
item_val = link_bottle_info[item_val - 1];
const uint16 *p = kHudItemBoxGfxPtrs[hud_cur_item - 1] + item_val * 4;
const uint16 *p = kHudItemBoxGfxPtrs[hud_cur_item - 1][item_val].v;
hud_tile_indices_buffer[37] = p[0];
hud_tile_indices_buffer[38] = p[1];
@@ -1484,3 +1493,6 @@ void Hud_UpdateHearts(uint16 *dst, const uint16 *src, int n) { // 8dfdab
}
}
const uint16 *Hud_GetItemBoxPtr(int item) {
return kHudItemBoxGfxPtrs[item]->v;
}

10
hud.h
View File

@@ -1,14 +1,6 @@
#pragma once
#include "types.h"
extern const uint16 *const kHudItemBoxGfxPtrs[];
void Hud_RefreshIcon();
uint8 CheckPalaceItemPosession();
void Hud_GotoPrevItem();
@@ -38,7 +30,6 @@ void Hud_BottleMenu();
void Hud_UpdateBottleMenu();
void Hud_EraseBottleMenu();
void Hud_RestoreNormalMenu();
void Hud_DrawItem(uint16 a, const uint16 *src);
void Hud_SearchForEquippedItem();
uint16 Hud_GetPaletteMask(uint8 what);
void Hud_DrawYButtonItems(uint16 mask);
@@ -70,3 +61,4 @@ void Hud_UpdateInternal();
void Hud_Update_IgnoreItemBox();
void Hud_Update_IgnoreHealth();
void Hud_UpdateHearts(uint16 *dst, const uint16 *src, int n);
const uint16 *Hud_GetItemBoxPtr(int item);

View File

@@ -1,4 +1,3 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -20,6 +19,9 @@
#include "zelda_rtl.h"
extern Ppu *GetPpuForRendering();
extern Dsp *GetDspForRendering();
extern uint8 g_emulated_ram[0x20000];
bool g_run_without_emu = false;
@@ -33,13 +35,17 @@ bool RunOneFrame(Snes *snes, int input_state, bool turbo);
static uint8_t* readFile(char* name, size_t* length);
static bool loadRom(char* name, Snes* snes);
static bool checkExtention(const char* name, bool forZip);
static void playAudio(Snes *snes, SDL_AudioDeviceID device, int16_t* audioBuffer);
static void renderScreen(SDL_Renderer* renderer, SDL_Texture* texture);
static void handleInput(int keyCode, int modCode, bool pressed);
int input1_current_state;
void NORETURN Die(const char *error) {
fprintf(stderr, "Error: %s\n", error);
exit(1);
}
void setButtonState(int button, bool pressed) {
// set key in constroller
if (pressed) {
@@ -49,27 +55,6 @@ void setButtonState(int button, bool pressed) {
}
}
void ZeldaReadSram(Snes *snes) {
FILE *f = fopen("saves/sram.dat", "rb");
if (f) {
fread(g_zenv.sram, 1, 8192, f);
memcpy(snes->cart->ram, g_zenv.sram, 8192);
fclose(f);
}
}
void ZeldaWriteSram() {
rename("saves/sram.dat", "saves/sram.bak");
FILE *f = fopen("saves/sram.dat", "wb");
if (f) {
fwrite(g_zenv.sram, 1, 8192, f);
fclose(f);
} else {
fprintf(stderr, "Unable to write saves/sram.dat\n");
}
}
#undef main
int main(int argc, char** argv) {
// set up SDL
@@ -243,9 +228,6 @@ int main(int argc, char** argv) {
return 0;
}
extern struct Ppu *GetPpuForRendering();
extern struct Dsp *GetDspForRendering();
static void playAudio(Snes *snes, SDL_AudioDeviceID device, int16_t* audioBuffer) {
// generate enough samples
if (!kIsOrigEmu && snes) {
@@ -335,31 +317,11 @@ static void handleInput(int keyCode, int keyMod, bool pressed) {
}
}
static bool checkExtention(const char* name, bool forZip) {
if(name == NULL) return false;
int length = strlen(name);
if(length < 4) return false;
if(forZip) {
if(strcmp(name + length - 4, ".zip") == 0) return true;
if(strcmp(name + length - 4, ".ZIP") == 0) return true;
} else {
if(strcmp(name + length - 4, ".smc") == 0) return true;
if(strcmp(name + length - 4, ".SMC") == 0) return true;
if(strcmp(name + length - 4, ".sfc") == 0) return true;
if(strcmp(name + length - 4, ".SFC") == 0) return true;
}
return false;
}
static bool loadRom(char* name, Snes* snes) {
// zip library from https://github.com/kuba--/zip
size_t length = 0;
uint8_t* file = NULL;
file = readFile(name, &length);
if(file == NULL) {
puts("Failed to read file");
return false;
}
if(!file) Die("Failed to read file");
PatchRom(file);
@@ -368,6 +330,7 @@ static bool loadRom(char* name, Snes* snes) {
return result;
}
static uint8_t* readFile(char* name, size_t* length) {
FILE* f = fopen(name, "rb");
if(f == NULL) {
@@ -377,6 +340,7 @@ static uint8_t* readFile(char* name, size_t* length) {
int size = ftell(f);
rewind(f);
uint8_t* buffer = (uint8_t *)malloc(size);
if (!buffer) Die("malloc failed");
fread(buffer, size, 1, f);
fclose(f);
*length = size;

View File

@@ -2746,7 +2746,7 @@ void RenderText_FindYItem_Next() { // 8ecded
void RenderText_DrawSelectedYItem() { // 8ece14
int item = choice_in_multiselect_box;
const uint16 *p = kHudItemBoxGfxPtrs[item];
const uint16 *p = Hud_GetItemBoxPtr(item);
p += ((item == 3 || item == 32) ? 1 : (&link_item_bow)[item]) * 4;
uint8 *vwf300 = &g_ram[0x1300];
memcpy(vwf300 + 0xc2, p, 4);

View File

View File

@@ -276,7 +276,7 @@ void NMI_DoUpdates() { // 8089e0
}
if (nmi_copy_packets_flag) {
uint8 *p = (uint8 *)uvram.t3.data;
uint8 *p = (uint8 *)uvram.data;
do {
int dst = WORD(p[0]);
int vmain = p[2];
@@ -321,7 +321,7 @@ void NMI_UploadBG3Text() { // 808ce4
}
void NMI_UpdateOWScroll() { // 808d13
uint8 *src = (uint8 *)uvram.t3.data, *src_org = src;
uint8 *src = (uint8 *)uvram.data, *src_org = src;
int f = WORD(src[0]);
int step = (f & 0x8000) ? 32 : 1;
int len = f & 0x3fff;

View File

@@ -21,7 +21,7 @@ def replace_in_file(fname):
for filename in glob.glob('*.cpp') + glob.glob('*.h'):
for filename in glob.glob('*.c') + glob.glob('*.h'):
replace_in_file(filename)

View File

@@ -225,7 +225,7 @@ static PlayerHandlerFunc *const kOverworldSubmodules[48] = {
&Overworld_Func1E,
&Overworld_Func1F,
&Overworld_LoadOverlays2,
&Overworld_LoadAmbientOverlay,
&Overworld_LoadAmbientOverlayFalse,
&Overworld_Func22,
&Module09_MirrorWarp,
&Overworld_StartMosaicTransition,
@@ -2054,7 +2054,7 @@ void Overworld_LoadAmbientOverlay(bool load_map_data) { // 82ed25
INIDISP_copy = 0;
}
void Overworld_LoadAmbientOverlay() { // 82ed24
void Overworld_LoadAmbientOverlayFalse() { // 82ed24
Overworld_LoadAmbientOverlay(false);
}
@@ -2109,7 +2109,7 @@ void Overworld_HandleOverlaysAndBombDoors() { // 82ef29
void TriggerAndFinishMapLoadStripe_Y(int n) { // 82ef7a
BYTE(overworld_screen_trans_dir_bits2) = 8;
nmi_subroutine_index = 3;
uint16 *dst = uvram.t3.data;
uint16 *dst = uvram.data;
*dst++ = 0x80;
do {
dst = BufferAndBuildMap16Stripes_Y(dst);
@@ -2122,7 +2122,7 @@ void TriggerAndFinishMapLoadStripe_Y(int n) { // 82ef7a
void TriggerAndFinishMapLoadStripe_X(int n) { // 82efb3
BYTE(overworld_screen_trans_dir_bits2) = 2;
nmi_subroutine_index = 3;
uint16 *dst = uvram.t3.data;
uint16 *dst = uvram.data;
*dst++ = 0x8040;
do {
dst = BufferAndBuildMap16Stripes_X(dst);
@@ -2240,7 +2240,7 @@ void CreateInitialOWScreenView_Small_East() { // 82f1b7
}
void OverworldTransitionScrollAndLoadMap() { // 82f20e
uint16 *dst = uvram.t3.data;
uint16 *dst = uvram.data;
switch (BYTE(overworld_screen_trans_dir_bits2)) {
case 1: dst = BuildFullStripeDuringTransition_East(dst); break;
case 2: dst = BuildFullStripeDuringTransition_West(dst); break;
@@ -2251,7 +2251,7 @@ void OverworldTransitionScrollAndLoadMap() { // 82f20e
submodule_index = 0;
}
dst[0] = dst[1] = 0xffff;
if (dst != uvram.t3.data)
if (dst != uvram.data)
nmi_subroutine_index = 3;
}
@@ -2288,7 +2288,7 @@ uint16 *BuildFullStripeDuringTransition_East(uint16 *dst) { // 82f24a
}
void OverworldHandleMapScroll() { // 82f273
uint16 *dst = uvram.t3.data;
uint16 *dst = uvram.data;
switch (BYTE(overworld_screen_trans_dir_bits2)) {
case 1:
dst = CheckForNewlyLoadedMapAreas_East(dst);
@@ -2321,7 +2321,7 @@ void OverworldHandleMapScroll() { // 82f273
submodule_index = 0;
}
dst[0] = dst[1] = 0xffff;
if (dst != uvram.t3.data)
if (dst != uvram.data)
nmi_subroutine_index = 3;
overworld_screen_transition = overworld_screen_trans_dir_bits2;
}
@@ -3313,8 +3313,8 @@ uint16 Overworld_ToolAndTileInteraction(uint16 x, uint16 y) { // 9bbd82
scratch_1 = y & ~0xf;
index_of_interacting_tile = yv;
yv = (attr == 0x72a) ? 0xdc8 : 0xdc7;
check_secret:
uint32 result;
check_secret:
result = Overworld_RevealSecret(pos);
if (result != 0)
yv = result;

View File

@@ -96,7 +96,7 @@ void Overworld_LoadBirdTravelPos(int k);
void FluteMenu_LoadSelectedScreenPalettes();
void FindPartnerWhirlpoolExit();
void Overworld_LoadAmbientOverlay(bool load_map_data);
void Overworld_LoadAmbientOverlay();
void Overworld_LoadAmbientOverlayFalse();
void Overworld_LoadAndBuildScreen();
void Module08_02_LoadAndAdvance();
void Overworld_DrawQuadrantsAndOverlays();

View File

@@ -2006,8 +2006,8 @@ void Link_HandleAPress() { // 879baa
}
action = 1;
}
attempt_action:
static const uint8 kAbilityBitmasks[] = { 0xE0, 0x40, 4, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0 };
attempt_action:
if (!(kAbilityBitmasks[action] & link_ability_flags)) {
bitfield_for_a_button = 0;
return;

View File

@@ -396,10 +396,10 @@ static const uint16 kLinkDmaGraphicsIndices[511] = {
203, 72, 113, 99, 26, 295, 102, 30, 105, 203, 107, 10, 10, 109, 109, 13, 13, 112, 114, 110, 203, 297, 299, 300, 301, 302, 63, 16, 16, 79, 79, 294,
80, 294, 19, 19, 20, 20, 21, 21, 81, 82, 81, 23, 23, 24, 24, 25, 130, 131, 132, 133, 134, 134, 28, 28, 29, 121, 122, 123, 124, 129, 129,
};
struct LinkSpriteBody {
typedef struct LinkSpriteBody {
int8 y, x;
uint8 tile;
};
} LinkSpriteBody;
static const LinkSpriteBody kLinkSpriteBodys[303] = {
{ 0, 0, 0x00},
{ 1, 0, 0x00},

View File

@@ -1,10 +1,10 @@
#pragma once
#include "types.h"
struct SwordResult {
typedef struct SwordResult {
uint8 r6;
uint8 r12;
};
} SwordResult;
bool PlayerOam_WantInvokeSword();
void CalculateSwordHitBox();

View File

@@ -24,9 +24,9 @@ static const int8 kPolySinCos[320] = {
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
};
struct Vertex3 {
typedef struct Vertex3 {
int8 x, y, z;
};
} Vertex3;
static const Vertex3 kPoly0_Vtx[6] = {
{ 0, 65, 0},
{ 0, -65, 0},
@@ -60,12 +60,12 @@ static const uint8 kPoly1_Polys[28] = {
4, 1, 5, 4, 2, 4,
4, 3, 0, 2, 4, 3,
};
struct PolyConfig {
typedef struct PolyConfig {
uint8 num_vtx, num_poly;
uint16 vtx_val, polys_val;
const Vertex3 *vertex;
const uint8 *poly;
};
} PolyConfig;
static const PolyConfig kPolyConfigs[2] = {
{6, 8, 0xff98, 0xffaa, kPoly0_Vtx, kPoly0_Polys},
{6, 5, 0xffd2, 0xffe4, kPoly1_Vtx, kPoly1_Polys},

View File

@@ -31,8 +31,6 @@ void apu_free(Apu* apu) {
}
void apu_saveload(Apu *apu, SaveLoadFunc *func, void *ctx) {
size_t size = sizeof(struct Apu2);
size_t size2 = offsetof(Apu, hist);
func(ctx, apu->ram, offsetof(Apu, hist) - offsetof(Apu, ram));
dsp_saveload(apu->dsp, func, ctx);
spc_saveload(apu->spc, func, ctx);
@@ -157,7 +155,7 @@ void apu_cpuWrite(Apu* apu, uint16_t adr, uint8_t val) {
int i = apu->hist.count;
if (i != 256) {
apu->hist.count = i + 1;
apu->hist.addr[i] = (DspReg)apu->dspAdr;
apu->hist.addr[i] = apu->dspAdr;
apu->hist.val[i] = val;
}
if(apu->dspAdr < 0x80) dsp_write(apu->dsp, apu->dspAdr, val);

View File

@@ -39,7 +39,7 @@ struct Apu {
};
};
struct Apu2 {
typedef struct Apu2 {
// Snes* snes;
Spc* spc;
Dsp* dsp;
@@ -51,7 +51,7 @@ struct Apu2 {
uint8_t outPorts[4];
Timer timer[3];
uint8_t cpuCyclesLeft;
};
} Apu2;
Apu* apu_init();
void apu_free(Apu* apu);

View File

@@ -8,6 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "dsp_regs.h"
typedef struct Dsp Dsp;
#include "saveload.h"
@@ -81,11 +82,9 @@ struct Dsp {
};
#include "../dsp_regs.h"
typedef struct DspRegWriteHistory {
uint32_t count;
enum DspReg addr[256];
uint8_t addr[256];
uint8_t val[256];
} DspRegWriteHistory;

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef DSP_REGS_H
#define DSP_REGS_H
enum DspReg {
V0VOLL = 0,
@@ -105,4 +106,5 @@ enum DspReg {
ENDX = 0x7C,
EDL = 0x7D,
FIR7 = 0x7F,
};
};
#endif // DSP_REGS_H

View File

@@ -3,21 +3,157 @@
#include <stdlib.h>
#include <SDL.h>
#include <assert.h>
#include <algorithm>
#include "types.h"
#include "snes/spc.h"
#include "snes/dsp_regs.h"
#include "tracing.h"
#include "spc_player.h"
#include "dsp_regs.h"
typedef struct MemMap {
uint16 off, org_off;
} MemMap;
typedef struct MemMapSized {
uint16 off, org_off, size;
} MemMapSized;
static const MemMap kChannel_Maps[] = {
{offsetof(Channel, pattern_order_ptr_for_chan), 0x8030},
{offsetof(Channel, note_ticks_left), 0x70},
{offsetof(Channel, note_keyoff_ticks_left), 0x71},
{offsetof(Channel, subroutine_num_loops), 0x80},
{offsetof(Channel, volume_fade_ticks), 0x90},
{offsetof(Channel, pan_num_ticks), 0x91},
{offsetof(Channel, pitch_slide_length), 0xa0},
{offsetof(Channel, pitch_slide_delay_left), 0xa1},
{offsetof(Channel, vibrato_hold_count), 0xb0},
{offsetof(Channel, vib_depth), 0xb1},
{offsetof(Channel, tremolo_hold_count), 0xc0},
{offsetof(Channel, tremolo_depth), 0xc1},
{offsetof(Channel, vibrato_change_count), 0x100},
{offsetof(Channel, note_length), 0x200},
{offsetof(Channel, note_gate_off_fixedpt), 0x201},
{offsetof(Channel, channel_volume_master), 0x210},
{offsetof(Channel, instrument_id), 0x211},
{offsetof(Channel, instrument_pitch_base), 0x8220},
{offsetof(Channel, saved_pattern_ptr), 0x8230},
{offsetof(Channel, pattern_start_ptr), 0x8240},
{offsetof(Channel, pitch_envelope_num_ticks), 0x280},
{offsetof(Channel, pitch_envelope_delay), 0x281},
{offsetof(Channel, pitch_envelope_direction), 0x290},
{offsetof(Channel, pitch_envelope_slide_value), 0x291},
{offsetof(Channel, vibrato_count), 0x2a0},
{offsetof(Channel, vibrato_rate), 0x2a1},
{offsetof(Channel, vibrato_delay_ticks), 0x2b0},
{offsetof(Channel, vibrato_fade_num_ticks), 0x2b1},
{offsetof(Channel, vibrato_fade_add_per_tick), 0x2c0},
{offsetof(Channel, vibrato_depth_target), 0x2c1},
{offsetof(Channel, tremolo_count), 0x2d0},
{offsetof(Channel, tremolo_rate), 0x2d1},
{offsetof(Channel, tremolo_delay_ticks), 0x2e0},
{offsetof(Channel, channel_transposition), 0x2f0},
{offsetof(Channel, channel_volume), 0x8300},
{offsetof(Channel, volume_fade_addpertick), 0x8310},
{offsetof(Channel, volume_fade_target), 0x320},
{offsetof(Channel, final_volume), 0x321},
{offsetof(Channel, pan_value), 0x8330},
{offsetof(Channel, pan_add_per_tick), 0x8340},
{offsetof(Channel, pan_target_value), 0x350},
{offsetof(Channel, pan_flag_with_phase_invert), 0x351},
{offsetof(Channel, pitch), 0x8360},
{offsetof(Channel, pitch_add_per_tick), 0x8370},
{offsetof(Channel, pitch_target), 0x380},
{offsetof(Channel, fine_tune), 0x381},
{offsetof(Channel, sfx_sound_ptr), 0x8390},
{offsetof(Channel, sfx_which_sound), 0x3a0},
{offsetof(Channel, sfx_arr_countdown), 0x3a1},
{offsetof(Channel, sfx_note_length_left), 0x3b0},
{offsetof(Channel, sfx_note_length), 0x3b1},
{offsetof(Channel, sfx_pan), 0x3d0},
};
static const MemMapSized kSpcPlayer_Maps[] = {
{offsetof(SpcPlayer, new_value_from_snes), 0x0, 4},
{offsetof(SpcPlayer, port_to_snes), 0x4, 4},
{offsetof(SpcPlayer, last_value_from_snes), 0x8, 4},
{offsetof(SpcPlayer, counter_sf0c), 0xc, 1},
{offsetof(SpcPlayer, _always_zero), 0xe, 2},
{offsetof(SpcPlayer, temp_accum), 0x10, 2},
{offsetof(SpcPlayer, ttt), 0x12, 1},
{offsetof(SpcPlayer, did_affect_volumepitch_flag), 0x13, 1},
{offsetof(SpcPlayer, addr0), 0x14, 2},
{offsetof(SpcPlayer, addr1), 0x16, 2},
{offsetof(SpcPlayer, lfsr_value), 0x18, 2},
{offsetof(SpcPlayer, is_chan_on), 0x1a, 1},
{offsetof(SpcPlayer, fast_forward), 0x1b, 1},
{offsetof(SpcPlayer, sfx_start_arg_pan), 0x20, 1},
{offsetof(SpcPlayer, sfx_sound_ptr_cur), 0x2c, 2},
{offsetof(SpcPlayer, music_ptr_toplevel), 0x40, 2},
{offsetof(SpcPlayer, block_count), 0x42, 1},
{offsetof(SpcPlayer, sfx_timer_accum), 0x43, 1},
{offsetof(SpcPlayer, chn), 0x44, 1},
{offsetof(SpcPlayer, key_ON), 0x45, 1},
{offsetof(SpcPlayer, key_OFF), 0x46, 1},
{offsetof(SpcPlayer, cur_chan_bit), 0x47, 1},
{offsetof(SpcPlayer, reg_FLG), 0x48, 1},
{offsetof(SpcPlayer, reg_NON), 0x49, 1},
{offsetof(SpcPlayer, reg_EON), 0x4a, 1},
{offsetof(SpcPlayer, reg_PMON), 0x4b, 1},
{offsetof(SpcPlayer, echo_stored_time), 0x4c, 1},
{offsetof(SpcPlayer, echo_parameter_EDL), 0x4d, 1},
{offsetof(SpcPlayer, reg_EFB), 0x4e, 1},
{offsetof(SpcPlayer, global_transposition), 0x50, 1},
{offsetof(SpcPlayer, main_tempo_accum), 0x51, 1},
{offsetof(SpcPlayer, tempo), 0x52, 2},
{offsetof(SpcPlayer, tempo_fade_num_ticks), 0x54, 1},
{offsetof(SpcPlayer, tempo_fade_final), 0x55, 1},
{offsetof(SpcPlayer, tempo_fade_add), 0x56, 2},
{offsetof(SpcPlayer, master_volume), 0x58, 2},
{offsetof(SpcPlayer, master_volume_fade_ticks), 0x5a, 1},
{offsetof(SpcPlayer, master_volume_fade_target), 0x5b, 1},
{offsetof(SpcPlayer, master_volume_fade_add_per_tick), 0x5c, 2},
{offsetof(SpcPlayer, vol_dirty), 0x5e, 1},
{offsetof(SpcPlayer, percussion_base_id), 0x5f, 1},
{offsetof(SpcPlayer, echo_volume_left), 0x60, 2},
{offsetof(SpcPlayer, echo_volume_right), 0x62, 2},
{offsetof(SpcPlayer, echo_volume_fade_add_left), 0x64, 2},
{offsetof(SpcPlayer, echo_volume_fade_add_right), 0x66, 2},
{offsetof(SpcPlayer, echo_volume_fade_ticks), 0x68, 1},
{offsetof(SpcPlayer, echo_volume_fade_target_left), 0x69, 1},
{offsetof(SpcPlayer, echo_volume_fade_target_right), 0x6a, 1},
{offsetof(SpcPlayer, sfx_channel_index), 0x3c0, 1},
{offsetof(SpcPlayer, current_bit), 0x3c1, 1},
{offsetof(SpcPlayer, dsp_register_index), 0x3c2, 1},
{offsetof(SpcPlayer, echo_channels), 0x3c3, 1},
{offsetof(SpcPlayer, byte_3C4), 0x3c4, 1},
{offsetof(SpcPlayer, byte_3C5), 0x3c5, 1},
{offsetof(SpcPlayer, echo_fract_incr), 0x3c7, 1},
{offsetof(SpcPlayer, sfx_channel_index2), 0x3c8, 1},
{offsetof(SpcPlayer, sfx_channel_bit), 0x3c9, 1},
{offsetof(SpcPlayer, pause_music_ctr), 0x3ca, 1},
{offsetof(SpcPlayer, port2_active), 0x3cb, 1},
{offsetof(SpcPlayer, port2_current_bit), 0x3cc, 1},
{offsetof(SpcPlayer, port3_active), 0x3cd, 1},
{offsetof(SpcPlayer, port3_current_bit), 0x3ce, 1},
{offsetof(SpcPlayer, port1_active), 0x3cf, 1},
{offsetof(SpcPlayer, port1_current_bit), 0x3e0, 1},
{offsetof(SpcPlayer, byte_3E1), 0x3e1, 1},
{offsetof(SpcPlayer, sfx_play_echo_flag), 0x3e2, 1},
{offsetof(SpcPlayer, sfx_channels_echo_mask2), 0x3e3, 1},
{offsetof(SpcPlayer, port1_counter), 0x3e4, 1},
{offsetof(SpcPlayer, channel_67_volume), 0x3e5, 1},
{offsetof(SpcPlayer, cutk_always_zero), 0x3ff, 1},
};
static void PlayNote(SpcPlayer *p, Channel *c, uint8 note);
static void Dsp_Write(SpcPlayer *p, uint8_t reg, uint8 value) {
if (DspRegWriteHistory *hist = p->reg_write_history) {
DspRegWriteHistory *hist = p->reg_write_history;
if (hist) {
if (hist->count < 256) {
hist->addr[hist->count] = (DspReg)reg;
hist->addr[hist->count] = reg;
hist->val[hist->count] = value;
hist->count++;
}
@@ -85,7 +221,7 @@ static void WriteVolumeToDsp(SpcPlayer *p, Channel *c, uint16 volume) {
t = t * c->final_volume >> 8;
if ((c->pan_flag_with_phase_invert << i) & 0x80)
t = -t;
Dsp_Write(p, (DspReg)(V0VOLL + i + c->index * 16), t);
Dsp_Write(p, V0VOLL + i + c->index * 16, t);
volume = 0x1400 - volume;
}
}
@@ -108,8 +244,8 @@ static void WritePitch(SpcPlayer *p, Channel *c, uint16 pitch) {
t = c->instrument_pitch_base * t >> 8;
if (!(p->cur_chan_bit & p->is_chan_on)) {
uint8 reg = c->index * 16;
Dsp_Write(p, (DspReg)(reg + V0PITCHL), t & 0xff);
Dsp_Write(p, (DspReg)(reg + V0PITCHH), t >> 8);
Dsp_Write(p, reg + V0PITCHL, t & 0xff);
Dsp_Write(p, reg + V0PITCHH, t >> 8);
}
}
@@ -149,7 +285,7 @@ static void Channel_SetInstrument(SpcPlayer *p, Channel *c, uint8 instrument) {
// noise
p->reg_FLG = (p->reg_FLG & 0x20) | ip[0] & 0x1f;
p->reg_NON |= p->cur_chan_bit;
Dsp_Write(p, (DspReg)(reg + V0SRCN), 0);
Dsp_Write(p, reg + V0SRCN, 0);
} else {
Dsp_Write(p, reg + V0SRCN, ip[0]);
}
@@ -648,8 +784,8 @@ static void PlayNote(SpcPlayer *p, Channel *c, uint8 note) {
return;
static const char *const kNoteNames[] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" };
if (c->index==0)
printf("%s%d\n", kNoteNames[(note & 0x7f) % 12], (note & 0x7f) / 12 + 1);
//if (c->index==0)
// printf("%s%d\n", kNoteNames[(note & 0x7f) % 12], (note & 0x7f) / 12 + 1);
c->pitch = ((note & 0x7f) + p->global_transposition + c->channel_transposition) << 8 | c->fine_tune;
c->vibrato_count = c->vibrato_fade_num_ticks << 7;
@@ -1072,7 +1208,7 @@ void SpcPlayer_CopyVariablesToRam(SpcPlayer *p) {
for (const MemMap *m = &kChannel_Maps[0]; m != &kChannel_Maps[countof(kChannel_Maps)]; m++)
memcpy(&p->ram[(m->org_off & 0x7fff) + i * 2], (uint8 *)c + m->off, m->org_off & 0x8000 ? 2 : 1);
}
for (const MemMap2 *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
for (const MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
memcpy(&p->ram[m->org_off], (uint8 *)p + m->off, m->size);
}
@@ -1082,7 +1218,7 @@ void SpcPlayer_CopyVariablesFromRam(SpcPlayer *p) {
for (const MemMap *m = &kChannel_Maps[0]; m != &kChannel_Maps[countof(kChannel_Maps)]; m++)
memcpy((uint8 *)c + m->off, &p->ram[(m->org_off & 0x7fff) + i * 2], m->org_off & 0x8000 ? 2 : 1);
}
for (const MemMap2 *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
for (const MemMapSized *m = &kSpcPlayer_Maps[0]; m != &kSpcPlayer_Maps[countof(kSpcPlayer_Maps)]; m++)
memcpy((uint8 *)p + m->off, &p->ram[m->org_off], m->size);
}
@@ -1140,8 +1276,8 @@ void SpcPlayer_Upload(SpcPlayer *p, const uint8_t *data) {
// =======================================
DspRegWriteHistory my_write_hist;
SpcPlayer my_spc, my_spc_snapshot;
static DspRegWriteHistory my_write_hist;
static SpcPlayer my_spc, my_spc_snapshot;
static int loop_ctr;
bool CompareSpcImpls(SpcPlayer *p, SpcPlayer *p_org, Apu *apu) {

View File

@@ -1,8 +1,7 @@
#include <stddef.h>
struct DspRegWriteHistory;
struct Dsp;
#include "snes/dsp.h"
struct Channel {
typedef struct Channel {
uint16 pattern_order_ptr_for_chan;
uint8 note_ticks_left;
uint8 note_keyoff_ticks_left;
@@ -56,8 +55,9 @@ struct Channel {
uint8 sfx_note_length;
uint8 sfx_pan;
uint8 index;
};
struct SpcPlayer {
} Channel;
typedef struct SpcPlayer {
DspRegWriteHistory *reg_write_history;
uint8 timer_cycles;
Dsp *dsp;
@@ -135,139 +135,7 @@ struct SpcPlayer {
uint8 input_ports[4];
Channel channel[8];
uint8 ram[65536]; // rest of ram
};
struct MemMap {
uint16 off, org_off;
};
struct MemMap2 {
uint16 off, org_off, size;
};
const MemMap kChannel_Maps[] = {
{offsetof(Channel, pattern_order_ptr_for_chan), 0x8030},
{offsetof(Channel, note_ticks_left), 0x70},
{offsetof(Channel, note_keyoff_ticks_left), 0x71},
{offsetof(Channel, subroutine_num_loops), 0x80},
{offsetof(Channel, volume_fade_ticks), 0x90},
{offsetof(Channel, pan_num_ticks), 0x91},
{offsetof(Channel, pitch_slide_length), 0xa0},
{offsetof(Channel, pitch_slide_delay_left), 0xa1},
{offsetof(Channel, vibrato_hold_count), 0xb0},
{offsetof(Channel, vib_depth), 0xb1},
{offsetof(Channel, tremolo_hold_count), 0xc0},
{offsetof(Channel, tremolo_depth), 0xc1},
{offsetof(Channel, vibrato_change_count), 0x100},
{offsetof(Channel, note_length), 0x200},
{offsetof(Channel, note_gate_off_fixedpt), 0x201},
{offsetof(Channel, channel_volume_master), 0x210},
{offsetof(Channel, instrument_id), 0x211},
{offsetof(Channel, instrument_pitch_base), 0x8220},
{offsetof(Channel, saved_pattern_ptr), 0x8230},
{offsetof(Channel, pattern_start_ptr), 0x8240},
{offsetof(Channel, pitch_envelope_num_ticks), 0x280},
{offsetof(Channel, pitch_envelope_delay), 0x281},
{offsetof(Channel, pitch_envelope_direction), 0x290},
{offsetof(Channel, pitch_envelope_slide_value), 0x291},
{offsetof(Channel, vibrato_count), 0x2a0},
{offsetof(Channel, vibrato_rate), 0x2a1},
{offsetof(Channel, vibrato_delay_ticks), 0x2b0},
{offsetof(Channel, vibrato_fade_num_ticks), 0x2b1},
{offsetof(Channel, vibrato_fade_add_per_tick), 0x2c0},
{offsetof(Channel, vibrato_depth_target), 0x2c1},
{offsetof(Channel, tremolo_count), 0x2d0},
{offsetof(Channel, tremolo_rate), 0x2d1},
{offsetof(Channel, tremolo_delay_ticks), 0x2e0},
{offsetof(Channel, channel_transposition), 0x2f0},
{offsetof(Channel, channel_volume), 0x8300},
{offsetof(Channel, volume_fade_addpertick), 0x8310},
{offsetof(Channel, volume_fade_target), 0x320},
{offsetof(Channel, final_volume), 0x321},
{offsetof(Channel, pan_value), 0x8330},
{offsetof(Channel, pan_add_per_tick), 0x8340},
{offsetof(Channel, pan_target_value), 0x350},
{offsetof(Channel, pan_flag_with_phase_invert), 0x351},
{offsetof(Channel, pitch), 0x8360},
{offsetof(Channel, pitch_add_per_tick), 0x8370},
{offsetof(Channel, pitch_target), 0x380},
{offsetof(Channel, fine_tune), 0x381},
{offsetof(Channel, sfx_sound_ptr), 0x8390},
{offsetof(Channel, sfx_which_sound), 0x3a0},
{offsetof(Channel, sfx_arr_countdown), 0x3a1},
{offsetof(Channel, sfx_note_length_left), 0x3b0},
{offsetof(Channel, sfx_note_length), 0x3b1},
{offsetof(Channel, sfx_pan), 0x3d0},
};
const MemMap2 kSpcPlayer_Maps[] = {
{offsetof(SpcPlayer, new_value_from_snes), 0x0, 4},
{offsetof(SpcPlayer, port_to_snes), 0x4, 4},
{offsetof(SpcPlayer, last_value_from_snes), 0x8, 4},
{offsetof(SpcPlayer, counter_sf0c), 0xc, 1},
{offsetof(SpcPlayer, _always_zero), 0xe, 2},
{offsetof(SpcPlayer, temp_accum), 0x10, 2},
{offsetof(SpcPlayer, ttt), 0x12, 1},
{offsetof(SpcPlayer, did_affect_volumepitch_flag), 0x13, 1},
{offsetof(SpcPlayer, addr0), 0x14, 2},
{offsetof(SpcPlayer, addr1), 0x16, 2},
{offsetof(SpcPlayer, lfsr_value), 0x18, 2},
{offsetof(SpcPlayer, is_chan_on), 0x1a, 1},
{offsetof(SpcPlayer, fast_forward), 0x1b, 1},
{offsetof(SpcPlayer, sfx_start_arg_pan), 0x20, 1},
{offsetof(SpcPlayer, sfx_sound_ptr_cur), 0x2c, 2},
{offsetof(SpcPlayer, music_ptr_toplevel), 0x40, 2},
{offsetof(SpcPlayer, block_count), 0x42, 1},
{offsetof(SpcPlayer, sfx_timer_accum), 0x43, 1},
{offsetof(SpcPlayer, chn), 0x44, 1},
{offsetof(SpcPlayer, key_ON), 0x45, 1},
{offsetof(SpcPlayer, key_OFF), 0x46, 1},
{offsetof(SpcPlayer, cur_chan_bit), 0x47, 1},
{offsetof(SpcPlayer, reg_FLG), 0x48, 1},
{offsetof(SpcPlayer, reg_NON), 0x49, 1},
{offsetof(SpcPlayer, reg_EON), 0x4a, 1},
{offsetof(SpcPlayer, reg_PMON), 0x4b, 1},
{offsetof(SpcPlayer, echo_stored_time), 0x4c, 1},
{offsetof(SpcPlayer, echo_parameter_EDL), 0x4d, 1},
{offsetof(SpcPlayer, reg_EFB), 0x4e, 1},
{offsetof(SpcPlayer, global_transposition), 0x50, 1},
{offsetof(SpcPlayer, main_tempo_accum), 0x51, 1},
{offsetof(SpcPlayer, tempo), 0x52, 2},
{offsetof(SpcPlayer, tempo_fade_num_ticks), 0x54, 1},
{offsetof(SpcPlayer, tempo_fade_final), 0x55, 1},
{offsetof(SpcPlayer, tempo_fade_add), 0x56, 2},
{offsetof(SpcPlayer, master_volume), 0x58, 2},
{offsetof(SpcPlayer, master_volume_fade_ticks), 0x5a, 1},
{offsetof(SpcPlayer, master_volume_fade_target), 0x5b, 1},
{offsetof(SpcPlayer, master_volume_fade_add_per_tick), 0x5c, 2},
{offsetof(SpcPlayer, vol_dirty), 0x5e, 1},
{offsetof(SpcPlayer, percussion_base_id), 0x5f, 1},
{offsetof(SpcPlayer, echo_volume_left), 0x60, 2},
{offsetof(SpcPlayer, echo_volume_right), 0x62, 2},
{offsetof(SpcPlayer, echo_volume_fade_add_left), 0x64, 2},
{offsetof(SpcPlayer, echo_volume_fade_add_right), 0x66, 2},
{offsetof(SpcPlayer, echo_volume_fade_ticks), 0x68, 1},
{offsetof(SpcPlayer, echo_volume_fade_target_left), 0x69, 1},
{offsetof(SpcPlayer, echo_volume_fade_target_right), 0x6a, 1},
{offsetof(SpcPlayer, sfx_channel_index), 0x3c0, 1},
{offsetof(SpcPlayer, current_bit), 0x3c1, 1},
{offsetof(SpcPlayer, dsp_register_index), 0x3c2, 1},
{offsetof(SpcPlayer, echo_channels), 0x3c3, 1},
{offsetof(SpcPlayer, byte_3C4), 0x3c4, 1},
{offsetof(SpcPlayer, byte_3C5), 0x3c5, 1},
{offsetof(SpcPlayer, echo_fract_incr), 0x3c7, 1},
{offsetof(SpcPlayer, sfx_channel_index2), 0x3c8, 1},
{offsetof(SpcPlayer, sfx_channel_bit), 0x3c9, 1},
{offsetof(SpcPlayer, pause_music_ctr), 0x3ca, 1},
{offsetof(SpcPlayer, port2_active), 0x3cb, 1},
{offsetof(SpcPlayer, port2_current_bit), 0x3cc, 1},
{offsetof(SpcPlayer, port3_active), 0x3cd, 1},
{offsetof(SpcPlayer, port3_current_bit), 0x3ce, 1},
{offsetof(SpcPlayer, port1_active), 0x3cf, 1},
{offsetof(SpcPlayer, port1_current_bit), 0x3e0, 1},
{offsetof(SpcPlayer, byte_3E1), 0x3e1, 1},
{offsetof(SpcPlayer, sfx_play_echo_flag), 0x3e2, 1},
{offsetof(SpcPlayer, sfx_channels_echo_mask2), 0x3e3, 1},
{offsetof(SpcPlayer, port1_counter), 0x3e4, 1},
{offsetof(SpcPlayer, channel_67_volume), 0x3e5, 1},
{offsetof(SpcPlayer, cutk_always_zero), 0x3ff, 1},
};
} SpcPlayer;
SpcPlayer *SpcPlayer_Create();
void SpcPlayer_GenerateSamples(SpcPlayer *p);

View File

@@ -2366,8 +2366,9 @@ void AgahnimBalls_DamageAgahnim(int k, uint8 dmg, uint8 r0_hit_timer) { // 86ed
sprite_flags5[k] & 0x10 ? 0x1c : 8;
sound_effect_2 = sfx | Sprite_CalculateSfxPan(k);
}
uint8 type;
flag4:
uint8 type = sprite_type[k];
type = sprite_type[k];
sprite_F[k] = (damage_type_determiner >= 13) ? 0 :
(type == 9) ? 20 :
(type == 0x53 || type == 0x18) ? 11 : 15;

View File

@@ -3,13 +3,13 @@
#include "variables.h"
struct PrepOamCoordsRet {
typedef struct PrepOamCoordsRet {
uint16 x, y;
uint8 r4;
uint8 flags;
};
} PrepOamCoordsRet;
struct SpriteHitBox {
typedef struct SpriteHitBox {
uint8 r0_xlo;
uint8 r8_xhi;
uint8 r1_ylo;
@@ -23,25 +23,23 @@ struct SpriteHitBox {
uint8 r11_spr_yhi;
uint8 r6_spr_xsize;
uint8 r7_spr_ysize;
};
} SpriteHitBox;
struct SpriteSpawnInfo {
typedef struct SpriteSpawnInfo {
uint16 r0_x;
uint16 r2_y;
uint8 r4_z;
uint16 r5_overlord_x;
uint16 r7_overlord_y;
};
} SpriteSpawnInfo;
extern const uint8 kAbsorbBigKey[2];
struct DrawMultipleData {
typedef struct DrawMultipleData {
int8 x, y;
uint16 char_flags;
uint8 ext;
};
} DrawMultipleData;

View File

@@ -13108,9 +13108,9 @@ void FortuneTeller_PerformPseudoScience(int k) { // 8dc849
if (link_sword_type < 4) ADD_MSG(13);
ADD_MSG(14);
ADD_MSG(15);
int j;
done:
int j = ((sram_progress_flags ^= 0x40) & 0x40) != 0;
j = ((sram_progress_flags ^= 0x40) & 0x40) != 0;
Sprite_ShowMessageUnconditional(kFortuneTeller_Readings[slots[j]]);
}
@@ -21258,8 +21258,8 @@ void Sprite_9A_Kyameron(int k) { // 9e9e7b
sprite_ai_state[k] = 4;
sprite_delay_main[k] = 15;
SpriteSfx_QueueSfx2WithPan(k, 0x28);
skip_sound:
static const uint8 kKyameron_Moving_Gfx[4] = {3, 2, 1, 0};
skip_sound:
sprite_graphics[k] = kKyameron_Moving_Gfx[++sprite_subtype2[k] >> 3 & 3];
if (!((k ^ frame_counter) & 7)) {
uint16 x = (GetRandomNumber() & 0xf) - 4;
@@ -24935,6 +24935,7 @@ void OldMan_EnableCutscene() { // 9ee989
}
void Sprite_AD_OldMan(int k) { // 9ee992
static const uint16 kOldMountainManMsgs[3] = {0x9e, 0x9f, 0xa0};
int j;
OldMountainMan_Draw(k);
if (Sprite_ReturnIfInactive(k))
@@ -25006,7 +25007,6 @@ void Sprite_AD_OldMan(int k) { // 9ee992
}
break;
case 2: // sitting at home
static const uint16 kOldMountainManMsgs[3] = {0x9e, 0x9f, 0xa0};
Sprite_BehaveAsBarrier(k);
if (sprite_ai_state[k]) {
link_hearts_filler = 160;

View File

@@ -61,7 +61,7 @@ def print_dialogue():
print_int_array('kDialogueText', new_r, 'uint8', True, 16, file = f)
f.close()
ROM = util.LoadedRom()
ROM = util.LoadedRom(sys.argv[1])
kCompSpritePtrs = [

View File

@@ -463,8 +463,8 @@ def extract_sound_data(rom):
print_song('ending', open('sound_ending.txt', 'w'))
if __name__ == "__main__":
ROM = util.LoadedRom()
song = sys.argv[1]
ROM = util.LoadedRom(sys.argv[1])
song = sys.argv[2]
load_song(ROM, song)
print_song(song, sys.stdout)

View File

@@ -459,11 +459,11 @@ def extract_sound_data(rom):
print_all_sfx(open('sfx.txt', 'w'))
if __name__ == "__main__":
if len(sys.argv) < 2:
print('extract_music.py [intro|lightworld|indoor|ending]')
if len(sys.argv) < 3:
print('extract_music.py [rom-filename] [intro|lightworld|indoor|ending]')
sys.exit(0)
ROM = util.LoadedRom()
song = sys.argv[1]
ROM = util.LoadedRom(None if sys.argv[1] == '' else sys.argv[1])
song = sys.argv[2]
load_song(ROM, song)
print_song(song, sys.stdout)

View File

@@ -7,22 +7,10 @@ import tables
import yaml
import extract_music
import os
import getopt
PATH=''
option_list, args = getopt.getopt(sys.argv[1:], 'r:', ['rom_path='])
rom_path = None
for opt, arg in option_list:
if opt in ('-r', '--rom_path'):
rom_path = arg
try:
ROM = util.LoadedRom(rom_path)
except Exception as error:
print(f"Failed to load ROM data for extraction. Error: {error}")
sys.exit(1)
ROM = util.LoadedRom(sys.argv[1] if len(sys.argv) >= 2 else None)
get_byte = ROM.get_byte
get_word = ROM.get_word

View File

@@ -41,13 +41,13 @@ static const uint8 kTagalong_IndoorOffsets[8] = {0, 3, 6, 7, 9, 10, 11, 12};
static const uint8 kTagalong_OutdoorOffsets[4] = {0, 1, 4, 5};
static const uint16 kTagalong_IndoorRooms[7] = {0xf1, 0x61, 0x51, 2, 0xdb, 0xab, 0x22};
static const uint16 kTagalong_OutdoorRooms[3] = {3, 0x5e, 0};
struct TagalongSprXY {
typedef struct TagalongSprXY {
int8 y1, x1, y2, x2;
};
struct TagalongDmaFlags {
} TagalongSprXY;
typedef struct TagalongDmaFlags {
uint8 dma6, dma7;
uint8 flags;
};
} TagalongDmaFlags;
static const TagalongSprXY kTagalongDraw_SprXY[56] = {
{-2, 0, 0, 0},
{-2, 0, 0, 0},
@@ -393,8 +393,8 @@ void Follower_BasicMover() { // 89a197
}
if (link_x_vel | link_y_vel) {
label_e:
uint8 t;
label_e:
t = tagalong_var1 - 15;
if (sign8(t))
t += 20;
@@ -643,9 +643,9 @@ incr:
bytewise_extended_oam[oam - oam_buf] = ext;
oam++;
}
uint8 pal;
skip_first_sprites:
uint8 pal = kTagalongDraw_Pals[savegame_tagalong];
pal = kTagalongDraw_Pals[savegame_tagalong];
if (pal == 7 && overworld_palette_swap_flag)
pal = 0;

View File

@@ -1,9 +1,9 @@
#pragma once
#include "types.h"
struct TagalongMessageInfo {
typedef struct TagalongMessageInfo {
uint16 y, x, bit, msg, tagalong;
};
} TagalongMessageInfo;
bool Tagalong_IsFollowing();
bool Follower_ValidateMessageFreedom();

47
types.h
View File

@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#pragma once
typedef uint8_t uint8;
@@ -16,9 +17,12 @@ typedef int32_t int32;
#ifdef _MSC_VER
#define countof _countof
#define NORETURN __declspec(noreturn)
#else
#define countof(a) (sizeof(a)/sizeof(*(a)))
#define NORETURN
#endif
static inline uint16 abs16(uint16 t) { return sign16(t) ? -t : t; }
static inline uint8 abs8(uint8 t) { return sign8(t) ? -t : t; }
@@ -29,48 +33,43 @@ static inline uint8 abs8(uint8 t) { return sign8(t) ? -t : t; }
static inline uint16 swap16(uint16 v) { return (v << 8) | (v >> 8); }
struct Point16U {
typedef struct Point16U {
uint16 x, y;
};
struct PointU8 {
} Point16U;
typedef struct PointU8 {
uint8 x, y;
};
struct Pair16U {
} PointU8;
typedef struct Pair16U {
uint16 a, b;
};
} Pair16U;
struct PairU8 {
typedef struct PairU8 {
uint8 a, b;
};
} PairU8;
struct ProjectSpeedRet {
typedef struct ProjectSpeedRet {
uint8 x, y;
uint8 xdiff, ydiff;
};
} ProjectSpeedRet;
struct OamEnt {
typedef struct OamEnt {
uint8 x, y, charnum, flags;
};
} OamEnt;
struct UploadVram_Row {
typedef struct UploadVram_Row {
uint16 col[32];
};
} UploadVram_Row;
struct UploadVram_32x32 {
typedef struct UploadVram_32x32 {
UploadVram_Row row[32];
};
} UploadVram_32x32;
struct UploadVram_3 {
typedef struct UploadVram_3 {
uint8 pad[256];
uint16 data[4];
};
} UploadVram_3;
union UploadVram {
UploadVram_3 t3;
};
#define uvram (*(UploadVram*)(&g_ram[0x1000]))
#define uvram (*(UploadVram_3*)(&g_ram[0x1000]))
typedef void PlayerHandlerFunc();
typedef void HandlerFuncK(int k);

View File

@@ -123,77 +123,77 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ancilla.cpp" />
<ClCompile Include="attract.cpp" />
<ClCompile Include="dungeon.cpp" />
<ClCompile Include="ending.cpp" />
<ClCompile Include="hud.cpp" />
<ClCompile Include="load_gfx.cpp" />
<ClCompile Include="main.cpp">
<ClCompile Include="ancilla.c" />
<ClCompile Include="attract.c" />
<ClCompile Include="dungeon.c" />
<ClCompile Include="ending.c" />
<ClCompile Include="hud.c" />
<ClCompile Include="load_gfx.c" />
<ClCompile Include="main.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="messaging.cpp" />
<ClCompile Include="misc.cpp" />
<ClCompile Include="nmi.cpp" />
<ClCompile Include="other_modules.cpp" />
<ClCompile Include="overlord.cpp" />
<ClCompile Include="overworld.cpp" />
<ClCompile Include="player.cpp" />
<ClCompile Include="player_oam.cpp" />
<ClCompile Include="poly.cpp" />
<ClCompile Include="select_file.cpp" />
<ClCompile Include="snes\apu.cpp">
<ClCompile Include="messaging.c" />
<ClCompile Include="misc.c" />
<ClCompile Include="nmi.c" />
<ClCompile Include="other_modules.c" />
<ClCompile Include="overlord.c" />
<ClCompile Include="overworld.c" />
<ClCompile Include="player.c" />
<ClCompile Include="player_oam.c" />
<ClCompile Include="poly.c" />
<ClCompile Include="select_file.c" />
<ClCompile Include="snes\apu.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\cart.cpp">
<ClCompile Include="snes\cart.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\cpu.cpp">
<ClCompile Include="snes\cpu.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\dma.cpp">
<ClCompile Include="snes\dma.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\dsp.cpp">
<ClCompile Include="snes\dsp.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\input.cpp">
<ClCompile Include="snes\input.c">
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\ppu.cpp">
<ClCompile Include="snes\ppu.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AnySuitable</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\snes.cpp">
<ClCompile Include="snes\snes.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\snes_other.cpp">
<ClCompile Include="snes\snes_other.c">
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="snes\spc.cpp">
<ClCompile Include="snes\spc.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="spc_player.cpp" />
<ClCompile Include="sprite.cpp" />
<ClCompile Include="sprite_main.cpp">
<ClCompile Include="spc_player.c" />
<ClCompile Include="sprite.c" />
<ClCompile Include="sprite_main.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="tagalong.cpp" />
<ClCompile Include="tile_detect.cpp" />
<ClCompile Include="tracing.cpp">
<ClCompile Include="tagalong.c" />
<ClCompile Include="tile_detect.c" />
<ClCompile Include="tracing.c">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</InlineFunctionExpansion>
</ClCompile>
<ClCompile Include="zelda_cpu_infra.cpp" />
<ClCompile Include="zelda_rtl.cpp" />
<ClCompile Include="zelda_cpu_infra.c" />
<ClCompile Include="zelda_rtl.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ancilla.h" />
@@ -217,6 +217,7 @@
<ClInclude Include="snes\cpu.h" />
<ClInclude Include="snes\dma.h" />
<ClInclude Include="snes\dsp.h" />
<ClInclude Include="snes\dsp_regs.h" />
<ClInclude Include="snes\input.h" />
<ClInclude Include="snes\ppu.h" />
<ClInclude Include="snes\saveload.h" />

View File

@@ -10,109 +10,109 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="snes\apu.cpp">
<ClCompile Include="snes\apu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\cart.cpp">
<ClCompile Include="snes\cart.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\cpu.cpp">
<ClCompile Include="snes\cpu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\dma.cpp">
<ClCompile Include="snes\dma.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\dsp.cpp">
<ClCompile Include="snes\dsp.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\input.cpp">
<ClCompile Include="snes\input.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<ClCompile Include="main.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\ppu.cpp">
<ClCompile Include="snes\ppu.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\snes.cpp">
<ClCompile Include="snes\snes.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\snes_other.cpp">
<ClCompile Include="snes\snes_other.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="snes\spc.cpp">
<ClCompile Include="snes\spc.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="tracing.cpp">
<ClCompile Include="tracing.c">
<Filter>Snes</Filter>
</ClCompile>
<ClCompile Include="zelda_rtl.cpp">
<ClCompile Include="zelda_rtl.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="hud.cpp">
<ClCompile Include="hud.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="dungeon.cpp">
<ClCompile Include="dungeon.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="nmi.cpp">
<ClCompile Include="nmi.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="player_oam.cpp">
<ClCompile Include="player_oam.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="load_gfx.cpp">
<ClCompile Include="load_gfx.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="messaging.cpp">
<ClCompile Include="messaging.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="overworld.cpp">
<ClCompile Include="overworld.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="sprite.cpp">
<ClCompile Include="sprite.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="sprite_main.cpp">
<ClCompile Include="sprite_main.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="tagalong.cpp">
<ClCompile Include="tagalong.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="overlord.cpp">
<ClCompile Include="overlord.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="poly.cpp">
<ClCompile Include="poly.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="ancilla.cpp">
<ClCompile Include="ancilla.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="ending.cpp">
<ClCompile Include="ending.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="attract.cpp">
<ClCompile Include="attract.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="select_file.cpp">
<ClCompile Include="select_file.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="spc_player.cpp">
<ClCompile Include="spc_player.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="player.cpp">
<ClCompile Include="player.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="tile_detect.cpp">
<ClCompile Include="tile_detect.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="other_modules.cpp">
<ClCompile Include="other_modules.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="misc.cpp">
<ClCompile Include="misc.c">
<Filter>Zelda</Filter>
</ClCompile>
<ClCompile Include="zelda_cpu_infra.cpp">
<ClCompile Include="zelda_cpu_infra.c">
<Filter>Zelda</Filter>
</ClCompile>
</ItemGroup>
@@ -228,6 +228,9 @@
<ClInclude Include="sprite_main.h">
<Filter>Zelda</Filter>
</ClInclude>
<ClInclude Include="snes\dsp_regs.h">
<Filter>Snes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -7,39 +7,35 @@
#include "nmi.h"
#include "poly.h"
#include "attract.h"
#include "spc_player.h"
#include "snes/snes.h"
#include "snes/cpu.h"
#include "snes/cart.h"
#include "tracing.h"
#include <vector>
Snes *g_snes;
Cpu *g_cpu;
uint8 g_emulated_ram[0x20000];
void SaveLoadSlot(int cmd, int which);
//uint8 *GetPtr(uint32 addr) {
// Cart *cart = g_snes->cart;
// return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
//}
uint8 *GetPtr(uint32 addr) {
Cart *cart = g_snes->cart;
return &cart->rom[(((addr >> 16) << 15) | (addr & 0x7fff)) & (cart->romSize - 1)];
}
//extern "C" uint8 *GetCartRamPtr(uint32 addr) {
// Cart *cart = g_snes->cart;
// return &cart->ram[addr];
//}
uint8 *GetCartRamPtr(uint32 addr) {
Cart *cart = g_snes->cart;
return &cart->ram[addr];
}
struct Snapshot {
typedef struct Snapshot {
uint16 a, x, y, sp, dp, pc;
uint8 k, db, flags;
uint8 ram[0x20000];
uint16 vram[0x8000];
uint16 sram[0x2000];
};
} Snapshot;
static Snapshot g_snapshot_mine, g_snapshot_theirs, g_snapshot_before;
@@ -322,16 +318,36 @@ Dsp *GetDspForRendering() {
return g_zenv.player->dsp;
}
typedef struct ByteArray {
uint8 *data;
size_t size, capacity;
} ByteArray;
void saveFunc(void *ctx, void *data, size_t data_size) {
std::vector<uint8> *vec = (std::vector<uint8> *)ctx;
vec->resize(vec->size() + data_size);
memcpy(vec->data() + vec->size() - data_size, data, data_size);
void ByteArray_Resize(ByteArray *arr, size_t new_size) {
arr->size = new_size;
if (new_size > arr->capacity) {
size_t minsize = arr->capacity + (arr->capacity >> 1) + 8;
arr->capacity = new_size < minsize ? minsize : new_size;
void *data = realloc(arr->data, arr->capacity);
if (!data) Die("memory allocation failed");
arr->data = data;
}
}
struct LoadFuncState {
void ByteArray_Destroy(ByteArray *arr) {
free(arr->data);
arr->data = NULL;
}
void saveFunc(void *ctx_in, void *data, size_t data_size) {
ByteArray *arr = (ByteArray *)ctx_in;
ByteArray_Resize(arr, arr->size + data_size);
memcpy(arr->data + arr->size - data_size, data, data_size);
}
typedef struct LoadFuncState {
uint8 *p, *pend;
};
} LoadFuncState;
void loadFunc(void *ctx, void *data, size_t data_size) {
LoadFuncState *st = (LoadFuncState *)ctx;
@@ -340,7 +356,6 @@ void loadFunc(void *ctx, void *data, size_t data_size) {
st->p += data_size;
}
void CopyStateAfterSnapshotRestore(bool is_reset) {
memcpy(g_zenv.ram, g_snes->ram, 0x20000);
memcpy(g_zenv.sram, g_snes->cart->ram, g_snes->cart->ramSize);
@@ -357,9 +372,7 @@ void CopyStateAfterSnapshotRestore(bool is_reset) {
g_zenv.player->timer_cycles = 0;
}
std::vector<uint8> SaveSnesState() {
std::vector<uint8> data;
void SaveSnesState(ByteArray *ctx) {
MakeSnapshot(&g_snapshot_before);
// Copy from my state into the emulator
@@ -371,138 +384,115 @@ std::vector<uint8> SaveSnesState() {
memcpy(g_snes->apu->dsp->ram, g_zenv.player->dsp->ram, sizeof(Dsp) - offsetof(Dsp, ram));
memcpy(g_snes->dma->channel, g_zenv.dma->channel, sizeof(Dma) - offsetof(Dma, channel));
snes_saveload(g_snes, &saveFunc, &data);
snes_saveload(g_snes, &saveFunc, ctx);
RestoreSnapshot(&g_snapshot_before);
return data;
}
class StateRecorder {
public:
StateRecorder() : last_inputs_(0), frames_since_last_(0), total_frames_(0), replay_mode_(false) {}
void Record(uint16 inputs);
void RecordPatchByte(uint32 addr, const uint8 *value, int num);
void Load(FILE *f, bool replay_mode);
void Save(FILE *f);
uint16 ReadNextReplayState();
bool is_replay_mode() { return replay_mode_; }
void MigrateToBaseSnapshot();
private:
void RecordJoypadBit(int command);
void AppendByte(uint8 v);
void AppendVl(uint32 v);
uint16 last_inputs_;
uint32 frames_since_last_;
uint32 total_frames_;
typedef struct StateRecorder {
uint16 last_inputs;
uint32 frames_since_last;
uint32 total_frames;
// For replay
uint32 replay_pos_, replay_frame_counter_, replay_next_cmd_at_;
uint8 replay_cmd_;
bool replay_mode_;
uint32 replay_pos;
uint32 replay_frame_counter;
uint32 replay_next_cmd_at;
uint8 replay_cmd;
bool replay_mode;
std::vector<uint8> log_;
std::vector<uint8> base_snapshot_;
};
ByteArray log;
ByteArray base_snapshot;
} StateRecorder;
uint32 RamChecksum() {
uint64_t cksum = 0, cksum2 = 0;
for (int i = 0; i < 0x20000; i += 4) {
cksum += *(uint32 *)&g_ram[i];
cksum2 += cksum;
}
return cksum ^ (cksum >> 32) ^ cksum2 ^ (cksum2 >> 32);
static StateRecorder state_recorder;
void StateRecorder_Init(StateRecorder *sr) {
memset(sr, 0, sizeof(*sr));
}
void StateRecorder::AppendByte(uint8 v) {
log_.push_back(v);
void StateRecorder_AppendByte(StateRecorder *sr, uint8 v) {
ByteArray_Resize(&sr->log, sr->log.size + 1);
sr->log.data[sr->log.size - 1] = v;
printf("%.2x ", v);
}
void StateRecorder::AppendVl(uint32 v) {
void StateRecorder_AppendVl(StateRecorder *sr, uint32 v) {
for (; v >= 255; v -= 255)
AppendByte(255);
AppendByte(v);
StateRecorder_AppendByte(sr, 255);
StateRecorder_AppendByte(sr, v);
}
void StateRecorder::RecordJoypadBit(int command) {
int frames = frames_since_last_;
AppendByte(command << 4 | (frames < 15 ? frames : 15));
void StateRecorder_RecordJoypadBit(StateRecorder *sr, int command) {
int frames = sr->frames_since_last;
StateRecorder_AppendByte(sr, command << 4 | (frames < 15 ? frames : 15));
if (frames >= 15)
AppendVl(frames - 15);
frames_since_last_ = 0;
StateRecorder_AppendVl(sr, frames - 15);
sr->frames_since_last = 0;
}
void StateRecorder::Record(uint16 inputs) {
uint16 diff = inputs ^ last_inputs_;
void StateRecorder_Record(StateRecorder *sr, uint16 inputs) {
uint16 diff = inputs ^ sr->last_inputs;
if (diff != 0) {
last_inputs_ = inputs;
printf("0x%.4x %d: ", diff, frames_since_last_);
sr->last_inputs = inputs;
printf("0x%.4x %d: ", diff, sr->frames_since_last);
for (int i = 0; i < 12; i++) {
if ((diff >> i) & 1)
RecordJoypadBit(i);
StateRecorder_RecordJoypadBit(sr, i);
}
printf("\n");
}
frames_since_last_++;
total_frames_++;
sr->frames_since_last++;
sr->total_frames++;
}
void StateRecorder::RecordPatchByte(uint32 addr, const uint8 *value, int num) {
void StateRecorder_RecordPatchByte(StateRecorder *sr, uint32 addr, const uint8 *value, int num) {
assert(addr < 0x20000);
printf("%d: PatchByte(0x%x, 0x%x. %d): ", frames_since_last_, addr, *value, num);
printf("%d: PatchByte(0x%x, 0x%x. %d): ", sr->frames_since_last, addr, *value, num);
int frames = frames_since_last_;
int frames = sr->frames_since_last;
sr->frames_since_last = 0;
int lq = (num - 1) <= 3 ? (num - 1) : 3;
AppendByte(0xc0 | (frames != 0 ? 1 : 0) | (addr & 0x10000 ? 2 : 0) | lq << 2);
StateRecorder_AppendByte(sr, 0xc0 | (frames != 0 ? 1 : 0) | (addr & 0x10000 ? 2 : 0) | lq << 2);
if (frames != 0)
AppendVl(frames - 1);
StateRecorder_AppendVl(sr, frames - 1);
if (lq == 3)
AppendVl(num - 1 - 3);
frames_since_last_ = 0;
AppendByte(addr >> 8);
AppendByte(addr);
StateRecorder_AppendVl(sr, num - 1 - 3);
StateRecorder_AppendByte(sr, addr >> 8);
StateRecorder_AppendByte(sr, addr);
for(int i = 0; i < num; i++)
AppendByte(value[i]);
StateRecorder_AppendByte(sr, value[i]);
printf("\n");
}
void StateRecorder::Load(FILE *f, bool replay_mode) {
void StateRecorder_Load(StateRecorder *sr, FILE *f, bool replay_mode) {
uint32 hdr[8] = { 0 };
fread(hdr, 8, 4, f);
assert(hdr[0] == 1);
total_frames_ = hdr[1];
log_.resize(hdr[2]);
fread(log_.data(), 1, hdr[2], f);
last_inputs_ = hdr[3];
frames_since_last_ = hdr[4];
sr->total_frames = hdr[1];
ByteArray_Resize(&sr->log, hdr[2]);
fread(sr->log.data, 1, sr->log.size, f);
sr->last_inputs = hdr[3];
sr->frames_since_last = hdr[4];
base_snapshot_.resize((hdr[5] & 1) ? hdr[6] : 0);
fread(base_snapshot_.data(), 1, base_snapshot_.size(), f);
ByteArray_Resize(&sr->base_snapshot, (hdr[5] & 1) ? hdr[6] : 0);
fread(sr->base_snapshot.data, 1, sr->base_snapshot.size, f);
bool is_reset = false;
replay_mode_ = replay_mode;
sr->replay_mode = replay_mode;
if (replay_mode) {
replay_next_cmd_at_ = frames_since_last_ = 0;
last_inputs_ = 0;
replay_pos_ = 0;
replay_frame_counter_ = 0;
replay_cmd_ = 0xff;
sr->replay_next_cmd_at = sr->frames_since_last = 0;
sr->last_inputs = 0;
sr->replay_pos = 0;
sr->replay_frame_counter = 0;
sr->replay_cmd = 0xff;
// Load snapshot from |base_snapshot_|, or reset if empty.
if (base_snapshot_.size()) {
LoadFuncState state = { base_snapshot_.data(), base_snapshot_.data() + base_snapshot_.size() };
if (sr->base_snapshot.size) {
LoadFuncState state = { sr->base_snapshot.data, sr->base_snapshot.data + sr->base_snapshot.size };
snes_saveload(g_snes, &loadFunc, &state);
assert(state.p == state.pend);
} else {
@@ -511,97 +501,97 @@ void StateRecorder::Load(FILE *f, bool replay_mode) {
is_reset = true;
}
} else {
std::vector<uint8> data;
data.resize(hdr[6]);
fread(data.data(), 1, data.size(), f);
LoadFuncState state = { data.data(), data.data() + data.size() };
ByteArray arr = { 0 };
ByteArray_Resize(&arr, hdr[6]);
fread(arr.data, 1, arr.size, f);
LoadFuncState state = { arr.data, arr.data + arr.size };
snes_saveload(g_snes, &loadFunc, &state);
ByteArray_Destroy(&arr);
assert(state.p == state.pend);
}
CopyStateAfterSnapshotRestore(is_reset);
}
void StateRecorder::Save(FILE *f) {
void StateRecorder_Save(StateRecorder *sr, FILE *f) {
uint32 hdr[8] = { 0 };
std::vector<uint8> data = SaveSnesState();
assert(base_snapshot_.size() == 0 || base_snapshot_.size() == data.size());
ByteArray arr = {0};
SaveSnesState(&arr);
assert(sr->base_snapshot.size == 0 || sr->base_snapshot.size == arr.size);
hdr[0] = 1;
hdr[1] = total_frames_;
hdr[2] = log_.size();
hdr[3] = last_inputs_;
hdr[4] = frames_since_last_;
hdr[5] = (base_snapshot_.size() ? 1 : 0);
hdr[6] = data.size();
hdr[1] = sr->total_frames;
hdr[2] = sr->log.size;
hdr[3] = sr->last_inputs;
hdr[4] = sr->frames_since_last;
hdr[5] = sr->base_snapshot.size ? 1 : 0;
hdr[6] = arr.size;
fwrite(hdr, 8, 4, f);
fwrite(log_.data(), 1, log_.size(), f);
fwrite(base_snapshot_.data(), 1, base_snapshot_.size(), f);
fwrite(data.data(), 1, data.size(), f);
fwrite(sr->log.data, 1, sr->log.size, f);
fwrite(sr->base_snapshot.data, 1, sr->base_snapshot.size, f);
fwrite(arr.data, 1, arr.size, f);
ByteArray_Destroy(&arr);
}
void StateRecorder::MigrateToBaseSnapshot() {
void StateRecorder_MigrateToBaseSnapshot(StateRecorder *sr) {
printf("Migrating to base snapshot!\n");
std::vector<uint8> data = SaveSnesState();
base_snapshot_ = std::move(data);
replay_mode_ = false;
frames_since_last_ = 0;
last_inputs_ = 0;
total_frames_ = 0;
log_.clear();
sr->base_snapshot.size = 0;
SaveSnesState(&sr->base_snapshot);
sr->replay_mode = false;
sr->frames_since_last = 0;
sr->last_inputs = 0;
sr->total_frames = 0;
sr->log.size = 0;
}
uint16 StateRecorder::ReadNextReplayState() {
assert(replay_mode_);
while (frames_since_last_ >= replay_next_cmd_at_) {
frames_since_last_ = 0;
uint16 StateRecorder_ReadNextReplayState(StateRecorder *sr) {
assert(sr->replay_mode);
while (sr->frames_since_last >= sr->replay_next_cmd_at) {
sr->frames_since_last = 0;
// Apply next command
if (replay_cmd_ != 0xff) {
if (replay_cmd_ < 0xc0) {
last_inputs_ ^= 1 << (replay_cmd_ >> 4);
} else if (replay_cmd_ < 0xd0) {
int nb = 1 + ((replay_cmd_ >> 2) & 3);
if (sr->replay_cmd != 0xff) {
if (sr->replay_cmd < 0xc0) {
sr->last_inputs ^= 1 << (sr->replay_cmd >> 4);
} else if (sr->replay_cmd < 0xd0) {
int nb = 1 + ((sr->replay_cmd >> 2) & 3);
uint8 t;
if (nb == 4) do {
nb += t = log_[replay_pos_++];
nb += t = sr->log.data[sr->replay_pos++];
} while (t == 255);
uint32 addr = ((replay_cmd_ >> 1) & 1) << 16;
addr |= log_[replay_pos_++] << 8;
addr |= log_[replay_pos_++];
uint32 addr = ((sr->replay_cmd >> 1) & 1) << 16;
addr |= sr->log.data[sr->replay_pos++] << 8;
addr |= sr->log.data[sr->replay_pos++];
do {
g_emulated_ram[addr & 0x1ffff] = g_ram[addr & 0x1ffff] = log_[replay_pos_++];
g_emulated_ram[addr & 0x1ffff] = g_ram[addr & 0x1ffff] = sr->log.data[sr->replay_pos++];
} while (addr++, --nb);
} else {
assert(0);
}
}
if (replay_pos_ >= log_.size()) {
replay_cmd_ = 0xff;
replay_next_cmd_at_ = 0xffffffff;
if (sr->replay_pos >= sr->log.size) {
sr->replay_cmd = 0xff;
sr->replay_next_cmd_at = 0xffffffff;
break;
}
// Read the next one
uint8 cmd = log_[replay_pos_++], t;
uint8 cmd = sr->log.data[sr->replay_pos++], t;
int mask = (cmd < 0xc0) ? 0xf : 0x1;
int frames = cmd & mask;
if (frames == mask) do {
frames += t = log_[replay_pos_++];
frames += t = sr->log.data[sr->replay_pos++];
} while (t == 255);
replay_next_cmd_at_ = frames;
replay_cmd_ = cmd;
sr->replay_next_cmd_at = frames;
sr->replay_cmd = cmd;
}
frames_since_last_++;
sr->frames_since_last++;
// Turn off replay mode after we reached the final frame position
if (++replay_frame_counter_ >= total_frames_) {
replay_mode_ = false;
if (++sr->replay_frame_counter >= sr->total_frames) {
sr->replay_mode = false;
}
return last_inputs_;
return sr->last_inputs;
}
StateRecorder input_recorder;
static int frame_ctr;
int IncrementCrystalCountdown(uint8 *a, int v) {
@@ -619,24 +609,24 @@ bool RunOneFrame(Snes *snes, int input_state, bool turbo) {
}
// Either copy state or apply state
if (input_recorder.is_replay_mode()) {
input_state = input_recorder.ReadNextReplayState();
if (state_recorder.replay_mode) {
input_state = StateRecorder_ReadNextReplayState(&state_recorder);
} else {
input_recorder.Record(input_state);
StateRecorder_Record(&state_recorder, input_state);
turbo = false;
// This is whether APUI00 is true or false, this is used by the ancilla code.
uint8 apui00 = g_zenv.player->port_to_snes[0] != 0;
if (apui00 != g_ram[kRam_APUI00]) {
g_emulated_ram[kRam_APUI00] = g_ram[kRam_APUI00] = apui00;
input_recorder.RecordPatchByte(kRam_APUI00, &apui00, 1);
if (apui00 != g_ram[0x648]) {
g_emulated_ram[0x648] = g_ram[0x648] = apui00;
StateRecorder_RecordPatchByte(&state_recorder, 0x648, &apui00, 1);
}
// Whenever we're no longer replaying, we'll remember what bugs were fixed,
// but only if game is initialized.
if (g_ram[kRam_BugsFixed] < kBugFix_Latest && animated_tile_data_src != 0) {
g_emulated_ram[kRam_BugsFixed] = g_ram[kRam_BugsFixed] = kBugFix_Latest;
input_recorder.RecordPatchByte(kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
StateRecorder_RecordPatchByte(&state_recorder, kRam_BugsFixed, &g_ram[kRam_BugsFixed], 1);
}
}
@@ -761,7 +751,6 @@ void PatchRom(uint8_t *rom) {
.9B:C049 85 00 mov.w R0, A
.9B:C04B 68 pop A
.9B:C04C 85 02 mov.w R2, A
*/
uint8_t *tp = rom + 0x6ffd8;
*tp++ = 0xa5; *tp++ = 0x00; *tp++ = 0x48;
@@ -869,51 +858,72 @@ void SaveLoadSlot(int cmd, int which) {
cmd==kSaveLoad_Save ? "Saving" : cmd==kSaveLoad_Load ? "Loading" : "Replaying", which);
if (cmd != kSaveLoad_Save)
input_recorder.Load(f, cmd == kSaveLoad_Replay);
StateRecorder_Load(&state_recorder, f, cmd == kSaveLoad_Replay);
else
input_recorder.Save(f);
StateRecorder_Save(&state_recorder, f);
fclose(f);
}
}
class PatchRamByteBatch {
public:
PatchRamByteBatch() : count_(0), addr_(0) {}
~PatchRamByteBatch();
void Patch(uint32 addr, uint8 value);
private:
uint32 count_, addr_;
uint8 vals_[256];
};
PatchRamByteBatch::~PatchRamByteBatch() {
if (count_)
input_recorder.RecordPatchByte(addr_, vals_, count_);
void ZeldaReadSram(Snes *snes) {
FILE *f = fopen("saves/sram.dat", "rb");
if (f) {
fread(g_zenv.sram, 1, 8192, f);
memcpy(snes->cart->ram, g_zenv.sram, 8192);
fclose(f);
}
}
void PatchRamByteBatch::Patch(uint32 addr, uint8 value) {
if (count_ >= 256 || addr != addr_ + count_) {
if (count_)
input_recorder.RecordPatchByte(addr_, vals_, count_);
addr_ = addr;
count_ = 0;
void ZeldaWriteSram() {
rename("saves/sram.dat", "saves/sram.bak");
FILE *f = fopen("saves/sram.dat", "wb");
if (f) {
fwrite(g_zenv.sram, 1, 8192, f);
fclose(f);
} else {
fprintf(stderr, "Unable to write saves/sram.dat\n");
}
vals_[count_++] = value;
}
typedef struct StateRecoderMultiPatch {
uint32 count;
uint32 addr;
uint8 vals[256];
} StateRecoderMultiPatch;
void StateRecoderMultiPatch_Init(StateRecoderMultiPatch *mp) {
mp->count = mp->addr = 0;
}
void StateRecoderMultiPatch_Commit(StateRecoderMultiPatch *mp) {
if (mp->count)
StateRecorder_RecordPatchByte(&state_recorder, mp->addr, mp->vals, mp->count);
}
void StateRecoderMultiPatch_Patch(StateRecoderMultiPatch *mp, uint32 addr, uint8 value) {
if (mp->count >= 256 || addr != mp->addr + mp->count) {
StateRecoderMultiPatch_Commit(mp);
mp->addr = addr;
mp->count = 0;
}
mp->vals[mp->count++] = value;
g_emulated_ram[addr] = g_ram[addr] = value;
}
void PatchCommand(char c) {
PatchRamByteBatch b;
StateRecoderMultiPatch mp;
StateRecoderMultiPatch_Init(&mp);
if (c == 'w') {
b.Patch(0xf372, 80); // health filler
b.Patch(0xf373, 80); // magic filler
// b.Patch(0x1FE01, 25);
StateRecoderMultiPatch_Patch(&mp, 0xf372, 80); // health filler
StateRecoderMultiPatch_Patch(&mp, 0xf373, 80); // magic filler
// b.Patch(0x1FE01, 25);
} else if (c == 'k') {
input_recorder.MigrateToBaseSnapshot();
StateRecorder_MigrateToBaseSnapshot(&state_recorder);
} else if (c == 'o') {
b.Patch(0xf36f, 1);
StateRecoderMultiPatch_Patch(&mp, 0xf36f, 1);
}
StateRecoderMultiPatch_Commit(&mp);
}

View File

@@ -3,5 +3,6 @@
uint8 *GetPtr(uint32 addr);
void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b = -1, int whatflags = 0);
void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b = -1, int whatflags = 0);
void RunEmulatedFuncSilent(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);
void RunEmulatedFunc(uint32 pc, uint16 a, uint16 x, uint16 y, bool mf, bool xf, int b, int whatflags);

View File

@@ -4,20 +4,19 @@
#include "nmi.h"
#include "poly.h"
#include "attract.h"
#include "spc_player.h"
#include "snes/ppu.h"
ZeldaEnv g_zenv;
// These point to the rewritten instance of the emu.
uint8 g_ram[131072];
struct SimpleHdma {
typedef struct SimpleHdma {
const uint8 *table;
const uint8 *indir_ptr;
uint8 rep_count;
uint8 mode;
uint8 ppu_addr;
uint8 indir_bank;
};
} SimpleHdma;
void SimpleHdma_Init(SimpleHdma *c, DmaChannel *dc);
void SimpleHdma_DoLine(SimpleHdma *c);
@@ -34,6 +33,11 @@ static const uint8 bAdrOffsets[8][4] = {
static const uint8 transferLength[8] = {
1, 2, 2, 4, 4, 4, 2, 4
};
const uint16 kUpperBitmasks[] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1 };
const uint8 kLitTorchesColorPlus[] = {31, 8, 4, 0};
const uint8 kDungeonCrystalPendantBit[13] = {0, 0, 4, 2, 0, 16, 2, 1, 64, 4, 1, 32, 8};
const int8 kGetBestActionToPerformOnTile_x[4] = { 7, 7, -3, 16 };
const int8 kGetBestActionToPerformOnTile_y[4] = { 6, 24, 12, 12 };
#define AT_WORD(x) (uint8)(x), (x)>>8
// direct
static const uint8 kAttractDmaTable0[13] = {0x20, AT_WORD(0x00ff), 0x50, AT_WORD(0xe018), 0x50, AT_WORD(0xe018), 1, AT_WORD(0x00ff), 0};
@@ -181,7 +185,7 @@ void ZeldaDrawPpuFrame() {
}
void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint8 reg7, uint8 indirect_bank) {
struct Dma *dma = g_zenv.dma;
Dma *dma = g_zenv.dma;
if (addr6) {
dma_write(dma, DMAP6, transfer_unit);
dma_write(dma, BBAD6, reg6);

View File

@@ -1,3 +1,5 @@
#ifndef ZELDA_RTL_H
#define ZELDA_RTL_H
#pragma once
#include <stdio.h>
@@ -8,60 +10,54 @@
#include "types.h"
#include "snes_regs.h"
#include "snes/dma.h"
#include "snes/ppu.h"
#include "spc_player.h"
struct ZeldaEnv {
typedef struct ZeldaEnv {
uint8 *ram;
uint8 *sram;
uint16 *vram;
struct Ppu *ppu;
struct SpcPlayer *player;
struct Dma *dma;
};
Ppu *ppu;
SpcPlayer *player;
Dma *dma;
} ZeldaEnv;
extern ZeldaEnv g_zenv;
// it's here so that the variables.h can access it
extern uint8 g_ram[131072];
extern const uint16 kUpperBitmasks[];
extern const uint8 kLitTorchesColorPlus[];
extern const uint8 kDungeonCrystalPendantBit[];
extern const int8 kGetBestActionToPerformOnTile_x[];
extern const int8 kGetBestActionToPerformOnTile_y[];
static inline void zelda_snes_dummy_write(uint32 adr, uint8 val) {}
static inline void zelda_snes_dummy_write(uint32_t adr, uint8_t val) {}
const uint16 kUpperBitmasks[] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1 };
const uint8 kLitTorchesColorPlus[] = {31, 8, 4, 0};
const uint8 kDungeonCrystalPendantBit[13] = {0, 0, 4, 2, 0, 16, 2, 1, 64, 4, 1, 32, 8};
const int8 kGetBestActionToPerformOnTile_x[4] = { 7, 7, -3, 16 };
const int8 kGetBestActionToPerformOnTile_y[4] = { 6, 24, 12, 12 };
struct MovableBlockData {
typedef struct MovableBlockData {
uint16 room;
uint16 tilemap;
};
} MovableBlockData;
struct OamEntSigned {
typedef struct OamEntSigned {
int8 x, y;
uint8 charnum, flags;
};
} OamEntSigned;
#define movable_block_datas ((MovableBlockData*)(g_ram+0xf940))
#define oam_buf ((OamEnt*)(g_ram+0x800))
struct OwScrollVars {
typedef struct OwScrollVars {
uint16 ystart, yend, xstart, xend;
};
} OwScrollVars;
#define ow_scroll_vars0 (*(OwScrollVars*)(g_ram+0x600))
#define ow_scroll_vars1 (*(OwScrollVars*)(g_ram+0x608))
#define ow_scroll_vars0_exit (*(OwScrollVars*)(g_ram+0xC154))
extern const uint8 kLayoutQuadrantFlags[];
extern const uint8 kVariousPacks[16];
extern const uint8 kMaxBombsForLevel[];
@@ -75,7 +71,7 @@ extern const uint16 kOverworld_OffsetBaseX[64];
// forwards
struct MirrorHdmaVars {
typedef struct MirrorHdmaVars {
uint16 var0;
uint16 var1[2];
uint16 var3[2];
@@ -88,7 +84,7 @@ struct MirrorHdmaVars {
uint16 var11;
uint16 pad;
uint8 ctr2, ctr;
};
} MirrorHdmaVars;
// Special RAM locations that are unused but I use for compat things.
@@ -199,4 +195,8 @@ void ZeldaRunFrame(uint16 input, int run_what);
void ClearOamBuffer();
void Startup_InitializeMemory();
void LoadSongBank(const uint8 *p);
void NORETURN Die(const char *error);
void ZeldaWriteSram();
void ZeldaReadSram(Snes *snes);
#endif // ZELDA_RTL_H