Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7be4d672b | ||
|
|
393e572945 | ||
|
|
95659d2f40 | ||
|
|
3f52f05e03 | ||
|
|
73a7155f7f | ||
|
|
5baed18b31 | ||
|
|
b67db8a713 | ||
|
|
c28692b32d | ||
|
|
dd8556eebe | ||
|
|
39c5060cbe | ||
|
|
3a080d6bb3 | ||
|
|
e272415f12 | ||
|
|
b23a298b54 | ||
|
|
12bb1f82bc | ||
|
|
9b608eb53a |
19
ancilla.c
19
ancilla.c
@@ -4753,12 +4753,10 @@ endif_5:
|
||||
}
|
||||
}
|
||||
|
||||
void AncillaAdd_SomariaBlock(uint8 type, uint8 y) { // 88e078
|
||||
int AncillaAdd_SomariaBlock(uint8 type, uint8 y) { // 88e078
|
||||
int k = AncillaAdd_AddAncilla_Bank08(type, y);
|
||||
if (k < 0) {
|
||||
Refund_Magic(4);
|
||||
return;
|
||||
}
|
||||
if (k < 0)
|
||||
return k;
|
||||
for (int j = 4; j >= 0; j--) {
|
||||
if (j == k || ancilla_type[j] != 0x2c)
|
||||
continue;
|
||||
@@ -4771,7 +4769,7 @@ void AncillaAdd_SomariaBlock(uint8 type, uint8 y) { // 88e078
|
||||
bitmask_of_dragstate = 0;
|
||||
link_speed_setting = 0;
|
||||
}
|
||||
return;
|
||||
return k;
|
||||
}
|
||||
|
||||
Ancilla_Sfx3_Near(0x2a);
|
||||
@@ -4804,6 +4802,7 @@ void AncillaAdd_SomariaBlock(uint8 type, uint8 y) { // 88e078
|
||||
Ancilla_SetY(k, link_y_coord + kCaneOfSomaria_Y[j]);
|
||||
SomariaBlock_CheckForTransitTile(k);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
void SomariaBlock_CheckForTransitTile(int k) { // 88e191
|
||||
@@ -5378,7 +5377,10 @@ void Ancilla3A_BigBombExplosion(int k) { // 88f18d
|
||||
}
|
||||
if (ancilla_item_to_link[k] == 3 && ancilla_arr3[k] == 1) {
|
||||
Bomb_CheckForDestructibles(Ancilla_GetX(k), Ancilla_GetY(k), 0); // r14?
|
||||
follower_indicator = 0;
|
||||
|
||||
// Changed so this is reset elsewhere
|
||||
if (!(enhanced_features0 & kFeatures0_MiscBugFixes))
|
||||
follower_indicator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6087,7 +6089,7 @@ void AncillaAdd_SomariaPlatformPoof(int k) { // 898dd2
|
||||
Player_TileDetectNearby();
|
||||
}
|
||||
|
||||
void AncillaAdd_SuperBombExplosion(uint8 a, uint8 y) { // 898df9
|
||||
int AncillaAdd_SuperBombExplosion(uint8 a, uint8 y) { // 898df9
|
||||
int k = Ancilla_AddAncilla(a, y);
|
||||
if (k >= 0) {
|
||||
ancilla_R[k] = 0;
|
||||
@@ -6101,6 +6103,7 @@ void AncillaAdd_SuperBombExplosion(uint8 a, uint8 y) { // 898df9
|
||||
int x = tagalong_x_lo[j] | tagalong_x_hi[j] << 8;
|
||||
Ancilla_SetXY(k, x + 8, y + 16);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
void ConfigureRevivalAncillae() { // 898e4e
|
||||
|
||||
@@ -173,7 +173,7 @@ void Ancilla31_ByrnaSpark(int k);
|
||||
void Ancilla_SwordBeam(int k);
|
||||
void Ancilla0D_SpinAttackFullChargeSpark(int k);
|
||||
void Ancilla27_Duck(int k);
|
||||
void AncillaAdd_SomariaBlock(uint8 type, uint8 y);
|
||||
int AncillaAdd_SomariaBlock(uint8 type, uint8 y);
|
||||
void SomariaBlock_CheckForTransitTile(int k);
|
||||
int Ancilla_CheckBasicSpriteCollision(int k);
|
||||
bool Ancilla_CheckBasicSpriteCollision_Single(int k, int j);
|
||||
@@ -219,7 +219,7 @@ void AncillaAdd_ChargedSpinAttackSparkle();
|
||||
void AncillaAdd_ExplodingWeatherVane(uint8 a, uint8 y);
|
||||
void AncillaAdd_CutsceneDuck(uint8 a, uint8 y);
|
||||
void AncillaAdd_SomariaPlatformPoof(int k);
|
||||
void AncillaAdd_SuperBombExplosion(uint8 a, uint8 y);
|
||||
int AncillaAdd_SuperBombExplosion(uint8 a, uint8 y);
|
||||
void ConfigureRevivalAncillae();
|
||||
void AncillaAdd_LampFlame(uint8 a, uint8 y);
|
||||
void AncillaAdd_MSCutscene(uint8 a, uint8 y);
|
||||
|
||||
32
dungeon.c
32
dungeon.c
@@ -2052,13 +2052,14 @@ void RoomBounds_SubA(RoomBounds *r) {
|
||||
}
|
||||
|
||||
void Dungeon_StartInterRoomTrans_Left() {
|
||||
assert(submodule_index == 0);
|
||||
link_quadrant_x ^= 1;
|
||||
Dungeon_AdjustQuadrant();
|
||||
RoomBounds_SubA(&room_bounds_x);
|
||||
Dung_SaveDataForCurrentRoom();
|
||||
DungeonTransition_AdjustCamera_X(link_quadrant_x ^ 1);
|
||||
HandleEdgeTransition_AdjustCameraBoundaries(3);
|
||||
submodule_index++;
|
||||
submodule_index = 1;
|
||||
if (link_quadrant_x) {
|
||||
RoomBounds_SubB(&room_bounds_x);
|
||||
BYTE(dungeon_room_index_prev) = dungeon_room_index;
|
||||
@@ -2072,7 +2073,7 @@ void Dungeon_StartInterRoomTrans_Left() {
|
||||
}
|
||||
dungeon_room_index--;
|
||||
}
|
||||
submodule_index += 1;
|
||||
submodule_index = 2;
|
||||
if (room_transitioning_flags & 1) {
|
||||
link_is_on_lower_level ^= 1;
|
||||
link_is_on_lower_level_mirror = link_is_on_lower_level;
|
||||
@@ -2091,13 +2092,14 @@ void Dung_StartInterRoomTrans_Left_Plus() {
|
||||
}
|
||||
|
||||
void Dungeon_StartInterRoomTrans_Up() {
|
||||
assert(submodule_index == 0);
|
||||
link_quadrant_y ^= 2;
|
||||
Dungeon_AdjustQuadrant();
|
||||
RoomBounds_SubA(&room_bounds_y);
|
||||
Dung_SaveDataForCurrentRoom();
|
||||
DungeonTransition_AdjustCamera_Y(link_quadrant_y ^ 2);
|
||||
HandleEdgeTransition_AdjustCameraBoundaries(1);
|
||||
submodule_index++;
|
||||
submodule_index = 1;
|
||||
if (link_quadrant_y) {
|
||||
RoomBounds_SubB(&room_bounds_y);
|
||||
BYTE(dungeon_room_index_prev) = dungeon_room_index;
|
||||
@@ -2119,7 +2121,7 @@ void Dungeon_StartInterRoomTrans_Up() {
|
||||
Dungeon_AdjustAfterSpiralStairs();
|
||||
}
|
||||
BYTE(dungeon_room_index) -= 0x10;
|
||||
submodule_index += 1;
|
||||
submodule_index = 2;
|
||||
if (room_transitioning_flags & 1) {
|
||||
link_is_on_lower_level ^= 1;
|
||||
link_is_on_lower_level_mirror = link_is_on_lower_level;
|
||||
@@ -2133,13 +2135,14 @@ void Dungeon_StartInterRoomTrans_Up() {
|
||||
}
|
||||
|
||||
void Dungeon_StartInterRoomTrans_Down() {
|
||||
assert(submodule_index == 0);
|
||||
link_quadrant_y ^= 2;
|
||||
Dungeon_AdjustQuadrant();
|
||||
RoomBounds_AddA(&room_bounds_y);
|
||||
Dung_SaveDataForCurrentRoom();
|
||||
DungeonTransition_AdjustCamera_Y(link_quadrant_y);
|
||||
HandleEdgeTransition_AdjustCameraBoundaries(0);
|
||||
submodule_index++;
|
||||
submodule_index = 1;
|
||||
if (!link_quadrant_y) {
|
||||
RoomBounds_AddB(&room_bounds_y);
|
||||
BYTE(dungeon_room_index_prev) = dungeon_room_index;
|
||||
@@ -2153,7 +2156,7 @@ void Dungeon_StartInterRoomTrans_Down() {
|
||||
Dungeon_AdjustAfterSpiralStairs();
|
||||
}
|
||||
BYTE(dungeon_room_index) += 16;
|
||||
submodule_index += 1;
|
||||
submodule_index = 2;
|
||||
if (room_transitioning_flags & 1) {
|
||||
link_is_on_lower_level ^= 1;
|
||||
link_is_on_lower_level_mirror = link_is_on_lower_level;
|
||||
@@ -4281,6 +4284,14 @@ void Dungeon_FlipCrystalPegAttribute() { // 81c22a
|
||||
void Dungeon_HandleRoomTags() { // 81c2fd
|
||||
if (!flag_skip_call_tag_routines) {
|
||||
Dungeon_DetectStaircase();
|
||||
|
||||
// Dungeon_DetectStaircase might change the submodule, so avoid
|
||||
// calling the tag routines cause they could also change the submodule,
|
||||
// causing items to spawn in incorrect locations cause link_x/y_coord gets
|
||||
// out of sync if you enter a staircase exactly when a room tag triggers.
|
||||
if (enhanced_features0 & kFeatures0_MiscBugFixes && submodule_index != 0)
|
||||
return;
|
||||
|
||||
g_ram[14] = 0;
|
||||
kDungTagroutines[dung_hdr_tag[0]](0);
|
||||
g_ram[14] = 1;
|
||||
@@ -7958,13 +7969,14 @@ void HandleEdgeTransitionMovementEast_RightBy8() { // 82b62e
|
||||
}
|
||||
|
||||
void Dungeon_StartInterRoomTrans_Right() { // 82b63a
|
||||
assert(submodule_index == 0);
|
||||
link_quadrant_x ^= 1;
|
||||
Dungeon_AdjustQuadrant();
|
||||
RoomBounds_AddA(&room_bounds_x);
|
||||
Dung_SaveDataForCurrentRoom();
|
||||
DungeonTransition_AdjustCamera_X(link_quadrant_x);
|
||||
HandleEdgeTransition_AdjustCameraBoundaries(2);
|
||||
submodule_index++;
|
||||
submodule_index = 1;
|
||||
if (!link_quadrant_x) {
|
||||
RoomBounds_AddB(&room_bounds_x);
|
||||
BYTE(dungeon_room_index_prev) = dungeon_room_index;
|
||||
@@ -7978,7 +7990,7 @@ void Dungeon_StartInterRoomTrans_Right() { // 82b63a
|
||||
}
|
||||
dungeon_room_index += 1;
|
||||
}
|
||||
submodule_index += 1;
|
||||
submodule_index = 2;
|
||||
if (room_transitioning_flags & 1) {
|
||||
link_is_on_lower_level ^= 1;
|
||||
link_is_on_lower_level_mirror = link_is_on_lower_level;
|
||||
@@ -8591,7 +8603,7 @@ void HandleLinkOnSpiralStairs() { // 87f2c1
|
||||
link_actual_vel_x = 2;
|
||||
}
|
||||
}
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
Link_HandleMovingAnimation_StartWithDash();
|
||||
if (!link_timer_push_get_tired && sign8(--countdown_timer_for_staircases)) {
|
||||
countdown_timer_for_staircases = 0;
|
||||
@@ -8630,7 +8642,7 @@ void SpiralStairs_FindLandingSpot() { // 87f391
|
||||
link_actual_vel_x = -4, link_actual_vel_y = 2;
|
||||
if (some_animation_timer_steps == 2)
|
||||
link_actual_vel_x = 0, link_actual_vel_y = 16;
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
Link_HandleMovingAnimation_StartWithDash();
|
||||
if ((uint8)link_x_coord == (uint8)tiledetect_which_y_pos[1])
|
||||
some_animation_timer_steps = 2;
|
||||
|
||||
38
main.c
38
main.c
@@ -65,6 +65,9 @@ static int g_snes_width, g_snes_height;
|
||||
static int g_sdl_audio_mixer_volume = SDL_MIX_MAXVOLUME;
|
||||
|
||||
void NORETURN Die(const char *error) {
|
||||
#if defined(NDEBUG) && defined(_WIN32)
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, kWindowTitle, error, NULL);
|
||||
#endif
|
||||
fprintf(stderr, "Error: %s\n", error);
|
||||
exit(1);
|
||||
}
|
||||
@@ -123,13 +126,12 @@ static SDL_HitTestResult HitTestCallback(SDL_Window *win, const SDL_Point *area,
|
||||
(SDL_GetModState() & KMOD_CTRL) != 0 ? SDL_HITTEST_DRAGGABLE : SDL_HITTEST_NORMAL;
|
||||
}
|
||||
|
||||
static bool RenderScreenWithPerf(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
|
||||
bool rv;
|
||||
static void RenderScreenWithPerf(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
|
||||
if (g_display_perf || g_config.display_perf_title) {
|
||||
static float history[64], average;
|
||||
static int history_pos;
|
||||
uint64 before = SDL_GetPerformanceCounter();
|
||||
rv = ZeldaDrawPpuFrame(pixel_buffer, pitch, render_flags);
|
||||
ZeldaDrawPpuFrame(pixel_buffer, pitch, render_flags);
|
||||
uint64 after = SDL_GetPerformanceCounter();
|
||||
float v = (double)SDL_GetPerformanceFrequency() / (after - before);
|
||||
average += v - history[history_pos];
|
||||
@@ -137,9 +139,8 @@ static bool RenderScreenWithPerf(uint8 *pixel_buffer, size_t pitch, uint32 rende
|
||||
history_pos = (history_pos + 1) & 63;
|
||||
g_curr_fps = average * (1.0f / 64);
|
||||
} else {
|
||||
rv = ZeldaDrawPpuFrame(pixel_buffer, pitch, render_flags);
|
||||
ZeldaDrawPpuFrame(pixel_buffer, pitch, render_flags);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Go some steps up and find zelda3.ini
|
||||
@@ -481,30 +482,27 @@ static void RenderNumber(uint8 *dst, size_t pitch, int n, bool big) {
|
||||
}
|
||||
|
||||
static void RenderScreen(SDL_Window *window, SDL_Renderer *renderer, SDL_Texture *texture, bool fullscreen) {
|
||||
uint8* pixels = NULL;
|
||||
uint8 *pixels = 0;
|
||||
int pitch = 0;
|
||||
int render_scale = PpuGetCurrentRenderScale(g_zenv.ppu, g_ppu_render_flags);
|
||||
SDL_Rect src_rect = { 0, 0, g_snes_width * render_scale >> 1, g_snes_height * render_scale >> 1};
|
||||
|
||||
uint64 t0 = SDL_GetPerformanceCounter();
|
||||
if(SDL_LockTexture(texture, NULL, (void**)&pixels, &pitch) != 0) {
|
||||
if(SDL_LockTexture(texture, &src_rect, (void**)&pixels, &pitch) != 0) {
|
||||
printf("Failed to lock texture: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
uint64 t1 = SDL_GetPerformanceCounter();
|
||||
bool hq = RenderScreenWithPerf(pixels, pitch, g_ppu_render_flags);
|
||||
RenderScreenWithPerf(pixels, pitch, g_ppu_render_flags);
|
||||
if (g_display_perf) {
|
||||
RenderNumber(pixels + (pitch * 2 << hq), pitch, g_curr_fps, hq);
|
||||
}
|
||||
if (g_config.display_perf_title) {
|
||||
char title[60];
|
||||
snprintf(title, sizeof(title), "%s | FPS: %d", kWindowTitle, g_curr_fps);
|
||||
SDL_SetWindowTitle(window, title);
|
||||
RenderNumber(pixels + pitch * render_scale, pitch, g_curr_fps, render_scale == 4);
|
||||
}
|
||||
uint64 t2 = SDL_GetPerformanceCounter();
|
||||
SDL_UnlockTexture(texture);
|
||||
uint64 t3 = SDL_GetPerformanceCounter();
|
||||
SDL_RenderClear(renderer);
|
||||
uint64 t4 = SDL_GetPerformanceCounter();
|
||||
SDL_Rect src_rect = { 0, 0, g_snes_width, g_snes_height };
|
||||
SDL_RenderCopy(renderer, texture, hq ? NULL : &src_rect, NULL);
|
||||
SDL_RenderCopy(renderer, texture, &src_rect, NULL);
|
||||
uint64 t5 = SDL_GetPerformanceCounter();
|
||||
|
||||
double f = 1e3 / (double)SDL_GetPerformanceFrequency();
|
||||
@@ -516,7 +514,11 @@ static void RenderScreen(SDL_Window *window, SDL_Renderer *renderer, SDL_Texture
|
||||
(t5 - t4) * f
|
||||
);
|
||||
|
||||
|
||||
if (g_config.display_perf_title) {
|
||||
char title[60];
|
||||
snprintf(title, sizeof(title), "%s | FPS: %d", kWindowTitle, g_curr_fps);
|
||||
SDL_SetWindowTitle(window, title);
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleCommand_Locked(uint32 j, bool pressed);
|
||||
@@ -743,7 +745,7 @@ static void LoadAssets() {
|
||||
uint8 *data = ReadFile("tables/zelda3_assets.dat", &length);
|
||||
if (!data)
|
||||
data = ReadFile("zelda3_assets.dat", &length);
|
||||
if (!data) Die("Failed to read zelda3_assets.dat");
|
||||
if (!data) Die("Failed to read zelda3_assets.dat. Please see the README for information about how you get this file.");
|
||||
|
||||
static const char kAssetsSig[] = { kAssets_Sig };
|
||||
|
||||
|
||||
@@ -2220,6 +2220,12 @@ void CopySaveToWRAM() { // 8ccfbb
|
||||
word_7E021F = 0x7f;
|
||||
word_7E0221 = 0xffff;
|
||||
|
||||
// If you save / quit in the middle of a mosaic effect, such as
|
||||
// being electrocuted by a buzz blob, the resumed game will skip
|
||||
// the location prompt and start in the sanctuary.
|
||||
if (enhanced_features0 & kFeatures0_MiscBugFixes)
|
||||
mosaic_level = 0;
|
||||
|
||||
hud_var1 = 128;
|
||||
main_module_index = 5;
|
||||
submodule_index = 0;
|
||||
|
||||
132
player.c
132
player.c
@@ -242,14 +242,20 @@ void PlayerHandler_00_Ground_3() { // 8781a0
|
||||
Link_HandleYItem();
|
||||
if (sram_progress_indicator != 0) {
|
||||
Link_HandleSwordCooldown();
|
||||
if (link_player_handler_state == 3) {
|
||||
link_x_vel = link_y_vel = 0;
|
||||
goto getout_dostuff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we're not handling potions. Things further
|
||||
// down don't assume this and change the module indexes randomly.
|
||||
// Also check for spin attack for some reason.
|
||||
if ((enhanced_features0 & kFeatures0_MiscBugFixes) && main_module_index == 14 && submodule_index != 2 ||
|
||||
link_player_handler_state == 3) {
|
||||
link_x_vel = link_y_vel = 0;
|
||||
goto getout_dostuff;
|
||||
}
|
||||
|
||||
|
||||
Link_HandleCape_passive_LiftCheck();
|
||||
if (link_incapacitated_timer) {
|
||||
link_moving_against_diag_tile = 0;
|
||||
@@ -737,7 +743,7 @@ lbl_jump_into_middle:
|
||||
if ((link_direction & 0xc) == 0)
|
||||
link_actual_vel_y = 0;
|
||||
}
|
||||
LinkHop_FindArbitraryLandingSpot(); // not
|
||||
Link_MovePosition(); // not
|
||||
timer_running:
|
||||
if (link_player_handler_state != 6) {
|
||||
Link_HandleCardinalCollision(); // not
|
||||
@@ -791,7 +797,7 @@ void LinkHop_HoppingSouthOW() { // 87894e
|
||||
link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
|
||||
link_z_coord = link_z_coord_mirror;
|
||||
link_actual_vel_z -= 2;
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
if (sign8(link_actual_vel_z)) {
|
||||
if (link_actual_vel_z < 0xa0)
|
||||
link_actual_vel_z = 0xa0;
|
||||
@@ -827,7 +833,7 @@ void LinkState_HandlingJump() { // 878a05
|
||||
link_actual_vel_z_copy = link_actual_vel_z_copy_mirror;
|
||||
BYTE(link_z_coord) = link_z_coord_mirror;
|
||||
link_actual_vel_z -= 2;
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
if (sign8(link_actual_vel_z)) {
|
||||
if (link_actual_vel_z < 0xa0)
|
||||
link_actual_vel_z = 0xa0;
|
||||
@@ -1014,7 +1020,7 @@ finish:
|
||||
void LinkState_HoppingDiagonallyUpOW() { // 878dc6
|
||||
draw_water_ripples_or_grass = 0;
|
||||
Player_ChangeZ(2);
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
if (sign8(link_z_coord)) {
|
||||
Link_SplashUponLanding();
|
||||
if (link_player_handler_state != kPlayerState_Swimming && !link_is_in_deep_water)
|
||||
@@ -1041,9 +1047,15 @@ void LinkState_HoppingDiagonallyDownOW() { // 878e15
|
||||
LinkHop_FindLandingSpotDiagonallyDown();
|
||||
link_x_coord = old_x;
|
||||
|
||||
static const uint8 kLedgeVelX[] = { 4, 4, 4, 10, 10, 10, 11, 18, 18, 18, 20, 20, 20, 20, 22, 22, 26, 26, 26, 26, 28, 28, 28, 28 };
|
||||
static const uint8 kLedgeVelX[] = {
|
||||
4, 4, 4, 10, 10, 10, 11, 18,
|
||||
18, 18, 20, 20, 20, 20, 22, 22,
|
||||
26, 26, 26, 26, 28, 28, 28, 28
|
||||
};
|
||||
|
||||
int8 velx = kLedgeVelX[(uint16)(link_y_coord - link_y_coord_original) >> 3];
|
||||
int t = (uint16)(link_y_coord - link_y_coord_original);
|
||||
// Fix out of bounds read
|
||||
int8 velx = kLedgeVelX[IntMin(t >> 3, 23)];
|
||||
link_actual_vel_x = (dir != 2) ? velx : -velx;
|
||||
if (!player_is_indoors)
|
||||
link_is_on_lower_level = 2;
|
||||
@@ -1359,7 +1371,12 @@ void LinkState_Pits() { // 8792d3
|
||||
} else {
|
||||
if (!link_is_running)
|
||||
goto aux_state;
|
||||
if (link_countdown_for_dash) {
|
||||
// If you use a turbo controller to perfectly spam the dash button,
|
||||
// the check for Link being in a hole is endlessly skipped and you
|
||||
// can levitate across chasms.
|
||||
// Fix this by ensuring that the dash button is held down before proceeding to the dash state.
|
||||
if (link_countdown_for_dash &&
|
||||
(!(enhanced_features0 & kFeatures0_MiscBugFixes) || (joypad1L_last & 0x80))) {
|
||||
LinkState_Dashing();
|
||||
return;
|
||||
}
|
||||
@@ -1444,6 +1461,8 @@ endif_1:
|
||||
ApplyLinksMovementToCamera();
|
||||
return;
|
||||
}
|
||||
|
||||
// Initiate fall down
|
||||
if (player_near_pit_state != 2) {
|
||||
if (link_item_moon_pearl) {
|
||||
link_need_for_poof_for_transform = 0;
|
||||
@@ -2736,7 +2755,7 @@ void LinkState_UsingQuake() { // 87a6d6
|
||||
BYTE(link_z_coord) = link_z_coord_mirror;
|
||||
link_auxiliary_state = 2;
|
||||
Player_ChangeZ(2);
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
link_actual_vel_z_mirror = link_actual_vel_z;
|
||||
link_actual_vel_z_copy_mirror = link_actual_vel_z_copy;
|
||||
BYTE(link_z_coord_mirror) = link_z_coord;
|
||||
@@ -3144,7 +3163,7 @@ void LinkState_Hookshotting() { // 87ab7c
|
||||
}
|
||||
return;
|
||||
loc_87AD49:
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
TileDetect_MainHandler(5);
|
||||
if (player_is_indoors) {
|
||||
uint8 x = tiledetect_vertical_ledge >> 4 | tiledetect_vertical_ledge | detection_of_ledge_tiles_horiz_uphoriz;
|
||||
@@ -3197,7 +3216,9 @@ void LinkItem_Cape() { // 87adc1
|
||||
link_direction &= ~0xf;
|
||||
if (!--cape_decrement_counter) {
|
||||
cape_decrement_counter = kCapeDepletionTimers[link_magic_consumption];
|
||||
if (!--link_magic_power) {
|
||||
// Avoid magic underflow if an anti-fairy consumes magic.
|
||||
if (link_magic_power == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes) ||
|
||||
!--link_magic_power) {
|
||||
Link_ForceUnequipCape();
|
||||
return;
|
||||
}
|
||||
@@ -3260,15 +3281,30 @@ void LinkItem_CaneOfSomaria() { // 87aec0
|
||||
if (player_on_somaria_platform || is_standing_in_doorway || !CheckYButtonPress())
|
||||
return;
|
||||
int i = 4;
|
||||
bool did_charge_magic = false;
|
||||
|
||||
while (ancilla_type[i] != 0x2c) {
|
||||
if (--i < 0) {
|
||||
if (!LinkCheckMagicCost(4))
|
||||
if (!LinkCheckMagicCost(4)) {
|
||||
// If you use the Cane of Somaria with an empty magic meter,
|
||||
// then quickly switch to the mushroom or magic powder after
|
||||
// the "no magic" prompt, you will automatically sprinkle magic powder
|
||||
// despite pressing no button and having no magic.
|
||||
if (enhanced_features0 & kFeatures0_MiscBugFixes)
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
did_charge_magic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
link_debug_value_2 = 1;
|
||||
AncillaAdd_SomariaBlock(44, 1);
|
||||
if (AncillaAdd_SomariaBlock(0x2c, 1) < 0) {
|
||||
// If you use the Cane of Somaria while two bombs and the boomerang are active,
|
||||
// magic will be refunded instead of used.
|
||||
if (did_charge_magic || !(enhanced_features0 & kFeatures0_MiscBugFixes))
|
||||
Refund_Magic(4);
|
||||
}
|
||||
link_delay_timer_spin_attack = kRodAnimDelays[0];
|
||||
link_animation_steps = 0;
|
||||
player_handler_timer = 0;
|
||||
@@ -3289,8 +3325,9 @@ void LinkItem_CaneOfSomaria() { // 87aec0
|
||||
player_handler_timer = 0;
|
||||
link_delay_timer_spin_attack = 0;
|
||||
link_debug_value_2 = 0;
|
||||
button_mask_b_y &= ~0x40;
|
||||
link_position_mode &= ~8;
|
||||
out:
|
||||
button_mask_b_y &= ~0x40;
|
||||
}
|
||||
|
||||
void LinkItem_CaneOfByrna() { // 87af3e
|
||||
@@ -3708,7 +3745,7 @@ reset_to_normal:
|
||||
if (!(link_direction & 0xc))
|
||||
link_actual_vel_y = 0;
|
||||
out:
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
out2:
|
||||
Link_HandleCardinalCollision();
|
||||
HandleIndoorCameraAndDoors();
|
||||
@@ -5099,11 +5136,17 @@ void StartMovementCollisionChecks_X_HandleOutdoors() { // 87c8e9
|
||||
return;
|
||||
} // endif_8
|
||||
|
||||
if ((R14 & 2) == 0 && (R12 & 5) != 0 && (!link_is_running || (link_direction_facing & 4))) {
|
||||
FlagMovingIntoSlopes_X();
|
||||
if ((link_moving_against_diag_tile & 0xf) != 0)
|
||||
return;
|
||||
} // endif_9
|
||||
// If force facing down (hold B button), while turboing on the Run key, we'll never
|
||||
// reach FlagMovingIntoSlopes_X causing a Dash Buffering glitch.
|
||||
// Fix by always calling it, not sure why you wouldn't always want to call it.
|
||||
if ((R14 & 2) == 0 && (R12 & 5) != 0) {
|
||||
bool skip_check = link_is_running && !(link_direction_facing & 4);
|
||||
if (!skip_check || (enhanced_features0 & kFeatures0_MiscBugFixes)) {
|
||||
FlagMovingIntoSlopes_X();
|
||||
if ((link_moving_against_diag_tile & 0xf) != 0)
|
||||
return;
|
||||
} // endif_9
|
||||
}
|
||||
|
||||
link_moving_against_diag_tile = 0;
|
||||
|
||||
@@ -5214,8 +5257,9 @@ void Link_HandleDiagonalKickback() { // 87ccab
|
||||
static const int8 x1[] = { 0, -1, -1, -1, -2, -2, -2, -3, -3, -3 };
|
||||
link_x_coord += sign8(link_x_vel) ? x1[-(int8)link_x_vel] : x0[link_x_vel];
|
||||
|
||||
static const int8 y0[] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3 };
|
||||
static const int8 y1[] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3 };
|
||||
static const int8 y0[10] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3 };
|
||||
// Bug in zelda, might read index 15
|
||||
static const int8 y1[16] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 0xa5, 0x30, 0xf0, 0x04, 0xa5, 0x31 };
|
||||
link_y_coord += sign8(link_y_vel) ? y1[-(int8)link_y_vel] : y0[link_y_vel];
|
||||
} else {
|
||||
noHorizOrNoVertical:
|
||||
@@ -5511,12 +5555,25 @@ void FlagMovingIntoSlopes_Y() { // 87e076
|
||||
if (tiledetect_diagonal_tile & 5) {
|
||||
int8 ym = tiledetect_which_y_pos[0] & 7;
|
||||
|
||||
if (!(tiledetect_diag_state & 2)) {
|
||||
ym = 8 - ym;
|
||||
if (enhanced_features0 & kFeatures0_MiscBugFixes) {
|
||||
if (tiledetect_diag_state & 2) {
|
||||
ym = -ym;
|
||||
} else {
|
||||
ym = kAvoidJudder1[o] - (8 - ym);
|
||||
}
|
||||
} else {
|
||||
ym += 8;
|
||||
// This code is bad because it could cause the player
|
||||
// to move up to 15 pixels, causing an array out bounds read.
|
||||
// Not sure how it works, but changed it to look more like the X version.
|
||||
if (!(tiledetect_diag_state & 2)) {
|
||||
ym = 8 - ym; // 0 to 8
|
||||
} else {
|
||||
ym += 8; // 8 to 15
|
||||
}
|
||||
// -15 to 7
|
||||
ym = kAvoidJudder1[o] - ym;
|
||||
}
|
||||
ym = kAvoidJudder1[o] - ym;
|
||||
|
||||
if (link_y_vel == 0)
|
||||
return;
|
||||
if (sign8(link_y_vel))
|
||||
@@ -5548,12 +5605,9 @@ void FlagMovingIntoSlopes_X() { // 87e112
|
||||
int8 xm = link_x_coord & 7;
|
||||
|
||||
if (tiledetect_diag_state != 4 && tiledetect_diag_state != 6) {
|
||||
o ^= 7;
|
||||
xm = -xm;
|
||||
} else {
|
||||
xm -= 8;
|
||||
xm = -xm;
|
||||
xm = kAvoidJudder1[o] - xm;
|
||||
xm = kAvoidJudder1[o] - (8 - xm);
|
||||
} // endif_5
|
||||
if (link_x_vel == 0)
|
||||
return;
|
||||
@@ -5677,10 +5731,10 @@ void Link_HandleVelocity() { // 87e245
|
||||
link_actual_vel_z = 0xff;
|
||||
link_z_coord = 0xffff;
|
||||
link_subpixel_z = 0;
|
||||
LinkHop_FindArbitraryLandingSpot();
|
||||
Link_MovePosition();
|
||||
}
|
||||
|
||||
void LinkHop_FindArbitraryLandingSpot() { // 87e370
|
||||
void Link_MovePosition() { // 87e370
|
||||
uint16 x = link_x_coord, y = link_y_coord;
|
||||
link_y_coord_safe_return_lo = link_y_coord;
|
||||
link_y_coord_safe_return_hi = link_y_coord >> 8;
|
||||
@@ -6015,6 +6069,14 @@ void HandleDoorTransitions() { // 87e901
|
||||
link_x_page_movement_delta = 0;
|
||||
link_y_page_movement_delta = 0;
|
||||
|
||||
// Using a potion might have changed us into a different module, and the routines
|
||||
// below just increment the submodule value, causing all kinds of havoc.
|
||||
// There's an added return to catch the same behavior a bit up, but this one catches more cases,
|
||||
// at the expense of link already having done his movement, so by returning here we might
|
||||
// miss handling the door causing other kinds of issues.
|
||||
if ((enhanced_features0 & kFeatures0_MiscBugFixes) && !(main_module_index == 7 && submodule_index == 0))
|
||||
return;
|
||||
|
||||
if (link_direction_last & 0xC && is_standing_in_doorway == 1) {
|
||||
if (link_direction_last & 4) {
|
||||
if (((t = link_y_coord + 28) & 0xfc) == 0)
|
||||
|
||||
2
player.h
2
player.h
@@ -207,7 +207,7 @@ void FlagMovingIntoSlopes_X();
|
||||
void Link_HandleRecoiling();
|
||||
void Player_HandleIncapacitated_Inner2();
|
||||
void Link_HandleVelocity();
|
||||
void LinkHop_FindArbitraryLandingSpot();
|
||||
void Link_MovePosition();
|
||||
void Link_HandleVelocityAndSandDrag(uint16 x, uint16 y);
|
||||
void HandleSwimStrokeAndSubpixels();
|
||||
void Player_SomethingWithVelocity_TiredOrSwim(uint16 xvel, uint16 yvel);
|
||||
|
||||
16
snes/ppu.c
16
snes/ppu.c
@@ -122,10 +122,14 @@ void ppu_saveload(Ppu *ppu, SaveLoadFunc *func, void *ctx) {
|
||||
func(ctx, tmp, 123);
|
||||
}
|
||||
|
||||
bool PpuBeginDrawing(Ppu *ppu, uint8_t *pixels, size_t pitch, uint32_t render_flags) {
|
||||
int PpuGetCurrentRenderScale(Ppu *ppu, uint32_t render_flags) {
|
||||
bool hq = ppu->mode == 7 && !ppu->forcedBlank &&
|
||||
(ppu->renderFlags & (kPpuRenderFlags_4x4Mode7 | kPpuRenderFlags_NewRenderer)) == (kPpuRenderFlags_4x4Mode7 | kPpuRenderFlags_NewRenderer);
|
||||
return hq ? 4 : 2;
|
||||
}
|
||||
|
||||
void PpuBeginDrawing(Ppu *ppu, uint8_t *pixels, size_t pitch, uint32_t render_flags) {
|
||||
ppu->renderFlags = render_flags;
|
||||
bool hq = ppu->mode == 7 && !ppu->forcedBlank &&
|
||||
(ppu->renderFlags & (kPpuRenderFlags_4x4Mode7 | kPpuRenderFlags_NewRenderer)) == (kPpuRenderFlags_4x4Mode7 | kPpuRenderFlags_NewRenderer);
|
||||
ppu->renderPitch = (uint)pitch;
|
||||
ppu->renderBuffer = pixels;
|
||||
|
||||
@@ -140,14 +144,12 @@ bool PpuBeginDrawing(Ppu *ppu, uint8_t *pixels, size_t pitch, uint32_t render_fl
|
||||
memset(&ppu->brightnessMult[32], ppu->brightnessMult[31], 31);
|
||||
}
|
||||
|
||||
if (hq) {
|
||||
if (PpuGetCurrentRenderScale(ppu, ppu->renderFlags) == 4) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
uint32 color = ppu->cgram[i];
|
||||
ppu->colorMapRgb[i] = ppu->brightnessMult[color & 0x1f] << 16 | ppu->brightnessMult[(color >> 5) & 0x1f] << 8 | ppu->brightnessMult[(color >> 10) & 0x1f];
|
||||
}
|
||||
}
|
||||
|
||||
return hq;
|
||||
}
|
||||
|
||||
static inline void ClearBackdrop(PpuPixelPrioBufs *buf) {
|
||||
@@ -833,7 +835,7 @@ static void PpuDrawBackgrounds(Ppu *ppu, int y, bool sub) {
|
||||
PpuDrawBackground_2bpp(ppu, y, sub, 2, 0xf200, 0x1200);
|
||||
} else {
|
||||
// mode 7
|
||||
PpuDrawBackground_mode7(ppu, y, sub, 0xc0);
|
||||
PpuDrawBackground_mode7(ppu, y, sub, 0xc000);
|
||||
if (ppu->lineHasSprites)
|
||||
PpuDrawSprites(ppu, y, sub, false);
|
||||
}
|
||||
|
||||
@@ -135,7 +135,10 @@ void ppu_runLine(Ppu* ppu, int line);
|
||||
uint8_t ppu_read(Ppu* ppu, uint8_t adr);
|
||||
void ppu_write(Ppu* ppu, uint8_t adr, uint8_t val);
|
||||
void ppu_saveload(Ppu *ppu, SaveLoadFunc *func, void *ctx);
|
||||
bool PpuBeginDrawing(Ppu *ppu, uint8_t *buffer, size_t pitch, uint32_t render_flags);
|
||||
void PpuBeginDrawing(Ppu *ppu, uint8_t *buffer, size_t pitch, uint32_t render_flags);
|
||||
|
||||
// Returns the current render scale, 1x = 256px, 2x=512px, 4x=1024px
|
||||
int PpuGetCurrentRenderScale(Ppu *ppu, uint32_t render_flags);
|
||||
|
||||
void PpuSetMode7PerspectiveCorrection(Ppu *ppu, int low, int high);
|
||||
void PpuSetExtraSideSpace(Ppu *ppu, int left, int right, int bottom);
|
||||
|
||||
@@ -11804,6 +11804,12 @@ void Sprite_D8_Heart(int k) { // 86cec0
|
||||
if (Sprite_ReturnIfInactive(k))
|
||||
return;
|
||||
Sprite_CheckAbsorptionByPlayer(k);
|
||||
|
||||
// Avoid calling Sprite_HandleAbsorptionByPlayer twice, it's called
|
||||
// also from within Sprite_HandleDraggingByAncilla
|
||||
if (sprite_state[k] == 0 && (enhanced_features0 & kFeatures0_MiscBugFixes))
|
||||
return;
|
||||
|
||||
if (Sprite_HandleDraggingByAncilla(k))
|
||||
return;
|
||||
Sprite_MoveXY(k);
|
||||
|
||||
26
tagalong.c
26
tagalong.c
@@ -426,8 +426,23 @@ void Follower_NotFollowing() { // 89a2b2
|
||||
Tagalong_Draw();
|
||||
} else {
|
||||
if (follower_indicator == 13 && !player_is_indoors && !super_bomb_indicator_unk2) {
|
||||
AncillaAdd_SuperBombExplosion(0x3a, 0);
|
||||
follower_dropped = 0;
|
||||
// Fixed so we wait a little bit if we can't spawn the ancilla
|
||||
if (AncillaAdd_SuperBombExplosion(0x3a, 0) >= 0) {
|
||||
follower_dropped = 0;
|
||||
|
||||
// A ticking super bomb will cancel and teleport back to you as a follower if you do
|
||||
// any of these at count 0: (1) change screen via walking, mirror, or bird travel
|
||||
// (2) fill all ancillary slots
|
||||
// (3) die with a bottled faerie.
|
||||
// Fixed this by clearing the follower indicator here, instead of in the ancilla
|
||||
// bomb code.
|
||||
if (enhanced_features0 & kFeatures0_MiscBugFixes) {
|
||||
follower_indicator = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
super_bomb_indicator_unk1 = 1;
|
||||
}
|
||||
}
|
||||
Follower_DoLayers();
|
||||
}
|
||||
@@ -650,8 +665,11 @@ skip_first_sprites:
|
||||
if (pal == 7 && overworld_palette_swap_flag)
|
||||
pal = 0;
|
||||
|
||||
if (follower_indicator == 13 && super_bomb_indicator_unk2 == 1)
|
||||
pal = (frame_counter & 7);
|
||||
if (follower_indicator == 13) {
|
||||
// Display colorful superbomb palette also on frame 0.
|
||||
if (enhanced_features0 & kFeatures0_MiscBugFixes ? (super_bomb_indicator_unk2 <= 1) : (super_bomb_indicator_unk2 == 1))
|
||||
pal = (frame_counter & 7);
|
||||
}
|
||||
|
||||
const TagalongSprXY *sprd = kTagalongDraw_SprXY + frame + (kTagalongDraw_Offs[follower_indicator] >> 3);
|
||||
const TagalongDmaFlags *sprf = kTagalongDmaAndFlags + frame;
|
||||
|
||||
@@ -46,12 +46,14 @@ static void MakeSnapshot(Snapshot *s) {
|
||||
memcpy(s->ram, g_snes->ram, 0x20000);
|
||||
memcpy(s->sram, g_snes->cart->ram, g_snes->cart->ramSize);
|
||||
memcpy(s->vram, g_snes->ppu->vram, sizeof(uint16) * 0x8000);
|
||||
memcpy(s->ram + 0x1DBA0, s->ram + 0x1B00, 224 * 2); // hdma_table (partial)
|
||||
}
|
||||
|
||||
static void MakeMySnapshot(Snapshot *s) {
|
||||
memcpy(s->ram, g_zenv.ram, 0x20000);
|
||||
memcpy(s->sram, g_zenv.sram, 0x2000);
|
||||
memcpy(s->vram, g_zenv.ppu->vram, sizeof(uint16) * 0x8000);
|
||||
memcpy(s->ram + 0x1B00, s->ram + 0x1DBA0, 224 * 2); // hdma_table (partial)
|
||||
}
|
||||
|
||||
static void RestoreMySnapshot(Snapshot *s) {
|
||||
@@ -105,10 +107,8 @@ static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev) {
|
||||
memcpy(&b->ram[0x1f0d], &a->ram[0x1f0d], 0x3f - 0xd);
|
||||
memcpy(b->ram + 0x138, a->ram + 0x138, 256 - 0x38); // copy the stack over
|
||||
|
||||
memcpy(a->ram + 0x1DBA0, b->ram + 0x1DBA0, 240 * 2); // hdma_table
|
||||
memcpy(b->ram + 0x1B00, b->ram + 0x1DBA0, 224 * 2); // hdma_table (partial)
|
||||
|
||||
memcpy(a->ram + 0x1cc0, b->ram + 0x1cc0, 2); // some leftover stuff in hdma table
|
||||
memcpy(a->ram + 0x1dd60, b->ram + 0x1dd60, 16 * 2); // some leftover stuff in hdma table
|
||||
|
||||
if (memcmp(b->ram, a->ram, 0x20000)) {
|
||||
fprintf(stderr, "@%d: Memory compare failed (mine != theirs, prev):\n", frame_counter);
|
||||
@@ -351,7 +351,7 @@ again_mine:
|
||||
VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
|
||||
|
||||
if (g_fail) {
|
||||
// g_fail = false;
|
||||
g_fail = false;
|
||||
if (1) {
|
||||
RestoreMySnapshot(&g_snapshot_before);
|
||||
//SaveLoadSlot(kSaveLoad_Save, 0);
|
||||
|
||||
@@ -215,10 +215,10 @@ static void ConfigurePpuSideSpace() {
|
||||
PpuSetExtraSideSpace(g_zenv.ppu, extra_left, extra_right, extra_bottom);
|
||||
}
|
||||
|
||||
bool ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
|
||||
void ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
|
||||
SimpleHdma hdma_chans[2];
|
||||
|
||||
bool rv = PpuBeginDrawing(g_zenv.ppu, pixel_buffer, pitch, render_flags);
|
||||
PpuBeginDrawing(g_zenv.ppu, pixel_buffer, pitch, render_flags);
|
||||
|
||||
dma_startDma(g_zenv.dma, HDMAEN_copy, true);
|
||||
|
||||
@@ -257,8 +257,6 @@ bool ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags) {
|
||||
SimpleHdma_DoLine(&hdma_chans[0]);
|
||||
SimpleHdma_DoLine(&hdma_chans[1]);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint8 reg7, uint8 indirect_bank) {
|
||||
|
||||
@@ -42,7 +42,7 @@ void HdmaSetup(uint32 addr6, uint32 addr7, uint8 transfer_unit, uint8 reg6, uint
|
||||
|
||||
void ZeldaInitialize();
|
||||
void ZeldaReset(bool preserve_sram);
|
||||
bool ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags);
|
||||
void ZeldaDrawPpuFrame(uint8 *pixel_buffer, size_t pitch, uint32 render_flags);
|
||||
void ZeldaRunFrameInternal(uint16 input, int run_what);
|
||||
bool ZeldaRunFrame(int input_state);
|
||||
void LoadSongBank(const uint8 *p);
|
||||
|
||||
Reference in New Issue
Block a user