diff --git a/.gitignore b/.gitignore index 8feae6c84..6fa7558ac 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ Thumbs.db ehthumbs.db +# Visual Studio folder +.vs +*.pdb + # Folder config file Desktop.ini @@ -67,8 +71,6 @@ tools/agbcc /ctx.c reports .vscode/*.log -.vs/ -*.pdb *.gbapal *.lz *.rl diff --git a/Makefile b/Makefile index c81aa5759..bc3f79b7d 100644 --- a/Makefile +++ b/Makefile @@ -133,6 +133,9 @@ INCLUDE_DIRS = include INCLUDE_CPP_ARGS := $(INCLUDE_DIRS:%=-iquote %) INCLUDE_SCANINC_ARGS := $(INCLUDE_DIRS:%=-I %) +ASM_SUBDIR = asm +ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR) + C_SUBDIR = src C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR) @@ -172,6 +175,9 @@ C_HEADERS := $(shell find $(INCLUDE_DIRS) -name "*.h" -not -path "*/platform/*") ifeq ($(PLATFORM),gba) C_ASM_SRCS := $(shell find $(C_SUBDIR) -name "*.s") C_ASM_OBJS := $(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o,$(C_ASM_SRCS)) + +ASM_SRCS := $(wildcard $(ASM_SUBDIR)/*.s) +ASM_OBJS := $(patsubst $(ASM_SUBDIR)/%.s,$(ASM_BUILDDIR)/%.o,$(ASM_SRCS)) endif DATA_ASM_SRCS := $(wildcard $(DATA_ASM_SUBDIR)/*.s) @@ -186,7 +192,7 @@ MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS)) SOUND_ASM_SRCS := $(wildcard $(SOUND_ASM_SUBDIR)/*.s) SOUND_ASM_OBJS := $(patsubst $(SOUND_ASM_SUBDIR)/%.s,$(SOUND_ASM_BUILDDIR)/%.o,$(SOUND_ASM_SRCS)) -OBJS := $(C_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) +OBJS := $(C_OBJS) $(ASM_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS)) FORMAT_SRC_PATHS := $(shell find . -name "*.c" ! -path '*/src/data/*' ! -path '*/build/*' ! -path '*/ext/*') @@ -207,6 +213,12 @@ ifeq ($(PLATFORM),gba) INCLUDE_SCANINC_ARGS += -I tools/agbcc/include CPPFLAGS += -D PLATFORM_GBA=1 -D PLATFORM_SDL=0 -D PLATFORM_WIN32=0 -D CPU_ARCH_X86=0 -D CPU_ARCH_ARM=1 -nostdinc -I tools/agbcc/include CC1FLAGS += -fhex-asm + +ifeq ($(BUILD_NAME), sa1) + # It seems this bug was introduced to GCC after SA1 released. + PROLOGUE_FIX := -fprologue-bugfix +endif # BUILD_NAME == sa1 + else CC1FLAGS += -Wstrict-overflow=1 ifeq ($(PLATFORM),sdl) @@ -310,7 +322,7 @@ endif .PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall # Ensure required directories exist -$(shell mkdir -p $(C_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR)) +$(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR)) # a special command which ensures that stdout and stderr # get printed instead of output into the makefile @@ -343,12 +355,23 @@ ifneq ($(NODEP),1) export MACOSX_DEPLOYMENT_TARGET := 11 endif +ifeq ($(PLATFORM),gba) +# Use the old compiler for m4a, as it was prebuilt and statically linked to the original codebase +# PROLOGUE_FIX has to be set to nothing, since -fprologue-bugfix does not work with oldagbcc +$(C_BUILDDIR)/lib/m4a/m4a.o: CC1 := $(CC1_OLD) +$(C_BUILDDIR)/lib/m4a/m4a.o: PROLOGUE_FIX := +# Use `-O1` for agb_flash libs, as these were also prebuilt +$(C_BUILDDIR)/lib/agb_flash/agb_flash.o: CC1FLAGS := -O1 -mthumb-interwork -Werror +$(C_BUILDDIR)/lib/agb_flash/agb_flash%.o: CC1FLAGS := -O1 -mthumb-interwork -Werror +endif + +#### Main Targets #### + ifeq ($(PLATFORM),gba) all: compare compare: rom $(SHA1) $(BUILD_NAME).sha1 - else all: rom endif @@ -390,10 +413,9 @@ sdl_win32: win32: ; @$(MAKE) PLATFORM=win32 CPU_ARCH=i386 +#### RECIPES #### tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1 -#### Recipes #### - include songs.mk include graphics.mk @@ -407,9 +429,9 @@ include graphics.mk %.gbapal: %.pal ; $(GFX) $< $@ %.gbapal: %.png ; $(GFX) $< $@ -chao_garden/mb_chao_garden.gba.lz: chao_garden/mb_chao_garden.gba +chao_garden/mb_chao_garden.gba.lz: chao_garden/mb_chao_garden.gba $(GFX) $< $@ -search 1 - + data/mb_chao_garden_japan.gba.lz: data/mb_chao_garden_japan.gba $(GFX) $< $@ -search 1 @@ -459,21 +481,12 @@ ifeq ($(CREATE_PDB),1) endif endif -ifeq ($(PLATFORM),gba) -# Use the old compiler for m4a, as it was prebuilt and statically linked -# to the original codebase -$(C_BUILDDIR)/lib/m4a/m4a.o: CC1 := $(CC1_OLD) -# Use `-O1` for agb_flash libs, as these were also prebuilt -$(C_BUILDDIR)/lib/agb_flash/agb_flash.o: CC1FLAGS := -O1 -mthumb-interwork -Werror -$(C_BUILDDIR)/lib/agb_flash/agb_flash%.o: CC1FLAGS := -O1 -mthumb-interwork -Werror -endif - # Build c sources, and ensure alignment $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c @echo "$(CC1) -o $@ $<" @$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.i')) @$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i - @$(PREPROC) $(C_BUILDDIR)/$*.i | $(CC1) $(CC1FLAGS) -o $(C_BUILDDIR)/$*.s - + @$(PREPROC) $(C_BUILDDIR)/$*.i | $(CC1) $(PROLOGUE_FIX) $(CC1FLAGS) -o $(C_BUILDDIR)/$*.s - ifeq ($(PLATFORM), gba) @printf ".text\n\t.align\t2, 0\n" >> $(C_BUILDDIR)/$*.s endif @@ -484,15 +497,15 @@ $(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.c @$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d')) $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $< -ifneq ($(NODEP),1) --include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d)) -endif - # rule for sources from the src dir (parts of libraries) $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s @echo "$(AS) -o $@ $<" @$(AS) $(ASFLAGS) -o $@ $< +$(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s $$(asm_dep) + @echo "$(AS) -o $@ $<" + @$(AS) $(ASFLAGS) -o $@ $< + $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s @echo "$(AS) -o $@ $<" @$(PREPROC) $< "" | $(CPP) $(CPPFLAGS) - | $(AS) $(ASFLAGS) -o $@ - @@ -500,8 +513,9 @@ $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s # Scan the ASM data dependencies to determine if any .inc files have changed $(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $< - + ifneq ($(NODEP),1) +-include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d)) -include $(addprefix $(OBJ_DIR)/,$(DATA_ASM_SRCS:.s=.d)) endif @@ -521,7 +535,7 @@ endif chao_garden: tools @$(MAKE) -C chao_garden DEBUG=0 - + # Dependency here is already explicit, but we sometimes get a race condition if this # is not specified multi_boot/subgame_bootstrap/subgame_bootstrap.gba: multi_boot/programs/subgame_loader/subgame_loader.bin @@ -565,7 +579,7 @@ bribasa: $(TOOLDIRS): tool_libs @$(MAKE) -C $@ - + ### DEPS INSTALL COMMANDS ### $(SDL_MINGW_LIB): diff --git a/include/core.h b/include/core.h index 332879bd8..9e599f75b 100644 --- a/include/core.h +++ b/include/core.h @@ -265,7 +265,6 @@ extern u16 gBgCntRegs[4]; // [4]{s16 x, s16 y} extern s16 gBgScrollRegs[NUM_BACKGROUNDS][2]; -extern OamData gUnknown_030022C8; extern OamData gOamBuffer2[OAM_ENTRY_COUNT]; extern OamData gOamBuffer[OAM_ENTRY_COUNT]; @@ -340,8 +339,10 @@ extern struct GraphicsData gVramGraphicsCopyQueueBuffer[32]; extern void *gUnknown_030022AC; extern void *gUnknown_030022C0; +#if (GAME == GAME_SA2) extern s16 gMosaicReg; extern u8 gUnknown_030026F4; +#endif extern u16 gUnknown_03002820; extern u8 gUnknown_03002874; extern void *gUnknown_03002878; diff --git a/include/game/sa1_sa2_shared/globals.h b/include/game/sa1_sa2_shared/globals.h index e0b945f0f..3820b92c2 100644 --- a/include/game/sa1_sa2_shared/globals.h +++ b/include/game/sa1_sa2_shared/globals.h @@ -4,18 +4,24 @@ #include "multi_sio.h" #include "core.h" -#define GAME_MODE_SINGLE_PLAYER 0 -#define GAME_MODE_TIME_ATTACK 1 -#define GAME_MODE_BOSS_TIME_ATTACK 2 +#define GAME_MODE_SINGLE_PLAYER 0 +#define GAME_MODE_TIME_ATTACK 1 #define GAME_MODE_MULTI_PLAYER 3 -#define GAME_MODE_TEAM_PLAY 4 #if (GAME == GAME_SA1) +#define GAME_MODE_RACE 2 +#define GAME_MODE_CHAO_HUNT 4 +#define GAME_MODE_TEAM_PLAY 5 #define GAME_MODE_MULTI_PLAYER_COLLECT_RINGS 6 #elif (GAME == GAME_SA2) +#define GAME_MODE_BOSS_TIME_ATTACK 2 +#define GAME_MODE_TEAM_PLAY 4 #define GAME_MODE_MULTI_PLAYER_COLLECT_RINGS 5 #endif +// TODO: Improve this name; SA1 only? +#define IS_MP_OR_TEAM_PLAY ((gGameMode == GAME_MODE_MULTI_PLAYER) || (gGameMode == GAME_MODE_TEAM_PLAY)) + #if (GAME == GAME_SA1) #define IS_SINGLE_PLAYER ((gGameMode == GAME_MODE_SINGLE_PLAYER) || (gGameMode == GAME_MODE_TIME_ATTACK)) #elif (GAME == GAME_SA2) @@ -23,6 +29,20 @@ ((gGameMode == GAME_MODE_SINGLE_PLAYER) || (gGameMode == GAME_MODE_TIME_ATTACK) || (gGameMode == GAME_MODE_BOSS_TIME_ATTACK)) #endif +#if (GAME == GAME_SA1) +#define GAME_MODE_IS_TIME_ATTACK (gGameMode == GAME_MODE_TIME_ATTACK) +#elif (GAME == GAME_SA2) +#define GAME_MODE_IS_TIME_ATTACK (gGameMode == GAME_MODE_TIME_ATTACK || gGameMode == GAME_MODE_BOSS_TIME_ATTACK) +#endif + +#if (GAME == GAME_SA1) +#define GAME_MODE_REQUIRES_ITEM_RNG \ + ((gGameMode != GAME_MODE_SINGLE_PLAYER) && (gGameMode != GAME_MODE_TIME_ATTACK) && (gGameMode != GAME_MODE_RACE) \ + && (gGameMode != GAME_MODE_MULTI_PLAYER)) +#elif (GAME == GAME_SA2) +#define GAME_MODE_REQUIRES_ITEM_RNG (gGameMode == GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) +#endif + #define IS_MULTI_PLAYER (!(IS_SINGLE_PLAYER)) #define STAGE_FLAG__CLEAR 0x0000 @@ -110,7 +130,7 @@ extern u16 gBossCameraClampYUpper; extern u8 gRandomItemBox; extern u8 gUnknown_030053E0; -extern u8 gUnknown_0300543C; +extern s8 gUnknown_0300543C; extern struct Task *gEntitiesManagerTask; extern u8 gDestroySpotlights; @@ -127,7 +147,7 @@ extern u8 gDifficultyLevel; extern s8 gTrappedAnimalVariant; extern u8 gBossIndex; // TODO: Boss ID in XX-Stage? But it's used in checkpointc.c ... -extern u8 gUnknown_030054F8; +extern u8 gNumSingleplayerCharacters; // Incremented by 1 every frame if the game is not paused. // Starts before the stage-timer that is used for scores does. @@ -168,7 +188,7 @@ extern u8 gMultiplayerConnections; // Only set after the player passed it, used to determine extra score extern s32 gStageGoalX; -extern u8 gUnknown_03005428[4]; +extern u8 gMPRingCollectWins[4]; extern u8 gMultiplayerCharRings[MULTI_SIO_PLAYERS_MAX]; extern RoomEvent gRoomEventQueue[16]; diff --git a/include/game/stage/camera.h b/include/game/stage/camera.h index dee343206..643428023 100644 --- a/include/game/stage/camera.h +++ b/include/game/stage/camera.h @@ -14,11 +14,13 @@ #if !WIDESCREEN_HACK #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 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 @@ -32,7 +34,9 @@ struct Backgrounds { extern const Background gStageCameraBgTemplates[4]; +void InitCamera(u32); void UpdateCamera(void); +void DestroyCameraMovementTask(void); extern const Collision *gRefCollision; diff --git a/include/game/stage/player.h b/include/game/stage/player.h index e627ab4a7..57102a094 100644 --- a/include/game/stage/player.h +++ b/include/game/stage/player.h @@ -19,6 +19,7 @@ void Player_SetMovestate_IsInScriptedSequence(void); void Player_ClearMovestate_IsInScriptedSequence(void); void InitializePlayer(Player *p); +void DestroyPlayerTasks(Player *player); void Player_TransitionCancelFlyingAndBoost(Player *p); void sub_8023B5C(Player *, s32); void sub_8023260(Player *); diff --git a/include/global.h b/include/global.h index cfd068ce4..fd8ba7211 100644 --- a/include/global.h +++ b/include/global.h @@ -32,6 +32,13 @@ typedef void (*VoidFn)(void); // helper macros +// This macro is only needed while SA2 still has variables called gUnknown_XXXXXXX left +#if ((GAME == GAME_SA1) || (GAME == GAME_SA3)) +#define SA2_LABEL(_label) sa2__##_label +#else +#define SA2_LABEL(_label) _label +#endif + #if (PORTABLE) #define BUG_FIX diff --git a/multi_boot/roms/collect_rings/asm/code.s b/multi_boot/roms/collect_rings/asm/code.s index a30c387ff..e4773af78 100644 --- a/multi_boot/roms/collect_rings/asm/code.s +++ b/multi_boot/roms/collect_rings/asm/code.s @@ -24212,7 +24212,7 @@ sub_0200BEA8: @ 0x0200BEA8 asrs r1, r0, #0x18 cmp r1, #0x1c bne _0200BED0 - ldr r0, _0200BEEC @ =gUnknown_03005428 + ldr r0, _0200BEEC @ =gMPRingCollectWins ldrb r0, [r0] cmp r0, #0 beq _0200BF3C @@ -24230,7 +24230,7 @@ _0200BED0: .align 2, 0 _0200BEE4: .4byte gUnknown_03005444 _0200BEE8: .4byte gUnknown_03005524 -_0200BEEC: .4byte gUnknown_03005428 +_0200BEEC: .4byte gMPRingCollectWins _0200BEF0: .4byte gUnknown_03005548 _0200BEF4: ldr r0, _0200BF44 @ =sub_0200BF54 @@ -29385,7 +29385,7 @@ _0200E4BA: asrs r1, r0, #0x18 cmp r1, #0x1c bne _0200E4D6 - ldr r0, _0200E4F4 @ =gUnknown_03005428 + ldr r0, _0200E4F4 @ =gMPRingCollectWins ldrb r0, [r0] cmp r0, #0 beq _0200E4DA @@ -29403,7 +29403,7 @@ _0200E4E4: .4byte gUnknown_03005650 _0200E4E8: .4byte 0x80000080 _0200E4EC: .4byte 0x0000FB20 _0200E4F0: .4byte gUnknown_03005524 -_0200E4F4: .4byte gUnknown_03005428 +_0200E4F4: .4byte gMPRingCollectWins _0200E4F8: .4byte gUnknown_030053F4 _0200E4FC: .4byte gUnknown_03005434 _0200E500: @@ -29961,7 +29961,7 @@ _0200E904: asrs r1, r0, #0x18 cmp r1, #0x1c bne _0200E920 - ldr r0, _0200E98C @ =gUnknown_03005428 + ldr r0, _0200E98C @ =gMPRingCollectWins ldrb r0, [r0] cmp r0, #0 beq _0200E924 @@ -30020,7 +30020,7 @@ _0200E95A: b _0200E9A6 .align 2, 0 _0200E988: .4byte gUnknown_03005524 -_0200E98C: .4byte gUnknown_03005428 +_0200E98C: .4byte gMPRingCollectWins _0200E990: .4byte gUnknown_03005650 _0200E994: .4byte gUnknown_030026D0 _0200E998: .4byte sub_0200E7F8 @@ -32219,7 +32219,7 @@ _0200FA22: asrs r1, r0, #0x18 cmp r1, #0x1c bne _0200FA8A - ldr r0, _0200FAC8 @ =gUnknown_03005428 + ldr r0, _0200FAC8 @ =gMPRingCollectWins ldrb r0, [r0] cmp r0, #0 beq _0200FA8E @@ -32254,7 +32254,7 @@ _0200FA9A: .align 2, 0 _0200FAC0: .4byte gUnknown_02014FB8 _0200FAC4: .4byte gUnknown_03005524 -_0200FAC8: .4byte gUnknown_03005428 +_0200FAC8: .4byte gMPRingCollectWins _0200FACC: .4byte gUnknown_03005650 _0200FAD0: .4byte 0xFFFFBFFF _0200FAD4: .4byte gUnknown_030056C0 @@ -37628,7 +37628,7 @@ sub_02012308: @ 0x02012308 strb r4, [r0] ldr r0, _02012434 @ =gUnknown_0300546C strb r4, [r0] - ldr r0, _02012438 @ =gUnknown_03005428 + ldr r0, _02012438 @ =gMPRingCollectWins strb r4, [r0] ldr r5, _0201243C @ =gUnknown_030053D4 ldrh r0, [r5] @@ -37750,7 +37750,7 @@ _02012428: .4byte sub_020127B4 _0201242C: .4byte gUnknown_030057D0 _02012430: .4byte gUnknown_030053CC _02012434: .4byte gUnknown_0300546C -_02012438: .4byte gUnknown_03005428 +_02012438: .4byte gMPRingCollectWins _0201243C: .4byte gUnknown_030053D4 _02012440: .4byte 0x0000FF7F _02012444: .4byte gUnknown_030053E4 @@ -38038,7 +38038,7 @@ sub_020126AC: @ 0x020126AC ldr r0, _020126DC @ =gUnknown_03005404 movs r1, #0 str r1, [r0] - ldr r0, _020126E0 @ =gUnknown_03005428 + ldr r0, _020126E0 @ =gMPRingCollectWins strb r1, [r0] ldr r1, _020126E4 @ =gUnknown_030053FC movs r0, #3 @@ -38059,7 +38059,7 @@ _020126CA: bx r0 .align 2, 0 _020126DC: .4byte gUnknown_03005404 -_020126E0: .4byte gUnknown_03005428 +_020126E0: .4byte gMPRingCollectWins _020126E4: .4byte gUnknown_030053FC _020126E8: .4byte gUnknown_03005444 diff --git a/multi_boot/roms/collect_rings/sym_iwram.txt b/multi_boot/roms/collect_rings/sym_iwram.txt index 55dc1e177..16d52307c 100644 --- a/multi_boot/roms/collect_rings/sym_iwram.txt +++ b/multi_boot/roms/collect_rings/sym_iwram.txt @@ -161,7 +161,7 @@ . = 0x00005404; gUnknown_03005404 = .; . = 0x00005408; gUnknown_03005408 = .; . = 0x00005418; gUnknown_03005418 = .; -. = 0x00005428; gUnknown_03005428 = .; +. = 0x00005428; gMPRingCollectWins = .; . = 0x0000542C; gUnknown_0300542C = .; . = 0x00005430; gUnknown_03005430 = .; . = 0x00005434; gUnknown_03005434 = .; diff --git a/sound/keysplit_tables.inc b/sound/keysplit_tables.inc index 897515958..c97989d5c 100644 --- a/sound/keysplit_tables.inc +++ b/sound/keysplit_tables.inc @@ -1,3 +1,16 @@ +@ From pret: +@ Due to the way mks4agb (tool) works, key split table labels can +@ appear before the actual start of the key split table data. If you look at +@ the first keysplit table (KeySplitTable1), you'll notice it's offset backwards +@ by 18 bytes (not in SA2!). This is because the key split tables don't map instruments +@ for the entire note range (0-127)--they only map subsets, and the upper +@ and lower ranges aren't necessarily 0 or 127. +@ +@ For example if a key split table maps an note range of 10-20, then the key +@ split table label will be offset 10 bytes before the actual key split data +@ begins. Therefore, the notes naturally map to the key split table without +@ any extra offset calculation. + mAlignWord KeySplitTable1: @ 0x08AD4E20 .byte 1 diff --git a/src/game/multiboot/collect_rings/results.c b/src/game/multiboot/collect_rings/results.c index 121f5ef97..972b92447 100644 --- a/src/game/multiboot/collect_rings/results.c +++ b/src/game/multiboot/collect_rings/results.c @@ -509,10 +509,10 @@ void sub_8082788(void) UpdateSpriteAnimation(s); DisplaySprite(s); - if (gUnknown_03005428[i] > 99) { + if (gMPRingCollectWins[i] > 99) { temp = 99; } else { - temp = Base10DigitsToHexNibbles(gUnknown_03005428[i]); + temp = Base10DigitsToHexNibbles(gMPRingCollectWins[i]); } s = &resultsScreen->unk160[((temp) >> 4)]; diff --git a/src/game/multiboot/connection.c b/src/game/multiboot/connection.c index faa57e327..ee1d13c87 100644 --- a/src/game/multiboot/connection.c +++ b/src/game/multiboot/connection.c @@ -427,7 +427,7 @@ void sub_80818B8(void) if (recv->pat0.unk0 == 0x4010) { for (j = 0; j < 4; j++) { gMultiplayerCharacters[j] = 0; - gUnknown_03005428[j] = 0; + gMPRingCollectWins[j] = 0; gUnknown_030054B4[j] = j; gMultiplayerMissingHeartbeats[j] = 0; } @@ -519,7 +519,7 @@ void ShowSinglePakResults(void) u32 i; for (i = 0; i < MULTI_SIO_PLAYERS_MAX; i++) { gMultiplayerCharacters[i] = 0; - gUnknown_03005428[i] = 0; + gMPRingCollectWins[i] = 0; gUnknown_030054B4[i] = i; gMultiplayerMissingHeartbeats[i] = 0; } diff --git a/src/game/multiplayer/finish.c b/src/game/multiplayer/finish.c index 28d38ee09..9b730518f 100644 --- a/src/game/multiplayer/finish.c +++ b/src/game/multiplayer/finish.c @@ -292,7 +292,7 @@ void Task_TransitionToResultsScreen(void) gMultiplayerCharacters[sp00[i]] = 2; } else { gUnknown_030054B4[sp00[0]] = i; - gUnknown_03005428[sp00[0]]++; + gMPRingCollectWins[sp00[0]]++; gMultiplayerCharacters[sp00[0]] = i; } } diff --git a/src/game/sa1_sa2_shared/globals.c b/src/game/sa1_sa2_shared/globals.c index 822bec521..c4ea08ffe 100644 --- a/src/game/sa1_sa2_shared/globals.c +++ b/src/game/sa1_sa2_shared/globals.c @@ -19,14 +19,14 @@ u8 gActiveCollectRingEffectCount = 0; u32 gMultiplayerIds[MULTI_SIO_PLAYERS_MAX] = {}; u8 gRoomEventQueueSendPos = 0; u16 ALIGNED(4) gStageFlags = 0; -u8 ALIGNED(4) gUnknown_03005428[MULTI_SIO_PLAYERS_MAX] = {}; +u8 ALIGNED(4) gMPRingCollectWins[MULTI_SIO_PLAYERS_MAX] = {}; u8 gBossRingsRespawnCount = 0; bool8 ALIGNED(4) gBossRingsShallRespawn = FALSE; u32 gMultiplayerPseudoRandom = 0; u8 gRoomEventQueueWritePos = 0; -u8 ALIGNED(4) gUnknown_0300543C = 0; +s8 ALIGNED(4) gUnknown_0300543C = 0; u16 ALIGNED(4) gBossCameraClampYLower = 0; s8 ALIGNED(4) gTrappedAnimalVariant = 0; @@ -63,7 +63,7 @@ u8 ALIGNED(4) gDifficultyLevel = 0; s8 ALIGNED(4) gSelectedCharacter = 0; u8 ALIGNED(4) gSpecialRingCount = 0; -u8 ALIGNED(4) gUnknown_030054F8 = 0; +u8 ALIGNED(4) gNumSingleplayerCharacters = 0; s32 gUnknown_030054FC = 0; s8 gMultiplayerCharacters[4] = {}; diff --git a/src/game/sa1_sa2_shared/rings_manager.c b/src/game/sa1_sa2_shared/rings_manager.c index 53b8ee767..44eea4c46 100644 --- a/src/game/sa1_sa2_shared/rings_manager.c +++ b/src/game/sa1_sa2_shared/rings_manager.c @@ -171,7 +171,7 @@ void Task_RingsMgrMain(void) } sp08 = FALSE; - if (gCurrentLevel == LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)) { + if (IS_EXTRA_STAGE(gCurrentLevel)) { u32 res = SuperSonicGetFlags() & (SUPER_FLAG__200 | SUPER_FLAG__10 | SUPER_FLAG__8 | SUPER_FLAG__4); sp08 = TRUE; diff --git a/src/game/stage/camera.c b/src/game/stage/camera.c index f06c6cc86..ec8c8cd02 100644 --- a/src/game/stage/camera.c +++ b/src/game/stage/camera.c @@ -37,7 +37,7 @@ static void RenderMetatileLayers(s32, s32); // camera_destroy.h void Task_CallUpdateCamera(void); -void TaskDestructor_801E040(struct Task *); +void TaskDestructor_Camera(struct Task *); #define BOSS_CAM_FRAME_DELTA_PIXELS 5 @@ -445,7 +445,7 @@ void InitCamera(u32 level) camera->shakeOffsetX = 0; camera->shakeOffsetY = 0; - camera->movementTask = TaskCreate(Task_CallUpdateCamera, 0, 0xF00, 0, TaskDestructor_801E040); + camera->movementTask = TaskCreate(Task_CallUpdateCamera, 0, 0xF00, 0, TaskDestructor_Camera); camera->fnBgUpdate = sStageBgUpdateFuncs[level]; diff --git a/src/game/stage/camera_destroy.c b/src/game/stage/camera_destroy.c index f820aeffd..d40503dc1 100644 --- a/src/game/stage/camera_destroy.c +++ b/src/game/stage/camera_destroy.c @@ -17,7 +17,7 @@ void DestroyCameraMovementTask(void) gCamera.movementTask = NULL; } -void TaskDestructor_801E040(struct Task *unused) +void TaskDestructor_Camera(struct Task *unused) { s32 i; gCamera.movementTask = NULL; @@ -27,7 +27,7 @@ void TaskDestructor_801E040(struct Task *unused) gBgScrollRegs[i][1] = 0; } - if (gCurrentLevel == LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53) && (gFlags & FLAGS_40)) { + if (IS_EXTRA_STAGE(gCurrentLevel) && (gFlags & FLAGS_40)) { gIntrTable[INTR_INDEX_VCOUNT] = gIntrTableTemplate[INTR_INDEX_VCOUNT]; gFlags &= ~FLAGS_40; } @@ -38,9 +38,12 @@ void TaskDestructor_801E040(struct Task *unused) void Task_CallUpdateCamera(void) { gDispCnt |= (DISPCNT_BG1_ON | DISPCNT_BG2_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_ON); - if (gCurrentLevel == LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)) { + +#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; diff --git a/src/game/stage/player.c b/src/game/stage/player.c index e4c20ed8b..921c5313f 100644 --- a/src/game/stage/player.c +++ b/src/game/stage/player.c @@ -6333,7 +6333,7 @@ void Player_HandleWalkAnim(Player *p) void CallSetStageSpawnPos(u32 character, u32 level, u32 playerID, Player *p) { SetStageSpawnPos(character, level, playerID, p); } -void sub_80299FC(Player *p) +void DestroyPlayerTasks(Player *p) { TaskDestroy(p->spriteTask); p->spriteTask = NULL; diff --git a/src/game/stage/stage.c b/src/game/stage/stage.c index 094e0f630..ed2ad8c1d 100644 --- a/src/game/stage/stage.c +++ b/src/game/stage/stage.c @@ -42,7 +42,6 @@ void sub_801F044(void); void sub_80213C0(u32, u32, Player *); void CreateBossRunManager(u8); -void InitCamera(u32); void StageInit_CollectRings(void); void SetupStageIntro(void); @@ -135,7 +134,7 @@ void ApplyGameStageSettings(void) if ((gGameMode == GAME_MODE_TIME_ATTACK || gGameMode == GAME_MODE_BOSS_TIME_ATTACK || gGameMode == GAME_MODE_MULTI_PLAYER || gGameMode == GAME_MODE_TEAM_PLAY) || (gStageFlags & STAGE_FLAG__DEMO_RUNNING)) { - gDifficultyLevel = 0; + gDifficultyLevel = DIFFICULTY_NORMAL; } else { gDifficultyLevel = gLoadedSaveGame->difficultyLevel; } @@ -152,7 +151,9 @@ void GameStageStart(void) gTrappedAnimalVariant = 0; gBossIndex = 0; gRingCount = 0; - gUnknown_030054F8 = 1; + + // Unused leftover var from SA1, used for CPU "Partner" Tails + gNumSingleplayerCharacters = 1; if (gCurrentLevel != LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)) { CallSetStageSpawnPos(gSelectedCharacter, gCurrentLevel, 0, &gPlayer); @@ -195,7 +196,7 @@ void CreateGameStage(void) sub_801F044(); gUnknown_030053E0 = 0; - if (gCurrentLevel != LEVEL_INDEX(ZONE_FINAL, ACT_TRUE_AREA_53)) { + if (!IS_EXTRA_STAGE(gCurrentLevel)) { sub_80213C0(gSelectedCharacter, gCurrentLevel, &gPlayer); } @@ -310,7 +311,7 @@ void Task_GameStage(void) timeStep = framesSinceStageStart - gStageTime; gStageTime = framesSinceStageStart; - if (gGameMode == GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { + if (GAME_MODE_REQUIRES_ITEM_RNG) { if ((framesSinceStageStart & ~(0x1FF)) != ((framesSinceStageStart - timeStep) & ~(0x1FF))) { u32 mask, rand; u32 temp = MultiplayerPseudoRandom32(); @@ -328,7 +329,13 @@ void Task_GameStage(void) u32 temp = MultiplayerPseudoRandom32(); } - if (gCamera.unk50 & CAM_MODE_SPECTATOR) { +#if (GAME == GAME_SA1) + if (gCamera.sa2__unk50 & CAM_MODE_SPECTATOR) +#elif (GAME == GAME_SA2) + if (gCamera.unk50 & CAM_MODE_SPECTATOR) +#endif + { + if ((gInput & (L_BUTTON | R_BUTTON)) == (L_BUTTON | R_BUTTON)) { if (sioId != 3) { gCamera.spectatorTarget = 3; @@ -359,12 +366,22 @@ void Task_GameStage(void) gCamera.spectatorTarget = sioId; } +#if (GAME == GAME_SA1) + if (sa2__gUnknown_030053E0 > 0) { + sa2__gUnknown_030053E0--; + } +#elif (GAME == GAME_SA2) if (gUnknown_030053E0 > 0) { gUnknown_030053E0--; } +#endif } +#if (GAME == GAME_SA1) + sa2__gUnknown_0300544C = gStageFlags; +#elif (GAME == GAME_SA2) gUnknown_0300544C = gStageFlags; +#endif if (gStageFlags & STAGE_FLAG__ACT_START) { return; @@ -381,9 +398,15 @@ void Task_GameStage(void) if (IS_SINGLE_PLAYER) { gStageFlags |= STAGE_FLAG__ACT_START; +#if (GAME == GAME_SA1) + if (gLoadedSaveGame.timeLimitDisabled) { + return; + } +#elif (GAME == GAME_SA2) if (gLoadedSaveGame->timeLimitDisabled) { return; } +#endif gPlayer.itemEffect = 0; @@ -393,14 +416,23 @@ void Task_GameStage(void) gPlayer.qSpeedAirY = -Q(4.875); } - if (gCurrentLevel == LEVEL_INDEX(ZONE_3, ACT_BOSS)) { +#if (GAME == GAME_SA1) + if (gCurrentLevel == LEVEL_INDEX(ZONE_6, ACT_1)) +#elif (GAME == GAME_SA2) + if (gCurrentLevel == LEVEL_INDEX(ZONE_3, ACT_BOSS)) +#endif + { CreateScreenShake(0x800, 8, 16, -1, (SCREENSHAKE_VERTICAL | SCREENSHAKE_HORIZONTAL | SCREENSHAKE_RANDOM_VALUE)); } gPlayer.moveState |= MOVESTATE_DEAD; m4aSongNumStart(SE_TIME_UP); } else { gStageFlags |= STAGE_FLAG__ACT_START; +#if (GAME == GAME_SA1) + sa2__sub_8019F08(); +#elif (GAME == GAME_SA2) sub_8019F08(); +#endif } } else { gCourseTime += timeStep; @@ -411,9 +443,15 @@ void Task_GameStage(void) if (IS_SINGLE_PLAYER) { gStageFlags |= STAGE_FLAG__ACT_START; +#if (GAME == GAME_SA1) + if (gLoadedSaveGame.timeLimitDisabled && (gGameMode == GAME_MODE_SINGLE_PLAYER || IS_MULTI_PLAYER)) { + return; + } +#elif (GAME == GAME_SA2) if (gLoadedSaveGame->timeLimitDisabled && (gGameMode == GAME_MODE_SINGLE_PLAYER || IS_MULTI_PLAYER)) { return; } +#endif gPlayer.itemEffect = 0; @@ -426,7 +464,11 @@ void Task_GameStage(void) m4aSongNumStart(SE_TIME_UP); } else { gStageFlags |= STAGE_FLAG__ACT_START; +#if (GAME == GAME_SA1) + sa2__sub_8019F08(); +#elif (GAME == GAME_SA2) sub_8019F08(); +#endif } } } @@ -435,25 +477,46 @@ void HandleLifeLost(void) { gStageFlags |= STAGE_FLAG__DISABLE_PAUSE_MENU; - if (gGameMode == GAME_MODE_TIME_ATTACK || gGameMode == GAME_MODE_BOSS_TIME_ATTACK) { + if (GAME_MODE_IS_TIME_ATTACK) { TasksDestroyAll(); PAUSE_BACKGROUNDS_QUEUE(); - gUnknown_03005390 = 0; + + SA2_LABEL(gUnknown_03005390) = 0; + PAUSE_GRAPHICS_QUEUE(); CreateTimeAttackLobbyScreen(); +#if (GAME == GAME_SA2) gNumLives = 2; +#endif return; - } - - if (--gNumLives == 0) { - gStageFlags |= STAGE_FLAG__ACT_START; - CreateGameOverScreen(OVER_CAUSE_ZERO_LIVES); } else { - TasksDestroyAll(); - PAUSE_BACKGROUNDS_QUEUE(); - gUnknown_03005390 = 0; - PAUSE_GRAPHICS_QUEUE(); - CreateGameStage(); +#if (GAME == GAME_SA1) + if (IS_SINGLE_PLAYER && (--gNumLives == 0)) +#elif (GAME == GAME_SA2) + if (--gNumLives == 0) +#endif + { + gStageFlags |= STAGE_FLAG__ACT_START; + +#if (GAME == GAME_SA1) + if (SA2_LABEL(gUnknown_0300543C) > 0) { + SA2_LABEL(gUnknown_0300543C)--; + CreateGameOverScreen(OVER_CAUSE_ZERO_LIVES); + } else { + CreateGameOverScreen(OVER_CAUSE_TIME_UP); + } +#else + CreateGameOverScreen(OVER_CAUSE_ZERO_LIVES); +#endif + } else { + TasksDestroyAll(); + PAUSE_BACKGROUNDS_QUEUE(); + + SA2_LABEL(gUnknown_03005390) = 0; + + PAUSE_GRAPHICS_QUEUE(); + CreateGameStage(); + } } } @@ -591,14 +654,18 @@ void StageInit_Zone7ActBoss(void) StageInit_SetMusic_inline(gCurrentLevel); } -void DestroyCameraMovementTask(void); -void sub_80299FC(Player *player); - -void sub_801B68C(void) +void DestroyStageTasks(void) { TaskDestroy(gGameStageTask); gGameStageTask = NULL; - sub_80299FC(&gPlayer); + DestroyPlayerTasks(&gPlayer); + +#if (GAME == GAME_SA1) + if (IS_SINGLE_PLAYER) { + DestroyPlayerTasks(&gPartner); + } +#endif + DestroyCameraMovementTask(); } @@ -623,26 +690,81 @@ void HandleDeath(void) } } -// TODO: // Unused. -// Might be a leftover from the first game? +// Leftover from SA1, but smaller than in there. void GoToNextLevel(void) { + u16 irqEnable, irqMasterEnable, dispStat; + TasksDestroyAll(); PAUSE_BACKGROUNDS_QUEUE(); - gUnknown_03005390 = 0; + SA2_LABEL(gUnknown_03005390) = 0; PAUSE_GRAPHICS_QUEUE(); + +#if (GAME == GAME_SA1) + m4aMPlayAllStop(); + m4aSoundVSyncOff(); + + gFlags |= FLAGS_8000; + irqEnable = REG_IE; + irqMasterEnable = REG_IME; + dispStat = REG_DISPSTAT; + + REG_IE = 0; + REG_IE; + REG_IME = 0; + REG_IME; + REG_DISPSTAT = 0; + REG_DISPSTAT; + + gFlags &= ~FLAGS_4; + + SlowDmaStop(0); + SlowDmaStop(1); + SlowDmaStop(2); + SlowDmaStop(3); +#endif + WriteSaveGame(); - if (gGameMode == 0) { +#if (GAME == GAME_SA1) + REG_IE = irqEnable; + REG_IE; + REG_IME = irqMasterEnable; + REG_IME; + REG_DISPSTAT = dispStat; + REG_DISPSTAT; + + m4aSoundVSyncOn(); + + gFlags &= ~FLAGS_8000; +#endif + +#if (GAME == GAME_SA1) + if (gGameMode != GAME_MODE_TIME_ATTACK) +#elif (GAME == GAME_SA2) + if (gGameMode == GAME_MODE_SINGLE_PLAYER) +#endif + { if (++gCurrentLevel < NUM_LEVEL_IDS) { GameStageStart(); } } +#if (GAME == GAME_SA1) + else { + CreateTimeAttackLobbyScreen(); + } +#endif } void TaskDestructor_GameStage(struct Task *t) { +#if (GAME == GAME_SA1) + if ((gGameMode == GAME_MODE_TIME_ATTACK || (gGameMode == GAME_MODE_RACE) || (gGameMode == GAME_MODE_MULTI_PLAYER)) + || (gStageFlags & STAGE_FLAG__DEMO_RUNNING)) { + gLoadedSaveGame.difficultyLevel = gDifficultyLevel; + } +#endif gGameStageTask = NULL; m4aMPlayAllStop(); } diff --git a/src/lib/agb_flash/agb_flash_le_512k.c b/src/lib/agb_flash/agb_flash_le_512k.c index 10ff2a6bc..5b7e19e57 100644 --- a/src/lib/agb_flash/agb_flash_le_512k.c +++ b/src/lib/agb_flash/agb_flash_le_512k.c @@ -126,6 +126,13 @@ u16 ProgramFlashSector_LE(u16 sectorNum, void *src) if (sectorNum > 15) return 0x80FF; +#if AGBFLASH_USE_V126 + if (gFlash->sector.count == FLASH_ROM_SIZE_1M) { + SwitchFlashBank(sectorNum / SECTORS_PER_BANK); + sectorNum %= SECTORS_PER_BANK; + } +#endif + dest = FLASH_BASE + (sectorNum << gFlash->sector.shift); funcSrc = (u16 *)((intptr_t)VerifyEraseSector_Core ^ 1); funcDest = VerifyEraseSector_Core_Buffer;