From d485fedd3a97c8efa57b3b1df9b4fbe573f90481 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 26 Apr 2026 18:23:08 +0100 Subject: [PATCH] split backgrounds from camera.c and merge sa1 and sa2 camera.c --- Makefile | 15 +- chao_garden/include/global.h | 5 + include/game/shared/stage/camera.h | 10 + sa1/Makefile | 16 +- sa1/ldscript.txt | 19 +- sa1/src/game/shared/stage/camera.c | 1020 --------- .../backgrounds/{zone_1.c => zone_1.inc.c} | 2 +- .../backgrounds/{zone_2.c => zone_2.inc.c} | 0 ...one_2_interior.c => zone_2_interior.inc.c} | 0 .../backgrounds/{zone_3.c => zone_3.inc.c} | 0 .../sa1/stage/backgrounds/zone_3_firework.c | 53 - .../backgrounds/{zone_4.c => zone_4.inc.c} | 0 .../{zone_4_init.c => zone_4_init.inc.c} | 0 .../backgrounds/{zone_5.c => zone_5.inc.c} | 0 .../{zone_5_init.c => zone_5_init.inc.c} | 0 .../backgrounds/{zone_6.c => zone_6.inc.c} | 0 .../sa1/stage/backgrounds/zone_6_hblank.c | 17 - .../{zone_7_act_1.c => zone_7.inc.c} | 11 + .../{zone_7_act_2.c => zone_7_act_2.inc.c} | 2 +- .../sa1/stage/backgrounds/zone_7_act_2_init.c | 17 - src/game/sa1/stage/camera_destroy.c | 56 - src/game/sa2/stage/backgrounds/zone_1.inc.c | 112 + .../sa2/stage/backgrounds/zone_1_boss.inc.c | 16 + src/game/sa2/stage/backgrounds/zone_2.inc.c | 100 + .../sa2/stage/backgrounds/zone_2_boss.inc.c | 12 + src/game/sa2/stage/backgrounds/zone_3.inc.c | 205 ++ .../sa2/stage/backgrounds/zone_3_boss.inc.c | 11 + src/game/sa2/stage/backgrounds/zone_4.inc.c | 89 + src/game/sa2/stage/backgrounds/zone_5.inc.c | 169 ++ .../sa2/stage/backgrounds/zone_5_boss.inc.c | 11 + src/game/sa2/stage/backgrounds/zone_6.inc.c | 416 ++++ .../sa2/stage/backgrounds/zone_6_boss.inc.c | 12 + src/game/sa2/stage/backgrounds/zone_7.inc.c | 39 + .../sa2/stage/backgrounds/zone_7_init.inc.c | 316 +++ src/game/sa2/stage/backgrounds/zone_8.inc.c | 71 + .../stage/backgrounds/zone_extra_boss.inc.c | 29 + .../stage/backgrounds/zone_final_boss.inc.c | 13 + src/game/shared/stage/camera.c | 1894 +++-------------- 38 files changed, 1906 insertions(+), 2852 deletions(-) delete mode 100644 sa1/src/game/shared/stage/camera.c rename src/game/sa1/stage/backgrounds/{zone_1.c => zone_1.inc.c} (97%) rename src/game/sa1/stage/backgrounds/{zone_2.c => zone_2.inc.c} (100%) rename src/game/sa1/stage/backgrounds/{zone_2_interior.c => zone_2_interior.inc.c} (100%) rename src/game/sa1/stage/backgrounds/{zone_3.c => zone_3.inc.c} (100%) delete mode 100644 src/game/sa1/stage/backgrounds/zone_3_firework.c rename src/game/sa1/stage/backgrounds/{zone_4.c => zone_4.inc.c} (100%) rename src/game/sa1/stage/backgrounds/{zone_4_init.c => zone_4_init.inc.c} (100%) rename src/game/sa1/stage/backgrounds/{zone_5.c => zone_5.inc.c} (100%) rename src/game/sa1/stage/backgrounds/{zone_5_init.c => zone_5_init.inc.c} (100%) rename src/game/sa1/stage/backgrounds/{zone_6.c => zone_6.inc.c} (100%) delete mode 100644 src/game/sa1/stage/backgrounds/zone_6_hblank.c rename src/game/sa1/stage/backgrounds/{zone_7_act_1.c => zone_7.inc.c} (71%) rename src/game/sa1/stage/backgrounds/{zone_7_act_2.c => zone_7_act_2.inc.c} (97%) delete mode 100644 src/game/sa1/stage/backgrounds/zone_7_act_2_init.c delete mode 100644 src/game/sa1/stage/camera_destroy.c create mode 100644 src/game/sa2/stage/backgrounds/zone_1.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_1_boss.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_2.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_2_boss.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_3.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_3_boss.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_4.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_5.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_5_boss.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_6.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_6_boss.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_7.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_7_init.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_8.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_extra_boss.inc.c create mode 100644 src/game/sa2/stage/backgrounds/zone_final_boss.inc.c diff --git a/Makefile b/Makefile index 2c451472e..fea1deb85 100644 --- a/Makefile +++ b/Makefile @@ -171,20 +171,21 @@ OBJ_TILES_4BPP_SUBDIR = graphics/sa2/obj_tiles/4bpp TILESETS_SUBDIR = graphics/sa2/tilesets/ ifeq ($(PLATFORM),gba) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/*") +C_SRCS_IN := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") +C_SRCS_IN := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),sdl_psp) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") +C_SRCS_IN := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),ps2) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*") +C_SRCS_IN := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*") else ifeq ($(PLATFORM),sdl_win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") +C_SRCS_IN := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/ps2/*") +C_SRCS_IN := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/ps2/*") else -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*") +C_SRCS_IN := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/sa1/*") endif +C_SRCS := $(foreach src,$(C_SRCS_IN),$(if $(findstring .inc.c,$(src)),,$(src))) C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS)) ifeq ($(PLATFORM),gba) diff --git a/chao_garden/include/global.h b/chao_garden/include/global.h index a2690ffd5..52ffd7ff7 100644 --- a/chao_garden/include/global.h +++ b/chao_garden/include/global.h @@ -47,6 +47,11 @@ #define INCBIN_S8 INCBIN #define INCBIN_S16 INCBIN #define INCBIN_S32 INCBIN + +#define INCPAL(...) \ + { \ + 0 \ + } #endif // IDE support #define ARRAY_COUNT(array) (sizeof(array) / sizeof((array)[0])) diff --git a/include/game/shared/stage/camera.h b/include/game/shared/stage/camera.h index 5a5f6d9fd..b1c035044 100644 --- a/include/game/shared/stage/camera.h +++ b/include/game/shared/stage/camera.h @@ -168,6 +168,16 @@ void InitCamera(u32); void UpdateCamera(void); void DestroyCameraMovementTask(void); +// TODO: move to camera_hblank_callbacks.c +#if (GAME == GAME_SA2) +void HBlankCB_801E454(int_vcount vcount); +void sub_801E3F0(void); +void HBlankCB_801E434(int_vcount vcount); +void nullsub_801E494(void); +void HBlankCB_BgUpdateZone5ActBoss(int_vcount vcount); +void HBlankCB_BgUpdateZoneFinalActXX(int_vcount vcount); +#endif + #if (GAME == GAME_SA1) // TODO: should be included from terrain_collision.h extern const Collision *gRefCollision; diff --git a/sa1/Makefile b/sa1/Makefile index 27adb6072..baf8263d8 100644 --- a/sa1/Makefile +++ b/sa1/Makefile @@ -274,6 +274,7 @@ SA2_C_FILES := \ src/game/shared/stage/collision_3.c \ src/game/shared/stage/water_effects.c \ src/game/shared/stage/spot_light_beam_task.c \ + src/game/shared/stage/camera.c \ src/game/sa1/ui/game_2_0.c \ src/game/sa1/ui/game_2_1.c \ src/game/sa1/ui/stage_results.c \ @@ -397,21 +398,6 @@ SA2_C_FILES := \ src/game/sa1/stage/player_tails.c \ src/game/sa1/stage/player_super_sonic.c \ src/game/sa1/stage/mp_chao.c \ - src/game/sa1/stage/camera_destroy.c \ - src/game/sa1/stage/backgrounds/zone_5_init.c \ - src/game/sa1/stage/backgrounds/zone_4.c \ - src/game/sa1/stage/backgrounds/zone_3_firework.c \ - src/game/sa1/stage/backgrounds/zone_3.c \ - src/game/sa1/stage/backgrounds/zone_2_interior.c \ - src/game/sa1/stage/backgrounds/zone_7_act_2.c \ - src/game/sa1/stage/backgrounds/zone_4_init.c \ - src/game/sa1/stage/backgrounds/zone_2.c \ - src/game/sa1/stage/backgrounds/zone_6_hblank.c \ - src/game/sa1/stage/backgrounds/zone_6.c \ - src/game/sa1/stage/backgrounds/zone_7_act_1.c \ - src/game/sa1/stage/backgrounds/zone_1.c \ - src/game/sa1/stage/backgrounds/zone_7_act_2_init.c \ - src/game/sa1/stage/backgrounds/zone_5.c \ src/game/sa1/stage/trapped_animals.c \ src/game/sa1/stage/stage_ui_z.c \ src/game/sa1/stage/stage_ui.c \ diff --git a/sa1/ldscript.txt b/sa1/ldscript.txt index d67edb7ca..c97936591 100644 --- a/sa1/ldscript.txt +++ b/sa1/ldscript.txt @@ -114,22 +114,7 @@ SECTIONS { sa2/src/game/dummy_task.o(.text); src/game/shared/stage/stage.o(.text); - src/game/shared/stage/camera.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_1.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_2_interior.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_3.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_4.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_6.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_7_act_2.o(.text); - sa2/src/game/sa1/stage/camera_destroy.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_4_init.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_5_init.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_7_act_1.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_7_act_2_init.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_2.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_5.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_3_firework.o(.text); - sa2/src/game/sa1/stage/backgrounds/zone_6_hblank.o(.text); + sa2/src/game/shared/stage/camera.o(.text); sa2/src/game/shared/stage/terrain_collision.o(.text); sa2/src/game/shared/stage/mp_sprite_task.o(.text); sa2/src/game/shared/stage/dust_effect_braking.o(.text); @@ -360,7 +345,7 @@ SECTIONS { sa2/src/game/shared/stage/amy_attack_heart_effect.o(.rodata); sa2/src/game/shared/stage/music_manager.o(.rodata); src/game/shared/stage/stage.o(.rodata); - src/game/shared/stage/camera.o(.rodata); + sa2/src/game/shared/stage/camera.o(.rodata); src/data/sa1/tilemap_table.o(.rodata); sa2/src/game/shared/stage/terrain_collision.o(.rodata); data/sa1/data_0_4.o(.rodata); diff --git a/sa1/src/game/shared/stage/camera.c b/sa1/src/game/shared/stage/camera.c deleted file mode 100644 index 6afecd8d9..000000000 --- a/sa1/src/game/shared/stage/camera.c +++ /dev/null @@ -1,1020 +0,0 @@ -#include "global.h" -#include "core.h" -#include "sprite.h" -#include "animation_commands_bg.h" -#include "trig.h" - -#include "game/globals.h" - -#include "game/shared/stage/camera.h" -#include "game/shared/stage/stage.h" -#include "game/shared/stage/player.h" -#include "game/shared/stage/terrain_collision.h" -#include "game/shared/stage/spot_lights_manager.h" - -#if (GAME == GAME_SA1) -#include "game/shared/stage/mp_player.h" - -#include "constants/sa1/animations.h" -#include "constants/sa1/characters.h" -#include "constants/sa1/tilemaps.h" -#include "constants/sa1/zones.h" -#elif (GAME == GAME_SA2) -#include "game/sa2/stage/player_super_sonic.h" - -#include "constants/sa2/tilemaps.h" -#include "constants/sa2/zones.h" -#include "constants/sa2/characters.h" -#endif - -#define BOSS_CAM_FRAME_DELTA_PIXELS 5 - -#if (GAME == GAME_SA2) -#if !PORTABLE -#define USE_BOSS_BG_IN_ZONE_6_ACTS FALSE -#else -// The default flickering is very strong, so we disable it. -// TODO: Add a global option, so players can decide to use the original effect if they want to. -#define USE_BOSS_BG_IN_ZONE_6_ACTS TRUE -#endif -#endif - -// NOTE: -// unk8 is a regular integer in SA1, but Q_24_8 in SA2 -#if (GAME == GAME_SA1) -#define CAM_UNK8_INT(_val) (_val) -#else -#define CAM_UNK8_INT(_val) (I(_val)) -#endif - -#define STGBG_SCRN_DIM(w, h, charBase, screenBase) \ - { \ - ((w) / TILE_WIDTH), ((h) / TILE_WIDTH), charBase, screenBase \ - } -#define STGBG_WIDTH(arr) ((arr)[0]) -#define STGBG_HEIGHT(arr) ((arr)[1]) -#define STGBG_CHARBASE(arr) ((arr)[2]) -#define STGBG_SCREENBASE(arr) ((arr)[3]) - -#define CAMBG_MAP_FRONT_LAYER 0 -#define CAMBG_MAP_BACK_LAYER 1 -#define CAMBG_BACK_A_LAYER 2 -#define CAMBG_BACK_B_LAYER 3 - -#if !WIDESCREEN_HACK -#define SCREENBASE_SKY_CANYON_CLOUDS 27 -#define CAM_SCREENBASE_BACK_A 28 -#define CAM_SCREENBASE_BACK_B 29 -#define CAM_SCREENBASE_BACK_C 26 -#define CAM_SCREENBASE_MAP_FRONT 30 -#define CAM_SCREENBASE_MAP_BACK 31 - -#else -#define SCREENBASE_SKY_CANYON_CLOUDS 27 - -#define CAM_SCREENBASE_BACK_A 48 -#define CAM_SCREENBASE_BACK_B 50 -#define CAM_SCREENBASE_BACK_C 58 -#define CAM_SCREENBASE_MAP_FRONT 52 -#define CAM_SCREENBASE_MAP_BACK 56 -#endif - -// Probably a array (as it's aligned 16) -struct Backgrounds ALIGNED(16) gStageBackgroundsRam = {}; - -#ifndef COLLECT_RINGS_ROM -UNUSED u32 unused_3005950[3] = {}; -#endif - -struct Camera ALIGNED(8) gCamera = {}; - -static void RenderMetatileLayers(s32, s32); -void Task_CallUpdateCamera(void); -void TaskDestructor_Camera(struct Task *); -void Task_UpdateCamera(void); - -// Dummy callbacks -void CreateStageBg_Default(void); -void CreateStageBg_Dummy(void); -void StageBgUpdate_Dummy(s32 x, s32 y); - -const Background gStageCameraBgTemplates[4] = { - [CAMBG_MAP_FRONT_LAYER] = { - .graphics = { - .src = NULL, - .dest = (void*)BG_VRAM, - .size = 0, - .anim = 0, - }, - .layoutVram = (void*)BG_SCREEN_ADDR(CAM_SCREENBASE_MAP_FRONT), - .layout = NULL, - .xTiles = 0, - .yTiles = 0, - .unk18 = 0, - .unk1A = 0, - .tilemapId = 0, - .unk1E = 0, - .unk20 = 0, - .unk22 = 0, - .unk24 = 0, - .targetTilesX = (DISPLAY_WIDTH / TILE_WIDTH) + 1, - .targetTilesY = (DISPLAY_HEIGHT / TILE_WIDTH) + 1, - .paletteOffset = 0, - .animFrameCounter = 0, - .animDelayCounter = 0, - .flags = BACKGROUND_FLAG_IS_LEVEL_MAP | BACKGROUND_FLAG_20 | BACKGROUND_DISABLE_PALETTE_UPDATE | BACKGROUND_DISABLE_TILESET_UPDATE | BACKGROUND_FLAGS_BG_ID(1), - .scrollX = 0, - .scrollY = 0, - .prevScrollX = 32767, - .prevScrollY = 32767, - .metatileMap = NULL, - .mapWidth = 0, - .mapHeight = 0, - }, - [CAMBG_MAP_BACK_LAYER] = { - .graphics = { - .src = NULL, - .dest = (void*)BG_VRAM, - .size = 0, - .anim = 0, - }, - .layoutVram = (void*)BG_SCREEN_ADDR(CAM_SCREENBASE_MAP_BACK), - .layout = NULL, - .xTiles = 0, - .yTiles = 0, - .unk18 = 0, - .unk1A = 0, - .tilemapId = 0, - .unk1E = 0, - .unk20 = 0, - .unk22 = 0, - .unk24 = 0, - .targetTilesX = (DISPLAY_WIDTH / TILE_WIDTH) + 1, - .targetTilesY = (DISPLAY_HEIGHT / TILE_WIDTH) + 1, - .paletteOffset = 0, - .animFrameCounter = 0, - .animDelayCounter = 0, - .flags = BACKGROUND_FLAG_IS_LEVEL_MAP | BACKGROUND_FLAG_20 | BACKGROUND_FLAGS_BG_ID(2), - .scrollX = 0, - .scrollY = 0, - .prevScrollX = 32767, - .prevScrollY = 32767, - .metatileMap = NULL, - .mapWidth = 0, - .mapHeight = 0, - }, - [CAMBG_BACK_A_LAYER] = { - .graphics = { - .src = NULL, - .dest = (void*)BG_SCREEN_ADDR(16), - .size = 0, - .anim = 0, - }, - .layoutVram = (void*)BG_SCREEN_ADDR(CAM_SCREENBASE_BACK_B), - .layout = NULL, - .xTiles = 0, - .yTiles = 0, - .unk18 = 0, - .unk1A = 0, - .tilemapId = 0, - .unk1E = 0, - .unk20 = 0, - .unk22 = 0, - .unk24 = 0, - .targetTilesX = 32, - .targetTilesY = 32, - .paletteOffset = 0, - .animFrameCounter = 0, - .animDelayCounter = 0, - .flags = BACKGROUND_DISABLE_PALETTE_UPDATE | BACKGROUND_FLAGS_BG_ID(3), - .scrollX = 0, - .scrollY = 0, - .prevScrollX = 32767, - .prevScrollY = 32767, - .metatileMap = NULL, - .mapWidth = 0, - .mapHeight = 0, - }, - [CAMBG_BACK_B_LAYER] = { - .graphics = { - .src = NULL, - .dest = (void*)BG_CHAR_ADDR(3), - .size = 0, - .anim = 0, - }, - .layoutVram = (void*)BG_SCREEN_ADDR(CAM_SCREENBASE_BACK_A), - .layout = NULL, - .xTiles = 0, - .yTiles = 0, - .unk18 = 0, - .unk1A = 0, - .tilemapId = 0, - .unk1E = 0, - .unk20 = 0, - .unk22 = 0, - .unk24 = 0, - .targetTilesX = 32, - .targetTilesY = 32, - .paletteOffset = 0, - .animFrameCounter = 0, - .animDelayCounter = 0, - .flags = BACKGROUND_DISABLE_PALETTE_UPDATE | BACKGROUND_FLAGS_BG_ID(0), - .scrollX = 0, - .scrollY = 0, - .prevScrollX = 32767, - .prevScrollY = 32767, - .metatileMap = NULL, - .mapWidth = 0, - .mapHeight = 0, - }, -}; - -#if (GAME == GAME_SA1) -extern void CreateStageBg_Zone4(void); -extern void CreateStageBg_Zone5(void); -extern void CreateStageBg_Zone7_Act2(void); - -static const VoidFn sStageBgInitProcedures[NUM_LEVEL_IDS] = { - [LEVEL_INDEX(ZONE_1, ACT_1)] = NULL, - [LEVEL_INDEX(ZONE_1, ACT_2)] = NULL, - [LEVEL_INDEX(ZONE_2, ACT_1)] = NULL, - [LEVEL_INDEX(ZONE_2, ACT_2)] = NULL, - [LEVEL_INDEX(ZONE_3, ACT_1)] = NULL, - [LEVEL_INDEX(ZONE_3, ACT_2)] = NULL, - [LEVEL_INDEX(ZONE_4, ACT_1)] = CreateStageBg_Zone4, - [LEVEL_INDEX(ZONE_4, ACT_2)] = CreateStageBg_Zone4, - [LEVEL_INDEX(ZONE_5, ACT_1)] = CreateStageBg_Zone5, - [LEVEL_INDEX(ZONE_5, ACT_2)] = CreateStageBg_Zone5, - [LEVEL_INDEX(ZONE_6, ACT_1)] = NULL, - [LEVEL_INDEX(ZONE_6, ACT_2)] = NULL, - [LEVEL_INDEX(ZONE_7, ACT_1)] = NULL, - [LEVEL_INDEX(ZONE_7, ACT_2)] = CreateStageBg_Zone7_Act2, - [ACT_CHAO_HUNT_A] = NULL, - [ACT_CHAO_HUNT_B] = NULL, - [ACT_CHAO_HUNT_C] = NULL, - [ACT_CHAO_HUNT_D] = NULL, - -}; - -void StageBgUpdate_Zone1Acts12(s32, s32); -void StageBgUpdate_Zone2Act1(s32, s32); -void StageBgUpdate_Zone2Act2(s32, s32); -void StageBgUpdate_Zone3Acts12(s32, s32); -void StageBgUpdate_Zone4Acts12(s32, s32); -void StageBgUpdate_Zone5Acts12(s32, s32); -void StageBgUpdate_Zone6Act1(s32, s32); -void StageBgUpdate_Zone6Act2(s32, s32); -void StageBgUpdate_Zone7Act1(s32, s32); -void StageBgUpdate_Zone7Act2(s32, s32); -static const BgUpdate sStageBgUpdateFuncs[NUM_LEVEL_IDS] = { - [LEVEL_INDEX(ZONE_1, ACT_1)] = StageBgUpdate_Zone1Acts12, - [LEVEL_INDEX(ZONE_1, ACT_2)] = StageBgUpdate_Zone1Acts12, - [LEVEL_INDEX(ZONE_2, ACT_1)] = StageBgUpdate_Zone2Act1, - [LEVEL_INDEX(ZONE_2, ACT_2)] = StageBgUpdate_Zone2Act2, - [LEVEL_INDEX(ZONE_3, ACT_1)] = StageBgUpdate_Zone3Acts12, - [LEVEL_INDEX(ZONE_3, ACT_2)] = StageBgUpdate_Zone3Acts12, - [LEVEL_INDEX(ZONE_4, ACT_1)] = StageBgUpdate_Zone4Acts12, - [LEVEL_INDEX(ZONE_4, ACT_2)] = StageBgUpdate_Zone4Acts12, - [LEVEL_INDEX(ZONE_5, ACT_1)] = StageBgUpdate_Zone5Acts12, - [LEVEL_INDEX(ZONE_5, ACT_2)] = StageBgUpdate_Zone5Acts12, - [LEVEL_INDEX(ZONE_6, ACT_1)] = StageBgUpdate_Zone6Act1, - [LEVEL_INDEX(ZONE_6, ACT_2)] = StageBgUpdate_Zone6Act2, - [LEVEL_INDEX(ZONE_7, ACT_1)] = StageBgUpdate_Zone7Act1, - [LEVEL_INDEX(ZONE_7, ACT_2)] = StageBgUpdate_Zone7Act2, - [ACT_CHAO_HUNT_A] = StageBgUpdate_Zone1Acts12, - [ACT_CHAO_HUNT_B] = StageBgUpdate_Zone2Act2, - [ACT_CHAO_HUNT_C] = StageBgUpdate_Zone3Acts12, - [ACT_CHAO_HUNT_D] = StageBgUpdate_Zone6Act2, -}; - -static const s8 sStageBgDimensions[NUM_LEVEL_IDS][4] = { - [LEVEL_INDEX(ZONE_1, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_1, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_2, ACT_1)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_2, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_3, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_3, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_4, ACT_1)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_4, ACT_2)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_5, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_5, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_6, ACT_1)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_C), - [LEVEL_INDEX(ZONE_6, ACT_2)] = STGBG_SCRN_DIM(512, 256, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_7, ACT_1)] = STGBG_SCRN_DIM(296, 184, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_7, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [ACT_CHAO_HUNT_A] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [ACT_CHAO_HUNT_B] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [ACT_CHAO_HUNT_C] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [ACT_CHAO_HUNT_D] = STGBG_SCRN_DIM(512, 256, 2, CAM_SCREENBASE_BACK_A), -}; - -const TileInfoFirework gTileInfoZone3Fireworks[2] = { - [0] = { SA1_ANIM_FIREWORKS, 0, MAX_TILES(SA1_ANIM_FIREWORKS) }, - [1] = { SA1_ANIM_FIREWORKS_SMALL, 0, MAX_TILES(SA1_ANIM_FIREWORKS_SMALL) }, -}; -#elif (GAME == GAME_SA2) -void sub_801E3F0(void); -void HBlankCB_801E434(int_vcount vcount); -void HBlankCB_801E454(int_vcount vcount); -void nullsub_801E494(void); -void HBlankCB_BgUpdateZone5ActBoss(int_vcount vcount); -void HBlankCB_BgUpdateZoneFinalActXX(int_vcount vcount); - -// SA2 Zone specific backgrounds -void CreateStageBg_Zone1(void); -void StageBgUpdate_Zone1Acts12(s32 a, s32 b); -void StageBgUpdate_Zone1ActBoss(s32 a, s32 b); - -void CreateStageBg_Zone2(void); -void StageBgUpdate_Zone2Acts12(s32 a, s32 b); -void StageBgUpdate_Zone2ActBoss(s32 a, s32 b); - -void CreateStageBg_Zone3(void); -void StageBgUpdate_Zone3Acts12(s32 a, s32 b); -void StageBgUpdate_Zone3ActBoss(s32 a, s32 b); - -void CreateStageBg_Zone4(void); -void StageBgUpdate_Zone4Acts12(s32 a, s32 b); -void StageBgUpdate_Zone4ActBoss(s32 a, s32 b); - -void CreateStageBg_Zone5(void); -void StageBgUpdate_Zone5Acts12(s32 a, s32 b); -void StageBgUpdate_Zone5ActBoss(s32 a, s32 b); - -void CreateStageBg_Zone6_Acts(void); -void CreateStageBg_Zone6_Boss(void); -void StageBgUpdate_Zone6Acts12(s32 a, s32 b); -void StageBgUpdate_Zone6ActBoss(s32 a, s32 b); - -void CreateStageBg_Zone7(void); -void StageBgUpdate_Zone7Acts12(s32, s32); -void StageBgUpdate_Zone7ActBoss(s32, s32); -void Zone7BgUpdate_Inside(s32, s32); -void Zone7BgUpdate_Outside(s32, s32); - -void CreateStageBg_ZoneFinal_0(void); -void StageBgUpdate_Dummy(s32, s32); -void StageBgUpdate_ZoneFinalActXX(s32, s32); -void StageBgUpdate_ZoneFinalActTA53(s32, s32); - -#ifndef COLLECT_RINGS_ROM -const u16 gBossCameraYClamps[][2] = { - [ZONE_1] = { 32, DISPLAY_HEIGHT + 56 }, [ZONE_2] = { 32, DISPLAY_HEIGHT + 44 }, [ZONE_3] = { 32, DISPLAY_HEIGHT + 56 }, - [ZONE_4] = { 32, DISPLAY_HEIGHT + 48 }, [ZONE_5] = { 32, DISPLAY_HEIGHT + 48 }, [ZONE_6] = { 32, DISPLAY_HEIGHT + 72 }, - [ZONE_7] = { 32, DISPLAY_HEIGHT + 104 }, [ZONE_FINAL] = { 32, DISPLAY_HEIGHT + 104 }, [ZONE_FINAL + 1] = { 32, DISPLAY_HEIGHT + 104 }, -}; -#endif -static const VoidFn sStageBgInitProcedures[] = { - [LEVEL_INDEX(ZONE_1, ACT_1)] = CreateStageBg_Zone1, -#ifndef COLLECT_RINGS_ROM - [LEVEL_INDEX(ZONE_1, ACT_2)] = CreateStageBg_Zone1, - [LEVEL_INDEX(ZONE_1, ACT_BOSS)] = CreateStageBg_Zone1, - [LEVEL_INDEX(ZONE_1, ACT_UNUSED)] = NULL, // Anti-Formatting - [LEVEL_INDEX(ZONE_2, ACT_1)] = CreateStageBg_Default, - [LEVEL_INDEX(ZONE_2, ACT_2)] = CreateStageBg_Default, - [LEVEL_INDEX(ZONE_2, ACT_BOSS)] = CreateStageBg_Default, - [LEVEL_INDEX(ZONE_2, ACT_UNUSED)] = NULL, // - [LEVEL_INDEX(ZONE_3, ACT_1)] = CreateStageBg_Zone3, - [LEVEL_INDEX(ZONE_3, ACT_2)] = CreateStageBg_Zone3, - [LEVEL_INDEX(ZONE_3, ACT_BOSS)] = CreateStageBg_Zone3, - [LEVEL_INDEX(ZONE_3, ACT_UNUSED)] = NULL, // - [LEVEL_INDEX(ZONE_4, ACT_1)] = CreateStageBg_Zone4, - [LEVEL_INDEX(ZONE_4, ACT_2)] = CreateStageBg_Zone4, - [LEVEL_INDEX(ZONE_4, ACT_BOSS)] = CreateStageBg_Dummy, - [LEVEL_INDEX(ZONE_4, ACT_UNUSED)] = NULL, // - [LEVEL_INDEX(ZONE_5, ACT_1)] = CreateStageBg_Zone5, - [LEVEL_INDEX(ZONE_5, ACT_2)] = CreateStageBg_Zone5, - [LEVEL_INDEX(ZONE_5, ACT_BOSS)] = NULL, - [LEVEL_INDEX(ZONE_5, ACT_UNUSED)] = NULL, // - [LEVEL_INDEX(ZONE_6, ACT_1)] = CreateStageBg_Zone6_Acts, - [LEVEL_INDEX(ZONE_6, ACT_2)] = CreateStageBg_Zone6_Acts, - [LEVEL_INDEX(ZONE_6, ACT_BOSS)] = CreateStageBg_Zone6_Boss, - [LEVEL_INDEX(ZONE_6, ACT_UNUSED)] = NULL, // - [LEVEL_INDEX(ZONE_7, ACT_1)] = CreateStageBg_Zone7, - [LEVEL_INDEX(ZONE_7, ACT_2)] = CreateStageBg_Zone7, - [LEVEL_INDEX(ZONE_7, ACT_BOSS)] = CreateStageBg_Zone7, - [LEVEL_INDEX(ZONE_7, ACT_UNUSED)] = NULL, // - [LEVEL_INDEX(ZONE_FINAL, ACT_XX_FINAL_ZONE)] = NULL, // This doesn't make sense... - [LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)] = CreateStageBg_ZoneFinal_0, - [LEVEL_INDEX(ZONE_FINAL, ACT_BOSS)] = CreateStageBg_Zone1, - [LEVEL_INDEX(ZONE_FINAL, ACT_UNUSED)] = NULL, // - [LEVEL_INDEX(ZONE_UNUSED, ACT_1)] = NULL, - [LEVEL_INDEX(ZONE_UNUSED, ACT_2)] = NULL, -#endif -}; - -static const BgUpdate sStageBgUpdateFuncs[NUM_LEVEL_IDS] = { -#if COLLECT_RINGS_ROM - [LEVEL_INDEX(ZONE_1, ACT_1)] = StageBgUpdate_Dummy, -#else - // Zone 1 - [LEVEL_INDEX(ZONE_1, ACT_1)] = StageBgUpdate_Zone1Acts12, - [LEVEL_INDEX(ZONE_1, ACT_2)] = StageBgUpdate_Zone1Acts12, - [LEVEL_INDEX(ZONE_1, ACT_BOSS)] = StageBgUpdate_Zone1ActBoss, - [LEVEL_INDEX(ZONE_1, ACT_UNUSED)] = StageBgUpdate_Dummy, - - // Zone 2 - [LEVEL_INDEX(ZONE_2, ACT_1)] = StageBgUpdate_Zone2Acts12, - [LEVEL_INDEX(ZONE_2, ACT_2)] = StageBgUpdate_Zone2Acts12, - [LEVEL_INDEX(ZONE_2, ACT_BOSS)] = StageBgUpdate_Zone2ActBoss, - [LEVEL_INDEX(ZONE_2, ACT_UNUSED)] = StageBgUpdate_Dummy, - - // Zone 3 - [LEVEL_INDEX(ZONE_3, ACT_1)] = StageBgUpdate_Zone3Acts12, - [LEVEL_INDEX(ZONE_3, ACT_2)] = StageBgUpdate_Zone3Acts12, - [LEVEL_INDEX(ZONE_3, ACT_BOSS)] = StageBgUpdate_Zone3ActBoss, - [LEVEL_INDEX(ZONE_3, ACT_UNUSED)] = StageBgUpdate_Dummy, - - // Zone 4 - [LEVEL_INDEX(ZONE_4, ACT_1)] = StageBgUpdate_Zone4Acts12, - [LEVEL_INDEX(ZONE_4, ACT_2)] = StageBgUpdate_Zone4Acts12, - [LEVEL_INDEX(ZONE_4, ACT_BOSS)] = StageBgUpdate_Dummy, - [LEVEL_INDEX(ZONE_4, ACT_UNUSED)] = StageBgUpdate_Dummy, - - // Zone 5 - [LEVEL_INDEX(ZONE_5, ACT_1)] = StageBgUpdate_Zone5Acts12, - [LEVEL_INDEX(ZONE_5, ACT_2)] = StageBgUpdate_Zone5Acts12, - [LEVEL_INDEX(ZONE_5, ACT_BOSS)] = StageBgUpdate_Zone5ActBoss, - [LEVEL_INDEX(ZONE_5, ACT_UNUSED)] = StageBgUpdate_Dummy, - -// Zone 6 -#if PLATFORM_GBA - [LEVEL_INDEX(ZONE_6, ACT_1)] = StageBgUpdate_Zone6Acts12, - [LEVEL_INDEX(ZONE_6, ACT_2)] = StageBgUpdate_Zone6Acts12, -#else - [LEVEL_INDEX(ZONE_6, ACT_1)] = StageBgUpdate_Zone6ActBoss, - [LEVEL_INDEX(ZONE_6, ACT_2)] = StageBgUpdate_Zone6ActBoss, -#endif - [LEVEL_INDEX(ZONE_6, ACT_BOSS)] = StageBgUpdate_Zone6ActBoss, - [LEVEL_INDEX(ZONE_6, ACT_UNUSED)] = StageBgUpdate_Dummy, - - // Zone 7 - [LEVEL_INDEX(ZONE_7, ACT_1)] = StageBgUpdate_Zone7Acts12, - [LEVEL_INDEX(ZONE_7, ACT_2)] = StageBgUpdate_Zone7Acts12, - [LEVEL_INDEX(ZONE_7, ACT_BOSS)] = StageBgUpdate_Zone7ActBoss, - [LEVEL_INDEX(ZONE_7, ACT_UNUSED)] = StageBgUpdate_Dummy, - - // Zone Final - [LEVEL_INDEX(ZONE_FINAL, ACT_XX_FINAL_ZONE)] = StageBgUpdate_ZoneFinalActXX, - [LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)] = StageBgUpdate_ZoneFinalActTA53, - [LEVEL_INDEX(ZONE_FINAL, ACT_BOSS)] = StageBgUpdate_Zone1Acts12, - [LEVEL_INDEX(ZONE_FINAL, ACT_UNUSED)] = StageBgUpdate_Zone2Acts12, - - // Zone Unused - [LEVEL_INDEX(ZONE_UNUSED, ACT_1)] = StageBgUpdate_Zone1Acts12, - [LEVEL_INDEX(ZONE_UNUSED, ACT_2)] = StageBgUpdate_Zone6Acts12, -#endif -}; - -static const s8 sStageBgDimensions[NUM_LEVEL_IDS][4] = { - [LEVEL_INDEX(ZONE_1, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), -#ifndef COLLECT_RINGS_ROM - [LEVEL_INDEX(ZONE_1, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_1, ACT_BOSS)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_1, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_2, ACT_1)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_2, ACT_2)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_2, ACT_BOSS)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_2, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_3, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_3, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_3, ACT_BOSS)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_3, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_4, ACT_1)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_4, ACT_2)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_4, ACT_BOSS)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_4, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_5, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_5, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_5, ACT_BOSS)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_5, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_6, ACT_1)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_6, ACT_2)] = STGBG_SCRN_DIM(512, 256, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_6, ACT_BOSS)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_6, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_7, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_7, ACT_2)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_7, ACT_BOSS)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_7, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_FINAL, ACT_XX_FINAL_ZONE)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_FINAL, ACT_BOSS)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_FINAL, ACT_UNUSED)] = STGBG_SCRN_DIM(256, 512, 2, CAM_SCREENBASE_BACK_A), - [LEVEL_INDEX(ZONE_UNUSED, ACT_1)] = STGBG_SCRN_DIM(256, 256, 2, CAM_SCREENBASE_BACK_B), - [LEVEL_INDEX(ZONE_UNUSED, ACT_2)] = STGBG_SCRN_DIM(512, 256, 2, CAM_SCREENBASE_BACK_A), -#endif -}; -#endif - -void InitCamera(u32 level) -{ - u32 txtSize; - - struct Backgrounds *bgs; - const Background *bgTemplates; - Player *player = &gPlayer; - struct Camera *camera = &gCamera; - const s8 *bgDim = sStageBgDimensions[level]; - - gDispCnt = (DISPCNT_OBJ_ON | DISPCNT_WIN0_ON | DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_1D_MAP); -#ifndef COLLECT_RINGS_ROM - if (IS_EXTRA_STAGE(level)) { - gDispCnt - = (DISPCNT_OBJ_ON | DISPCNT_WIN0_ON | DISPCNT_BG0_ON | DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_OBJ_1D_MAP | DISPCNT_MODE_1); - } -#endif - -#if !WIDESCREEN_HACK - gBgCntRegs[1] = BGCNT_TXT256x256 | (BGCNT_PRIORITY(1) | BGCNT_SCREENBASE(CAM_SCREENBASE_MAP_FRONT) | BGCNT_16COLOR | BGCNT_CHARBASE(0)); - gBgCntRegs[2] = BGCNT_TXT256x256 | (BGCNT_PRIORITY(2) | BGCNT_SCREENBASE(CAM_SCREENBASE_MAP_BACK) | BGCNT_16COLOR | BGCNT_CHARBASE(0)); -#else - gBgCntRegs[1] = BGCNT_TXT512x512 | (BGCNT_PRIORITY(1) | BGCNT_SCREENBASE(CAM_SCREENBASE_MAP_FRONT) | BGCNT_16COLOR | BGCNT_CHARBASE(0)); - gBgCntRegs[2] = BGCNT_TXT512x512 | (BGCNT_PRIORITY(2) | BGCNT_SCREENBASE(CAM_SCREENBASE_MAP_BACK) | BGCNT_16COLOR | BGCNT_CHARBASE(0)); -#endif - txtSize = ((STGBG_WIDTH(bgDim) + 0x1F) >> 6 | ((STGBG_HEIGHT(bgDim) + 0x1F) >> 6) << 1) << 0xE; - gBgCntRegs[3] = txtSize | BGCNT_PRIORITY(3) | BGCNT_SCREENBASE(STGBG_SCREENBASE(bgDim)) | BGCNT_CHARBASE(STGBG_CHARBASE(bgDim)); - -#ifndef COLLECT_RINGS_ROM - if (IS_EXTRA_STAGE(level)) { -#if (GAME == GAME_SA1) - gBgCntRegs[0] - = BGCNT_TXT256x256 | (BGCNT_PRIORITY(2) | BGCNT_SCREENBASE(CAM_SCREENBASE_MAP_BACK) | BGCNT_16COLOR | BGCNT_CHARBASE(0)); - txtSize = ((STGBG_WIDTH(bgDim) + 0x1F) >> 6 | ((STGBG_HEIGHT(bgDim) + 0x1F) >> 6) << 1) << 0xE; - gBgCntRegs[1] = txtSize | BGCNT_PRIORITY(3) | BGCNT_SCREENBASE(STGBG_SCREENBASE(bgDim)) | BGCNT_CHARBASE(STGBG_CHARBASE(bgDim)); -#elif (GAME == GAME_SA2) - gDispCnt = (DISPCNT_OBJ_ON | DISPCNT_WIN0_ON | DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_OBJ_1D_MAP | DISPCNT_MODE_1); -#endif - } -#endif - - bgs = &gStageBackgroundsRam; - bgTemplates = gStageCameraBgTemplates; - - memcpy(&gStageBackgroundsRam.unk40, &bgTemplates[0], sizeof(Background)); - bgs->unk40.tilemapId = TM_LEVEL_METATILES_0(level); - - memcpy(&gStageBackgroundsRam.unk80, &bgTemplates[1], sizeof(Background)); - bgs->unk80.tilemapId = TM_LEVEL_METATILES_1(level); - -#if (GAME == GAME_SA1) - if (IS_EXTRA_STAGE(level)) { - gStageBackgroundsRam.unk80.flags &= ~BACKGROUND_FLAGS_MASK_BG_ID; - } -#endif - - memcpy(&gStageBackgroundsRam.unkC0, &bgTemplates[2], sizeof(Background)); - bgs->unkC0.tilemapId = TM_LEVEL_BG(level); - - bgs->unkC0.graphics.dest = (void *)BG_CHAR_ADDR(STGBG_CHARBASE(bgDim)); - bgs->unkC0.layoutVram = (void *)BG_SCREEN_ADDR(STGBG_SCREENBASE(bgDim)); - bgs->unkC0.targetTilesX = STGBG_WIDTH(bgDim); - bgs->unkC0.targetTilesY = STGBG_HEIGHT(bgDim); - -#if (GAME == GAME_SA1) - if (IS_EXTRA_STAGE(level)) { - gStageBackgroundsRam.unkC0.flags &= ~BACKGROUND_FLAGS_MASK_BG_ID; - gStageBackgroundsRam.unkC0.flags |= BACKGROUND_FLAGS_BG_ID(1); - } -#endif - - INIT_BG_SPRITES_LAYER_32(1); - INIT_BG_SPRITES_LAYER_32(2); - -#if (GAME == GAME_SA1) - if (level == LEVEL_INDEX(ZONE_6, ACT_1)) { - DrawBackground(&bgs->unkC0); - DmaCopy16(3, gStageBackgroundsRam.unkC0.layout, gStageBackgroundsRam.unkC0.layoutVram, 4096); - - gBgCntRegs[3] &= ~BGCNT_SCREENBASE_MASK; - gBgCntRegs[3] |= BGCNT_SCREENBASE(STGBG_SCREENBASE(bgDim) + 2); - gStageBackgroundsRam.unkC0.layoutVram = (void *)((uintptr_t)BG_SCREEN_ADDR(STGBG_SCREENBASE(bgDim) + 2)); - gStageBackgroundsRam.unkC0.unk20 = 0x40; - } -#endif - -#ifndef COLLECT_RINGS_ROM - if (gGameMode == GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) -#endif - { - bgs->unk40.flags |= BACKGROUND_UPDATE_ANIMATIONS | BACKGROUND_DISABLE_TILESET_UPDATE; - bgs->unk80.flags |= BACKGROUND_UPDATE_ANIMATIONS | BACKGROUND_DISABLE_TILESET_UPDATE; - } - -#ifndef COLLECT_RINGS_ROM - if (IS_EXTRA_STAGE(level)) { -#if (GAME == GAME_SA1) - DrawBackground(&bgs->unk80); - DrawBackground(&bgs->unkC0); -#endif - } else { - DrawBackground(&bgs->unk40); - DrawBackground(&bgs->unk80); - DrawBackground(&bgs->unkC0); - } -#endif - -#ifndef COLLECT_RINGS_ROM - if (gGameMode != GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { - gRefCollision = gCollisionTable[level]; - } else -#endif - { - gRefCollision = *(Collision **)(EWRAM_START + 0x33004); - } - - camera->minY = 0; - camera->maxY = gRefCollision->pxHeight; - camera->minX = 0; - camera->maxX = gRefCollision->pxWidth; - -#if (GAME == GAME_SA2) -#ifndef COLLECT_RINGS_ROM - if (IS_BOSS_STAGE(gCurrentLevel)) { - if (gCurrentLevel == LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)) { - SuperSonicGetPos(&player->qWorldX, &player->qWorldY); - gBossCameraClampYLower = gBossCameraYClamps[ZONE_FINAL + 1][0]; - gBossCameraClampYUpper = gBossCameraYClamps[ZONE_FINAL + 1][1]; - camera->x = 600; - camera->unk10 = DISPLAY_CENTER_X; - camera->unk14 = 0; - camera->y = 0; - camera->unk64 = -4; - } else { - camera->x = I(player->qWorldX); - // TODO: Handle boss camera restrictions for large screen sizes - // for now we use the original GBA values as otherwise the boss - // goes off the screen (not sure why yet) - camera->unk10 = I(player->qWorldX) - (2 * 240); - camera->y = I(player->qWorldY) - (DISPLAY_CENTER_Y + 4); - camera->unk14 = camera->y; - camera->unk64 = player->spriteOffsetY - 4; - } - } else -#endif -#endif - { -#if (GAME == GAME_SA1) - camera->SA2_LABEL(unk10) = I(gPlayer.qWorldX) - DISPLAY_CENTER_X; - camera->x = I(gPlayer.qWorldX) - DISPLAY_CENTER_X; - camera->SA2_LABEL(unk14) = (I(gPlayer.qWorldY) + camera->SA2_LABEL(unk4C)) - (DISPLAY_CENTER_Y + 4); - camera->y = (I(gPlayer.qWorldY) + camera->SA2_LABEL(unk4C)) - (DISPLAY_CENTER_Y + 4); -#elif (GAME == GAME_SA2) - camera->x = I(player->qWorldX) - DISPLAY_CENTER_X; - camera->y = I(player->qWorldY) - (DISPLAY_CENTER_Y + 4); - - if (camera->x < 0) { - camera->x = 0; - } - - if (camera->y < 0) { - camera->y = 0; - } - - camera->SA2_LABEL(unk10) = camera->x; - camera->SA2_LABEL(unk14) = camera->y; - camera->SA2_LABEL(unk64) = player->spriteOffsetY - 4; -#endif - } - -#if (GAME == GAME_SA1) - camera->SA2_LABEL(unk8) = 16; -#elif (GAME == GAME_SA2) - camera->SA2_LABEL(unk8) = 0x1000; -#endif - camera->SA2_LABEL(unkC) = 12; -#if (GAME == GAME_SA2) - camera->SA2_LABEL(unk56) = 0; -#endif - camera->shiftX = 0; - camera->shiftY = 0; - camera->SA2_LABEL(unk20) = 0; - camera->SA2_LABEL(unk24) = 0; - camera->SA2_LABEL(unk40) = 0; - camera->SA2_LABEL(unk44) = 8; - camera->SA2_LABEL(unk48) = 0; - camera->SA2_LABEL(unk4C) = 0; - camera->SA2_LABEL(unk50) = 0; - camera->SA2_LABEL(unk52) = 0; - camera->SA2_LABEL(unk54) = 0; - camera->shakeOffsetX = 0; - camera->shakeOffsetY = 0; -#if (GAME == GAME_SA1) - camera->SA2_LABEL(unk64) = gPlayer.spriteOffsetY - 4; -#endif - camera->movementTask = TaskCreate(Task_CallUpdateCamera, 0, 0xF00, 0, TaskDestructor_Camera); - - camera->fnBgUpdate = sStageBgUpdateFuncs[level]; - - if (sStageBgInitProcedures[level] != NULL) { - sStageBgInitProcedures[level](); - } -} - -// ALIGNED UP TO HERE -// Only need to use the original value for these zones -#define DISPLAY_WIDTH_FOR_BOSS_TAS \ - ((LEVEL_TO_ZONE(gCurrentLevel) == ZONE_2 || LEVEL_TO_ZONE(gCurrentLevel) == ZONE_6) ? (240 / 2) : DISPLAY_CENTER_X) - -void UpdateCamera(void) -{ - Player *player = &gPlayer; - struct Camera *camera = &gCamera; - s32 newX, newY; - -#if DEBUG - if (gInput & L_BUTTON) { - s32 speed = Q(10); - if (gInput & DPAD_DOWN) - gPlayer.qWorldY += speed; - if (gInput & DPAD_UP) - gPlayer.qWorldY -= speed; - if (gInput & DPAD_RIGHT) - gPlayer.qWorldX += speed; - if (gInput & DPAD_LEFT) - gPlayer.qWorldX -= speed; - } -#endif - - newX = camera->x; - newY = camera->y; - -#if (GAME == GAME_SA2) - camera->dx = camera->x; - camera->dy = camera->y; -#endif - - newX = CLAMP(newX, camera->minX, camera->maxX - (DISPLAY_WIDTH + 1)); - newY = CLAMP(newY, camera->minY, camera->maxY - (DISPLAY_HEIGHT + 1)); - -#if (GAME == GAME_SA2) - if (IS_BOSS_STAGE(gCurrentLevel)) { - s32 delta, playerY; - if (!IS_ALIVE(player)) { - if (camera->fnBgUpdate != NULL) { - camera->fnBgUpdate(gCamera.x, gCamera.y); - } - return; - } - - if (IS_EXTRA_STAGE(gCurrentLevel)) { - SuperSonicGetPos(&player->qWorldX, &player->qWorldY); - } - - camera->SA2_LABEL(unk20) += BOSS_CAM_FRAME_DELTA_PIXELS; - newX += BOSS_CAM_FRAME_DELTA_PIXELS; - -// Most TASes were written with the expection that -// the player gets pushed forwards when touching the boss -// and the camera is moving (due to a physics bug). -// So we need to emulate that behaviour on some specific -// levels -#if TAS_TESTING && TAS_TESTING_WIDESCREEN_HACK && DISPLAY_WIDTH > 240 - if (newX + (DISPLAY_WIDTH_FOR_BOSS_TAS + 1) < I(player->qWorldX)) -#else - if (newX + (DISPLAY_CENTER_X + 1) < I(player->qWorldX)) -#endif - { - if ((camera->SA2_LABEL(unk20) + DISPLAY_CENTER_Y) > newX) { - s32 playerScreenX = I(player->qWorldX); -#if TAS_TESTING && TAS_TESTING_WIDESCREEN_HACK && DISPLAY_WIDTH > 240 - playerScreenX -= DISPLAY_WIDTH_FOR_BOSS_TAS; -#else - playerScreenX -= DISPLAY_CENTER_X; -#endif - camera->shiftX = playerScreenX - newX; - } else { - newX = (camera->SA2_LABEL(unk20) + DISPLAY_CENTER_Y); - camera->shiftX = 0; - } - } else { - camera->shiftX = 0; - if ((newX + 96) > I(player->qWorldX)) { - newX = I(player->qWorldX); - newX -= 96; - if (newX < camera->SA2_LABEL(unk20)) { - newX = camera->SA2_LABEL(unk20); - } - } - } - - playerY = I(player->qWorldY); - delta = playerY - newY; - if (IS_EXTRA_STAGE(gCurrentLevel)) { - if (delta <= 48) { - s32 temp = newY - 48; - newY = delta + temp; - camera->shiftY = 0; - } else if (delta >= (gBossCameraClampYUpper - 208)) { - s32 temp = newY - 112; - newY = delta + temp; - camera->shiftY = 0; - } - } else { - if (delta <= 48) { - s32 temp = newY - 48; - newY = delta + temp; - camera->shiftY = 0; - } else { - newY += 2; - } - } - newY = CLAMP(newY, gBossCameraClampYLower, gBossCameraClampYUpper - DISPLAY_HEIGHT); - - newX = newX + camera->shiftX; - newY = newY + camera->shiftY; - newX += camera->shakeOffsetX; - newY += camera->shakeOffsetY; - - } else // if !IS_BOSS_STAGE(gCurrentLevel) -> -#endif - { - if (camera->SA2_LABEL(unk40) != 0) { - camera->SA2_LABEL(unk40)--; - } else { - s32 unk64, temp8; -#if (GAME == GAME_SA1) - if (IS_MULTI_PLAYER) { - MultiplayerPlayer *mpp = TASK_DATA(gMultiplayerPlayerTasks[camera->spectatorTarget]); - - if (!(camera->SA2_LABEL(unk50) & 0x1)) { - camera->SA2_LABEL(unk10) = (mpp->pos.x + camera->shiftX) - DISPLAY_CENTER_X; - } - - if (!(camera->SA2_LABEL(unk50) & 2)) { - unk64 = camera->SA2_LABEL(unk64); - temp8 = mpp->unk58[0] - 4; - if (GRAVITY_IS_INVERTED) { - temp8 = -temp8; - } - - if (unk64 != temp8) { - if (unk64 < temp8) { - unk64 += 5; - if (unk64 > temp8) { - unk64 = temp8; - } - } else { - unk64 -= 5; - if (unk64 < temp8) { - unk64 = temp8; - } - } - camera->SA2_LABEL(unk64) = unk64; - } - - camera->SA2_LABEL(unk14) = ((mpp->pos.y) + camera->shiftY) - DISPLAY_CENTER_Y + camera->SA2_LABEL(unk4C) + unk64; - } - } else { -#elif (GAME == GAME_SA2) - camera->SA2_LABEL(unk14) = I(player->qWorldY) + camera->shiftY - DISPLAY_CENTER_Y + camera->unk4C + unk64; -#endif - if (!(camera->SA2_LABEL(unk50) & 1)) { - s16 airSpeedX = player->qSpeedAirX; - camera->SA2_LABEL(unk10) = I(player->qWorldX) + camera->shiftX - DISPLAY_CENTER_X; -#if (GAME == GAME_SA2) - camera->SA2_LABEL(unk56) = (airSpeedX + (camera->SA2_LABEL(unk56) * 15)) >> 4; - camera->SA2_LABEL(unk10) += (camera->SA2_LABEL(unk56) >> 5); -#endif - } - if (!(camera->SA2_LABEL(unk50) & 2)) { - unk64 = camera->SA2_LABEL(unk64); - temp8 = player->spriteOffsetY - 4; - if (GRAVITY_IS_INVERTED) { - temp8 = -temp8; - } - - if (unk64 != temp8) { - if (unk64 < temp8) { - unk64 += 5; - if (unk64 > temp8) { - unk64 = temp8; - } - } else { - unk64 -= 5; - if (unk64 < temp8) { - unk64 = temp8; - } - } - camera->SA2_LABEL(unk64) = unk64; - } - - camera->SA2_LABEL(unk14) = I(player->qWorldY) + camera->shiftY - DISPLAY_CENTER_Y + camera->SA2_LABEL(unk4C) + unk64; - } - } - } - - if ((camera->SA2_LABEL(unk10) - newX) > camera->SA2_LABEL(unk44)) { - s32 temp = camera->SA2_LABEL(unk10) - newX - camera->SA2_LABEL(unk44); - s32 temp2 = CAM_UNK8_INT(camera->SA2_LABEL(unk8)); - if (temp2 > temp) { - temp2 = temp; - } - newX += temp2; - } else if ((camera->SA2_LABEL(unk10) - newX) < -camera->SA2_LABEL(unk44)) { - s32 temp = (camera->SA2_LABEL(unk10) - newX) + camera->SA2_LABEL(unk44); - s32 temp2 = -CAM_UNK8_INT(camera->SA2_LABEL(unk8)); - if (temp2 < temp) { - temp2 = temp; - } - - newX += temp2; - } - - newX = CLAMP(newX, camera->minX, camera->maxX - DISPLAY_WIDTH); - -#if (GAME == GAME_SA2) - if (camera->SA2_LABEL(unk8) < Q(16)) { - camera->SA2_LABEL(unk8) += Q(0.125); - } -#endif - if ((player->moveState & MOVESTATE_IN_AIR) && (player->character != CHARACTER_KNUCKLES || player->SA2_LABEL(unk61) != 9)) - - { - camera->SA2_LABEL(unk48) += 4; - camera->SA2_LABEL(unk48) = MIN(camera->SA2_LABEL(unk48), 24); - } else { - camera->SA2_LABEL(unk48) -= 4; - camera->SA2_LABEL(unk48) = MAX(camera->SA2_LABEL(unk48), 0); - } - - if ((camera->SA2_LABEL(unk14) - newY) > camera->SA2_LABEL(unk48)) { - newY += (camera->SA2_LABEL(unkC) > ((camera->SA2_LABEL(unk14) - newY) - camera->SA2_LABEL(unk48))) - ? ((camera->SA2_LABEL(unk14) - newY) - camera->SA2_LABEL(unk48)) - : camera->SA2_LABEL(unkC); - } else if ((camera->SA2_LABEL(unk14) - newY) < -(camera->SA2_LABEL(unk48))) { - newY += (-camera->SA2_LABEL(unkC) < (camera->SA2_LABEL(unk14) - newY) + camera->SA2_LABEL(unk48)) - ? (camera->SA2_LABEL(unk14) - newY) + camera->SA2_LABEL(unk48) - : -camera->SA2_LABEL(unkC); - } - - newY = CLAMP(newY, camera->minY, camera->maxY - DISPLAY_HEIGHT); - - // maybe a macro, these values are already clamped - newX = CLAMP(newX, camera->minX, camera->maxX - DISPLAY_WIDTH); - newY = CLAMP(newY, camera->minY, camera->maxY - DISPLAY_HEIGHT); - newX = newX + camera->shakeOffsetX; - newY = newY + camera->shakeOffsetY; - } - - camera->x = newX; - camera->y = newY; - -#if (GAME == GAME_SA2) - camera->dx -= newX; - camera->dy -= newY; -#endif - - RenderMetatileLayers(newX, newY); - - if (camera->fnBgUpdate != NULL) { - camera->fnBgUpdate(newX, newY); - } -} - -static void RenderMetatileLayers(s32 x, s32 y) -{ - Background *layer; - -#if (GAME == GAME_SA1) - if (IS_EXTRA_STAGE(gCurrentLevel)) { - s32 scrollX = (x + gStageTime * 8); - // 2688(0xA80) = - // 3072 - 600 - // Moon Zone Pixel Width - (4 * Metatile_Width) - const s32 scrollMaxX = (28 * 96); - - if (scrollX - 72 >= scrollMaxX) { - scrollX -= 72; - scrollX = Mod(scrollX, scrollMaxX) + 72; - } - - x = scrollX; - if (IS_EXTRA_STAGE(gCurrentLevel)) { - layer = &gStageBackgroundsRam.unk80; - gBgScrollRegs[0][0] = x % 8u; - gBgScrollRegs[0][1] = y % 8u; - layer->scrollX = x; - layer->scrollY = y; - DrawBackground(layer); - return; - } - } -#endif - - if (!IS_EXTRA_STAGE(gCurrentLevel)) { - layer = &gStageBackgroundsRam.unk40; - gBgScrollRegs[1][0] = x % 8u; - gBgScrollRegs[1][1] = y % 8u; - layer->scrollX = x; - layer->scrollY = y; - DrawBackground(layer); - UpdateBgAnimationTiles(layer); - - layer = &gStageBackgroundsRam.unk80; - gBgScrollRegs[2][0] = x % 8u; - gBgScrollRegs[2][1] = y % 8u; - layer->scrollX = x; - layer->scrollY = y; - DrawBackground(layer); - } -} diff --git a/src/game/sa1/stage/backgrounds/zone_1.c b/src/game/sa1/stage/backgrounds/zone_1.inc.c similarity index 97% rename from src/game/sa1/stage/backgrounds/zone_1.c rename to src/game/sa1/stage/backgrounds/zone_1.inc.c index 9cdf23a53..9aee8ca08 100644 --- a/src/game/sa1/stage/backgrounds/zone_1.c +++ b/src/game/sa1/stage/backgrounds/zone_1.inc.c @@ -1,6 +1,6 @@ #include "global.h" #include "flags.h" -#include "game/shared/stage/camera.h" + #include "game/globals.h" #include "game/shared/stage/camera.h" diff --git a/src/game/sa1/stage/backgrounds/zone_2.c b/src/game/sa1/stage/backgrounds/zone_2.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_2.c rename to src/game/sa1/stage/backgrounds/zone_2.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_2_interior.c b/src/game/sa1/stage/backgrounds/zone_2_interior.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_2_interior.c rename to src/game/sa1/stage/backgrounds/zone_2_interior.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_3.c b/src/game/sa1/stage/backgrounds/zone_3.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_3.c rename to src/game/sa1/stage/backgrounds/zone_3.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_3_firework.c b/src/game/sa1/stage/backgrounds/zone_3_firework.c deleted file mode 100644 index d6c8fdc1f..000000000 --- a/src/game/sa1/stage/backgrounds/zone_3_firework.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "global.h" -#include "core.h" -#include "flags.h" -#include "malloc_vram.h" -#include "game/sa1/stage/backgrounds/zone_3.h" -#include "game/shared/stage/camera.h" -#include "game/shared/stage/mp_sprite_task.h" -#include "game/globals.h" - -void VBlankCallback_803F920(void) { *(vu32 *)®_BG1HOFS = 0; } - -void HBlankCallback_803F92C(int_vcount line) -{ - s32 newLine = line - 90; - - if ((newLine >= 0) && (line != DISPLAY_HEIGHT - 1)) { - u32 *ptr = gBgOffsetsHBlankSecondary; - ptr += 90; - - *(vu32 *)®_BG1HOFS = ptr[newLine]; - } else { - *(vu32 *)®_BG1HOFS = 0; - } -} - -void sub_803F968(void) -{ - struct Camera *cam = &gCamera; - - if (gStageTime & 0x1) { - cam->shiftY = ((u32)(PseudoRandom32() & 0x70000) >> 16) - 8; - } -} - -struct Task *SpawnCasinoFireworkMP(s16 x, s16 y, s32 fireworkType) -{ - const TileInfoFirework *tileInfo = &gTileInfoZone3Fireworks[fireworkType % ARRAY_COUNT(gTileInfoZone3Fireworks)]; - CasinoParadiseFirework *firework; - struct Task *t; - Sprite *s; - - t = CreateMultiplayerSpriteTask(x, y, 0, 0, Task_UpdateFireworkAnimation, TaskDestructor_MultiplayerSpriteTask); - firework = TASK_DATA(t); - s = &firework->s; - - s->graphics.dest = VramMalloc(tileInfo->numTiles); - s->graphics.anim = tileInfo->anim; - s->variant = tileInfo->variant; - s->oamFlags = SPRITE_OAM_ORDER(31); - s->frameFlags = SPRITE_FLAG(PRIORITY, 3); - - return t; -} \ No newline at end of file diff --git a/src/game/sa1/stage/backgrounds/zone_4.c b/src/game/sa1/stage/backgrounds/zone_4.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_4.c rename to src/game/sa1/stage/backgrounds/zone_4.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_4_init.c b/src/game/sa1/stage/backgrounds/zone_4_init.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_4_init.c rename to src/game/sa1/stage/backgrounds/zone_4_init.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_5.c b/src/game/sa1/stage/backgrounds/zone_5.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_5.c rename to src/game/sa1/stage/backgrounds/zone_5.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_5_init.c b/src/game/sa1/stage/backgrounds/zone_5_init.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_5_init.c rename to src/game/sa1/stage/backgrounds/zone_5_init.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_6.c b/src/game/sa1/stage/backgrounds/zone_6.inc.c similarity index 100% rename from src/game/sa1/stage/backgrounds/zone_6.c rename to src/game/sa1/stage/backgrounds/zone_6.inc.c diff --git a/src/game/sa1/stage/backgrounds/zone_6_hblank.c b/src/game/sa1/stage/backgrounds/zone_6_hblank.c deleted file mode 100644 index 259847650..000000000 --- a/src/game/sa1/stage/backgrounds/zone_6_hblank.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "global.h" -#include "core.h" -#include "animation_commands_bg.h" -#include "game/globals.h" -#include "game/shared/stage/camera.h" -#include "game/sa1/stage/backgrounds/zone_6.h" - -void HBlankCallback_803FA1C(int_vcount line) -{ - if (line == 100) { - REG_BG0CNT &= ~BGCNT_TXT512x512; - REG_BG0CNT |= BGCNT_TXT256x512; - *(u32 *)®_BG0HOFS = (0 | (DISPLAY_HEIGHT << 16)); - } else if (line > 101 && line < 134) { - REG_BLDY = 16 - ((line - 101) >> 1); - } -} \ No newline at end of file diff --git a/src/game/sa1/stage/backgrounds/zone_7_act_1.c b/src/game/sa1/stage/backgrounds/zone_7.inc.c similarity index 71% rename from src/game/sa1/stage/backgrounds/zone_7_act_1.c rename to src/game/sa1/stage/backgrounds/zone_7.inc.c index fde9ff84f..ef976bc3b 100644 --- a/src/game/sa1/stage/backgrounds/zone_7_act_1.c +++ b/src/game/sa1/stage/backgrounds/zone_7.inc.c @@ -23,3 +23,14 @@ void StageBgUpdate_Zone7Act1(s32 x, s32 y) gCamera.SA2_LABEL(unk54) = ySub; gBgScrollRegs[3][1] = ySub; } + +void CreateStageBg_Zone7_Act2(void) +{ + Background *bg; + const Collision *collision; + + DmaFill32(3, 0, BG_TILE_ADDR(128), 0x4000); + DmaFill32(3, 0, BG_TILE_ADDR(448), 0x800); + + gBgCntRegs[2] = BGCNT_TXT512x256 | BGCNT_SCREENBASE(28) | BGCNT_256COLOR | 0x5; +} diff --git a/src/game/sa1/stage/backgrounds/zone_7_act_2.c b/src/game/sa1/stage/backgrounds/zone_7_act_2.inc.c similarity index 97% rename from src/game/sa1/stage/backgrounds/zone_7_act_2.c rename to src/game/sa1/stage/backgrounds/zone_7_act_2.inc.c index 564f951ff..5267c152f 100644 --- a/src/game/sa1/stage/backgrounds/zone_7_act_2.c +++ b/src/game/sa1/stage/backgrounds/zone_7_act_2.inc.c @@ -9,7 +9,7 @@ extern void HBlankCallback_803F92C(int_vcount line); extern void VBlankCallback_803F920(void); -void StageBgUpdate_Zone7Act2(void) +void StageBgUpdate_Zone7Act2(s32 x, s32 y) { struct Camera *cam = &gCamera; Background *bg = &gStageBackgroundsRam.unkC0; diff --git a/src/game/sa1/stage/backgrounds/zone_7_act_2_init.c b/src/game/sa1/stage/backgrounds/zone_7_act_2_init.c deleted file mode 100644 index 1d46a7131..000000000 --- a/src/game/sa1/stage/backgrounds/zone_7_act_2_init.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "global.h" -#include "core.h" -#include "animation_commands_bg.h" -#include "game/globals.h" -#include "game/shared/stage/camera.h" -#include "game/sa1/stage/backgrounds/zone_5.h" - -void CreateStageBg_Zone7_Act2(void) -{ - Background *bg; - const Collision *collision; - - DmaFill32(3, 0, BG_TILE_ADDR(128), 0x4000); - DmaFill32(3, 0, BG_TILE_ADDR(448), 0x800); - - gBgCntRegs[2] = BGCNT_TXT512x256 | BGCNT_SCREENBASE(28) | BGCNT_256COLOR | 0x5; -} diff --git a/src/game/sa1/stage/camera_destroy.c b/src/game/sa1/stage/camera_destroy.c deleted file mode 100644 index 73968a8d4..000000000 --- a/src/game/sa1/stage/camera_destroy.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "global.h" -#include "core.h" -#include "flags.h" -#include "game/shared/stage/camera.h" -#include "game/globals.h" -#include "game/shared/stage/camera.h" -#include "constants/sa1/zones.h" - -static void Task_CallUpdateCameraInternal(void); - -void DestroyCameraMovementTask(void) -{ - TaskDestroy(gCamera.movementTask); - gCamera.movementTask = NULL; -} - -void TaskDestructor_Camera(struct Task *unused) -{ - s32 i; - gCamera.movementTask = NULL; - - for (i = 0; i < NUM_BACKGROUNDS; i++) { - gBgScrollRegs[i][0] = 0; - gBgScrollRegs[i][1] = 0; - } - - if (IS_EXTRA_STAGE(gCurrentLevel) && (gFlags & FLAGS_40)) { - gIntrTable[INTR_INDEX_VCOUNT] = gIntrTableTemplate[INTR_INDEX_VCOUNT]; - gFlags &= ~FLAGS_40; - } - - gFlags &= ~FLAGS_EXECUTE_HBLANK_COPY; -} - -void Task_CallUpdateCamera(void) -{ - gDispCnt |= (DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_ON); - -#if (GAME == GAME_SA2) - if (IS_EXTRA_STAGE(gCurrentLevel)) { - gDispCnt &= ~DISPCNT_BG3_ON; - } -#endif - - if (gGameMode == GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { - gDispCnt &= ~DISPCNT_WIN0_ON; - } - - gCurTask->main = Task_CallUpdateCameraInternal; -} - -static void Task_CallUpdateCameraInternal(void) -{ - UpdateCamera(); - gOamMatrixIndex = 0x4; -} \ No newline at end of file diff --git a/src/game/sa2/stage/backgrounds/zone_1.inc.c b/src/game/sa2/stage/backgrounds/zone_1.inc.c new file mode 100644 index 000000000..a4cde2faa --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_1.inc.c @@ -0,0 +1,112 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +void CreateStageBg_Zone1(void) +{ + Background *background = &gStageBackgroundsRam.unk0; + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); + +#ifndef COLLECT_RINGS_ROM + if (gGameMode != GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { + const Background *templates = gStageCameraBgTemplates; + memcpy(background, &templates[3], sizeof(Background)); + + background->tilemapId = TM_STAGE_1_BG_0_COPY; + background->graphics.dest = (void *)BG_SCREEN_ADDR(24); + background->layoutVram = (void *)BG_SCREEN_ADDR(27); + + background->targetTilesX = 256 / TILE_WIDTH; + background->targetTilesY = 256 / TILE_WIDTH; + } else +#endif + { + const Background *templates = gStageCameraBgTemplates; + memcpy(background, &templates[3], sizeof(Background)); + background->tilemapId = TM_LEVEL_BG(LEVEL_INDEX(ZONE_1, ACT_1)); + + background->graphics.dest = (void *)BG_SCREEN_ADDR(24); + background->layoutVram = (void *)BG_SCREEN_ADDR(27); + + background->targetTilesX = 256 / TILE_WIDTH; + background->targetTilesY = 240 / TILE_WIDTH; + } + + DrawBackground(background); + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 0; +} + +#ifndef COLLECT_RINGS_ROM +void StageBgUpdate_Zone1Acts12(s32 UNUSED a, s32 UNUSED b) +{ + s32 i; + s32 initial1, initial2; + s16 camY; + u16 bgScroll; + u16 *cursor; + + if (gGameMode != GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { + if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT) { + s32 temp, val; + temp = (gPlayer.moveState & MOVESTATE_4000000) ? 7 : 0xF; + + val = gBgScrollRegs[0][0]; + if ((gStageTime & temp) == temp) { + val++; + } + gBgScrollRegs[0][0] = val; + gBgScrollRegs[0][0] &= 0xFF; + } else { + gBgScrollRegs[0][0] = gCamera.x >> 6; + gBgScrollRegs[0][0] &= 0xFF; + } + + gBgScrollRegs[0][1] = gCamera.y >> 9; + gFlags |= FLAGS_EXECUTE_HBLANK_COPY; + gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; + gHBlankCopySize = 4; + cursor = gBgOffsetsHBlankPrimary; + initial1 = 0; + + if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT) { + s32 temp, val; + temp = (gPlayer.moveState & MOVESTATE_4000000) ? 0xF : 0x1F; + + val = gBgScrollRegs[3][0]; + if ((gStageTime & temp) == temp) { + val++; + } + gBgScrollRegs[3][0] = val; + gBgScrollRegs[3][0] &= 0xFF; + bgScroll = gBgScrollRegs[3][0]; + } else { + bgScroll = gCamera.x >> 7; + gBgScrollRegs[3][0] = bgScroll; + } + + camY = gCamera.y >> 8; + initial2 = 0; + +#ifdef BUG_FIX + if (cursor != NULL) +#endif + { + for (i = 71; i >= 0; i--) { + *cursor++ = initial1; + *cursor++ = initial2; + } + + for (i = 86; i >= 0; i--) { + *cursor++ = bgScroll; + *cursor++ = camY; + } + } + } +} +#endif diff --git a/src/game/sa2/stage/backgrounds/zone_1_boss.inc.c b/src/game/sa2/stage/backgrounds/zone_1_boss.inc.c new file mode 100644 index 000000000..d8e405769 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_1_boss.inc.c @@ -0,0 +1,16 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +void StageBgUpdate_Zone1ActBoss(UNUSED s32 x, UNUSED s32 y) +{ + struct Camera *cam = &gCamera; + if (!PLAYER_IS_ALIVE) { + gStageTime--; + } + + gBgScrollRegs[0][0] = ((gStageTime + 4) >> 3) & 0xFF; + gBgScrollRegs[0][1] = cam->y >> 9; + gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_801E434; + gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; +} diff --git a/src/game/sa2/stage/backgrounds/zone_2.inc.c b/src/game/sa2/stage/backgrounds/zone_2.inc.c new file mode 100644 index 000000000..5c0db8cc1 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_2.inc.c @@ -0,0 +1,100 @@ +#include "trig.h" + +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +// (88.05%) https://decomp.me/scratch/ekyaq +// (91.40%) https://decomp.me/scratch/vapLV +// (95.71%) https://decomp.me/scratch/Naixp (more accurate) +NONMATCH("asm/non_matching/game/sa2/stage/background/StageBgUpdate_Zone2Acts12.inc", + void StageBgUpdate_Zone2Acts12(s32 cameraX, s32 cameraY)) +{ + s16 something; + u8 i, j; + s16 camFracY, camFracX; + + u16 *cursor; + s32 x0 = 0; + if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= 7) { + if (gBgScrollRegs[3][0] == 0) { + gBgScrollRegs[3][0] = cameraX; + } + gBgScrollRegs[3][0] += (gPlayer.qSpeedGround >> 8); + cameraX = gBgScrollRegs[3][0]; + } + + if (!IS_SINGLE_PLAYER) { + gBgScrollRegs[3][0] = cameraX >> 4; + camFracY = Div(cameraY, 0x10); + if (camFracY > 0x100) { + camFracY = 0x100; + } + gBgScrollRegs[3][1] = camFracY; + } else { + s32 dt; + + camFracY = Div(cameraY, 0x10); + + // Prevent wrapping of the background map at the bottom of the screen on high cameraY's +#if !WIDESCREEN_HACK + if (camFracY > 0x100) { + camFracY = 0x100; + } +#else + { + // TODO: Use proper maths for max, depending on DISPLAY_HEIGHT instead of a hardcoded value + const u32 max = 153; + + if (camFracY > max) { + camFracY = max; + } + } +#endif + + camFracX = Div(cameraX, 0x69); + if (camFracX > 0x100) { + camFracX = 0x100; + } + + gFlags |= FLAGS_EXECUTE_HBLANK_COPY; + gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; + gHBlankCopySize = sizeof(u16) * 2; + + cursor = gBgOffsetsHBlankPrimary; + dt = gStageTime * 0x18; + + // Sky and Clouds + for (i = 0; i < DISPLAY_HEIGHT - 1; i++) { + if ((u32)((camFracY + i) - 111) < 10) { + camFracX = ((((camFracY + i) - 110) * cameraX) >> 5) & 0xFF; + } else { + camFracX = (camFracY + i) > 120 ? ((cameraX * 10) >> 5) & 0xFF : camFracX; + } + *cursor++ = camFracX; + *cursor++ = camFracY; + if ((camFracY + i) + (SIN(((i * 8) + (camFracY << 3)) & ONE_CYCLE) >> 12) >= 178) { + break; + } + } + + // Red Bottom + something = (cameraX >> 3); + for (j = 0; i < DISPLAY_HEIGHT - 1; i++, j++) { + u16 cursorX, cursorY; + + x0 += 8; + x0 = CLAMP_SIN_PERIOD(x0); + cursorX = camFracX + (SIN(x0) >> 13) + (COS(((gStageTime * 2) + x0) & 0x3FF) >> 11) + + (SIN(CLAMP_SIN_PERIOD(dt + (i * 0x40))) >> 13); + *cursor++ = cursorX; + cursorY = (j / 2) + camFracY + (SIN(x0) >> 12) + (COS(CLAMP_SIN_PERIOD(gStageTime + (i * 8))) >> 10); + *cursor++ = cursorY; + }; + } +} +END_NONMATCH \ No newline at end of file diff --git a/src/game/sa2/stage/backgrounds/zone_2_boss.inc.c b/src/game/sa2/stage/backgrounds/zone_2_boss.inc.c new file mode 100644 index 000000000..7eaee61c7 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_2_boss.inc.c @@ -0,0 +1,12 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +void StageBgUpdate_Zone2ActBoss(UNUSED s32 a, UNUSED s32 b) +{ + if (!PLAYER_IS_ALIVE) { + gStageTime--; + } + + StageBgUpdate_Zone2Acts12(gStageTime, 4000); +} diff --git a/src/game/sa2/stage/backgrounds/zone_3.inc.c b/src/game/sa2/stage/backgrounds/zone_3.inc.c new file mode 100644 index 000000000..b6fe46388 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_3.inc.c @@ -0,0 +1,205 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +static s16 sUnknown_03000408; + +// TODO: make this static! +const u8 gUnknown_080D5B20[16][3] = { + { 14, 0, 1 }, // + { 22, 0, 3 }, // + { 30, 0, 2 }, // + { 38, 0, 1 }, // + { 46, 0, 3 }, // + { 62, 0, 1 }, // + { 70, 0, 2 }, // + { 86, 0, 1 }, // + { 94, 0, 2 }, // + { 126, 0, 1 }, // + { 168, 1, 1 }, // + { 174, 1, 2 }, // + { 182, 2, 3 }, // + { 198, 3, 4 }, // + { 222, 4, 5 }, // + { 255, 5, 6 }, // +}; + +// defined here but used in hblank_callbacks +// NOTE: Only values > 105 appear to be used. +const u8 gUnknown_080D5B50[DISPLAY_HEIGHT] = { // 0-94 + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 10, // + 10, 10, 8, 8, 8, 8, // 95-98 + 7, 7, 7, 7, // 99-102 + 6, 6, 6, // 103-104 + /* 105-159 */ + 6, 6, // + 6, 6, 6, // + 5, 5, 5, // + 5, 5, 5, // + 5, 5, 4, // + 4, 4, 4, // + 4, 4, 4, // + 4, 3, 3, // + 3, 3, 3, // + 3, 3, 3, // + 3, 3, 3, // + 3, 3, 3, // + 3, 3, 2, // + 2, 2, 2, // + 2, 2, 2, // + 2, 2, 2, // + 2, 2, 2, // + 2, 2, 2, // + + // Maybe padding? + 0 +}; + +void CreateStageBg_Zone3(void) +{ + Background *background = &gStageBackgroundsRam.unk0; + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); + + *background = gStageCameraBgTemplates[3]; + + background->tilemapId = TM_MUSIC_PLANT_MOVING_STARS; + background->graphics.dest = (void *)BG_SCREEN_ADDR(24); + background->layoutVram = (void *)BG_SCREEN_ADDR(27); + background->targetTilesX = 0x20; + background->targetTilesY = 0x20; + DrawBackground(background); + + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 0; + gBgScrollRegs[3][0] = 0; + gBgScrollRegs[3][1] = 0; +} + +// (85.02%) https://decomp.me/scratch/Esyzr +#if 01 +NONMATCH("asm/non_matching/game/sa2/stage/background/StageBgUpdate_Zone3Acts12.inc", + void StageBgUpdate_Zone3Acts12(s32 cameraX, s32 cameraY)) +#else +void StageBgUpdate_Zone3Acts12(s32 cameraX, s32 cameraY) +#endif +{ + s16 r6; + u8 i; + u8 sp40; + Vec2_16 sp[16]; + Vec2_16 *cursorStack; + u8 *cursor; + s32 pFlags; +#ifndef NON_MATCHING + register s16 sl asm("sl") = 0; + register u16 *bgBuffer asm("r5") = gBgOffsetsHBlankPrimary; + register s16 camFracY asm("r3") = (Div(cameraY, 60) << 16) >> 16; +#else + s16 sl = 0; + u16 *bgBuffer = gBgOffsetsHBlankPrimary; + s16 camFracY = Div(cameraY, 60); +#endif + + // Prevent wrapping of the background map at the bottom of the screen on high cameraY's +#if WIDESCREEN_HACK + if (camFracY > 256 - DISPLAY_HEIGHT) { + camFracY = 256 - DISPLAY_HEIGHT; + } +#endif + + gBgScrollRegs[0][1] = camFracY; + gBgScrollRegs[3][1] = camFracY; + + if (IS_SINGLE_PLAYER) { + if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && (gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT)) { + if (sUnknown_03000408 == 0) { + sUnknown_03000408 = cameraX; + } + sUnknown_03000408 += I(gPlayer.qSpeedGround); + cameraX = sUnknown_03000408; + } else { + sUnknown_03000408 = 0; + } + // _0801CC72 + i = 0; + + { + s32 r6 = camFracY; + cursor = (u8 *)gUnknown_080D5B20; + sp40 = camFracY; + + while (r6 >= cursor[i * 3]) { + if (++i >= ARRAY_COUNT(gUnknown_080D5B20)) { + break; + } + { + sl = i; + } + } + } + //_0801CCA8: + + for (i = 0; i < ARRAY_COUNT(gUnknown_080D5B20); i++) { + sp[i].x = (((gUnknown_080D5B20[i][1] * cameraX) >> 5) & 0xFF); + sp[i].y = (((gUnknown_080D5B20[i][2] * cameraX) >> 5) & 0xFF); + } + // __0801CCF0 + + cursorStack = &sp[sl]; + cursor = (u8 *)gUnknown_080D5B20[sl]; + for (i = 0; (u8)i < DISPLAY_HEIGHT - 1; sp40++, i++) { + *bgBuffer = cursorStack->y; + bgBuffer++; + + *bgBuffer = cursorStack->x; + bgBuffer++; + + if (sp40 >= *cursor) { + cursor += 3; + cursorStack++; + } + } + + // __0801CD2C + gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_801E454; + gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; + } +} +#if 01 +END_NONMATCH +#endif diff --git a/src/game/sa2/stage/backgrounds/zone_3_boss.inc.c b/src/game/sa2/stage/backgrounds/zone_3_boss.inc.c new file mode 100644 index 000000000..0f22cb836 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_3_boss.inc.c @@ -0,0 +1,11 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +void StageBgUpdate_Zone3ActBoss(UNUSED s32 a, UNUSED s32 b) +{ + gBgScrollRegs[0][1] = 0; + gBgScrollRegs[3][1] = 0; + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[3][0] = 0; +} diff --git a/src/game/sa2/stage/backgrounds/zone_4.inc.c b/src/game/sa2/stage/backgrounds/zone_4.inc.c new file mode 100644 index 000000000..4bce2308e --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_4.inc.c @@ -0,0 +1,89 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +static s16 sCameraShiftX; + +void CreateStageBg_Zone4(void) +{ + Background *background = &gStageBackgroundsRam.unk0; + const Background *templates; + gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); + + *background = gStageCameraBgTemplates[CAMBG_BACK_B_LAYER]; + + background->tilemapId = TM_SPOTLIGHT_SNOW; + background->graphics.dest = (void *)BG_SCREEN_ADDR(24); + background->layoutVram = (void *)BG_SCREEN_ADDR(27); + background->targetTilesX = 32; + background->targetTilesY = 32; + background->flags = BACKGROUND_DISABLE_PALETTE_UPDATE | BACKGROUND_FLAGS_BG_ID(3); + DrawBackground(background); + + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 0; + gBgScrollRegs[3][0] = 0; + gBgScrollRegs[3][1] = 0; + +// Software renderer for these devices are too slow +// to handle these spotlights +#if !defined(__PS2__) && !defined(__PSP__) + if (IS_SINGLE_PLAYER) { + CreateSpotlightsManager(); + } +#endif +} + +void StageBgUpdate_Zone4Acts12(s32 cameraX, s32 cameraY) +{ + Player *player = &gPlayer; + s32 camFracY; + + if ((player->moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT) { + if (sCameraShiftX == 0) { + sCameraShiftX = cameraX; + } + sCameraShiftX += I(player->qSpeedGround); + cameraX = sCameraShiftX; + } else { + sCameraShiftX = 0; + } + + if (IS_SINGLE_PLAYER && !(gStageFlags & STAGE_FLAG__100)) { + gWinRegs[WINREG_WINOUT] = 0x3e; + gWinRegs[WINREG_WININ] = 0x3f3f; + gWinRegs[WINREG_WIN0H] = WIN_RANGE(0, DISPLAY_WIDTH); + gWinRegs[WINREG_WIN0V] = WIN_RANGE(0, DISPLAY_HEIGHT); + gWinRegs[WINREG_WIN1H] = WIN_RANGE(0, DISPLAY_WIDTH); + gWinRegs[WINREG_WIN1V] = WIN_RANGE(0, DISPLAY_HEIGHT); + gBldRegs.bldY = 7; + gBldRegs.bldCnt = 0x3f41; + gBldRegs.bldAlpha = 0xc0c; + } + +#ifdef BUG_FIX + UpdateBgAnimationTiles(&gStageBackgroundsRam.unk0); + DrawBackground(&gStageBackgroundsRam.unk0); +#else + DrawBackground(&gStageBackgroundsRam.unk0); + UpdateBgAnimationTiles(&gStageBackgroundsRam.unk0); +#endif + + if ((gStageTime % 16u) == 0) { + gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 1) & 0xff; + gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] - 1) & 0xff; + } + gBgScrollRegs[3][0] = cameraX >> 4; + + camFracY = cameraY >> 6; +#if WIDESCREEN_HACK + if (camFracY > 256 - DISPLAY_HEIGHT) { + camFracY = 256 - DISPLAY_HEIGHT; + } +#endif + gBgScrollRegs[3][1] = camFracY; +} diff --git a/src/game/sa2/stage/backgrounds/zone_5.inc.c b/src/game/sa2/stage/backgrounds/zone_5.inc.c new file mode 100644 index 000000000..8b9a78096 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_5.inc.c @@ -0,0 +1,169 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +#if !WIDESCREEN_HACK +#define SCREENBASE_SKY_CANYON_CLOUDS 27 +#else +#define SCREENBASE_SKY_CANYON_CLOUDS 27 +#endif + +void CreateStageBg_Zone5(void) +{ + Background *background = &gStageBackgroundsRam.unk0; + + if (IS_SINGLE_PLAYER) { + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] = (BGCNT_TXT256x256 | BGCNT_SCREENBASE(SCREENBASE_SKY_CANYON_CLOUDS) | BGCNT_CHARBASE(3)); + *background = gStageCameraBgTemplates[3]; + background->tilemapId = TM_SKY_CANYON_CLOUDS_FOREGROUND; + background->graphics.dest = (void *)BG_SCREEN_ADDR(24); + background->layoutVram = (void *)BG_SCREEN_ADDR(SCREENBASE_SKY_CANYON_CLOUDS); + background->targetTilesX = (256 / TILE_WIDTH); + background->targetTilesY = (256 / TILE_WIDTH); + DrawBackground(background); + } + + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 160 - DISPLAY_HEIGHT; + gBgScrollRegs[3][0] = 0; + gBgScrollRegs[3][1] = 0; +} + +#if WIDESCREEN_HACK +// NOTE: This is very much temporary. +void HBlankCB_FixCloudRendering(int_vcount vcount) +{ + // NOTE: If gBgScrollRegs[0][1] doesn't also get set here, a transparent line will appear at the very top. + // Only setting REG_BG0VOFS leads to its value getting overwritten at the end of the frame, + // with gBgScrollRegs[0][1], so we have to set it accordingly. + if (vcount < 80 || vcount == 239) { + REG_BG0VOFS = 0; + gBgScrollRegs[0][1] = 0; + } else { + REG_BG0VOFS = 160 - DISPLAY_HEIGHT; + gBgScrollRegs[0][1] = 160 - DISPLAY_HEIGHT; + } +} +#endif + +#define BG_CLOUD_START_Y 96 + +void StageBgUpdate_Zone5Acts12(s32 UNUSED cameraX, s32 UNUSED cameraY) +{ + s32 num; + u16 *cursor, i, val; + gBgScrollRegs[0][0]++; + gBgScrollRegs[3][0] = 0; + num = gStageTime * 2; + + if (IS_SINGLE_PLAYER) { + gFlags = gFlags | FLAGS_EXECUTE_HBLANK_COPY; + gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; + gHBlankCopySize = 2; + cursor = gBgOffsetsHBlankPrimary; + + if (gCurrentLevel != LEVEL_INDEX(ZONE_5, ACT_BOSS)) { + gDispCnt |= DISPCNT_BG0_ON; + gDispCnt |= DISPCNT_WIN0_ON; + gWinRegs[WINREG_WINOUT] = WINOUT_WIN01_ALL; + gWinRegs[WINREG_WININ] = (WININ_WIN0_ALL | WININ_WIN1_ALL); + gWinRegs[WINREG_WIN0H] = WIN_RANGE(0, DISPLAY_WIDTH); + gWinRegs[WINREG_WIN0V] = WIN_RANGE(0, DISPLAY_HEIGHT); + gWinRegs[WINREG_WIN1H] = WIN_RANGE(0, DISPLAY_WIDTH); + gWinRegs[WINREG_WIN1V] = WIN_RANGE(0, DISPLAY_HEIGHT); + gBldRegs.bldY = 7; + gBldRegs.bldCnt = (BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG0); + gBldRegs.bldAlpha = BLDALPHA_BLEND(16, 16); + } + + // Move the parallax clouds +#if !WIDESCREEN_HACK + for (i = 0; i < BG_CLOUD_START_Y; i++) { + *cursor++ = 0; + } + + val = Div(num, 8); + for (; i < BG_CLOUD_START_Y + 4; i++) { + *cursor++ = val; + } + + val = Div(num, 7); + for (; i < BG_CLOUD_START_Y + 8; i++) { + *cursor++ = val; + } + + val = Div(num, 6); + for (; i < BG_CLOUD_START_Y + 16; i++) { + *cursor++ = val; + } + + val = Div(num, 5); + for (; i < BG_CLOUD_START_Y + 24; i++) { + *cursor++ = val; + } + + val = Div(num, 4); + for (; i < BG_CLOUD_START_Y + 32; i++) { + *cursor++ = val; + } + + val = Div(num, 3); + for (; i < BG_CLOUD_START_Y + 48; i++) { + *cursor++ = val; + } + + val = Div(num, 2); + for (; i < BG_CLOUD_START_Y + 63; i++) { + *cursor++ = val; + } +#else + // NOTE: Temporary solution to render the bottom of the background in a decent looking way + gHBlankCopySize = 2 * sizeof(u16); + + for (i = 0; i < DISPLAY_HEIGHT - 1; i++) { + s32 originalLine = (s32)(((float)i / (float)DISPLAY_HEIGHT) * 160.0f); + + if (originalLine > 159) { + originalLine = 159; + } + + if (originalLine < BG_CLOUD_START_Y) { + *cursor++ = 0; + *cursor++ = originalLine - i; + } else if (originalLine < BG_CLOUD_START_Y + 4) { + *cursor++ = num >> 3; + *cursor++ = originalLine - i; + } else if (originalLine < BG_CLOUD_START_Y + 8) { + *cursor++ = Div(num, 7); + *cursor++ = originalLine - i; + } else if (originalLine < BG_CLOUD_START_Y + 16) { + *cursor++ = Div(num, 6); + *cursor++ = originalLine - i; + } else if (originalLine < BG_CLOUD_START_Y + 24) { + *cursor++ = Div(num, 5); + *cursor++ = originalLine - i; + } else if (originalLine < BG_CLOUD_START_Y + 32) { + *cursor++ = num >> 2; + *cursor++ = originalLine - i; + } else if (originalLine < BG_CLOUD_START_Y + 48) { + *cursor++ = Div(num, 3); + *cursor++ = originalLine - i; + } else if (originalLine < BG_CLOUD_START_Y + 63) { + *cursor++ = num >> 1; + *cursor++ = originalLine - i; + } else { + *cursor++ = 0; + *cursor++ = originalLine - i; + } + } + + gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_FixCloudRendering; + gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; +#endif + } +} diff --git a/src/game/sa2/stage/backgrounds/zone_5_boss.inc.c b/src/game/sa2/stage/backgrounds/zone_5_boss.inc.c new file mode 100644 index 000000000..18d99323d --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_5_boss.inc.c @@ -0,0 +1,11 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +void StageBgUpdate_Zone5ActBoss(UNUSED s32 a, UNUSED s32 b) +{ + gDispCnt &= ~DISPCNT_BG1_ON; + gBgScrollRegs[0][0]++; + gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_BgUpdateZone5ActBoss; + gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; +} diff --git a/src/game/sa2/stage/backgrounds/zone_6.inc.c b/src/game/sa2/stage/backgrounds/zone_6.inc.c new file mode 100644 index 000000000..e53bf0885 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_6.inc.c @@ -0,0 +1,416 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +#if !PORTABLE +#define USE_BOSS_BG_IN_ZONE_6_ACTS FALSE +#else +// The default flickering is very strong, so we disable it. +// TODO: Add a global option, so players can decide to use the original effect if they want to. +#define USE_BOSS_BG_IN_ZONE_6_ACTS TRUE +#endif + +const s16 gUnknown_080D5BF0[] = { + Q_8_8(0.00), Q_8_8(0.25), Q_8_8(2.25), Q_8_8(2.50), Q_8_8(3.50), Q_8_8(3.625), Q_8_8(5.625), Q_8_8(5.75), Q_8_8(6.75), +}; + +// TODO: Make static and Rename to sBlendColors +const u8 gUnknown_080D5C02[2][16][3] = { + { + // r, g, b + { 0x1F, 0x00, 0x1F }, + { 0x01, 0x07, 0x14 }, + { 0x01, 0x09, 0x14 }, + { 0x00, 0x0A, 0x13 }, + { 0x00, 0x0C, 0x13 }, + { 0x00, 0x0D, 0x12 }, + { 0x00, 0x0F, 0x12 }, + { 0x00, 0x10, 0x11 }, + { 0x00, 0x12, 0x10 }, + { 0x00, 0x13, 0x10 }, + { 0x00, 0x15, 0x0F }, + { 0x00, 0x16, 0x0F }, + { 0x00, 0x18, 0x0E }, + { 0x00, 0x19, 0x0E }, + { 0x00, 0x1B, 0x0D }, + { 0x1F, 0x07, 0x00 }, + }, + { + // r, g, b + { 0x1F, 0x00, 0x00 }, + { 0x0F, 0x00, 0x1B }, + { 0x0E, 0x00, 0x19 }, + { 0x0D, 0x01, 0x17 }, + { 0x0C, 0x01, 0x15 }, + { 0x0B, 0x02, 0x13 }, + { 0x0A, 0x02, 0x11 }, + { 0x08, 0x03, 0x0F }, + { 0x07, 0x03, 0x0D }, + { 0x06, 0x04, 0x0B }, + { 0x05, 0x04, 0x09 }, + { 0x04, 0x05, 0x07 }, + { 0x03, 0x05, 0x05 }, + { 0x02, 0x06, 0x03 }, + { 0x01, 0x06, 0x01 }, + { 0x00, 0x07, 0x00 }, + }, +}; + +void CreateStageBg_Zone6_Acts(void) +{ + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] = BGCNT_SCREENBASE(26) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); + INIT_BG_SPRITES_LAYER_32(0); + DmaFill32(3, 0, BG_SCREEN_ADDR(24), sizeof(Background)); + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 0; + gBgScrollRegs[3][0] = 0; + gBgScrollRegs[3][1] = 0; + gStageTime = 0x380; + + if (USE_BOSS_BG_IN_ZONE_6_ACTS || IS_MULTI_PLAYER) { + CreateStageBg_Zone6_Boss(); + } + + gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[3] |= BGCNT_PRIORITY(2); +} + +void CreateStageBg_Zone6_Boss(void) +{ + Background *background = &gStageBackgroundsRam.unk0; + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] = BGCNT_SCREENBASE(26) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); + INIT_BG_SPRITES_LAYER_32(0); + DmaFill32(3, 0, BG_SCREEN_ADDR(24), sizeof(Background)); + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 0; + gBgScrollRegs[3][0] = 0; + gBgScrollRegs[3][1] = 0; + + *background = gStageCameraBgTemplates[3]; + background->tilemapId = TM_TECHNO_BASE_BG_CIRCUIT_MASK; + background->graphics.dest = (void *)BG_SCREEN_ADDR(24); + background->layoutVram = (void *)BG_SCREEN_ADDR(26); + background->targetTilesX = 32; + background->targetTilesY = 32; + + DrawBackground(background); +} + +// (82.58%) https://decomp.me/scratch/tB3Bs +// (85.82%) https://decomp.me/scratch/pNyvP +NONMATCH("asm/non_matching/game/sa2/stage/background/sub_801D24C.inc", void sub_801D24C(u8 p0, s16 p1, u8 p2)) +{ + s16 r6; + u16 *hOffsets; + s32 stageTime; + s32 stageTime2; + s16 i; + s16 r4; + s32 sl; + s32 p1_2; + + gFlags |= FLAGS_EXECUTE_HBLANK_COPY; + + gHBlankCopyTarget = (void *)®_BG0HOFS; + gHBlankCopySize = 4; + + gWinRegs[WINREG_WINOUT] = WINOUT_WIN01_ALL; + gBldRegs.bldCnt = (BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG0); + gBldRegs.bldAlpha = BLDALPHA_BLEND(16, 8); + gBldRegs.bldY = 16 * 10; + + hOffsets = gBgOffsetsHBlankPrimary; + + stageTime = (gStageTime & 0x3FF); + stageTime2 = ((gStageTime >> 1) & 0x3FF); + + // p1 *= 2.5 + + p1_2 = p1; + r6 = (DISPLAY_HEIGHT - 1) - ((p1_2 * 2) + (p1_2 >> 1)); + + if (r6 > (DISPLAY_HEIGHT - 1)) { + r6 = (DISPLAY_HEIGHT - 1); + } + + if (p2 != 0) { + s16 r2; + // _0801D2CA + gBldRegs.bldAlpha = BLDALPHA_BLEND(16, (16 - (p1_2 >> 4))); + + for (r4 = 0; r4 < r6; r4++) { + *hOffsets++ = 0; + *hOffsets++ = (-15 - r4) & 0xFF; + } + // _0801D312 + + while (r4 < (DISPLAY_HEIGHT - 1)) { + // _0801D31C + s32 sin = SIN_24_8(CLAMP_SIN_PERIOD(r4 * 16 + stageTime2 + stageTime)) >> 1; + sin++; + sin = (sin)-r4 * 2; + *hOffsets++ = sin & 0xFF; + + if ((r4 - 15) < r6) { + s32 r0 = (1 - r4); + r0 -= (((r4 - r6) - 15) * 8); + *hOffsets++ = r0 & 0xFE; + } else { + // _0801D3A0 + s32 sin = (SIN_24_8(CLAMP_SIN_PERIOD(stageTime + r4 * 4)) >> 1) + 1; + sin = sin - r4; + *hOffsets++ = (stageTime2 + sin) & 0xFF; + } + + r4++; + } + } else { + // _0801D3D6 + gBldRegs.bldAlpha = BLDALPHA_BLEND(16, (16 - (p1_2 >> 5))); + r4 = 0; + + // _0801D3FC + for (; r4 < r6; r4++) { + s32 sin = SIN_24_8(CLAMP_SIN_PERIOD(r4 * 16 + stageTime2 + stageTime)) >> 1; + sin += 1; + sin = sin - r4 * 2; + *hOffsets++ = sin & 0xFF; + + sin = SIN_24_8((CLAMP_SIN_PERIOD(stageTime2 + r4 * 4))) >> 1; + sin++; + sin = (sin)-r4 * 2; + *hOffsets++ = (stageTime2 + sin) & 0xFF; + } + + // _0801D44C + + while (r4 < (DISPLAY_HEIGHT - 1)) { + *hOffsets++ = 0; + + if ((r4 - 15) < r6) { + *hOffsets++ = ((((r4 - r6) - 15) << 3) - (r4 - 1)) & 0xFF; + } else { + *hOffsets++ = ((-r4 + 1) & 0xFF); + } + + r4++; + } + } + // _0801D498 + + if (p0 > 16) { + p0 = 16; + } + // _0801D4A2 + + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + s32 b, g, r; + r = (p0 * gUnknown_080D5C02[1][i][0]) >> 4; + r &= 0x1F; + + g = (p0 * gUnknown_080D5C02[1][i][1]) >> 4; + g &= 0x1F; + + b = (p0 * gUnknown_080D5C02[1][i][2]) >> 4; + b &= 0x1F; + + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(r, g, b)); + } + + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; +} +END_NONMATCH + +// (84.63%) https://decomp.me/scratch/W9B0j +// (82.95%) https://decomp.me/scratch/ZEtCx (newer) +NONMATCH("asm/non_matching/game/sa2/stage/background/StageBgUpdate_Zone6Acts12.inc", void StageBgUpdate_Zone6Acts12(s32 x, s32 UNUSED y)) +{ + u16 r6; + u8 r5; + u8 r2; + Background *bg = &gStageBackgroundsRam.unk0; + + gBgScrollRegs[3][0] = x >> 4; + + r6 = Mod(gStageTime, 0x680); + r5 = 0; + r2 = 8; + + if (r6 > gUnknown_080D5BF0[7]) { + r5 = 7; + } else + while (1) { + u32 r3; + u32 r0 = (r2 << 24); + r0 += (0xFF << 24); + r2 = r0 >> 24; + r3 = r2 << 24; + r0 = r3 >> 24; + if (((signed)r0 >= 0) || (r6 > gUnknown_080D5BF0[r0])) { + break; + } + } + + if (IS_MULTI_PLAYER) { + r5 = 5; + } + + SET_PALETTE_COLOR_BG(0, 0, RGB_BLACK); + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; + + switch (r5) { + case 0: { + if (r6 == 1) { + const Background *bgTemplate = gStageCameraBgTemplates; + memcpy(bg, (bgTemplate + 3), sizeof(Background)); + bg->tilemapId = TM_TECHNO_BASE_BG_PURPLE_GRID; + bg->graphics.dest = (void *)BG_CHAR_ADDR(3); + bg->layoutVram = (void *)BG_SCREEN_ADDR(26); + bg->targetTilesX = 32; + bg->targetTilesY = 32; + DrawBackground(bg); + } else if (r6 > 1) { + // _0801D636 + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[0] |= BGCNT_PRIORITY(3); + gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[3] |= BGCNT_PRIORITY(3); + + r2 = r6; + if (r2 > 63) + r2 = 63; + + r6 /= 4u; + + sub_801D24C(r6, 63 - r2, 0); + } + } break; + + case 1: { + sub_801D24C(15, 0, 0); + } break; + + case 2: { + u32 r0 = (r6 - 577); + r0 <<= 16; + r2 = (r0 << 8) >> 24; + r6 /= 4u; + r6 = (15 - r6); + + if (r6 != 0) { + sub_801D24C(r6, 63 - r2, 1); + } else { + gFlags &= ~FLAGS_EXECUTE_HBLANK_COPY; + gBldRegs.bldCnt = r6; + } + } break; + + case 3: { + s8 i; + gBgCntRegs[0] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[0] |= BGCNT_PRIORITY(3); + gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[3] |= BGCNT_PRIORITY(2); + + for (i = 0; i < 16; i++) { + SET_PALETTE_COLOR_BG(15, i, RGB_BLACK); + } + + // jumps to _0801D8EE for this + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; + } break; + + case 4: { + s8 i; + s32 v; + + if (r6 == 897) { + memcpy(&gStageBackgroundsRam.unk0, &gStageCameraBgTemplates[3], sizeof(Background)); + gStageBackgroundsRam.unk0.tilemapId = TM_TECHNO_BASE_BG_CIRCUIT_MASK; + bg->graphics.dest = (void *)BG_CHAR_ADDR(3); + bg->layoutVram = (void *)BG_SCREEN_ADDR(26); + bg->targetTilesX = 32; + bg->targetTilesY = 32; + DrawBackground(bg); + } else { + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] |= BGCNT_PRIORITY(3); + } + // _0801D76C + + v = r6 - 897; + r6 = v; + + for (i = 0; i < 16; i++) { + u32 red = ((gUnknown_080D5C02[0][i][0] * r6) >> 5) & 0x1F; + u32 green = ((gUnknown_080D5C02[0][i][1] * r6) >> 5) & 0x1F; + u32 blue = ((gUnknown_080D5C02[0][i][2] * r6) >> 5) & 0x1F; + + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); + } + + // jumps to _0801D83C for this + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; + gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; + gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; + } break; + + case 5: { + // _0801D7F8_case5 + s8 i; + + for (i = 0; i < 16; i++) { + u32 red = gUnknown_080D5C02[0][i][0]; + u32 green = gUnknown_080D5C02[0][i][1]; + u32 blue = gUnknown_080D5C02[0][i][2]; + + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); + } + + // _0801D83C + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; + + gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; + gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; + } break; + + case 6: { + s8 i; + s32 v; + + gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; + gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; + + v = r6 - 1441; + r6 = v; + r6 = (31 - r6) / 2u; + + for (i = 0; i < 16; i++) { + u32 red = ((gUnknown_080D5C02[0][i][0] * r6) >> 4) & 0x1F; + u32 green = ((gUnknown_080D5C02[0][i][1] * r6) >> 4) & 0x1F; + u32 blue = ((gUnknown_080D5C02[0][i][2] * r6) >> 4) & 0x1F; + + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); + } + + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; + } break; + + case 7: { + s8 i; + for (i = 0; i < 16; i++) { + SET_PALETTE_COLOR_BG(15, i, RGB_BLACK); + } + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; + gDispCnt &= ~(DISPCNT_BG0_ON); + } break; + } +} +END_NONMATCH diff --git a/src/game/sa2/stage/backgrounds/zone_6_boss.inc.c b/src/game/sa2/stage/backgrounds/zone_6_boss.inc.c new file mode 100644 index 000000000..0387d5da7 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_6_boss.inc.c @@ -0,0 +1,12 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +void StageBgUpdate_Zone6ActBoss(UNUSED s32 a, UNUSED s32 b) +{ + gBgCntRegs[0] |= BGCNT_PRIORITY(3); + gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[3] |= BGCNT_PRIORITY(2); + gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; + gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; +} diff --git a/src/game/sa2/stage/backgrounds/zone_7.inc.c b/src/game/sa2/stage/backgrounds/zone_7.inc.c new file mode 100644 index 000000000..028063883 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_7.inc.c @@ -0,0 +1,39 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +void StageBgUpdate_Zone7Acts12(s32 x, s32 y) +{ + u32 act = !!(gCurrentLevel ^ (LEVEL_INDEX(ZONE_7, ACT_1))); + u32 bgId = 0; + u8 regionId = 0; + + if (x >= sZone7BgTransitionRegions[act][regionId]) { + while (TRUE) { + if (++regionId >= NUM_ZONE7_BG_TRANSITION_POSITIONS) { + break; + } + if (x < sZone7BgTransitionRegions[act][regionId]) { + bgId = regionId % 2; + break; + } + }; + }; + + if (bgId == 0) { + Zone7BgUpdate_Inside(x, y); + } else { + Zone7BgUpdate_Outside(x, y); + } + + gPlayer.unk99[15] = bgId; +} + +void StageBgUpdate_Zone7ActBoss(UNUSED s32 x, UNUSED s32 y) +{ + if (!PLAYER_IS_ALIVE) { + gStageTime--; + } + + Zone7BgUpdate_Inside(gStageTime, 945); +} diff --git a/src/game/sa2/stage/backgrounds/zone_7_init.inc.c b/src/game/sa2/stage/backgrounds/zone_7_init.inc.c new file mode 100644 index 000000000..e92669397 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_7_init.inc.c @@ -0,0 +1,316 @@ +#include "trig.h" + +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +const s16 gUnknown_080D5C62[8][2] = { + { -Q_8_8(3.00), -Q_8_8(0.25) }, // + { -Q_8_8(1.50), +Q_8_8(0.00) }, // + + { -Q_8_8(3.00), -Q_8_8(0.25) }, // + { -Q_8_8(1.00), -Q_8_8(0.0859375) }, // + + { -Q_8_8(3.00), -Q_8_8(0.25) }, // + { -Q_8_8(1.50), +Q_8_8(0.00) }, // + + { -Q_8_8(3.00), -Q_8_8(0.25) }, // + { -Q_8_8(0.75), -Q_8_8(0.125) }, // +}; + +static const ColorRaw sPalette_Zone7BgCeiling[] = INCPAL("graphics/sa2/zone_7_bg_ceiling.pal"); + +void CreateStageBg_Zone7(void) +{ + Background *bg = &gStageBackgroundsRam.unk0; + const Background *src; + gDispCnt = DISPCNT_OBJ_ON | DISPCNT_BG2_ON | DISPCNT_BG1_ON | DISPCNT_OBJ_1D_MAP | DISPCNT_MODE_0; + + gBgCntRegs[0] = (BGCNT_TXT256x256 | BGCNT_SCREENBASE(22) | BGCNT_16COLOR | BGCNT_PRIORITY(15)); + + src = gStageCameraBgTemplates; + memcpy(bg, &src[3], sizeof(Background)); + + bg->tilemapId = TM_UNK_SPACE_BG; + bg->graphics.dest = (void *)BG_SCREEN_ADDR(24); + bg->layoutVram = (void *)BG_SCREEN_ADDR(22); + bg->targetTilesX = 32; + bg->targetTilesY = 20; + DrawBackground(bg); + + gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[3] |= BGCNT_PRIORITY(3); + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 0; +} + +// (98.52%) https://decomp.me/scratch/DUPkY +// (99.82%) https://decomp.me/scratch/pfVTf (fake match) +NONMATCH("asm/non_matching/game/sa2/stage/background/Zone7BgUpdate_Inside.inc", void Zone7BgUpdate_Inside(s32 x, s32 y)) +{ + u16 *dst; + s32 someX; + s32 lineY; + s32 ip; + u8 j; + u8 r1; + u8 r2; + u8 r5; + + if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && (gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT)) { + if (gBgScrollRegs[3][0] == 0) + gBgScrollRegs[3][0] = x; + + gBgScrollRegs[3][0] += I(gPlayer.qSpeedGround); + + x = gBgScrollRegs[3][0]; + } + + gDispCnt &= ~DISPCNT_BG0_ON; + gDispCnt |= DISPCNT_BG3_ON; + + gFlags |= FLAGS_EXECUTE_HBLANK_COPY; + + gHBlankCopyTarget = (void *)®_BG3HOFS; + gHBlankCopySize = 4; + + dst = (u16 *)gBgOffsetsHBlankPrimary; + +#ifndef NON_MATCHING + // Why call Div without using its return value? + someX = Div(x * 42, 400); +#endif + + // Move BG3 to the "ceiling" for the first 40 lines + for (lineY = 0; lineY < 40; lineY++) { + *dst++ = 8; + *dst++ = 16; + } + + // ip = Div(25*x, 400); + ip = Div(25 * x, 400) & 0xFF; + + for (lineY = 0; lineY < 119; lineY++) { + *dst++ = ip; + *dst++ = 17; + } + + // _0801DAA6 + // Draw the small, green-shining, moving pillars + // NOTE: j stored in *sp + j = 0; + do { + ip = (((gStageTime + x) / 8)) & 0xFF; + + r5 = (((100 * j) + 64) - (y >> 4)); + if (r5 < 240) { + // __0801DACA + if (r5 > 80) { + dst = gBgOffsetsHBlankPrimary; + r1 = ((r5 - 80) >> 4); + dst += (r5 - r1) << 1; + + lineY = r5; + for (r2 = 0; ((lineY < r1 + 160) && (r2 < r1)); lineY++, r2++) { + *dst++ = 0; + *dst++ = 208 - r5; + } + } + // _0801DB1C + dst = gBgOffsetsHBlankPrimary; + dst = ((void *)dst) + (r5 * 4); + + for (lineY = r5, r2 = 0; ((lineY < DISPLAY_HEIGHT) && (r2 < 16)); lineY++, r2++) { + *dst++ = ip; + *dst++ = (240 - r5); + } + + if (lineY < 80) { + s32 r0 = (80 - lineY) >> 4; + r1 = r0; + + for (r2 = 0; ((lineY < DISPLAY_HEIGHT) && (r2 < r1)); lineY++, r2++) { + *dst++ = 0; + *dst++ = (184 - r5); + } + } + } else { + // _0801DBAC + dst = gBgOffsetsHBlankPrimary; + + for (lineY = 255 - r5; lineY < 16; lineY++) { + *dst++ = ip; + *dst++ = 495 - r5; + } + // _0801DBD2 + + for (r2 = 0; r2 < 4; r2++) { + *dst++ = 0; + *dst++ = 439 - r5; + } + } + } while (++j < 2); // _0801DBEE == continue of (j < 2) + // _0801DBFA + + ip = ((gStageTime + x) / 2) & 0xFF; + + { + r5 = -(y >> 1); + + if (r5 < 224) { + u8 val; + if (r5 > 80) { + dst = gBgOffsetsHBlankPrimary; + + val = ((r5 - 80) >> 4); + dst += (r5 - val) << 1; + + lineY = r5, r2 = 0; + for (; ((lineY < (160 + val)) && (r2 < val)); lineY++, r2++) { + *dst++ = 0; + *dst++ = 208 - r5; + } + } + // _0801DC66 + dst = gBgOffsetsHBlankPrimary; + dst = ((void *)dst) + (r5 * 4); + + for (lineY = r5, r2 = 0; ((lineY < DISPLAY_HEIGHT) && (r2 < 32)); lineY++, r2++) { + *dst++ = ip; + *dst++ = 208 - r5; + } + + if (lineY < 80) { + for (r1 = (80 - lineY) >> 4, r2 = 0; ((lineY < 160) && (r2 < r1)); lineY++, r2++) { + *dst++ = 0; + *dst++ = 168 - r5; + } + } + } else { + // _0801DCDC + dst = gBgOffsetsHBlankPrimary; + + for (lineY = 255 - r5; lineY < 32; lineY++) { + *dst++ = ip; + *dst++ = 463 - r5; + } + + for (r2 = 0; r2 < 4; r2++) { + *dst++ = 0; + *dst++ = 423 - r5; + } + } +// _0801DD1A +#if 001 + { // Draw the "ceiling" movement + u32 new_r1 = (x >> 4) << 16; + const ColorRaw *src; + ColorRaw *dst; + s32 r6 = 0x7; + src = sPalette_Zone7BgCeiling; + dst = gBgPalette; + dst += 209; + new_r1 >>= 16; + + for (lineY = 0; lineY < 8; new_r1--, lineY++) { + s32 index = (new_r1 & r6) + 1; + *dst++ = src[index]; + } + } +#else + { // Draw the "ceiling" movement + for (lineY = 0; lineY < 8; lineY++) { + SET_PALETTE_COLOR_BG(13, lineY + 1, sPalette_Zone7BgCeiling[((x >> 4) & 0x7) + 1]); + } + } +#endif + } + + gFlags = gFlags | FLAGS_UPDATE_BACKGROUND_PALETTES; +} +END_NONMATCH + +void Zone7BgUpdate_Outside(s32 x, s32 y) +{ + u16 *cursor; + u8 frameCount; + int_vcount i; + u16 sp[32]; + u32 stageTime; + + gDispCnt &= ~DISPCNT_BG3_ON; + gDispCnt |= DISPCNT_BG0_ON; + + gFlags |= FLAGS_EXECUTE_HBLANK_COPY; + + gHBlankCopyTarget = (void *)®_BG0HOFS; + gHBlankCopySize = 2; + cursor = (u16 *)gBgOffsetsHBlankPrimary; + + stageTime = gStageTime; + frameCount = ((stageTime >> 3) & 0x1F); + if (frameCount >= 16) { + // Likely some sort of debug log +#ifndef NON_MATCHING + register u32 r1 asm("r1"); + register u8 r0 asm("r0"); + r0 = 31 - frameCount; + asm("" ::"r"(r0)); + r1 = r0; + asm("" ::"r"(r1)); +#endif + } + + for (i = 0; i < ARRAY_COUNT(sp); i++) { + sp[i] = 0xFF & (I(gUnknown_080D5C62[(i & 0x7)][0] * stageTime) + gUnknown_080D5C62[(i & 0x7)][1]); + } + + { + u16 sinVal, value; + u32 cosVal; + u32 scrollSpeed = (Q(80.5) - 1); + +#if !WIDESCREEN_HACK + for (i = 0; i < DISPLAY_HEIGHT / 2; i++) { + sinVal = SIN_24_8(((gStageTime * 4) + i * 2) & ONE_CYCLE) >> 3; + value = (COS_24_8(((i * scrollSpeed) >> 5) & ONE_CYCLE) >> 4) + sinVal; + value = (value + sp[(i & 0x1F)]) & 0xFF; + *cursor++ = value; + } + + for (; i < DISPLAY_HEIGHT - 1; i++) { + sinVal = SIN_24_8(((gStageTime << 2) + i * 2) & ONE_CYCLE) >> 3; + cosVal = (COS_24_8((((DISPLAY_HEIGHT - i) * scrollSpeed) >> 5) & ONE_CYCLE) >> 4); + value = cosVal + sinVal; + value = (value + sp[(i & 0x1F)]) & 0xFF; + *cursor++ = value; + } +#else + gHBlankCopySize = 2 * sizeof(u16); + + for (i = 0; i < DISPLAY_HEIGHT; i++) { + const s32 gbaHLines = 160; + s32 originalLine = (s32)(((float)i / (float)DISPLAY_HEIGHT) * (float)gbaHLines); + + if (originalLine < 80) { + sinVal = SIN_24_8(((gStageTime * 4) + originalLine * 2) & ONE_CYCLE) >> 3; + value = (COS_24_8(((originalLine * scrollSpeed) >> 5) & ONE_CYCLE) >> 4) + sinVal; + value = (value + sp[(originalLine & 0x1F)]) & 0xFF; + *cursor++ = value; + *cursor++ = originalLine - i; + } else if (originalLine < gbaHLines) { + sinVal = SIN_24_8(((gStageTime << 2) + originalLine * 2) & ONE_CYCLE) >> 3; + cosVal = (COS_24_8((((gbaHLines - originalLine) * scrollSpeed) >> 5) & ONE_CYCLE) >> 4); + value = cosVal + sinVal; + value = (value + sp[(originalLine & 0x1F)]) & 0xFF; + *cursor++ = value; + *cursor++ = originalLine - i; + } + } +#endif + } +} diff --git a/src/game/sa2/stage/backgrounds/zone_8.inc.c b/src/game/sa2/stage/backgrounds/zone_8.inc.c new file mode 100644 index 000000000..3f1a09f53 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_8.inc.c @@ -0,0 +1,71 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +#include "constants/sa2/tilemaps.h" +#include "constants/sa2/zones.h" +#include "constants/sa2/move_states.h" + +#define NUM_ZONE7_BG_TRANSITION_POSITIONS 8 + +const u16 sZone7BgTransitionRegions[2][NUM_ZONE7_BG_TRANSITION_POSITIONS] = { + { 697, 1849, 8857, 11832, 18553, 22009, 25369, 27673 }, // ACT 1 + { 1344, 2616, 9432, 15192, 18552, 19892, 23158, 25848 }, // ACT 2 +}; + +const ColorRaw sExtraBossPalette[PALETTE_LEN_4BPP] = INCPAL("graphics/sa2/boss_9_normal.pal"); + +void CreateStageBg_ZoneFinal_0(void) +{ + Background *bgDst; + const Background *bgSrc; + u8 i; + + gDispCnt = (DISPCNT_OBJ_ON | DISPCNT_BG0_ON | DISPCNT_OBJ_1D_MAP | DISPCNT_MODE_1); + INIT_BG_SPRITES_LAYER_32(2); + + bgDst = &gStageBackgroundsRam.unk80; + gBgCntRegs[2] = BGCNT_SCREENBASE(26) | BGCNT_256COLOR | BGCNT_CHARBASE(2) | BGCNT_PRIORITY(1); + bgSrc = gStageCameraBgTemplates; + memcpy(bgDst, &bgSrc[2], sizeof(Background)); + + bgDst->tilemapId = TM_EXTRA_BOSS_COCKPIT; + bgDst->graphics.dest = (void *)BG_CHAR_ADDR(2); + + // TODO: Should this be a different macro? + bgDst->layoutVram = (void *)BG_TILE_ADDR(416); + bgDst->targetTilesX = 10; + bgDst->targetTilesY = 9; + bgDst->flags |= BACKGROUND_FLAG_4; + DrawBackground(bgDst); + + bgDst = &gStageBackgroundsRam.unk0; + gBgCntRegs[0] = BGCNT_SCREENBASE(30) | BGCNT_16COLOR | BGCNT_CHARBASE(1) | BGCNT_PRIORITY(3); + + memcpy(bgDst, &bgSrc[3], sizeof(Background)); + + bgDst->tilemapId = TM_EXTRA_BOSS_BACKGROUND; + bgDst->graphics.dest = (void *)BG_CHAR_ADDR(1); + + // TODO: Should this be a different macro? + bgDst->layoutVram = (void *)BG_TILE_ADDR(480); + bgDst->targetTilesX = 32; + bgDst->targetTilesY = 20; + bgDst->flags = BACKGROUND_FLAGS_BG_ID(0); + DrawBackground(bgDst); + + gBgScrollRegs[0][0] = 0; + gBgScrollRegs[0][1] = 0; + gBgScrollRegs[1][0] = 0; + gBgScrollRegs[1][1] = 0; + gBgScrollRegs[2][0] = 0; + gBgScrollRegs[2][1] = 0; + gBgScrollRegs[3][0] = 0; + gBgScrollRegs[3][1] = 0; + + for (i = 0; i < ARRAY_COUNT(sExtraBossPalette); i++) { + SET_PALETTE_COLOR_BG(0, i, sExtraBossPalette[i]); + } + + gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; +} diff --git a/src/game/sa2/stage/backgrounds/zone_extra_boss.inc.c b/src/game/sa2/stage/backgrounds/zone_extra_boss.inc.c new file mode 100644 index 000000000..444b2d4ee --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_extra_boss.inc.c @@ -0,0 +1,29 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" +#include "game/sa2/stage/bosses/common.h" +#include "game/sa2/stage/bosses/boss_9.h" + +void StageBgUpdate_ZoneFinalActTA53(UNUSED s32 a, UNUSED s32 b) +{ + u32 aBool = FALSE; + int_vcount y; + + if (gActiveBossTask != NULL) { + TA53Boss *boss = TASK_DATA(gActiveBossTask); + aBool = boss->unk10 & 0x1; + } + + if (aBool) { + u16 *offset; + gFlags |= FLAGS_EXECUTE_HBLANK_COPY; + gHBlankCopyTarget = (void *)®_BG1HOFS; + gHBlankCopySize = 2; + + offset = (u16 *)gBgOffsetsHBlankPrimary; + for (y = 0; y < DISPLAY_HEIGHT - 1; y++) { + s16 val = SIN(((y + gStageTime) * 40) & ONE_CYCLE) >> 12; + *offset++ = val; + } + } +} diff --git a/src/game/sa2/stage/backgrounds/zone_final_boss.inc.c b/src/game/sa2/stage/backgrounds/zone_final_boss.inc.c new file mode 100644 index 000000000..ec1467309 --- /dev/null +++ b/src/game/sa2/stage/backgrounds/zone_final_boss.inc.c @@ -0,0 +1,13 @@ +#include "game/globals.h" +#include "game/shared/stage/camera.h" +#include "game/shared/stage/player.h" + +void StageBgUpdate_ZoneFinalActXX(UNUSED s32 x, UNUSED s32 y) +{ + if (!PLAYER_IS_ALIVE) { + gStageTime--; + } + + gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_BgUpdateZoneFinalActXX; + gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; +} diff --git a/src/game/shared/stage/camera.c b/src/game/shared/stage/camera.c index 411b4d473..646c3365d 100644 --- a/src/game/shared/stage/camera.c +++ b/src/game/shared/stage/camera.c @@ -29,16 +29,6 @@ #define BOSS_CAM_FRAME_DELTA_PIXELS 5 -#if (GAME == GAME_SA2) -#if !PORTABLE -#define USE_BOSS_BG_IN_ZONE_6_ACTS FALSE -#else -// The default flickering is very strong, so we disable it. -// TODO: Add a global option, so players can decide to use the original effect if they want to. -#define USE_BOSS_BG_IN_ZONE_6_ACTS TRUE -#endif -#endif - // NOTE: // unk8 is a regular integer in SA1, but Q_24_8 in SA2 #if (GAME == GAME_SA1) @@ -62,16 +52,12 @@ #define CAMBG_BACK_B_LAYER 3 #if !WIDESCREEN_HACK -#define SCREENBASE_SKY_CANYON_CLOUDS 27 -#define CAM_SCREENBASE_BACK_A 28 -#define CAM_SCREENBASE_BACK_B 29 -#define CAM_SCREENBASE_BACK_C 26 -#define CAM_SCREENBASE_MAP_FRONT 30 -#define CAM_SCREENBASE_MAP_BACK 31 - +#define CAM_SCREENBASE_BACK_A 28 +#define CAM_SCREENBASE_BACK_B 29 +#define CAM_SCREENBASE_BACK_C 26 +#define CAM_SCREENBASE_MAP_FRONT 30 +#define CAM_SCREENBASE_MAP_BACK 31 #else -#define SCREENBASE_SKY_CANYON_CLOUDS 27 - #define CAM_SCREENBASE_BACK_A 48 #define CAM_SCREENBASE_BACK_B 50 #define CAM_SCREENBASE_BACK_C 58 @@ -313,13 +299,6 @@ const TileInfoFirework gTileInfoZone3Fireworks[2] = { [1] = { SA1_ANIM_FIREWORKS_SMALL, 0, MAX_TILES(SA1_ANIM_FIREWORKS_SMALL) }, }; #elif (GAME == GAME_SA2) -void sub_801E3F0(void); -void HBlankCB_801E434(int_vcount vcount); -void HBlankCB_801E454(int_vcount vcount); -void nullsub_801E494(void); -void HBlankCB_BgUpdateZone5ActBoss(int_vcount vcount); -void HBlankCB_BgUpdateZoneFinalActXX(int_vcount vcount); - // SA2 Zone specific backgrounds void CreateStageBg_Zone1(void); void StageBgUpdate_Zone1Acts12(s32 a, s32 b); @@ -720,14 +699,32 @@ void UpdateCamera(void) Player *player = &gPlayer; struct Camera *camera = &gCamera; s32 newX, newY; + +#if DEBUG + if (gInput & L_BUTTON) { + s32 speed = Q(10); + if (gInput & DPAD_DOWN) + gPlayer.qWorldY += speed; + if (gInput & DPAD_UP) + gPlayer.qWorldY -= speed; + if (gInput & DPAD_RIGHT) + gPlayer.qWorldX += speed; + if (gInput & DPAD_LEFT) + gPlayer.qWorldX -= speed; + } +#endif + newX = camera->x; newY = camera->y; +#if (GAME == GAME_SA2) camera->dx = camera->x; camera->dy = camera->y; +#endif newX = CLAMP(newX, camera->minX, camera->maxX - (DISPLAY_WIDTH + 1)); newY = CLAMP(newY, camera->minY, camera->maxY - (DISPLAY_HEIGHT + 1)); +#if (GAME == GAME_SA2) #ifndef COLLECT_RINGS_ROM if (IS_BOSS_STAGE(gCurrentLevel)) { s32 delta, playerY; @@ -738,11 +735,11 @@ void UpdateCamera(void) return; } - if (gCurrentLevel == LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)) { + if (IS_EXTRA_STAGE(gCurrentLevel)) { SuperSonicGetPos(&player->qWorldX, &player->qWorldY); } - camera->unk10 += BOSS_CAM_FRAME_DELTA_PIXELS; + camera->SA2_LABEL(unk10) += BOSS_CAM_FRAME_DELTA_PIXELS; newX += BOSS_CAM_FRAME_DELTA_PIXELS; // Most TASes were written with the expection that @@ -751,11 +748,12 @@ void UpdateCamera(void) // So we need to emulate that behaviour on some specific // levels #if TAS_TESTING && TAS_TESTING_WIDESCREEN_HACK && DISPLAY_WIDTH > 240 - if (newX + (DISPLAY_WIDTH_FOR_BOSS_TAS + 1) < I(player->qWorldX)) { + if (newX + (DISPLAY_WIDTH_FOR_BOSS_TAS + 1) < I(player->qWorldX)) #else - if (newX + (DISPLAY_CENTER_X + 1) < I(player->qWorldX)) { + if (newX + (DISPLAY_CENTER_X + 1) < I(player->qWorldX)) #endif - if ((camera->unk10 + DISPLAY_CENTER_Y) > newX) { + { + if ((camera->SA2_LABEL(unk10) + DISPLAY_CENTER_Y) > newX) { s32 playerScreenX = I(player->qWorldX); #if TAS_TESTING && TAS_TESTING_WIDESCREEN_HACK && DISPLAY_WIDTH > 240 playerScreenX -= DISPLAY_WIDTH_FOR_BOSS_TAS; @@ -764,7 +762,7 @@ void UpdateCamera(void) #endif camera->shiftX = playerScreenX - newX; } else { - newX = (camera->unk10 + DISPLAY_CENTER_Y); + newX = (camera->SA2_LABEL(unk10) + DISPLAY_CENTER_Y); camera->shiftX = 0; } } else { @@ -772,15 +770,15 @@ void UpdateCamera(void) if ((newX + 96) > I(player->qWorldX)) { newX = I(player->qWorldX); newX -= 96; - if (newX < camera->unk10) { - newX = camera->unk10; + if (newX < camera->SA2_LABEL(unk10)) { + newX = camera->SA2_LABEL(unk10); } } } playerY = I(player->qWorldY); delta = playerY - newY; - if (gCurrentLevel == LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)) { + if (IS_EXTRA_STAGE(gCurrentLevel)) { if (delta <= 48) { s32 temp = newY - 48; newY = delta + temp; @@ -806,79 +804,125 @@ void UpdateCamera(void) newX += camera->shakeOffsetX; newY += camera->shakeOffsetY; - } else + } else // if !IS_BOSS_STAGE(gCurrentLevel) -> +#endif #endif { - if (camera->unk40 != 0) { - camera->unk40--; + if (camera->SA2_LABEL(unk40) != 0) { + camera->SA2_LABEL(unk40)--; } else { - if (!(camera->unk50 & 1)) { - s16 airSpeedX = player->qSpeedAirX; - camera->unk10 = I(player->qWorldX) + camera->shiftX - DISPLAY_CENTER_X; - camera->SA2_LABEL(unk56) = (airSpeedX + (camera->SA2_LABEL(unk56) * 15)) >> 4; - camera->unk10 += (camera->SA2_LABEL(unk56) >> 5); - } - if (!(camera->unk50 & 2)) { - s32 unk64 = camera->unk64; - s32 temp8 = player->spriteOffsetY - 4; - if (GRAVITY_IS_INVERTED) { - temp8 = -temp8; + s32 unk64, temp8; +#if (GAME == GAME_SA1) + if (IS_MULTI_PLAYER) { + MultiplayerPlayer *mpp = TASK_DATA(gMultiplayerPlayerTasks[camera->spectatorTarget]); + + if (!(camera->SA2_LABEL(unk50) & 0x1)) { + camera->SA2_LABEL(unk10) = (mpp->pos.x + camera->shiftX) - DISPLAY_CENTER_X; } - if (unk64 != temp8) { - if (unk64 < temp8) { - unk64 += 5; - if (unk64 > temp8) { - unk64 = temp8; - } - } else { - unk64 -= 5; - if (unk64 < temp8) { - unk64 = temp8; - } + if (!(camera->SA2_LABEL(unk50) & 2)) { + unk64 = camera->SA2_LABEL(unk64); + temp8 = mpp->unk58[0] - 4; + if (GRAVITY_IS_INVERTED) { + temp8 = -temp8; } - camera->unk64 = unk64; + + if (unk64 != temp8) { + if (unk64 < temp8) { + unk64 += 5; + if (unk64 > temp8) { + unk64 = temp8; + } + } else { + unk64 -= 5; + if (unk64 < temp8) { + unk64 = temp8; + } + } + camera->SA2_LABEL(unk64) = unk64; + } + + camera->SA2_LABEL(unk14) = ((mpp->pos.y) + camera->shiftY) - DISPLAY_CENTER_Y + camera->SA2_LABEL(unk4C) + unk64; + } + } else +#endif + { + if (!(camera->SA2_LABEL(unk50) & 1)) { + s16 airSpeedX = player->qSpeedAirX; + camera->SA2_LABEL(unk10) = I(player->qWorldX) + camera->shiftX - DISPLAY_CENTER_X; +#if (GAME == GAME_SA2) + camera->SA2_LABEL(unk56) = (airSpeedX + (camera->SA2_LABEL(unk56) * 15)) >> 4; + camera->SA2_LABEL(unk10) += (camera->SA2_LABEL(unk56) >> 5); +#endif } - camera->unk14 = I(player->qWorldY) + camera->shiftY - DISPLAY_CENTER_Y + camera->unk4C + unk64; + if (!(camera->SA2_LABEL(unk50) & 2)) { + unk64 = camera->SA2_LABEL(unk64); + temp8 = player->spriteOffsetY - 4; + if (GRAVITY_IS_INVERTED) { + temp8 = -temp8; + } + + if (unk64 != temp8) { + if (unk64 < temp8) { + unk64 += 5; + if (unk64 > temp8) { + unk64 = temp8; + } + } else { + unk64 -= 5; + if (unk64 < temp8) { + unk64 = temp8; + } + } + camera->SA2_LABEL(unk64) = unk64; + } + + camera->SA2_LABEL(unk14) = I(player->qWorldY) + camera->shiftY - DISPLAY_CENTER_Y + camera->SA2_LABEL(unk4C) + unk64; + } } } - if ((camera->unk10 - newX) > camera->unk44) { - s32 temp = camera->unk10 - newX - camera->unk44; - s32 temp2 = I(camera->unk8); + if ((camera->SA2_LABEL(unk10) - newX) > camera->SA2_LABEL(unk44)) { + s32 temp = camera->SA2_LABEL(unk10) - newX - camera->SA2_LABEL(unk44); + s32 temp2 = CAM_UNK8_INT(camera->SA2_LABEL(unk8)); if (temp2 > temp) { temp2 = temp; } newX += temp2; - } else if ((camera->unk10 - newX) < -camera->unk44) { - s32 temp = (camera->unk10 - newX) + camera->unk44; - s32 temp2 = -I(camera->unk8); + } else if ((camera->SA2_LABEL(unk10) - newX) < -camera->SA2_LABEL(unk44)) { + s32 temp = (camera->SA2_LABEL(unk10) - newX) + camera->SA2_LABEL(unk44); + s32 temp2 = -CAM_UNK8_INT(camera->SA2_LABEL(unk8)); if (temp2 < temp) { temp2 = temp; } newX += temp2; } - newX = CLAMP(newX, camera->minX, camera->maxX - DISPLAY_WIDTH); - if (camera->unk8 < Q(16)) { - camera->unk8 += Q(0.125); +#if (GAME == GAME_SA2) + if (camera->SA2_LABEL(unk8) < Q(16)) { + camera->SA2_LABEL(unk8) += Q(0.125); } +#endif if ((player->moveState & MOVESTATE_IN_AIR) && (player->character != CHARACTER_KNUCKLES || player->SA2_LABEL(unk61) != 9)) { - camera->unk48 += 4; - camera->unk48 = MIN(camera->unk48, 24); + camera->SA2_LABEL(unk48) += 4; + camera->SA2_LABEL(unk48) = MIN(camera->SA2_LABEL(unk48), 24); } else { - camera->unk48 -= 4; - camera->unk48 = MAX(camera->unk48, 0); + camera->SA2_LABEL(unk48) -= 4; + camera->SA2_LABEL(unk48) = MAX(camera->SA2_LABEL(unk48), 0); } - if ((camera->unk14 - newY) > camera->unk48) { - newY += (camera->unkC > ((camera->unk14 - newY) - camera->unk48)) ? ((camera->unk14 - newY) - camera->unk48) : camera->unkC; - } else if ((camera->unk14 - newY) < -(camera->unk48)) { - newY += (-camera->unkC < (camera->unk14 - newY) + camera->unk48) ? (camera->unk14 - newY) + camera->unk48 : -camera->unkC; + if ((camera->SA2_LABEL(unk14) - newY) > camera->SA2_LABEL(unk48)) { + newY += (camera->SA2_LABEL(unkC) > ((camera->SA2_LABEL(unk14) - newY) - camera->SA2_LABEL(unk48))) + ? ((camera->SA2_LABEL(unk14) - newY) - camera->SA2_LABEL(unk48)) + : camera->SA2_LABEL(unkC); + } else if ((camera->SA2_LABEL(unk14) - newY) < -(camera->SA2_LABEL(unk48))) { + newY += (-camera->SA2_LABEL(unkC) < (camera->SA2_LABEL(unk14) - newY) + camera->SA2_LABEL(unk48)) + ? (camera->SA2_LABEL(unk14) - newY) + camera->SA2_LABEL(unk48) + : -camera->SA2_LABEL(unkC); } newY = CLAMP(newY, camera->minY, camera->maxY - DISPLAY_HEIGHT); @@ -890,11 +934,13 @@ void UpdateCamera(void) newY = newY + camera->shakeOffsetY; } + // TODO: CAMERA_SET_POS macro camera->x = newX; camera->y = newY; - +#if (GAME == GAME_SA2) camera->dx -= newX; camera->dy -= newY; +#endif RenderMetatileLayers(newX, newY); @@ -905,11 +951,38 @@ void UpdateCamera(void) void RenderMetatileLayers(s32 x, s32 y) { + Background *layer; +#if (GAME == GAME_SA1) + if (IS_EXTRA_STAGE(gCurrentLevel)) { + s32 scrollX = (x + gStageTime * 8); + // 2688(0xA80) = + // 3072 - 600 + // Moon Zone Pixel Width - (4 * Metatile_Width) + const s32 scrollMaxX = (28 * 96); + + if (scrollX - 72 >= scrollMaxX) { + scrollX -= 72; + scrollX = Mod(scrollX, scrollMaxX) + 72; + } + + x = scrollX; + if (IS_EXTRA_STAGE(gCurrentLevel)) { + layer = &gStageBackgroundsRam.unk80; + gBgScrollRegs[0][0] = x % 8u; + gBgScrollRegs[0][1] = y % 8u; + layer->scrollX = x; + layer->scrollY = y; + DrawBackground(layer); + return; + } + } +#endif + #ifndef COLLECT_RINGS_ROM if (!IS_EXTRA_STAGE(gCurrentLevel)) #endif { - Background *layer = &gStageBackgroundsRam.unk40; + layer = &gStageBackgroundsRam.unk40; gBgScrollRegs[1][0] = x % 8u; gBgScrollRegs[1][1] = y % 8u; layer->scrollX = x; @@ -926,1429 +999,25 @@ void RenderMetatileLayers(s32 x, s32 y) } } -/************************************ ZONE 1 ************************************/ - -void CreateStageBg_Zone1(void) -{ - Background *background = &gStageBackgroundsRam.unk0; - gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); - +#if (GAME == GAME_SA1) +#include "../src/game/sa1/stage/backgrounds/zone_1.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_2_interior.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_3.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_4.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_6.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_7_act_2.inc.c" +#elif (GAME == GAME_SA2) +#include "../src/game/sa2/stage/backgrounds/zone_1.inc.c" #ifndef COLLECT_RINGS_ROM - if (gGameMode != GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { - const Background *templates = gStageCameraBgTemplates; - memcpy(background, &templates[3], sizeof(Background)); - - background->tilemapId = TM_STAGE_1_BG_0_COPY; - background->graphics.dest = (void *)BG_SCREEN_ADDR(24); - background->layoutVram = (void *)BG_SCREEN_ADDR(27); - - background->targetTilesX = 256 / TILE_WIDTH; - background->targetTilesY = 256 / TILE_WIDTH; - } else +#include "../src/game/sa2/stage/backgrounds/zone_2.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_3.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_4.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_5.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_6.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_7_init.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_8.inc.c" #endif - { - const Background *templates = gStageCameraBgTemplates; - memcpy(background, &templates[3], sizeof(Background)); - background->tilemapId = TM_LEVEL_BG(LEVEL_INDEX(ZONE_1, ACT_1)); - - background->graphics.dest = (void *)BG_SCREEN_ADDR(24); - background->layoutVram = (void *)BG_SCREEN_ADDR(27); - - background->targetTilesX = 256 / TILE_WIDTH; - background->targetTilesY = 240 / TILE_WIDTH; - } - - DrawBackground(background); - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 0; -} - -#ifndef COLLECT_RINGS_ROM - -void StageBgUpdate_Zone1Acts12(s32 UNUSED a, s32 UNUSED b) -{ - s32 i; - s32 initial1, initial2; - s16 camY; - u16 bgScroll; - u16 *cursor; - - if (gGameMode != GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { - if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT) { - s32 temp, val; - temp = (gPlayer.moveState & MOVESTATE_4000000) ? 7 : 0xF; - - val = gBgScrollRegs[0][0]; - if ((gStageTime & temp) == temp) { - val++; - } - gBgScrollRegs[0][0] = val; - gBgScrollRegs[0][0] &= 0xFF; - } else { - gBgScrollRegs[0][0] = gCamera.x >> 6; - gBgScrollRegs[0][0] &= 0xFF; - } - - gBgScrollRegs[0][1] = gCamera.y >> 9; - gFlags |= FLAGS_EXECUTE_HBLANK_COPY; - gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; - gHBlankCopySize = 4; - cursor = gBgOffsetsHBlankPrimary; - initial1 = 0; - - if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT) { - s32 temp, val; - temp = (gPlayer.moveState & MOVESTATE_4000000) ? 0xF : 0x1F; - - val = gBgScrollRegs[3][0]; - if ((gStageTime & temp) == temp) { - val++; - } - gBgScrollRegs[3][0] = val; - gBgScrollRegs[3][0] &= 0xFF; - bgScroll = gBgScrollRegs[3][0]; - } else { - bgScroll = gCamera.x >> 7; - gBgScrollRegs[3][0] = bgScroll; - } - - camY = gCamera.y >> 8; - initial2 = 0; - -#ifdef BUG_FIX - if (cursor != NULL) #endif - { - for (i = 71; i >= 0; i--) { - *cursor++ = initial1; - *cursor++ = initial2; - } - - for (i = 86; i >= 0; i--) { - *cursor++ = bgScroll; - *cursor++ = camY; - } - } - } -} - -/************************************ ZONE 2 ************************************/ - -// (88.05%) https://decomp.me/scratch/ekyaq -// (91.40%) https://decomp.me/scratch/vapLV -// (95.71%) https://decomp.me/scratch/Naixp (more accurate) -NONMATCH("asm/non_matching/game/sa2/stage/background/StageBgUpdate_Zone2Acts12.inc", - void StageBgUpdate_Zone2Acts12(s32 cameraX, s32 cameraY)) -{ - s16 something; - u8 i, j; - s16 camFracY, camFracX; - - u16 *cursor; - s32 x0 = 0; - if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= 7) { - if (gBgScrollRegs[3][0] == 0) { - gBgScrollRegs[3][0] = cameraX; - } - gBgScrollRegs[3][0] += (gPlayer.qSpeedGround >> 8); - cameraX = gBgScrollRegs[3][0]; - } - - if (!IS_SINGLE_PLAYER) { - gBgScrollRegs[3][0] = cameraX >> 4; - camFracY = Div(cameraY, 0x10); - if (camFracY > 0x100) { - camFracY = 0x100; - } - gBgScrollRegs[3][1] = camFracY; - } else { - s32 dt; - - camFracY = Div(cameraY, 0x10); - - // Prevent wrapping of the background map at the bottom of the screen on high cameraY's -#if !WIDESCREEN_HACK - if (camFracY > 0x100) { - camFracY = 0x100; - } -#else - { - // TODO: Use proper maths for max, depending on DISPLAY_HEIGHT instead of a hardcoded value - const u32 max = 153; - - if (camFracY > max) { - camFracY = max; - } - } -#endif - - camFracX = Div(cameraX, 0x69); - if (camFracX > 0x100) { - camFracX = 0x100; - } - - gFlags |= FLAGS_EXECUTE_HBLANK_COPY; - gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; - gHBlankCopySize = sizeof(u16) * 2; - - cursor = gBgOffsetsHBlankPrimary; - dt = gStageTime * 0x18; - - // Sky and Clouds - for (i = 0; i < DISPLAY_HEIGHT - 1; i++) { - if ((u32)((camFracY + i) - 111) < 10) { - camFracX = ((((camFracY + i) - 110) * cameraX) >> 5) & 0xFF; - } else { - camFracX = (camFracY + i) > 120 ? ((cameraX * 10) >> 5) & 0xFF : camFracX; - } - *cursor++ = camFracX; - *cursor++ = camFracY; - if ((camFracY + i) + (SIN(((i * 8) + (camFracY << 3)) & ONE_CYCLE) >> 12) >= 178) { - break; - } - } - - // Red Bottom - something = (cameraX >> 3); - for (j = 0; i < DISPLAY_HEIGHT - 1; i++, j++) { - u16 cursorX, cursorY; - - x0 += 8; - x0 = CLAMP_SIN_PERIOD(x0); - cursorX = camFracX + (SIN(x0) >> 13) + (COS(((gStageTime * 2) + x0) & 0x3FF) >> 11) - + (SIN(CLAMP_SIN_PERIOD(dt + (i * 0x40))) >> 13); - *cursor++ = cursorX; - cursorY = (j / 2) + camFracY + (SIN(x0) >> 12) + (COS(CLAMP_SIN_PERIOD(gStageTime + (i * 8))) >> 10); - *cursor++ = cursorY; - }; - } -} -END_NONMATCH - -// TODO: make this static! -extern const u8 gUnknown_080D5B20[16][3]; - -const u8 gUnknown_080D5B20[16][3] = { - { 14, 0, 1 }, // - { 22, 0, 3 }, // - { 30, 0, 2 }, // - { 38, 0, 1 }, // - { 46, 0, 3 }, // - { 62, 0, 1 }, // - { 70, 0, 2 }, // - { 86, 0, 1 }, // - { 94, 0, 2 }, // - { 126, 0, 1 }, // - { 168, 1, 1 }, // - { 174, 1, 2 }, // - { 182, 2, 3 }, // - { 198, 3, 4 }, // - { 222, 4, 5 }, // - { 255, 5, 6 }, // -}; - -// NOTE: Only values > 105 appear to be used. -const u8 gUnknown_080D5B50[DISPLAY_HEIGHT] = { // 0-94 - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 10, // - 10, 10, 8, 8, 8, 8, // 95-98 - 7, 7, 7, 7, // 99-102 - 6, 6, 6, // 103-104 - /* 105-159 */ - 6, 6, // - 6, 6, 6, // - 5, 5, 5, // - 5, 5, 5, // - 5, 5, 4, // - 4, 4, 4, // - 4, 4, 4, // - 4, 3, 3, // - 3, 3, 3, // - 3, 3, 3, // - 3, 3, 3, // - 3, 3, 3, // - 3, 3, 2, // - 2, 2, 2, // - 2, 2, 2, // - 2, 2, 2, // - 2, 2, 2, // - 2, 2, 2, // - - // Maybe padding? - 0 -}; - -/************************************ ZONE 3 ************************************/ - -static s16 sUnknown_03000408; - -void CreateStageBg_Zone3(void) -{ - Background *background = &gStageBackgroundsRam.unk0; - gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); - - *background = gStageCameraBgTemplates[3]; - - background->tilemapId = TM_MUSIC_PLANT_MOVING_STARS; - background->graphics.dest = (void *)BG_SCREEN_ADDR(24); - background->layoutVram = (void *)BG_SCREEN_ADDR(27); - background->targetTilesX = 0x20; - background->targetTilesY = 0x20; - DrawBackground(background); - - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 0; - gBgScrollRegs[3][0] = 0; - gBgScrollRegs[3][1] = 0; -} - -// (85.02%) https://decomp.me/scratch/Esyzr -#if 01 -NONMATCH("asm/non_matching/game/sa2/stage/background/StageBgUpdate_Zone3Acts12.inc", - void StageBgUpdate_Zone3Acts12(s32 cameraX, s32 cameraY)) -#else -void StageBgUpdate_Zone3Acts12(s32 cameraX, s32 cameraY) -#endif -{ - s16 r6; - u8 i; - u8 sp40; - Vec2_16 sp[16]; - Vec2_16 *cursorStack; - u8 *cursor; - s32 pFlags; -#ifndef NON_MATCHING - register s16 sl asm("sl") = 0; - register u16 *bgBuffer asm("r5") = gBgOffsetsHBlankPrimary; - register s16 camFracY asm("r3") = (Div(cameraY, 60) << 16) >> 16; -#else - s16 sl = 0; - u16 *bgBuffer = gBgOffsetsHBlankPrimary; - s16 camFracY = Div(cameraY, 60); -#endif - - // Prevent wrapping of the background map at the bottom of the screen on high cameraY's -#if WIDESCREEN_HACK - if (camFracY > 256 - DISPLAY_HEIGHT) { - camFracY = 256 - DISPLAY_HEIGHT; - } -#endif - - gBgScrollRegs[0][1] = camFracY; - gBgScrollRegs[3][1] = camFracY; - - if (IS_SINGLE_PLAYER) { - if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && (gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT)) { - if (sUnknown_03000408 == 0) { - sUnknown_03000408 = cameraX; - } - sUnknown_03000408 += I(gPlayer.qSpeedGround); - cameraX = sUnknown_03000408; - } else { - sUnknown_03000408 = 0; - } - // _0801CC72 - i = 0; - - { - s32 r6 = camFracY; - cursor = (u8 *)gUnknown_080D5B20; - sp40 = camFracY; - - while (r6 >= cursor[i * 3]) { - if (++i >= ARRAY_COUNT(gUnknown_080D5B20)) { - break; - } - { - sl = i; - } - } - } - //_0801CCA8: - - for (i = 0; i < ARRAY_COUNT(gUnknown_080D5B20); i++) { - sp[i].x = (((gUnknown_080D5B20[i][1] * cameraX) >> 5) & 0xFF); - sp[i].y = (((gUnknown_080D5B20[i][2] * cameraX) >> 5) & 0xFF); - } - // __0801CCF0 - - cursorStack = &sp[sl]; - cursor = (u8 *)gUnknown_080D5B20[sl]; - for (i = 0; (u8)i < DISPLAY_HEIGHT - 1; sp40++, i++) { - *bgBuffer = cursorStack->y; - bgBuffer++; - - *bgBuffer = cursorStack->x; - bgBuffer++; - - if (sp40 >= *cursor) { - cursor += 3; - cursorStack++; - } - } - - // __0801CD2C - gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_801E454; - gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; - } -} -#if 01 -END_NONMATCH -#endif - -/************************************ ZONE 4 ************************************/ - -static s16 sCameraShiftX; - -void CreateStageBg_Zone4(void) -{ - Background *background = &gStageBackgroundsRam.unk0; - const Background *templates; - gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); - - *background = gStageCameraBgTemplates[CAMBG_BACK_B_LAYER]; - - background->tilemapId = TM_SPOTLIGHT_SNOW; - background->graphics.dest = (void *)BG_SCREEN_ADDR(24); - background->layoutVram = (void *)BG_SCREEN_ADDR(27); - background->targetTilesX = 32; - background->targetTilesY = 32; - background->flags = BACKGROUND_DISABLE_PALETTE_UPDATE | BACKGROUND_FLAGS_BG_ID(3); - DrawBackground(background); - - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 0; - gBgScrollRegs[3][0] = 0; - gBgScrollRegs[3][1] = 0; - -// Software renderer for these devices are too slow -// to handle these spotlights -#if !defined(__PS2__) && !defined(__PSP__) - if (IS_SINGLE_PLAYER) { - CreateSpotlightsManager(); - } -#endif -} - -void StageBgUpdate_Zone4Acts12(s32 cameraX, s32 cameraY) -{ - Player *player = &gPlayer; - s32 camFracY; - - if ((player->moveState & MOVESTATE_GOAL_REACHED) && gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT) { - if (sCameraShiftX == 0) { - sCameraShiftX = cameraX; - } - sCameraShiftX += I(player->qSpeedGround); - cameraX = sCameraShiftX; - } else { - sCameraShiftX = 0; - } - - if (IS_SINGLE_PLAYER && !(gStageFlags & STAGE_FLAG__100)) { - gWinRegs[WINREG_WINOUT] = 0x3e; - gWinRegs[WINREG_WININ] = 0x3f3f; - gWinRegs[WINREG_WIN0H] = WIN_RANGE(0, DISPLAY_WIDTH); - gWinRegs[WINREG_WIN0V] = WIN_RANGE(0, DISPLAY_HEIGHT); - gWinRegs[WINREG_WIN1H] = WIN_RANGE(0, DISPLAY_WIDTH); - gWinRegs[WINREG_WIN1V] = WIN_RANGE(0, DISPLAY_HEIGHT); - gBldRegs.bldY = 7; - gBldRegs.bldCnt = 0x3f41; - gBldRegs.bldAlpha = 0xc0c; - } - -#ifdef BUG_FIX - UpdateBgAnimationTiles(&gStageBackgroundsRam.unk0); - DrawBackground(&gStageBackgroundsRam.unk0); -#else - DrawBackground(&gStageBackgroundsRam.unk0); - UpdateBgAnimationTiles(&gStageBackgroundsRam.unk0); -#endif - - if ((gStageTime % 16u) == 0) { - gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 1) & 0xff; - gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] - 1) & 0xff; - } - gBgScrollRegs[3][0] = cameraX >> 4; - - camFracY = cameraY >> 6; -#if WIDESCREEN_HACK - if (camFracY > 256 - DISPLAY_HEIGHT) { - camFracY = 256 - DISPLAY_HEIGHT; - } -#endif - gBgScrollRegs[3][1] = camFracY; -} - -/************************************ ZONE 5 ************************************/ - -void CreateStageBg_Zone5(void) -{ - Background *background = &gStageBackgroundsRam.unk0; - - if (IS_SINGLE_PLAYER) { - gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] = (BGCNT_TXT256x256 | BGCNT_SCREENBASE(SCREENBASE_SKY_CANYON_CLOUDS) | BGCNT_CHARBASE(3)); - *background = gStageCameraBgTemplates[3]; - background->tilemapId = TM_SKY_CANYON_CLOUDS_FOREGROUND; - background->graphics.dest = (void *)BG_SCREEN_ADDR(24); - background->layoutVram = (void *)BG_SCREEN_ADDR(SCREENBASE_SKY_CANYON_CLOUDS); - background->targetTilesX = (256 / TILE_WIDTH); - background->targetTilesY = (256 / TILE_WIDTH); - DrawBackground(background); - } - - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 160 - DISPLAY_HEIGHT; - gBgScrollRegs[3][0] = 0; - gBgScrollRegs[3][1] = 0; -} - -#if WIDESCREEN_HACK -// NOTE: This is very much temporary. -void HBlankCB_FixCloudRendering(int_vcount vcount) -{ - // NOTE: If gBgScrollRegs[0][1] doesn't also get set here, a transparent line will appear at the very top. - // Only setting REG_BG0VOFS leads to its value getting overwritten at the end of the frame, - // with gBgScrollRegs[0][1], so we have to set it accordingly. - if (vcount < 80 || vcount == 239) { - REG_BG0VOFS = 0; - gBgScrollRegs[0][1] = 0; - } else { - REG_BG0VOFS = 160 - DISPLAY_HEIGHT; - gBgScrollRegs[0][1] = 160 - DISPLAY_HEIGHT; - } -} -#endif - -#define BG_CLOUD_START_Y 96 - -void StageBgUpdate_Zone5Acts12(s32 UNUSED cameraX, s32 UNUSED cameraY) -{ - s32 num; - u16 *cursor, i, val; - gBgScrollRegs[0][0]++; - gBgScrollRegs[3][0] = 0; - num = gStageTime * 2; - - if (IS_SINGLE_PLAYER) { - gFlags = gFlags | FLAGS_EXECUTE_HBLANK_COPY; - gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; - gHBlankCopySize = 2; - cursor = gBgOffsetsHBlankPrimary; - - if (gCurrentLevel != LEVEL_INDEX(ZONE_5, ACT_BOSS)) { - gDispCnt |= DISPCNT_BG0_ON; - gDispCnt |= DISPCNT_WIN0_ON; - gWinRegs[WINREG_WINOUT] = WINOUT_WIN01_ALL; - gWinRegs[WINREG_WININ] = (WININ_WIN0_ALL | WININ_WIN1_ALL); - gWinRegs[WINREG_WIN0H] = WIN_RANGE(0, DISPLAY_WIDTH); - gWinRegs[WINREG_WIN0V] = WIN_RANGE(0, DISPLAY_HEIGHT); - gWinRegs[WINREG_WIN1H] = WIN_RANGE(0, DISPLAY_WIDTH); - gWinRegs[WINREG_WIN1V] = WIN_RANGE(0, DISPLAY_HEIGHT); - gBldRegs.bldY = 7; - gBldRegs.bldCnt = (BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG0); - gBldRegs.bldAlpha = BLDALPHA_BLEND(16, 16); - } - - // Move the parallax clouds -#if !WIDESCREEN_HACK - for (i = 0; i < BG_CLOUD_START_Y; i++) { - *cursor++ = 0; - } - - val = Div(num, 8); - for (; i < BG_CLOUD_START_Y + 4; i++) { - *cursor++ = val; - } - - val = Div(num, 7); - for (; i < BG_CLOUD_START_Y + 8; i++) { - *cursor++ = val; - } - - val = Div(num, 6); - for (; i < BG_CLOUD_START_Y + 16; i++) { - *cursor++ = val; - } - - val = Div(num, 5); - for (; i < BG_CLOUD_START_Y + 24; i++) { - *cursor++ = val; - } - - val = Div(num, 4); - for (; i < BG_CLOUD_START_Y + 32; i++) { - *cursor++ = val; - } - - val = Div(num, 3); - for (; i < BG_CLOUD_START_Y + 48; i++) { - *cursor++ = val; - } - - val = Div(num, 2); - for (; i < BG_CLOUD_START_Y + 63; i++) { - *cursor++ = val; - } -#else - // NOTE: Temporary solution to render the bottom of the background in a decent looking way - gHBlankCopySize = 2 * sizeof(u16); - - for (i = 0; i < DISPLAY_HEIGHT - 1; i++) { - s32 originalLine = (s32)(((float)i / (float)DISPLAY_HEIGHT) * 160.0f); - - if (originalLine > 159) { - originalLine = 159; - } - - if (originalLine < BG_CLOUD_START_Y) { - *cursor++ = 0; - *cursor++ = originalLine - i; - } else if (originalLine < BG_CLOUD_START_Y + 4) { - *cursor++ = num >> 3; - *cursor++ = originalLine - i; - } else if (originalLine < BG_CLOUD_START_Y + 8) { - *cursor++ = Div(num, 7); - *cursor++ = originalLine - i; - } else if (originalLine < BG_CLOUD_START_Y + 16) { - *cursor++ = Div(num, 6); - *cursor++ = originalLine - i; - } else if (originalLine < BG_CLOUD_START_Y + 24) { - *cursor++ = Div(num, 5); - *cursor++ = originalLine - i; - } else if (originalLine < BG_CLOUD_START_Y + 32) { - *cursor++ = num >> 2; - *cursor++ = originalLine - i; - } else if (originalLine < BG_CLOUD_START_Y + 48) { - *cursor++ = Div(num, 3); - *cursor++ = originalLine - i; - } else if (originalLine < BG_CLOUD_START_Y + 63) { - *cursor++ = num >> 1; - *cursor++ = originalLine - i; - } else { - *cursor++ = 0; - *cursor++ = originalLine - i; - } - } - - gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_FixCloudRendering; - gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; -#endif - } -} - -/************************************ ZONE 6 ************************************/ - -const s16 gUnknown_080D5BF0[] = { - Q_8_8(0.00), Q_8_8(0.25), Q_8_8(2.25), Q_8_8(2.50), Q_8_8(3.50), Q_8_8(3.625), Q_8_8(5.625), Q_8_8(5.75), Q_8_8(6.75), -}; - -// TODO: Make static and Rename to sBlendColors -const u8 gUnknown_080D5C02[2][16][3] = { - { - // r, g, b - { 0x1F, 0x00, 0x1F }, - { 0x01, 0x07, 0x14 }, - { 0x01, 0x09, 0x14 }, - { 0x00, 0x0A, 0x13 }, - { 0x00, 0x0C, 0x13 }, - { 0x00, 0x0D, 0x12 }, - { 0x00, 0x0F, 0x12 }, - { 0x00, 0x10, 0x11 }, - { 0x00, 0x12, 0x10 }, - { 0x00, 0x13, 0x10 }, - { 0x00, 0x15, 0x0F }, - { 0x00, 0x16, 0x0F }, - { 0x00, 0x18, 0x0E }, - { 0x00, 0x19, 0x0E }, - { 0x00, 0x1B, 0x0D }, - { 0x1F, 0x07, 0x00 }, - }, - { - // r, g, b - { 0x1F, 0x00, 0x00 }, - { 0x0F, 0x00, 0x1B }, - { 0x0E, 0x00, 0x19 }, - { 0x0D, 0x01, 0x17 }, - { 0x0C, 0x01, 0x15 }, - { 0x0B, 0x02, 0x13 }, - { 0x0A, 0x02, 0x11 }, - { 0x08, 0x03, 0x0F }, - { 0x07, 0x03, 0x0D }, - { 0x06, 0x04, 0x0B }, - { 0x05, 0x04, 0x09 }, - { 0x04, 0x05, 0x07 }, - { 0x03, 0x05, 0x05 }, - { 0x02, 0x06, 0x03 }, - { 0x01, 0x06, 0x01 }, - { 0x00, 0x07, 0x00 }, - }, -}; - -void CreateStageBg_Zone6_Acts(void) -{ - gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] = BGCNT_SCREENBASE(26) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); - INIT_BG_SPRITES_LAYER_32(0); - DmaFill32(3, 0, BG_SCREEN_ADDR(24), sizeof(Background)); - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 0; - gBgScrollRegs[3][0] = 0; - gBgScrollRegs[3][1] = 0; - gStageTime = 0x380; - - if (USE_BOSS_BG_IN_ZONE_6_ACTS || IS_MULTI_PLAYER) { - CreateStageBg_Zone6_Boss(); - } - - gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); - gBgCntRegs[3] |= BGCNT_PRIORITY(2); -} - -void CreateStageBg_Zone6_Boss(void) -{ - Background *background = &gStageBackgroundsRam.unk0; - gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] = BGCNT_SCREENBASE(26) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); - INIT_BG_SPRITES_LAYER_32(0); - DmaFill32(3, 0, BG_SCREEN_ADDR(24), sizeof(Background)); - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 0; - gBgScrollRegs[3][0] = 0; - gBgScrollRegs[3][1] = 0; - - *background = gStageCameraBgTemplates[3]; - background->tilemapId = TM_TECHNO_BASE_BG_CIRCUIT_MASK; - background->graphics.dest = (void *)BG_SCREEN_ADDR(24); - background->layoutVram = (void *)BG_SCREEN_ADDR(26); - background->targetTilesX = 32; - background->targetTilesY = 32; - - DrawBackground(background); -} - -// (82.58%) https://decomp.me/scratch/tB3Bs -// (85.82%) https://decomp.me/scratch/pNyvP -NONMATCH("asm/non_matching/game/sa2/stage/background/sub_801D24C.inc", void sub_801D24C(u8 p0, s16 p1, u8 p2)) -{ - s16 r6; - u16 *hOffsets; - s32 stageTime; - s32 stageTime2; - s16 i; - s16 r4; - s32 sl; - s32 p1_2; - - gFlags |= FLAGS_EXECUTE_HBLANK_COPY; - - gHBlankCopyTarget = (void *)®_BG0HOFS; - gHBlankCopySize = 4; - - gWinRegs[WINREG_WINOUT] = WINOUT_WIN01_ALL; - gBldRegs.bldCnt = (BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND | BLDCNT_TGT1_BG0); - gBldRegs.bldAlpha = BLDALPHA_BLEND(16, 8); - gBldRegs.bldY = 16 * 10; - - hOffsets = gBgOffsetsHBlankPrimary; - - stageTime = (gStageTime & 0x3FF); - stageTime2 = ((gStageTime >> 1) & 0x3FF); - - // p1 *= 2.5 - - p1_2 = p1; - r6 = (DISPLAY_HEIGHT - 1) - ((p1_2 * 2) + (p1_2 >> 1)); - - if (r6 > (DISPLAY_HEIGHT - 1)) { - r6 = (DISPLAY_HEIGHT - 1); - } - - if (p2 != 0) { - s16 r2; - // _0801D2CA - gBldRegs.bldAlpha = BLDALPHA_BLEND(16, (16 - (p1_2 >> 4))); - - for (r4 = 0; r4 < r6; r4++) { - *hOffsets++ = 0; - *hOffsets++ = (-15 - r4) & 0xFF; - } - // _0801D312 - - while (r4 < (DISPLAY_HEIGHT - 1)) { - // _0801D31C - s32 sin = SIN_24_8(CLAMP_SIN_PERIOD(r4 * 16 + stageTime2 + stageTime)) >> 1; - sin++; - sin = (sin)-r4 * 2; - *hOffsets++ = sin & 0xFF; - - if ((r4 - 15) < r6) { - s32 r0 = (1 - r4); - r0 -= (((r4 - r6) - 15) * 8); - *hOffsets++ = r0 & 0xFE; - } else { - // _0801D3A0 - s32 sin = (SIN_24_8(CLAMP_SIN_PERIOD(stageTime + r4 * 4)) >> 1) + 1; - sin = sin - r4; - *hOffsets++ = (stageTime2 + sin) & 0xFF; - } - - r4++; - } - } else { - // _0801D3D6 - gBldRegs.bldAlpha = BLDALPHA_BLEND(16, (16 - (p1_2 >> 5))); - r4 = 0; - - // _0801D3FC - for (; r4 < r6; r4++) { - s32 sin = SIN_24_8(CLAMP_SIN_PERIOD(r4 * 16 + stageTime2 + stageTime)) >> 1; - sin += 1; - sin = sin - r4 * 2; - *hOffsets++ = sin & 0xFF; - - sin = SIN_24_8((CLAMP_SIN_PERIOD(stageTime2 + r4 * 4))) >> 1; - sin++; - sin = (sin)-r4 * 2; - *hOffsets++ = (stageTime2 + sin) & 0xFF; - } - - // _0801D44C - - while (r4 < (DISPLAY_HEIGHT - 1)) { - *hOffsets++ = 0; - - if ((r4 - 15) < r6) { - *hOffsets++ = ((((r4 - r6) - 15) << 3) - (r4 - 1)) & 0xFF; - } else { - *hOffsets++ = ((-r4 + 1) & 0xFF); - } - - r4++; - } - } - // _0801D498 - - if (p0 > 16) { - p0 = 16; - } - // _0801D4A2 - - for (i = 0; i < PALETTE_LEN_4BPP; i++) { - s32 b, g, r; - r = (p0 * gUnknown_080D5C02[1][i][0]) >> 4; - r &= 0x1F; - - g = (p0 * gUnknown_080D5C02[1][i][1]) >> 4; - g &= 0x1F; - - b = (p0 * gUnknown_080D5C02[1][i][2]) >> 4; - b &= 0x1F; - - SET_PALETTE_COLOR_BG(15, i, RGB16_REV(r, g, b)); - } - - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; -} -END_NONMATCH - -// (84.63%) https://decomp.me/scratch/W9B0j -// (82.95%) https://decomp.me/scratch/ZEtCx (newer) -NONMATCH("asm/non_matching/game/sa2/stage/background/StageBgUpdate_Zone6Acts12.inc", void StageBgUpdate_Zone6Acts12(s32 x, s32 UNUSED y)) -{ - u16 r6; - u8 r5; - u8 r2; - Background *bg = &gStageBackgroundsRam.unk0; - - gBgScrollRegs[3][0] = x >> 4; - - r6 = Mod(gStageTime, 0x680); - r5 = 0; - r2 = 8; - - if (r6 > gUnknown_080D5BF0[7]) { - r5 = 7; - } else - while (1) { - u32 r3; - u32 r0 = (r2 << 24); - r0 += (0xFF << 24); - r2 = r0 >> 24; - r3 = r2 << 24; - r0 = r3 >> 24; - if (((signed)r0 >= 0) || (r6 > gUnknown_080D5BF0[r0])) { - break; - } - } - - if (IS_MULTI_PLAYER) { - r5 = 5; - } - - SET_PALETTE_COLOR_BG(0, 0, RGB_BLACK); - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; - - switch (r5) { - case 0: { - if (r6 == 1) { - const Background *bgTemplate = gStageCameraBgTemplates; - memcpy(bg, (bgTemplate + 3), sizeof(Background)); - bg->tilemapId = TM_TECHNO_BASE_BG_PURPLE_GRID; - bg->graphics.dest = (void *)BG_CHAR_ADDR(3); - bg->layoutVram = (void *)BG_SCREEN_ADDR(26); - bg->targetTilesX = 32; - bg->targetTilesY = 32; - DrawBackground(bg); - } else if (r6 > 1) { - // _0801D636 - gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] &= ~BGCNT_PRIORITY(3); - gBgCntRegs[0] |= BGCNT_PRIORITY(3); - gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); - gBgCntRegs[3] |= BGCNT_PRIORITY(3); - - r2 = r6; - if (r2 > 63) - r2 = 63; - - r6 /= 4u; - - sub_801D24C(r6, 63 - r2, 0); - } - } break; - - case 1: { - sub_801D24C(15, 0, 0); - } break; - - case 2: { - u32 r0 = (r6 - 577); - r0 <<= 16; - r2 = (r0 << 8) >> 24; - r6 /= 4u; - r6 = (15 - r6); - - if (r6 != 0) { - sub_801D24C(r6, 63 - r2, 1); - } else { - gFlags &= ~FLAGS_EXECUTE_HBLANK_COPY; - gBldRegs.bldCnt = r6; - } - } break; - - case 3: { - s8 i; - gBgCntRegs[0] &= ~BGCNT_PRIORITY(3); - gBgCntRegs[0] |= BGCNT_PRIORITY(3); - gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); - gBgCntRegs[3] |= BGCNT_PRIORITY(2); - - for (i = 0; i < 16; i++) { - SET_PALETTE_COLOR_BG(15, i, RGB_BLACK); - } - - // jumps to _0801D8EE for this - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; - } break; - - case 4: { - s8 i; - s32 v; - - if (r6 == 897) { - memcpy(&gStageBackgroundsRam.unk0, &gStageCameraBgTemplates[3], sizeof(Background)); - gStageBackgroundsRam.unk0.tilemapId = TM_TECHNO_BASE_BG_CIRCUIT_MASK; - bg->graphics.dest = (void *)BG_CHAR_ADDR(3); - bg->layoutVram = (void *)BG_SCREEN_ADDR(26); - bg->targetTilesX = 32; - bg->targetTilesY = 32; - DrawBackground(bg); - } else { - gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] |= BGCNT_PRIORITY(3); - } - // _0801D76C - - v = r6 - 897; - r6 = v; - - for (i = 0; i < 16; i++) { - u32 red = ((gUnknown_080D5C02[0][i][0] * r6) >> 5) & 0x1F; - u32 green = ((gUnknown_080D5C02[0][i][1] * r6) >> 5) & 0x1F; - u32 blue = ((gUnknown_080D5C02[0][i][2] * r6) >> 5) & 0x1F; - - SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); - } - - // jumps to _0801D83C for this - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; - gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; - gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; - } break; - - case 5: { - // _0801D7F8_case5 - s8 i; - - for (i = 0; i < 16; i++) { - u32 red = gUnknown_080D5C02[0][i][0]; - u32 green = gUnknown_080D5C02[0][i][1]; - u32 blue = gUnknown_080D5C02[0][i][2]; - - SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); - } - - // _0801D83C - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; - - gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; - gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; - } break; - - case 6: { - s8 i; - s32 v; - - gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; - gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; - - v = r6 - 1441; - r6 = v; - r6 = (31 - r6) / 2u; - - for (i = 0; i < 16; i++) { - u32 red = ((gUnknown_080D5C02[0][i][0] * r6) >> 4) & 0x1F; - u32 green = ((gUnknown_080D5C02[0][i][1] * r6) >> 4) & 0x1F; - u32 blue = ((gUnknown_080D5C02[0][i][2] * r6) >> 4) & 0x1F; - - SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); - } - - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; - } break; - - case 7: { - s8 i; - for (i = 0; i < 16; i++) { - SET_PALETTE_COLOR_BG(15, i, RGB_BLACK); - } - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; - gDispCnt &= ~(DISPCNT_BG0_ON); - } break; - } -} -END_NONMATCH - -/************************************ ZONE 7 ************************************/ - -const s16 gUnknown_080D5C62[8][2] = { - { -Q_8_8(3.00), -Q_8_8(0.25) }, // - { -Q_8_8(1.50), +Q_8_8(0.00) }, // - - { -Q_8_8(3.00), -Q_8_8(0.25) }, // - { -Q_8_8(1.00), -Q_8_8(0.0859375) }, // - - { -Q_8_8(3.00), -Q_8_8(0.25) }, // - { -Q_8_8(1.50), +Q_8_8(0.00) }, // - - { -Q_8_8(3.00), -Q_8_8(0.25) }, // - { -Q_8_8(0.75), -Q_8_8(0.125) }, // -}; - -static const ColorRaw sPalette_Zone7BgCeiling[] = INCPAL("graphics/sa2/zone_7_bg_ceiling.pal"); - -void CreateStageBg_Zone7(void) -{ - Background *bg = &gStageBackgroundsRam.unk0; - const Background *src; - gDispCnt = DISPCNT_OBJ_ON | DISPCNT_BG2_ON | DISPCNT_BG1_ON | DISPCNT_OBJ_1D_MAP | DISPCNT_MODE_0; - - gBgCntRegs[0] = (BGCNT_TXT256x256 | BGCNT_SCREENBASE(22) | BGCNT_16COLOR | BGCNT_PRIORITY(15)); - - src = gStageCameraBgTemplates; - memcpy(bg, &src[3], sizeof(Background)); - - bg->tilemapId = TM_UNK_SPACE_BG; - bg->graphics.dest = (void *)BG_SCREEN_ADDR(24); - bg->layoutVram = (void *)BG_SCREEN_ADDR(22); - bg->targetTilesX = 32; - bg->targetTilesY = 20; - DrawBackground(bg); - - gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); - gBgCntRegs[3] |= BGCNT_PRIORITY(3); - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 0; -} - -// (98.52%) https://decomp.me/scratch/DUPkY -// (99.82%) https://decomp.me/scratch/pfVTf (fake match) -NONMATCH("asm/non_matching/game/sa2/stage/background/Zone7BgUpdate_Inside.inc", void Zone7BgUpdate_Inside(s32 x, s32 y)) -{ - u16 *dst; - s32 someX; - s32 lineY; - s32 ip; - u8 j; - u8 r1; - u8 r2; - u8 r5; - - if ((gPlayer.moveState & MOVESTATE_GOAL_REACHED) && (gSpecialRingCount >= SPECIAL_STAGE_REQUIRED_SP_RING_COUNT)) { - if (gBgScrollRegs[3][0] == 0) - gBgScrollRegs[3][0] = x; - - gBgScrollRegs[3][0] += I(gPlayer.qSpeedGround); - - x = gBgScrollRegs[3][0]; - } - - gDispCnt &= ~DISPCNT_BG0_ON; - gDispCnt |= DISPCNT_BG3_ON; - - gFlags |= FLAGS_EXECUTE_HBLANK_COPY; - - gHBlankCopyTarget = (void *)®_BG3HOFS; - gHBlankCopySize = 4; - - dst = (u16 *)gBgOffsetsHBlankPrimary; - -#ifndef NON_MATCHING - // Why call Div without using its return value? - someX = Div(x * 42, 400); -#endif - - // Move BG3 to the "ceiling" for the first 40 lines - for (lineY = 0; lineY < 40; lineY++) { - *dst++ = 8; - *dst++ = 16; - } - - // ip = Div(25*x, 400); - ip = Div(25 * x, 400) & 0xFF; - - for (lineY = 0; lineY < 119; lineY++) { - *dst++ = ip; - *dst++ = 17; - } - - // _0801DAA6 - // Draw the small, green-shining, moving pillars - // NOTE: j stored in *sp - j = 0; - do { - ip = (((gStageTime + x) / 8)) & 0xFF; - - r5 = (((100 * j) + 64) - (y >> 4)); - if (r5 < 240) { - // __0801DACA - if (r5 > 80) { - dst = gBgOffsetsHBlankPrimary; - r1 = ((r5 - 80) >> 4); - dst += (r5 - r1) << 1; - - lineY = r5; - for (r2 = 0; ((lineY < r1 + 160) && (r2 < r1)); lineY++, r2++) { - *dst++ = 0; - *dst++ = 208 - r5; - } - } - // _0801DB1C - dst = gBgOffsetsHBlankPrimary; - dst = ((void *)dst) + (r5 * 4); - - for (lineY = r5, r2 = 0; ((lineY < DISPLAY_HEIGHT) && (r2 < 16)); lineY++, r2++) { - *dst++ = ip; - *dst++ = (240 - r5); - } - - if (lineY < 80) { - s32 r0 = (80 - lineY) >> 4; - r1 = r0; - - for (r2 = 0; ((lineY < DISPLAY_HEIGHT) && (r2 < r1)); lineY++, r2++) { - *dst++ = 0; - *dst++ = (184 - r5); - } - } - } else { - // _0801DBAC - dst = gBgOffsetsHBlankPrimary; - - for (lineY = 255 - r5; lineY < 16; lineY++) { - *dst++ = ip; - *dst++ = 495 - r5; - } - // _0801DBD2 - - for (r2 = 0; r2 < 4; r2++) { - *dst++ = 0; - *dst++ = 439 - r5; - } - } - } while (++j < 2); // _0801DBEE == continue of (j < 2) - // _0801DBFA - - ip = ((gStageTime + x) / 2) & 0xFF; - - { - r5 = -(y >> 1); - - if (r5 < 224) { - u8 val; - if (r5 > 80) { - dst = gBgOffsetsHBlankPrimary; - - val = ((r5 - 80) >> 4); - dst += (r5 - val) << 1; - - lineY = r5, r2 = 0; - for (; ((lineY < (160 + val)) && (r2 < val)); lineY++, r2++) { - *dst++ = 0; - *dst++ = 208 - r5; - } - } - // _0801DC66 - dst = gBgOffsetsHBlankPrimary; - dst = ((void *)dst) + (r5 * 4); - - for (lineY = r5, r2 = 0; ((lineY < DISPLAY_HEIGHT) && (r2 < 32)); lineY++, r2++) { - *dst++ = ip; - *dst++ = 208 - r5; - } - - if (lineY < 80) { - for (r1 = (80 - lineY) >> 4, r2 = 0; ((lineY < 160) && (r2 < r1)); lineY++, r2++) { - *dst++ = 0; - *dst++ = 168 - r5; - } - } - } else { - // _0801DCDC - dst = gBgOffsetsHBlankPrimary; - - for (lineY = 255 - r5; lineY < 32; lineY++) { - *dst++ = ip; - *dst++ = 463 - r5; - } - - for (r2 = 0; r2 < 4; r2++) { - *dst++ = 0; - *dst++ = 423 - r5; - } - } -// _0801DD1A -#if 001 - { // Draw the "ceiling" movement - u32 new_r1 = (x >> 4) << 16; - const ColorRaw *src; - ColorRaw *dst; - s32 r6 = 0x7; - src = sPalette_Zone7BgCeiling; - dst = gBgPalette; - dst += 209; - new_r1 >>= 16; - - for (lineY = 0; lineY < 8; new_r1--, lineY++) { - s32 index = (new_r1 & r6) + 1; - *dst++ = src[index]; - } - } -#else - { // Draw the "ceiling" movement - for (lineY = 0; lineY < 8; lineY++) { - SET_PALETTE_COLOR_BG(13, lineY + 1, sPalette_Zone7BgCeiling[((x >> 4) & 0x7) + 1]); - } - } -#endif - } - - gFlags = gFlags | FLAGS_UPDATE_BACKGROUND_PALETTES; -} -END_NONMATCH - -void Zone7BgUpdate_Outside(s32 x, s32 y) -{ - u16 *cursor; - u8 frameCount; - int_vcount i; - u16 sp[32]; - u32 stageTime; - - gDispCnt &= ~DISPCNT_BG3_ON; - gDispCnt |= DISPCNT_BG0_ON; - - gFlags |= FLAGS_EXECUTE_HBLANK_COPY; - - gHBlankCopyTarget = (void *)®_BG0HOFS; - gHBlankCopySize = 2; - cursor = (u16 *)gBgOffsetsHBlankPrimary; - - stageTime = gStageTime; - frameCount = ((stageTime >> 3) & 0x1F); - if (frameCount >= 16) { - // Likely some sort of debug log -#ifndef NON_MATCHING - register u32 r1 asm("r1"); - register u8 r0 asm("r0"); - r0 = 31 - frameCount; - asm("" ::"r"(r0)); - r1 = r0; - asm("" ::"r"(r1)); -#endif - } - - for (i = 0; i < ARRAY_COUNT(sp); i++) { - sp[i] = 0xFF & (I(gUnknown_080D5C62[(i & 0x7)][0] * stageTime) + gUnknown_080D5C62[(i & 0x7)][1]); - } - - { - u16 sinVal, value; - u32 cosVal; - u32 scrollSpeed = (Q(80.5) - 1); - -#if !WIDESCREEN_HACK - for (i = 0; i < DISPLAY_HEIGHT / 2; i++) { - sinVal = SIN_24_8(((gStageTime * 4) + i * 2) & ONE_CYCLE) >> 3; - value = (COS_24_8(((i * scrollSpeed) >> 5) & ONE_CYCLE) >> 4) + sinVal; - value = (value + sp[(i & 0x1F)]) & 0xFF; - *cursor++ = value; - } - - for (; i < DISPLAY_HEIGHT - 1; i++) { - sinVal = SIN_24_8(((gStageTime << 2) + i * 2) & ONE_CYCLE) >> 3; - cosVal = (COS_24_8((((DISPLAY_HEIGHT - i) * scrollSpeed) >> 5) & ONE_CYCLE) >> 4); - value = cosVal + sinVal; - value = (value + sp[(i & 0x1F)]) & 0xFF; - *cursor++ = value; - } -#else - gHBlankCopySize = 2 * sizeof(u16); - - for (i = 0; i < DISPLAY_HEIGHT; i++) { - const s32 gbaHLines = 160; - s32 originalLine = (s32)(((float)i / (float)DISPLAY_HEIGHT) * (float)gbaHLines); - - if (originalLine < 80) { - sinVal = SIN_24_8(((gStageTime * 4) + originalLine * 2) & ONE_CYCLE) >> 3; - value = (COS_24_8(((originalLine * scrollSpeed) >> 5) & ONE_CYCLE) >> 4) + sinVal; - value = (value + sp[(originalLine & 0x1F)]) & 0xFF; - *cursor++ = value; - *cursor++ = originalLine - i; - } else if (originalLine < gbaHLines) { - sinVal = SIN_24_8(((gStageTime << 2) + originalLine * 2) & ONE_CYCLE) >> 3; - cosVal = (COS_24_8((((gbaHLines - originalLine) * scrollSpeed) >> 5) & ONE_CYCLE) >> 4); - value = cosVal + sinVal; - value = (value + sp[(originalLine & 0x1F)]) & 0xFF; - *cursor++ = value; - *cursor++ = originalLine - i; - } - } -#endif - } -} - -/************************************ ZONE FINAL ************************************/ - -#define NUM_ZONE7_BG_TRANSITION_POSITIONS 8 - -const u16 sZone7BgTransitionRegions[2][NUM_ZONE7_BG_TRANSITION_POSITIONS] = { - { 697, 1849, 8857, 11832, 18553, 22009, 25369, 27673 }, // ACT 1 - { 1344, 2616, 9432, 15192, 18552, 19892, 23158, 25848 }, // ACT 2 -}; - -const ColorRaw sExtraBossPalette[PALETTE_LEN_4BPP] = INCPAL("graphics/sa2/boss_9_normal.pal"); - -void CreateStageBg_ZoneFinal_0(void) -{ - Background *bgDst; - const Background *bgSrc; - u8 i; - - gDispCnt = (DISPCNT_OBJ_ON | DISPCNT_BG0_ON | DISPCNT_OBJ_1D_MAP | DISPCNT_MODE_1); - INIT_BG_SPRITES_LAYER_32(2); - - bgDst = &gStageBackgroundsRam.unk80; - gBgCntRegs[2] = BGCNT_SCREENBASE(26) | BGCNT_256COLOR | BGCNT_CHARBASE(2) | BGCNT_PRIORITY(1); - bgSrc = gStageCameraBgTemplates; - memcpy(bgDst, &bgSrc[2], sizeof(Background)); - - bgDst->tilemapId = TM_EXTRA_BOSS_COCKPIT; - bgDst->graphics.dest = (void *)BG_CHAR_ADDR(2); - - // TODO: Should this be a different macro? - bgDst->layoutVram = (void *)BG_TILE_ADDR(416); - bgDst->targetTilesX = 10; - bgDst->targetTilesY = 9; - bgDst->flags |= BACKGROUND_FLAG_4; - DrawBackground(bgDst); - - bgDst = &gStageBackgroundsRam.unk0; - gBgCntRegs[0] = BGCNT_SCREENBASE(30) | BGCNT_16COLOR | BGCNT_CHARBASE(1) | BGCNT_PRIORITY(3); - - memcpy(bgDst, &bgSrc[3], sizeof(Background)); - - bgDst->tilemapId = TM_EXTRA_BOSS_BACKGROUND; - bgDst->graphics.dest = (void *)BG_CHAR_ADDR(1); - - // TODO: Should this be a different macro? - bgDst->layoutVram = (void *)BG_TILE_ADDR(480); - bgDst->targetTilesX = 32; - bgDst->targetTilesY = 20; - bgDst->flags = BACKGROUND_FLAGS_BG_ID(0); - DrawBackground(bgDst); - - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[0][1] = 0; - gBgScrollRegs[1][0] = 0; - gBgScrollRegs[1][1] = 0; - gBgScrollRegs[2][0] = 0; - gBgScrollRegs[2][1] = 0; - gBgScrollRegs[3][0] = 0; - gBgScrollRegs[3][1] = 0; - - for (i = 0; i < ARRAY_COUNT(sExtraBossPalette); i++) { - SET_PALETTE_COLOR_BG(0, i, sExtraBossPalette[i]); - } - - gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; -} -#endif // COLLECT_RINGS_ROM - -/************************************ MISC TASKS ************************************/ void DestroyCameraMovementTask(void) { @@ -2406,6 +1075,7 @@ void Task_UpdateCamera(void) gOamMatrixIndex = 4; } +#if (GAME == GAME_SA2) #ifndef COLLECT_RINGS_ROM void CreateStageBg_Default(void) { @@ -2419,161 +1089,89 @@ void CreateStageBg_Dummy(void) { } #endif void StageBgUpdate_Dummy(s32 x, s32 y) { } -#ifndef COLLECT_RINGS_ROM -/************************************ BOSS 1 ************************************/ - -void StageBgUpdate_Zone1ActBoss(UNUSED s32 x, UNUSED s32 y) -{ - struct Camera *cam = &gCamera; - if (!PLAYER_IS_ALIVE) { - gStageTime--; - } - - gBgScrollRegs[0][0] = ((gStageTime + 4) >> 3) & 0xFF; - gBgScrollRegs[0][1] = cam->y >> 9; - gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_801E434; - gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; -} - -/************************************ BOSS 2 ************************************/ - -void StageBgUpdate_Zone2ActBoss(UNUSED s32 a, UNUSED s32 b) -{ - if (!PLAYER_IS_ALIVE) { - gStageTime--; - } - - StageBgUpdate_Zone2Acts12(gStageTime, 4000); -} - -/************************************ BOSS 3 ************************************/ - -void StageBgUpdate_Zone3ActBoss(UNUSED s32 a, UNUSED s32 b) -{ - gBgScrollRegs[0][1] = 0; - gBgScrollRegs[3][1] = 0; - gBgScrollRegs[0][0] = 0; - gBgScrollRegs[3][0] = 0; -} - -/************************************ BOSS 5 ************************************/ - -void StageBgUpdate_Zone5ActBoss(UNUSED s32 a, UNUSED s32 b) -{ - gDispCnt &= ~DISPCNT_BG1_ON; - gBgScrollRegs[0][0]++; - gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_BgUpdateZone5ActBoss; - gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; -} - -/************************************ BOSS 6 ************************************/ - -void StageBgUpdate_Zone6ActBoss(UNUSED s32 a, UNUSED s32 b) -{ - gBgCntRegs[0] |= BGCNT_PRIORITY(3); - gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); - gBgCntRegs[3] |= BGCNT_PRIORITY(2); - gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; - gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; -} - -/*********************************** BOSS/ZONE 7 ********************************/ - -// Not sure why this is defined here, it's possible the function name was confused -// and this was defined twice in the same function -void StageBgUpdate_Zone7Acts12(s32 x, s32 y) -{ - u32 act = !!(gCurrentLevel ^ (LEVEL_INDEX(ZONE_7, ACT_1))); - u32 bgId = 0; - u8 regionId = 0; - - if (x >= sZone7BgTransitionRegions[act][regionId]) { - while (TRUE) { - if (++regionId >= NUM_ZONE7_BG_TRANSITION_POSITIONS) { - break; - } - if (x < sZone7BgTransitionRegions[act][regionId]) { - bgId = regionId % 2; - break; - } - }; - }; - - if (bgId == 0) { - Zone7BgUpdate_Inside(x, y); - } else { - Zone7BgUpdate_Outside(x, y); - } - - gPlayer.unk99[15] = bgId; -} - -void StageBgUpdate_Zone7ActBoss(UNUSED s32 x, UNUSED s32 y) -{ - if (!PLAYER_IS_ALIVE) { - gStageTime--; - } - - Zone7BgUpdate_Inside(gStageTime, 945); -} - -/************************************ BOSS FINAL ************************************/ - -void StageBgUpdate_ZoneFinalActXX(UNUSED s32 x, UNUSED s32 y) -{ - if (!PLAYER_IS_ALIVE) { - gStageTime--; - } - - gHBlankCallbacks[gNumHBlankCallbacks++] = HBlankCB_BgUpdateZoneFinalActXX; - gFlags |= FLAGS_EXECUTE_HBLANK_CALLBACKS; -} - -/************************************ BOSS EXTRA ************************************/ - -#include "game/sa2/stage/bosses/common.h" -#include "game/sa2/stage/bosses/boss_9.h" - -void StageBgUpdate_ZoneFinalActTA53(UNUSED s32 a, UNUSED s32 b) -{ - u32 aBool = FALSE; - int_vcount y; - - if (gActiveBossTask != NULL) { - TA53Boss *boss = TASK_DATA(gActiveBossTask); - aBool = boss->unk10 & 0x1; - } - - if (aBool) { - u16 *offset; - gFlags |= FLAGS_EXECUTE_HBLANK_COPY; - gHBlankCopyTarget = (void *)®_BG1HOFS; - gHBlankCopySize = 2; - - offset = (u16 *)gBgOffsetsHBlankPrimary; - for (y = 0; y < DISPLAY_HEIGHT - 1; y++) { - s16 val = SIN(((y + gStageTime) * 40) & ONE_CYCLE) >> 12; - *offset++ = val; - } - } -} - -/************************************ CALLBACKS ************************************/ - #endif -// Unused -void sub_801E3F0(void) +#if (GAME == GAME_SA1) +#include "../src/game/sa1/stage/backgrounds/zone_4_init.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_5_init.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_7.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_2.inc.c" +#include "../src/game/sa1/stage/backgrounds/zone_5.inc.c" +#elif (GAME == GAME_SA2) +#ifndef COLLECT_RINGS_ROM +#include "../src/game/sa2/stage/backgrounds/zone_1_boss.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_2_boss.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_3_boss.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_5_boss.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_6_boss.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_7.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_final_boss.inc.c" +#include "../src/game/sa2/stage/backgrounds/zone_extra_boss.inc.c" +#endif +#endif + +// TODO: extract these as camera_utils? +#if (GAME == GAME_SA1) +void VBlankCallback_803F920(void) { *(vu32 *)®_BG1HOFS = 0; } + +void HBlankCallback_803F92C(int_vcount line) +{ + s32 newLine = line - 90; + + if ((newLine >= 0) && (line != DISPLAY_HEIGHT - 1)) { + u32 *ptr = gBgOffsetsHBlankSecondary; + ptr += 90; + + *(vu32 *)®_BG1HOFS = ptr[newLine]; + } else { + *(vu32 *)®_BG1HOFS = 0; + } +} +#endif + +UNUSED void SA2_LABEL(sub_801E3F0)(void) { struct Camera *cam = &gCamera; + if (gStageTime & 0x1) { - u16 rand = (PseudoRandom32() & 0x70000) >> 16; - cam->shiftY = rand - 8; + cam->shiftY = ((u32)(PseudoRandom32() & 0x70000) >> 16) - 8; } } -#ifndef COLLECT_RINGS_ROM +#if (GAME == GAME_SA1) +// Not sure why this is defined here +struct Task *SpawnCasinoFireworkMP(s16 x, s16 y, s32 fireworkType) +{ + const TileInfoFirework *tileInfo = &gTileInfoZone3Fireworks[fireworkType % ARRAY_COUNT(gTileInfoZone3Fireworks)]; + CasinoParadiseFirework *firework; + struct Task *t; + Sprite *s; + t = CreateMultiplayerSpriteTask(x, y, 0, 0, Task_UpdateFireworkAnimation, TaskDestructor_MultiplayerSpriteTask); + firework = TASK_DATA(t); + s = &firework->s; + + s->graphics.dest = VramMalloc(tileInfo->numTiles); + s->graphics.anim = tileInfo->anim; + s->variant = tileInfo->variant; + s->oamFlags = SPRITE_OAM_ORDER(31); + s->frameFlags = SPRITE_FLAG(PRIORITY, 3); + + return t; +} + +void HBlankCallback_803FA1C(int_vcount line) +{ + if (line == 100) { + REG_BG0CNT &= ~BGCNT_TXT512x512; + REG_BG0CNT |= BGCNT_TXT256x512; + *(u32 *)®_BG0HOFS = (0 | (DISPLAY_HEIGHT << 16)); + } else if (line > 101 && line < 134) { + REG_BLDY = 16 - ((line - 101) >> 1); + } +} +#elif (GAME == GAME_SA2) +#ifndef COLLECT_RINGS_ROM void HBlankCB_801E434(int_vcount vcount) { if (vcount == 73) { @@ -2613,5 +1211,5 @@ void HBlankCB_BgUpdateZoneFinalActXX(int_vcount vcount) REG_BG3HOFS = (u8)gStageTime; } } - +#endif #endif