diff --git a/.gitignore b/.gitignore index 0fbd6c8a..1649f4d3 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,5 @@ lib/libs2d_engine.a !/lib/PR/hvqm/*.o +# .orig files +*.orig diff --git a/CHANGES b/CHANGES index 67053301..4713fe88 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,49 @@ +Refresh 14 + +1.) Label whomp and some object fields (#1174) +2.) Generate MIO0 object files using binutils `ld` instead of `as` (#1173) +3.) Bowser documentation (#1166) +4.) Fix comment syntax in 00_sound_player.0 (#1172) +5.) Rename in-game menu variables (#1163) +6.) Document double red coin sound and JP sound glitch (#1170) +7.) Document different bug in external.c (#1168) +8.) updated names/types of octagonal platform data (#1164) +9.) Label a number of unnamed variables. (#1169) +10.) Document JP PU sound glitch (#1167) +11.) Set model ids to spawn_triangle_break_particles (#1165) +12.) Fix borders in clear_frame_buffer (#1162) +13.) Fix seq header files for 64-bit (#1161) +14.) Game_init.c remaining doc (#1158) +15.) Label a couple static variables in sound_init.c (#1159) +16.) Properly define dialog values (status, flags, cutscenes) (#1153) +17.) Label all of amp's assets. (#1018) +18.) Split audio/synthesis.c into Shindou/non-Shindou files (#1144) +19.) Avoid CC_CHECK warnings when using gcc (#1157) +20.) level_select_menu.c => title_screen.c (#1152) +21.) Use C preprocessor on assembly files (#1126) +22.) Replace output_level_headers.py with sed equivalent (#1109) +23.) Fix CC_CHECK warnings related to unused symbols and UB (#1155) +24.) Define remaining floor lower limit values (#1147) +25.) use r+b mode for libultra.a patch tool (#1148) +26.) Use proper values for gPrevFrameObjectCount ifs (#1146) +27.) Some minor bowser.inc.c labelling. (#1150) +28.) fix king bob-omb texture pointers (#1145) +29.) Split audio/load.c into Shindou/non-Shindou files (#1143) +30.) Small Shindou audio cleanups (#1142) +31.) Fix endians in ALSeqData (#1141) +32.) Document S8 decoder rsp operation and some more (#1139) +33.) Fix Shindou synthesis_process_note fake match (#1140) +34.) More audio documentation, for the new rsp code and other fixes (#1138) +35.) Build fixes for macOS: cpp, clang, recomp, aiff_extract_codebook (#1135) +36.) Add ENABLE_RUMBLE to config.h (#1122) +37.) Reduce recomp memory consumption by using smaller disassembly blocks (#1128) +38.) Makefile fixes (#1123) +39.) Update README.md +40.) Update README.md +41.) Reflect current decompilation status +42.) Allow both archives and ELF objects to be patched (#1127) +43.) Remove WIP mention in README for sh version. + Refresh 13 2 - No more nonmatchings remain for all builds including Shindou. diff --git a/Makefile b/Makefile index 484b2c28..84330d1b 100644 --- a/Makefile +++ b/Makefile @@ -38,8 +38,9 @@ endif # COMPILER - selects the C compiler to use # gcc - uses the GNU C Compiler +# clang - uses clang C/C++ frontend for LLVM COMPILER ?= gcc -$(eval $(call validate-option,COMPILER,gcc)) +$(eval $(call validate-option,COMPILER,gcc clang)) # LIBGCCDIR - selects the libgcc configuration for checking for dividing by zero @@ -66,7 +67,7 @@ endif DEFINES += NO_ERRNO_H=1 NO_GZIP=1 -COMPRESS ?= yay0 +COMPRESS ?= rnc1 $(eval $(call validate-option,COMPRESS,mio0 yay0 gzip rnc1 rnc2 uncomp)) ifeq ($(COMPRESS),gzip) DEFINES += GZIP=1 @@ -115,9 +116,10 @@ TARGET := sm64.$(VERSION) # f3d_new - default for EU and Shindou versions # f3dex - # f3dex2 - +# l3dex2 - F3DEX2 version that only renders in wireframe # f3dzex - newer, experimental microcode used in Animal Crossing # super3d - extremely experimental version of Fast3D lacking many features for speed -$(eval $(call validate-option,GRUCODE,f3d_old f3dex f3dex2 f3dex2pl f3d_new f3dzex super3d)) +$(eval $(call validate-option,GRUCODE,f3d_old f3dex f3dex2 f3dex2pl f3d_new f3dzex super3d l3dex2)) ifeq ($(GRUCODE),f3d_old) DEFINES += F3D_OLD=1 @@ -127,6 +129,8 @@ else ifeq ($(GRUCODE),f3dex) # Fast3DEX DEFINES += F3DEX_GBI=1 F3DEX_GBI_SHARED=1 else ifeq ($(GRUCODE),f3dex2) # Fast3DEX2 DEFINES += F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1 +else ifeq ($(GRUCODE),l3dex2) # Line3DEX2 + DEFINES += L3DEX2_GBI=1 L3DEX2_ALONE=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1 else ifeq ($(GRUCODE),f3dex2pl) # Fast3DEX2_PosLight DEFINES += F3DEX2PL_GBI=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1 else ifeq ($(GRUCODE),f3dzex) # Fast3DZEX (2.08J / Animal Forest - Dōbutsu no Mori) @@ -153,7 +157,12 @@ LINK_LIBRARIES = $(foreach i,$(LIBRARIES),-l$(i)) ifeq ($(COMPILER),gcc) NON_MATCHING := 1 MIPSISET := -mips3 - OPT_FLAGS := -O2 -g + OPT_FLAGS := -O2 +else ifeq ($(COMPILER),clang) + NON_MATCHING := 1 + # clang doesn't support ABI 'o32' for 'mips3' + MIPSISET := -mips2 + OPT_FLAGS := -O2 endif @@ -286,6 +295,10 @@ ifeq ($(filter clean distclean print-%,$(MAKECMDGOALS)),) ifeq ($(DUMMY),FAIL) $(error Failed to extract assets) endif + DUMMY != $(PYTHON) extract_assets.py jp >&2 || echo FAIL + ifeq ($(DUMMY),FAIL) + $(error Failed to extract assets) + endif endif # Make tools if out of date @@ -317,7 +330,7 @@ ACTOR_DIR := actors LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h))) # Directories containing source files -SRC_DIRS += src src/game src/engine src/audio src/menu src/buffers actors levels bin data assets asm lib sound +SRC_DIRS += src src/boot src/game src/engine src/audio src/menu src/buffers actors levels bin data assets asm lib sound LIBZ_SRC_DIRS := src/libz GODDARD_SRC_DIRS := src/goddard src/goddard/dynlists BIN_DIRS := bin bin/$(VERSION) @@ -385,6 +398,10 @@ export LD_LIBRARY_PATH=./tools AS := $(CROSS)as ifeq ($(COMPILER),gcc) CC := $(CROSS)gcc + $(BUILD_DIR)/actors/%.o: OPT_FLAGS := -O2 -mlong-calls + $(BUILD_DIR)/levels/%.o: OPT_FLAGS := -O2 -mlong-calls +else ifeq ($(COMPILER),clang) + CC := clang endif # Prefer gcc's cpp if installed on the system ifneq (,$(call find-command,cpp-10)) @@ -417,10 +434,13 @@ DEF_INC_CFLAGS := $(foreach i,$(INCLUDE_DIRS),-I$(i)) $(C_DEFINES) # C compiler options CFLAGS = -G 0 $(OPT_FLAGS) $(TARGET_CFLAGS) $(MIPSISET) $(DEF_INC_CFLAGS) ifeq ($(COMPILER),gcc) - CFLAGS += -mno-shared -march=vr4300 -mfix4300 -mabi=32 -mhard-float -mdivide-breaks -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-PIC -mno-abicalls -fno-strict-aliasing -fno-inline-functions -ffreestanding -fwrapv -Wall -Wextra -Wno-missing-braces + CFLAGS += -mno-shared -march=vr4300 -mfix4300 -mabi=32 -mhard-float -mdivide-breaks -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-PIC -mno-abicalls -fno-strict-aliasing -fno-inline-functions -ffreestanding -fwrapv -Wall -Wextra -Wno-missing-braces -fno-jump-tables +else ifeq ($(COMPILER),clang) + CFLAGS += -target mips -mabi=32 -G 0 -mhard-float -fomit-frame-pointer -fno-stack-protector -fno-common -I include -I src/ -I $(BUILD_DIR)/include -fno-PIC -mno-abicalls -fno-strict-aliasing -fno-inline-functions -ffreestanding -fwrapv -Wall -Wextra -Wno-missing-braces -fno-jump-tables else CFLAGS += -non_shared -Wab,-r4300_mul -Xcpluscomm -Xfullwarn -signed -32 endif +ASMFLAGS = -G 0 $(OPT_FLAGS) $(TARGET_CFLAGS) -mips3 $(DEF_INC_CFLAGS) -mno-shared -march=vr4300 -mfix4300 -mabi=32 -mhard-float -mdivide-breaks -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-PIC -mno-abicalls -fno-strict-aliasing -fno-inline-functions -ffreestanding -fwrapv -Wall -Wextra ASFLAGS := -march=vr4300 -mabi=32 $(foreach i,$(INCLUDE_DIRS),-I$(i)) $(foreach d,$(DEFINES),--defsym $(d)) RSPASMFLAGS := $(foreach d,$(DEFINES),-definelabel $(subst =, ,$(d))) @@ -474,8 +494,8 @@ YELLOW := \033[0;33m BLINK := \033[33;5m endif -# Use Objcopy instead of extract_data_for_mio -ifeq ($(COMPILER),gcc) +# For non-IDO, use objcopy instead of extract_data_for_mio +ifneq ($(COMPILER),ido) EXTRACT_DATA_FOR_MIO := $(OBJCOPY) -O binary --only-section=.data endif @@ -492,6 +512,9 @@ all: $(ROM) ifeq ($(COMPARE),1) @$(PRINT) "$(GREEN)Checking if ROM matches.. $(NO_COL)\n" @$(SHA1SUM) --quiet -c $(TARGET).sha1 && $(PRINT) "$(TARGET): $(GREEN)OK$(NO_COL)\n" || ($(PRINT) "$(YELLOW)Building the ROM file has succeeded, but does not match the original ROM.\nThis is expected, and not an error, if you are making modifications.\nTo silence this message, use 'make COMPARE=0.' $(NO_COL)\n" && false) +else + @$(SHA1SUM) $(ROM) + @$(PRINT) "${GREEN}Build succeeded.$(NO_COL)\n" endif clean: @@ -515,17 +538,18 @@ $(BUILD_DIR)/asm/boot.o: $(IPL3_RAW_FILES) $(BUILD_DIR)/src/game/crash_screen.o: $(CRASH_TEXTURE_C_FILES) $(BUILD_DIR)/src/game/version.o: $(BUILD_DIR)/src/game/version_data.h $(BUILD_DIR)/lib/rsp.o: $(BUILD_DIR)/rsp/rspboot.bin $(BUILD_DIR)/rsp/fast3d.bin $(BUILD_DIR)/rsp/audio.bin -$(SOUND_BIN_DIR)/sound_data.o: $(SOUND_BIN_DIR)/sound_data.ctl.inc.c $(SOUND_BIN_DIR)/sound_data.tbl.inc.c $(SOUND_BIN_DIR)/sequences.bin.inc.c $(SOUND_BIN_DIR)/bank_sets.inc.c +$(SOUND_BIN_DIR)/sound_data.o: $(SOUND_BIN_DIR)/sound_data.ctl $(SOUND_BIN_DIR)/sound_data.tbl $(SOUND_BIN_DIR)/sequences.bin $(SOUND_BIN_DIR)/bank_sets $(BUILD_DIR)/levels/scripts.o: $(BUILD_DIR)/include/level_headers.h ifeq ($(VERSION),sh) - $(BUILD_DIR)/src/audio/load.o: $(SOUND_BIN_DIR)/bank_sets.inc.c $(SOUND_BIN_DIR)/sequences_header.inc.c $(SOUND_BIN_DIR)/ctl_header.inc.c $(SOUND_BIN_DIR)/tbl_header.inc.c + $(BUILD_DIR)/src/audio/load_sh.o: $(SOUND_BIN_DIR)/bank_sets.inc.c $(SOUND_BIN_DIR)/sequences_header.inc.c $(SOUND_BIN_DIR)/ctl_header.inc.c $(SOUND_BIN_DIR)/tbl_header.inc.c endif $(CRASH_TEXTURE_C_FILES): TEXTURE_ENCODING := u32 ifeq ($(COMPILER),gcc) $(BUILD_DIR)/src/libz/%.o: OPT_FLAGS := -Os +$(BUILD_DIR)/src/libz/%.o: CFLAGS += -Wno-implicit-fallthrough -Wno-unused-parameter -Wno-pointer-sign endif ifeq ($(VERSION),eu) @@ -565,6 +589,7 @@ $(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h $(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h +$(BUILD_DIR)/src/game/puppycam2.o: $(BUILD_DIR)/include/text_strings.h #==============================================================================# @@ -638,7 +663,7 @@ $(BUILD_DIR)/%.table: %.aiff $(V)$(AIFF_EXTRACT_CODEBOOK) $< >$@ $(BUILD_DIR)/%.aifc: $(BUILD_DIR)/%.table %.aiff - $(call print,Encoding VADPCM:,$<,$@) + $(call print,Encoding ADPCM:,$(word 2,$^),$@) $(V)$(VADPCM_ENC) -c $^ $@ $(ENDIAN_BITWIDTH): $(TOOLS_DIR)/determine-endian-bitwidth.c @@ -646,8 +671,8 @@ $(ENDIAN_BITWIDTH): $(TOOLS_DIR)/determine-endian-bitwidth.c $(V)$(CC) -c $(CFLAGS) -o $@.dummy2 $< 2>$@.dummy1; true $(V)grep -o 'msgbegin --endian .* --bitwidth .* msgend' $@.dummy1 > $@.dummy2 $(V)head -n1 <$@.dummy2 | cut -d' ' -f2-5 > $@ - @$(RM) $@.dummy1 - @$(RM) $@.dummy2 + $(V)$(RM) $@.dummy1 + $(V)$(RM) $@.dummy2 $(SOUND_BIN_DIR)/sound_data.ctl: sound/sound_banks/ $(SOUND_BANK_FILES) $(SOUND_SAMPLE_AIFCS) $(ENDIAN_BITWIDTH) @$(PRINT) "$(GREEN)Generating: $(BLUE)$@ $(NO_COL)\n" @@ -683,7 +708,7 @@ $(SOUND_BIN_DIR)/%.m64: $(SOUND_BIN_DIR)/%.o # Convert binary file to a comma-separated list of byte values for inclusion in C code $(BUILD_DIR)/%.inc.c: $(BUILD_DIR)/% - $(call print,Piping:,$<,$@) + $(call print,Converting to C:,$<,$@) $(V)hexdump -v -e '1/1 "0x%X,"' $< > $@ $(V)echo >> $@ @@ -714,7 +739,7 @@ $(BUILD_DIR)/text/%/define_text.inc.c: text/define_text.inc.c text/%/courses.h t # Level headers $(BUILD_DIR)/include/level_headers.h: levels/level_headers.h.in $(call print,Preprocessing level headers:,$<,$@) - $(V)$(CPP) $(CPPFLAGS) -I . levels/level_headers.h.in | $(PYTHON) $(TOOLS_DIR)/output_level_headers.py > $(BUILD_DIR)/include/level_headers.h + $(V)$(CPP) $(CPPFLAGS) -I . $< | sed -E 's|(.+)|#include "\1"|' > $@ # Generate version_data.h $(BUILD_DIR)/src/game/version_data.h: tools/make_version.sh @@ -736,11 +761,7 @@ $(BUILD_DIR)/%.o: $(BUILD_DIR)/%.c # Assemble assembly code $(BUILD_DIR)/%.o: %.s $(call print,Assembling:,$<,$@) - $(V)$(CC) -c $(CFLAGS) $(foreach i,$(INCLUDE_DIRS),-Wa,-I$(i)) -x assembler-with-cpp -MMD -MF $(BUILD_DIR)/$*.d -o $@ $< - -$(BUILD_DIR)/sound/sequences/00_sound_player.o: sound/sequences/00_sound_player.s - $(call print,Assembling:,$<,$@) - $(V)$(AS) $(ASFLAGS) -MD $(BUILD_DIR)/sound/sequences/00_sound_player.d -o $@ $< + $(V)$(CROSS)gcc -c $(ASMFLAGS) $(foreach i,$(INCLUDE_DIRS),-Wa,-I$(i)) -x assembler-with-cpp -MMD -MF $(BUILD_DIR)/$*.d -o $@ $< # Assemble RSP assembly code $(BUILD_DIR)/rsp/%.bin $(BUILD_DIR)/rsp/%_data.bin: rsp/%.s @@ -748,7 +769,7 @@ $(BUILD_DIR)/rsp/%.bin $(BUILD_DIR)/rsp/%_data.bin: rsp/%.s $(V)$(RSPASM) -sym $@.sym $(RSPASMFLAGS) -strequ CODE_FILE $(BUILD_DIR)/rsp/$*.bin -strequ DATA_FILE $(BUILD_DIR)/rsp/$*_data.bin $< # Run linker script through the C preprocessor -$(BUILD_DIR)/$(LD_SCRIPT): $(LD_SCRIPT) +$(BUILD_DIR)/$(LD_SCRIPT): $(LD_SCRIPT) $(BUILD_DIR)/goddard.txt $(call print,Preprocessing linker script:,$<,$@) $(V)$(CPP) $(CPPFLAGS) -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $< @@ -762,15 +783,34 @@ $(BUILD_DIR)/libz.a: $(LIBZ_O_FILES) @$(PRINT) "$(GREEN)Linking libz: $(BLUE)$@ $(NO_COL)\n" $(V)$(AR) rcs -o $@ $(LIBZ_O_FILES) +# SS2: Goddard rules to get size +$(BUILD_DIR)/sm64_prelim.ld: sm64.ld $(O_FILES) $(YAY0_OBJ_FILES) $(SEG_FILES) $(BUILD_DIR)/libgoddard.a $(BUILD_DIR)/libz.a + $(call print,Preprocessing preliminary linker script:,$<,$@) + $(V)$(CPP) $(CPPFLAGS) -DPRELIMINARY=1 -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $< + +$(BUILD_DIR)/sm64_prelim.elf: $(BUILD_DIR)/sm64_prelim.ld + @$(PRINT) "$(GREEN)Linking Preliminary ELF file: $(BLUE)$@ $(NO_COL)\n" + $(V)$(LD) --gc-sections -L $(BUILD_DIR) -T undefined_syms.txt -T $< -Map $(BUILD_DIR)/sm64_prelim.map --no-check-sections $(addprefix -R ,$(SEG_FILES)) -o $@ $(O_FILES) -L$(LIBS_DIR) -l$(ULTRALIB) -Llib $(LINK_LIBRARIES) -u sprintf -u osMapTLB -Llib/gcclib/$(LIBGCCDIR) -lgcc + +$(BUILD_DIR)/goddard.txt: $(BUILD_DIR)/sm64_prelim.elf + $(call print,Getting Goddard size...) + $(V)python3 tools/getGoddardSize.py $(BUILD_DIR)/sm64_prelim.map $(VERSION) + # Link SM64 ELF file -$(ELF): $(O_FILES) $(YAY0_OBJ_FILES) $(SEG_FILES) $(BUILD_DIR)/$(LD_SCRIPT) undefined_syms.txt $(BUILD_DIR)/libz.a $(BUILD_DIR)/libgoddard.a +$(ELF): $(BUILD_DIR)/sm64_prelim.elf $(O_FILES) $(YAY0_OBJ_FILES) $(SEG_FILES) $(BUILD_DIR)/$(LD_SCRIPT) undefined_syms.txt $(BUILD_DIR)/libz.a $(BUILD_DIR)/libgoddard.a @$(PRINT) "$(GREEN)Linking ELF file: $(BLUE)$@ $(NO_COL)\n" - $(V)$(LD) --gc-sections -L $(BUILD_DIR) -T undefined_syms.txt -T $(BUILD_DIR)/$(LD_SCRIPT) -Map $(BUILD_DIR)/sm64.$(VERSION).map --no-check-sections $(addprefix -R ,$(SEG_FILES)) -o $@ $(O_FILES) -L$(LIBS_DIR) -l$(ULTRALIB) -Llib $(LINK_LIBRARIES) -u sprintf -u osMapTLB -Llib/gcclib/$(LIBGCCDIR) -lgcc + $(V)$(LD) --gc-sections -L $(BUILD_DIR) -T undefined_syms.txt -T $(BUILD_DIR)/$(LD_SCRIPT) -T goddard.txt -Map $(BUILD_DIR)/sm64.$(VERSION).map --no-check-sections $(addprefix -R ,$(SEG_FILES)) -o $@ $(O_FILES) -L$(LIBS_DIR) -l$(ULTRALIB) -Llib $(LINK_LIBRARIES) -u sprintf -u osMapTLB -Llib/gcclib/$(LIBGCCDIR) -lgcc # Build ROM $(ROM): $(ELF) $(call print,Building ROM:,$<,$@) - $(V)$(OBJCOPY) --pad-to=0x800000 --gap-fill=0xFF $< $@ -O binary +ifeq ($(CONSOLE),n64) + $(V)$(OBJCOPY) --pad-to=0x101000 --gap-fill=0xFF $< $@ -O binary +else ifeq ($(CONSOLE),bb) + $(V)$(OBJCOPY) --gap-fill=0x00 $< $@ -O binary + $(V)dd if=$@ of=tmp bs=16K conv=sync + $(V)mv tmp $@ +endif $(V)$(N64CKSUM) $@ $(BUILD_DIR)/$(TARGET).objdump: $(ELF) diff --git a/Makefile.split b/Makefile.split index 0e0eab6c..43c08655 100644 --- a/Makefile.split +++ b/Makefile.split @@ -161,8 +161,8 @@ endef ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),distclean) $(BUILD_DIR)/level_rules.mk: levels/level_rules.mk levels/level_defines.h - @$(PRINT) "$(GREEN)Preprocessing level make rules: $(BLUE)$@ $(NO_COL)\n" - @$(CPP) $(VERSION_CFLAGS) -I . -o $@ $< + $(call print,Preprocessing level make rules:,$<,$@) + $(V)$(CPP) $(CPPFLAGS) $(VERSION_CFLAGS) -I . -o $@ $< include $(BUILD_DIR)/level_rules.mk endif endif @@ -179,11 +179,11 @@ $(eval $(call level_rules,menu,generic)) # Menu (File Select) # Ending cake textures are generated in a special way $(BUILD_DIR)/levels/ending/cake_eu.inc.c: levels/ending/cake_eu.png - @$(PRINT) "$(GREEN)Splitting $(YELLOW)$< $(GREEN)to: $(BLUE)$@ $(NO_COL)\n" - @$(SKYCONV) --type cake-eu --split $^ $(BUILD_DIR)/levels/ending + $(call print,Splitting:,$<,$@) + $(V)$(SKYCONV) --type cake-eu --split $^ $(BUILD_DIR)/levels/ending $(BUILD_DIR)/levels/ending/cake.inc.c: levels/ending/cake.png - @$(PRINT) "$(GREEN)Splitting $(YELLOW)$< $(GREEN)to: $(BLUE)$@ $(NO_COL)\n" - @$(SKYCONV) --type cake --split $^ $(BUILD_DIR)/levels/ending + $(call print,Splitting:,$<,$@) + $(V)$(SKYCONV) --type cake --split $^ $(BUILD_DIR)/levels/ending # -------------------------------------- # Texture Bin Rules @@ -250,7 +250,7 @@ $(BUILD_DIR)/bin/eu/translation_fr.elf: SEGMENT_ADDRESS := 0x19000000 # -------------------------------------- $(BUILD_DIR)/bin/%_skybox.c: textures/skyboxes/%.png - $(V)$(PRINT) "$(GREEN)Splitting $(YELLOW)$< $(GREEN)to: $(BLUE)$@ $(NO_COL)\n" + $(call print,Splitting:,$<,$@) $(V)$(SKYCONV) --type sky --split $^ $(BUILD_DIR)/bin $(BUILD_DIR)/bin/%_skybox.elf: SEGMENT_ADDRESS := 0x0A000000 diff --git a/README.md b/README.md index 0f2c3738..4e02802f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,20 @@ -# UltraSM64-extbounds +# ![](https://i.imgur.com/CeOukzk.gif) HackerSM64 ![](https://i.imgur.com/s0LUbTo.gif) **AFTER CLONING THE REPO, CHECK OUT THE `include/config.h` FILE BEFORE ANYTHING ELSE! IT THERE'S A LOT OF STUFF IN THIS REPO THAT CAN BE TOGGLED THERE.** +HackerSM64 now has a discord server! https://discord.gg/brETAakcXr + +This repo needs BOTH an US ROM and a JP ROM in order to build. Place baserom.us.z64 in the repo as usual and ALSO place baserom.jp.z64 + This repo needs gcc in order to be able to build it. To install it, run `sudo apt install gcc-mips-linux-gnu` This is a fork of the ultrasm64 repo by CrashOveride which includes the following commonly used patches (patches marked with `*` are toggleable in `config.h`): +**Lighting Engine by Wiseguy** +- Lighting Engine is available on a separate branch `(lighting-engine)`. Instructions on how to use it are in the readme of that branch. + +**Puppycam** +- Puppycam is available on the master branch now, you can toogle it in config.h. * + **Collision:** - Slope fix and exposed ceilings fix - No false ledgegrabs fix * @@ -17,6 +27,7 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - Platform Displacement 2 by Arthurtilly * - Water Surface Type patch by thecozies - Rounded corners by FramePerfection, merged by Cheezepin +- Automatically calculate the optimal collision distance for an object based on its vertices, by Kaze * **Common Hack Changes:** - Better extended boundaries by anonymous_moose @@ -27,27 +38,41 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - Nonstop stars * - Removed course-specific camera processing * - You can increase the number of frames that you have to perform a firsty * +- Ability to set Mario's movement speed when hanging from a ceiling * +- Tighter hanging controls (mario will face the direction of the analog stick directly while hanging from a ceiling) * +- reonucam3: custom camera by me. This is included as a .patch file in the enhancements folder, you need to apply it if you want this camera. + This video shows a rundown of the features: https://youtu.be/TQNkznX9Z3k **Hacker QOL:** - Global, non-level based, star IDs (off by default) * -- FPS counter (use the function `print_fps(x,y)` anywhere that runs code every frame) +- Debug mode: prints mario's coordinates, angle and speed, and a FPS counter. - Automatic console/emulator detection. If emulator is detected, LODs are disabled. * - Ability to configure whether there's a 100 coin star at all and how many coins are required to spawn it * -- Ability to easily change the warp that EXIT COURSE takes you to via config.h, or disable it entirely -- 16 bit model IDs by someone2639. This means you can have up to 65536 models (lol) +- Ability to easily change the warp that EXIT COURSE takes you to via config.h, or disable it entirely. * +- 16 bit model IDs by someone2639. This means you can have up to 65536 models (lol). You can set the maximum number of model IDs in `config.h`. - Apply_patch.sh improved - Removed the ifdef hell in `file_select.c` and `ingame_menu.c` - Added Blake's custom function for object model stuff: `obj_set_model` and `obj_has_model` - The "far" variable is now u16, allowing you to increase the farclip (the max distance at which geometry is rendered). However, when increasing the farclip, make sure to increase the nearclip by the same ratio, or rendering will break on console and LLE plugins. - Many general use defines for object struct members, meant for use in custom object behaviors. Check `object_fields.h` for more info on this. (By MrComit) - Included `actors/group0.c` in `behavior_data.c` +- The internal ROM name is now set with a define in `config.h` to make it simpler +- There is a `gIsConsole` variable that is 1 when running on console and 0 when running on emulator. This way you can wrap your code in a console check. +- Expanded audio heap allows for a larger concurrent note count and the importing of more m64 sequences and sound banks (By ArcticJaguar725) * +- You can set a test level in config.h in order to boot straight into it, so you can quickly test the level you're working on. * +- Allows all surfaces in the game to have a `force` parameter. Activating this doesn't REQUIRE you to set `force` for every surface: If you don't set, it will default to 0x0000 rather than crashing. Increases RAM usage of collision. * +- The clown font includes the entire English alphabet. +- Colored ia4 text support. Format: `"@XXXXXXXX[YOUR TEXT]@--------"` (By ArcticJaguar725) + - Example Text: `"@FF0000FFRED @00FF00FFGREEN @0000FFFFBLUE @FFFFFF00INVISIBLE @--------NORMAL"` + - NOTE: It is not mandatory to reset the text color with `"@--------"`, but text will need to be recolored each time it scrolls in a dialog box, or the custom color will reset. +- Toggle visiblity of collision surfaces and object hitboxes with Visual Surface Debug. `config.h` has VISUAL_DEBUG which can be turned on to enable this feature. **Other Bugfixes:** - Castle music fix (Fixes the castle music sometimes triggering after getting a dialog) * - bparam4 fix (the game no longer uses bparam4 to check if an object is mario and therefore you can safely use it) - Instant warp offset fix (makes the instant warp offset work even when warping to a different area) * - haveyourcake, also known as cake screen fix. Made by Wiseguy and ported/PR'd by Cheezepin -- Tree particle fix (Whether a tree uses snow particles or not is decided via the model IDs instead of the course number) +- Tree particle fix (Whether a tree uses snow particles or not is decided via the model IDs instead of the course number) * - Coordinate overflow fix by falcobuster. Your levels will render correctly on console and LLE emulators even when using 2x or 4x bounds, while not hurting anything on HLE plugins. *This is automatic now, you don't have to set WORLD_SCALE manually.* - A couple vanilla texture fixes - Smoke fix (the smoke texture uses the correct texture format) @@ -57,7 +82,15 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - This means that you'll have to do your framebuffer effects on buffer 0 for emulator, but NOT for console. You can use the `gIsConsole` variable to check for console when doing your framebuffer effects. - Widescreen (16:9) support toggleable by pressing `L` in the pause menu. * - S2DEX engine by someone2639! To use it, compile with `make TEXT_ENGINE=s2dex_text_engine` or just set `TEXT_ENGINE` to `s2dex_text_engine` in the makefile. -- ia8 coins (64x64), the vanilla coin texture is upgraded to accomodate. +- ia8 coins (64x64), the vanilla coin texture is upgraded to accomodate. * +- Skybox size modifier. You can have 2x, 3x and 4x size skyboxes (you can select the skybox size in `config.h`.) Please note that this might affect console performance, especially 4x mode. 2x or 3x mode is recommended if aiming for console. By CowQuack * +- You can set the black border size to different values for console and emulator. It's set to 0 by default for both. * +- This repo supports much better implementation of reverb over vanilla's fake echo reverb. Great for caves or eerie levels, as well as just a better audio experience in general. See `audio/synthesis.c` for more configuration info. (By ArcticJaguar725) * +- Fazana's "puppyprint" text engine. * + - Use `print_small_text` to print normal text. The two last params are aligment and how many characters to print (-1 means PRINT_ALL). + - Use `render_multi_image` to draw large texture rectangles consisting of multiple images on the screen. + - More info in `puppyprint.c` +- Wiseguy's Farcall TLB mapping allows to store executable code inside uncompressed segments, that can be loaded and ran as needed, instead of it having to be loaded at all times. See `farcall.h` in the include folder for instructions and details. # UltraSM64 @@ -70,6 +103,10 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - Newer compression options are supported. - UNFLoader (flashcart USB library) is supported, allowing for debugging on EverDrive/64Drive. - It has been patched with someone2639's shiftable segments patch +- Wiseguy's instant input patch has been added to allow for less input lag on emulation (Does not affect console) + This does mean that any framebuffer effects will have to be done on buffer 0 if targeting emulators +- Automatic console and emulator detection: Use the `gIsConsole` variable to wrap your code in an emulator check. +- Separate defines for emulator and console black border height. - Getting HVQM FMV support to work with the game is WIP. Requirements are the same as regular SM64, however a GCC MIPS cross compiler is also required. If you're on Debian-like Linux, you can use the ``gcc-mips-linux-gnu`` package. The toolchain that comes with my SDK is also supported. @@ -92,21 +129,28 @@ The repository supports targeting the iQue Player in addition to the N64. The iQ To target iQue, run make with the ``CONSOLE=bb`` argument. ## Compression -The repository supports using DEFLATE compression instead of Nintendo's Yay0. This boasts a better compression ratio, but at a slight cost to load times. + +The repo also supports RNC (Rob Northen Compression). RNC has two methods. + +Method 1 is designed to compress as small as possible, while method 2 is designed so that decompression is as fast as possible. + +Method 1 is the current default, and is the best all-rounder in terms of speed and ratio. + +Both methods are fast. Method 1 has better compression than 2, so I suggest using method 1 if using RNC. + +To switch to RNC, run make with either ``COMPRESS=rnc1`` or ``COMPRESS=rnc2``, depending on preferred method. + +The repository also supports using DEFLATE compression. This boasts a better compression ratio, but at a slight cost to load times. On average I'd estimate that the bottleneck on decompression is about 1-2 seconds. To switch to gzip, run make with the ``COMPRESS=gzip`` argument. The repo also supports gziping with ``libdeflate-gzip``. This compresses at a slightly better ratio than standard ``gzip``, with no real downside from a decompression standpoint. -To use ``libdeflate-gzip``, first clone the [repo](https://github.com/ebiggers/libdeflate), then make and make install it. + +To use ``libdeflate-gzip``, first clone the [repo](https://github.com/ebiggers/libdeflate), then `make` and `make install` it. + Then run make for sm64 with ``GZIPVER=libdef`` in addition to ``COMPRESS=gzip`` -The repo also supports RNC (Rob Northen Compression). RNC has two methods. -Method 1 is designed to compress as small as possible, while method 2 is designed so that decompression is as fast as possible. - -Both methods are fast. Method 1 has better compression than 2, so I suggest using method 1 if using RNC. -To switch to RNC, run make with either ``COMPRESS=rnc1`` or ``COMPRESS=rnc2``, depending on preferred method. - The repo also supports building a ROM with no compression. This is not recommended as it increases ROM size significantly, with little point other than load times decreased to almost nothing. To switch to no compression, run make with the ``COMPRESS=uncomp`` argument. diff --git a/actors/amp/anims/anim_0800401C.inc.c b/actors/amp/anims/animation.inc.c similarity index 87% rename from actors/amp/anims/anim_0800401C.inc.c rename to actors/amp/anims/animation.inc.c index f114dcfc..2763f4dc 100644 --- a/actors/amp/anims/anim_0800401C.inc.c +++ b/actors/amp/anims/animation.inc.c @@ -1,5 +1,4 @@ -// 0x08003E30 -static const s16 amp_seg8_animvalue_08003E30[] = { +static const s16 dAmpAnimValue[] = { 0x0000, 0x0000, 0x0D79, 0x1AF2, 0x286B, 0x35E4, 0x435D, 0x50D6, 0x5E50, 0x6BC9, 0x7942, 0x86BE, 0x9437, 0xA1B0, 0xAF2A, 0xBCA3, 0xCA1C, 0xD795, 0xE50E, 0xF287, 0x1872, 0x0000, 0x1AF2, 0x35E4, @@ -23,8 +22,7 @@ static const s16 amp_seg8_animvalue_08003E30[] = { 0xC001, 0x3FFF, }; -// 0x08003F74 -static const u16 amp_seg8_animindex_08003F74[] = { +static const u16 dAmpAnimIndex[] = { 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x00A1, 0x0001, 0x0000, 0x0013, 0x008D, 0x0001, 0x00A0, @@ -40,15 +38,14 @@ static const u16 amp_seg8_animindex_08003F74[] = { 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x004E, }; -// 0x0800401C -static const struct Animation amp_seg8_anim_0800401C = { +static const struct Animation dAmpAnimation = { 0, 0, 0, 0, 0x13, - ANIMINDEX_NUMPARTS(amp_seg8_animindex_08003F74), - amp_seg8_animvalue_08003E30, - amp_seg8_animindex_08003F74, + ANIMINDEX_NUMPARTS(dAmpAnimIndex), + dAmpAnimValue, + dAmpAnimIndex, 0, }; diff --git a/actors/amp/anims/data.inc.c b/actors/amp/anims/data.inc.c index ad33202f..ed31deb4 100644 --- a/actors/amp/anims/data.inc.c +++ b/actors/amp/anims/data.inc.c @@ -1 +1 @@ -#include "anim_0800401C.inc.c" +#include "animation.inc.c" diff --git a/actors/amp/anims/table.inc.c b/actors/amp/anims/table.inc.c index 77485e89..33e67941 100644 --- a/actors/amp/anims/table.inc.c +++ b/actors/amp/anims/table.inc.c @@ -1,4 +1,3 @@ -// 0x08004034 -const struct Animation *const amp_seg8_anims_08004034[] = { - &_seg8_anim_0800401C, +const struct Animation *const dAmpAnimsList[] = { + &dAmpAnimation, }; diff --git a/actors/amp/geo.inc.c b/actors/amp/geo.inc.c index 378a84bb..9c9e1d69 100644 --- a/actors/amp/geo.inc.c +++ b/actors/amp/geo.inc.c @@ -1,19 +1,18 @@ -// 0x0F000028 -const GeoLayout amp_geo[] = { +const GeoLayout dAmpGeo[] = { GEO_SHADOW(SHADOW_CIRCLE_4_VERTS, 0xC8, 100), GEO_OPEN_NODE(), GEO_SCALE(0x00, 16384), GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, amp_seg8_dl_08002C88), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, dAmpEyeDl), GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), GEO_SWITCH_CASE(2, geo_switch_anim_state), GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), - GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, amp_seg8_dl_08002BA0), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, dAmpElectricityDl), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), @@ -21,7 +20,7 @@ const GeoLayout amp_geo[] = { GEO_SWITCH_CASE(2, geo_switch_anim_state), GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), - GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, amp_seg8_dl_08002BA0), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, dAmpElectricityDl), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), @@ -29,7 +28,7 @@ const GeoLayout amp_geo[] = { GEO_SWITCH_CASE(2, geo_switch_anim_state), GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), - GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, amp_seg8_dl_08002BA0), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, dAmpElectricityDl), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), @@ -37,16 +36,16 @@ const GeoLayout amp_geo[] = { GEO_SWITCH_CASE(2, geo_switch_anim_state), GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), - GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, amp_seg8_dl_08002BA0), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, dAmpElectricityDl), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, amp_seg8_dl_08002D70), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, dAmpMouthDl), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), GEO_BILLBOARD(), GEO_OPEN_NODE(), - GEO_DISPLAY_LIST(LAYER_ALPHA, amp_seg8_dl_08002E58), + GEO_DISPLAY_LIST(LAYER_ALPHA, dAmpBodyDl), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), diff --git a/actors/amp/model.inc.c b/actors/amp/model.inc.c index 15745bd0..67185c8f 100644 --- a/actors/amp/model.inc.c +++ b/actors/amp/model.inc.c @@ -1,27 +1,22 @@ // Amp -// 0x08000F18 -ALIGNED8 static const Texture amp_seg8_texture_08000F18[] = { +ALIGNED8 static const Texture dAmpElectricityTexture[] = { #include "actors/amp/amp_electricity.rgba16.inc.c" }; -// 0x08001318 -ALIGNED8 static const Texture amp_seg8_texture_08001318[] = { +ALIGNED8 static const Texture dAmpEyesTexture[] = { #include "actors/amp/amp_eyes.rgba16.inc.c" }; -// 0x08001B18 -ALIGNED8 static const Texture amp_seg8_texture_08001B18[] = { +ALIGNED8 static const Texture dAmpBodyTexture[] = { #include "actors/amp/amp_body.rgba16.inc.c" }; -// 0x08002318 -ALIGNED8 static const Texture amp_seg8_texture_08002318[] = { +ALIGNED8 static const Texture dAmpMouthTexture[] = { #include "actors/amp/amp_mouth.rgba16.inc.c" }; -// 0x08002B18 -static const Vtx amp_seg8_vertex_08002B18[] = { +static const Vtx dAmpElectricityVertices[] = { {{{ 224, 0, -89}, 0, { 0, 480}, {0xff, 0xff, 0xff, 0xff}}}, {{{ 187, 149, 0}, 0, { 223, 1078}, {0xff, 0xff, 0xff, 0xff}}}, {{{ 224, 0, 90}, 0, { 479, 478}, {0xff, 0xff, 0xff, 0xff}}}, @@ -29,18 +24,16 @@ static const Vtx amp_seg8_vertex_08002B18[] = { {{{ 224, 0, -89}, 0, { 0, 478}, {0xff, 0xff, 0xff, 0xff}}}, }; -// 0x08002B68 - 0x08002BA0 -const Gfx amp_seg8_dl_08002B68[] = { - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, amp_seg8_texture_08000F18), +const Gfx dAmpElectricitySubDl[] = { + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dAmpElectricityTexture), gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 16 * 32 - 1, CALC_DXT(16, G_IM_SIZ_16b_BYTES)), - gsSPVertex(amp_seg8_vertex_08002B18, 5, 0), + gsSPVertex(dAmpElectricityVertices, 5, 0), gsSP2Triangles( 0, 1, 2, 0x0, 2, 3, 4, 0x0), gsSPEndDisplayList(), }; -// 0x08002BA0 - 0x08002C10 -const Gfx amp_seg8_dl_08002BA0[] = { +const Gfx dAmpElectricityDl[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), gsSPClearGeometryMode(G_LIGHTING | G_CULL_BACK), @@ -49,7 +42,7 @@ const Gfx amp_seg8_dl_08002BA0[] = { gsDPTileSync(), gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 5, G_TX_NOLOD, G_TX_CLAMP, 4, G_TX_NOLOD), gsDPSetTileSize(0, 0, 0, (16 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC), - gsSPDisplayList(amp_seg8_dl_08002B68), + gsSPDisplayList(dAmpElectricitySubDl), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), @@ -57,26 +50,23 @@ const Gfx amp_seg8_dl_08002BA0[] = { gsSPEndDisplayList(), }; -// 0x08002C10 -static const Vtx amp_seg8_vertex_08002C10[] = { +static const Vtx dAmpEyeVertices[] = { {{{ 68, 72, 158}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}}, {{{ -27, -71, 164}, 0, { 990, 990}, {0xff, 0xff, 0xff, 0xff}}}, {{{ 68, -71, 158}, 0, { 990, 0}, {0xff, 0xff, 0xff, 0xff}}}, {{{ -27, 72, 164}, 0, { 0, 990}, {0xff, 0xff, 0xff, 0xff}}}, }; -// 0x08002C50 - 0x08002C88 -const Gfx amp_seg8_dl_08002C50[] = { - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, amp_seg8_texture_08001318), +const Gfx dAmpEyeSubDl[] = { + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dAmpEyesTexture), gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)), - gsSPVertex(amp_seg8_vertex_08002C10, 4, 0), + gsSPVertex(dAmpEyeVertices, 4, 0), gsSP2Triangles( 0, 1, 2, 0x0, 0, 3, 1, 0x0), gsSPEndDisplayList(), }; -// 0x08002C88 - 0x08002CF8 -const Gfx amp_seg8_dl_08002C88[] = { +const Gfx dAmpEyeDl[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), gsSPClearGeometryMode(G_LIGHTING), @@ -85,7 +75,7 @@ const Gfx amp_seg8_dl_08002C88[] = { gsDPTileSync(), gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 5, G_TX_NOLOD, G_TX_CLAMP, 5, G_TX_NOLOD), gsDPSetTileSize(0, 0, 0, (32 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC), - gsSPDisplayList(amp_seg8_dl_08002C50), + gsSPDisplayList(dAmpEyeSubDl), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), @@ -93,26 +83,23 @@ const Gfx amp_seg8_dl_08002C88[] = { gsSPEndDisplayList(), }; -// 0x08002CF8 -static const Vtx amp_seg8_vertex_08002CF8[] = { +static const Vtx dAmpMouthVertices[] = { {{{ -29, 72, 164}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}}, {{{ -124, -71, 121}, 0, { 990, 990}, {0xff, 0xff, 0xff, 0xff}}}, {{{ -29, -71, 164}, 0, { 990, 0}, {0xff, 0xff, 0xff, 0xff}}}, {{{ -124, 72, 121}, 0, { 0, 990}, {0xff, 0xff, 0xff, 0xff}}}, }; -// 0x08002D38 - 0x08002D70 -const Gfx amp_seg8_dl_08002D38[] = { - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, amp_seg8_texture_08002318), +const Gfx dAmpMouthSubDl[] = { + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dAmpMouthTexture), gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)), - gsSPVertex(amp_seg8_vertex_08002CF8, 4, 0), + gsSPVertex(dAmpMouthVertices, 4, 0), gsSP2Triangles( 0, 1, 2, 0x0, 0, 3, 1, 0x0), gsSPEndDisplayList(), }; -// 0x08002D70 - 0x08002DE0 -const Gfx amp_seg8_dl_08002D70[] = { +const Gfx dAmpMouthDl[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), gsSPClearGeometryMode(G_LIGHTING), @@ -121,7 +108,7 @@ const Gfx amp_seg8_dl_08002D70[] = { gsDPTileSync(), gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 5, G_TX_NOLOD, G_TX_CLAMP, 5, G_TX_NOLOD), gsDPSetTileSize(0, 0, 0, (32 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC), - gsSPDisplayList(amp_seg8_dl_08002D38), + gsSPDisplayList(dAmpMouthSubDl), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), @@ -129,26 +116,23 @@ const Gfx amp_seg8_dl_08002D70[] = { gsSPEndDisplayList(), }; -// 0x08002DE0 -static const Vtx amp_seg8_vertex_08002DE0[] = { +static const Vtx dAmpBodyVertices[] = { {{{ -39, -39, 0}, 0, { 0, 990}, {0xff, 0xff, 0xff, 0xff}}}, {{{ 40, 40, 0}, 0, { 990, 0}, {0xff, 0xff, 0xff, 0xff}}}, {{{ -39, 40, 0}, 0, { 0, 0}, {0xff, 0xff, 0xff, 0xff}}}, {{{ 40, -39, 0}, 0, { 990, 990}, {0xff, 0xff, 0xff, 0xff}}}, }; -// 0x08002E20 - 0x08002E58 -const Gfx amp_seg8_dl_08002E20[] = { - gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, amp_seg8_texture_08001B18), +const Gfx dAmpBodySubDl[] = { + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dAmpBodyTexture), gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)), - gsSPVertex(amp_seg8_vertex_08002DE0, 4, 0), + gsSPVertex(dAmpBodyVertices, 4, 0), gsSP2Triangles( 0, 1, 2, 0x0, 0, 3, 1, 0x0), gsSPEndDisplayList(), }; -// 0x08002E58 - 0x08002EC8 -const Gfx amp_seg8_dl_08002E58[] = { +const Gfx dAmpBodyDl[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), gsSPClearGeometryMode(G_LIGHTING), @@ -157,7 +141,7 @@ const Gfx amp_seg8_dl_08002E58[] = { gsDPTileSync(), gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 5, G_TX_NOLOD, G_TX_CLAMP, 5, G_TX_NOLOD), gsDPSetTileSize(0, 0, 0, (32 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC), - gsSPDisplayList(amp_seg8_dl_08002E20), + gsSPDisplayList(dAmpBodySubDl), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), @@ -165,15 +149,18 @@ const Gfx amp_seg8_dl_08002E58[] = { gsSPEndDisplayList(), }; -// 0x08002EC8 -static const Lights1 amp_seg8_lights_08002EC8 = gdSPDefLights1( +/** + * Everything beyond this point is unused, and seems to be an attempt at a 3D modelled + * amp. The model and attempt are overall slightly buggy, with misread lights and a slightly + * broken model. + */ + +UNUSED static const Lights1 dAmpUnused3DLights = gdSPDefLights1( 0x33, 0x3f, 0x00, 0xcf, 0xff, 0x00, 0x28, 0x28, 0x28 ); -// //! Another malformed entry: Vertex interpreted as light -// 0x08002EE0 -static const Vtx amp_seg8_vertex_08002EE0[] = { +UNUSED static const Vtx dAmpUnused3DVtx01[] = { {{{ 280, 0, 35}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, {{{ 240, -160, 0}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, {{{ 280, 0, -35}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, @@ -182,8 +169,7 @@ static const Vtx amp_seg8_vertex_08002EE0[] = { {{{ 280, 0, 35}, 0, { 0, 0}, {0x7b, 0x1e, 0x00, 0xff}}}, }; -// 0x08002F40 -static const Vtx amp_seg8_vertex_08002F40[] = { +UNUSED static const Vtx dAmpUnused3DVtx02[] = { {{{ 280, 0, 35}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, {{{ 240, -160, 0}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, {{{ 280, 0, -35}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, @@ -192,8 +178,7 @@ static const Vtx amp_seg8_vertex_08002F40[] = { {{{ 280, 0, 35}, 0, { 0, 0}, {0x7b, 0x1e, 0x00, 0xff}}}, }; -// 0x08002FA0 -static const Vtx amp_seg8_vertex_08002FA0[] = { +UNUSED static const Vtx dAmpUnused3DVtx03[] = { {{{ 280, 0, 35}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, {{{ 240, -160, 0}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, {{{ 280, 0, -35}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0x00}}}, @@ -202,8 +187,7 @@ static const Vtx amp_seg8_vertex_08002FA0[] = { {{{ 280, 0, 35}, 0, { 0, 0}, {0x7b, 0x1e, 0x00, 0xff}}}, }; -// 0x08003000 -static const Vtx amp_seg8_vertex_08003000[] = { +UNUSED static const Vtx dAmpUnused3DVtx04[] = { {{{ 280, 0, -35}, 0, { 0, 0}, {0x7b, 0x1e, 0x00, 0x00}}}, {{{ 240, 160, 0}, 0, { 0, 0}, {0x7b, 0x1e, 0x00, 0x00}}}, {{{ 280, 0, 35}, 0, { 0, 0}, {0x7b, 0x1e, 0x00, 0x00}}}, @@ -212,8 +196,7 @@ static const Vtx amp_seg8_vertex_08003000[] = { {{{ 280, 0, -35}, 0, { 0, 0}, {0x7b, 0xe2, 0x00, 0xff}}}, }; -// 0x08003060 -static const Vtx amp_seg8_vertex_08003060[] = { +UNUSED static const Vtx dAmpUnused3DVtx05[] = { {{{ -184, -54, -54}, 0, { 0, 0}, {0x8b, 0xde, 0xde, 0x00}}}, {{{ -184, -76, 0}, 0, { 0, 0}, {0x8b, 0xd0, 0x00, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -232,8 +215,7 @@ static const Vtx amp_seg8_vertex_08003060[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003160 -static const Vtx amp_seg8_vertex_08003160[] = { +UNUSED static const Vtx dAmpUnused3DVtx06[] = { {{{ -184, 0, -76}, 0, { 0, 0}, {0x8b, 0x00, 0xd0, 0xff}}}, {{{ -184, -54, -54}, 0, { 0, 0}, {0x8b, 0xde, 0xde, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -252,8 +234,7 @@ static const Vtx amp_seg8_vertex_08003160[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003260 -static const Vtx amp_seg8_vertex_08003260[] = { +UNUSED static const Vtx dAmpUnused3DVtx07[] = { {{{ -184, 54, -54}, 0, { 0, 0}, {0x8b, 0x22, 0xde, 0xff}}}, {{{ -184, 0, -76}, 0, { 0, 0}, {0x8b, 0x00, 0xd0, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -272,8 +253,7 @@ static const Vtx amp_seg8_vertex_08003260[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003360 -static const Vtx amp_seg8_vertex_08003360[] = { +UNUSED static const Vtx dAmpUnused3DVtx08[] = { {{{ -184, 76, 0}, 0, { 0, 0}, {0x8b, 0x30, 0x00, 0xff}}}, {{{ -184, 54, -54}, 0, { 0, 0}, {0x8b, 0x22, 0xde, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -292,8 +272,7 @@ static const Vtx amp_seg8_vertex_08003360[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003460 -static const Vtx amp_seg8_vertex_08003460[] = { +UNUSED static const Vtx dAmpUnused3DVtx09[] = { {{{ -184, 54, 54}, 0, { 0, 0}, {0x8b, 0x22, 0x22, 0xff}}}, {{{ -184, 76, 0}, 0, { 0, 0}, {0x8b, 0x30, 0x00, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -312,8 +291,7 @@ static const Vtx amp_seg8_vertex_08003460[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003560 -static const Vtx amp_seg8_vertex_08003560[] = { +UNUSED static const Vtx dAmpUnused3DVtx10[] = { {{{ -184, 0, 76}, 0, { 0, 0}, {0x8b, 0x00, 0x30, 0xff}}}, {{{ -184, 54, 54}, 0, { 0, 0}, {0x8b, 0x22, 0x22, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -332,8 +310,7 @@ static const Vtx amp_seg8_vertex_08003560[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003660 -static const Vtx amp_seg8_vertex_08003660[] = { +UNUSED static const Vtx dAmpUnused3DVtx11[] = { {{{ -184, -54, 54}, 0, { 0, 0}, {0x8b, 0xde, 0x22, 0xff}}}, {{{ -184, 0, 76}, 0, { 0, 0}, {0x8b, 0x00, 0x30, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -352,8 +329,7 @@ static const Vtx amp_seg8_vertex_08003660[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003760 -static const Vtx amp_seg8_vertex_08003760[] = { +UNUSED static const Vtx dAmpUnused3DVtx12[] = { {{{ -184, -76, 0}, 0, { 0, 0}, {0x8b, 0xd0, 0x00, 0xff}}}, {{{ -184, -54, 54}, 0, { 0, 0}, {0x8b, 0xde, 0x22, 0x00}}}, {{{ -200, 0, 0}, 0, { 0, 0}, {0x81, 0x00, 0x00, 0x00}}}, @@ -372,70 +348,63 @@ static const Vtx amp_seg8_vertex_08003760[] = { {{{ 200, 0, 0}, 0, { 0, 0}, {0x7f, 0x00, 0x00, 0xff}}}, }; -// 0x08003860 -static const Vtx amp_seg8_vertex_08003860[] = { +UNUSED static const Vtx dAmpUnused3DVtx13[] = { {{{ -37, 90, 205}, 0, { 0, 0}, {0xcc, 0x00, 0x73, 0x00}}}, {{{ -129, 90, 163}, 0, { 0, 0}, {0xcc, 0x00, 0x73, 0x00}}}, {{{ -129, -90, 163}, 0, { 0, 0}, {0xcc, 0x00, 0x73, 0x00}}}, {{{ -37, -90, 205}, 0, { 0, 0}, {0xcc, 0x00, 0x73, 0xff}}}, }; -// 0x080038A0 -static const Vtx amp_seg8_vertex_080038A0[] = { +UNUSED static const Vtx dAmpUnused3DVtx14[] = { {{{ 112, -7, 182}, 0, { 0, 0}, {0x4c, 0xd8, 0x5c, 0x00}}}, {{{ 66, -139, 162}, 0, { 0, 0}, {0x4c, 0xd8, 0x5c, 0x00}}}, {{{ 175, -77, 98}, 0, { 0, 0}, {0x4c, 0xd8, 0x5c, 0x00}}}, }; -// 0x080038D0 -static const Vtx amp_seg8_vertex_080038D0[] = { +UNUSED static const Vtx dAmpUnused3DVtx15[] = { {{{ 63, 90, 198}, 0, { 0, 0}, {0x08, 0x00, 0x7e, 0x00}}}, {{{ -35, 90, 205}, 0, { 0, 0}, {0x08, 0x00, 0x7e, 0x00}}}, {{{ -35, -90, 205}, 0, { 0, 0}, {0x08, 0x00, 0x7e, 0x00}}}, {{{ 63, -90, 198}, 0, { 0, 0}, {0x08, 0x00, 0x7e, 0xff}}}, }; -// 0x08003910 - 0x08003940 -const Gfx amp_seg8_dl_08003910[] = { - gsSPLight(&_seg8_lights_08002EC8.l, 1), - gsSPLight(&_seg8_lights_08002EC8.a, 2), - gsSPVertex(amp_seg8_vertex_08002EE0, 6, 0), +UNUSED const Gfx dAmpUnused3DElectricDl1[] = { + gsSPLight(&dAmpUnused3DLights.l, 1), + gsSPLight(&dAmpUnused3DLights.a, 2), + gsSPVertex(dAmpUnused3DVtx01, 6, 0), gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0), gsSPEndDisplayList(), }; -// 0x08003940 - 0x08003970 -const Gfx amp_seg8_dl_08003940[] = { - gsSPLight(&_seg8_lights_08002EC8.l, 1), - gsSPLight(&_seg8_lights_08002EC8.a, 2), - gsSPVertex(amp_seg8_vertex_08002F40, 6, 0), +UNUSED const Gfx dAmpUnused3DElectricDl2[] = { + gsSPLight(&dAmpUnused3DLights.l, 1), + gsSPLight(&dAmpUnused3DLights.a, 2), + gsSPVertex(dAmpUnused3DVtx02, 6, 0), gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0), gsSPEndDisplayList(), }; -// 0x08003970 - 0x080039A0 -const Gfx amp_seg8_dl_08003970[] = { - gsSPLight(&_seg8_lights_08002EC8.l, 1), - gsSPLight(&_seg8_lights_08002EC8.a, 2), - gsSPVertex(amp_seg8_vertex_08002FA0, 6, 0), +UNUSED const Gfx dAmpUnused3DElectricDl3[] = { + gsSPLight(&dAmpUnused3DLights.l, 1), + gsSPLight(&dAmpUnused3DLights.a, 2), + gsSPVertex(dAmpUnused3DVtx03, 6, 0), gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0), gsSPEndDisplayList(), }; -// 0x080039A0 - 0x080039D0 -const Gfx amp_seg8_dl_080039A0[] = { - gsSPLight(&_seg8_lights_08002EC8.l, 1), - gsSPLight(&_seg8_lights_08002EC8.a, 2), - gsSPVertex(amp_seg8_vertex_08003000, 6, 0), +UNUSED const Gfx dAmpUnused3DElectricDl4[] = { + gsSPLight(&dAmpUnused3DLights.l, 1), + gsSPLight(&dAmpUnused3DLights.a, 2), + gsSPVertex(dAmpUnused3DVtx04, 6, 0), gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0), gsSPEndDisplayList(), }; -// 0x080039D0 - 0x08003DA8 -const Gfx amp_seg8_dl_080039D0[] = { - gsSPLight((const u8*)amp_seg8_vertex_08002EE0 + 0x8, 1), - gsSPLight((const u8*)amp_seg8_vertex_08002EE0, 2), - gsSPVertex(amp_seg8_vertex_08003060, 16, 0), +UNUSED const Gfx dAmpUnused3DModelDl[] = { + //! Vertex interpreted as light + gsSPLight((const u8*)dAmpUnused3DVtx01 + 0x8, 1), + gsSPLight((const u8*)dAmpUnused3DVtx01, 2), + gsSPVertex(dAmpUnused3DVtx05, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -443,7 +412,7 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSP2Triangles( 8, 9, 10, 0x0, 10, 9, 11, 0x0), gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0), gsSP2Triangles(12, 13, 14, 0x0, 14, 13, 15, 0x0), - gsSPVertex(amp_seg8_vertex_08003160, 16, 0), + gsSPVertex(dAmpUnused3DVtx06, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -451,7 +420,7 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSP2Triangles( 8, 9, 10, 0x0, 10, 9, 11, 0x0), gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0), gsSP2Triangles(12, 13, 14, 0x0, 14, 13, 15, 0x0), - gsSPVertex(amp_seg8_vertex_08003260, 16, 0), + gsSPVertex(dAmpUnused3DVtx07, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -459,7 +428,7 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSP2Triangles( 8, 9, 10, 0x0, 10, 9, 11, 0x0), gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0), gsSP2Triangles(12, 13, 14, 0x0, 14, 13, 15, 0x0), - gsSPVertex(amp_seg8_vertex_08003360, 16, 0), + gsSPVertex(dAmpUnused3DVtx08, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -467,7 +436,7 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSP2Triangles( 8, 9, 10, 0x0, 10, 9, 11, 0x0), gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0), gsSP2Triangles(12, 13, 14, 0x0, 14, 13, 15, 0x0), - gsSPVertex(amp_seg8_vertex_08003460, 16, 0), + gsSPVertex(dAmpUnused3DVtx09, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -475,7 +444,7 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSP2Triangles( 8, 9, 10, 0x0, 10, 9, 11, 0x0), gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0), gsSP2Triangles(12, 13, 14, 0x0, 14, 13, 15, 0x0), - gsSPVertex(amp_seg8_vertex_08003560, 16, 0), + gsSPVertex(dAmpUnused3DVtx10, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -483,7 +452,7 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSP2Triangles( 8, 9, 10, 0x0, 10, 9, 11, 0x0), gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0), gsSP2Triangles(12, 13, 14, 0x0, 14, 13, 15, 0x0), - gsSPVertex(amp_seg8_vertex_08003660, 16, 0), + gsSPVertex(dAmpUnused3DVtx11, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -491,7 +460,7 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSP2Triangles( 8, 9, 10, 0x0, 10, 9, 11, 0x0), gsSP2Triangles(10, 11, 12, 0x0, 12, 11, 13, 0x0), gsSP2Triangles(12, 13, 14, 0x0, 14, 13, 15, 0x0), - gsSPVertex(amp_seg8_vertex_08003760, 16, 0), + gsSPVertex(dAmpUnused3DVtx12, 16, 0), gsSP2Triangles( 0, 1, 2, 0x0, 1, 0, 3, 0x0), gsSP2Triangles( 1, 3, 4, 0x0, 4, 3, 5, 0x0), gsSP2Triangles( 4, 5, 6, 0x0, 6, 5, 7, 0x0), @@ -502,29 +471,29 @@ const Gfx amp_seg8_dl_080039D0[] = { gsSPEndDisplayList(), }; -// 0x08003DA8 - 0x08003DD8 -const Gfx amp_seg8_dl_08003DA8[] = { - gsSPLight((const u8*)amp_seg8_vertex_08002EE0 + 0x8, 1), - gsSPLight((const u8*)amp_seg8_vertex_08002EE0, 2), - gsSPVertex(amp_seg8_vertex_08003860, 4, 0), +UNUSED const Gfx dAmpUnused3DElectricDl5[] = { + //! Vertex interpreted as light + gsSPLight((const u8*)dAmpUnused3DVtx01 + 0x8, 1), + gsSPLight((const u8*)dAmpUnused3DVtx01, 2), + gsSPVertex(dAmpUnused3DVtx13, 4, 0), gsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0), gsSPEndDisplayList(), }; -// 0x08003DD8 - 0x08003E00 -const Gfx amp_seg8_dl_08003DD8[] = { - gsSPLight((const u8*)amp_seg8_vertex_08002EE0 + 0x8, 1), - gsSPLight((const u8*)amp_seg8_vertex_08002EE0, 2), - gsSPVertex(amp_seg8_vertex_080038A0, 3, 0), +UNUSED const Gfx dAmpUnused3DElectricDl6[] = { + //! Vertex interpreted as light + gsSPLight((const u8*)dAmpUnused3DVtx01 + 0x8, 1), + gsSPLight((const u8*)dAmpUnused3DVtx01, 2), + gsSPVertex(dAmpUnused3DVtx14, 3, 0), gsSP1Triangle( 0, 1, 2, 0x0), gsSPEndDisplayList(), }; -// 0x08003E00 - 0x08003E30 -const Gfx amp_seg8_dl_08003E00[] = { - gsSPLight((const u8*)amp_seg8_vertex_08002EE0 + 0x8, 1), - gsSPLight((const u8*)amp_seg8_vertex_08002EE0, 2), - gsSPVertex(amp_seg8_vertex_080038D0, 4, 0), +UNUSED const Gfx dAmpUnused3DElectricDl7[] = { + //! Vertex interpreted as light + gsSPLight((const u8*)dAmpUnused3DVtx01 + 0x8, 1), + gsSPLight((const u8*)dAmpUnused3DVtx01, 2), + gsSPVertex(dAmpUnused3DVtx15, 4, 0), gsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0), gsSPEndDisplayList(), }; diff --git a/actors/bobomb/model.inc.c b/actors/bobomb/model.inc.c index b4f56adb..6e4296c2 100644 --- a/actors/bobomb/model.inc.c +++ b/actors/bobomb/model.inc.c @@ -180,7 +180,7 @@ static const Lights1 bobomb_seg8_lights_08022E00 = gdSPDefLights1( ); // Unreferenced light group -static const Lights1 bobomb_lights_unused = gdSPDefLights1( +UNUSED static const Lights1 bobomb_lights_unused = gdSPDefLights1( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28 ); diff --git a/actors/bowser/flames_data.inc.c b/actors/bowser/flames_data.inc.c new file mode 100644 index 00000000..1ba334ab --- /dev/null +++ b/actors/bowser/flames_data.inc.c @@ -0,0 +1,98 @@ +// 0x060576FC + +const s16 dBowserFlamesOrientationValues[] = { +// posX, posY, posZ, rotY, rotX + 0, 280, 80, 0x00E9, 0x1A96, + 0, 278, 83, 0x00EC, 0x1C7F, + 0, 273, 92, 0x00F9, 0x20BF, + 0, 268, 102, 0x010F, 0x2519, + 0, 263, 109, 0x011D, 0x2751, + 0, 263, 110, 0x011C, 0x2714, + 0, 265, 106, 0x0112, 0x2601, + 0, 268, 102, 0x0109, 0x24C0, + 0, 271, 96, 0x00FF, 0x2358, + 0, 274, 90, 0x00F7, 0x21CB, + 0, 277, 84, 0x00EE, 0x201C, + 0, 280, 78, 0x00E7, 0x1E4E, + 0, 284, 71, 0x00DF, 0x1C64, + 0, 288, 63, 0x00D9, 0x1A61, + 0, 291, 56, 0x00D3, 0x184B, + 0, 295, 48, 0x00CF, 0x1622, + 0, 298, 40, 0x00CA, 0x13E9, + 0, 301, 32, 0x00C7, 0x11A5, + 0, 304, 23, 0x00C4, 0x0F59, + 0, 308, 15, 0x00C1, 0x0D08, + 0, 311, 7, 0x00C0, 0x0AB5, + 0, 313, 0, 0x00C0, 0x0863, + 0, 315, -8, 0x00BF, 0x0615, + 0, 317, -15, 0x00CE, 0x03A3, + 0, 319, -22, 0x00F8, 0x00ED, + 0, 320, -29, 0x0131, 0xFFFF, + 0, 322, -36, 0x0172, 0xFFFF, + 0, 322, -40, 0x01B5, 0xFFFF, + 0, 323, -45, 0x01ED, 0xFFFF, + 0, 323, -48, 0x0213, 0xFFFF, + 0, 323, -51, 0x0219, 0xFFFF, + 0, 323, -52, 0x01F2, 0xFFFF, + 0, 323, -51, 0x018F, 0xFFFF, + 0, 323, -49, 0x00E5, 0xFFFF, + 0, 322, -45, 0xFFFF, 0xFFFF, + 0, 320, -35, 0xFFFF, 0xFFFF, + 0, 317, -23, 0xFFFF, 0xFFFF, + 0, 312, -7, 0xFFFF, 0xFFFF, + 0, 306, 11, 0xFFFF, 0xFFFF, + 0, 299, 31, 0xFFFF, 0xFFFF, + 0, 288, 51, 0xFFFF, 0xFFFF, + 0, 278, 70, 0xFFFF, 0xFFFF, + 0, 267, 89, 0xFFFF, 0xFFFF, + 0, 256, 106, 0xFFFF, 0x023A, + 0, 244, 120, 0xFFFF, 0x04AA, + 0, 236, 132, 0xFFFF, 0x069F, + 0, 229, 139, 0xFFFF, 0x0803, + 0, 224, 144, 0xFFFF, 0x08C0, + 0, 222, 147, 0xFFFF, 0x0928, + 0, 221, 148, 0xFFFF, 0x099D, + 0, 221, 149, 0xFFFF, 0x0A16, + 0, 221, 150, 0xFFFF, 0x0A8D, + 0, 221, 150, 0xFFFF, 0x0AF6, + 0, 222, 150, 0xFFFF, 0x0B4A, + 0, 222, 150, 0xFFFF, 0x0B84, + 0, 222, 149, 0x020A, 0x0BA0, + 0, 223, 149, 0x0524, 0x0B9E, + 0, 225, 148, 0x07EC, 0x0B84, + 0, 226, 147, 0x0A3F, 0x0B57, + 0, 227, 145, 0x0BFB, 0x0B1F, + 0, 228, 144, 0x0D00, 0x0AE5, + 0, 230, 142, 0x0D6F, 0x0AA0, + 0, 232, 140, 0x0D8B, 0x0A48, + 0, 233, 138, 0x0D5D, 0x09DE, + 0, 236, 136, 0x0CED, 0x096A, + 0, 238, 134, 0x0C49, 0x08EA, + 0, 239, 132, 0x0B76, 0x0863, + 0, 241, 130, 0x0A80, 0x07D9, + 0, 244, 128, 0x0970, 0x074E, + 0, 246, 125, 0x084E, 0x06C7, + 0, 248, 122, 0x0723, 0x0649, + 0, 251, 120, 0x05F8, 0x05D7, + 0, 253, 117, 0x04D6, 0x0579, + 0, 254, 114, 0x03C3, 0x0532, + 0, 256, 111, 0x02C9, 0x0509, + 0, 259, 108, 0x01F0, 0x0504, + 0, 261, 105, 0x0141, 0x0525, + 0, 262, 103, 0x00C3, 0x0572, + 0, 264, 100, 0x006E, 0x0619, + 0, 267, 97, 0x0032, 0x0734, + 0, 268, 95, 0x000C, 0x08AF, + 0, 269, 93, 0xFFFF, 0x0A74, + 0, 272, 90, 0xFFFF, 0x0C70, + 0, 273, 88, 0xFFFF, 0x0E8E, + 0, 274, 86, 0x0014, 0x10B6, + 0, 275, 84, 0x0032, 0x12DA, + 0, 277, 82, 0x0056, 0x14E1, + 0, 277, 82, 0x007E, 0x16B9, + 0, 278, 80, 0x00A4, 0x184B, + 0, 278, 80, 0x00C6, 0x1983, + 0, 279, 80, 0x00DF, 0x1A4D, + 0, 280, 80, 0x00E9, 0x1A96, + 0, 0, 0, 0x0000, 0x0000, +}; diff --git a/actors/bowser/flames_pos.inc.c b/actors/bowser/flames_pos.inc.c deleted file mode 100644 index 25bddc3e..00000000 --- a/actors/bowser/flames_pos.inc.c +++ /dev/null @@ -1,96 +0,0 @@ -// 0x060576FC -const s16 bowser_seg6_unkmoveshorts_060576FC[] = { - 0x0000, 0x0118, 0x0050, 0x00E9, 0x1A96, - 0x0000, 0x0116, 0x0053, 0x00EC, 0x1C7F, - 0x0000, 0x0111, 0x005C, 0x00F9, 0x20BF, - 0x0000, 0x010C, 0x0066, 0x010F, 0x2519, - 0x0000, 0x0107, 0x006D, 0x011D, 0x2751, - 0x0000, 0x0107, 0x006E, 0x011C, 0x2714, - 0x0000, 0x0109, 0x006A, 0x0112, 0x2601, - 0x0000, 0x010C, 0x0066, 0x0109, 0x24C0, - 0x0000, 0x010F, 0x0060, 0x00FF, 0x2358, - 0x0000, 0x0112, 0x005A, 0x00F7, 0x21CB, - 0x0000, 0x0115, 0x0054, 0x00EE, 0x201C, - 0x0000, 0x0118, 0x004E, 0x00E7, 0x1E4E, - 0x0000, 0x011C, 0x0047, 0x00DF, 0x1C64, - 0x0000, 0x0120, 0x003F, 0x00D9, 0x1A61, - 0x0000, 0x0123, 0x0038, 0x00D3, 0x184B, - 0x0000, 0x0127, 0x0030, 0x00CF, 0x1622, - 0x0000, 0x012A, 0x0028, 0x00CA, 0x13E9, - 0x0000, 0x012D, 0x0020, 0x00C7, 0x11A5, - 0x0000, 0x0130, 0x0017, 0x00C4, 0x0F59, - 0x0000, 0x0134, 0x000F, 0x00C1, 0x0D08, - 0x0000, 0x0137, 0x0007, 0x00C0, 0x0AB5, - 0x0000, 0x0139, 0x0000, 0x00C0, 0x0863, - 0x0000, 0x013B, 0xFFF8, 0x00BF, 0x0615, - 0x0000, 0x013D, 0xFFF1, 0x00CE, 0x03A3, - 0x0000, 0x013F, 0xFFEA, 0x00F8, 0x00ED, - 0x0000, 0x0140, 0xFFE3, 0x0131, 0xFFFF, - 0x0000, 0x0142, 0xFFDC, 0x0172, 0xFFFF, - 0x0000, 0x0142, 0xFFD8, 0x01B5, 0xFFFF, - 0x0000, 0x0143, 0xFFD3, 0x01ED, 0xFFFF, - 0x0000, 0x0143, 0xFFD0, 0x0213, 0xFFFF, - 0x0000, 0x0143, 0xFFCD, 0x0219, 0xFFFF, - 0x0000, 0x0143, 0xFFCC, 0x01F2, 0xFFFF, - 0x0000, 0x0143, 0xFFCD, 0x018F, 0xFFFF, - 0x0000, 0x0143, 0xFFCF, 0x00E5, 0xFFFF, - 0x0000, 0x0142, 0xFFD3, 0xFFFF, 0xFFFF, - 0x0000, 0x0140, 0xFFDD, 0xFFFF, 0xFFFF, - 0x0000, 0x013D, 0xFFE9, 0xFFFF, 0xFFFF, - 0x0000, 0x0138, 0xFFF9, 0xFFFF, 0xFFFF, - 0x0000, 0x0132, 0x000B, 0xFFFF, 0xFFFF, - 0x0000, 0x012B, 0x001F, 0xFFFF, 0xFFFF, - 0x0000, 0x0120, 0x0033, 0xFFFF, 0xFFFF, - 0x0000, 0x0116, 0x0046, 0xFFFF, 0xFFFF, - 0x0000, 0x010B, 0x0059, 0xFFFF, 0xFFFF, - 0x0000, 0x0100, 0x006A, 0xFFFF, 0x023A, - 0x0000, 0x00F4, 0x0078, 0xFFFF, 0x04AA, - 0x0000, 0x00EC, 0x0084, 0xFFFF, 0x069F, - 0x0000, 0x00E5, 0x008B, 0xFFFF, 0x0803, - 0x0000, 0x00E0, 0x0090, 0xFFFF, 0x08C0, - 0x0000, 0x00DE, 0x0093, 0xFFFF, 0x0928, - 0x0000, 0x00DD, 0x0094, 0xFFFF, 0x099D, - 0x0000, 0x00DD, 0x0095, 0xFFFF, 0x0A16, - 0x0000, 0x00DD, 0x0096, 0xFFFF, 0x0A8D, - 0x0000, 0x00DD, 0x0096, 0xFFFF, 0x0AF6, - 0x0000, 0x00DE, 0x0096, 0xFFFF, 0x0B4A, - 0x0000, 0x00DE, 0x0096, 0xFFFF, 0x0B84, - 0x0000, 0x00DE, 0x0095, 0x020A, 0x0BA0, - 0x0000, 0x00DF, 0x0095, 0x0524, 0x0B9E, - 0x0000, 0x00E1, 0x0094, 0x07EC, 0x0B84, - 0x0000, 0x00E2, 0x0093, 0x0A3F, 0x0B57, - 0x0000, 0x00E3, 0x0091, 0x0BFB, 0x0B1F, - 0x0000, 0x00E4, 0x0090, 0x0D00, 0x0AE5, - 0x0000, 0x00E6, 0x008E, 0x0D6F, 0x0AA0, - 0x0000, 0x00E8, 0x008C, 0x0D8B, 0x0A48, - 0x0000, 0x00E9, 0x008A, 0x0D5D, 0x09DE, - 0x0000, 0x00EC, 0x0088, 0x0CED, 0x096A, - 0x0000, 0x00EE, 0x0086, 0x0C49, 0x08EA, - 0x0000, 0x00EF, 0x0084, 0x0B76, 0x0863, - 0x0000, 0x00F1, 0x0082, 0x0A80, 0x07D9, - 0x0000, 0x00F4, 0x0080, 0x0970, 0x074E, - 0x0000, 0x00F6, 0x007D, 0x084E, 0x06C7, - 0x0000, 0x00F8, 0x007A, 0x0723, 0x0649, - 0x0000, 0x00FB, 0x0078, 0x05F8, 0x05D7, - 0x0000, 0x00FD, 0x0075, 0x04D6, 0x0579, - 0x0000, 0x00FE, 0x0072, 0x03C3, 0x0532, - 0x0000, 0x0100, 0x006F, 0x02C9, 0x0509, - 0x0000, 0x0103, 0x006C, 0x01F0, 0x0504, - 0x0000, 0x0105, 0x0069, 0x0141, 0x0525, - 0x0000, 0x0106, 0x0067, 0x00C3, 0x0572, - 0x0000, 0x0108, 0x0064, 0x006E, 0x0619, - 0x0000, 0x010B, 0x0061, 0x0032, 0x0734, - 0x0000, 0x010C, 0x005F, 0x000C, 0x08AF, - 0x0000, 0x010D, 0x005D, 0xFFFF, 0x0A74, - 0x0000, 0x0110, 0x005A, 0xFFFF, 0x0C70, - 0x0000, 0x0111, 0x0058, 0xFFFF, 0x0E8E, - 0x0000, 0x0112, 0x0056, 0x0014, 0x10B6, - 0x0000, 0x0113, 0x0054, 0x0032, 0x12DA, - 0x0000, 0x0115, 0x0052, 0x0056, 0x14E1, - 0x0000, 0x0115, 0x0052, 0x007E, 0x16B9, - 0x0000, 0x0116, 0x0050, 0x00A4, 0x184B, - 0x0000, 0x0116, 0x0050, 0x00C6, 0x1983, - 0x0000, 0x0117, 0x0050, 0x00DF, 0x1A4D, - 0x0000, 0x0118, 0x0050, 0x00E9, 0x1A96, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, -}; diff --git a/actors/bowser/geo.inc.c b/actors/bowser/geo.inc.c index 06d2f13a..b59e23a6 100644 --- a/actors/bowser/geo.inc.c +++ b/actors/bowser/geo.inc.c @@ -110,10 +110,10 @@ const GeoLayout bowser_geo_0000D8[] = { const GeoLayout bowser_geo_000424[] = { GEO_SHADOW(SHADOW_CIRCLE_9_VERTS, 0x9B, 400), GEO_OPEN_NODE(), -#ifdef VERSION_JP - GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_06040210), -#else +#if BUGFIX_BOWSER_FADING_OUT GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_06040358), +#else + GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_06040210), #endif GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_TRANSPARENT, -89, -2, -18, NULL), @@ -200,10 +200,10 @@ const GeoLayout bowser_geo_000424[] = { GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603A4E8), GEO_CLOSE_NODE(), -#ifdef VERSION_JP - GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603B8D0), -#else +#if BUGFIX_BOWSER_FADING_OUT GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603B948), +#else + GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603B8D0), #endif GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), @@ -226,10 +226,10 @@ const GeoLayout bowser_geo_000424[] = { const GeoLayout bowser_geo_000770[] = { GEO_NODE_START(), GEO_OPEN_NODE(), -#ifdef VERSION_JP - GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_06040210), -#else +#if BUGFIX_BOWSER_FADING_OUT GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_06040358), +#else + GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_06040210), #endif GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_TRANSPARENT, -89, -2, -18, NULL), @@ -316,10 +316,10 @@ const GeoLayout bowser_geo_000770[] = { GEO_OPEN_NODE(), GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603A4E8), GEO_CLOSE_NODE(), -#ifdef VERSION_JP - GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603B8D0), -#else +#if BUGFIX_BOWSER_FADING_OUT GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603B948), +#else + GEO_ANIMATED_PART(LAYER_TRANSPARENT, 0, 0, 0, bowser_seg6_dl_0603B8D0), #endif GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), @@ -341,7 +341,7 @@ const GeoLayout bowser_geo_000770[] = { #ifndef VERSION_JP // 0x0D000AB8 const GeoLayout bowser_shadow_geo[] = { - GEO_SHADOW(0x00, 0x9B, 400), + GEO_SHADOW(SHADOW_CIRCLE_9_VERTS, 0x9B, 400), GEO_RETURN(), }; #endif @@ -351,11 +351,10 @@ const GeoLayout bowser_geo[] = { GEO_NODE_START(), GEO_OPEN_NODE(), GEO_ASM(0, geo_update_layer_transparency), -#ifdef VERSION_JP - GEO_SWITCH_CASE(2, geo_switch_anim_state), -#endif #ifndef VERSION_JP GEO_SWITCH_CASE(3, geo_switch_anim_state), +#else + GEO_SWITCH_CASE(2, geo_switch_anim_state), #endif GEO_OPEN_NODE(), GEO_NODE_START(), @@ -384,19 +383,16 @@ const GeoLayout bowser_geo[] = { }; // 0x0D000B18 / 0B40 -const GeoLayout bowser2_geo[] = { +const GeoLayout bowser_geo_no_shadow[] = { GEO_NODE_START(), GEO_OPEN_NODE(), GEO_ASM(0, geo_update_layer_transparency), - -#ifdef VERSION_JP - GEO_SWITCH_CASE(2, geo_switch_anim_state), -#endif #ifndef VERSION_JP GEO_SWITCH_CASE(3, geo_switch_anim_state), +#else + GEO_SWITCH_CASE(2, geo_switch_anim_state), #endif GEO_OPEN_NODE(), - GEO_NODE_START(), GEO_OPEN_NODE(), GEO_ASM(0, geo_bits_bowser_coloring), diff --git a/actors/bowser/model.inc.c b/actors/bowser/model.inc.c index 69a0b083..66d7a843 100644 --- a/actors/bowser/model.inc.c +++ b/actors/bowser/model.inc.c @@ -52,13 +52,13 @@ ALIGNED8 static const Texture bowser_seg6_texture_06025C38[] = { // unreferenced, seen in pre-Spaceworld 1995 B-roll footage build // 0x06026438 -ALIGNED8 static const Texture bowser_seg6_texture_06026438[] = { +UNUSED ALIGNED8 static const Texture bowser_seg6_texture_06026438[] = { #include "actors/bowser/bowser_blue_eye_unused.rgba16.inc.c" }; // unreferenced (stubbed texture? possibly original texture for mouth) // 0x06027438 -ALIGNED8 static const Texture bowser_seg6_texture_06027438[] = { +UNUSED ALIGNED8 static const Texture bowser_seg6_texture_06027438[] = { #include "actors/bowser/bowser_mouth_unused.rgba16.inc.c" }; @@ -1184,7 +1184,7 @@ const Gfx bowser_seg6_dl_0603B8D0[] = { gsSPEndDisplayList(), }; -#ifndef VERSION_JP +#if BUGFIX_BOWSER_FADING_OUT // 0x0603B948 - 0x0603B9C8 const Gfx bowser_seg6_dl_0603B948[] = { gsDPPipeSync(), @@ -2870,7 +2870,7 @@ const Gfx bowser_seg6_dl_06040210[] = { gsSPEndDisplayList(), }; -#ifndef VERSION_JP +#if BUGFIX_BOWSER_FADING_OUT // 0x06040358 - 0x06040428 const Gfx bowser_seg6_dl_06040358[] = { gsDPPipeSync(), diff --git a/actors/bubba/model.inc.c b/actors/bubba/model.inc.c index 5775b710..8e32bbbb 100644 --- a/actors/bubba/model.inc.c +++ b/actors/bubba/model.inc.c @@ -14,7 +14,7 @@ ALIGNED8 static const Texture bubba_seg5_texture_05000008[] = { // unused eye texture, assumed leftover from when actor file was copied from bub // 0x05000408 -ALIGNED8 static const Texture bubba_seg5_texture_05000408[] = { +UNUSED ALIGNED8 static const Texture bubba_seg5_texture_05000408[] = { #include "actors/bubba/bubba_eyes_unused.rgba16.inc.c" }; diff --git a/actors/chair/model.inc.c b/actors/chair/model.inc.c index 1a833f5b..86c65dad 100644 --- a/actors/chair/model.inc.c +++ b/actors/chair/model.inc.c @@ -23,7 +23,7 @@ ALIGNED8 static const Texture chair_seg5_texture_05004060[] = { // unreferenced // 0x05004460 -ALIGNED8 static const Texture chair_seg5_texture_05004460[] = { +UNUSED ALIGNED8 static const Texture chair_seg5_texture_05004460[] = { #include "actors/chair/chair_surface_unused.rgba16.inc.c" }; diff --git a/actors/chillychief/geo.inc.c b/actors/chillychief/geo.inc.c index 96ec2e1c..78a0bfa2 100644 --- a/actors/chillychief/geo.inc.c +++ b/actors/chillychief/geo.inc.c @@ -5,39 +5,39 @@ const GeoLayout chilly_chief_geo[] = { GEO_OPEN_NODE(), GEO_SCALE(0, 0x7333), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 75, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 75, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 146, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 146, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, chilly_chief_seg6_dl_06002B30), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, chilly_chief_seg6_dl_06002B30), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 0, 0, -75, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, -75, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 146, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 146, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, chilly_chief_seg6_dl_06002BC8), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, chilly_chief_seg6_dl_06002BC8), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), GEO_BILLBOARD(), GEO_OPEN_NODE(), GEO_DISPLAY_LIST(LAYER_ALPHA, chilly_chief_seg6_dl_06002D88), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, chilly_chief_seg6_dl_06002C60), - GEO_ANIMATED_PART(4, 0, 0, 0, chilly_chief_seg6_dl_06003010), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, chilly_chief_seg6_dl_06002C60), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, chilly_chief_seg6_dl_06003010), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), @@ -51,39 +51,39 @@ const GeoLayout chilly_chief_big_geo[] = { GEO_OPEN_NODE(), GEO_SCALE(0, 0xE666), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 75, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 75, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 146, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 146, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, chilly_chief_seg6_dl_06002B30), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, chilly_chief_seg6_dl_06002B30), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 0, 0, -75, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, -75, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 146, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 146, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, chilly_chief_seg6_dl_06002BC8), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, chilly_chief_seg6_dl_06002BC8), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), GEO_BILLBOARD(), GEO_OPEN_NODE(), GEO_DISPLAY_LIST(LAYER_ALPHA, chilly_chief_seg6_dl_06002EF0), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, chilly_chief_seg6_dl_06002C60), - GEO_ANIMATED_PART(4, 0, 0, 0, chilly_chief_seg6_dl_06003010), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, chilly_chief_seg6_dl_06002C60), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, chilly_chief_seg6_dl_06003010), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), diff --git a/actors/common0.h b/actors/common0.h index f4a791db..53c7f396 100644 --- a/actors/common0.h +++ b/actors/common0.h @@ -4,24 +4,12 @@ #include "types.h" // amp -extern const GeoLayout amp_geo[]; -extern const Gfx amp_seg8_dl_08002B68[]; -extern const Gfx amp_seg8_dl_08002BA0[]; -extern const Gfx amp_seg8_dl_08002C50[]; -extern const Gfx amp_seg8_dl_08002C88[]; -extern const Gfx amp_seg8_dl_08002D38[]; -extern const Gfx amp_seg8_dl_08002D70[]; -extern const Gfx amp_seg8_dl_08002E20[]; -extern const Gfx amp_seg8_dl_08002E58[]; -extern const Gfx amp_seg8_dl_08003910[]; -extern const Gfx amp_seg8_dl_08003940[]; -extern const Gfx amp_seg8_dl_08003970[]; -extern const Gfx amp_seg8_dl_080039A0[]; -extern const Gfx amp_seg8_dl_080039D0[]; -extern const Gfx amp_seg8_dl_08003DA8[]; -extern const Gfx amp_seg8_dl_08003DD8[]; -extern const Gfx amp_seg8_dl_08003E00[]; -extern const struct Animation *const amp_seg8_anims_08004034[]; +extern const GeoLayout dAmpGeo[]; +extern const Gfx dAmpElectricityDl[]; +extern const Gfx dAmpEyeDl[]; +extern const Gfx dAmpMouthDl[]; +extern const Gfx dAmpBodyDl[]; +extern const struct Animation *const dAmpAnimsList[]; // blue_coin_switch extern const GeoLayout blue_coin_switch_geo[]; diff --git a/actors/group11.c b/actors/group11.c index 2dddacb5..669a72c8 100644 --- a/actors/group11.c +++ b/actors/group11.c @@ -13,7 +13,6 @@ UNUSED static const u64 binid_0 = 0; #include "wiggler_body/model.inc.c" #include "wiggler_body/anims/data.inc.c" -#include "wiggler_body/geo.inc.c" #include "wiggler_body/anims/table.inc.c" #include "wiggler_head/model.inc.c" diff --git a/actors/group11_geo.c b/actors/group11_geo.c index 5a3f296c..ae26eddc 100644 --- a/actors/group11_geo.c +++ b/actors/group11_geo.c @@ -8,6 +8,7 @@ #include "group11.h" #include "bubba/geo.inc.c" +#include "wiggler_body/geo.inc.c" #include "wiggler_head/geo.inc.c" #include "lakitu_enemy/geo.inc.c" #include "spiny_egg/geo.inc.c" diff --git a/actors/group12.c b/actors/group12.c index b6ed0af7..ece6a0bd 100644 --- a/actors/group12.c +++ b/actors/group12.c @@ -18,7 +18,7 @@ UNUSED static const u64 binid_2 = 2; #include "bowser/model.inc.c" #include "bowser/anims/data.inc.c" #include "bowser/anims/table.inc.c" -#include "bowser/flames_pos.inc.c" +#include "bowser/flames_data.inc.c" UNUSED static const u64 binid_3 = 3; #include "bomb/model.inc.c" diff --git a/actors/group12.h b/actors/group12.h index 2a73af21..02258c86 100644 --- a/actors/group12.h +++ b/actors/group12.h @@ -17,7 +17,7 @@ extern const GeoLayout bowser_geo_000424[]; extern const GeoLayout bowser_geo_000770[]; extern const GeoLayout bowser_shadow_geo[]; extern const GeoLayout bowser_geo[]; -extern const GeoLayout bowser2_geo[]; +extern const GeoLayout bowser_geo_no_shadow[]; extern const Gfx bowser_seg6_dl_06039110[]; extern const Gfx bowser_seg6_dl_060391C8[]; extern const Gfx bowser_seg6_dl_06039260[]; @@ -90,7 +90,7 @@ extern const Gfx bowser_seg6_dl_06043548[]; extern const Gfx bowser_seg6_dl_06043648[]; extern const Gfx bowser_seg6_dl_06043698[]; extern const struct Animation *const bowser_seg6_anims_06057690[]; -extern const s16 bowser_seg6_unkmoveshorts_060576FC[]; +extern const s16 dBowserFlamesOrientationValues[]; // bowser_flame extern const GeoLayout bowser_flames_geo[]; diff --git a/actors/group16.c b/actors/group16.c index 5435ac0f..50338e05 100644 --- a/actors/group16.c +++ b/actors/group16.c @@ -10,7 +10,6 @@ #include "chillychief/model.inc.c" #include "chillychief/anims/data.inc.c" -#include "chillychief/geo.inc.c" #include "chillychief/anims/table.inc.c" UNUSED static const u64 binid_0 = 0; diff --git a/actors/group16_geo.c b/actors/group16_geo.c index ab80df19..114eb979 100644 --- a/actors/group16_geo.c +++ b/actors/group16_geo.c @@ -7,4 +7,5 @@ #include "common1.h" #include "group16.h" +#include "chillychief/geo.inc.c" #include "moneybag/geo.inc.c" diff --git a/actors/group4.c b/actors/group4.c index 080a026d..d9a0e4ee 100644 --- a/actors/group4.c +++ b/actors/group4.c @@ -14,7 +14,6 @@ UNUSED static const u64 binid_0 = 0; #include "manta/model.inc.c" #include "manta/anims/data.inc.c" -#include "manta/geo.inc.c" #include "manta/anims/table.inc.c" UNUSED static const u64 binid_1 = 1; diff --git a/actors/group4_geo.c b/actors/group4_geo.c index 6e93672f..c922414b 100644 --- a/actors/group4_geo.c +++ b/actors/group4_geo.c @@ -8,5 +8,6 @@ #include "group4.h" #include "clam_shell/geo.inc.c" +#include "manta/geo.inc.c" #include "sushi/geo.inc.c" #include "unagi/geo.inc.c" diff --git a/actors/haunted_cage/model.inc.c b/actors/haunted_cage/model.inc.c index 0f221d98..d1a44e44 100644 --- a/actors/haunted_cage/model.inc.c +++ b/actors/haunted_cage/model.inc.c @@ -41,7 +41,7 @@ ALIGNED8 static const Texture haunted_cage_seg5_texture_0500DA88[] = { // also could be some sort of shader mask from much earlier in development, considering // Big Boo's Haunt was a very very early level. // 0x0500E288 -ALIGNED8 static const Texture haunted_cage_seg5_texture_0500E288[] = { +UNUSED ALIGNED8 static const Texture haunted_cage_seg5_texture_0500E288[] = { #include "actors/haunted_cage/bbh_cage_garbage.rgba16.inc.c" }; diff --git a/actors/heave_ho/model.inc.c b/actors/heave_ho/model.inc.c index 3868cd1d..36f97f23 100644 --- a/actors/heave_ho/model.inc.c +++ b/actors/heave_ho/model.inc.c @@ -1,19 +1,19 @@ // Heave Ho // Unreferenced light group -static const Lights1 heave_ho_lights_unused1 = gdSPDefLights1( +UNUSED static const Lights1 heave_ho_lights_unused1 = gdSPDefLights1( 0x2c, 0x2c, 0x2c, 0xb2, 0xb2, 0xb2, 0x28, 0x28, 0x28 ); // Unreferenced light group -static const Lights1 heave_ho_lights_unused2 = gdSPDefLights1( +UNUSED static const Lights1 heave_ho_lights_unused2 = gdSPDefLights1( 0x3f, 0x38, 0x00, 0xff, 0xe3, 0x00, 0x28, 0x28, 0x28 ); // Unreferenced light group -static const Lights1 heave_ho_lights_unused3 = gdSPDefLights1( +UNUSED static const Lights1 heave_ho_lights_unused3 = gdSPDefLights1( 0x3f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x28, 0x28, 0x28 ); @@ -31,13 +31,13 @@ static const Lights1 heave_ho_seg5_lights_0500E980 = gdSPDefLights1( ); // Unreferenced light group -static const Lights1 heave_ho_lights_unused4 = gdSPDefLights1( +UNUSED static const Lights1 heave_ho_lights_unused4 = gdSPDefLights1( 0x3b, 0x38, 0x21, 0xec, 0xe3, 0x84, 0x28, 0x28, 0x28 ); // Unreferenced light group -static const Lights1 heave_ho_lights_unused5 = gdSPDefLights1( +UNUSED static const Lights1 heave_ho_lights_unused5 = gdSPDefLights1( 0x32, 0x32, 0x32, 0xc8, 0xc8, 0xc8, 0x28, 0x28, 0x28 ); diff --git a/actors/king_bobomb/model.inc.c b/actors/king_bobomb/model.inc.c index 3065684c..6c91b210 100644 --- a/actors/king_bobomb/model.inc.c +++ b/actors/king_bobomb/model.inc.c @@ -31,12 +31,12 @@ UNUSED static const Lights1 king_bobomb_lights_unused5 = gdSPDefLights1( ); // 0x05000078 -ALIGNED8 static const Texture king_bobomb_seg5_texture_05000078[] = { +UNUSED ALIGNED8 static const Texture king_bobomb_seg5_texture_05000078[] = { #include "actors/king_bobomb/bob-omb_buddy_left_side_unused.rgba16.inc.c" }; // 0x05001078 -ALIGNED8 static const Texture king_bobomb_seg5_texture_05001078[] = { +UNUSED ALIGNED8 static const Texture king_bobomb_seg5_texture_05001078[] = { #include "actors/king_bobomb/bob-omb_buddy_right_side_unused.rgba16.inc.c" }; @@ -46,7 +46,7 @@ ALIGNED8 static const Texture king_bobomb_seg5_texture_05002078[] = { }; // 0x05002878 -ALIGNED8 static const Texture king_bobomb_seg5_texture_05002878[] = { +UNUSED ALIGNED8 static const Texture king_bobomb_seg5_texture_05002878[] = { #include "actors/king_bobomb/king_bob-omb_body_unused.rgba16.inc.c" }; @@ -55,6 +55,11 @@ ALIGNED8 static const Texture king_bobomb_seg5_texture_05004878[] = { #include "actors/king_bobomb/king_bob-omb_eyes.rgba16.inc.c" }; +// 0x05005078 - Unused +UNUSED ALIGNED8 static const Texture king_bobomb_seg5_texture_05005078[] = { +#include "actors/king_bobomb/king_bob-omb_eyes_blink.rgba16.inc.c" +}; + // 0x05005878 ALIGNED8 static const Texture king_bobomb_seg5_texture_05005878[] = { #include "actors/king_bobomb/king_bob-omb_hand.rgba16.inc.c" @@ -66,7 +71,7 @@ ALIGNED8 static const Texture king_bobomb_seg5_texture_05006078[] = { }; // 0x05006478 -ALIGNED8 static const Texture king_bobomb_seg5_texture_05006478[] = { +UNUSED ALIGNED8 static const Texture king_bobomb_seg5_texture_05006478[] = { #include "actors/king_bobomb/bob-omb_buddy_body_unused.rgba16.inc.c" }; diff --git a/actors/koopa_flag/model.inc.c b/actors/koopa_flag/model.inc.c index d56af4be..7840c95c 100644 --- a/actors/koopa_flag/model.inc.c +++ b/actors/koopa_flag/model.inc.c @@ -1,19 +1,19 @@ // Koopa Flag // 0x06000000 -static const Lights1 koopa_flag_seg6_lights_06000000 = gdSPDefLights1( +UNUSED static const Lights1 koopa_flag_seg6_lights_06000000 = gdSPDefLights1( 0x00, 0x1b, 0x00, 0x00, 0x6e, 0x00, 0x28, 0x28, 0x28 ); // 0x06000018 -static const Lights1 koopa_flag_seg6_lights_06000018 = gdSPDefLights1( +UNUSED static const Lights1 koopa_flag_seg6_lights_06000018 = gdSPDefLights1( 0x3f, 0x39, 0x15, 0xff, 0xe6, 0x57, 0x28, 0x28, 0x28 ); // 0x06000030 -static const Lights1 koopa_flag_seg6_lights_06000030 = gdSPDefLights1( +UNUSED static const Lights1 koopa_flag_seg6_lights_06000030 = gdSPDefLights1( 0x2b, 0x15, 0x01, 0xac, 0x54, 0x05, 0x28, 0x28, 0x28 ); diff --git a/actors/lakitu_cameraman/model.inc.c b/actors/lakitu_cameraman/model.inc.c index 7392743b..a83d34f9 100644 --- a/actors/lakitu_cameraman/model.inc.c +++ b/actors/lakitu_cameraman/model.inc.c @@ -1,7 +1,7 @@ // Lakitu (Cameraman) // 0x06000000 -ALIGNED8 static const Texture lakitu_seg6_texture_06000000[] = { +UNUSED ALIGNED8 static const Texture lakitu_seg6_texture_06000000[] = { #include "actors/lakitu_cameraman/lakitu_cameraman_cloud_face_unused.rgba16.inc.c" }; diff --git a/actors/lakitu_enemy/model.inc.c b/actors/lakitu_enemy/model.inc.c index 669f917f..b8613994 100644 --- a/actors/lakitu_enemy/model.inc.c +++ b/actors/lakitu_enemy/model.inc.c @@ -20,7 +20,7 @@ UNUSED static const Lights1 lakitu_enemy_lights_unused2 = gdSPDefLights1( // Unreferenced texture // 0x0500ECE0 -ALIGNED8 static const Texture lakitu_enemy_seg5_texture_0500ECE0[] = { +UNUSED ALIGNED8 static const Texture lakitu_enemy_seg5_texture_0500ECE0[] = { #include "actors/lakitu_enemy/lakitu_enemy_cloud_face_unused.rgba16.inc.c" }; diff --git a/actors/manta/geo.inc.c b/actors/manta/geo.inc.c index d60ce675..4c669e7d 100644 --- a/actors/manta/geo.inc.c +++ b/actors/manta/geo.inc.c @@ -2,56 +2,56 @@ const GeoLayout manta_seg5_geo_05008D14[] = { GEO_SCALE(0, 16384), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05006750), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05006750), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 440, 220, 6, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 440, 220, 6, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05005358), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05005358), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 220, 0, 0, manta_seg5_dl_050055A8), + GEO_ANIMATED_PART(LAYER_OPAQUE, 220, 0, 0, manta_seg5_dl_050055A8), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 180, 0, 0, manta_seg5_dl_05005768), + GEO_ANIMATED_PART(LAYER_OPAQUE, 180, 0, 0, manta_seg5_dl_05005768), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 440, -220, 6, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 440, -220, 6, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05005C38), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05005C38), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 220, 0, 0, manta_seg5_dl_05005E88), + GEO_ANIMATED_PART(LAYER_OPAQUE, 220, 0, 0, manta_seg5_dl_05005E88), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 180, 0, 0, manta_seg5_dl_05006048), + GEO_ANIMATED_PART(LAYER_OPAQUE, 180, 0, 0, manta_seg5_dl_05006048), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05006C08), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05006C08), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 168, 0, 0, manta_seg5_dl_05006B70), + GEO_ANIMATED_PART(LAYER_OPAQUE, 168, 0, 0, manta_seg5_dl_05006B70), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 236, 0, 0, manta_seg5_dl_05006B08), - GEO_ANIMATED_PART(1, 236, 0, 0, manta_seg5_dl_05004E90), + GEO_ANIMATED_PART(LAYER_OPAQUE, 236, 0, 0, manta_seg5_dl_05006B08), + GEO_ANIMATED_PART(LAYER_OPAQUE, 236, 0, 0, manta_seg5_dl_05004E90), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 688, 120, -6, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 688, 120, -6, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05005038), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05005038), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 668, 170, 6, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 668, 170, 6, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05004DB8), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05004DB8), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 688, -120, -6, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 688, -120, -6, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05005918), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05005918), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, 668, -170, 6, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 668, -170, 6, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, manta_seg5_dl_05004A70), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, manta_seg5_dl_05004A70), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), diff --git a/actors/manta/model.inc.c b/actors/manta/model.inc.c index dc5c6519..f0efc467 100644 --- a/actors/manta/model.inc.c +++ b/actors/manta/model.inc.c @@ -13,7 +13,7 @@ static const Lights1 manta_seg5_lights_05001770 = gdSPDefLights1( ); // Unreferenced light group -static const Lights1 manta_lights_unused = gdSPDefLights1( +UNUSED static const Lights1 manta_lights_unused = gdSPDefLights1( 0x3f, 0x3f, 0x35, 0xff, 0xff, 0xd7, 0x28, 0x28, 0x28 ); diff --git a/actors/mario/model.inc.c b/actors/mario/model.inc.c index 191d5332..9fccd9c7 100644 --- a/actors/mario/model.inc.c +++ b/actors/mario/model.inc.c @@ -78,13 +78,13 @@ ALIGNED8 static const Texture mario_texture_eyes_closed[] = { // Unreferenced // 0x04004890 -ALIGNED8 static const Texture mario_texture_eyes_closed_unused1[] = { +UNUSED ALIGNED8 static const Texture mario_texture_eyes_closed_unused1[] = { #include "actors/mario/mario_eyes_closed_unused_0.rgba16.inc.c" }; // Unreferenced // 0x04005090 -ALIGNED8 static const Texture mario_texture_eyes_closed_unused2[] = { +UNUSED ALIGNED8 static const Texture mario_texture_eyes_closed_unused2[] = { #include "actors/mario/mario_eyes_closed_unused_1.rgba16.inc.c" }; diff --git a/actors/wiggler_body/geo.inc.c b/actors/wiggler_body/geo.inc.c index a55a1f93..38568c74 100644 --- a/actors/wiggler_body/geo.inc.c +++ b/actors/wiggler_body/geo.inc.c @@ -4,9 +4,9 @@ const GeoLayout wiggler_body_geo[] = { GEO_OPEN_NODE(), GEO_SCALE(0, 16384), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, NULL), GEO_OPEN_NODE(), GEO_BILLBOARD(), GEO_OPEN_NODE(), @@ -14,23 +14,23 @@ const GeoLayout wiggler_body_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, -31, 0, 51, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, -31, 0, 51, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, wiggler_seg5_dl_0500BE98), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, wiggler_seg5_dl_0500BE98), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 39, 0, 0, wiggler_seg5_dl_0500BE10), + GEO_ANIMATED_PART(LAYER_OPAQUE, 39, 0, 0, wiggler_seg5_dl_0500BE10), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 41, 0, 0, wiggler_seg5_dl_0500BCB8), + GEO_ANIMATED_PART(LAYER_OPAQUE, 41, 0, 0, wiggler_seg5_dl_0500BCB8), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), - GEO_ANIMATED_PART(1, -31, 0, -49, NULL), + GEO_ANIMATED_PART(LAYER_OPAQUE, -31, 0, -49, NULL), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 0, 0, 0, wiggler_seg5_dl_0500C100), + GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, wiggler_seg5_dl_0500C100), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 39, 0, 0, wiggler_seg5_dl_0500C078), + GEO_ANIMATED_PART(LAYER_OPAQUE, 39, 0, 0, wiggler_seg5_dl_0500C078), GEO_OPEN_NODE(), - GEO_ANIMATED_PART(1, 41, 0, 0, wiggler_seg5_dl_0500BF20), + GEO_ANIMATED_PART(LAYER_OPAQUE, 41, 0, 0, wiggler_seg5_dl_0500BF20), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), diff --git a/actors/wiggler_head/model.inc.c b/actors/wiggler_head/model.inc.c index afc3337e..2e2f405e 100644 --- a/actors/wiggler_head/model.inc.c +++ b/actors/wiggler_head/model.inc.c @@ -237,7 +237,7 @@ static const Vtx wiggler_seg5_vertex_0500D228[] = { }; // Unused vertices? what are these? [D318] -static const Vtx wiggler_seg5_vertex_0500D318[] = { +UNUSED static const Vtx wiggler_seg5_vertex_0500D318[] = { {{{ 92, 51, 0}, 0, { 0, 0}, {0x5d, 0x55, 0x00, 0x00}}}, {{{ 87, 46, -28}, 0, { 0, 0}, {0x5a, 0x53, 0xe1, 0x00}}}, {{{ 49, 88, -28}, 0, { 0, 0}, {0x5a, 0x53, 0xe1, 0x00}}}, diff --git a/asm/boot.s b/asm/boot.s index be12ff0a..17a0ace7 100644 --- a/asm/boot.s +++ b/asm/boot.s @@ -1,21 +1,21 @@ -# assembler directives -.set noat # allow manual use of $at -.set noreorder # don't insert nops after branches +// assembler directives +.set noat // allow manual use of $at +.set noreorder // don't insert nops after branches .set gp=64 -.include "macros.inc" +#include "macros.inc" -# 0xA0000000-0xBFFFFFFF: KSEG1 direct map non-cache mirror of 0x00000000 -# 0xA4000000-0xA4000FFF: RSP DMEM +// 0xA0000000-0xBFFFFFFF: KSEG1 direct map non-cache mirror of 0x00000000 +// 0xA4000000-0xA4000FFF: RSP DMEM -# 0xA4000000-0xA400003F: ROM header +// 0xA4000000-0xA400003F: ROM header .section .text, "ax" -# 0xA4000040-0xA4000B6F: IPL3 +// 0xA4000040-0xA4000B6F: IPL3 -# IPL3 entry point jumped to from IPL2 -glabel ipl3_entry # 0xA4000040 +// IPL3 entry point jumped to from IPL2 +glabel ipl3_entry // 0xA4000040 mtc0 $zero, $13 mtc0 $zero, $9 mtc0 $zero, $11 @@ -797,7 +797,7 @@ func_A4000AD0: nop nop -# 0xA4000B70-0xA4000FFF: IPL3 Font +// 0xA4000B70-0xA4000FFF: IPL3 Font glabel ipl3_font .incbin "textures/ipl3_raw/ipl3_font_00.ia1" .incbin "textures/ipl3_raw/ipl3_font_01.ia1" diff --git a/asm/entry.s b/asm/entry.s index 1f407aaf..fce4800c 100644 --- a/asm/entry.s +++ b/asm/entry.s @@ -1,9 +1,9 @@ -# assembler directives -.set noat # allow manual use of $at -.set noreorder # don't insert nops after branches +// assembler directives +.set noat // allow manual use of $at +.set noreorder // don't insert nops after branches .set gp=64 -.include "macros.inc" +#include "macros.inc" .section .text, "ax" @@ -25,4 +25,4 @@ entry_point: lui $sp, %hi(gIdleThreadStack) # Set the high half of the stack pointer to that of the idle thread stack addiu $t2, %lo(main_func) # Get the low half of the init function address jr $t2 # Jump to the init function - addiu $sp, %lo(gIdleThreadStack) # Set the low half of the stack pointer to that of the idle thread stack \ No newline at end of file + addiu $sp, %lo(gIdleThreadStack) # Set the low half of the stack pointer to that of the idle thread stack diff --git a/asm/rom_header.s b/asm/rom_header.s index 4eeaa07f..4ce1ab32 100644 --- a/asm/rom_header.s +++ b/asm/rom_header.s @@ -2,7 +2,7 @@ * Super Mario 64 ROM header * Only the first 0x18 bytes matter to the console. */ - +#include "config.h" .byte 0x80, 0x37, 0x12, 0x40 /* PI BSD Domain 1 register */ .word 0x0000000F /* Clockrate setting*/ .word entry_point /* Entrypoint */ @@ -14,22 +14,25 @@ .word 0x00000000 /* Checksum 2 */ .word 0x00000000 /* Unknown */ .word 0x00000000 /* Unknown */ -.if VERSION_SH == 1 -.ascii "SUPERMARIO64 " /* Internal ROM name */ -.else -.ascii "SUPER MARIO 64 " /* Internal ROM name */ -.endif +.ascii INTERNAL_ROM_NAME /* Internal ROM name */ .word 0x00000000 /* Unknown */ .word 0x0000004E /* Cartridge */ -.ascii "SM" /* Cartridge ID */ +.ascii "ED" /* Cartridge ID */ /* Region */ -.if VERSION_US == 1 - .ascii "E" /* NTSC-U (North America) */ -.elseif (VERSION_JP == 1 || VERSION_SH == 1) +#if defined(VERSION_JP) || defined(VERSION_SH) .ascii "J" /* NTSC-J (Japan) */ -.else - .ascii "P" /* PAL (Europe) */ -.endif - - .byte 0x00 /* Version */ +#else + .ascii "E" /* NTSC-U (North America) */ +#endif +#if defined(SRAM) + .byte 0x30 /* Version */ +#elif defined(EEP16K) + .byte 0x20 /* Version */ +#elif defined(SRAM768K) + .byte 0x40 /* Version */ +#elif defined(FLASHRAM) + .byte 0x50 /* Version */ +#else + .byte 0x10 /* Version */ +#endif diff --git a/assets.json b/assets.json index dd27f39f..691735f2 100644 --- a/assets.json +++ b/assets.json @@ -266,8 +266,9 @@ "actors/king_bobomb/king_bob-omb_arm.rgba16.png": [32,32,2048,{"jp":[1257760,8312],"us":[1264928,8312],"eu":[1136896,8312],"sh":[1113408,8312]}], "actors/king_bobomb/king_bob-omb_body_unused.rgba16.png": [64,64,8192,{"jp":[1257760,10360],"us":[1264928,10360],"eu":[1136896,10360],"sh":[1113408,10360]}], "actors/king_bobomb/king_bob-omb_crown_rim.rgba16.png": [32,16,1024,{"jp":[1257760,24696],"us":[1264928,24696],"eu":[1136896,24696],"sh":[1113408,24696]}], -"actors/king_bobomb/king_bob-omb_eyes.rgba16.png": [32,64,4096,{"jp":[1257760,18552],"us":[1264928,18552],"eu":[1136896,18552],"sh":[1113408,18552]}], -"actors/king_bobomb/king_bob-omb_hand.rgba16.png": [32,32,2048,{"jp":[1215456,64],"us":[1222624,64],"eu":[1094592,64],"sh":[1071104,64]}], +"actors/king_bobomb/king_bob-omb_eyes.rgba16.png": [32,32,2048,{"jp":[1257760,18552],"us":[1264928,18552],"eu":[1136896,18552],"sh":[1113408,18552]}], +"actors/king_bobomb/king_bob-omb_eyes_blink.rgba16.png": [32,32,2048,{"jp":[1257760,20600],"us":[1264928,20600],"eu":[1136896,20600],"sh":[1113408,20600]}], +"actors/king_bobomb/king_bob-omb_hand.rgba16.png": [32,32,2048,{"jp":[1257760,22648],"us":[1264928,22648],"eu":[1136896,22648],"sh":[1113408,22648]}], "actors/king_bobomb/king_bob-omb_left_side.rgba16.png": [32,64,4096,{"jp":[1257760,33912],"us":[1264928,33912],"eu":[1136896,33912],"sh":[1113408,33912]}], "actors/king_bobomb/king_bob-omb_right_side.rgba16.png": [32,64,4096,{"jp":[1257760,38008],"us":[1264928,38008],"eu":[1136896,38008],"sh":[1113408,38008]}], "actors/klepto/klepto_beak.rgba16.png": [32,64,4096,{"jp":[1327760,4104],"us":[1334928,4104],"eu":[1206896,4104],"sh":[1183408,4104]}], diff --git a/bin/segment2.c b/bin/segment2.c index eb2bdb3a..13f3cb7b 100644 --- a/bin/segment2.c +++ b/bin/segment2.c @@ -9,6 +9,11 @@ #include "make_const_nonconst.h" // SM64 (US/JP/EU/SH) Segment 02 +#ifdef PUPPYPRINT +ALIGNED8 const Texture small_font[] = { +#include "textures/segment2/custom_text.i4.inc.c" +}; +#endif ALIGNED8 static const Texture texture_hud_char_0[] = { #include "textures/segment2/segment2.00000.rgba16.inc.c" @@ -86,11 +91,9 @@ ALIGNED8 static const Texture texture_hud_char_I[] = { #include "textures/segment2/segment2.02400.rgba16.inc.c" }; -#if defined(VERSION_JP) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_J[] = { #include "textures/segment2/segment2.02600.rgba16.inc.c" }; -#endif ALIGNED8 static const Texture texture_hud_char_K[] = { #include "textures/segment2/segment2.02800.rgba16.inc.c" @@ -116,11 +119,9 @@ ALIGNED8 static const Texture texture_hud_char_P[] = { #include "textures/segment2/segment2.03200.rgba16.inc.c" }; -#if defined(VERSION_JP) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_Q[] = { #include "textures/segment2/segment2.03400.rgba16.inc.c" }; -#endif ALIGNED8 static const Texture texture_hud_char_R[] = { #include "textures/segment2/segment2.03600.rgba16.inc.c" @@ -138,31 +139,25 @@ ALIGNED8 static const Texture texture_hud_char_U[] = { #include "textures/segment2/segment2.03C00.rgba16.inc.c" }; -#if defined(VERSION_JP) || defined(VERSION_EU) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_V[] = { #include "textures/segment2/segment2.03E00.rgba16.inc.c" }; -#endif ALIGNED8 static const Texture texture_hud_char_W[] = { #include "textures/segment2/segment2.04000.rgba16.inc.c" }; -#if defined(VERSION_JP) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_X[] = { #include "textures/segment2/segment2.04200.rgba16.inc.c" }; -#endif ALIGNED8 static const Texture texture_hud_char_Y[] = { #include "textures/segment2/segment2.04400.rgba16.inc.c" }; -#if defined(VERSION_JP) || defined(VERSION_EU) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_Z[] = { #include "textures/segment2/segment2.04600.rgba16.inc.c" }; -#endif ALIGNED8 static const Texture texture_hud_char_apostrophe[] = { #include "textures/segment2/segment2.04800.rgba16.inc.c" @@ -178,7 +173,6 @@ ALIGNED8 static const Texture texture_hud_char_umlaut[] = { }; #endif -#if defined(VERSION_JP) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_exclamation[] = { #include "textures/segment2/segment2.04C00.rgba16.inc.c"// JP ! }; @@ -198,7 +192,6 @@ ALIGNED8 static const Texture texture_hud_char_ampersand[] = { ALIGNED8 static const Texture texture_hud_char_percent[] = { #include "textures/segment2/segment2.05400.rgba16.inc.c"// JP % }; -#endif ALIGNED8 static const Texture texture_hud_char_multiply[] = { #include "textures/segment2/segment2.05600.rgba16.inc.c" @@ -216,11 +209,9 @@ ALIGNED8 static const Texture texture_hud_char_star[] = { #include "textures/segment2/segment2.05C00.rgba16.inc.c" }; -#if defined(VERSION_JP) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_decimal_point[] = { #include "textures/segment2/segment2.05E00.rgba16.inc.c" }; -#endif #if defined(VERSION_JP) || defined(VERSION_SH) ALIGNED8 static const Texture texture_hud_char_beta_key[] = { @@ -1827,16 +1818,16 @@ const Texture *const main_hud_lut[] = { texture_hud_char_4, texture_hud_char_5, texture_hud_char_6, texture_hud_char_7, texture_hud_char_8, texture_hud_char_9, texture_hud_char_A, texture_hud_char_B, texture_hud_char_C, texture_hud_char_D, texture_hud_char_E, texture_hud_char_F, - texture_hud_char_G, texture_hud_char_H, texture_hud_char_I, 0x0, + texture_hud_char_G, texture_hud_char_H, texture_hud_char_I, texture_hud_char_J, texture_hud_char_K, texture_hud_char_L, texture_hud_char_M, texture_hud_char_N, - texture_hud_char_O, texture_hud_char_P, 0x0, texture_hud_char_R, - texture_hud_char_S, texture_hud_char_T, texture_hud_char_U, 0x0, - texture_hud_char_W, 0x0, texture_hud_char_Y, 0x0, - 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, + texture_hud_char_O, texture_hud_char_P, texture_hud_char_Q, texture_hud_char_R, + texture_hud_char_S, texture_hud_char_T, texture_hud_char_U, texture_hud_char_V, + texture_hud_char_W, texture_hud_char_X, texture_hud_char_Y, texture_hud_char_Z, + texture_hud_char_exclamation, texture_hud_char_double_exclamation, texture_hud_char_question, texture_hud_char_ampersand, + texture_hud_char_percent, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, texture_hud_char_multiply, texture_hud_char_coin, - texture_hud_char_mario_head, texture_hud_char_star, 0x0, 0x0, + texture_hud_char_mario_head, texture_hud_char_star, texture_hud_char_decimal_point, 0x0, texture_hud_char_apostrophe, texture_hud_char_double_quote, #else texture_hud_char_0, texture_hud_char_1, texture_hud_char_2, texture_hud_char_3, @@ -2097,14 +2088,8 @@ const Gfx dl_hud_img_begin[] = { gsDPSetTexturePersp(G_TP_NONE), gsDPSetAlphaCompare(G_AC_THRESHOLD), gsDPSetBlendColor(255, 255, 255, 255), -#if defined(VERSION_EU) || defined(VERSION_SH) gsDPSetRenderMode(G_RM_NOOP, G_RM_NOOP2), -#endif -#ifdef VERSION_EU gsDPSetTextureFilter(G_TF_POINT), -#elif defined(VERSION_JP) || defined(VERSION_US) - gsDPSetRenderMode(G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2), -#endif gsSPEndDisplayList(), }; @@ -2124,13 +2109,8 @@ const Gfx dl_hud_img_end[] = { gsDPSetTexturePersp(G_TP_PERSP), gsDPSetRenderMode(G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2), gsDPSetAlphaCompare(G_AC_NONE), -#ifdef VERSION_EU gsDPSetTextureFilter(G_TF_BILERP), -#endif gsDPSetCycleType(G_CYC_1CYCLE), -#if defined(VERSION_JP) || defined(VERSION_US) - gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), -#endif gsSPEndDisplayList(), }; @@ -2186,7 +2166,6 @@ const Gfx dl_draw_text_bg_box[] = { gsSPEndDisplayList(), }; -#ifndef VERSION_EU // 0x0200EE28 - 0x0200EE68 static const Vtx vertex_ia8_char[] = { #if defined(VERSION_JP) || defined(VERSION_SH) @@ -2201,21 +2180,8 @@ static const Vtx vertex_ia8_char[] = { {{{ 0, 16, 0}, 0, { 480, 256}, {0xff, 0xff, 0xff, 0xff}}}, #endif }; -// !EU -#endif #ifdef VERSION_EU -// 0x020073B0 -const Gfx dl_ia_text_begin[] = { - gsDPPipeSync(), - gsDPSetTexturePersp(G_TP_NONE), - gsDPSetCombineMode(G_CC_FADEA, G_CC_FADEA), - gsDPSetEnvColor(255, 255, 255, 255), - gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2), - gsDPSetTextureFilter(G_TF_POINT), - gsSPEndDisplayList(), -}; - // 0x020073E8 - 0x02007418 const Gfx dl_ia_text_tex_settings[] = { gsDPSetTile(G_IM_FMT_IA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_MIRROR, 3, G_TX_NOLOD, G_TX_WRAP | G_TX_MIRROR, 4, G_TX_NOLOD), @@ -2223,21 +2189,14 @@ const Gfx dl_ia_text_tex_settings[] = { gsDPLoadBlock(G_TX_LOADTILE, 0, 0, ((16 * 8 + G_IM_SIZ_4b_INCR) >> G_IM_SIZ_4b_SHIFT) - 1, CALC_DXT(16, G_IM_SIZ_4b_BYTES)), gsDPSetTile(G_IM_FMT_IA, G_IM_SIZ_4b, 1, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_MIRROR, 3, G_TX_NOLOD, G_TX_WRAP | G_TX_MIRROR, 4, G_TX_NOLOD), gsDPSetTileSize(0, 0, 0, (16 - 1) << G_TEXTURE_IMAGE_FRAC, (8 - 1) << G_TEXTURE_IMAGE_FRAC), + gsSPVertex(vertex_ia8_char, 4, 0), + gsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0), + gsSPEndDisplayList(), gsSPEndDisplayList(), }; +#endif -// 0x02007418 - 0x02007450 -const Gfx dl_ia_text_end[] = { - gsDPPipeSync(), - gsDPSetTexturePersp(G_TP_PERSP), - gsDPSetRenderMode(G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2), - gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), - gsDPSetEnvColor(255, 255, 255, 255), - gsDPSetTextureFilter(G_TF_BILERP), - gsSPEndDisplayList(), -}; - -#elif defined(VERSION_US) +#if defined(VERSION_US) || defined(VERSION_EU) const Gfx dl_ia_text_begin[] = { gsDPPipeSync(), gsSPClearGeometryMode(G_LIGHTING), @@ -2248,7 +2207,9 @@ const Gfx dl_ia_text_begin[] = { gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), gsSPEndDisplayList(), }; +#endif +#ifdef VERSION_US const Gfx dl_ia_text_tex_settings[] = { gsDPSetTile(G_IM_FMT_IA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 3, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD), gsDPLoadSync(), @@ -2259,8 +2220,9 @@ const Gfx dl_ia_text_tex_settings[] = { gsSP2Triangles( 0, 1, 2, 0x0, 0, 2, 3, 0x0), gsSPEndDisplayList(), }; +#endif -#else +#if defined(VERSION_JP) || defined(VERSION_SH) // 0x0200EE68 - 0x0200EEA8 const Gfx dl_ia_text_begin[] = { gsDPPipeSync(), @@ -2286,7 +2248,6 @@ const Gfx dl_ia_text_tex_settings[] = { }; #endif -#ifndef VERSION_EU // 0x0200EEF0 - 0x0200EF30 const Gfx dl_ia_text_end[] = { gsDPPipeSync(), @@ -2298,7 +2259,6 @@ const Gfx dl_ia_text_end[] = { gsDPSetTextureFilter(G_TF_BILERP), gsSPEndDisplayList(), }; -#endif // 0x0200EF30 - 0x0200EF60 static const Vtx vertex_triangle[] = { @@ -2498,7 +2458,7 @@ const Texture texture_waterbox_lava[] = { }; // Unreferenced light group -static const Lights1 segment2_lights_unused = gdSPDefLights1( +UNUSED static const Lights1 segment2_lights_unused = gdSPDefLights1( 0x40, 0x40, 0x40, 0xff, 0xff, 0xff, 0x28, 0x28, 0x28 ); diff --git a/charmap.txt b/charmap.txt index 49aaee55..a1581c13 100644 --- a/charmap.txt +++ b/charmap.txt @@ -220,6 +220,7 @@ 'ィ' = 0xD6 'ゥ' = 0xD7 'ォ' = 0xD8 +'@' = 0xDF '[%]' = 0xE0 '(' = 0xE1 '' = 0xE1 diff --git a/data/behavior_data.c b/data/behavior_data.c index 79df196a..584b4402 100644 --- a/data/behavior_data.c +++ b/data/behavior_data.c @@ -1966,6 +1966,7 @@ const BehaviorScript bhvBowser[] = { SPAWN_CHILD(/*Model*/ MODEL_NONE, /*Behavior*/ bhvBowserBodyAnchor), SPAWN_CHILD(/*Model*/ MODEL_BOWSER_BOMB_CHILD_OBJ, /*Behavior*/ bhvBowserFlameSpawn), SPAWN_OBJ(/*Model*/ MODEL_NONE, /*Behavior*/ bhvBowserTailAnchor), + // Beta leftover that spawn 50 coins when Bowser is defeated SET_INT(oNumLootCoins, 50), SET_OBJ_PHYSICS(/*Wall hitbox radius*/ 0, /*Gravity*/ -400, /*Bounciness*/ -70, /*Drag strength*/ 1000, /*Friction*/ 1000, /*Buoyancy*/ 200, /*Unused*/ 0, 0), SET_HOME(), @@ -3024,7 +3025,7 @@ const BehaviorScript bhvHiddenStaircaseStep[] = { END_LOOP(), }; -const BehaviorScript bhvBooBossSpawnedBridge[] = { +const BehaviorScript bhvBooStaircase[] = { BEGIN(OBJ_LIST_SURFACE), OR_INT(oFlags, OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE), LOAD_COLLISION_DATA(bbh_seg7_collision_staircase_step), @@ -3032,7 +3033,7 @@ const BehaviorScript bhvBooBossSpawnedBridge[] = { SET_FLOAT(oCollisionDistance, 1000), SET_HOME(), BEGIN_LOOP(), - CALL_NATIVE(bhv_boo_boss_spawned_bridge_loop), + CALL_NATIVE(bhv_boo_staircase), CALL_NATIVE(load_object_collision_model), END_LOOP(), }; @@ -3142,7 +3143,7 @@ const BehaviorScript bhvUnusedFakeStar[] = { }; // What is this? -static const BehaviorScript unused_1[] = { +UNUSED static const BehaviorScript unused_1[] = { BREAK(), BREAK(), BREAK(), @@ -3506,7 +3507,7 @@ UNUSED static const u64 behavior_data_unused_0 = 0; const BehaviorScript bhvMario[] = { BEGIN(OBJ_LIST_PLAYER), SET_INT(oIntangibleTimer, 0), - OR_INT(oFlags, OBJ_FLAG_0100), + OR_INT(oFlags, OBJ_FLAG_PLAYER), OR_INT(oUnk94, 0x0001), SET_HITBOX(/*Radius*/ 37, /*Height*/ 160), BEGIN_LOOP(), @@ -3630,7 +3631,7 @@ const BehaviorScript bhvMenuButton[] = { const BehaviorScript bhvMenuButtonManager[] = { BEGIN(OBJ_LIST_LEVEL), - OR_INT(oFlags, (OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM | OBJ_FLAG_0020 | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), + OR_INT(oFlags, (OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM | OBJ_FLAG_UPDATE_TRANSFORM_FOR_THROW_MATRIX | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), CALL_NATIVE(bhv_menu_button_manager_init), BEGIN_LOOP(), SET_INT(oIntangibleTimer, 0), @@ -3852,7 +3853,7 @@ const BehaviorScript bhvSignOnWall[] = { const BehaviorScript bhvHomingAmp[] = { BEGIN(OBJ_LIST_GENACTOR), OR_INT(oFlags, (OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO | OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW | OBJ_FLAG_MOVE_XZ_USING_FVEL | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), - LOAD_ANIMATIONS(oAnimations, amp_seg8_anims_08004034), + LOAD_ANIMATIONS(oAnimations, dAmpAnimsList), ANIMATE(0), SET_FLOAT(oGraphYOffset, 40), SET_INT(oIntangibleTimer, 0), @@ -3865,7 +3866,7 @@ const BehaviorScript bhvHomingAmp[] = { const BehaviorScript bhvCirclingAmp[] = { BEGIN(OBJ_LIST_GENACTOR), OR_INT(oFlags, (OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO | OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_MOVE_XZ_USING_FVEL | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), - LOAD_ANIMATIONS(oAnimations, amp_seg8_anims_08004034), + LOAD_ANIMATIONS(oAnimations, dAmpAnimsList), ANIMATE(0), SET_FLOAT(oGraphYOffset, 40), SET_INT(oIntangibleTimer, 0), @@ -4827,7 +4828,7 @@ const BehaviorScript bhvHidden1upInPoleSpawner[] = { const BehaviorScript bhvControllablePlatform[] = { BEGIN(OBJ_LIST_SURFACE), - OR_INT(oFlags, (OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM | OBJ_FLAG_0020 | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), + OR_INT(oFlags, (OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM | OBJ_FLAG_UPDATE_TRANSFORM_FOR_THROW_MATRIX | OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE)), LOAD_COLLISION_DATA(hmc_seg7_collision_controllable_platform), SET_HOME(), CALL_NATIVE(bhv_controllable_platform_init), diff --git a/enhancements/crash.patch b/enhancements/crash.patch index c3c8b537..87c5c8f9 100644 --- a/enhancements/crash.patch +++ b/enhancements/crash.patch @@ -1,13 +1,13 @@ diff --git a/asm/crash.s b/asm/crash.s new file mode 100644 -index 00000000..0b2a5574 +index 00000000..033bf952 --- /dev/null +++ b/asm/crash.s @@ -0,0 +1,153 @@ -+# SM64 Crash Handler -+# See Readme below. ++// SM64 Crash Handler ++// See Readme below. + -+.include "macros.inc" ++#include "macros.inc" + +/* --------------------------------------------------------------- + * IMPORTANT README: @@ -58,7 +58,7 @@ index 00000000..0b2a5574 + sw $a3, %lo(nAssertStopProgram)($at) + beqz $a3, .end_2 + nop -+ syscall # trigger crash screen ++ syscall // trigger crash screen +.end_2: + jr $ra + nop @@ -75,15 +75,15 @@ index 00000000..0b2a5574 + jr $ra + mfc0 $v0, COP0_BADVADDR + -+# If the error code field of cop0's cause register is non-zero, -+# draw crash details to the screen and hang -+# -+# If there wasn't an error, continue to the original handler ++// If the error code field of cop0's cause register is non-zero, ++// draw crash details to the screen and hang ++ ++// If there wasn't an error, continue to the original handler + +glabel __crash_handler_entry + mfc0 $k1, COP0_CAUSE + andi $k1, $k1, (0x1F << 2) -+ beqzl $k1, .end2 # exit if ExCode is 0 ++ beqzl $k1, .end2 // exit if ExCode is 0 + lui $k0, %hi(__osException) + la $k0, exceptionRegContext + sd $zero, 0x018 ($k0) @@ -116,7 +116,7 @@ index 00000000..0b2a5574 + sd $sp, 0x0F0 ($k0) + sd $fp, 0x0F8 ($k0) + sd $ra, 0x100 ($k0) -+ # cop unusable exception fired twice on startup so we'll ignore it for now ++ // cop unusable exception fired twice on startup so we'll ignore it for now + li $t0, (0x0B << 2) + beq $k1, $t0, .end + nop @@ -155,14 +155,14 @@ index 00000000..0b2a5574 + lui $k0, %hi(__osException) + .end2: + addiu $k0, $k0, %lo(__osException) -+ jr $k0 # run the original handler ++ jr $k0 // run the original handler + nop diff --git a/lib/asm/__osExceptionPreamble.s b/lib/asm/__osExceptionPreamble.s -index e14928ce..4d12129e 100644 +index c3b97993..c552a485 100644 --- a/lib/asm/__osExceptionPreamble.s +++ b/lib/asm/__osExceptionPreamble.s -@@ -18,8 +18,8 @@ - .endif +@@ -11,8 +11,8 @@ + #endif glabel __osExceptionPreamble - lui $k0, %hi(__osException) @@ -173,10 +173,10 @@ index e14928ce..4d12129e 100644 nop diff --git a/sm64.ld b/sm64.ld -index f80f5b4d..569344bc 100755 +index 7d9b5b4a..c7bb81b9 100755 --- a/sm64.ld +++ b/sm64.ld -@@ -116,6 +116,7 @@ SECTIONS +@@ -117,6 +117,7 @@ SECTIONS BUILD_DIR/src/game/rendering_graph_node.o(.text); BUILD_DIR/src/game/profiler.o(.text); BUILD_DIR/asm/decompress.o(.text); diff --git a/enhancements/debug_box.patch b/enhancements/debug_box.patch index 2ec23b9f..4dacd2be 100644 --- a/enhancements/debug_box.patch +++ b/enhancements/debug_box.patch @@ -2,10 +2,10 @@ diff --git a/src/game/area.c b/src/game/area.c index af9d0156..c68a7f6e 100644 --- a/src/game/area.c +++ b/src/game/area.c -@@ -21,6 +21,7 @@ - #include "engine/geo_layout.h" +@@ -22,6 +22,7 @@ #include "save_file.h" #include "level_table.h" + #include "dialog_ids.h" +#include "debug_box.h" struct SpawnInfo gPlayerSpawnInfos[1]; diff --git a/enhancements/fps.patch b/enhancements/fps.patch index ad8bfaa0..e5e1acca 100644 --- a/enhancements/fps.patch +++ b/enhancements/fps.patch @@ -1,10 +1,10 @@ diff --git a/src/game/game_init.c b/src/game/game_init.c -index b6334688..62ed106c 100644 +index b961ca52..531231cf 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c -@@ -59,6 +59,47 @@ struct DemoInput *gCurrDemoInput = NULL; // demo input sequence - u16 gDemoInputListID = 0; - struct DemoInput gRecordedDemoInput = { 0 }; // possibly removed in EU. TODO: Check +@@ -82,6 +82,47 @@ struct DemoInput gRecordedDemoInput = { 0 }; + // Display + // ---------------------------------------------------------------------------------------------------- +// SDK states that 1 cycle takes about 21.33 nanoseconds +#define SECONDS_PER_CYCLE 0.00000002133f @@ -48,9 +48,9 @@ index b6334688..62ed106c 100644 +} + /** - * Initializes the Reality Display Processor (RDP). - * This function initializes settings such as texture filtering mode, -@@ -633,5 +674,7 @@ void thread5_game_loop(UNUSED void *arg) { + * Sets the initial RDP (Reality Display Processor) rendering settings. + */ +@@ -694,5 +735,7 @@ void thread5_game_loop(UNUSED void *arg) { // amount of free space remaining. print_text_fmt_int(180, 20, "BUF %d", gGfxPoolEnd - (u8 *) gDisplayListHead); } diff --git a/enhancements/ique_support.patch b/enhancements/ique_support.patch index ed2a508c..8487c48e 100644 --- a/enhancements/ique_support.patch +++ b/enhancements/ique_support.patch @@ -13,16 +13,16 @@ index 00000000..e60550ab +extern enum ConsoleType get_console_type(void); diff --git a/lib/asm/skGetId.s b/lib/asm/skGetId.s new file mode 100644 -index 00000000..8fb4c449 +index 00000000..58e7d4f9 --- /dev/null +++ b/lib/asm/skGetId.s @@ -0,0 +1,18 @@ -+# Code by stuckpixel ++// Code by stuckpixel + +.set noreorder +.set gp=64 + -+.include "macros.inc" ++#include "macros.inc" + +glabel skGetId + li $v0, 0 @@ -36,10 +36,10 @@ index 00000000..8fb4c449 + nop + nop diff --git a/lib/src/__osViSwapContext.c b/lib/src/__osViSwapContext.c -index b9d364b1..fa149b5d 100644 +index 990cb11f..22756e91 100644 --- a/lib/src/__osViSwapContext.c +++ b/lib/src/__osViSwapContext.c -@@ -52,7 +52,9 @@ void __osViSwapContext() { +@@ -54,7 +54,9 @@ void __osViSwapContext() { HW_REG(VI_INTR_REG, u32) = s0->fldRegs[field].vIntr; HW_REG(VI_X_SCALE_REG, u32) = s1->unk20; HW_REG(VI_Y_SCALE_REG, u32) = s1->unk2c; @@ -269,7 +269,7 @@ index 1a86477b..a94f8721 100644 return sp34; } diff --git a/lib/src/osInitialize.c b/lib/src/osInitialize.c -index ea247636..4adb45cb 100644 +index ba73024b..6deaf407 100644 --- a/lib/src/osInitialize.c +++ b/lib/src/osInitialize.c @@ -1,6 +1,7 @@ @@ -280,7 +280,7 @@ index ea247636..4adb45cb 100644 #define PIF_ADDR_START (void *) 0x1FC007FC -@@ -54,6 +55,7 @@ void osInitialize(void) { +@@ -51,6 +52,7 @@ void osInitialize(void) { UNUSED u32 eu_sp30; #endif UNUSED u32 sp2c; @@ -289,24 +289,24 @@ index ea247636..4adb45cb 100644 __osSetSR(__osGetSR() | 0x20000000); __osSetFpcCsr(0x01000800); diff --git a/sm64.ld b/sm64.ld -index f80f5b4d..e53d4e40 100755 +index 7d9b5b4a..be853a3b 100755 --- a/sm64.ld +++ b/sm64.ld -@@ -300,6 +300,8 @@ SECTIONS - #ifdef VERSION_SH - BUILD_DIR/libultra.a:unk_shindou_file_3.o(.text) +@@ -306,6 +306,8 @@ SECTIONS + #if ENABLE_RUMBLE + BUILD_DIR/libultra.a:unk_shindou_file_3.o(.text); #endif + BUILD_DIR/libultra.a:consoleType.o(.text) + BUILD_DIR/libultra.a:skGetId.o(.text) BUILD_DIR/lib/rsp.o(.text); #else BUILD_DIR/src/game*.o(.text); -@@ -410,6 +412,8 @@ SECTIONS - BUILD_DIR/libultra.a:__osGetCause.o(.text); - BUILD_DIR/libultra.a:__osAtomicDec.o(.text); - BUILD_DIR/libultra.a:guLookAtRef.o(.text); /* Fast3DEX2 only */ -+ BUILD_DIR/libultra.a:consoleType.o(.text); -+ BUILD_DIR/libultra.a:skGetId.o(.text); +@@ -428,6 +430,8 @@ SECTIONS + #if ENABLE_RUMBLE + BUILD_DIR/libultra.a:unk_shindou_file_3.o(.text); + #endif ++ BUILD_DIR/libultra.a:consoleType.o(.text) ++ BUILD_DIR/libultra.a:skGetId.o(.text) BUILD_DIR/lib/rsp.o(.text); #endif diff --git a/enhancements/mem_error_screen.patch b/enhancements/mem_error_screen.patch index 2b1ff034..5752b8c1 100644 --- a/enhancements/mem_error_screen.patch +++ b/enhancements/mem_error_screen.patch @@ -1,22 +1,22 @@ diff --git a/Makefile b/Makefile -index f81fd27b..318140f2 100644 +index f50b7622..124c7ec6 100644 --- a/Makefile +++ b/Makefile -@@ -419,6 +419,7 @@ $(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h +@@ -478,6 +478,7 @@ $(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h $(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h -+$(BUILD_DIR)/src/game/mem_error_screen.o: $(BUILD_DIR)/include/text_strings.h ++$(BUILD_DIR)/src/boot/mem_error_screen.o: $(BUILD_DIR)/include/text_strings.h #==============================================================================# diff --git a/include/segments.h b/include/segments.h -index a8c1bf97..84c3d7a4 100644 +index a97d6ee8..186c968e 100644 --- a/include/segments.h +++ b/include/segments.h -@@ -1,6 +1,9 @@ - #ifndef SEGMENTS_H - #define SEGMENTS_H +@@ -3,6 +3,9 @@ + + #include "config.h" +/* Use expansion pack RAM */ +#define USE_EXT_RAM 1 @@ -58,7 +58,7 @@ index 17c773ed..677a5ae9 100644 + JUMP(/*target*/ level_script_entry_error_screen), +}; diff --git a/levels/intro/geo.c b/levels/intro/geo.c -index 7a297fe7..71b16442 100644 +index 30a87806..6bf7b79a 100644 --- a/levels/intro/geo.c +++ b/levels/intro/geo.c @@ -15,6 +15,24 @@ @@ -100,7 +100,7 @@ index 99277e86..04797cd7 100644 + #endif diff --git a/levels/intro/script.c b/levels/intro/script.c -index a130cc04..926c0d09 100644 +index 04b8fc4c..ca9058c4 100644 --- a/levels/intro/script.c +++ b/levels/intro/script.c @@ -18,6 +18,21 @@ @@ -137,19 +137,19 @@ index d41a91c8..7d047236 100644 struct LevelCommand *level_script_execute(struct LevelCommand *cmd); -diff --git a/src/game/main.c b/src/game/main.c -index 9615f25a..e2d7b3d4 100644 ---- a/src/game/main.c -+++ b/src/game/main.c +diff --git a/src/boot/main.c b/src/boot/main.c +index 1a9d9e7e..f4f7a9e5 100644 +--- a/src/boot/main.c ++++ b/src/boot/main.c @@ -11,6 +11,7 @@ #include "segments.h" - #include "main.h" - #include "rumble_init.h" + #include "game/main.h" + #include "game/rumble_init.h" +#include "mem_error_screen.h" // Message IDs #define MESG_SP_COMPLETE 100 -@@ -127,6 +128,10 @@ void alloc_pool(void) { +@@ -131,6 +132,10 @@ void alloc_pool(void) { void *start = (void *) SEG_POOL_START; void *end = (void *) SEG_POOL_END; @@ -160,7 +160,7 @@ index 9615f25a..e2d7b3d4 100644 main_pool_init(start, end); gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT); } -@@ -332,7 +337,10 @@ void thread3_main(UNUSED void *arg) { +@@ -336,7 +341,10 @@ void thread3_main(UNUSED void *arg) { create_thread(&gSoundThread, 4, thread4_sound, NULL, gThread4Stack + 0x2000, 20); osStartThread(&gSoundThread); @@ -172,11 +172,11 @@ index 9615f25a..e2d7b3d4 100644 osStartThread(&gGameLoopThread); while (TRUE) { -diff --git a/src/game/mem_error_screen.c b/src/game/mem_error_screen.c +diff --git a/src/boot/mem_error_screen.c b/src/boot/mem_error_screen.c new file mode 100644 -index 00000000..81efaf91 +index 00000000..f432927c --- /dev/null -+++ b/src/game/mem_error_screen.c ++++ b/src/boot/mem_error_screen.c @@ -0,0 +1,104 @@ +/* clang-format off */ +/* @@ -274,15 +274,14 @@ index 00000000..81efaf91 + + addr = segmented_to_virtual(level_script_entry_error_screen); + -+ rendering_init(); ++ render_init(); + + while (1) { -+ config_gfx_pool(); ++ select_gfx_pool(); + addr = level_script_execute(addr); + display_and_vsync(); + } +} -\ No newline at end of file diff --git a/src/game/mem_error_screen.h b/src/game/mem_error_screen.h new file mode 100644 index 00000000..9fbff34c diff --git a/enhancements/record_demo.patch b/enhancements/record_demo.patch index 5e90000c..a02b9f17 100644 --- a/enhancements/record_demo.patch +++ b/enhancements/record_demo.patch @@ -1,5 +1,5 @@ diff --git a/src/game/game_init.c b/src/game/game_init.c -index b6334688..9363074b 100644 +index b961ca52..adfde049 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -11,6 +11,7 @@ @@ -10,9 +10,9 @@ index b6334688..9363074b 100644 #include "profiler.h" #include "save_file.h" #include "seq_ids.h" -@@ -335,6 +336,45 @@ void display_and_vsync(void) { - gGlobalTimer++; - } +@@ -386,6 +387,45 @@ void display_and_vsync(void) { + // Controls + // ---------------------------------------------------------------------------------------------------- +/* + * This enhancement allows you to record gameplay demos for the mario head screen. @@ -24,7 +24,7 @@ index b6334688..9363074b 100644 + * +*/ + -+#include "../src/game/mario.h" ++#include "mario.h" + +#define DEMOREC_STATUS_NOT_RECORDING 0 +#define DEMOREC_STATUS_PREPARING 1 @@ -53,15 +53,15 @@ index b6334688..9363074b 100644 +struct DemoInput* gRecordedInputsPtr = (struct DemoInput*)gRecordedInputs; +struct DemoInput gRecordedDemoInputCopy; + - // this function records distinct inputs over a 255-frame interval to RAM locations and was likely - // used to record the demo sequences seen in the final game. This function is unused. - static void record_demo(void) { -@@ -368,6 +408,118 @@ static void record_demo(void) { + /** + * This function records distinct inputs over a 255-frame interval to RAM locations and was likely + * used to record the demo sequences seen in the final game. This function is unused. +@@ -420,6 +460,118 @@ UNUSED static void record_demo(void) { gRecordedDemoInput.timer++; } +void record_new_demo_input(void) { -+ if(gRecordedDemoInput.timer == 1 && gRecordedDemoInputCopy.timer > 0) { ++ if (gRecordedDemoInput.timer == 1 && gRecordedDemoInputCopy.timer > 0) { + gRecordedInputs[gNumOfRecordedInputs].timer = gRecordedDemoInputCopy.timer; + gRecordedInputs[gNumOfRecordedInputs + 1].timer = 0; + gRecordedInputs[gNumOfRecordedInputs].rawStickX = gRecordedDemoInputCopy.rawStickX; @@ -86,13 +86,13 @@ index b6334688..9363074b 100644 +void recording(void) { + + // Force-stop when someone makes too many inputs. -+ if(gNumOfRecordedInputs + 1 > DEMOREC_MAX_INPUTS) { ++ if (gNumOfRecordedInputs + 1 > DEMOREC_MAX_INPUTS) { + gRecordingStatus = DEMOREC_STATUS_STOPPING; + return; + } + + copy_gRecordedDemoInput(); -+ record_demo(); // Defined in game.c ++ record_demo(); + record_new_demo_input(); +} + @@ -112,10 +112,10 @@ index b6334688..9363074b 100644 + case DEMOREC_STATUS_NOT_RECORDING: + break; + case DEMOREC_STATUS_PREPARING: -+ if(gMarioObject != NULL && gCurrLevelNum >= 5) { // If the game is in an active level ++ if (gMarioObject != NULL && gCurrLevelNum != LEVEL_NONE) { // If the game is in an active level + gRecordingStatus = DEMOREC_STATUS_RECORDING; + -+ // A bit of a hack, but it works. ++ // First 4 values in demo inputs are used to define level ID + gNumOfRecordedInputs = 1; + gRecordedInputs[0].timer = gCurrLevelNum; + gRecordedInputs[0].rawStickX = 0; @@ -127,7 +127,7 @@ index b6334688..9363074b 100644 + recording(); + break; + case DEMOREC_STATUS_DONE: -+ if(gDoneDelay > DEMOREC_DONE_DELAY) ++ if (gDoneDelay > DEMOREC_DONE_DELAY) + gRecordingStatus = DEMOREC_STATUS_NOT_RECORDING; + else + gDoneDelay++; @@ -159,8 +159,8 @@ index b6334688..9363074b 100644 + // so the debug level select is used for that. + gDebugLevelSelect = TRUE; + -+ if(gPlayer1Controller->buttonPressed & L_TRIG) { -+ if(gRecordingStatus == DEMOREC_STATUS_NOT_RECORDING) { ++ if (gPlayer1Controller->buttonPressed & L_TRIG) { ++ if (gRecordingStatus == DEMOREC_STATUS_NOT_RECORDING) { + gRecordingStatus = DEMOREC_STATUS_PREPARING; + } else if (gRecordingStatus == DEMOREC_STATUS_RECORDING) { + gRecordingStatus = DEMOREC_STATUS_STOPPING; @@ -172,12 +172,12 @@ index b6334688..9363074b 100644 + print_status(); +} + - // take the updated controller struct and calculate - // the new x, y, and distance floats. - void adjust_analog_stick(struct Controller *controller) { -@@ -623,6 +775,7 @@ void thread5_game_loop(UNUSED void *arg) { + /** + * Take the updated controller struct and calculate the new x, y, and distance floats. + */ +@@ -684,6 +836,7 @@ void thread5_game_loop(UNUSED void *arg) { audio_game_loop_tick(); - config_gfx_pool(); + select_gfx_pool(); read_controller_inputs(); + recordingDemo(); addr = level_script_execute(addr); diff --git a/enhancements/reonu_cam.patch b/enhancements/reonu_cam.patch deleted file mode 100644 index 4e210fe9..00000000 --- a/enhancements/reonu_cam.patch +++ /dev/null @@ -1,183 +0,0 @@ -diff --git a/src/game/camera.c b/src/game/camera.c -index 13d3fe2..be49880 100644 ---- a/src/game/camera.c -+++ b/src/game/camera.c -@@ -259,6 +259,7 @@ s16 sCameraSoundFlags; - * Stores what C-Buttons are pressed this frame. - */ - u16 sCButtonsPressed; -+u16 stoppedMovingCamera; - /** - * A copy of gDialogID, the dialog displayed during the cutscene. - */ -@@ -433,6 +434,9 @@ u8 sFramesSinceCutsceneEnded = 0; - * 3 = Dialog doesn't have a response - */ - u8 sCutsceneDialogResponse = 0; -+u8 stickReset = 1; -+u8 cButtonCounter; -+u8 lastCameraMove; - struct PlayerCameraState *sMarioCamState = &gPlayerCameraState[0]; - struct PlayerCameraState *sLuigiCamState = &gPlayerCameraState[1]; - u32 unused8032D008 = 0; -@@ -442,6 +446,9 @@ Vec3f sUnusedModeBasePosition_3 = { 646.0f, 143.0f, -1513.0f }; - Vec3f sUnusedModeBasePosition_4 = { 646.0f, 143.0f, -1513.0f }; - Vec3f sUnusedModeBasePosition_5 = { 646.0f, 143.0f, -1513.0f }; - -+#define MOVED_LEFT 1 -+#define MOVED_RIGHT 2 -+ - s32 update_radial_camera(struct Camera *c, Vec3f, Vec3f); - s32 update_outward_radial_camera(struct Camera *c, Vec3f, Vec3f); - s32 update_behind_mario_camera(struct Camera *c, Vec3f, Vec3f); -@@ -1176,14 +1183,39 @@ void mode_8_directions_camera(struct Camera *c) { - - radial_camera_input(c, 0.f); - -- if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { -- s8DirModeYawOffset += DEGREES(45); -- play_sound_cbutton_side(); -- } -- if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { -- s8DirModeYawOffset -= DEGREES(45); -- play_sound_cbutton_side(); -+ if (gPlayer1Controller->buttonDown & L_CBUTTONS) { -+ s8DirModeYawOffset -= DEGREES(4); -+ cButtonCounter++; -+ stoppedMovingCamera = 0; -+ lastCameraMove = MOVED_LEFT; -+ -+ } -+ else if (gPlayer1Controller->buttonDown & R_CBUTTONS) { -+ s8DirModeYawOffset += DEGREES(4); -+ cButtonCounter++; -+ stoppedMovingCamera = 0; -+ lastCameraMove = MOVED_RIGHT; -+ } -+ else if (gPlayer2Controller->rawStickX) { -+ s8DirModeYawOffset += DEGREES(gPlayer2Controller->rawStickX * 4 / 64); -+ } else { -+ stoppedMovingCamera = 1; -+ } -+ -+ if (stoppedMovingCamera == 1) { -+ if ((cButtonCounter < 5) && (cButtonCounter > 0)) { -+ if (lastCameraMove == MOVED_RIGHT) { -+ s8DirModeYawOffset += DEGREES(45); -+ cButtonCounter = 0; -+ } else { -+ s8DirModeYawOffset -= DEGREES(45); -+ cButtonCounter = 0; -+ } -+ } else { -+ cButtonCounter = 0; -+ } - } -+ - - lakitu_zoom(400.f, 0x900); - c->nextYaw = update_8_directions_camera(c, c->focus, pos); -@@ -2760,7 +2792,7 @@ s32 mode_c_up_camera(struct Camera *c) { - sPanDistance = 0.f; - - // Exit C-Up mode -- if (gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)) { -+ if ((gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)) || (gPlayer2Controller->rawStickY < -10)) { - exit_c_up(c); - } - return 0; -@@ -3015,14 +3047,11 @@ void update_camera(struct Camera *c) { - // Only process R_TRIG if 'fixed' is not selected in the menu - if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { - if (gPlayer1Controller->buttonPressed & R_TRIG) { -- if (set_cam_angle(0) == CAM_ANGLE_LAKITU) { -- set_cam_angle(CAM_ANGLE_MARIO); -- } else { -- set_cam_angle(CAM_ANGLE_LAKITU); -- } -+ s8DirModeYawOffset = gMarioState->faceAngle[1]-0x8000; -+ play_sound_rbutton_changed(); - } - } -- play_sound_if_cam_switched_to_lakitu_or_mario(); -+ //play_sound_if_cam_switched_to_lakitu_or_mario(); - } - - // Initialize the camera -@@ -3865,7 +3894,7 @@ s32 find_c_buttons_pressed(u16 currentState, u16 buttonsPressed, u16 buttonsDown - currentState &= ~R_CBUTTONS; - } - -- if (buttonsPressed & U_CBUTTONS) { -+ if ((buttonsPressed & U_CBUTTONS)) { - currentState |= U_CBUTTONS; - currentState &= ~D_CBUTTONS; - } -@@ -4816,19 +4845,19 @@ void play_camera_buzz_if_c_sideways(void) { - } - - void play_sound_cbutton_up(void) { -- play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); -+ //play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); - } - - void play_sound_cbutton_down(void) { -- play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); -+ //play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); - } - - void play_sound_cbutton_side(void) { -- play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource); -+ //play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource); - } - - void play_sound_button_change_blocked(void) { -- play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource); -+ //play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource); - } - - void play_sound_rbutton_changed(void) { -@@ -4925,7 +4954,7 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { - } - - // Zoom in / enter C-Up -- if (gPlayer1Controller->buttonPressed & U_CBUTTONS) { -+ if (((gPlayer1Controller->buttonPressed & U_CBUTTONS) || (gPlayer2Controller->rawStickY > 40)) && (stickReset)) { - if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { - gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; - play_sound_cbutton_up(); -@@ -4935,7 +4964,7 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { - } - - // Zoom out -- if (gPlayer1Controller->buttonPressed & D_CBUTTONS) { -+ if ((gPlayer1Controller->buttonPressed & D_CBUTTONS) || (gPlayer2Controller->rawStickY < -40)) { - if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { - gCameraMovementFlags |= CAM_MOVE_ALREADY_ZOOMED_OUT; - #ifndef VERSION_JP -@@ -4946,7 +4975,11 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { - play_sound_cbutton_down(); - } - } -- -+ if ((gPlayer2Controller->rawStickY > 40) || (gPlayer2Controller->rawStickY < -40)) { -+ stickReset = 0; -+ } else { -+ stickReset = 1; -+ } - //! returning uninitialized variable - return dummy; - } -diff --git a/src/game/hud.c b/src/game/hud.c -index f11b626..003a634 100644 ---- a/src/game/hud.c -+++ b/src/game/hud.c -@@ -506,7 +506,7 @@ void render_hud(void) { - - if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) { - render_hud_power_meter(); -- render_hud_camera_status(); -+ //render_hud_camera_status(); - } - - if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER) { diff --git a/enhancements/reonucam3.patch b/enhancements/reonucam3.patch new file mode 100644 index 00000000..169eab26 --- /dev/null +++ b/enhancements/reonucam3.patch @@ -0,0 +1,585 @@ +diff --git a/include/text_strings.h.in b/include/text_strings.h.in +index 711d4562..f1c83171 100644 +--- a/include/text_strings.h.in ++++ b/include/text_strings.h.in +@@ -93,6 +93,12 @@ + #define TEXT_HUD_WIDE_INFO _("PLEASE CONFIGURE YOUR DISPLAY OR YOUR EMULATOR TO\nSTRETCH THE IMAGE TO 16:9") + #endif + ++#define TEXT_CAM_INFO_SLOWEST _("CAM SPEED: SLOWEST") ++#define TEXT_CAM_INFO_SLOW _("CAM SPEED: SLOW") ++#define TEXT_CAM_INFO_MEDIUM _("CAM SPEED: MEDIUM") ++#define TEXT_CAM_INFO_FAST _("CAM SPEED: FAST") ++#define TEXT_CAM_INFO_FASTEST _("CAM SPEED: FASTEST") ++ + #if defined(VERSION_JP) || defined(VERSION_SH) + + /** +diff --git a/src/game/camera.c b/src/game/camera.c +index 25b27983..2ff11930 100644 +--- a/src/game/camera.c ++++ b/src/game/camera.c +@@ -98,6 +98,7 @@ Vec3f sPlayer2FocusOffset; + * The pitch used for the credits easter egg. + */ + s16 sCreditsPlayer2Pitch; ++s16 rButtonCounter2; + /** + * The yaw used for the credits easter egg. + */ +@@ -107,6 +108,7 @@ s16 sCreditsPlayer2Yaw; + */ + u8 sFramesPaused; + ++ + extern struct CameraFOVStatus sFOVState; + extern struct TransitionInfo sModeTransition; + extern struct PlayerGeometry sMarioGeometry; +@@ -259,6 +261,7 @@ s16 sCameraSoundFlags; + * Stores what C-Buttons are pressed this frame. + */ + u16 sCButtonsPressed; ++u16 rButtonCounter; + /** + * A copy of gDialogID, the dialog displayed during the cutscene. + */ +@@ -437,6 +440,7 @@ u8 sFramesSinceCutsceneEnded = 0; + * 3 = Dialog doesn't have a response + */ + u8 sCutsceneDialogResponse = DIALOG_RESPONSE_NONE; ++u8 stickReset = 1; + struct PlayerCameraState *sMarioCamState = &gPlayerCameraState[0]; + struct PlayerCameraState *sLuigiCamState = &gPlayerCameraState[1]; + u32 unused8032D008 = 0; +@@ -755,6 +759,7 @@ void set_camera_height(struct Camera *c, f32 goalHeight) { + UNUSED s16 action = sMarioCamState->action; + f32 baseOff = 125.f; + f32 camCeilHeight = find_ceil(c->pos[0], gLakituState.goalPos[1] - 50.f, c->pos[2], &surface); ++ f32 approachRate = 20.0f; + + if (sMarioCamState->action & ACT_FLAG_HANGING) { + marioCeilHeight = sMarioGeometry.currCeilHeight; +@@ -790,7 +795,8 @@ void set_camera_height(struct Camera *c, f32 goalHeight) { + c->pos[1] = goalHeight; + } + } +- approach_camera_height(c, goalHeight, 20.f); ++ approachRate += ABS(c->pos[1] - goalHeight) / 20; ++ approach_camera_height(c, goalHeight, approachRate); + if (camCeilHeight != CELL_HEIGHT_LIMIT) { + camCeilHeight -= baseOff; + if ((c->pos[1] > camCeilHeight && sMarioGeometry.currFloorHeight + baseOff < camCeilHeight) +@@ -934,9 +940,25 @@ s32 update_8_directions_camera(struct Camera *c, Vec3f focus, Vec3f pos) { + UNUSED f32 unused1; + UNUSED f32 unused2; + UNUSED f32 unused3; +- f32 yOff = 125.f; ++ f32 yOff; + f32 baseDist = 1000.f; + ++ if (gMarioState->action & ACT_FLAG_SWIMMING) { ++ yOff = -125.f; ++ } else { ++ yOff = 125.f; ++ } ++ ++ if ((gPlayer1Controller->buttonDown & R_TRIG) && (gPlayer1Controller->buttonDown & U_CBUTTONS)) { ++ gKeepCliffCam = 1; ++ pitch = DEGREES(60); ++ } else if (((gPlayer1Controller->buttonDown & U_CBUTTONS) || (gPlayer1Controller->buttonDown & R_TRIG)) && gKeepCliffCam) { ++ pitch = DEGREES(60); ++ } else { ++ gKeepCliffCam = 0; ++ } ++ ++ + sAreaYaw = camYaw; + calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f); + focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw); +@@ -1170,6 +1192,28 @@ void mode_radial_camera(struct Camera *c) { + pan_ahead_of_player(c); + } + ++// Returns the camera speed based on the user's camera speed setting ++f32 set_camera_speed(void) { ++ switch(gCameraSpeed) { ++ case 0: ++ return 0.5f; ++ break; ++ case 1: ++ return 1; ++ break; ++ case 2: ++ return 1.5; ++ break; ++ case 3: ++ return 2; ++ break; ++ case 4: ++ return 3.5; ++ break; ++ } ++ return 0; ++} ++ + /** + * A mode that only has 8 camera angles, 45 degrees apart + */ +@@ -1177,42 +1221,59 @@ void mode_8_directions_camera(struct Camera *c) { + Vec3f pos; + UNUSED u8 unused[8]; + s16 oldAreaYaw = sAreaYaw; ++ // Get the camera speed based on the user's setting ++ f32 cameraSpeed = set_camera_speed(); + + radial_camera_input(c, 0.f); + +- if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { +- s8DirModeYawOffset += DEGREES(45); +- play_sound_cbutton_side(); +- } +- if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { +- s8DirModeYawOffset -= DEGREES(45); +- play_sound_cbutton_side(); ++ if ((gPlayer1Controller->buttonPressed & L_CBUTTONS) && !(gPlayer1Controller->buttonDown & R_TRIG)) { ++ s8DirModeBaseYaw -= DEGREES(45); ++ } else if ((gPlayer1Controller->buttonPressed & R_CBUTTONS) && !(gPlayer1Controller->buttonDown & R_TRIG)) { ++ s8DirModeBaseYaw += DEGREES(45); ++ } else if (gPlayer2Controller->rawStickX) { ++ s8DirModeBaseYaw += DEGREES(gPlayer2Controller->rawStickX * 4 / 64); // Analog camera support (Use the "Dual Analog" input mode in Parallel Launcher) + } +-#ifdef PARALLEL_LAKITU_CAM +- // extra functionality +- else if (gPlayer1Controller->buttonPressed & U_JPAD) { +- s8DirModeYawOffset = 0; +- s8DirModeYawOffset = gMarioState->faceAngle[1]-0x8000; +- } +- else if (gPlayer1Controller->buttonDown & L_JPAD) { +- s8DirModeYawOffset -= DEGREES(2); +- } +- else if (gPlayer1Controller->buttonDown & R_JPAD) { +- s8DirModeYawOffset += DEGREES(2); ++ ++ if (gPlayer1Controller->buttonDown & R_TRIG) { ++ if (gPlayer1Controller->buttonDown & L_CBUTTONS) { ++ s8DirModeBaseYaw -= DEGREES(cameraSpeed); ++ } else if (gPlayer1Controller->buttonDown & R_CBUTTONS) { ++ s8DirModeBaseYaw += DEGREES(cameraSpeed); ++ } ++ rButtonCounter++; // This increses whenever R is held. ++ } else { ++ if (rButtonCounter > 0 && rButtonCounter <= 5 && !((gPlayer1Controller->buttonDown & L_CBUTTONS) || (gPlayer1Controller->buttonDown & R_CBUTTONS) || (gMarioState->action & ACT_FLAG_SWIMMING_OR_FLYING))) { ++ // This centers the camera behind mario. It triggers when you let go of R in less than 5 frames. ++ s8DirModeYawOffset = 0; ++ s8DirModeBaseYaw = gMarioState->faceAngle[1]-0x8000; ++ gMarioState->area->camera->yaw = s8DirModeBaseYaw; ++ play_sound_rbutton_changed(); ++ } ++ rButtonCounter = 0; ++ } ++ if (gPlayer1Controller->buttonPressed & R_TRIG) { ++ if (rButtonCounter2 <= 5) { ++ set_cam_angle(CAM_ANGLE_MARIO); // Enter mario cam if R is pressed 2 times in less than 5 frames ++ rButtonCounter2 = 6; ++ } else { ++ rButtonCounter2 = 0; ++ } ++ } else { ++ rButtonCounter2++; + } +- else if (gPlayer1Controller->buttonPressed & D_JPAD) { +- s8DirModeYawOffset = s8DirModeYawOffset&0xE000; ++ if (gPlayer1Controller->buttonPressed & D_JPAD) { ++ s8DirModeBaseYaw = (s8DirModeBaseYaw + 0x1000) & 0xE000; // Lock the camera to the nearest 45deg axis + } +-#endif + + lakitu_zoom(400.f, 0x900); + c->nextYaw = update_8_directions_camera(c, c->focus, pos); ++ set_camera_height(c, pos[1]); + c->pos[0] = pos[0]; + c->pos[2] = pos[2]; + sAreaYawChange = sAreaYaw - oldAreaYaw; +- set_camera_height(c, pos[1]); + } + ++ + /** + * Updates the camera in outward radial mode. + * sModeOffsetYaw is calculated in radial_camera_move, which calls offset_yaw_outward_radial +@@ -2116,7 +2177,7 @@ s16 update_default_camera(struct Camera *c) { + gLakituState.goalPos[1], + gLakituState.goalPos[2], &ceil); + s16 yawDir; +- ++ + handle_c_button_movement(c); + vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); + +@@ -3036,6 +3097,8 @@ void update_lakitu(struct Camera *c) { + void update_camera(struct Camera *c) { + UNUSED u8 unused[24]; + ++ extern s16 s8DirModeBaseYaw; ++ + gCamera = c; + update_camera_hud_status(c); + if (c->cutscene == 0 && +@@ -3046,14 +3109,13 @@ void update_camera(struct Camera *c) { + // Only process R_TRIG if 'fixed' is not selected in the menu + if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { + if (gPlayer1Controller->buttonPressed & R_TRIG) { +- if (set_cam_angle(0) == CAM_ANGLE_LAKITU) { +- set_cam_angle(CAM_ANGLE_MARIO); +- } else { ++ if (set_cam_angle(0) == CAM_ANGLE_MARIO) { ++ s8DirModeBaseYaw = ((gMarioState->faceAngle[1]-0x8000) + 0x1000) & 0xE000; + set_cam_angle(CAM_ANGLE_LAKITU); + } + } + } +- play_sound_if_cam_switched_to_lakitu_or_mario(); ++ //play_sound_if_cam_switched_to_lakitu_or_mario(); + } + + // Initialize the camera +@@ -3356,7 +3418,6 @@ void init_camera(struct Camera *c) { + struct Surface *floor = 0; + Vec3f marioOffset; + s32 i; +- + sCreditsPlayer2Pitch = 0; + sCreditsPlayer2Yaw = 0; + gPrevLevel = gCurrLevelArea / 16; +@@ -4901,15 +4962,15 @@ void play_camera_buzz_if_c_sideways(void) { + } + + void play_sound_cbutton_up(void) { +- play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); ++ //play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + + void play_sound_cbutton_down(void) { +- play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); ++ //play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + + void play_sound_cbutton_side(void) { +- play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource); ++ //play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource); + } + + void play_sound_button_change_blocked(void) { +@@ -5013,7 +5074,7 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { + } + + // Zoom in / enter C-Up +- if (gPlayer1Controller->buttonPressed & U_CBUTTONS) { ++ if (((gPlayer1Controller->buttonPressed & U_CBUTTONS) || (gPlayer2Controller->rawStickY > 40)) && (stickReset) && !(gPlayer1Controller->buttonDown & R_TRIG)) { + if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { + gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; + play_sound_cbutton_up(); +@@ -5023,7 +5084,7 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { + } + + // Zoom out +- if (gPlayer1Controller->buttonPressed & D_CBUTTONS) { ++ if ((gPlayer1Controller->buttonPressed & D_CBUTTONS) || (gPlayer2Controller->rawStickY < -40)) { + if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { + gCameraMovementFlags |= CAM_MOVE_ALREADY_ZOOMED_OUT; + #ifndef VERSION_JP +@@ -5035,6 +5096,12 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { + } + } + ++ if ((gPlayer2Controller->rawStickY > 40) || (gPlayer2Controller->rawStickY < -40)) { ++ stickReset = 0; ++ } else { ++ stickReset = 1; ++ } ++ + //! returning uninitialized variable + return dummy; + } +@@ -5600,7 +5667,7 @@ void set_camera_mode_8_directions(struct Camera *c) { + if (c->mode != CAMERA_MODE_8_DIRECTIONS) { + c->mode = CAMERA_MODE_8_DIRECTIONS; + sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; +- s8DirModeBaseYaw = 0; ++ s8DirModeBaseYaw = ((gMarioState->faceAngle[1]-0x8000) + 0x1000) & 0xE000; + s8DirModeYawOffset = 0; + } + } +diff --git a/src/game/game_init.c b/src/game/game_init.c +index 317e33bf..6687016d 100644 +--- a/src/game/game_init.c ++++ b/src/game/game_init.c +@@ -51,6 +51,11 @@ u8 gBorderHeight; + #ifdef CUSTOM_DEBUG + u8 gCustomDebugMode; + #endif ++u8 gCameraSpeed = 2; ++u8 gWaterCamOverride; ++u8 gFlyingCamOverride; ++u8 gKeepCliffCam; ++s32 gCliffTimer; + #ifdef EEP + s8 gEepromProbe; + #endif +@@ -739,6 +744,7 @@ void thread5_game_loop(UNUSED void *arg) { + + play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0); + set_sound_mode(save_file_get_sound_mode()); ++ gCameraSpeed = (save_file_get_camera_speed()); + #ifdef WIDE + gWidescreen = save_file_get_widescreen_mode(); + #endif +diff --git a/src/game/game_init.h b/src/game/game_init.h +index 84a31755..817c58df 100644 +--- a/src/game/game_init.h ++++ b/src/game/game_init.h +@@ -45,6 +45,10 @@ extern u8 gIsConsole; + #ifdef WIDE + extern s16 gWidescreen; + #endif ++extern u8 gCameraSpeed; ++extern u8 gWaterCamOverride; ++extern u8 gFlyingCamOverride; ++extern u8 gKeepCliffCam; + extern u8 gBorderHeight; + #ifdef CUSTOM_DEBUG + extern u8 gCustomDebugMode; +diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c +index 6cbfd8e1..01dd4de8 100644 +--- a/src/game/ingame_menu.c ++++ b/src/game/ingame_menu.c +@@ -59,6 +59,12 @@ void *languageTable[][3] = + #endif + }; + ++u8 textCamInfoSlowest[] = { TEXT_CAM_INFO_SLOWEST }; ++u8 textCamInfoSlow[] = { TEXT_CAM_INFO_SLOW }; ++u8 textCamInfoMedium[] = { TEXT_CAM_INFO_MEDIUM }; ++u8 textCamInfoFast[] = { TEXT_CAM_INFO_FAST}; ++u8 textCamInfoFastest[] = { TEXT_CAM_INFO_FASTEST }; ++ + extern u8 gLastCompletedCourseNum; + extern u8 gLastCompletedStarNum; + +@@ -1504,6 +1510,45 @@ void reset_red_coins_collected(void) { + gRedCoinsCollected = 0; + } + ++void render_camera_speed_setting(void) { ++ gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); ++ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); ++ switch (gCameraSpeed) { ++ case 0: ++ print_generic_string(190, 20, textCamInfoSlowest); ++ break; ++ case 1: ++ print_generic_string(190, 20, textCamInfoSlow); ++ break; ++ case 2: ++ print_generic_string(190, 20, textCamInfoMedium); ++ break; ++ case 3: ++ print_generic_string(190, 20, textCamInfoFast); ++ break; ++ case 4: ++ print_generic_string(190, 20, textCamInfoFastest); ++ break; ++ } ++ gSPDisplayList(gDisplayListHead++, dl_ia_text_end); ++ ++ if (gPlayer1Controller->buttonPressed & R_JPAD) { ++ if (gCameraSpeed < 4) { ++ gCameraSpeed += 1; ++ } else { ++ gCameraSpeed = 0; ++ } ++ save_file_set_camera_speed(gCameraSpeed); ++ } else if (gPlayer1Controller->buttonPressed & L_JPAD) { ++ if (gCameraSpeed > 0) { ++ gCameraSpeed -= 1; ++ } else { ++ gCameraSpeed = 4; ++ } ++ save_file_set_camera_speed(gCameraSpeed); ++ } ++} ++ + void change_dialog_camera_angle(void) { + if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { + gDialogCameraAngleIndex = CAM_SELECTION_MARIO; +@@ -1942,6 +1987,11 @@ s16 render_pause_courses_and_castle(void) { + } + #if defined(WIDE) && !defined(PUPPYCAM) + render_widescreen_setting(); ++ render_camera_speed_setting(); ++ if (gPlayer1Controller->buttonPressed & L_TRIG){ ++ gWidescreen ^= 1; ++ save_file_set_widescreen_mode(gWidescreen); ++ } + #endif + if (gDialogTextAlpha < 250) { + gDialogTextAlpha += 25; +diff --git a/src/game/mario.c b/src/game/mario.c +index 31e97bce..29b5e9c4 100644 +--- a/src/game/mario.c ++++ b/src/game/mario.c +@@ -1468,32 +1468,39 @@ void update_mario_inputs(struct MarioState *m) { + void set_submerged_cam_preset_and_spawn_bubbles(struct MarioState *m) { + f32 heightBelowWater; + s16 camPreset; ++ extern s16 s8DirModeBaseYaw; ++ if (!gWaterCamOverride) { ++ if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) { ++ heightBelowWater = (f32)(m->waterLevel - 80) - m->pos[1]; ++ camPreset = m->area->camera->mode; ++ if (m->action & ACT_FLAG_METAL_WATER) { ++ if (camPreset != CAMERA_MODE_CLOSE) { ++ set_camera_mode(m->area->camera, CAMERA_MODE_CLOSE, 1); ++ } ++ } else { ++ if ((heightBelowWater > 800.0f) && (camPreset != CAMERA_MODE_BEHIND_MARIO)) { ++ set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); ++ } + +- if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) { +- heightBelowWater = (f32)(m->waterLevel - 80) - m->pos[1]; +- camPreset = m->area->camera->mode; +- +- if (m->action & ACT_FLAG_METAL_WATER) { +- if (camPreset != CAMERA_MODE_CLOSE) { +- set_camera_mode(m->area->camera, CAMERA_MODE_CLOSE, 1); +- } +- } else { +- if ((heightBelowWater > 800.0f) && (camPreset != CAMERA_MODE_BEHIND_MARIO)) { +- set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); +- } +- +- if ((heightBelowWater < 400.0f) && (camPreset != CAMERA_MODE_WATER_SURFACE)) { +- set_camera_mode(m->area->camera, CAMERA_MODE_WATER_SURFACE, 1); +- } ++ if ((heightBelowWater < 400.0f) && (camPreset != CAMERA_MODE_WATER_SURFACE)) { ++ set_camera_mode(m->area->camera, CAMERA_MODE_WATER_SURFACE, 1); ++ } + +- // As long as Mario isn't drowning or at the top +- // of the water with his head out, spawn bubbles. +- if (!(m->action & ACT_FLAG_INTANGIBLE)) { +- if ((m->pos[1] < (f32)(m->waterLevel - 160)) || (m->faceAngle[0] < -0x800)) { +- m->particleFlags |= PARTICLE_BUBBLE; ++ // As long as Mario isn't drowning or at the top ++ // of the water with his head out, spawn bubbles. ++ if (!(m->action & ACT_FLAG_INTANGIBLE)) { ++ if ((m->pos[1] < (f32)(m->waterLevel - 160)) || (m->faceAngle[0] < -0x800)) { ++ m->particleFlags |= PARTICLE_BUBBLE; ++ } + } + } + } ++ } else { ++ set_camera_mode(m->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); ++ } ++ if ((gPlayer1Controller->buttonPressed & R_TRIG) && (m->action & ACT_FLAG_SWIMMING)) { ++ s8DirModeBaseYaw = ((gMarioState->faceAngle[1]-0x8000) + 0x1000) & 0xE000; ++ gWaterCamOverride ^= 1; + } + } + +diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c +index ce6467ef..c7e998c1 100644 +--- a/src/game/mario_actions_airborne.c ++++ b/src/game/mario_actions_airborne.c +@@ -1736,6 +1736,10 @@ s32 act_shot_from_cannon(struct MarioState *m) { + s32 act_flying(struct MarioState *m) { + s16 startPitch = m->faceAngle[0]; + ++ if (gPlayer1Controller->buttonPressed & R_TRIG) { ++ gFlyingCamOverride ^= 1; ++ } ++ + if (m->input & INPUT_Z_PRESSED) { + if (m->area->camera->mode == CAMERA_MODE_BEHIND_MARIO) { + set_camera_mode(m->area->camera, m->area->camera->defMode, 1); +@@ -1750,8 +1754,10 @@ s32 act_flying(struct MarioState *m) { + return set_mario_action(m, ACT_FREEFALL, 0); + } + +- if (m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) { ++ if (!gFlyingCamOverride) { + set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); ++ } else { ++ set_camera_mode(m->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); + } + + if (m->actionState == 0) { +@@ -1933,7 +1939,7 @@ s32 act_flying_triple_jump(struct MarioState *m) { + } + + if (m->vel[1] < 4.0f) { +- if (m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) { ++ if ((m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) && (!gFlyingCamOverride)) { + set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); + } + +@@ -1944,7 +1950,7 @@ s32 act_flying_triple_jump(struct MarioState *m) { + set_mario_action(m, ACT_FLYING, 1); + } + +- if (m->actionTimer++ == 10 && m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) { ++ if (m->actionTimer++ == 10 && m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO && (!gFlyingCamOverride)) { + set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); + } + +diff --git a/src/game/save_file.c b/src/game/save_file.c +index bcdcdbaf..3f0b8ca1 100644 +--- a/src/game/save_file.c ++++ b/src/game/save_file.c +@@ -673,6 +673,12 @@ u8 save_file_get_widescreen_mode(void) { + return gSaveBuffer.menuData[0].wideMode; + } + ++void save_file_set_camera_speed(u8 speed) { ++ gSaveBuffer.menuData[0].cameraSpeedSetting = speed; ++ gMainMenuDataModified = TRUE; ++ save_main_menu_data(); ++} ++ + void save_file_set_widescreen_mode(u8 mode) { + gSaveBuffer.menuData[0].wideMode = mode; + +@@ -685,6 +691,10 @@ u16 save_file_get_sound_mode(void) { + return gSaveBuffer.menuData[0].soundMode; + } + ++u8 save_file_get_camera_speed(void) { ++ return gSaveBuffer.menuData[0].cameraSpeedSetting; ++} ++ + void save_file_move_cap_to_default_location(void) { + if (save_file_get_flags() & SAVE_FLAG_CAP_ON_GROUND) { + switch (gSaveBuffer.files[gCurrSaveFileNum - 1][0].capLevel) { +diff --git a/src/game/save_file.h b/src/game/save_file.h +index 64cf0c63..085ec1d9 100644 +--- a/src/game/save_file.h ++++ b/src/game/save_file.h +@@ -63,6 +63,7 @@ struct MainMenuSaveData + #ifdef WIDE + u8 wideMode: 1; + #endif ++ u8 cameraSpeedSetting: 3; + + #ifdef VERSION_EU + u8 language: 2; +@@ -178,6 +179,8 @@ u16 save_file_get_sound_mode(void); + u8 save_file_get_widescreen_mode(void); + void save_file_set_widescreen_mode(u8 mode); + #endif ++u8 save_file_get_camera_speed(void); ++void save_file_set_camera_speed(u8 speed); + void save_file_move_cap_to_default_location(void); + + void disable_warp_checkpoint(void); diff --git a/extract_assets.py b/extract_assets.py index 3b6427e3..bde5ef21 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -20,6 +20,8 @@ def read_local_asset_list(f): def asset_needs_update(asset, version): + if version <= 6 and asset in ["actors/king_bobomb/king_bob-omb_eyes.rgba16.png", "actors/king_bobomb/king_bob-omb_hand.rgba16.png"]: + return True if version <= 5 and asset == "textures/spooky/bbh_textures.00800.rgba16.png": return True if version <= 4 and asset in ["textures/mountain/ttm_textures.01800.rgba16.png", "textures/mountain/ttm_textures.05800.rgba16.png"]: @@ -59,7 +61,7 @@ def clean_assets(local_asset_file): def main(): # In case we ever need to change formats of generated files, we keep a # revision ID in the local asset file. - new_version = 6 + new_version = 7 try: local_asset_file = open(".assets-local.txt") diff --git a/gziprules.mk b/gziprules.mk index 5dfb9cfd..8f0be75c 100644 --- a/gziprules.mk +++ b/gziprules.mk @@ -10,10 +10,10 @@ endif # Strip gzip header $(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.gz $(call print,Converting:,$<,$@) - $(V)dd bs=10 skip=1 if=$< of=$(<:.gz=.gz.strip) + $(V)dd bs=10 skip=1 if=$< of=$(<:.gz=.gz.strip) status=none $(V)$(FILESIZER) $(<:.gz=.gz.strip) $@ `stat --format="%s" $(<:.gz=.bin)` # convert binary szp to object file $(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp $(call print,Converting GZIP to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ + $(V)$(LD) -r -b binary $< -o $@ diff --git a/include/behavior_data.h b/include/behavior_data.h index 7acb3309..66c410b7 100644 --- a/include/behavior_data.h +++ b/include/behavior_data.h @@ -261,7 +261,7 @@ extern const BehaviorScript bhvBoo[]; extern const BehaviorScript bhvMerryGoRoundBoo[]; extern const BehaviorScript bhvGhostHuntBoo[]; extern const BehaviorScript bhvHiddenStaircaseStep[]; -extern const BehaviorScript bhvBooBossSpawnedBridge[]; +extern const BehaviorScript bhvBooStaircase[]; extern const BehaviorScript bhvBbhTiltingTrapPlatform[]; extern const BehaviorScript bhvHauntedBookshelf[]; extern const BehaviorScript bhvMeshElevator[]; diff --git a/include/config.h b/include/config.h index 508d769e..4790cfa1 100644 --- a/include/config.h +++ b/include/config.h @@ -1,13 +1,13 @@ #ifndef CONFIG_H #define CONFIG_H -// ULTRASM64-EXTBOUNDS CONFIG FLAGS NEAR BOTTOM +// HACKERSM64 CONFIG DEFINES NEAR BOTTOM /** * @file config.h * A catch-all file for configuring various bugfixes and other settings (maybe eventually) in SM64 */ // Bug Fixes -// --| US Version Nintendo Bug Fixes +// --| Post-JP Version Nintendo Bug Fixes /// Fixes bug where obtaining over 999 coins sets the number of lives to 999 (or -25) #define BUGFIX_MAX_LIVES (0 || VERSION_US || VERSION_EU || VERSION_SH) /// Fixes bug where the Boss music won't fade out after defeating King Bob-omb @@ -21,6 +21,16 @@ #define BUGFIX_PIRANHA_PLANT_SLEEP_DAMAGE (0 || VERSION_US || VERSION_SH) /// Fixes bug where it shows a star when you grab a key in bowser battle stages #define BUGFIX_STAR_BOWSER_KEY (0 || VERSION_US || VERSION_EU || VERSION_SH) +/// Fixes bug that enables Mario in time stop even if is not ready to speak +#define BUGFIX_DIALOG_TIME_STOP (0 || VERSION_US || VERSION_EU || VERSION_SH) +/// Fixes bug that causes Mario to still collide with Bowser in BITS after his defeat +#define BUGFIX_BOWSER_COLLIDE_BITS_DEAD (0 || VERSION_US || VERSION_EU || VERSION_SH) +/// Fixes bug where Bowser wouldn't reset his speed when fallen off (and adds missing checks) +#define BUGFIX_BOWSER_FALLEN_OFF_STAGE (0 || VERSION_US || VERSION_EU || VERSION_SH) +/// Fixes bug where Bowser would look weird while fading out +#define BUGFIX_BOWSER_FADING_OUT (0 || VERSION_US || VERSION_EU || VERSION_SH) +/// Removes multi-language cake screen +#define EU_CUSTOM_CAKE_FIX 1 // Support Rumble Pak // Currently not recommended, as it may cause random crashes. @@ -35,20 +45,25 @@ // Border Height Define for NTSC Versions #ifdef TARGET_N64 -#ifndef VERSION_EU -#define BORDER_HEIGHT 0 -#else -#define BORDER_HEIGHT 0 -#endif -#else -// What's the point of having a border? -#define BORDER_HEIGHT 0 +// Size of the black border at the top and bottom of the screen. You can set it to different values for console and emulator. +// There is generally no reason to have a value other than 0 for emulator. As for console, it provides a (small) performance boost. +#define BORDER_HEIGHT_CONSOLE 0 +#define BORDER_HEIGHT_EMULATOR 0 #endif -// -- ultrasm64-extbounds specific settings -- +// -- HackerSM64 specific settings -- + +// TEST LEVEL +// Uncomment this define and set a test level in order to boot straight into said level. +// This allows you to quickly test the level you're working on. +// If you want the game to boot normally, just comment out the define again. +//#define TEST_LEVEL LEVEL_BOB // COMMON HACK CHANGES +// Internal ROM name. NEEDS TO BE **EXACTLY** 20 CHARACTERS. Can't be 19 characters, can't be 21 characters. You can fill it with spaces. +// The end quote should be here: " +#define INTERNAL_ROM_NAME "SUPERMARIO64 " // Disable lives and hide the lives counter #define DISABLE_LIVES // Skip peach letter cutscene @@ -57,41 +72,57 @@ #define CASTLE_MUSIC_FIX // Remove course specific camera processing #define CAMERA_FIX +// Change the movement speed when hanging from a ceiling (the vanilla value is 4.f) +#define HANGING_SPEED 12.f +// Makes Mario face the direction of the analog stick directly while hanging from a ceiling, without doing "semicircles" +#define TIGHTER_HANGING_CONTROLS +// Makes Mario turn around instantly when moving on the ground +//#define SUPER_RESPONSIVE_CONTROLS // Disables fall damage #define NO_FALL_DAMAGE // Disables the scream that mario makes when falling off a great height (this is separate from actual fall damage) //#define NO_FALL_DAMAGE_SOUND // Number of coins to spawn the "100 coin" star. If you remove the define altogether, then there won't be a 100 coin star at all. #define X_COIN_STAR 100 -// Platform displacement 2 also known as momentum patch. Makes Mario keep the momemtum from moving platforms. Breaks treadmills. +// Platform displacement 2 also known as momentum patch. Makes Mario keep the momemtum from moving platforms. Doesn't break treadmills anymore! #define PLATFORM_DISPLACEMENT_2 // Stars don't kick you out of the level -// #define NON_STOP_STARS +//#define NON_STOP_STARS // Uncomment this if you want global star IDs (useful for creating an open world hack ala MVC) //#define GLOBAL_STAR_IDS // Uncomment this if you want to skip the title screen (Super Mario 64 logo) //#define SKIP_TITLE_SCREEN // Uncomment this if you want to keep the mario head and not skip it //#define KEEP_MARIO_HEAD -// Makes the coins ia8 64x64 instead of ia16 32x32. Uses new i8 textures so that vanilla coins look better. -#define IA8_COINS - - -// HACKER QOL -// Enable widescreen (16:9) support -#define WIDE -// When this option is enabled, LODs will ONLY work on console. -// When this option is disabled, LODs will work regardless of whether console or emulator is used. -// Regardless of whether this setting is enabled or not, you can use gIsConsole to wrap your own code in a console check. -#define AUTO_LOD -// Increase the maximum pole length (it will treat bparam1 and bparam2 as a single value) -#define LONGER_POLES -// Disable AA (Recommended: it changes nothing on emulator, and it makes console run better) -#define DISABLE_AA +// Enables "parallel lakitu camera" or "aglab cam" which lets you move the camera smoothly with the dpad +#define PARALLEL_LAKITU_CAM // Allows Mario to ledgegrab sloped floors #define NO_FALSE_LEDGEGRABS +// Adds multiple languages to the game. Just a placeholder for the most part, because it only works with EU, and must be enabled with EU. +#define MULTILANG (0 || VERSION_EU) +// Enables Puppy Camera 2, a rewritten camera that can be freely configured and modified. +//#define PUPPYCAM +// Automatically calculate the optimal collision distance for an object based on its vertices. +#define AUTO_COLLISION_DISTANCE + + +// HACKER QOL +// Increase the maximum pole length (it will treat bparam1 and bparam2 as a single value) +#define LONGER_POLES // Number of possible unique model ID's (keep it higher than 256) #define MODEL_ID_COUNT 256 +// Increase audio heap size to allow for more concurrent notes to be played and for more custom sequences/banks to be imported (does nothing with EU and SH versions) +#define EXPAND_AUDIO_HEAP +// Allow all surfaces types to have force, (doesn't require setting force, just allows it to be optional). +#define ALL_SURFACES_HAVE_FORCE +// Custom debug mode. Press DPAD left to show the debug UI. Press DPAD right to enter the noclip mode. +//#define CUSTOM_DEBUG +// Include Puppyprint, a display library for text and large images. Also includes a custom, enhanced performance profiler. +//#define PUPPYPRINT +#define PUPPYPRINT_DEBUG 0 +// Visual debug enables some collision visuals. Tapping Right on the dpad will cycle between visual hitboxes, visual surfaces, both, and neither. +// If puppyprint is enabled, then this can be cycled only while the screen is active. +//#define VISUAL_DEBUG // BUG/GAME QOL FIXES // Fix instant warp offset not working when warping across different areas @@ -122,9 +153,29 @@ #define EXIT_COURSE_NODE 0x1F // OTHER ENHANCEMENTS -//Skybox size modifier, changing this will add support for larger skybox images. NOTE: Vanilla skyboxes may break if you change this option. Be sure to rescale them accordingly. -//Whenever you change this, make sure to run "make -C tools clean" to rebuild the skybox tool (alternatively go into skyconv.c and change the file in any way (like adding/deleting a space) to specifically rebuild that tool). +// Enable widescreen (16:9) support +#define WIDE +// Skybox size modifier, changing this will add support for larger skybox images. NOTE: Vanilla skyboxes may break if you change this option. Be sure to rescale them accordingly. +// Whenever you change this, make sure to run "make -C tools clean" to rebuild the skybox tool (alternatively go into skyconv.c and change the file in any way (like adding/deleting a space) to specifically rebuild that tool). +// When increasing this, you should probably also increase the GFX pool size. (the GFX_POOL_SIZE define in src/game/game_init.h) #define SKYBOX_SIZE 1 +// When this option is enabled, LODs will ONLY work on console. +// When this option is disabled, LODs will work regardless of whether console or emulator is used. +// Regardless of whether this setting is enabled or not, you can use gIsConsole to wrap your own code in a console check. +#define AUTO_LOD +// Disable AA (Recommended: it changes nothing on emulator, and it makes console run better) +#define DISABLE_AA +// Makes the coins ia8 64x64 instead of ia16 32x32. Uses new ia8 textures so that vanilla coins look better. +#define IA8_COINS +// Use a much better implementation of reverb over vanilla's fake echo reverb. Great for caves or eerie levels, as well as just a better audio experience in general. +// Reverb parameters can be configured in audio/synthesis.c to meet desired aesthetic/performance needs. Currently US/JP only. +//#define BETTER_REVERB +// Collision data is the type that the collision system uses. All data by default is stored as an s16, but you may change it to s32. +// Naturally, that would double the size of all collision data, but would allow you to use 32 bit values instead of 16. +// Rooms are s8 in vanilla, but if you somehow have more than 255 rooms, you may raise this number. +// Currently, they *must* say as s8, because the room tables generated by literally anything are explicitly u8 and don't use a macro, making this currently infeasable. +#define COLLISION_DATA_TYPE s16 +#define ROOM_DATA_TYPE s8 // If you want to change the extended boundaries mode, go to engine/extended_bounds.h and change EXTENDED_BOUNDS_MODE diff --git a/include/dialog_ids.h b/include/dialog_ids.h index 6feadafb..2d9a2410 100644 --- a/include/dialog_ids.h +++ b/include/dialog_ids.h @@ -2,6 +2,7 @@ #define DIALOG_IDS_H enum DialogId { + DIALOG_NONE = -1, DIALOG_000, DIALOG_001, DIALOG_002, diff --git a/include/eu_translation.h b/include/eu_translation.h index 19686825..90f62ff4 100644 --- a/include/eu_translation.h +++ b/include/eu_translation.h @@ -4,7 +4,8 @@ // EU changes most text to arrays for each language. This define allows these // differences to be combined. #ifdef VERSION_EU - #define LANGUAGE_ARRAY(cmd) cmd[LANGUAGE_FUNCTION] + //#define LANGUAGE_ARRAY(cmd) cmd[LANGUAGE_FUNCTION] + #define LANGUAGE_ARRAY(cmd) cmd #else #define LANGUAGE_ARRAY(cmd) cmd #endif diff --git a/include/farcall.h b/include/farcall.h new file mode 100644 index 00000000..e8be2ae8 --- /dev/null +++ b/include/farcall.h @@ -0,0 +1,61 @@ +#ifndef __FARCALL_H__ +#define __FARCALL_H__ + +#ifdef __GNUC__ +#define farcall(x) x +#define far __attribute__(( long_call )) +#pragma GCC diagnostic ignored "-Wattributes" // Workaround for a bug that produces errant warnings in gcc +#define near __attribute(( near )) +#else +#define farcall(x) (*(&(x))) +#define far +#define near +#endif + +#endif + +/* +How to use: + +Simply place any code you want in any groupX_geo.c or any level's script.c (see the first note for a potential gotcha when using code in level script segments). + +To call segment code from normal code or vice versa (or segment code from other segmented code) + - Add `#include "farcall.h"` to the given file + - Declare any functions that are not in that file like so (with far) + `far void print_text(s32, s32, const char*);` + - Call any functions that are not in the file like so: + `farcall(print_text)(10, 10 "test");` + +If you forget any of the above 3 steps, you will get an error during linking your ROM that looks something like: +`script.c:(.text+0x24): relocation truncated to fit: R_MIPS_26 against ...` +So if you see that error, make sure you've followed the above three steps. + +If you're using gcc, you don't need to use farcall to call far functions, as declaring a function as far is enough. + +Additionally if using gcc, you don't need to declare any functions as far in segmented code due to a change in the makefile. + Instead, you can declare local functions as `near` to optimize local calls, but this is not required. + +If you have code in a groupX_geo.c file, you must load it in level scripts by doing LOAD_RAW_WITH_CODE instead of the normal LOAD_RAW. + This has two extra arguments, which should be passed as `_groupX_geoSegmentNoloadStart` and `_groupX_geoSegmentNoloadEnd`. + For example, if you added code to group3's geo segment: + +LOAD_RAW_WITH_CODE(0x0C, _group3_geoSegmentRomStart, _group3_geoSegmentRomEnd, _group3_geoSegmentNoloadStart, _group3_geoSegmentNoloadEnd), + +For convenience, included is a new header: src/game/obj_behaviors_2_nonstatic.h. In addition to effectively removing + the static keyword from object_behaviors_2.c, this header defines prototypes for all functions in that file. This + allows you to reference those functions elsewhere, which is convenient for segmented behavior callbacks. + +Notes: + - As of right now, Fast64 will not retain LOAD_RAW_WITH_CODE commands in the level script. + This means that you will have to readd those on each export, but this may change in a future Fast64 version. + The same is true for any code in the level file, so I suggest making a code.inc.c file in the level's folder + and adding an `#include "levels/x/code.inc.c"` into the level script file. + That include will also be wiped on each export, but is easy enough to add after an export. + - Variables in segments will get reset to their defaults every time a segment is loaded. + Use variables declared in normal code and extern them if this isn't desirable. + - Because of the limited number of TLB entries, at most 256kB of segmented memory can be mapped with this patch. + If you want to be sure that everything is being mapped, use the TLB entries view in PJ64 2.4's debugger. + - TLB mapping requires at least 4kB alignment, so memory allocations for segments with code are automatically padded to meet this alignment. + This means that potentially up to 4kB of RAM can be wasted when a given segment with code is loaded. + This should be far less than the potential savings from using this patch, but is something that should be kept in mind. +*/ diff --git a/include/ique/PR/abi.h b/include/ique/PR/abi.h index 2631214f..b73cb726 100644 --- a/include/ique/PR/abi.h +++ b/include/ique/PR/abi.h @@ -56,13 +56,14 @@ #define A_ADDMIXER 4 #define A_RESAMPLE_ZOH 6 -#define A_INTERL 17 +#define A_DMEMMOVE2 16 +#define A_DOWNSAMPLE_HALF 17 #define A_ENVSETUP1 18 #define A_ENVMIXER 19 #define A_LOADBUFF 20 #define A_SAVEBUFF 21 #define A_ENVSETUP2 22 -#define A_UNK_23 23 +#define A_S8DEC 23 #define A_HILOGAIN 24 #define A_UNK_25 25 #define A_DUPLICATE 26 @@ -306,6 +307,8 @@ typedef short ENVMIX_STATE[40]; * address is later used as parameter, the 8 high bits will be an index * to the segment table and the lower 24 bits are added to the base address * stored in the segment table for this entry. The result is the physical address. + * With the newer rsp audio code, this segment table is not used. The address is + * used directly instead. * * Transfers to/from DRAM are executed using DMA and hence follow these restrictions: * All DRAM addresses should be aligned by 8 bytes, or they will be @@ -349,14 +352,6 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (uintptr_t)(s); \ } -#define aADPCM_23(pkt, f, s) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = _SHIFTL(A_UNK_23, 24, 8) | _SHIFTL(f, 16, 8); \ - _a->words.w1 = (uintptr_t)(s); \ -} - /* * Not used in SM64. */ @@ -570,15 +565,6 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ } -#define aInterl(pkt, f, i, o, c) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = (_SHIFTL(A_INTERL, 24, 8) | _SHIFTL(f, 16, 8) | \ - _SHIFTL(i, 0, 16)); \ - _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ -} - /* * Sets internal volume parameters. * See aEnvMixer for more info. @@ -663,12 +649,50 @@ typedef short ENVMIX_STATE[40]; #undef aEnvMixer #undef aInterleave +// New or modified operations in the new audio microcode below + +/** + * Decompresses S8 data. + * Possible flags: A_INIT and A_LOOP. + * + * First set up internal data in DMEM: + * aSetLoop(cmd++, physicalAddressOfLoopState) (if A_LOOP is set) + * + * Then before this command, call: + * aSetBuffer(cmd++, 0, in, out, count) + * + * Note: count will be rounded up to the nearest multiple of 32 bytes. + * + * S8 decompression works by expanding s8 bytes into s16 numbers, + * by performing a left shift of 8 steps. + * + * Before the algorithm starts, the previous 16 samples are loaded according to flag: + * A_INIT: all zeros + * A_LOOP: the address set by aSetLoop + * no flags: the DRAM address in the s parameter + * These 16 samples are immediately copied to the destination address. + * + * The result of "count" bytes will be written after these 16 initial samples. + * The last 16 samples written to the destination will also be written to + * the state address in DRAM. + */ +#define aS8Dec(pkt, f, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_S8DEC, 24, 8) | _SHIFTL(f, 16, 8); \ + _a->words.w1 = (uintptr_t)(s); \ +} + /* * Mix two tracks by simple clamped addition. * * s: DMEM source track 1 * d: DMEM source track 2 and destination - * c: number of bytes to write (rounded down to 16 byte alignment) + * c: number of bytes to write + * + * Note: count is first rounded down to the nearest multiple of 16 bytes + * and then rounded up to the nearest multiple of 64 bytes. */ #define aAddMixer(pkt, s, d, c) \ { \ @@ -726,6 +750,28 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (_SHIFTL(d, 16, 16) | _SHIFTL(0x80, 0, 16)); \ } +/* + * Copies memory in DMEM, second version. + * + * Copies t * c bytes from address i to address o. + * + * Note: count is first rounded up to the nearest multiple of 32 bytes, + * before the multiplication by t. + * + * Note: This acts as memcpy where 32 bytes are moved at a time, therefore + * if input and output overlap, output address should be less than input address. + * + * Not used in SM64. + */ +#define aDMEMMove2(pkt, t, i, o, c) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_DMEMMOVE2, 24, 8) | \ + _SHIFTL(t, 16, 8) | _SHIFTL(i, 0, 16); \ + _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ +} + /* * Fast resample. * @@ -734,14 +780,37 @@ typedef short ENVMIX_STATE[40]; * * This works like the other resample command but just takes the "nearest" sample, * instead of a function of the four nearest samples. + * + * Initially the current position is calculated as (in << 16) + startFract. + * For every sample to create, the value is simply taken from the sample + * at address ((position >> 17) << 1). Then the current position is incremented + * by (pitch << 2). + * + * Note: count represents the number of output bytes to create, and is + * rounded up to the nearest multiple of 8 bytes. */ -#define aResampleZoh(pkt, pitch, start_fract) \ +#define aResampleZoh(pkt, pitch, startFract) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_RESAMPLE_ZOH, 24, 8) | \ _SHIFTL(pitch, 0, 16)); \ - _a->words.w1 = _SHIFTL(start_fract, 0, 16); \ + _a->words.w1 = _SHIFTL(startFract, 0, 16); \ +} + +/* + * Fast downsampling by taking every other sample, discarding others. + * + * Note: nSamples refers to the number of output samples to create, and + * is first rounded up to the nearest multiple of 8. + */ +#define aDownsampleHalf(pkt, nSamples, i, o) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_DOWNSAMPLE_HALF, 24, 8) | \ + _SHIFTL(nSamples, 0, 16)); \ + _a->words.w1 = _SHIFTL(i, 16, 16) | _SHIFTL(o, 0, 16); \ } /* @@ -764,39 +833,87 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = _SHIFTL(i, 16, 16) | _SHIFTL(o, 0, 16); \ } -#define aEnvSetup1(pkt, a, b, c, d) \ +/* + * See aEnvMixer for more info. + */ +#define aEnvSetup1(pkt, initialVolReverb, rampReverb, rampLeft, rampRight) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_ENVSETUP1, 24, 8) | \ - _SHIFTL(a, 16, 8) | _SHIFTL(b, 0, 16)); \ - _a->words.w1 = _SHIFTL(c, 16, 16) | _SHIFTL(d, 0, 16); \ + _SHIFTL(initialVolReverb, 16, 8) | \ + _SHIFTL(rampReverb, 0, 16)); \ + _a->words.w1 = _SHIFTL(rampLeft, 16, 16) | \ + _SHIFTL(rampRight, 0, 16); \ } -#define aEnvSetup2(pkt, volLeft, volRight) \ +/* + * See aEnvMixer for more info. + */ +#define aEnvSetup2(pkt, initialVolLeft, initialVolRight) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_ENVSETUP2, 24, 8); \ - _a->words.w1 = _SHIFTL(volLeft, 16, 16) | \ - _SHIFTL(volRight, 0, 16); \ + _a->words.w1 = _SHIFTL(initialVolLeft, 16, 16) | \ + _SHIFTL(initialVolRight, 0, 16); \ } -#define aEnvMixer(pkt, inBuf, nSamples, bit1, bit2, bit3, dryLeft, dryRight, wetLeft, wetRight) \ +/* + * Mixes an envelope with mono sound into 4 channels. + * + * To allow for many parameters, a sequence of aEnvSetup1, aEnvSetup2, + * aEnvMixer shall always be called. + * + * The function works in blocks of 8 samples. + * However, nSamples is rounded up to the nearest multiple of 16 samples. + * + * For each sample in a block: + * 1. sampleLeft = in * volLeft * (negLeft ? -1 : 1) + * 2. sampleRight = in * volRight * (negRight ? -1 : 1) + * 3. dryLeft += sampleLeft + * 4. dryRight += sampleRight + * 5. if swapReverb: swap sampleLeft and sampleRight + * 6. wetLeft += sampleLeft * volReverb + * 7. wetRight += sampleRight * volReverb + * + * After each block, all vol variables are added by their corresponding + * ramp value. + * + * Each volume variable is treated as a UQ0.16 number. Make sure + * the ramp additions don't overflow, or wrapping will occur. + * The initialVolReverb parameter is only 8 bits, but will be left + * shifted 8 bits by the rsp. + */ +#define aEnvMixer(pkt, inBuf, nSamples, swapReverb, negLeft, negRight, \ + dryLeft, dryRight, wetLeft, wetRight) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_ENVMIXER, 24, 8) | \ _SHIFTL((inBuf) >> 4, 16, 8) | \ _SHIFTL(nSamples, 8, 8)) | \ - _SHIFTL(bit1, 2, 1) | _SHIFTL(bit2, 1, 1) | \ - _SHIFTL(bit3, 0, 1); \ + _SHIFTL(swapReverb, 2, 1) | _SHIFTL(negLeft, 1, 1) |\ + _SHIFTL(negRight, 0, 1); \ _a->words.w1 = _SHIFTL((dryLeft) >> 4, 24, 8) | \ _SHIFTL((dryRight) >> 4, 16, 8) | \ _SHIFTL((wetLeft) >> 4, 8, 8) | \ _SHIFTL((wetRight) >> 4, 0, 8); \ } +/* + * Interleaves two mono channels into stereo. + * + * The count refers to the size of each input. Hence 2 * count bytes + * will be written out. + * + * A left sample will be placed before the right sample. + * All addresses (output, left, right) are DMEM addresses. + * + * Note: count will be rounded up to the nearest multiple of 8 bytes. + * The previous version of this function rounded up to the nearest + * multiple of 16 bytes. + */ #define aInterleave(pkt, o, l, r, c) \ { \ Acmd *_a = (Acmd *)pkt; \ @@ -806,7 +923,26 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = _SHIFTL(l, 16, 16) | _SHIFTL(r, 0, 16); \ } -// countOrBuf meaning depends on flag +/* + * Linear filter function. + * + * Calculates out[i] = sum all elements in the vector in[i..i-7] * filter[0..7], + * where "*" represents dot multiplication. The input/output contains s16 + * samples and filter contains Q1.15 signed fixed point numbers. + * Every result sample is rounded and clamped. + * + * First initiate by calling with the flag f set to 2, countOrBuf contains + * the length in bytes that shall be processed in the next call. The addr + * parameter shall contain the DRAM address to the filter table (16 bytes). + * The count will be rounded up to the nearest multiple of 16 bytes. + * + * The aFilter function shall then be called in direct succession, with flag + * set to either 0 or 1. The countOrBuf parameter shall contain the DMEM + * address for the input/output. The addr parameter shall contain the DRAM + * address for the state, containing the last previous 8 input samples. + * The state is always written to upon exit, but is only read at entry if + * the flag is 0 (otherwise all-zero samples are used instead). + */ #define aFilter(pkt, f, countOrBuf, addr) \ { \ Acmd *_a = (Acmd *)pkt; \ @@ -816,22 +952,41 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (uintptr_t)(addr); \ } -#define aHilogain(pkt, id, buflen, i) \ +/* + * Modifies the volume of samples using a simple UQ4.4 gain multiplier. + * + * Performs the following: + * + * 1. Count c is rounded up to 32 byte alignment + * 2. g is a u8 that contains a UQ4.4 number + * 3. Modify each sample s, so that s = clamp_s16(s * g >> 4) + */ +#define aHiLoGain(pkt, g, buflen, i) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_HILOGAIN, 24, 8) | \ - _SHIFTL((id), 16, 8) | _SHIFTL((buflen), 0, 16); \ + _SHIFTL((g), 16, 8) | _SHIFTL((buflen), 0, 16); \ _a->words.w1 = _SHIFTL((i), 16, 16); \ } -#define aUnknown25(pkt, f, g, i, o) \ +/* + * Performs the following: + * + * 1. Count c is rounded up to 64 byte alignment + * 2. f is added to i + * 3. i and o are from now treated as s16 pointers + * 4. 32 s16 samples are loaded from i to tbl + * 5. for (u32 idx = 0; idx * sizeof(s16) < c; idx++) + * o[idx] = clamp_s16((s32)o[idx] * (s32)tbl[idx % 32]); + */ +#define aUnknown25(pkt, f, c, o, i) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_UNK_25, 24, 8) | \ - _SHIFTL((f), 16, 8) | _SHIFTL((g), 0, 16)); \ - _a->words.w1 = _SHIFTL((i), 16, 16) | _SHIFTL((o), 0, 16); \ + _SHIFTL((f), 16, 8) | _SHIFTL((c), 0, 16)); \ + _a->words.w1 = _SHIFTL((o), 16, 16) | _SHIFTL((i), 0, 16); \ } #endif diff --git a/include/ique/PR/libaudio.h b/include/ique/PR/libaudio.h index 3fffe9c0..cb7a5b19 100644 --- a/include/ique/PR/libaudio.h +++ b/include/ique/PR/libaudio.h @@ -8,7 +8,8 @@ typedef struct u8 *offset; s32 len; #ifdef VERSION_SH - s8 magic[2]; // tbl: 0x0204, otherwise: 0x0203 + s8 medium; + s8 magic; // tbl: 0x04, otherwise: 0x03 // for ctl (else zeros): union { @@ -38,7 +39,9 @@ typedef struct #ifdef VERSION_SH s16 unk2; u8 *data; +#if !IS_64_BIT s32 pad[2]; +#endif #endif ALSeqData seqArray[1]; } ALSeqFile; diff --git a/include/level_commands.h b/include/level_commands.h index 6e2a0602..e5392d27 100644 --- a/include/level_commands.h +++ b/include/level_commands.h @@ -49,16 +49,36 @@ CMD_PTR(entry) #else #define EXECUTE(seg, script, scriptEnd, entry) \ - CMD_BBH(0x00, 0x10, seg), \ + CMD_BBH(0x00, 0x18, seg), \ CMD_PTR(script), \ CMD_PTR(scriptEnd), \ - CMD_PTR(entry) + CMD_PTR(entry), \ + CMD_PTR(NULL), \ + CMD_PTR(NULL) #define EXIT_AND_EXECUTE(seg, script, scriptEnd, entry) \ - CMD_BBH(0x01, 0x10, seg), \ + CMD_BBH(0x01, 0x18, seg), \ CMD_PTR(script), \ CMD_PTR(scriptEnd), \ - CMD_PTR(entry) + CMD_PTR(entry), \ + CMD_PTR(NULL), \ + CMD_PTR(NULL) + +#define EXECUTE_WITH_CODE(seg, script, scriptEnd, entry, bssStart, bssEnd) \ + CMD_BBH(0x00, 0x18, seg), \ + CMD_PTR(script), \ + CMD_PTR(scriptEnd), \ + CMD_PTR(entry), \ + CMD_PTR(bssStart), \ + CMD_PTR(bssEnd) + +#define EXIT_AND_EXECUTE_WITH_CODE(seg, script, scriptEnd, entry, bssStart, bssEnd) \ + CMD_BBH(0x01, 0x18, seg), \ + CMD_PTR(script), \ + CMD_PTR(scriptEnd), \ + CMD_PTR(entry), \ + CMD_PTR(bssStart), \ + CMD_PTR(bssEnd) #endif #define EXIT() \ @@ -160,9 +180,18 @@ CMD_PTR(romEnd) #define LOAD_RAW(seg, romStart, romEnd) \ - CMD_BBH(0x17, 0x0C, seg), \ + CMD_BBH(0x17, 0x14, seg), \ CMD_PTR(romStart), \ - CMD_PTR(romEnd) + CMD_PTR(romEnd), \ + CMD_PTR(0), \ + CMD_PTR(0) + +#define LOAD_RAW_WITH_CODE(seg, romStart, romEnd, bssStart, bssEnd) \ + CMD_BBH(0x17, 0x14, seg), \ + CMD_PTR(romStart), \ + CMD_PTR(romEnd), \ + CMD_PTR(bssStart), \ + CMD_PTR(bssEnd) #define LOAD_YAY0(seg, romStart, romEnd) \ CMD_BBH(0x18, 0x0C, seg), \ diff --git a/include/macros.inc b/include/macros.inc index f642978a..838c32a3 100644 --- a/include/macros.inc +++ b/include/macros.inc @@ -1,4 +1,4 @@ -# Assembly Macros +/* Assembly Macros */ .set K0BASE, 0x80000000 .set K1BASE, 0xA0000000 diff --git a/include/model_ids.h b/include/model_ids.h index 1cd0a253..3e7c8845 100644 --- a/include/model_ids.h +++ b/include/model_ids.h @@ -410,12 +410,12 @@ // second set of actor bins, (0x64-0x73) // group 12 -#define MODEL_BOWSER 0x64 // bowser_geo - 2nd geo loaded is bowser_geo_000424, starts with shadow command +#define MODEL_BOWSER 0x64 // bowser_geo #define MODEL_BOWSER_BOMB_CHILD_OBJ 0x65 // bowser_bomb_geo - Spawns as a chill object in bowser's behavior command, causing an explosion if it touches a bomb #define MODEL_BOWSER_SMOKE 0x66 // bowser_impact_smoke_geo #define MODEL_BOWSER_FLAMES 0x67 // bowser_flames_geo #define MODEL_BOWSER_WAVE 0x68 // invisible_bowser_accessory_geo -#define MODEL_BOWSER2 0x69 // bowser2_geo - 2nd geo loaded is bowser_geo_000770, starts with node command, only difference +#define MODEL_BOWSER_NO_SHADOW 0x69 // bowser_geo_no_shadow // group 13 #define MODEL_BUB 0x64 // cheep_cheep_geo @@ -531,7 +531,7 @@ #define MODEL_KOOPA_WITHOUT_SHELL 0xBF // koopa_without_shell_geo #define MODEL_GOOMBA 0xC0 // goomba_geo #define MODEL_SEAWEED 0xC1 // seaweed_geo -#define MODEL_AMP 0xC2 // amp_geo +#define MODEL_AMP 0xC2 // dAmpGeo #define MODEL_BOBOMB_BUDDY 0xC3 // bobomb_buddy_geo // find me // find me diff --git a/include/n64/PR/abi.h b/include/n64/PR/abi.h index 2631214f..b73cb726 100644 --- a/include/n64/PR/abi.h +++ b/include/n64/PR/abi.h @@ -56,13 +56,14 @@ #define A_ADDMIXER 4 #define A_RESAMPLE_ZOH 6 -#define A_INTERL 17 +#define A_DMEMMOVE2 16 +#define A_DOWNSAMPLE_HALF 17 #define A_ENVSETUP1 18 #define A_ENVMIXER 19 #define A_LOADBUFF 20 #define A_SAVEBUFF 21 #define A_ENVSETUP2 22 -#define A_UNK_23 23 +#define A_S8DEC 23 #define A_HILOGAIN 24 #define A_UNK_25 25 #define A_DUPLICATE 26 @@ -306,6 +307,8 @@ typedef short ENVMIX_STATE[40]; * address is later used as parameter, the 8 high bits will be an index * to the segment table and the lower 24 bits are added to the base address * stored in the segment table for this entry. The result is the physical address. + * With the newer rsp audio code, this segment table is not used. The address is + * used directly instead. * * Transfers to/from DRAM are executed using DMA and hence follow these restrictions: * All DRAM addresses should be aligned by 8 bytes, or they will be @@ -349,14 +352,6 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (uintptr_t)(s); \ } -#define aADPCM_23(pkt, f, s) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = _SHIFTL(A_UNK_23, 24, 8) | _SHIFTL(f, 16, 8); \ - _a->words.w1 = (uintptr_t)(s); \ -} - /* * Not used in SM64. */ @@ -570,15 +565,6 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ } -#define aInterl(pkt, f, i, o, c) \ -{ \ - Acmd *_a = (Acmd *)pkt; \ - \ - _a->words.w0 = (_SHIFTL(A_INTERL, 24, 8) | _SHIFTL(f, 16, 8) | \ - _SHIFTL(i, 0, 16)); \ - _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ -} - /* * Sets internal volume parameters. * See aEnvMixer for more info. @@ -663,12 +649,50 @@ typedef short ENVMIX_STATE[40]; #undef aEnvMixer #undef aInterleave +// New or modified operations in the new audio microcode below + +/** + * Decompresses S8 data. + * Possible flags: A_INIT and A_LOOP. + * + * First set up internal data in DMEM: + * aSetLoop(cmd++, physicalAddressOfLoopState) (if A_LOOP is set) + * + * Then before this command, call: + * aSetBuffer(cmd++, 0, in, out, count) + * + * Note: count will be rounded up to the nearest multiple of 32 bytes. + * + * S8 decompression works by expanding s8 bytes into s16 numbers, + * by performing a left shift of 8 steps. + * + * Before the algorithm starts, the previous 16 samples are loaded according to flag: + * A_INIT: all zeros + * A_LOOP: the address set by aSetLoop + * no flags: the DRAM address in the s parameter + * These 16 samples are immediately copied to the destination address. + * + * The result of "count" bytes will be written after these 16 initial samples. + * The last 16 samples written to the destination will also be written to + * the state address in DRAM. + */ +#define aS8Dec(pkt, f, s) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_S8DEC, 24, 8) | _SHIFTL(f, 16, 8); \ + _a->words.w1 = (uintptr_t)(s); \ +} + /* * Mix two tracks by simple clamped addition. * * s: DMEM source track 1 * d: DMEM source track 2 and destination - * c: number of bytes to write (rounded down to 16 byte alignment) + * c: number of bytes to write + * + * Note: count is first rounded down to the nearest multiple of 16 bytes + * and then rounded up to the nearest multiple of 64 bytes. */ #define aAddMixer(pkt, s, d, c) \ { \ @@ -726,6 +750,28 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (_SHIFTL(d, 16, 16) | _SHIFTL(0x80, 0, 16)); \ } +/* + * Copies memory in DMEM, second version. + * + * Copies t * c bytes from address i to address o. + * + * Note: count is first rounded up to the nearest multiple of 32 bytes, + * before the multiplication by t. + * + * Note: This acts as memcpy where 32 bytes are moved at a time, therefore + * if input and output overlap, output address should be less than input address. + * + * Not used in SM64. + */ +#define aDMEMMove2(pkt, t, i, o, c) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_DMEMMOVE2, 24, 8) | \ + _SHIFTL(t, 16, 8) | _SHIFTL(i, 0, 16); \ + _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ +} + /* * Fast resample. * @@ -734,14 +780,37 @@ typedef short ENVMIX_STATE[40]; * * This works like the other resample command but just takes the "nearest" sample, * instead of a function of the four nearest samples. + * + * Initially the current position is calculated as (in << 16) + startFract. + * For every sample to create, the value is simply taken from the sample + * at address ((position >> 17) << 1). Then the current position is incremented + * by (pitch << 2). + * + * Note: count represents the number of output bytes to create, and is + * rounded up to the nearest multiple of 8 bytes. */ -#define aResampleZoh(pkt, pitch, start_fract) \ +#define aResampleZoh(pkt, pitch, startFract) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_RESAMPLE_ZOH, 24, 8) | \ _SHIFTL(pitch, 0, 16)); \ - _a->words.w1 = _SHIFTL(start_fract, 0, 16); \ + _a->words.w1 = _SHIFTL(startFract, 0, 16); \ +} + +/* + * Fast downsampling by taking every other sample, discarding others. + * + * Note: nSamples refers to the number of output samples to create, and + * is first rounded up to the nearest multiple of 8. + */ +#define aDownsampleHalf(pkt, nSamples, i, o) \ +{ \ + Acmd *_a = (Acmd *)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_DOWNSAMPLE_HALF, 24, 8) | \ + _SHIFTL(nSamples, 0, 16)); \ + _a->words.w1 = _SHIFTL(i, 16, 16) | _SHIFTL(o, 0, 16); \ } /* @@ -764,39 +833,87 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = _SHIFTL(i, 16, 16) | _SHIFTL(o, 0, 16); \ } -#define aEnvSetup1(pkt, a, b, c, d) \ +/* + * See aEnvMixer for more info. + */ +#define aEnvSetup1(pkt, initialVolReverb, rampReverb, rampLeft, rampRight) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_ENVSETUP1, 24, 8) | \ - _SHIFTL(a, 16, 8) | _SHIFTL(b, 0, 16)); \ - _a->words.w1 = _SHIFTL(c, 16, 16) | _SHIFTL(d, 0, 16); \ + _SHIFTL(initialVolReverb, 16, 8) | \ + _SHIFTL(rampReverb, 0, 16)); \ + _a->words.w1 = _SHIFTL(rampLeft, 16, 16) | \ + _SHIFTL(rampRight, 0, 16); \ } -#define aEnvSetup2(pkt, volLeft, volRight) \ +/* + * See aEnvMixer for more info. + */ +#define aEnvSetup2(pkt, initialVolLeft, initialVolRight) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_ENVSETUP2, 24, 8); \ - _a->words.w1 = _SHIFTL(volLeft, 16, 16) | \ - _SHIFTL(volRight, 0, 16); \ + _a->words.w1 = _SHIFTL(initialVolLeft, 16, 16) | \ + _SHIFTL(initialVolRight, 0, 16); \ } -#define aEnvMixer(pkt, inBuf, nSamples, bit1, bit2, bit3, dryLeft, dryRight, wetLeft, wetRight) \ +/* + * Mixes an envelope with mono sound into 4 channels. + * + * To allow for many parameters, a sequence of aEnvSetup1, aEnvSetup2, + * aEnvMixer shall always be called. + * + * The function works in blocks of 8 samples. + * However, nSamples is rounded up to the nearest multiple of 16 samples. + * + * For each sample in a block: + * 1. sampleLeft = in * volLeft * (negLeft ? -1 : 1) + * 2. sampleRight = in * volRight * (negRight ? -1 : 1) + * 3. dryLeft += sampleLeft + * 4. dryRight += sampleRight + * 5. if swapReverb: swap sampleLeft and sampleRight + * 6. wetLeft += sampleLeft * volReverb + * 7. wetRight += sampleRight * volReverb + * + * After each block, all vol variables are added by their corresponding + * ramp value. + * + * Each volume variable is treated as a UQ0.16 number. Make sure + * the ramp additions don't overflow, or wrapping will occur. + * The initialVolReverb parameter is only 8 bits, but will be left + * shifted 8 bits by the rsp. + */ +#define aEnvMixer(pkt, inBuf, nSamples, swapReverb, negLeft, negRight, \ + dryLeft, dryRight, wetLeft, wetRight) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_ENVMIXER, 24, 8) | \ _SHIFTL((inBuf) >> 4, 16, 8) | \ _SHIFTL(nSamples, 8, 8)) | \ - _SHIFTL(bit1, 2, 1) | _SHIFTL(bit2, 1, 1) | \ - _SHIFTL(bit3, 0, 1); \ + _SHIFTL(swapReverb, 2, 1) | _SHIFTL(negLeft, 1, 1) |\ + _SHIFTL(negRight, 0, 1); \ _a->words.w1 = _SHIFTL((dryLeft) >> 4, 24, 8) | \ _SHIFTL((dryRight) >> 4, 16, 8) | \ _SHIFTL((wetLeft) >> 4, 8, 8) | \ _SHIFTL((wetRight) >> 4, 0, 8); \ } +/* + * Interleaves two mono channels into stereo. + * + * The count refers to the size of each input. Hence 2 * count bytes + * will be written out. + * + * A left sample will be placed before the right sample. + * All addresses (output, left, right) are DMEM addresses. + * + * Note: count will be rounded up to the nearest multiple of 8 bytes. + * The previous version of this function rounded up to the nearest + * multiple of 16 bytes. + */ #define aInterleave(pkt, o, l, r, c) \ { \ Acmd *_a = (Acmd *)pkt; \ @@ -806,7 +923,26 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = _SHIFTL(l, 16, 16) | _SHIFTL(r, 0, 16); \ } -// countOrBuf meaning depends on flag +/* + * Linear filter function. + * + * Calculates out[i] = sum all elements in the vector in[i..i-7] * filter[0..7], + * where "*" represents dot multiplication. The input/output contains s16 + * samples and filter contains Q1.15 signed fixed point numbers. + * Every result sample is rounded and clamped. + * + * First initiate by calling with the flag f set to 2, countOrBuf contains + * the length in bytes that shall be processed in the next call. The addr + * parameter shall contain the DRAM address to the filter table (16 bytes). + * The count will be rounded up to the nearest multiple of 16 bytes. + * + * The aFilter function shall then be called in direct succession, with flag + * set to either 0 or 1. The countOrBuf parameter shall contain the DMEM + * address for the input/output. The addr parameter shall contain the DRAM + * address for the state, containing the last previous 8 input samples. + * The state is always written to upon exit, but is only read at entry if + * the flag is 0 (otherwise all-zero samples are used instead). + */ #define aFilter(pkt, f, countOrBuf, addr) \ { \ Acmd *_a = (Acmd *)pkt; \ @@ -816,22 +952,41 @@ typedef short ENVMIX_STATE[40]; _a->words.w1 = (uintptr_t)(addr); \ } -#define aHilogain(pkt, id, buflen, i) \ +/* + * Modifies the volume of samples using a simple UQ4.4 gain multiplier. + * + * Performs the following: + * + * 1. Count c is rounded up to 32 byte alignment + * 2. g is a u8 that contains a UQ4.4 number + * 3. Modify each sample s, so that s = clamp_s16(s * g >> 4) + */ +#define aHiLoGain(pkt, g, buflen, i) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = _SHIFTL(A_HILOGAIN, 24, 8) | \ - _SHIFTL((id), 16, 8) | _SHIFTL((buflen), 0, 16); \ + _SHIFTL((g), 16, 8) | _SHIFTL((buflen), 0, 16); \ _a->words.w1 = _SHIFTL((i), 16, 16); \ } -#define aUnknown25(pkt, f, g, i, o) \ +/* + * Performs the following: + * + * 1. Count c is rounded up to 64 byte alignment + * 2. f is added to i + * 3. i and o are from now treated as s16 pointers + * 4. 32 s16 samples are loaded from i to tbl + * 5. for (u32 idx = 0; idx * sizeof(s16) < c; idx++) + * o[idx] = clamp_s16((s32)o[idx] * (s32)tbl[idx % 32]); + */ +#define aUnknown25(pkt, f, c, o, i) \ { \ Acmd *_a = (Acmd *)pkt; \ \ _a->words.w0 = (_SHIFTL(A_UNK_25, 24, 8) | \ - _SHIFTL((f), 16, 8) | _SHIFTL((g), 0, 16)); \ - _a->words.w1 = _SHIFTL((i), 16, 16) | _SHIFTL((o), 0, 16); \ + _SHIFTL((f), 16, 8) | _SHIFTL((c), 0, 16)); \ + _a->words.w1 = _SHIFTL((o), 16, 16) | _SHIFTL((i), 0, 16); \ } #endif diff --git a/include/n64/PR/gbi.h b/include/n64/PR/gbi.h index 702a9933..16968a8e 100644 --- a/include/n64/PR/gbi.h +++ b/include/n64/PR/gbi.h @@ -76,13 +76,13 @@ * * IMPLEMENTATION NOTE: * There is another group of RDP commands that includes the triangle commands - * generated by the RSP code. These are the raw commands the rasterizer - * hardware chews on, with slope info, etc. They will follow the RDP + * generated by the RSP code. These are the raw commands the rasterizer + * hardware chews on, with slope info, etc. They will follow the RDP * ordering... * * IMPLEMENTATION NOTE: - * The RDP hardware has some of these bit patterns wired up. If the hardware - * changes, we must adjust this table, likewise we can't change/add things + * The RDP hardware has some of these bit patterns wired up. If the hardware + * changes, we must adjust this table, likewise we can't change/add things * once the hardware is frozen. (actually, the RDP hardware only looks at * the lower 6 bits of the command byte) * @@ -206,7 +206,7 @@ #define G_TEXRECT 0xe4 /* -28 */ -/* +/* * The following commands are the "generated" RDP commands; the user * never sees them, the RSP microcode generates them. * @@ -326,7 +326,7 @@ * * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE: * The weird bit-ordering is for the micro-code: the lower byte - * can be OR'd in with G_TRI_SHADE (11001100) to construct + * can be OR'd in with G_TRI_SHADE (11001100) to construct * the triangle command directly. Don't break it... * * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE: @@ -340,7 +340,7 @@ * appropriately and use primcolor to see anything. * * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle. - * If it is not set, then do 'flat shading', where only one vertex color + * If it is not set, then do 'flat shading', where only one vertex color * is used (and all 3 vertices are set to that same color by the ucode) * See the man page for gSP1Triangle(). * @@ -718,154 +718,162 @@ #define G_BL_1 2 #define G_BL_0 3 +#ifdef DISABLE_AA +#define AA_DEF +#define RD_DEF +#else +#define AA_DEF AA_EN | +#define RD_DEF IM_RD | +#endif + #define GBL_c1(m1a, m1b, m2a, m2b) \ (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 #define GBL_c2(m1a, m1b, m2a, m2b) \ (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 #define RM_AA_ZB_OPA_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_ZB_OPA_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_XLU_SURF(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_OPA_DECAL(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL | \ + AA_DEF Z_CMP | RD_DEF CVG_DST_WRAP | ALPHA_CVG_SEL | \ ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_ZB_OPA_DECAL(clk) \ - AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | \ + AA_DEF Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | \ ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_XLU_DECAL(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_OPA_INTER(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ ALPHA_CVG_SEL | ZMODE_INTER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_ZB_OPA_INTER(clk) \ - AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | CVG_DST_CLAMP | \ ALPHA_CVG_SEL | ZMODE_INTER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_XLU_INTER(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ FORCE_BL | ZMODE_INTER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_XLU_LINE(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_DEC_LINE(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_TEX_EDGE(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_EN | Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_TEX_INTER(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_SUB_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ + AA_DEF Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_PCL_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ ZMODE_OPA | G_AC_DITHER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_OPA_TERR(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_TEX_TERR(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_SUB_TERR(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ + AA_DEF Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_OPA_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_OPA_SURF(clk) \ - AA_EN | CVG_DST_CLAMP | \ + AA_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_XLU_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | \ + AA_DEF IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | \ ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_XLU_LINE(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ + AA_DEF IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_DEC_LINE(clk) \ - AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA | \ + AA_DEF IM_RD | CVG_DST_FULL | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_TEX_EDGE(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_EN | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_SUB_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_FULL | \ + AA_DEF IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_PCL_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF IM_RD | CVG_DST_CLAMP | \ ZMODE_OPA | G_AC_DITHER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_OPA_TERR(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_TEX_TERR(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_SUB_TERR(clk) \ - AA_EN | IM_RD | CVG_DST_FULL | \ + AA_DEF IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) @@ -874,27 +882,27 @@ Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | \ ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - + #define RM_ZB_XLU_SURF(clk) \ Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_OPA_DECAL(clk) \ Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - + #define RM_ZB_XLU_DECAL(clk) \ Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_CLD_SURF(clk) \ Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_OVL_SURF(clk) \ Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_PCL_SURF(clk) \ Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | \ G_AC_DITHER | \ @@ -1151,7 +1159,7 @@ * element, we can't depend on the C compiler to align things * properly. * - * 64-bit structure alignment is enforced by wrapping structures with + * 64-bit structure alignment is enforced by wrapping structures with * unions that contain a dummy "long long int". Why this works is * explained in the ANSI C Spec, or on page 186 of the second edition * of K&R, "The C Programming Language". @@ -1223,14 +1231,14 @@ typedef struct { /* 20 bytes for above */ /* padding to bring structure size to 64 bit allignment */ - char dummy[4]; + char dummy[4]; } uSprite_t; -typedef union { +typedef union { uSprite_t s; - /* Need to make sure this is 64 bit aligned */ + /* Need to make sure this is 64 bit aligned */ long long int force_structure_allignment[3]; } uSprite; @@ -1315,7 +1323,7 @@ typedef union { */ #ifdef F3DEX_GBI_2 /* 0,4 are reserved by G_MTX */ -# define G_MV_MMTX 2 +# define G_MV_MMTX 2 # define G_MV_PMTX 6 # define G_MV_VIEWPORT 8 # define G_MV_LIGHT 10 @@ -1373,7 +1381,7 @@ typedef union { /* * These are offsets from the address in the dmem table - */ + */ #define G_MWO_NUMLIGHT 0x00 #define G_MWO_CLIP_RNX 0x04 #define G_MWO_CLIP_RNY 0x0c @@ -1455,7 +1463,7 @@ typedef union { * * Note: only directional (infinite) lights are currently supported. * - * Note: the weird order is for the DMEM alignment benefit of + * Note: the weird order is for the DMEM alignment benefit of * the microcode. * */ @@ -1775,7 +1783,7 @@ typedef struct { /* * Textured rectangles are 128 bits not 64 bits - */ + */ typedef struct { unsigned long w0; unsigned long w1; @@ -1933,7 +1941,7 @@ typedef union { gsDma1p(G_VTX, v, sizeof(Vtx)*(n), ((n)-1)<<4|(v0)) #endif - + #ifdef F3DEX_GBI_2 # define gSPViewport(pkt, v) \ gDma2p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0) @@ -2192,7 +2200,7 @@ typedef union { /*** *** 1 Triangle - ***/ + ***/ #define gSP1Triangle(pkt, v0, v1, v2, flag) \ { \ Gfx *_g = (Gfx *)(pkt); \ @@ -2368,7 +2376,7 @@ typedef union { * Insert values into Matrix * * where = element of matrix (byte offset) - * num = new element (32 bit value replacing 2 int or 2 frac matrix + * num = new element (32 bit value replacing 2 int or 2 frac matrix * componants */ #ifdef F3DEX_GBI_2 @@ -2396,7 +2404,7 @@ typedef union { #define gsSPForceMatrix(mptr) \ gsDma2p(G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0), \ gsMoveWd(G_MW_FORCEMTX,0,0x00010000) - + #else /* F3DEX_GBI_2 */ #define gSPForceMatrix(pkt, mptr) \ { \ @@ -2444,7 +2452,7 @@ typedef union { /* * gSPBranchLessZ Branch DL if (vtx.z) less than or equal (zval). * - * dl = DL branch to + * dl = DL branch to * vtx = Vertex * zval = Screen depth * near = Near plane @@ -2491,7 +2499,7 @@ typedef union { /* * gSPBranchLessZraw Branch DL if (vtx.z) less than or equal (raw zval). * - * dl = DL branch to + * dl = DL branch to * vtx = Vertex * zval = Raw value of screen depth */ @@ -2592,7 +2600,7 @@ typedef union { #define NUMLIGHTS_7 7 /* * n should be one of: NUMLIGHTS_0, NUMLIGHTS_1, ..., NUMLIGHTS_7 - * NOTE: in addition to the number of directional lights specified, + * NOTE: in addition to the number of directional lights specified, * there is always 1 ambient light */ #define gSPNumLights(pkt, n) \ @@ -2604,7 +2612,7 @@ typedef union { #define LIGHT_2 2 #define LIGHT_3 3 #define LIGHT_4 4 -#define LIGHT_5 5 +#define LIGHT_5 5 #define LIGHT_6 6 #define LIGHT_7 7 #define LIGHT_8 8 @@ -2829,7 +2837,7 @@ typedef union { * min, max: range 0 to 1000: 0=nearplane, 1000=farplane * min is where fog begins (usually less than max and often 0) * max is where fog is thickest (usually 1000) - * + * */ #define gSPFogFactor(pkt, fm, fo) \ gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \ @@ -2869,7 +2877,7 @@ typedef union { _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\ (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)) \ }} -/* +/* * Different version of SPTexture macro, has an additional parameter * which is currently reserved in the microcode. */ @@ -2908,7 +2916,7 @@ typedef union { _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \ (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)) \ }} -/* +/* * Different version of SPTexture macro, has an additional parameter * which is currently reserved in the microcode. */ @@ -3135,7 +3143,7 @@ typedef union { gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode) #endif -/* 'blendmask' is not supported anymore. +/* 'blendmask' is not supported anymore. * The bits are reserved for future use. * Fri May 26 13:45:55 PDT 1995 */ @@ -3341,7 +3349,7 @@ typedef union { * * This command makes all othermode parameters set. * Do not use this command in the same DL with another g*SPSetOtherMode DLs. - * + * * [Usage] * gDPSetOtherMode(pkt, modeA, modeB) * @@ -3594,9 +3602,9 @@ typedef union { ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ } -/* +/* * Allow tmem address and render tile to be specified. - * The S at the end means odd lines are already word Swapped + * The S at the end means odd lines are already word Swapped */ #define gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, \ height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ @@ -3812,13 +3820,13 @@ typedef union { ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ ((height)-1) << G_TEXTURE_IMAGE_FRAC) -/* +/* * Allows tmem and render tile to be specified. Useful when loading * several tiles at a time. * * Here is the static form of the pre-swapped texture block loading * See gDPLoadTextureBlockS() for reference. Basically, just don't - * calculate DxT, use 0 + * calculate DxT, use 0 */ #define gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height, \ @@ -3902,7 +3910,7 @@ typedef union { } /* - * 4-bit load block. Allows tmem and render tile to be specified. Useful when + * 4-bit load block. Allows tmem and render tile to be specified. Useful when * loading multiple tiles. The S means odd lines are already word swapped. */ #define gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height,\ @@ -4337,7 +4345,7 @@ typedef union { G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*16, 1, \ pal, 0, 0, 0, 0, 0, 0) -#endif /* _HW_VERSION_1 */ +#endif /* _HW_VERSION_1 */ /* * Load a 256-entry palette (for 8-bit CI textures) @@ -4379,7 +4387,7 @@ typedef union { gsDPLoadSync(), \ gsDPLoadTLUTCmd(G_TX_LOADTILE, 255), \ gsDPPipeSync() - + #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ #define gsDPLoadTLUT_pal256(dram) \ @@ -4434,7 +4442,7 @@ typedef union { G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count, \ 0, 0, 0, 0, 0, 0, 0) -#endif /* _HW_VERSION_1 */ +#endif /* _HW_VERSION_1 */ #define gDPSetScissor(pkt, mode, ulx, uly, lrx, lry) \ { \ @@ -4611,7 +4619,7 @@ typedef union { }} /* Notice that textured rectangles are 128-bit commands, therefore - * gsDPTextureRectangle() should not be used in display lists + * gsDPTextureRectangle() should not be used in display lists * under normal circumstances (use gsSPTextureRectangle()). * That is also why there is no gDPTextureRectangle() macros. */ diff --git a/include/n64/PR/libaudio.h b/include/n64/PR/libaudio.h index 3fffe9c0..cb7a5b19 100644 --- a/include/n64/PR/libaudio.h +++ b/include/n64/PR/libaudio.h @@ -8,7 +8,8 @@ typedef struct u8 *offset; s32 len; #ifdef VERSION_SH - s8 magic[2]; // tbl: 0x0204, otherwise: 0x0203 + s8 medium; + s8 magic; // tbl: 0x04, otherwise: 0x03 // for ctl (else zeros): union { @@ -38,7 +39,9 @@ typedef struct #ifdef VERSION_SH s16 unk2; u8 *data; +#if !IS_64_BIT s32 pad[2]; +#endif #endif ALSeqData seqArray[1]; } ALSeqFile; diff --git a/include/object_constants.h b/include/object_constants.h index 95f5ce53..cca7c870 100644 --- a/include/object_constants.h +++ b/include/object_constants.h @@ -28,23 +28,26 @@ #define RESPAWN_INFO_DONT_RESPAWN 0xFF /* oFlags */ -#define OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE (1 << 0) // 0x00000001 -#define OBJ_FLAG_MOVE_XZ_USING_FVEL (1 << 1) // 0x00000002 -#define OBJ_FLAG_MOVE_Y_WITH_TERMINAL_VEL (1 << 2) // 0x00000004 -#define OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW (1 << 3) // 0x00000008 -#define OBJ_FLAG_SET_FACE_ANGLE_TO_MOVE_ANGLE (1 << 4) // 0x00000010 -#define OBJ_FLAG_0020 (1 << 5) // 0x00000020 -#define OBJ_FLAG_COMPUTE_DIST_TO_MARIO (1 << 6) // 0x00000040 -#define OBJ_FLAG_ACTIVE_FROM_AFAR (1 << 7) // 0x00000080 -#define OBJ_FLAG_0100 (1 << 8) // 0x00000100 -#define OBJ_FLAG_TRANSFORM_RELATIVE_TO_PARENT (1 << 9) // 0x00000200 -#define OBJ_FLAG_HOLDABLE (1 << 10) // 0x00000400 -#define OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM (1 << 11) // 0x00000800 -#define OBJ_FLAG_1000 (1 << 12) // 0x00001000 -#define OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO (1 << 13) // 0x00002000 -#define OBJ_FLAG_PERSISTENT_RESPAWN (1 << 14) // 0x00004000 -#define OBJ_FLAG_8000 (1 << 15) // 0x00008000 -#define OBJ_FLAG_30 (1 << 30) // 0x40000000 +#define OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE (1 << 0) // 0x00000001 +#define OBJ_FLAG_MOVE_XZ_USING_FVEL (1 << 1) // 0x00000002 +#define OBJ_FLAG_MOVE_Y_WITH_TERMINAL_VEL (1 << 2) // 0x00000004 +#define OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW (1 << 3) // 0x00000008 +#define OBJ_FLAG_SET_FACE_ANGLE_TO_MOVE_ANGLE (1 << 4) // 0x00000010 +#define OBJ_FLAG_UPDATE_TRANSFORM_FOR_THROW_MATRIX (1 << 5) // 0x00000020 +#define OBJ_FLAG_COMPUTE_DIST_TO_MARIO (1 << 6) // 0x00000040 +#define OBJ_FLAG_ACTIVE_FROM_AFAR (1 << 7) // 0x00000080 +#define OBJ_FLAG_PLAYER (1 << 8) // 0x00000100 +#define OBJ_FLAG_TRANSFORM_RELATIVE_TO_PARENT (1 << 9) // 0x00000200 +#define OBJ_FLAG_HOLDABLE (1 << 10) // 0x00000400 +#define OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM (1 << 11) // 0x00000800 +#define OBJ_FLAG_1000 (1 << 12) // 0x00001000 +#define OBJ_FLAG_COMPUTE_ANGLE_TO_MARIO (1 << 13) // 0x00002000 +#define OBJ_FLAG_PERSISTENT_RESPAWN (1 << 14) // 0x00004000 +#define OBJ_FLAG_8000 (1 << 15) // 0x00008000 +#ifdef AUTO_COLLISION_DISTANCE +#define OBJ_FLAG_DONT_CALC_COLL_DIST (1 << 16) // 0x00010000 +#endif +#define OBJ_FLAG_HITBOX_WAS_SET (1 << 30) // 0x40000000 /* oHeldState */ #define HELD_FREE 0 @@ -53,23 +56,18 @@ #define HELD_DROPPED 3 /* oDialogState */ -#define DIALOG_UNK1_ENABLE_TIME_STOP 0 -#define DIALOG_UNK1_INTERRUPT_MARIO_ACTION 1 -#define DIALOG_UNK1_BEGIN_DIALOG 2 -#define DIALOG_UNK1_AWAIT_DIALOG 3 -#define DIALOG_UNK1_DISABLE_TIME_STOP 4 +#define DIALOG_STATUS_ENABLE_TIME_STOP 0 +#define DIALOG_STATUS_INTERRUPT 1 +#define DIALOG_STATUS_START_DIALOG 2 +#define DIALOG_STATUS_STOP_DIALOG 3 +#define DIALOG_STATUS_DISABLE_TIME_STOP 4 -#define DIALOG_UNK1_FLAG_DEFAULT (1 << 1) // 0x02 -#define DIALOG_UNK1_FLAG_RESPONSE (1 << 2) // 0x04 -#define DIALOG_UNK1_FLAG_4 (1 << 4) // 0x10 - -#define DIALOG_UNK2_ENABLE_TIME_STOP 0 -#define DIALOG_UNK2_TURN_AND_INTERRUPT_MARIO_ACTION 1 -#define DIALOG_UNK2_AWAIT_DIALOG 2 -#define DIALOG_UNK2_END_DIALOG 3 - -#define DIALOG_UNK2_FLAG_0 (1 << 0) // 0x01 -#define DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED (1 << 4) // 0x10 +#define DIALOG_FLAG_NONE 0 +#define DIALOG_FLAG_TURN_TO_MARIO (1 << 0) // 0x01 // cutscene only +#define DIALOG_FLAG_TEXT_DEFAULT (1 << 1) // 0x02 +#define DIALOG_FLAG_TEXT_RESPONSE (1 << 2) // 0x04 // non-cutscene only +#define DIALOG_FLAG_UNK_CAPSWITCH (1 << 3) // 0x08 // not defined +#define DIALOG_FLAG_TIME_STOP_ENABLED (1 << 4) // 0x10 /* oMoveFlags */ #define OBJ_MOVE_LANDED (1 << 0) // 0x0001 @@ -191,6 +189,112 @@ #define BOBOMB_BUDDY_HAS_NOT_TALKED 0 #define BOBOMB_BUDDY_HAS_TALKED 2 +/* Bowser */ + /* Tail oAction */ + #define BOWSER_ACT_TAIL_DEFAULT 0 + #define BOWSER_ACT_TAIL_THROWN 1 + #define BOWSER_ACT_TAIL_TOUCHED_MARIO 2 + /* oAction */ + #define BOWSER_ACT_DEFAULT 0 + #define BOWSER_ACT_THROWN 1 + #define BOWSER_ACT_JUMP_ONTO_STAGE 2 + #define BOWSER_ACT_DANCE 3 + #define BOWSER_ACT_DEAD 4 + #define BOWSER_ACT_WAIT 5 + #define BOWSER_ACT_INTRO_WALK 6 + #define BOWSER_ACT_CHARGE_MARIO 7 + #define BOWSER_ACT_SPIT_FIRE_INTO_SKY 8 + #define BOWSER_ACT_SPIT_FIRE_ONTO_FLOOR 9 + #define BOWSER_ACT_HIT_EDGE 10 + #define BOWSER_ACT_TURN_FROM_EDGE 11 + #define BOWSER_ACT_HIT_MINE 12 + #define BOWSER_ACT_BIG_JUMP 13 + #define BOWSER_ACT_WALK_TO_MARIO 14 + #define BOWSER_ACT_BREATH_FIRE 15 + #define BOWSER_ACT_TELEPORT 16 + #define BOWSER_ACT_QUICK_JUMP 17 + #define BOWSER_ACT_UNUSED_SLOW_WALK 18 + #define BOWSER_ACT_TILT_LAVA_PLATFORM 19 + /* Animations */ + #define BOWSER_ANIM_STAND_UP 0 + #define BOWSER_ANIM_STAND_UP_UNUSED 1 // slightly different + #define BOWSER_ANIM_SHAKING 2 + #define BOWSER_ANIM_GRABBED 3 + #define BOWSER_ANIM_BROKEN 4 // broken animation + #define BOWSER_ANIM_FALL_DOWN 5 // unused + #define BOWSER_ANIM_BREATH 6 + #define BOWSER_ANIM_JUMP 7 // unused, short jump, replaced by start/stop + #define BOWSER_ANIM_JUMP_STOP 8 + #define BOWSER_ANIM_JUMP_START 9 + #define BOWSER_ANIM_DANCE 10 + #define BOWSER_ANIM_BREATH_UP 11 + #define BOWSER_ANIM_IDLE 12 + #define BOWSER_ANIM_SLOW_GAIT 13 + #define BOWSER_ANIM_LOOK_DOWN_STOP_WALK 14 + #define BOWSER_ANIM_LOOK_UP_START_WALK 15 + #define BOWSER_ANIM_FLIP_DOWN 16 + #define BOWSER_ANIM_LAY_DOWN 17 + #define BOWSER_ANIM_RUN_START 18 + #define BOWSER_ANIM_RUN 19 + #define BOWSER_ANIM_RUN_STOP 20 + #define BOWSER_ANIM_RUN_SLIP 21 + #define BOWSER_ANIM_BREATH_QUICK 22 + #define BOWSER_ANIM_EDGE_MOVE 23 + #define BOWSER_ANIM_EDGE_STOP 24 + #define BOWSER_ANIM_FLIP 25 + #define BOWSER_ANIM_STAND_UP_FROM_FLIP 26 + /* oBehParams2ndByte */ + #define BOWSER_BP_BITDW 0 + #define BOWSER_BP_BITFS 1 + #define BOWSER_BP_BITS 2 + /* oBowserCamAct */ + #define BOWSER_CAM_ACT_IDLE 0 + #define BOWSER_CAM_ACT_WALK 1 + #define BOWSER_CAM_ACT_END 2 + /* oBowserStatus */ + #define BOWSER_STATUS_ANGLE_MARIO (1 << 1) // 0x00000002 + #define BOWSER_STATUS_ANGLE_CENTRE (1 << 2) // 0x00000004 + #define BOWSER_STATUS_DIST_MARIO (1 << 3) // 0x00000008 + #define BOWSER_STATUS_DIST_CENTRE (1 << 4) // 0x00000010 + #define BOWSER_STATUS_BIG_JUMP (1 << 16) // 0x00010000 + #define BOWSER_STATUS_FIRE_SKY (1 << 17) // 0x00020000 + /* oBowserGrabbedStatus */ + #define BOWSER_GRAB_STATUS_NONE 0 + #define BOWSER_GRAB_STATUS_GRABBED 1 + #define BOWSER_GRAB_STATUS_HOLDING 2 + /* oSubAction */ + #define BOWSER_SUB_ACT_DEAD_FLY_BACK 0 + #define BOWSER_SUB_ACT_DEAD_BOUNCE 1 + #define BOWSER_SUB_ACT_DEAD_WAIT 2 + #define BOWSER_SUB_ACT_DEAD_DEFAULT_END 3 + #define BOWSER_SUB_ACT_DEAD_DEFAULT_END_OVER 4 + #define BOWSER_SUB_ACT_DEAD_FINAL_END 10 + #define BOWSER_SUB_ACT_DEAD_FINAL_END_OVER 11 + + #define BOWSER_SUB_ACT_CHARGE_START 0 + #define BOWSER_SUB_ACT_CHARGE_RUN 1 + #define BOWSER_SUB_ACT_CHARGE_END 2 + #define BOWSER_SUB_ACT_CHARGE_SLIP 3 + + #define BOWSER_SUB_ACT_TELEPORT_START 0 + #define BOWSER_SUB_ACT_TELEPORT_MOVE 1 + #define BOWSER_SUB_ACT_TELEPORT_STOP 2 + + #define BOWSER_SUB_ACT_HIT_MINE_START 0 + #define BOWSER_SUB_ACT_HIT_MINE_FALL 1 + #define BOWSER_SUB_ACT_HIT_MINE_STOP 2 + + #define BOWSER_SUB_ACT_JUMP_ON_STAGE_IDLE 0 + #define BOWSER_SUB_ACT_JUMP_ON_STAGE_START 1 + #define BOWSER_SUB_ACT_JUMP_ON_STAGE_LAND 2 + #define BOWSER_SUB_ACT_JUMP_ON_STAGE_STOP 3 + +/* Bowser Bits Platform*/ + /* oAction */ + #define BOWSER_BITS_PLAT_ACT_START 0 + #define BOWSER_BITS_PLAT_ACT_CHECK 1 + #define BOWSER_BITS_PLAT_ACT_FALL 2 + /* Fish Spawer */ /* oAction */ #define FISH_SPAWNER_ACT_SPAWN 0 diff --git a/include/object_fields.h b/include/object_fields.h index e4f13555..f474fe29 100644 --- a/include/object_fields.h +++ b/include/object_fields.h @@ -65,8 +65,8 @@ #define /*0x0B4*/ oVelZ OBJECT_FIELD_F32(0x0B) #define /*0x0B8*/ oForwardVel OBJECT_FIELD_F32(0x0C) #define /*0x0B8*/ oForwardVelS32 OBJECT_FIELD_S32(0x0C) -#define /*0x0BC*/ oUnkBC OBJECT_FIELD_F32(0x0D) -#define /*0x0C0*/ oUnkC0 OBJECT_FIELD_F32(0x0E) +#define /*0x0BC*/ oLeftVel OBJECT_FIELD_F32(0x0D) +#define /*0x0C0*/ oUpVel OBJECT_FIELD_F32(0x0E) #define /*0x0C4*/ O_MOVE_ANGLE_INDEX 0x0F #define /*0x0C4*/ O_MOVE_ANGLE_PITCH_INDEX (O_MOVE_ANGLE_INDEX + 0) #define /*0x0C4*/ O_MOVE_ANGLE_YAW_INDEX (O_MOVE_ANGLE_INDEX + 1) @@ -274,24 +274,24 @@ #define /*0x0FC*/ oBBallSpawnerPeriodMinus1 OBJECT_FIELD_S32(0x1D) /* Bowser */ -#define /*0x088*/ oBowserUnk88 OBJECT_FIELD_S32(0x00) -#define /*0x0F4*/ oBowserUnkF4 OBJECT_FIELD_S32(0x1B) -#define /*0x0F8*/ oBowserUnkF8 OBJECT_FIELD_S32(0x1C) +#define /*0x088*/ oBowserCamAct OBJECT_FIELD_S32(0x00) +#define /*0x0F4*/ oBowserStatus OBJECT_FIELD_S32(0x1B) +#define /*0x0F8*/ oBowserTimer OBJECT_FIELD_S32(0x1C) #define /*0x0FC*/ oBowserDistToCentre OBJECT_FIELD_F32(0x1D) -#define /*0x106*/ oBowserUnk106 OBJECT_FIELD_S16(0x1F, 1) -#define /*0x108*/ oBowserUnk108 OBJECT_FIELD_S16(0x20, 0) +#define /*0x106*/ oBowserBitsJustJump OBJECT_FIELD_S16(0x1F, 1) +#define /*0x108*/ oBowserRandSplitFloor OBJECT_FIELD_S16(0x20, 0) #define /*0x10A*/ oBowserHeldAnglePitch OBJECT_FIELD_S16(0x20, 1) #define /*0x10D*/ oBowserHeldAngleVelYaw OBJECT_FIELD_S16(0x21, 0) -#define /*0x10E*/ oBowserUnk10E OBJECT_FIELD_S16(0x21, 1) -#define /*0x110*/ oBowserUnk110 OBJECT_FIELD_S16(0x22, 0) +#define /*0x10E*/ oBowserGrabbedStatus OBJECT_FIELD_S16(0x21, 1) +#define /*0x110*/ oBowserIsReacting OBJECT_FIELD_S16(0x22, 0) #define /*0x112*/ oBowserAngleToCentre OBJECT_FIELD_S16(0x22, 1) -#define /*0x1AC*/ oBowserUnk1AC OBJECT_FIELD_S16(0x49, 0) -#define /*0x1AE*/ oBowserUnk1AE OBJECT_FIELD_S16(0x49, 1) +#define /*0x1AC*/ oBowserTargetOpacity OBJECT_FIELD_S16(0x49, 0) +#define /*0x1AE*/ oBowserEyesTimer OBJECT_FIELD_S16(0x49, 1) #define /*0x1B0*/ oBowserEyesShut OBJECT_FIELD_S16(0x4A, 0) -#define /*0x1B2*/ oBowserUnk1B2 OBJECT_FIELD_S16(0x4A, 1) +#define /*0x1B2*/ oBowserRainbowLight OBJECT_FIELD_S16(0x4A, 1) /* Bowser Shockwave */ -#define /*0x0F4*/ oBowserShockWaveUnkF4 OBJECT_FIELD_F32(0x1B) +#define /*0x0F4*/ oBowserShockWaveScale OBJECT_FIELD_F32(0x1B) /* Black Smoke Bowser */ #define /*0x0F4*/ oBlackSmokeBowserUnkF4 OBJECT_FIELD_F32(0x1B) @@ -497,7 +497,7 @@ /* Flame */ #define /*0x0F4*/ oFlameScale OBJECT_FIELD_F32(0x1B) #define /*0x0F8*/ oFlameSpeedTimerOffset OBJECT_FIELD_S32(0x1C) -#define /*0x0FC*/ oFlameUnkFC OBJECT_FIELD_F32(0x1D) +#define /*0x0FC*/ oFlameUnusedRand OBJECT_FIELD_F32(0x1D) #define /*0x100*/ oFlameBowser OBJECT_FIELD_OBJ(0x1E) /* Blue Flame */ @@ -626,7 +626,7 @@ #define /*0x0F4*/ oKoopaRaceEndpointRaceBegun OBJECT_FIELD_S32(0x1B) #define /*0x0F8*/ oKoopaRaceEndpointKoopaFinished OBJECT_FIELD_S32(0x1C) #define /*0x0FC*/ oKoopaRaceEndpointRaceStatus OBJECT_FIELD_S32(0x1D) -#define /*0x100*/ oKoopaRaceEndpointUnk100 OBJECT_FIELD_S32(0x1E) +#define /*0x100*/ oKoopaRaceEndpointDialog OBJECT_FIELD_S32(0x1E) #define /*0x104*/ oKoopaRaceEndpointRaceEnded OBJECT_FIELD_S32(0x1F) /* Koopa Shell Flame */ @@ -770,10 +770,14 @@ #define /*0x0F8*/ oPitouneUnkF8 OBJECT_FIELD_F32(0x1C) #define /*0x0FC*/ oPitouneUnkFC OBJECT_FIELD_F32(0x1D) -/* Platform */ -#define /*0x0F4*/ oPlatformTimer OBJECT_FIELD_S32(0x1B) -#define /*0x0F8*/ oPlatformUnkF8 OBJECT_FIELD_OBJ(0x1C) -#define /*0x0FC*/ oPlatformUnkFC OBJECT_FIELD_S32(0x1D) +/* Falling Rising Bitfs Platform */ +#define /*0x0F4*/ oBitfsPlatformTimer OBJECT_FIELD_S32(0x1B) + +/* Falling Bowser Bits Platform */ +#define /*0x0F8*/ oBitsPlatformBowser OBJECT_FIELD_OBJ(0x1C) +#define /*0x0FC*/ oBitsPlatformTimer OBJECT_FIELD_S32(0x1D) + +/* WF Platform */ #define /*0x10C*/ oPlatformUnk10C OBJECT_FIELD_F32(0x21) #define /*0x110*/ oPlatformUnk110 OBJECT_FIELD_F32(0x22) @@ -877,7 +881,7 @@ // 0x1D-0x21 reserved for pathing /* Snowman's Head */ -#define /*0x0F4*/ oSnowmansHeadUnkF4 OBJECT_FIELD_S32(0x1B) +#define /*0x0F4*/ oSnowmansHeadDialogActive OBJECT_FIELD_S32(0x1B) /* Snowman Wind Blowing */ #define /*0x0F4*/ oSLSnowmanWindOriginalYaw OBJECT_FIELD_S32(0x1B) diff --git a/include/segment_symbols.h b/include/segment_symbols.h index 7ed21340..eba62dc8 100644 --- a/include/segment_symbols.h +++ b/include/segment_symbols.h @@ -6,13 +6,19 @@ extern u8 _##name##SegmentRomStart[]; \ extern u8 _##name##SegmentRomEnd[]; +#define DECLARE_NOLOAD(name) \ + extern u8 _##name##SegmentBssStart[]; \ + extern u8 _##name##SegmentBssEnd[]; + #define DECLARE_ACTOR_SEGMENT(name) \ DECLARE_SEGMENT(name##_mio0) \ DECLARE_SEGMENT(name##_yay0) \ - DECLARE_SEGMENT(name##_geo) + DECLARE_SEGMENT(name##_geo) \ + DECLARE_NOLOAD(name##_geo) #define DECLARE_LEVEL_SEGMENT(name) \ DECLARE_SEGMENT(name) \ + DECLARE_NOLOAD(name) \ DECLARE_SEGMENT(name##_segment_7) DECLARE_ACTOR_SEGMENT(common0) @@ -39,9 +45,11 @@ DECLARE_ACTOR_SEGMENT(group17) DECLARE_SEGMENT(entry) DECLARE_SEGMENT(engine) DECLARE_SEGMENT(behavior) +DECLARE_NOLOAD(behavior) DECLARE_SEGMENT(scripts) DECLARE_SEGMENT(goddard) DECLARE_SEGMENT(framebuffers) +DECLARE_SEGMENT(assets) extern u8 _goddardSegmentStart[]; extern u8 _engineSegmentStart[]; extern u8 _engineSegmentBssEnd[]; diff --git a/include/segments.h b/include/segments.h index dc01b57e..963cd3e3 100644 --- a/include/segments.h +++ b/include/segments.h @@ -27,8 +27,6 @@ */ #define SEG_POOL_START _framebuffersSegmentBssEnd // 0x0165000 in size -#define SEG_GODDARD SEG_POOL_START + 0x113000 - #define POOL_SIZE RAM_END - SEG_POOL_START #endif // SEGMENTS_H diff --git a/include/seq_ids.h b/include/seq_ids.h index 0aec73d1..8166de64 100644 --- a/include/seq_ids.h +++ b/include/seq_ids.h @@ -6,6 +6,8 @@ #define SEQ_BASE_ID 0x7f #define SEQ_VARIATION 0x80 +#define SEQ_MENU_GAME_OVER (SEQ_MENU_TITLE_SCREEN | SEQ_VARIATION) + enum SeqId { SEQ_SOUND_PLAYER, // 0x00 SEQ_EVENT_CUTSCENE_COLLECT_STAR, // 0x01 diff --git a/include/seq_macros.inc b/include/seq_macros.inc index e0633acb..d73d9923 100644 --- a/include/seq_macros.inc +++ b/include/seq_macros.inc @@ -1,7 +1,7 @@ -# Macros for disassembled sequence files. This file was automatically generated by seq_decoder.py. -# To regenerate it, run: ./tools/seq_decoder.py --emit-asm-macros >seq_macros.inc +// Macros for disassembled sequence files. This file was automatically generated by seq_decoder.py. +// To regenerate it, run: ./tools/seq_decoder.py --emit-asm-macros > include/seq_macros.inc -# seq commands +// seq commands .macro seq_testchdisabled a .byte 0x0 + \a @@ -155,7 +155,7 @@ .byte 0xff .endm -.ifdef VERSION_SH +#ifdef VERSION_SH .macro seq_unreservenotes .byte 0xf0 @@ -166,9 +166,9 @@ .byte \a .endm -.else +#else -.ifdef VERSION_EU +#ifdef VERSION_EU .macro seq_unreservenotes .byte 0xf0 @@ -179,7 +179,7 @@ .byte \a .endm -.else +#else .macro seq_unreservenotes .byte 0xf1 @@ -190,11 +190,11 @@ .byte \a .endm -.endif +#endif -.endif +#endif -# chan commands +// chan commands .macro chan_startchannel a, b .byte 0x10 + \a @@ -462,7 +462,7 @@ var_long \a .endm -.ifdef VERSION_SH +#ifdef VERSION_SH .macro chan_setnotepriority a .byte 0xe9 @@ -495,7 +495,7 @@ .byte 0x90 + \a .endm -.else +#else .macro chan_testlayerfinished a .byte 0x0 + \a @@ -514,7 +514,7 @@ .byte 0xa0 + \a .endm -.ifdef VERSION_EU +#ifdef VERSION_EU .macro chan_setnotepriority a .byte 0xe9 @@ -530,7 +530,7 @@ .byte \a .endm -.else +#else .macro chan_setnotepriority a .byte 0x60 + \a @@ -545,11 +545,11 @@ .byte \a .endm -.endif +#endif -.endif +#endif -# layer commands +// layer commands .macro layer_note0 a, b, c, d .byte 0x0 + \a @@ -659,7 +659,7 @@ .byte \c .endm -# envelope commands +// envelope commands .macro envelope_disable a .byte 0x0, 0x0 @@ -686,7 +686,7 @@ .byte \b >> 8, \b & 0xff .endm -# other commands +// other commands .macro var_long x .byte (0x80 | (\x & 0x7f00) >> 8), (\x & 0xff) diff --git a/include/sm64.h b/include/sm64.h index 34bfec22..88446c92 100644 --- a/include/sm64.h +++ b/include/sm64.h @@ -59,7 +59,7 @@ #define INPUT_A_DOWN 0x0080 #define INPUT_IN_POISON_GAS 0x0100 #define INPUT_IN_WATER 0x0200 -#define INPUT_UNKNOWN_10 0x0400 +#define INPUT_STOMPED 0x0400 #define INPUT_INTERACT_OBJ_GRABBABLE 0x0800 #define INPUT_UNKNOWN_12 0x1000 #define INPUT_B_PRESSED 0x2000 diff --git a/include/sounds.h b/include/sounds.h index a734a103..f3a5f555 100644 --- a/include/sounds.h +++ b/include/sounds.h @@ -386,7 +386,7 @@ #define SOUND_ENV_UNK12 /* 0x40120000 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x12, 0x00, 0) // unverified, unused #define SOUND_ENV_SLIDING /* 0x40130000 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x13, 0x00, 0) // unverified #define SOUND_ENV_STAR /* 0x40140010 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x14, 0x00, SOUND_LOWER_BACKGROUND_MUSIC) // unverified -#define SOUND_ENV_UNKNOWN4 /* 0x41150000 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x15, 0x00, SOUND_NO_VOLUME_LOSS) // unverified +#define SOUND_ENV_MOVING_BIG_PLATFORM /* 0x41150000 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x15, 0x00, SOUND_NO_VOLUME_LOSS) // unverified #define SOUND_ENV_WATER_DRAIN /* 0x41160000 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x16, 0x00, SOUND_NO_VOLUME_LOSS) // unverified #define SOUND_ENV_METAL_BOX_PUSH /* 0x40178000 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x17, 0x80, 0) // unverified #define SOUND_ENV_SINK_QUICKSAND /* 0x40188000 */ SOUND_ARG_LOAD(SOUND_BANK_ENV, 0x18, 0x80, 0) // unverified diff --git a/include/surface_terrains.h b/include/surface_terrains.h index 29ccb034..6f231e93 100644 --- a/include/surface_terrains.h +++ b/include/surface_terrains.h @@ -1,6 +1,8 @@ #ifndef SURFACE_TERRAINS_H #define SURFACE_TERRAINS_H +#include "config.h" + // Surface Types #define SURFACE_DEFAULT 0x0000 // Environment default #define SURFACE_BURNING 0x0001 // Lava / Frostbite (in SL), but is used mostly for Lava @@ -202,7 +204,11 @@ #define COL_TRI_INIT(surfType, triNum) surfType, triNum // Collision Tri +#ifdef ALL_SURFACES_HAVE_FORCE +#define COL_TRI(v1, v2, v3) v1, v2, v3, 0 +#else #define COL_TRI(v1, v2, v3) v1, v2, v3 +#endif // Collision Tri With Special Params #define COL_TRI_SPECIAL(v1, v2, v3, param) v1, v2, v3, param diff --git a/include/text_strings.h.in b/include/text_strings.h.in index d2660588..c5ee3fa8 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -3,6 +3,66 @@ #include "text_menu_strings.h" +#if defined(PUPPYCAM) +#define NC_CAMX_EN _("Camera X Sensitivity") +#define NC_CAMY_EN _("Camera Y Sensitivity") +#define NC_INVERTX_EN _("Invert X Axis") +#define NC_INVERTY_EN _("Invert Y Axis") +#define NC_CAMC_EN _("Camera Centre Speed") +#define NC_ANALOGUE_EN _("Analogue Camera") +#define NC_SCHEME_EN _("Control Scheme") +#define OPTION_ENABLED_EN _("Enabled") +#define OPTION_DISABLED_EN _("Disabled") +#define OPTION_SCHEME1_EN _("Double Tap") +#define OPTION_SCHEME2_EN _("Single Press") +#define OPTION_SCHEME3_EN _("Classic") +#define OPTION_LANGUAGE_EN _("Language") +#define NC_WIDE_EN _("Widescreen") +#define NC_HIGHLIGHT_L _(">") +#define NC_HIGHLIGHT_R _("<") +#define NC_BUTTON_EN _("[R]: Options") +#define NC_BUTTON2_EN _("[R]: Return") +#define NC_OPTION_EN _("OPTIONS") + +#if MULTILANG +#define NC_CAMX_FR _("Sensibilite sur l'axe X") +#define NC_CAMY_FR _("Sensibilite sur l'axe Y") +#define NC_INVERTX_FR _("Invertir Axe X") +#define NC_INVERTY_FR _("Invertir Axe Y") +#define NC_CAMC_FR _("Vitesse de Centrage") +#define NC_ANALOGUE_FR _("Camera Analogue") +#define NC_SCHEME_FR _("Control Scheme") +#define OPTION_ENABLED_FR _("Active") +#define OPTION_DISABLED_FR _("Desactive") +#define OPTION_SCHEME1_FR _("Double Tap") +#define OPTION_SCHEME2_FR _("Single Press") +#define OPTION_SCHEME3_FR _("Classic") +#define OPTION_LANGUAGE_FR _("Language") +#define NC_WIDE_FR _("Widescreen") +#define NC_BUTTON_FR _("[R]: Options") +#define NC_BUTTON2_FR _("[R]: Retournez") +#define NC_OPTION_FR _("OPTIONS") + +#define NC_CAMX_DE _("Camera X Sensitivity") +#define NC_CAMY_DE _("Camera Y Sensitivity") +#define NC_INVERTY_DE _("Invert Y Axis") +#define NC_INVERTX_DE _("Invert X Axis") +#define NC_CAMC_DE _("Camera Centre Speed") +#define NC_ANALOGUE_DE _("Analogue Camera") +#define NC_SCHEME_DE _("Control Scheme") +#define OPTION_ENABLED_DE _("Enabled") +#define OPTION_DISABLED_DE _("Disabled") +#define OPTION_SCHEME1_DE _("Double Tap") +#define OPTION_SCHEME2_DE _("Single Press") +#define OPTION_SCHEME3_DE _("Classic") +#define OPTION_LANGUAGE_DE _("Language") +#define NC_WIDE_DE _("Widescreen") +#define NC_BUTTON_DE _("[R]: Options") +#define NC_BUTTON2_DE _("[R]: Return") +#define NC_OPTION_DE _("OPTIONS") +#endif +#endif + /** * Global Symbols */ @@ -26,12 +86,10 @@ #define TEXT_HUD_CONGRATULATIONS _("CONGRATULATIONS") // Course Complete Text, Bowser Courses //Widescreen stuff -#ifdef WIDE +#if defined(WIDE) && !defined(PUPPYCAM) #define TEXT_HUD_CURRENT_RATIO_43 _("ASPECT RATIO: 4:3") #define TEXT_HUD_CURRENT_RATIO_169 _("ASPECT RATIO: 16:9") #define TEXT_HUD_PRESS_L _("PRESS L TO SWITCH") -#define TEXT_HUD_WIDE_INFO _("PLEASE CONFIGURE YOUR DISPLAY OR YOUR EMULATOR TO") -#define TEXT_HUD_WIDE_INFO2 _("STRETCH THE IMAGE TO 16:9") #endif #if defined(VERSION_JP) || defined(VERSION_SH) @@ -233,7 +291,12 @@ #endif -#ifdef VERSION_EU + +#define TEXT_ENGLISH _("ENGLISH") +#define TEXT_FRENCH _("FRANÇAIS") +#define TEXT_GERMAN _("DEUTSCH") + +#if MULTILANG /** * File Select Text @@ -317,10 +380,6 @@ #define TEXT_MONO_DE _("MONO") #define TEXT_HEADSET_DE _("PHONES") -#define TEXT_ENGLISH _("ENGLISH") -#define TEXT_FRENCH _("FRANÇAIS") -#define TEXT_GERMAN _("DEUTSCH") - #define TEXT_HI_SCORE_FR _("MEILLEUR SCORE") #define TEXT_HI_SCORE_DE _("BESTLEISTUNG") diff --git a/include/types.h b/include/types.h index 475655cf..f2467ea0 100644 --- a/include/types.h +++ b/include/types.h @@ -32,7 +32,7 @@ struct Controller /*0x14*/ OSContStatus *statusData; /*0x18*/ OSContPad *controllerData; #if ENABLE_RUMBLE - /*0x1C*/ int port; + /*0x1C*/ s32 port; #endif }; @@ -49,12 +49,15 @@ typedef uintptr_t GeoLayout; typedef uintptr_t LevelScript; typedef s16 Movtex; typedef s16 MacroObject; -typedef s16 Collision; +typedef COLLISION_DATA_TYPE Collision; //Collision is by default an s16, but it's best to have it match the type of COLLISION_DATA_TYPE typedef s16 Trajectory; typedef s16 PaintingData; typedef uintptr_t BehaviorScript; typedef u8 Texture; typedef u16 ModelID; +typedef COLLISION_DATA_TYPE TerrainData; +typedef ROOM_DATA_TYPE RoomData; +typedef TerrainData Vec3t[3]; enum SpTaskState { SPTASK_STATE_NOT_STARTED, @@ -229,15 +232,15 @@ struct Waypoint struct Surface { - /*0x00*/ s16 type; - /*0x02*/ s16 force; + /*0x00*/ TerrainData type; + /*0x02*/ TerrainData force; /*0x04*/ s8 flags; - /*0x05*/ s8 room; + /*0x05*/ RoomData room; /*0x06*/ s16 lowerY; /*0x08*/ s16 upperY; - /*0x0A*/ Vec3s vertex1; - /*0x10*/ Vec3s vertex2; - /*0x16*/ Vec3s vertex3; + /*0x0A*/ Vec3t vertex1; + /*0x10*/ Vec3t vertex2; + /*0x16*/ Vec3t vertex3; /*0x1C*/ struct { f32 x; f32 y; @@ -263,27 +266,6 @@ struct MarioBodyState u8 padding[4]; }; -struct OffsetSizePair -{ - u32 offset; - u32 size; -}; - -struct MarioAnimDmaRelatedThing -{ - u32 count; - u8 *srcAddr; - struct OffsetSizePair anim[1]; // dynamic size -}; - -struct MarioAnimation -{ - struct MarioAnimDmaRelatedThing *animDmaTable; - u8 *currentAnimAddr; - struct Animation *targetAnim; - u8 padding[4]; -}; - struct MarioState { /*0x00*/ u16 unk00; @@ -329,7 +311,7 @@ struct MarioState /*0x94*/ struct PlayerCameraState *statusForCamera; /*0x98*/ struct MarioBodyState *marioBodyState; /*0x9C*/ struct Controller *controller; - /*0xA0*/ struct MarioAnimation *animation; + /*0xA0*/ struct DmaHandlerList *animList; /*0xA4*/ u32 collidedObjInteractTypes; /*0xA8*/ s16 numCoins; /*0xAA*/ s16 numStars; diff --git a/levels/bitfs/areas/1/3/model.inc.c b/levels/bitfs/areas/1/3/model.inc.c index 654e123e..5687c306 100644 --- a/levels/bitfs/areas/1/3/model.inc.c +++ b/levels/bitfs/areas/1/3/model.inc.c @@ -177,7 +177,7 @@ static const Vtx bitfs_seg7_vertex_07003340[] = { // TODO: what is this? // Possibly vertices for a perfect triangle, but flag seems to be used here. // 0x070033B0 - 0x070033E0 -static const s16 bitfs_seg7_todo_070033B0[] = { +UNUSED static const s16 bitfs_seg7_todo_070033B0[] = { 0x0080, 0x0100, 0x0000, 0x0000, 0x03de, 0x0000, 0xFFFF, 0xFFFF, 0xFF81, 0x0100, 0x0000, 0x0000, 0xFBE4, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07DA, 0xFFFF, 0xFFFF, diff --git a/levels/ending/geo.c b/levels/ending/geo.c index b8e2711a..867bebb5 100644 --- a/levels/ending/geo.c +++ b/levels/ending/geo.c @@ -21,7 +21,9 @@ const GeoLayout ending_geo_000050[] = { GEO_OPEN_NODE(), GEO_NODE_ORTHO(100), GEO_OPEN_NODE(), +#ifdef VERSION_EU GEO_BACKGROUND_COLOR(0x0001), +#endif GEO_ASM(0, geo_exec_cake_end_screen), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), diff --git a/levels/ending/header.h b/levels/ending/header.h index 2bf34c02..30bee900 100644 --- a/levels/ending/header.h +++ b/levels/ending/header.h @@ -8,9 +8,13 @@ extern const GeoLayout ending_geo_000050[]; // leveldata extern const Gfx dl_cake_end_screen[]; +#ifndef EU_CUSTOM_CAKE_FIX extern const Gfx dl_cake_end_screen_eu_070296F8[]; extern const Gfx dl_cake_end_screen_eu_07029768[]; extern const Gfx dl_cake_end_screen_eu_070297D8[]; +#else +extern const Gfx dl_cake_end_screen_eu_fix[]; +#endif extern const Gfx dl_cake_end_screen[]; // script diff --git a/levels/ending/leveldata.c b/levels/ending/leveldata.c index f28605e6..84b953f4 100644 --- a/levels/ending/leveldata.c +++ b/levels/ending/leveldata.c @@ -200,6 +200,7 @@ static const Gfx dl_cake_end_eu_070296D8[] = { gsSPEndDisplayList(), }; +#ifndef EU_CUSTOM_CAKE_FIX // 0x070296F8 - 0x07029768 const Gfx dl_cake_end_screen_eu_070296F8[] = { gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, cake_end_texture_eu_38), @@ -242,6 +243,13 @@ const Gfx dl_cake_end_screen_eu_070297D8[] = { gsSPEndDisplayList(), }; +#else +const Gfx dl_cake_end_screen_eu_fix[] = { + gsSPDisplayList(dl_cake_end_eu_070296D8), + gsSPEndDisplayList(), +}; +#endif + // VERSION_EU #else diff --git a/levels/entry.c b/levels/entry.c index 17c773ed..a7bc8209 100644 --- a/levels/entry.c +++ b/levels/entry.c @@ -7,11 +7,19 @@ #include "make_const_nonconst.h" +#include "config.h" + +extern const LevelScript level_main_scripts_entry[]; const LevelScript level_script_entry[] = { INIT_LEVEL(), SLEEP(/*frames*/ 2), BLACKOUT(/*active*/ FALSE), - SET_REG(/*value*/ 0), + #ifdef TEST_LEVEL + SET_REG(TEST_LEVEL), + EXECUTE(/*seg*/ 0x15, _scriptsSegmentRomStart, _scriptsSegmentRomEnd, level_main_scripts_entry), + #else + SET_REG(0), EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_splash_screen), + #endif JUMP(/*target*/ level_script_entry), -}; +}; \ No newline at end of file diff --git a/levels/intro/script.c b/levels/intro/script.c index e0109bed..4fe236fb 100644 --- a/levels/intro/script.c +++ b/levels/intro/script.c @@ -8,7 +8,7 @@ #include "game/area.h" #include "game/level_update.h" -#include "menu/level_select_menu.h" +#include "menu/title_screen.h" #include "levels/scripts.h" #include "levels/menu/header.h" @@ -17,13 +17,15 @@ #include "make_const_nonconst.h" #include "levels/intro/header.h" +#include "farcall.h" #include "config.h" +#include "game/print.h" const LevelScript level_intro_splash_screen[] = { INIT_LEVEL(), #ifdef SKIP_TITLE_SCREEN - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_regular), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_regular, _introSegmentBssStart, _introSegmentBssEnd), #endif FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd), LOAD_RAW(/*seg*/ 0x13, _behaviorSegmentRomStart, _behaviorSegmentRomEnd), @@ -38,14 +40,14 @@ const LevelScript level_intro_splash_screen[] = { // Start animation LOAD_AREA(/*area*/ 1), - CALL(/*arg*/ 0, /*func*/ lvl_intro_update), + CALL(/*arg*/ LVL_INTRO_PLAY_ITS_A_ME_MARIO, /*func*/ lvl_intro_update), SLEEP(/*frames*/ 75), TRANSITION(/*transType*/ WARP_TRANSITION_FADE_INTO_COLOR, /*time*/ 16, /*color*/ 0x00, 0x00, 0x00), SLEEP(/*frames*/ 16), CMD2A(/*unk2*/ 1), CLEAR_LEVEL(), SLEEP(/*frames*/ 2), - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_regular), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_regular, _introSegmentBssStart, _introSegmentBssEnd), }; const LevelScript level_intro_mario_head_regular[] = { @@ -69,10 +71,10 @@ const LevelScript level_intro_mario_head_regular[] = { SLEEP(/*frames*/ 2), BLACKOUT(/*active*/ FALSE), LOAD_AREA(/*area*/ 1), - SET_MENU_MUSIC(/*seq*/ 0x0002), + SET_MENU_MUSIC(/*seq*/ SEQ_MENU_TITLE_SCREEN), TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_STAR, /*time*/ 20, /*color*/ 0x00, 0x00, 0x00), SLEEP(/*frames*/ 20), - CALL_LOOP(/*arg*/ 1, /*func*/ lvl_intro_update), + CALL_LOOP(/*arg*/ LVL_INTRO_REGULAR, /*func*/ lvl_intro_update), JUMP_IF(/*op*/ OP_EQ, /*arg*/ 100, script_intro_L1), JUMP_IF(/*op*/ OP_EQ, /*arg*/ 101, script_intro_L2), JUMP(script_intro_L4), @@ -96,10 +98,10 @@ const LevelScript level_intro_mario_head_dizzy[] = { SLEEP(/*frames*/ 2), BLACKOUT(/*active*/ FALSE), LOAD_AREA(/*area*/ 1), - SET_MENU_MUSIC(/*seq*/ 0x0082), + SET_MENU_MUSIC(/*seq*/ SEQ_MENU_GAME_OVER), TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_STAR, /*time*/ 20, /*color*/ 0x00, 0x00, 0x00), SLEEP(/*frames*/ 20), - CALL_LOOP(/*arg*/ 2, /*func*/ lvl_intro_update), + CALL_LOOP(/*arg*/ LVL_INTRO_GAME_OVER, /*func*/ lvl_intro_update), JUMP_IF(/*op*/ OP_EQ, /*arg*/ 100, script_intro_L1), JUMP_IF(/*op*/ OP_EQ, /*arg*/ 101, script_intro_L2), JUMP(script_intro_L4), @@ -118,10 +120,10 @@ const LevelScript level_intro_entry_4[] = { FREE_LEVEL_POOL(), LOAD_AREA(/*area*/ 1), - SET_MENU_MUSIC(/*seq*/ 0x0002), + SET_MENU_MUSIC(/*seq*/ SEQ_MENU_TITLE_SCREEN), TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF), SLEEP(/*frames*/ 16), - CALL_LOOP(/*arg*/ 3, /*func*/ lvl_intro_update), + CALL_LOOP(/*arg*/ LVL_INTRO_LEVEL_SELECT, /*func*/ lvl_intro_update), JUMP_IF(/*op*/ OP_EQ, /*arg*/ -1, script_intro_L5), JUMP(script_intro_L3), }; @@ -143,7 +145,7 @@ const LevelScript script_intro_L2[] = { SLEEP(/*frames*/ 16), CLEAR_LEVEL(), SLEEP(/*frames*/ 2), - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_entry_4), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_entry_4, _introSegmentBssStart, _introSegmentBssEnd), }; const LevelScript script_intro_L3[] = { @@ -169,5 +171,5 @@ const LevelScript script_intro_L5[] = { SLEEP(/*frames*/ 16), CLEAR_LEVEL(), SLEEP(/*frames*/ 2), - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_splash_screen), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_splash_screen, _introSegmentBssStart, _introSegmentBssEnd), }; diff --git a/levels/lll/texture.inc.c b/levels/lll/texture.inc.c index 67ed21cd..8d7e49f5 100644 --- a/levels/lll/texture.inc.c +++ b/levels/lll/texture.inc.c @@ -14,7 +14,7 @@ ALIGNED8 static const Texture lll_seg7_texture_07001000[] = { }; // 0x07001800 - 0x07002000 -ALIGNED8 static const Texture lll_seg7_texture_07001800[] = { +UNUSED ALIGNED8 static const Texture lll_seg7_texture_07001800[] = { #include "levels/lll/3.rgba16.inc.c" }; @@ -34,7 +34,7 @@ ALIGNED8 static const Texture lll_seg7_texture_07003000[] = { }; // 0x07003800 - 0x07004000 -ALIGNED8 static const Texture lll_seg7_texture_07003800[] = { +UNUSED ALIGNED8 static const Texture lll_seg7_texture_07003800[] = { #include "levels/lll/7.rgba16.inc.c" }; diff --git a/levels/menu/script.c b/levels/menu/script.c index 00d8d957..5360dea5 100644 --- a/levels/menu/script.c +++ b/levels/menu/script.c @@ -43,7 +43,7 @@ const LevelScript level_main_menu_entry_1[] = { FREE_LEVEL_POOL(), LOAD_AREA(/*area*/ 1), - SET_MENU_MUSIC(/*seq*/ 0x0021), + SET_MENU_MUSIC(/*seq*/ SEQ_MENU_FILE_SELECT), TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF), CALL(/*arg*/ 0, /*func*/ lvl_init_menu_values_and_cursor_pos), CALL_LOOP(/*arg*/ 0, /*func*/ lvl_update_obj_and_load_file_selected), diff --git a/levels/scripts.c b/levels/scripts.c index 8e30e0f8..48c7c2e1 100644 --- a/levels/scripts.c +++ b/levels/scripts.c @@ -44,14 +44,14 @@ static const LevelScript script_exec_level_table[2 #undef DEFINE_LEVEL #undef STUB_LEVEL -static const LevelScript script_L1[4]; -static const LevelScript script_L2[4]; -static const LevelScript goto_mario_head_regular[4]; -static const LevelScript goto_mario_head_dizzy[4]; -static const LevelScript script_L5[4]; +static const LevelScript script_L1[6]; +static const LevelScript script_L2[6]; +static const LevelScript goto_mario_head_regular[6]; +static const LevelScript goto_mario_head_dizzy[6]; +static const LevelScript script_L5[6]; #define STUB_LEVEL(_0, _1, _2, _3, _4, _5, _6, _7, _8) -#define DEFINE_LEVEL(_0, _1, _2, folder, _4, _5, _6, _7, _8, _9, _10) static const LevelScript script_exec_ ## folder [4 + 1]; +#define DEFINE_LEVEL(_0, _1, _2, folder, _4, _5, _6, _7, _8, _9, _10) static const LevelScript script_exec_ ## folder [6 + 1]; #include "level_defines.h" @@ -61,9 +61,9 @@ static const LevelScript script_L5[4]; const LevelScript level_main_scripts_entry[] = { LOAD_YAY0(/*seg*/ 0x04, _group0_yay0SegmentRomStart, _group0_yay0SegmentRomEnd), LOAD_YAY0(/*seg*/ 0x03, _common1_yay0SegmentRomStart, _common1_yay0SegmentRomEnd), - LOAD_RAW( /*seg*/ 0x17, _group0_geoSegmentRomStart, _group0_geoSegmentRomEnd), - LOAD_RAW( /*seg*/ 0x16, _common1_geoSegmentRomStart, _common1_geoSegmentRomEnd), - LOAD_RAW( /*seg*/ 0x13, _behaviorSegmentRomStart, _behaviorSegmentRomEnd), + LOAD_RAW_WITH_CODE( /*seg*/ 0x17, _group0_geoSegmentRomStart, _group0_geoSegmentRomEnd, _group0_geoSegmentBssStart, _group0_geoSegmentBssEnd), + LOAD_RAW_WITH_CODE( /*seg*/ 0x16, _common1_geoSegmentRomStart, _common1_geoSegmentRomEnd, _common1_geoSegmentBssStart, _common1_geoSegmentBssEnd), + LOAD_RAW_WITH_CODE( /*seg*/ 0x13, _behaviorSegmentRomStart, _behaviorSegmentRomEnd, _behaviorSegmentBssStart, _behaviorSegmentBssEnd), ALLOC_LEVEL_POOL(), LOAD_MODEL_FROM_GEO(MODEL_MARIO, mario_geo), LOAD_MODEL_FROM_GEO(MODEL_SMOKE, smoke_geo), @@ -127,23 +127,23 @@ const LevelScript level_main_scripts_entry[] = { }; static const LevelScript script_L1[] = { - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_splash_screen), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_splash_screen, _introSegmentBssStart, _introSegmentBssEnd), }; static const LevelScript script_L2[] = { - EXIT_AND_EXECUTE(/*seg*/ 0x0E, _endingSegmentRomStart, _endingSegmentRomEnd, level_ending_entry), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x0E, _endingSegmentRomStart, _endingSegmentRomEnd, level_ending_entry, _endingSegmentBssStart, _endingSegmentBssEnd), }; static const LevelScript goto_mario_head_regular[] = { - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_regular), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_regular, _introSegmentBssStart, _introSegmentBssEnd), }; static const LevelScript goto_mario_head_dizzy[] = { - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_dizzy), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_dizzy, _introSegmentBssStart, _introSegmentBssEnd), }; static const LevelScript script_L5[] = { - EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_entry_4), + EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_entry_4, _introSegmentBssStart, _introSegmentBssEnd), }; // Include the level jumptable. @@ -161,7 +161,7 @@ static const LevelScript script_exec_level_table[] = { #define DEFINE_LEVEL(_0, _1, _2, folder, _4, _5, _6, _7, _8, _9, _10) \ static const LevelScript script_exec_ ## folder [] = { \ - EXECUTE(0x0E, _ ## folder ## SegmentRomStart, _ ## folder ## SegmentRomEnd, level_ ## folder ## _entry), \ + EXECUTE_WITH_CODE(0x0E, _ ## folder ## SegmentRomStart, _ ## folder ## SegmentRomEnd, level_ ## folder ## _entry, _ ## folder ## SegmentBssStart, _ ## folder ## SegmentBssEnd), \ RETURN(), \ }; @@ -171,7 +171,7 @@ static const LevelScript script_exec_ ## folder [] = { \ const LevelScript script_func_global_1[] = { LOAD_MODEL_FROM_GEO(MODEL_BLUE_COIN_SWITCH, blue_coin_switch_geo), - LOAD_MODEL_FROM_GEO(MODEL_AMP, amp_geo), + LOAD_MODEL_FROM_GEO(MODEL_AMP, dAmpGeo), LOAD_MODEL_FROM_GEO(MODEL_PURPLE_SWITCH, purple_switch_geo), LOAD_MODEL_FROM_GEO(MODEL_CHECKERBOARD_PLATFORM, checkerboard_platform_geo), LOAD_MODEL_FROM_GEO(MODEL_BREAKABLE_BOX, breakable_box_geo), @@ -297,7 +297,7 @@ const LevelScript script_func_global_13[] = { LOAD_MODEL_FROM_GEO(MODEL_BOWSER_SMOKE, bowser_impact_smoke_geo), LOAD_MODEL_FROM_GEO(MODEL_BOWSER_FLAMES, bowser_flames_geo), LOAD_MODEL_FROM_GEO(MODEL_BOWSER_WAVE, invisible_bowser_accessory_geo), - LOAD_MODEL_FROM_GEO(MODEL_BOWSER2, bowser2_geo), + LOAD_MODEL_FROM_GEO(MODEL_BOWSER_NO_SHADOW, bowser_geo_no_shadow), RETURN(), }; diff --git a/levels/scripts.h b/levels/scripts.h index 24bdec37..dc019682 100644 --- a/levels/scripts.h +++ b/levels/scripts.h @@ -2,6 +2,7 @@ #define SCRIPTS_H #include "types.h" +#include "game/puppycam2.h" // scripts extern const LevelScript level_main_scripts_entry[]; diff --git a/levels/ssl/texture.inc.c b/levels/ssl/texture.inc.c index 032ca1ea..d3ca223d 100644 --- a/levels/ssl/texture.inc.c +++ b/levels/ssl/texture.inc.c @@ -19,7 +19,7 @@ ALIGNED8 static const Texture ssl_seg7_texture_07001800[] = { }; // 0x07002000 - 0x07002800 -ALIGNED8 static const Texture ssl_seg7_texture_07002000[] = { +UNUSED ALIGNED8 static const Texture ssl_seg7_texture_07002000[] = { #include "levels/ssl/4.rgba16.inc.c" }; diff --git a/mio0rules.mk b/mio0rules.mk index 123c3c0b..3bbe04bc 100644 --- a/mio0rules.mk +++ b/mio0rules.mk @@ -6,4 +6,4 @@ $(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin # convert binary szp to object file $(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp $(call print,Converting MIO0 to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file + $(V)$(LD) -r -b binary $< -o $@ \ No newline at end of file diff --git a/rename_sym.sh b/rename_sym.sh index 326dcb2e..639105b6 100755 --- a/rename_sym.sh +++ b/rename_sym.sh @@ -10,4 +10,4 @@ fi #echo "Replace $1 with $2?" #read -grep -rl "$1" text/**/*.{c,h} assets/**/*.c enhancements/*.patch lib/**/*.{c,h,s} asm/**/*.s bin/**/*.c data/*.c levels/**/*.{c,h} actors/**/*.c src/**/*.{c,h} include/**/*.{h,in} undefined_syms.txt | xargs sed -i "s/\b$1\b/$2/g" +grep -rl "$1" text/**/*.{c,h} assets/**/*.c enhancements/*.patch lib/**/*.{c,h,s} asm/**/*.s bin/**/*.c data/*.c levels/**/*.{c,h} actors/**/*.{c,h} src/**/*.{c,h} include/**/*.{h,in} undefined_syms.txt | xargs sed -i "s/\b$1\b/$2/g" diff --git a/rnc1rules.mk b/rnc1rules.mk index 293d46b5..a05dd8c3 100644 --- a/rnc1rules.mk +++ b/rnc1rules.mk @@ -6,4 +6,4 @@ $(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin # convert binary szp to object file $(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp $(call print,Converting RNC1 to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file + $(V)$(LD) -r -b binary $< -o $@ \ No newline at end of file diff --git a/rnc2rules.mk b/rnc2rules.mk index 88738c2b..d1fd05af 100644 --- a/rnc2rules.mk +++ b/rnc2rules.mk @@ -6,4 +6,4 @@ $(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin # convert binary szp to object file $(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp $(call print,Converting RNC2 to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file + $(V)$(LD) -r -b binary $< -o $@ \ No newline at end of file diff --git a/rsp/audio.s b/rsp/audio.s index b10e8dbd..901a7d0d 100644 --- a/rsp/audio.s +++ b/rsp/audio.s @@ -53,15 +53,15 @@ dispatchTable: jumpTableEntry cmd_SPNOOP jumpTableEntry cmd_SETLOOP - jumpTableEntry cmd_17e4 - jumpTableEntry cmd_INTERL + jumpTableEntry cmd_DMEMMOVE2 + jumpTableEntry cmd_DOWNSAMPLE_HALF jumpTableEntry cmd_ENVSETUP1 jumpTableEntry cmd_ENVMIXER jumpTableEntry cmd_LOADBUFF jumpTableEntry cmd_SAVEBUFF jumpTableEntry cmd_ENVSETUP2 - jumpTableEntry cmd_1b78 + jumpTableEntry cmd_S8DEC jumpTableEntry cmd_HILOGAIN jumpTableEntry cmd_1c7c @@ -938,12 +938,12 @@ cmd_RESAMPLE: .endif addi $8, $8, -8 .ifdef VERSION_SH - sdv $v16[0], 0x00($8) + sdv $v16[0], 0x00($8) .endif @@audio_c410c: lsv $v23[14], 0x08($23) // saved pitch_accumulator .ifdef VERSION_SH - ldv $v16[0], 0x00($8) + ldv $v16[0], 0x00($8) .else ldv $v16[0], 0x00($23) // saved next 4 unprocessed samples sdv $v16[0], 0x00($8) // store them before the input samples @@ -1100,8 +1100,8 @@ cmd_RESAMPLE: mtc0 $zero, SP_SEMAPHORE .ifdef VERSION_SH -cmd_17e4: - srl $t7, $k0, 16 +cmd_DMEMMOVE2: + srl $t7, $k0, 16 andi $t7, $t7, 0xff andi $t5, $k0, 0xffff srl $t6, $t9, 0x10 @@ -1150,7 +1150,7 @@ cmd_DUPLICATE: j cmd_SPNOOP nop -cmd_INTERL: +cmd_DOWNSAMPLE_HALF: andi $t4, $k0, 0xffff andi $t6, $t9, 0xffff srl $t5, $t9, 0x10 @@ -1606,24 +1606,24 @@ cmd_MIXER: j cmd_SPNOOP nop -cmd_1b78: - lhu $13, 0x0(r24) +cmd_S8DEC: + lhu $13, (audio_in_buf)(r24) vxor $v2, $v2, $v2 - lhu $14, 0x2(r24) + lhu $14, (audio_out_buf)(r24) vxor $v3, $v3, $v3 - lhu $12, 0x4(r24) + lhu $12, (audio_count)(r24) sll $17, $25, 8 - srl $17, $17, 8 - sqv $v2[0], 0x0(r14) + srl $17, $17, 8 // state addr + sqv $v2[0], 0x0(r14) // store 0 to first 16 samples if A_INIT sqv $v3[0], 0x10(r14) srl $1, $26, 16 andi $1, $1, 0x1 - bgtz $1, @audio_4001bd8 + bgtz $1, @audio_4001bd8 // A_INIT srl $1, $26, 16 andi $1, $1, 0x2 - beq $0, $1, @audio_4001bbc + beq $0, $1, @audio_4001bbc // A_LOOP addi $2, $17, 0x0 - lw $2, 0x10(r24) + lw $2, (audio_loop_value)(r24) @audio_4001bbc: addi $1, $14, 0x0 jal dma_read_start @@ -1635,10 +1635,10 @@ cmd_1b78: mtc0 $0, sp_semaphore @audio_4001bd8: addi $14, $14, 0x20 - beq $12, $0, @audio_4001c04 + beq $12, $0, @audio_4001c04 // this of very few ops allows count=0 nop @audio_4001be4: - lpv $v2[0], 0x0(r13) + lpv $v2[0], 0x0(r13) // load each byte to upper 8 bits per elem lpv $v3[0], 0x8(r13) addi $13, $13, 0x10 addi $12, $12, 0xffe0 @@ -1647,7 +1647,7 @@ cmd_1b78: bgtz $12, @audio_4001be4 addi $14, $14, 0x20 @audio_4001c04: - addi $1, $14, 0xffe0 + addi $1, $14, 0xffe0 // write last 16 samples to the state addi $2, $17, 0x0 jal dma_write_start addi $3, $0, 0x1f diff --git a/sm64.ld b/sm64.ld index c3c8da76..01d6292b 100755 --- a/sm64.ld +++ b/sm64.ld @@ -52,10 +52,20 @@ OUTPUT_ARCH (mips) END_SEG(name##_segment_7) \ BEGIN_SEG(name, 0x0E000000) \ { \ - KEEP(BUILD_DIR/levels/name/script.o(.data)); \ - KEEP(BUILD_DIR/levels/name/geo.o(.data)); \ + KEEP(BUILD_DIR/levels/name/script.o(.*data*)); \ + KEEP(BUILD_DIR/levels/name/script.o(.text)); \ + KEEP(BUILD_DIR/levels/name/script.o(.rodata*)); \ + KEEP(BUILD_DIR/levels/name/geo.o(.*data*)); \ + KEEP(BUILD_DIR/levels/name/geo.o(.text)); \ + KEEP(BUILD_DIR/levels/name/geo.o(.rodata*)); \ } \ - END_SEG(name) + END_SEG(name) \ + BEGIN_NOLOAD(name) \ + { \ + KEEP(BUILD_DIR/levels/name/script.o(.bss*)); \ + KEEP(BUILD_DIR/levels/name/geo.o(.bss*)); \ + } \ + END_NOLOAD(name) #define STANDARD_OBJECTS(name, segAddr, geoAddr) \ BEGIN_SEG(name##_yay0, segAddr) \ @@ -66,9 +76,16 @@ OUTPUT_ARCH (mips) END_SEG(name##_yay0) \ BEGIN_SEG(name##_geo, geoAddr) \ { \ - KEEP(BUILD_DIR/actors/name##_geo.o(.data)); \ + KEEP(BUILD_DIR/actors/name##_geo.o(.*data*)); \ + KEEP(BUILD_DIR/actors/name##_geo.o(.rodata*)); \ + KEEP(BUILD_DIR/actors/name##_geo.o(.text)); \ } \ END_SEG(name##_geo) \ + BEGIN_NOLOAD(name##_geo) \ + { \ + KEEP(BUILD_DIR/actors/name##_geo.o(.bss*)); \ + } \ + END_NOLOAD(name##_geo) \ _##name##_mio0SegmentRomStart = _##name##_yay0SegmentRomStart; \ _##name##_mio0SegmentRomEnd = _##name##_yay0SegmentRomEnd; @@ -131,9 +148,8 @@ SECTIONS { KEEP(BUILD_DIR/asm/entry.o(.text)); - BUILD_DIR/src/game*.o(.text); + BUILD_DIR/src/boot*.o(.text); BUILD_DIR/src/hvqm*.o(.text); - BUILD_DIR/src/gdb*.o(.text); BUILD_DIR/src/usb*.o(.text); BUILD_DIR/src/audio*.o(.text); #ifdef S2DEX_TEXT_ENGINE @@ -152,8 +168,7 @@ SECTIONS lib/PR/hvqm/hvqm2sp1.o(.text); /* data */ - BUILD_DIR/src/game*.o(.*data*); - BUILD_DIR/src/gdb*.o(.*data*); + BUILD_DIR/src/boot*.o(.*data*); BUILD_DIR/src/usb*.o(.*data*); BUILD_DIR/src/audio*.o(.*data*); #ifdef S2DEX_TEXT_ENGINE @@ -171,8 +186,7 @@ SECTIONS lib/PR/hvqm/hvqm2sp1.o(.data*); /* rodata */ - BUILD_DIR/src/game*.o(.rodata*); - BUILD_DIR/src/gdb*.o(.*rodata*); + BUILD_DIR/src/boot*.o(.rodata*); BUILD_DIR/src/usb*.o(.rodata*); BUILD_DIR/src/audio*.o(.rodata*); #ifdef S2DEX_TEXT_ENGINE @@ -190,11 +204,13 @@ SECTIONS lib/PR/hvqm/hvqm2sp1.o(.rodata*); } END_SEG(main) + #ifndef PRELIMINARY + ASSERT((_mainSegmentRomEnd <= 0x101000), "Error: Please shrink your main segment to under 1MB.") + #endif BEGIN_NOLOAD(main) { - BUILD_DIR/src/game*.o(.*bss*); + BUILD_DIR/src/boot*.o(.*bss*); BUILD_DIR/src/hvqm*.o(.*bss*); - BUILD_DIR/src/gdb*.o(.*bss*); BUILD_DIR/src/usb*.o(.*bss*); BUILD_DIR/src/audio*.o(.*bss*); #ifdef S2DEX_TEXT_ENGINE @@ -215,29 +231,29 @@ SECTIONS } END_NOLOAD(main) - /*ASSERT((. <= SEG_ENGINE), "Error: main segment extended into engine.")*/ - . = _mainSegmentBssEnd; BEGIN_SEG(engine, .) { + BUILD_DIR/src/game*.o(.text); BUILD_DIR/src/engine*.o(.text); /* data */ + BUILD_DIR/src/game*.o(.*data*); BUILD_DIR/src/engine*.o(.data*); BUILD_DIR/src/engine*.o(.sdata*); /* rodata */ + BUILD_DIR/src/game*.o(.rodata*); BUILD_DIR/src/engine*.o(.rodata*); } END_SEG(engine) BEGIN_NOLOAD(engine) { + BUILD_DIR/src/game*.o(.*bss*); BUILD_DIR/src/engine*.o(.bss*); . = ALIGN(0x40); } END_NOLOAD(engine) - /*ASSERT((. <= SEG_FRAMEBUFFERS), "Error: engine segment extended into framebuffers.")*/ - . = _engineSegmentBssEnd; BEGIN_NOLOAD(framebuffers) { @@ -250,10 +266,11 @@ SECTIONS __expansionRamStart = 0x80400000; #ifndef USE_EXT_RAM - ASSERT((. <= __expansionRamStart), "Error: RDRAM expanded into Expansion RAM, despite Expansion RAM not being defined.") + #ifndef PRELIMINARY + ASSERT((. <= __expansionRamStart), "Error: RDRAM expanded into Expansion RAM, despite Expansion RAM not being defined.") + #endif #endif - BEGIN_SEG(entry, 0x10000000) { BUILD_DIR/levels/entry.o(.data); @@ -297,65 +314,84 @@ SECTIONS /* use segmented addressing for behaviors */ BEGIN_SEG(behavior, 0x13000000) { - KEEP(BUILD_DIR/data/behavior_data.o(.data)); + KEEP(BUILD_DIR/data/behavior_data.o(.data*)); + KEEP(BUILD_DIR/data/behavior_data.o(.rodata*)); + KEEP(BUILD_DIR/data/behavior_data.o(.text)); } END_SEG(behavior) + BEGIN_NOLOAD(behavior) + { + KEEP(BUILD_DIR/data/behavior_data.o(.bss*)); + } + END_NOLOAD(behavior) + /* 0x8016F000 21D7D0-255EC0 [386F0] */ - BEGIN_SEG(goddard, SEG_GODDARD) + BEGIN_SEG(goddard, RAM_END - GODDARD_SIZE) { - BUILD_DIR/src/menu*.o(.text); - BUILD_DIR/src/menu*.o(.data*); - BUILD_DIR/src/menu*.o(.rodata*); -#ifdef KEEP_MARIO_HEAD - BUILD_DIR/libgoddard.a:*.o(.text); - /* goddard subsystem data */ - BUILD_DIR/libgoddard.a:gd_main.o(.data*); - BUILD_DIR/libgoddard.a:draw_objects.o(.data*); - BUILD_DIR/libgoddard.a:objects.o(.data*); - BUILD_DIR/libgoddard.a:particles.o(.data*); - BUILD_DIR/libgoddard.a:dynlist_proc.o(.data*); - BUILD_DIR/libgoddard.a:debug_utils.o(.data*); - BUILD_DIR/libgoddard.a:joints.o(.data*); - BUILD_DIR/libgoddard.a:shape_helper.o(.data*); - BUILD_DIR/libgoddard.a:renderer.o(.data*); - /* goddard subsystem rodata */ - BUILD_DIR/libgoddard.a:gd_main.o(.rodata*); - BUILD_DIR/libgoddard.a:gd_memory.o(.rodata*); - BUILD_DIR/libgoddard.a:draw_objects.o(.rodata*); - BUILD_DIR/libgoddard.a:objects.o(.rodata*); - BUILD_DIR/libgoddard.a:skin_movement.o(.rodata*); - BUILD_DIR/libgoddard.a:particles.o(.rodata*); - BUILD_DIR/libgoddard.a:dynlist_proc.o(.rodata*); - BUILD_DIR/libgoddard.a:old_menu.o(.rodata*); - BUILD_DIR/libgoddard.a:debug_utils.o(.rodata*); - BUILD_DIR/libgoddard.a:joints.o(.rodata*); - BUILD_DIR/libgoddard.a:skin.o(.rodata*); - BUILD_DIR/libgoddard.a:gd_math.o(.rodata*); - BUILD_DIR/libgoddard.a:shape_helper.o(.rodata*); - BUILD_DIR/libgoddard.a:renderer.o(.rodata*); -#endif + KEEP(BUILD_DIR/src/menu*.o(.text)); + KEEP(BUILD_DIR/src/menu*.o(.data*)); + KEEP(BUILD_DIR/src/menu*.o(.rodata*)); + #ifdef KEEP_MARIO_HEAD + KEEP(BUILD_DIR/libgoddard.a:*.o(.text)); + KEEP(BUILD_DIR/libgoddard.a:gd_main.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:draw_objects.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:objects.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:particles.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:dynlist_proc.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:debug_utils.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:joints.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:shape_helper.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:renderer.o(.data*)); + KEEP(BUILD_DIR/libgoddard.a:gd_main.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:gd_memory.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:draw_objects.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:objects.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:skin_movement.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:particles.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:dynlist_proc.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:old_menu.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:debug_utils.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:joints.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:skin.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:gd_math.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:shape_helper.o(.rodata*)); + KEEP(BUILD_DIR/libgoddard.a:renderer.o(.rodata*)); + #endif + . = ALIGN(16); } END_SEG(goddard) BEGIN_NOLOAD(goddard) { - BUILD_DIR/src/menu*.o(.bss*); -#ifdef KEEP_MARIO_HEAD - BUILD_DIR/libgoddard.a:*.o(.bss*); -#endif + KEEP(BUILD_DIR/src/menu*.o(.bss*)); + #ifdef KEEP_MARIO_HEAD + KEEP(BUILD_DIR/libgoddard.a:*.o(.bss*)); + #endif + . = ALIGN(16); } END_NOLOAD(goddard) - ASSERT((. <= (SEG_POOL_START + POOL_SIZE)), "Error: extended past pool end.") - + #ifndef PRELIMINARY + ASSERT((. <= (SEG_POOL_START + POOL_SIZE)), "Error: extended past pool end.") + #endif + #ifdef PRELIMINARY + GODDARD_SIZE = SIZEOF(.goddard) + SIZEOF(.goddard.noload); + #endif /* 0x268020 0x268020-0 [0] */ BEGIN_SEG(intro, 0x14000000) { - KEEP(BUILD_DIR/levels/intro/script.o(.data)); + KEEP(BUILD_DIR/levels/intro/script.o(.*data)); + KEEP(BUILD_DIR/levels/intro/script.o(.rodata*)); + KEEP(BUILD_DIR/levels/intro/script.o(.text)); KEEP(BUILD_DIR/levels/intro/geo.o(.data)); } END_SEG(intro) + BEGIN_NOLOAD(intro) + { + KEEP(BUILD_DIR/levels/intro/script.o(.bss*)); + } + END_NOLOAD(intro) BEGIN_SEG(intro_segment_7, 0x07000000) { KEEP(BUILD_DIR/levels/intro/leveldata.szp.o(.data)); diff --git a/sound/sequences/00_sound_player.s b/sound/sequences/00_sound_player.s index 68502f9c..1d1e0173 100644 --- a/sound/sequences/00_sound_player.s +++ b/sound/sequences/00_sound_player.s @@ -1,22 +1,16 @@ -.include "seq_macros.inc" +#include "seq_macros.inc" + .section .rodata .align 0 + sequence_start: - -.ifdef VERSION_SH - .set VERSION_EU_SH, 1 -.endif -.ifdef VERSION_EU - .set VERSION_EU_SH, 1 -.endif - seq_setmutebhv 0x60 seq_setmutescale 0 -.ifdef VERSION_SH +#ifdef VERSION_SH seq_setvol 100 -.else +#else seq_setvol 127 -.endif +#endif seq_settempo 120 seq_initchannels 0x3ff seq_startchannel 0, .channel0 @@ -77,7 +71,7 @@ chan_stereoheadseteffects 1 chan_setdyntable .channel59_table chan_jump .main_loop_023589 -# Main loop for standard, non-continuous sound effects +// Main loop for standard, non-continuous sound effects .main_loop_023589: chan_delay1 chan_ioreadval 0 @@ -91,17 +85,17 @@ chan_iowriteval 5 chan_ioreadval 4 chan_dyncall -# keep looping until layer 0 finishes or we are told to stop or to play something else +// keep looping until layer 0 finishes or we are told to stop or to play something else .poll_023589: chan_delay1 chan_ioreadval 0 -chan_bltz .skip_023589 # if we have a signal: - chan_beqz .force_stop_023589 # told to stop - chan_jump .start_playing_023589 # told to play something else +chan_bltz .skip_023589 // if we have a signal: + chan_beqz .force_stop_023589 // told to stop + chan_jump .start_playing_023589 // told to play something else .skip_023589: chan_testlayerfinished 0 -chan_beqz .poll_023589 # if layer 0 hasn't finished, keep polling -chan_jump .main_loop_023589 # otherwise go back to the main loop +chan_beqz .poll_023589 // if layer 0 hasn't finished, keep polling +chan_jump .main_loop_023589 // otherwise go back to the main loop .force_stop_023589: chan_freelayer 0 chan_freelayer 1 @@ -144,7 +138,7 @@ chan_stereoheadseteffects 1 chan_setdyntable .channel6_table chan_jump .main_loop_146 -# Main loop for moving, env and air sound effects, which play continuously +// Main loop for moving, env and air sound effects, which play continuously .main_loop_146: chan_delay1 chan_ioreadval 0 @@ -159,7 +153,7 @@ chan_iowriteval 5 chan_ioreadval 4 chan_dyncall -# keep looping until we are told to stop or to play something else +// keep looping until we are told to stop or to play something else .poll_146: chan_delay1 chan_ioreadval 0 @@ -181,7 +175,7 @@ chan_iowriteval 5 chan_stereoheadseteffects 1 chan_setdyntable .channel7_table -# Loop for menu sound effects +// Loop for menu sound effects .main_loop_7: chan_delay1 chan_ioreadval 0 @@ -198,19 +192,19 @@ chan_setpanmix 127 chan_ioreadval 4 chan_dyncall -# keep looping until layer 0 finishes or we are told to stop or to play something else +// keep looping until layer 0 finishes or we are told to stop or to play something else .poll_7: chan_delay1 chan_ioreadval 0 -chan_bltz .skip_7 # if we have a signal: - chan_beqz .force_stop_7 # told to stop +chan_bltz .skip_7 // if we have a signal: + chan_beqz .force_stop_7 // told to stop chan_unreservenotes - chan_jump .start_playing_7 # told to play something else + chan_jump .start_playing_7 // told to play something else .skip_7: chan_testlayerfinished 0 -chan_beqz .poll_7 # if layer 0 hasn't finished, keep polling +chan_beqz .poll_7 // if layer 0 hasn't finished, keep polling chan_unreservenotes -chan_jump .main_loop_7 # otherwise go back to the main loop +chan_jump .main_loop_7 // otherwise go back to the main loop .force_stop_7: chan_freelayer 0 chan_freelayer 1 @@ -218,7 +212,7 @@ chan_freelayer 2 chan_unreservenotes chan_jump .main_loop_7 -# Delay for a number of ticks (1-255) in an interruptible manner. +// Delay for a number of ticks (1-255) in an interruptible manner. .delay: chan_writeseq_nextinstr 0, 1 chan_loop 20 @@ -233,15 +227,15 @@ chan_end chan_setpanmix 127 chan_setvolscale 127 chan_setvibratoextent 0 -chan_ioreadval 1 # IO slots 0-3 are reset to -1 when read; restore the value +chan_ioreadval 1 // IO slots 0-3 are reset to -1 when read; restore the value chan_iowriteval 0 -chan_break # break out of the loop -chan_break # force the caller to return immediately +chan_break // break out of the loop +chan_break // force the caller to return immediately chan_end -# Set reverb in way that takes area echo level and volume into account. This -# is done by writing to IO slot 5 and letting get_sound_reverb in external.c -# do the necessary math. +// Set reverb in way that takes area echo level and volume into account. This +// is done by writing to IO slot 5 and letting get_sound_reverb in external.c +// do the necessary math. .set_reverb: chan_writeseq_nextinstr 0, 1 chan_setreverb 10 @@ -342,15 +336,15 @@ sound_ref .sound_action_bounce_off_object sound_ref .chan_7ED sound_ref .sound_action_read_sign sound_ref .chan_810 -.ifdef VERSION_JP +#ifdef VERSION_JP sound_ref .sound_action_jump_default sound_ref .sound_action_jump_default sound_ref .sound_action_jump_default -.else +#else sound_ref .chan_828 sound_ref .sound_action_intro_unk45e sound_ref .sound_action_intro_unk45f -.endif +#endif sound_ref .sound_action_heavy_landing_default sound_ref .sound_action_heavy_landing_grass sound_ref .sound_action_heavy_landing_water @@ -988,7 +982,7 @@ layer_portamento 0x81, 42, 255 layer_note1 37, 0x1e, 105 layer_end -.sound_action_climb_down_tree: # unused +.sound_action_climb_down_tree: // unused chan_setbank 0 chan_setinstr 1 chan_setlayer 0, .layer_579 @@ -999,7 +993,7 @@ layer_portamento 0x81, 44, 255 layer_note1 40, 0xb4, 100 layer_end -.chan_582: # unused +.chan_582: // unused chan_setbank 0 chan_setinstr 2 chan_setlayer 0, .layer_58A @@ -1418,8 +1412,8 @@ layer_note1 39, 0xa, 127 layer_note1 42, 0x8, 127 layer_end -.ifndef VERSION_JP - .chan_828: # unused +#ifndef VERSION_JP + .chan_828: // unused chan_setbank 7 chan_setinstr 3 chan_setlayer 0, .layer_83C @@ -1464,7 +1458,7 @@ layer_end .layer_871: layer_transpose 8 layer_jump .layer_776 -.endif +#endif .sound_action_heavy_landing_default: chan_call .heavy_landing_common @@ -2029,7 +2023,7 @@ sound_ref .sound_mario_punch_wah sound_ref .sound_mario_uh sound_ref .sound_mario_hrmm sound_ref .sound_mario_wah2 -.ifdef VERSION_JP +#ifdef VERSION_JP sound_ref .sound_mario_jump_hoo sound_ref .sound_mario_jump_hoo sound_ref .sound_mario_jump_hoo @@ -2046,7 +2040,7 @@ sound_ref .sound_mario_wah2 sound_ref .sound_mario_jump_hoo sound_ref .sound_mario_jump_hoo sound_ref .sound_mario_jump_hoo -.else +#else sound_ref .sound_peach_dear_mario sound_ref .sound_mario_jump_hoo sound_ref .sound_mario_jump_hoo @@ -2071,7 +2065,7 @@ sound_ref .sound_mario_wah2 sound_ref .sound_peach_bake_a_cake sound_ref .sound_peach_for_mario sound_ref .sound_peach_mario2 -.endif +#endif .sound_mario_jump_hoo: chan_setbank 8 @@ -2080,9 +2074,9 @@ chan_setlayer 0, .layer_C3C chan_end .layer_C3C: -.ifdef VERSION_EU_SH +#if defined(VERSION_EU) || defined(VERSION_SH) layer_transpose 2 -.endif +#endif layer_portamento 0x82, 41, 127 layer_note1 37, 0x14, 127 layer_end @@ -2119,9 +2113,9 @@ chan_setlayer 0, .layer_C6C chan_end .layer_C6C: -.ifdef VERSION_EU_SH +#if defined(VERSION_EU) || defined(VERSION_SH) layer_transpose 1 -.endif +#endif layer_portamento 0x82, 44, 200 layer_note1 39, 0x30, 127 layer_end @@ -2482,7 +2476,7 @@ chan_end layer_transpose -1 layer_jump .layer_C4E -.ifndef VERSION_JP +#ifndef VERSION_JP .sound_peach_dear_mario: chan_setbank 10 chan_setinstr 15 @@ -2697,9 +2691,9 @@ layer_jump .layer_C4E .layer_F8A: layer_note1 39, 0x50, 127 layer_end -.endif +#endif -.ifdef VERSION_EU_SH +#if defined(VERSION_EU) || defined(VERSION_SH) .chan_unused_F9A_eu: chan_setbank 8 chan_setinstr 0 @@ -2709,7 +2703,7 @@ layer_jump .layer_C4E .layer_FA2_eu: layer_delay 0x5 layer_end -.endif +#endif .channel38_table: sound_ref .sound_general_activate_cap_switch @@ -2830,7 +2824,7 @@ sound_ref .sound_general_boing3 sound_ref .sound_general_grand_star sound_ref .sound_general_grand_star_jump sound_ref .sound_general_boat_rock -.ifdef VERSION_JP +#ifdef VERSION_JP sound_ref .sound_menu_enter_hole sound_ref .sound_menu_enter_hole sound_ref .sound_menu_enter_hole @@ -2841,7 +2835,7 @@ sound_ref .sound_general_boat_rock sound_ref .sound_general_bubbles sound_ref .sound_menu_enter_hole sound_ref .sound_menu_enter_hole -.else +#else sound_ref .sound_general_vanish_sfx sound_ref .sound_menu_enter_hole sound_ref .sound_general_red_coin @@ -2852,7 +2846,7 @@ sound_ref .sound_general_boat_rock sound_ref .sound_general_boing2 sound_ref .sound_general_yoshi_walk sound_ref .sound_general_enemy_alert1 -.endif +#endif .sound_general_activate_cap_switch: chan_setbank 5 @@ -3408,17 +3402,17 @@ chan_setbank 9 chan_setinstr 3 chan_setval 40 chan_call .set_reverb -.ifdef VERSION_SH +#ifdef VERSION_SH chan_setreverb 40 -.endif +#endif chan_setlayer 0, .layer_141A chan_end .layer_141A: layer_transpose 24 -.ifdef VERSION_SH +#ifdef VERSION_SH layer_note1 51, 0xc, 90 -.endif +#endif layer_note1 39, 0x4, 90 layer_note1 51, 0xc, 90 layer_note1 39, 0x4, 50 @@ -3487,18 +3481,18 @@ layer_end .sound_general_chain_chomp2: chan_setbank 7 -.ifdef VERSION_JP +#ifdef VERSION_JP chan_setinstr 8 -.else +#else chan_setinstr 14 -.endif +#endif chan_setval 15 chan_call .set_reverb chan_setlayer 0, .layer_14C6 chan_setlayer 1, .layer_14E3 -.ifndef VERSION_JP +#ifndef VERSION_JP chan_setlayer 2, .layer_14E3 -.endif +#endif chan_setval 1 chan_call .delay chan_setenvelope .envelope_3368 @@ -3507,11 +3501,11 @@ chan_setinstr 7 chan_setval 13 chan_call .delay chan_setbank 7 -.ifdef VERSION_JP +#ifdef VERSION_JP chan_setinstr 8 -.else +#else chan_setinstr 14 -.endif +#endif chan_end .layer_14C6: @@ -3527,12 +3521,12 @@ layer_end .layer_14E3: layer_loop 2 -.ifdef VERSION_JP +#ifdef VERSION_JP layer_portamento 0x81, 36, 255 layer_note1 24, 0x18, 127 -.else +#else layer_note1 34, 0x19, 100 -.endif +#endif layer_loopend layer_end @@ -4154,24 +4148,27 @@ layer_note1 31, 0x14, 127 layer_end .sound_general_red_coin: -.ifdef VERSION_JP +#ifdef VERSION_JP chan_setbank 9 chan_setinstr 3 chan_setlayer 0, .layer_1909 chan_setlayer 1, .layer_1902 chan_setlayer 2, .layer_1907 -.else - .ifdef VERSION_EU_SH +#else + #if defined(VERSION_EU) || defined(VERSION_SH) chan_setbank 9 chan_setinstr 3 - .else + #else chan_setinstr 128 - .endif + #endif chan_setenvelope .envelope_3378 + // Small bugfix: .main_loop_023589 expects layer 0 to live the longest. + // I don't think this actually makes any audible difference given the + // silence at the end. chan_setlayer 0, .layer_1907 chan_setlayer 1, .layer_1902 chan_setlayer 2, .layer_1909 -.endif +#endif chan_end .layer_1902: @@ -4191,6 +4188,12 @@ layer_note0 58, 0x10, 100, 80 layer_note0 58, 0x10, 60, 80 layer_note0 58, 0x10, 40, 80 layer_note0 58, 0x10, 25, 80 +// This small delay should not have any effect, but decreases the probability of +// encountering double red coin glitch. Without it, layer 0 finishes in 1.04 +// seconds, and with some bad luck around scheduling/lag the sound spawner with +// a lifetime of 30 frames that creates the sound may deactivate on the same +// frame. That leads to double sound glitch on JP, see src/audio/external.c. +// With the delay, the same thing can still happen but requires more CPU lag. layer_delay 0xa layer_end @@ -4422,7 +4425,7 @@ layer_portamento 0x81, 36, 40 layer_note1 41, 0xc, 127 layer_end -.ifdef VERSION_JP +#ifdef VERSION_JP .sound_general_boat_rock: chan_setbank 9 chan_setinstr 0 @@ -4438,7 +4441,7 @@ layer_end layer_portamento 0x1, 32, 0x7f layer_note1 60, 0x28, 100 layer_end -.else +#else .sound_general_boat_rock: chan_setbank 4 chan_setinstr 2 @@ -4476,7 +4479,7 @@ layer_end layer_portamento 0x81, 19, 255 layer_note1 31, 0x32, 115 layer_end -.endif +#endif .channel4_table: sound_ref .sound_env_waterfall1 @@ -4525,21 +4528,21 @@ chan_setbank 5 chan_setinstr 1 chan_setval 25 chan_call .set_reverb -.ifdef VERSION_JP +#ifdef VERSION_JP chan_setenvelope .envelope_32E4 -.else +#else chan_setenvelope .envelope_32C4 -.endif +#endif chan_setlayer 0, .layer_1B53 chan_end .layer_1B53: layer_somethingon -.ifdef VERSION_JP +#ifdef VERSION_JP layer_delay 0x6 -.else +#else layer_delay 0x4 -.endif +#endif .layer_1B56: layer_note1 41, 0x12c, 95 layer_jump .layer_1B56 @@ -4694,11 +4697,11 @@ chan_end .layer_1C69: layer_portamento 0x81, 15, 255 -.ifdef VERSION_JP +#ifdef VERSION_JP layer_note1 11, 0x1f4, 100 -.else +#else layer_note1 11, 0x1f4, 127 -.endif +#endif layer_end .sound_env_elevator3: @@ -5374,11 +5377,11 @@ chan_end .layer_20D2: layer_portamento 0x81, 44, 255 -.ifdef VERSION_JP +#ifdef VERSION_JP layer_note1 36, 0x18, 90 -.else +#else layer_note1 36, 0x18, 115 -.endif +#endif layer_delay 0x32 layer_end @@ -5398,13 +5401,13 @@ layer_note1 31, 0x26, 127 layer_end .layer_20F4: -.ifdef VERSION_JP +#ifdef VERSION_JP layer_note1 38, 0x8, 120 layer_note1 33, 0x1e, 120 -.else +#else layer_note1 38, 0x8, 127 layer_note1 33, 0x1e, 127 -.endif +#endif layer_end .sound_obj_bully_metal: @@ -6989,7 +6992,7 @@ sound_ref .sound_menu_thank_you_playing_my_game sound_ref .sound_menu_read_a_sign sound_ref .sound_menu_exit_a_sign sound_ref .sound_menu_mario_castle_warp2 -.ifdef VERSION_JP +#ifdef VERSION_JP sound_ref .sound_menu_message_next_page sound_ref .sound_menu_coin_its_a_me_mario sound_ref .sound_menu_yoshi_gain_lives @@ -7003,7 +7006,7 @@ sound_ref .sound_menu_mario_castle_warp2 sound_ref .sound_menu_mario_castle_warp sound_ref .sound_menu_star_sound sound_ref .sound_menu_change_select -.else +#else sound_ref .sound_menu_star_sound_okey_dokey sound_ref .sound_menu_star_sound_lets_a_go sound_ref .sound_menu_yoshi_gain_lives @@ -7033,7 +7036,7 @@ sound_ref .sound_menu_mario_castle_warp2 sound_ref .sound_menu_power_meter sound_ref .sound_menu_camera_buzz sound_ref .sound_menu_camera_turn -.endif +#endif .sound_menu_change_select: chan_setbank 9 @@ -7506,13 +7509,13 @@ layer_end chan_reservenotes 4 chan_setbank 9 chan_setinstr 2 -.ifdef VERSION_SH +#ifdef VERSION_SH chan_setval 15 .set EXIT_PIPE_NOTE_VELOCITY, 106 -.else +#else chan_setval 30 .set EXIT_PIPE_NOTE_VELOCITY, 126 -.endif +#endif chan_call .set_reverb chan_setenvelope .envelope_3464 chan_setdecayrelease 220 @@ -7774,7 +7777,7 @@ chan_setlayer 0, .layer_3041 chan_setlayer 1, .layer_2FC9 chan_end -.ifndef VERSION_JP +#ifndef VERSION_JP .sound_menu_star_sound_okey_dokey: chan_setbank 4 chan_setinstr 14 @@ -7828,33 +7831,33 @@ chan_end .layer_3146: layer_delay 0x6 - .ifdef VERSION_SH + #ifdef VERSION_SH .set RED_COIN_NOTE_VELOCITY_SUB, 10 - .else + #else .set RED_COIN_NOTE_VELOCITY_SUB, 0 - .endif + #endif .layer_3148: layer_call .transpose_by_coin_index - layer_note0 46, 0xc, 75 - RED_COIN_NOTE_VELOCITY_SUB, 20 - layer_note0 45, 0xc, 75 - RED_COIN_NOTE_VELOCITY_SUB, 20 - layer_note0 46, 0xc, 75 - RED_COIN_NOTE_VELOCITY_SUB, 20 - layer_note0 58, 0x10, 80 - RED_COIN_NOTE_VELOCITY_SUB, 80 - layer_note0 58, 0x10, 45 - RED_COIN_NOTE_VELOCITY_SUB, 80 - layer_note0 58, 0x10, 20 - RED_COIN_NOTE_VELOCITY_SUB, 80 - layer_note0 58, 0x10, 15 - RED_COIN_NOTE_VELOCITY_SUB, 80 + layer_note0 46, 0xc, (75 - RED_COIN_NOTE_VELOCITY_SUB), 20 + layer_note0 45, 0xc, (75 - RED_COIN_NOTE_VELOCITY_SUB), 20 + layer_note0 46, 0xc, (75 - RED_COIN_NOTE_VELOCITY_SUB), 20 + layer_note0 58, 0x10, (80 - RED_COIN_NOTE_VELOCITY_SUB), 80 + layer_note0 58, 0x10, (45 - RED_COIN_NOTE_VELOCITY_SUB), 80 + layer_note0 58, 0x10, (20 - RED_COIN_NOTE_VELOCITY_SUB), 80 + layer_note0 58, 0x10, (15 - RED_COIN_NOTE_VELOCITY_SUB), 80 layer_end .layer_3168: layer_call .transpose_by_coin_index - layer_note0 41, 0xc, 75 - RED_COIN_NOTE_VELOCITY_SUB, 20 - layer_note0 40, 0xc, 75 - RED_COIN_NOTE_VELOCITY_SUB, 20 - layer_note0 41, 0xc, 75 - RED_COIN_NOTE_VELOCITY_SUB, 20 - layer_note0 53, 0x10, 80 - RED_COIN_NOTE_VELOCITY_SUB, 80 - layer_note0 53, 0x10, 45 - RED_COIN_NOTE_VELOCITY_SUB, 80 - layer_note0 53, 0x10, 20 - RED_COIN_NOTE_VELOCITY_SUB, 80 - layer_note0 53, 0x10, 15 - RED_COIN_NOTE_VELOCITY_SUB, 80 + layer_note0 41, 0xc, (75 - RED_COIN_NOTE_VELOCITY_SUB), 20 + layer_note0 40, 0xc, (75 - RED_COIN_NOTE_VELOCITY_SUB), 20 + layer_note0 41, 0xc, (75 - RED_COIN_NOTE_VELOCITY_SUB), 20 + layer_note0 53, 0x10, (80 - RED_COIN_NOTE_VELOCITY_SUB), 80 + layer_note0 53, 0x10, (45 - RED_COIN_NOTE_VELOCITY_SUB), 80 + layer_note0 53, 0x10, (20 - RED_COIN_NOTE_VELOCITY_SUB), 80 + layer_note0 53, 0x10, (15 - RED_COIN_NOTE_VELOCITY_SUB), 80 layer_end .transpose_by_coin_index: @@ -7877,7 +7880,7 @@ chan_end layer_transpose 0 layer_note1 32, 0x7f, 115 layer_end -.endif +#endif .sound_general_bird_chirp2: chan_setbank 5 @@ -8084,14 +8087,14 @@ envelope_line 1 32700 envelope_line 10 0 envelope_goto 2 -.ifndef VERSION_JP +#ifndef VERSION_JP .envelope_3378: envelope_line 3 32700 envelope_line 10 30000 envelope_line 10 10000 envelope_line 100 0 envelope_goto 3 -.endif +#endif .envelope_338C: envelope_line 1 32700 @@ -8150,11 +8153,11 @@ envelope_goto 2 .envelope_341C: envelope_line 25 32760 envelope_line 60 10000 -.ifdef VERSION_SH +#ifdef VERSION_SH envelope_hang -.else +#else envelope_goto 2 -.endif +#endif .envelope_3428: envelope_line 1 10000 diff --git a/sound/sound_data.c b/sound/sound_data.c deleted file mode 100644 index 84c6616a..00000000 --- a/sound/sound_data.c +++ /dev/null @@ -1,17 +0,0 @@ -unsigned char gSoundDataADSR[] = { -#include "sound/sound_data.ctl.inc.c" -}; - -unsigned char gSoundDataRaw[] = { -#include "sound/sound_data.tbl.inc.c" -}; - -unsigned char gMusicData[] = { -#include "sound/sequences.bin.inc.c" -}; - -#ifndef VERSION_SH -unsigned char gBankSetsData[] = { -#include "sound/bank_sets.inc.c" -}; -#endif diff --git a/sound/sound_data.s b/sound/sound_data.s new file mode 100644 index 00000000..2a31186d --- /dev/null +++ b/sound/sound_data.s @@ -0,0 +1,21 @@ +.include "macros.inc" + +.section .data + +glabel gSoundDataADSR +.incbin "sound/sound_data.ctl" +.balign 16 + +glabel gSoundDataRaw +.incbin "sound/sound_data.tbl" +.balign 16 + +glabel gMusicData +.incbin "sound/sequences.bin" +.balign 16 + +#ifndef VERSION_SH +glabel gBankSetsData +.incbin "sound/bank_sets" +.balign 16 +#endif \ No newline at end of file diff --git a/src/audio/copt/seq_channel_layer_process_script_copt.inc.c b/src/audio/copt/seq_channel_layer_process_script_copt.inc.c index ab8da804..1677bd5c 100644 --- a/src/audio/copt/seq_channel_layer_process_script_copt.inc.c +++ b/src/audio/copt/seq_channel_layer_process_script_copt.inc.c @@ -126,12 +126,12 @@ void seq_channel_layer_process_script(struct SequenceChannelLayer *layer) { u8 sameSound; u8 cmd; // a0 sp3E, EU s2 u8 cmdSemitone; // sp3D, t0 - u16 sp3A; // t2, a0, a1 + u16 sp3A = 0; // t2, a0, a1 f32 tuning; // f0 - s32 vel; // sp30, t3 + s32 vel = 0; // sp30, t3 s32 usedSemitone; // a1 - f32 freqScale; // sp28, f0 - f32 sp24; + f32 freqScale = 0.0f; // sp28, f0 + f32 sp24 = 0.0f; f32 temp_f12; f32 temp_f2; diff --git a/src/audio/data.c b/src/audio/data.c index 4fdc13e5..cb110405 100644 --- a/src/audio/data.c +++ b/src/audio/data.c @@ -49,6 +49,39 @@ struct AudioSessionSettingsEU gAudioSessionPresets[] = { // - memory used for temporary sequences // - memory used for temporary banks #if defined(VERSION_JP) || defined(VERSION_US) +#ifdef EXPAND_AUDIO_HEAP +struct AudioSessionSettings gAudioSessionPresets[18] = { +#ifdef VERSION_JP + { 32000, 32, 1, 0x0800, 0x2FFF, 0x7FFF, 0x7200, 0xC000, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0A00, 0x47FF, 0x7FFF, 0x7200, 0xC000, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x1000, 0x2FFF, 0x7FFF, 0x7200, 0xC000, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0E00, 0x3FFF, 0x7FFF, 0x7200, 0xC000, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0C00, 0x4FFF, 0x7FFF, 0x7200, 0xC000, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0800, 0x2FFF, 0x7FFF, 0x7C00, 0xC400, 0x7E00, 0x5400 }, + { 32000, 32, 1, 0x0A00, 0x47FF, 0x7FFF, 0x7E00, 0xC400, 0x8800, 0x5500 }, + { 32000, 40, 1, 0x0800, 0x37FF, 0x7FFF, 0x6600, 0xAA00, 0x8000, 0x3600 }, +#else + { 32000, 32, 1, 0x0C00, 0x2FFF, 0x7FFF, 0x7400, 0xDA00, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0A00, 0x47FF, 0x7FFF, 0x7400, 0xDA00, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x1000, 0x2FFF, 0x7FFF, 0x7400, 0xDA00, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0E00, 0x3FFF, 0x7FFF, 0x7400, 0xDA00, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0C00, 0x4FFF, 0x7FFF, 0x7400, 0xDA00, 0x8800, 0x5400 }, + { 32000, 32, 1, 0x0C00, 0x2FFF, 0x7FFF, 0x8000, 0xDC00, 0x7E00, 0x5400 }, + { 32000, 32, 1, 0x0A00, 0x47FF, 0x7FFF, 0x8200, 0xDC00, 0x8800, 0x5500 }, + { 32000, 40, 1, 0x0800, 0x37FF, 0x7FFF, 0x6980, 0xC500, 0x8000, 0x3600 }, +#endif + { 27000, 32, 1, 0x0800, 0x2FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 27000, 32, 1, 0x0800, 0x3FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 27000, 32, 1, 0x1000, 0x2FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 27000, 32, 1, 0x1000, 0x3FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 27000, 32, 1, 0x0C00, 0x4FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 32000, 28, 1, 0x0800, 0x2FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 32000, 24, 1, 0x0800, 0x2FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 32000, 20, 1, 0x0800, 0x2FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 32000, 16, 1, 0x0800, 0x2FFF, 0x7FFF, 0x4A00, 0xAA00, 0xE800, 0x4800 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; +#else struct AudioSessionSettings gAudioSessionPresets[18] = { #ifdef VERSION_JP { 32000, 16, 1, 0x0800, 0x2FFF, 0x7FFF, 0x3900, 0x6000, 0x4400, 0x2A00 }, @@ -81,6 +114,7 @@ struct AudioSessionSettings gAudioSessionPresets[18] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; #endif +#endif // gAudioCosineTable[k] = round((2**15 - 1) * cos(pi/2 * k / 127)). Unused. #if defined(VERSION_JP) || defined(VERSION_US) u16 gAudioCosineTable[128] = { @@ -877,12 +911,6 @@ u16 unk_sh_data_4[] = { 0x5FFF, 0x9001, 0x7FFF, 0x8001 }; - -char shindouDebugPrint1[] = "Terminate-Canceled Channel %d,Phase %d\n"; -char shindouDebugPrint2[] = "S->W\n"; -char shindouDebugPrint3[] = "W->S\n"; -char shindouDebugPrint4[] = "S-Resample Pitch %x (old %d -> delay %d)\n"; -// These debug prints are continued in shindou_debug_prints_1.c. #endif #ifndef VERSION_SH diff --git a/src/audio/data.h b/src/audio/data.h index ee8b30b1..e0f7b1cd 100644 --- a/src/audio/data.h +++ b/src/audio/data.h @@ -5,6 +5,7 @@ #include "internal.h" #include "types.h" +#include "synthesis.h" #define AUDIO_LOCK_UNINITIALIZED 0 #define AUDIO_LOCK_NOT_LOADING 0x76557364 @@ -109,6 +110,20 @@ extern u16 gUnused80226E98[0x10]; extern u32 gAudioRandom; +#ifdef EXPAND_AUDIO_HEAP +#if defined(VERSION_US) || defined(VERSION_JP) +#define EXT_AUDIO_HEAP_SIZE 0x24400 +#define EXT_AUDIO_INIT_POOL_SIZE 0x8000 +#else +// EU and SH versions not yet supported for extended audio heap +#define EXT_AUDIO_HEAP_SIZE 0x24400 +#define EXT_AUDIO_INIT_POOL_SIZE 0x8000 +#endif +#else +#define EXT_AUDIO_HEAP_SIZE 0x0 +#define EXT_AUDIO_INIT_POOL_SIZE 0x0 +#endif + #ifdef VERSION_SH extern f32 unk_sh_data_1[]; @@ -136,12 +151,12 @@ extern OSMesgQueue *D_SH_80350FA8; #if defined(VERSION_EU) || defined(VERSION_SH) #define UNUSED_COUNT_80333EE8 24 -#define AUDIO_HEAP_SIZE 0x2c500 -#define AUDIO_INIT_POOL_SIZE 0x2c00 +#define AUDIO_HEAP_SIZE (0x2c500 + EXT_AUDIO_HEAP_SIZE + EXT_AUDIO_INIT_POOL_SIZE + BETTER_REVERB_SIZE) +#define AUDIO_INIT_POOL_SIZE (0x2c00 + EXT_AUDIO_INIT_POOL_SIZE) #else #define UNUSED_COUNT_80333EE8 16 -#define AUDIO_HEAP_SIZE 0x31150 -#define AUDIO_INIT_POOL_SIZE 0x2500 +#define AUDIO_HEAP_SIZE (0x31150 + EXT_AUDIO_HEAP_SIZE + EXT_AUDIO_INIT_POOL_SIZE + BETTER_REVERB_SIZE) +#define AUDIO_INIT_POOL_SIZE (0x2500 + EXT_AUDIO_INIT_POOL_SIZE) #endif #ifdef VERSION_SH diff --git a/src/audio/effects.c b/src/audio/effects.c index 91c2f034..71065168 100644 --- a/src/audio/effects.c +++ b/src/audio/effects.c @@ -190,6 +190,7 @@ s8 get_vibrato_pitch_change(struct VibratoState *vib) { switch (index & 0x30) { case 0x10: index = 31 - index; + // fall through case 0x00: return vib->curve[index]; @@ -291,6 +292,7 @@ void note_vibrato_init(struct Note *note) { vib = ¬e->vibratoState; +/* This code was probably removed from EU and SH for a reason; probably because it's dumb and makes vibrato harder to use well. #if defined(VERSION_JP) || defined(VERSION_US) if (note->parentLayer->seqChannel->vibratoExtentStart == 0 && note->parentLayer->seqChannel->vibratoExtentTarget == 0 @@ -299,6 +301,7 @@ void note_vibrato_init(struct Note *note) { return; } #endif +*/ vib->active = TRUE; vib->time = 0; @@ -385,8 +388,8 @@ s32 adsr_update(struct AdsrState *adsr) { adsr->state = ADSR_STATE_HANG; break; } - // fallthrough } + // fall through case ADSR_STATE_START_LOOP: adsr->envIndex = 0; @@ -394,11 +397,12 @@ s32 adsr_update(struct AdsrState *adsr) { adsr->currentHiRes = adsr->current << 0x10; #endif adsr->state = ADSR_STATE_LOOP; - // fallthrough #ifdef VERSION_SH restart: #endif + // fall through + case ADSR_STATE_LOOP: adsr->delay = BSWAP16(adsr->envelope[adsr->envIndex].delay); switch (adsr->delay) { diff --git a/src/audio/external.c b/src/audio/external.c index bcd37a2d..33e7f98c 100644 --- a/src/audio/external.c +++ b/src/audio/external.c @@ -324,17 +324,6 @@ u8 sSoundBankFreeListFront[SOUND_BANK_COUNT] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; u8 sNumSoundsInBank[SOUND_BANK_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // only used for debugging u8 sMaxChannelsForSoundBank[SOUND_BANK_COUNT] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; -// Banks 2 and 7 both grew from 0x30 sounds to 0x40 in size in US. -#ifdef VERSION_JP -#define BANK27_SIZE 0x30 -#else -#define BANK27_SIZE 0x40 -#endif -u8 sNumSoundsPerBank[SOUND_BANK_COUNT] = { - 0x70, 0x30, BANK27_SIZE, 0x80, 0x20, 0x80, 0x20, BANK27_SIZE, 0x80, 0x80, -}; -#undef BANK27_SIZE - // sBackgroundMusicMaxTargetVolume and sBackgroundMusicTargetVolume use the 0x80 // bit to indicate that they are set, and the rest of the bits for the actual value #define TARGET_VOLUME_IS_PRESENT_FLAG 0x80 @@ -484,15 +473,9 @@ void unused_8031E4F0(void) { stubbed_printf("\n"); stubbed_printf("BNK "); -#ifdef VERSION_SH -#define count 1 -#else -#define count 4 -#endif - for (i = 0; i < 40; i += count) { + for (i = 0; i < 40; i += 4) { stubbed_printf("%1x", 0); } -#undef count stubbed_printf("\n"); stubbed_printf("FIXHEAP "); @@ -820,17 +803,15 @@ void play_sound(s32 soundBits, f32 *pos) { * Called from threads: thread4_sound, thread5_game_loop (EU only) */ static void process_sound_request(u32 bits, f32 *pos) { - u8 bank; - u8 soundIndex; - u8 counter = 0; - u8 soundId; + s32 bank; + s32 soundIndex; + s32 counter = 0; f32 dist; const f32 one = 1.0f; bank = (bits & SOUNDARGS_MASK_BANK) >> SOUNDARGS_SHIFT_BANK; - soundId = (bits & SOUNDARGS_MASK_SOUNDID) >> SOUNDARGS_SHIFT_SOUNDID; - if (soundId >= sNumSoundsPerBank[bank] || sSoundBankDisabled[bank]) { + if (sSoundBankDisabled[bank]) { return; } @@ -1148,8 +1129,8 @@ static void select_current_sounds(u8 bank) { } /** - * Given an x and z coordinates, return the pan. This is a value between 0 and - * 1 that represents the audio direction. + * Given x and z coordinates, return the pan. This is a value nominally between + * 0 and 1 that represents the audio direction. * * Pan: * 0.0 - fully left @@ -1183,12 +1164,17 @@ static f32 get_sound_pan(f32 x, f32 z) { pan = US_FLOAT(0.5); } else if (x >= US_FLOAT(0.0) && absX >= absZ) { // far right pan - pan = US_FLOAT(1.0) - (US_FLOAT(44000.0) - absX) / (US_FLOAT(3.0) * (US_FLOAT(44000.0) - absZ)); + pan = US_FLOAT(1.0) - (2 * AUDIO_MAX_DISTANCE - absX) / (US_FLOAT(3.0) * (2 * AUDIO_MAX_DISTANCE - absZ)); } else if (x < 0 && absX > absZ) { // far left pan - pan = (US_FLOAT(44000.0) - absX) / (US_FLOAT(3.0) * (US_FLOAT(44000.0) - absZ)); + pan = (2 * AUDIO_MAX_DISTANCE - absX) / (US_FLOAT(3.0) * (2 * AUDIO_MAX_DISTANCE - absZ)); } else { // center pan + //! @bug (JP PU sound glitch) If |x|, |z| > AUDIO_MAX_DISTANCE, we'll + // end up in this case, and pan may be set to something outside of [0,1] + // since x is not clamped. On JP, this can lead to an out-of-bounds + // float read in note_set_vel_pan_reverb when x is highly negative, + // causing console crashes when that float is a nan or denormal. pan = 0.5 + x / (US_FLOAT(6.0) * absZ); } @@ -1234,6 +1220,8 @@ static f32 get_sound_volume(u8 bank, u8 soundIndex, f32 volumeRange) { if (sSoundBanks[bank][soundIndex].soundBits & SOUND_VIBRATO) { #ifdef VERSION_JP + //! @bug Intensity is 0 when the sound is far away. Due to the subtraction below, it is possible to end up with a negative intensity. + // When it is, objects with a volumeRange of 1 can still occasionally be lightly heard. if (intensity != 0.0) #else if (intensity >= 0.08f) @@ -1435,7 +1423,7 @@ static void update_game_sound(void) { func_802ad770(0x05020000 | ((channelIndex & 0xff) << 8), get_sound_reverb(bank, soundIndex, channelIndex)); #else - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverb = + gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverbVol = get_sound_reverb(bank, soundIndex, channelIndex); #endif @@ -1476,7 +1464,7 @@ static void update_game_sound(void) { *sSoundBanks[bank][soundIndex].z); gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->freqScale = get_sound_freq_scale(bank, soundIndex); - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverb = + gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverbVol = get_sound_reverb(bank, soundIndex, channelIndex); #endif break; @@ -1499,7 +1487,7 @@ static void update_game_sound(void) { func_802ad728(0x04020000 | ((channelIndex & 0xff) << 8), get_sound_freq_scale(bank, soundIndex)); #else - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverb = + gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverbVol = get_sound_reverb(bank, soundIndex, channelIndex); gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->volume = get_sound_volume(bank, soundIndex, VOLUME_RANGE_UNK2); @@ -1515,6 +1503,13 @@ static void update_game_sound(void) { #ifdef VERSION_JP // If the sound was marked for deletion (bits set to NO_SOUND), then stop playing it // and delete it + // @bug (JP double red coin sound) If the sound finished within the same frame as + // being marked for deletion, the signal to stop playing will be interpreted as a + // signal to *start* playing, as .main_loop_023589 in 00_sound_player does not check + // for soundScriptIO[0] being zero. This happens most commonly for red coin sounds + // whose sound spawners deactivate 30 frames after the sound starts to play, while + // the sound itself runs for 1.20 seconds. With enough lag these may coincide. + // Fixed on US by checking that layer0->finished is FALSE. else if (soundStatus == SOUND_STATUS_STOPPED) { update_background_music_after_sound(bank, soundIndex); gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[0] = 0; @@ -1526,17 +1521,19 @@ static void update_game_sound(void) { sSoundBanks[bank][soundIndex].soundStatus = SOUND_STATUS_STOPPED; delete_sound_from_bank(bank, soundIndex); } else if (soundStatus == SOUND_STATUS_STOPPED - && gSequencePlayers[SEQ_PLAYER_SFX] - .channels[channelIndex] - ->layers[0] - ->finished - == FALSE) { + && gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex] + ->layers[0]->finished == FALSE) { update_background_music_after_sound(bank, soundIndex); gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[0] = 0; delete_sound_from_bank(bank, soundIndex); } #endif // If sound has finished playing, then delete it + // @bug (JP sound glitch) On JP, ...->layers[0] has not been checked for null, + // so this access can crash if an earlier layer allocation failed due to too + // many sounds playing at once. This crash is comparatively common; RTA + // speedrunners even have a setup for avoiding it within the SSL pyramid: + // https://www.youtube.com/watch?v=QetyTgbQxcw else if (gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->layers[0]->enabled == FALSE) { update_background_music_after_sound(bank, soundIndex); @@ -1610,7 +1607,7 @@ static void update_game_sound(void) { func_802ad770(0x05020000 | ((channelIndex & 0xff) << 8), get_sound_reverb(bank, soundIndex, channelIndex)); #else - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverb = + gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverbVol = get_sound_reverb(bank, soundIndex, channelIndex); #endif @@ -1651,7 +1648,7 @@ static void update_game_sound(void) { *sSoundBanks[bank][soundIndex].z); gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->freqScale = get_sound_freq_scale(bank, soundIndex); - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverb = + gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverbVol = get_sound_reverb(bank, soundIndex, channelIndex); #endif break; @@ -1674,7 +1671,7 @@ static void update_game_sound(void) { func_802ad728(0x04020000 | ((channelIndex & 0xff) << 8), get_sound_freq_scale(bank, soundIndex)); #else - gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverb = + gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->reverbVol = get_sound_reverb(bank, soundIndex, channelIndex); gSequencePlayers[SEQ_PLAYER_SFX].channels[channelIndex]->volume = get_sound_volume(bank, soundIndex, VOLUME_RANGE_UNK2); diff --git a/src/audio/external.h b/src/audio/external.h index ce14b297..96dbc104 100644 --- a/src/audio/external.h +++ b/src/audio/external.h @@ -25,9 +25,6 @@ extern f32 gGlobalSoundSource[3]; extern u32 gAudioRandom; struct SPTask *create_next_audio_frame_task(void); -#ifdef VERSION_SH -struct SPTask *func_sh_802f5a80(void); -#endif void play_sound(s32 soundBits, f32 *pos); void audio_signal_game_loop_tick(void); void seq_player_fade_out(u8 player, u16 fadeDuration); diff --git a/src/audio/heap.c b/src/audio/heap.c index a81c8b44..424df28e 100644 --- a/src/audio/heap.c +++ b/src/audio/heap.c @@ -6,6 +6,9 @@ #include "synthesis.h" #include "seqplayer.h" #include "effects.h" +#include "game/game_init.h" +#include "game/puppyprint.h" +#include "game/vc_check.h" #define ALIGN16(val) (((val) + 0xF) & ~0xF) @@ -204,8 +207,6 @@ void discard_bank(s32 bankId) { #if defined(VERSION_EU) if (note->noteSubEu.bankId == bankId) { -#elif defined(VERSION_SH) - if (note->unkSH33 == bankId) { #else if (note->bankId == bankId) { #endif @@ -340,6 +341,10 @@ extern s32 D_SH_80315EE8; void sound_init_main_pools(s32 sizeForAudioInitPool) { sound_alloc_pool_init(&gAudioInitPool, gAudioHeap, sizeForAudioInitPool); sound_alloc_pool_init(&gAudioSessionPool, gAudioHeap + sizeForAudioInitPool, gAudioHeapSize - sizeForAudioInitPool); + #if PUPPYPRINT_DEBUG + audioPool[0] = sizeForAudioInitPool; + audioPool[1] = gAudioHeapSize - sizeForAudioInitPool; + #endif } #ifdef VERSION_SH @@ -352,20 +357,32 @@ void session_pools_init(struct PoolSplit *a) { gAudioSessionPool.cur = gAudioSessionPool.start; sound_alloc_pool_init(&gNotesAndBuffersPool, SOUND_ALLOC_FUNC(&gAudioSessionPool, a->wantSeq), a->wantSeq); sound_alloc_pool_init(&gSeqAndBankPool, SOUND_ALLOC_FUNC(&gAudioSessionPool, a->wantCustom), a->wantCustom); + #if PUPPYPRINT_DEBUG + audioPool[2] = a->wantSeq; + audioPool[3] = a->wantCustom; + #endif } void seq_and_bank_pool_init(struct PoolSplit2 *a) { gSeqAndBankPool.cur = gSeqAndBankPool.start; sound_alloc_pool_init(&gPersistentCommonPool, SOUND_ALLOC_FUNC(&gSeqAndBankPool, a->wantPersistent), a->wantPersistent); sound_alloc_pool_init(&gTemporaryCommonPool, SOUND_ALLOC_FUNC(&gSeqAndBankPool, a->wantTemporary), a->wantTemporary); + #if PUPPYPRINT_DEBUG + audioPool[4] = a->wantPersistent; + audioPool[5] = a->wantTemporary; + #endif } void persistent_pools_init(struct PoolSplit *a) { gPersistentCommonPool.cur = gPersistentCommonPool.start; sound_alloc_pool_init(&gSeqLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantSeq), a->wantSeq); sound_alloc_pool_init(&gBankLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantBank), a->wantBank); - sound_alloc_pool_init(&gUnusedLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantUnused), - a->wantUnused); + sound_alloc_pool_init(&gUnusedLoadedPool.persistent.pool, SOUND_ALLOC_FUNC(&gPersistentCommonPool, a->wantUnused), a->wantUnused); + #if PUPPYPRINT_DEBUG + audioPool[6] = a->wantSeq; + audioPool[7] = a->wantBank; + audioPool[8] = a->wantUnused; + #endif persistent_pool_clear(&gSeqLoadedPool.persistent); persistent_pool_clear(&gBankLoadedPool.persistent); persistent_pool_clear(&gUnusedLoadedPool.persistent); @@ -375,8 +392,12 @@ void temporary_pools_init(struct PoolSplit *a) { gTemporaryCommonPool.cur = gTemporaryCommonPool.start; sound_alloc_pool_init(&gSeqLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantSeq), a->wantSeq); sound_alloc_pool_init(&gBankLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantBank), a->wantBank); - sound_alloc_pool_init(&gUnusedLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantUnused), - a->wantUnused); + sound_alloc_pool_init(&gUnusedLoadedPool.temporary.pool, SOUND_ALLOC_FUNC(&gTemporaryCommonPool, a->wantUnused), a->wantUnused); + #if PUPPYPRINT_DEBUG + audioPool[9] = a->wantSeq; + audioPool[10] = a->wantBank; + audioPool[11] = a->wantUnused; + #endif temporary_pool_clear(&gSeqLoadedPool.temporary); temporary_pool_clear(&gBankLoadedPool.temporary); temporary_pool_clear(&gUnusedLoadedPool.temporary); @@ -384,7 +405,7 @@ void temporary_pools_init(struct PoolSplit *a) { #undef SOUND_ALLOC_FUNC #if defined(VERSION_JP) || defined(VERSION_US) -static void unused_803163D4(void) { +UNUSED static void unused_803163D4(void) { } #endif @@ -411,9 +432,9 @@ void *alloc_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 size, s32 arg #endif u32 nullID = -1; UNUSED s32 i; - u8 *table; + u8 *table = NULL; #ifndef VERSION_SH - u8 isSound; + u8 isSound = FALSE; #endif #if defined(VERSION_JP) || defined(VERSION_US) u16 firstVal; @@ -512,7 +533,7 @@ void *alloc_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 size, s32 arg if (poolIdx == 1) { if (firstVal == SOUND_LOAD_STATUS_4) { for (i = 0; i < gMaxSimultaneousNotes; i++) { - if (gNotes[i].unkSH33 == tp->entries[0].id && gNotes[i].noteSubEu.enabled) { + if (gNotes[i].bankId == tp->entries[0].id && gNotes[i].noteSubEu.enabled) { break; } } @@ -525,7 +546,7 @@ void *alloc_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 size, s32 arg } if (secondVal == SOUND_LOAD_STATUS_4) { for (i = 0; i < gMaxSimultaneousNotes; i++) { - if (gNotes[i].unkSH33 == tp->entries[1].id && gNotes[i].noteSubEu.enabled) { + if (gNotes[i].bankId == tp->entries[1].id && gNotes[i].noteSubEu.enabled) { break; } } @@ -591,7 +612,7 @@ void *alloc_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 size, s32 arg } else if (poolIdx == 1) { if (firstVal == SOUND_LOAD_STATUS_COMPLETE) { for (i = 0; i < gMaxSimultaneousNotes; i++) { - if (gNotes[i].unkSH33 == tp->entries[0].id && gNotes[i].noteSubEu.enabled) { + if (gNotes[i].bankId == tp->entries[0].id && gNotes[i].noteSubEu.enabled) { break; } } @@ -602,7 +623,7 @@ void *alloc_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 size, s32 arg } if (secondVal == SOUND_LOAD_STATUS_COMPLETE) { for (i = 0; i < gMaxSimultaneousNotes; i++) { - if (gNotes[i].unkSH33 == tp->entries[1].id && gNotes[i].noteSubEu.enabled) { + if (gNotes[i].bankId == tp->entries[1].id && gNotes[i].noteSubEu.enabled) { break; } } @@ -1089,6 +1110,11 @@ s32 audio_shut_down_and_reset_step(void) { * Waits until a specified number of audio frames have been created */ void wait_for_audio_frames(s32 frames) { + // VC emulator stubs this function because busy loops are not supported + // Technically we can put infinite loop that _looks_ like -O0 for emu but this is cleaner + if (gIsVC) + return; + gAudioFrameCount = 0; // Sound thread will update gAudioFrameCount while (gAudioFrameCount < frames) { @@ -1119,6 +1145,9 @@ void audio_reset_session(void) { #if defined(VERSION_JP) || defined(VERSION_US) s32 frames; s32 remainingDmas; +#ifdef BETTER_REVERB + s8 reverbConsole; +#endif #else struct SynthesisReverb *reverb; #endif @@ -1231,6 +1260,29 @@ void audio_reset_session(void) { gMaxSimultaneousNotes = preset->maxSimultaneousNotes; gSamplesPerFrameTarget = ALIGN16(gAiFrequency / 60); gReverbDownsampleRate = preset->reverbDownsampleRate; +#if defined(BETTER_REVERB) && (defined(VERSION_US) || defined(VERSION_JP)) + if (gIsConsole) + reverbConsole = betterReverbDownsampleConsole; // Console! + else + reverbConsole = betterReverbDownsampleEmulator; // Setting this to 1 is REALLY slow, please use sparingly! + + if (reverbConsole <= 0) { + reverbConsole = 1; + toggleBetterReverb = FALSE; + } + else { + toggleBetterReverb = TRUE; + } + + if (toggleBetterReverb && betterReverbWindowsSize >= 0) + reverbWindowSize = betterReverbWindowsSize; + + if (gReverbDownsampleRate < (1 << (reverbConsole - 1))) + gReverbDownsampleRate = (1 << (reverbConsole - 1)); + reverbWindowSize /= gReverbDownsampleRate; + if (reverbWindowSize < DEFAULT_LEN_2CH) // Minimum window size to not overflow + reverbWindowSize = DEFAULT_LEN_2CH; +#endif switch (gReverbDownsampleRate) { case 1: @@ -1252,7 +1304,6 @@ void audio_reset_session(void) { sReverbDownsampleRateLog = 0; } - gReverbDownsampleRate = preset->reverbDownsampleRate; gVolume = preset->volume; gMinAiBufferLength = gSamplesPerFrameTarget - 0x10; updatesPerFrame = gSamplesPerFrameTarget / 160 + 1; @@ -1280,7 +1331,7 @@ void audio_reset_session(void) { temporaryMem = DOUBLE_SIZE_ON_64_BIT(preset->temporaryBankMem + preset->temporarySeqMem); #endif totalMem = persistentMem + temporaryMem; - wantMisc = gAudioSessionPool.size - totalMem - 0x100; + wantMisc = gAudioSessionPool.size - totalMem - 0x100 - BETTER_REVERB_SIZE; sSessionPoolSplit.wantSeq = wantMisc; sSessionPoolSplit.wantCustom = totalMem; session_pools_init(&sSessionPoolSplit); @@ -1423,6 +1474,24 @@ void audio_reset_session(void) { gSynthesisReverb.items[1][i].toDownsampleRight = mem + DEFAULT_LEN_1CH / sizeof(s16); } } + + // This does not have to be reset after being initialized for the first time, which would speed up load times dramatically. + // However, reseting this allows for proper clearing of the reverb buffers, as well as dynamic customization of the delays array. +#if defined(BETTER_REVERB) && (defined(VERSION_US) || defined(VERSION_JP)) + if (toggleBetterReverb) { + for (i = 0; i < NUM_ALLPASS; ++i) { + delaysL[i] = delaysBaselineL[i] / gReverbDownsampleRate; + delaysR[i] = delaysBaselineR[i] / gReverbDownsampleRate; + } + + delayBufsL = (s32**) soundAlloc(&gAudioSessionPool, NUM_ALLPASS * sizeof(s32*)); + delayBufsR = (s32**) soundAlloc(&gAudioSessionPool, NUM_ALLPASS * sizeof(s32*)); + for (i = 0; i < NUM_ALLPASS; ++i) { + delayBufsL[i] = (s32*) soundAlloc(&gAudioSessionPool, delaysL[i] * sizeof(s32)); + delayBufsR[i] = (s32*) soundAlloc(&gAudioSessionPool, delaysR[i] * sizeof(s32)); + } + } +#endif } #endif @@ -1684,7 +1753,7 @@ void func_sh_802f23ec(void) { s32 i; s32 idx; s32 seqCount; - u32 bankId1; // non symmetric fake match? can also change 0xff to 0xffU for same effect + s32 bankId1; s32 bankId2; s32 instId; s32 drumId; @@ -1697,7 +1766,7 @@ void func_sh_802f23ec(void) { for (idx = 0; idx < seqCount; idx++) { bankId1 = gCtlEntries[idx].bankId1; bankId2 = gCtlEntries[idx].bankId2; - if ((bankId1 != 0xff && entry->bankId == bankId1) || (bankId2 != 0xff && entry->bankId == bankId2) || entry->bankId == 0) { + if ((bankId1 != 0xffu && entry->bankId == bankId1) || (bankId2 != 0xff && entry->bankId == bankId2) || entry->bankId == 0) { if (get_bank_or_seq(1, 3, idx) != NULL) { if (IS_BANK_LOAD_COMPLETE(idx) != FALSE) { for (i = 0; i < gUnkPool2.numEntries; i++) { diff --git a/src/audio/heap.h b/src/audio/heap.h index e01dc8d4..4bc73bd3 100644 --- a/src/audio/heap.h +++ b/src/audio/heap.h @@ -131,12 +131,14 @@ void audio_reset_session(void); #else void audio_reset_session(struct AudioSessionSettings *preset); #endif +void discard_bank(s32 bankId); #ifdef VERSION_SH void fill_filter(s16 filter[8], s32 arg1, s32 arg2); u8 *func_sh_802f1d40(u32 size, s32 bank, u8 *arg2, s8 medium); u8 *func_sh_802f1d90(u32 size, s32 bank, u8 *arg2, s8 medium); void *unk_pool1_lookup(s32 poolIdx, s32 id); +void *unk_pool1_alloc(s32 poolIndex, s32 arg1, u32 size); #endif #endif // AUDIO_HEAP_H diff --git a/src/audio/internal.h b/src/audio/internal.h index 4446c6b1..68d9cf84 100644 --- a/src/audio/internal.h +++ b/src/audio/internal.h @@ -41,6 +41,11 @@ #define TATUMS_PER_BEAT 48 +// abi.h contains more details about the ADPCM and S8 codecs, "skip" skips codec processing +#define CODEC_ADPCM 0 +#define CODEC_S8 1 +#define CODEC_SKIP 2 + #ifdef VERSION_JP #define TEMPO_SCALE 1 #else @@ -378,8 +383,8 @@ union ReverbBits { /* 0x00 */ u8 asByte; }; struct ReverbInfo { - u8 reverb; - u8 bankId; + u8 reverbVol; + u8 synthesisVolume; // UQ4.4, although 0 <= x < 1 is rounded up to 1 u8 pan; union ReverbBits reverbBits; f32 freqScale; @@ -390,9 +395,9 @@ struct ReverbInfo { struct NoteAttributes { - u8 reverb; + u8 reverbVol; #ifdef VERSION_SH - u8 unk1; + u8 synthesisVolume; // UQ4.4, although 0 <= x < 1 is rounded up to 1 #endif #if defined(VERSION_EU) || defined(VERSION_SH) u8 pan; @@ -435,7 +440,7 @@ struct SequenceChannel #endif /*0x01, 0x02*/ u8 noteAllocPolicy; /*0x02, 0x03, 0x03*/ u8 muteBehavior; - /*0x03, 0x04, 0x04*/ u8 reverb; // or dry/wet mix + /*0x03, 0x04, 0x04*/ u8 reverbVol; // until EU: Q1.7, after EU: UQ0.8 /*0x04, ????*/ u8 notePriority; // 0-3 #ifdef VERSION_SH u8 unkSH06; // some priority @@ -450,7 +455,7 @@ struct SequenceChannel /*0x06, */ u8 updatesPerFrameUnused; #endif #ifdef VERSION_SH - /* 0x0C*/ u8 unkSH0C; // bankId + /* 0x0C*/ u8 synthesisVolume; // UQ4.4, although 0 <= x < 1 is rounded up to 1 #endif /*0x08, 0x0C, 0x0E*/ u16 vibratoRateStart; // initially 0x800 /*0x0A, 0x0E, 0x10*/ u16 vibratoExtentStart; @@ -526,7 +531,7 @@ struct SequenceChannelLayer // 0..0x3f; this makes 0x40..0x7f accessible as well) /*0x20, 0x24, 0x24*/ f32 freqScale; #ifdef VERSION_SH - /* 0x28*/ f32 unkSH28; + /* 0x28*/ f32 freqScaleMultiplier; #endif /*0x24, 0x28, 0x2C*/ f32 velocitySquare; #if defined(VERSION_JP) || defined(VERSION_US) @@ -567,8 +572,8 @@ struct NoteSynthesisState /*0x04, 0x06*/ u16 samplePosFrac; /*0x08*/ s32 samplePosInt; /*0x0C*/ struct NoteSynthesisBuffers *synthesisBuffers; - /*0x10*/ s16 curVolLeft; - /*0x12*/ s16 curVolRight; + /*0x10*/ s16 curVolLeft; // UQ0.16 (EU Q1.15) + /*0x12*/ s16 curVolRight; // UQ0.16 (EU Q1.15) }; struct NotePlaybackState { @@ -577,7 +582,7 @@ struct NotePlaybackState /* 0x01, 0x01*/ u8 waveId; /* 0x02, 0x02*/ u8 sampleCountIndex; #ifdef VERSION_SH - /* 0x03*/ u8 unkSH33; // bankId? + /* 0x03*/ u8 bankId; /* 0x04*/ u8 unkSH34; #endif /*0x08, 0x04, 0x06*/ s16 adsrVolScale; @@ -605,12 +610,16 @@ struct NoteSubEu /*0x01*/ u8 bookOffset : 3; /*0x01*/ u8 isSyntheticWave : 1; /*0x01*/ u8 hasTwoAdpcmParts : 1; +#ifdef VERSION_EU /*0x02*/ u8 bankId; +#else + /*0x02*/ u8 synthesisVolume; // UQ4.4, although 0 <= x < 1 is rounded up to 1 +#endif /*0x03*/ u8 headsetPanRight; /*0x04*/ u8 headsetPanLeft; - /*0x05*/ u8 reverbVol; - /*0x06*/ u16 targetVolLeft; - /*0x08*/ u16 targetVolRight; + /*0x05*/ u8 reverbVol; // UQ0.7 (EU Q1.7) + /*0x06*/ u16 targetVolLeft; // UQ0.12 (EU UQ0.10) + /*0x08*/ u16 targetVolRight; // UQ0.12 (EU UQ0.10) /*0x0A*/ u16 resamplingRateFixedPoint; // stored as signed but loaded as u16 /*0x0C*/ union { s16 *samples; @@ -638,7 +647,7 @@ struct Note /* 0x31, 0x31*/ u8 waveId; /* 0x32, 0x32*/ u8 sampleCountIndex; #ifdef VERSION_SH - /* 0x33*/ u8 unkSH33; // bankId? + /* 0x33*/ u8 bankId; /* 0x34*/ u8 unkSH34; #endif /*0x08, 0x34, 0x36*/ s16 adsrVolScale; @@ -696,17 +705,17 @@ struct Note /*0x30, 0x48*/ struct SequenceChannelLayer *wantedParentLayer; /*0x34*/ struct NoteSynthesisBuffers *synthesisBuffers; /*0x38*/ f32 frequency; - /*0x3C*/ u16 targetVolLeft; - /*0x3E*/ u16 targetVolRight; - /*0x40*/ u8 reverb; + /*0x3C*/ u16 targetVolLeft; // Q1.15, but will always be non-negative + /*0x3E*/ u16 targetVolRight; // Q1.15, but will always be non-negative + /*0x40*/ u8 reverbVol; // Q1.7 /*0x41*/ u8 unused1; // never read, set to 0x3f /*0x44*/ struct NoteAttributes attributes; /*0x54, 0x58*/ struct AdsrState adsr; /*0x74, 0x7C*/ struct Portamento portamento; /*0x84, 0x8C*/ struct VibratoState vibratoState; - /*0x9C*/ s16 curVolLeft; - /*0x9E*/ s16 curVolRight; - /*0xA0*/ s16 reverbVol; + /*0x9C*/ s16 curVolLeft; // Q1.15, but will always be non-negative + /*0x9E*/ s16 curVolRight; // Q1.15, but will always be non-negative + /*0xA0*/ s16 reverbVolShifted; // Q1.15 /*0xA2*/ s16 unused2; // never read, set to 0 /*0xA4, 0x00*/ struct AudioListItem listItem; /* */ u8 pad2[0xc]; diff --git a/src/audio/load.c b/src/audio/load.c index 054a0221..9ee4da8d 100644 --- a/src/audio/load.c +++ b/src/audio/load.c @@ -1,10 +1,13 @@ +#ifndef VERSION_SH #include +#include #include "data.h" #include "external.h" #include "heap.h" #include "load.h" #include "seqplayer.h" +#include "game/puppyprint.h" #define ALIGN16(val) (((val) + 0xF) & ~0xF) @@ -20,16 +23,11 @@ struct SharedDma { // EU only void port_eu_init(void); -// SH only -#if defined(VERSION_SH) -void func_sh_802f6a9c(void); -void func_sh_802f51d4(struct AudioBankSound *sound, struct AudioBank *memBase, struct PatchStruct *patchInfo); -#endif struct Note *gNotes; -#if defined(VERSION_EU) || defined(VERSION_SH) -static u8 pad[4]; +#if defined(VERSION_EU) +UNUSED static u8 pad[4]; #endif struct SequencePlayer gSequencePlayers[SEQUENCE_PLAYERS]; @@ -40,35 +38,6 @@ struct SequenceChannel gSequenceChannelNone; struct AudioListItem gLayerFreeList; struct NotePool gNoteFreeLists; -#ifdef VERSION_SH -struct AudioBankSample *D_SH_8034EA88[0x80]; -struct UnkStructSH8034EC88 D_SH_8034EC88[0x80]; -s32 D_SH_8034F688; // index into D_SH_8034EA88 -s32 D_SH_8034F68C; // index or size for D_SH_8034EC88 - -struct PendingDmaAudioBank { - s8 inProgress; - s8 timer; - s8 medium; - struct AudioBank *audioBank; - uintptr_t devAddr; - void *vAddr; - u32 remaining; - u32 transferSize; - u32 encodedInfo; - OSMesgQueue *retQueue; - OSMesgQueue dmaRetQueue; - OSMesg mesgs[1]; - OSIoMesg ioMesg; -}; -struct PendingDmaAudioBank D_SH_8034F690[16]; - -OSMesgQueue gUnkQueue1; -OSMesg gUnkMesgBufs1[0x10]; -OSMesgQueue gUnkQueue2; -OSMesg gUnkMesgBufs2[0x10]; -#endif - OSMesgQueue gCurrAudioFrameDmaQueue; OSMesg gCurrAudioFrameDmaMesgBufs[AUDIO_FRAME_DMA_QUEUE_SIZE]; OSIoMesg gCurrAudioFrameDmaIoMesgBufs[AUDIO_FRAME_DMA_QUEUE_SIZE]; @@ -77,11 +46,7 @@ OSMesgQueue gAudioDmaMesgQueue; OSMesg gAudioDmaMesg; OSIoMesg gAudioDmaIoMesg; -#ifdef VERSION_SH -struct SharedDma *sSampleDmas; // sh: 0x803503D0 -#else struct SharedDma sSampleDmas[0x60]; -#endif u32 gSampleDmaNumListItems; // sh: 0x803503D4 u32 sSampleDmaListSize1; // sh: 0x803503D8 u32 sUnused80226B40; // set to 0, never read, sh: 0x803503DC @@ -111,14 +76,11 @@ struct AudioBufferParametersEU gAudioBufferParameters; s32 gAiFrequency; #endif -#ifdef VERSION_SH -struct AudioBufferParametersEU gAudioBufferParameters; -#endif u32 sDmaBufSize; s32 gMaxAudioCmds; s32 gMaxSimultaneousNotes; -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) s16 gTempoInternalToExternal; #else s32 gSamplesPerFrameTarget; @@ -131,7 +93,7 @@ s8 gAudioUpdatesPerFrame; s8 gSoundMode; -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) s8 gAudioUpdatesPerFrame; #endif @@ -145,27 +107,9 @@ extern u8 gBankSetsData[]; // bank_sets.s ALSeqFile *get_audio_file_header(s32 arg0); -#ifdef VERSION_SH -void *func_sh_802f3688(s32 arg0); -void *get_bank_or_seq_wrapper(s32 arg0, s32 arg1); -void func_sh_802f3d78(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); -void func_sh_802f3c38(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 medium); -void func_sh_802f4a4c(s32 audioResetStatus); -void func_sh_802f4bd8(struct PendingDmaSample *arg0, s32 len); -void func_sh_802f4c5c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); -struct PendingDmaAudioBank *func_sh_802f4cb4(uintptr_t devAddr, void *vAddr, s32 size, s32 medium, s32 numChunks, OSMesgQueue *retQueue, s32 encodedInfo); -void func_sh_802f4dcc(s32 audioResetStatus); -void func_sh_802f4e50(struct PendingDmaAudioBank *audioBank, s32 audioResetStatus); -void func_sh_802f50ec(struct PendingDmaAudioBank *arg0, size_t len); -void func_sh_802f517c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); -s32 func_sh_802f5310(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo, s32 arg3); -void *func_sh_802F3564(s32 arg0); -#endif - /** * Performs an immediate DMA copy */ -#if !defined(VERSION_SH) void audio_dma_copy_immediate(uintptr_t devAddr, void *vAddr, size_t nbytes) { eu_stubbed_printf_3("Romcopy %x -> %x ,size %x\n", devAddr, vAddr, nbytes); osInvalDCache(vAddr, nbytes); @@ -174,7 +118,6 @@ void audio_dma_copy_immediate(uintptr_t devAddr, void *vAddr, size_t nbytes) { osRecvMesg(&gAudioDmaMesgQueue, NULL, OS_MESG_BLOCK); eu_stubbed_printf_0("Romcopyend\n"); } -#endif #ifdef VERSION_EU u8 audioString34[] = "CAUTION:WAVE CACHE FULL %d"; @@ -198,19 +141,25 @@ u8 audioString49[] = "BANK LOAD MISS! FOR %d\n"; /** * Performs an asynchronus (normal priority) DMA copy */ -#if !defined(VERSION_SH) void audio_dma_copy_async(uintptr_t devAddr, void *vAddr, size_t nbytes, OSMesgQueue *queue, OSIoMesg *mesg) { + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif osInvalDCache(vAddr, nbytes); osPiStartDma(mesg, OS_MESG_PRI_NORMAL, OS_READ, devAddr, vAddr, nbytes, queue); + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif } -#endif /** * Performs a partial asynchronous (normal priority) DMA copy. This is limited * to 0x1000 bytes transfer at once. */ -#ifndef VERSION_SH void audio_dma_partial_copy_async(uintptr_t *devAddr, u8 **vAddr, ssize_t *remaining, OSMesgQueue *queue, OSIoMesg *mesg) { + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif #if defined(VERSION_EU) ssize_t transfer = (*remaining >= 0x1000 ? 0x1000 : *remaining); #else @@ -221,14 +170,16 @@ void audio_dma_partial_copy_async(uintptr_t *devAddr, u8 **vAddr, ssize_t *remai osPiStartDma(mesg, OS_MESG_PRI_NORMAL, OS_READ, *devAddr, *vAddr, transfer, queue); *devAddr += transfer; *vAddr += transfer; + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif } -#endif void decrease_sample_dma_ttls() { u32 i; for (i = 0; i < sSampleDmaListSize1; i++) { -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) struct SharedDma *temp = &sSampleDmas[i]; #else struct SharedDma *temp = sSampleDmas + i; @@ -243,7 +194,7 @@ void decrease_sample_dma_ttls() { } for (i = sSampleDmaListSize1; i < gSampleDmaNumListItems; i++) { -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) struct SharedDma *temp = &sSampleDmas[i]; #else struct SharedDma *temp = sSampleDmas + i; @@ -260,40 +211,22 @@ void decrease_sample_dma_ttls() { sUnused80226B40 = 0; } -extern char shindouDebugPrint62[]; -#ifdef VERSION_SH -void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef, s32 medium) { - UNUSED s32 sp60; -#else void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef) { -#endif -#ifdef VERSION_SH - struct SharedDma *dma; - s32 hasDma = FALSE; -#else s32 hasDma = FALSE; struct SharedDma *dma; -#endif uintptr_t dmaDevAddr; -#ifdef VERSION_SH - UNUSED u32 pad; - u32 dmaIndex; - u32 transfer; -#else u32 transfer; u32 i; u32 dmaIndex; -#endif ssize_t bufferPos; -#ifdef VERSION_SH - u32 i; -#else UNUSED u32 pad; -#endif + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif if (arg2 != 0 || *dmaIndexRef >= sSampleDmaListSize1) { for (i = sSampleDmaListSize1; i < gSampleDmaNumListItems; i++) { -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) dma = &sSampleDmas[i]; #else dma = sSampleDmas + i; @@ -314,9 +247,15 @@ void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef) { } dma->ttl = 60; *dmaIndexRef = (u8) i; -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif return &dma->buffer[(devAddr - dma->source)]; #else + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif return (devAddr - dma->source) + dma->buffer; #endif } @@ -356,18 +295,21 @@ void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef) { sSampleDmaReuseQueueTail1++; } dma->ttl = 2; -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif return dma->buffer + (devAddr - dma->source); #else + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif return (devAddr - dma->source) + dma->buffer; #endif } } if (!hasDma) { -#ifdef VERSION_SH - if (1) {} -#endif // Allocate a DMA from reuse queue 1. This queue will hopefully never // be empty, since TTL 2 is so small. dmaIndex = sSampleDmaReuseQueue1[sSampleDmaReuseQueueTail1++]; @@ -387,17 +329,18 @@ void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef) { osPiStartDma(&gCurrAudioFrameDmaIoMesgBufs[gCurrAudioFrameDmaCount++], OS_MESG_PRI_NORMAL, OS_READ, dmaDevAddr, dma->buffer, transfer, &gCurrAudioFrameDmaQueue); *dmaIndexRef = dmaIndex; - return (devAddr - dmaDevAddr) + dma->buffer; -#elif defined (VERSION_SH) - func_sh_802f3dd0(&gCurrAudioFrameDmaIoMesgBufs[gCurrAudioFrameDmaCount++], OS_MESG_PRI_NORMAL, OS_READ, - dmaDevAddr, dma->buffer, transfer, &gCurrAudioFrameDmaQueue, medium, shindouDebugPrint62); - *dmaIndexRef = dmaIndex; + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif return (devAddr - dmaDevAddr) + dma->buffer; #else gCurrAudioFrameDmaCount++; osPiStartDma(&gCurrAudioFrameDmaIoMesgBufs[gCurrAudioFrameDmaCount - 1], OS_MESG_PRI_NORMAL, OS_READ, dmaDevAddr, dma->buffer, transfer, &gCurrAudioFrameDmaQueue); *dmaIndexRef = dmaIndex; + #if PUPPYPRINT_DEBUG + dmaAudioTime[perfIteration] += osGetTime()-first; + #endif return dma->buffer + (devAddr - dmaDevAddr); #endif } @@ -405,7 +348,7 @@ void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef) { void init_sample_dma_buffers(UNUSED s32 arg0) { s32 i; -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) #define j i #else s32 j; @@ -413,25 +356,16 @@ void init_sample_dma_buffers(UNUSED s32 arg0) { #if defined(VERSION_EU) sDmaBufSize = 0x400; -#elif defined(VERSION_SH) - sDmaBufSize = 0x2D0; - sSampleDmas = sound_alloc_uninitialized(&gNotesAndBuffersPool, - gMaxSimultaneousNotes * 4 * sizeof(struct SharedDma) * gAudioBufferParameters.presetUnk4); #else sDmaBufSize = 144 * 9; #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) for (i = 0; i < gMaxSimultaneousNotes * 3 * gAudioBufferParameters.presetUnk4; i++) #else for (i = 0; i < gMaxSimultaneousNotes * 3; i++) #endif { -#if defined(VERSION_SH) - if ((sSampleDmas[gSampleDmaNumListItems].buffer = sound_alloc_uninitialized(&gNotesAndBuffersPool, sDmaBufSize)) == NULL) { - break; - } -#else sSampleDmas[gSampleDmaNumListItems].buffer = soundAlloc(&gNotesAndBuffersPool, sDmaBufSize); if (sSampleDmas[gSampleDmaNumListItems].buffer == NULL) { #if defined(VERSION_EU) @@ -440,7 +374,6 @@ void init_sample_dma_buffers(UNUSED s32 arg0) { goto out1; #endif } -#endif sSampleDmas[gSampleDmaNumListItems].bufSize = sDmaBufSize; sSampleDmas[gSampleDmaNumListItems].source = 0; sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0; @@ -465,19 +398,12 @@ out1: sSampleDmaReuseQueueHead1 = (u8) gSampleDmaNumListItems; sSampleDmaListSize1 = gSampleDmaNumListItems; -#if defined(VERSION_SH) - sDmaBufSize = 0x2D0; -#elif defined(VERSION_EU) +#if defined(VERSION_EU) sDmaBufSize = 0x200; #else sDmaBufSize = 160 * 9; #endif for (i = 0; i < gMaxSimultaneousNotes; i++) { -#if defined(VERSION_SH) - if ((sSampleDmas[gSampleDmaNumListItems].buffer = sound_alloc_uninitialized(&gNotesAndBuffersPool, sDmaBufSize)) == NULL) { - break; - } -#else sSampleDmas[gSampleDmaNumListItems].buffer = soundAlloc(&gNotesAndBuffersPool, sDmaBufSize); if (sSampleDmas[gSampleDmaNumListItems].buffer == NULL) { #if defined(VERSION_EU) @@ -486,17 +412,11 @@ out1: goto out2; #endif } -#endif -#if defined(VERSION_SH) sSampleDmas[gSampleDmaNumListItems].bufSize = sDmaBufSize; -#endif sSampleDmas[gSampleDmaNumListItems].source = 0; sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0; sSampleDmas[gSampleDmaNumListItems].unused2 = 0; sSampleDmas[gSampleDmaNumListItems].ttl = 0; -#ifndef VERSION_SH - sSampleDmas[gSampleDmaNumListItems].bufSize = sDmaBufSize; -#endif gSampleDmaNumListItems++; } #if defined(VERSION_JP) || defined(VERSION_US) @@ -516,68 +436,15 @@ out2: sSampleDmaReuseQueueTail2 = 0; sSampleDmaReuseQueueHead2 = gSampleDmaNumListItems - sSampleDmaListSize1; -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) #undef j #endif } -#ifndef static -// Keep supporting the good old "#define static" hack. -#undef static -#endif - -#if defined(VERSION_SH) -void patch_seq_file(ALSeqFile *seqFile, u8 *data, u16 arg2) { - ALSeqFile *phi_a2; - s32 i; - - seqFile->unk2 = arg2; - seqFile->data = data; - for (i = 0; i < seqFile->seqCount; i++) { - if (seqFile->seqArray[i].len != 0 && seqFile->seqArray[i].magic[0] == 2) { - seqFile->seqArray[i].offset += (uintptr_t)data; - } - } -} - -void *func_sh_802f2e24(s32 arg0, s32 *arg1) { - s32 phi_s2; - s32 phi_s0; - s32 phi_s1; - void *sp28; - - phi_s0 = ((u16 *)gAlBankSets)[func_sh_802f39a0(0, arg0)]; - phi_s1 = gAlBankSets[phi_s0++]; - phi_s2 = 0xFF; - while (phi_s1 > 0) { - phi_s2 = gAlBankSets[phi_s0++]; - phi_s2 = (s32) phi_s2; - sp28 = func_sh_802f3688(phi_s2); - phi_s1--; - } - *arg1 = phi_s2; - return sp28; -} -#endif - #if defined(VERSION_JP) || defined(VERSION_US) // This function gets optimized out on US due to being static and never called -static +UNUSED static #endif -#if defined(VERSION_SH) -void preload_sequence(s32 arg0, s32 arg1) { - UNUSED s32 pad; - s32 sp18; - - arg0 = func_sh_802f39a0(0, arg0); - if (arg1 & PRELOAD_BANKS) { - func_sh_802f2e24(arg0, &sp18); - } - if (arg1 & PRELOAD_SEQUENCE) { - func_sh_802F3564(arg0); - } -} -#else void patch_sound(UNUSED struct AudioBankSound *sound, UNUSED u8 *memBase, UNUSED u8 *offsetBase) { struct AudioBankSample *sample; void *patched; @@ -613,9 +480,11 @@ void patch_sound(UNUSED struct AudioBankSound *sound, UNUSED u8 *memBase, UNUSED #undef PATCH } -#endif -#if defined(VERSION_JP) || defined(VERSION_US) +#ifdef VERSION_EU +#define PATCH_SOUND patch_sound +#else +// copt inline of the above #define PATCH_SOUND(_sound, mem, offset) \ { \ struct AudioBankSound *sound = _sound; \ @@ -640,457 +509,40 @@ void patch_sound(UNUSED struct AudioBankSound *sound, UNUSED u8 *memBase, UNUSED } #endif -#if defined(VERSION_SH) -s32 func_sh_802f2f38(struct AudioBankSample *sample, s32 bankId) { - u8 *sp24; - - if (sample->isPatched == TRUE && sample->medium != 0) { - sp24 = func_sh_802f1d90(sample->size, bankId, sample->sampleAddr, sample->medium); - if (sp24 == NULL) { - return -1; - } - if (sample->medium == 1) { - func_sh_802f3d78(sample->sampleAddr, sp24, sample->size, gAlTbl->unk2); - } else { - func_sh_802f3c38(sample->sampleAddr, sp24, sample->size, sample->medium); - } - sample->medium = 0; - sample->sampleAddr = sp24; - } -} - -s32 func_sh_802f3024(s32 bankId, s32 instId, s32 arg2) { - struct Instrument *instr; - struct Drum *drum; - - if (instId < 0x7F) { - instr = get_instrument_inner(bankId, instId); - if (instr == NULL) { - return -1; - } - if (instr->normalRangeLo != 0) { - func_sh_802f2f38(instr->lowNotesSound.sample, bankId); - } - func_sh_802f2f38(instr->normalNotesSound.sample, bankId); - if (instr->normalRangeHi != 0x7F) { - func_sh_802f2f38(instr->highNotesSound.sample, bankId); - } - //! missing return - } else if (instId == 0x7F) { - drum = get_drum(bankId, arg2); - if (drum == NULL) { - return -1; - } - func_sh_802f2f38(drum->sound.sample, bankId); - return 0; - } -} - -void func_sh_802f30f4(s32 arg0, s32 arg1, s32 arg2, OSMesgQueue *arg3) { - if (func_802f3f08(2, func_sh_802f39a0(2, arg0), arg1, arg2, arg3) == 0) { - osSendMesg(arg3, 0, 0); - } -} - -void func_sh_802f3158(s32 index, s32 numChunks, s32 arg2, OSMesgQueue *retQueue) { - s32 val; - s32 v; - - val = ((u16 *) gAlBankSets)[func_sh_802f39a0(0, index)]; - v = gAlBankSets[val++]; - - while (v > 0) { - func_802f3f08(1, func_sh_802f39a0(1, gAlBankSets[val++]), numChunks, arg2, retQueue); - v--; - } -} - -u8 *func_sh_802f3220(u32 index, u32 *a1) { - s32 val; - - val = ((u16 *) gAlBankSets)[func_sh_802f39a0(0, index)]; - *a1 = gAlBankSets[val++]; - if (*a1 == 0) { - return NULL; - } - return &gAlBankSets[val]; -} - -void func_sh_802f3288(s32 idx) { - s32 s0; - s32 s2; - - idx = ((u16*)gAlBankSets)[func_sh_802f39a0(0, idx)]; - s2 = gAlBankSets[idx++]; - while (s2 > 0) { - s2--; - s0 = func_sh_802f39a0(1, gAlBankSets[idx++]); - - if (unk_pool1_lookup(1, s0) == 0) { - func_sh_802f3368(s0); - if (gBankLoadStatus[s0] != 5) { - gBankLoadStatus[s0] = 0; - } - - continue; - } - - } -} - -s32 func_sh_802f3368(s32 arg0) { - struct SoundMultiPool *pool = &gBankLoadedPool; - struct TemporaryPool *temporary = &pool->temporary; - struct PersistentPool *persistent; - u32 i; - - if (temporary->entries[0].id == arg0) { - temporary->entries[0].id = -1; - } else if (arg0 == temporary->entries[1].id) { - temporary->entries[1].id = -1; - } - - persistent = &pool->persistent; - for (i = 0; i < persistent->numEntries; i++) { - if (persistent->entries[i].id == arg0) { - persistent->entries[i].id = -1; - } - - } - - discard_bank(arg0); -} - - -void func_sh_802F3430(s32 arg0, s32 arg1, s32 arg2); -void func_sh_802F3410(s32 arg0, s32 arg1, s32 arg2) { - func_sh_802F3430(arg0, arg1, arg2); -} - -void func_sh_802F3430(s32 arg0, s32 arg1, s32 arg2) { - struct SequencePlayer *seqPlayer; - u8 *seqData; - u32 temp; - u32 s0; - s32 s1; - u8 bank; - u32 id; - - seqPlayer = &gSequencePlayers[arg0]; - - temp = func_sh_802f39a0(0, arg1); - sequence_player_disable(seqPlayer); - id = temp; - - s0 = ((u16 *) gAlBankSets)[id]; - s1 = gAlBankSets[s0++]; - bank = 0xff; - - while (s1 > 0) { - bank = gAlBankSets[s0++]; - func_sh_802f3688(bank); - s1--; - } - - seqData = func_sh_802F3564(id); - init_sequence_player(arg0); - seqPlayer->seqId = id; - seqPlayer->defaultBank[0] = bank; - seqPlayer->enabled = 1; - seqPlayer->seqData = seqData; - seqPlayer->scriptState.pc = seqData; - seqPlayer->scriptState.depth = 0; - seqPlayer->delay = 0; - seqPlayer->finished = 0; - - if (id) { - } - - for (id = 0; id < 0x10; id++) { - } - -} - -void *func_sh_802F3564(s32 arg0) { - void *a = func_sh_802f39a0(0, arg0); - s32 b; - return func_sh_802f3764(0, a, &b); -} - -extern u8 gUnkLoadStatus[0x40]; - -void *func_sh_802f3598(s32 idx, s32 *medium) { - void *ret; - ALSeqFile *f; - s32 temp; - s32 sp28; - - f = get_audio_file_header(2); - idx = func_sh_802f39a0(2, idx); - ret = get_bank_or_seq_wrapper(2, idx); - if (ret != NULL) { - if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { - gUnkLoadStatus[idx] = SOUND_LOAD_STATUS_COMPLETE; - } - - *medium = 0; - return ret; - } - - temp = f->seqArray[idx].magic[1]; - if (temp == 4) { - *medium = f->seqArray[idx].magic[0]; - return f->seqArray[idx].offset; - } else { - ret = func_sh_802f3764(2, idx, &sp28); - if (ret != 0) { - *medium = 0; - return ret; - } - - *medium = f->seqArray[idx].magic[0]; - } - return f->seqArray[idx].offset; - -} - -void *func_sh_802f3688(s32 idx) { - void *ret; - s32 bankId1; - s32 bankId2; - s32 sp38; - struct PatchStruct patchInfo; - - idx = func_sh_802f39a0(1, idx); - bankId1 = gCtlEntries[idx].bankId1; - bankId2 = gCtlEntries[idx].bankId2; - - patchInfo.bankId1 = bankId1; - patchInfo.bankId2 = bankId2; - - if (patchInfo.bankId1 != 0xFF) { - patchInfo.baseAddr1 = func_sh_802f3598(patchInfo.bankId1, &patchInfo.medium1); - } else { - patchInfo.baseAddr1 = NULL; - } - - if (bankId2 != 0xFF) { - patchInfo.baseAddr2 = func_sh_802f3598(bankId2, &patchInfo.medium2); - } else { - patchInfo.baseAddr2 = NULL; - } - - if ((ret = func_sh_802f3764(1, idx, &sp38)) == NULL) { - return NULL; - } - - if (sp38 == 1) { - func_sh_802f5310(idx, ret, &patchInfo, 0); - } - - return ret; -} - -void *func_sh_802f3764(s32 poolIdx, s32 idx, s32 *arg2) { - s32 size; - ALSeqFile *f; - void *vAddr; - s32 sp30; - UNUSED u32 pad2; - u8 *devAddr; - s8 loadStatus; - s32 sp18; - - vAddr = get_bank_or_seq_wrapper(poolIdx, idx); - if (vAddr != NULL) { - *arg2 = 0; - loadStatus = SOUND_LOAD_STATUS_COMPLETE; - } else { - f = get_audio_file_header(poolIdx); - size = f->seqArray[idx].len; - size = ALIGN16(size); - sp30 = f->seqArray[idx].magic[0]; - sp18 = f->seqArray[idx].magic[1]; - devAddr = f->seqArray[idx].offset; - - - switch (sp18) - { - case 0: - vAddr = unk_pool1_alloc(poolIdx, idx, size); - if (vAddr == NULL) { - return vAddr; - } - break; - case 1: - vAddr = alloc_bank_or_seq(poolIdx, size, 1, idx); - if (vAddr == NULL) { - return vAddr; - } - break; - case 2: - vAddr = alloc_bank_or_seq(poolIdx, size, 0, idx); - if (vAddr == NULL) { - return vAddr; - } - break; - - case 3: - case 4: - vAddr = alloc_bank_or_seq(poolIdx, size, 2, idx); - if (vAddr == NULL) { - return vAddr; - } - break; - } - - *arg2 = 1; - if (sp30 == 1) { - func_sh_802f3d78((uintptr_t) devAddr, vAddr, size, f->unk2); - } else { - func_sh_802f3c38((uintptr_t) devAddr, vAddr, size, sp30); - } - - switch (sp18) - { - case 0: - loadStatus = SOUND_LOAD_STATUS_5; - break; - - default: - loadStatus = SOUND_LOAD_STATUS_COMPLETE; - break; - } - } - - switch (poolIdx) - { - case 0: - if (gSeqLoadStatus[idx] != SOUND_LOAD_STATUS_5) { - gSeqLoadStatus[idx] = loadStatus; - } - break; - - case 1: - if (gBankLoadStatus[idx] != SOUND_LOAD_STATUS_5) { - gBankLoadStatus[idx] = loadStatus; - } - break; - - case 2: - if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { - gUnkLoadStatus[idx] = loadStatus; - } - break; - } - - return vAddr; -} - -s32 func_sh_802f39a0(s32 arg0, s32 idx) { - ALSeqFile *f; - - f = get_audio_file_header(arg0); - if (f->seqArray[idx].len == 0) { - idx = (s32) f->seqArray[idx].offset; // TODO: something doesn't seem right here... - } - return idx; -} - -void *get_bank_or_seq_wrapper(s32 poolIdx, s32 id) { - void *ret; - - ret = unk_pool1_lookup(poolIdx, id); - if (ret != NULL) { - return ret; - } - ret = get_bank_or_seq(poolIdx, 2, id); - if (ret != 0) { - return ret; - } - return NULL; -} - -ALSeqFile *get_audio_file_header(s32 index) { - ALSeqFile *ret; - switch(index) { - default: - ret = NULL; - break; - case 0: - ret = gSeqFileHeader; - break; - case 1: - ret = gAlCtlHeader; - break; - case 2: - ret = gAlTbl; - break; - } - return ret; -} -#endif - // on US/JP this inlines patch_sound, using some -sopt compiler flag -#if defined(VERSION_SH) -void patch_audio_bank(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo) { -#else void patch_audio_bank(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32 numDrums) { -#endif struct Instrument *instrument; -#if defined(VERSION_SH) - void **itInstrs; -#else struct Instrument **itInstrs; -#endif struct Instrument **end; -#if defined(VERSION_SH) - s32 i; -#else - struct AudioBank *temp; // Maybe Shindou also has this; I'm not sure. + struct AudioBank *temp; u32 i; -#endif void *patched; struct Drum *drum; -#ifndef VERSION_SH struct Drum **drums; -#endif #if defined(VERSION_EU) u32 numDrums2; -#elif defined(VERSION_SH) - s32 numDrums2; - s32 numInstruments2; #endif -#define BASE_OFFSET(x, base) (void *)((uintptr_t) (x) + (uintptr_t) base) -#define PATCH(x, base) (patched = BASE_OFFSET(x, base)) +#define BASE_OFFSET_REAL(x, base) (void *)((uintptr_t) (x) + (uintptr_t) base) +#define PATCH(x, base) (patched = BASE_OFFSET_REAL(x, base)) #define PATCH_MEM(x) x = PATCH(x, mem) -#if defined(VERSION_SH) - numDrums2 = gCtlEntries[bankId].numDrums; - numInstruments2 = gCtlEntries[bankId].numInstruments; - itInstrs = mem->drums; - if (mem->drums) { - } +#if defined(VERSION_JP) || defined(VERSION_US) +#define BASE_OFFSET(x, base) BASE_OFFSET_REAL(x, base) #else - drums = mem->drums; +#define BASE_OFFSET(x, base) BASE_OFFSET_REAL(base, x) #endif + + drums = mem->drums; #if defined(VERSION_JP) || defined(VERSION_US) if (drums != NULL && numDrums > 0) { mem->drums = (void *)((uintptr_t) drums + (uintptr_t) mem); if (numDrums > 0) //! unneeded when -sopt is enabled for (i = 0; i < numDrums; i++) { #else -#if defined(VERSION_EU) numDrums2 = numDrums; if (drums != NULL && numDrums2 > 0) { mem->drums = PATCH(drums, mem); -#elif defined(VERSION_SH) - if (itInstrs != NULL && numDrums2 != 0) { - if (1) { - mem->drums = PATCH(itInstrs, mem); - } -#endif for (i = 0; i < numDrums2; i++) { #endif patched = mem->drums[i]; @@ -1102,16 +554,11 @@ void patch_audio_bank(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32 //! copt replaces drum with 'patched' for these two lines PATCH_SOUND(&(*(struct Drum *)patched).sound, mem, offset); patched = (*(struct Drum *)patched).envelope; - drum->envelope = BASE_OFFSET(mem, patched); #else -#if defined(VERSION_EU) patch_sound(&drum->sound, (u8 *) mem, offset); -#elif defined(VERSION_SH) - func_sh_802f51d4(&drum->sound, mem, patchInfo); -#endif patched = drum->envelope; - drum->envelope = BASE_OFFSET(patched, mem); #endif + drum->envelope = BASE_OFFSET(mem, patched); drum->loaded = 1; } @@ -1119,25 +566,17 @@ void patch_audio_bank(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32 } } -#ifndef VERSION_SH //! Doesn't affect EU, but required for US/JP temp = &*mem; -#endif #if defined(VERSION_JP) || defined(VERSION_US) if (numInstruments >= 1) #endif -#if defined(VERSION_SH) - if (numInstruments2 > 0) { - itInstrs = mem->instruments; - end = numInstruments2 + (struct Instrument **) itInstrs; -#else if (numInstruments > 0) { //! Doesn't affect EU, but required for US/JP struct Instrument **tempInst; itInstrs = temp->instruments; tempInst = temp->instruments; end = numInstruments + tempInst; -#endif #if defined(VERSION_JP) || defined(VERSION_US) l2: @@ -1145,141 +584,35 @@ l2: do { #endif if (*itInstrs != NULL) { -#ifdef VERSION_SH - *itInstrs = BASE_OFFSET(mem, *itInstrs); -#else *itInstrs = BASE_OFFSET(*itInstrs, mem); -#endif instrument = *itInstrs; if (instrument->loaded == 0) { -#if defined(VERSION_JP) || defined(VERSION_US) PATCH_SOUND(&instrument->lowNotesSound, (u8 *) mem, offset); PATCH_SOUND(&instrument->normalNotesSound, (u8 *) mem, offset); PATCH_SOUND(&instrument->highNotesSound, (u8 *) mem, offset); -#elif defined(VERSION_EU) - patch_sound(&instrument->lowNotesSound, (u8 *) mem, offset); - patch_sound(&instrument->normalNotesSound, (u8 *) mem, offset); - patch_sound(&instrument->highNotesSound, (u8 *) mem, offset); -#elif defined(VERSION_SH) - if (instrument->normalRangeLo != 0) { - func_sh_802f51d4(&instrument->lowNotesSound, mem, patchInfo); - } - func_sh_802f51d4(&instrument->normalNotesSound, mem, patchInfo); - if (instrument->normalRangeHi != 0x7F) { - func_sh_802f51d4(&instrument->highNotesSound, mem, patchInfo); - } -#endif patched = instrument->envelope; - -#if defined(VERSION_JP) || defined(VERSION_US) instrument->envelope = BASE_OFFSET(mem, patched); instrument->loaded = 1; -#else - instrument->envelope = BASE_OFFSET(patched, mem); - instrument->loaded = 1; -#endif } } -#ifndef VERSION_SH itInstrs++; -#else - itInstrs = ((struct Instrument **) itInstrs) + 1; -#endif #if defined(VERSION_JP) || defined(VERSION_US) //! goto generated by copt, required to match US/JP if (end != itInstrs) { goto l2; } #else -#ifdef VERSION_EU } while (end != itInstrs); -#else - } while ((struct Instrument **) itInstrs != (0, end)); //! This is definitely fake -#endif #endif } -#if defined(VERSION_SH) - gCtlEntries[bankId].drums = mem->drums; - gCtlEntries[bankId].instruments = mem->instruments; -#endif #undef PATCH_MEM #undef PATCH +#undef BASE_OFFSET_REAL #undef BASE_OFFSET #undef PATCH_SOUND } -#if defined(VERSION_SH) -void func_sh_802f3ed4(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED void *vAddr, UNUSED size_t nbytes); - -extern char shindouDebugPrint81[]; -extern char shindouDebugPrint82[]; -void func_sh_802f3c38(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 medium) { - nbytes = ALIGN16(nbytes); - osInvalDCache(vAddr, nbytes); - -lock: - if (gAudioLoadLockSH != 0) { - goto lock; - } - - if (nbytes >= 0x400U) { - func_sh_802f3dd0(&gAudioDmaIoMesg, 1, 0, devAddr, vAddr, 0x400, &gAudioDmaMesgQueue, medium, shindouDebugPrint81); - osRecvMesg(&gAudioDmaMesgQueue, NULL, 1); - nbytes = nbytes - 0x400; - devAddr = devAddr + 0x400; - vAddr = (u8*)vAddr + 0x400; - goto lock; - } - - if (nbytes != 0) { - func_sh_802f3dd0(&gAudioDmaIoMesg, 1, 0, devAddr, vAddr, nbytes, &gAudioDmaMesgQueue, medium, shindouDebugPrint82); - osRecvMesg(&gAudioDmaMesgQueue, NULL, 1); - } -} - -void func_sh_802f3d78(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { - uintptr_t sp1C; - - sp1C = devAddr; - osInvalDCache(vAddr, nbytes); - func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); -} - -s32 func_sh_802f3dd0(OSIoMesg *m, s32 pri, s32 direction, uintptr_t devAddr, void *dramAddr, s32 size, OSMesgQueue *retQueue, s32 medium, const char *arg8) { - OSPiHandle *handle; - if (gAudioLoadLockSH >= 0x11U) { - return -1; - } - switch (medium) { - case 2: - handle = osCartRomInit(); - break; - default: - return 0; - } - if ((size & 0xf) != 0) { - size = ALIGN16(size); - } - m->hdr.pri = pri; - m->hdr.retQueue = retQueue; - m->dramAddr = dramAddr; - m->devAddr = devAddr; - m->size = size; - handle->transferInfo.cmdType = 2; - osEPiStartDma(handle, m, direction); - return 0; -} - -s32 func_sh_802f3ec4(UNUSED s32 arg0, UNUSED uintptr_t *arg1) { - return 0; -} - -void func_sh_802f3ed4(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED void *vAddr, UNUSED size_t nbytes) { -} -#endif - -#ifndef VERSION_SH struct AudioBank *bank_load_immediate(s32 bankId, s32 arg1) { UNUSED u32 pad1[4]; u32 buf[4]; @@ -1311,9 +644,7 @@ struct AudioBank *bank_load_immediate(s32 bankId, s32 arg1) { gBankLoadStatus[bankId] = SOUND_LOAD_STATUS_COMPLETE; return ret; } -#endif -#ifndef VERSION_SH struct AudioBank *bank_load_async(s32 bankId, s32 arg1, struct SequencePlayer *seqPlayer) { u32 numInstruments, numDrums; UNUSED u32 pad1[2]; @@ -1369,9 +700,7 @@ struct AudioBank *bank_load_async(s32 bankId, s32 arg1, struct SequencePlayer *s gBankLoadStatus[bankId] = SOUND_LOAD_STATUS_IN_PROGRESS; return ret; } -#endif -#ifndef VERSION_SH void *sequence_dma_immediate(s32 seqId, s32 arg1) { s32 seqLength; void *ptr; @@ -1389,9 +718,7 @@ void *sequence_dma_immediate(s32 seqId, s32 arg1) { gSeqLoadStatus[seqId] = SOUND_LOAD_STATUS_COMPLETE; return ptr; } -#endif -#ifndef VERSION_SH void *sequence_dma_async(s32 seqId, s32 arg1, struct SequencePlayer *seqPlayer) { s32 seqLength; void *ptr; @@ -1428,9 +755,7 @@ void *sequence_dma_async(s32 seqId, s32 arg1, struct SequencePlayer *seqPlayer) } return ptr; } -#endif -#ifndef VERSION_SH u8 get_missing_bank(u32 seqId, s32 *nonNullCount, s32 *nullCount) { void *temp; u32 bankId; @@ -1440,7 +765,7 @@ u8 get_missing_bank(u32 seqId, s32 *nonNullCount, s32 *nullCount) { *nullCount = 0; *nonNullCount = 0; -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) offset = ((u16 *) gAlBankSets)[seqId]; for (i = gAlBankSets[offset++], ret = 0; i != 0; i--) { bankId = gAlBankSets[offset++]; @@ -1452,12 +777,10 @@ u8 get_missing_bank(u32 seqId, s32 *nonNullCount, s32 *nullCount) { #endif if (IS_BANK_LOAD_COMPLETE(bankId) == TRUE) { -#ifndef VERSION_SH -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) temp = get_bank_or_seq(&gBankLoadedPool, 2, bankId); #else temp = get_bank_or_seq(&gBankLoadedPool, 2, gAlBankSets[offset - 1]); -#endif #endif } else { temp = NULL; @@ -1473,12 +796,10 @@ u8 get_missing_bank(u32 seqId, s32 *nonNullCount, s32 *nullCount) { return ret; } -#endif -#ifndef VERSION_SH -struct AudioBank *load_banks_immediate(s32 seqId, u8 *arg1) { - void *ret; - u32 bankId; +struct AudioBank *load_banks_immediate(s32 seqId, u8 *outDefaultBank) { + void *ret = NULL; + u32 bankId = 0; u16 offset; u8 i; @@ -1507,12 +828,10 @@ struct AudioBank *load_banks_immediate(s32 seqId, u8 *arg1) { ret = bank_load_immediate(bankId, 2); } } - *arg1 = bankId; + *outDefaultBank = bankId; return ret; } -#endif -#ifndef VERSION_SH void preload_sequence(u32 seqId, u8 preloadMask) { void *sequenceData; u8 temp; @@ -1542,9 +861,7 @@ void preload_sequence(u32 seqId, u8 preloadMask) { gAudioLoadLock = AUDIO_LOCK_NOT_LOADING; } -#endif -#ifndef VERSION_SH void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync); void load_sequence(u32 player, u32 seqId, s32 loadAsync) { @@ -1556,9 +873,7 @@ void load_sequence(u32 player, u32 seqId, s32 loadAsync) { gAudioLoadLock = AUDIO_LOCK_NOT_LOADING; } } -#endif -#ifndef VERSION_SH void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) { void *sequenceData; struct SequencePlayer *seqPlayer = &gSequencePlayers[player]; @@ -1572,26 +887,16 @@ void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) { if (loadAsync) { s32 numMissingBanks = 0; s32 dummy = 0; -#ifdef VERSION_SH - s32 bankId = 0xBA17; // dummy code to avoid problems -#else s32 bankId = get_missing_bank(seqId, &dummy, &numMissingBanks); -#endif if (numMissingBanks == 1) { -#ifndef VERSION_SH eu_stubbed_printf_0("Ok,one bank slow load Start \n"); if (bank_load_async(bankId, 2, seqPlayer) == NULL) { return; } -#endif // @bug This should set the last bank (i.e. the first in the JSON) // as default, not the missing one. This code path never gets // taken, though -- all sequence loading is synchronous. seqPlayer->defaultBank[0] = bankId; -#ifdef VERSION_SH - } - } -#else } else { eu_stubbed_printf_1("Sorry,too many %d bank is none.fast load Start \n", numMissingBanks); if (load_banks_immediate(seqId, &seqPlayer->defaultBank[0]) == NULL) { @@ -1601,29 +906,23 @@ void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) { } else if (load_banks_immediate(seqId, &seqPlayer->defaultBank[0]) == NULL) { return; } -#endif eu_stubbed_printf_2("Seq %d:Default Load Id is %d\n", seqId, seqPlayer->defaultBank[0]); eu_stubbed_printf_0("Seq Loading Start\n"); seqPlayer->seqId = seqId; -#ifndef VERSION_SH sequenceData = get_bank_or_seq(&gSeqLoadedPool, 2, seqId); -#endif if (sequenceData == NULL) { if (seqPlayer->seqDmaInProgress) { eu_stubbed_printf_0("Error:Before Sequence-SlowDma remain.\n"); eu_stubbed_printf_0(" Cancel Seq Start.\n"); return; } -#ifndef VERSION_SH if (loadAsync) { sequenceData = sequence_dma_async(seqId, 2, seqPlayer); } else { - sequenceData = sequence_dma_immediate(seqId, 2); } -#endif if (sequenceData == NULL) { return; @@ -1638,142 +937,11 @@ void load_sequence_internal(u32 player, u32 seqId, s32 loadAsync) { seqPlayer->seqData = sequenceData; seqPlayer->scriptState.pc = sequenceData; } -#endif -#if defined(VERSION_SH) -void *func_sh_802f3ee8(uintptr_t devAddr, void *vAddr) { - s32 b; - return func_sh_802f3764(devAddr, vAddr, &b); -} - -void *func_802f3f08(s32 poolIdx, s32 idx, s32 numChunks, s32 arg3, OSMesgQueue *retQueue) { - s32 size; - ALSeqFile *f; - void *vAddr; - s32 medium; - s32 sp18; - uintptr_t devAddr; - s32 loadStatus; - - switch (poolIdx) { - case 0: - if (gSeqLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { - return 0; - } - break; - case 1: - if (gBankLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { - return 0; - } - break; - case 2: - if (gUnkLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { - return 0; - } - break; - - } - vAddr = get_bank_or_seq_wrapper(poolIdx, idx); - if (vAddr != NULL) { - loadStatus = 2; - osSendMesg(retQueue, (OSMesg) (arg3 << 0x18), 0); - } else { - f = get_audio_file_header(poolIdx); - size = f->seqArray[idx].len; - size = ALIGN16(size); - medium = f->seqArray[idx].magic[0]; - sp18 = f->seqArray[idx].magic[1]; - devAddr = (uintptr_t) f->seqArray[idx].offset; - loadStatus = 2; - - switch (sp18) { - case 0: - vAddr = unk_pool1_alloc(poolIdx, idx, size); - if (vAddr == NULL) { - return vAddr; - } - loadStatus = 5; - break; - case 1: - vAddr = alloc_bank_or_seq(poolIdx, size, 1, idx); - if (vAddr == NULL) { - return vAddr; - } - break; - case 2: - vAddr = alloc_bank_or_seq(poolIdx, size, 0, idx); - if (vAddr == NULL) { - return vAddr; - } - break; - - case 4: - case 3: - vAddr = alloc_bank_or_seq(poolIdx, size, 2, idx); - if (vAddr == NULL) { - return vAddr; - } - break; - } - - func_sh_802f4cb4(devAddr, vAddr, size, medium, numChunks, retQueue, (arg3 << 0x18) | (poolIdx << 0x10) | (idx << 8) | loadStatus); - loadStatus = SOUND_LOAD_STATUS_IN_PROGRESS; - } - - switch (poolIdx) { - case 0: - if (gSeqLoadStatus[idx] != 5) { - gSeqLoadStatus[idx] = loadStatus; - } - break; - - case 1: - if (gBankLoadStatus[idx] != 5) { - gBankLoadStatus[idx] = loadStatus; - } - break; - - case 2: - if (gUnkLoadStatus[idx] != 5) { - gUnkLoadStatus[idx] = loadStatus; - } - break; - } - - return vAddr; -} - -void func_802f41e4(s32 audioResetStatus) { - func_sh_802f4a4c(audioResetStatus); - func_sh_802f573c(audioResetStatus); - func_sh_802f4dcc(audioResetStatus); -} -#endif - -#if defined(VERSION_SH) -u8 gShindouSoundBanksHeader[] = { -#include "sound/ctl_header.inc.c" -}; - -u8 gBankSetsData[] = { -#include "sound/bank_sets.inc.c" -}; - -u8 gShindouSampleBanksHeader[] = { -#include "sound/tbl_header.inc.c" -}; - -u8 gShindouSequencesHeader[] = { -#include "sound/sequences_header.inc.c" -}; -#endif - -// (void) must be omitted from parameters +// (void) must be omitted from parameters to fix stack with -framepointer void audio_init() { #if defined(VERSION_EU) UNUSED s8 pad[16]; -#elif defined(VERSION_SH) - UNUSED s8 pad[24]; #else UNUSED s8 pad[32]; #endif @@ -1782,7 +950,7 @@ void audio_init() { #endif s32 i, j, k; UNUSED s32 lim1; // lim1 unused in EU -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) UNUSED u8 buf[0x10]; s32 UNUSED lim2, lim3; #else @@ -1792,15 +960,8 @@ void audio_init() { UNUSED u64 *ptr64; void *data; UNUSED s32 pad2; -#ifdef VERSION_SH - s32 seqCount; -#endif -#ifdef VERSION_SH - gAudioLoadLockSH = 0; -#else gAudioLoadLock = AUDIO_LOCK_UNINITIALIZED; -#endif #if defined(VERSION_JP) || defined(VERSION_US) lim1 = gUnusedCount80333EE8; @@ -1818,10 +979,10 @@ void audio_init() { // It seems boot.s doesn't clear the .bss area for audio, so do it here. i = 0; lim3 = ((uintptr_t) &gAudioGlobalsEndMarker - (uintptr_t) &gAudioGlobalsStartMarker) / 8; - ptr64 = &gAudioGlobalsStartMarker - 1; + ptr64 = &gAudioGlobalsStartMarker; for (k = lim3; k >= 0; k--) { - i++; ptr64[i] = 0; + i++; } #endif @@ -1839,17 +1000,12 @@ void audio_init() { } #endif -#ifdef VERSION_EU - D_EU_802298D0 = 20.03042f; - gRefreshRate = 50; + //D_EU_802298D0 = 20.03042f; + D_EU_802298D0 = 16.713f; + gRefreshRate = 60; port_eu_init(); if (k) { } -#else - D_EU_802298D0 = 16.713f; - gRefreshRate = 60; - func_sh_802f6a9c(); -#endif #endif #ifdef TARGET_N64 @@ -1876,28 +1032,20 @@ void audio_init() { osCreateMesgQueue(&gAudioDmaMesgQueue, &gAudioDmaMesg, 1); osCreateMesgQueue(&gCurrAudioFrameDmaQueue, gCurrAudioFrameDmaMesgBufs, ARRAY_COUNT(gCurrAudioFrameDmaMesgBufs)); -#ifdef VERSION_SH - osCreateMesgQueue(&gUnkQueue1, gUnkMesgBufs1, 0x10); - osCreateMesgQueue(&gUnkQueue2, gUnkMesgBufs2, 0x10); -#endif gCurrAudioFrameDmaCount = 0; gSampleDmaNumListItems = 0; sound_init_main_pools(gAudioInitPoolSize); for (i = 0; i < NUMAIBUFFERS; i++) { -#ifdef VERSION_SH - gAiBuffers[i] = sound_alloc_uninitialized(&gAudioInitPool, AIBUFFER_LEN); -#else gAiBuffers[i] = soundAlloc(&gAudioInitPool, AIBUFFER_LEN); -#endif for (j = 0; j < (s32) (AIBUFFER_LEN / sizeof(s16)); j++) { gAiBuffers[i][j] = 0; } } -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(VERSION_EU) gAudioResetPresetIdToLoad = 0; gAudioResetStatus = 1; audio_shut_down_and_reset_step(); @@ -1910,31 +1058,7 @@ void audio_init() { eu_stubbed_printf_3("Heap %x %x %x\n", 0, 0, 0); eu_stubbed_printf_0("Main Heap Initialize.\n"); - // Load header for sequence data (assets/music_data.sbk.s) -#ifdef VERSION_SH - gSeqFileHeader = (ALSeqFile *) gShindouSequencesHeader; - gAlCtlHeader = (ALSeqFile *) gShindouSoundBanksHeader; - gAlTbl = (ALSeqFile *) gShindouSampleBanksHeader; - gAlBankSets = gBankSetsData; - gSequenceCount = (s16) gSeqFileHeader->seqCount; - patch_seq_file(gSeqFileHeader, gMusicData, D_SH_80315EF4); - patch_seq_file(gAlCtlHeader, gSoundDataADSR, D_SH_80315EF8); - patch_seq_file(gAlTbl, gSoundDataRaw, D_SH_80315EFC); - seqCount = gAlCtlHeader->seqCount; - gCtlEntries = sound_alloc_uninitialized(&gAudioInitPool, seqCount * sizeof(struct CtlEntry)); - for (i = 0; i < seqCount; i++) { - gCtlEntries[i].bankId1 = (u8) ((gAlCtlHeader->seqArray[i].ctl.as_s16.bankAndFf >> 8) & 0xff); - gCtlEntries[i].bankId2 = (u8) (gAlCtlHeader->seqArray[i].ctl.as_s16.bankAndFf & 0xff); - gCtlEntries[i].numInstruments = (u8) ((gAlCtlHeader->seqArray[i].ctl.as_s16.numInstrumentsAndDrums >> 8) & 0xff); - gCtlEntries[i].numDrums = (u8) (gAlCtlHeader->seqArray[i].ctl.as_s16.numInstrumentsAndDrums & 0xff); - } - data = sound_alloc_uninitialized(&gAudioInitPool, D_SH_80315EF0); - if (data == NULL) { - D_SH_80315EF0 = 0; - } - sound_alloc_pool_init(&gUnkPool1.pool, data, D_SH_80315EF0); - init_sequence_players(); -#else + // Load headers for sounds and sequences gSeqFileHeader = (ALSeqFile *) buf; data = gMusicData; audio_dma_copy_immediate((uintptr_t) data, gSeqFileHeader, 0x10); @@ -1949,7 +1073,7 @@ void audio_init() { audio_dma_copy_immediate((uintptr_t) data, gSeqFileHeader, size); alSeqFileNew(gSeqFileHeader, data); - // Load header for CTL (assets/sound_data.ctl.s, i.e. ADSR) + // Load header for CTL (instrument metadata) gAlCtlHeader = (ALSeqFile *) buf; data = gSoundDataADSR; audio_dma_copy_immediate((uintptr_t) data, gAlCtlHeader, 0x10); @@ -1960,7 +1084,7 @@ void audio_init() { audio_dma_copy_immediate((uintptr_t) data, gAlCtlHeader, size); alSeqFileNew(gAlCtlHeader, data); - // Load header for TBL (assets/sound_data.tbl.s, i.e. raw data) + // Load header for TBL (raw sound data) gAlTbl = (ALSeqFile *) buf; audio_dma_copy_immediate((uintptr_t) data, gAlTbl, 0x10); size = gAlTbl->seqCount * sizeof(ALSeqData) + 4; @@ -1969,7 +1093,7 @@ void audio_init() { audio_dma_copy_immediate((uintptr_t) gSoundDataRaw, gAlTbl, size); alSeqFileNew(gAlTbl, gSoundDataRaw); - // Load bank sets for each sequence (assets/bank_sets.s) + // Load bank sets for each sequence gAlBankSets = soundAlloc(&gAudioInitPool, 0x100); audio_dma_copy_immediate((uintptr_t) gBankSetsData, gAlBankSets, 0x100); @@ -1978,539 +1102,13 @@ void audio_init() { // Should probably contain the sizes of the data banks, but those aren't // easily accessible from here. osSyncPrintf("---------- Init Completed. ------------\n"); - osSyncPrintf(" Syndrv :[%6d]\n", gSoundDataADSR); // gSoundDataADSR - osSyncPrintf(" Seqdrv :[%6d]\n", gMusicData); // gMusicData - osSyncPrintf(" audiodata :[%6d]\n", gSoundDataRaw); // gSoundDataRaw + osSyncPrintf(" Syndrv :[%6d]\n", gSoundDataRaw - gSoundDataADSR); // gSoundDataADSR +#ifndef VERSION_SH + osSyncPrintf(" Seqdrv :[%6d]\n", gBankSetsData - gMusicData); // gMusicData +#else + osSyncPrintf(" Seqdrv :[%6d]\n", _assetsSegmentRomEnd - gMusicData); // gMusicData +#endif + osSyncPrintf(" audiodata :[%6d]\n", gMusicData - gSoundDataRaw); // gSoundDataRaw osSyncPrintf("---------------------------------------\n"); -#endif -} - -#if defined(VERSION_SH) -s32 func_802f47c8(s32 bankId, u8 idx, s8 *io) { - struct AudioBankSample *sample = func_sh_802f4978(bankId, idx); - struct PendingDmaSample *temp; - if (sample == NULL) { - *io = 0; - return -1; - } - if (sample->medium == 0) { - *io = 2; - return 0; - } - temp = &D_SH_80343D00.arr[D_SH_80343D00.someIndex]; - if (temp->state == 3) { - temp->state = 0; - } - temp->sample = *sample; - temp->io = io; - temp->vAddr = func_sh_802f1d40(sample->size, bankId, sample->sampleAddr, sample->medium); - if (temp->vAddr == NULL) { - if (sample->medium == 1 || sample->codec == 2) { - *io = 0; - return -1; - } else { - *io = 3; - return -1; - } - } - temp->state = 1; - temp->remaining = ALIGN16(sample->size); - temp->resultSampleAddr = (u8 *) temp->vAddr; - temp->devAddr = (uintptr_t) sample->sampleAddr; - temp->medium = sample->medium; - temp->bankId = bankId; - temp->idx = idx; - D_SH_80343D00.someIndex ^= 1; - return 0; -} - -struct AudioBankSample *func_sh_802f4978(s32 bankId, s32 idx) { - struct Drum *drum; - struct Instrument *inst; - struct AudioBankSample *ret; - - if (idx < 128) { - inst = get_instrument_inner(bankId, idx); - if (inst == 0) { - return NULL; - } - ret = inst->normalNotesSound.sample; - } else { - drum = get_drum(bankId, idx - 128); - if (drum == 0) { - return NULL; - } - ret = drum->sound.sample; - } - return ret; -} -void stub_sh_802f49dc(void) { - -} - -void func_sh_802f49e4(struct PendingDmaSample *arg0) { - struct AudioBankSample *sample = func_sh_802f4978(arg0->bankId, arg0->idx); - if (sample != NULL) { - arg0->sample = *sample; - sample->sampleAddr = arg0->resultSampleAddr; - sample->medium = 0; - } -} - -void func_sh_802f4a4c(s32 audioResetStatus) { - ALSeqFile *alTbl; - struct PendingDmaSample *entry; - - s32 i; - - alTbl = gAlTbl; - - for (i = 0; i < 2; i++) { - entry = &D_SH_80343D00.arr[i]; - switch (entry->state) { - case 2: - osRecvMesg(&entry->queue, NULL, 1); - if (audioResetStatus != 0) { - entry->state = 3; - break; - } - // fallthrough - case 1: - entry->state = 2; - if (entry->remaining == 0) { - func_sh_802f49e4(entry); - entry->state = 3; - *entry->io = 1; - } else if (entry->remaining < 0x1000) { - if (1 == entry->medium) { - func_sh_802f4c5c(entry->devAddr, entry->vAddr, entry->remaining, alTbl->unk2); - } else { - func_sh_802f4bd8(entry, entry->remaining); - } - entry->remaining = 0; - } else { - if (1 == entry->medium) { - func_sh_802f4c5c(entry->devAddr, entry->vAddr, 0x1000, alTbl->unk2); - } else { - func_sh_802f4bd8(entry, 0x1000); - } - entry->remaining = (s32) (entry->remaining - 0x1000); - entry->vAddr = (u8 *) entry->vAddr + 0x1000; - entry->devAddr = entry->devAddr + 0x1000; - } - break; - } - } -} - -extern char shindouDebugPrint102[]; -void func_sh_802f4bd8(struct PendingDmaSample *arg0, s32 len) { // len must be signed - osInvalDCache(arg0->vAddr, len); - osCreateMesgQueue(&arg0->queue, arg0->mesgs, 1); - func_sh_802f3dd0(&arg0->ioMesg, 0, 0, arg0->devAddr, arg0->vAddr, len, &arg0->queue, arg0->medium, shindouDebugPrint102); -} - -void func_sh_802f4c5c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { - uintptr_t sp1C; - - sp1C = devAddr; - osInvalDCache(vAddr, nbytes); - func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); -} - -struct PendingDmaAudioBank *func_sh_802f4cb4(uintptr_t devAddr, void *vAddr, s32 size, s32 medium, s32 numChunks, OSMesgQueue *retQueue, s32 encodedInfo) { - struct PendingDmaAudioBank *item; - s32 i; - - for (i = 0; i < ARRAY_COUNT(D_SH_8034F690); i++) { - if (D_SH_8034F690[i].inProgress == 0) { - item = &D_SH_8034F690[i]; - break; - } - } - if (i == ARRAY_COUNT(D_SH_8034F690)) { - return NULL; - } - - item->inProgress = 1; - item->devAddr = devAddr; - item->audioBank = vAddr; - item->vAddr = vAddr; - item->remaining = size; - if (numChunks == 0) { - item->transferSize = 0x1000; - } else { - item->transferSize = ((size / numChunks) + 0xFF) & ~0xFF; - if (item->transferSize < 0x100) { - item->transferSize = 0x100; - } - } - item->retQueue = retQueue; - item->timer = 3; - item->medium = medium; - item->encodedInfo = encodedInfo; - osCreateMesgQueue(&item->dmaRetQueue, item->mesgs, 1); - return item; -} - -void func_sh_802f4dcc(s32 audioResetStatus) { - s32 i; - - if (gAudioLoadLockSH != 1) { - for (i = 0; i < ARRAY_COUNT(D_SH_8034F690); i++) { - if (D_SH_8034F690[i].inProgress == 1) { - func_sh_802f4e50(&D_SH_8034F690[i], audioResetStatus); - } - } - } -} - -void func_sh_802f4e50(struct PendingDmaAudioBank *audioBank, s32 audioResetStatus) { - ALSeqFile *alSeqFile; - u32 *encodedInfo; - OSMesg mesg; - u32 temp; - u32 seqId; - s32 bankId1; - s32 bankId2; - struct PatchStruct patchStruct; - alSeqFile = gAlTbl; - if (audioBank->timer >= 2) { - audioBank->timer--; - return; - } - if (audioBank->timer == 1) { - audioBank->timer = 0; - } else { - if (audioResetStatus != 0) { - osRecvMesg(&audioBank->dmaRetQueue, NULL, OS_MESG_BLOCK); - audioBank->inProgress = 0; - return; - } - if (osRecvMesg(&audioBank->dmaRetQueue, NULL, OS_MESG_NOBLOCK) == -1) { - return; - } - } - - encodedInfo = &audioBank->encodedInfo; - if (audioBank->remaining == 0) { - mesg = (OSMesg) audioBank->encodedInfo; - mesg = mesg; //! needs an extra read from mesg here to match... - temp = *encodedInfo; - seqId = (temp >> 8) & 0xFF; - switch ((u8) (temp >> 0x10)) { - case 0: - if (gSeqLoadStatus[seqId] != 5) { - gSeqLoadStatus[seqId] = (u8) (temp & 0xFF); - } - break; - case 2: - if (gUnkLoadStatus[seqId] != 5) { - gUnkLoadStatus[seqId] = (u8) (temp & 0xFF); - } - break; - case 1: - if (gBankLoadStatus[seqId] != 5) { - gBankLoadStatus[seqId] = (u8) (temp & 0xFF); - } - bankId1 = gCtlEntries[seqId].bankId1; - bankId2 = gCtlEntries[seqId].bankId2; - patchStruct.bankId1 = bankId1; - patchStruct.bankId2 = bankId2; - if (bankId1 != 0xFF) { - patchStruct.baseAddr1 = func_sh_802f3598(bankId1, &patchStruct.medium1); - } else { - patchStruct.baseAddr1 = NULL; - } - if (bankId2 != 0xFF) { - patchStruct.baseAddr2 = func_sh_802f3598(bankId2, &patchStruct.medium2); - } else { - patchStruct.baseAddr2 = NULL; - } - - func_sh_802f5310(seqId, audioBank->audioBank, &patchStruct, 1); - break; - } - mesg = (OSMesg) audioBank->encodedInfo; - audioBank->inProgress = 0; - osSendMesg(audioBank->retQueue, mesg, OS_MESG_NOBLOCK); - } else if (audioBank->remaining < audioBank->transferSize) { - if (audioBank->medium == 1) { - func_sh_802f517c(audioBank->devAddr, audioBank->vAddr, audioBank->remaining, alSeqFile->unk2); - } else { - func_sh_802f50ec(audioBank, audioBank->remaining); - } - - audioBank->remaining = 0; - } else { - if (audioBank->medium == 1) { - func_sh_802f517c(audioBank->devAddr, audioBank->vAddr, audioBank->transferSize, alSeqFile->unk2); - } else { - func_sh_802f50ec(audioBank, audioBank->transferSize); - } - - audioBank->remaining -= audioBank->transferSize; - audioBank->devAddr += audioBank->transferSize; - audioBank->vAddr = ((u8 *) audioBank->vAddr) + audioBank->transferSize; - } -} - -extern char shindouDebugPrint110[]; -void func_sh_802f50ec(struct PendingDmaAudioBank *arg0, size_t len) { - len += 0xf; - len &= ~0xf; - osInvalDCache(arg0->vAddr, len); - osCreateMesgQueue(&arg0->dmaRetQueue, arg0->mesgs, 1); - func_sh_802f3dd0(&arg0->ioMesg, 0, 0, arg0->devAddr, arg0->vAddr, len, &arg0->dmaRetQueue, arg0->medium, shindouDebugPrint110); -} - - -void func_sh_802f517c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { - uintptr_t sp1C; - - sp1C = devAddr; - osInvalDCache(vAddr, nbytes); - func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); -} - -void func_sh_802f51d4(struct AudioBankSound *sound, struct AudioBank *memBase, struct PatchStruct *patchInfo) { - struct AudioBankSample *sample; - void *patched; - -#define PATCH(x, base) (patched = (void *)((uintptr_t) (x) + (uintptr_t) base)) - - if ((uintptr_t) sound->sample <= 0x80000000) { - sample = sound->sample = PATCH(sound->sample, memBase); - if (sample->size != 0 && sample->isPatched != TRUE) { - sample->loop = PATCH(sample->loop, memBase); - sample->book = PATCH(sample->book, memBase); - switch (sample->medium) { - case 0: - sample->sampleAddr = PATCH(sample->sampleAddr, patchInfo->baseAddr1); - sample->medium = patchInfo->medium1; - break; - case 1: - sample->sampleAddr = PATCH(sample->sampleAddr, patchInfo->baseAddr2); - sample->medium = patchInfo->medium2; - break; - - case 2: - case 3: - break; - } - sample->isPatched = TRUE; - if (sample->bit1 && sample->medium != 0) { - D_SH_8034EA88[D_SH_8034F688++] = sample; - } - } - } -#undef PATCH -} - -s32 func_sh_802f5310(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo, s32 arg3) { - UNUSED u32 pad[2]; - u8 *addr; - UNUSED u32 pad1[3]; - s32 sp4C; - struct AudioBankSample *temp_s0; - s32 i; - s32 count; - s32 temp; - - sp4C = 0; - if (D_SH_8034F68C != 0) { - sp4C = 1; - } else { - D_SH_80343CF0 = 0; - } - D_SH_8034F688 = 0; - patch_audio_bank(bankId, mem, patchInfo); - - count = 0; - for (i = 0; i < D_SH_8034F688; i++) { - count += ALIGN16(D_SH_8034EA88[i]->size); - } - - for (i = 0; i < D_SH_8034F688; i++) { - if (D_SH_8034F68C != 0x78) { - temp_s0 = D_SH_8034EA88[i]; - switch (arg3) { - case 0: - temp = temp_s0->medium = patchInfo->medium1; - if (temp != 0) { - if (temp_s0->size) { - } - addr = func_sh_802f1d90(temp_s0->size, patchInfo->bankId1, temp_s0->sampleAddr, temp_s0->medium); - } else { - temp = temp_s0->medium = patchInfo->medium2; - if (temp != 0) { - addr = func_sh_802f1d90(temp_s0->size, patchInfo->bankId2, temp_s0->sampleAddr, temp_s0->medium); - } - } - break; - - case 1: - temp = temp_s0->medium = patchInfo->medium1; - if (temp != 0) { - addr = func_sh_802f1d40(temp_s0->size, patchInfo->bankId1, temp_s0->sampleAddr, temp_s0->medium); - } else { - temp = temp_s0->medium = patchInfo->medium2; - if (temp != 0) { - addr = func_sh_802f1d40(temp_s0->size, patchInfo->bankId2, temp_s0->sampleAddr, temp_s0->medium); - } - } - break; - } - switch ((uintptr_t) addr) { - case 0: - break; - default: - switch (arg3) { - case 0: - if (temp_s0->medium == 1) { - func_sh_802f3d78((uintptr_t) temp_s0->sampleAddr, addr, temp_s0->size, gAlTbl->unk2); - temp_s0->sampleAddr = addr; - temp_s0->medium = 0; - } else { - func_sh_802f3c38((uintptr_t) temp_s0->sampleAddr, addr, temp_s0->size, temp_s0->medium); - temp_s0->sampleAddr = addr; - temp_s0->medium = 0; - } - break; - - case 1: - D_SH_8034EC88[D_SH_8034F68C].sample = temp_s0; - D_SH_8034EC88[D_SH_8034F68C].ramAddr = addr; - D_SH_8034EC88[D_SH_8034F68C].encodedInfo = (D_SH_8034F68C << 24) | 0xffffff; - D_SH_8034EC88[D_SH_8034F68C].isFree = FALSE; - D_SH_8034EC88[D_SH_8034F68C].endAndMediumIdentification = temp_s0->sampleAddr + temp_s0->size + temp_s0->medium; - D_SH_8034F68C++; - break; - } - } - continue; - } - break; - } - - D_SH_8034F688 = 0; - if (D_SH_8034F68C != 0 && sp4C == 0) { - temp_s0 = D_SH_8034EC88[D_SH_8034F68C - 1].sample; - temp = (temp_s0->size >> 12); - temp += 1; - count = (uintptr_t) temp_s0->sampleAddr; - func_sh_802f4cb4( - count, - D_SH_8034EC88[D_SH_8034F68C - 1].ramAddr, - temp_s0->size, - temp_s0->medium, - temp, - &gUnkQueue2, - D_SH_8034EC88[D_SH_8034F68C - 1].encodedInfo); - } -} - -s32 func_sh_802f573c(s32 audioResetStatus) { - struct AudioBankSample *sample; - u32 idx; - u8 *sampleAddr; - u32 size; - s32 unk; - u8 *added; - - if (D_SH_8034F68C > 0) { - if (audioResetStatus != 0) { - if (osRecvMesg(&gUnkQueue2, (OSMesg *) &idx, OS_MESG_NOBLOCK)){ - } - D_SH_8034F68C = 0; - return 0; - } - if (osRecvMesg(&gUnkQueue2, (OSMesg *) &idx, OS_MESG_NOBLOCK) == -1) { - return 0; - } - idx >>= 0x18; - if (D_SH_8034EC88[idx].isFree == FALSE) { - sample = D_SH_8034EC88[idx].sample; - added = (sample->sampleAddr + sample->size + sample->medium); - if (added == D_SH_8034EC88[idx].endAndMediumIdentification) { - sample->sampleAddr = D_SH_8034EC88[idx].ramAddr; - sample->medium = 0; - } - D_SH_8034EC88[idx].isFree = TRUE; - } - - next: - if (D_SH_8034F68C > 0) { - if (D_SH_8034EC88[D_SH_8034F68C - 1].isFree == TRUE) { - D_SH_8034F68C--; - goto next; - } - sample = D_SH_8034EC88[D_SH_8034F68C - 1].sample; - sampleAddr = sample->sampleAddr; - size = sample->size; - unk = size >> 0xC; - unk += 1; - added = ((sampleAddr + size) + sample->medium); - if (added != D_SH_8034EC88[D_SH_8034F68C - 1].endAndMediumIdentification) { - D_SH_8034EC88[D_SH_8034F68C - 1].isFree = TRUE; - D_SH_8034F68C--; - goto next; - } - size = sample->size; - func_sh_802f4cb4(sampleAddr, D_SH_8034EC88[D_SH_8034F68C - 1].ramAddr, size, sample->medium, - unk, &gUnkQueue2, D_SH_8034EC88[D_SH_8034F68C - 1].encodedInfo); - } - } - return 1; -} - -s32 func_sh_802f5900(struct AudioBankSample *sample, s32 numLoaded, struct AudioBankSample *arg2[]) { - s32 i; - - for (i = 0; i < numLoaded; i++) { - if (sample->sampleAddr == arg2[i]->sampleAddr) { - break; - } - } - if (i == numLoaded) { - arg2[numLoaded++] = sample; - } - return numLoaded; -} - -s32 func_sh_802f5948(s32 bankId, struct AudioBankSample *list[]) { - s32 i; - struct Drum *drum; - struct Instrument *inst; - s32 numLoaded; - s32 numDrums; - s32 numInstruments; - - numLoaded = 0; - numDrums = gCtlEntries[bankId].numDrums; - numInstruments = gCtlEntries[bankId].numInstruments; - - for (i = 0; i < numDrums; i++) { - drum = get_drum(bankId, i); - if (drum == NULL) { - continue; - } - numLoaded = func_sh_802f5900(drum->sound.sample, numLoaded, list); - } - for (i = 0; i < numInstruments; i++) { - inst = get_instrument_inner(bankId, i); - if (inst == NULL) { - continue; - - } - if (inst->normalRangeLo != 0) { - numLoaded = func_sh_802f5900(inst->lowNotesSound.sample, numLoaded, list); - } - if (inst->normalRangeHi != 127) { - numLoaded = func_sh_802f5900(inst->highNotesSound.sample, numLoaded, list); - } - numLoaded = func_sh_802f5900(inst->normalNotesSound.sample, numLoaded, list); - } - return numLoaded; } #endif diff --git a/src/audio/load.h b/src/audio/load.h index d96f27b7..63379d21 100644 --- a/src/audio/load.h +++ b/src/audio/load.h @@ -89,18 +89,25 @@ void patch_audio_bank(s32 bankId, struct AudioBank *mem, struct PatchStruct *pat #else void patch_audio_bank(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32 numDrums); #endif -#ifndef VERSION_SH +#ifdef VERSION_SH +void preload_sequence(u32 seqId, s32 preloadMask); +#else void preload_sequence(u32 seqId, u8 preloadMask); #endif void load_sequence(u32 player, u32 seqId, s32 loadAsync); #ifdef VERSION_SH -void func_sh_802f3158(s32 index, s32 arg1, s32 arg2, OSMesgQueue *retQueue); -u8 *func_sh_802f3220(u32 index, u32 *a1); +void func_sh_802f3158(s32 seqId, s32 arg1, s32 arg2, OSMesgQueue *retQueue); +u8 *func_sh_802f3220(u32 seqId, u32 *a1); struct AudioBankSample *func_sh_802f4978(s32 bankId, s32 idx); -void *func_802f3f08(s32 poolIdx, s32 arg1, s32 arg2, s32 arg3, OSMesgQueue *retQueue); -s32 func_sh_802f3368(s32 arg0); +s32 func_sh_802f47c8(s32 bankId, u8 idx, s8 *io); +void *func_sh_802f3f08(s32 poolIdx, s32 arg1, s32 arg2, s32 arg3, OSMesgQueue *retQueue); +void func_sh_802f41e4(s32 audioResetStatus); +BAD_RETURN(s32) func_sh_802f3368(s32 bankId); void *func_sh_802f3764(s32 arg0, s32 idx, s32 *arg2); +s32 func_sh_802f3024(s32 bankId, s32 instId, s32 arg2); +void func_sh_802f30f4(s32 arg0, s32 arg1, s32 arg2, OSMesgQueue *arg3); +void func_sh_802f3288(s32 idx); #endif diff --git a/src/audio/load_sh.c b/src/audio/load_sh.c new file mode 100644 index 00000000..240722ed --- /dev/null +++ b/src/audio/load_sh.c @@ -0,0 +1,1637 @@ +#ifdef VERSION_SH +#include +#include + +#include "data.h" +#include "external.h" +#include "heap.h" +#include "load.h" +#include "seqplayer.h" + +#define ALIGN16(val) (((val) + 0xF) & ~0xF) + +struct SharedDma { + /*0x0*/ u8 *buffer; // target, points to pre-allocated buffer + /*0x4*/ uintptr_t source; // device address + /*0x8*/ u16 sizeUnused; // set to bufSize, never read + /*0xA*/ u16 bufSize; // size of buffer + /*0xC*/ u8 unused2; // set to 0, never read + /*0xD*/ u8 reuseIndex; // position in sSampleDmaReuseQueue1/2, if ttl == 0 + /*0xE*/ u8 ttl; // duration after which the DMA can be discarded +}; // size = 0x10 + +void port_eu_init(void); +void patch_sound(struct AudioBankSound *sound, struct AudioBank *memBase, struct PatchStruct *patchInfo); +void *func_802f3f08(s32 poolIdx, s32 idx, s32 numChunks, s32 arg3, OSMesgQueue *retQueue); + +struct Note *gNotes; + +UNUSED static u32 pad; + +struct SequencePlayer gSequencePlayers[SEQUENCE_PLAYERS]; +struct SequenceChannel gSequenceChannels[SEQUENCE_CHANNELS]; +struct SequenceChannelLayer gSequenceLayers[SEQUENCE_LAYERS]; + +struct SequenceChannel gSequenceChannelNone; +struct AudioListItem gLayerFreeList; +struct NotePool gNoteFreeLists; + +struct AudioBankSample *D_SH_8034EA88[0x80]; +struct UnkStructSH8034EC88 D_SH_8034EC88[0x80]; +s32 D_SH_8034F688; // index into D_SH_8034EA88 +s32 D_SH_8034F68C; // index or size for D_SH_8034EC88 + +struct PendingDmaAudioBank { + s8 inProgress; + s8 timer; + s8 medium; + struct AudioBank *audioBank; + uintptr_t devAddr; + void *vAddr; + u32 remaining; + u32 transferSize; + u32 encodedInfo; + OSMesgQueue *retQueue; + OSMesgQueue dmaRetQueue; + OSMesg mesgs[1]; + OSIoMesg ioMesg; +}; +struct PendingDmaAudioBank sPendingDmaAudioBanks[16]; + +OSMesgQueue gUnkQueue1; +OSMesg gUnkMesgBufs1[0x10]; +OSMesgQueue gUnkQueue2; +OSMesg gUnkMesgBufs2[0x10]; + +OSMesgQueue gCurrAudioFrameDmaQueue; +OSMesg gCurrAudioFrameDmaMesgBufs[AUDIO_FRAME_DMA_QUEUE_SIZE]; +OSIoMesg gCurrAudioFrameDmaIoMesgBufs[AUDIO_FRAME_DMA_QUEUE_SIZE]; + +OSMesgQueue gAudioDmaMesgQueue; +OSMesg gAudioDmaMesg; +OSIoMesg gAudioDmaIoMesg; + +struct SharedDma *sSampleDmas; +u32 gSampleDmaNumListItems; +u32 sSampleDmaListSize1; +u32 sUnused80226B40; // set to 0, never read + +// Circular buffer of DMAs with ttl = 0. tail <= head, wrapping around mod 256. +u8 sSampleDmaReuseQueue1[256]; +u8 sSampleDmaReuseQueue2[256]; +u8 sSampleDmaReuseQueueTail1; +u8 sSampleDmaReuseQueueTail2; +u8 sSampleDmaReuseQueueHead1; +u8 sSampleDmaReuseQueueHead2; + +ALSeqFile *gSeqFileHeader; +ALSeqFile *gAlCtlHeader; +ALSeqFile *gAlTbl; +u8 *gAlBankSets; +u16 gSequenceCount; + +struct CtlEntry *gCtlEntries; + +struct AudioBufferParametersEU gAudioBufferParameters; +u32 sDmaBufSize; +s32 gMaxAudioCmds; +s32 gMaxSimultaneousNotes; + +s16 gTempoInternalToExternal; + +s8 gSoundMode; + +s8 gAudioUpdatesPerFrame; + +extern u64 gAudioGlobalsStartMarker; +extern u64 gAudioGlobalsEndMarker; + +extern u8 gSoundDataADSR[]; // ctl +extern u8 gSoundDataRaw[]; // tbl +extern u8 gMusicData[]; // sequences + +ALSeqFile *get_audio_file_header(s32 arg0); + +void *func_sh_802f3688(s32 bankId); +void *get_bank_or_seq_wrapper(s32 arg0, s32 arg1); +void func_sh_802f3d78(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); +void func_sh_802f3c38(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 medium); +s32 func_sh_802f3dd0(OSIoMesg *m, s32 pri, s32 direction, uintptr_t devAddr, + void *dramAddr, s32 size, OSMesgQueue *retQueue, s32 medium, UNUSED const char *reason); +void func_sh_802f4a4c(s32 audioResetStatus); +void func_sh_802f4bd8(struct PendingDmaSample *arg0, s32 len); +void func_sh_802f4c5c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); +struct PendingDmaAudioBank *func_sh_802f4cb4(uintptr_t devAddr, void *vAddr, s32 size, + s32 medium, s32 numChunks, OSMesgQueue *retQueue, s32 encodedInfo); +void func_sh_802f4dcc(s32 audioResetStatus); +void func_sh_802f4e50(struct PendingDmaAudioBank *audioBank, s32 audioResetStatus); +void func_sh_802f50ec(struct PendingDmaAudioBank *arg0, size_t len); +void func_sh_802f517c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3); +BAD_RETURN(s32) func_sh_802f5310(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo, s32 arg3); +s32 func_sh_802f573c(s32 audioResetStatus); +void *func_sh_802f3564(s32 seqId); +s32 func_sh_802f3ec4(s32 arg0, uintptr_t *arg1); +void func_sh_802f3ed4(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED void *vAddr, UNUSED size_t nbytes); + +s32 canonicalize_index(s32 poolIdx, s32 idx); + +void decrease_sample_dma_ttls() { + u32 i; + + for (i = 0; i < sSampleDmaListSize1; i++) { + struct SharedDma *temp = &sSampleDmas[i]; + if (temp->ttl != 0) { + temp->ttl--; + if (temp->ttl == 0) { + temp->reuseIndex = sSampleDmaReuseQueueHead1; + sSampleDmaReuseQueue1[sSampleDmaReuseQueueHead1++] = (u8) i; + } + } + } + + for (i = sSampleDmaListSize1; i < gSampleDmaNumListItems; i++) { + struct SharedDma *temp = &sSampleDmas[i]; + if (temp->ttl != 0) { + temp->ttl--; + if (temp->ttl == 0) { + temp->reuseIndex = sSampleDmaReuseQueueHead2; + sSampleDmaReuseQueue2[sSampleDmaReuseQueueHead2++] = (u8) i; + } + } + } + + sUnused80226B40 = 0; +} + +extern char shindouDebugPrint62[]; // "SUPERDMA" +void *dma_sample_data(uintptr_t devAddr, u32 size, s32 arg2, u8 *dmaIndexRef, s32 medium) { + UNUSED s32 sp60; + struct SharedDma *dma; + s32 hasDma = FALSE; + uintptr_t dmaDevAddr; + UNUSED u32 pad; + u32 dmaIndex; + u32 transfer; + ssize_t bufferPos; + u32 i; + + if (arg2 != 0 || *dmaIndexRef >= sSampleDmaListSize1) { + for (i = sSampleDmaListSize1; i < gSampleDmaNumListItems; i++) { + dma = &sSampleDmas[i]; + bufferPos = devAddr - dma->source; + if (0 <= bufferPos && (size_t) bufferPos <= dma->bufSize - size) { + // We already have a DMA request for this memory range. + if (dma->ttl == 0 && sSampleDmaReuseQueueTail2 != sSampleDmaReuseQueueHead2) { + // Move the DMA out of the reuse queue, by swapping it with the + // tail, and then incrementing the tail. + if (dma->reuseIndex != sSampleDmaReuseQueueTail2) { + sSampleDmaReuseQueue2[dma->reuseIndex] = + sSampleDmaReuseQueue2[sSampleDmaReuseQueueTail2]; + sSampleDmas[sSampleDmaReuseQueue2[sSampleDmaReuseQueueTail2]].reuseIndex = + dma->reuseIndex; + } + sSampleDmaReuseQueueTail2++; + } + dma->ttl = 60; + *dmaIndexRef = (u8) i; + return &dma->buffer[(devAddr - dma->source)]; + } + } + + if (sSampleDmaReuseQueueTail2 != sSampleDmaReuseQueueHead2 && arg2 != 0) { + // Allocate a DMA from reuse queue 2. This queue can be empty, since + // TTL 60 is pretty large. + dmaIndex = sSampleDmaReuseQueue2[sSampleDmaReuseQueueTail2]; + sSampleDmaReuseQueueTail2++; + dma = sSampleDmas + dmaIndex; + hasDma = TRUE; + } + } else { + dma = sSampleDmas + *dmaIndexRef; + bufferPos = devAddr - dma->source; + if (0 <= bufferPos && (size_t) bufferPos <= dma->bufSize - size) { + // We already have DMA for this memory range. + if (dma->ttl == 0) { + // Move the DMA out of the reuse queue, by swapping it with the + // tail, and then incrementing the tail. + if (dma->reuseIndex != sSampleDmaReuseQueueTail1) { + sSampleDmaReuseQueue1[dma->reuseIndex] = + sSampleDmaReuseQueue1[sSampleDmaReuseQueueTail1]; + sSampleDmas[sSampleDmaReuseQueue1[sSampleDmaReuseQueueTail1]].reuseIndex = + dma->reuseIndex; + } + sSampleDmaReuseQueueTail1++; + } + dma->ttl = 2; + return dma->buffer + (devAddr - dma->source); + } + } + + if (!hasDma) { + if (1) {} + // Allocate a DMA from reuse queue 1. This queue will hopefully never + // be empty, since TTL 2 is so small. + dmaIndex = sSampleDmaReuseQueue1[sSampleDmaReuseQueueTail1++]; + dma = sSampleDmas + dmaIndex; + hasDma = TRUE; + } + + transfer = dma->bufSize; + dmaDevAddr = devAddr & ~0xF; + dma->ttl = 2; + dma->source = dmaDevAddr; + dma->sizeUnused = transfer; + func_sh_802f3dd0(&gCurrAudioFrameDmaIoMesgBufs[gCurrAudioFrameDmaCount++], OS_MESG_PRI_NORMAL, OS_READ, + dmaDevAddr, dma->buffer, transfer, &gCurrAudioFrameDmaQueue, medium, shindouDebugPrint62); + *dmaIndexRef = dmaIndex; + return (devAddr - dmaDevAddr) + dma->buffer; +} + +void init_sample_dma_buffers(UNUSED s32 arg0) { + s32 i; + + sDmaBufSize = 0x2D0; + sSampleDmas = sound_alloc_uninitialized(&gNotesAndBuffersPool, + gMaxSimultaneousNotes * 4 * sizeof(struct SharedDma) * gAudioBufferParameters.presetUnk4); + + for (i = 0; i < gMaxSimultaneousNotes * 3 * gAudioBufferParameters.presetUnk4; i++) + { + if ((sSampleDmas[gSampleDmaNumListItems].buffer = sound_alloc_uninitialized(&gNotesAndBuffersPool, sDmaBufSize)) == NULL) { + break; + } + sSampleDmas[gSampleDmaNumListItems].bufSize = sDmaBufSize; + sSampleDmas[gSampleDmaNumListItems].source = 0; + sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0; + sSampleDmas[gSampleDmaNumListItems].unused2 = 0; + sSampleDmas[gSampleDmaNumListItems].ttl = 0; + gSampleDmaNumListItems++; + } + + for (i = 0; (u32) i < gSampleDmaNumListItems; i++) { + sSampleDmaReuseQueue1[i] = (u8) i; + sSampleDmas[i].reuseIndex = (u8) i; + } + + for (i = gSampleDmaNumListItems; i < 0x100; i++) { + sSampleDmaReuseQueue1[i] = 0; + } + + sSampleDmaReuseQueueTail1 = 0; + sSampleDmaReuseQueueHead1 = (u8) gSampleDmaNumListItems; + sSampleDmaListSize1 = gSampleDmaNumListItems; + + sDmaBufSize = 0x2D0; + for (i = 0; i < gMaxSimultaneousNotes; i++) { + if ((sSampleDmas[gSampleDmaNumListItems].buffer = sound_alloc_uninitialized(&gNotesAndBuffersPool, sDmaBufSize)) == NULL) { + break; + } + sSampleDmas[gSampleDmaNumListItems].bufSize = sDmaBufSize; + sSampleDmas[gSampleDmaNumListItems].source = 0; + sSampleDmas[gSampleDmaNumListItems].sizeUnused = 0; + sSampleDmas[gSampleDmaNumListItems].unused2 = 0; + sSampleDmas[gSampleDmaNumListItems].ttl = 0; + gSampleDmaNumListItems++; + } + + for (i = sSampleDmaListSize1; (u32) i < gSampleDmaNumListItems; i++) { + sSampleDmaReuseQueue2[i - sSampleDmaListSize1] = (u8) i; + sSampleDmas[i].reuseIndex = (u8)(i - sSampleDmaListSize1); + } + + // This probably meant to touch the range size1..size2 as well... but it + // doesn't matter, since these values are never read anyway. + for (i = gSampleDmaNumListItems; i < 0x100; i++) { + sSampleDmaReuseQueue2[i] = sSampleDmaListSize1; + } + + sSampleDmaReuseQueueTail2 = 0; + sSampleDmaReuseQueueHead2 = gSampleDmaNumListItems - sSampleDmaListSize1; +} + +void patch_seq_file(ALSeqFile *seqFile, u8 *data, u16 arg2) { + s32 i; + + seqFile->unk2 = arg2; + seqFile->data = data; + for (i = 0; i < seqFile->seqCount; i++) { + if (seqFile->seqArray[i].len != 0 && seqFile->seqArray[i].medium == 2) { + seqFile->seqArray[i].offset += (uintptr_t)data; + } + } +} + +struct AudioBank *load_banks_immediate(s32 seqId, s32 *outDefaultBank) { + u8 bank; + s32 offset; + s32 i; + void *ret; + + offset = ((u16 *)gAlBankSets)[canonicalize_index(0, seqId)]; + bank = 0xFF; + for (i = gAlBankSets[offset++]; i > 0; i--) { + bank = gAlBankSets[offset++]; + ret = func_sh_802f3688(bank); + } + *outDefaultBank = bank; + return ret; +} + +void preload_sequence(u32 seqId, s32 preloadMask) { + UNUSED s32 pad; + s32 temp; + + seqId = canonicalize_index(0, seqId); + if (preloadMask & PRELOAD_BANKS) { + load_banks_immediate(seqId, &temp); + } + if (preloadMask & PRELOAD_SEQUENCE) { + func_sh_802f3564(seqId); + } +} + +s32 func_sh_802f2f38(struct AudioBankSample *sample, s32 bankId) { + u8 *sp24; + + if (sample->isPatched == TRUE && sample->medium != 0) { + sp24 = func_sh_802f1d90(sample->size, bankId, sample->sampleAddr, sample->medium); + if (sp24 == NULL) { + return -1; + } + if (sample->medium == 1) { + func_sh_802f3d78((uintptr_t) sample->sampleAddr, sp24, sample->size, gAlTbl->unk2); + } else { + func_sh_802f3c38((uintptr_t) sample->sampleAddr, sp24, sample->size, sample->medium); + } + sample->medium = 0; + sample->sampleAddr = sp24; + } +#ifdef AVOID_UB + return 0; +#endif +} + +s32 func_sh_802f3024(s32 bankId, s32 instId, s32 arg2) { + struct Instrument *instr; + struct Drum *drum; + + if (instId < 0x7F) { + instr = get_instrument_inner(bankId, instId); + if (instr == NULL) { + return -1; + } + if (instr->normalRangeLo != 0) { + func_sh_802f2f38(instr->lowNotesSound.sample, bankId); + } + func_sh_802f2f38(instr->normalNotesSound.sample, bankId); + if (instr->normalRangeHi != 0x7F) { + func_sh_802f2f38(instr->highNotesSound.sample, bankId); + } + //! @bug missing return + } else if (instId == 0x7F) { + drum = get_drum(bankId, arg2); + if (drum == NULL) { + return -1; + } + func_sh_802f2f38(drum->sound.sample, bankId); + return 0; + } +#ifdef AVOID_UB + return 0; +#endif +} + +void func_sh_802f30f4(s32 arg0, s32 arg1, s32 arg2, OSMesgQueue *arg3) { + if (func_802f3f08(2, canonicalize_index(2, arg0), arg1, arg2, arg3) == 0) { + osSendMesg(arg3, 0, 0); + } +} + +void func_sh_802f3158(s32 seqId, s32 numChunks, s32 arg2, OSMesgQueue *retQueue) { + s32 val; + s32 v; + + val = ((u16 *) gAlBankSets)[canonicalize_index(0, seqId)]; + v = gAlBankSets[val++]; + + while (v > 0) { + func_802f3f08(1, canonicalize_index(1, gAlBankSets[val++]), numChunks, arg2, retQueue); + v--; + } +} + +u8 *func_sh_802f3220(u32 seqId, u32 *a1) { + s32 val; + + val = ((u16 *) gAlBankSets)[canonicalize_index(0, seqId)]; + *a1 = gAlBankSets[val++]; + if (*a1 == 0) { + return NULL; + } + return &gAlBankSets[val]; +} + +void func_sh_802f3288(s32 idx) { + s32 bankId; + s32 s2; + + idx = ((u16*)gAlBankSets)[canonicalize_index(0, idx)]; + s2 = gAlBankSets[idx++]; + while (s2 > 0) { + s2--; + bankId = canonicalize_index(1, gAlBankSets[idx++]); + + if (unk_pool1_lookup(1, bankId) == NULL) { + func_sh_802f3368(bankId); + if (gBankLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { + gBankLoadStatus[bankId] = SOUND_LOAD_STATUS_NOT_LOADED; + } + + continue; + } + + } +} + +BAD_RETURN(s32) func_sh_802f3368(s32 bankId) { + struct SoundMultiPool *pool = &gBankLoadedPool; + struct TemporaryPool *temporary = &pool->temporary; + struct PersistentPool *persistent; + u32 i; + + if (temporary->entries[0].id == bankId) { + temporary->entries[0].id = -1; + } else if (temporary->entries[1].id == bankId) { + temporary->entries[1].id = -1; + } + + persistent = &pool->persistent; + for (i = 0; i < persistent->numEntries; i++) { + if (persistent->entries[i].id == bankId) { + persistent->entries[i].id = -1; + } + + } + + discard_bank(bankId); +} + + +void load_sequence_internal(s32 player, s32 seqId, s32 loadAsync); +void load_sequence(u32 player, u32 seqId, s32 loadAsync) { + load_sequence_internal(player, seqId, loadAsync); +} + +void load_sequence_internal(s32 player, s32 seqId, UNUSED s32 loadAsync) { + struct SequencePlayer *seqPlayer; + u8 *sequenceData; + u32 s0; + s32 count; + u8 bank; + s32 i; + + seqPlayer = &gSequencePlayers[player]; + + seqId = canonicalize_index(0, seqId); + sequence_player_disable(seqPlayer); + + s0 = ((u16 *) gAlBankSets)[seqId]; + count = gAlBankSets[s0++]; + bank = 0xff; + + while (count > 0) { + bank = gAlBankSets[s0++]; + func_sh_802f3688(bank); + count--; + } + + sequenceData = func_sh_802f3564(seqId); + init_sequence_player(player); + seqPlayer->seqId = seqId; + seqPlayer->defaultBank[0] = bank; + seqPlayer->enabled = 1; + seqPlayer->seqData = sequenceData; + seqPlayer->scriptState.pc = sequenceData; + seqPlayer->scriptState.depth = 0; + seqPlayer->delay = 0; + seqPlayer->finished = 0; + + for (i = 0; i < 0x10; i++) { + } +} + +void *func_sh_802f3564(s32 seqId) { + s32 seqId2 = canonicalize_index(0, seqId); + s32 temp; + return func_sh_802f3764(0, seqId2, &temp); +} + +extern u8 gUnkLoadStatus[0x40]; + +void *func_sh_802f3598(s32 idx, s32 *medium) { + void *ret; + ALSeqFile *f; + s32 temp; + s32 sp28; + + f = get_audio_file_header(2); + idx = canonicalize_index(2, idx); + ret = get_bank_or_seq_wrapper(2, idx); + if (ret != NULL) { + if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { + gUnkLoadStatus[idx] = SOUND_LOAD_STATUS_COMPLETE; + } + + *medium = 0; + return ret; + } + + temp = f->seqArray[idx].magic; + if (temp == 4) { + *medium = f->seqArray[idx].medium; + return f->seqArray[idx].offset; + } else { + ret = func_sh_802f3764(2, idx, &sp28); + if (ret != 0) { + *medium = 0; + return ret; + } + + *medium = f->seqArray[idx].medium; + } + return f->seqArray[idx].offset; + +} + +void *func_sh_802f3688(s32 bankId) { + void *ret; + s32 bankId1; + s32 bankId2; + s32 sp38; + struct PatchStruct patchInfo; + + bankId = canonicalize_index(1, bankId); + bankId1 = gCtlEntries[bankId].bankId1; + bankId2 = gCtlEntries[bankId].bankId2; + + patchInfo.bankId1 = bankId1; + patchInfo.bankId2 = bankId2; + + if (patchInfo.bankId1 != 0xFF) { + patchInfo.baseAddr1 = func_sh_802f3598(patchInfo.bankId1, &patchInfo.medium1); + } else { + patchInfo.baseAddr1 = NULL; + } + + if (bankId2 != 0xFF) { + patchInfo.baseAddr2 = func_sh_802f3598(bankId2, &patchInfo.medium2); + } else { + patchInfo.baseAddr2 = NULL; + } + + if ((ret = func_sh_802f3764(1, bankId, &sp38)) == NULL) { + return NULL; + } + + if (sp38 == 1) { + func_sh_802f5310(bankId, ret, &patchInfo, 0); + } + + return ret; +} + +void *func_sh_802f3764(s32 poolIdx, s32 idx, s32 *arg2) { + s32 size; + ALSeqFile *f; + void *vAddr; + s32 medium; + UNUSED u32 pad2; + u8 *devAddr; + s8 loadStatus; + s32 sp18; + + vAddr = get_bank_or_seq_wrapper(poolIdx, idx); + if (vAddr != NULL) { + *arg2 = 0; + loadStatus = SOUND_LOAD_STATUS_COMPLETE; + } else { + f = get_audio_file_header(poolIdx); + size = f->seqArray[idx].len; + size = ALIGN16(size); + medium = f->seqArray[idx].medium; + sp18 = f->seqArray[idx].magic; + devAddr = f->seqArray[idx].offset; + + + switch (sp18) + { + case 0: + vAddr = unk_pool1_alloc(poolIdx, idx, size); + if (vAddr == NULL) { + return vAddr; + } + break; + case 1: + vAddr = alloc_bank_or_seq(poolIdx, size, 1, idx); + if (vAddr == NULL) { + return vAddr; + } + break; + case 2: + vAddr = alloc_bank_or_seq(poolIdx, size, 0, idx); + if (vAddr == NULL) { + return vAddr; + } + break; + + case 3: + case 4: + vAddr = alloc_bank_or_seq(poolIdx, size, 2, idx); + if (vAddr == NULL) { + return vAddr; + } + break; + } + + *arg2 = 1; + if (medium == 1) { + func_sh_802f3d78((uintptr_t) devAddr, vAddr, size, f->unk2); + } else { + func_sh_802f3c38((uintptr_t) devAddr, vAddr, size, medium); + } + + switch (sp18) { + case 0: + loadStatus = SOUND_LOAD_STATUS_5; + break; + + default: + loadStatus = SOUND_LOAD_STATUS_COMPLETE; + break; + } + } + + switch (poolIdx) { + case 0: + if (gSeqLoadStatus[idx] != SOUND_LOAD_STATUS_5) { + gSeqLoadStatus[idx] = loadStatus; + } + break; + + case 1: + if (gBankLoadStatus[idx] != SOUND_LOAD_STATUS_5) { + gBankLoadStatus[idx] = loadStatus; + } + break; + + case 2: + if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { + gUnkLoadStatus[idx] = loadStatus; + } + break; + } + + return vAddr; +} + +s32 canonicalize_index(s32 poolIdx, s32 idx) { + ALSeqFile *f; + + f = get_audio_file_header(poolIdx); + if (f->seqArray[idx].len == 0) { + idx = (s32) (uintptr_t) f->seqArray[idx].offset; + } + return idx; +} + +void *get_bank_or_seq_wrapper(s32 poolIdx, s32 id) { + void *ret; + + ret = unk_pool1_lookup(poolIdx, id); + if (ret != NULL) { + return ret; + } + ret = get_bank_or_seq(poolIdx, 2, id); + if (ret != 0) { + return ret; + } + return NULL; +} + +ALSeqFile *get_audio_file_header(s32 poolIdx) { + ALSeqFile *ret; + switch (poolIdx) { + default: + ret = NULL; + break; + case 0: + ret = gSeqFileHeader; + break; + case 1: + ret = gAlCtlHeader; + break; + case 2: + ret = gAlTbl; + break; + } + return ret; +} + +void patch_audio_bank(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo) { + struct Instrument *instrument; + void **itInstrs; + struct Instrument **end; + s32 i; + void *patched; + struct Drum *drum; + s32 numDrums; + s32 numInstruments; + +#define BASE_OFFSET(x, base) (void *)((uintptr_t) (x) + (uintptr_t) base) +#define PATCH(x, base) (patched = BASE_OFFSET(x, base)) +#define PATCH_MEM(x) x = PATCH(x, mem) + + numDrums = gCtlEntries[bankId].numDrums; + numInstruments = gCtlEntries[bankId].numInstruments; + itInstrs = (void **) mem->drums; + if (mem->drums) { + } + if (itInstrs != NULL && numDrums != 0) { + if (1) { + mem->drums = PATCH(itInstrs, mem); + } + for (i = 0; i < numDrums; i++) { + patched = mem->drums[i]; + if (patched != NULL) { + drum = PATCH(patched, mem); + mem->drums[i] = drum; + if (drum->loaded == 0) { + patch_sound(&drum->sound, mem, patchInfo); + patched = drum->envelope; + drum->envelope = BASE_OFFSET(patched, mem); + drum->loaded = 1; + } + + } + } + } + + if (numInstruments > 0) { + itInstrs = (void **) mem->instruments; + end = numInstruments + (struct Instrument **) itInstrs; + + do { + if (*itInstrs != NULL) { + *itInstrs = BASE_OFFSET(*itInstrs, mem); + instrument = *itInstrs; + + if (instrument->loaded == 0) { + if (instrument->normalRangeLo != 0) { + patch_sound(&instrument->lowNotesSound, mem, patchInfo); + } + patch_sound(&instrument->normalNotesSound, mem, patchInfo); + if (instrument->normalRangeHi != 0x7F) { + patch_sound(&instrument->highNotesSound, mem, patchInfo); + } + patched = instrument->envelope; + + instrument->envelope = BASE_OFFSET(patched, mem); + instrument->loaded = 1; + } + } + itInstrs = (void **) ((struct Instrument **) itInstrs) + 1; + } while ((struct Instrument **) itInstrs != ((void) 0, end)); //! This is definitely fake + } + gCtlEntries[bankId].drums = mem->drums; + gCtlEntries[bankId].instruments = mem->instruments; +#undef PATCH_MEM +#undef PATCH +#undef BASE_OFFSET +} + +extern char shindouDebugPrint81[]; // "FastCopy" +extern char shindouDebugPrint82[]; // "FastCopy" +void func_sh_802f3c38(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 medium) { + nbytes = ALIGN16(nbytes); + osInvalDCache(vAddr, nbytes); + +again: + if (gAudioLoadLockSH != 0) { + goto again; + } + + if (nbytes >= 0x400U) { + func_sh_802f3dd0(&gAudioDmaIoMesg, 1, 0, devAddr, vAddr, 0x400, &gAudioDmaMesgQueue, medium, shindouDebugPrint81); + osRecvMesg(&gAudioDmaMesgQueue, NULL, 1); + nbytes = nbytes - 0x400; + devAddr = devAddr + 0x400; + vAddr = (u8*)vAddr + 0x400; + goto again; + } + + if (nbytes != 0) { + func_sh_802f3dd0(&gAudioDmaIoMesg, 1, 0, devAddr, vAddr, nbytes, &gAudioDmaMesgQueue, medium, shindouDebugPrint82); + osRecvMesg(&gAudioDmaMesgQueue, NULL, 1); + } +} + +void func_sh_802f3d78(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { + uintptr_t sp1C; + + sp1C = devAddr; + osInvalDCache(vAddr, nbytes); + func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); +} + +s32 func_sh_802f3dd0(OSIoMesg *m, s32 pri, s32 direction, uintptr_t devAddr, void *dramAddr, s32 size, OSMesgQueue *retQueue, s32 medium, UNUSED const char *reason) { + OSPiHandle *handle; + if (gAudioLoadLockSH >= 0x11U) { + return -1; + } + switch (medium) { + case 2: + handle = osCartRomInit(); + break; + default: + return 0; + } + if ((size & 0xf) != 0) { + size = ALIGN16(size); + } + m->hdr.pri = pri; + m->hdr.retQueue = retQueue; + m->dramAddr = dramAddr; + m->devAddr = devAddr; + m->size = size; + handle->transferInfo.cmdType = 2; + osEPiStartDma(handle, m, direction); + return 0; +} + +s32 func_sh_802f3ec4(UNUSED s32 arg0, UNUSED uintptr_t *arg1) { + return 0; +} + +void func_sh_802f3ed4(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED void *vAddr, UNUSED size_t nbytes) { +} + +void *func_sh_802f3ee8(s32 poolIdx, s32 idx) { + s32 temp; + return func_sh_802f3764(poolIdx, idx, &temp); +} + +void *func_802f3f08(s32 poolIdx, s32 idx, s32 numChunks, s32 arg3, OSMesgQueue *retQueue) { + s32 size; + ALSeqFile *f; + void *vAddr; + s32 medium; + s32 sp18; + uintptr_t devAddr; + s32 loadStatus; + + switch (poolIdx) { + case 0: + if (gSeqLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { + return 0; + } + break; + case 1: + if (gBankLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { + return 0; + } + break; + case 2: + if (gUnkLoadStatus[idx] == SOUND_LOAD_STATUS_IN_PROGRESS) { + return 0; + } + break; + + } + vAddr = get_bank_or_seq_wrapper(poolIdx, idx); + if (vAddr != NULL) { + loadStatus = 2; + osSendMesg(retQueue, (OSMesg) (arg3 << 0x18), 0); + } else { + f = get_audio_file_header(poolIdx); + size = f->seqArray[idx].len; + size = ALIGN16(size); + medium = f->seqArray[idx].medium; + sp18 = f->seqArray[idx].magic; + devAddr = (uintptr_t) f->seqArray[idx].offset; + loadStatus = 2; + + switch (sp18) { + case 0: + vAddr = unk_pool1_alloc(poolIdx, idx, size); + if (vAddr == NULL) { + return vAddr; + } + loadStatus = SOUND_LOAD_STATUS_5; + break; + case 1: + vAddr = alloc_bank_or_seq(poolIdx, size, 1, idx); + if (vAddr == NULL) { + return vAddr; + } + break; + case 2: + vAddr = alloc_bank_or_seq(poolIdx, size, 0, idx); + if (vAddr == NULL) { + return vAddr; + } + break; + + case 4: + case 3: + vAddr = alloc_bank_or_seq(poolIdx, size, 2, idx); + if (vAddr == NULL) { + return vAddr; + } + break; + } + + func_sh_802f4cb4(devAddr, vAddr, size, medium, numChunks, retQueue, (arg3 << 0x18) | (poolIdx << 0x10) | (idx << 8) | loadStatus); + loadStatus = SOUND_LOAD_STATUS_IN_PROGRESS; + } + + switch (poolIdx) { + case 0: + if (gSeqLoadStatus[idx] != SOUND_LOAD_STATUS_5) { + gSeqLoadStatus[idx] = loadStatus; + } + break; + + case 1: + if (gBankLoadStatus[idx] != SOUND_LOAD_STATUS_5) { + gBankLoadStatus[idx] = loadStatus; + } + break; + + case 2: + if (gUnkLoadStatus[idx] != SOUND_LOAD_STATUS_5) { + gUnkLoadStatus[idx] = loadStatus; + } + break; + } + + return vAddr; +} + +void func_sh_802f41e4(s32 audioResetStatus) { + func_sh_802f4a4c(audioResetStatus); + func_sh_802f573c(audioResetStatus); + func_sh_802f4dcc(audioResetStatus); +} + +#if defined(VERSION_SH) +u8 gShindouSoundBanksHeader[] = { +#include "sound/ctl_header.inc.c" +}; + +u8 gBankSetsData[] = { +#include "sound/bank_sets.inc.c" +}; + +u8 gShindouSampleBanksHeader[] = { +#include "sound/tbl_header.inc.c" +}; + +u8 gShindouSequencesHeader[] = { +#include "sound/sequences_header.inc.c" +}; +#endif + +// (void) must be omitted from parameters +void audio_init() { + UNUSED s8 pad[0x34]; + s32 i, j, k; + s32 lim; + u64 *ptr64; + void *data; + UNUSED u8 pad2[4]; + s32 seqCount; + + gAudioLoadLockSH = 0; + + for (i = 0; i < gAudioHeapSize / 8; i++) { + ((u64 *) gAudioHeap)[i] = 0; + } + +#ifdef TARGET_N64 + // It seems boot.s doesn't clear the .bss area for audio, so do it here. + lim = ((uintptr_t) &gAudioGlobalsEndMarker - (uintptr_t) &gAudioGlobalsStartMarker) / 8; + ptr64 = &gAudioGlobalsStartMarker; + for (k = lim; k >= 0; k--) { + *ptr64++ = 0; + } +#endif + + D_EU_802298D0 = 16.713f; + gRefreshRate = 60; + port_eu_init(); + +#ifdef TARGET_N64 + eu_stubbed_printf_3("Clear Workarea %x -%x size %x \n", + (uintptr_t) &gAudioGlobalsStartMarker, + (uintptr_t) &gAudioGlobalsEndMarker, + (uintptr_t) &gAudioGlobalsEndMarker - (uintptr_t) &gAudioGlobalsStartMarker + ); +#endif + + eu_stubbed_printf_1("AudioHeap is %x\n", gAudioHeapSize); + + for (i = 0; i < NUMAIBUFFERS; i++) { + gAiBufferLengths[i] = 0xa0; + } + + gAudioFrameCount = 0; + gAudioTaskIndex = 0; + gCurrAiBufferIndex = 0; + gSoundMode = 0; + gAudioTask = NULL; + gAudioTasks[0].task.t.data_size = 0; + gAudioTasks[1].task.t.data_size = 0; + osCreateMesgQueue(&gAudioDmaMesgQueue, &gAudioDmaMesg, 1); + osCreateMesgQueue(&gCurrAudioFrameDmaQueue, gCurrAudioFrameDmaMesgBufs, + ARRAY_COUNT(gCurrAudioFrameDmaMesgBufs)); + osCreateMesgQueue(&gUnkQueue1, gUnkMesgBufs1, 0x10); + osCreateMesgQueue(&gUnkQueue2, gUnkMesgBufs2, 0x10); + gCurrAudioFrameDmaCount = 0; + gSampleDmaNumListItems = 0; + + sound_init_main_pools(gAudioInitPoolSize); + + for (i = 0; i < NUMAIBUFFERS; i++) { + gAiBuffers[i] = sound_alloc_uninitialized(&gAudioInitPool, AIBUFFER_LEN); + + for (j = 0; j < (s32) (AIBUFFER_LEN / sizeof(s16)); j++) { + gAiBuffers[i][j] = 0; + } + } + + gAudioResetPresetIdToLoad = 0; + gAudioResetStatus = 1; + audio_shut_down_and_reset_step(); + + // Not sure about these prints + eu_stubbed_printf_1("Heap reset.Synth Change %x \n", 0); + eu_stubbed_printf_3("Heap %x %x %x\n", 0, 0, 0); + eu_stubbed_printf_0("Main Heap Initialize.\n"); + + // Load headers for sounds and sequences + gSeqFileHeader = (ALSeqFile *) gShindouSequencesHeader; + gAlCtlHeader = (ALSeqFile *) gShindouSoundBanksHeader; + gAlTbl = (ALSeqFile *) gShindouSampleBanksHeader; + gAlBankSets = gBankSetsData; + gSequenceCount = (s16) gSeqFileHeader->seqCount; + patch_seq_file(gSeqFileHeader, gMusicData, D_SH_80315EF4); + patch_seq_file(gAlCtlHeader, gSoundDataADSR, D_SH_80315EF8); + patch_seq_file(gAlTbl, gSoundDataRaw, D_SH_80315EFC); + seqCount = gAlCtlHeader->seqCount; + gCtlEntries = sound_alloc_uninitialized(&gAudioInitPool, seqCount * sizeof(struct CtlEntry)); + for (i = 0; i < seqCount; i++) { + gCtlEntries[i].bankId1 = (u8) ((gAlCtlHeader->seqArray[i].ctl.as_s16.bankAndFf >> 8) & 0xff); + gCtlEntries[i].bankId2 = (u8) (gAlCtlHeader->seqArray[i].ctl.as_s16.bankAndFf & 0xff); + gCtlEntries[i].numInstruments = (u8) ((gAlCtlHeader->seqArray[i].ctl.as_s16.numInstrumentsAndDrums >> 8) & 0xff); + gCtlEntries[i].numDrums = (u8) (gAlCtlHeader->seqArray[i].ctl.as_s16.numInstrumentsAndDrums & 0xff); + } + data = sound_alloc_uninitialized(&gAudioInitPool, D_SH_80315EF0); + if (data == NULL) { + D_SH_80315EF0 = 0; + } + sound_alloc_pool_init(&gUnkPool1.pool, data, D_SH_80315EF0); + init_sequence_players(); +} + +s32 func_sh_802f47c8(s32 bankId, u8 idx, s8 *io) { + struct AudioBankSample *sample = func_sh_802f4978(bankId, idx); + struct PendingDmaSample *temp; + if (sample == NULL) { + *io = 0; + return -1; + } + if (sample->medium == 0) { + *io = 2; + return 0; + } + temp = &D_SH_80343D00.arr[D_SH_80343D00.someIndex]; + if (temp->state == 3) { + temp->state = 0; + } + temp->sample = *sample; + temp->io = io; + temp->vAddr = func_sh_802f1d40(sample->size, bankId, sample->sampleAddr, sample->medium); + if (temp->vAddr == NULL) { + if (sample->medium == 1 || sample->codec == CODEC_SKIP) { + *io = 0; + return -1; + } else { + *io = 3; + return -1; + } + } + temp->state = 1; + temp->remaining = ALIGN16(sample->size); + temp->resultSampleAddr = (u8 *) temp->vAddr; + temp->devAddr = (uintptr_t) sample->sampleAddr; + temp->medium = sample->medium; + temp->bankId = bankId; + temp->idx = idx; + D_SH_80343D00.someIndex ^= 1; + return 0; +} + +struct AudioBankSample *func_sh_802f4978(s32 bankId, s32 idx) { + struct Drum *drum; + struct Instrument *inst; + struct AudioBankSample *ret; + + if (idx < 128) { + inst = get_instrument_inner(bankId, idx); + if (inst == 0) { + return NULL; + } + ret = inst->normalNotesSound.sample; + } else { + drum = get_drum(bankId, idx - 128); + if (drum == 0) { + return NULL; + } + ret = drum->sound.sample; + } + return ret; +} + +void stub_sh_802f49dc(void) { +} + +void func_sh_802f49e4(struct PendingDmaSample *arg0) { + struct AudioBankSample *sample = func_sh_802f4978(arg0->bankId, arg0->idx); + if (sample != NULL) { + arg0->sample = *sample; + sample->sampleAddr = arg0->resultSampleAddr; + sample->medium = 0; + } +} + +void func_sh_802f4a4c(s32 audioResetStatus) { + ALSeqFile *alTbl; + struct PendingDmaSample *entry; + + s32 i; + + alTbl = gAlTbl; + + for (i = 0; i < 2; i++) { + entry = &D_SH_80343D00.arr[i]; + switch (entry->state) { + case 2: + osRecvMesg(&entry->queue, NULL, 1); + if (audioResetStatus != 0) { + entry->state = 3; + break; + } + // fallthrough + case 1: + entry->state = 2; + if (entry->remaining == 0) { + func_sh_802f49e4(entry); + entry->state = 3; + *entry->io = 1; + } else if (entry->remaining < 0x1000) { + if (entry->medium == 1) { + func_sh_802f4c5c(entry->devAddr, entry->vAddr, entry->remaining, alTbl->unk2); + } else { + func_sh_802f4bd8(entry, entry->remaining); + } + entry->remaining = 0; + } else { + if (entry->medium == 1) { + func_sh_802f4c5c(entry->devAddr, entry->vAddr, 0x1000, alTbl->unk2); + } else { + func_sh_802f4bd8(entry, 0x1000); + } + entry->remaining = (s32) (entry->remaining - 0x1000); + entry->vAddr = (u8 *) entry->vAddr + 0x1000; + entry->devAddr = entry->devAddr + 0x1000; + } + break; + } + } +} + +extern char shindouDebugPrint102[]; // "SLOWCOPY" +void func_sh_802f4bd8(struct PendingDmaSample *arg0, s32 len) { // len must be signed + osInvalDCache(arg0->vAddr, len); + osCreateMesgQueue(&arg0->queue, arg0->mesgs, 1); + func_sh_802f3dd0(&arg0->ioMesg, 0, 0, arg0->devAddr, arg0->vAddr, len, &arg0->queue, arg0->medium, shindouDebugPrint102); +} + +void func_sh_802f4c5c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { + uintptr_t sp1C; + + sp1C = devAddr; + osInvalDCache(vAddr, nbytes); + func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); +} + +struct PendingDmaAudioBank *func_sh_802f4cb4(uintptr_t devAddr, void *vAddr, s32 size, s32 medium, s32 numChunks, OSMesgQueue *retQueue, s32 encodedInfo) { + struct PendingDmaAudioBank *item; + s32 i; + + for (i = 0; i < ARRAY_COUNT(sPendingDmaAudioBanks); i++) { + if (sPendingDmaAudioBanks[i].inProgress == 0) { + item = &sPendingDmaAudioBanks[i]; + break; + } + } + if (i == ARRAY_COUNT(sPendingDmaAudioBanks)) { + return NULL; + } + + item->inProgress = 1; + item->devAddr = devAddr; + item->audioBank = vAddr; + item->vAddr = vAddr; + item->remaining = size; + if (numChunks == 0) { + item->transferSize = 0x1000; + } else { + item->transferSize = ((size / numChunks) + 0xFF) & ~0xFF; + if (item->transferSize < 0x100) { + item->transferSize = 0x100; + } + } + item->retQueue = retQueue; + item->timer = 3; + item->medium = medium; + item->encodedInfo = encodedInfo; + osCreateMesgQueue(&item->dmaRetQueue, item->mesgs, 1); + return item; +} + +void func_sh_802f4dcc(s32 audioResetStatus) { + s32 i; + + if (gAudioLoadLockSH != 1) { + for (i = 0; i < ARRAY_COUNT(sPendingDmaAudioBanks); i++) { + if (sPendingDmaAudioBanks[i].inProgress == 1) { + func_sh_802f4e50(&sPendingDmaAudioBanks[i], audioResetStatus); + } + } + } +} + +void func_sh_802f4e50(struct PendingDmaAudioBank *audioBank, s32 audioResetStatus) { + ALSeqFile *alSeqFile; + u32 *encodedInfo; + OSMesg mesg; + u32 temp; + u32 bankId; + s32 bankId1; + s32 bankId2; + struct PatchStruct patchStruct; + alSeqFile = gAlTbl; + if (audioBank->timer >= 2) { + audioBank->timer--; + return; + } + if (audioBank->timer == 1) { + audioBank->timer = 0; + } else { + if (audioResetStatus != 0) { + osRecvMesg(&audioBank->dmaRetQueue, NULL, OS_MESG_BLOCK); + audioBank->inProgress = 0; + return; + } + if (osRecvMesg(&audioBank->dmaRetQueue, NULL, OS_MESG_NOBLOCK) == -1) { + return; + } + } + + encodedInfo = &audioBank->encodedInfo; + if (audioBank->remaining == 0) { + mesg = (OSMesg) audioBank->encodedInfo; +#pragma GCC diagnostic push +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wself-assign" +#endif + mesg = mesg; //! needs an extra read from mesg here to match... +#pragma GCC diagnostic pop + temp = *encodedInfo; + bankId = (temp >> 8) & 0xFF; + switch ((u8) (temp >> 0x10)) { + case 0: + if (gSeqLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { + gSeqLoadStatus[bankId] = (u8) (temp & 0xFF); + } + break; + case 2: + if (gUnkLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { + gUnkLoadStatus[bankId] = (u8) (temp & 0xFF); + } + break; + case 1: + if (gBankLoadStatus[bankId] != SOUND_LOAD_STATUS_5) { + gBankLoadStatus[bankId] = (u8) (temp & 0xFF); + } + bankId1 = gCtlEntries[bankId].bankId1; + bankId2 = gCtlEntries[bankId].bankId2; + patchStruct.bankId1 = bankId1; + patchStruct.bankId2 = bankId2; + if (bankId1 != 0xFF) { + patchStruct.baseAddr1 = func_sh_802f3598(bankId1, &patchStruct.medium1); + } else { + patchStruct.baseAddr1 = NULL; + } + if (bankId2 != 0xFF) { + patchStruct.baseAddr2 = func_sh_802f3598(bankId2, &patchStruct.medium2); + } else { + patchStruct.baseAddr2 = NULL; + } + + func_sh_802f5310(bankId, audioBank->audioBank, &patchStruct, 1); + break; + } + mesg = (OSMesg) audioBank->encodedInfo; + audioBank->inProgress = 0; + osSendMesg(audioBank->retQueue, mesg, OS_MESG_NOBLOCK); + } else if (audioBank->remaining < audioBank->transferSize) { + if (audioBank->medium == 1) { + func_sh_802f517c(audioBank->devAddr, audioBank->vAddr, audioBank->remaining, alSeqFile->unk2); + } else { + func_sh_802f50ec(audioBank, audioBank->remaining); + } + + audioBank->remaining = 0; + } else { + if (audioBank->medium == 1) { + func_sh_802f517c(audioBank->devAddr, audioBank->vAddr, audioBank->transferSize, alSeqFile->unk2); + } else { + func_sh_802f50ec(audioBank, audioBank->transferSize); + } + + audioBank->remaining -= audioBank->transferSize; + audioBank->devAddr += audioBank->transferSize; + audioBank->vAddr = ((u8 *) audioBank->vAddr) + audioBank->transferSize; + } +} + +extern char shindouDebugPrint110[]; // "BGCOPY" +void func_sh_802f50ec(struct PendingDmaAudioBank *arg0, size_t len) { + len += 0xf; + len &= ~0xf; + osInvalDCache(arg0->vAddr, len); + osCreateMesgQueue(&arg0->dmaRetQueue, arg0->mesgs, 1); + func_sh_802f3dd0(&arg0->ioMesg, 0, 0, arg0->devAddr, arg0->vAddr, len, &arg0->dmaRetQueue, arg0->medium, shindouDebugPrint110); +} + + +void func_sh_802f517c(uintptr_t devAddr, void *vAddr, size_t nbytes, s32 arg3) { + uintptr_t sp1C; + + sp1C = devAddr; + osInvalDCache(vAddr, nbytes); + func_sh_802f3ed4(func_sh_802f3ec4(arg3, &sp1C), sp1C, vAddr, nbytes); +} + +void patch_sound(struct AudioBankSound *sound, struct AudioBank *memBase, struct PatchStruct *patchInfo) { + struct AudioBankSample *sample; + void *patched; + +#define PATCH(x, base) (patched = (void *)((uintptr_t) (x) + (uintptr_t) base)) + + if ((uintptr_t) sound->sample <= 0x80000000) { + sample = sound->sample = PATCH(sound->sample, memBase); + if (sample->size != 0 && sample->isPatched != TRUE) { + sample->loop = PATCH(sample->loop, memBase); + sample->book = PATCH(sample->book, memBase); + switch (sample->medium) { + case 0: + sample->sampleAddr = PATCH(sample->sampleAddr, patchInfo->baseAddr1); + sample->medium = patchInfo->medium1; + break; + case 1: + sample->sampleAddr = PATCH(sample->sampleAddr, patchInfo->baseAddr2); + sample->medium = patchInfo->medium2; + break; + + case 2: + case 3: + break; + } + sample->isPatched = TRUE; + if (sample->bit1 && sample->medium != 0) { + D_SH_8034EA88[D_SH_8034F688++] = sample; + } + } + } +#undef PATCH +} + +BAD_RETURN(s32) func_sh_802f5310(s32 bankId, struct AudioBank *mem, struct PatchStruct *patchInfo, s32 arg3) { + UNUSED u32 pad[2]; + u8 *addr; + UNUSED u32 pad1[3]; + s32 sp4C; + struct AudioBankSample *temp_s0; + s32 i; + uintptr_t count; + s32 temp; + + sp4C = 0; + if (D_SH_8034F68C != 0) { + sp4C = 1; + } else { + D_SH_80343CF0 = 0; + } + D_SH_8034F688 = 0; + patch_audio_bank(bankId, mem, patchInfo); + + count = 0; + for (i = 0; i < D_SH_8034F688; i++) { + count += ALIGN16(D_SH_8034EA88[i]->size); + } + + for (i = 0; i < D_SH_8034F688; i++) { + if (D_SH_8034F68C != 0x78) { + temp_s0 = D_SH_8034EA88[i]; + switch (arg3) { + case 0: + temp = temp_s0->medium = patchInfo->medium1; + if (temp != 0) { + if (temp_s0->size) { + } + addr = func_sh_802f1d90(temp_s0->size, patchInfo->bankId1, temp_s0->sampleAddr, temp_s0->medium); + } else { + temp = temp_s0->medium = patchInfo->medium2; + if (temp != 0) { + addr = func_sh_802f1d90(temp_s0->size, patchInfo->bankId2, temp_s0->sampleAddr, temp_s0->medium); + } + } + break; + + case 1: + temp = temp_s0->medium = patchInfo->medium1; + if (temp != 0) { + addr = func_sh_802f1d40(temp_s0->size, patchInfo->bankId1, temp_s0->sampleAddr, temp_s0->medium); + } else { + temp = temp_s0->medium = patchInfo->medium2; + if (temp != 0) { + addr = func_sh_802f1d40(temp_s0->size, patchInfo->bankId2, temp_s0->sampleAddr, temp_s0->medium); + } + } + break; + } + switch ((uintptr_t) addr) { + case 0: + break; + default: + switch (arg3) { + case 0: + if (temp_s0->medium == 1) { + func_sh_802f3d78((uintptr_t) temp_s0->sampleAddr, addr, temp_s0->size, gAlTbl->unk2); + temp_s0->sampleAddr = addr; + temp_s0->medium = 0; + } else { + func_sh_802f3c38((uintptr_t) temp_s0->sampleAddr, addr, temp_s0->size, temp_s0->medium); + temp_s0->sampleAddr = addr; + temp_s0->medium = 0; + } + break; + + case 1: + D_SH_8034EC88[D_SH_8034F68C].sample = temp_s0; + D_SH_8034EC88[D_SH_8034F68C].ramAddr = addr; + D_SH_8034EC88[D_SH_8034F68C].encodedInfo = (D_SH_8034F68C << 24) | 0xffffff; + D_SH_8034EC88[D_SH_8034F68C].isFree = FALSE; + D_SH_8034EC88[D_SH_8034F68C].endAndMediumIdentification = temp_s0->sampleAddr + temp_s0->size + temp_s0->medium; + D_SH_8034F68C++; + break; + } + } + continue; + } + break; + } + + D_SH_8034F688 = 0; + if (D_SH_8034F68C != 0 && sp4C == 0) { + temp_s0 = D_SH_8034EC88[D_SH_8034F68C - 1].sample; + temp = (temp_s0->size >> 12); + temp += 1; + count = (uintptr_t) temp_s0->sampleAddr; + func_sh_802f4cb4( + count, + D_SH_8034EC88[D_SH_8034F68C - 1].ramAddr, + temp_s0->size, + temp_s0->medium, + temp, + &gUnkQueue2, + D_SH_8034EC88[D_SH_8034F68C - 1].encodedInfo); + } +} + +s32 func_sh_802f573c(s32 audioResetStatus) { + struct AudioBankSample *sample; + u32 idx; + u8 *sampleAddr; + u32 size; + s32 unk; + u8 *added; + + if (D_SH_8034F68C > 0) { + if (audioResetStatus != 0) { + if (osRecvMesg(&gUnkQueue2, (OSMesg *) &idx, OS_MESG_NOBLOCK)){ + } + D_SH_8034F68C = 0; + return 0; + } + if (osRecvMesg(&gUnkQueue2, (OSMesg *) &idx, OS_MESG_NOBLOCK) == -1) { + return 0; + } + idx >>= 0x18; + if (D_SH_8034EC88[idx].isFree == FALSE) { + sample = D_SH_8034EC88[idx].sample; + added = (sample->sampleAddr + sample->size + sample->medium); + if (added == D_SH_8034EC88[idx].endAndMediumIdentification) { + sample->sampleAddr = D_SH_8034EC88[idx].ramAddr; + sample->medium = 0; + } + D_SH_8034EC88[idx].isFree = TRUE; + } + +next: + if (D_SH_8034F68C > 0) { + if (D_SH_8034EC88[D_SH_8034F68C - 1].isFree == TRUE) { + D_SH_8034F68C--; + goto next; + } + sample = D_SH_8034EC88[D_SH_8034F68C - 1].sample; + sampleAddr = sample->sampleAddr; + size = sample->size; + unk = size >> 0xC; + unk += 1; + added = ((sampleAddr + size) + sample->medium); + if (added != D_SH_8034EC88[D_SH_8034F68C - 1].endAndMediumIdentification) { + D_SH_8034EC88[D_SH_8034F68C - 1].isFree = TRUE; + D_SH_8034F68C--; + goto next; + } + size = sample->size; + func_sh_802f4cb4((uintptr_t) sampleAddr, D_SH_8034EC88[D_SH_8034F68C - 1].ramAddr, size, sample->medium, + unk, &gUnkQueue2, D_SH_8034EC88[D_SH_8034F68C - 1].encodedInfo); + } + } + return 1; +} + +s32 func_sh_802f5900(struct AudioBankSample *sample, s32 numLoaded, struct AudioBankSample *arg2[]) { + s32 i; + + for (i = 0; i < numLoaded; i++) { + if (sample->sampleAddr == arg2[i]->sampleAddr) { + break; + } + } + if (i == numLoaded) { + arg2[numLoaded++] = sample; + } + return numLoaded; +} + +s32 func_sh_802f5948(s32 bankId, struct AudioBankSample *list[]) { + s32 i; + struct Drum *drum; + struct Instrument *inst; + s32 numLoaded; + s32 numDrums; + s32 numInstruments; + + numLoaded = 0; + numDrums = gCtlEntries[bankId].numDrums; + numInstruments = gCtlEntries[bankId].numInstruments; + + for (i = 0; i < numDrums; i++) { + drum = get_drum(bankId, i); + if (drum == NULL) { + continue; + } + numLoaded = func_sh_802f5900(drum->sound.sample, numLoaded, list); + } + for (i = 0; i < numInstruments; i++) { + inst = get_instrument_inner(bankId, i); + if (inst == NULL) { + continue; + + } + if (inst->normalRangeLo != 0) { + numLoaded = func_sh_802f5900(inst->lowNotesSound.sample, numLoaded, list); + } + if (inst->normalRangeHi != 127) { + numLoaded = func_sh_802f5900(inst->highNotesSound.sample, numLoaded, list); + } + numLoaded = func_sh_802f5900(inst->normalNotesSound.sample, numLoaded, list); + } + return numLoaded; +} +#endif diff --git a/src/audio/playback.c b/src/audio/playback.c index dc07fd78..ff42e765 100644 --- a/src/audio/playback.c +++ b/src/audio/playback.c @@ -15,7 +15,7 @@ void note_set_resampling_rate(struct Note *note, f32 resamplingRateInput); #ifdef VERSION_SH void note_set_vel_pan_reverb(struct Note *note, struct ReverbInfo *reverbInfo) #else -void note_set_vel_pan_reverb(struct Note *note, f32 velocity, u8 pan, u8 reverb) +void note_set_vel_pan_reverb(struct Note *note, f32 velocity, u8 pan, u8 reverbVol) #endif { struct NoteSubEu *sub = ¬e->noteSubEu; @@ -30,7 +30,7 @@ void note_set_vel_pan_reverb(struct Note *note, f32 velocity, u8 pan, u8 reverb) UNUSED u32 pad1; f32 velocity; u8 pan; - u8 reverb; + u8 reverbVol; struct ReverbBitsData reverbBits; #endif @@ -38,7 +38,7 @@ void note_set_vel_pan_reverb(struct Note *note, f32 velocity, u8 pan, u8 reverb) note_set_resampling_rate(note, reverbInfo->freqScale); velocity = reverbInfo->velocity; pan = reverbInfo->pan; - reverb = reverbInfo->reverb; + reverbVol = reverbInfo->reverbVol; reverbBits = reverbInfo->reverbBits.s; pan &= 0x7f; #else @@ -119,7 +119,7 @@ void note_set_vel_pan_reverb(struct Note *note, f32 velocity, u8 pan, u8 reverb) } #ifdef VERSION_SH -if (velocity < 0.0f) { + if (velocity < 0.0f) { velocity = 0.0f; } if (velocity > 1.0f) { @@ -128,7 +128,7 @@ if (velocity < 0.0f) { sub->targetVolLeft = ((s32) (velocity * volLeft * 4095.999f)); sub->targetVolRight = ((s32) (velocity * volRight * 4095.999f)); - sub->bankId = reverbInfo->bankId; + sub->synthesisVolume = reverbInfo->synthesisVolume; sub->filter = reverbInfo->filter; #else if (velocity < 0.0f) { @@ -144,11 +144,12 @@ if (velocity < 0.0f) { sub->targetVolRight = ((s32) (velocity * volRight) & 0xffff) >> 5; #endif - if (sub->reverbVol != reverb) { + //! @bug for the change to UQ0.7, the if statement should also have been changed accordingly + if (sub->reverbVol != reverbVol) { #ifdef VERSION_SH - sub->reverbVol = reverb >> 1; + sub->reverbVol = reverbVol >> 1; #else - sub->reverbVol = reverb; + sub->reverbVol = reverbVol; #endif sub->envMixerNeedsInit = TRUE; return; @@ -345,7 +346,7 @@ void process_notes(void) { #ifndef VERSION_SH f32 frequency; #if defined(VERSION_JP) || defined(VERSION_US) - u8 reverb; + u8 reverbVol; #endif f32 velocity; #if defined(VERSION_JP) || defined(VERSION_US) @@ -359,11 +360,11 @@ void process_notes(void) { struct NoteSubEu *noteSubEu; #ifndef VERSION_SH UNUSED u8 pad[12]; - u8 reverb; + u8 reverbVol; UNUSED u8 pad3; u8 pan; #else - u8 pad[8]; + UNUSED u8 pad[8]; struct ReverbInfo reverbInfo; #endif u8 bookOffset; @@ -508,9 +509,9 @@ void process_notes(void) { reverbInfo.freqScale = attributes->freqScale; reverbInfo.velocity = attributes->velocity; reverbInfo.pan = attributes->pan; - reverbInfo.reverb = attributes->reverb; + reverbInfo.reverbVol = attributes->reverbVol; reverbInfo.reverbBits = attributes->reverbBits; - reverbInfo.bankId = attributes->unk1; + reverbInfo.synthesisVolume = attributes->synthesisVolume; reverbInfo.filter = attributes->filter; bookOffset = noteSubEu->bookOffset; } else { @@ -518,8 +519,8 @@ void process_notes(void) { reverbInfo.velocity = playbackState->parentLayer->noteVelocity; reverbInfo.pan = playbackState->parentLayer->notePan; reverbInfo.reverbBits = playbackState->parentLayer->reverbBits; - reverbInfo.reverb = playbackState->parentLayer->seqChannel->reverb; - reverbInfo.bankId = playbackState->parentLayer->seqChannel->unkSH0C; + reverbInfo.reverbVol = playbackState->parentLayer->seqChannel->reverbVol; + reverbInfo.synthesisVolume = playbackState->parentLayer->seqChannel->synthesisVolume; reverbInfo.filter = playbackState->parentLayer->seqChannel->filter; bookOffset = playbackState->parentLayer->seqChannel->bookOffset & 0x7; if (playbackState->parentLayer->seqChannel->seqPlayer->muted @@ -538,7 +539,7 @@ void process_notes(void) { frequency = attributes->freqScale; velocity = attributes->velocity; pan = attributes->pan; - reverb = attributes->reverb; + reverbVol = attributes->reverbVol; if (1) { } bookOffset = noteSubEu->bookOffset; @@ -546,7 +547,7 @@ void process_notes(void) { frequency = playbackState->parentLayer->noteFreqScale; velocity = playbackState->parentLayer->noteVelocity; pan = playbackState->parentLayer->notePan; - reverb = playbackState->parentLayer->seqChannel->reverb; + reverbVol = playbackState->parentLayer->seqChannel->reverbVol; bookOffset = playbackState->parentLayer->seqChannel->bookOffset & 0x7; } @@ -554,7 +555,7 @@ void process_notes(void) { frequency *= gAudioBufferParameters.resampleRate; velocity = velocity * scale * scale; note_set_resampling_rate(note, frequency); - note_set_vel_pan_reverb(note, velocity, pan, reverb); + note_set_vel_pan_reverb(note, velocity, pan, reverbVol); #endif noteSubEu->bookOffset = bookOffset; skip:; @@ -603,12 +604,12 @@ void process_notes(void) { frequency = attributes->freqScale; velocity = attributes->velocity; pan = attributes->pan; - reverb = attributes->reverb; + reverbVol = attributes->reverbVol; } else { frequency = note->parentLayer->noteFreqScale; velocity = note->parentLayer->noteVelocity; pan = note->parentLayer->notePan; - reverb = note->parentLayer->seqChannel->reverb; + reverbVol = note->parentLayer->seqChannel->reverbVol; } scale = note->adsrVolScale; @@ -621,7 +622,7 @@ void process_notes(void) { scale *= 4.3498e-5f; // ~1 / 23000 velocity = velocity * scale * scale; note_set_frequency(note, frequency); - note_set_vel_pan_reverb(note, velocity, pan, reverb); + note_set_vel_pan_reverb(note, velocity, pan, reverbVol); continue; } #endif @@ -746,9 +747,9 @@ void seq_channel_layer_decay_release_internal(struct SequenceChannelLayer *seqLa attributes->reverbBits = seqLayer->reverbBits; #endif if (seqLayer->seqChannel != NULL) { - attributes->reverb = seqLayer->seqChannel->reverb; + attributes->reverbVol = seqLayer->seqChannel->reverbVol; #ifdef VERSION_SH - attributes->unk1 = seqLayer->seqChannel->unkSH0C; + attributes->synthesisVolume = seqLayer->seqChannel->synthesisVolume; attributes->filter = seqLayer->seqChannel->filter; if (seqLayer->seqChannel->seqPlayer->muted && (seqLayer->seqChannel->muteBehavior & 8) != 0) { note->noteSubEu.finished = TRUE; @@ -1159,7 +1160,7 @@ void note_init_for_layer(struct Note *note, struct SequenceChannelLayer *seqLaye build_synthetic_wave(note, seqLayer, instId); } #ifdef VERSION_SH - note->unkSH33 = seqLayer->seqChannel->bankId; + note->bankId = seqLayer->seqChannel->bankId; #else sub->bankId = seqLayer->seqChannel->bankId; #endif @@ -1444,7 +1445,7 @@ void note_init_all(void) { #if defined(VERSION_EU) || defined(VERSION_SH) note->waveId = 0; #else - note->reverb = 0; + note->reverbVol = 0; note->usesHeadsetPanEffects = FALSE; note->sampleCount = 0; note->instOrWave = 0; diff --git a/src/audio/playback.h b/src/audio/playback.h index d0eaf2ba..e2e15bf9 100644 --- a/src/audio/playback.h +++ b/src/audio/playback.h @@ -33,7 +33,7 @@ void note_init_all(void); #if defined(VERSION_SH) void note_set_vel_pan_reverb(struct Note *note, struct ReverbInfo *reverbInfo); #elif defined(VERSION_EU) -void note_set_vel_pan_reverb(struct Note *note, f32 velocity, u8 pan, u8 reverb); +void note_set_vel_pan_reverb(struct Note *note, f32 velocity, u8 pan, u8 reverbVol); #endif #if defined(VERSION_EU) || defined(VERSION_SH) diff --git a/src/audio/port_eu.c b/src/audio/port_eu.c index f591792c..f69222ab 100644 --- a/src/audio/port_eu.c +++ b/src/audio/port_eu.c @@ -34,7 +34,6 @@ extern struct EuAudioCmd sAudioCmd[0x100]; void func_8031D690(s32 player, FadeT fadeInTime); void seq_player_fade_to_zero_volume(s32 player, FadeT fadeOutTime); -void port_eu_init_queues(void); void decrease_sample_dma_ttls(void); s32 audio_shut_down_and_reset_step(void); void func_802ad7ec(u32); @@ -305,7 +304,7 @@ void func_802ad7ec(u32 arg0) { chan->changes.as_bitfields.freqScale = TRUE; break; case 5: - chan->reverb = cmd->u2.as_s8; + chan->reverbVol = cmd->u2.as_s8; break; case 6: if (cmd->u.s.arg3 < 8) { diff --git a/src/audio/unk_shindou_audio_file.c b/src/audio/port_sh.c similarity index 87% rename from src/audio/unk_shindou_audio_file.c rename to src/audio/port_sh.c index 5e7908bd..899cbb38 100644 --- a/src/audio/unk_shindou_audio_file.c +++ b/src/audio/port_sh.c @@ -1,4 +1,5 @@ #ifdef VERSION_SH +// TODO: merge this with port_eu.c? #include @@ -7,6 +8,7 @@ #include "load.h" #include "synthesis.h" #include "internal.h" +#include "seqplayer.h" #define EXTRA_BUFFERED_AI_SAMPLES_TARGET 0x80 #define SAMPLES_TO_OVERPRODUCE 0x10 @@ -15,12 +17,13 @@ extern s32 D_SH_80314FC8; extern struct SPTask *D_SH_80314FCC; extern u8 D_SH_80315098; extern u8 D_SH_8031509C; +extern OSMesgQueue *D_SH_80350F68; -void func_sh_802f62e0(s32 playerIndex, s32 numFrames); -void func_sh_802f6288(s32 arg0, s32 numFrames); -void func_sh_802f6554(u32 arg0); +void func_8031D690(s32 playerIndex, s32 numFrames); +void seq_player_fade_to_zero_volume(s32 arg0, s32 numFrames); +void func_802ad7ec(u32 arg0); -struct SPTask *func_sh_802f5a80(void) { +struct SPTask *create_next_audio_frame_task(void) { u32 samplesRemainingInAI; s32 writtenCmds; s32 index; @@ -59,7 +62,7 @@ struct SPTask *func_sh_802f5a80(void) { gCurrAudioFrameDmaCount = 0; decrease_sample_dma_ttls(); - func_802f41e4(gAudioResetStatus); + func_sh_802f41e4(gAudioResetStatus); if (osRecvMesg(D_SH_80350F88, (OSMesg *) &sp38, OS_MESG_NOBLOCK) != -1) { if (gAudioResetStatus == 0) { gAudioResetStatus = 5; @@ -99,7 +102,7 @@ struct SPTask *func_sh_802f5a80(void) { if (osRecvMesg(D_SH_80350F68, (OSMesg *) &sp34, 0) != -1) { do { - func_sh_802f6554(sp34); + func_802ad7ec(sp34); } while (osRecvMesg(D_SH_80350F68, (OSMesg *) &sp34, 0) != -1); } @@ -143,7 +146,7 @@ struct SPTask *func_sh_802f5a80(void) { } } -void func_sh_802f5fb8(struct EuAudioCmd *cmd) { +void eu_process_audio_cmd(struct EuAudioCmd *cmd) { s32 i; struct Note *note; struct NoteSubEu *sub; @@ -155,8 +158,8 @@ void func_sh_802f5fb8(struct EuAudioCmd *cmd) { case 0x82: case 0x88: - func_sh_802F3410(cmd->u.s.arg1, cmd->u.s.arg2, cmd->u.s.arg3); - func_sh_802f62e0(cmd->u.s.arg1, cmd->u2.as_s32); + load_sequence(cmd->u.s.arg1, cmd->u.s.arg2, cmd->u.s.arg3); + func_8031D690(cmd->u.s.arg1, cmd->u2.as_s32); break; case 0x83: @@ -165,7 +168,7 @@ void func_sh_802f5fb8(struct EuAudioCmd *cmd) { sequence_player_disable(&gSequencePlayers[cmd->u.s.arg1]); } else { - func_sh_802f6288(cmd->u.s.arg1, cmd->u2.as_s32); + seq_player_fade_to_zero_volume(cmd->u.s.arg1, cmd->u2.as_s32); } } break; @@ -220,32 +223,32 @@ void func_sh_802f5fb8(struct EuAudioCmd *cmd) { } } -void func_sh_802f6288(s32 arg0, s32 numFrames) { +void seq_player_fade_to_zero_volume(s32 arg0, s32 fadeOutTime) { struct SequencePlayer *player; - if (numFrames == 0) { - numFrames = 1; + if (fadeOutTime == 0) { + fadeOutTime = 1; } player = &gSequencePlayers[arg0]; player->state = 2; - player->fadeRemainingFrames = numFrames; - player->fadeVelocity = -(player->fadeVolume / (f32) numFrames); + player->fadeRemainingFrames = fadeOutTime; + player->fadeVelocity = -(player->fadeVolume / (f32) fadeOutTime); } -void func_sh_802f62e0(s32 playerIndex, s32 numFrames) { +void func_8031D690(s32 playerIndex, s32 fadeInTime) { struct SequencePlayer *player; - if (numFrames != 0) { + if (fadeInTime != 0) { player = &gSequencePlayers[playerIndex]; player->state = 1; - player->fadeTimerUnkEu = numFrames; - player->fadeRemainingFrames = numFrames; + player->fadeTimerUnkEu = fadeInTime; + player->fadeRemainingFrames = fadeInTime; player->fadeVolume = 0.0f; player->fadeVelocity = 0.0f; } } -void func_sh_802f6330(void) { +void port_eu_init_queues(void) { D_SH_80350F18 = 0; D_SH_80350F19 = 0; D_SH_80350F38 = &D_SH_80350F20; @@ -258,8 +261,8 @@ void func_sh_802f6330(void) { osCreateMesgQueue(D_SH_80350FA8, D_SH_80350F8C, 1); } -extern struct EuAudioCmd sAudioCmd[0x100]; // sAudioCmd, maybe? -void func_802ad6f0(s32 arg0, s32 *arg1) { // func_sh_802f63f8 +extern struct EuAudioCmd sAudioCmd[0x100]; +void func_802ad6f0(s32 arg0, s32 *arg1) { struct EuAudioCmd *cmd = &sAudioCmd[D_SH_80350F18 & 0xff]; cmd->u.first = arg0; cmd->u2.as_u32 = *arg1; @@ -269,34 +272,30 @@ void func_802ad6f0(s32 arg0, s32 *arg1) { // func_sh_802f63f8 } } -void func_802ad728(u32 arg0, f32 arg1) { // func_sh_802f6450 +void func_802ad728(u32 arg0, f32 arg1) { func_802ad6f0(arg0, (s32 *) &arg1); } -void func_802ad74c(u32 arg0, u32 arg1) { // func_sh_802f6474 +void func_802ad74c(u32 arg0, u32 arg1) { func_802ad6f0(arg0, (s32 *) &arg1); } -void func_802ad770(u32 arg0, s8 arg1) { // func_sh_802f6498 +void func_802ad770(u32 arg0, s8 arg1) { s32 sp1C = arg1 << 24; func_802ad6f0(arg0, &sp1C); } char shindouDebugPrint133[] = "AudioSend: %d -> %d (%d)\n"; -extern OSMesgQueue *D_SH_80350F68; void func_sh_802F64C8(void) { static s32 D_SH_8031503C = 0; - s32 a0 = (D_SH_80350F18 - D_SH_80350F19 + 0x100) & 0xff; - s32 a1; + s32 mesg; - if (D_SH_8031503C < a0) { - D_SH_8031503C = a0; + if (((D_SH_80350F18 - D_SH_80350F19 + 0x100) & 0xff) > D_SH_8031503C) { + D_SH_8031503C = (D_SH_80350F18 - D_SH_80350F19 + 0x100) & 0xff; } - a0 = ((D_SH_80350F19 & 0xff) << 8) | (D_SH_80350F18 & 0xFF); - a1 = a0; - a0 = D_SH_80350F68; - osSendMesg(a0, a1, 0); + mesg = ((D_SH_80350F19 & 0xff) << 8) | (D_SH_80350F18 & 0xff); + osSendMesg(D_SH_80350F68, (OSMesg)mesg, OS_MESG_NOBLOCK); D_SH_80350F19 = D_SH_80350F18; } @@ -304,16 +303,16 @@ void func_sh_802f6540(void) { D_SH_80350F19 = D_SH_80350F18; } -void func_sh_802f6554(u32 arg0) { +void func_802ad7ec(u32 arg0) { struct EuAudioCmd *cmd; struct SequencePlayer *seqPlayer; struct SequenceChannel *chan; - u8 a0; + u8 end; - static char shindouDebugPrint134[] = "Continue Port\n"; - static char shindouDebugPrint135[] = "%d -> %d\n"; - static char shindouDebugPrint136[] = "Sync-Frame Break. (Remain %d)\n"; - static char shindouDebugPrint137[] = "Undefined Port Command %d\n"; + UNUSED static char shindouDebugPrint134[] = "Continue Port\n"; + UNUSED static char shindouDebugPrint135[] = "%d -> %d\n"; + UNUSED static char shindouDebugPrint136[] = "Sync-Frame Break. (Remain %d)\n"; + UNUSED static char shindouDebugPrint137[] = "Undefined Port Command %d\n"; static u8 D_SH_80315098 = 0; static u8 D_SH_8031509C = 0; @@ -322,10 +321,10 @@ void func_sh_802f6554(u32 arg0) { D_SH_80315098 = (arg0 >> 8) & 0xff; } - a0 = arg0 & 0xff; + end = arg0 & 0xff; for (;;) { - if (D_SH_80315098 == a0) { + if (D_SH_80315098 == end) { D_SH_8031509C = 0; break; } @@ -336,12 +335,12 @@ void func_sh_802f6554(u32 arg0) { break; } else if ((cmd->u.s.op & 0xf0) == 0xf0) { - func_sh_802f5fb8(cmd); + eu_process_audio_cmd(cmd); } else if (cmd->u.s.arg1 < SEQUENCE_PLAYERS) { seqPlayer = &gSequencePlayers[cmd->u.s.arg1]; if ((cmd->u.s.op & 0x80) != 0) { - func_sh_802f5fb8(cmd); + eu_process_audio_cmd(cmd); } else if ((cmd->u.s.op & 0x40) != 0) { switch (cmd->u.s.op) { @@ -399,8 +398,9 @@ void func_sh_802f6554(u32 arg0) { } break; case 5: - if (chan->reverb != cmd->u2.as_s8) { - chan->reverb = cmd->u2.as_s8; + //! @bug u8 s8 comparison (but harmless) + if (chan->reverbVol != cmd->u2.as_s8) { + chan->reverbVol = cmd->u2.as_s8; } break; case 6: @@ -489,9 +489,8 @@ s8 func_sh_802f6a6c(s32 playerIndex, s32 index) { return gSequencePlayers[playerIndex].seqVariationEu[index]; } -void func_sh_802f6a9c(void) { - // creates a bunch of os message queues - func_sh_802f6330(); +void port_eu_init(void) { + port_eu_init_queues(); } char shindouDebugPrint138[] = "specchg conjunction error (Msg:%d Cur:%d)\n"; @@ -525,9 +524,13 @@ char shindouDebugPrint164[] = "Audio: C-Alloc : lowerPrio is NULL\n"; char shindouDebugPrint165[] = "Intterupt UseStop %d (Kill %d)\n"; char shindouDebugPrint166[] = "Intterupt RelWait %d (Kill %d)\n"; char shindouDebugPrint167[] = "Drop Voice (Prio %x)\n"; -s32 D_SH_803154CC = 0; // Either an unused variable or a file boundary. +s32 D_SH_803154CC = 0; // file boundary + +// effects.c char shindouDebugPrint168[] = "Audio:Envp: overflow %f\n"; -s32 D_SH_803154EC = 0; // Either an unused variable or a file boundary. +s32 D_SH_803154EC = 0; // file boundary + +// seqplayer.c char shindouDebugPrint169[] = "Audio:Track:Warning: No Free Notetrack\n"; char shindouDebugPrint170[] = "SUBTRACK DIM\n"; char shindouDebugPrint171[] = "Audio:Track: Warning :SUBTRACK had been stolen by other Group.\n"; diff --git a/src/audio/seqplayer.c b/src/audio/seqplayer.c index a5a92b84..7df4dd32 100644 --- a/src/audio/seqplayer.c +++ b/src/audio/seqplayer.c @@ -55,9 +55,9 @@ void sequence_channel_init(struct SequenceChannel *seqChannel) { seqChannel->panChannelWeight = 1.0f; seqChannel->noteUnused = NULL; #endif - seqChannel->reverb = 0; + seqChannel->reverbVol = 0; #ifdef VERSION_SH - seqChannel->unkSH0C = 0; + seqChannel->synthesisVolume = 0; #endif seqChannel->notePriority = NOTE_PRIORITY_DEFAULT; #ifdef VERSION_SH @@ -142,7 +142,7 @@ s32 seq_channel_set_layer(struct SequenceChannel *seqChannel, s32 layerIndex) { layer->freqScale = 1.0f; layer->velocitySquare = 0.0f; #ifdef VERSION_SH - layer->unkSH28 = 1.0f; + layer->freqScaleMultiplier = 1.0f; #endif layer->instOrWave = 0xff; #else @@ -989,7 +989,7 @@ void seq_channel_layer_process_script_part1(struct SequenceChannelLayer *layer) } s32 seq_channel_layer_process_script_part5(struct SequenceChannelLayer *layer, s32 cmd) { - if (!layer->stopSomething && layer->sound != NULL && layer->sound->sample->codec == 2 && + if (!layer->stopSomething && layer->sound != NULL && layer->sound->sample->codec == CODEC_SKIP && layer->sound->sample->medium != 0) { layer->stopSomething = TRUE; return -1; @@ -1176,7 +1176,7 @@ s32 seq_channel_layer_process_script_part2(struct SequenceChannelLayer *layer) { case 0xce: cmd = m64_read_u8(state) + 0x80; - layer->unkSH28 = unk_sh_data_1[cmd]; + layer->freqScaleMultiplier = unk_sh_data_1[cmd]; // missing break :) default: @@ -1320,7 +1320,7 @@ s32 seq_channel_layer_process_script_part4(struct SequenceChannelLayer *layer, s } } layer->delayUnused = layer->delay; - layer->freqScale *= layer->unkSH28; + layer->freqScale *= layer->freqScaleMultiplier; return sameSound; } @@ -1493,7 +1493,7 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) { u8 loBits; u16 sp5A; s32 sp38; - s8 value; + s8 value = 0; s32 i; u8 *seqData; @@ -1828,7 +1828,7 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) { #endif case 0xd4: // chan_setreverb - seqChannel->reverb = m64_read_u8(state); + seqChannel->reverbVol = m64_read_u8(state); break; case 0xc6: // chan_setbank; switch bank within set @@ -1972,8 +1972,8 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) { seqChannel->transposition = (s8) *seqData++; seqChannel->newPan = *seqData++; seqChannel->panChannelWeight = *seqData++; - seqChannel->reverb = *seqData++; - seqChannel->reverbIndex = *seqData++; // reverb index? + seqChannel->reverbVol = *seqData++; + seqChannel->reverbIndex = *seqData++; seqChannel->changes.as_bitfields.pan = TRUE; break; @@ -1984,7 +1984,7 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) { seqChannel->transposition = (s8) m64_read_u8(state); seqChannel->newPan = m64_read_u8(state); seqChannel->panChannelWeight = m64_read_u8(state); - seqChannel->reverb = m64_read_u8(state); + seqChannel->reverbVol = m64_read_u8(state); seqChannel->reverbIndex = m64_read_u8(state); seqChannel->changes.as_bitfields.pan = TRUE; break; @@ -2016,7 +2016,7 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) { #endif #ifdef VERSION_SH case 0xed: - seqChannel->unkSH0C = m64_read_u8(state); + seqChannel->synthesisVolume = m64_read_u8(state); break; case 0xef: @@ -2112,7 +2112,7 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) { case 0x10: seqChannel->soundScriptIO[loBits] = -1; - if (func_802f47c8(seqChannel->bankId, (u8)value, &seqChannel->soundScriptIO[loBits]) == -1) { + if (func_sh_802f47c8(seqChannel->bankId, (u8)value, &seqChannel->soundScriptIO[loBits]) == -1) { } break; #else @@ -2235,7 +2235,7 @@ void sequence_player_process_sequence(struct SequencePlayer *seqPlayer) { #endif u8 loBits; u8 temp; - s32 value; + s32 value = 0; s32 i; u16 u16v; u8 *seqData; diff --git a/src/audio/shindou_debug_prints.c b/src/audio/shindou_debug_prints.c index 5f85e24a..261d4521 100644 --- a/src/audio/shindou_debug_prints.c +++ b/src/audio/shindou_debug_prints.c @@ -1,7 +1,14 @@ #include #ifdef VERSION_SH -// The first four debug prints are in data.c. +// synthesis.c +char shindouDebugPrint1[] = "Terminate-Canceled Channel %d,Phase %d\n"; +char shindouDebugPrint2[] = "S->W\n"; +char shindouDebugPrint3[] = "W->S\n"; +char shindouDebugPrint4[] = "S-Resample Pitch %x (old %d -> delay %d)\n"; +s32 shindouDebugPrintPadding1[] = {0,0,0}; + +// heap.c char shindouDebugPrint5[] = "Warning:Kill Note %x \n"; char shindouDebugPrint6[] = "Kill Voice %d (ID %d) %d\n"; char shindouDebugPrint7[] = "Warning: Running Sequence's data disappear!\n"; @@ -58,8 +65,9 @@ char shindouDebugPrint57[] = "Request--------Single-Stay, %d\n"; char shindouDebugPrint58[] = "Try Kill %d \n"; char shindouDebugPrint59[] = "Try Kill %x %x\n"; char shindouDebugPrint60[] = "Try Kill %x %x %x\n"; -// Zero padding here. These aren't used variables, so they could be either unused variables or a file boundary. s32 shindouDebugPrintPadding[] = {0, 0, 0}; + +// load.c char shindouDebugPrint61[] = "CAUTION:WAVE CACHE FULL %d"; char shindouDebugPrint62[] = "SUPERDMA"; char shindouDebugPrint63[] = "Bank Change... top %d lba %d\n"; @@ -124,6 +132,8 @@ char shindouDebugPrint121[] = "N start %d\n"; char shindouDebugPrint122[] = "============Error: Magic is Broken: %x\n"; char shindouDebugPrint123[] = "Error: No Handle.\n"; char shindouDebugPrint124[] = "Success: %x\n"; + +// port_eu.c char shindouDebugPrint125[] = "DAC:Lost 1 Frame.\n"; char shindouDebugPrint126[] = "DMA: Request queue over.( %d )\n"; char shindouDebugPrint127[] = "Spec Change Override. %d -> %d\n"; diff --git a/src/audio/synthesis.c b/src/audio/synthesis.c index b9f73753..982a0a77 100644 --- a/src/audio/synthesis.c +++ b/src/audio/synthesis.c @@ -1,3 +1,4 @@ +#ifndef VERSION_SH #include #include "synthesis.h" @@ -7,9 +8,9 @@ #include "seqplayer.h" #include "internal.h" #include "external.h" +#include "game/game_init.h" -#ifndef VERSION_SH #define DMEM_ADDR_TEMP 0x0 #define DMEM_ADDR_RESAMPLED 0x20 #define DMEM_ADDR_RESAMPLED2 0x160 @@ -22,18 +23,6 @@ #define DMEM_ADDR_RIGHT_CH 0x600 #define DMEM_ADDR_WET_LEFT_CH 0x740 #define DMEM_ADDR_WET_RIGHT_CH 0x880 -#else -#define DMEM_ADDR_TEMP 0x450 -#define DMEM_ADDR_RESAMPLED 0x470 -#define DMEM_ADDR_RESAMPLED2 0x5f0 -#define DMEM_ADDR_UNCOMPRESSED_NOTE 0x5f0 -#define DMEM_ADDR_NOTE_PAN_TEMP 0x650 -#define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x990 -#define DMEM_ADDR_LEFT_CH 0x990 -#define DMEM_ADDR_RIGHT_CH 0xb10 -#define DMEM_ADDR_WET_LEFT_CH 0xc90 -#define DMEM_ADDR_WET_RIGHT_CH 0xe10 -#endif #define aSetLoadBufferPair(pkt, c, off) \ aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_LEFT_CH, 0, DEFAULT_LEN_1CH - c); \ @@ -47,7 +36,137 @@ aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_RIGHT_CH, d); \ aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off))); -#define ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1)) +#define AUDIO_ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1)) + +#if defined(BETTER_REVERB) && (defined(VERSION_US) || defined(VERSION_JP)) +/* ----------------------------------------------------------------------BEGIN REVERB PARAMETERS---------------------------------------------------------------------- */ + + +/** + * This reverb is a much more natural, ambient implementation over vanilla's, though at the cost of some memory and performance. + * These parameters are here to provide maximum control over the usage of the reverb effect, as well as with game performance. + * + * To take advantage of the reverb effect, you can change the echo parameters set in levels/level_defines.h to tailor the reverb to each specific level area. + * To adjust reverb presence with individual sound effects, apply the .set_reverb command within sound/sequences/00_sound_player.s (see examples of other sounds that use it). + * To use with M64 sequences, set the Effect parameter for each channel accordingly (CC 91 for MIDI files). + * + * Most parameter configuration is to be done here, though BETTER_REVERB_SIZE can be adjusted in audio/synthesis.h. + * + * If after changing the parameters, you hear increasing noise followed by a sudden disappearance of reverb and/or scratchy audio, this indicates an s16 overflow. + * If this happens, stop immediately and reduce the parameters at fault. This becomes a ticking time bomb, and may eventually result in very loud noise if it reaches the point of s32 overflow. + * Depending on the violating parameters chosen, you probably won't ever experience s32 overflow, but s16 overflow still isn't a pleasant experience. + * Checks to prevent this have not been implemented to maximize performance potential, so choose your parameters wisely. The current defaults are unlikely to have this problem. + * Generally speaking, a sound that doesn't seem to be fading at a natural rate is a parameter red flag (also known as feedback). + */ + + +// Setting this to 4 corrupts the game, so set this value to -1 to use vanilla reverb if this is too slow, or if it just doesn't fit the desired aesthetic of a level. +// You can change this value before audio_reset_session gets called if different levels can tolerate the demand better than others or just have different reverb goals. +// A higher downsample value hits the game's frequency limit sooner, which can cause the reverb sometimes to be off pitch. This is a vanilla level issue (and also counter intuitive). +// Higher downsample values also result in slightly shorter reverb decay times. +s8 betterReverbDownsampleConsole = 3; + +// Most emulators can handle a default value of 2, but 3 may be advisable in some cases if targeting older emulators (e.g. PJ64 1.6). Setting this to -1 also uses vanilla reverb. +// Using a value of 1 is not recommended except in very specific situations. If you do decide to use 1 here, you must adjust BETTER_REVERB_SIZE appropriately. +// You can change this value before audio_reset_session gets called if different levels can tolerate the demand better than others or just have different reverb goals. +// A higher downsample value hits the game's frequency limit sooner, which can cause the reverb sometimes to be off pitch. This is a vanilla level issue (and also counter intuitive). +// Higher downsample values also result in slightly shorter reverb decay times. +s8 betterReverbDownsampleEmulator = 2; + +// This value represents the number of filters to use with the reverb. This can be decreased to improve performance, but at the cost of a lesser presence of reverb in the final audio. +// Filter count should always be a multiple of 3. Never ever set this value to be greater than NUM_ALLPASS. +// Setting it to anything less than 3 will disable reverb outright. +// This can be changed at any time, but is best set when calling audio_reset_session. +u32 reverbFilterCountConsole = NUM_ALLPASS - 6; + +// This value represents the number of filters to use with the reverb. This can be decreased to improve performance, but at the cost of a lesser presence of reverb in the final audio. +// Filter count should always be a multiple of 3. Never ever set this value to be greater than NUM_ALLPASS. +// Setting it to anything less than 3 will disable reverb outright. +// This can be changed at any time, but is best set when calling audio_reset_session. +u32 reverbFilterCountEmulator = NUM_ALLPASS; + +// Set this to TRUE to use mono over stereo for reverb. This should increase performance, but at the cost of a less fullfilling reverb experience. +// If performance is desirable, it is recommended to change reverbFilterCountConsole or betterReverbDownsampleConsole first. +// This can be changed at any time, but is best set when calling audio_reset_session. +u8 monoReverbConsole = FALSE; + +// Set this to TRUE to use mono over stereo for reverb. This should increase performance, but at the cost of a less fullfilling reverb experience. +// If performance is desirable, it is recommended to change reverbFilterCountEmulator or betterReverbDownsampleEmulator first. +// This can be changed at any time, but is best set when calling audio_reset_session. +u8 monoReverbEmulator = FALSE; + +// This value controls the size of the reverb buffer. It affects the global reverb delay time. This variable is one of the easiest to control. +// It is not recommended setting this to values greater than 0x1000 * 2^(downsample factor - 1), as you run the risk of running into a memory issue (though this is far from a guarantee). +// Setting the value lower than the downsample buffer size will destroy the game audio. This is taken into account automatically, but also means the value set here isn't what always gets used. +// If this value is changed, it will go into effect the next time audio_reset_session is called. +// Set to -1 to use a default preset instead. Higher values represent more audio delay (usually better for echoey spaces). +s32 betterReverbWindowsSize = -1; + +// These values are set to s32 instead of u8 to increase performance. Setting these to values larger than 0xFF (255) or less than 0 may cause issues and is not recommended. +s32 gReverbRevIndex = 0x5F; // Affects decay time mostly (large values can cause terrible feedback!); can be messed with at any time +s32 gReverbGainIndex = 0x9F; // Affects signal immediately retransmitted back into buffers (mid-high values yield the strongest effect); can be messed with at any time +s32 gReverbWetSignal = 0xE7; // Amount of reverb specific output in final signal (also affects decay); can be messed with at any time, also very easy to control + +// s32 gReverbDrySignal = 0x00; // Amount of original input in final signal (large values can cause terrible feedback!); declaration and uses commented out by default to improve compiler optimization + + +/* ---------------------------------------------------------------------ADVANCED REVERB PARAMETERS-------------------------------------------------------------------- */ + + +// These values affect filter delays. Bigger values will result in fatter echo (and more memory); must be cumulatively smaller than BETTER_REVERB_SIZE/2. +// If setting a reverb downsample value to 1, these must be cumulatively smaller than BETTER_REVERB_SIZE/4. +// These values should never be changed unless in this declaration or during a call to audio_reset_session, as it could otherwise lead to a major memory leak or garbage audio. +// None of the delay values should ever be smaller than 1 either; these are s32s purely to avoid typecasts. +// These values are currently set by using delaysBaseline in the audio_reset_session function, so its behavior must be overridden to use dynamically (or at all). +s32 delaysL[NUM_ALLPASS] = { + 1080, 1352, 1200, + 1200, 1232, 1432, + 1384, 1048, 1352, + 928, 1504, 1512 +}; +s32 delaysR[NUM_ALLPASS] = { + 1384, 1352, 1048, + 928, 1512, 1504, + 1080, 1200, 1352, + 1200, 1432, 1232 +}; + +// Like the delays array, but represents default max values that don't change (also probably somewhat redundant) +// Change this array rather than the delays array to customize reverb delay times globally. +// Similarly to delaysL/R, these should be kept within the memory constraints defined by BETTER_REVERB_SIZE. +const s32 delaysBaselineL[NUM_ALLPASS] = { + 1080, 1352, 1200, + 1200, 1232, 1432, + 1384, 1048, 1352, + 928, 1504, 1512 +}; +const s32 delaysBaselineR[NUM_ALLPASS] = { + 1384, 1352, 1048, + 928, 1512, 1504, + 1080, 1200, 1352, + 1200, 1432, 1232 +}; + +// These values affect reverb decay depending on the filter index; can be messed with at any time +s32 reverbMultsL[NUM_ALLPASS / 3] = {0xD7, 0x6F, 0x36, 0x22}; +s32 reverbMultsR[NUM_ALLPASS / 3] = {0xCF, 0x73, 0x38, 0x1F}; + + +/* -----------------------------------------------------------------------END REVERB PARAMETERS----------------------------------------------------------------------- */ + +// Do not touch these values manually, unless you want potential for problems. +u32 reverbFilterCount = NUM_ALLPASS; +u32 reverbFilterCountm1 = NUM_ALLPASS - 1; +u8 monoReverb = FALSE; +u8 toggleBetterReverb = TRUE; +s32 allpassIdxL[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +s32 allpassIdxR[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +s32 tmpBufL[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +s32 tmpBufR[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +s32 **delayBufsL; +s32 **delayBufsR; +#endif + struct VolumeChange { u16 sourceLeft; @@ -57,12 +176,8 @@ struct VolumeChange { }; u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex); -#if defined(VERSION_EU) || defined(VERSION_SH) -#ifdef VERSION_SH -u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, u16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex); -#else -u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, u16 *aiBuf, s32 bufLen, u64 *cmd); -#endif +#ifdef VERSION_EU +u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s16 *aiBuf, s32 bufLen, u64 *cmd); u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad); u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags); u64 *process_envelope(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, u32 flags); @@ -78,7 +193,7 @@ u64 *process_envelope_inner(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 flags, s32 leftRight); #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU struct SynthesisReverb gSynthesisReverbs[4]; u8 sAudioSynthesisPad[0x10]; #else @@ -86,13 +201,91 @@ struct SynthesisReverb gSynthesisReverb; u8 sAudioSynthesisPad[0x20]; #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#if defined(BETTER_REVERB) && (defined(VERSION_US) || defined(VERSION_JP)) +static inline s16 clamp16(s32 x) { + if (x >= 32767) + return 32767; + if (x <= -32768) + return -32768; + + return (s16) x; +} + +static inline void reverb_samples(s16 *outSampleL, s16 *outSampleR, s32 inSampleL, s32 inSampleR) { + u32 i = 0; + s32 j = 0; + u8 k = 0; + s32 outTmpL = 0; + s32 outTmpR = 0; + s32 tmpCarryoverL = ((tmpBufL[reverbFilterCountm1] * gReverbRevIndex) / 256) + inSampleL; + s32 tmpCarryoverR = ((tmpBufR[reverbFilterCountm1] * gReverbRevIndex) / 256) + inSampleR; + + for (; i < reverbFilterCount; ++i, ++j) { + tmpBufL[i] = delayBufsL[i][allpassIdxL[i]]; + tmpBufR[i] = delayBufsR[i][allpassIdxR[i]]; + + if (j == 2) { + j = -1; + outTmpL += (tmpBufL[i] * reverbMultsL[k]) / 256; + outTmpR += (tmpBufR[i] * reverbMultsR[k++]) / 256; + delayBufsL[i][allpassIdxL[i]] = tmpCarryoverL; + delayBufsR[i][allpassIdxR[i]] = tmpCarryoverR; + if (i != reverbFilterCountm1) { + tmpCarryoverL = (tmpBufL[i] * gReverbRevIndex) / 256; + tmpCarryoverR = (tmpBufR[i] * gReverbRevIndex) / 256; + } + } + else { + delayBufsL[i][allpassIdxL[i]] = (tmpBufL[i] * (-gReverbGainIndex)) / 256 + tmpCarryoverL; + delayBufsR[i][allpassIdxR[i]] = (tmpBufR[i] * (-gReverbGainIndex)) / 256 + tmpCarryoverR; + tmpCarryoverL = (delayBufsL[i][allpassIdxL[i]] * gReverbGainIndex) / 256 + tmpBufL[i]; + tmpCarryoverR = (delayBufsR[i][allpassIdxR[i]] * gReverbGainIndex) / 256 + tmpBufR[i]; + } + + if (++allpassIdxL[i] == delaysL[i]) + allpassIdxL[i] = 0; + if (++allpassIdxR[i] == delaysR[i]) + allpassIdxR[i] = 0; + } + + *outSampleL = clamp16((outTmpL * gReverbWetSignal/* + inSampleL * gReverbDrySignal*/) / 256); + *outSampleR = clamp16((outTmpR * gReverbWetSignal/* + inSampleR * gReverbDrySignal*/) / 256); +} + +static inline void reverb_mono_sample(s16 *outSample, s32 inSample) { + u32 i = 0; + s32 j = 0; + u8 k = 0; + s32 outTmp = 0; + s32 tmpCarryover = ((tmpBufL[reverbFilterCountm1] * gReverbRevIndex) / 256) + inSample; + + for (; i < reverbFilterCount; ++i, ++j) { + tmpBufL[i] = delayBufsL[i][allpassIdxL[i]]; + + if (j == 2) { + j = -1; + outTmp += (tmpBufL[i] * reverbMultsL[k++]) / 256; + delayBufsL[i][allpassIdxL[i]] = tmpCarryover; + if (i != reverbFilterCountm1) + tmpCarryover = (tmpBufL[i] * gReverbRevIndex) / 256; + } + else { + delayBufsL[i][allpassIdxL[i]] = (tmpBufL[i] * (-gReverbGainIndex)) / 256 + tmpCarryover; + tmpCarryover = (delayBufsL[i][allpassIdxL[i]] * gReverbGainIndex) / 256 + tmpBufL[i]; + } + + if (++allpassIdxL[i] == delaysL[i]) + allpassIdxL[i] = 0; + } + + *outSample = clamp16((outTmp * gReverbWetSignal/* + inSample * gReverbDrySignal*/) / 256); +} +#endif + +#ifdef VERSION_EU s16 gVolume; s8 gUseReverb; s8 gNumSynthesisReverbs; -#ifdef VERSION_SH -s16 D_SH_803479B4; // contains 4096 -#endif struct NoteSubEu *gNoteSubsEu; #endif @@ -106,7 +299,7 @@ u8 audioString1[] = "pitch %x: delaybytes %d : olddelay %d\n"; u8 audioString2[] = "cont %x: delaybytes %d : olddelay %d\n"; #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU // Equivalent functionality as the US/JP version, // just that the reverb structure is chosen from an array with index void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex) { @@ -168,7 +361,12 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) { s32 nSamples; s32 numSamplesAfterDownsampling; s32 excessiveSamples; + +#ifdef BETTER_REVERB + if (!toggleBetterReverb && gReverbDownsampleRate != 1) { +#else if (gReverbDownsampleRate != 1) { +#endif if (gSynthesisReverb.framesLeftToIgnore == 0) { // Now that the RSP has finished, downsample the samples produced two frames ago by skipping // samples. @@ -190,6 +388,49 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) { } } } +#ifdef BETTER_REVERB + else if (toggleBetterReverb) { + item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex]; + if (gSoundMode == SOUND_MODE_MONO || monoReverb) { + if (gReverbDownsampleRate != 1) { + osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH); + for (srcPos = 0, dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos; srcPos += gReverbDownsampleRate, dstPos++) { + reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2); + gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos]; + } + for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) { + reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2); + gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos]; + } + } + else { // Too slow for practical use, not recommended most of the time. + for (dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos; dstPos++) { + reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2); + gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos]; + } + for (dstPos = 0; dstPos < item->lengthB / 2; dstPos++) { + reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2); + gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos]; + } + } + } + else { + if (gReverbDownsampleRate != 1) { + osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH); + for (srcPos = 0, dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos; srcPos += gReverbDownsampleRate, dstPos++) + reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], item->toDownsampleLeft[srcPos], item->toDownsampleRight[srcPos]); + for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) + reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], item->toDownsampleLeft[srcPos], item->toDownsampleRight[srcPos]); + } + else { // Too slow for practical use, not recommended most of the time. + for (dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos; dstPos++) + reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], gSynthesisReverb.ringBuffer.left[dstPos], gSynthesisReverb.ringBuffer.right[dstPos]); + for (dstPos = 0; dstPos < item->lengthB / 2; dstPos++) + reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], gSynthesisReverb.ringBuffer.left[dstPos], gSynthesisReverb.ringBuffer.right[dstPos]); + } + } + } +#endif item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex]; numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate; @@ -215,59 +456,31 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) { } #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU u64 *synthesis_load_reverb_ring_buffer(u64 *cmd, u16 addr, u16 srcOffset, s32 len, s32 reverbIndex) { -#ifdef VERSION_SH - aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[srcOffset]), - addr, len); - aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[srcOffset]), - addr + DEFAULT_LEN_1CH, len); -#else aSetBuffer(cmd++, 0, addr, 0, len); aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[srcOffset])); aSetBuffer(cmd++, 0, addr + DEFAULT_LEN_1CH, 0, len); aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[srcOffset])); -#endif return cmd; } #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU u64 *synthesis_save_reverb_ring_buffer(u64 *cmd, u16 addr, u16 destOffset, s32 len, s32 reverbIndex) { -#ifdef VERSION_SH - aSaveBuffer(cmd++, addr, - VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[destOffset]), len); - aSaveBuffer(cmd++, addr + DEFAULT_LEN_1CH, - VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[destOffset]), len); -#else aSetBuffer(cmd++, 0, 0, addr, len); aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[destOffset])); aSetBuffer(cmd++, 0, 0, addr + DEFAULT_LEN_1CH, len); aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[destOffset])); -#endif return cmd; } #endif -#if defined(VERSION_SH) -void func_sh_802ed644(s32 updateIndexStart, s32 noteIndex) { - s32 i; - - for (i = updateIndexStart + 1; i < gAudioBufferParameters.updatesPerFrame; i++) { - if (!gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].needsInit) { - gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].enabled = FALSE; - } else { - break; - } - } -} -#endif - -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU void synthesis_load_note_subs_eu(s32 updateIndex) { struct NoteSubEu *src; struct NoteSubEu *dest; @@ -286,7 +499,7 @@ void synthesis_load_note_subs_eu(s32 updateIndex) { } #endif -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU s32 get_volume_ramping(u16 sourceVol, u16 targetVol, s32 arg2) { // This roughly computes 2^16 * (targetVol / sourceVol) ^ (8 / arg2), // but with discretizations of targetVol, sourceVol and arg2. @@ -309,46 +522,32 @@ s32 get_volume_ramping(u16 sourceVol, u16 targetVol, s32 arg2) { } #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU // TODO: (Scrub C) pointless mask and whitespace u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) { s32 i, j; -#ifndef VERSION_SH f32 *leftVolRamp; f32 *rightVolRamp; -#endif u32 *aiBufPtr; u64 *cmd = cmdBuf; s32 chunkLen; -#ifndef VERSION_SH s32 nextVolRampTable; -#endif for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) { process_sequences(i - 1); synthesis_load_note_subs_eu(gAudioBufferParameters.updatesPerFrame - i); } -#ifndef VERSION_SH aSegment(cmd++, 0, 0); -#endif aiBufPtr = (u32 *) aiBuf; for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) { -#ifdef VERSION_SH - if (i == 1) { - chunkLen = bufLen; - } else { - if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) { - chunkLen = gAudioBufferParameters.samplesPerUpdateMax; - } else if (bufLen / i <= gAudioBufferParameters.samplesPerUpdateMin) { - chunkLen = gAudioBufferParameters.samplesPerUpdateMin; - } else { - chunkLen = gAudioBufferParameters.samplesPerUpdate; - } - } -#else if (i == 1) { +#pragma GCC diagnostic push +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wself-assign" +#endif // self-assignment has no affect when added here, could possibly simplify a macro definition chunkLen = bufLen; nextVolRampTable = nextVolRampTable; leftVolRamp = gLeftVolRampings[nextVolRampTable]; rightVolRamp = gRightVolRampings[nextVolRampTable & 0xFFFFFFFF]; +#pragma GCC diagnostic pop } else { if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) { chunkLen = gAudioBufferParameters.samplesPerUpdateMax; nextVolRampTable = 2; leftVolRamp = gLeftVolRampings[2]; rightVolRamp = gRightVolRampings[2]; @@ -360,7 +559,6 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) { } gCurrentLeftVolRamping = leftVolRamp; gCurrentRightVolRamping = rightVolRamp; -#endif for (j = 0; j < gNumSynthesisReverbs; j++) { if (gSynthesisReverbs[j].useReverb != 0) { prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j); @@ -391,6 +589,22 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) { aSegment(cmdBuf, 0, 0); +#ifdef BETTER_REVERB + if (gIsConsole) { + reverbFilterCount = reverbFilterCountConsole; + monoReverb = monoReverbConsole; + } + else { + reverbFilterCount = reverbFilterCountEmulator; + monoReverb = monoReverbEmulator; + } + if (reverbFilterCount > NUM_ALLPASS) + reverbFilterCount = NUM_ALLPASS; + reverbFilterCountm1 = reverbFilterCount - 1; + if (reverbFilterCount < 3) + reverbFilterCountm1 = 0; +#endif + for (i = gAudioUpdatesPerFrame; i > 0; i--) { if (i == 1) { // 'bufLen' will automatically be divisible by 8, no need to round @@ -422,7 +636,7 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) { #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s16 updateIndex) { struct ReverbRingBufferItem *item; s16 startPad; @@ -430,25 +644,18 @@ u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s1 item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex]; -#ifndef VERSION_SH aClearBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH); -#endif if (gSynthesisReverbs[reverbIndex].downsampleRate == 1) { cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex); if (item->lengthB != 0) { cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex); } -#ifdef VERSION_SH - aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH); - aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH); -#else aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH); aMix(cmd++, 0, 0x7fff, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH); aMix(cmd++, 0, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH); -#endif } else { startPad = (item->startPos % 8u) * 2; - paddedLengthA = ALIGN(startPad + item->lengthA, 4); + paddedLengthA = AUDIO_ALIGN(startPad + item->lengthA, 4); cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, (item->startPos - startPad / 2), DEFAULT_LEN_1CH, reverbIndex); if (item->lengthB != 0) { @@ -461,45 +668,13 @@ u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s1 aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED2 + startPad, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2); aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateRight)); -#ifdef VERSION_SH - aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH); - aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH); -#else aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH); aMix(cmd++, 0, 0x7fff, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH); aMix(cmd++, 0, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH); -#endif - } -#ifdef VERSION_SH - if (gSynthesisReverbs[reverbIndex].panRight != 0 || gSynthesisReverbs[reverbIndex].panLeft != 0) { - // Leak some audio from the left reverb channel into the right reverb channel and vice versa (pan) - aDMEMMove(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_1CH); - aMix(cmd++, gSynthesisReverbs[reverbIndex].panRight, DMEM_ADDR_WET_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_1CH); - aMix(cmd++, gSynthesisReverbs[reverbIndex].panLeft, DMEM_ADDR_RESAMPLED, DMEM_ADDR_WET_RIGHT_CH, DEFAULT_LEN_1CH); - } -#endif - return cmd; -} -#endif - -#if defined(VERSION_SH) -u64 *synthesis_load_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) { - struct ReverbRingBufferItem *item; - struct SynthesisReverb *reverb; - - reverb = &gSynthesisReverbs[reverbIndex]; - item = &reverb->items[reverb->curFrame][updateIndex]; - // Get the oldest samples in the ring buffer into the wet channels - cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex); - if (item->lengthB != 0) { - // Ring buffer wrapped - cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex); } return cmd; } -#endif -#if defined(VERSION_EU) u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) { struct ReverbRingBufferItem *item; @@ -516,8 +691,8 @@ u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) { break; default: - // Downsampling is done later by CPU when RSP is done, therefore we need to have double - // buffering. Left and right buffers are adjacent in memory. + // Downsampling is done later by CPU when RSP is done, therefore we need to have double + // buffering. Left and right buffers are adjacent in memory. aSetBuffer(cmd++, 0, 0, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH); aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex].toDownsampleLeft)); gSynthesisReverbs[reverbIndex].resampleFlags = 0; @@ -526,50 +701,9 @@ u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) { } return cmd; } -#elif defined(VERSION_SH) -u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) { - struct ReverbRingBufferItem *item; - - item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex]; - switch (gSynthesisReverbs[reverbIndex].downsampleRate) { - case 1: - // Put the oldest samples in the ring buffer into the wet channels - cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex); - if (item->lengthB != 0) { - // Ring buffer wrapped - cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex); - } - break; - - default: - // Downsampling is done later by CPU when RSP is done, therefore we need to have double - // buffering. Left and right buffers are adjacent in memory. - aSaveBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH, - VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex].toDownsampleLeft), DEFAULT_LEN_2CH); - break; - } - gSynthesisReverbs[reverbIndex].resampleFlags = 0; - return cmd; -} - -u64 *func_sh_802EDF24(u64 *cmd, s16 reverbIndex, s16 updateIndex) { - struct ReverbRingBufferItem *item; - struct SynthesisReverb *reverb; - - reverb = &gSynthesisReverbs[reverbIndex]; - item = &reverb->items[reverb->curFrame][updateIndex]; - // Put the oldest samples in the ring buffer into the wet channels - cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex); - if (item->lengthB != 0) { - // Ring buffer wrapped - cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex); - } - return cmd; -} - #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) { struct NoteSubEu *noteSubEu; u8 noteIndices[56]; @@ -611,53 +745,20 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI for (; i < notePos; i++) { temp = updateIndex * gMaxSimultaneousNotes; if (j == gNoteSubsEu[temp + noteIndices[i]].reverbIndex) { -#ifdef VERSION_SH - cmd = synthesis_process_note(noteIndices[i], - &gNoteSubsEu[temp + noteIndices[i]], - &gNotes[noteIndices[i]].synthesisState, - aiBuf, bufLen, cmd, updateIndex); -#else cmd = synthesis_process_note(&gNotes[noteIndices[i]], &gNoteSubsEu[temp + noteIndices[i]], &gNotes[noteIndices[i]].synthesisState, aiBuf, bufLen, cmd); -#endif continue; } else { break; } } if (gSynthesisReverbs[j].useReverb != 0) { -#ifdef VERSION_SH - if (gSynthesisReverbs[j].unk100 != NULL) { - aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk100); - aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_LEFT_CH, gSynthesisReverbs[j].unk108); - } - if (gSynthesisReverbs[j].unk104 != NULL) { - aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk104); - aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_RIGHT_CH, gSynthesisReverbs[j].unk10C); - } -#endif cmd = synthesis_save_reverb_samples(cmd, j, updateIndex); -#ifdef VERSION_SH - if (gSynthesisReverbs[j].unk5 != -1) { - if (gSynthesisReverbs[gSynthesisReverbs[j].unk5].downsampleRate == 1) { - cmd = synthesis_load_reverb_samples(cmd, gSynthesisReverbs[j].unk5, updateIndex); - aMix(cmd++, gSynthesisReverbs[j].unk08, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_2CH); - cmd = func_sh_802EDF24(cmd++, gSynthesisReverbs[j].unk5, updateIndex); - } - } -#endif } } for (; i < notePos; i++) { -#ifdef VERSION_SH - struct NoteSubEu *noteSubEu2 = &gNoteSubsEu[updateIndex * gMaxSimultaneousNotes + noteIndices[i]]; - cmd = synthesis_process_note(noteIndices[i], - noteSubEu2, - &gNotes[noteIndices[i]].synthesisState, - aiBuf, bufLen, cmd, updateIndex); -#else temp = updateIndex * gMaxSimultaneousNotes; if (IS_BANK_LOAD_COMPLETE(gNoteSubsEu[temp + noteIndices[i]].bankId) == TRUE) { cmd = synthesis_process_note(&gNotes[noteIndices[i]], @@ -667,22 +768,16 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI } else { gAudioErrorFlags = (gNoteSubsEu[temp + noteIndices[i]].bankId + (i << 8)) + 0x10000000; } -#endif } temp = bufLen * 2; -#ifdef VERSION_SH - aInterleave(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH, temp); - aSaveBuffer(cmd++, DMEM_ADDR_TEMP, VIRTUAL_TO_PHYSICAL2(aiBuf), temp * 2); -#else aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, temp); aInterleave(cmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH); aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, temp * 2); aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(aiBuf)); -#endif return cmd; } -#elif defined(VERSION_JP) || defined(VERSION_US) +#else u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) { UNUSED s32 pad1[1]; s16 ra; @@ -720,7 +815,7 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI // Same as above but upsample the previously downsampled samples used for reverb first temp = 0; //! jesus christ t4 = (v1->startPos & 7) * 2; - ra = ALIGN(v1->lengthA + t4, 4); + ra = AUDIO_ALIGN(v1->lengthA + t4, 4); aSetLoadBufferPair(cmd++, 0, v1->startPos - t4 / 2); if (v1->lengthB != 0) { // Ring buffer wrapped @@ -758,10 +853,9 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI } #endif -#ifndef VERSION_SH -#if defined(VERSION_EU) +#ifdef VERSION_EU // Processes just one note, not all -u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, u16 *aiBuf, s32 bufLen, u64 *cmd) { +u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, UNUSED s16 *aiBuf, s32 bufLen, u64 *cmd) { UNUSED s32 pad0[3]; #else u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { @@ -772,31 +866,31 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { struct AudioBankSample *audioBookSample; // sp164, sp138 struct AdpcmLoop *loopInfo; // sp160, sp134 s16 *curLoadedBook = NULL; // sp154, sp130 -#if defined(VERSION_EU) +#ifdef VERSION_EU UNUSED u8 padEU[0x04]; #endif UNUSED u8 pad8[0x04]; -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU u16 resamplingRateFixedPoint; // sp5c, sp11A #endif s32 noteFinished; // 150 t2, sp124 s32 restart; // 14c t3, sp120 s32 flags; // sp148, sp11C -#if defined(VERSION_EU) +#ifdef VERSION_EU u16 resamplingRateFixedPoint; // sp5c, sp11A #endif UNUSED u8 pad7[0x0c]; // sp100 UNUSED s32 tempBufLen; -#if defined(VERSION_EU) - s32 sp130; //sp128, sp104 +#ifdef VERSION_EU + s32 sp130 = 0; //sp128, sp104 UNUSED u32 pad9; #else UNUSED u32 pad9; - s32 sp130; //sp128, sp104 + s32 sp130 = 0; //sp128, sp104 #endif s32 nAdpcmSamplesProcessed; // signed required for US s32 t0; -#if defined(VERSION_EU) +#ifdef VERSION_EU u8 *sampleAddr; // sp120, spF4 s32 s6; #else @@ -804,7 +898,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { u8 *sampleAddr; // sp120, spF4 #endif -#if defined(VERSION_EU) +#ifdef VERSION_EU s32 samplesLenAdjusted; // 108, spEC // Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange // behavior with the break near the end of the loop, causing US and JP to need a goto instead @@ -829,26 +923,26 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { u32 samplesLenFixedPoint; // v1_1 s32 nSamplesInThisIteration; // v1_2 u32 a3; -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU s32 t9; #endif u8 *v0_2; s32 nParts; // spE8, spBC s32 curPart; // spE4, spB8 -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU f32 resamplingRate; // f12 #endif s32 temp; -#if defined(VERSION_EU) +#ifdef VERSION_EU s32 s5Aligned; #endif s32 resampledTempLen; // spD8, spAC u16 noteSamplesDmemAddrBeforeResampling; // spD6, spAA -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU for (noteIndex = 0; noteIndex < gMaxSimultaneousNotes; noteIndex++) { note = &gNotes[noteIndex]; #ifdef VERSION_US @@ -866,17 +960,17 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { } else { #endif flags = 0; -#if defined(VERSION_EU) +#ifdef VERSION_EU tempBufLen = bufLen; #endif -#if defined(VERSION_EU) +#ifdef VERSION_EU if (noteSubEu->needsInit == TRUE) { #else if (note->needsInit == TRUE) { #endif flags = A_INIT; -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU note->samplePosInt = 0; note->samplePosFrac = 0; #else @@ -890,7 +984,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { #endif } -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU if (note->frequency < US_FLOAT(2.0)) { nParts = 1; if (note->frequency > US_FLOAT(1.99996)) { @@ -916,7 +1010,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { synthesisState->samplePosFrac = samplesLenFixedPoint & 0xFFFF; #endif -#if defined(VERSION_EU) +#ifdef VERSION_EU if (noteSubEu->isSyntheticWave) { cmd = load_wave_samples(cmd, noteSubEu, synthesisState, samplesLenFixedPoint >> 0x10); noteSamplesDmemAddrBeforeResampling = (synthesisState->samplePosInt * 2) + DMEM_ADDR_UNCOMPRESSED_NOTE; @@ -935,7 +1029,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { else { // ADPCM note -#if defined(VERSION_EU) +#ifdef VERSION_EU audioBookSample = noteSubEu->sound.audioBankSound->sample; #else audioBookSample = note->sound->sample; @@ -961,7 +1055,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { if (curLoadedBook != audioBookSample->book->book) { u32 nEntries; // v1 curLoadedBook = audioBookSample->book->book; -#if defined(VERSION_EU) +#ifdef VERSION_EU nEntries = 16 * audioBookSample->book->order * audioBookSample->book->npredictors; aLoadADPCM(cmd++, nEntries, VIRTUAL_TO_PHYSICAL2(curLoadedBook + noteSubEu->bookOffset)); #else @@ -970,7 +1064,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { #endif } -#if defined(VERSION_EU) +#ifdef VERSION_EU if (noteSubEu->bookOffset) { curLoadedBook = euUnknownData_80301950; // what's this? never read } @@ -983,7 +1077,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { noteFinished = FALSE; restart = FALSE; nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed; -#if defined(VERSION_EU) +#ifdef VERSION_EU s2 = synthesisState->samplePosInt & 0xf; samplesRemaining = endPos - synthesisState->samplePosInt; #else @@ -991,7 +1085,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { samplesRemaining = endPos - note->samplePosInt; #endif -#if defined(VERSION_EU) +#ifdef VERSION_EU if (s2 == 0 && synthesisState->restart == FALSE) { s2 = 16; } @@ -1007,7 +1101,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { s0 = t0 * 16; s3 = s6 + s0 - nSamplesToProcess; } else { -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU s0 = samplesRemaining + s2 - 0x10; #else s0 = samplesRemaining - s6; @@ -1027,7 +1121,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { } if (t0 != 0) { -#if defined(VERSION_EU) +#ifdef VERSION_EU temp = (synthesisState->samplePosInt - s2 + 0x10) / 16; if (audioBookSample->loaded == 0x81) { v0_2 = sampleAddr + temp * 9; @@ -1050,7 +1144,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { a3 = 0; } -#if defined(VERSION_EU) +#ifdef VERSION_EU if (synthesisState->restart != FALSE) { aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state)); flags = A_LOOP; // = 2 @@ -1065,7 +1159,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { #endif nSamplesInThisIteration = s0 + s6 - s3; -#if defined(VERSION_EU) +#ifdef VERSION_EU if (nAdpcmSamplesProcessed == 0) { aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2); @@ -1073,7 +1167,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); sp130 = s2 * 2; } else { - s5Aligned = ALIGN(s5, 5); + s5Aligned = AUDIO_ALIGN(s5, 5); aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2); aADPCMdec(cmd++, flags, @@ -1087,9 +1181,9 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->adpcmdecState)); sp130 = s2 * 2; } else { - aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN(s5, 5), s0 * 2); + aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + AUDIO_ALIGN(s5, 5), s0 * 2); aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->adpcmdecState)); - aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN(s5, 5) + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2); + aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + AUDIO_ALIGN(s5, 5) + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2); } #endif @@ -1118,7 +1212,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { if (noteFinished) { aClearBuffer(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (samplesLenAdjusted - nAdpcmSamplesProcessed) * 2); -#if defined(VERSION_EU) +#ifdef VERSION_EU noteSubEu->finished = 1; note->noteSubEu.finished = 1; note->noteSubEu.enabled = 0; @@ -1129,7 +1223,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { #endif break; } -#if defined(VERSION_EU) +#ifdef VERSION_EU if (restart) { synthesisState->restart = TRUE; synthesisState->samplePosInt = loopInfo->start; @@ -1155,14 +1249,14 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { switch (curPart) { case 0: aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED, samplesLenAdjusted + 4); -#if defined(VERSION_EU) +#ifdef VERSION_EU aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->dummyResampleState)); #else aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->dummyResampleState)); #endif resampledTempLen = samplesLenAdjusted + 4; noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED + 4; -#if defined(VERSION_EU) +#ifdef VERSION_EU if (noteSubEu->finished != FALSE) { #else if (note->finished != FALSE) { @@ -1175,7 +1269,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED2, samplesLenAdjusted + 8); -#if defined(VERSION_EU) +#ifdef VERSION_EU aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2( synthesisState->synthesisBuffers->dummyResampleState)); @@ -1191,7 +1285,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { } } -#if defined(VERSION_EU) +#ifdef VERSION_EU if (noteSubEu->finished != FALSE) { #else if (note->finished != FALSE) { @@ -1203,7 +1297,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { flags = 0; -#if defined(VERSION_EU) +#ifdef VERSION_EU if (noteSubEu->needsInit == TRUE) { flags = A_INIT; noteSubEu->needsInit = FALSE; @@ -1221,28 +1315,28 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { noteSamplesDmemAddrBeforeResampling, flags); #endif -#if defined(VERSION_JP) || defined(VERSION_US) - if (note->headsetPanRight != 0 || note->prevHeadsetPanRight != 0) { - leftRight = 1; - } else if (note->headsetPanLeft != 0 || note->prevHeadsetPanLeft != 0) { - leftRight = 2; -#else +#ifdef VERSION_EU if (noteSubEu->headsetPanRight != 0 || synthesisState->prevHeadsetPanRight != 0) { leftRight = 1; } else if (noteSubEu->headsetPanLeft != 0 || synthesisState->prevHeadsetPanLeft != 0) { leftRight = 2; +#else + if (note->headsetPanRight != 0 || note->prevHeadsetPanRight != 0) { + leftRight = 1; + } else if (note->headsetPanLeft != 0 || note->prevHeadsetPanLeft != 0) { + leftRight = 2; #endif } else { leftRight = 0; } -#if defined(VERSION_EU) +#ifdef VERSION_EU cmd = process_envelope(cmd, noteSubEu, synthesisState, bufLen, 0, leftRight, flags); #else cmd = process_envelope(cmd, note, bufLen, 0, leftRight, flags); #endif -#if defined(VERSION_EU) +#ifdef VERSION_EU if (noteSubEu->usesHeadsetPanEffects) { cmd = note_apply_headset_pan_effects(cmd, noteSubEu, synthesisState, bufLen * 2, flags, leftRight); } @@ -1252,7 +1346,7 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { } #endif } -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU } t9 = bufLen * 2; @@ -1265,389 +1359,25 @@ u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) { return cmd; } -#else // VERSION_SH -u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, UNUSED u16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) { - UNUSED s32 pad0[3]; - struct AudioBankSample *audioBookSample; // sp164, sp138 - struct AdpcmLoop *loopInfo; // sp160, sp134 - s16 *curLoadedBook; // sp154, sp130 - UNUSED u8 padEU[0x04]; - UNUSED u8 pad8[0x04]; - s32 noteFinished; // 150 t2, sp124 - s32 restart; // 14c t3, sp120 - s32 flags; // sp148, sp11C, t8 - u16 resamplingRateFixedPoint; // sp5c, sp11A - s32 nSamplesToLoad; //s0, Ec - UNUSED u8 pad7[0x0c]; // sp100 - s32 sp130; //sp128, sp104 - UNUSED s32 tempBufLen; - UNUSED u32 pad9; - s32 t0; - u8 *sampleAddr; // sp120, spF4 - s32 s6; - s32 samplesLenAdjusted; // 108, spEC - s32 nAdpcmSamplesProcessed; // signed required for US // spc0 - s32 endPos; // sp110, spE4 - s32 nSamplesToProcess; // sp10c/a0, spE0 - // Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange - // behavior with the break near the end of the loop, causing US and JP to need a goto instead - UNUSED s32 samplesLenInt; - s32 s2; - s32 leftRight; //s0 - s32 s5; //s4 - u32 samplesLenFixedPoint; // v1_1 - s32 s3; // spA0 - s32 nSamplesInThisIteration; // v1_2 - u32 a3; - u8 *v0_2; - s32 unk_s6; // sp90 - s32 s5Aligned; - s32 sp88; - s32 sp84; - u32 temp; - s32 nParts; // spE8, spBC - s32 curPart; // spE4, spB8 - s32 aligned; - UNUSED u32 padSH1; - s32 resampledTempLen; // spD8, spAC, sp6c - u16 noteSamplesDmemAddrBeforeResampling; // spD6, spAA, sp6a -- 6C - UNUSED u32 padSH2; - UNUSED u32 padSH3; - UNUSED u32 padSH4; - struct Note *note; // sp58 - u16 sp56; // sp56 - u16 addr; - u8 bankId; - curLoadedBook = NULL; - note = &gNotes[noteIndex]; - flags = 0; - if (noteSubEu->needsInit == TRUE) { - flags = A_INIT; - synthesisState->restart = 0; - synthesisState->samplePosInt = 0; - synthesisState->samplePosFrac = 0; - synthesisState->curVolLeft = 0; - synthesisState->curVolRight = 0; - synthesisState->prevHeadsetPanRight = 0; - synthesisState->prevHeadsetPanLeft = 0; - synthesisState->reverbVol = noteSubEu->reverbVol; - synthesisState->unk5 = 0; - note->noteSubEu.finished = 0; - } - - resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint; - nParts = noteSubEu->hasTwoAdpcmParts + 1; - samplesLenFixedPoint = (resamplingRateFixedPoint * bufLen * 2) + synthesisState->samplePosFrac; - nSamplesToLoad = (samplesLenFixedPoint >> 0x10); - synthesisState->samplePosFrac = samplesLenFixedPoint & 0xFFFF; - - if ((synthesisState->unk5 == 1) && (nParts == 2)) { - nSamplesToLoad += 2; - sp56 = 2; - } else if ((synthesisState->unk5 == 2) && (nParts == 1)) { - nSamplesToLoad -= 4; - sp56 = 4; - } else { - sp56 = 0; - } - - - synthesisState->unk5 = nParts; - - if (noteSubEu->isSyntheticWave) { - cmd = load_wave_samples(cmd, noteSubEu, synthesisState, nSamplesToLoad); - noteSamplesDmemAddrBeforeResampling = (synthesisState->samplePosInt * 2) + DMEM_ADDR_UNCOMPRESSED_NOTE; - synthesisState->samplePosInt += nSamplesToLoad; - } else { - // ADPCM note - audioBookSample = noteSubEu->sound.audioBankSound->sample; - loopInfo = audioBookSample->loop; - endPos = loopInfo->end; - sampleAddr = audioBookSample->sampleAddr; - resampledTempLen = 0; - for (curPart = 0; curPart < nParts; curPart++) { - nAdpcmSamplesProcessed = 0; // s8 - s5 = 0; // s4 - - if (nParts == 1) { - samplesLenAdjusted = nSamplesToLoad; - } else if (nSamplesToLoad & 1) { - samplesLenAdjusted = (nSamplesToLoad & ~1) + (curPart * 2); - } else { - samplesLenAdjusted = nSamplesToLoad; - } - - if (audioBookSample->codec == 0) { - if (curLoadedBook != (*audioBookSample->book).book) { - u32 nEntries; - switch (noteSubEu->bookOffset) { - case 1: - curLoadedBook = euUnknownData_80301950 + 1; - break; - case 2: - curLoadedBook = euUnknownData_80301950 + 2; - break; - case 3: - default: - curLoadedBook = audioBookSample->book->book; - break; - } - nEntries = 16 * audioBookSample->book->order * audioBookSample->book->npredictors; - aLoadADPCM(cmd++, nEntries, VIRTUAL_TO_PHYSICAL2(curLoadedBook)); - } - } - - while (nAdpcmSamplesProcessed != samplesLenAdjusted) { - s32 samplesRemaining; // v1 - s32 s0; - - noteFinished = FALSE; - restart = FALSE; - s2 = synthesisState->samplePosInt & 0xf; - samplesRemaining = endPos - synthesisState->samplePosInt; - nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed; - - if (s2 == 0 && synthesisState->restart == FALSE) { - s2 = 16; - } - s6 = 16 - s2; // a1 - if (nSamplesToProcess < samplesRemaining) { - t0 = (nSamplesToProcess - s6 + 0xf) / 16; - s0 = t0 * 16; - s3 = s6 + s0 - nSamplesToProcess; - } else { - s0 = samplesRemaining - s6; - s3 = 0; - if (s0 <= 0) { - s0 = 0; - s6 = samplesRemaining; - } - t0 = (s0 + 0xf) / 16; - if (loopInfo->count != 0) { - // Loop around and restart - restart = 1; - } else { - noteFinished = 1; - } - } - switch (audioBookSample->codec) { - case 0: - unk_s6 = 9; - sp88 = 0x10; - sp84 = 0; - break; - case 1: - unk_s6 = 0x10; - sp88 = 0x10; - sp84 = 0; - break; - case 2: goto skip; - } - if (t0 != 0) { - temp = (synthesisState->samplePosInt + sp88 - s2) / 16; - if (audioBookSample->medium == 0) { - v0_2 = sp84 + (temp * unk_s6) + sampleAddr; - } else { - v0_2 = dma_sample_data((uintptr_t)(sp84 + (temp * unk_s6) + sampleAddr), - ALIGN(t0 * unk_s6 + 16, 4), flags, &synthesisState->sampleDmaIndex, audioBookSample->medium); - } - - a3 = ((uintptr_t)v0_2 & 0xf); - addr = DMEM_ADDR_COMPRESSED_ADPCM_DATA; - addr -= ALIGN(t0 * unk_s6 + 16, 4); - aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(v0_2 - a3), addr & 0xffff, ALIGN(t0 * unk_s6 + 16, 4)); - } else { - s0 = 0; - a3 = 0; - } - if (synthesisState->restart != FALSE) { - aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state)); - flags = A_LOOP; // = 2 - synthesisState->restart = FALSE; - } - nSamplesInThisIteration = s0 + s6 - s3; - if (nAdpcmSamplesProcessed == 0) { - switch (audioBookSample->codec) { - case 0: - aligned = ALIGN(t0 * unk_s6 + 16, 4); - //! I have no idea. - addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff; - addr += a3; - aSetBuffer(cmd++, 0, addr, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2); - aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); - break; - case 1: - aligned = ALIGN(t0 * unk_s6 + 16, 4); - addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff; - addr += a3; - aSetBuffer(cmd++, 0, addr, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2); - aADPCM_23(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); - break; - } - sp130 = s2 * 2; - } else { - s5Aligned = ALIGN(s5 + 16, 4); - switch (audioBookSample->codec) { - case 0: - aligned = ALIGN(t0 * unk_s6 + 16, 4); - addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff; - addr += a3; - aSetBuffer(cmd++, 0, addr, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2); - aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); - break; - case 1: - aligned = ALIGN(t0 * unk_s6 + 16, 4); - addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff; - addr += a3; - aSetBuffer(cmd++, 0, addr, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2); - aADPCM_23(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); - - break; - } - aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2); - } - nAdpcmSamplesProcessed += nSamplesInThisIteration; - switch (flags) { - case A_INIT: // = 1 - sp130 = 0x20; - s5 = (s0 + 0x10) * 2; - break; - case A_LOOP: // = 2 - s5 = (nSamplesInThisIteration) * 2 + s5; - break; - default: - if (s5 != 0) { - s5 = (nSamplesInThisIteration) * 2 + s5; - } else { - s5 = (s2 + (nSamplesInThisIteration)) * 2; - } - break; - } - flags = 0; -skip: - if (noteFinished) { - aClearBuffer(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5, - (samplesLenAdjusted - nAdpcmSamplesProcessed) * 2); - noteSubEu->finished = 1; - note->noteSubEu.finished = 1; - func_sh_802ed644(updateIndex, noteIndex); - break; - } - if (restart != 0) { - synthesisState->restart = TRUE; - synthesisState->samplePosInt = loopInfo->start; - } else { - synthesisState->samplePosInt += nSamplesToProcess; - } - } - - switch (nParts) { - case 1: - noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + sp130; - break; - case 2: - switch (curPart) { - case 0: - aInterl(cmd++, 0, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED); - resampledTempLen = samplesLenAdjusted; - noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED; - if (noteSubEu->finished != FALSE) { - aClearBuffer(cmd++, noteSamplesDmemAddrBeforeResampling + resampledTempLen, samplesLenAdjusted + 0x10); - } - break; - case 1: - aInterl(cmd++, 0, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, resampledTempLen + DMEM_ADDR_RESAMPLED); - break; - } - } - if (noteSubEu->finished != FALSE) { - break; - } - } - } - flags = 0; - if (noteSubEu->needsInit == TRUE) { - flags = A_INIT; - noteSubEu->needsInit = FALSE; - } - flags = flags | sp56; - cmd = final_resample(cmd, synthesisState, bufLen * 2, resamplingRateFixedPoint, - noteSamplesDmemAddrBeforeResampling, flags); - if ((flags & 1) != 0) { - flags = 1; - } - - if (noteSubEu->filter) { - aFilter(cmd++, 0x02, bufLen * 2, noteSubEu->filter); - aFilter(cmd++, flags, DMEM_ADDR_TEMP, synthesisState->synthesisBuffers->filterBuffer); - - } - - if (noteSubEu->bookOffset == 3) { - aUnknown25(cmd++, 0, bufLen * 2, DMEM_ADDR_TEMP, DMEM_ADDR_TEMP); - } - - bankId = noteSubEu->bankId; - if (bankId != 0) { - if (bankId < 0x10) { - bankId = 0x10; - } - - aHilogain(cmd++, bankId, (bufLen + 0x10) * 2, DMEM_ADDR_TEMP); - } - - if (noteSubEu->headsetPanRight != 0 || synthesisState->prevHeadsetPanRight != 0) { - leftRight = 1; - } else if (noteSubEu->headsetPanLeft != 0 || synthesisState->prevHeadsetPanLeft != 0) { - leftRight = 2; - } else { - leftRight = 0; - } - cmd = process_envelope(cmd, noteSubEu, synthesisState, bufLen, 0x450, leftRight, flags); - if (noteSubEu->usesHeadsetPanEffects) { - if ((flags & 1) == 0) { - flags = 0; - } - cmd = note_apply_headset_pan_effects(cmd, noteSubEu, synthesisState, bufLen * 2, flags, leftRight); - } - - return cmd; -} -#endif - -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad) { s32 a3; s32 repeats; -#ifndef VERSION_SH s32 i; aSetBuffer(cmd++, /*flags*/ 0, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ 0, /*count*/ 128); aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples)); -#else - aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples), - DMEM_ADDR_UNCOMPRESSED_NOTE, 128); -#endif synthesisState->samplePosInt &= 0x3f; a3 = 64 - synthesisState->samplePosInt; if (a3 < nSamplesToLoad) { repeats = (nSamplesToLoad - a3 + 63) / 64; -#ifndef VERSION_SH for (i = 0; i < repeats; i++) { aDMEMMove(cmd++, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + (1 + i) * 128, /*count*/ 128); } -#else - if (repeats != 0) { - aDuplicate(cmd++, - /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, - /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + 128, - /*copies*/ repeats); - } -#endif } return cmd; } @@ -1669,18 +1399,10 @@ u64 *load_wave_samples(u64 *cmd, struct Note *note, s32 nSamplesToLoad) { } #endif -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags) { -#ifdef VERSION_SH - if (pitch == 0) { - aClearBuffer(cmd++, DMEM_ADDR_TEMP, count); - } else { -#endif - aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count); - aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->finalResampleState)); -#ifdef VERSION_SH - } -#endif + aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count); + aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->finalResampleState)); return cmd; } #else @@ -1691,8 +1413,7 @@ u64 *final_resample(u64 *cmd, struct Note *note, s32 count, u16 pitch, u16 dmemI } #endif -#ifndef VERSION_SH -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU u64 *process_envelope(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf, s32 headsetPanSettings, UNUSED u32 flags) { UNUSED u8 pad[16]; @@ -1782,7 +1503,7 @@ u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisStat } } -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU if (targetLeft == sourceLeft && targetRight == sourceRight && !note->envMixerNeedsInit) { #else if (vol->targetLeft == vol->sourceLeft && vol->targetRight == vol->sourceRight @@ -1792,7 +1513,7 @@ u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisStat } else { mixerFlags = A_INIT; -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU rampLeft = gCurrentLeftVolRamping[targetLeft >> 5] * gCurrentRightVolRamping[sourceLeft >> 5]; rampRight = gCurrentLeftVolRamping[targetRight >> 5] * gCurrentRightVolRamping[sourceRight >> 5]; #else @@ -1801,7 +1522,7 @@ u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisStat #endif // The operation's parameters change meanings depending on flags -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU aSetVolume(cmd++, A_VOL | A_LEFT, sourceLeft, 0, 0); aSetVolume(cmd++, A_VOL | A_RIGHT, sourceRight, 0, 0); aSetVolume32(cmd++, A_RATE | A_LEFT, targetLeft, rampLeft); @@ -1812,16 +1533,16 @@ u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisStat aSetVolume(cmd++, A_VOL | A_RIGHT, vol->sourceRight, 0, 0); aSetVolume32(cmd++, A_RATE | A_LEFT, vol->targetLeft, rampLeft); aSetVolume32(cmd++, A_RATE | A_RIGHT, vol->targetRight, rampRight); - aSetVolume(cmd++, A_AUX, gVolume, 0, note->reverbVol); + aSetVolume(cmd++, A_AUX, gVolume, 0, note->reverbVolShifted); #endif } -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU if (gUseReverb && note->reverbVol != 0) { aEnvMixer(cmd++, mixerFlags | A_AUX, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->mixEnvelopeState)); #else - if (gSynthesisReverb.useReverb && note->reverb) { + if (gSynthesisReverb.useReverb && note->reverbVol != 0) { aEnvMixer(cmd++, mixerFlags | A_AUX, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->mixEnvelopeState)); #endif @@ -1840,7 +1561,7 @@ u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisStat /*out*/ DMEM_ADDR_WET_RIGHT_CH); } } else { -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU aEnvMixer(cmd++, mixerFlags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->mixEnvelopeState)); #else aEnvMixer(cmd++, mixerFlags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->mixEnvelopeState)); @@ -1858,123 +1579,29 @@ u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisStat return cmd; } -#elif defined(VERSION_SH) -u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, UNUSED u32 flags) { - u16 sourceRight; - u16 sourceLeft; - u16 targetLeft; - u16 targetRight; - s16 rampLeft; - s16 rampRight; - s32 sourceReverbVol; - s16 reverbVol; - s32 temp = 0; - - sourceLeft = synthesisState->curVolLeft; - sourceRight = synthesisState->curVolRight; - targetLeft = note->targetVolLeft; - targetRight = note->targetVolRight; - targetLeft <<= 4; - targetRight <<= 4; - - if (targetLeft != sourceLeft) { - rampLeft = (targetLeft - sourceLeft) / (nSamples >> 3); - } else { - rampLeft = 0; - } - if (targetRight != sourceRight) { - rampRight = (targetRight - sourceRight) / (nSamples >> 3); - } else { - rampRight = 0; - } - - sourceReverbVol = synthesisState->reverbVol; - if (note->reverbVol != sourceReverbVol) { - temp = ((note->reverbVol & 0x7f) - (sourceReverbVol & 0x7f)) << 9; - reverbVol = temp / (nSamples >> 3); - synthesisState->reverbVol = note->reverbVol; - } else { - reverbVol = 0; - } - synthesisState->curVolLeft = sourceLeft + rampLeft * (nSamples >> 3); - synthesisState->curVolRight = sourceRight + rampRight * (nSamples >> 3); - - if (note->usesHeadsetPanEffects) { - aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DEFAULT_LEN_1CH); - aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, reverbVol, rampLeft, rampRight); - aEnvSetup2(cmd++, sourceLeft, sourceRight); - - switch (headsetPanSettings) { - case 1: - aEnvMixer(cmd++, - inBuf, nSamples, - (sourceReverbVol & 0x80) >> 7, - note->stereoStrongRight, note->stereoStrongLeft, - DMEM_ADDR_NOTE_PAN_TEMP, - DMEM_ADDR_RIGHT_CH, - DMEM_ADDR_WET_LEFT_CH, - DMEM_ADDR_WET_RIGHT_CH); - break; - case 2: - aEnvMixer(cmd++, - inBuf, nSamples, - (sourceReverbVol & 0x80) >> 7, - note->stereoStrongRight, note->stereoStrongLeft, - DMEM_ADDR_LEFT_CH, - DMEM_ADDR_NOTE_PAN_TEMP, - DMEM_ADDR_WET_LEFT_CH, - DMEM_ADDR_WET_RIGHT_CH); - break; - default: - aEnvMixer(cmd++, - inBuf, nSamples, - (sourceReverbVol & 0x80) >> 7, - note->stereoStrongRight, note->stereoStrongLeft, - DMEM_ADDR_LEFT_CH, - DMEM_ADDR_RIGHT_CH, - DMEM_ADDR_WET_LEFT_CH, - DMEM_ADDR_WET_RIGHT_CH); - break; - } - } else { - aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, reverbVol, rampLeft, rampRight); - aEnvSetup2(cmd++, sourceLeft, sourceRight); - aEnvMixer(cmd++, - inBuf, nSamples, - (sourceReverbVol & 0x80) >> 7, - note->stereoStrongRight, note->stereoStrongLeft, - DMEM_ADDR_LEFT_CH, - DMEM_ADDR_RIGHT_CH, - DMEM_ADDR_WET_LEFT_CH, - DMEM_ADDR_WET_RIGHT_CH); - } - return cmd; -} -#endif - -#if defined(VERSION_EU) || defined(VERSION_SH) +#ifdef VERSION_EU u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight) { #else u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 flags, s32 leftRight) { #endif u16 dest; u16 pitch; -#if defined(VERSION_JP) || defined(VERSION_US) - u16 prevPanShift; - u16 panShift; -#else +#ifdef VERSION_EU u8 prevPanShift; u8 panShift; UNUSED u8 unkDebug; +#else + u16 prevPanShift; + u16 panShift; #endif switch (leftRight) { case 1: dest = DMEM_ADDR_LEFT_CH; -#if defined(VERSION_JP) || defined(VERSION_US) - panShift = note->headsetPanRight; -#else +#ifdef VERSION_EU panShift = noteSubEu->headsetPanRight; +#else + panShift = note->headsetPanRight; #endif note->prevHeadsetPanLeft = 0; prevPanShift = note->prevHeadsetPanRight; @@ -1982,10 +1609,10 @@ u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 break; case 2: dest = DMEM_ADDR_RIGHT_CH; -#if defined(VERSION_JP) || defined(VERSION_US) - panShift = note->headsetPanLeft; -#else +#ifdef VERSION_EU panShift = noteSubEu->headsetPanLeft; +#else + panShift = note->headsetPanLeft; #endif note->prevHeadsetPanRight = 0; @@ -1996,26 +1623,8 @@ u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 return cmd; } - if (flags != 1) // A_INIT? - { + if (flags != 1) { // A_INIT? // Slightly adjust the sample rate in order to fit a change in pan shift -#ifdef VERSION_SH - if (panShift != prevPanShift) { - pitch = (((bufLen << 0xf) / 2) - 1) / ((bufLen + panShift - prevPanShift - 2) / 2); - aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, (bufLen + panShift) - prevPanShift); - aResampleZoh(cmd++, pitch, 0); - } else { - aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen); - } - - if (prevPanShift != 0) { - aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer), - DMEM_ADDR_NOTE_PAN_TEMP, ALIGN(prevPanShift, 4)); - aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift, bufLen + panShift - prevPanShift); - } else { - aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP, bufLen + panShift); - } -#else if (prevPanShift == 0) { // Kind of a hack that moves the first samples into the resample state aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, 8); @@ -2026,7 +1635,7 @@ u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, 32); aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panResampleState)); -#if defined(VERSION_EU) +#ifdef VERSION_EU pitch = (bufLen << 0xf) / (bufLen + panShift - prevPanShift + 8); if (pitch) { } @@ -2057,58 +1666,48 @@ u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 } else { aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP, panShift + bufLen - prevPanShift); } -#endif } else { // Just shift right aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen); -#ifdef VERSION_SH - aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, panShift); - aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + panShift, bufLen); -#else aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + panShift, bufLen); aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, panShift); -#endif } if (panShift) { // Save excessive samples for next iteration -#ifdef VERSION_SH - aSaveBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP + bufLen, - VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer), ALIGN(panShift, 4)); -#else aSetBuffer(cmd++, 0, 0, DMEM_ADDR_NOTE_PAN_TEMP + bufLen, panShift); aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer)); -#endif } -#ifdef VERSION_SH - aAddMixer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, dest, (bufLen + 0x3f) & 0xffc0); -#else aSetBuffer(cmd++, 0, 0, 0, bufLen); aMix(cmd++, 0, /*gain*/ 0x7fff, /*in*/ DMEM_ADDR_NOTE_PAN_TEMP, /*out*/ dest); -#endif return cmd; } -#if defined(VERSION_JP) || defined(VERSION_US) +#ifndef VERSION_EU // Moved to playback.c in EU void note_init_volume(struct Note *note) { note->targetVolLeft = 0; note->targetVolRight = 0; - note->reverb = 0; note->reverbVol = 0; + note->reverbVolShifted = 0; note->unused2 = 0; note->curVolLeft = 1; note->curVolRight = 1; note->frequency = 0.0f; } -void note_set_vel_pan_reverb(struct Note *note, f32 velocity, f32 pan, u8 reverb) { +void note_set_vel_pan_reverb(struct Note *note, f32 velocity, f32 pan, u8 reverbVol) { s32 panIndex; f32 volLeft; f32 volRight; + // Anding with 127 avoids out-of-bounds reads when pan is outside of [0, 1]. + // This can occur during PU movement -- see the bug comment in get_sound_pan + // in external.c. An out-of-bounds read by itself doesn't crash, but if the + // resulting value is a nan or denormal, performing arithmetic on it crashes + // on console. #ifdef VERSION_JP panIndex = MIN((s32)(pan * 127.5), 127); #else @@ -2170,9 +1769,9 @@ void note_set_vel_pan_reverb(struct Note *note, f32 velocity, f32 pan, u8 reverb if (note->targetVolRight == 0) { note->targetVolRight++; } - if (note->reverb != reverb) { - note->reverb = reverb; - note->reverbVol = reverb << 8; + if (note->reverbVol != reverbVol) { + note->reverbVol = reverbVol; + note->reverbVolShifted = reverbVol << 8; note->envMixerNeedsInit = TRUE; return; } @@ -2215,3 +1814,4 @@ void note_disable(struct Note *note) { note->prevParentLayer = NO_LAYER; } #endif +#endif diff --git a/src/audio/synthesis.h b/src/audio/synthesis.h index 244fc4a8..09eae59f 100644 --- a/src/audio/synthesis.h +++ b/src/audio/synthesis.h @@ -17,6 +17,42 @@ #define MAX_UPDATES_PER_FRAME 4 #endif +#if defined(BETTER_REVERB) && (defined(VERSION_US) || defined(VERSION_JP)) + // Size determined by ((all delaysBaselineL/R values * 8) / (2 ^ Minimum Downsample Factor)) + array pointers. + // The default value can be increased or decreased in conjunction with the values in delaysBaselineL/R +#define BETTER_REVERB_SIZE 0xF200 + +// #define BETTER_REVERB_SIZE 0x7A00 // Default for use only with a downsampling value of 3 (i.e. double the emulator default) +// #define BETTER_REVERB_SIZE 0x1E200 // Default for use with a downsampling value of 1 (i.e. no downsampling at all) + +#define NUM_ALLPASS 12 // Number of delay filters to use with better reverb; do not change this value if you don't know what you're doing. + +extern s8 betterReverbDownsampleConsole; +extern s8 betterReverbDownsampleEmulator; +extern u32 reverbFilterCountConsole; +extern u32 reverbFilterCountEmulator; +extern u8 monoReverbConsole; +extern u8 monoReverbEmulator; +extern s32 betterReverbWindowsSize; +extern s32 gReverbRevIndex; +extern s32 gReverbGainIndex; +extern s32 gReverbWetSigna; +// extern s32 gReverbDrySignal; + +extern const s32 delaysBaselineL[NUM_ALLPASS]; +extern const s32 delaysBaselineR[NUM_ALLPASS]; +extern s32 delaysL[NUM_ALLPASS]; +extern s32 delaysR[NUM_ALLPASS]; +extern s32 reverbMultsL[NUM_ALLPASS / 3]; +extern s32 reverbMultsR[NUM_ALLPASS / 3]; +extern s32 **delayBufsL; +extern s32 **delayBufsR; + +extern u8 toggleBetterReverb; +#else +#define BETTER_REVERB_SIZE 0 +#endif + struct ReverbRingBufferItem { s16 numSamplesAfterDownsampling; @@ -90,7 +126,7 @@ extern s16 D_SH_803479B4; u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen); #if defined(VERSION_JP) || defined(VERSION_US) void note_init_volume(struct Note *note); -void note_set_vel_pan_reverb(struct Note *note, f32 velocity, f32 pan, u8 reverb); +void note_set_vel_pan_reverb(struct Note *note, f32 velocity, f32 pan, u8 reverbVol); void note_set_frequency(struct Note *note, f32 frequency); void note_enable(struct Note *note); void note_disable(struct Note *note); diff --git a/src/audio/synthesis_sh.c b/src/audio/synthesis_sh.c new file mode 100644 index 00000000..d27df362 --- /dev/null +++ b/src/audio/synthesis_sh.c @@ -0,0 +1,910 @@ +#ifdef VERSION_SH +#include + +#include "synthesis.h" +#include "heap.h" +#include "data.h" +#include "load.h" +#include "seqplayer.h" +#include "internal.h" +#include "external.h" + + +#define DMEM_ADDR_TEMP 0x450 +#define DMEM_ADDR_RESAMPLED 0x470 +#define DMEM_ADDR_RESAMPLED2 0x5f0 +#define DMEM_ADDR_UNCOMPRESSED_NOTE 0x5f0 +#define DMEM_ADDR_NOTE_PAN_TEMP 0x650 +#define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x990 +#define DMEM_ADDR_LEFT_CH 0x990 +#define DMEM_ADDR_RIGHT_CH 0xb10 +#define DMEM_ADDR_WET_LEFT_CH 0xc90 +#define DMEM_ADDR_WET_RIGHT_CH 0xe10 + +#define aSetLoadBufferPair(pkt, c, off) \ + aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_LEFT_CH, 0, DEFAULT_LEN_1CH - c); \ + aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off))); \ + aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_RIGHT_CH, 0, DEFAULT_LEN_1CH - c); \ + aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off))) + +#define aSetSaveBufferPair(pkt, c, d, off) \ + aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_LEFT_CH, d); \ + aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off))); \ + aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_RIGHT_CH, d); \ + aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off))); + +#define ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1)) + +struct VolumeChange { + u16 sourceLeft; + u16 sourceRight; + u16 targetLeft; + u16 targetRight; +}; + +u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex); +u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex); +u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad); +u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags); +u64 *process_envelope(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, u32 flags); +u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight); + +struct SynthesisReverb gSynthesisReverbs[4]; +u8 sAudioSynthesisPad[0x10]; + +s16 gVolume; +s8 gUseReverb; +s8 gNumSynthesisReverbs; +s16 D_SH_803479B4; // contains 4096 +struct NoteSubEu *gNoteSubsEu; + +// Equivalent functionality as the US/JP version, +// just that the reverb structure is chosen from an array with index +// Identical in EU. +void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex) { + struct ReverbRingBufferItem *item; + struct SynthesisReverb *reverb = &gSynthesisReverbs[reverbIndex]; + s32 srcPos; + s32 dstPos; + s32 nSamples; + s32 excessiveSamples; + s32 UNUSED pad[3]; + if (reverb->downsampleRate != 1) { + if (reverb->framesLeftToIgnore == 0) { + // Now that the RSP has finished, downsample the samples produced two frames ago by skipping + // samples. + item = &reverb->items[reverb->curFrame][updateIndex]; + + // Touches both left and right since they are adjacent in memory + osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH); + + for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2; + srcPos += reverb->downsampleRate, dstPos++) { + reverb->ringBuffer.left[item->startPos + dstPos] = + item->toDownsampleLeft[srcPos]; + reverb->ringBuffer.right[item->startPos + dstPos] = + item->toDownsampleRight[srcPos]; + } + for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += reverb->downsampleRate, dstPos++) { + reverb->ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos]; + reverb->ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos]; + } + } + } + + item = &reverb->items[reverb->curFrame][updateIndex]; + nSamples = chunkLen / reverb->downsampleRate; + excessiveSamples = (nSamples + reverb->nextRingBufferPos) - reverb->bufSizePerChannel; + if (excessiveSamples < 0) { + // There is space in the ring buffer before it wraps around + item->lengthA = nSamples * 2; + item->lengthB = 0; + item->startPos = (s32) reverb->nextRingBufferPos; + reverb->nextRingBufferPos += nSamples; + } else { + // Ring buffer wrapped around + item->lengthA = (nSamples - excessiveSamples) * 2; + item->lengthB = excessiveSamples * 2; + item->startPos = reverb->nextRingBufferPos; + reverb->nextRingBufferPos = excessiveSamples; + } + // These fields are never read later + item->numSamplesAfterDownsampling = nSamples; + item->chunkLen = chunkLen; +} + +u64 *synthesis_load_reverb_ring_buffer(u64 *cmd, u16 addr, u16 srcOffset, s32 len, s32 reverbIndex) { + aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[srcOffset]), + addr, len); + aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[srcOffset]), + addr + DEFAULT_LEN_1CH, len); + return cmd; +} + +u64 *synthesis_save_reverb_ring_buffer(u64 *cmd, u16 addr, u16 destOffset, s32 len, s32 reverbIndex) { + aSaveBuffer(cmd++, addr, + VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[destOffset]), len); + aSaveBuffer(cmd++, addr + DEFAULT_LEN_1CH, + VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[destOffset]), len); + return cmd; +} + +void func_sh_802ed644(s32 updateIndexStart, s32 noteIndex) { + s32 i; + + for (i = updateIndexStart + 1; i < gAudioBufferParameters.updatesPerFrame; i++) { + if (!gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].needsInit) { + gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].enabled = FALSE; + } else { + break; + } + } +} + +void synthesis_load_note_subs_eu(s32 updateIndex) { + struct NoteSubEu *src; + struct NoteSubEu *dest; + s32 i; + + for (i = 0; i < gMaxSimultaneousNotes; i++) { + src = &gNotes[i].noteSubEu; + dest = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i]; + if (src->enabled) { + *dest = *src; + src->needsInit = FALSE; + } else { + dest->enabled = FALSE; + } + } +} + +// TODO: (Scrub C) pointless mask and whitespace +u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) { + s32 i, j; + u32 *aiBufPtr; + u64 *cmd = cmdBuf; + s32 chunkLen; + + for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) { + process_sequences(i - 1); + synthesis_load_note_subs_eu(gAudioBufferParameters.updatesPerFrame - i); + } + aiBufPtr = (u32 *) aiBuf; + for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) { + if (i == 1) { + chunkLen = bufLen; + } else { + if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) { + chunkLen = gAudioBufferParameters.samplesPerUpdateMax; + } else if (bufLen / i <= gAudioBufferParameters.samplesPerUpdateMin) { + chunkLen = gAudioBufferParameters.samplesPerUpdateMin; + } else { + chunkLen = gAudioBufferParameters.samplesPerUpdate; + } + } + for (j = 0; j < gNumSynthesisReverbs; j++) { + if (gSynthesisReverbs[j].useReverb != 0) { + prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j); + } + } + cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioBufferParameters.updatesPerFrame - i); + bufLen -= chunkLen; + aiBufPtr += chunkLen; + } + + for (j = 0; j < gNumSynthesisReverbs; j++) { + if (gSynthesisReverbs[j].framesLeftToIgnore != 0) { + gSynthesisReverbs[j].framesLeftToIgnore--; + } + gSynthesisReverbs[j].curFrame ^= 1; + } + *writtenCmds = cmd - cmdBuf; + return cmd; +} + +u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s16 updateIndex) { + struct ReverbRingBufferItem *item; + s16 startPad; + s16 paddedLengthA; + + item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex]; + + if (gSynthesisReverbs[reverbIndex].downsampleRate == 1) { + cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex); + if (item->lengthB != 0) { + cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex); + } + aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH); + aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH); + } else { + startPad = (item->startPos % 8u) * 2; + paddedLengthA = ALIGN(startPad + item->lengthA, 4); + + cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, (item->startPos - startPad / 2), DEFAULT_LEN_1CH, reverbIndex); + if (item->lengthB != 0) { + cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + paddedLengthA, 0, DEFAULT_LEN_1CH - paddedLengthA, reverbIndex); + } + + aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED + startPad, DMEM_ADDR_WET_LEFT_CH, bufLen * 2); + aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateLeft)); + + aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED2 + startPad, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2); + aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateRight)); + + aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH); + aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH); + } + if (gSynthesisReverbs[reverbIndex].panRight != 0 || gSynthesisReverbs[reverbIndex].panLeft != 0) { + // Leak some audio from the left reverb channel into the right reverb channel and vice versa (pan) + aDMEMMove(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_1CH); + aMix(cmd++, gSynthesisReverbs[reverbIndex].panRight, DMEM_ADDR_WET_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_1CH); + aMix(cmd++, gSynthesisReverbs[reverbIndex].panLeft, DMEM_ADDR_RESAMPLED, DMEM_ADDR_WET_RIGHT_CH, DEFAULT_LEN_1CH); + } + return cmd; +} + +u64 *synthesis_load_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) { + struct ReverbRingBufferItem *item; + struct SynthesisReverb *reverb; + + reverb = &gSynthesisReverbs[reverbIndex]; + item = &reverb->items[reverb->curFrame][updateIndex]; + // Get the oldest samples in the ring buffer into the wet channels + cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex); + if (item->lengthB != 0) { + // Ring buffer wrapped + cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex); + } + return cmd; +} + +u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) { + struct ReverbRingBufferItem *item; + + item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex]; + switch (gSynthesisReverbs[reverbIndex].downsampleRate) { + case 1: + // Put the oldest samples in the ring buffer into the wet channels + cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex); + if (item->lengthB != 0) { + // Ring buffer wrapped + cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex); + } + break; + + default: + // Downsampling is done later by CPU when RSP is done, therefore we need to have double + // buffering. Left and right buffers are adjacent in memory. + aSaveBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH, + VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex].toDownsampleLeft), DEFAULT_LEN_2CH); + break; + } + gSynthesisReverbs[reverbIndex].resampleFlags = 0; + return cmd; +} + +u64 *func_sh_802EDF24(u64 *cmd, s16 reverbIndex, s16 updateIndex) { + struct ReverbRingBufferItem *item; + struct SynthesisReverb *reverb; + + reverb = &gSynthesisReverbs[reverbIndex]; + item = &reverb->items[reverb->curFrame][updateIndex]; + // Put the oldest samples in the ring buffer into the wet channels + cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex); + if (item->lengthB != 0) { + // Ring buffer wrapped + cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex); + } + return cmd; +} + +u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) { + struct NoteSubEu *noteSubEu; + u8 noteIndices[56]; + s32 temp; + s32 i; + s16 j; + s16 notePos = 0; + + if (gNumSynthesisReverbs == 0) { + for (i = 0; i < gMaxSimultaneousNotes; i++) { + if (gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i].enabled) { + noteIndices[notePos++] = i; + } + } + } else { + for (j = 0; j < gNumSynthesisReverbs; j++) { + for (i = 0; i < gMaxSimultaneousNotes; i++) { + noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i]; + if (noteSubEu->enabled && j == noteSubEu->reverbIndex) { + noteIndices[notePos++] = i; + } + } + } + + for (i = 0; i < gMaxSimultaneousNotes; i++) { + noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i]; + if (noteSubEu->enabled && noteSubEu->reverbIndex >= gNumSynthesisReverbs) { + noteIndices[notePos++] = i; + } + } + } + aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH); + i = 0; + for (j = 0; j < gNumSynthesisReverbs; j++) { + gUseReverb = gSynthesisReverbs[j].useReverb; + if (gUseReverb != 0) { + cmd = synthesis_resample_and_mix_reverb(cmd, bufLen, j, updateIndex); + } + for (; i < notePos; i++) { + temp = updateIndex * gMaxSimultaneousNotes; + if (j == gNoteSubsEu[temp + noteIndices[i]].reverbIndex) { + cmd = synthesis_process_note(noteIndices[i], + &gNoteSubsEu[temp + noteIndices[i]], + &gNotes[noteIndices[i]].synthesisState, + aiBuf, bufLen, cmd, updateIndex); + continue; + } else { + break; + } + } + if (gSynthesisReverbs[j].useReverb != 0) { + if (gSynthesisReverbs[j].unk100 != NULL) { + aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk100); + aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_LEFT_CH, gSynthesisReverbs[j].unk108); + } + if (gSynthesisReverbs[j].unk104 != NULL) { + aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk104); + aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_RIGHT_CH, gSynthesisReverbs[j].unk10C); + } + cmd = synthesis_save_reverb_samples(cmd, j, updateIndex); + if (gSynthesisReverbs[j].unk5 != -1) { + if (gSynthesisReverbs[gSynthesisReverbs[j].unk5].downsampleRate == 1) { + cmd = synthesis_load_reverb_samples(cmd, gSynthesisReverbs[j].unk5, updateIndex); + aMix(cmd++, gSynthesisReverbs[j].unk08, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_2CH); + cmd = func_sh_802EDF24(cmd++, gSynthesisReverbs[j].unk5, updateIndex); + } + } + } + } + for (; i < notePos; i++) { + struct NoteSubEu *noteSubEu2 = &gNoteSubsEu[updateIndex * gMaxSimultaneousNotes + noteIndices[i]]; + cmd = synthesis_process_note(noteIndices[i], + noteSubEu2, + &gNotes[noteIndices[i]].synthesisState, + aiBuf, bufLen, cmd, updateIndex); + } + + temp = bufLen * 2; + aInterleave(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH, temp); + aSaveBuffer(cmd++, DMEM_ADDR_TEMP, VIRTUAL_TO_PHYSICAL2(aiBuf), temp * 2); + return cmd; +} + +u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, UNUSED s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) { + UNUSED s32 pad0[3]; + struct AudioBankSample *audioBookSample; // sp164, sp138 + struct AdpcmLoop *loopInfo; // sp160, sp134 + s16 *curLoadedBook; // sp154, sp130 + UNUSED u8 padEU[0x04]; + UNUSED u8 pad8[0x04]; + s32 noteFinished; // 150 t2, sp124 + s32 restart; // 14c t3, sp120 + s32 flags; // sp148, sp11C, t8 + u16 resamplingRateFixedPoint; // sp5c, sp11A + s32 nSamplesToLoad; //s0, Ec + UNUSED u8 pad7[0x0c]; // sp100 + s32 sp130; //sp128, sp104 + UNUSED s32 tempBufLen; + UNUSED u32 pad9; + s32 t0; + u8 *sampleAddr; // sp120, spF4 + s32 s6; + s32 samplesLenAdjusted; // 108, spEC + s32 nAdpcmSamplesProcessed; // signed required for US // spc0 + s32 endPos; // sp110, spE4 + s32 nSamplesToProcess; // sp10c/a0, spE0 + // Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange + // behavior with the break near the end of the loop, causing US and JP to need a goto instead + UNUSED s32 samplesLenInt; + s32 s2; + s32 leftRight; //s0 + s32 s5; //s4 + u32 samplesLenFixedPoint; // v1_1 + s32 s3; // spA0 + s32 nSamplesInThisIteration; // v1_2 + u32 a3; + u8 *v0_2; + s32 unk_s6; // sp90 + s32 s5Aligned; + s32 sp88; + s32 sp84; + u32 temp; + s32 nParts; // spE8, spBC + s32 curPart; // spE4, spB8 + s32 aligned; + UNUSED u32 padSH1; + s32 resampledTempLen; // spD8, spAC, sp6c + u16 noteSamplesDmemAddrBeforeResampling; // spD6, spAA, sp6a -- 6C + UNUSED u32 padSH2; + UNUSED u32 padSH3; + UNUSED u32 padSH4; + struct Note *note; // sp58 + u16 sp56; // sp56 + u16 addr; + u8 synthesisVolume; + + curLoadedBook = NULL; + note = &gNotes[noteIndex]; + flags = 0; + if (noteSubEu->needsInit == TRUE) { + flags = A_INIT; + synthesisState->restart = 0; + synthesisState->samplePosInt = 0; + synthesisState->samplePosFrac = 0; + synthesisState->curVolLeft = 0; + synthesisState->curVolRight = 0; + synthesisState->prevHeadsetPanRight = 0; + synthesisState->prevHeadsetPanLeft = 0; + synthesisState->reverbVol = noteSubEu->reverbVol; + synthesisState->unk5 = 0; + note->noteSubEu.finished = 0; + } + + resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint; + nParts = noteSubEu->hasTwoAdpcmParts + 1; + samplesLenFixedPoint = (resamplingRateFixedPoint * bufLen * 2) + synthesisState->samplePosFrac; + nSamplesToLoad = (samplesLenFixedPoint >> 0x10); + synthesisState->samplePosFrac = samplesLenFixedPoint & 0xFFFF; + + if ((synthesisState->unk5 == 1) && (nParts == 2)) { + nSamplesToLoad += 2; + sp56 = 2; + } else if ((synthesisState->unk5 == 2) && (nParts == 1)) { + nSamplesToLoad -= 4; + sp56 = 4; + } else { + sp56 = 0; + } + + + synthesisState->unk5 = nParts; + + if (noteSubEu->isSyntheticWave) { + cmd = load_wave_samples(cmd, noteSubEu, synthesisState, nSamplesToLoad); + noteSamplesDmemAddrBeforeResampling = (synthesisState->samplePosInt * 2) + DMEM_ADDR_UNCOMPRESSED_NOTE; + synthesisState->samplePosInt += nSamplesToLoad; + } else { + // ADPCM note + audioBookSample = noteSubEu->sound.audioBankSound->sample; + loopInfo = audioBookSample->loop; + endPos = loopInfo->end; + sampleAddr = audioBookSample->sampleAddr; + resampledTempLen = 0; + for (curPart = 0; curPart < nParts; curPart++) { + nAdpcmSamplesProcessed = 0; // s8 + s5 = 0; // s4 + + if (nParts == 1) { + samplesLenAdjusted = nSamplesToLoad; + } else if (nSamplesToLoad & 1) { + samplesLenAdjusted = (nSamplesToLoad & ~1) + (curPart * 2); + } else { + samplesLenAdjusted = nSamplesToLoad; + } + + if (audioBookSample->codec == CODEC_ADPCM) { + if (curLoadedBook != (*audioBookSample->book).book) { + u32 nEntries; + switch (noteSubEu->bookOffset) { + case 1: + curLoadedBook = euUnknownData_80301950 + 1; + break; + case 2: + curLoadedBook = euUnknownData_80301950 + 2; + break; + case 3: + default: + curLoadedBook = audioBookSample->book->book; + break; + } + nEntries = 16 * audioBookSample->book->order * audioBookSample->book->npredictors; + aLoadADPCM(cmd++, nEntries, VIRTUAL_TO_PHYSICAL2(curLoadedBook)); + } + } + + while (nAdpcmSamplesProcessed != samplesLenAdjusted) { + s32 samplesRemaining; // v1 + s32 s0; + + noteFinished = FALSE; + restart = FALSE; + s2 = synthesisState->samplePosInt & 0xf; + samplesRemaining = endPos - synthesisState->samplePosInt; + nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed; + + if (s2 == 0 && synthesisState->restart == FALSE) { + s2 = 16; + } + s6 = 16 - s2; // a1 + if (nSamplesToProcess < samplesRemaining) { + t0 = (nSamplesToProcess - s6 + 0xf) / 16; + s0 = t0 * 16; + s3 = s6 + s0 - nSamplesToProcess; + } else { + s0 = samplesRemaining - s6; + s3 = 0; + if (s0 <= 0) { + s0 = 0; + s6 = samplesRemaining; + } + t0 = (s0 + 0xf) / 16; + if (loopInfo->count != 0) { + // Loop around and restart + restart = 1; + } else { + noteFinished = 1; + } + } + switch (audioBookSample->codec) { + case CODEC_ADPCM: + unk_s6 = 9; + sp88 = 0x10; + sp84 = 0; + break; + case CODEC_S8: + unk_s6 = 0x10; + sp88 = 0x10; + sp84 = 0; + break; + case CODEC_SKIP: goto skip; + } + if (t0 != 0) { + temp = (synthesisState->samplePosInt + sp88 - s2) / 16; + if (audioBookSample->medium == 0) { + v0_2 = sp84 + (temp * unk_s6) + sampleAddr; + } else { + v0_2 = dma_sample_data((uintptr_t)(sp84 + (temp * unk_s6) + sampleAddr), + ALIGN(t0 * unk_s6 + 16, 4), flags, &synthesisState->sampleDmaIndex, audioBookSample->medium); + } + + a3 = ((uintptr_t)v0_2 & 0xf); + aligned = ALIGN(t0 * unk_s6 + 16, 4); + addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff; + aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(v0_2 - a3), addr, ALIGN(t0 * unk_s6 + 16, 4)); + } else { + s0 = 0; + a3 = 0; + } + if (synthesisState->restart != FALSE) { + aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state)); + flags = A_LOOP; // = 2 + synthesisState->restart = FALSE; + } + nSamplesInThisIteration = s0 + s6 - s3; + if (nAdpcmSamplesProcessed == 0) { + switch (audioBookSample->codec) { + case CODEC_ADPCM: + aligned = ALIGN(t0 * unk_s6 + 16, 4); + addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff; + aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2); + aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); + break; + case CODEC_S8: + aligned = ALIGN(t0 * unk_s6 + 16, 4); + addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff; + aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2); + aS8Dec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); + break; + } + sp130 = s2 * 2; + } else { + s5Aligned = ALIGN(s5 + 16, 4); + switch (audioBookSample->codec) { + case CODEC_ADPCM: + aligned = ALIGN(t0 * unk_s6 + 16, 4); + addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff; + aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2); + aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); + break; + case CODEC_S8: + aligned = ALIGN(t0 * unk_s6 + 16, 4); + addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff; + aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2); + aS8Dec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState)); + break; + } + aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2); + } + nAdpcmSamplesProcessed += nSamplesInThisIteration; + switch (flags) { + case A_INIT: // = 1 + sp130 = 0x20; + s5 = (s0 + 0x10) * 2; + break; + case A_LOOP: // = 2 + s5 = (nSamplesInThisIteration) * 2 + s5; + break; + default: + if (s5 != 0) { + s5 = (nSamplesInThisIteration) * 2 + s5; + } else { + s5 = (s2 + (nSamplesInThisIteration)) * 2; + } + break; + } + flags = 0; +skip: + if (noteFinished) { + aClearBuffer(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5, + (samplesLenAdjusted - nAdpcmSamplesProcessed) * 2); + noteSubEu->finished = 1; + note->noteSubEu.finished = 1; + func_sh_802ed644(updateIndex, noteIndex); + break; + } + if (restart != 0) { + synthesisState->restart = TRUE; + synthesisState->samplePosInt = loopInfo->start; + } else { + synthesisState->samplePosInt += nSamplesToProcess; + } + } + + switch (nParts) { + case 1: + noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + sp130; + break; + case 2: + switch (curPart) { + case 0: + aDownsampleHalf(cmd++, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED); + resampledTempLen = samplesLenAdjusted; + noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED; + if (noteSubEu->finished != FALSE) { + aClearBuffer(cmd++, noteSamplesDmemAddrBeforeResampling + resampledTempLen, samplesLenAdjusted + 0x10); + } + break; + case 1: + aDownsampleHalf(cmd++, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, resampledTempLen + DMEM_ADDR_RESAMPLED); + break; + } + } + if (noteSubEu->finished != FALSE) { + break; + } + } + } + flags = 0; + if (noteSubEu->needsInit == TRUE) { + flags = A_INIT; + noteSubEu->needsInit = FALSE; + } + flags = flags | sp56; + cmd = final_resample(cmd, synthesisState, bufLen * 2, resamplingRateFixedPoint, + noteSamplesDmemAddrBeforeResampling, flags); + if ((flags & 1) != 0) { + flags = 1; + } + + if (noteSubEu->filter) { + aFilter(cmd++, 0x02, bufLen * 2, noteSubEu->filter); + aFilter(cmd++, flags, DMEM_ADDR_TEMP, synthesisState->synthesisBuffers->filterBuffer); + + } + + if (noteSubEu->bookOffset == 3) { + aUnknown25(cmd++, 0, bufLen * 2, DMEM_ADDR_TEMP, DMEM_ADDR_TEMP); + } + + synthesisVolume = noteSubEu->synthesisVolume; + if (synthesisVolume != 0) { + if (synthesisVolume < 0x10) { + synthesisVolume = 0x10; + } + + aHiLoGain(cmd++, synthesisVolume, (bufLen + 0x10) * 2, DMEM_ADDR_TEMP); + } + + if (noteSubEu->headsetPanRight != 0 || synthesisState->prevHeadsetPanRight != 0) { + leftRight = 1; + } else if (noteSubEu->headsetPanLeft != 0 || synthesisState->prevHeadsetPanLeft != 0) { + leftRight = 2; + } else { + leftRight = 0; + } + cmd = process_envelope(cmd, noteSubEu, synthesisState, bufLen, DMEM_ADDR_TEMP, leftRight, flags); + if (noteSubEu->usesHeadsetPanEffects) { + if ((flags & 1) == 0) { + flags = 0; + } + cmd = note_apply_headset_pan_effects(cmd, noteSubEu, synthesisState, bufLen * 2, flags, leftRight); + } + + return cmd; +} + +u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad) { + s32 a3; + s32 repeats; + aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples), + DMEM_ADDR_UNCOMPRESSED_NOTE, 128); + + synthesisState->samplePosInt &= 0x3f; + a3 = 64 - synthesisState->samplePosInt; + if (a3 < nSamplesToLoad) { + repeats = (nSamplesToLoad - a3 + 63) / 64; + if (repeats != 0) { + aDuplicate(cmd++, + /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, + /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + 128, + /*copies*/ repeats); + } + } + return cmd; +} + +u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags) { + if (pitch == 0) { + aClearBuffer(cmd++, DMEM_ADDR_TEMP, count); + } else { + aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count); + aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->finalResampleState)); + } + return cmd; +} + +u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, UNUSED u32 flags) { + u16 sourceRight; + u16 sourceLeft; + u16 targetLeft; + u16 targetRight; + s16 rampLeft; + s16 rampRight; + s32 sourceReverbVol; + s16 rampReverb; + s32 reverbVolDiff = 0; + + sourceLeft = synthesisState->curVolLeft; + sourceRight = synthesisState->curVolRight; + targetLeft = note->targetVolLeft; + targetRight = note->targetVolRight; + targetLeft <<= 4; + targetRight <<= 4; + + if (targetLeft != sourceLeft) { + rampLeft = (targetLeft - sourceLeft) / (nSamples >> 3); + } else { + rampLeft = 0; + } + if (targetRight != sourceRight) { + rampRight = (targetRight - sourceRight) / (nSamples >> 3); + } else { + rampRight = 0; + } + + sourceReverbVol = synthesisState->reverbVol; + if (note->reverbVol != sourceReverbVol) { + reverbVolDiff = ((note->reverbVol & 0x7f) - (sourceReverbVol & 0x7f)) << 9; + rampReverb = reverbVolDiff / (nSamples >> 3); + synthesisState->reverbVol = note->reverbVol; + } else { + rampReverb = 0; + } + synthesisState->curVolLeft = sourceLeft + rampLeft * (nSamples >> 3); + synthesisState->curVolRight = sourceRight + rampRight * (nSamples >> 3); + + if (note->usesHeadsetPanEffects) { + aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DEFAULT_LEN_1CH); + aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, rampReverb, rampLeft, rampRight); + aEnvSetup2(cmd++, sourceLeft, sourceRight); + + switch (headsetPanSettings) { + case 1: + aEnvMixer(cmd++, + inBuf, nSamples, + (sourceReverbVol & 0x80) >> 7, + note->stereoStrongRight, note->stereoStrongLeft, + DMEM_ADDR_NOTE_PAN_TEMP, + DMEM_ADDR_RIGHT_CH, + DMEM_ADDR_WET_LEFT_CH, + DMEM_ADDR_WET_RIGHT_CH); + break; + case 2: + aEnvMixer(cmd++, + inBuf, nSamples, + (sourceReverbVol & 0x80) >> 7, + note->stereoStrongRight, note->stereoStrongLeft, + DMEM_ADDR_LEFT_CH, + DMEM_ADDR_NOTE_PAN_TEMP, + DMEM_ADDR_WET_LEFT_CH, + DMEM_ADDR_WET_RIGHT_CH); + break; + default: + aEnvMixer(cmd++, + inBuf, nSamples, + (sourceReverbVol & 0x80) >> 7, + note->stereoStrongRight, note->stereoStrongLeft, + DMEM_ADDR_LEFT_CH, + DMEM_ADDR_RIGHT_CH, + DMEM_ADDR_WET_LEFT_CH, + DMEM_ADDR_WET_RIGHT_CH); + break; + } + } else { + aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, rampReverb, rampLeft, rampRight); + aEnvSetup2(cmd++, sourceLeft, sourceRight); + aEnvMixer(cmd++, + inBuf, nSamples, + (sourceReverbVol & 0x80) >> 7, + note->stereoStrongRight, note->stereoStrongLeft, + DMEM_ADDR_LEFT_CH, + DMEM_ADDR_RIGHT_CH, + DMEM_ADDR_WET_LEFT_CH, + DMEM_ADDR_WET_RIGHT_CH); + } + return cmd; +} + +u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight) { + u16 dest; + u16 pitch; + u8 prevPanShift; + u8 panShift; + UNUSED u8 unkDebug; + + switch (leftRight) { + case 1: + dest = DMEM_ADDR_LEFT_CH; + panShift = noteSubEu->headsetPanRight; + note->prevHeadsetPanLeft = 0; + prevPanShift = note->prevHeadsetPanRight; + note->prevHeadsetPanRight = panShift; + break; + case 2: + dest = DMEM_ADDR_RIGHT_CH; + panShift = noteSubEu->headsetPanLeft; + note->prevHeadsetPanRight = 0; + + prevPanShift = note->prevHeadsetPanLeft; + note->prevHeadsetPanLeft = panShift; + break; + default: + return cmd; + } + + if (flags != 1) { // A_INIT? + // Slightly adjust the sample rate in order to fit a change in pan shift + if (panShift != prevPanShift) { + pitch = (((bufLen << 0xf) / 2) - 1) / ((bufLen + panShift - prevPanShift - 2) / 2); + aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, (bufLen + panShift) - prevPanShift); + aResampleZoh(cmd++, pitch, 0); + } else { + aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen); + } + + if (prevPanShift != 0) { + aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer), + DMEM_ADDR_NOTE_PAN_TEMP, ALIGN(prevPanShift, 4)); + aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift, bufLen + panShift - prevPanShift); + } else { + aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP, bufLen + panShift); + } + } else { + // Just shift right + aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen); + aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, panShift); + aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + panShift, bufLen); + } + + if (panShift) { + // Save excessive samples for next iteration + aSaveBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP + bufLen, + VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer), ALIGN(panShift, 4)); + } + + aAddMixer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, dest, (bufLen + 0x3f) & 0xffc0); + + return cmd; +} +#endif diff --git a/src/game/decompress.s b/src/boot/decompress.s similarity index 100% rename from src/game/decompress.s rename to src/boot/decompress.s diff --git a/src/game/main.c b/src/boot/main.c similarity index 95% rename from src/game/main.c rename to src/boot/main.c index 3e62b774..d27d0b5a 100644 --- a/src/game/main.c +++ b/src/boot/main.c @@ -5,19 +5,20 @@ #include "sm64.h" #include "audio/external.h" -#include "game_init.h" -#include "memory.h" -#include "sound_init.h" -#include "profiler.h" +#include "game/game_init.h" +#include "game/memory.h" +#include "game/sound_init.h" +#include "game/profiler.h" #include "buffers/buffers.h" #include "segments.h" -#include "main.h" -#include "rumble_init.h" -#include "version.h" +#include "game/main.h" +#include "game/rumble_init.h" +#include "game/version.h" #ifdef UNF #include "usb/usb.h" #include "usb/debug.h" #endif +#include "game/puppyprint.h" // Message IDs #define MESG_SP_COMPLETE 100 @@ -33,7 +34,7 @@ OSThread gGameLoopThread; OSThread gSoundThread; OSIoMesg gDmaIoMesg; -OSMesg D_80339BEC; +OSMesg gMainReceivedMesg; OSMesgQueue gDmaMesgQueue; OSMesgQueue gSIEventMesgQueue; @@ -60,7 +61,7 @@ struct SPTask *sNextDisplaySPTask = NULL; s8 sAudioEnabled = TRUE; u32 gNumVblanks = 0; s8 gResetTimer = 0; -s8 D_8032C648 = 0; +s8 gNmiResetBarsTimer = 0; s8 gDebugLevelSelect = FALSE; s8 gShowProfiler = FALSE; @@ -128,7 +129,7 @@ extern void func_sh_802f69cc(void); void handle_nmi_request(void) { gResetTimer = 1; - D_8032C648 = 0; + gNmiResetBarsTimer = 0; stop_sounds_in_continuous_banks(); sound_banks_disable(SEQ_PLAYER_SFX, SOUND_BANKS_BACKGROUND); fadeout_music(90); @@ -188,6 +189,9 @@ void start_gfx_sptask(void) { if (gActiveSPTask == NULL && sCurrentDisplaySPTask != NULL && sCurrentDisplaySPTask->state == SPTASK_STATE_NOT_STARTED) { profiler_log_gfx_time(TASKS_QUEUED); + #if PUPPYPRINT_DEBUG + rspDelta = osGetTime(); + #endif start_sptask(M_GFXTASK); } } @@ -233,6 +237,9 @@ void handle_vblank(void) { if (gActiveSPTask == NULL && sCurrentDisplaySPTask != NULL && sCurrentDisplaySPTask->state != SPTASK_STATE_FINISHED) { profiler_log_gfx_time(TASKS_QUEUED); + #if PUPPYPRINT_DEBUG + rspDelta = osGetTime(); + #endif start_sptask(M_GFXTASK); } } @@ -265,6 +272,9 @@ void handle_sp_complete(void) { // The gfx task completed before we had time to interrupt it. // Mark it finished, just like below. curSPTask->state = SPTASK_STATE_FINISHED; + #if PUPPYPRINT_DEBUG + profiler_update(rspGenTime, rspDelta); + #endif profiler_log_gfx_time(RSP_COMPLETE); } @@ -295,6 +305,9 @@ void handle_sp_complete(void) { // The SP process is done, but there is still a Display Processor notification // that needs to arrive before we can consider the task completely finished and // null out sCurrentDisplaySPTask. That happens in handle_dp_complete. + #if PUPPYPRINT_DEBUG + profiler_update(rspGenTime, rspDelta); + #endif profiler_log_gfx_time(RSP_COMPLETE); } } @@ -386,7 +399,7 @@ void dispatch_audio_sptask(struct SPTask *spTask) { } } -void send_display_list(struct SPTask *spTask) { +void exec_display_list(struct SPTask *spTask) { if (spTask != NULL) { osWritebackDCacheAll(); spTask->state = SPTASK_STATE_NOT_STARTED; @@ -490,10 +503,10 @@ extern u32 gISVFlag; void osInitialize_fakeisv() { /* global flag to skip `__checkHardware_isv` from being called. */ gISVFlag = 0x49533634; // 'IS64' - + /* printf writes go to this address, cen64(1) has this hardcoded. */ gISVDbgPrnAdrs = 0x13FF0000; - + /* `__printfunc`, used by `osSyncPrintf` will be set. */ __osInitialize_isv(); } diff --git a/src/game/memory.c b/src/boot/memory.c similarity index 81% rename from src/game/memory.c rename to src/boot/memory.c index c2d63b4e..8dc7d7a4 100644 --- a/src/game/memory.c +++ b/src/boot/memory.c @@ -6,9 +6,9 @@ #include "buffers/buffers.h" #include "slidec.h" -#include "game_init.h" -#include "main.h" -#include "memory.h" +#include "game/game_init.h" +#include "game/main.h" +#include "game/memory.h" #include "segment_symbols.h" #include "segments.h" #ifdef GZIP @@ -21,6 +21,7 @@ #include "usb/usb.h" #include "usb/debug.h" #endif +#include "game/puppyprint.h" // round up to the next multiple @@ -134,6 +135,9 @@ void main_pool_init(void *start, void *end) { sPoolListHeadL->next = NULL; sPoolListHeadR->prev = NULL; sPoolListHeadR->next = NULL; + #if PUPPYPRINT_DEBUG + mempool = sPoolFreeSpace; + #endif } /** @@ -256,6 +260,9 @@ u32 main_pool_pop_state(void) { */ void dma_read(u8 *dest, u8 *srcStart, u8 *srcEnd) { u32 size = ALIGN16(srcEnd - srcStart); + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif osInvalDCache(dest, size); while (size != 0) { @@ -263,40 +270,94 @@ void dma_read(u8 *dest, u8 *srcStart, u8 *srcEnd) { osPiStartDma(&gDmaIoMesg, OS_MESG_PRI_NORMAL, OS_READ, (uintptr_t) srcStart, dest, copySize, &gDmaMesgQueue); - osRecvMesg(&gDmaMesgQueue, &D_80339BEC, OS_MESG_BLOCK); + osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK); dest += copySize; srcStart += copySize; size -= copySize; } + #if PUPPYPRINT_DEBUG + dmaTime[perfIteration] += osGetTime()-first; + #endif } /** * Perform a DMA read from ROM, allocating space in the memory pool to write to. * Return the destination address. */ -static void *dynamic_dma_read(u8 *srcStart, u8 *srcEnd, u32 side) { +void *dynamic_dma_read(u8 *srcStart, u8 *srcEnd, u32 side, u32 alignment, u32 bssLength) { void *dest; u32 size = ALIGN16(srcEnd - srcStart); + u32 offset = 0; - dest = main_pool_alloc(size, side); + if (alignment && side == MEMORY_POOL_LEFT) + { + offset = ALIGN((uintptr_t)sPoolListHeadL + 16, alignment) - ((uintptr_t)sPoolListHeadL + 16); + } + + dest = main_pool_alloc(offset + size + bssLength, side); if (dest != NULL) { - dma_read(dest, srcStart, srcEnd); + dma_read((u8 *)dest + offset, srcStart, srcEnd); + if (bssLength) + bzero((u8 *)dest + offset + size, bssLength); } return dest; } +#define TLB_PAGE_SIZE 4096 //Blocksize of TLB transfers. Larger values can be faster to transfer, but more wasteful of RAM. +s32 gTlbEntries = 0; +u8 gTlbSegments[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +void mapTLBPages(uintptr_t virtualAddress, uintptr_t physicalAddress, s32 length, s32 segment) +{ + while (length > 0) + { + if (length > TLB_PAGE_SIZE) + { + osMapTLB(gTlbEntries++, OS_PM_4K, (void *)virtualAddress, physicalAddress, physicalAddress + TLB_PAGE_SIZE, -1); + virtualAddress += TLB_PAGE_SIZE; + physicalAddress += TLB_PAGE_SIZE; + length -= TLB_PAGE_SIZE; + gTlbSegments[segment]++; + } + else + { + osMapTLB(gTlbEntries++, OS_PM_4K, (void *)virtualAddress, physicalAddress, -1, -1); + gTlbSegments[segment]++; + } + virtualAddress += TLB_PAGE_SIZE; + physicalAddress += TLB_PAGE_SIZE; + length -= TLB_PAGE_SIZE; + } +} + #ifndef NO_SEGMENTED_MEMORY /** * Load data from ROM into a newly allocated block, and set the segment base * address to this block. */ -void *load_segment(s32 segment, u8 *srcStart, u8 *srcEnd, u32 side) { - void *addr = dynamic_dma_read(srcStart, srcEnd, side); +void *load_segment(s32 segment, u8 *srcStart, u8 *srcEnd, u32 side, u8 *bssStart, u8 *bssEnd) { + void *addr; - if (addr != NULL) { - set_segment_base_addr(segment, addr); + if (bssStart != NULL && side == MEMORY_POOL_LEFT) + { + addr = dynamic_dma_read(srcStart, srcEnd, side, TLB_PAGE_SIZE, (uintptr_t)bssEnd - (uintptr_t)bssStart); + if (addr != NULL) { + u8 *realAddr = (u8 *)ALIGN((uintptr_t)addr, TLB_PAGE_SIZE); + set_segment_base_addr(segment, realAddr); + mapTLBPages(segment << 24, VIRTUAL_TO_PHYSICAL(realAddr), (srcEnd - srcStart) + ((uintptr_t)bssEnd - (uintptr_t)bssStart), segment); + } } + else + { + addr = dynamic_dma_read(srcStart, srcEnd, side, 0, 0); + if (addr != NULL) { + set_segment_base_addr(segment, addr); + } + } + #if PUPPYPRINT_DEBUG + ramsizeSegment[segment+nameTable-2] = (s32)srcEnd- (s32)srcStart; + #endif return addr; } @@ -374,6 +435,9 @@ void *load_segment_decompress(s32 segment, u8 *srcStart, u8 *srcEnd) { } } else { } + #if PUPPYPRINT_DEBUG + ramsizeSegment[segment+nameTable-2] = (s32)srcEnd - (s32)srcStart; + #endif return dest; } @@ -588,41 +652,37 @@ void *alloc_display_list(u32 size) { return ptr; } -static struct MarioAnimDmaRelatedThing *func_802789F0(u8 *srcAddr) { - struct MarioAnimDmaRelatedThing *sp1C = dynamic_dma_read(srcAddr, srcAddr + sizeof(u32), - MEMORY_POOL_LEFT); - u32 size = sizeof(u32) + (sizeof(u8 *) - sizeof(u32)) + sizeof(u8 *) + - sp1C->count * sizeof(struct OffsetSizePair); - main_pool_free(sp1C); +static struct DmaTable *load_dma_table_address(u8 *srcAddr) { + struct DmaTable *table = dynamic_dma_read(srcAddr, srcAddr + sizeof(u32), + MEMORY_POOL_LEFT, 0, 0); + u32 size = table->count * sizeof(struct OffsetSizePair) + + sizeof(struct DmaTable) - sizeof(struct OffsetSizePair); + main_pool_free(table); - sp1C = dynamic_dma_read(srcAddr, srcAddr + size, MEMORY_POOL_LEFT); - sp1C->srcAddr = srcAddr; - return sp1C; + table = dynamic_dma_read(srcAddr, srcAddr + size, MEMORY_POOL_LEFT, 0, 0); + table->srcAddr = srcAddr; + return table; } -void func_80278A78(struct MarioAnimation *a, void *b, struct Animation *target) { - if (b != NULL) { - a->animDmaTable = func_802789F0(b); +void setup_dma_table_list(struct DmaHandlerList *list, void *srcAddr, void *buffer) { + if (srcAddr != NULL) { + list->dmaTable = load_dma_table_address(srcAddr); } - a->currentAnimAddr = NULL; - a->targetAnim = target; + list->currentAddr = NULL; + list->bufTarget = buffer; } -// TODO: (Scrub C) -s32 load_patchable_table(struct MarioAnimation *a, u32 index) { +s32 load_patchable_table(struct DmaHandlerList *list, s32 index) { s32 ret = FALSE; - struct MarioAnimDmaRelatedThing *sp20 = a->animDmaTable; - u8 *addr; - u32 size; + struct DmaTable *table = list->dmaTable; - if (index < sp20->count) { - do { - addr = sp20->srcAddr + sp20->anim[index].offset; - size = sp20->anim[index].size; - } while (0); - if (a->currentAnimAddr != addr) { - dma_read((u8 *) a->targetAnim, addr, addr + size); - a->currentAnimAddr = addr; + if ((u32)index < table->count) { + u8 *addr = table->srcAddr + table->anim[index].offset; + s32 size = table->anim[index].size; + + if (list->currentAddr != addr) { + dma_read(list->bufTarget, addr, addr + size); + list->currentAddr = addr; ret = TRUE; } } diff --git a/src/game/rnc1.s b/src/boot/rnc1.s similarity index 100% rename from src/game/rnc1.s rename to src/boot/rnc1.s diff --git a/src/game/rnc2.s b/src/boot/rnc2.s similarity index 100% rename from src/game/rnc2.s rename to src/boot/rnc2.s diff --git a/src/game/slidec.h b/src/boot/slidec.h similarity index 100% rename from src/game/slidec.h rename to src/boot/slidec.h diff --git a/src/game/slidec.s b/src/boot/slidec.s similarity index 100% rename from src/game/slidec.s rename to src/boot/slidec.s diff --git a/src/buffers/buffers.c b/src/buffers/buffers.c index d37193e8..a20b7592 100644 --- a/src/buffers/buffers.c +++ b/src/buffers/buffers.c @@ -2,19 +2,15 @@ #include #include "buffers.h" +#include "audio/data.h" #ifdef HVQM #include #endif #include "config.h" +#include "audio/synthesis.h" ALIGNED8 u8 gDecompressionHeap[0xD000]; -#if defined(VERSION_EU) -ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(0x31200) - 0x3800]; -#elif defined(VERSION_SH) -ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(0x31200) - 0x4800]; -#else -ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(0x31200)]; -#endif +ALIGNED16 u8 gAudioHeap[DOUBLE_SIZE_ON_64_BIT(0x31200 + EXT_AUDIO_HEAP_SIZE + EXT_AUDIO_INIT_POOL_SIZE + BETTER_REVERB_SIZE)]; ALIGNED8 u8 gIdleThreadStack[0x800]; ALIGNED8 u8 gThread3Stack[0x2000]; @@ -24,10 +20,15 @@ ALIGNED8 u8 gThread5Stack[0x2000]; ALIGNED8 u8 gThread6Stack[0x2000]; #endif // 0x400 bytes -ALIGNED8 u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8]; +#if UNF +ALIGNED16 u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8]; +ALIGNED16 u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE]; +#else // 0xc00 bytes for f3dex, 0x900 otherwise +ALIGNED8 u8 gGfxSPTaskStack[SP_DRAM_STACK_SIZE8]; ALIGNED8 u8 gGfxSPTaskYieldBuffer[OS_YIELD_DATA_SIZE]; +#endif // UNF // 0x200 bytes -ALIGNED8 struct SaveBuffer gSaveBuffer; +struct SaveBuffer __attribute__ ((aligned (8))) gSaveBuffer; // 0x190a0 bytes struct GfxPool gGfxPools[2]; diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index cc39e5a2..5617e5b9 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -31,7 +31,7 @@ static u16 gRandomSeed16; // Unused function that directly jumps to a behavior command and resets the object's stack index. -static void goto_behavior_unused(const BehaviorScript *bhvAddr) { +UNUSED static void goto_behavior_unused(const BehaviorScript *bhvAddr) { gCurBhvCommand = segmented_to_virtual(bhvAddr); gCurrentObject->bhvStackIndex = 0; } @@ -107,7 +107,7 @@ static uintptr_t cur_obj_bhv_stack_pop(void) { return bhvAddr; } -static void stub_behavior_script_1(void) { +UNUSED static void stub_behavior_script_1(void) { for (;;) { ; } @@ -687,7 +687,7 @@ static s32 bhv_cmd_begin(void) { // It cannot be simply re-added to the table, as unlike all other bhv commands it takes a parameter. // Theoretically this command would have been of variable size. // Included below is a modified/repaired version of this function that would work properly. -static void bhv_cmd_set_int_random_from_table(s32 tableSize) { +UNUSED static void bhv_cmd_set_int_random_from_table(s32 tableSize) { u8 field = BHV_CMD_GET_2ND_U8(0); s32 table[16]; s32 i; diff --git a/src/engine/extended_bounds.h b/src/engine/extended_bounds.h index 3acb24c7..591a183e 100644 --- a/src/engine/extended_bounds.h +++ b/src/engine/extended_bounds.h @@ -21,10 +21,10 @@ level boundaries are 4 times as big (-32768 to 32767) Collision calculations remain as fast as vanilla, at the cost of using far more RAM (16 times vanilla). 64x64 collision cells. - - If you see "SURFACE POOL FULL" or "SURFACE NODE POOL FULL" in game, you should increase - SURFACE_POOL_SIZE or SURFACE_NODE_POOL_SIZE, respectively, or reduce the amount of + + If you see "SURFACE POOL FULL" or "SURFACE NODE POOL FULL" in game, you should increase + SURFACE_POOL_SIZE or SURFACE_NODE_POOL_SIZE, respectively, or reduce the amount of collision surfaces in your level. */ @@ -55,22 +55,18 @@ #undef LEVEL_BOUNDARY_MAX // Undefine the old value to avoid compiler warnings #define LEVEL_BOUNDARY_MAX 0x2000L #define CELL_SIZE 0x400 - #define WORLD_SCALE 1.f #elif EXTENDED_BOUNDS_MODE == 1 #undef LEVEL_BOUNDARY_MAX #define LEVEL_BOUNDARY_MAX 0x4000L #define CELL_SIZE 0x400 - #define WORLD_SCALE 2.f #elif EXTENDED_BOUNDS_MODE == 2 #undef LEVEL_BOUNDARY_MAX #define LEVEL_BOUNDARY_MAX 0x2000L #define CELL_SIZE 0x200 - #define WORLD_SCALE 1.f #elif EXTENDED_BOUNDS_MODE == 3 #undef LEVEL_BOUNDARY_MAX #define LEVEL_BOUNDARY_MAX 0x8000L #define CELL_SIZE 0x400 - #define WORLD_SCALE 4.f #endif STATIC_ASSERT(LEVEL_BOUNDARY_MAX != 0, "You must set a valid extended bounds mode!"); diff --git a/src/engine/graph_node.h b/src/engine/graph_node.h index c8d48f89..89276f59 100644 --- a/src/engine/graph_node.h +++ b/src/engine/graph_node.h @@ -17,9 +17,6 @@ // Whether the node type has a function pointer of type GraphNodeFunc #define GRAPH_NODE_TYPE_FUNCTIONAL 0x100 -// Type used for Bowser and an unused geo function in obj_behaviors.c -#define GRAPH_NODE_TYPE_400 0x400 - // The discriminant for different types of geo nodes #define GRAPH_NODE_TYPE_ROOT 0x001 #define GRAPH_NODE_TYPE_ORTHO_PROJECTION 0x002 diff --git a/src/engine/level_script.c b/src/engine/level_script.c index c6131953..97c06e93 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -24,6 +24,7 @@ #include "math_util.h" #include "surface_collision.h" #include "surface_load.h" +#include "game/puppycam2.h" #include "config.h" @@ -92,7 +93,7 @@ static s32 eval_script_op(s8 op, s32 arg) { static void level_cmd_load_and_execute(void) { main_pool_push_state(); - load_segment(CMD_GET(s16, 2), CMD_GET(void *, 4), CMD_GET(void *, 8), MEMORY_POOL_LEFT); + load_segment(CMD_GET(s16, 2), CMD_GET(void *, 4), CMD_GET(void *, 8), MEMORY_POOL_LEFT, CMD_GET(void *, 16), CMD_GET(void *, 20)); *sStackTop++ = (uintptr_t) NEXT_CMD; *sStackTop++ = (uintptr_t) sStackBase; @@ -108,7 +109,7 @@ static void level_cmd_exit_and_execute(void) { main_pool_push_state(); load_segment(CMD_GET(s16, 2), CMD_GET(void *, 4), CMD_GET(void *, 8), - MEMORY_POOL_LEFT); + MEMORY_POOL_LEFT, CMD_GET(void *, 16), CMD_GET(void *, 20)); sStackTop = sStackBase; sCurrentCmd = segmented_to_virtual(targetAddr); @@ -273,7 +274,7 @@ static void level_cmd_load_to_fixed_address(void) { static void level_cmd_load_raw(void) { load_segment(CMD_GET(s16, 2), CMD_GET(void *, 4), CMD_GET(void *, 8), - MEMORY_POOL_LEFT); + MEMORY_POOL_LEFT, CMD_GET(void *, 12), CMD_GET(void *, 16)); sCurrentCmd = CMD_NEXT; } @@ -323,11 +324,36 @@ static void level_cmd_init_level(void) { sCurrentCmd = CMD_NEXT; } +extern s32 gTlbEntries; +extern u8 gTlbSegments[32]; + +//This clears all the temporary bank TLB maps. group0, common1 and behavourdata are always loaded, +//and they're also loaded first, so that means we just leave the first 3 indexes mapped. +void unmap_tlbs(void) +{ + s32 i; + for (i = 0; i < 32; i++) + { + if (gTlbSegments[i] && i != 0x17 && i != 0x16 && i != 0x13) + { + while (gTlbSegments[i] > 0) + { + osUnmapTLB(gTlbEntries); + gTlbSegments[i]--; + gTlbEntries--; + } + + } + + } +} + static void level_cmd_clear_level(void) { clear_objects(); clear_area_graph_nodes(); clear_areas(); main_pool_pop_state(); + unmap_tlbs(); sCurrentCmd = CMD_NEXT; } @@ -768,6 +794,43 @@ static void level_cmd_get_or_set_var(void) { sCurrentCmd = CMD_NEXT; } +static void level_cmd_puppyvolume(void) +{ +#ifdef PUPPYCAM + if ((sPuppyVolumeStack[gPuppyVolumeCount] = mem_pool_alloc(gPuppyMemoryPool,sizeof(struct sPuppyVolume))) == NULL) + { + sCurrentCmd = CMD_NEXT; + gPuppyError |= PUPPY_ERROR_POOL_FULL; + return; + } + + sPuppyVolumeStack[gPuppyVolumeCount]->pos[0] = CMD_GET(s16, 2); + sPuppyVolumeStack[gPuppyVolumeCount]->pos[1] = CMD_GET(s16, 4); + sPuppyVolumeStack[gPuppyVolumeCount]->pos[2] = CMD_GET(s16, 6); + + sPuppyVolumeStack[gPuppyVolumeCount]->radius[0] = CMD_GET(s16, 8); + sPuppyVolumeStack[gPuppyVolumeCount]->radius[1] = CMD_GET(s16, 10); + sPuppyVolumeStack[gPuppyVolumeCount]->radius[2] = CMD_GET(s16, 12); + + sPuppyVolumeStack[gPuppyVolumeCount]->rot = CMD_GET(s16, 14); + + sPuppyVolumeStack[gPuppyVolumeCount]->func = CMD_GET(void *, 16); + sPuppyVolumeStack[gPuppyVolumeCount]->angles = segmented_to_virtual(CMD_GET(void *, 20)); + + sPuppyVolumeStack[gPuppyVolumeCount]->flagsAdd = CMD_GET(s32, 24); + sPuppyVolumeStack[gPuppyVolumeCount]->flagsRemove = CMD_GET(s32, 28); + + sPuppyVolumeStack[gPuppyVolumeCount]->flagPersistance = CMD_GET(u8, 32); + + sPuppyVolumeStack[gPuppyVolumeCount]->shape = CMD_GET(u8, 33); + sPuppyVolumeStack[gPuppyVolumeCount]->room = CMD_GET(s16, 34); + + gPuppyVolumeCount++; +#endif + sCurrentCmd = CMD_NEXT; +} + + static void (*LevelScriptJumpTable[])(void) = { /*00*/ level_cmd_load_and_execute, /*01*/ level_cmd_exit_and_execute, @@ -830,7 +893,8 @@ static void (*LevelScriptJumpTable[])(void) = { /*3A*/ level_cmd_3A, /*3B*/ level_cmd_create_whirlpool, /*3C*/ level_cmd_get_or_set_var, - /*3D*/ level_cmd_change_area_skybox, + /*3D*/ level_cmd_puppyvolume, + /*3E*/ level_cmd_change_area_skybox, }; struct LevelCommand *level_script_execute(struct LevelCommand *cmd) { @@ -842,7 +906,7 @@ struct LevelCommand *level_script_execute(struct LevelCommand *cmd) { } profiler_log_thread5_time(LEVEL_SCRIPT_EXECUTE); - init_render_image(); + init_rcp(); render_game(); end_master_display_list(); alloc_display_list(0); diff --git a/src/engine/math_util.c b/src/engine/math_util.c index eb61fb90..25db470f 100644 --- a/src/engine/math_util.c +++ b/src/engine/math_util.c @@ -6,9 +6,15 @@ #include "surface_collision.h" #include "extended_bounds.h" #include "trig_tables.inc.c" +#include "surface_load.h" +#include "game/puppyprint.h" +#include "game/rendering_graph_node.h" #include "config.h" +#define RAY_OFFSET 30.0f /*How many units to extrapolate surfaces when testing for a raycast*/ +#define RAY_STEPS 4 /*How many steps to do when casting rays, default to quartersteps.*/ + // Variables for a spline curve animation (used for the flight path in the grand star cutscene) Vec4s *gSplineKeyframe; float gSplineKeyframeFraction; @@ -17,7 +23,14 @@ int gSplineState; // These functions have bogus return values. // Disable the compiler warning. #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wreturn-local-addr" + +#ifdef __GNUC__ +#if defined(__clang__) + #pragma GCC diagnostic ignored "-Wreturn-stack-address" +#else + #pragma GCC diagnostic ignored "-Wreturn-local-addr" +#endif +#endif /// Copy vector 'src' to 'dest' void *vec3f_copy(Vec3f dest, Vec3f src) { @@ -203,7 +216,7 @@ void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s16 roll) { dx = to[0] - from[0]; dz = to[2] - from[2]; - invLength = -1.0 / sqrtf(dx * dx + dz * dz); + invLength = -1.0f / MAX(sqrtf(dx * dx + dz * dz), 0.00001f); dx *= invLength; dz *= invLength; @@ -215,7 +228,7 @@ void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s16 roll) { yColZ = to[1] - from[1]; zColZ = to[2] - from[2]; - invLength = -1.0 / sqrtf(xColZ * xColZ + yColZ * yColZ + zColZ * zColZ); + invLength = -1.0f / MAX(sqrtf(xColZ * xColZ + yColZ * yColZ + zColZ * zColZ), 0.00001f); xColZ *= invLength; yColZ *= invLength; zColZ *= invLength; @@ -224,7 +237,7 @@ void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s16 roll) { yColX = zColY * xColZ - xColY * zColZ; zColX = xColY * yColZ - yColY * xColZ; - invLength = 1.0 / sqrtf(xColX * xColX + yColX * yColX + zColX * zColX); + invLength = 1.0f / MAX(sqrtf(xColX * xColX + yColX * yColX + zColX * zColX), 0.00001f); xColX *= invLength; yColX *= invLength; @@ -234,7 +247,7 @@ void mtxf_lookat(Mat4 mtx, Vec3f from, Vec3f to, s16 roll) { yColY = zColZ * xColX - xColZ * zColX; zColY = xColZ * yColX - yColZ * xColX; - invLength = 1.0 / sqrtf(xColY * xColY + yColY * yColY + zColY * zColY); + invLength = 1.0f / MAX(sqrtf(xColY * xColY + yColY * yColY + zColY * zColY), 0.00001f); xColY *= invLength; yColY *= invLength; zColY *= invLength; @@ -568,10 +581,10 @@ void mtxf_mul_vec3s(Mat4 mtx, Vec3s b) { void mtxf_to_mtx(Mtx *dest, Mat4 src) { Mat4 temp; register s32 i, j; - + for( i = 0; i < 4; i++ ) { for( j = 0; j < 3; j++ ) { - temp[i][j] = src[i][j] / WORLD_SCALE; + temp[i][j] = src[i][j] / gWorldScale; } temp[i][3] = src[i][3]; } @@ -867,3 +880,231 @@ s32 anim_spline_poll(Vec3f result) { return hasEnded; } + +/// Multiply vector 'dest' by a +void *vec3f_mul(Vec3f dest, f32 a) +{ + dest[0] *= a; + dest[1] *= a; + dest[2] *= a; + return dest; //! warning: function returns address of local variable +} + +/// Get length of vector 'a' +f32 vec3f_length(Vec3f a) +{ + return sqrtf(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); +} + +/// Get dot product of vectors 'a' and 'b' +f32 vec3f_dot(Vec3f a, Vec3f b) +{ + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +/// Make 'dest' the difference of vectors a and b. +void *vec3f_dif(Vec3f dest, Vec3f a, Vec3f b) { + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; + dest[2] = a[2] - b[2]; + return dest; //! warning: function returns address of local variable +} + +//Raycasting +s32 ray_surface_intersect(Vec3f orig, Vec3f dir, f32 dir_length, struct Surface *surface, Vec3f hit_pos, f32 *length) +{ + Vec3f v0, v1, v2, e1, e2, h, s, q; + f32 a, f, u, v; + Vec3f add_dir; + Vec3f norm; + + //Ignore certain surface types. + if (surface->type == SURFACE_INTANGIBLE || surface->flags & SURFACE_FLAG_NO_CAM_COLLISION) + return FALSE; + + // Get surface normal and some other stuff + norm[0] = 0; + norm[1] = surface->normal.y; + norm[2] = 0; + vec3f_mul(norm,RAY_OFFSET); + + vec3s_to_vec3f(v0, surface->vertex1); + vec3s_to_vec3f(v1, surface->vertex2); + vec3s_to_vec3f(v2, surface->vertex3); + + vec3f_add(v0, norm); + vec3f_add(v1, norm); + vec3f_add(v2, norm); + + vec3f_dif(e1, v1, v0); + vec3f_dif(e2, v2, v0); + + vec3f_cross(h, dir, e2); + + // Check if we're perpendicular from the surface + a = vec3f_dot(e1, h); + if (a > -0.00001f && a < 0.00001f) + return FALSE; + + // Check if we're making contact with the surface + f = 1.0f / a; + + vec3f_dif(s, orig, v0); + u = f * vec3f_dot(s, h); + if (u < 0.0f || u > 1.0f) + return FALSE; + + vec3f_cross(q, s, e1); + v = f * vec3f_dot(dir, q); + if (v < 0.0f || u + v > 1.0f) + return FALSE; + + // Get the length between our origin and the surface contact point + *length = f * vec3f_dot(e2, q); + if (*length <= 0.00001 || *length > dir_length) + return FALSE; + + // Successful contact + vec3f_copy(add_dir, dir); + vec3f_mul(add_dir, *length); + vec3f_sum(hit_pos, orig, add_dir); + return TRUE; +} + +void find_surface_on_ray_list(struct SurfaceNode *list, Vec3f orig, Vec3f dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length) +{ + s32 hit; + f32 length; + Vec3f chk_hit_pos; + f32 top, bottom; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif + + // Get upper and lower bounds of ray + if (dir[1] >= 0.0f) + { + top = orig[1] + dir[1] * dir_length; + bottom = orig[1]; + } + else + { + top = orig[1]; + bottom = orig[1] + dir[1] * dir_length; + } + + // Iterate through every surface of the list + for (; list != NULL; list = list->next) + { + // Reject surface if out of vertical bounds + if (list->surface->lowerY > top || list->surface->upperY < bottom) + continue; + + // Check intersection between the ray and this surface + if ((hit = ray_surface_intersect(orig, dir, dir_length, list->surface, chk_hit_pos, &length)) != 0) + { + if (length <= *max_length) + { + *hit_surface = list->surface; + vec3f_copy(hit_pos, chk_hit_pos); + *max_length = length; + } + } + } + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif +} + +void find_surface_on_ray_cell(s16 cellX, s16 cellZ, Vec3f orig, Vec3f normalized_dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length, s32 flags) +{ + // Skip if OOB + if (cellX >= 0 && cellX <= (NUM_CELLS - 1) && cellZ >= 0 && cellZ <= (NUM_CELLS - 1)) + { + // Iterate through each surface in this partition + if (normalized_dir[1] > -0.99999f && flags & RAYCAST_FIND_CEIL) + { + find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + } + if (normalized_dir[1] < 0.99999f && flags & RAYCAST_FIND_FLOOR) + { + find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + } + if (flags & RAYCAST_FIND_WALL) + { + find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + } + if (flags & RAYCAST_FIND_WATER) + { + find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + } + } +} + +void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, s32 flags) +{ + f32 max_length; + s32 cellZ, cellX, cellPrevX, cellPrevZ; + f32 fCellZ, fCellX; + f32 dir_length; + Vec3f normalized_dir; + f32 step, dx, dz; + s32 i; + + // Set that no surface has been hit + *hit_surface = NULL; + vec3f_sum(hit_pos, orig, dir); + + // Get normalized direction + dir_length = vec3f_length(dir); + max_length = dir_length; + vec3f_copy(normalized_dir, dir); + vec3f_normalize(normalized_dir); + + // Get our cell coordinate + fCellX = (orig[0] + LEVEL_BOUNDARY_MAX) / CELL_SIZE; + fCellZ = (orig[2] + LEVEL_BOUNDARY_MAX) / CELL_SIZE; + cellX = fCellX; + cellZ = fCellZ; + cellPrevX = cellX; + cellPrevZ = cellZ; + + // Don't do DDA if straight down + if (normalized_dir[1] >= 0.99999f || normalized_dir[1] <= -0.99999f) + { + find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags); + return; + } + + // Get cells we cross using DDA + if (ABS(dir[0]) >= ABS(dir[2])) + step = RAY_STEPS*ABS(dir[0]) / CELL_SIZE; + else + step = RAY_STEPS*ABS(dir[2]) / CELL_SIZE; + + dx = dir[0] / step / CELL_SIZE; + dz = dir[2] / step / CELL_SIZE; + + for (i = 0; i < step && *hit_surface == NULL; i++) + { + find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags); + + // Move cell coordinate + fCellX += dx; + fCellZ += dz; + cellPrevX = cellX; + cellPrevZ = cellZ; + cellX = fCellX; + cellZ = fCellZ; + + if ((cellPrevX != cellX) && (cellPrevZ != cellZ)) + { + find_surface_on_ray_cell(cellX, cellPrevZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags); + find_surface_on_ray_cell(cellPrevX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length, flags); + } + } +} diff --git a/src/engine/math_util.h b/src/engine/math_util.h index 2938061c..5cfac85b 100644 --- a/src/engine/math_util.h +++ b/src/engine/math_util.h @@ -31,9 +31,17 @@ extern f32 gCosineTable[]; #define min(a, b) ((a) <= (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#define ABS(x) ((x) > 0.f ? (x) : -(x)) #define sqr(x) ((x) * (x)) +#define RAYCAST_FIND_FLOOR (0x1) +#define RAYCAST_FIND_WALL (0x2) +#define RAYCAST_FIND_CEIL (0x4) +#define RAYCAST_FIND_WATER (0x8) +#define RAYCAST_FIND_ALL (0xFFFFFFFF) + void *vec3f_copy(Vec3f dest, Vec3f src); void *vec3f_set(Vec3f dest, f32 x, f32 y, f32 z); void *vec3f_add(Vec3f dest, Vec3f a); @@ -72,5 +80,6 @@ f32 atan2f(f32 a, f32 b); void spline_get_weights(Vec4f result, f32 t, UNUSED s32 c); void anim_spline_init(Vec4s *keyFrames); s32 anim_spline_poll(Vec3f result); +extern void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos, s32 flags); #endif // MATH_UTIL_H diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 8b28e708..93654597 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -7,6 +7,7 @@ #include "game/object_list_processor.h" #include "surface_collision.h" #include "surface_load.h" +#include "game/puppyprint.h" /************************************************** * WALLS * @@ -183,10 +184,13 @@ s32 f32_find_wall_collision(f32 *xPtr, f32 *yPtr, f32 *zPtr, f32 offsetY, f32 ra */ s32 find_wall_collisions(struct WallCollisionData *colData) { struct SurfaceNode *node; - s16 cellX, cellZ; + s32 cellX, cellZ; s32 numCollisions = 0; - s16 x = colData->x; - s16 z = colData->z; + s32 x = colData->x; + s32 z = colData->z; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif colData->numWalls = 0; @@ -213,6 +217,10 @@ s32 find_wall_collisions(struct WallCollisionData *colData) { // Increment the debug tracker. gNumCalls.wall += 1; + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif + return numCollisions; } @@ -263,7 +271,7 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 nx = surf->normal.x; ny = surf->normal.y; nz = surf->normal.z; - oo = surf->originOffset; + oo = surf->originOffset; // If a wall, ignore it. Likely a remnant, should never occur. if (ny == 0.0f) { continue; @@ -293,19 +301,19 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 * Find the lowest ceiling above a given position and return the height. */ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { - s16 cellZ, cellX; + s32 cellZ, cellX; struct Surface *ceil, *dynamicCeil; struct SurfaceNode *surfaceList; f32 height = CELL_HEIGHT_LIMIT; f32 dynamicHeight = CELL_HEIGHT_LIMIT; - s16 x, y, z; + s32 x, y, z; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif - //! (Parallel Universes) Because position is casted to an s16, reaching higher - // float locations can return ceilings despite them not existing there. - //(Dynamic ceilings will unload due to the range.) - x = (s16) posX; - y = (s16) posY; - z = (s16) posZ; + x = posX; + y = posY; + z = posZ; *pceil = NULL; if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) { @@ -337,6 +345,10 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { // Increment the debug tracker. gNumCalls.ceil += 1; + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif + return height; } @@ -358,7 +370,7 @@ f32 unused_obj_find_floor_height(struct Object *obj) { */ struct FloorGeometry sFloorGeo; -static u8 unused8038BE50[0x40]; +UNUSED static u8 unused8038BE50[0x40]; /** * Return the floor height underneath (xPos, yPos, zPos) and populate `floorGeo` @@ -476,17 +488,17 @@ static f32 get_floor_height_at_location(s32 x, s32 z, struct Surface *surf) { * Iterate through the list of water floors and find the first water floor under a given point. */ struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, - f32 *pheight) { + s32 *pheight) { register struct Surface *surf; struct Surface *floor = NULL; struct SurfaceNode *topSurfaceNode = surfaceNode; struct SurfaceNode *bottomSurfaceNode = surfaceNode; - f32 height = FLOOR_LOWER_LIMIT; - f32 bottomHeight = FLOOR_LOWER_LIMIT; + s32 height = FLOOR_LOWER_LIMIT; + s32 bottomHeight = FLOOR_LOWER_LIMIT; // Iterate through the list of water floors until there are no more water floors. while (bottomSurfaceNode != NULL) { - f32 curBottomHeight = FLOOR_LOWER_LIMIT; + s32 curBottomHeight = FLOOR_LOWER_LIMIT; surf = bottomSurfaceNode->surface; bottomSurfaceNode = bottomSurfaceNode->next; @@ -500,7 +512,7 @@ struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 // Iterate through the list of water tops until there are no more water tops. while (topSurfaceNode != NULL) { - f32 curHeight = FLOOR_LOWER_LIMIT; + s32 curHeight = FLOOR_LOWER_LIMIT; surf = topSurfaceNode->surface; topSurfaceNode = topSurfaceNode->next; @@ -541,13 +553,13 @@ f32 unused_find_dynamic_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfl f32 floorHeight = FLOOR_LOWER_LIMIT; // Would normally cause PUs, but dynamic floors unload at that range. - s16 x = (s16) xPos; - s16 y = (s16) yPos; - s16 z = (s16) zPos; + s32 x = xPos; + s32 y = yPos; + s32 z = zPos; // Each level is split into cells to limit load, find the appropriate cell. - s16 cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - s16 cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + s32 cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + s32 cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; surfaceList = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; floor = find_floor_from_list(surfaceList, x, y, z, &floorHeight); @@ -561,7 +573,10 @@ f32 unused_find_dynamic_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfl * Find the highest floor under a given position and return the height. */ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { - s16 cellZ, cellX; + s32 cellZ, cellX; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif struct Surface *floor, *dynamicFloor; struct SurfaceNode *surfaceList; @@ -572,16 +587,22 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { //! (Parallel Universes) Because position is casted to an s16, reaching higher // float locations can return floors despite them not existing there. //(Dynamic floors will unload due to the range.) - s16 x = (s16) xPos; - s16 y = (s16) yPos; - s16 z = (s16) zPos; + s32 x = xPos; + s32 y = yPos; + s32 z = zPos; *pfloor = NULL; if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) { + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif return height; } if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) { + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif return height; } @@ -628,23 +649,27 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { // Increment the debug tracker. gNumCalls.floor += 1; + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif + return height; } /** * Find the highest water floor under a given position and return the height. */ -f32 find_water_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { - s16 cellZ, cellX; +s32 find_water_floor(s32 xPos, s32 yPos, s32 zPos, struct Surface **pfloor) { + s32 cellZ, cellX; struct Surface *floor = NULL; struct SurfaceNode *surfaceList; - f32 height = FLOOR_LOWER_LIMIT; + s32 height = FLOOR_LOWER_LIMIT; - s16 x = (s16) xPos; - s16 y = (s16) yPos; - s16 z = (s16) zPos; + s32 x = xPos; + s32 y = yPos; + s32 z = zPos; if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) { return height; @@ -677,14 +702,17 @@ f32 find_water_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { /** * Finds the height of water at a given location. */ -f32 find_water_level_and_floor(f32 x, f32 z, struct Surface **pfloor) { +s32 find_water_level_and_floor(s32 x, s32 z, struct Surface **pfloor) { s32 i; s32 numRegions; - s16 val; - f32 loX, hiX, loZ, hiZ; - f32 waterLevel = FLOOR_LOWER_LIMIT; - s16 *p = gEnvironmentRegions; + s32 val; + s32 loX, hiX, loZ, hiZ; + s32 waterLevel = FLOOR_LOWER_LIMIT; + TerrainData *p = gEnvironmentRegions; struct Surface *floor = NULL; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif if (gCheckingSurfaceCollisionsForCamera) { waterLevel = find_water_floor(x, gLakituState.pos[1], z, &floor); @@ -715,20 +743,27 @@ f32 find_water_level_and_floor(f32 x, f32 z, struct Surface **pfloor) { *pfloor = floor; } + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif + return waterLevel; } /** * Finds the height of water at a given location. */ -f32 find_water_level(f32 x, f32 z) { +s32 find_water_level(s32 x, s32 z) { s32 i; s32 numRegions; - s16 val; - f32 loX, hiX, loZ, hiZ; - f32 waterLevel = FLOOR_LOWER_LIMIT; - s16 *p = gEnvironmentRegions; + s32 val; + s32 loX, hiX, loZ, hiZ; + s32 waterLevel = FLOOR_LOWER_LIMIT; + TerrainData *p = gEnvironmentRegions; struct Surface *floor; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif if (gCheckingSurfaceCollisionsForCamera) { waterLevel = find_water_floor(x, gLakituState.pos[1], z, &floor); @@ -757,20 +792,26 @@ f32 find_water_level(f32 x, f32 z) { } } + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif + return waterLevel; } /** * Finds the height of the poison gas (used only in HMC) at a given location. */ -f32 find_poison_gas_level(f32 x, f32 z) { +s32 find_poison_gas_level(s32 x, s32 z) { s32 i; s32 numRegions; - UNUSED s32 unused; - s16 val; - f32 loX, hiX, loZ, hiZ; - f32 gasLevel = FLOOR_LOWER_LIMIT; - s16 *p = gEnvironmentRegions; + s32 val; + s32 loX, hiX, loZ, hiZ; + s32 gasLevel = FLOOR_LOWER_LIMIT; + TerrainData *p = gEnvironmentRegions; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif if (p != NULL) { numRegions = *p++; @@ -797,6 +838,10 @@ f32 find_poison_gas_level(f32 x, f32 z) { } } + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif + return gasLevel; } diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index 86540788..bcd6baf4 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -11,7 +11,7 @@ #define CELL_HEIGHT_LIMIT 20000 #define FLOOR_LOWER_LIMIT -11000 #define FLOOR_LOWER_LIMIT_MISC (FLOOR_LOWER_LIMIT + 1000) -// same as FLOOR_LOWER_LIMIT_MISC, explicitly for shadow.c +// same as FLOOR_LOWER_LIMIT_MISC, explicitly for shadow.c // It doesn't match if ".0" is removed or ".f" is added #define FLOOR_LOWER_LIMIT_SHADOW (FLOOR_LOWER_LIMIT + 1000.0) @@ -40,9 +40,9 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil); f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometry **floorGeo); f32 find_floor_height(f32 x, f32 y, f32 z); f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor); -f32 find_water_level_and_floor(f32 x, f32 z, struct Surface **pfloor); -f32 find_water_level(f32 x, f32 z); -f32 find_poison_gas_level(f32 x, f32 z); +s32 find_water_level_and_floor(s32 x, s32 z, struct Surface **pfloor); +s32 find_water_level(s32 x, s32 z); +s32 find_poison_gas_level(s32 x, s32 z); void debug_surface_list_info(f32 xPos, f32 zPos); #endif // SURFACE_COLLISION_H diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index d2999892..601b8a54 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -14,8 +14,9 @@ #include "game/mario.h" #include "game/object_list_processor.h" #include "surface_load.h" +#include "game/puppyprint.h" -s32 unused8038BE90; +#include "config.h" /** * Partitions for course and object surfaces. The arrays represent @@ -35,8 +36,6 @@ struct Surface *sSurfacePool; */ s16 sSurfacePoolSize; -u8 unused8038EEA8[0x30]; - u8 gSurfacePoolError = 0; /** @@ -113,14 +112,14 @@ static void clear_static_surfaces(void) { * @param cellZ The Z position of the cell in which the surface resides * @param surface The surface to add */ -static void add_surface_to_cell(s16 dynamic, s16 cellX, s16 cellZ, struct Surface *surface) { +static void add_surface_to_cell(s32 dynamic, s32 cellX, s32 cellZ, struct Surface *surface) { struct SurfaceNode *newNode = alloc_surface_node(); struct SurfaceNode *list; - s16 surfacePriority; - s16 priority; - s16 sortDir; - s16 listIndex; - s16 isWater = surface->type == SURFACE_NEW_WATER || surface->type == SURFACE_NEW_WATER_BOTTOM; + s32 surfacePriority; + s32 priority; + s32 sortDir; + s32 listIndex; + s32 isWater = surface->type == SURFACE_NEW_WATER || surface->type == SURFACE_NEW_WATER_BOTTOM; if (surface->normal.y > 0.01) { listIndex = isWater ? SPATIAL_PARTITION_WATER : SPATIAL_PARTITION_FLOORS; @@ -171,7 +170,7 @@ static void add_surface_to_cell(s16 dynamic, s16 cellX, s16 cellZ, struct Surfac /** * Returns the lowest of three values. */ -static s16 min_3(s16 a0, s16 a1, s16 a2) { +static s32 min_3(s32 a0, s32 a1, s32 a2) { if (a1 < a0) { a0 = a1; } @@ -186,7 +185,7 @@ static s16 min_3(s16 a0, s16 a1, s16 a2) { /** * Returns the highest of three values. */ -static s16 max_3(s16 a0, s16 a1, s16 a2) { +static s32 max_3(s32 a0, s32 a1, s32 a2) { if (a1 > a0) { a0 = a1; } @@ -203,8 +202,8 @@ static s16 max_3(s16 a0, s16 a1, s16 a2) { * time). This function determines the lower cell for a given x/z position. * @param coord The coordinate to test */ -static s16 lower_cell_index(s32 coord) { - s16 index; +static s32 lower_cell_index(s32 coord) { + s32 index; // Move from range [-0x2000, 0x2000) to [0, 0x4000) coord += LEVEL_BOUNDARY_MAX; @@ -235,8 +234,8 @@ static s16 lower_cell_index(s32 coord) { * time). This function determines the upper cell for a given x/z position. * @param coord The coordinate to test */ -static s16 upper_cell_index(s32 coord) { - s16 index; +static s32 upper_cell_index(s32 coord) { + s32 index; // Move from range [-0x2000, 0x2000) to [0, 0x4000) coord += LEVEL_BOUNDARY_MAX; @@ -270,15 +269,11 @@ static s16 upper_cell_index(s32 coord) { * @param dynamic Boolean determining whether the surface is static or dynamic */ static void add_surface(struct Surface *surface, s32 dynamic) { - // minY/maxY maybe? s32 instead of s16, though. - UNUSED s32 unused1, unused2; - s16 minX, minZ, maxX, maxZ; + s32 minX, minZ, maxX, maxZ; - s16 minCellX, minCellZ, maxCellX, maxCellZ; + s32 minCellX, minCellZ, maxCellX, maxCellZ; - s16 cellZ, cellX; - // cellY maybe? s32 instead of s16, though. - UNUSED s32 unused3 = 0; + s32 cellZ, cellX; minX = min_3(surface->vertex1[0], surface->vertex2[0], surface->vertex3[0]); minZ = min_3(surface->vertex1[2], surface->vertex2[2], surface->vertex3[2]); @@ -297,15 +292,12 @@ static void add_surface(struct Surface *surface, s32 dynamic) { } } -static void stub_surface_load_1(void) { -} - /** * Initializes a Surface struct using the given vertex data * @param vertexData The raw data containing vertex positions * @param vertexIndices Helper which tells positions in vertexData to start reading vertices */ -static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) { +static struct Surface *read_surface_data(TerrainData *vertexData, TerrainData **vertexIndices) { struct Surface *surface; register s32 x1, y1, z1; register s32 x2, y2, z2; @@ -313,7 +305,7 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) { s32 maxY, minY; f32 nx, ny, nz; f32 mag; - s16 offset1, offset2, offset3; + s32 offset1, offset2, offset3; offset1 = 3 * (*vertexIndices)[0]; offset2 = 3 * (*vertexIndices)[1]; @@ -389,11 +381,12 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) { return surface; } +#ifndef ALL_SURFACES_HAVE_FORCE /** * Returns whether a surface has exertion/moves Mario * based on the surface type. */ -static s32 surface_has_force(s16 surfaceType) { +static s32 surface_has_force(s32 surfaceType) { s32 hasForce = FALSE; switch (surfaceType) { @@ -412,12 +405,13 @@ static s32 surface_has_force(s16 surfaceType) { } return hasForce; } +#endif /** * Returns whether a surface should have the * SURFACE_FLAG_NO_CAM_COLLISION flag. */ -static s32 surf_has_no_cam_collision(s16 surfaceType) { +static s32 surf_has_no_cam_collision(s32 surfaceType) { s32 flags = 0; switch (surfaceType) { @@ -439,13 +433,15 @@ static s32 surf_has_no_cam_collision(s16 surfaceType) { * Load in the surfaces for a given surface type. This includes setting the flags, * exertion, and room. */ -static void load_static_surfaces(s16 **data, s16 *vertexData, s16 surfaceType, s8 **surfaceRooms) { +static void load_static_surfaces(TerrainData **data, TerrainData *vertexData, s32 surfaceType, RoomData **surfaceRooms) { s32 i; s32 numSurfaces; struct Surface *surface; - s8 room = 0; + s32 room = 0; +#ifndef ALL_SURFACES_HAVE_FORCE s16 hasForce = surface_has_force(surfaceType); - s16 flags = surf_has_no_cam_collision(surfaceType); +#endif + s32 flags = surf_has_no_cam_collision(surfaceType); numSurfaces = *(*data); *data += 1; @@ -462,30 +458,36 @@ static void load_static_surfaces(s16 **data, s16 *vertexData, s16 surfaceType, s surface->type = surfaceType; surface->flags = (s8) flags; +#ifdef ALL_SURFACES_HAVE_FORCE + surface->force = *(*data + 3); +#else if (hasForce) { surface->force = *(*data + 3); } else { surface->force = 0; } +#endif add_surface(surface, FALSE); } +#ifdef ALL_SURFACES_HAVE_FORCE + *data += 4; +#else *data += 3; if (hasForce) { *data += 1; } +#endif } } /** * Read the data for vertices for reference by triangles. */ -static s16 *read_vertex_data(s16 **data) { +static TerrainData *read_vertex_data(TerrainData **data) { s32 numVertices; - UNUSED s16 unused1[3]; - UNUSED s16 unused2[3]; - s16 *vertexData; + TerrainData *vertexData; numVertices = *(*data); (*data)++; @@ -499,7 +501,7 @@ static s16 *read_vertex_data(s16 **data) { /** * Loads in special environmental regions, such as water, poison gas, and JRB fog. */ -static void load_environmental_regions(s16 **data) { +static void load_environmental_regions(TerrainData **data) { s32 numRegions; s32 i; @@ -510,8 +512,8 @@ static void load_environmental_regions(s16 **data) { } for (i = 0; i < numRegions; i++) { - UNUSED s16 val, loX, loZ, hiX, hiZ; - s16 height; + UNUSED TerrainData val, loX, loZ, hiX, hiZ; + TerrainData height; val = *(*data)++; @@ -542,14 +544,16 @@ void alloc_surface_pools(void) { /** * Get the size of the terrain data, to get the correct size when copying later. */ -u32 get_area_terrain_size(s16 *data) { - s16 *startPos = data; +u32 get_area_terrain_size(TerrainData *data) { + TerrainData *startPos = data; s32 end = FALSE; - s16 terrainLoadType; + TerrainData terrainLoadType; s32 numVertices; s32 numRegions; s32 numSurfaces; - s16 hasForce; +#ifndef ALL_SURFACES_HAVE_FORCE + TerrainData hasForce; +#endif while (!end) { terrainLoadType = *data++; @@ -578,8 +582,12 @@ u32 get_area_terrain_size(s16 *data) { default: numSurfaces = *data++; +#ifdef ALL_SURFACES_HAVE_FORCE + data += 4 * numSurfaces; +#else hasForce = surface_has_force(terrainLoadType); data += (3 + hasForce) * numSurfaces; +#endif break; } } @@ -593,14 +601,15 @@ u32 get_area_terrain_size(s16 *data) { * Process the level file, loading in vertices, surfaces, some objects, and environmental * boxes (water, gas, JRB fog). */ -void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects) { - s16 terrainLoadType; - s16 *vertexData; - UNUSED s32 unused; +void load_area_terrain(s32 index, TerrainData *data, RoomData *surfaceRooms, s16 *macroObjects) { + s32 terrainLoadType; + TerrainData *vertexData = NULL; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif // Initialize the data for this. gEnvironmentRegions = NULL; - unused8038BE90 = 0; gSurfaceNodesAllocated = 0; gSurfacesAllocated = 0; @@ -645,6 +654,9 @@ void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects gNumStaticSurfaceNodes = gSurfaceNodesAllocated; gNumStaticSurfaces = gSurfacesAllocated; + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif } /** @@ -659,14 +671,11 @@ void clear_dynamic_surfaces(void) { } } -static void unused_80383604(void) { -} - /** * Applies an object's transformation to the object's vertices. */ -void transform_object_vertices(s16 **data, s16 *vertexData) { - register s16 *vertices; +void transform_object_vertices(TerrainData **data, TerrainData *vertexData) { + register TerrainData *vertices; register f32 vx, vy, vz; register s32 numVertices; @@ -694,9 +703,9 @@ void transform_object_vertices(s16 **data, s16 *vertexData) { vz = *(vertices++); //! No bounds check on vertex data - *vertexData++ = (s16)(vx * m[0][0] + vy * m[1][0] + vz * m[2][0] + m[3][0]); - *vertexData++ = (s16)(vx * m[0][1] + vy * m[1][1] + vz * m[2][1] + m[3][1]); - *vertexData++ = (s16)(vx * m[0][2] + vy * m[1][2] + vz * m[2][2] + m[3][2]); + *vertexData++ = (TerrainData)(vx * m[0][0] + vy * m[1][0] + vz * m[2][0] + m[3][0]); + *vertexData++ = (TerrainData)(vx * m[0][1] + vy * m[1][1] + vz * m[2][1] + m[3][1]); + *vertexData++ = (TerrainData)(vx * m[0][2] + vy * m[1][2] + vz * m[2][2] + m[3][2]); } *data = vertices; @@ -705,13 +714,15 @@ void transform_object_vertices(s16 **data, s16 *vertexData) { /** * Load in the surfaces for the gCurrentObject. This includes setting the flags, exertion, and room. */ -void load_object_surfaces(s16 **data, s16 *vertexData) { +void load_object_surfaces(TerrainData **data, TerrainData *vertexData) { s32 surfaceType; s32 i; s32 numSurfaces; - s16 hasForce; - s16 flags; - s16 room; +#ifndef ALL_SURFACES_HAVE_FORCE + TerrainData hasForce; +#endif + s32 flags; + s32 room; surfaceType = *(*data); (*data)++; @@ -719,7 +730,9 @@ void load_object_surfaces(s16 **data, s16 *vertexData) { numSurfaces = *(*data); (*data)++; +#ifndef ALL_SURFACES_HAVE_FORCE hasForce = surface_has_force(surfaceType); +#endif flags = surf_has_no_cam_collision(surfaceType); flags |= SURFACE_FLAG_DYNAMIC; @@ -739,35 +752,68 @@ void load_object_surfaces(s16 **data, s16 *vertexData) { surface->object = gCurrentObject; surface->type = surfaceType; +#ifdef ALL_SURFACES_HAVE_FORCE + surface->force = *(*data + 3); +#else if (hasForce) { surface->force = *(*data + 3); } else { surface->force = 0; } +#endif surface->flags |= flags; surface->room = (s8) room; add_surface(surface, TRUE); } +#ifdef ALL_SURFACES_HAVE_FORCE + *data += 4; +#else if (hasForce) { *data += 4; } else { *data += 3; } +#endif } } +#ifdef AUTO_COLLISION_DISTANCE +// From Kaze +static void get_optimal_coll_dist(struct Object *o) { + register f32 thisVertDist, maxDist = 0.0f; + Vec3f v; + TerrainData *collisionData = gCurrentObject->collisionData; + o->oFlags |= OBJ_FLAG_DONT_CALC_COLL_DIST; + collisionData++; + register u32 vertsLeft = *(collisionData); + collisionData++; + // vertices = *data; + while (vertsLeft) { + v[0] = *(collisionData + 0) * o->header.gfx.scale[0]; + v[1] = *(collisionData + 1) * o->header.gfx.scale[1]; + v[2] = *(collisionData + 2) * o->header.gfx.scale[2]; + thisVertDist = ((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2])); + if (thisVertDist > maxDist) maxDist = thisVertDist; + collisionData += 3; + vertsLeft--; + } + o->oCollisionDistance = (sqrtf(maxDist) + 100.0f); +} +#endif + /** * Transform an object's vertices, reload them, and render the object. */ void load_object_collision_model(void) { - UNUSED s32 unused; - s16 vertexData[600]; + TerrainData vertexData[600]; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif - s16 *collisionData = gCurrentObject->collisionData; + TerrainData *collisionData = gCurrentObject->collisionData; f32 marioDist = gCurrentObject->oDistanceToMario; - f32 tangibleDist = gCurrentObject->oCollisionDistance; // On an object's first frame, the distance is set to 19000.0f. // If the distance hasn't been updated, update it now. @@ -775,14 +821,20 @@ void load_object_collision_model(void) { marioDist = dist_between_objects(gCurrentObject, gMarioObject); } +#ifdef AUTO_COLLISION_DISTANCE + if (!(gCurrentObject->oFlags & OBJ_FLAG_DONT_CALC_COLL_DIST)) { + get_optimal_coll_dist(gCurrentObject); + } +#endif + // If the object collision is supposed to be loaded more than the // drawing distance of 4000, extend the drawing range. - if (gCurrentObject->oCollisionDistance > 4000.0f) { + if (gCurrentObject->oCollisionDistance > gCurrentObject->oDrawingDistance) { gCurrentObject->oDrawingDistance = gCurrentObject->oCollisionDistance; } // Update if no Time Stop, in range, and in the current room. - if (!(gTimeStopState & TIME_STOP_ACTIVE) && marioDist < tangibleDist + if (!(gTimeStopState & TIME_STOP_ACTIVE) && marioDist < gCurrentObject->oCollisionDistance && !(gCurrentObject->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) { collisionData++; transform_object_vertices(&collisionData, vertexData); @@ -798,4 +850,7 @@ void load_object_collision_model(void) { } else { gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; } + #if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime()-first; + #endif } diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index d947cf80..dea40ce4 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -38,9 +38,9 @@ extern s16 sSurfacePoolSize; void alloc_surface_pools(void); #ifdef NO_SEGMENTED_MEMORY -u32 get_area_terrain_size(s16 *data); +u32 get_area_terrain_size(TerrainData *data); #endif -void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects); +void load_area_terrain(s32 index, TerrainData *data, RoomData *surfaceRooms, s16 *macroObjects); void clear_dynamic_surfaces(void); void load_object_collision_model(void); diff --git a/src/game/area.c b/src/game/area.c index a6b7c99c..eb1b829a 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -22,6 +22,9 @@ #include "engine/geo_layout.h" #include "save_file.h" #include "level_table.h" +#include "dialog_ids.h" +#include "puppyprint.h" +#include "debug_box.h" struct SpawnInfo gPlayerSpawnInfos[1]; struct GraphNode *gGraphNodePointers[MODEL_ID_COUNT]; @@ -33,7 +36,7 @@ s16 gCurrCourseNum; s16 gCurrActNum; s16 gCurrAreaIndex; s16 gSavedCourseNum; -s16 gPauseScreenMode; +s16 gMenuOptSelectIndex; s16 gSaveOptSelectIndex; struct SpawnInfo *gMarioSpawnInfo = &gPlayerSpawnInfos[0]; @@ -197,8 +200,8 @@ void clear_areas(void) { gAreaData[i].unused28 = NULL; gAreaData[i].whirlpools[0] = NULL; gAreaData[i].whirlpools[1] = NULL; - gAreaData[i].dialog[0] = 255; - gAreaData[i].dialog[1] = 255; + gAreaData[i].dialog[0] = DIALOG_NONE; + gAreaData[i].dialog[1] = DIALOG_NONE; gAreaData[i].musicParam = 0; gAreaData[i].musicParam2 = 0; } @@ -301,6 +304,7 @@ void area_update_objects(void) { * transition type, time in frames, and the RGB color that will fill the screen. */ void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue) { +#ifndef L3DEX2_ALONE gWarpTransition.isActive = TRUE; gWarpTransition.type = transType; gWarpTransition.time = time; @@ -351,6 +355,7 @@ void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue) { gWarpTransition.data.endTexRadius = GFX_DIMENSIONS_FULL_RADIUS; } } +#endif } /* @@ -367,29 +372,36 @@ void render_game(void) { if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) { geo_process_root(gCurrentArea->unk04, D_8032CE74, D_8032CE78, gFBSetColor); + #ifdef VISUAL_DEBUG + if (hitboxView) + render_debug_boxes(); + if (surfaceView) + visual_surface_loop(); + #endif + gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&D_8032CF00)); - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, - SCREEN_HEIGHT - BORDER_HEIGHT); + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, gBorderHeight, SCREEN_WIDTH, + SCREEN_HEIGHT - gBorderHeight); render_hud(); gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); render_text_labels(); do_cutscene_handler(); print_displaying_credits_entry(); - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, - SCREEN_HEIGHT - BORDER_HEIGHT); - gPauseScreenMode = render_menus_and_dialogs(); + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, gBorderHeight, SCREEN_WIDTH, + SCREEN_HEIGHT - gBorderHeight); + gMenuOptSelectIndex = render_menus_and_dialogs(); - if (gPauseScreenMode != 0) { - gSaveOptSelectIndex = gPauseScreenMode; + if (gMenuOptSelectIndex != 0) { + gSaveOptSelectIndex = gMenuOptSelectIndex; } if (D_8032CE78 != NULL) { make_viewport_clip_rect(D_8032CE78); } else - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, - SCREEN_HEIGHT - BORDER_HEIGHT); + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, gBorderHeight, SCREEN_WIDTH, + SCREEN_HEIGHT - gBorderHeight); if (gWarpTransition.isActive) { if (gWarpTransDelay == 0) { @@ -415,6 +427,11 @@ void render_game(void) { } } + + #if PUPPYPRINT_DEBUG + puppyprint_render_profiler(); + #endif + D_8032CE74 = NULL; D_8032CE78 = NULL; } diff --git a/src/game/area.h b/src/game/area.h index fa6c8e1b..262a5f1a 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -118,6 +118,24 @@ struct WarpTransition /*0x04*/ struct WarpTransitionData data; }; +enum MenuOption { + MENU_OPT_NONE, + MENU_OPT_1, + MENU_OPT_2, + MENU_OPT_3, + MENU_OPT_DEFAULT = MENU_OPT_1, + + // Course Pause Menu + MENU_OPT_CONTINUE = MENU_OPT_1, + MENU_OPT_EXIT_COURSE = MENU_OPT_2, + MENU_OPT_CAMERA_ANGLE_R = MENU_OPT_3, + + // Save Menu + MENU_OPT_SAVE_AND_CONTINUE = MENU_OPT_1, + MENU_OPT_SAVE_AND_QUIT = MENU_OPT_2, + MENU_OPT_CONTINUE_DONT_SAVE = MENU_OPT_3 +}; + extern struct GraphNode **gLoadedGraphNodes; extern struct SpawnInfo gPlayerSpawnInfos[]; extern struct GraphNode *gGraphNodePointers[MODEL_ID_COUNT]; @@ -127,7 +145,7 @@ extern s16 gCurrCourseNum; extern s16 gCurrActNum; extern s16 gCurrAreaIndex; extern s16 gSavedCourseNum; -extern s16 gPauseScreenMode; +extern s16 gMenuOptSelectIndex; extern s16 gSaveOptSelectIndex; extern struct SpawnInfo *gMarioSpawnInfo; diff --git a/src/game/behavior_actions.c b/src/game/behavior_actions.c index 940698a7..0240e095 100644 --- a/src/game/behavior_actions.c +++ b/src/game/behavior_actions.c @@ -23,6 +23,7 @@ #include "level_table.h" #include "level_update.h" #include "levels/bob/header.h" +#include "levels/bowser_3/header.h" #include "levels/castle_inside/header.h" #include "levels/hmc/header.h" #include "main.h" @@ -61,14 +62,6 @@ struct Struct8032F34C { const void *segAddr; }; -struct Struct8032F698 { - void *unk0; - s16 unk1; - s16 unk2; - s16 unk3; - s16 unk4; -}; - struct Struct802C0DF0 { u8 unk0; u8 unk1; @@ -89,10 +82,10 @@ struct OpenableGrill { const Collision *collision; }; -s32 D_8032F0C0[] = { SAVE_FLAG_HAVE_WING_CAP, SAVE_FLAG_HAVE_METAL_CAP, SAVE_FLAG_HAVE_VANISH_CAP }; +static s32 sCapSaveFlags[] = { SAVE_FLAG_HAVE_WING_CAP, SAVE_FLAG_HAVE_METAL_CAP, SAVE_FLAG_HAVE_VANISH_CAP }; // Boo Roll -s16 D_8032F0CC[] = { 6047, 5664, 5292, 4934, 4587, 4254, 3933, 3624, 3329, 3046, 2775, +static s16 sBooHitRotations[] = { 6047, 5664, 5292, 4934, 4587, 4254, 3933, 3624, 3329, 3046, 2775, 2517, 2271, 2039, 1818, 1611, 1416, 1233, 1063, 906, 761, 629, 509, 402, 308, 226, 157, 100, 56, 25, 4, 0 }; @@ -115,21 +108,21 @@ s16 D_8032F0CC[] = { 6047, 5664, 5292, 4934, 4587, 4254, 3933, 3624, 3329, 3046, #include "behaviors/white_puff_explode.inc.c" // not in behavior file -struct SpawnParticlesInfo D_8032F270 = { 2, 20, MODEL_MIST, 0, 40, 5, 30, 20, 252, 30, 330.0f, 10.0f }; +struct SpawnParticlesInfo sMistParticles = { 2, 20, MODEL_MIST, 0, 40, 5, 30, 20, 252, 30, 330.0f, 10.0f }; // generate_wind_puffs/dust (something like that) void spawn_mist_particles_variable(s32 count, s32 offsetY, f32 size) { - D_8032F270.sizeBase = size; - D_8032F270.sizeRange = size / 20.0; - D_8032F270.offsetY = offsetY; + sMistParticles.sizeBase = size; + sMistParticles.sizeRange = size / 20.0; + sMistParticles.offsetY = offsetY; if (count == 0) { - D_8032F270.count = 20; + sMistParticles.count = 20; } else if (count > 20) { - D_8032F270.count = count; + sMistParticles.count = count; } else { - D_8032F270.count = 4; + sMistParticles.count = 4; } - cur_obj_spawn_particles(&D_8032F270); + cur_obj_spawn_particles(&sMistParticles); } #include "behaviors/sparkle_spawn_star.inc.c" @@ -205,6 +198,8 @@ void spawn_sparkle_particles(s32 n, s32 a1, s32 a2, s32 r) { #include "behaviors/bowser_key.inc.c" #include "behaviors/bullet_bill.inc.c" #include "behaviors/bowser.inc.c" +#include "behaviors/bowser_falling_platform.inc.c" +#include "behaviors/bowser_flame.inc.c" #include "behaviors/blue_fish.inc.c" // Not in behavior file, duplicate of vec3f_copy except without bad return. diff --git a/src/game/behavior_actions.h b/src/game/behavior_actions.h index d068492e..97939170 100644 --- a/src/game/behavior_actions.h +++ b/src/game/behavior_actions.h @@ -231,7 +231,7 @@ void bhv_big_boo_loop(void); void bhv_courtyard_boo_triplet_init(void); void obj_set_secondary_camera_focus(void); void bhv_boo_loop(void); -void bhv_boo_boss_spawned_bridge_loop(void); +void bhv_boo_staircase(void); void bhv_bbh_tilting_trap_platform_loop(void); void bhv_haunted_bookshelf_loop(void); void bhv_merry_go_round_loop(void); diff --git a/src/game/behaviors/beta_boo_key.inc.c b/src/game/behaviors/beta_boo_key.inc.c index 27a85dee..472aa0fb 100644 --- a/src/game/behaviors/beta_boo_key.inc.c +++ b/src/game/behaviors/beta_boo_key.inc.c @@ -87,14 +87,14 @@ static void beta_boo_key_dropped_loop(void) { if (obj_check_if_collided_with_object(o, gMarioObject)) { // This interaction status is 0x01, the first interaction status flag. // It was only used for Hoot in the final game, but it seems it could've - // done something else or held some special meaning in beta. + // treated as a TRUE/FALSE statement or held some special meaning in beta. // Earlier, in beta_boo_key_drop (called when the parent boo is killed), // o->parentObj is set to the parent boo's parentObj. This means that // here, the parentObj is actually the parent of the old parent boo. // One theory about this code is that there was a boo spawner, which // spawned "false" boos and one "true" boo with the key, and the player // was intended to find the one with the key to progress. - o->parentObj->oInteractStatus = INT_STATUS_HOOT_GRABBED_BY_MARIO; + o->parentObj->oInteractStatus = TRUE; // Delete the object and spawn sparkles obj_mark_for_deletion(o); diff --git a/src/game/behaviors/bobomb.inc.c b/src/game/behaviors/bobomb.inc.c index 2e3a314c..34eef764 100644 --- a/src/game/behaviors/bobomb.inc.c +++ b/src/game/behaviors/bobomb.inc.c @@ -46,7 +46,7 @@ void bobomb_check_interactions(void) { obj_set_hitbox(o, &sBobombHitbox); if ((o->oInteractStatus & INT_STATUS_INTERACTED) != 0) { - if ((o->oInteractStatus & INT_STATUS_MARIO_UNK1) != 0) + if ((o->oInteractStatus & INT_STATUS_MARIO_KNOCKBACK_DMG) != 0) { o->oMoveAngleYaw = gMarioObject->header.gfx.angle[1]; o->oForwardVel = 25.0; @@ -98,8 +98,7 @@ void bobomb_act_chase_mario(void) { } void bobomb_act_launched(void) { - s16 collisionFlags = 0; - collisionFlags = object_step(); + s16 collisionFlags = object_step(); if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) == OBJ_COL_FLAG_GROUNDED) o->oAction = BOBOMB_ACT_EXPLODE; /* bit 0 */ } @@ -203,7 +202,7 @@ void bobomb_thrown_loop(void) { o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; o->oHeldState = 0; - o->oFlags &= ~0x8; /* bit 3 */ + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; /* bit 3 */ o->oForwardVel = 25.0; o->oVelY = 20.0; o->oAction = BOBOMB_ACT_LAUNCHED; @@ -344,7 +343,7 @@ void bobomb_buddy_cannon_dialog(s16 dialogFirstText, s16 dialogSecondText) { break; case BOBOMB_BUDDY_CANNON_STOP_TALKING: - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; o->oBobombBuddyHasTalkedToMario = BOBOMB_BUDDY_HAS_TALKED; @@ -356,14 +355,14 @@ void bobomb_buddy_cannon_dialog(s16 dialogFirstText, s16 dialogSecondText) { } void bobomb_buddy_act_talk(void) { - if (set_mario_npc_dialog(1) == 2) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_FRONT) == MARIO_DIALOG_STATUS_SPEAK) { o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; switch (o->oBobombBuddyRole) { case BOBOMB_BUDDY_ROLE_ADVICE: if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, o->oBehParams2ndByte) != BOBOMB_BUDDY_BP_STYPE_GENERIC) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; o->oBobombBuddyHasTalkedToMario = BOBOMB_BUDDY_HAS_TALKED; diff --git a/src/game/behaviors/boo.inc.c b/src/game/behaviors/boo.inc.c index 32c01894..aef903fe 100644 --- a/src/game/behaviors/boo.inc.c +++ b/src/game/behaviors/boo.inc.c @@ -197,8 +197,8 @@ static void boo_move_during_hit(s32 roll, f32 fVel) { o->oMoveAngleYaw = o->oBooMoveYawDuringHit; if (roll != FALSE) { - o->oFaceAngleYaw += D_8032F0CC[o->oTimer]; - o->oFaceAngleRoll += D_8032F0CC[o->oTimer]; + o->oFaceAngleYaw += sBooHitRotations[o->oTimer]; + o->oFaceAngleRoll += sBooHitRotations[o->oTimer]; } } @@ -223,7 +223,7 @@ static s32 boo_update_after_bounced_on(f32 a0) { } if (o->oTimer < 32) { - boo_move_during_hit(FALSE, D_8032F0CC[o->oTimer]/5000.0f * a0); + boo_move_during_hit(FALSE, sBooHitRotations[o->oTimer]/5000.0f * a0); } else { cur_obj_become_tangible(); boo_reset_after_hit(); @@ -243,7 +243,7 @@ static s32 big_boo_update_during_nonlethal_hit(f32 a0) { } if (o->oTimer < 32) { - boo_move_during_hit(TRUE, D_8032F0CC[o->oTimer]/5000.0f * a0); + boo_move_during_hit(TRUE, sBooHitRotations[o->oTimer]/5000.0f * a0); } else if (o->oTimer < 48) { big_boo_shake_after_hit(); } else { @@ -464,7 +464,7 @@ static void boo_act_4(void) { dialogID = DIALOG_107; } - if (cur_obj_update_dialog(2, 2, dialogID, 0)) { + if (cur_obj_update_dialog(MARIO_DIALOG_LOOK_UP, DIALOG_FLAG_TEXT_DEFAULT, dialogID, 0)) { create_sound_spawner(SOUND_OBJ_DYING_ENEMY1); obj_mark_for_deletion(o); @@ -644,9 +644,9 @@ static void big_boo_act_4(void) { if (o->oTimer > 60 && o->oDistanceToMario < 600.0f) { obj_set_pos(o, 973, 0, 717); - spawn_object_relative(0, 0, 0, 0, o, MODEL_BBH_STAIRCASE_STEP, bhvBooBossSpawnedBridge); - spawn_object_relative(1, 0, 0, -200, o, MODEL_BBH_STAIRCASE_STEP, bhvBooBossSpawnedBridge); - spawn_object_relative(2, 0, 0, 200, o, MODEL_BBH_STAIRCASE_STEP, bhvBooBossSpawnedBridge); + spawn_object_relative(0, 0, 0, 0, o, MODEL_BBH_STAIRCASE_STEP, bhvBooStaircase); + spawn_object_relative(1, 0, 0, -200, o, MODEL_BBH_STAIRCASE_STEP, bhvBooStaircase); + spawn_object_relative(2, 0, 0, 200, o, MODEL_BBH_STAIRCASE_STEP, bhvBooStaircase); obj_mark_for_deletion(o); } @@ -863,8 +863,8 @@ void bhv_boo_in_castle_loop(void) { cur_obj_move_using_fvel_and_gravity(); } -void bhv_boo_boss_spawned_bridge_loop(void) { - f32 targetY; +void bhv_boo_staircase(void) { + f32 targetY = 0.0f; switch (o->oBehParams2ndByte) { case 1: @@ -898,7 +898,7 @@ void bhv_boo_boss_spawned_bridge_loop(void) { cur_obj_play_sound_2(SOUND_GENERAL_UNKNOWN4_LOWPRIO); } - if (cur_obj_move_up_and_down(o->oTimer)) { + if (jiggle_bbh_stair(o->oTimer)) { o->oAction++; } diff --git a/src/game/behaviors/boulder.inc.c b/src/game/behaviors/boulder.inc.c index 18bd53fb..42e03cfb 100644 --- a/src/game/behaviors/boulder.inc.c +++ b/src/game/behaviors/boulder.inc.c @@ -11,10 +11,8 @@ void bhv_big_boulder_init(void) { } void boulder_act_1(void) { - s16 sp1E; - - sp1E = object_step_without_floor_orient(); - if ((sp1E & 0x09) == 0x01 && o->oVelY > 10.0f) { + s16 collisionFlags = object_step_without_floor_orient(); + if ((collisionFlags & OBJ_COL_FLAGS_LANDED) == OBJ_COL_FLAG_GROUNDED && o->oVelY > 10.0f) { cur_obj_play_sound_2(SOUND_GENERAL_GRINDEL_ROLL); spawn_mist_particles(); } diff --git a/src/game/behaviors/bowling_ball.inc.c b/src/game/behaviors/bowling_ball.inc.c index f1e16cb1..bac6193b 100644 --- a/src/game/behaviors/bowling_ball.inc.c +++ b/src/game/behaviors/bowling_ball.inc.c @@ -79,6 +79,9 @@ void bowling_ball_set_waypoints(void) { void bhv_bowling_ball_roll_loop(void) { s16 collisionFlags; s32 sp18; +#ifdef AVOID_UB + sp18 = 0; +#endif bowling_ball_set_waypoints(); collisionFlags = object_step(); @@ -109,6 +112,9 @@ void bhv_bowling_ball_roll_loop(void) { void bhv_bowling_ball_initializeLoop(void) { s32 sp1c; +#ifdef AVOID_UB + sp1c = 0; +#endif bowling_ball_set_waypoints(); @@ -252,7 +258,7 @@ void bhv_free_bowling_ball_init(void) { } void bhv_free_bowling_ball_roll_loop(void) { - s16 collisionFlags = object_step(); + /*s16 collisionFlags = */object_step(); bowling_ball_set_hitbox(); if (o->oForwardVel > 10.0f) { @@ -260,8 +266,9 @@ void bhv_free_bowling_ball_roll_loop(void) { cur_obj_play_sound_1(SOUND_ENV_UNKNOWN2); } - if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) && !(collisionFlags & OBJ_COL_FLAGS_LANDED)) - cur_obj_play_sound_2(SOUND_GENERAL_QUIET_POUND1_LOWPRIO); + /* Always false, commented out to suppress compiler warnings */ + // if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) && !(collisionFlags & OBJ_COL_FLAGS_LANDED)) + // cur_obj_play_sound_2(SOUND_GENERAL_QUIET_POUND1_LOWPRIO); if (!is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 6000)) { o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index 965ce660..93394344 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -1,116 +1,180 @@ #include "config.h" // bowser.c.inc +/** + * Behavior for Bowser and it's actions (Tail, Flame, Body) + */ -void bowser_tail_anchor_act_0(void) { +// Bowser's Tail + +/** + * Checks whenever the Bowser and his tail should be intangible or not + * By default it starts tangible + */ +void bowser_tail_anchor_act_default(void) { struct Object *bowser = o->parentObj; cur_obj_become_tangible(); cur_obj_scale(1.0f); - if (bowser->oAction == 19) + + if (bowser->oAction == BOWSER_ACT_TILT_LAVA_PLATFORM) { + // Bowser cannot be touched when he tilts BITFS platform bowser->oIntangibleTimer = -1; - else if (obj_check_if_collided_with_object(o, gMarioObject)) { + } else if (obj_check_if_collided_with_object(o, gMarioObject)) { + // When Mario collides his tail, it now gets + // intangible so he can grab it through bowser->oIntangibleTimer = 0; - o->oAction = 2; - } else + o->oAction = BOWSER_ACT_TAIL_TOUCHED_MARIO; + } else { bowser->oIntangibleTimer = -1; + } } -void bowser_tail_anchor_act_1(void) { - if (o->oTimer > 30) - o->oAction = 0; +/** + * While Bowser get's thrown, wait 30 frames then + * return to the default tail action check + */ +void bowser_tail_anchor_thrown(void) { + if (o->oTimer > 30) { + o->oAction = BOWSER_ACT_TAIL_DEFAULT; + } } -void bowser_tail_anchor_act_2(void) { - if (o->parentObj->oAction == 19) { +/** + * Makes the tail intangible so Mario can grab it + */ +void bowser_tail_anchor_act_touched_mario(void) { + // Return to main action when Bowser tilts BITFS platform + if (o->parentObj->oAction == BOWSER_ACT_TILT_LAVA_PLATFORM) { o->parentObj->oIntangibleTimer = -1; - o->oAction = 0; + o->oAction = BOWSER_ACT_TAIL_DEFAULT; } cur_obj_become_intangible(); } -void (*sBowserTailAnchorActions[])(void) = { bowser_tail_anchor_act_0, bowser_tail_anchor_act_1, - bowser_tail_anchor_act_2 }; -s8 D_8032F4FC[] = { 7, 8, 9, 12, 13, 14, 15, 4, 3, 16, 17, 19, 3, 3, 3, 3 }; -s16 D_8032F50C[] = { 60, 0 }; -s16 D_8032F510[] = { 50, 0 }; -s8 D_8032F514[] = { 24, 42, 60, -1 }; -s16 sBowserDefeatedDialogText[3] = { DIALOG_119, DIALOG_120, DIALOG_121 }; -s16 D_8032F520[][3] = { { 1, 10, 40 }, { 0, 0, 74 }, { -1, -10, 114 }, { 1, -20, 134 }, - { -1, 20, 154 }, { 1, 40, 164 }, { -1, -40, 174 }, { 1, -80, 179 }, - { -1, 80, 184 }, { 1, 160, 186 }, { -1, -160, 186 }, { 1, 0, 0 }, }; +void (*sBowserTailAnchorActions[])(void) = { + bowser_tail_anchor_act_default, + bowser_tail_anchor_thrown, + bowser_tail_anchor_act_touched_mario, +}; +/** + * Bowser's tail main loop + */ void bhv_bowser_tail_anchor_loop(void) { + // Call its actions cur_obj_call_action_function(sBowserTailAnchorActions); + // Position the tail o->oParentRelativePosX = 90.0f; - if (o->parentObj->oAction == 4) + + // Make it intangible while Bowser is dead + if (o->parentObj->oAction == BOWSER_ACT_DEAD) { o->parentObj->oIntangibleTimer = -1; + } + o->oInteractStatus = 0; } +// Bowser's Flame + +/** + * Bowser's Flame spawn main loop + */ void bhv_bowser_flame_spawn_loop(void) { struct Object *bowser = o->parentObj; - s32 sp30; - f32 sp2C; - f32 sp28; - f32 sp24 = coss(bowser->oMoveAngleYaw); - f32 sp20 = sins(bowser->oMoveAngleYaw); - s16 *sp1C = segmented_to_virtual(bowser_seg6_unkmoveshorts_060576FC); - if (bowser->oSoundStateID == 6) { - sp30 = bowser->header.gfx.animInfo.animFrame + 1.0f; - if (bowser->header.gfx.animInfo.curAnim->loopEnd == sp30) - sp30 = 0; - if (sp30 > 45 && sp30 < 85) { + s32 animFrame; + f32 posX; + f32 posZ; + f32 cossYaw = coss(bowser->oMoveAngleYaw); + f32 sinsYaw = sins(bowser->oMoveAngleYaw); + s16 *data = segmented_to_virtual(dBowserFlamesOrientationValues); + + // Check for Bowser breathing animation + if (bowser->oSoundStateID == BOWSER_ANIM_BREATH) { + + // Start counting anim frames then reset it when it ends + animFrame = bowser->header.gfx.animInfo.animFrame + 1.0f; + if (bowser->header.gfx.animInfo.curAnim->loopEnd == animFrame) { + animFrame = 0; + } + + // Bowser is breathing, play sound and adjust flame position + // each animFrame based off the orientantion data + if (animFrame > 45 && animFrame < 85) { cur_obj_play_sound_1(SOUND_AIR_BOWSER_SPIT_FIRE); - sp2C = sp1C[5 * sp30]; - sp28 = sp1C[5 * sp30 + 2]; - o->oPosX = bowser->oPosX + (sp28 * sp20 + sp2C * sp24); - o->oPosY = bowser->oPosY + sp1C[5 * sp30 + 1]; - o->oPosZ = bowser->oPosZ + (sp28 * sp24 - sp2C * sp20); - o->oMoveAnglePitch = sp1C[5 * sp30 + 4] + 0xC00; - o->oMoveAngleYaw = sp1C[5 * sp30 + 3] + (s16) bowser->oMoveAngleYaw; - if (!(sp30 & 1)) + posX = data[5 * animFrame]; + posZ = data[5 * animFrame + 2]; + o->oPosX = bowser->oPosX + (posZ * sinsYaw + posX * cossYaw); + o->oPosY = bowser->oPosY + data[5 * animFrame + 1]; + o->oPosZ = bowser->oPosZ + (posZ * cossYaw - posX * sinsYaw); + o->oMoveAnglePitch = data[5 * animFrame + 4] + 0xC00; + o->oMoveAngleYaw = data[5 * animFrame + 3] + (s16) bowser->oMoveAngleYaw; + // Spawns the flames on a non-odd animFrame value + if (!(animFrame & 1)) { spawn_object(o, MODEL_RED_FLAME, bhvFlameMovingForwardGrowing); + } } } } +/** + * Bowser's Body main loop + */ void bhv_bowser_body_anchor_loop(void) { + // Copy position and angles from Bowser itself obj_copy_pos_and_angle(o, o->parentObj); - if (o->parentObj->oAction == 4) { -#ifndef VERSION_JP - if (o->parentObj->oSubAction == 11) + // If Bowser is dead, set interaction type to text + // so that he can be ready to speak his dialog + if (o->parentObj->oAction == BOWSER_ACT_DEAD) { +#if BUGFIX_BOWSER_COLLIDE_BITS_DEAD + // Clear interaction type at the last sub action in BITS + // Fixes collision coliding after defeating him + if (o->parentObj->oSubAction == BOWSER_SUB_ACT_DEAD_FINAL_END_OVER) { o->oInteractType = 0; - else - o->oInteractType = 0x800000; + } else { + o->oInteractType = INTERACT_TEXT; + } #else - o->oInteractType = 0x800000; + o->oInteractType = INTERACT_TEXT; #endif } else { - o->oInteractType = 8; - if (o->parentObj->oOpacity < 100) + // Do damage if Mario touches Bowser + o->oInteractType = INTERACT_DAMAGE; + // Make body intangible while is transparent + // in BITFS (Teleporting) + if (o->parentObj->oOpacity < 100) { cur_obj_become_intangible(); - else + } else { cur_obj_become_tangible(); + } } - if (o->parentObj->oHeldState != HELD_FREE) + // Make body intangible while Bowser is getting grabbed + if (o->parentObj->oHeldState != HELD_FREE) { cur_obj_become_intangible(); + } o->oInteractStatus = 0; } +/** + * Bowser's shockwave attack, spawns only in BITS + */ s32 bowser_spawn_shockwave(void) { struct Object *wave; - if (o->oBehParams2ndByte == 2) { + if (o->oBehParams2ndByte == BOWSER_BP_BITS) { wave = spawn_object(o, MODEL_BOWSER_WAVE, bhvBowserShockWave); wave->oPosY = o->oFloorHeight; - return 1; + return TRUE; } - return 0; + return FALSE; } -void bowser_bounce(s32 *a) { +/** + * Misc effects that Bowser plays when he lands with drastic actions + * Plays step sound, spawns particles and changes camera event + */ +void bowser_bounce_effects(s32 *timer) { if (o->oMoveFlags & OBJ_MOVE_LANDED) { - a[0]++; - if (a[0] < 4) { + (*timer)++; + if (*timer < 4) { cur_obj_start_cam_event(o, CAM_EVENT_BOWSER_THROW_BOUNCE); spawn_mist_particles_variable(0, 0, 60.0f); cur_obj_play_sound_2(SOUND_OBJ_BOWSER_WALK); @@ -118,175 +182,272 @@ void bowser_bounce(s32 *a) { } } -#define BITDW (o->oBehParams2ndByte == 0) -#define BITFS (o->oBehParams2ndByte == 1) -#define BITS (o->oBehParams2ndByte == 2) - +/** + * Makes Bowser look up and walk on an specific animation frame + * Returns TRUE if the animation is almost over + */ s32 bowser_set_anim_look_up_and_walk(void) { - cur_obj_init_animation_with_sound(15); - if (cur_obj_check_anim_frame(21)) + cur_obj_init_animation_with_sound(BOWSER_ANIM_LOOK_UP_START_WALK); + if (cur_obj_check_anim_frame(21)) { o->oForwardVel = 3.0f; - if (cur_obj_check_if_near_animation_end()) - return 1; - else - return 0; -} - -s32 bowser_set_anim_slow_gait(void) { - o->oForwardVel = 3.0f; - cur_obj_init_animation_with_sound(13); - if (cur_obj_check_if_near_animation_end()) - return 1; - else - return 0; -} - -s32 bowser_set_anim_look_down(void) { - cur_obj_init_animation_with_sound(14); - if (cur_obj_check_anim_frame(20)) - o->oForwardVel = 0.0f; - if (cur_obj_check_if_near_animation_end()) - return 1; - else - return 0; -} - -void bowser_initialize_action(void) { - if (o->oBowserUnk88 == 0) - o->oAction = 5; - else if (o->oBowserUnk88 == 1) - o->oAction = 6; - else if (o->oBehParams2ndByte == 1) - o->oAction = 13; - else - o->oAction = 0; -} - -void bowser_act_text_wait(void) // not much -{ - o->oForwardVel = 0.0f; - cur_obj_init_animation_with_sound(12); - bowser_initialize_action(); -} - -void bowser_act_intro_walk(void) { - if (o->oSubAction == 0) { - if (bowser_set_anim_look_up_and_walk()) - o->oSubAction++; - } else if (o->oSubAction == 1) { - if (bowser_set_anim_slow_gait()) - o->oSubAction++; - } else if (bowser_set_anim_look_down()) { - if (o->oBowserUnk88 == 1) - o->oBowserUnk88 = 0; - bowser_initialize_action(); + } + if (cur_obj_check_if_near_animation_end()) { + return TRUE; + } else { + return FALSE; } } -static void bowser_debug_actions(void) // unused -{ +/** + * Makes Bowser do a slow gait (or slow walk) + * Returns TRUE if the animation is almost over + */ +s32 bowser_set_anim_slow_gait(void) { + o->oForwardVel = 3.0f; + cur_obj_init_animation_with_sound(BOWSER_ANIM_SLOW_GAIT); + if (cur_obj_check_if_near_animation_end()) { + return TRUE; + } else { + return FALSE; + } +} + +/** + * Makes Bowser look down and stop on an specific animation frame + * Returns TRUE if the animation is almost over + */ +s32 bowser_set_anim_look_down_stop_walk(void) { + cur_obj_init_animation_with_sound(BOWSER_ANIM_LOOK_DOWN_STOP_WALK); + if (cur_obj_check_anim_frame(20)) { + o->oForwardVel = 0.0f; + } + if (cur_obj_check_if_near_animation_end()) { + return TRUE; + } else { + return FALSE; + } +} + + +/** + * Set Bowser an action depending of the CamAct value + * CamAct changes value on the cutscene itself (cutscene_bowser_arena) + */ +void bowser_init_camera_actions(void) { + if (o->oBowserCamAct == BOWSER_CAM_ACT_IDLE) { + o->oAction = BOWSER_ACT_WAIT; + } else if (o->oBowserCamAct == BOWSER_CAM_ACT_WALK) { + o->oAction = BOWSER_ACT_INTRO_WALK; + // Start with a big jump in BITFS to do a platform tilt + } else if (o->oBehParams2ndByte == BOWSER_BP_BITFS) { + o->oAction = BOWSER_ACT_BIG_JUMP; + } else { + o->oAction = BOWSER_ACT_DEFAULT; + } +} + +/** + * Bowser's idle action that plays when he is initialized + * or the CamAct gets in idle mode + */ +void bowser_act_wait(void) { + o->oForwardVel = 0.0f; + cur_obj_init_animation_with_sound(BOWSER_ANIM_IDLE); + bowser_init_camera_actions(); +} + +/** + * Bowser's cutscene walk that last a few seconds to introduce itself + * Do subactions until the animation ends, then go to next subaction + */ +void bowser_act_intro_walk(void) { + // First look up and walk + if (o->oSubAction == 0) { + if (bowser_set_anim_look_up_and_walk()) { + o->oSubAction++; + } + // Then slowly walk + } else if (o->oSubAction == 1) { + if (bowser_set_anim_slow_gait()) { + o->oSubAction++; + } + // And finally stop, and set to wait mode + } else if (bowser_set_anim_look_down_stop_walk()) { + if (o->oBowserCamAct == BOWSER_CAM_ACT_WALK) { + o->oBowserCamAct = BOWSER_CAM_ACT_IDLE; + } + bowser_init_camera_actions(); + } +} + +/** + * List of actions to debug Bowser + */ +s8 sBowserDebugActions[] = { + BOWSER_ACT_CHARGE_MARIO, + BOWSER_ACT_SPIT_FIRE_INTO_SKY, + BOWSER_ACT_SPIT_FIRE_ONTO_FLOOR, + BOWSER_ACT_HIT_MINE, + BOWSER_ACT_BIG_JUMP, + BOWSER_ACT_WALK_TO_MARIO, + BOWSER_ACT_BREATH_FIRE, + BOWSER_ACT_DEAD, + BOWSER_ACT_DANCE, + BOWSER_ACT_TELEPORT, + BOWSER_ACT_QUICK_JUMP, + BOWSER_ACT_TILT_LAVA_PLATFORM, + BOWSER_ACT_DANCE, + BOWSER_ACT_DANCE, + BOWSER_ACT_DANCE, + BOWSER_ACT_DANCE, +}; + +/** + * Debug function that allows to change Bowser's actions (most of them) + */ +UNUSED static void bowser_debug_actions(void) { if (gDebugInfo[5][1] != 0) { - o->oAction = D_8032F4FC[gDebugInfo[5][2] & 0xf]; + o->oAction = sBowserDebugActions[gDebugInfo[5][2] & 0xf]; gDebugInfo[5][1] = 0; } } -void bowser_bitdw_act_controller(void) { +/** + * Set actions (and attacks) for Bowser in "Bowser in the Dark World" + */ +void bowser_bitdw_actions(void) { + // Generate random float f32 rand = random_float(); - if (o->oBowserUnk110 == 0) { - if (o->oBowserUnkF4 & 2) { - if (o->oDistanceToMario < 1500.0f) - o->oAction = 15; // nearby - else - o->oAction = 17; // far away - } else - o->oAction = 14; - o->oBowserUnk110++; - } else { - o->oBowserUnk110 = 0; -#ifndef VERSION_JP - if (!gCurrDemoInput) { - if (rand < 0.1) - o->oAction = 3; // rare 1/10 chance - else - o->oAction = 14; // common + // Set attacks when Bowser Reacts + if (o->oBowserIsReacting == FALSE) { + if (o->oBowserStatus & BOWSER_STATUS_ANGLE_MARIO) { + if (o->oDistanceToMario < 1500.0f) { + o->oAction = BOWSER_ACT_BREATH_FIRE; // nearby + } else { + o->oAction = BOWSER_ACT_QUICK_JUMP; // far away + } } else { - o->oAction = 14; // ensure demo starts with action 14. + // Keep walking + o->oAction = BOWSER_ACT_WALK_TO_MARIO; + } + o->oBowserIsReacting++; + } else { + o->oBowserIsReacting = FALSE; + // Set starting Bowser level actions, randomly he can also start + // dancing after the introduction +#ifndef VERSION_JP + if (!gCurrDemoInput) { // demo check because entry exits post JP + if (rand < 0.1) { + o->oAction = BOWSER_ACT_DANCE; // 10% chance + } else { + o->oAction = BOWSER_ACT_WALK_TO_MARIO; // common + } + } else { + o->oAction = BOWSER_ACT_WALK_TO_MARIO; } #else - if (rand < 0.1) - o->oAction = 3; // rare 1/10 chance - else - o->oAction = 14; // common + if (rand < 0.1) { + o->oAction = BOWSER_ACT_DANCE; // 10% chance + } else { + o->oAction = BOWSER_ACT_WALK_TO_MARIO; // common + } #endif } } -void bowser_bitfs_act_controller(void) { +/** + * Set actions (and attacks) for Bowser in "Bowser in the Fire Sea" + */ +void bowser_bitfs_actions(void) { + // Generate random float f32 rand = random_float(); - if (o->oBowserUnk110 == 0) { - if (o->oBowserUnkF4 & 2) { - if (o->oDistanceToMario < 1300.0f) // nearby - { - if (rand < 0.5) // 50/50 - o->oAction = 16; - else - o->oAction = 9; - } else // far away - { - o->oAction = 7; + // Set attacks when Bowser Reacts + if (o->oBowserIsReacting == FALSE) { + if (o->oBowserStatus & BOWSER_STATUS_ANGLE_MARIO) { + if (o->oDistanceToMario < 1300.0f) { // nearby + if (rand < 0.5) { // 50% chance + o->oAction = BOWSER_ACT_TELEPORT; + } else { + o->oAction = BOWSER_ACT_SPIT_FIRE_ONTO_FLOOR; + } + } else { // far away + o->oAction = BOWSER_ACT_CHARGE_MARIO; if (500.0f < o->oBowserDistToCentre && o->oBowserDistToCentre < 1500.0f - && rand < 0.5) // away from centre and good luck - o->oAction = 13; + && rand < 0.5) { // 50% chance + o->oAction = BOWSER_ACT_BIG_JUMP; + } } - } else - o->oAction = 14; - o->oBowserUnk110++; + } else { + // Keep walking + o->oAction = BOWSER_ACT_WALK_TO_MARIO; + } + o->oBowserIsReacting++; } else { - o->oBowserUnk110 = 0; - o->oAction = 14; + // Keep walking + o->oBowserIsReacting = FALSE; + o->oAction = BOWSER_ACT_WALK_TO_MARIO; } } -void bowser_general_bits_act_controller(void) { +/** + * List of actions (and attacks) for "Bowser in the Sky" + */ +void bowser_bits_action_list(void) { f32 rand = random_float(); - if (o->oBowserUnkF4 & 2) { - if (o->oDistanceToMario < 1000.0f) { - if (rand < 0.4) - o->oAction = 9; - else if (rand < 0.8) - o->oAction = 8; - else - o->oAction = 15; - } else if (rand < 0.5) - o->oAction = 13; - else - o->oAction = 7; - } else - o->oAction = 14; + if (o->oBowserStatus & BOWSER_STATUS_ANGLE_MARIO) { + if (o->oDistanceToMario < 1000.0f) { // nearby + if (rand < 0.4) { + o->oAction = BOWSER_ACT_SPIT_FIRE_ONTO_FLOOR; // 40% chance + } else if (rand < 0.8) { + o->oAction = BOWSER_ACT_SPIT_FIRE_INTO_SKY; // 80% chance + } else { + o->oAction = BOWSER_ACT_BREATH_FIRE; + } // far away + } else if (rand < 0.5) { + o->oAction = BOWSER_ACT_BIG_JUMP; // 50% chance + } else { + o->oAction = BOWSER_ACT_CHARGE_MARIO; + } + } else { + // Keep walking + o->oAction = BOWSER_ACT_WALK_TO_MARIO; + } } -void bowser_set_act_jump(void) { - o->oAction = 13; +/** + * Sets big jump action, not much to say + * Never gets called since oBowserBitsJustJump is always FALSE + */ +void bowser_set_act_big_jump(void) { + o->oAction = BOWSER_ACT_BIG_JUMP; } -void bowser_bits_act_controller(void) { - switch (o->oBowserUnk110) { - case 0: - if (o->oBowserUnk106 == 0) - bowser_general_bits_act_controller(); - else - bowser_set_act_jump(); - o->oBowserUnk110 = 1; +/** + * Set actions (and attacks) for Bowser in "Bowser in the Sky" + */ +void bowser_bits_actions(void) { + switch (o->oBowserIsReacting) { + case FALSE: + // oBowserBitsJustJump never changes value, + // so its always FALSE, maybe a debug define + if (o->oBowserBitsJustJump == FALSE) { + bowser_bits_action_list(); + } else { + bowser_set_act_big_jump(); + } + o->oBowserIsReacting = TRUE; break; - case 1: - o->oBowserUnk110 = 0; - o->oAction = 14; + case TRUE: + o->oBowserIsReacting = FALSE; + o->oAction = BOWSER_ACT_WALK_TO_MARIO; break; } } -#ifndef VERSION_JP +/** + * Reset Bowser position and speed if he wasn't able to land properly on stage + */ +#if BUGFIX_BOWSER_FALLEN_OFF_STAGE void bowser_reset_fallen_off_stage(void) { if (o->oVelY < 0 && o->oPosY < (o->oHomeY - 300.0f)) { o->oPosX = o->oPosZ = 0; @@ -297,378 +458,562 @@ void bowser_reset_fallen_off_stage(void) { } #endif -void bowser_act_unused_slow_walk(void) // unused? -{ - if (cur_obj_init_animation_and_check_if_near_end(12)) - o->oAction = 0; +/** + * Unused, makes Bowser be in idle and after it returns to default action + */ +void bowser_act_idle(void) { + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_IDLE)) { + o->oAction = BOWSER_ACT_DEFAULT; + } } -void bowser_act_default(void) // only lasts one frame -{ - o->oBowserEyesShut = 0; - cur_obj_init_animation_with_sound(12); - // stop him still +/** + * Default Bowser act that doesn't last very long + */ +void bowser_act_default(void) { + // Set eye state + o->oBowserEyesShut = FALSE; + // Set idle animation + cur_obj_init_animation_with_sound(BOWSER_ANIM_IDLE); + // Stop him still o->oAngleVelYaw = 0; o->oForwardVel = 0.0f; o->oVelY = 0.0f; - if (BITDW) - bowser_bitdw_act_controller(); - else if (BITFS) - bowser_bitfs_act_controller(); - else - bowser_bits_act_controller(); - // Action 14 commonly follows + // Set level specific actions + if (o->oBehParams2ndByte == BOWSER_BP_BITDW) { + bowser_bitdw_actions(); + } else if (o->oBehParams2ndByte == BOWSER_BP_BITFS) { + bowser_bitfs_actions(); + } else { // BOWSER_BP_BITS + bowser_bits_actions(); + } } +/** + * Makes Bowser play breath animation and sound effect + * The actual breath attack is in bhv_bowser_flame_spawn_loop + * called as a child obj behavior in Bowser + */ void bowser_act_breath_fire(void) { o->oForwardVel = 0.0f; - if (o->oTimer == 0) + if (o->oTimer == 0) { cur_obj_play_sound_2(SOUND_OBJ_BOWSER_INHALING); - if (cur_obj_init_animation_and_check_if_near_end(6)) - o->oAction = 0; + } + // Init animation and return to default act after it ends + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_BREATH)) { + o->oAction = BOWSER_ACT_DEFAULT; + } } -void bowser_act_walk_to_mario(void) // turn towards Mario -{ +/** + * Makes Bowser walk towards Mario + */ +void bowser_act_walk_to_mario(void) { UNUSED s32 facing; // is Bowser facing Mario? s16 turnSpeed; s16 angleFromMario = abs_angle_diff(o->oMoveAngleYaw, o->oAngleToMario); - if (BITFS) + + // Set turning speed depending of the health + // Also special case for BITFS + if (o->oBehParams2ndByte == BOWSER_BP_BITFS) { turnSpeed = 0x400; - else if (o->oHealth > 2) + } else if (o->oHealth > 2) { turnSpeed = 0x400; - else if (o->oHealth == 2) + } else if (o->oHealth == 2) { turnSpeed = 0x300; - else + } else { // 1 health (BITFS-BITS) turnSpeed = 0x200; + } facing = cur_obj_rotate_yaw_toward(o->oAngleToMario, turnSpeed); if (o->oSubAction == 0) { - o->oBowserUnkF8 = 0; - if (bowser_set_anim_look_up_and_walk()) + o->oBowserTimer = 0; + // Start walking + if (bowser_set_anim_look_up_and_walk()) { o->oSubAction++; - } else if (o->oSubAction == 1) { - if (bowser_set_anim_slow_gait()) { - o->oBowserUnkF8++; - if (o->oBowserUnkF4 & 0x20000) { - if (o->oBowserUnkF8 > 4) - o->oBowserUnkF4 &= ~0x20000; - } else if (angleFromMario < 0x2000) - o->oSubAction++; } - } else if (bowser_set_anim_look_down()) - o->oAction = 0; + } else if (o->oSubAction == 1) { + // Keep walking slowly + if (bowser_set_anim_slow_gait()) { + o->oBowserTimer++; + // Reset fire sky status + if (o->oBowserStatus & BOWSER_STATUS_FIRE_SKY) { + if (o->oBowserTimer > 4) { + o->oBowserStatus &= ~BOWSER_STATUS_FIRE_SKY; + } + // Do subaction below if angles is less than 0x2000 + } else if (angleFromMario < 0x2000) { + o->oSubAction++; + } + } + // Stop walking and set to default action + } else if (bowser_set_anim_look_down_stop_walk()) { + o->oAction = BOWSER_ACT_DEFAULT; + } } +/** + * Makes Bowser teleport while invisible + */ void bowser_act_teleport(void) { switch (o->oSubAction) { - case 0: + // Set opacity target to invisible and become intangible + case BOWSER_SUB_ACT_TELEPORT_START: cur_obj_become_intangible(); - o->oBowserUnk1AC = 0; - o->oBowserUnkF8 = 30; - if (o->oTimer == 0) + o->oBowserTargetOpacity = 0; + o->oBowserTimer = 30; // set timer value + // Play sound effect + if (o->oTimer == 0) { cur_obj_play_sound_2(SOUND_OBJ2_BOWSER_TELEPORT); + } + // Bowser is invisible, move angle to face Mario if (o->oOpacity == 0) { o->oSubAction++; o->oMoveAngleYaw = o->oAngleToMario; } break; - case 1: - if (o->oBowserUnkF8--) + case BOWSER_SUB_ACT_TELEPORT_MOVE: + // reduce timer and set velocity teleport while at it + if (o->oBowserTimer--) { o->oForwardVel = 100.0f; - else { - o->oSubAction = 2; - o->oMoveAngleYaw = o->oAngleToMario; } - if (abs_angle_diff(o->oMoveAngleYaw, o->oAngleToMario) > 0x4000) + else { + o->oSubAction = BOWSER_SUB_ACT_TELEPORT_STOP; + o->oMoveAngleYaw = o->oAngleToMario; // update angle + } + // + if (abs_angle_diff(o->oMoveAngleYaw, o->oAngleToMario) > 0x4000) { if (o->oDistanceToMario > 500.0f) { - o->oSubAction = 2; - o->oMoveAngleYaw = o->oAngleToMario; // large change in angle? + o->oSubAction = BOWSER_SUB_ACT_TELEPORT_STOP; + o->oMoveAngleYaw = o->oAngleToMario; // update angle cur_obj_play_sound_2(SOUND_OBJ2_BOWSER_TELEPORT); } + } break; - case 2: - o->oForwardVel = 0.0f; - o->oBowserUnk1AC = 0xFF; - if (o->oOpacity == 0xFF) - o->oAction = 0; + // Set opacity target to visible and become tangible + case BOWSER_SUB_ACT_TELEPORT_STOP: + o->oForwardVel = 0.0f; // reset velocity + o->oBowserTargetOpacity = 0xFF; + // Set to default action once visible + if (o->oOpacity == 0xFF) { + o->oAction = BOWSER_ACT_DEFAULT; + } cur_obj_become_tangible(); break; } } -void bowser_act_spit_fire_into_sky(void) // only in sky -{ +/** + * Makes Bowser do a fire split into the sky + */ +void bowser_act_spit_fire_into_sky(void) { s32 frame; - cur_obj_init_animation_with_sound(11); + // Play animation + cur_obj_init_animation_with_sound(BOWSER_ANIM_BREATH_UP); + // Set frames frame = o->header.gfx.animInfo.animFrame; + // Spawn flames in the middle of the animation if (frame > 24 && frame < 36) { cur_obj_play_sound_1(SOUND_AIR_BOWSER_SPIT_FIRE); - if (frame == 35) + if (frame == 35) { // Spawns Blue flames at this frame spawn_object_relative(1, 0, 0x190, 0x64, o, MODEL_RED_FLAME, bhvBlueBowserFlame); - else + } else { // Spawns Red flames spawn_object_relative(0, 0, 0x190, 0x64, o, MODEL_RED_FLAME, bhvBlueBowserFlame); + } } - if (cur_obj_check_if_near_animation_end()) - o->oAction = 0; - o->oBowserUnkF4 |= 0x20000; + // Return to default act once the animation is over + if (cur_obj_check_if_near_animation_end()) { + o->oAction = BOWSER_ACT_DEFAULT; + } + // Set fire sky status + o->oBowserStatus |= BOWSER_STATUS_FIRE_SKY; } +/** + * Flips Bowser back on stage if he hits a mine with more than 1 health + */ void bowser_act_hit_mine(void) { + // Similar vel values from bowser_fly_back_dead if (o->oTimer == 0) { o->oForwardVel = -400.0f; o->oVelY = 100.0f; o->oMoveAngleYaw = o->oBowserAngleToCentre + 0x8000; - o->oBowserEyesShut = 1; + o->oBowserEyesShut = TRUE; // close eyes } - if (o->oSubAction == 0) { - cur_obj_init_animation_with_sound(25); + // Play flip animation + if (o->oSubAction == BOWSER_SUB_ACT_HIT_MINE_START) { + cur_obj_init_animation_with_sound(BOWSER_ANIM_FLIP); o->oSubAction++; - o->oBowserUnkF8 = 0; - } else if (o->oSubAction == 1) { - cur_obj_init_animation_with_sound(25); + o->oBowserTimer = 0; + // Play flip animation again, extend it and play bounce effects + } else if (o->oSubAction == BOWSER_SUB_ACT_HIT_MINE_FALL) { + cur_obj_init_animation_with_sound(BOWSER_ANIM_FLIP); cur_obj_extend_animation_if_at_end(); - bowser_bounce(&o->oBowserUnkF8); - if ((o->oBowserUnkF8 > 2)) { - cur_obj_init_animation_with_sound(26); + bowser_bounce_effects(&o->oBowserTimer); + // Reset vel and stand up + if (o->oBowserTimer > 2) { + cur_obj_init_animation_with_sound(BOWSER_ANIM_STAND_UP_FROM_FLIP); o->oVelY = 0.0f; o->oForwardVel = 0.0f; o->oSubAction++; } - } else if (o->oSubAction == 2) { + // Play these actions once he is stand up + } else if (o->oSubAction == BOWSER_SUB_ACT_HIT_MINE_STOP) { if (cur_obj_check_if_near_animation_end()) { - if (o->oHealth == 1) - o->oAction = 3; - else - o->oAction = 0; - o->oBowserEyesShut = 0; + // Makes Bowser dance at one health (in BITS) + if (o->oHealth == 1) { + o->oAction = BOWSER_ACT_DANCE; + } else { + o->oAction = BOWSER_ACT_DEFAULT; + } + o->oBowserEyesShut = FALSE; // open eyes } } else { } } -s32 bowser_set_anim_in_air(void) { - cur_obj_init_animation_with_sound(9); - if (cur_obj_check_anim_frame(11)) - return 1; - else - return 0; +/** + * Makes Bowser do his jump start animation + * Returns TRUE on the middle of the jump + */ +s32 bowser_set_anim_jump(void) { + cur_obj_init_animation_with_sound(BOWSER_ANIM_JUMP_START); + if (cur_obj_check_anim_frame(11)) { + return TRUE; + } else { + return FALSE; + } } +/** + * Reset speed, play jump stop animation and do attacks in BITDW + * Returns TRUE when Bowser lands + */ s32 bowser_land(void) { if (o->oMoveFlags & OBJ_MOVE_LANDED) { o->oForwardVel = 0; o->oVelY = 0; spawn_mist_particles_variable(0, 0, 60.0f); - cur_obj_init_animation_with_sound(8); + cur_obj_init_animation_with_sound(BOWSER_ANIM_JUMP_STOP); o->header.gfx.animInfo.animFrame = 0; cur_obj_start_cam_event(o, CAM_EVENT_BOWSER_JUMP); - if (BITDW) { - if (o->oDistanceToMario < 850.0f) - gMarioObject->oInteractStatus |= INT_STATUS_MARIO_UNK1; - else - gMarioObject->oInteractStatus |= INT_STATUS_HOOT_GRABBED_BY_MARIO; // hmm... + // Set status attacks in BITDW since the other levels + // have different attacks defined + if (o->oBehParams2ndByte == BOWSER_BP_BITDW) { + if (o->oDistanceToMario < 850.0f) { + gMarioObject->oInteractStatus |= INT_STATUS_MARIO_KNOCKBACK_DMG; + } else { + gMarioObject->oInteractStatus |= INT_STATUS_MARIO_STUNNED; + } } - return 1; - } else - return 0; + return TRUE; + } else { + return FALSE; + } } +/** + * Makes Bowser do a second hop speed only in BITS + */ void bowser_short_second_hop(void) { - if (BITS && o->oBowserUnkF4 & 0x10000) - if (o->oBowserDistToCentre > 1000.0f) + if (o->oBehParams2ndByte == BOWSER_BP_BITS && o->oBowserStatus & BOWSER_STATUS_BIG_JUMP) { + if (o->oBowserDistToCentre > 1000.0f) { o->oForwardVel = 60.0f; + } + } } -void bowser_act_jump(void) { +/** + * Makes Bowser do a big jump + */ +void bowser_act_big_jump(void) { UNUSED s32 unused; if (o->oSubAction == 0) { - if (bowser_set_anim_in_air()) { - if (BITS && o->oBowserUnkF4 & 0x10000) + // Set jump animation + if (bowser_set_anim_jump()) { + // Set vel depending of the stage and status + if (o->oBehParams2ndByte == BOWSER_BP_BITS && o->oBowserStatus & BOWSER_STATUS_BIG_JUMP) { o->oVelY = 70.0f; - else + } else { o->oVelY = 80.0f; - o->oBowserUnkF8 = 0; + } + o->oBowserTimer = 0; bowser_short_second_hop(); o->oSubAction++; } } else if (o->oSubAction == 1) { -#ifndef VERSION_JP - if (o->oBehParams2ndByte == 2 && o->oBowserUnkF4 & 0x10000) +#if BUGFIX_BOWSER_FALLEN_OFF_STAGE + // Reset Bowser back on stage in BITS if he doesn't land properly + if (o->oBehParams2ndByte == BOWSER_BP_BITS && o->oBowserStatus & BOWSER_STATUS_BIG_JUMP) { bowser_reset_fallen_off_stage(); + } #endif + // Land on stage, reset status jump and velocity if (bowser_land()) { - o->oBowserUnkF4 &= ~0x10000; + o->oBowserStatus &= ~BOWSER_STATUS_BIG_JUMP; o->oForwardVel = 0.0f; o->oSubAction++; + // Spawn shockwave (BITS only) if is not on a platform bowser_spawn_shockwave(); - if (BITFS) - o->oAction = 19; + // Tilt platform in BITFS + if (o->oBehParams2ndByte == BOWSER_BP_BITFS) { + o->oAction = BOWSER_ACT_TILT_LAVA_PLATFORM; + } } else { } - } else if (cur_obj_check_if_near_animation_end()) - o->oAction = 0; + // Set to default action when the animation is over + } else if (cur_obj_check_if_near_animation_end()) { + o->oAction = BOWSER_ACT_DEFAULT; + } } -void bowser_act_jump_towards_mario(void) { - f32 sp1C = D_8032F50C[0]; - f32 sp18 = D_8032F510[0]; +/** + * Fixed values for the quick jump action + */ +s16 sBowserVelYAir[] = { 60 }; +s16 sBowserFVelAir[] = { 50 }; + +/** + * Makes Bowser do a "quick" jump in BITDW + */ +void bowser_act_quick_jump(void) { + f32 velY = sBowserVelYAir[0]; + f32 fVel = sBowserFVelAir[0]; if (o->oSubAction == 0) { - if (bowser_set_anim_in_air()) { - o->oVelY = sp1C; - o->oForwardVel = sp18; - o->oBowserUnkF8 = 0; + // Set fixed val positions while jumping + if (bowser_set_anim_jump()) { + o->oVelY = velY; + o->oForwardVel = fVel; + o->oBowserTimer = 0; o->oSubAction++; } + // Lands then quickly returns to default action } else if (o->oSubAction == 1) { - if (bowser_land()) + if (bowser_land()) { o->oSubAction++; - } else if (cur_obj_check_if_near_animation_end()) - o->oAction = 0; + } + } else if (cur_obj_check_if_near_animation_end()) { + o->oAction = BOWSER_ACT_DEFAULT; + } } +/** + * Makes Bowser moving around if he is on an edge floor + */ void bowser_act_hit_edge(void) { + // Reset speed and timer o->oForwardVel = 0.0f; - if (o->oTimer == 0) - o->oBowserUnkF8 = 0; + if (o->oTimer == 0) { + o->oBowserTimer = 0; + } switch (o->oSubAction) { case 0: - cur_obj_init_animation_with_sound(23); - if (cur_obj_check_if_near_animation_end()) - o->oBowserUnkF8++; - if (o->oBowserUnkF8 > 0) + // Move on the edge + cur_obj_init_animation_with_sound(BOWSER_ANIM_EDGE_MOVE); + if (cur_obj_check_if_near_animation_end()) { + o->oBowserTimer++; + } + if (o->oBowserTimer > 0) { o->oSubAction++; + } break; case 1: - cur_obj_init_animation_with_sound(24); - if (cur_obj_check_if_near_animation_end()) - o->oAction = 11; + // Stop moving on the edge + cur_obj_init_animation_with_sound(BOWSER_ANIM_EDGE_STOP); + // Turn around once the animation ends + if (cur_obj_check_if_near_animation_end()) { + o->oAction = BOWSER_ACT_TURN_FROM_EDGE; + } break; } } +/** + * Makes Bowser do a fire split attack + */ void bowser_act_spit_fire_onto_floor(void) { - if (gHudDisplay.wedges < 4) - o->oBowserUnk108 = 3; - else - o->oBowserUnk108 = random_float() * 3.0f + 1.0f; - cur_obj_init_animation_with_sound(22); - if (cur_obj_check_anim_frame(5)) + // Set fixed rand value if Mario is low health + if (gHudDisplay.wedges < 4) { + o->oBowserRandSplitFloor = 3; + } else { + o->oBowserRandSplitFloor = random_float() * 3.0f + 1.0f; + } + + // Play animation and split fire at a specific frame + cur_obj_init_animation_with_sound(BOWSER_ANIM_BREATH_QUICK); + if (cur_obj_check_anim_frame(5)) { obj_spit_fire(0, 200, 180, 7.0f, MODEL_RED_FLAME, 30.0f, 10.0f, 0x1000); - if (cur_obj_check_if_near_animation_end()) + } + // Use subaction as a timer when the animation is over + if (cur_obj_check_if_near_animation_end()) { o->oSubAction++; - if (o->oSubAction >= o->oBowserUnk108) - o->oAction = 0; + } + // Return to default act once we get past rand value + if (o->oSubAction >= o->oBowserRandSplitFloor) { + o->oAction = BOWSER_ACT_DEFAULT; + } } -s32 bowser_turn_on_timer(s32 a0, s16 a1) { +/** + * Turns around Bowser from an specific yaw angle + * Returns TRUE once the timer is bigger than the time set + */ +s32 bowser_turn_on_timer(s32 time, s16 yaw) { if (o->oSubAction == 0) { - if (cur_obj_init_animation_and_check_if_near_end(15)) + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_LOOK_UP_START_WALK)) { o->oSubAction++; + } } else if (o->oSubAction == 1) { - if (cur_obj_init_animation_and_check_if_near_end(14)) + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_LOOK_DOWN_STOP_WALK)) { o->oSubAction++; - } else - cur_obj_init_animation_with_sound(12); + } + } else { + cur_obj_init_animation_with_sound(BOWSER_ANIM_IDLE); + } o->oForwardVel = 0.0f; - o->oMoveAngleYaw += a1; - if (o->oTimer >= a0) - return 1; - else - return 0; + o->oMoveAngleYaw += yaw; + if (o->oTimer >= time) { + return TRUE; + } else { + return FALSE; + } } +/** + * Makes Bowser turn around after hitting the edge + */ void bowser_act_turn_from_edge(void) { - if (bowser_turn_on_timer(63, 0x200)) - o->oAction = 0; + if (bowser_turn_on_timer(63, 0x200)) { + o->oAction = BOWSER_ACT_DEFAULT; + } } +/** + * Makes Bowser charge (run) to Mario + */ void bowser_act_charge_mario(void) { - s32 sp34; - if (o->oTimer == 0) + s32 time; + // Reset Speed to prepare charge + if (o->oTimer == 0) { o->oForwardVel = 0.0f; + } + switch (o->oSubAction) { - case 0: - o->oBowserUnkF8 = 0; - if (cur_obj_init_animation_and_check_if_near_end(18)) - o->oSubAction = 1; - break; - case 1: - o->oForwardVel = 50.0f; - if (cur_obj_init_animation_and_check_if_near_end(0x13) != 0) { - o->oBowserUnkF8++; - if (o->oBowserUnkF8 >= 6) - o->oSubAction = 3; - if (o->oBowserUnkF8 >= 2) - if (abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw) > 0x2000) - o->oSubAction = 3; + case BOWSER_SUB_ACT_CHARGE_START: + // Start running + o->oBowserTimer = 0; + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_RUN_START)) { + o->oSubAction = BOWSER_SUB_ACT_CHARGE_RUN; } + break; + case BOWSER_SUB_ACT_CHARGE_RUN: + // Set speed to run + o->oForwardVel = 50.0f; + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_RUN)) { + o->oBowserTimer++; + // Split if 6 timer frames has passed + if (o->oBowserTimer >= 6) { + o->oSubAction = BOWSER_SUB_ACT_CHARGE_SLIP; + } + // Slip if Mario has a differentiable angle and 2 timer frames has passed + if (o->oBowserTimer >= 2) { + if (abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw) > 0x2000) { + o->oSubAction = BOWSER_SUB_ACT_CHARGE_SLIP; + } + } + } + // Rotate to Mario cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x200); break; - case 3: - o->oBowserUnkF8 = 0; - cur_obj_init_animation_with_sound(21); + case BOWSER_SUB_ACT_CHARGE_SLIP: + // Spawn smoke puff while slipping + o->oBowserTimer = 0; + cur_obj_init_animation_with_sound(BOWSER_ANIM_RUN_SLIP); spawn_object_relative_with_scale(0, 100, -50, 0, 3.0f, o, MODEL_SMOKE, bhvWhitePuffSmoke2); spawn_object_relative_with_scale(0, -100, -50, 0, 3.0f, o, MODEL_SMOKE, bhvWhitePuffSmoke2); - if (approach_f32_signed(&o->oForwardVel, 0, -1.0f)) - o->oSubAction = 2; + // End Charge once Bowser stops running + if (approach_f32_signed(&o->oForwardVel, 0, -1.0f)) { + o->oSubAction = BOWSER_SUB_ACT_CHARGE_END; + } cur_obj_extend_animation_if_at_end(); break; - case 2: + case BOWSER_SUB_ACT_CHARGE_END: + // Stop running o->oForwardVel = 0.0f; - cur_obj_init_animation_with_sound(20); + cur_obj_init_animation_with_sound(BOWSER_ANIM_RUN_STOP); if (cur_obj_check_if_near_animation_end()) { - if (BITS) - sp34 = 10; - else - sp34 = 30; - if (o->oBowserUnkF8 > sp34) - o->oAction = 0; - o->oBowserUnkF8++; + // Set time delay to go to default action + if (o->oBehParams2ndByte == BOWSER_BP_BITS) { + time = 10; + } else { + time = 30; + } + if (o->oBowserTimer > time) { + o->oAction = BOWSER_ACT_DEFAULT; + } + o->oBowserTimer++; } cur_obj_extend_animation_if_at_end(); break; } - if (o->oMoveFlags & OBJ_MOVE_HIT_EDGE) - o->oAction = 10; + // Bowser is close to falling so set hit edge action + if (o->oMoveFlags & OBJ_MOVE_HIT_EDGE) { + o->oAction = BOWSER_ACT_HIT_EDGE; + } } +/** + * Checks if Bowser hits a mine from a distance, returns TRUE if so + */ s32 bowser_check_hit_mine(void) { struct Object *mine; - f32 sp18; - mine = cur_obj_find_nearest_object_with_behavior(bhvBowserBomb, &sp18); - if (mine != NULL && sp18 < 800.0f) { + f32 dist; + + mine = cur_obj_find_nearest_object_with_behavior(bhvBowserBomb, &dist); + if (mine != NULL && dist < 800.0f) { mine->oInteractStatus |= INT_STATUS_HIT_MINE; - return 1; + return TRUE; } - return 0; + + return FALSE; } -void bowser_act_thrown_dropped(void) -{ +/** + * Bowser's thrown act that gets called after Mario releases him + */ +void bowser_act_thrown(void) { UNUSED s32 unused; + // Keep Bowser's timer at 0 unless he lands if (o->oTimer < 2) - o->oBowserUnkF8 = 0; + o->oBowserTimer = 0; if (o->oSubAction == 0) { - cur_obj_init_animation_with_sound(2); - bowser_bounce(&o->oBowserUnkF8); + // Play shake animations and do bounce effects + cur_obj_init_animation_with_sound(BOWSER_ANIM_SHAKING); + bowser_bounce_effects(&o->oBowserTimer); + // Reset speed when he moves on ground if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) { o->oForwardVel = 0.0f; - o->oSubAction++; + o->oSubAction++; // stops this current subaction } - } else if (cur_obj_init_animation_and_check_if_near_end(0)) - o->oAction = 0; + // Stand up and after play, set to default act + } else if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_STAND_UP)) + o->oAction = BOWSER_ACT_DEFAULT; + // Hit mine check, reduce health and set specific action depending of it if (bowser_check_hit_mine()) { o->oHealth--; - if (o->oHealth <= 0) - o->oAction = 4; - else - o->oAction = 12; + if (o->oHealth <= 0) { + o->oAction = BOWSER_ACT_DEAD; + } else { + o->oAction = BOWSER_ACT_HIT_MINE; + } } } +/** + * Set Bowser invisible and stops him (after falling) + */ void bowser_set_goal_invisible(void) { - o->oBowserUnk1AC = 0; + o->oBowserTargetOpacity = 0; if (o->oOpacity == 0) { o->oForwardVel = 0.0f; o->oVelY = 0.0f; @@ -676,60 +1021,83 @@ void bowser_set_goal_invisible(void) { } } +/** + * Makes Bowser jump back on stage after falling + */ void bowser_act_jump_onto_stage(void) { - s32 sp2C; + s32 onDynamicFloor; UNUSED s32 unused; - struct Surface *sp24 = o->oFloor; - if (sp24 != NULL && sp24->flags & 1) - sp2C = 1; - else - sp2C = 0; - o->oBowserUnkF4 |= 0x10000; + struct Surface *floor = o->oFloor; + + // Set dynamic floor check (Object platforms) + if (floor != NULL && floor->flags & SURFACE_FLAG_DYNAMIC) { + onDynamicFloor = TRUE; + } else { + onDynamicFloor = FALSE; + } + // Set status Jump + o->oBowserStatus |= BOWSER_STATUS_BIG_JUMP; + switch (o->oSubAction) { - case 0: + // Stops Bowser and makes him invisible + case BOWSER_SUB_ACT_JUMP_ON_STAGE_IDLE: if (o->oTimer == 0) { o->oFaceAnglePitch = 0; o->oFaceAngleRoll = 0; } //? missing else o->oFaceAnglePitch += 0x800; o->oFaceAngleRoll += 0x800; - if (!(o->oFaceAnglePitch & 0xFFFF)) + if (!(o->oFaceAnglePitch & 0xFFFF)) { o->oSubAction++; + } bowser_set_goal_invisible(); break; - case 1: - cur_obj_init_animation_with_sound(9); + // Start jump animation and make him visible after an animation frame + case BOWSER_SUB_ACT_JUMP_ON_STAGE_START: + cur_obj_init_animation_with_sound(BOWSER_ANIM_JUMP_START); if (cur_obj_check_anim_frame(11)) { o->oMoveAngleYaw = o->oBowserAngleToCentre; o->oVelY = 150.0f; - o->oBowserUnk1AC = 0xFF; - o->oBowserUnkF8 = 0; + o->oBowserTargetOpacity = 0xFF; + o->oBowserTimer = 0; o->oSubAction++; - } else + } else { bowser_set_goal_invisible(); + } break; - case 2: + // Approach him back on stage + case BOWSER_SUB_ACT_JUMP_ON_STAGE_LAND: if (o->oPosY > o->oHomeY) { o->oDragStrength = 0.0f; if (o->oBowserDistToCentre < 2500.0f) { - if (absf(o->oFloorHeight - o->oHomeY) < 100.0f) + if (absf(o->oFloorHeight - o->oHomeY) < 100.0f) { approach_f32_signed(&o->oForwardVel, 0, -5.0f); - else + } else { cur_obj_forward_vel_approach_upward(150.0f, 2.0f); + } } else cur_obj_forward_vel_approach_upward(150.0f, 2.0f); } + // Land on stage if (bowser_land()) { o->oDragStrength = 10.0f; o->oSubAction++; - if (sp2C == 0) + // Spawn shockwave (BITS only) if is not on a platform + if (onDynamicFloor == FALSE) { bowser_spawn_shockwave(); - else if (BITS) - o->oAction = 13; - if (BITFS) - o->oAction = 19; + // If is on a dynamic floor in BITS, then jump + // because of the falling platform + } else if (o->oBehParams2ndByte == BOWSER_BP_BITS) { + o->oAction = BOWSER_ACT_BIG_JUMP; + } + // If is on a dynamic floor in BITFS, then tilt platform + if (o->oBehParams2ndByte == BOWSER_BP_BITFS) { + o->oAction = BOWSER_ACT_TILT_LAVA_PLATFORM; + } } -#ifndef VERSION_JP + // Reset him back on stage if he still didn't landed yet + // Post-JP made this check as a separate function +#if BUGFIX_BOWSER_FALLEN_OFF_STAGE bowser_reset_fallen_off_stage(); #else if (o->oVelY < 0.0f && o->oPosY < o->oHomeY - 300.0f) { @@ -739,10 +1107,11 @@ void bowser_act_jump_onto_stage(void) { } #endif break; - case 3: + // Bowser landed, so reset action after he's done jumping + case BOWSER_SUB_ACT_JUMP_ON_STAGE_STOP: if (cur_obj_check_if_near_animation_end()) { - o->oAction = 0; - o->oBowserUnkF4 &= ~0x10000; + o->oAction = BOWSER_ACT_DEFAULT; + o->oBowserStatus &= ~BOWSER_STATUS_BIG_JUMP; cur_obj_extend_animation_if_at_end(); } break; @@ -750,77 +1119,123 @@ void bowser_act_jump_onto_stage(void) { print_debug_bottom_up("sp %d", o->oForwardVel); } +/** + * The frames of the Bowser's timer on which to play a "stomp" sound + */ +s8 sBowserDanceStepNoises[] = { 24, 42, 60, -1 }; + +/** + * Makes Bowser's dance as a "taunt" + */ void bowser_act_dance(void) { - if (is_item_in_array(o->oTimer, D_8032F514)) + // Play a stomp sound effect on certain frames + if (is_item_in_array(o->oTimer, sBowserDanceStepNoises)) { cur_obj_play_sound_2(SOUND_OBJ_BOWSER_WALK); - if (cur_obj_init_animation_and_check_if_near_end(10)) - o->oAction = 0; + } + // Play dance animation and after that return to default action + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_DANCE)) { + o->oAction = BOWSER_ACT_DEFAULT; + } } -void bowser_spawn_grand_star_key(void) { - if (BITS) +/** + * Spawn collectable that Bowser spawns after despawning + * Spawns a Key in BITDW/BITFS or Grand Star in BITS + */ +void bowser_spawn_collectable(void) { + if (o->oBehParams2ndByte == BOWSER_BP_BITS) { gSecondCameraFocus = spawn_object(o, MODEL_STAR, bhvGrandStar); - else { + } else { gSecondCameraFocus = spawn_object(o, MODEL_BOWSER_KEY, bhvBowserKey); cur_obj_play_sound_2(SOUND_GENERAL2_BOWSER_KEY); } gSecondCameraFocus->oAngleVelYaw = o->oAngleVelYaw; } +/** + * Makes Bowser fly back on stage defeated + */ void bowser_fly_back_dead(void) { - cur_obj_init_animation_with_sound(16); - if (BITS) + cur_obj_init_animation_with_sound(BOWSER_ANIM_FLIP_DOWN); + // More knockback in BITS + if (o->oBehParams2ndByte == BOWSER_BP_BITS) { o->oForwardVel = -400.0f; - else + } else { o->oForwardVel = -200.0f; + } o->oVelY = 100.0f; o->oMoveAngleYaw = o->oBowserAngleToCentre + 0x8000; - o->oBowserUnkF8 = 0; - o->oSubAction++; + o->oBowserTimer = 0; + o->oSubAction++; // BOWSER_SUB_ACT_DEAD_BOUNCE } +/** + * Plays bounce effects after landing upside down + */ void bowser_dead_bounce(void) { - o->oBowserEyesShut = 1; - bowser_bounce(&o->oBowserUnkF8); - if (o->oMoveFlags & OBJ_MOVE_LANDED) + o->oBowserEyesShut = TRUE; // close eyes + bowser_bounce_effects(&o->oBowserTimer); + if (o->oMoveFlags & OBJ_MOVE_LANDED) { cur_obj_play_sound_2(SOUND_OBJ_BOWSER_WALK); + } if (o->oMoveFlags & OBJ_MOVE_ON_GROUND) { o->oForwardVel = 0.0f; - o->oSubAction++; + o->oSubAction++; // BOWSER_SUB_ACT_DEAD_WAIT } } +/** + * Wait for Mario to get close while Bowser is defeated + * Returns TRUE if he is close enough + */ s32 bowser_dead_wait_for_mario(void) { - s32 ret = 0; + s32 ret = FALSE; cur_obj_become_intangible(); - if (cur_obj_init_animation_and_check_if_near_end(17) && o->oDistanceToMario < 700.0f - && abs_angle_diff(gMarioObject->oMoveAngleYaw, o->oAngleToMario) > 0x6000) - ret = 1; + if (cur_obj_init_animation_and_check_if_near_end(BOWSER_ANIM_LAY_DOWN) && o->oDistanceToMario < 700.0f + && abs_angle_diff(gMarioObject->oMoveAngleYaw, o->oAngleToMario) > 0x6000) { + ret = TRUE; + } cur_obj_extend_animation_if_at_end(); - o->oBowserUnkF8 = 0; + o->oBowserTimer = 0; return ret; } -s32 bowser_dead_twirl_into_trophy(void) { - s32 ret = 0; - if (o->header.gfx.scale[0] < 0.8) +/** + * Makes Bowser twirl up by changing his scale + * Returns TRUE once done + */ +s32 bowser_dead_twirl_up(void) { + s32 ret = FALSE; + // Set angle rotation once he has low X scale value + if (o->header.gfx.scale[0] < 0.8) { o->oAngleVelYaw += 0x80; + } + // Slowly scale down his X and Z value if (o->header.gfx.scale[0] > 0.2) { o->header.gfx.scale[0] = o->header.gfx.scale[0] - 0.02; o->header.gfx.scale[2] = o->header.gfx.scale[2] - 0.02; } else { + // Now scale down his Y value (and send Bowser up) o->header.gfx.scale[1] = o->header.gfx.scale[1] - 0.01; o->oVelY = 20.0f; o->oGravity = 0.0f; } - if (o->header.gfx.scale[1] < 0.5) - ret = 1; + // At half Y scale value, he is high enough, so we are done + if (o->header.gfx.scale[1] < 0.5) { + ret = TRUE; + } + // Copy angle rotation to moving rotation o->oMoveAngleYaw += o->oAngleVelYaw; - if (o->oOpacity >= 3) + // Slowly fade out + if (o->oOpacity >= 3) { o->oOpacity -= 2; + } return ret; } +/** + * Hides Bowser after his death sequence is done + */ void bowser_dead_hide(void) { cur_obj_scale(0); o->oForwardVel = 0; @@ -828,297 +1243,457 @@ void bowser_dead_hide(void) { o->oGravity = 0; } -s32 bowser_dead_not_bits_end(void) { - s32 ret = 0; - if (o->oBowserUnkF8 < 2) { - if (o->oBowserUnkF8 == 0) { +/** + * Dialog values that are set on each stage Bowser's is defeated + */ +s16 sBowserDefeatedDialogText[3] = { DIALOG_119, DIALOG_120, DIALOG_121 }; + +/** + * Bowser's dead sequence that plays in BITDW/BITFS + * Returns TRUE once done + */ +s32 bowser_dead_default_stage_ending(void) { + s32 ret = FALSE; + if (o->oBowserTimer < 2) { + // Lower music volume + if (o->oBowserTimer == 0) { seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); - o->oBowserUnkF8++; + o->oBowserTimer++; } - if (cur_obj_update_dialog(2, 18, sBowserDefeatedDialogText[o->oBehParams2ndByte], 0)) { - o->oBowserUnkF8++; + // Play Bowser defeated dialog + if (cur_obj_update_dialog(MARIO_DIALOG_LOOK_UP, + (DIALOG_FLAG_TEXT_DEFAULT | DIALOG_FLAG_TIME_STOP_ENABLED), + sBowserDefeatedDialogText[o->oBehParams2ndByte], 0)) { + // Dialog is done, fade out music and play explode sound effect + o->oBowserTimer++; cur_obj_play_sound_2(SOUND_GENERAL2_BOWSER_EXPLODE); seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60); seq_player_fade_out(SEQ_PLAYER_LEVEL, 1); } - } else if (bowser_dead_twirl_into_trophy()) { + // Hide Bowser and spawn collectable once done twirling + } else if (bowser_dead_twirl_up()) { bowser_dead_hide(); - spawn_triangle_break_particles(20, 116, 1.0f, 0); - bowser_spawn_grand_star_key(); - set_mario_npc_dialog(0); - ret = 1; + spawn_triangle_break_particles(20, MODEL_YELLOW_COIN, 1.0f, 0); + bowser_spawn_collectable(); + set_mario_npc_dialog(MARIO_DIALOG_STOP); + ret = TRUE; } return ret; } -s32 bowser_dead_bits_end(void) { +/** + * Bowser's dead sequence that plays in BITS + * Returns TRUE once done + */ +s32 bowser_dead_final_stage_ending(void) { UNUSED s32 unused; - s32 ret = 0; + s32 ret = FALSE; s32 dialogID; - if (o->oBowserUnkF8 < 2) { - if (gHudDisplay.stars < 120) + if (o->oBowserTimer < 2) { + // Set dialog whenever you have 120 stars or not + if (gHudDisplay.stars < 120) { dialogID = DIALOG_121; - else + } else { dialogID = DIALOG_163; - if (o->oBowserUnkF8 == 0) { - seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); - o->oBowserUnkF8++; } - if (cur_obj_update_dialog(2, 18, dialogID, 0)) { - cur_obj_set_model(MODEL_BOWSER2); + // Lower music volume + if (o->oBowserTimer == 0) { + seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); + o->oBowserTimer++; + } + // Play Bowser defeated dialog + if (cur_obj_update_dialog(MARIO_DIALOG_LOOK_UP, + (DIALOG_FLAG_TEXT_DEFAULT | DIALOG_FLAG_TIME_STOP_ENABLED), dialogID, 0)) { + // Dialog is done, fade out music and spawn grand star + cur_obj_set_model(MODEL_BOWSER_NO_SHADOW); seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60); seq_player_fade_out(SEQ_PLAYER_LEVEL, 1); - bowser_spawn_grand_star_key(); - o->oBowserUnkF8++; + bowser_spawn_collectable(); + o->oBowserTimer++; } + // Slowly fade him out } else if (o->oOpacity > 4) o->oOpacity -= 4; else { + // And at last, hide him bowser_dead_hide(); - ret = 1; + ret = TRUE; } return ret; } +/** + * Bowser's dead action, plays when he has no health left + * This action is divided in subaction functions + */ void bowser_act_dead(void) { switch (o->oSubAction) { - case 0: + case BOWSER_SUB_ACT_DEAD_FLY_BACK: bowser_fly_back_dead(); break; - case 1: + case BOWSER_SUB_ACT_DEAD_BOUNCE: bowser_dead_bounce(); break; - case 2: + case BOWSER_SUB_ACT_DEAD_WAIT: + // Check if Mario is close to Bowser if (bowser_dead_wait_for_mario()) { - o->oBowserUnkF8 = 0; - if (BITS) - o->oSubAction = 10; - else { + o->oBowserTimer = 0; + // Set different (final) subaction in BITS + // Non-BITS Bowser uses default subaction and sets dithering + if (o->oBehParams2ndByte == BOWSER_BP_BITS) { + o->oSubAction = BOWSER_SUB_ACT_DEAD_FINAL_END; + } else { o->activeFlags |= ACTIVE_FLAG_DITHERED_ALPHA; - o->oSubAction++; + o->oSubAction++; // BOWSER_SUB_ACT_DEAD_DEFAULT_END } } break; - case 3: - if (bowser_dead_not_bits_end()) - o->oSubAction++; + case BOWSER_SUB_ACT_DEAD_DEFAULT_END: + if (bowser_dead_default_stage_ending()) { + o->oSubAction++; // BOWSER_SUB_ACT_DEAD_DEFAULT_END_OVER + } break; - case 4: + case BOWSER_SUB_ACT_DEAD_DEFAULT_END_OVER: break; - case 10: - if (bowser_dead_bits_end()) - o->oSubAction++; + case BOWSER_SUB_ACT_DEAD_FINAL_END: + if (bowser_dead_final_stage_ending()) { + o->oSubAction++; // BOWSER_SUB_ACT_DEAD_FINAL_END_OVER + } break; - case 11: + case BOWSER_SUB_ACT_DEAD_FINAL_END_OVER: break; } } -void bowser_tilt_platform(struct Object *platform, s16 a1) { +/** + * Sets values for the BITFS platform to tilt + */ +void bowser_tilt_platform(struct Object *platform, s16 angSpeed) { s16 angle; angle = o->oBowserAngleToCentre + 0x8000; - platform->oAngleVelPitch = coss(angle) * a1; - platform->oAngleVelRoll = -sins(angle) * a1; + platform->oAngleVelPitch = coss(angle) * angSpeed; + platform->oAngleVelRoll = -sins(angle) * angSpeed; } -void bowser_act_ride_tilting_platform(void) { +/** + * Struct for the BITFS tilt platform + */ +struct BowserTiltPlatformInfo { + // Flag value to make sure platform moves smoothly + // 0 = Don't move + // 1 = Move angle behind Bowser + // -1 = Move angle in front of Bowser + s16 flag; + // Sets platform's tilt angle speed (pattern: positive then negative) + s16 angSpeed; + // Sets how much time the platform can tilt, increases each move + s16 time; +}; + +/** + * Data for the BITFS tilt Platform + */ +struct BowserTiltPlatformInfo sBowsertiltPlatformData[] = { + { 1, 10, 40 }, + { 0, 0, 74 }, + { -1, -10, 114 }, + { 1, -20, 134 }, + { -1, 20, 154 }, + { 1, 40, 164 }, + { -1, -40, 174 }, + { 1, -80, 179 }, + { -1, 80, 184 }, + { 1, 160, 186 }, + { -1, -160, 186 }, + { 1, 0, 0 }, +}; + +/** + * Makes the platform in BITFS tilt from left to right + */ +void bowser_act_tilt_lava_platform(void) { + // Set platform object struct Object *platform = cur_obj_nearest_object_with_behavior(bhvTiltingBowserLavaPlatform); - UNUSED s16 sp2A = o->oBowserAngleToCentre + 0x8000; - s16 sp28; + UNUSED s16 angle = o->oBowserAngleToCentre + 0x8000; + s16 angSpeed; UNUSED s32 unused; s32 i; - s32 sp1C; - if (platform == NULL) - o->oAction = 0; - else { + s32 isNotTilting; + // If there's not platform, return to default action + if (platform == NULL) { + o->oAction = BOWSER_ACT_DEFAULT; + } else { i = 0; - sp1C = 1; - while (D_8032F520[i][2] != 0) { - if (o->oTimer < D_8032F520[i][2]) { - sp28 = D_8032F520[i][1]; - if (D_8032F520[i][0] > 0) - sp28 = (D_8032F520[i][2] - o->oTimer - 1) * sp28; - else - sp28 = (o->oTimer - D_8032F520[i - 1][2]) * sp28; - bowser_tilt_platform(platform, sp28); - if (sp28 != 0) - play_sound(SOUND_ENV_UNKNOWN4, platform->header.gfx.cameraToObject); - sp1C = 0; + isNotTilting = TRUE; + // Active platform tilting if the timer is not 0 + while (sBowsertiltPlatformData[i].time != 0) { + // Move if the time values is more than the timer + if (o->oTimer < sBowsertiltPlatformData[i].time) { + // Set angle speed + angSpeed = sBowsertiltPlatformData[i].angSpeed; + // Move angle behind Bowser + if (sBowsertiltPlatformData[i].flag > 0) { + angSpeed = (sBowsertiltPlatformData[i].time - o->oTimer - 1) * angSpeed; + } else { // Move angle in front of Bowser + angSpeed = (o->oTimer - sBowsertiltPlatformData[i - 1].time) * angSpeed; + } + // Set angle values to the platform + bowser_tilt_platform(platform, angSpeed); + // Play sound effect + if (angSpeed != 0) { + play_sound(SOUND_ENV_MOVING_BIG_PLATFORM, platform->header.gfx.cameraToObject); + } + isNotTilting = FALSE; break; } i++; } - if (sp1C) { - o->oAction = 0; + // If Bowser is done tilting, reset platform angles + // and set Bowser to default action + if (isNotTilting) { + o->oAction = BOWSER_ACT_DEFAULT; platform->oAngleVelPitch = 0; platform->oAngleVelRoll = 0; platform->oFaceAnglePitch = 0; platform->oFaceAngleRoll = 0; } } + // Extend "idle" animation cur_obj_extend_animation_if_at_end(); } -s32 bowser_check_fallen_off_stage(void) // bowser off stage? -{ - if (o->oAction != 2 && o->oAction != 19) { +/** + * Check if Bowser is offstage from a large distance or landed on a lethal floor + */ +s32 bowser_check_fallen_off_stage(void) { + if (o->oAction != BOWSER_ACT_JUMP_ONTO_STAGE && o->oAction != BOWSER_ACT_TILT_LAVA_PLATFORM) { if (o->oPosY < o->oHomeY - 1000.0f) - return 1; + return TRUE; if (o->oMoveFlags & OBJ_MOVE_LANDED) { - if (o->oFloorType == SURFACE_BURNING) - return 1; - if (o->oFloorType == SURFACE_DEATH_PLANE) - return 1; + // Check for Fire Sea + if (o->oFloorType == SURFACE_BURNING) { + return TRUE; + } + // Check for Dark World - Sky + if (o->oFloorType == SURFACE_DEATH_PLANE) { + return TRUE; + } } } - return 0; + return FALSE; } #ifdef PLATFORM_DISPLACEMENT_2 struct PlatformDisplacementInfo sBowserDisplacementInfo; #endif -void (*sBowserActions[])(void) = { bowser_act_default, bowser_act_thrown_dropped, bowser_act_jump_onto_stage, bowser_act_dance, - bowser_act_dead, bowser_act_text_wait, bowser_act_intro_walk, bowser_act_charge_mario, - bowser_act_spit_fire_into_sky, bowser_act_spit_fire_onto_floor, bowser_act_hit_edge, bowser_act_turn_from_edge, - bowser_act_hit_mine, bowser_act_jump, bowser_act_walk_to_mario, bowser_act_breath_fire, - bowser_act_teleport, bowser_act_jump_towards_mario, bowser_act_unused_slow_walk, bowser_act_ride_tilting_platform }; -struct SoundState D_8032F5B8[] = { { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 1, 0, -1, SOUND_OBJ_BOWSER_WALK }, - { 1, 0, -1, SOUND_OBJ2_BOWSER_ROAR }, - { 1, 0, -1, SOUND_OBJ2_BOWSER_ROAR }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 1, 20, 40, SOUND_OBJ_BOWSER_WALK }, - { 1, 20, -1, SOUND_OBJ_BOWSER_WALK }, - { 1, 20, 40, SOUND_OBJ_BOWSER_WALK }, - { 1, 0, -1, SOUND_OBJ_BOWSER_TAIL_PICKUP }, - { 1, 0, -1, SOUND_OBJ_BOWSER_DEFEATED }, - { 1, 8, -1, SOUND_OBJ_BOWSER_WALK }, - { 1, 8, 17, SOUND_OBJ_BOWSER_WALK }, - { 1, 8, -10, SOUND_OBJ_BOWSER_WALK }, - { 0, 0, 0, NO_SOUND }, - { 1, 5, -1, SOUND_OBJ_FLAME_BLOWN }, - { 0, 0, 0, NO_SOUND }, - { 0, 0, 0, NO_SOUND }, - { 1, 0, -1, SOUND_OBJ_BOWSER_TAIL_PICKUP }, - { 1, 0, -1, SOUND_OBJ2_BOWSER_ROAR } }; -s8 D_8032F690[4] = { 0, 0, 1, 0 }; -s8 D_8032F694[4] = { 1, 1, 3, 0 }; -extern u8 bowser_3_seg7_collision_07004B94[]; -extern u8 bowser_3_seg7_collision_07004C18[]; -extern u8 bowser_3_seg7_collision_07004C9C[]; -extern u8 bowser_3_seg7_collision_07004D20[]; -extern u8 bowser_3_seg7_collision_07004DA4[]; -extern u8 bowser_3_seg7_collision_07004E28[]; -extern u8 bowser_3_seg7_collision_07004EAC[]; -extern u8 bowser_3_seg7_collision_07004F30[]; -extern u8 bowser_3_seg7_collision_07004FB4[]; -extern u8 bowser_3_seg7_collision_07005038[]; -struct Struct8032F698 D_8032F698[] = { { NULL, 0, 0, 0, 0 }, - { bowser_3_seg7_collision_07004B94, -800, -1000, -20992, 0 }, - { bowser_3_seg7_collision_07004C18, -1158, 390, -18432, 0 }, - { bowser_3_seg7_collision_07004C9C, -1158, 390, -7680, 0 }, - { bowser_3_seg7_collision_07004D20, 0, 1240, -6144, 0 }, - { bowser_3_seg7_collision_07004DA4, 0, 1240, 6144, 0 }, - { bowser_3_seg7_collision_07004E28, 1158, 390, 7680, 0 }, - { bowser_3_seg7_collision_07004EAC, 1158, 390, 18432, 0 }, - { bowser_3_seg7_collision_07004F30, 800, -1000, 20992, 0 }, - { bowser_3_seg7_collision_07004FB4, 800, -1000, -31744, 0 }, - { bowser_3_seg7_collision_07005038, -800, -1000, 31744, 0 } }; +/** + * Set Bowser's actions + */ +void (*sBowserActions[])(void) = { + bowser_act_default, + bowser_act_thrown, + bowser_act_jump_onto_stage, + bowser_act_dance, + bowser_act_dead, + bowser_act_wait, + bowser_act_intro_walk, + bowser_act_charge_mario, + bowser_act_spit_fire_into_sky, + bowser_act_spit_fire_onto_floor, + bowser_act_hit_edge, + bowser_act_turn_from_edge, + bowser_act_hit_mine, + bowser_act_big_jump, + bowser_act_walk_to_mario, + bowser_act_breath_fire, + bowser_act_teleport, + bowser_act_quick_jump, + bowser_act_idle, + bowser_act_tilt_lava_platform +}; + +/** + * Set Bowser's sound animations + */ +struct SoundState sBowserSoundStates[] = { + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 1, 0, -1, SOUND_OBJ_BOWSER_WALK }, + { 1, 0, -1, SOUND_OBJ2_BOWSER_ROAR }, + { 1, 0, -1, SOUND_OBJ2_BOWSER_ROAR }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 1, 20, 40, SOUND_OBJ_BOWSER_WALK }, + { 1, 20, -1, SOUND_OBJ_BOWSER_WALK }, + { 1, 20, 40, SOUND_OBJ_BOWSER_WALK }, + { 1, 0, -1, SOUND_OBJ_BOWSER_TAIL_PICKUP }, + { 1, 0, -1, SOUND_OBJ_BOWSER_DEFEATED }, + { 1, 8, -1, SOUND_OBJ_BOWSER_WALK }, + { 1, 8, 17, SOUND_OBJ_BOWSER_WALK }, + { 1, 8, -10, SOUND_OBJ_BOWSER_WALK }, + { 0, 0, 0, NO_SOUND }, + { 1, 5, -1, SOUND_OBJ_FLAME_BLOWN }, + { 0, 0, 0, NO_SOUND }, + { 0, 0, 0, NO_SOUND }, + { 1, 0, -1, SOUND_OBJ_BOWSER_TAIL_PICKUP }, + { 1, 0, -1, SOUND_OBJ2_BOWSER_ROAR }, +}; + +/** + * Set whenever Bowser should have rainbow light or not on each stage + */ +s8 sBowserRainbowLight[] = { FALSE, FALSE, TRUE }; + +/** + * Set how much health Bowser has on each stage + */ +s8 sBowserHealth[] = { 1, 1, 3 }; + +/** + * Update Bowser's actions when he's hands free + */ void bowser_free_update(void) { struct Surface *floor; struct Object *platform; UNUSED f32 floorHeight; #ifdef PLATFORM_DISPLACEMENT_2 + s16 tmpOFaceAngleYaw = (s16) o->oFaceAngleYaw; if ((platform = o->platform) != NULL) { - apply_platform_displacement(&sBowserDisplacementInfo, &o->oPosX, &o->oFaceAngleYaw, platform); + // NOTE: This function was at one point using '&o->oFaceAngleYaw', which is a s32 address. Should tmpOFaceAngleYaw be using the first 16 bits instead, or was that a bug? + apply_platform_displacement(&sBowserDisplacementInfo, &o->oPosX, &tmpOFaceAngleYaw, platform); + o->oFaceAngleYaw = tmpOFaceAngleYaw; } #else - if ((platform = o->platform) != NULL) + if ((platform = o->platform) != NULL) { apply_platform_displacement(FALSE, platform); + } #endif - o->oBowserUnk10E = 0; + // Reset grabbed status + o->oBowserGrabbedStatus = BOWSER_GRAB_STATUS_NONE; + // Update positions and actions (default action) cur_obj_update_floor_and_walls(); cur_obj_call_action_function(sBowserActions); cur_obj_move_standard(-78); - if (bowser_check_fallen_off_stage()) - o->oAction = 2; // bowser go home? + // Jump on stage if Bowser has fallen off + if (bowser_check_fallen_off_stage()) { + o->oAction = BOWSER_ACT_JUMP_ONTO_STAGE; + } + // Check floor height and platform floorHeight = find_floor(o->oPosX, o->oPosY, o->oPosZ, &floor); - if ((floor != NULL) && (floor->object != 0)) + if ((floor != NULL) && (floor->object != NULL)) { o->platform = floor->object; - else + } else { o->platform = NULL; - exec_anim_sound_state(D_8032F5B8); + } + // Sound states for Bowser Animations + exec_anim_sound_state(sBowserSoundStates); } +/** + * Update Bowser's actions when he's getting held + */ void bowser_held_update(void) { - o->oBowserUnkF4 &= ~0x20000; + // Reset fire sky status and make him intangible + o->oBowserStatus &= ~BOWSER_STATUS_FIRE_SKY; cur_obj_become_intangible(); - switch (o->oBowserUnk10E) { - case 0: + switch (o->oBowserGrabbedStatus) { + // Play pickup sound, start grabbed animation, and set throw action + // Throw action won't be played until he's actually released + case BOWSER_GRAB_STATUS_NONE: cur_obj_play_sound_2(SOUND_OBJ_BOWSER_TAIL_PICKUP); - cur_obj_unrender_and_reset_state(3, 1); - o->oBowserUnk10E++; + cur_obj_unrender_set_action_and_anim(BOWSER_ANIM_GRABBED, BOWSER_ACT_THROWN); + o->oBowserGrabbedStatus++; break; - case 1: + // After the grabbed animation ends, play shaking animation in a loop + case BOWSER_GRAB_STATUS_GRABBED: if (cur_obj_check_if_near_animation_end()) { - cur_obj_init_animation_with_sound(2); - o->oBowserUnk10E++; + cur_obj_init_animation_with_sound(BOWSER_ANIM_SHAKING); + o->oBowserGrabbedStatus++; } break; - case 2: + case BOWSER_GRAB_STATUS_HOLDING: break; } + // Reset move flags o->oMoveFlags = 0; + // Copy angle values from Mario o->oBowserHeldAnglePitch = gMarioObject->oMoveAnglePitch; o->oBowserHeldAngleVelYaw = gMarioObject->oAngleVelYaw; o->oMoveAngleYaw = gMarioObject->oMoveAngleYaw; } +/** + * Update Bowser's actions when he's thrown and dropped + */ void bowser_thrown_dropped_update(void) { - f32 sp1C; - o->oBowserUnk10E = 0; - cur_obj_get_thrown_or_placed(1.0f, 1.0f, 1); - sp1C = o->oBowserHeldAngleVelYaw / 3000.0 * 70.0f; - if (sp1C < 0.0f) - sp1C = -sp1C; - if (sp1C > 90.0f) - sp1C *= 2.5; // > 90 => get bigger? - o->oForwardVel = coss(o->oBowserHeldAnglePitch) * sp1C; - o->oVelY = -sins(o->oBowserHeldAnglePitch) * sp1C; + f32 swingSpd; + // Reset grabbed status + o->oBowserGrabbedStatus = BOWSER_GRAB_STATUS_NONE; + // Set throw action and vel values + cur_obj_get_thrown_or_placed(1.0f, 1.0f, BOWSER_ACT_THROWN); + // Set swing speed based of angle + swingSpd = o->oBowserHeldAngleVelYaw / 3000.0 * 70.0f; + // If less than 0, reduce speed + if (swingSpd < 0.0f) { + swingSpd = -swingSpd; + } + // If more than 90, increase speed + if (swingSpd > 90.0f) { + swingSpd *= 2.5; + } + // Set distance speed when throwing + o->oForwardVel = coss(o->oBowserHeldAnglePitch) * swingSpd; + o->oVelY = -sins(o->oBowserHeldAnglePitch) * swingSpd; cur_obj_become_intangible(); - o->prevObj->oAction = 1; // not sure what prevObj is + + // Reset timer and subactions + o->prevObj->oAction = BOWSER_ACT_TAIL_THROWN; // prevObj is Bowser's Tail o->prevObj->oTimer = 0; - o->prevObj->oSubAction = 0; + o->prevObj->oSubAction = 0; //! Tail doesn't have sub actions + o->oTimer = 0; o->oSubAction = 0; } +/** + * Bowser's main loop + */ void bhv_bowser_loop(void) { - s16 angleToMario; // AngleToMario from Bowser's perspective + s16 angleToMario; // AngleToMario from Bowser's perspective s16 angleToCentre; // AngleToCentre from Bowser's perspective + // Set distance/angle values o->oBowserDistToCentre = sqrtf(o->oPosX * o->oPosX + o->oPosZ * o->oPosZ); o->oBowserAngleToCentre = atan2s(0.0f - o->oPosZ, 0.0f - o->oPosX); angleToMario = abs_angle_diff(o->oMoveAngleYaw, o->oAngleToMario); angleToCentre = abs_angle_diff(o->oMoveAngleYaw, o->oBowserAngleToCentre); - o->oBowserUnkF4 &= ~0xFF; - if (angleToMario < 0x2000) - o->oBowserUnkF4 |= 2; - if (angleToCentre < 0x3800) - o->oBowserUnkF4 |= 4; - if (o->oBowserDistToCentre < 1000.0f) - o->oBowserUnkF4 |= 0x10; - if (o->oDistanceToMario < 850.0f) - o->oBowserUnkF4 |= 8; + + // Reset Status + o->oBowserStatus &= ~0xFF; + + // Set bitflag status for distance/angle values + // Only the first one is used + if (angleToMario < 0x2000) { + o->oBowserStatus |= BOWSER_STATUS_ANGLE_MARIO; + } + if (angleToCentre < 0x3800) { + o->oBowserStatus |= BOWSER_STATUS_ANGLE_CENTRE; // unused + } + if (o->oBowserDistToCentre < 1000.0f) { + o->oBowserStatus |= BOWSER_STATUS_DIST_CENTRE; // unused + } + if (o->oDistanceToMario < 850.0f) { + o->oBowserStatus |= BOWSER_STATUS_DIST_MARIO; // unused + } + + // Update Held state actions switch (o->oHeldState) { case HELD_FREE: bowser_free_update(); @@ -1133,465 +1708,220 @@ void bhv_bowser_loop(void) { bowser_thrown_dropped_update(); break; } + // Adjust model to the floor cur_obj_align_gfx_with_floor(); - if (o->oAction != 4) - if (o->oBowserUnk1AC != o->oOpacity) { - if (o->oBowserUnk1AC > o->oOpacity) { + + // Adjust opacity (when not dead) + // Mostly for the teleport action in BITFS + if (o->oAction != BOWSER_ACT_DEAD) { + if (o->oBowserTargetOpacity != o->oOpacity) { + // increase opacity when oBowserTargetOpacity is 0xFF + if (o->oBowserTargetOpacity > o->oOpacity) { o->oOpacity += 20; - if (o->oOpacity >= 0x100) + if (o->oOpacity >= 0x100) { o->oOpacity = 0xFF; + } + // reduce opacity when oBowserTargetOpacity is 0 } else { o->oOpacity -= 20; - if (o->oOpacity < 0) + if (o->oOpacity < 0) { o->oOpacity = 0; + } } } + } } +/** + * Bowser's initial values and actions + */ void bhv_bowser_init(void) { - s32 level; // 0 is dw, 1 is fs, 2 is sky - o->oBowserUnk110 = 1; + s32 level; + // Set "reaction" value + // It goes true when Bowser is a non-walking state + o->oBowserIsReacting = TRUE; + // Set no transparency opacity o->oOpacity = 0xFF; - o->oBowserUnk1AC = 0xFF; - if (gCurrLevelNum == LEVEL_BOWSER_2) - level = 1; - else if (gCurrLevelNum == LEVEL_BOWSER_3) - level = 2; - else - level = 0; + o->oBowserTargetOpacity = 0xFF; + // Set Bowser B-param depending of the stage + if (gCurrLevelNum == LEVEL_BOWSER_2) { + level = BOWSER_BP_BITFS; + } else if (gCurrLevelNum == LEVEL_BOWSER_3) { + level = BOWSER_BP_BITS; + } else { // LEVEL_BOWSER_1 + level = BOWSER_BP_BITDW; + } o->oBehParams2ndByte = level; - o->oBowserUnk1B2 = D_8032F690[level]; - o->oHealth = D_8032F694[level]; + // Set health and rainbow light depending of the level + o->oBowserRainbowLight = sBowserRainbowLight[level]; + o->oHealth = sBowserHealth[level]; + // Start camera event, this event is not defined so maybe + // the "start arena" cutscene was originally called this way cur_obj_start_cam_event(o, CAM_EVENT_BOWSER_INIT); - o->oAction = 5; - o->oBowserUnk1AE = 0; - o->oBowserEyesShut = 0; + o->oAction = BOWSER_ACT_WAIT; + // Set eyes status + o->oBowserEyesTimer = 0; + o->oBowserEyesShut = FALSE; } -#undef BITDW -#undef BITFS -#undef BITS +Gfx *geo_update_body_rot_from_parent(s32 callContext, UNUSED struct GraphNode *node, Mat4 mtx) { + Mat4 mtx2; + struct Object *obj; -Gfx *geo_update_body_rot_from_parent(s32 run, UNUSED struct GraphNode *node, Mat4 mtx) { - Mat4 sp20; - struct Object *sp1C; - - if (run == TRUE) { - sp1C = (struct Object *) gCurGraphNodeObject; - if (sp1C->prevObj != NULL) { - create_transformation_from_matrices(sp20, mtx, *gCurGraphNodeCamera->matrixPtr); - obj_update_pos_from_parent_transformation(sp20, sp1C->prevObj); - obj_set_gfx_pos_from_pos(sp1C->prevObj); + if (callContext == GEO_CONTEXT_RENDER) { + obj = (struct Object *) gCurGraphNodeObject; + if (obj->prevObj != NULL) { + create_transformation_from_matrices(mtx2, mtx, *gCurGraphNodeCamera->matrixPtr); + obj_update_pos_from_parent_transformation(mtx2, obj->prevObj); + obj_set_gfx_pos_from_pos(obj->prevObj); } } return NULL; } -void bowser_open_eye_switch(struct Object *a0, struct GraphNodeSwitchCase *switchCase) { - s32 sp1C; - s16 sp1A; - sp1A = abs_angle_diff(a0->oMoveAngleYaw, a0->oAngleToMario); - sp1C = switchCase->selectedCase; - switch (sp1C) { - case 0: - if (sp1A > 0x2000) { - if (a0->oAngleVelYaw > 0) - switchCase->selectedCase = 5; - if (a0->oAngleVelYaw < 0) - switchCase->selectedCase = 3; +/** + * Bowser's eyes Geo-Switch-Case IDs, defined from Mario's POV + */ +enum BowserEyesGSCId +{ + /*0x00*/ BOWSER_EYES_OPEN, + /*0x01*/ BOWSER_EYES_HALF_CLOSED, + /*0x02*/ BOWSER_EYES_CLOSED, + /*0x03*/ BOWSER_EYES_LEFT, + /*0x04*/ BOWSER_EYES_FAR_LEFT, + /*0x05*/ BOWSER_EYES_RIGHT, + /*0x06*/ BOWSER_EYES_FAR_RIGHT, + /*0x07*/ BOWSER_EYES_DERP, // unused + /*0x08*/ BOWSER_EYES_CROSS, // unused + /*0x08*/ BOWSER_EYES_RESET // set eyes back to open +}; + +/** + * Controls Bowser's eye open stage, including blinking and look directions + */ +void bowser_open_eye_switch(struct Object *obj, struct GraphNodeSwitchCase *switchCase) { + s32 eyeCase; + s16 angleFromMario; + angleFromMario = abs_angle_diff(obj->oMoveAngleYaw, obj->oAngleToMario); + eyeCase = switchCase->selectedCase; + switch (eyeCase) { + case BOWSER_EYES_OPEN: + // Mario is in Bowser's field of view + if (angleFromMario > 0x2000) { + if (obj->oAngleVelYaw > 0) + switchCase->selectedCase = BOWSER_EYES_RIGHT; + if (obj->oAngleVelYaw < 0) + switchCase->selectedCase = BOWSER_EYES_LEFT; } - if (a0->oBowserUnk1AE > 50) - switchCase->selectedCase = 1; + // Half close, start blinking + if (obj->oBowserEyesTimer > 50) + switchCase->selectedCase = BOWSER_EYES_HALF_CLOSED; break; - case 1: - if (a0->oBowserUnk1AE > 2) - switchCase->selectedCase = 2; + case BOWSER_EYES_HALF_CLOSED: + // Close, blinking + if (obj->oBowserEyesTimer > 2) + switchCase->selectedCase = BOWSER_EYES_CLOSED; break; - case 2: - if (a0->oBowserUnk1AE > 2) - switchCase->selectedCase = 9; + case BOWSER_EYES_CLOSED: + // Reset blinking + if (obj->oBowserEyesTimer > 2) + switchCase->selectedCase = BOWSER_EYES_RESET; break; - case 9: - if (a0->oBowserUnk1AE > 2) - switchCase->selectedCase = 0; + case BOWSER_EYES_RESET: + // Open, no longer blinking + if (obj->oBowserEyesTimer > 2) + switchCase->selectedCase = BOWSER_EYES_OPEN; break; - case 5: - if (a0->oBowserUnk1AE > 2) { - switchCase->selectedCase = 6; - if (a0->oAngleVelYaw <= 0) - switchCase->selectedCase = 0; + case BOWSER_EYES_RIGHT: + // Look more on the right if angle didn't change + // Otherwise, look at the center (open) + if (obj->oBowserEyesTimer > 2) { + switchCase->selectedCase = BOWSER_EYES_FAR_RIGHT; + if (obj->oAngleVelYaw <= 0) + switchCase->selectedCase = BOWSER_EYES_OPEN; } break; - case 6: - if (a0->oAngleVelYaw <= 0) - switchCase->selectedCase = 5; + case BOWSER_EYES_FAR_RIGHT: + // Look close right if angle was drastically changed + if (obj->oAngleVelYaw <= 0) + switchCase->selectedCase = BOWSER_EYES_RIGHT; break; - case 3: - if (a0->oBowserUnk1AE > 2) { - switchCase->selectedCase = 4; - if (a0->oAngleVelYaw >= 0) - switchCase->selectedCase = 0; + case BOWSER_EYES_LEFT: + // Look more on the left if angle didn't change + // Otherwise, look at the center (open) + if (obj->oBowserEyesTimer > 2) { + switchCase->selectedCase = BOWSER_EYES_FAR_LEFT; + if (obj->oAngleVelYaw >= 0) + switchCase->selectedCase = BOWSER_EYES_OPEN; } break; - case 4: - if (a0->oAngleVelYaw >= 0) - switchCase->selectedCase = 3; + case BOWSER_EYES_FAR_LEFT: + // Look close left if angle was drastically changed + if (obj->oAngleVelYaw >= 0) + switchCase->selectedCase = BOWSER_EYES_LEFT; break; default: - switchCase->selectedCase = 0; + switchCase->selectedCase = BOWSER_EYES_OPEN; + } + // Reset timer if eye case has changed + if (switchCase->selectedCase != eyeCase) { + obj->oBowserEyesTimer = -1; } - if (switchCase->selectedCase != sp1C) - a0->oBowserUnk1AE = -1; } -/** Geo switch for controlling the state of bowser's eye direction and open/closed +/** + * Geo switch for controlling the state of Bowser's eye direction and open/closed * state. Checks whether oBowserEyesShut is TRUE and closes eyes if so and processes * direction otherwise. */ -Gfx *geo_switch_bowser_eyes(s32 run, struct GraphNode *node, UNUSED Mat4 *mtx) { - UNUSED s16 sp36; +Gfx *geo_switch_bowser_eyes(s32 callContext, struct GraphNode *node, UNUSED Mat4 *mtx) { + UNUSED s16 eyeShut; UNUSED s32 unused; struct Object *obj = (struct Object *) gCurGraphNodeObject; struct GraphNodeSwitchCase *switchCase = (struct GraphNodeSwitchCase *) node; - if (run == TRUE) { + if (callContext == GEO_CONTEXT_RENDER) { if (gCurGraphNodeHeldObject != NULL) obj = gCurGraphNodeHeldObject->objNode; - switch (sp36 = obj->oBowserEyesShut) { - case 0: // eyes open, handle eye looking direction + switch (eyeShut = obj->oBowserEyesShut) { + case FALSE: // eyes open, handle eye looking direction bowser_open_eye_switch(obj, switchCase); break; - case 1: // eyes closed, blinking - switchCase->selectedCase = 2; + case TRUE: // eyes closed, blinking + switchCase->selectedCase = BOWSER_EYES_CLOSED; break; } - obj->oBowserUnk1AE++; + obj->oBowserEyesTimer++; } return NULL; } -Gfx *geo_bits_bowser_coloring(s32 run, struct GraphNode *node, UNUSED s32 a2) { - Gfx *sp2C = NULL; - Gfx *sp28; - struct Object *sp24; - struct GraphNodeGenerated *sp20; +/** + * Geo switch that sets Bowser's Rainbow coloring (in BITS) + */ +Gfx *geo_bits_bowser_coloring(s32 callContext, struct GraphNode *node, UNUSED s32 context) { + Gfx *gfxHead = NULL; + Gfx *gfx; + struct Object *obj; + struct GraphNodeGenerated *graphNode; - if (run == 1) { - sp24 = (struct Object *) gCurGraphNodeObject; - sp20 = (struct GraphNodeGenerated *) node; - if (gCurGraphNodeHeldObject != 0) - sp24 = gCurGraphNodeHeldObject->objNode; - if (sp24->oOpacity == 0xFF) - sp20->fnNode.node.flags = (sp20->fnNode.node.flags & 0xFF) | GRAPH_NODE_TYPE_FUNCTIONAL; - else - sp20->fnNode.node.flags = (sp20->fnNode.node.flags & 0xFF) | (GRAPH_NODE_TYPE_FUNCTIONAL | GRAPH_NODE_TYPE_400); - sp28 = sp2C = alloc_display_list(2 * sizeof(Gfx)); - - if (sp24->oBowserUnk1B2 != 0) { - gSPClearGeometryMode(sp28++, G_LIGHTING); + if (callContext == GEO_CONTEXT_RENDER) { + obj = (struct Object *) gCurGraphNodeObject; + graphNode = (struct GraphNodeGenerated *) node; + if (gCurGraphNodeHeldObject != 0) { + obj = gCurGraphNodeHeldObject->objNode; } - gSPEndDisplayList(sp28); - } - return sp2C; -} - -void falling_bowser_plat_act_0(void) { - o->oPlatformUnkF8 = cur_obj_nearest_object_with_behavior(bhvBowser); - obj_set_collision_data(o, D_8032F698[o->oBehParams2ndByte].unk0); - if (o->oPlatformUnkF8 != 0) - o->oAction = 1; -} - -void falling_bowser_plat_act_1(void) { - UNUSED s32 unused; - struct Object *sp0 = o->oPlatformUnkF8; - if (sp0->platform == o) - if (sp0->oAction == 13 && sp0->oBowserUnkF4 & 0x10000) - o->oAction = 2; - if (sp0->oHealth == 1 && (sp0->oAction == 3 || sp0->oHeldState != HELD_FREE)) - o->oSubAction = 1; - if (o->oSubAction == 0) - o->oPlatformUnkFC = 0; - else { - if ((gDebugInfo[4][6] + 20) * (o->oBehParams2ndByte - 1) < o->oPlatformUnkFC) - o->oAction = 2; - o->oPlatformUnkFC++; - } -} - -void falling_bowser_plat_act_2(void) { - Vec3f sp24; - s16 sp22; - f32 sp1C; - UNUSED struct Object *sp18 = o->oPlatformUnkF8; - if (o->oTimer == 0 || o->oTimer == 22) - cur_obj_play_sound_2(SOUND_GENERAL_BOWSER_PLATFORM_2); - if (o->oTimer < 22) { - set_environmental_camera_shake(SHAKE_ENV_FALLING_BITS_PLAT); - o->oVelY = 8.0f; - o->oGravity = 0.0f; - } else - o->oGravity = -4.0f; - if ((o->oTimer & 1) == 0 && o->oTimer < 14) { - sp22 = D_8032F698[o->oBehParams2ndByte].unk3 + (gDebugInfo[4][1] << 8); - sp1C = -(o->oTimer / 2) * 290 + 1740; - vec3f_copy_2(sp24, &o->oPosX); - o->oPosX = D_8032F698[o->oBehParams2ndByte].unk1 + sins(sp22 + 5296) * sp1C; - o->oPosZ = D_8032F698[o->oBehParams2ndByte].unk2 + coss(sp22 + 5296) * sp1C; - o->oPosY = 307.0f; - spawn_mist_particles_variable(4, 0, 100.0f); - o->oPosX = D_8032F698[o->oBehParams2ndByte].unk1 + sins(sp22 - 5296) * sp1C; - o->oPosZ = D_8032F698[o->oBehParams2ndByte].unk2 + coss(sp22 - 5296) * sp1C; - spawn_mist_particles_variable(4, 0, 100); - vec3f_copy_2(&o->oPosX, sp24); - } - cur_obj_move_using_fvel_and_gravity(); - if (o->oTimer > 300) - obj_mark_for_deletion(o); -} - -void (*sFallingBowserPlatformActions[])(void) = { falling_bowser_plat_act_0, - falling_bowser_plat_act_1, - falling_bowser_plat_act_2 }; - -struct ObjectHitbox sGrowingBowserFlameHitbox = { - /* interactType: */ INTERACT_FLAME, - /* downOffset: */ 20, - /* damageOrCoinValue: */ 1, - /* health: */ 0, - /* numLootCoins: */ 0, - /* radius: */ 10, - /* height: */ 40, - /* hurtboxRadius: */ 0, - /* hurtboxHeight: */ 0, -}; - -struct ObjectHitbox sBowserFlameHitbox = { - /* interactType: */ INTERACT_FLAME, - /* downOffset: */ 0, - /* damageOrCoinValue: */ 1, - /* health: */ 0, - /* numLootCoins: */ 0, - /* radius: */ 10, - /* height: */ 40, - /* hurtboxRadius: */ 0, - /* hurtboxHeight: */ 0, -}; - -f32 D_8032F748[] = { -8.0f, -6.0f, -3.0f }; - -void bhv_falling_bowser_platform_loop(void) { - cur_obj_call_action_function(sFallingBowserPlatformActions); -} - -void bowser_flame_despawn(void) { - obj_mark_for_deletion(o); - spawn_object_with_scale(o, MODEL_NONE, bhvBlackSmokeUpward, 1.0f); - if (random_float() < 0.1) - spawn_object(o, MODEL_YELLOW_COIN, bhvTemporaryYellowCoin); -} - -s32 bowser_flame_should_despawn(s32 maxTime) { - if (maxTime < o->oTimer) - return 1; - if (o->oFloorType == SURFACE_BURNING) - return 1; - if (o->oFloorType == SURFACE_DEATH_PLANE) - return 1; - return 0; -} - -void bhv_flame_bowser_init(void) { - o->oAnimState = (s32)(random_float() * 10.0f); - o->oMoveAngleYaw = random_u16(); - if (random_float() < 0.2) - o->oVelY = 80.0f; - else - o->oVelY = 20.0f; - o->oForwardVel = 10.0f; - o->oGravity = -1.0f; - o->oFlameScale = random_float() + 1.0f; -} - -void bhv_flame_large_burning_out_init(void) { - o->oAnimState = (s32)(random_float() * 10.0f); - o->oMoveAngleYaw = random_u16(); - o->oVelY = 10.0f; - o->oForwardVel = 0.0f; - o->oFlameScale = 7.0f; -} - -void bowser_flame_move(void) { - s32 sp4; - sp4 = ((o->oFlameSpeedTimerOffset + gGlobalTimer) & 0x3F) << 10; - o->oPosX += sins(o->oMoveAngleYaw) * sins(sp4) * 4.0f; - o->oPosZ += coss(o->oMoveAngleYaw) * sins(sp4) * 4.0f; -} - -void bhv_flame_bowser_loop(void) { - cur_obj_update_floor_and_walls(); - cur_obj_move_standard(78); - if (o->oVelY < -4.0f) - o->oVelY = -4.0f; - if (o->oAction == 0) { - cur_obj_become_intangible(); - bowser_flame_move(); - if (o->oMoveFlags & OBJ_MOVE_LANDED) { - o->oAction++; - if (cur_obj_has_behavior(bhvFlameLargeBurningOut)) - o->oFlameScale = 8.0f; - else - o->oFlameScale = random_float() * 2 + 6.0f; - o->oForwardVel = 0; - o->oVelY = 0; - o->oGravity = 0; + // Set layers if object is transparent or not + if (obj->oOpacity == 0xFF) { + graphNode->fnNode.node.flags = (graphNode->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8); + } else { + graphNode->fnNode.node.flags = (graphNode->fnNode.node.flags & 0xFF) | (LAYER_TRANSPARENT << 8); } - } else { - cur_obj_become_tangible(); - if (o->oTimer > o->oFlameScale * 10 + 5.0f) { - o->oFlameScale -= 0.15; - if (o->oFlameScale <= 0) - bowser_flame_despawn(); + gfx = gfxHead = alloc_display_list(2 * sizeof(Gfx)); + // If TRUE, clear lighting to give rainbow color + if (obj->oBowserRainbowLight != 0) { + gSPClearGeometryMode(gfx++, G_LIGHTING); } + gSPEndDisplayList(gfx); } - cur_obj_scale(o->oFlameScale); - o->oGraphYOffset = o->header.gfx.scale[1] * 14.0f; - obj_set_hitbox(o, &sBowserFlameHitbox); -} - -void bhv_flame_moving_forward_growing_init(void) { - o->oForwardVel = 30.0f; - obj_translate_xz_random(o, 80.0f); - o->oAnimState = (s32)(random_float() * 10.0f); - o->oFlameScale = 3.0f; -} - -void bhv_flame_moving_forward_growing_loop(void) { - UNUSED s32 unused; - UNUSED struct Object *sp18; - obj_set_hitbox(o, &sGrowingBowserFlameHitbox); - o->oFlameScale = o->oFlameScale + 0.5; - cur_obj_scale(o->oFlameScale); - if (o->oMoveAnglePitch > 0x800) - o->oMoveAnglePitch -= 0x200; - cur_obj_set_pos_via_transform(); - cur_obj_update_floor_height(); - if (o->oFlameScale > 30.0f) - obj_mark_for_deletion(o); - if (o->oPosY < o->oFloorHeight) { - o->oPosY = o->oFloorHeight; - sp18 = spawn_object(o, MODEL_RED_FLAME, bhvFlameBowser); - obj_mark_for_deletion(o); - } -} - -void bhv_flame_floating_landing_init(void) { - o->oAnimState = (s32)(random_float() * 10.0f); - o->oMoveAngleYaw = random_u16(); - if (o->oBehParams2ndByte != 0) - o->oForwardVel = random_float() * 5.0f; - else - o->oForwardVel = random_float() * 70.0f; - o->oVelY = random_float() * 20.0f; - o->oGravity = -1.0f; - o->oFlameSpeedTimerOffset = random_float() * 64.0f; -} - -void bhv_flame_floating_landing_loop(void) { - UNUSED s32 unused; - cur_obj_update_floor_and_walls(); - cur_obj_move_standard(0x4e); - bowser_flame_move(); - if (bowser_flame_should_despawn(900)) - obj_mark_for_deletion(o); - if (o->oVelY < D_8032F748[o->oBehParams2ndByte]) - o->oVelY = D_8032F748[o->oBehParams2ndByte]; - if (o->oMoveFlags & OBJ_MOVE_LANDED) { - if (o->oBehParams2ndByte == 0) - spawn_object(o, MODEL_RED_FLAME, bhvFlameLargeBurningOut); - else - spawn_object(o, MODEL_NONE, bhvBlueFlamesGroup); //? wonder if they meant MODEL_BLUE_FLAME? - obj_mark_for_deletion(o); - } - o->oGraphYOffset = o->header.gfx.scale[1] * 14.0f; -} - -void bhv_blue_bowser_flame_init(void) { - obj_translate_xz_random(o, 80.0f); - o->oAnimState = (s32)(random_float() * 10.0f); - o->oVelY = 7.0f; - o->oForwardVel = 35.0f; - o->oFlameScale = 3.0f; - o->oFlameUnkFC = random_float() * 0.5; - o->oGravity = 1.0f; - o->oFlameSpeedTimerOffset = (s32)(random_float() * 64.0f); -} - -void bhv_blue_bowser_flame_loop(void) { - s32 i; - obj_set_hitbox(o, &sGrowingBowserFlameHitbox); - if (o->oFlameScale < 16.0f) - o->oFlameScale = o->oFlameScale + 0.5; - cur_obj_scale(o->oFlameScale); - cur_obj_update_floor_and_walls(); - cur_obj_move_standard(0x4e); - if (o->oTimer > 0x14) { - if (o->oBehParams2ndByte == 0) - for (i = 0; i < 3; i++) - spawn_object_relative_with_scale(0, 0, 0, 0, 5.0f, o, MODEL_RED_FLAME, - bhvFlameFloatingLanding); - else { - spawn_object_relative_with_scale(1, 0, 0, 0, 8.0f, o, MODEL_BLUE_FLAME, - bhvFlameFloatingLanding); - spawn_object_relative_with_scale(2, 0, 0, 0, 8.0f, o, MODEL_BLUE_FLAME, - bhvFlameFloatingLanding); - } - obj_mark_for_deletion(o); - } -} - -void bhv_flame_bouncing_init(void) { - o->oAnimState = (s32)(random_float() * 10.0f); - o->oVelY = 30.0f; - o->oForwardVel = 20.0f; - o->oFlameScale = o->header.gfx.scale[0]; - o->oFlameSpeedTimerOffset = (s32)(random_float() * 64.0f); -} - -void bhv_flame_bouncing_loop(void) { - struct Object *bowser; - if (o->oTimer == 0) - o->oFlameBowser = cur_obj_nearest_object_with_behavior(bhvBowser); - bowser = o->oFlameBowser; - o->oForwardVel = 15.0f; - o->oBounciness = -1.0f; - cur_obj_scale(o->oFlameScale); - obj_set_hitbox(o, &sGrowingBowserFlameHitbox); - cur_obj_update_floor_and_walls(); - cur_obj_move_standard(78); - if (bowser_flame_should_despawn(300)) - obj_mark_for_deletion(o); - if (bowser != NULL) - if (bowser->oHeldState == 0) - if (lateral_dist_between_objects(o, bowser) < 300.0f) - obj_mark_for_deletion(o); -} - -void bhv_blue_flames_group_loop(void) { - struct Object *flame; - s32 i; - if (o->oTimer == 0) { - o->oMoveAngleYaw = obj_angle_to_object(o, gMarioObject); - o->oBlueFlameNextScale = 5.0f; - } - if (o->oTimer < 16) { - if ((o->oTimer & 1) == 0) { - for (i = 0; i < 3; i++) { - flame = spawn_object(o, MODEL_BLUE_FLAME, bhvFlameBouncing); - flame->oMoveAngleYaw += i * 0x5555; - flame->header.gfx.scale[0] = o->oBlueFlameNextScale; - } - o->oBlueFlameNextScale -= 0.5; - } - } else - obj_mark_for_deletion(o); + return gfxHead; } diff --git a/src/game/behaviors/bowser_falling_platform.inc.c b/src/game/behaviors/bowser_falling_platform.inc.c new file mode 100644 index 00000000..0d1e0e43 --- /dev/null +++ b/src/game/behaviors/bowser_falling_platform.inc.c @@ -0,0 +1,90 @@ +struct BowserFallingPlatformData { + const Collision *collision; + s16 posX; + s16 posZ; + s16 angle; +}; + +struct BowserFallingPlatformData sBowserFallingPlatform[] = { + { NULL, 0, 0, 0 }, + { bowser_3_seg7_collision_07004B94, -800, -1000, -20992 }, + { bowser_3_seg7_collision_07004C18, -1158, 390, -18432 }, + { bowser_3_seg7_collision_07004C9C, -1158, 390, -7680 }, + { bowser_3_seg7_collision_07004D20, 0, 1240, -6144 }, + { bowser_3_seg7_collision_07004DA4, 0, 1240, 6144 }, + { bowser_3_seg7_collision_07004E28, 1158, 390, 7680 }, + { bowser_3_seg7_collision_07004EAC, 1158, 390, 18432 }, + { bowser_3_seg7_collision_07004F30, 800, -1000, 20992 }, + { bowser_3_seg7_collision_07004FB4, 800, -1000, -31744 }, + { bowser_3_seg7_collision_07005038, -800, -1000, 31744 } +}; + +void falling_bowser_plat_act_start(void) { + o->oBitsPlatformBowser = cur_obj_nearest_object_with_behavior(bhvBowser); + obj_set_collision_data(o, sBowserFallingPlatform[o->oBehParams2ndByte].collision); + if (o->oBitsPlatformBowser != 0) + o->oAction = BOWSER_BITS_PLAT_ACT_CHECK; +} + +void falling_bowser_plat_act_check(void) { + UNUSED s32 unused; + struct Object *bowser = o->oBitsPlatformBowser; + if (bowser->platform == o) { + if (bowser->oAction == BOWSER_ACT_BIG_JUMP && bowser->oBowserStatus & BOWSER_STATUS_BIG_JUMP) { + o->oAction = BOWSER_BITS_PLAT_ACT_FALL; + } + } + if (bowser->oHealth == 1 && (bowser->oAction == BOWSER_ACT_DANCE || bowser->oHeldState != HELD_FREE)) { + o->oSubAction = 1; + } + if (o->oSubAction == 0) { + o->oBitsPlatformTimer = 0; + } else { + if ((gDebugInfo[4][6] + 20) * (o->oBehParams2ndByte - 1) < o->oBitsPlatformTimer) + o->oAction = BOWSER_BITS_PLAT_ACT_FALL; + o->oBitsPlatformTimer++; + } +} + +void falling_bowser_plat_act_fall(void) { + Vec3f pos; + s16 angle; + f32 val; + UNUSED struct Object *bowser = o->oBitsPlatformBowser; + if (o->oTimer == 0 || o->oTimer == 22) { + cur_obj_play_sound_2(SOUND_GENERAL_BOWSER_PLATFORM_2); + } + if (o->oTimer < 22) { + set_environmental_camera_shake(SHAKE_ENV_FALLING_BITS_PLAT); + o->oVelY = 8.0f; + o->oGravity = 0.0f; + } else + o->oGravity = -4.0f; + if ((o->oTimer & 1) == 0 && o->oTimer < 14) { + angle = sBowserFallingPlatform[o->oBehParams2ndByte].angle + (gDebugInfo[4][1] << 8); + val = -(o->oTimer / 2) * 290 + 1740; + vec3f_copy_2(pos, &o->oPosX); + o->oPosX = sBowserFallingPlatform[o->oBehParams2ndByte].posX + sins(angle + 0x14B0) * val; + o->oPosZ = sBowserFallingPlatform[o->oBehParams2ndByte].posZ + coss(angle + 0x14B0) * val; + o->oPosY = 307.0f; + spawn_mist_particles_variable(4, 0, 100.0f); + o->oPosX = sBowserFallingPlatform[o->oBehParams2ndByte].posX + sins(angle - 0x14B0) * val; + o->oPosZ = sBowserFallingPlatform[o->oBehParams2ndByte].posZ + coss(angle - 0x14B0) * val; + spawn_mist_particles_variable(4, 0, 100); + vec3f_copy_2(&o->oPosX, pos); + } + cur_obj_move_using_fvel_and_gravity(); + if (o->oTimer > 300) { + obj_mark_for_deletion(o); + } +} + +void (*sFallingBowserPlatformActions[])(void) = { + falling_bowser_plat_act_start, + falling_bowser_plat_act_check, + falling_bowser_plat_act_fall, +}; + +void bhv_falling_bowser_platform_loop(void) { + cur_obj_call_action_function(sFallingBowserPlatformActions); +} diff --git a/src/game/behaviors/bowser_flame.inc.c b/src/game/behaviors/bowser_flame.inc.c new file mode 100644 index 00000000..4501d977 --- /dev/null +++ b/src/game/behaviors/bowser_flame.inc.c @@ -0,0 +1,263 @@ +struct ObjectHitbox sGrowingBowserFlameHitbox = { + /* interactType: */ INTERACT_FLAME, + /* downOffset: */ 20, + /* damageOrCoinValue: */ 1, + /* health: */ 0, + /* numLootCoins: */ 0, + /* radius: */ 10, + /* height: */ 40, + /* hurtboxRadius: */ 0, + /* hurtboxHeight: */ 0, +}; + +struct ObjectHitbox sBowserFlameHitbox = { + /* interactType: */ INTERACT_FLAME, + /* downOffset: */ 0, + /* damageOrCoinValue: */ 1, + /* health: */ 0, + /* numLootCoins: */ 0, + /* radius: */ 10, + /* height: */ 40, + /* hurtboxRadius: */ 0, + /* hurtboxHeight: */ 0, +}; + +void bowser_flame_despawn(void) { + obj_mark_for_deletion(o); + spawn_object_with_scale(o, MODEL_NONE, bhvBlackSmokeUpward, 1.0f); + if (random_float() < 0.1) { + spawn_object(o, MODEL_YELLOW_COIN, bhvTemporaryYellowCoin); + } +} + +s32 bowser_flame_should_despawn(s32 maxTime) { + if (maxTime < o->oTimer) { + return TRUE; + } + + // Flames should despawn if they fall off the arena. + if (o->oFloorType == SURFACE_BURNING) { + return TRUE; + } + if (o->oFloorType == SURFACE_DEATH_PLANE) { + return TRUE; + } + + return FALSE; +} + +void bhv_flame_bowser_init(void) { + o->oAnimState = (s32)(random_float() * 10.0f); + o->oMoveAngleYaw = random_u16(); + if (random_float() < 0.2) { + o->oVelY = 80.0f; + } else { + o->oVelY = 20.0f; + } + o->oForwardVel = 10.0f; + o->oGravity = -1.0f; + o->oFlameScale = random_float() + 1.0f; +} + +void bhv_flame_large_burning_out_init(void) { + o->oAnimState = (s32)(random_float() * 10.0f); + o->oMoveAngleYaw = random_u16(); + o->oVelY = 10.0f; + o->oForwardVel = 0.0f; + o->oFlameScale = 7.0f; +} + +void bowser_flame_move(void) { + s32 timer; + timer = ((o->oFlameSpeedTimerOffset + gGlobalTimer) & 0x3F) << 10; + o->oPosX += sins(o->oMoveAngleYaw) * sins(timer) * 4.0f; + o->oPosZ += coss(o->oMoveAngleYaw) * sins(timer) * 4.0f; +} + +void bhv_flame_bowser_loop(void) { + cur_obj_update_floor_and_walls(); + cur_obj_move_standard(78); + if (o->oVelY < -4.0f) { + o->oVelY = -4.0f; + } + if (o->oAction == 0) { + cur_obj_become_intangible(); + bowser_flame_move(); + if (o->oMoveFlags & OBJ_MOVE_LANDED) { + o->oAction++; + if (cur_obj_has_behavior(bhvFlameLargeBurningOut)) { + o->oFlameScale = 8.0f; + } else { + o->oFlameScale = random_float() * 2 + 6.0f; + } + o->oForwardVel = 0; + o->oVelY = 0; + o->oGravity = 0; + } + } else { + cur_obj_become_tangible(); + if (o->oTimer > o->oFlameScale * 10 + 5.0f) { + o->oFlameScale -= 0.15; + if (o->oFlameScale <= 0) { + bowser_flame_despawn(); + } + } + } + cur_obj_scale(o->oFlameScale); + o->oGraphYOffset = o->header.gfx.scale[1] * 14.0f; + obj_set_hitbox(o, &sBowserFlameHitbox); +} + +void bhv_flame_moving_forward_growing_init(void) { + o->oForwardVel = 30.0f; + obj_translate_xz_random(o, 80.0f); + o->oAnimState = (s32)(random_float() * 10.0f); + o->oFlameScale = 3.0f; +} + +void bhv_flame_moving_forward_growing_loop(void) { + UNUSED s32 unused; + UNUSED struct Object *flame; + obj_set_hitbox(o, &sGrowingBowserFlameHitbox); + o->oFlameScale = o->oFlameScale + 0.5; + cur_obj_scale(o->oFlameScale); + if (o->oMoveAnglePitch > 0x800) { + o->oMoveAnglePitch -= 0x200; + } + cur_obj_set_pos_via_transform(); + cur_obj_update_floor_height(); + if (o->oFlameScale > 30.0f) { + obj_mark_for_deletion(o); + } + if (o->oPosY < o->oFloorHeight) { + o->oPosY = o->oFloorHeight; + flame = spawn_object(o, MODEL_RED_FLAME, bhvFlameBowser); + obj_mark_for_deletion(o); + } +} + +void bhv_flame_floating_landing_init(void) { + o->oAnimState = (s32)(random_float() * 10.0f); + o->oMoveAngleYaw = random_u16(); + if (o->oBehParams2ndByte != 0) { + o->oForwardVel = random_float() * 5.0f; + } else { + o->oForwardVel = random_float() * 70.0f; + } + o->oVelY = random_float() * 20.0f; + o->oGravity = -1.0f; + o->oFlameSpeedTimerOffset = random_float() * 64.0f; +} + +f32 sFlameFloatingYLimit[] = { -8.0f, -6.0f, -3.0f }; + +void bhv_flame_floating_landing_loop(void) { + UNUSED s32 unused; + cur_obj_update_floor_and_walls(); + cur_obj_move_standard(78); + bowser_flame_move(); + if (bowser_flame_should_despawn(900)) { + obj_mark_for_deletion(o); + } + if (o->oVelY < sFlameFloatingYLimit[o->oBehParams2ndByte]) { + o->oVelY = sFlameFloatingYLimit[o->oBehParams2ndByte]; + } + if (o->oMoveFlags & OBJ_MOVE_LANDED) { + if (o->oBehParams2ndByte == 0) { + spawn_object(o, MODEL_RED_FLAME, bhvFlameLargeBurningOut); + } else { + spawn_object(o, MODEL_NONE, bhvBlueFlamesGroup); //? wonder if they meant MODEL_BLUE_FLAME? + } + obj_mark_for_deletion(o); + } + o->oGraphYOffset = o->header.gfx.scale[1] * 14.0f; +} + +void bhv_blue_bowser_flame_init(void) { + obj_translate_xz_random(o, 80.0f); + o->oAnimState = (s32)(random_float() * 10.0f); + o->oVelY = 7.0f; + o->oForwardVel = 35.0f; + o->oFlameScale = 3.0f; + o->oFlameUnusedRand = random_float() * 0.5; + o->oGravity = 1.0f; + o->oFlameSpeedTimerOffset = (s32)(random_float() * 64.0f); +} + +void bhv_blue_bowser_flame_loop(void) { + s32 i; + obj_set_hitbox(o, &sGrowingBowserFlameHitbox); + if (o->oFlameScale < 16.0f) { + o->oFlameScale = o->oFlameScale + 0.5; + } + cur_obj_scale(o->oFlameScale); + cur_obj_update_floor_and_walls(); + cur_obj_move_standard(78); + if (o->oTimer > 0x14) { + if (o->oBehParams2ndByte == 0) { + for (i = 0; i < 3; i++) { + spawn_object_relative_with_scale(0, 0, 0, 0, 5.0f, o, MODEL_RED_FLAME, + bhvFlameFloatingLanding); + } + } else { + spawn_object_relative_with_scale(1, 0, 0, 0, 8.0f, o, MODEL_BLUE_FLAME, + bhvFlameFloatingLanding); + spawn_object_relative_with_scale(2, 0, 0, 0, 8.0f, o, MODEL_BLUE_FLAME, + bhvFlameFloatingLanding); + } + obj_mark_for_deletion(o); + } +} + +void bhv_flame_bouncing_init(void) { + o->oAnimState = (s32)(random_float() * 10.0f); + o->oVelY = 30.0f; + o->oForwardVel = 20.0f; + o->oFlameScale = o->header.gfx.scale[0]; + o->oFlameSpeedTimerOffset = (s32)(random_float() * 64.0f); +} + +void bhv_flame_bouncing_loop(void) { + struct Object *bowser; + if (o->oTimer == 0) { + o->oFlameBowser = cur_obj_nearest_object_with_behavior(bhvBowser); + } + bowser = o->oFlameBowser; + o->oForwardVel = 15.0f; + o->oBounciness = -1.0f; + cur_obj_scale(o->oFlameScale); + obj_set_hitbox(o, &sGrowingBowserFlameHitbox); + cur_obj_update_floor_and_walls(); + cur_obj_move_standard(78); + if (bowser_flame_should_despawn(300)) { + obj_mark_for_deletion(o); + } + if (bowser != NULL) { + if (bowser->oHeldState == HELD_FREE) { + if (lateral_dist_between_objects(o, bowser) < 300.0f) { + obj_mark_for_deletion(o); + } + } + } +} + +void bhv_blue_flames_group_loop(void) { + struct Object *flame; + s32 i; + if (o->oTimer == 0) { + o->oMoveAngleYaw = obj_angle_to_object(o, gMarioObject); + o->oBlueFlameNextScale = 5.0f; + } + if (o->oTimer < 16) { + if ((o->oTimer & 1) == 0) { + for (i = 0; i < 3; i++) { + flame = spawn_object(o, MODEL_BLUE_FLAME, bhvFlameBouncing); + flame->oMoveAngleYaw += i * 0x5555; + flame->header.gfx.scale[0] = o->oBlueFlameNextScale; + } + o->oBlueFlameNextScale -= 0.5; + } + } else { + obj_mark_for_deletion(o); + } +} diff --git a/src/game/behaviors/break_particles.inc.c b/src/game/behaviors/break_particles.inc.c index a5a6a069..c7160ecd 100644 --- a/src/game/behaviors/break_particles.inc.c +++ b/src/game/behaviors/break_particles.inc.c @@ -11,7 +11,7 @@ void spawn_triangle_break_particles(s16 numTris, s16 triModel, f32 triSize, s16 triangle->oFaceAngleYaw = triangle->oMoveAngleYaw; triangle->oFaceAnglePitch = random_u16(); triangle->oVelY = random_f32_around_zero(50.0f); - if (triModel == 138 || triModel == 56) { + if (triModel == MODEL_DIRT_ANIMATION || triModel == MODEL_SL_CRACKED_ICE_CHUNK) { triangle->oAngleVelPitch = 0xF00; triangle->oAngleVelYaw = 0x500; triangle->oForwardVel = 30.0f; diff --git a/src/game/behaviors/breakable_box_small.inc.c b/src/game/behaviors/breakable_box_small.inc.c index bb9a4edd..e2ecc8c6 100644 --- a/src/game/behaviors/breakable_box_small.inc.c +++ b/src/game/behaviors/breakable_box_small.inc.c @@ -29,27 +29,27 @@ void small_breakable_box_spawn_dust(void) { } void small_breakable_box_act_move(void) { - s16 sp1E = object_step(); + s16 collisionFlags = object_step(); obj_attack_collided_from_other_object(o); - if (sp1E == 1) + if (collisionFlags == OBJ_COL_FLAG_GROUNDED) cur_obj_play_sound_2(SOUND_GENERAL_BOX_LANDING_2); - if (sp1E & 1) { + if (collisionFlags & OBJ_COL_FLAG_GROUNDED) { if (o->oForwardVel > 20.0f) { cur_obj_play_sound_2(SOUND_ENV_SLIDING); small_breakable_box_spawn_dust(); } } - if (sp1E & 2) { + if (collisionFlags & OBJ_COL_FLAG_HIT_WALL) { spawn_mist_particles(); - spawn_triangle_break_particles(20, 138, 0.7f, 3); + spawn_triangle_break_particles(20, MODEL_DIRT_ANIMATION, 0.7f, 3); obj_spawn_yellow_coins(o, 3); create_sound_spawner(SOUND_GENERAL_BREAK_BOX); o->activeFlags = ACTIVE_FLAG_DEACTIVATED; } - obj_check_floor_death(sp1E, sObjFloor); + obj_check_floor_death(collisionFlags, sObjFloor); } void breakable_box_small_released_loop(void) { @@ -106,7 +106,7 @@ void breakable_box_small_get_thrown(void) { cur_obj_enable_rendering(); o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; o->oHeldState = 0; - o->oFlags &= ~0x08; + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; o->oForwardVel = 40.0f; o->oVelY = 20.0f; o->oBreakableBoxSmallReleased = 1; diff --git a/src/game/behaviors/bully.inc.c b/src/game/behaviors/bully.inc.c index 21c561a7..3695a847 100644 --- a/src/game/behaviors/bully.inc.c +++ b/src/game/behaviors/bully.inc.c @@ -64,7 +64,7 @@ void bully_check_mario_collision(void) { o->oInteractStatus &= ~INT_STATUS_INTERACTED; o->oAction = BULLY_ACT_KNOCKBACK; - o->oFlags &= ~0x8; /* bit 3 */ + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; /* bit 3 */ cur_obj_init_animation(3); o->oBullyMarioCollisionAngle = o->oMoveAngleYaw; } @@ -98,7 +98,7 @@ void bully_act_knockback(void) { if (o->oForwardVel < 10.0 && (s32) o->oVelY == 0) { o->oForwardVel = 1.0; o->oBullyKBTimerAndMinionKOCounter++; - o->oFlags |= 0x8; /* bit 3 */ + o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; /* bit 3 */ o->oMoveAngleYaw = o->oFaceAngleYaw; obj_turn_toward_object(o, gMarioObject, 16, 1280); } else @@ -113,7 +113,7 @@ void bully_act_knockback(void) { void bully_act_back_up(void) { if (o->oTimer == 0) { - o->oFlags &= ~0x8; /* bit 3 */ + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; /* bit 3 */ o->oMoveAngleYaw += 0x8000; } @@ -128,13 +128,13 @@ void bully_act_back_up(void) { if (o->oTimer == 15) { o->oMoveAngleYaw = o->oFaceAngleYaw; - o->oFlags |= 0x8; /* bit 3 */ + o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; /* bit 3 */ o->oAction = BULLY_ACT_PATROL; } } void bully_backup_check(s16 collisionFlags) { - if (!(collisionFlags & 0x8) && o->oAction != BULLY_ACT_KNOCKBACK) /* bit 3 */ + if (!(collisionFlags & OBJ_COL_FLAG_NO_Y_VEL) && o->oAction != BULLY_ACT_KNOCKBACK) /* bit 3 */ { o->oPosX = o->oBullyPrevX; o->oPosZ = o->oBullyPrevZ; @@ -346,10 +346,10 @@ void bhv_big_bully_with_minions_loop(void) { case BULLY_ACT_ACTIVATE_AND_FALL: collisionFlags = object_step(); - if ((collisionFlags & 0x9) == 0x9) /* bits 0 and 3 */ + if ((collisionFlags & OBJ_COL_FLAGS_LANDED) == OBJ_COL_FLAGS_LANDED) /* bits 0 and 3 */ o->oAction = BULLY_ACT_PATROL; - if (collisionFlags == 1) { + if (collisionFlags == OBJ_COL_FLAG_GROUNDED) { cur_obj_play_sound_2(SOUND_OBJ_THWOMP); set_camera_shake_from_point(SHAKE_POS_SMALL, o->oPosX, o->oPosY, o->oPosZ); spawn_mist_particles(); diff --git a/src/game/behaviors/camera_lakitu.inc.c b/src/game/behaviors/camera_lakitu.inc.c index c3e7f441..2b66cff3 100644 --- a/src/game/behaviors/camera_lakitu.inc.c +++ b/src/game/behaviors/camera_lakitu.inc.c @@ -32,7 +32,7 @@ static void camera_lakitu_intro_act_trigger_cutscene(void) { && gMarioObject->oPosZ > -2000.0f && gMarioObject->oPosZ < -177.0f && gMarioObject->oPosZ < -177.0f) // always double check your conditions { - if (set_mario_npc_dialog(2) == 1) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_START) { o->oAction = CAMERA_LAKITU_INTRO_ACT_SPAWN_CLOUD; } } @@ -42,7 +42,7 @@ static void camera_lakitu_intro_act_trigger_cutscene(void) { * Warp up into the air and spawn cloud, then enter the TODO action. */ static void camera_lakitu_intro_act_spawn_cloud(void) { - if (set_mario_npc_dialog(2) == 2) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_SPEAK) { o->oAction = CAMERA_LAKITU_INTRO_ACT_UNK2; o->oPosX = 1800.0f; @@ -63,6 +63,10 @@ static void camera_lakitu_intro_act_spawn_cloud(void) { static void camera_lakitu_intro_act_show_dialog(void) { s16 targetMovePitch; s16 targetMoveYaw; +#ifdef AVOID_UB + targetMovePitch = 0; + targetMoveYaw = 0; +#endif cur_obj_play_sound_1(SOUND_AIR_LAKITU_FLY); @@ -115,7 +119,8 @@ static void camera_lakitu_intro_act_show_dialog(void) { } } } - } else if (cur_obj_update_dialog_with_cutscene(2, DIALOG_UNK2_FLAG_0, CUTSCENE_DIALOG, DIALOG_034) != 0) { + } else if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, DIALOG_034)) { o->oCameraLakituFinishedDialog = TRUE; } } diff --git a/src/game/behaviors/cannon.inc.c b/src/game/behaviors/cannon.inc.c index 5f55ca83..6a18f18d 100644 --- a/src/game/behaviors/cannon.inc.c +++ b/src/game/behaviors/cannon.inc.c @@ -107,10 +107,6 @@ void (*sOpenedCannonActions[])(void) = { opened_cannon_act_0, opened_cannon_act_ opened_cannon_act_3, opened_cannon_act_4, opened_cannon_act_5, opened_cannon_act_6 }; -u8 unused0EA1FC[] = { 2, 0, 0, 0, 0, 0, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0, 65, 32, 0, 0, - 63, 128, 0, 0, 2, 0, 0, 0, 65, 160, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0, - 65, 160, 0, 0, 63, 128, 0, 0, 8, 0, 0, 0, 65, 32, 0, 0, 63, 128, 0, 0 }; - void bhv_cannon_base_loop(void) { cur_obj_call_action_function(sOpenedCannonActions); if (o->oCannonUnkF8) diff --git a/src/game/behaviors/cap.inc.c b/src/game/behaviors/cap.inc.c index 066ff1fb..09e13d1a 100644 --- a/src/game/behaviors/cap.inc.c +++ b/src/game/behaviors/cap.inc.c @@ -118,11 +118,11 @@ void cap_scale_vertically(void) { } void wing_vanish_cap_act_0(void) { - s16 sp1E; + s16 collisionFlags; o->oFaceAngleYaw += o->oForwardVel * 128.0f; - sp1E = object_step(); - if (sp1E & 0x01) { + collisionFlags = object_step(); + if (collisionFlags & OBJ_COL_FLAG_GROUNDED) { cap_check_quicksand(); if (o->oVelY != 0.0f) { o->oCapUnkF4 = 1; @@ -161,11 +161,11 @@ void bhv_metal_cap_init(void) { } void metal_cap_act_0(void) { - s16 sp1E; + s16 collisionFlags; o->oFaceAngleYaw += o->oForwardVel * 128.0f; - sp1E = object_step(); - if (sp1E & 0x01) + collisionFlags = object_step(); + if (collisionFlags & OBJ_COL_FLAG_GROUNDED) cap_check_quicksand(); } @@ -220,12 +220,12 @@ void normal_cap_set_save_flags(void) { } void normal_cap_act_0(void) { - s16 sp1E; + s16 collisionFlags; o->oFaceAngleYaw += o->oForwardVel * 128.0f; o->oFaceAnglePitch += o->oForwardVel * 80.0f; - sp1E = object_step(); - if (sp1E & 0x01) { + collisionFlags = object_step(); + if (collisionFlags & OBJ_COL_FLAG_GROUNDED) { cap_check_quicksand(); if (o->oVelY != 0.0f) { diff --git a/src/game/behaviors/capswitch.inc.c b/src/game/behaviors/capswitch.inc.c index 3db6dd7c..4aa69dbc 100644 --- a/src/game/behaviors/capswitch.inc.c +++ b/src/game/behaviors/capswitch.inc.c @@ -1,12 +1,14 @@ // capswitch.c.inc +UNUSED u8 sCapSwitchText[] = { DIALOG_010, DIALOG_011, DIALOG_012 }; + void cap_switch_act_0(void) { o->oAnimState = o->oBehParams2ndByte; cur_obj_scale(0.5f); o->oPosY += 71.0f; spawn_object_relative_with_scale(0, 0, -71, 0, 0.5f, o, MODEL_CAP_SWITCH_BASE, bhvCapSwitchBase); if (gCurrLevelNum != LEVEL_UNKNOWN_32) { - if (save_file_get_flags() & D_8032F0C0[o->oBehParams2ndByte]) { + if (save_file_get_flags() & sCapSaveFlags[o->oBehParams2ndByte]) { o->oAction = 3; o->header.gfx.scale[1] = 0.1f; } else @@ -17,7 +19,7 @@ void cap_switch_act_0(void) { void cap_switch_act_1(void) { if (cur_obj_is_mario_on_platform()) { - save_file_set_flags(D_8032F0C0[o->oBehParams2ndByte]); + save_file_set_flags(sCapSaveFlags[o->oBehParams2ndByte]); o->oAction = 2; cur_obj_play_sound_2(SOUND_GENERAL_ACTIVATE_CAP_SWITCH); } @@ -30,13 +32,17 @@ void cap_switch_act_2(void) { if (o->oTimer == 4) { cur_obj_shake_screen(SHAKE_POS_SMALL); spawn_mist_particles(); - spawn_triangle_break_particles(60, 139, 0.3f, o->oBehParams2ndByte); + spawn_triangle_break_particles(60, MODEL_CARTOON_STAR, 0.3f, o->oBehParams2ndByte); #if ENABLE_RUMBLE queue_rumble_data(5, 80); #endif } } else { - sp1C = cur_obj_update_dialog_with_cutscene(1, 0x0C, CUTSCENE_CAP_SWITCH_PRESS, 0); + //! Neither of these flags are defined in this function so they do nothing. + // On an extra note, there's a specific check for this cutscene and + // there's no dialog defined since the cutscene itself calls the dialog. + sp1C = cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_FRONT, + (DIALOG_FLAG_TEXT_RESPONSE | DIALOG_FLAG_UNK_CAPSWITCH), CUTSCENE_CAP_SWITCH_PRESS, 0); if (sp1C) o->oAction = 3; } diff --git a/src/game/behaviors/chain_chomp.inc.c b/src/game/behaviors/chain_chomp.inc.c index 382be8d7..57afa831 100644 --- a/src/game/behaviors/chain_chomp.inc.c +++ b/src/game/behaviors/chain_chomp.inc.c @@ -256,8 +256,8 @@ static void chain_chomp_released_trigger_cutscene(void) { //! Can delay this if we get into a cutscene-unfriendly action after the // last post ground pound and before this - if (set_mario_npc_dialog(2) == 2 && (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) - && cutscene_object(CUTSCENE_STAR_SPAWN, o) == 1) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_SPEAK + && (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) && cutscene_object(CUTSCENE_STAR_SPAWN, o) == 1) { o->oChainChompReleaseStatus = CHAIN_CHOMP_RELEASED_LUNGE_AROUND; o->oTimer = 0; } @@ -342,7 +342,7 @@ static void chain_chomp_released_jump_away(void) { */ static void chain_chomp_released_end_cutscene(void) { if (cutscene_object(CUTSCENE_STAR_SPAWN, o) == -1) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); o->oAction = CHAIN_CHOMP_ACT_UNLOAD_CHAIN; } } @@ -536,7 +536,7 @@ void bhv_chain_chomp_gate_update(void) { spawn_mist_particles_with_sound(SOUND_GENERAL_WALL_EXPLOSION); set_camera_shake_from_point(SHAKE_POS_SMALL, o->oPosX, o->oPosY, o->oPosZ); spawn_mist_particles_variable(0, 0x7F, 200.0f); - spawn_triangle_break_particles(30, 0x8A, 3.0f, 4); + spawn_triangle_break_particles(30, MODEL_DIRT_ANIMATION, 3.0f, 4); obj_mark_for_deletion(o); } } diff --git a/src/game/behaviors/chuckya.inc.c b/src/game/behaviors/chuckya.inc.c index f9e5dac0..e74fe9c1 100644 --- a/src/game/behaviors/chuckya.inc.c +++ b/src/game/behaviors/chuckya.inc.c @@ -1,5 +1,17 @@ // chuckya.c.inc +struct UnusedChuckyaData { + u8 unk0; + f32 unk4; + f32 unk8; +}; + +struct UnusedChuckyaData sUnusedChuckyaData[] = { { 2, 0.f, 1.f }, + { 2, 10.f, 1.f }, + { 2, 20.f, 1.f }, + { 2, 20.f, 1.f }, + { 8, 10.f, 1.f }}; + void common_anchor_mario_behavior(f32 sp28, f32 sp2C, s32 sp30) { switch (o->parentObj->oChuckyaUnk88) { case 0: @@ -72,6 +84,9 @@ s32 approach_forward_vel(f32 *arr, f32 spC, f32 sp10) { void chuckya_act_0(void) { s32 sp3C; +#ifdef AVOID_UB + sp3C = 0; +#endif UNUSED u8 pad[16]; s32 sp28; if (o->oTimer == 0) @@ -197,7 +212,7 @@ void bhv_chuckya_loop(void) { chuckya_move(); break; case HELD_HELD: - cur_obj_unrender_and_reset_state(2, 0); + cur_obj_unrender_set_action_and_anim(2, 0); break; case HELD_THROWN: case HELD_DROPPED: diff --git a/src/game/behaviors/coin.inc.c b/src/game/behaviors/coin.inc.c index 2aeebca8..ea6b84cd 100644 --- a/src/game/behaviors/coin.inc.c +++ b/src/game/behaviors/coin.inc.c @@ -12,7 +12,7 @@ struct ObjectHitbox sYellowCoinHitbox = { /* hurtboxHeight: */ 0, }; -s16 D_8032F2A4[][2] = { { 0, -150 }, { 0, -50 }, { 0, 50 }, { 0, 150 }, +s16 sCoinArrowPositions[][2] = { { 0, -150 }, { 0, -50 }, { 0, 50 }, { 0, 150 }, { -50, 100 }, { -100, 50 }, { 50, 100 }, { 100, 50 } }; s32 bhv_coin_sparkles_init(void) { @@ -161,8 +161,8 @@ void spawn_coin_in_formation(s32 sp50, s32 sp54) { sp40[1] = sins(sp50 << 13) * 200.0f + 200.0f; break; case 4: - sp40[0] = D_8032F2A4[sp50][0]; - sp40[2] = D_8032F2A4[sp50][1]; + sp40[0] = sCoinArrowPositions[sp50][0]; + sp40[2] = sCoinArrowPositions[sp50][1]; break; } if (sp54 & 0x10) diff --git a/src/game/behaviors/collide_particles.inc.c b/src/game/behaviors/collide_particles.inc.c index ff93a511..9b013699 100644 --- a/src/game/behaviors/collide_particles.inc.c +++ b/src/game/behaviors/collide_particles.inc.c @@ -1,10 +1,10 @@ // collide_particles.c.inc -s16 D_8032F2CC[] = { 0xD000, 0, 0x3000, 0, 0xDE67, 0x2199, - 0x2199, 0x2199, 0xDE67, 0xDE67, 0x2199, 0xDE67 }; +static s16 sTinyTriMovementParams[] = { 0xD000, 0, 0x3000, 0, 0xDE67, 0x2199, + 0x2199, 0x2199, 0xDE67, 0xDE67, 0x2199, 0xDE67 }; -s16 D_8032F2E4[] = { 0xE000, 0, 0, 0, 0x2000, 0, 0xE99A, - 0x1666, 0x1666, 0x1666, 0xE99A, 0xE99A, 0x1666, 0xE99A }; +static s16 sTinyStarMovementParams[] = { 0xE000, 0, 0, 0, 0x2000, 0, 0xE99A, + 0x1666, 0x1666, 0x1666, 0xE99A, 0xE99A, 0x1666, 0xE99A }; void bhv_punch_tiny_triangle_loop(void) { s16 sp1E; @@ -28,9 +28,9 @@ void bhv_punch_tiny_triangle_init(void) { struct Object *triangle; for (i = 0; i < 6; i++) { triangle = spawn_object(o, MODEL_DIRT_ANIMATION, bhvPunchTinyTriangle); - triangle->oMoveAngleYaw = gMarioObject->oMoveAngleYaw + D_8032F2CC[2 * i] + 0x8000; - triangle->oVelY = sins(D_8032F2CC[2 * i + 1]) * 25.0f; - triangle->oForwardVel = coss(D_8032F2CC[2 * i + 1]) * 25.0f; + triangle->oMoveAngleYaw = gMarioObject->oMoveAngleYaw + sTinyTriMovementParams[2 * i] + 0x8000; + triangle->oVelY = sins(sTinyTriMovementParams[2 * i + 1]) * 25.0f; + triangle->oForwardVel = coss(sTinyTriMovementParams[2 * i + 1]) * 25.0f; } } @@ -54,9 +54,9 @@ void bhv_tiny_star_particles_init(void) { struct Object *particle; for (i = 0; i < 7; i++) { particle = spawn_object(o, MODEL_CARTOON_STAR, bhvWallTinyStarParticle); - particle->oMoveAngleYaw = gMarioObject->oMoveAngleYaw + D_8032F2E4[2 * i] + 0x8000; - particle->oVelY = sins(D_8032F2E4[2 * i + 1]) * 25.0f; - particle->oForwardVel = coss(D_8032F2E4[2 * i + 1]) * 25.0f; + particle->oMoveAngleYaw = gMarioObject->oMoveAngleYaw + sTinyStarMovementParams[2 * i] + 0x8000; + particle->oVelY = sins(sTinyStarMovementParams[2 * i + 1]) * 25.0f; + particle->oForwardVel = coss(sTinyStarMovementParams[2 * i + 1]) * 25.0f; } } diff --git a/src/game/behaviors/door.inc.c b/src/game/behaviors/door.inc.c index db48e4f9..a02ee597 100644 --- a/src/game/behaviors/door.inc.c +++ b/src/game/behaviors/door.inc.c @@ -6,11 +6,11 @@ struct DoorAction s32 action; }; -struct DoorAction D_8032F300[] = { { 0x40000, 3 }, { 0x80000, 4 }, { 0x10000, 1 }, { 0x20000, 2 }, { -1, 0 }, }; +static struct DoorAction sDoorActions[] = { { INT_STATUS_WARP_DOOR_PULLED, 3 }, { INT_STATUS_WARP_DOOR_PUSHED, 4 }, { INT_STATUS_DOOR_PULLED, 1 }, { INT_STATUS_DOOR_PUSHED, 2 }, { -1, 0 }, }; -s32 D_8032F328[] = { SOUND_GENERAL_OPEN_WOOD_DOOR, SOUND_GENERAL_OPEN_IRON_DOOR }; +static s32 sDoorOpenSounds[] = { SOUND_GENERAL_OPEN_WOOD_DOOR, SOUND_GENERAL_OPEN_IRON_DOOR }; -s32 D_8032F330[] = { SOUND_GENERAL_CLOSE_WOOD_DOOR, SOUND_GENERAL_CLOSE_IRON_DOOR }; +static s32 sDoorCloseSounds[] = { SOUND_GENERAL_CLOSE_WOOD_DOOR, SOUND_GENERAL_CLOSE_IRON_DOOR }; void door_animation_and_reset(s32 sp18) { cur_obj_init_animation_with_sound(sp18); @@ -29,27 +29,27 @@ void set_door_camera_event(void) { void play_door_open_noise(void) { s32 sp1C = cur_obj_has_model(MODEL_HMC_METAL_DOOR); if (o->oTimer == 0) { - cur_obj_play_sound_2(D_8032F328[sp1C]); + cur_obj_play_sound_2(sDoorOpenSounds[sp1C]); gTimeStopState |= TIME_STOP_MARIO_OPENED_DOOR; } if (o->oTimer == 70) { - cur_obj_play_sound_2(D_8032F330[sp1C]); + cur_obj_play_sound_2(sDoorCloseSounds[sp1C]); } } void play_warp_door_open_noise(void) { s32 sp1C = cur_obj_has_model(MODEL_HMC_METAL_DOOR); if (o->oTimer == 30) - cur_obj_play_sound_2(D_8032F330[sp1C]); + cur_obj_play_sound_2(sDoorCloseSounds[sp1C]); } void bhv_door_loop(void) { s32 sp1C = 0; - while (D_8032F300[sp1C].flag != (u32)~0) { - if (cur_obj_clear_interact_status_flag(D_8032F300[sp1C].flag)) { + while (sDoorActions[sp1C].flag != (u32)~0) { + if (cur_obj_clear_interact_status_flag(sDoorActions[sp1C].flag)) { set_door_camera_event(); - cur_obj_change_action(D_8032F300[sp1C].action); + cur_obj_change_action(sDoorActions[sp1C].action); } sp1C++; } diff --git a/src/game/behaviors/dorrie.inc.c b/src/game/behaviors/dorrie.inc.c index 3eb3c04e..d6d3c8c2 100644 --- a/src/game/behaviors/dorrie.inc.c +++ b/src/game/behaviors/dorrie.inc.c @@ -68,7 +68,8 @@ void dorrie_act_lower_head(void) { if (o->oTimer > 150) { dorrie_begin_head_raise(FALSE); } else if (gMarioObject->platform == o) { - if (o->oDorrieForwardDistToMario > 830.0f && set_mario_npc_dialog(2) == 1) { + if (o->oDorrieForwardDistToMario > 830.0f + && set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_START) { dorrie_begin_head_raise(TRUE); } else if (o->oDorrieForwardDistToMario > 320.0f) { o->oTimer = 0; @@ -77,7 +78,7 @@ void dorrie_act_lower_head(void) { #else if (gMarioObject->platform == o) { if (o->oDorrieOffsetY == -17.0f && o->oDorrieForwardDistToMario > 780.0f - && set_mario_npc_dialog(2) == 1) { + && set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_START) { dorrie_begin_head_raise(TRUE); } else if (o->oDorrieForwardDistToMario > 320.0f) { o->oTimer = 0; @@ -97,10 +98,10 @@ void dorrie_act_raise_head(void) { if (cur_obj_check_if_near_animation_end()) { o->oAction = DORRIE_ACT_MOVE; } else if (o->oDorrieLiftingMario && o->header.gfx.animInfo.animFrame < 74) { - if (set_mario_npc_dialog(2) == 2) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_SPEAK) { o->oDorrieHeadRaiseSpeed += 0x1CC; if (cur_obj_check_anim_frame(73)) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); } dorrie_raise_head(); } else { diff --git a/src/game/behaviors/elevator.inc.c b/src/game/behaviors/elevator.inc.c index f9df6856..34369071 100644 --- a/src/game/behaviors/elevator.inc.c +++ b/src/game/behaviors/elevator.inc.c @@ -1,5 +1,13 @@ // elevator.c.inc +static s16 sElevatorHeights[] = { -51, 0, 0, + -461, 0, 0, + -512, 0, 0, + -2611, 0, 0, + -2360, 0, 0, + 214, 0, 0, + -50, 1945, 1 }; + void elevator_starting_shake(void) { cur_obj_play_sound_2(SOUND_GENERAL_QUIET_POUND1); cur_obj_shake_screen(SHAKE_POS_SMALL); @@ -84,15 +92,15 @@ void elevator_act_3(void) // nearly identical to action 2 } void bhv_elevator_init(void) { - s32 sp1C = D_8032F38C[o->oBehParams2ndByte * 3 + 2]; + s32 sp1C = sElevatorHeights[o->oBehParams2ndByte * 3 + 2]; if (sp1C == 0) { - o->oElevatorUnkF4 = D_8032F38C[o->oBehParams2ndByte * 3]; + o->oElevatorUnkF4 = sElevatorHeights[o->oBehParams2ndByte * 3]; o->oElevatorUnkF8 = o->oHomeY; o->oElevatorUnkFC = (o->oElevatorUnkF4 + o->oElevatorUnkF8) / 2; o->oElevatorUnk100 = cur_obj_has_behavior(bhvRrElevatorPlatform); } else { - o->oElevatorUnkF4 = D_8032F38C[o->oBehParams2ndByte * 3]; - o->oElevatorUnkF8 = D_8032F38C[o->oBehParams2ndByte * 3 + 1]; + o->oElevatorUnkF4 = sElevatorHeights[o->oBehParams2ndByte * 3]; + o->oElevatorUnkF8 = sElevatorHeights[o->oBehParams2ndByte * 3 + 1]; o->oElevatorUnkFC = (o->oElevatorUnkF4 + o->oElevatorUnkF8) / 2; o->oElevatorUnk100 = 2; } @@ -101,15 +109,6 @@ void bhv_elevator_init(void) { void (*sElevatorActions[])(void) = { elevator_act_0, elevator_act_1, elevator_act_2, elevator_act_3, elevator_act_4 }; -struct SpawnParticlesInfo D_8032F3CC = { 3, 20, MODEL_MIST, 20, 10, 5, 0, 0, 0, 30, 30.0f, 1.5f }; - -struct SpawnParticlesInfo D_8032F3E0 = { 0, 5, MODEL_SAND_DUST, 0, 0, 20, 20, 0, 252, 30, 5.0f, 2.0f }; - -s16 D_8032F3F4[] = { 2, -8, 1, 4 }; - -struct SpawnParticlesInfo D_8032F3FC = { 0, 5, MODEL_WHITE_PARTICLE_DL, 0, 0, 20, 20, 0, 252, 30, - 2.0f, 2.0f }; - void bhv_elevator_loop(void) { cur_obj_call_action_function(sElevatorActions); } diff --git a/src/game/behaviors/exclamation_box.inc.c b/src/game/behaviors/exclamation_box.inc.c index 3fb177f0..3d70e032 100644 --- a/src/game/behaviors/exclamation_box.inc.c +++ b/src/game/behaviors/exclamation_box.inc.c @@ -38,7 +38,7 @@ void bhv_rotating_exclamation_box_loop(void) { void exclamation_box_act_0(void) { if (o->oBehParams2ndByte < 3) { o->oAnimState = o->oBehParams2ndByte; - if ((save_file_get_flags() & D_8032F0C0[o->oBehParams2ndByte]) + if ((save_file_get_flags() & sCapSaveFlags[o->oBehParams2ndByte]) || ((o->oBehParams >> 24) & 0xFF) != 0) o->oAction = 2; else @@ -55,7 +55,7 @@ void exclamation_box_act_1(void) { spawn_object(o, MODEL_EXCLAMATION_POINT, bhvRotatingExclamationMark); cur_obj_set_model(MODEL_EXCLAMATION_BOX_OUTLINE); } - if ((save_file_get_flags() & D_8032F0C0[o->oBehParams2ndByte]) + if ((save_file_get_flags() & sCapSaveFlags[o->oBehParams2ndByte]) || ((o->oBehParams >> 24) & 0xFF) != 0) { o->oAction = 2; cur_obj_set_model(MODEL_EXCLAMATION_BOX); @@ -113,8 +113,8 @@ void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1) { sp1C->oForwardVel = 3.0f; sp1C->oMoveAngleYaw = gMarioObject->oMoveAngleYaw; o->oBehParams |= a0->unk2 << 24; - if (a0->model == 122) - o->oFlags |= 0x4000; + if (a0->model == MODEL_STAR) + o->oFlags |= OBJ_FLAG_PERSISTENT_RESPAWN; break; } a0++; @@ -124,7 +124,7 @@ void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1) { void exclamation_box_act_4(void) { exclamation_box_spawn_contents(sExclamationBoxContents, o->oBehParams2ndByte); spawn_mist_particles_variable(0, 0, 46.0f); - spawn_triangle_break_particles(20, 139, 0.3f, o->oAnimState); + spawn_triangle_break_particles(20, MODEL_CARTOON_STAR, 0.3f, o->oAnimState); create_sound_spawner(SOUND_GENERAL_BREAK_BOX); if (o->oBehParams2ndByte < 3) { o->oAction = 5; diff --git a/src/game/behaviors/eyerok.inc.c b/src/game/behaviors/eyerok.inc.c index 473d7475..b22cff34 100644 --- a/src/game/behaviors/eyerok.inc.c +++ b/src/game/behaviors/eyerok.inc.c @@ -63,7 +63,7 @@ static void eyerok_boss_act_wake_up(void) { } static void eyerok_boss_act_show_intro_text(void) { - if (cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, DIALOG_117)) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, DIALOG_FLAG_NONE, CUTSCENE_DIALOG, DIALOG_117)) { o->oAction = EYEROK_BOSS_ACT_FIGHT; } } @@ -117,7 +117,7 @@ static void eyerok_boss_act_fight(void) { static void eyerok_boss_act_die(void) { if (o->oTimer == 60) { - if (cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, DIALOG_118)) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, DIALOG_FLAG_NONE, CUTSCENE_DIALOG, DIALOG_118)) { spawn_default_star(0.0f, -900.0f, -3700.0f); } else { o->oTimer -= 1; diff --git a/src/game/behaviors/falling_rising_platform.inc.c b/src/game/behaviors/falling_rising_platform.inc.c index 4bd7ecd5..35359690 100644 --- a/src/game/behaviors/falling_rising_platform.inc.c +++ b/src/game/behaviors/falling_rising_platform.inc.c @@ -1,15 +1,18 @@ // falling_rising_platform.c.inc void bhv_squishable_platform_loop(void) { - o->header.gfx.scale[1] = (sins(o->oPlatformTimer) + 1.0) * 0.3 + 0.4; - o->oPlatformTimer += 0x80; + o->header.gfx.scale[1] = (sins(o->oBitfsPlatformTimer) + 1.0) * 0.3 + 0.4; + o->oBitfsPlatformTimer += 0x80; +#ifdef AUTO_COLLISION_DISTANCE + o->oFlags &= ~OBJ_FLAG_DONT_CALC_COLL_DIST; +#endif } void bhv_bitfs_sinking_platform_loop(void) { o->oPosY -= - sins(o->oPlatformTimer) + sins(o->oBitfsPlatformTimer) * 0.58; //! f32 double conversion error accumulates on Wii VC causing the platform to rise up - o->oPlatformTimer += 0x100; + o->oBitfsPlatformTimer += 0x100; } // TODO: Named incorrectly. fix @@ -21,8 +24,8 @@ void bhv_bitfs_sinking_cage_platform_loop(void) { if (o->oBehParams2ndByte != 0) { if (o->oTimer == 0) o->oPosY -= 300.0f; - o->oPosY += sins(o->oPlatformTimer) * 7.0f; + o->oPosY += sins(o->oBitfsPlatformTimer) * 7.0f; } else - o->oPosY -= sins(o->oPlatformTimer) * 3.0f; - o->oPlatformTimer += 0x100; + o->oPosY -= sins(o->oBitfsPlatformTimer) * 3.0f; + o->oBitfsPlatformTimer += 0x100; } diff --git a/src/game/behaviors/fire_piranha_plant.inc.c b/src/game/behaviors/fire_piranha_plant.inc.c index a6d867b2..c4b1bc56 100644 --- a/src/game/behaviors/fire_piranha_plant.inc.c +++ b/src/game/behaviors/fire_piranha_plant.inc.c @@ -35,7 +35,7 @@ void bhv_fire_piranha_plant_init(void) { obj_set_hitbox(o, &sFirePiranhaPlantHitbox); if ((u16)(o->oBehParams >> 16) != 0) { - o->oFlags |= 0x00004000; + o->oFlags |= OBJ_FLAG_PERSISTENT_RESPAWN; o->oHealth = 1; if (o->oBehParams & 0x0000FF00) { diff --git a/src/game/behaviors/fish.inc.c b/src/game/behaviors/fish.inc.c index 33cc6028..9590b096 100644 --- a/src/game/behaviors/fish.inc.c +++ b/src/game/behaviors/fish.inc.c @@ -33,6 +33,9 @@ static void fish_spawner_act_spawn(void) { case FISH_SPAWNER_BP_FEW_CYAN: model = MODEL_CYAN_FISH; schoolQuantity = 5; minDistToMario = 1500.0f; fishAnimation = cyan_fish_seg6_anims_0600E264; break; + + default: + return; } diff --git a/src/game/behaviors/grand_star.inc.c b/src/game/behaviors/grand_star.inc.c index afdf0855..29c71c49 100644 --- a/src/game/behaviors/grand_star.inc.c +++ b/src/game/behaviors/grand_star.inc.c @@ -51,7 +51,7 @@ void bhv_grand_star_loop(void) { o->oPosY = o->oHomeY + 200.0f; grand_star_zero_velocity(); gObjCutsceneDone = 1; - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); o->oAction++; o->oInteractStatus = 0; cur_obj_play_sound_2(SOUND_GENERAL_GRAND_STAR_JUMP); diff --git a/src/game/behaviors/ground_particles.inc.c b/src/game/behaviors/ground_particles.inc.c index 26dd285a..c7259311 100644 --- a/src/game/behaviors/ground_particles.inc.c +++ b/src/game/behaviors/ground_particles.inc.c @@ -1,25 +1,34 @@ // ground_particles.c.inc +static struct SpawnParticlesInfo sGlobalMistParticles = { 3, 20, MODEL_MIST, 20, 10, 5, 0, 0, 0, 30, 30.0f, 1.5f }; + +static struct SpawnParticlesInfo sSandParticles = { 0, 5, MODEL_SAND_DUST, 0, 0, 20, 20, 0, 252, 30, 5.0f, 2.0f }; + +static s16 sSmokeMovementParams[] = { 2, -8, 1, 4 }; + +static struct SpawnParticlesInfo sSnowParticles = { 0, 5, MODEL_WHITE_PARTICLE_DL, 0, 0, 20, 20, 0, 252, 30, + 2.0f, 2.0f }; + void bhv_pound_white_puffs_init(void) { clear_particle_flags(0x8000); spawn_mist_from_global(); } void spawn_mist_from_global(void) { - cur_obj_spawn_particles(&D_8032F3CC); + cur_obj_spawn_particles(&sGlobalMistParticles); } void bhv_ground_sand_init(void) { clear_particle_flags(0x4000); - cur_obj_spawn_particles(&D_8032F3E0); + cur_obj_spawn_particles(&sSandParticles); } void spawn_smoke_with_velocity(void) { struct Object *smoke = spawn_object_with_scale(o, MODEL_SMOKE, bhvWhitePuffSmoke2, 1.0f); - smoke->oForwardVel = D_8032F3F4[0]; - smoke->oVelY = D_8032F3F4[1]; - smoke->oGravity = D_8032F3F4[2]; - obj_translate_xyz_random(smoke, D_8032F3F4[3]); + smoke->oForwardVel = sSmokeMovementParams[0]; + smoke->oVelY = sSmokeMovementParams[1]; + smoke->oGravity = sSmokeMovementParams[2]; + obj_translate_xyz_random(smoke, sSmokeMovementParams[3]); } // TODO Fix name @@ -29,5 +38,5 @@ void clear_particle_flags(u32 flags) { void bhv_ground_snow_init(void) { clear_particle_flags(1 << 16); - cur_obj_spawn_particles(&D_8032F3FC); + cur_obj_spawn_particles(&sSnowParticles); } diff --git a/src/game/behaviors/heave_ho.inc.c b/src/game/behaviors/heave_ho.inc.c index 9afe9c58..74daefeb 100644 --- a/src/game/behaviors/heave_ho.inc.c +++ b/src/game/behaviors/heave_ho.inc.c @@ -111,7 +111,7 @@ void bhv_heave_ho_loop(void) { heave_ho_move(); break; case HELD_HELD: - cur_obj_unrender_and_reset_state(0, 0); + cur_obj_unrender_set_action_and_anim(0, 0); break; case HELD_THROWN: cur_obj_get_dropped(); diff --git a/src/game/behaviors/hoot.inc.c b/src/game/behaviors/hoot.inc.c index f43f0ffd..95692e58 100644 --- a/src/game/behaviors/hoot.inc.c +++ b/src/game/behaviors/hoot.inc.c @@ -225,7 +225,7 @@ void hoot_turn_to_home(void) { } void hoot_awake_loop(void) { - if (o->oInteractStatus == INT_STATUS_HOOT_GRABBED_BY_MARIO) { + if (o->oInteractStatus == TRUE) { //! Note: Not a flag, treated as a TRUE/FALSE statement hoot_action_loop(); cur_obj_init_animation(1); } else { @@ -254,8 +254,9 @@ void bhv_hoot_loop(void) { case HOOT_AVAIL_WANTS_TO_TALK: hoot_awake_loop(); - if (set_mario_npc_dialog(2) == 2 && cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_044)) { - set_mario_npc_dialog(0); + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_SPEAK + && cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_044)) { + set_mario_npc_dialog(MARIO_DIALOG_STOP); cur_obj_become_tangible(); diff --git a/src/game/behaviors/intro_peach.inc.c b/src/game/behaviors/intro_peach.inc.c index 2838a910..37b40301 100644 --- a/src/game/behaviors/intro_peach.inc.c +++ b/src/game/behaviors/intro_peach.inc.c @@ -40,7 +40,7 @@ void bhv_intro_peach_loop(void) { case 2: intro_peach_set_pos_and_opacity(gCurrentObject, 255.f, 3.f); - if ((gCurrentObject->oTimer > 100) && (get_dialog_id() == -1)) + if ((gCurrentObject->oTimer > 100) && (get_dialog_id() == DIALOG_NONE)) gCurrentObject->oAction += 1; break; case 3: diff --git a/src/game/behaviors/jrb_ship.inc.c b/src/game/behaviors/jrb_ship.inc.c index 3b627da0..4f805aec 100644 --- a/src/game/behaviors/jrb_ship.inc.c +++ b/src/game/behaviors/jrb_ship.inc.c @@ -42,7 +42,7 @@ void bhv_jrb_sliding_box_loop(void) { struct Surface *sp38; UNUSED Vec3f sp2C; Vec3f sp20; - s16 sp1E; + s16 sp1E = 0; if (o->oJrbSlidingBoxUnkF4 == NULL) { sp3C = cur_obj_nearest_object_with_behavior(bhvInSunkenShip3); if (sp3C != NULL) // NULL check only for assignment, not for dereference? diff --git a/src/game/behaviors/jumping_box.inc.c b/src/game/behaviors/jumping_box.inc.c index 287d7377..5c86169d 100644 --- a/src/game/behaviors/jumping_box.inc.c +++ b/src/game/behaviors/jumping_box.inc.c @@ -52,7 +52,7 @@ void bhv_jumping_box_loop(void) { case HELD_HELD: obj_copy_pos(o, gMarioObject); cur_obj_set_model(MODEL_BREAKABLE_BOX_SMALL); - cur_obj_unrender_and_reset_state(-1, 0); + cur_obj_unrender_set_action_and_anim(-1, 0); break; case HELD_THROWN: cur_obj_get_thrown_or_placed(40.0f, 20.0f, 1); diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c index b8a54aa6..7741c64b 100644 --- a/src/game/behaviors/king_bobomb.inc.c +++ b/src/game/behaviors/king_bobomb.inc.c @@ -35,7 +35,8 @@ void king_bobomb_act_0(void) { o->oSubAction++; seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); } - } else if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_017)) { + } else if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, DIALOG_017)) { o->oAction = 2; o->oFlags |= OBJ_FLAG_HOLDABLE; } @@ -170,12 +171,13 @@ void king_bobomb_act_6(void) { void king_bobomb_act_7(void) { cur_obj_init_animation_with_sound(2); - if (cur_obj_update_dialog_with_cutscene(2, 2, CUTSCENE_DIALOG, DIALOG_116)) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TEXT_DEFAULT, CUTSCENE_DIALOG, DIALOG_116)) { create_sound_spawner(SOUND_OBJ_KING_WHOMP_DEATH); cur_obj_hide(); cur_obj_become_intangible(); spawn_mist_particles_variable(0, 0, 200.0f); - spawn_triangle_break_particles(20, 138, 3.0f, 4); + spawn_triangle_break_particles(20, MODEL_DIRT_ANIMATION, 3.0f, 4); cur_obj_shake_screen(SHAKE_POS_SMALL); #ifndef VERSION_JP cur_obj_spawn_star_at_y_offset(2000.0f, 4500.0f, -4500.0f, 200.0f); @@ -262,7 +264,8 @@ void king_bobomb_act_5(void) { // bobomb returns home o->oSubAction++; break; case 4: - if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_128)) + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, DIALOG_128)) o->oAction = 2; break; } @@ -311,7 +314,7 @@ void bhv_king_bobomb_loop(void) { king_bobomb_move(); break; case HELD_HELD: - cur_obj_unrender_and_reset_state(6, 1); + cur_obj_unrender_set_action_and_anim(6, 1); break; case HELD_THROWN: case HELD_DROPPED: diff --git a/src/game/behaviors/klepto.inc.c b/src/game/behaviors/klepto.inc.c index 46d7ffcc..1a5768a5 100644 --- a/src/game/behaviors/klepto.inc.c +++ b/src/game/behaviors/klepto.inc.c @@ -180,7 +180,7 @@ static void klepto_act_wait_for_mario(void) { klepto_target_mario(); if (o->oKleptoDistanceToTarget < 1000.0f) { o->oAction = KLEPTO_ACT_TURN_TOWARD_MARIO; - o->oFlags &= ~0x00000008; + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; } } @@ -195,7 +195,7 @@ static void klepto_act_turn_toward_mario(void) { cur_obj_play_sound_2(SOUND_OBJ_KLEPTO1); o->oAction = KLEPTO_ACT_DIVE_AT_MARIO; o->oMoveAngleYaw = o->oFaceAngleYaw; - o->oFlags |= 0x00000008; + o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; cur_obj_init_animation_with_sound(3); } @@ -287,7 +287,7 @@ static void klepto_act_retreat(void) { o->oAction = KLEPTO_ACT_RESET_POSITION; o->oHomeY = 1500.0f; o->oKleptoUnk1AE = -100; - o->oFlags |= 0x00000008; + o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; cur_obj_become_tangible(); } } @@ -371,7 +371,7 @@ void bhv_klepto_update(void) { o->oGravity = -2.0f; o->oMoveAngleYaw = o->oAngleToMario + 0x8000; - o->oFlags &= ~0x00000008; + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; cur_obj_become_intangible(); } else if (gMarioStates[0].action == ACT_SLEEPING || (gMarioStates[0].action diff --git a/src/game/behaviors/koopa.inc.c b/src/game/behaviors/koopa.inc.c index 49c1c2dc..8e3e8779 100644 --- a/src/game/behaviors/koopa.inc.c +++ b/src/game/behaviors/koopa.inc.c @@ -482,7 +482,7 @@ s32 obj_begin_race(s32 noTimer) { } // Unfreeze mario and disable time stop to begin the race - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); disable_time_stop_including_mario(); } else if (o->oTimer > 50) { return TRUE; @@ -518,7 +518,7 @@ static void koopa_the_quick_act_show_init_text(void) { s32 response = obj_update_race_proposition_dialog( sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].initText); - if (response == 1) { + if (response == DIALOG_RESPONSE_YES) { UNUSED s32 unused; gMarioShotFromCannon = FALSE; @@ -531,7 +531,7 @@ static void koopa_the_quick_act_show_init_text(void) { o->oKoopaTurningAwayFromWall = FALSE; o->oFlags |= OBJ_FLAG_ACTIVE_FROM_AFAR; - } else if (response == 2) { + } else if (response == DIALOG_RESPONSE_NO) { o->oAction = KOOPA_THE_QUICK_ACT_WAIT_BEFORE_RACE; o->oKoopaTheQuickInitTextboxCooldown = 60; } @@ -707,7 +707,7 @@ static void koopa_the_quick_act_stop(void) { static void koopa_the_quick_act_after_race(void) { cur_obj_init_animation_with_sound(7); - if (o->parentObj->oKoopaRaceEndpointUnk100 == 0) { + if (o->parentObj->oKoopaRaceEndpointDialog == 0) { if (cur_obj_can_mario_activate_textbox_2(400.0f, 400.0f)) { stop_background_music(SEQUENCE_ARGS(4, SEQ_LEVEL_SLIDE)); @@ -717,23 +717,24 @@ static void koopa_the_quick_act_after_race(void) { if (o->parentObj->oKoopaRaceEndpointRaceStatus < 0) { // Mario cheated o->parentObj->oKoopaRaceEndpointRaceStatus = 0; - o->parentObj->oKoopaRaceEndpointUnk100 = DIALOG_006; + o->parentObj->oKoopaRaceEndpointDialog = DIALOG_006; } else { // Mario won - o->parentObj->oKoopaRaceEndpointUnk100 = + o->parentObj->oKoopaRaceEndpointDialog = sKoopaTheQuickProperties[o->oKoopaTheQuickRaceIndex].winText; } } else { // KtQ won - o->parentObj->oKoopaRaceEndpointUnk100 = DIALOG_041; + o->parentObj->oKoopaRaceEndpointDialog = DIALOG_041; } o->oFlags &= ~OBJ_FLAG_ACTIVE_FROM_AFAR; } - } else if (o->parentObj->oKoopaRaceEndpointUnk100 > 0) { - s32 dialogResponse = cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, o->parentObj->oKoopaRaceEndpointUnk100); + } else if (o->parentObj->oKoopaRaceEndpointDialog > 0) { + s32 dialogResponse = cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, o->parentObj->oKoopaRaceEndpointDialog); if (dialogResponse != 0) { - o->parentObj->oKoopaRaceEndpointUnk100 = -1; + o->parentObj->oKoopaRaceEndpointDialog = DIALOG_NONE; o->oTimer = 0; } } else if (o->parentObj->oKoopaRaceEndpointRaceStatus != 0) { diff --git a/src/game/behaviors/koopa_shell_underwater.inc.c b/src/game/behaviors/koopa_shell_underwater.inc.c index ff0eef70..7d670ab5 100644 --- a/src/game/behaviors/koopa_shell_underwater.inc.c +++ b/src/game/behaviors/koopa_shell_underwater.inc.c @@ -22,7 +22,7 @@ void bhv_koopa_shell_underwater_loop(void) { set_koopa_shell_underwater_hitbox(); break; case HELD_HELD: - cur_obj_unrender_and_reset_state(-1, 0); + cur_obj_unrender_set_action_and_anim(-1, 0); break; case HELD_THROWN: case HELD_DROPPED: diff --git a/src/game/behaviors/manta_ray.inc.c b/src/game/behaviors/manta_ray.inc.c index 4b79abc3..5e1c27ff 100644 --- a/src/game/behaviors/manta_ray.inc.c +++ b/src/game/behaviors/manta_ray.inc.c @@ -43,6 +43,9 @@ void bhv_manta_ray_init(void) { static void manta_ray_move(void) { s16 animFrame; s32 pathStatus; +#ifdef AVOID_UB + pathStatus = 0; +#endif animFrame = o->header.gfx.animInfo.animFrame; gCurrentObject->oPathedStartWaypoint = (struct Waypoint *) sMantaRayTraj; @@ -53,7 +56,7 @@ static void manta_ray_move(void) { o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, o->oMantaTargetYaw, 0x80); o->oMoveAnglePitch = approach_s16_symmetric(o->oMoveAnglePitch, o->oMantaTargetPitch, 0x80); - + // This causes the ray to tilt as it turns. if ((s16) o->oMantaTargetYaw != (s16) o->oMoveAngleYaw) { o->oMoveAngleRoll -= 91; diff --git a/src/game/behaviors/mips.inc.c b/src/game/behaviors/mips.inc.c index 980457eb..adba6333 100644 --- a/src/game/behaviors/mips.inc.c +++ b/src/game/behaviors/mips.inc.c @@ -113,6 +113,9 @@ void bhv_mips_act_follow_path(void) { s32 followStatus; struct Waypoint **pathBase; struct Waypoint *waypoint; +#ifdef AVOID_UB + followStatus = 0; +#endif // Retrieve current waypoint. pathBase = segmented_to_virtual(&inside_castle_seg7_trajectory_mips); @@ -160,13 +163,10 @@ void bhv_mips_act_wait_for_animation_done(void) { * Handles MIPS falling down after being thrown. */ void bhv_mips_act_fall_down(void) { - - s16 collisionFlags = 0; - - collisionFlags = object_step(); + s16 collisionFlags = object_step(); o->header.gfx.animInfo.animFrame = 0; - if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) == 1) { + if (collisionFlags & OBJ_COL_FLAG_GROUNDED) { o->oAction = MIPS_ACT_WAIT_FOR_ANIMATION_DONE; o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; @@ -239,13 +239,13 @@ void bhv_mips_held(void) { else dialogID = DIALOG_162; - if (set_mario_npc_dialog(1) == 2) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_FRONT) == MARIO_DIALOG_STATUS_SPEAK) { o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogID)) { o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; o->oMipsStarStatus = MIPS_STAR_STATUS_SHOULD_SPAWN_STAR; - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); } } } diff --git a/src/game/behaviors/moneybag.inc.c b/src/game/behaviors/moneybag.inc.c index 7c366632..b8567bd5 100644 --- a/src/game/behaviors/moneybag.inc.c +++ b/src/game/behaviors/moneybag.inc.c @@ -74,7 +74,7 @@ void moneybag_jump(s8 collisionFlags) { case MONEYBAG_JUMP_JUMP: cur_obj_init_animation(2); - if ((collisionFlags & 1) == 1) /* bit 0 */ + if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) == OBJ_COL_FLAG_GROUNDED) /* bit 0 */ { o->oForwardVel = 0; o->oVelY = 0; diff --git a/src/game/behaviors/moving_coin.inc.c b/src/game/behaviors/moving_coin.inc.c index d992b13e..b01e32b8 100644 --- a/src/game/behaviors/moving_coin.inc.c +++ b/src/game/behaviors/moving_coin.inc.c @@ -31,7 +31,7 @@ s32 coin_step(s16 *collisionFlagsPtr) { obj_check_floor_death(*collisionFlagsPtr, sObjFloor); - if ((*collisionFlagsPtr & 0x1) != 0 && (*collisionFlagsPtr & 0x8) == 0) /* bit 0, bit 3 */ + if ((*collisionFlagsPtr & OBJ_COL_FLAG_GROUNDED) && !(*collisionFlagsPtr & OBJ_COL_FLAG_NO_Y_VEL)) /* bit 0, bit 3 */ { cur_obj_play_sound_2(SOUND_GENERAL_COIN_DROP); return 1; @@ -152,7 +152,7 @@ void blue_coin_sliding_away_from_mario(void) { if (coin_step(&collisionFlags) != 0) o->oVelY += 18.0f; - if ((collisionFlags & 0x2) != 0) + if (collisionFlags & OBJ_COL_FLAG_HIT_WALL) o->oAction = 3; /* bit 1 */ if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 1000) == 0) diff --git a/src/game/behaviors/mushroom_1up.inc.c b/src/game/behaviors/mushroom_1up.inc.c index aac7c98d..5921827c 100644 --- a/src/game/behaviors/mushroom_1up.inc.c +++ b/src/game/behaviors/mushroom_1up.inc.c @@ -57,11 +57,11 @@ void pole_1up_move_towards_mario(void) { bhv_1up_interact(); } -void one_up_move_away_from_mario(s16 sp1A) { +void one_up_move_away_from_mario(s16 collisionFlags) { o->oForwardVel = 8.0f; o->oMoveAngleYaw = o->oAngleToMario + 0x8000; bhv_1up_interact(); - if (sp1A & 0x02) + if (collisionFlags & OBJ_COL_FLAG_HIT_WALL) o->oAction = 2; if (!is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 3000)) @@ -105,9 +105,7 @@ void bhv_1up_walking_loop(void) { } void bhv_1up_running_away_loop(void) { - s16 sp26; - - sp26 = object_step(); + s16 collisionFlags = object_step(); switch (o->oAction) { case 0: if (o->oTimer >= 18) @@ -127,7 +125,7 @@ void bhv_1up_running_away_loop(void) { case 1: spawn_object(o, MODEL_NONE, bhvSparkleSpawn); - one_up_move_away_from_mario(sp26); + one_up_move_away_from_mario(collisionFlags); break; case 2: @@ -140,10 +138,8 @@ void bhv_1up_running_away_loop(void) { } void sliding_1up_move(void) { - s16 sp1E; - - sp1E = object_step(); - if (sp1E & 0x01) { + s16 collisionFlags = object_step(); + if (collisionFlags & OBJ_COL_FLAG_GROUNDED) { o->oForwardVel += 25.0f; o->oVelY = 0; } else { @@ -185,7 +181,7 @@ void bhv_1up_loop(void) { } void bhv_1up_jump_on_approach_loop(void) { - s16 sp26; + s16 collisionFlags; switch (o->oAction) { case 0: @@ -196,13 +192,13 @@ void bhv_1up_jump_on_approach_loop(void) { break; case 1: - sp26 = object_step(); - one_up_move_away_from_mario(sp26); + collisionFlags = object_step(); + one_up_move_away_from_mario(collisionFlags); spawn_object(o, MODEL_NONE, bhvSparkleSpawn); break; case 2: - sp26 = object_step(); + collisionFlags = object_step(); bhv_1up_interact(); obj_flicker_and_disappear(o, 30); break; @@ -212,7 +208,7 @@ void bhv_1up_jump_on_approach_loop(void) { } void bhv_1up_hidden_loop(void) { - s16 sp26; + s16 collisionFlags; switch (o->oAction) { case 0: o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; @@ -225,19 +221,19 @@ void bhv_1up_hidden_loop(void) { break; case 1: - sp26 = object_step(); - one_up_move_away_from_mario(sp26); + collisionFlags = object_step(); + one_up_move_away_from_mario(collisionFlags); spawn_object(o, MODEL_NONE, bhvSparkleSpawn); break; case 2: - sp26 = object_step(); + collisionFlags = object_step(); bhv_1up_interact(); obj_flicker_and_disappear(o, 30); break; case 3: - sp26 = object_step(); + collisionFlags = object_step(); if (o->oTimer >= 18) spawn_object(o, MODEL_NONE, bhvSparkleSpawn); @@ -264,7 +260,6 @@ void bhv_1up_hidden_trigger_loop(void) { } void bhv_1up_hidden_in_pole_loop(void) { - UNUSED s16 sp26; switch (o->oAction) { case 0: o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; @@ -278,11 +273,11 @@ void bhv_1up_hidden_in_pole_loop(void) { case 1: pole_1up_move_towards_mario(); - sp26 = object_step(); + object_step(); break; case 3: - sp26 = object_step(); + object_step(); if (o->oTimer >= 18) spawn_object(o, MODEL_NONE, bhvSparkleSpawn); diff --git a/src/game/behaviors/racing_penguin.inc.c b/src/game/behaviors/racing_penguin.inc.c index 5aeeb257..a287229d 100644 --- a/src/game/behaviors/racing_penguin.inc.c +++ b/src/game/behaviors/racing_penguin.inc.c @@ -27,7 +27,7 @@ static void racing_penguin_act_wait_for_mario(void) { static void racing_penguin_act_show_init_text(void) { s32 response = obj_update_race_proposition_dialog(sRacingPenguinData[o->oBehParams2ndByte].text); - if (response == 1) { + if (response == DIALOG_RESPONSE_YES) { struct Object *child; child = cur_obj_nearest_object_with_behavior(bhvPenguinRaceFinishLine); @@ -42,7 +42,7 @@ static void racing_penguin_act_show_init_text(void) { o->oAction = RACING_PENGUIN_ACT_PREPARE_FOR_RACE; o->oVelY = 60.0f; - } else if (response == 2) { + } else if (response == DIALOG_RESPONSE_NO) { o->oAction = RACING_PENGUIN_ACT_WAIT_FOR_MARIO; o->oRacingPenguinInitTextCooldown = 60; } @@ -143,7 +143,8 @@ static void racing_penguin_act_show_final_text(void) { o->oForwardVel = 4.0f; } } else if (o->oRacingPenguinFinalTextbox > 0) { - if ((textResult = cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, o->oRacingPenguinFinalTextbox)) != 0) { + if ((textResult = cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, o->oRacingPenguinFinalTextbox))) { o->oRacingPenguinFinalTextbox = -1; o->oTimer = 0; } diff --git a/src/game/behaviors/rotating_octagonal_plat.inc.c b/src/game/behaviors/rotating_octagonal_plat.inc.c index 86d758c8..2126c944 100644 --- a/src/game/behaviors/rotating_octagonal_plat.inc.c +++ b/src/game/behaviors/rotating_octagonal_plat.inc.c @@ -1,15 +1,15 @@ // rotating_octagonal_plat.inc.c -void const *D_80331A44[] = { +static const Collision *sOctagonalPlatformCollision[] = { bits_seg7_collision_0701AA84, rr_seg7_collision_07029508, }; -s16 D_80331A4C[] = { 300, -300, 600, -600 }; +static s16 sOctagonalPlatformAngularVelocities[] = { 300, -300, 600, -600 }; void bhv_rotating_octagonal_plat_init(void) { - o->collisionData = segmented_to_virtual(D_80331A44[(u8)(o->oBehParams >> 16)]); - o->oAngleVelYaw = D_80331A4C[(u8)(o->oBehParams >> 24)]; + o->collisionData = segmented_to_virtual(sOctagonalPlatformCollision[(u8)(o->oBehParams >> 16)]); + o->oAngleVelYaw = sOctagonalPlatformAngularVelocities[(u8)(o->oBehParams >> 24)]; } void bhv_rotating_octagonal_plat_loop(void) { diff --git a/src/game/behaviors/scuttlebug.inc.c b/src/game/behaviors/scuttlebug.inc.c index 16840e1c..febf64f2 100644 --- a/src/game/behaviors/scuttlebug.inc.c +++ b/src/game/behaviors/scuttlebug.inc.c @@ -77,7 +77,7 @@ void bhv_scuttlebug_loop(void) { cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x400); break; case 3: - o->oFlags &= ~8; + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; o->oForwardVel = -10.0f; o->oVelY = 30.0f; cur_obj_play_sound_2(SOUND_OBJ2_SCUTTLEBUG_ALERT); @@ -89,7 +89,7 @@ void bhv_scuttlebug_loop(void) { o->oSubAction++; o->oVelY = 0.0f; o->oScuttlebugUnkFC = 0; - o->oFlags |= 8; + o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; o->oInteractStatus = 0; } break; diff --git a/src/game/behaviors/shock_wave.inc.c b/src/game/behaviors/shock_wave.inc.c index c714e91a..9665f997 100644 --- a/src/game/behaviors/shock_wave.inc.c +++ b/src/game/behaviors/shock_wave.inc.c @@ -1,25 +1,38 @@ // shock_wave.c.inc -f32 D_8032F420[] = { 1.9f, 2.4f, 4.0f, 4.8f }; +/** + * Shockwave scale distance hit points + */ +f32 sBowserShockwaveHitPoints[] = { 1.9f, 2.4f, 4.0f, 4.8f }; +/** + * Bowser's shockwave attack main loop + */ void bhv_bowser_shock_wave_loop(void) { - f32 sp2C, sp28, sp24, sp20; - s16 sp1E = 70; - o->oBowserShockWaveUnkF4 = o->oTimer * 10; - cur_obj_scale(o->oBowserShockWaveUnkF4); + f32 distMin1, distMax1, distMin2, distMax2; + s16 fadeFrames = 70; + // Scale shockwave as the timer goes on + o->oBowserShockWaveScale = o->oTimer * 10; + cur_obj_scale(o->oBowserShockWaveScale); + // Slightly reduce opacity each 3 frames if (gGlobalTimer % 3) o->oOpacity -= 1; - if (o->oTimer > sp1E) + // Reduce opacity faster after 70 frames have passed + if (o->oTimer > fadeFrames) o->oOpacity -= 5; + // Delete object when it's fully transparent if (o->oOpacity <= 0) obj_mark_for_deletion(o); - if (o->oTimer < sp1E && mario_is_in_air_action() == 0) { - sp2C = o->oBowserShockWaveUnkF4 * D_8032F420[0]; - sp28 = o->oBowserShockWaveUnkF4 * D_8032F420[1]; - sp24 = o->oBowserShockWaveUnkF4 * D_8032F420[2]; - sp20 = o->oBowserShockWaveUnkF4 * D_8032F420[3]; - if ((sp2C < o->oDistanceToMario && o->oDistanceToMario < sp28) - || (sp24 < o->oDistanceToMario && o->oDistanceToMario < sp20)) - gMarioObject->oInteractStatus |= INT_STATUS_HIT_BY_SHOCKWAVE; + // If object times is less than 70 frame and Mario is not in the air... + if (o->oTimer < fadeFrames && mario_is_in_air_action() == 0) { + // ..define distance values depending of the scale multiplied by hit points + distMin1 = o->oBowserShockWaveScale * sBowserShockwaveHitPoints[0]; + distMax1 = o->oBowserShockWaveScale * sBowserShockwaveHitPoints[1]; + distMin2 = o->oBowserShockWaveScale * sBowserShockwaveHitPoints[2]; + distMax2 = o->oBowserShockWaveScale * sBowserShockwaveHitPoints[3]; + // If Mario is in between distMin and distMax values, shock him + if ((distMin1 < o->oDistanceToMario && o->oDistanceToMario < distMax1) + || (distMin2 < o->oDistanceToMario && o->oDistanceToMario < distMax2)) + gMarioObject->oInteractStatus |= INT_STATUS_MARIO_SHOCKWAVE; } } diff --git a/src/game/behaviors/skeeter.inc.c b/src/game/behaviors/skeeter.inc.c index a726760f..6451d4ea 100644 --- a/src/game/behaviors/skeeter.inc.c +++ b/src/game/behaviors/skeeter.inc.c @@ -70,7 +70,7 @@ static void skeeter_act_lunge(void) { if (o->oMoveFlags & OBJ_MOVE_HIT_WALL) { o->oMoveAngleYaw = cur_obj_reflect_move_angle_off_wall(); o->oForwardVel *= 0.3f; - o->oFlags &= ~0x00000008; + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; } if (obj_forward_vel_approach(0.0f, 0.8f) && cur_obj_check_if_at_animation_end()) { @@ -84,7 +84,7 @@ static void skeeter_act_lunge(void) { o->oAction = SKEETER_ACT_IDLE; o->oSkeeterWaitTime = random_linear_offset(0, 30); - o->oFlags |= 0x00000008; + o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; } } } diff --git a/src/game/behaviors/sl_snowman_wind.inc.c b/src/game/behaviors/sl_snowman_wind.inc.c index 7d84258b..508615ab 100644 --- a/src/game/behaviors/sl_snowman_wind.inc.c +++ b/src/game/behaviors/sl_snowman_wind.inc.c @@ -21,7 +21,7 @@ void bhv_sl_snowman_wind_loop(void) { // Mario has come close, begin dialog. } else if (o->oSubAction == SL_SNOWMAN_WIND_ACT_TALKING) { - if (cur_obj_update_dialog(2, 2, DIALOG_153, 0)) + if (cur_obj_update_dialog(MARIO_DIALOG_LOOK_UP, DIALOG_FLAG_TEXT_DEFAULT, DIALOG_153, 0)) o->oSubAction++; // Blowing, spawn wind particles (SL_SNOWMAN_WIND_ACT_BLOWING) diff --git a/src/game/behaviors/snow_mound.inc.c b/src/game/behaviors/snow_mound.inc.c index f8fcc539..b9bfb978 100644 --- a/src/game/behaviors/snow_mound.inc.c +++ b/src/game/behaviors/snow_mound.inc.c @@ -33,7 +33,7 @@ void bhv_snow_mound_spawn_loop(void) { if (o->oTimer == 64 || o->oTimer == 128 || o->oTimer == 192 || o->oTimer == 224 || o->oTimer == 256) sp1C = spawn_object(o, MODEL_SL_SNOW_TRIANGLE, bhvSlidingSnowMound); - if (o->oTimer == 256) { + if (sp1C && o->oTimer == 256) { sp1C->header.gfx.scale[0] = 2.0f; sp1C->header.gfx.scale[1] = 2.0f; } diff --git a/src/game/behaviors/snowman.inc.c b/src/game/behaviors/snowman.inc.c index 97374f93..35ed8dd9 100644 --- a/src/game/behaviors/snowman.inc.c +++ b/src/game/behaviors/snowman.inc.c @@ -51,12 +51,14 @@ void adjust_rolling_face_pitch(f32 f12) { } void snowmans_bottom_act_1(void) { - UNUSED s16 sp26; s32 sp20; UNUSED s16 sp1E; +#ifdef AVOID_UB + sp20 = 0; +#endif o->oPathedStartWaypoint = segmented_to_virtual(&ccm_seg7_trajectory_snowman); - sp26 = object_step_without_floor_orient(); + object_step_without_floor_orient(); sp20 = cur_obj_follow_path(sp20); o->oSnowmansBottomUnkF8 = o->oPathedTargetYaw; o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, o->oSnowmansBottomUnkF8, 0x400); @@ -77,9 +79,7 @@ void snowmans_bottom_act_1(void) { } void snowmans_bottom_act_2(void) { - UNUSED s16 sp26; - - sp26 = object_step_without_floor_orient(); + object_step_without_floor_orient(); if (o->oForwardVel > 70.0) o->oForwardVel = 70.0f; @@ -103,15 +103,13 @@ void snowmans_bottom_act_2(void) { } void snowmans_bottom_act_3(void) { - UNUSED s16 sp1E; - - sp1E = object_step_without_floor_orient(); - if ((sp1E & 0x09) == 0x09) { + s16 collisionFlags = object_step_without_floor_orient(); + if ((collisionFlags & OBJ_COL_FLAGS_LANDED) == OBJ_COL_FLAGS_LANDED) { o->oAction = 4; cur_obj_become_intangible(); } - if ((sp1E & 0x01) != 0) { + if ((collisionFlags & 0x01) != 0) { spawn_mist_particles_variable(0, 0, 70.0f); o->oPosX = -4230.0f; o->oPosZ = 1813.0f; @@ -125,12 +123,12 @@ void bhv_snowmans_bottom_loop(void) { switch (o->oAction) { case 0: if (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 400) == 1 - && set_mario_npc_dialog(1) == 2) { + && set_mario_npc_dialog(MARIO_DIALOG_LOOK_FRONT) == MARIO_DIALOG_STATUS_SPEAK) { sp1E = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_110); if (sp1E) { o->oForwardVel = 10.0f; o->oAction = 1; - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); } } break; @@ -187,11 +185,11 @@ void bhv_snowmans_head_init(void) { void bhv_snowmans_head_loop(void) { UNUSED s16 sp1E; - s16 sp1C; + s16 collisionFlags; switch (o->oAction) { case 0: - if (trigger_obj_dialog_when_facing(&o->oSnowmansHeadUnkF4, DIALOG_109, 400.0f, 1)) + if (trigger_obj_dialog_when_facing(&o->oSnowmansHeadDialogActive, DIALOG_109, 400.0f, MARIO_DIALOG_LOOK_FRONT)) o->oAction = 1; break; @@ -199,8 +197,8 @@ void bhv_snowmans_head_loop(void) { break; case 2: - sp1C = object_step_without_floor_orient(); - if (sp1C & 0x08) + collisionFlags = object_step_without_floor_orient(); + if (collisionFlags & OBJ_COL_FLAG_NO_Y_VEL) o->oAction = 3; break; @@ -215,7 +213,7 @@ void bhv_snowmans_head_loop(void) { break; case 4: - if (trigger_obj_dialog_when_facing(&o->oSnowmansHeadUnkF4, DIALOG_111, 700.0f, 2)) { + if (trigger_obj_dialog_when_facing(&o->oSnowmansHeadDialogActive, DIALOG_111, 700.0f, MARIO_DIALOG_LOOK_UP)) { spawn_mist_particles(); spawn_default_star(-4700.0f, -1024.0f, 1890.0f); o->oAction = 1; diff --git a/src/game/behaviors/spawn_star.inc.c b/src/game/behaviors/spawn_star.inc.c index 76846121..434a48c3 100644 --- a/src/game/behaviors/spawn_star.inc.c +++ b/src/game/behaviors/spawn_star.inc.c @@ -130,18 +130,27 @@ struct Object *spawn_star(struct Object *sp30, f32 sp34, f32 sp38, f32 sp3C) { void spawn_default_star(f32 sp20, f32 sp24, f32 sp28) { struct Object *sp1C; +#ifdef AVOID_UB + sp1C = 0; +#endif sp1C = spawn_star(sp1C, sp20, sp24, sp28); sp1C->oBehParams2ndByte = 0; } void spawn_red_coin_cutscene_star(f32 sp20, f32 sp24, f32 sp28) { struct Object *sp1C; +#ifdef AVOID_UB + sp1C = 0; +#endif sp1C = spawn_star(sp1C, sp20, sp24, sp28); sp1C->oBehParams2ndByte = 1; } void spawn_no_exit_star(f32 sp20, f32 sp24, f32 sp28) { struct Object *sp1C; +#ifdef AVOID_UB + sp1C = 0; +#endif sp1C = spawn_star(sp1C, sp20, sp24, sp28); sp1C->oBehParams2ndByte = 1; sp1C->oInteractionSubtype |= INT_SUBTYPE_NO_EXIT; diff --git a/src/game/behaviors/spindrift.inc.c b/src/game/behaviors/spindrift.inc.c index bc04018e..4e904486 100644 --- a/src/game/behaviors/spindrift.inc.c +++ b/src/game/behaviors/spindrift.inc.c @@ -27,12 +27,12 @@ void bhv_spindrift_loop(void) { cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x400); break; case 1: - o->oFlags &= ~8; + o->oFlags &= ~OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; o->oForwardVel = -10.0f; if (o->oTimer > 20) { o->oAction = 0; o->oInteractStatus = 0; - o->oFlags |= 8; + o->oFlags |= OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW; } break; } diff --git a/src/game/behaviors/star_door.inc.c b/src/game/behaviors/star_door.inc.c index 4ae7bc82..67f52701 100644 --- a/src/game/behaviors/star_door.inc.c +++ b/src/game/behaviors/star_door.inc.c @@ -1,8 +1,8 @@ // star_door.c.inc void star_door_update_pos(void) { - o->oVelX = (o->oUnkBC) * coss(o->oMoveAngleYaw); - o->oVelZ = (o->oUnkBC) * -sins(o->oMoveAngleYaw); + o->oVelX = (o->oLeftVel) * coss(o->oMoveAngleYaw); + o->oVelZ = (o->oLeftVel) * -sins(o->oMoveAngleYaw); o->oPosX += o->oVelX; o->oPosZ += o->oVelZ; } @@ -27,7 +27,7 @@ void bhv_star_door_loop(void) { #endif } cur_obj_become_intangible(); - o->oUnkBC = -8.0f; + o->oLeftVel = -8.0f; star_door_update_pos(); if (o->oTimer >= 16) o->oAction++; @@ -43,7 +43,7 @@ void bhv_star_door_loop(void) { queue_rumble_data(35, 30); #endif } - o->oUnkBC = 8.0f; + o->oLeftVel = 8.0f; star_door_update_pos(); if (o->oTimer >= 16) o->oAction++; diff --git a/src/game/behaviors/switch_hidden_objects.inc.c b/src/game/behaviors/switch_hidden_objects.inc.c index e159700f..09875866 100644 --- a/src/game/behaviors/switch_hidden_objects.inc.c +++ b/src/game/behaviors/switch_hidden_objects.inc.c @@ -54,7 +54,7 @@ void hidden_breakable_box_actions(void) { o->oAction = 0; if (cur_obj_was_attacked_or_ground_pounded()) { spawn_mist_particles(); - spawn_triangle_break_particles(30, 138, 3.0f, 4); + spawn_triangle_break_particles(30, MODEL_DIRT_ANIMATION, 3.0f, 4); o->oAction++; cur_obj_play_sound_2(SOUND_GENERAL_BREAK_BOX); } diff --git a/src/game/behaviors/thi_top.inc.c b/src/game/behaviors/thi_top.inc.c index 23c97a06..727020d0 100644 --- a/src/game/behaviors/thi_top.inc.c +++ b/src/game/behaviors/thi_top.inc.c @@ -1,11 +1,9 @@ // thi_top.c.inc -struct SpawnParticlesInfo D_8032F134 = { +struct SpawnParticlesInfo sThiTopPuffs = { 0, 30, MODEL_WHITE_PARTICLE_SMALL, 0, 40, 0, 20, 40, 252, 30, 20.0f, 0.0f }; -UNUSED u8 unused8032F134[] = { 10, 11, 12 }; - void bhv_thi_huge_island_top_loop(void) { if (gTHIWaterDrained & 1) { if (o->oTimer == 0) @@ -21,8 +19,8 @@ void bhv_thi_tiny_island_top_loop(void) { if (o->oDistanceToMario < 500.0f) if (gMarioStates[0].action == ACT_GROUND_POUND_LAND) { o->oAction++; - cur_obj_spawn_particles(&D_8032F134); - spawn_triangle_break_particles(20, 138, 0.3f, 3); + cur_obj_spawn_particles(&sThiTopPuffs); + spawn_triangle_break_particles(20, MODEL_DIRT_ANIMATION, 0.3f, 3); cur_obj_play_sound_2(SOUND_GENERAL_ACTIVATE_CAP_SWITCH); cur_obj_hide(); } diff --git a/src/game/behaviors/tox_box.inc.c b/src/game/behaviors/tox_box.inc.c index 2bbb40bf..1b50d26e 100644 --- a/src/game/behaviors/tox_box.inc.c +++ b/src/game/behaviors/tox_box.inc.c @@ -17,7 +17,7 @@ void tox_box_move(f32 forwardVel, f32 a1, s16 deltaPitch, s16 deltaRoll) { o->oPosY = 99.41124 * sins((f32)(o->oTimer + 1) / 8 * 0x8000) + o->oHomeY + 3.0f; o->oForwardVel = forwardVel; - o->oUnkC0 = a1; + o->oUpVel = a1; o->oFaceAnglePitch += deltaPitch; if ((s16) o->oFaceAnglePitch < 0) deltaRoll = -deltaRoll; diff --git a/src/game/behaviors/tree_particles.inc.c b/src/game/behaviors/tree_particles.inc.c index 4df2ca49..2ae44920 100644 --- a/src/game/behaviors/tree_particles.inc.c +++ b/src/game/behaviors/tree_particles.inc.c @@ -11,11 +11,11 @@ void bhv_tree_snow_or_leaf_loop(void) { } if (o->oPosY < o->oFloorHeight) obj_mark_for_deletion(o); - if (o->oFloorHeight < -11000.0f) + if (o->oFloorHeight < FLOOR_LOWER_LIMIT) obj_mark_for_deletion(o); if (o->oTimer > 100) obj_mark_for_deletion(o); - if (gPrevFrameObjectCount > 212) + if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY - 28)) obj_mark_for_deletion(o); o->oFaceAnglePitch += o->oAngleVelPitch; o->oFaceAngleRoll += o->oAngleVelRoll; diff --git a/src/game/behaviors/tumbling_bridge.inc.c b/src/game/behaviors/tumbling_bridge.inc.c index ffe02a12..0879e7c4 100644 --- a/src/game/behaviors/tumbling_bridge.inc.c +++ b/src/game/behaviors/tumbling_bridge.inc.c @@ -104,9 +104,6 @@ void tumbling_bridge_act_0(void) { void (*sTumblingBridgeActions[])(void) = { tumbling_bridge_act_0, tumbling_bridge_act_1, tumbling_bridge_act_2, tumbling_bridge_act_3 }; -s16 D_8032F38C[] = { -51, 0, 0, -461, 0, 0, -512, 0, 0, -2611, 0, - 0, -2360, 0, 0, 214, 0, 0, -50, 1945, 1, 0 }; - void bhv_tumbling_bridge_loop(void) { cur_obj_call_action_function(sTumblingBridgeActions); } diff --git a/src/game/behaviors/tuxie.inc.c b/src/game/behaviors/tuxie.inc.c index 1dae5850..d0713644 100644 --- a/src/game/behaviors/tuxie.inc.c +++ b/src/game/behaviors/tuxie.inc.c @@ -54,7 +54,8 @@ void tuxies_mother_act_1(void) { dialogID = DIALOG_058; else dialogID = DIALOG_059; - if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, dialogID)) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, dialogID)) { if (dialogID == DIALOG_058) o->oSubAction = 1; else @@ -117,7 +118,8 @@ void tuxies_mother_act_0(void) { o->oSubAction++; break; case 1: - if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_057)) + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, DIALOG_057)) o->oSubAction++; break; case 2: @@ -260,7 +262,7 @@ void bhv_small_penguin_loop(void) { small_penguin_free_actions(); break; case HELD_HELD: - cur_obj_unrender_and_reset_state(0, 0); + cur_obj_unrender_set_action_and_anim(0, 0); if (cur_obj_has_behavior(bhvPenguinBaby)) obj_set_behavior(o, bhvSmallPenguin); obj_copy_pos(o, gMarioObject); diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index 2e6ce836..fc5d00c9 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -383,7 +383,8 @@ void ukiki_act_go_to_cage(void) { case UKIKI_SUB_ACT_CAGE_TALK_TO_MARIO: cur_obj_init_animation_with_sound(UKIKI_ANIM_HANDSTAND); - if (cur_obj_update_dialog_with_cutscene(3, 1, CUTSCENE_DIALOG, DIALOG_080)) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_DOWN, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, DIALOG_080)) { o->oSubAction++; } break; @@ -501,7 +502,7 @@ void ukiki_free_loop(void) { * * Possibly unused so AnimState could be used for wearing a cap? */ -static void ukiki_blink_timer(void) { +UNUSED static void ukiki_blink_timer(void) { if (gGlobalTimer % 50 < 7) { o->oAnimState = UKIKI_ANIM_STATE_EYE_CLOSED; } else { @@ -516,16 +517,16 @@ void cage_ukiki_held_loop(void) { if (o->oPosY - o->oHomeY > -100.0f) { switch(o->oUkikiTextState) { case UKIKI_TEXT_DEFAULT: - if (set_mario_npc_dialog(2) == 2) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_UP) == MARIO_DIALOG_STATUS_SPEAK) { create_dialog_box_with_response(DIALOG_079); o->oUkikiTextState = UKIKI_TEXT_CAGE_TEXTBOX; } break; case UKIKI_TEXT_CAGE_TEXTBOX: - if (gDialogResponse != 0) { - set_mario_npc_dialog(0); - if (gDialogResponse == 1) { + if (gDialogResponse != DIALOG_RESPONSE_NONE) { + set_mario_npc_dialog(MARIO_DIALOG_STOP); + if (gDialogResponse == DIALOG_RESPONSE_YES) { o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; o->oUkikiTextState = UKIKI_TEXT_GO_TO_CAGE; } else { @@ -567,7 +568,7 @@ void cap_ukiki_held_loop(void) { break; case UKIKI_TEXT_STEAL_CAP: - if (cur_obj_update_dialog(2, 2, DIALOG_100, 0)) { + if (cur_obj_update_dialog(MARIO_DIALOG_LOOK_UP, DIALOG_FLAG_TEXT_DEFAULT, DIALOG_100, 0)) { o->oInteractionSubtype |= INT_SUBTYPE_DROP_IMMEDIATELY; o->oUkikiTextState = UKIKI_TEXT_STOLE_CAP; } @@ -577,9 +578,10 @@ void cap_ukiki_held_loop(void) { break; case UKIKI_TEXT_HAS_CAP: - if (cur_obj_update_dialog(2, 18, DIALOG_101, 0)) { + if (cur_obj_update_dialog(MARIO_DIALOG_LOOK_UP, + (DIALOG_FLAG_TEXT_DEFAULT | DIALOG_FLAG_TIME_STOP_ENABLED), DIALOG_101, 0)) { mario_retrieve_cap(); - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); o->oUkikiHasCap &= ~UKIKI_CAP_ON; o->oUkikiTextState = UKIKI_TEXT_GAVE_CAP_BACK; } @@ -617,7 +619,7 @@ void bhv_ukiki_loop(void) { break; case HELD_HELD: - cur_obj_unrender_and_reset_state(UKIKI_ANIM_HELD, 0); + cur_obj_unrender_set_action_and_anim(UKIKI_ANIM_HELD, 0); obj_copy_pos(o, gMarioObject); if (o->oBehParams2ndByte == UKIKI_CAP) { diff --git a/src/game/behaviors/ukiki_cage.inc.c b/src/game/behaviors/ukiki_cage.inc.c index 68a64e8a..2acce450 100644 --- a/src/game/behaviors/ukiki_cage.inc.c +++ b/src/game/behaviors/ukiki_cage.inc.c @@ -36,7 +36,7 @@ void bhv_ukiki_cage_star_loop(void) { case UKIKI_CAGE_STAR_ACT_SPAWN_STAR: obj_mark_for_deletion(o); spawn_mist_particles(); - spawn_triangle_break_particles(20, 138, 0.7, 3); + spawn_triangle_break_particles(20, MODEL_DIRT_ANIMATION, 0.7, 3); spawn_default_star(2500.0f, -1200.0f, 1300.0f); break; } diff --git a/src/game/behaviors/unagi.inc.c b/src/game/behaviors/unagi.inc.c index df9041e9..063ca6c6 100644 --- a/src/game/behaviors/unagi.inc.c +++ b/src/game/behaviors/unagi.inc.c @@ -163,6 +163,7 @@ void bhv_unagi_loop(void) { break; case 2: unagi_act_2(); + // fall through case 3: unagi_act_3(); break; diff --git a/src/game/behaviors/unused_poundable_platform.inc.c b/src/game/behaviors/unused_poundable_platform.inc.c index 23816905..0e2feb08 100644 --- a/src/game/behaviors/unused_poundable_platform.inc.c +++ b/src/game/behaviors/unused_poundable_platform.inc.c @@ -18,7 +18,7 @@ void bhv_unused_poundable_platform(void) { if (o->oAction == 0) { if (cur_obj_is_mario_ground_pounding_platform()) { spawn_mist_particles(); - spawn_triangle_break_particles(20, 56, 3.0f, 0); + spawn_triangle_break_particles(20, MODEL_SL_CRACKED_ICE_CHUNK, 3.0f, 0); o->oAction++; } } else if (o->oTimer > 7) { diff --git a/src/game/behaviors/whomp.inc.c b/src/game/behaviors/whomp.inc.c index 138e1753..b8ab613a 100644 --- a/src/game/behaviors/whomp.inc.c +++ b/src/game/behaviors/whomp.inc.c @@ -1,20 +1,20 @@ // whomp.c.inc void whomp_play_sfx_from_pound_animation(void) { - UNUSED s32 sp2C = o->header.gfx.animInfo.animFrame; - s32 sp28 = 0; + UNUSED s32 animFrame = o->header.gfx.animInfo.animFrame; + s32 playSound = 0; if (o->oForwardVel < 5.0f) { - sp28 = cur_obj_check_anim_frame(0); - sp28 |= cur_obj_check_anim_frame(23); + playSound = cur_obj_check_anim_frame(0); + playSound |= cur_obj_check_anim_frame(23); } else { - sp28 = cur_obj_check_anim_frame_in_range(0, 3); - sp28 |= cur_obj_check_anim_frame_in_range(23, 3); + playSound = cur_obj_check_anim_frame_in_range(0, 3); + playSound |= cur_obj_check_anim_frame_in_range(23, 3); } - if (sp28) + if (playSound) cur_obj_play_sound_2(SOUND_OBJ_POUNDING1); } -void whomp_act_0(void) { +void whomp_init(void) { cur_obj_init_animation_with_accel_and_sound(0, 1.0f); cur_obj_set_pos_to_home(); if (o->oBehParams2ndByte != 0) { @@ -28,14 +28,15 @@ void whomp_act_0(void) { cur_obj_set_pos_to_home(); o->oHealth = 3; } - } else if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_114)) + } else if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, DIALOG_114)) o->oAction = 2; } else if (o->oDistanceToMario < 500.0f) o->oAction = 1; whomp_play_sfx_from_pound_animation(); } -void whomp_act_7(void) { +void whomp_turn(void) { if (o->oSubAction == 0) { o->oForwardVel = 0.0f; cur_obj_init_animation_with_accel_and_sound(0, 1.0f); @@ -51,21 +52,24 @@ void whomp_act_7(void) { whomp_play_sfx_from_pound_animation(); } -void whomp_act_1(void) { - s16 sp26; - f32 sp20; - f32 sp1C; - sp26 = abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw); - sp20 = cur_obj_lateral_dist_to_home(); +void whomp_patrol(void) { + s16 marioAngle; + f32 distWalked; + f32 patrolDist; + + marioAngle = abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw); + distWalked = cur_obj_lateral_dist_to_home(); if (gCurrLevelNum == LEVEL_BITS) - sp1C = 200.0f; + patrolDist = 200.0f; else - sp1C = 700.0f; + patrolDist = 700.0f; + cur_obj_init_animation_with_accel_and_sound(0, 1.0f); o->oForwardVel = 3.0f; - if (sp20 > sp1C) + + if (distWalked > patrolDist) o->oAction = 7; - else if (sp26 < 0x2000) { + else if (marioAngle < 0x2000) { if (o->oDistanceToMario < 1500.0f) { o->oForwardVel = 9.0f; cur_obj_init_animation_with_accel_and_sound(0, 3.0f); @@ -76,14 +80,15 @@ void whomp_act_1(void) { whomp_play_sfx_from_pound_animation(); } -void whomp_act_2(void) { - s16 sp1E; +void king_whomp_chase(void) { + s16 marioAngle; cur_obj_init_animation_with_accel_and_sound(0, 1.0f); o->oForwardVel = 3.0f; cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x200); + if (o->oTimer > 30) { - sp1E = abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw); - if (sp1E < 0x2000) { + marioAngle = abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw); + if (marioAngle < 0x2000) { if (o->oDistanceToMario < 1500.0f) { o->oForwardVel = 9.0f; cur_obj_init_animation_with_accel_and_sound(0, 3.0f); @@ -92,6 +97,7 @@ void whomp_act_2(void) { o->oAction = 3; } } + whomp_play_sfx_from_pound_animation(); if (mario_is_far_below_object(1000.0f)) { o->oAction = 0; @@ -99,14 +105,14 @@ void whomp_act_2(void) { } } -void whomp_act_3(void) { +void whomp_prepare_jump(void) { o->oForwardVel = 0.0f; cur_obj_init_animation_with_accel_and_sound(1, 1.0f); if (cur_obj_check_if_near_animation_end()) o->oAction = 4; } -void whomp_act_4(void) { +void whomp_jump(void) { if (o->oTimer == 0) o->oVelY = 40.0f; if (o->oTimer < 8) { @@ -121,7 +127,7 @@ void whomp_act_4(void) { } } -void whomp_act_5(void) { +void whomp_land(void) { if (o->oSubAction == 0 && o->oMoveFlags & OBJ_MOVE_LANDED) { cur_obj_play_sound_2(SOUND_OBJ_WHOMP_LOWPRIO); cur_obj_shake_screen(SHAKE_POS_SMALL); @@ -145,7 +151,7 @@ void king_whomp_on_ground(void) { vec3f_copy_2(pos, &o->oPosX); vec3f_copy_2(&o->oPosX, &gMarioObject->oPosX); spawn_mist_particles_variable(0, 0, 100.0f); - spawn_triangle_break_particles(20, 138, 3.0f, 4); + spawn_triangle_break_particles(20, MODEL_DIRT_ANIMATION, 3.0f, 4); cur_obj_shake_screen(SHAKE_POS_SMALL); vec3f_copy_2(&o->oPosX, pos); } @@ -180,12 +186,13 @@ void whomp_on_ground(void) { o->oSubAction = 0; } -void whomp_act_6(void) { +void whomp_on_ground_general(void) { if (o->oSubAction != 10) { o->oForwardVel = 0.0f; o->oAngleVelPitch = 0; o->oAngleVelYaw = 0; o->oAngleVelRoll = 0; + if (o->oBehParams2ndByte != 0) king_whomp_on_ground(); else @@ -207,14 +214,15 @@ void whomp_act_6(void) { } } -void whomp_act_8(void) { +void whomp_die(void) { if (o->oBehParams2ndByte != 0) { - if (cur_obj_update_dialog_with_cutscene(2, 2, CUTSCENE_DIALOG, DIALOG_115)) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_TEXT_DEFAULT, CUTSCENE_DIALOG, DIALOG_115)) { obj_set_angle(o, 0, 0, 0); cur_obj_hide(); cur_obj_become_intangible(); spawn_mist_particles_variable(0, 0, 200.0f); - spawn_triangle_break_particles(20, 138, 3.0f, 4); + spawn_triangle_break_particles(20, MODEL_DIRT_ANIMATION, 3.0f, 4); cur_obj_shake_screen(SHAKE_POS_SMALL); o->oPosY += 100.0f; spawn_default_star(180.0f, 3880.0f, 340.0f); @@ -223,21 +231,21 @@ void whomp_act_8(void) { } } else { spawn_mist_particles_variable(0, 0, 100.0f); - spawn_triangle_break_particles(20, 138, 3.0f, 4); + spawn_triangle_break_particles(20, MODEL_DIRT_ANIMATION, 3.0f, 4); cur_obj_shake_screen(SHAKE_POS_SMALL); create_sound_spawner(SOUND_OBJ_THWOMP); obj_mark_for_deletion(o); } } -void whomp_act_9(void) { +void king_whomp_stop_music(void) { if (o->oTimer == 60) stop_background_music(SEQUENCE_ARGS(4, SEQ_EVENT_BOSS)); } void (*sWhompActions[])(void) = { - whomp_act_0, whomp_act_1, whomp_act_2, whomp_act_3, whomp_act_4, - whomp_act_5, whomp_act_6, whomp_act_7, whomp_act_8, whomp_act_9 + whomp_init, whomp_patrol, king_whomp_chase, whomp_prepare_jump, whomp_jump, + whomp_land, whomp_on_ground_general, whomp_turn, whomp_die, king_whomp_stop_music }; // MM diff --git a/src/game/behaviors/wiggler.inc.c b/src/game/behaviors/wiggler.inc.c index 3d27856b..9bdc0e1e 100644 --- a/src/game/behaviors/wiggler.inc.c +++ b/src/game/behaviors/wiggler.inc.c @@ -228,7 +228,8 @@ static void wiggler_act_walk(void) { // If Mario is positioned below the wiggler, assume he entered through the // lower cave entrance, so don't display text. - if (gMarioObject->oPosY < o->oPosY || cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, DIALOG_150) != 0) { + if (gMarioObject->oPosY < o->oPosY || cur_obj_update_dialog_with_cutscene( + MARIO_DIALOG_LOOK_UP, DIALOG_FLAG_NONE, CUTSCENE_DIALOG, DIALOG_150)) { o->oWigglerTextStatus = WIGGLER_TEXT_STATUS_COMPLETED_DIALOG; } } else { @@ -304,7 +305,8 @@ static void wiggler_act_jumped_on(void) { // defeated) or go back to walking if (o->header.gfx.scale[1] >= 4.0f) { if (o->oTimer > 30) { - if (cur_obj_update_dialog_with_cutscene(2, 0, CUTSCENE_DIALOG, attackText[o->oHealth - 2]) != 0) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + DIALOG_FLAG_NONE, CUTSCENE_DIALOG, attackText[o->oHealth - 2])) { // Because we don't want the wiggler to disappear after being // defeated, we leave its health at 1 if (--o->oHealth == 1) { diff --git a/src/game/behaviors/yoshi.inc.c b/src/game/behaviors/yoshi.inc.c index c588d311..f2ba6de6 100644 --- a/src/game/behaviors/yoshi.inc.c +++ b/src/game/behaviors/yoshi.inc.c @@ -18,11 +18,11 @@ void bhv_yoshi_init(void) { } void yoshi_walk_loop(void) { - UNUSED s16 sp26; + UNUSED s16 collisionFlags; s16 sp24 = o->header.gfx.animInfo.animFrame; o->oForwardVel = 10.0f; - sp26 = object_step(); + collisionFlags = object_step(); o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, o->oYoshiTargetYaw, 0x500); if (is_point_close_to_object(o, o->oHomeX, 3174.0f, o->oHomeZ, 200)) o->oAction = YOSHI_ACT_IDLE; @@ -76,7 +76,7 @@ void yoshi_idle_loop(void) { void yoshi_talk_loop(void) { if ((s16) o->oMoveAngleYaw == (s16) o->oAngleToMario) { cur_obj_init_animation(0); - if (set_mario_npc_dialog(1) == 2) { + if (set_mario_npc_dialog(MARIO_DIALOG_LOOK_FRONT) == MARIO_DIALOG_STATUS_SPEAK) { o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; if (cutscene_object_with_dialog(CUTSCENE_DIALOG, o, DIALOG_161)) { o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; @@ -123,7 +123,7 @@ void yoshi_finish_jumping_and_despawn_loop(void) { obj_move_xyz_using_fvel_and_yaw(o); o->oVelY -= 2.0; if (o->oPosY < 2100.0f) { - set_mario_npc_dialog(0); + set_mario_npc_dialog(MARIO_DIALOG_STOP); gObjCutsceneDone = TRUE; sYoshiDead = TRUE; o->activeFlags = ACTIVE_FLAG_DEACTIVATED; diff --git a/src/game/camera.c b/src/game/camera.c index 13d3fe28..64604a7c 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -391,9 +391,13 @@ struct CameraStoredInfo sCameraStoreCutscene; // first iteration of data u32 unused8032CFC0 = 0; struct Object *gCutsceneFocus = NULL; -// other camera focuses? + u32 unused8032CFC8 = 0; u32 unused8032CFCC = 0; + +/** + * The information of a second focus camera used by some objects + */ struct Object *gSecondCameraFocus = NULL; /** @@ -432,7 +436,7 @@ u8 sFramesSinceCutsceneEnded = 0; * 2 = No * 3 = Dialog doesn't have a response */ -u8 sCutsceneDialogResponse = 0; +u8 sCutsceneDialogResponse = DIALOG_RESPONSE_NONE; struct PlayerCameraState *sMarioCamState = &gPlayerCameraState[0]; struct PlayerCameraState *sLuigiCamState = &gPlayerCameraState[1]; u32 unused8032D008 = 0; @@ -1184,6 +1188,22 @@ void mode_8_directions_camera(struct Camera *c) { s8DirModeYawOffset -= DEGREES(45); play_sound_cbutton_side(); } +#ifdef PARALLEL_LAKITU_CAM + // extra functionality + else if (gPlayer1Controller->buttonPressed & U_JPAD) { + s8DirModeYawOffset = 0; + s8DirModeYawOffset = gMarioState->faceAngle[1]-0x8000; + } + else if (gPlayer1Controller->buttonDown & L_JPAD) { + s8DirModeYawOffset -= DEGREES(2); + } + else if (gPlayer1Controller->buttonDown & R_JPAD) { + s8DirModeYawOffset += DEGREES(2); + } + else if (gPlayer1Controller->buttonPressed & D_JPAD) { + s8DirModeYawOffset = s8DirModeYawOffset&0xE000; + } +#endif lakitu_zoom(400.f, 0x900); c->nextYaw = update_8_directions_camera(c, c->focus, pos); @@ -1605,7 +1625,8 @@ s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) { switch (gCurrLevelArea) { case AREA_BOB: pos[1] += 125.f; - //! fall through, makes the BoB boss fight camera move up twice as high as it should + // fall through + //! makes the BoB boss fight camera move up twice as high as it should case AREA_WF: pos[1] += 125.f; } @@ -1704,9 +1725,12 @@ struct ParallelTrackingPoint sBBHLibraryParTrackPath[] = { }; s32 unused_update_mode_5_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) { +#ifdef AVOID_UB + return 0; +#endif } -static void stub_camera_1(UNUSED s32 unused) { +UNUSED static void stub_camera_1(UNUSED s32 unused) { } void mode_boss_fight_camera(struct Camera *c) { @@ -2029,6 +2053,9 @@ void mode_behind_mario_camera(struct Camera *c) { } s32 nop_update_water_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) { +#ifdef AVOID_UB + return 0; +#endif } /** @@ -2227,7 +2254,7 @@ s16 update_default_camera(struct Camera *c) { if ((closeToMario & 1) && avoidStatus != 0) { yawVel = 0; } - if (yawVel != 0 && get_dialog_id() == -1) { + if (yawVel != 0 && get_dialog_id() == DIALOG_NONE) { camera_approach_s16_symmetric_bool(&yaw, yawGoal, yawVel); } } @@ -3011,7 +3038,11 @@ void update_camera(struct Camera *c) { gCamera = c; update_camera_hud_status(c); - if (c->cutscene == 0) { + if (c->cutscene == 0 && + #ifdef PUPPYCAM + !gPuppyCam.enabled && + #endif + !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) { // Only process R_TRIG if 'fixed' is not selected in the menu if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { if (gPlayer1Controller->buttonPressed & R_TRIG) { @@ -3033,6 +3064,9 @@ void update_camera(struct Camera *c) { sStatusFlags |= CAM_FLAG_FRAME_AFTER_CAM_INIT; } + #ifdef PUPPYCAM + if (!gPuppyCam.enabled || c->cutscene != 0 || gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) { + #endif // Store previous geometry information sMarioGeometry.prevFloorHeight = sMarioGeometry.currFloorHeight; sMarioGeometry.prevCeilHeight = sMarioGeometry.currCeilHeight; @@ -3155,10 +3189,16 @@ void update_camera(struct Camera *c) { } } } + #ifdef PUPPYCAM + } + #endif // Start any Mario-related cutscenes start_cutscene(c, get_cutscene_from_mario_status(c)); stub_camera_2(c); gCheckingSurfaceCollisionsForCamera = FALSE; + #ifdef PUPPYCAM + if (!gPuppyCam.enabled || c->cutscene != 0 || gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) { + #endif if (gCurrLevelNum != LEVEL_CASTLE) { // If fixed camera is selected as the alternate mode, then fix the camera as long as the right // trigger is held @@ -3196,7 +3236,43 @@ void update_camera(struct Camera *c) { } update_lakitu(c); + #ifdef PUPPYCAM + } + //Just a cute little bit that syncs puppycamera up to vanilla when playing a vanilla cutscene :3 + if (c->cutscene != 0) + { + gPuppyCam.yawTarget = gCamera->yaw; + gPuppyCam.yaw = gCamera->yaw; + if (gMarioState->action == ACT_ENTERING_STAR_DOOR) + { //god this is stupid and the fact I have to continue doing this is testament to the idiocy of the star door cutscene >:( + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000; + gPuppyCam.yaw = gMarioState->faceAngle[1]+0x8000; + } + } + if (c->cutscene == 0 && gPuppyCam.enabled && !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) + { + // Clear the recent cutscene after 8 frames + if (gRecentCutscene != 0 && sFramesSinceCutsceneEnded < 8) { + sFramesSinceCutsceneEnded++; + if (sFramesSinceCutsceneEnded >= 8) { + gRecentCutscene = 0; + sFramesSinceCutsceneEnded = 0; + } + } + puppycam_loop(); + // Apply camera shakes + shake_camera_pitch(gLakituState.pos, gLakituState.focus); + shake_camera_yaw(gLakituState.pos, gLakituState.focus); + shake_camera_roll(&gLakituState.roll); + shake_camera_handheld(gLakituState.pos, gLakituState.focus); + if (sMarioCamState->action == ACT_DIVE && gLakituState.lastFrameAction != ACT_DIVE) { + set_camera_shake_from_hit(SHAKE_HIT_FROM_BELOW); + } + gLakituState.roll += sHandheldShakeRoll; + gLakituState.roll += gLakituState.keyDanceRoll; + } + #endif gLakituState.lastFrameAction = sMarioCamState->action; } @@ -3329,12 +3405,18 @@ void init_camera(struct Camera *c) { // Set the camera's starting position or start a cutscene for certain levels switch (gCurrLevelNum) { + // Calls the initial cutscene when you enter Bowser battle levels + // Note: This replaced an "old" way to call these cutscenes using + // a camEvent value: CAM_EVENT_BOWSER_INIT case LEVEL_BOWSER_1: #ifndef VERSION_JP + // Since Bowser 1 has a demo entry, check for it + // If it is, then set CamAct to the end to directly activate Bowser + // If it isn't, then start cutscene if (gCurrDemoInput == NULL) { start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); } else if (gSecondCameraFocus != NULL) { - gSecondCameraFocus->oBowserUnk88 = 2; + gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_END; } #else start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA); @@ -3427,6 +3509,12 @@ void init_camera(struct Camera *c) { gLakituState.nextYaw = gLakituState.yaw; c->yaw = gLakituState.yaw; c->nextYaw = gLakituState.yaw; + #ifdef CAMERA_FIX + set_camera_mode(c, CAMERA_MODE_8_DIRECTIONS, 0); + #endif + #ifdef PUPPYCAM + puppycam_init(); + #endif } /** @@ -4850,6 +4938,9 @@ void play_sound_if_cam_switched_to_lakitu_or_mario(void) { */ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { s16 dummy; +#ifdef AVOID_UB + dummy = 0; +#endif if ((gCameraMovementFlags & CAM_MOVE_ENTERED_ROTATE_SURFACE) || !(gCameraMovementFlags & CAM_MOVE_ROTATE)) { @@ -5092,7 +5183,7 @@ s32 determine_dance_cutscene(UNUSED struct Camera *c) { * @return `pullResult` or `pushResult` depending on Mario's door action */ u8 open_door_cutscene(u8 pullResult, u8 pushResult) { - s16 result; + s16 result = 0; if (sMarioCamState->action == ACT_PULLING_DOOR) { result = pullResult; @@ -5317,7 +5408,7 @@ void set_focus_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack * @param forwBack offset to Mario's front/back, relative to his faceAngle * @param yawOff offset to Mario's faceAngle, changes the direction of `leftRight` and `forwBack` */ -static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { +UNUSED static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { u16 yaw = sMarioCamState->faceAngle[1] + yawOff; c->pos[0] = sMarioCamState->pos[0] + forwBack * sins(yaw) + leftRight * coss(yaw); @@ -5366,7 +5457,7 @@ void determine_pushing_or_pulling_door(s16 *rotation) { if (sMarioCamState->action == ACT_PULLING_DOOR) { *rotation = 0; } else { - *rotation = DEGREES(180); + *rotation = DEGREES(-180); } } @@ -6865,31 +6956,31 @@ void start_object_cutscene(u8 cutscene, struct Object *o) { */ u8 start_object_cutscene_without_focus(u8 cutscene) { sObjectCutscene = cutscene; - sCutsceneDialogResponse = 0; + sCutsceneDialogResponse = DIALOG_RESPONSE_NONE; return 0; } -s32 unused_dialog_cutscene_response(u8 cutscene) { +s16 unused_dialog_cutscene_response(u8 cutscene) { // if not in a cutscene, start this one if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) { sObjectCutscene = cutscene; } // if playing this cutscene and Mario responded, return the response - if ((gCamera->cutscene == cutscene) && (sCutsceneDialogResponse != 0)) { - return (s16) sCutsceneDialogResponse; + if ((gCamera->cutscene == cutscene) && (sCutsceneDialogResponse)) { + return sCutsceneDialogResponse; } else { return 0; } } s16 cutscene_object_with_dialog(u8 cutscene, struct Object *o, s16 dialogID) { - s16 response = 0; + s16 response = DIALOG_RESPONSE_NONE; if ((gCamera->cutscene == 0) && (sObjectCutscene == 0)) { if (gRecentCutscene != cutscene) { start_object_cutscene(cutscene, o); - if (dialogID != -1) { + if (dialogID != DIALOG_NONE) { sCutsceneDialogID = dialogID; } else { sCutsceneDialogID = DIALOG_001; @@ -6904,7 +6995,7 @@ s16 cutscene_object_with_dialog(u8 cutscene, struct Object *o, s16 dialogID) { } s16 cutscene_object_without_dialog(u8 cutscene, struct Object *o) { - s16 response = cutscene_object_with_dialog(cutscene, o, -1); + s16 response = cutscene_object_with_dialog(cutscene, o, DIALOG_NONE); return response; } @@ -6989,7 +7080,7 @@ void copy_spline_segment(struct CutsceneSplinePoint dst[], struct CutsceneSpline s16 cutscene_common_set_dialog_state(s32 state) { s16 timer = gCutsceneTimer; // If the dialog ended, return CUTSCENE_LOOP, which would end the cutscene shot - if (set_mario_npc_dialog(state) == 2) { + if (set_mario_npc_dialog(state) == MARIO_DIALOG_STATUS_SPEAK) { timer = CUTSCENE_LOOP; } return timer; @@ -6997,19 +7088,19 @@ s16 cutscene_common_set_dialog_state(s32 state) { /// Unused SSL cutscene? static UNUSED void unused_cutscene_mario_dialog_looking_down(UNUSED struct Camera *c) { - gCutsceneTimer = cutscene_common_set_dialog_state(3); + gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_DOWN); } /** * Cause Mario to enter the normal dialog state. */ static BAD_RETURN(s32) cutscene_mario_dialog(UNUSED struct Camera *c) { - gCutsceneTimer = cutscene_common_set_dialog_state(1); + gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_FRONT); } /// Unused SSL cutscene? static UNUSED void unused_cutscene_mario_dialog_looking_up(UNUSED struct Camera *c) { - gCutsceneTimer = cutscene_common_set_dialog_state(2); + gCutsceneTimer = cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_UP); } /** @@ -7198,7 +7289,7 @@ void cutscene_unsoften_music(UNUSED struct Camera *c) { seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60); } -static void stub_camera_5(UNUSED struct Camera *c) { +UNUSED static void stub_camera_5(UNUSED struct Camera *c) { } BAD_RETURN(s32) cutscene_unused_start(UNUSED struct Camera *c) { @@ -7684,7 +7775,7 @@ BAD_RETURN(s32) cutscene_dance_rotate_move_towards_mario(struct Camera *c) { /** * Speculated to be dance-related due to its proximity to the other dance functions */ -static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) { +UNUSED static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) { } /** @@ -8035,10 +8126,10 @@ BAD_RETURN(s32) cutscene_bowser_area_shake_fov(UNUSED struct Camera *c) { } /** - * Set oBowserUnk88 to 1, which causes bowser to start walking. + * Set oBowserCamAct to 1, which causes bowser to start walking. */ BAD_RETURN(s32) cutscene_bowser_area_start_bowser_walking(UNUSED struct Camera *c) { - gSecondCameraFocus->oBowserUnk88 = 1; + gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_WALK; } /** @@ -8095,11 +8186,11 @@ BAD_RETURN(s32) cutscene_bowser_arena_pan_left(UNUSED struct Camera *c) { * Duplicate of cutscene_mario_dialog(). */ BAD_RETURN(s32) cutscene_bowser_arena_mario_dialog(UNUSED struct Camera *c) { - cutscene_common_set_dialog_state(1); + cutscene_common_set_dialog_state(MARIO_DIALOG_LOOK_FRONT); } void cutscene_stop_dialog(UNUSED struct Camera *c) { - cutscene_common_set_dialog_state(0); + cutscene_common_set_dialog_state(MARIO_DIALOG_STOP); } /** @@ -8140,7 +8231,7 @@ BAD_RETURN(s32) bowser_fight_intro_dialog(UNUSED struct Camera *c) { case LEVEL_BOWSER_2: dialog = DIALOG_092; break; - default: + default: // LEVEL_BOWSER_3 dialog = DIALOG_093; } @@ -8153,7 +8244,7 @@ BAD_RETURN(s32) bowser_fight_intro_dialog(UNUSED struct Camera *c) { BAD_RETURN(s32) cutscene_bowser_arena_dialog(struct Camera *c) { cutscene_event(bowser_fight_intro_dialog, c, 0, 0); - if (get_dialog_id() == -1) { + if (get_dialog_id() == DIALOG_NONE) { gCutsceneTimer = CUTSCENE_LOOP; } } @@ -8167,7 +8258,7 @@ BAD_RETURN(s32) cutscene_bowser_arena_end(struct Camera *c) { transition_next_state(c, 20); sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; sModeOffsetYaw = sMarioCamState->faceAngle[1] + DEGREES(90); - gSecondCameraFocus->oBowserUnk88 = 2; + gSecondCameraFocus->oBowserCamAct = BOWSER_CAM_ACT_END; } /** @@ -8597,7 +8688,7 @@ BAD_RETURN(s32) cutscene_death_stomach_goto_mario(struct Camera *c) { /** * Ah, yes */ -static void unused_water_death_move_to_side_of_mario(struct Camera *c) { +UNUSED static void unused_water_death_move_to_side_of_mario(struct Camera *c) { water_death_move_to_mario_side(c); } @@ -8871,7 +8962,7 @@ BAD_RETURN(s32) cutscene_enter_pyramid_top(struct Camera *c) { } } -static void unused_cutscene_goto_cvar(struct Camera *c) { +UNUSED static void unused_cutscene_goto_cvar(struct Camera *c) { f32 dist; dist = calc_abs_dist(sCutsceneVars[3].point, sMarioCamState->pos); @@ -8969,7 +9060,7 @@ BAD_RETURN(s32) cutscene_dialog_create_dialog_box(struct Camera *c) { } //! Unused. This may have been used before sCutsceneDialogResponse was implemented. - sCutsceneVars[8].angle[0] = 3; + sCutsceneVars[8].angle[0] = DIALOG_RESPONSE_NOT_DEFINED; } /** @@ -8981,13 +9072,13 @@ BAD_RETURN(s32) cutscene_dialog(struct Camera *c) { cutscene_event(cutscene_dialog_create_dialog_box, c, 10, 10); sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; - if (gDialogResponse != 0) { + if (gDialogResponse != DIALOG_RESPONSE_NONE) { sCutsceneDialogResponse = gDialogResponse; } - if ((get_dialog_id() == -1) && (sCutsceneVars[8].angle[0] != 0)) { + if ((get_dialog_id() == DIALOG_NONE) && (sCutsceneVars[8].angle[0] != 0)) { if (c->cutscene != CUTSCENE_RACE_DIALOG) { - sCutsceneDialogResponse = 3; + sCutsceneDialogResponse = DIALOG_RESPONSE_NOT_DEFINED; } gCutsceneTimer = CUTSCENE_LOOP; @@ -9032,7 +9123,7 @@ BAD_RETURN(s32) cutscene_read_message_start(struct Camera *c) { sCutsceneVars[0].angle[0] = 0; } -static void unused_cam_to_mario(struct Camera *c) { +UNUSED static void unused_cam_to_mario(struct Camera *c) { Vec3s dir; vec3s_set(dir, 0, sMarioCamState->faceAngle[1], 0); @@ -9052,7 +9143,7 @@ BAD_RETURN(s32) cutscene_read_message(struct Camera *c) { switch (sCutsceneVars[0].angle[0]) { // Do nothing until message is gone. case 0: - if (get_dialog_id() != -1) { + if (get_dialog_id() != DIALOG_NONE) { sCutsceneVars[0].angle[0] += 1; set_time_stop_flags(TIME_STOP_ENABLED | TIME_STOP_DIALOG); } @@ -9064,7 +9155,7 @@ BAD_RETURN(s32) cutscene_read_message(struct Camera *c) { // This could cause softlocks. If a message starts one frame after another one closes, the // cutscene will never end. - if (get_dialog_id() == -1) { + if (get_dialog_id() == DIALOG_NONE) { gCutsceneTimer = CUTSCENE_LOOP; retrieve_info_star(c); transition_next_state(c, 15); @@ -9397,11 +9488,11 @@ BAD_RETURN(s32) cutscene_cap_switch_press(struct Camera *c) { cutscene_event(cutscene_cap_switch_press_create_dialog, c, 10, 10); vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); - if (gDialogResponse != 0) { + if (gDialogResponse != DIALOG_RESPONSE_NONE) { sCutsceneVars[4].angle[0] = gDialogResponse; } - if ((get_dialog_id() == -1) && (sCutsceneVars[4].angle[0] != 0)) { + if ((get_dialog_id() == DIALOG_NONE) && (sCutsceneVars[4].angle[0] != 0)) { sCutsceneDialogResponse = sCutsceneVars[4].angle[0]; if (sCutsceneVars[4].angle[0] == 1) { cap_switch_save(gCutsceneFocus->oBehParams2ndByte); @@ -9495,8 +9586,8 @@ s32 intro_peach_move_camera_start_to_pipe(struct Camera *c, struct CutsceneSplin // The two splines used by this function are reflected in the horizontal plane for some reason, // so they are rotated every frame. Why do this, Nintendo? - rotate_in_xz(c->focus, c->focus, DEGREES(180)); - rotate_in_xz(c->pos, c->pos, DEGREES(180)); + rotate_in_xz(c->focus, c->focus, DEGREES(-180)); + rotate_in_xz(c->pos, c->pos, DEGREES(-180)); vec3f_set(offset, -1328.f, 260.f, 4664.f); vec3f_add(c->focus, offset); @@ -9534,7 +9625,7 @@ BAD_RETURN(s32) cutscene_intro_peach_start_to_pipe_spline(struct Camera *c) { * Loop the cutscene until Mario exits the dialog. */ BAD_RETURN(s32) cutscene_intro_peach_dialog(struct Camera *c) { - if (get_dialog_id() == -1) { + if (get_dialog_id() == DIALOG_NONE) { vec3f_copy(gLakituState.goalPos, c->pos); vec3f_copy(gLakituState.goalFocus, c->focus); sStatusFlags |= (CAM_FLAG_SMOOTH_MOVEMENT | CAM_FLAG_UNUSED_CUTSCENE_ACTIVE); @@ -9656,7 +9747,7 @@ BAD_RETURN(s32) cutscene_intro_peach_letter(struct Camera *c) { cutscene_event(play_sound_peach_reading_letter, c, 83, 83); #endif - if ((gCutsceneTimer > 120) && (get_dialog_id() == -1)) { + if ((gCutsceneTimer > 120) && (get_dialog_id() == DIALOG_NONE)) { // Start the next scene gCutsceneTimer = CUTSCENE_LOOP; } diff --git a/src/game/camera.h b/src/game/camera.h index f56ed027..aac94161 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -7,6 +7,7 @@ #include "area.h" #include "engine/geo_layout.h" #include "engine/graph_node.h" +#include "puppycam2.h" #include "level_table.h" @@ -16,7 +17,6 @@ * @see camera.c */ -#define ABS(x) ((x) > 0.f ? (x) : -(x)) #define ABS2(x) ((x) >= 0.f ? (x) : -(x)) /** diff --git a/src/game/debug.c b/src/game/debug.c index e735035d..060002bb 100644 --- a/src/game/debug.c +++ b/src/game/debug.c @@ -337,7 +337,7 @@ void reset_debug_objectinfo(void) { * C Right) and then toggles the debug flags from FF to 2; 2 is unused, * despite so this has no effect, being called. (unused) */ -static void check_debug_button_seq(void) { +UNUSED static void check_debug_button_seq(void) { s16 *buttonArr; s16 cButtonMask; @@ -367,7 +367,7 @@ static void check_debug_button_seq(void) { * Poll the debug info flags and controller for appropriate presses that * control sDebugPage's range. (unused) */ -static void try_change_debug_page(void) { +UNUSED static void try_change_debug_page(void) { if (gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) { if ((gPlayer1Controller->buttonPressed & L_JPAD) && (gPlayer1Controller->buttonDown & (L_TRIG | R_TRIG))) { @@ -392,8 +392,8 @@ static void try_change_debug_page(void) { * sDebugSysCursor. This is used to adjust enemy and effect behaviors * on the fly. (unused) */ -#ifndef VERSION_SH -static +#ifdef VERSION_EU +UNUSED static #endif void try_modify_debug_controls(void) { s32 sp4; @@ -525,9 +525,6 @@ void try_do_mario_debug_object_spawn(void) { } // TODO: figure out what this is -#ifndef VERSION_SH -static -#endif void debug_print_obj_move_flags(void) { #ifndef VERSION_EU // TODO: Is there a better way to diff this? static EU doesn't seem to work. if (gCurrentObject->oMoveFlags & OBJ_MOVE_LANDED) { diff --git a/src/game/debug_box.c b/src/game/debug_box.c new file mode 100644 index 00000000..79ad8593 --- /dev/null +++ b/src/game/debug_box.c @@ -0,0 +1,573 @@ +#include + +#ifdef VISUAL_DEBUG + +/** + * @file debug_box.c + * Draws 3D boxes for debugging purposes + * Originally written by Synray, modified by Fazana. + * + * How to use: + * + * Just call debug_box() whenever you want to draw one! + * + * debug_box by default takes two arguments: a center and bounds vec3f. + * This will draw a box starting from the point (center - bounds) to (center + bounds). + * + * Use debug_box_rot to draw a box rotated in the xz-plane. + * + * If you want to draw a box by specifying min and max points, use debug_box_pos() instead. + */ + +#include "sm64.h" +#include "game/game_init.h" +#include "game/geo_misc.h" +#include "engine/math_util.h" +#include "area.h" +#include "level_update.h" +#include "print.h" +#include "engine/surface_collision.h" +#include "engine/surface_load.h" +#include "object_list_processor.h" + +#include "debug_box.h" + +u8 hitboxView = 0; +u8 surfaceView = 0; + +/** + * Internal struct containing box info + */ +struct DebugBox { + u32 color; + Vec3s center; + Vec3s bounds; + s16 yaw; + u8 type; +}; + +struct DebugVert +{ + Vec3s pos; + Vec3f normal; +}; + +struct DebugBox sBoxes[MAX_DEBUG_BOXES]; +s16 sNumBoxes = 0; + +extern Mat4 gMatStack[32]; //XXX: Hack + +/** + * The debug boxes' default transparency + */ +#define DBG_BOX_ALPHA 0x7F +/** + * The debug boxes' default color. sCurBoxColor is reset to this every frame. + */ +#define DBG_BOX_DEF_COLOR 0xFF0000 + +/** + * The color that new boxes will be drawn with. + */ +u32 sCurBoxColor = DBG_BOX_ALPHA << 24 | DBG_BOX_DEF_COLOR; + +/** + * The allocated size of a rotated box's dl + */ +#define DBG_BOX_DLSIZE ((s32)(6 * sizeof(Gfx) + 8 * sizeof(Vtx))) + +/** + * Sets up the RCP for drawing the boxes + */ +static const Gfx dl_debug_box_begin[] = { + gsDPPipeSync(), + gsDPSetRenderMode(G_RM_ZB_XLU_SURF, G_RM_NOOP2), + gsSPClearGeometryMode(G_LIGHTING | G_CULL_BACK), + gsSPSetGeometryMode(G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH), + gsSPTexture(0, 0, 0, 0, G_OFF), + gsDPSetCombineMode(G_CC_FADE, G_CC_FADE), + gsSPEndDisplayList(), +}; + +static const Gfx dl_debug_box_begin_water[] = { + gsDPPipeSync(), + gsDPSetRenderMode(G_RM_ZB_XLU_SURF, G_RM_NOOP2), + gsSPClearGeometryMode(G_LIGHTING), + gsSPSetGeometryMode(G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH), + gsSPTexture(0, 0, 0, 0, G_OFF), + gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), + gsSPEndDisplayList(), +}; + +static const Gfx dl_debug_box_end[] = { + gsDPPipeSync(), + gsDPSetRenderMode(G_RM_OPA_SURF, G_RM_OPA_SURF2), + gsSPClearGeometryMode(G_LIGHTING | G_CULL_BACK), + gsSPTexture(0, 0, 0, 0, G_OFF), + gsDPSetCombineMode(G_CC_FADE, G_CC_FADE), + gsDPSetEnvColor(0xFF, 0xFF, 0xFF, 0xFF), + gsSPEndDisplayList(), +}; + +static const Gfx dl_visual_surface[] = { + gsDPPipeSync(), + gsDPSetRenderMode(G_RM_ZB_XLU_DECAL, G_RM_NOOP2), + gsSPClearGeometryMode(G_LIGHTING), + gsSPSetGeometryMode(G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH), + gsSPTexture(0, 0, 0, 0, G_OFF), + gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), + gsSPEndDisplayList(), +}; + +u8 viewCycle = 0; + +//Puppyprint will call this from elsewhere. +void debug_box_input(void) +{ + if (gPlayer1Controller->buttonPressed & R_JPAD) + { + viewCycle++; + if (viewCycle > 3) + viewCycle = 0; + + hitboxView = 0; + surfaceView = 0; + + if (viewCycle == 1 || viewCycle == 3) + hitboxView = 1; + if (viewCycle == 2 || viewCycle == 3) + surfaceView = 1; + } +} + +s16 gVisualSurfaceCount; +s32 gVisualOffset; +extern s32 gSurfaceNodesAllocated; +extern s32 gSurfacesAllocated; + +void iterate_surfaces_visual(s32 x, s32 z, Vtx *verts) +{ + struct SurfaceNode *node; + struct Surface *surf; + s32 cellX, cellZ; + s32 i = 0; + s32 col[3] = {0xFF, 0x00, 0x00}; + + if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) { + return; + } + if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) { + return; + } + + cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + + for (i = 0; i < 8; i++) + { + switch (i) + { + case 0: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next; col[0] = 0x00; col[1] = 0xFF; col[2] = 0x00; break; + case 1: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next; col[0] = 0x00; col[1] = 0xFF; col[2] = 0x00; break; + case 2: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; col[0] = 0x00; col[1] = 0x00; col[2] = 0xFF; break; + case 3: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; col[0] = 0x00; col[1] = 0x00; col[2] = 0xFF; break; + case 4: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next; col[0] = 0xFF; col[1] = 0x00; col[2] = 0x00; break; + case 5: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next; col[0] = 0xFF; col[1] = 0x00; col[2] = 0x00; break; + case 6: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next; col[0] = 0xFF; col[1] = 0xFF; col[2] = 0x00; break; + case 7: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next; col[0] = 0xFF; col[1] = 0xFF; col[2] = 0x00; break; + } + + while (node != NULL) + { + surf = node->surface; + node = node->next; + + make_vertex(verts, gVisualSurfaceCount, surf->vertex1[0], surf->vertex1[1], surf->vertex1[2], 0, 0, col[0], col[1], col[2], 0x80); + make_vertex(verts, gVisualSurfaceCount+1, surf->vertex2[0], surf->vertex2[1], surf->vertex2[2], 0, 0, col[0], col[1], col[2], 0x80); + make_vertex(verts, gVisualSurfaceCount+2, surf->vertex3[0], surf->vertex3[1], surf->vertex3[2], 0, 0, col[0], col[1], col[2], 0x80); + + gVisualSurfaceCount+=3; + } + } +} + +void iterate_surfaces_envbox(Vtx *verts) +{ + TerrainData *p = gEnvironmentRegions; + s32 numRegions; + s32 col[3] = {0xFF, 0xFF, 0x00}; + s32 i = 0; + + if (p != NULL) + { + numRegions = *p++; + for (i = 0; i < numRegions; i++) + { + make_vertex(verts, gVisualSurfaceCount, p[1], p[5], p[2], 0, 0, col[0], col[1], col[2], 0x80); + make_vertex(verts, gVisualSurfaceCount+1, p[1], p[5], p[4], 0, 0, col[0], col[1], col[2], 0x80); + make_vertex(verts, gVisualSurfaceCount+2, p[3], p[5], p[2], 0, 0, col[0], col[1], col[2], 0x80); + + make_vertex(verts, gVisualSurfaceCount+3, p[3], p[5], p[2], 0, 0, col[0], col[1], col[2], 0x80); + make_vertex(verts, gVisualSurfaceCount+4, p[1], p[5], p[4], 0, 0, col[0], col[1], col[2], 0x80); + make_vertex(verts, gVisualSurfaceCount+5, p[3], p[5], p[4], 0, 0, col[0], col[1], col[2], 0x80); + + gVisualSurfaceCount+=6; + gVisualOffset+=6; + p+= 6; + } + } +} + +#if defined(F3DEX_GBI_2) || defined(F3DEX_GBI) +#define VERTCOUNT 30 +#else +#define VERTCOUNT 12 +#endif // F3DEX_GBI_2 + +void visual_surface_display(Vtx *verts, s32 iteration) +{ + s32 vts; + s32 vtl = 0; + s32 count = VERTCOUNT; + s32 ntx = 0; + if (!iteration) + { + vts = gVisualSurfaceCount; + } + else + { + vts = gVisualOffset; + } + + while (vts > 0) + { + if (count == VERTCOUNT) + { + ntx = MIN(VERTCOUNT, vts); + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts + ((gVisualSurfaceCount)-vts)), ntx, 0); + count = 0; + vtl = VERTCOUNT; + } + + if (vtl >= 6) + { + gSP2Triangles(gDisplayListHead++, count + 0, count + 1, count + 2, 0, count + 3, count + 4, count + 5, 0); + vts -= 6; + vtl -= 6; + count+= 6; + } + else + if (vtl >= 3) + { + gSP1Triangle(gDisplayListHead++, count + 0, count + 1, count + 2, 0); + vts -= 3; + vtl -= 6; + count+= 3; + } + } +} + +s32 iterate_surface_count(s32 x, s32 z) +{ + struct SurfaceNode *node; + s32 cellX, cellZ; + s32 i = 0; + s32 j = 0; + TerrainData *p = gEnvironmentRegions; + s32 numRegions; + + if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) { + return 0; + } + if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) { + return 0; + } + + cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + + for (i = 0; i < 8; i++) + { + switch (i) + { + case 0: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next; break; + case 1: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next; break; + case 2: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; break; + case 3: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; break; + case 4: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next; break; + case 5: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next; break; + case 6: node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next; break; + case 7: node = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next; break; + } + + while (node != NULL) + { + node = node->next; + j++; + } + } + if (p != NULL) + { + numRegions = *p++; + j += numRegions*6; + } + + return j; +} + +void visual_surface_loop(void) +{ + Vtx *verts; + Mtx *mtx; + + if (!gSurfaceNodesAllocated || !gSurfacesAllocated || !gMarioState->marioObj) + return; + + mtx = alloc_display_list(sizeof(Mtx)); + verts = alloc_display_list((iterate_surface_count(gMarioState->pos[0], gMarioState->pos[2])*3) * sizeof(Vtx)); + + gVisualSurfaceCount = 0; + gVisualOffset = 0; + + if (mtx == NULL || verts == NULL) + return; + + mtxf_to_mtx(mtx, gMatStack[1]); + + gSPDisplayList(gDisplayListHead++, dl_visual_surface); + + gSPMatrix(gDisplayListHead++, mtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); + + iterate_surfaces_visual(gMarioState->pos[0], gMarioState->pos[2], verts); + + visual_surface_display(verts, 0); + + iterate_surfaces_envbox(verts); + + gSPDisplayList(gDisplayListHead++, dl_debug_box_begin_water); + + visual_surface_display(verts, 1); + + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); + gSPDisplayList(gDisplayListHead++, dl_debug_box_end); +} + +/** + * Adds a box to the list to be rendered this frame. + * + * If there are already MAX_DEBUG_BOXES boxes, does nothing. + */ +static void append_debug_box(Vec3f center, Vec3f bounds, s16 yaw, s32 type) +{ + if (hitboxView) + { + if (sNumBoxes >= MAX_DEBUG_BOXES) { + return; + } + + vec3f_to_vec3s(sBoxes[sNumBoxes].center, center); + vec3f_to_vec3s(sBoxes[sNumBoxes].bounds, bounds); + + sBoxes[sNumBoxes].yaw = yaw; + sBoxes[sNumBoxes].color = sCurBoxColor; + sBoxes[sNumBoxes].type = type; + + ++sNumBoxes; + } + +} + +/** + * Draw new boxes with the given color. + * Color format is 32-bit ARGB. + * If the alpha component is zero, DBG_BOX_ALPHA (0x7f) will be used instead. + * Ex: 0xFF0000 becomes 0x7FFF0000 + */ +void debug_box_color(u32 color) +{ + if ((color >> 24) == 0) color |= (DBG_BOX_ALPHA << 24); + sCurBoxColor = color; +} + +/** + * Draws a debug box from (center - bounds) to (center + bounds) + * To draw a rotated box, use debug_box_rot() + * + * @see debug_box_rot() + */ +void debug_box(Vec3f center, Vec3f bounds, s32 type) +{ + append_debug_box(center, bounds, 0, type); +} + +/** + * Draws a debug box from (center - bounds) to (center + bounds), rotating it by `yaw` + */ +void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw, s32 type) +{ + append_debug_box(center, bounds, yaw, type); +} + +/** + * Draws a debug box from pMin to pMax + * To draw a rotated box this way, use debug_box_pos_rot() + * + * @see debug_box_pos_rot() + */ +void debug_box_pos(Vec3f pMin, Vec3f pMax, s32 type) +{ + debug_box_pos_rot(pMin, pMax, 0, type); +} + +/** + * Draws a debug box from pMin to pMax, rotating it in the xz-plane by `yaw` + */ +void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw, s32 type) +{ + Vec3f center, bounds; + + bounds[0] = (pMax[0] - pMin[0]) / 2.0f; + bounds[1] = (pMax[1] - pMin[1]) / 2.0f; + bounds[2] = (pMax[2] - pMin[2]) / 2.0f; + + center[0] = pMin[0] + bounds[0]; + center[1] = pMin[1] + bounds[1]; + center[2] = pMin[2] + bounds[2]; + + append_debug_box(center, bounds, yaw, type); +} + +#define DBG_BOX_VTX_BOX(i, x, y, z) make_vertex(debugBoxVtx, i, x, y, z, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF) +#define DBG_BOX_VTX_CYL(i, x, y, z) make_vertex(debugCylinderVtx, i, x, y, z, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF) +#define CYLINDER_VERTS 24 + +static void render_box(int index, Vtx *vbox, Vtx *vcylinder) +{ + Mtx *translate; + Mtx *rotate; + Mtx *scale; + Mtx *mtx; + struct DebugBox *box = &sBoxes[index]; + s32 color = box->color; + + // Translate to the origin, rotate, then translate back, effectively rotating the box about + // its center + mtx = alloc_display_list(sizeof(Mtx)); + translate = alloc_display_list(sizeof(Mtx)); + rotate = alloc_display_list(sizeof(Mtx)); + scale = alloc_display_list(sizeof(Mtx)); + + if (mtx == NULL || translate == NULL || rotate == NULL || scale == NULL) + return; + + mtxf_to_mtx(mtx, gMatStack[1]); + guTranslate(translate, box->center[0], box->center[1], box->center[2]); + guRotate(rotate, box->yaw / (float)0x10000 * 360.0f, 0, 1.0f, 0); + guScale(scale, (f32) box->bounds[0]*0.01f, (f32) box->bounds[1]*0.01f, (f32) box->bounds[2]*0.01f); + + gSPMatrix(gDisplayListHead++, mtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); + gSPMatrix(gDisplayListHead++, translate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + gSPMatrix(gDisplayListHead++, rotate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + gSPMatrix(gDisplayListHead++, scale, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + + gDPSetEnvColor(gDisplayListHead++, (color >> 16) & 0xFF, (color >> 8) & 0xFF, (color) & 0xFF, (color >> 24) & 0xFF); + + if (box->type == DEBUG_SHAPE_BOX) + { + + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vbox), 8, 0); + gSP2Triangles(gDisplayListHead++, 5, 4, 6, 0x0, 5, 6, 7, 0x0); // front + gSP2Triangles(gDisplayListHead++, 0, 1, 2, 0x0, 2, 1, 3, 0x0); // back + + gSP2Triangles(gDisplayListHead++, 4, 0, 2, 0x0, 2, 6, 4, 0x0); // left + gSP2Triangles(gDisplayListHead++, 1, 5, 3, 0x0, 3, 5, 7, 0x0); // right + + gSP2Triangles(gDisplayListHead++, 1, 0, 4, 0x0, 1, 4, 5, 0x0); // top + gSP2Triangles(gDisplayListHead++, 2, 3, 6, 0x0, 6, 3, 7, 0x0); // bottom + } + else + { + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vcylinder), 26, 0); + //Bottom + /*gSP2Triangles(gDisplayListHead++, 0, 1, 3, 0, 0, 3, 5, 0); + gSP2Triangles(gDisplayListHead++, 0, 5, 7, 0, 0, 7, 9, 0); + gSP2Triangles(gDisplayListHead++, 0, 9, 11, 0, 0, 11, 13, 0); + gSP2Triangles(gDisplayListHead++, 0, 13, 15, 0, 0, 15, 17, 0); + gSP2Triangles(gDisplayListHead++, 0, 17, 19, 0, 0, 19, 21, 0); + gSP2Triangles(gDisplayListHead++, 0, 21, 23, 0, 0, 23, 1, 0);*/ + + //Side + gSP2Triangles(gDisplayListHead++, 1, 2, 3, 0, 2, 3, 4, 0); + gSP2Triangles(gDisplayListHead++, 3, 4, 5, 0, 4, 5, 6, 0); + gSP2Triangles(gDisplayListHead++, 5, 6, 7, 0, 6, 7, 8, 0); + gSP2Triangles(gDisplayListHead++, 7, 8, 9, 0, 8, 9, 10, 0); + gSP2Triangles(gDisplayListHead++, 9, 10, 11, 0, 10, 11, 12, 0); + gSP2Triangles(gDisplayListHead++, 11, 12, 13, 0, 12, 13, 14, 0); + gSP2Triangles(gDisplayListHead++, 13, 14, 15, 0, 14, 15, 16, 0); + gSP2Triangles(gDisplayListHead++, 15, 16, 17, 0, 16, 17, 18, 0); + gSP2Triangles(gDisplayListHead++, 17, 18, 19, 0, 18, 19, 20, 0); + gSP2Triangles(gDisplayListHead++, 19, 20, 21, 0, 20, 21, 22, 0); + gSP2Triangles(gDisplayListHead++, 21, 22, 23, 0, 22, 23, 24, 0); + gSP2Triangles(gDisplayListHead++, 23, 24, 1, 0, 24, 1, 2, 0); + + //Top + gSP2Triangles(gDisplayListHead++, 25, 2, 4, 0, 25, 4, 6, 0); + gSP2Triangles(gDisplayListHead++, 25, 6, 8, 0, 25, 8, 10, 0); + gSP2Triangles(gDisplayListHead++, 25, 10, 12, 0, 25, 12, 14, 0); + gSP2Triangles(gDisplayListHead++, 25, 14, 16, 0, 25, 16, 18, 0); + gSP2Triangles(gDisplayListHead++, 25, 18, 20, 0, 25, 20, 22, 0); + gSP2Triangles(gDisplayListHead++, 25, 22, 24, 0, 25, 24, 2, 0); + } + + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); +} + +void render_debug_boxes(void) +{ + s32 i; + Vtx *debugBoxVtx; + Vtx *debugCylinderVtx; + + debug_box_color(DBG_BOX_DEF_COLOR); + + if (sNumBoxes == 0) + return; + + //Create the vertices for the box. + debugBoxVtx = alloc_display_list(8 * sizeof(Vtx)); + debugCylinderVtx = alloc_display_list(26 * sizeof(Vtx)); + + if (debugBoxVtx == NULL || debugCylinderVtx == NULL) + return; + + DBG_BOX_VTX_BOX(0, -100, 100, -100); + DBG_BOX_VTX_BOX(1, 100, 100, -100); + DBG_BOX_VTX_BOX(2, -100, -100, -100); + DBG_BOX_VTX_BOX(3, 100, -100, -100); + DBG_BOX_VTX_BOX(4, -100, 100, 100); + DBG_BOX_VTX_BOX(5, 100, 100, 100); + DBG_BOX_VTX_BOX(6, -100, -100, 100); + DBG_BOX_VTX_BOX(7, 100, -100, 100); + + DBG_BOX_VTX_CYL(0, 0, 0, 0); + for (i = 0; i < (CYLINDER_VERTS); i++) + { + DBG_BOX_VTX_CYL(1+i, + 0 + (100 * coss((0xFFFF/((CYLINDER_VERTS)/2))*(i / 2))), + 0 + (100 * (i % 2)), + 0 + (100 * sins((0xFFFF/((CYLINDER_VERTS)/2))*(i / 2)))); + } + DBG_BOX_VTX_CYL(CYLINDER_VERTS+1, 0, 100, 0); + + gSPDisplayList(gDisplayListHead++, dl_debug_box_begin); + + for (i = 0; i < sNumBoxes; ++i) { + render_box(i, debugBoxVtx, debugCylinderVtx); + } + + sNumBoxes = 0; + + gSPDisplayList(gDisplayListHead++, dl_debug_box_end); +} + +#endif diff --git a/src/game/debug_box.h b/src/game/debug_box.h new file mode 100644 index 00000000..8b7a28bc --- /dev/null +++ b/src/game/debug_box.h @@ -0,0 +1,38 @@ +#ifndef DEBUG_BOX_H +#define DEBUG_BOX_H + +#ifdef VISUAL_DEBUG + +/** + * @file debug_box.h + * Draws debug boxes, see debug_box.c for details + */ + +#include "types.h" + +/** + * The max amount of debug boxes before debug_box() just returns. + * You can set this to something higher, but you might run out of space in the gfx pool. + */ +#define MAX_DEBUG_BOXES 512 + +#define DEBUG_SHAPE_BOX 0x0 +#define DEBUG_SHAPE_CYLINDER 0x1 + +extern u8 hitboxView; +extern u8 surfaceView; +extern void debug_box_input(void); + +void debug_box_color(u32 color); +void debug_box(Vec3f center, Vec3f bounds, s32 type); +void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw, s32 type); + +void debug_box_pos(Vec3f pMin, Vec3f pMax, s32 type); +void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw, s32 type); + +void render_debug_boxes(void); +extern void visual_surface_loop(void); + +#endif + +#endif /* DEBUG_BOX_H */ diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c index 9bc0e6e9..b67b72fd 100644 --- a/src/game/envfx_bubbles.c +++ b/src/game/envfx_bubbles.c @@ -455,6 +455,8 @@ void envfx_set_bubble_texture(s32 mode, s16 index) { imageArr = segmented_to_virtual(&bubble_ptr_0B006848); frame = 0; break; + default: + return; } gDPSetTextureImage(sGfxCursor++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, *(imageArr + frame)); diff --git a/src/game/envfx_snow.c b/src/game/envfx_snow.c index 192219db..5686da78 100644 --- a/src/game/envfx_snow.c +++ b/src/game/envfx_snow.c @@ -1,6 +1,7 @@ #include #include "sm64.h" +#include "dialog_ids.h" #include "game_init.h" #include "memory.h" #include "ingame_menu.h" @@ -272,7 +273,7 @@ void envfx_update_snow_blizzard(s32 snowCylinderX, s32 snowCylinderY, s32 snowCy * find it. The radius of 3000 units is quite large for that though, covering * more than half of the mirror room. */ -static s32 is_in_mystery_snow_area(s32 x, UNUSED s32 y, s32 z) { +UNUSED static s32 is_in_mystery_snow_area(s32 x, UNUSED s32 y, s32 z) { if (sqr(x - 3380) + sqr(z + 520) < sqr(3000)) { return 1; } @@ -463,7 +464,7 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) Gfx *envfx_update_particles(s32 mode, Vec3s marioPos, Vec3s camTo, Vec3s camFrom) { Gfx *gfx; - if (get_dialog_id() != -1) { + if (get_dialog_id() != DIALOG_NONE) { return NULL; } diff --git a/src/game/farcall_helpers.h b/src/game/farcall_helpers.h new file mode 100644 index 00000000..d42daf15 --- /dev/null +++ b/src/game/farcall_helpers.h @@ -0,0 +1,84 @@ +#ifndef OBJ_BEHAVIORS_2_NONSTATIC_H +#define OBJ_BEHAVIORS_2_NONSTATIC_H + +#include "object_fields.h" +#include "object_constants.h" +#include "object_helpers.h" +#include "object_collision.h" +#include "obj_behaviors.h" +#include "object_list_processor.h" +#include "interaction.h" +#include "behavior_data.h" +#include "engine/behavior_script.h" +#include "engine/math_util.h" +#include "engine/surface_load.h" +#include "engine/surface_collision.h" +#include "sound_init.h" +#include "spawn_sound.h" +#include "farcall.h" +#include "audio/external.h" +#include "level_update.h" +#include "mario.h" +#include "save_file.h" +#include "game_init.h" +#include "obj_behaviors_2.h" +#include "level_headers.h" +#include "level_misc_macros.h" + +#define o gCurrentObject + +s32 obj_is_rendering_enabled(void); +s16 obj_get_pitch_from_vel(void); +s32 obj_update_race_proposition_dialog(s16 dialogID); +void obj_set_dist_from_home(f32 distFromHome); +s32 obj_is_near_to_and_facing_mario(f32 maxDist, s16 maxAngleDiff); +void obj_perform_position_op(s32 op); +void platform_on_track_update_pos_or_spawn_ball(s32 ballIndex, f32 x, f32 y, f32 z); +void cur_obj_spin_all_dimensions(f32 arg0, f32 arg1); +void obj_rotate_yaw_and_bounce_off_walls(s16 targetYaw, s16 turnAmount); +s16 obj_get_pitch_to_home(f32 latDistToHome); +void obj_compute_vel_from_move_pitch(f32 speed); +s32 clamp_s16(s16 *value, s16 minimum, s16 maximum); +s32 clamp_f32(f32 *value, f32 minimum, f32 maximum); +void cur_obj_init_anim_extend(s32 arg0); +s32 cur_obj_init_anim_and_check_if_end(s32 arg0); +s32 cur_obj_init_anim_check_frame(s32 arg0, s32 arg1); +s32 cur_obj_set_anim_if_at_end(s32 arg0); +s32 cur_obj_play_sound_at_anim_range(s8 arg0, s8 arg1, u32 sound); +s16 obj_turn_pitch_toward_mario(f32 targetOffsetY, s16 turnAmount); +s32 approach_f32_ptr(f32 *px, f32 target, f32 delta); +s32 obj_forward_vel_approach(f32 target, f32 delta); +s32 obj_y_vel_approach(f32 target, f32 delta); +s32 obj_move_pitch_approach(s16 target, s16 delta); +s32 obj_face_pitch_approach(s16 targetPitch, s16 deltaPitch); +s32 obj_face_yaw_approach(s16 targetYaw, s16 deltaYaw); +s32 obj_face_roll_approach(s16 targetRoll, s16 deltaRoll); +s32 obj_smooth_turn(s16 *angleVel, s32 *angle, s16 targetAngle, f32 targetSpeedProportion, + s16 accel, s16 minSpeed, s16 maxSpeed); +void obj_roll_to_match_yaw_turn(s16 targetYaw, s16 maxRoll, s16 rollSpeed); +s16 random_linear_offset(s16 base, s16 range); +s16 random_mod_offset(s16 base, s16 step, s16 mod); +s16 obj_random_fixed_turn(s16 delta); +s32 obj_grow_then_shrink(f32 *scaleVel, f32 shootFireScale, f32 endScale); +s32 oscillate_toward(s32 *value, f32 *vel, s32 target, f32 velCloseToZero, f32 accel, + f32 slowdown); +void obj_update_blinking(s32 *blinkTimer, s16 baseCycleLength, s16 cycleLengthRange, + s16 blinkLength); +s32 obj_resolve_object_collisions(s32 *targetYaw); +s32 obj_bounce_off_walls_edges_objects(s32 *targetYaw); +s32 obj_resolve_collisions_and_turn(s16 targetYaw, s16 turnSpeed); +void obj_die_if_health_non_positive(void); +void obj_unused_die(void); +void obj_set_knockback_action(s32 attackType); +void obj_set_squished_action(void); +s32 obj_die_if_above_lava_and_health_non_positive(void); +s32 obj_handle_attacks(struct ObjectHitbox *hitbox, s32 attackedMarioAction, + u8 *attackHandlers); +void obj_act_knockback(UNUSED f32 baseScale); +void obj_act_squished(f32 baseScale); +s32 obj_update_standard_actions(f32 scale); +s32 obj_check_attacks(struct ObjectHitbox *hitbox, s32 attackedMarioAction); +s32 obj_move_for_one_second(s32 endAction); +void treat_far_home_as_mario(f32 threshold); + +#endif diff --git a/src/game/game_init.c b/src/game/game_init.c index 241d3c83..450fe395 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -29,18 +29,30 @@ #ifdef SRAM #include "sram.h" #endif +#include "puppyprint.h" #include +#include "puppycam2.h" +#include "debug_box.h" +#include "vc_check.h" -// FIXME: I'm not sure all of these variables belong in this file, but I don't -// know of a good way to split them +// First 3 controller slots struct Controller gControllers[3]; + +// Gfx handlers struct SPTask *gGfxSPTask; Gfx *gDisplayListHead; u8 *gGfxPoolEnd; struct GfxPool *gGfxPool; + +// OS Controllers OSContStatus gControllerStatuses[4]; OSContPad gControllerPads[4]; u8 gControllerBits; +u8 gIsConsole = TRUE; // Needs to be initialized before audio_reset_session is called +u8 gBorderHeight; +#ifdef CUSTOM_DEBUG +u8 gCustomDebugMode; +#endif #ifdef EEP s8 gEepromProbe; #endif @@ -48,45 +60,59 @@ s8 gEepromProbe; s8 gSramProbe; #endif OSMesgQueue gGameVblankQueue; -OSMesgQueue D_80339CB8; -OSMesg D_80339CD0; -OSMesg D_80339CD4; +OSMesgQueue gGfxVblankQueue; +OSMesg gGameMesgBuf[1]; +OSMesg gGfxMesgBuf[1]; + +// Vblank Handler struct VblankHandler gGameVblankHandler; + +// Buffers uintptr_t gPhysicalFrameBuffers[3]; uintptr_t gPhysicalZBuffer; -void *D_80339CF0; -void *D_80339CF4; -struct MarioAnimation D_80339D10; -struct MarioAnimation gDemo; -UNUSED u8 filler80339D30[0x90]; -s32 unused8032C690 = 0; +// Mario Anims and Demo allocation +void *gMarioAnimsMemAlloc; +void *gDemoInputsMemAlloc; +struct DmaHandlerList gMarioAnimsBuf; +struct DmaHandlerList gDemoInputsBuf; + +// fillers +UNUSED static u8 sfillerGameInit[0x90]; +UNUSED static s32 sUnusedGameInitValue = 0; + +// General timer that runs as the game starts u32 gGlobalTimer = 0; -u8 gIsConsole; #ifdef WIDE -u8 gWidescreen; +s16 gWidescreen; #endif u8 *gAreaSkyboxStart[7]; u8 *gAreaSkyboxEnd[7]; -u16 sCurrFBNum = 0; -u16 frameBufferIndex = 0; +// Framebuffer rendering values (max 3) +u16 sRenderedFramebuffer = 0; +u16 sRenderingFrameBuffer = 0; + +// Goddard Vblank Function Caller void (*gGoddardVblankCallback)(void) = NULL; + +// Defined controller slots struct Controller *gPlayer1Controller = &gControllers[0]; struct Controller *gPlayer2Controller = &gControllers[1]; -// probably debug only, see note below -struct Controller *gPlayer3Controller = &gControllers[2]; -struct DemoInput *gCurrDemoInput = NULL; // demo input sequence +struct Controller *gPlayer3Controller = &gControllers[2]; // Probably debug only, see note below + +// Title Screen Demo Handler +struct DemoInput *gCurrDemoInput = NULL; u16 gDemoInputListID = 0; -struct DemoInput gRecordedDemoInput = { 0 }; // possibly removed in EU. TODO: Check +struct DemoInput gRecordedDemoInput = { 0 }; + +// Display +// ---------------------------------------------------------------------------------------------------- /** - * Initializes the Reality Display Processor (RDP). - * This function initializes settings such as texture filtering mode, - * scissoring, and render mode (although keep in mind that this render - * mode is not used in-game, where it is set in render_graph_node.c). + * Sets the initial RDP (Reality Display Processor) rendering settings. */ -void my_rdp_init(void) { +void init_rdp(void) { gDPPipeSync(gDisplayListHead++); gDPPipelineMode(gDisplayListHead++, G_PM_1PRIMITIVE); @@ -113,11 +139,9 @@ void my_rdp_init(void) { } /** - * Initializes the RSP's built-in geometry and lighting engines. - * Most of these (with the notable exception of gSPNumLights), are - * almost immediately overwritten. + * Sets the initial RSP (Reality Signal Processor) settings. */ -void my_rsp_init(void) { +void init_rsp(void) { gSPClearGeometryMode(gDisplayListHead++, G_SHADE | G_SHADING_SMOOTH | G_CULL_BOTH | G_FOG | G_LIGHTING | G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_LOD); @@ -126,17 +150,17 @@ void my_rsp_init(void) { gSPNumLights(gDisplayListHead++, NUMLIGHTS_1); gSPTexture(gDisplayListHead++, 0, 0, 0, G_TX_RENDERTILE, G_OFF); - // @bug Nintendo did not explicitly define the clipping ratio. - // For Fast3DEX2, this causes the dreaded warped vertices issue - // unless the clipping ratio is changed back to the intended value, - // as Fast3DEX2 uses a different initial value than Fast3D(EX). + // @bug Failing to set the clip ratio will result in warped triangles in F3DEX2 + // without this change: https://jrra.zone/n64/doc/n64man/gsp/gSPClipRatio.htm #ifdef F3DEX_GBI_2 gSPClipRatio(gDisplayListHead++, FRUSTRATIO_1); #endif } -/** Clear the Z buffer. */ -void clear_z_buffer(void) { +/** + * Initialize the z buffer for the current frame. + */ +void init_z_buffer(void) { gDPPipeSync(gDisplayListHead++); gDPSetDepthSource(gDisplayListHead++, G_ZS_PIXEL); @@ -146,22 +170,27 @@ void clear_z_buffer(void) { gDPSetFillColor(gDisplayListHead++, GPACK_ZDZ(G_MAXFBZ, 0) << 16 | GPACK_ZDZ(G_MAXFBZ, 0)); - gDPFillRectangle(gDisplayListHead++, 0, BORDER_HEIGHT, SCREEN_WIDTH - 1, - SCREEN_HEIGHT - 1 - BORDER_HEIGHT); + gDPFillRectangle(gDisplayListHead++, 0, gBorderHeight, SCREEN_WIDTH - 1, + SCREEN_HEIGHT - 1 - gBorderHeight); } -/** Sets up the final framebuffer image. */ -void display_frame_buffer(void) { +/** + * Tells the RDP which of the three framebuffers it shall draw to. + */ +void select_frame_buffer(void) { gDPPipeSync(gDisplayListHead++); gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); gDPSetColorImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, - gPhysicalFrameBuffers[frameBufferIndex]); - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, - SCREEN_HEIGHT - BORDER_HEIGHT); + gPhysicalFrameBuffers[sRenderingFrameBuffer]); + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, gBorderHeight, SCREEN_WIDTH, + SCREEN_HEIGHT - gBorderHeight); } -/** Clears the framebuffer, allowing it to be overwritten. */ +/** + * Clear the framebuffer and fill it with a 32-bit color. + * Information about the color argument: https://jrra.zone/n64/doc/n64man/gdp/gDPSetFillColor.htm + */ void clear_frame_buffer(s32 color) { gDPPipeSync(gDisplayListHead++); @@ -170,15 +199,17 @@ void clear_frame_buffer(s32 color) { gDPSetFillColor(gDisplayListHead++, color); gDPFillRectangle(gDisplayListHead++, - GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), BORDER_HEIGHT, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - BORDER_HEIGHT - 1); + GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), gBorderHeight, + GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - gBorderHeight - 1); gDPPipeSync(gDisplayListHead++); gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); } -/** Clears and initializes the viewport. */ +/** + * Resets the viewport, readying it for the final image. + */ void clear_viewport(Vp *viewport, s32 color) { s16 vpUlx = (viewport->vp.vtrans[0] - viewport->vp.vscale[0]) / 4 + 1; s16 vpUly = (viewport->vp.vtrans[1] - viewport->vp.vscale[1]) / 4 + 1; @@ -203,7 +234,9 @@ void clear_viewport(Vp *viewport, s32 color) { gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); } -/** Draws the horizontal screen borders */ +/** + * Draw the horizontal screen borders. + */ void draw_screen_borders(void) { gDPPipeSync(gDisplayListHead++); @@ -213,15 +246,19 @@ void draw_screen_borders(void) { gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(0, 0, 0, 0) << 16 | GPACK_RGBA5551(0, 0, 0, 0)); -#if BORDER_HEIGHT != 0 - gDPFillRectangle(gDisplayListHead++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), 0, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, BORDER_HEIGHT - 1); - gDPFillRectangle(gDisplayListHead++, - GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), SCREEN_HEIGHT - BORDER_HEIGHT, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - 1); -#endif + if (gBorderHeight) { + gDPFillRectangle(gDisplayListHead++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), 0, + GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, gBorderHeight - 1); + gDPFillRectangle(gDisplayListHead++, + GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), SCREEN_HEIGHT - gBorderHeight, + GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - 1); + } } +/** + * Defines the viewport scissoring rectangle. + * Scissoring: https://jrra.zone/n64/doc/pro-man/pro12/12-03.htm#01 + */ void make_viewport_clip_rect(Vp *viewport) { s16 vpUlx = (viewport->vp.vtrans[0] - viewport->vp.vscale[0]) / 4 + 1; s16 vpPly = (viewport->vp.vtrans[1] - viewport->vp.vscale[1]) / 4 + 1; @@ -232,20 +269,22 @@ void make_viewport_clip_rect(Vp *viewport) { } /** - * Loads the F3D microcodes. - * Refer to this function if you would like to load - * other microcodes (i.e. S2DEX). + * Initializes the Fast3D OSTask structure. + * If you plan on using gSPLoadUcode, make sure to add OS_TASK_LOADABLE to the flags member. */ -void create_task_structure(void) { +void create_gfx_task_structure(void) { s32 entries = gDisplayListHead - gGfxPool->buffer; - gGfxSPTask->msgqueue = &D_80339CB8; + gGfxSPTask->msgqueue = &gGfxVblankQueue; gGfxSPTask->msg = (OSMesg) 2; gGfxSPTask->task.t.type = M_GFXTASK; gGfxSPTask->task.t.ucode_boot = rspbootTextStart; gGfxSPTask->task.t.ucode_boot_size = ((u8 *) rspbootTextEnd - (u8 *) rspbootTextStart); gGfxSPTask->task.t.flags = 0; -#ifdef F3DZEX_GBI_2 +#ifdef L3DEX2_ALONE + gGfxSPTask->task.t.ucode = gspL3DEX2_fifoTextStart; + gGfxSPTask->task.t.ucode_data = gspL3DEX2_fifoDataStart; +#elif F3DZEX_GBI_2 gGfxSPTask->task.t.ucode = gspF3DZEX2_PosLight_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspF3DZEX2_PosLight_fifoDataStart; #elif F3DEX2PL_GBI @@ -259,7 +298,7 @@ void create_task_structure(void) { gGfxSPTask->task.t.ucode_data = gspF3DEX_fifoDataStart; #elif SUPER3D_GBI gGfxSPTask->task.t.ucode = gspSuper3D_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspSuper3D_fifoDataStart; + gGfxSPTask->task.t.ucode_data = gspSuper3D_fifoDataStart; #else gGfxSPTask->task.t.ucode = gspFast3D_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspFast3D_fifoDataStart; @@ -277,16 +316,20 @@ void create_task_structure(void) { gGfxSPTask->task.t.yield_data_size = OS_YIELD_DATA_SIZE; } -/** Starts rendering the scene. */ -void init_render_image(void) { +/** + * Set default RCP (Reality Co-Processor) settings. + */ +void init_rcp(void) { move_segment_table_to_dmem(); - my_rdp_init(); - my_rsp_init(); - clear_z_buffer(); - display_frame_buffer(); + init_rdp(); + init_rsp(); + init_z_buffer(); + select_frame_buffer(); } -/** Ends the master display list. */ +/** + * End the master display list and initialize the graphics task structure for the next frame to be rendered. + */ void end_master_display_list(void) { draw_screen_borders(); if (gShowProfiler) { @@ -296,89 +339,113 @@ void end_master_display_list(void) { gDPFullSync(gDisplayListHead++); gSPEndDisplayList(gDisplayListHead++); - create_task_structure(); + create_gfx_task_structure(); } +/** + * Draw the bars that appear when the N64 is soft reset. + */ void draw_reset_bars(void) { - s32 sp24; - s32 sp20; + s32 width, height; s32 fbNum; - u64 *sp18; + u64 *fbPtr; - if (gResetTimer != 0 && D_8032C648 < 15) { - if (sCurrFBNum == 0) { + if (gResetTimer != 0 && gNmiResetBarsTimer < 15) { + if (sRenderedFramebuffer == 0) { fbNum = 2; } else { - fbNum = sCurrFBNum - 1; + fbNum = sRenderedFramebuffer - 1; } - sp18 = (u64 *) PHYSICAL_TO_VIRTUAL(gPhysicalFrameBuffers[fbNum]); - sp18 += D_8032C648++ * (SCREEN_WIDTH / 4); + fbPtr = (u64 *) PHYSICAL_TO_VIRTUAL(gPhysicalFrameBuffers[fbNum]); + fbPtr += gNmiResetBarsTimer++ * (SCREEN_WIDTH / 4); - for (sp24 = 0; sp24 < ((SCREEN_HEIGHT / 16) + 1); sp24++) { + for (width = 0; width < ((SCREEN_HEIGHT / 16) + 1); width++) { // Loop must be one line to match on -O2 - for (sp20 = 0; sp20 < (SCREEN_WIDTH / 4); sp20++) *sp18++ = 0; - sp18 += ((SCREEN_WIDTH / 4) * 14); + for (height = 0; height < (SCREEN_WIDTH / 4); height++) *fbPtr++ = 0; + fbPtr += ((SCREEN_WIDTH / 4) * 14); } } osWritebackDCacheAll(); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); + osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); + osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); } -void rendering_init(void) { +/** + * Initial settings for the first rendered frame. + */ +void render_init(void) { if (IO_READ(DPC_PIPEBUSY_REG) == 0) { gIsConsole = 0; + gBorderHeight = BORDER_HEIGHT_EMULATOR; } else { gIsConsole = 1; + gBorderHeight = BORDER_HEIGHT_CONSOLE; } gGfxPool = &gGfxPools[0]; set_segment_base_addr(1, gGfxPool->buffer); gGfxSPTask = &gGfxPool->spTask; gDisplayListHead = gGfxPool->buffer; - gGfxPoolEnd = (u8 *) (gGfxPool->buffer + GFX_POOL_SIZE); - init_render_image(); + gGfxPoolEnd = (u8 *)(gGfxPool->buffer + GFX_POOL_SIZE); + init_rcp(); clear_frame_buffer(0); end_master_display_list(); - send_display_list(&gGfxPool->spTask); + exec_display_list(&gGfxPool->spTask); // Skip incrementing the initial framebuffer index on emulators so that they display immediately as the Gfx task finishes - if ((*(volatile u32 *)0xA4100010) != 0) { // Read RDP Clock Register, has a value of zero on emulators - frameBufferIndex++; + // VC probably emulates osViSwapBuffer accurately so instant patch breaks VC compatibility + if (gIsConsole) { // Read RDP Clock Register, has a value of zero on emulators + sRenderingFrameBuffer++; } gGlobalTimer++; } -void config_gfx_pool(void) { - gGfxPool = &gGfxPools[gGlobalTimer % 2]; +/** + * Selects the location of the F3D output buffer (gDisplayListHead). + */ +void select_gfx_pool(void) { + gGfxPool = &gGfxPools[gGlobalTimer % ARRAY_COUNT(gGfxPools)]; set_segment_base_addr(1, gGfxPool->buffer); gGfxSPTask = &gGfxPool->spTask; gDisplayListHead = gGfxPool->buffer; gGfxPoolEnd = (u8 *) (gGfxPool->buffer + GFX_POOL_SIZE); } -/** Handles vsync. */ +/** + * This function: + * - Sends the current master display list out to be rendered. + * - Tells the VI which color framebuffer to be displayed. + * - Yields to the VI framerate twice, locking the game at 30 FPS. + * - Selects which framebuffer will be rendered and displayed to next time. + */ void display_and_vsync(void) { + gIsVC = IS_VC(); + if (IO_READ(DPC_PIPEBUSY_REG) && gIsConsole != 1) + { + gIsConsole = 1; + gBorderHeight = BORDER_HEIGHT_CONSOLE; + } profiler_log_thread5_time(BEFORE_DISPLAY_LISTS); - osRecvMesg(&D_80339CB8, &D_80339BEC, OS_MESG_BLOCK); + //gIsConsole = (IO_READ(DPC_PIPEBUSY_REG)); + osRecvMesg(&gGfxVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); if (gGoddardVblankCallback != NULL) { gGoddardVblankCallback(); gGoddardVblankCallback = NULL; } - send_display_list(&gGfxPool->spTask); + exec_display_list(&gGfxPool->spTask); profiler_log_thread5_time(AFTER_DISPLAY_LISTS); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); - osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFrameBuffers[sCurrFBNum])); + osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); + osViSwapBuffer((void *) PHYSICAL_TO_VIRTUAL(gPhysicalFrameBuffers[sRenderedFramebuffer])); profiler_log_thread5_time(THREAD5_END); - osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK); + osRecvMesg(&gGameVblankQueue, &gMainReceivedMesg, OS_MESG_BLOCK); // Skip swapping buffers on emulator so that they display immediately as the Gfx task finishes - if ((*(volatile u32 *)0xA4100010) != 0) { // Read RDP Clock Register, has a value of zero on emulators - if (++sCurrFBNum == 3) { - sCurrFBNum = 0; + if (gIsConsole || gIsVC) { // Read RDP Clock Register, has a value of zero on emulators + if (++sRenderedFramebuffer == 3) { + sRenderedFramebuffer = 0; } - if (++frameBufferIndex == 3) { - frameBufferIndex = 0; + if (++sRenderingFrameBuffer == 3) { + sRenderingFrameBuffer = 0; } } gGlobalTimer++; @@ -394,7 +461,7 @@ UNUSED static void record_demo(void) { s8 rawStickX = gPlayer1Controller->rawStickX; s8 rawStickY = gPlayer1Controller->rawStickY; - // if the stick is in deadzone, set its value to 0 to + // If the stick is in deadzone, set its value to 0 to // nullify the effects. We do not record deadzone inputs. if (rawStickX > -8 && rawStickX < 8) { rawStickX = 0; @@ -404,9 +471,8 @@ UNUSED static void record_demo(void) { rawStickY = 0; } - // record the distinct input and timer so long as they - // are unique. If the timer hits 0xFF, reset the timer - // for the next demo input. + // Rrecord the distinct input and timer so long as they are unique. + // If the timer hits 0xFF, reset the timer for the next demo input. if (gRecordedDemoInput.timer == 0xFF || buttonMask != gRecordedDemoInput.buttonMask || rawStickX != gRecordedDemoInput.rawStickX || rawStickY != gRecordedDemoInput.rawStickY) { gRecordedDemoInput.timer = 0; @@ -417,16 +483,17 @@ UNUSED static void record_demo(void) { gRecordedDemoInput.timer++; } -// take the updated controller struct and calculate -// the new x, y, and distance floats. +/** + * Take the updated controller struct and calculate the new x, y, and distance floats. + */ void adjust_analog_stick(struct Controller *controller) { UNUSED u8 pad[8]; - // reset the controller's x and y floats. + // Reset the controller's x and y floats. controller->stickX = 0; controller->stickY = 0; - // modulate the rawStickX and rawStickY to be the new f32 values by adding/subtracting 6. + // Modulate the rawStickX and rawStickY to be the new f32 values by adding/subtracting 6. if (controller->rawStickX <= -8) { controller->stickX = controller->rawStickX + 6; } @@ -443,12 +510,12 @@ void adjust_analog_stick(struct Controller *controller) { controller->stickY = controller->rawStickY - 6; } - // calculate f32 magnitude from the center by vector length. + // Calculate f32 magnitude from the center by vector length. controller->stickMag = sqrtf(controller->stickX * controller->stickX + controller->stickY * controller->stickY); - // magnitude cannot exceed 64.0f: if it does, modify the values appropriately to - // flatten the values down to the allowed maximum value. + // Magnitude cannot exceed 64.0f: if it does, modify the values + // appropriately to flatten the values down to the allowed maximum value. if (controller->stickMag > 64) { controller->stickX *= 64 / controller->stickMag; controller->stickY *= 64 / controller->stickMag; @@ -456,64 +523,56 @@ void adjust_analog_stick(struct Controller *controller) { } } -// if a demo sequence exists, this will run the demo -// input list until it is complete. called every frame. +/** + * If a demo sequence exists, this will run the demo input list until it is complete. + */ void run_demo_inputs(void) { - // eliminate the unused bits. + // Eliminate the unused bits. gControllers[0].controllerData->button &= VALID_BUTTONS; - /* - Check if a demo inputs list - exists and if so, run the - active demo input list. - */ + // Check if a demo inputs list exists and if so, + // run the active demo input list. if (gCurrDemoInput != NULL) { - /* - clear player 2's inputs if they exist. Player 2's controller - cannot be used to influence a demo. At some point, Nintendo - may have planned for there to be a demo where 2 players moved - around instead of just one, so clearing player 2's influence from - the demo had to have been necessary to perform this. Co-op mode, perhaps? - */ + // Clear player 2's inputs if they exist. Player 2's controller + // cannot be used to influence a demo. At some point, Nintendo + // may have planned for there to be a demo where 2 players moved + // around instead of just one, so clearing player 2's influence from + // the demo had to have been necessary to perform this. Co-op mode, perhaps? if (gControllers[1].controllerData != NULL) { gControllers[1].controllerData->stick_x = 0; gControllers[1].controllerData->stick_y = 0; gControllers[1].controllerData->button = 0; } - // the timer variable being 0 at the current input means the demo is over. - // set the button to the END_DEMO mask to end the demo. + // The timer variable being 0 at the current input means the demo is over. + // Set the button to the END_DEMO mask to end the demo. if (gCurrDemoInput->timer == 0) { gControllers[0].controllerData->stick_x = 0; gControllers[0].controllerData->stick_y = 0; gControllers[0].controllerData->button = END_DEMO; } else { - // backup the start button if it is pressed, since we don't want the + // Backup the start button if it is pressed, since we don't want the // demo input to override the mask where start may have been pressed. u16 startPushed = gControllers[0].controllerData->button & START_BUTTON; - // perform the demo inputs by assigning the current button mask and the stick inputs. + // Perform the demo inputs by assigning the current button mask and the stick inputs. gControllers[0].controllerData->stick_x = gCurrDemoInput->rawStickX; gControllers[0].controllerData->stick_y = gCurrDemoInput->rawStickY; - /* - to assign the demo input, the button information is stored in - an 8-bit mask rather than a 16-bit mask. this is because only - A, B, Z, Start, and the C-Buttons are used in a demo, as bits - in that order. In order to assign the mask, we need to take the - upper 4 bits (A, B, Z, and Start) and shift then left by 8 to - match the correct input mask. We then add this to the masked - lower 4 bits to get the correct button mask. - */ + // To assign the demo input, the button information is stored in + // an 8-bit mask rather than a 16-bit mask. this is because only + // A, B, Z, Start, and the C-Buttons are used in a demo, as bits + // in that order. In order to assign the mask, we need to take the + // upper 4 bits (A, B, Z, and Start) and shift then left by 8 to + // match the correct input mask. We then add this to the masked + // lower 4 bits to get the correct button mask. gControllers[0].controllerData->button = ((gCurrDemoInput->buttonMask & 0xF0) << 8) + ((gCurrDemoInput->buttonMask & 0xF)); - // if start was pushed, put it into the demo sequence being input to - // end the demo. + // If start was pushed, put it into the demo sequence being input to end the demo. gControllers[0].controllerData->button |= startPushed; - // run the current demo input's timer down. if it hits 0, advance the - // demo input list. + // Run the current demo input's timer down. if it hits 0, advance the demo input list. if (--gCurrDemoInput->timer == 0) { gCurrDemoInput++; } @@ -521,14 +580,15 @@ void run_demo_inputs(void) { } } -// update the controller struct with available inputs if present. +/** + * Update the controller struct with available inputs if present. + */ void read_controller_inputs(void) { s32 i; - // if any controllers are plugged in, update the - // controller information. + // If any controllers are plugged in, update the controller information. if (gControllerBits) { - osRecvMesg(&gSIEventMesgQueue, &D_80339BEC, OS_MESG_BLOCK); + osRecvMesg(&gSIEventMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK); osContGetReadData(&gControllerPads[0]); #if ENABLE_RUMBLE release_rumble_pak_control(); @@ -539,8 +599,7 @@ void read_controller_inputs(void) { for (i = 0; i < 2; i++) { struct Controller *controller = &gControllers[i]; - // if we're receiving inputs, update the controller struct - // with the new button info. + // if we're receiving inputs, update the controller struct with the new button info. if (controller->controllerData != NULL) { controller->rawStickX = controller->controllerData->stick_x; controller->rawStickY = controller->controllerData->stick_y; @@ -561,9 +620,9 @@ void read_controller_inputs(void) { } } - // For some reason, player 1's inputs are copied to player 3's port. This - // potentially may have been a way the developers "recorded" the inputs - // for demos, despite record_demo existing. + // For some reason, player 1's inputs are copied to player 3's port. + // This potentially may have been a way the developers "recorded" + // the inputs for demos, despite record_demo existing. gPlayer3Controller->rawStickX = gPlayer1Controller->rawStickX; gPlayer3Controller->rawStickY = gPlayer1Controller->rawStickY; gPlayer3Controller->stickX = gPlayer1Controller->stickX; @@ -573,11 +632,13 @@ void read_controller_inputs(void) { gPlayer3Controller->buttonDown = gPlayer1Controller->buttonDown; } -// initialize the controller structs to point at the OSCont information. +/** + * Initialize the controller structs to point at the OSCont information. + */ void init_controllers(void) { s16 port, cont; - // set controller 1 to point to the set of status/pads for input 1 and + // Set controller 1 to point to the set of status/pads for input 1 and // init the controllers. gControllers[0].statusData = &gControllerStatuses[0]; gControllers[0].controllerData = &gControllerPads[0]; @@ -592,15 +653,15 @@ void init_controllers(void) { gSramProbe = nuPiInitSram(); #endif - // loop over the 4 ports and link the controller structs to the appropriate + // Loop over the 4 ports and link the controller structs to the appropriate // status and pad. Interestingly, although there are pointers to 3 controllers, // only 2 are connected here. The third seems to have been reserved for debug // purposes and was never connected in the retail ROM, thus gPlayer3Controller // cannot be used, despite being referenced in various code. for (cont = 0, port = 0; port < 4 && cont < 2; port++) { - // is controller plugged in? + // Is controller plugged in? if (gControllerBits & (1 << port)) { - // the game allows you to have just 1 controller plugged + // The game allows you to have just 1 controller plugged // into any port in order to play the game. this was probably // so if any of the ports didn't work, you can have controllers // plugged into any of them and it will work. @@ -613,30 +674,47 @@ void init_controllers(void) { } } -void setup_game_memory(void) { - UNUSED u8 pad[8]; +// Game thread core +// ---------------------------------------------------------------------------------------------------- +/** + * Setup main segments and framebuffers. + */ +void setup_game_memory(void) { + UNUSED u64 padding; + + // Setup general Segment 0 set_segment_base_addr(0, (void *) 0x80000000); - osCreateMesgQueue(&D_80339CB8, &D_80339CD4, 1); - osCreateMesgQueue(&gGameVblankQueue, &D_80339CD0, 1); + // Create Mesg Queues + osCreateMesgQueue(&gGfxVblankQueue, gGfxMesgBuf, ARRAY_COUNT(gGfxMesgBuf)); + osCreateMesgQueue(&gGameVblankQueue, gGameMesgBuf, ARRAY_COUNT(gGameMesgBuf)); + // Setup z buffer and framebuffer gPhysicalZBuffer = VIRTUAL_TO_PHYSICAL(gZBuffer); gPhysicalFrameBuffers[0] = VIRTUAL_TO_PHYSICAL(gFrameBuffer0); gPhysicalFrameBuffers[1] = VIRTUAL_TO_PHYSICAL(gFrameBuffer1); gPhysicalFrameBuffers[2] = VIRTUAL_TO_PHYSICAL(gFrameBuffer2); - D_80339CF0 = main_pool_alloc(0x4000, MEMORY_POOL_LEFT); - set_segment_base_addr(17, (void *) D_80339CF0); - func_80278A78(&D_80339D10, gMarioAnims, D_80339CF0); - D_80339CF4 = main_pool_alloc(2048, MEMORY_POOL_LEFT); - set_segment_base_addr(24, (void *) D_80339CF4); - func_80278A78(&gDemo, gDemoInputs, D_80339CF4); - load_segment(0x10, _entrySegmentRomStart, _entrySegmentRomEnd, MEMORY_POOL_LEFT); - load_segment_decompress(2, _segment2_yay0SegmentRomStart, _segment2_yay0SegmentRomEnd); + // Setup Mario Animations + gMarioAnimsMemAlloc = main_pool_alloc(0x4000, MEMORY_POOL_LEFT); + set_segment_base_addr(17, (void *) gMarioAnimsMemAlloc); + setup_dma_table_list(&gMarioAnimsBuf, gMarioAnims, gMarioAnimsMemAlloc); + // Setup Demo Inputs List + gDemoInputsMemAlloc = main_pool_alloc(0x800, MEMORY_POOL_LEFT); + set_segment_base_addr(24, (void *) gDemoInputsMemAlloc); + setup_dma_table_list(&gDemoInputsBuf, gDemoInputs, gDemoInputsMemAlloc); + // Setup Level Script Entry + load_segment(0x10, _entrySegmentRomStart, _entrySegmentRomEnd, MEMORY_POOL_LEFT, NULL, NULL); + // Setup Segment 2 (Fonts, Text, etc) + load_segment_decompress(2, _segment2_mio0SegmentRomStart, _segment2_mio0SegmentRomEnd); } -// main game loop thread. runs forever as long as the game -// continues. +/** + * Main game loop thread. Runs forever as long as the game continues. + */ void thread5_game_loop(UNUSED void *arg) { struct LevelCommand *addr; + #if PUPPYPRINT_DEBUG + OSTime lastTime = 0; + #endif setup_game_memory(); #if ENABLE_RUMBLE @@ -650,25 +728,39 @@ void thread5_game_loop(UNUSED void *arg) { createHvqmThread(); #endif save_file_load_all(); + #ifdef PUPPYCAM + puppycam_boot(); + #endif set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1); - // point addr to the entry point into the level script data. + // Point address to the entry point into the level script data. addr = segmented_to_virtual(level_script_entry); play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0); set_sound_mode(save_file_get_sound_mode()); - rendering_init(); +#ifdef WIDE + gWidescreen = save_file_get_widescreen_mode(); +#endif + render_init(); while (TRUE) { - // if the reset timer is active, run the process to reset the game. + // If the reset timer is active, run the process to reset the game. if (gResetTimer) { draw_reset_bars(); continue; } profiler_log_thread5_time(THREAD5_START); + #if PUPPYPRINT_DEBUG + while (TRUE) + { + lastTime = osGetTime(); + collisionTime[perfIteration] = 0; + behaviourTime[perfIteration] = 0; + dmaTime[perfIteration] = 0; + #endif - // if any controllers are plugged in, start read the data for when + // If any controllers are plugged in, start read the data for when // read_controller_inputs is called later. if (gControllerBits) { #if ENABLE_RUMBLE @@ -678,9 +770,29 @@ void thread5_game_loop(UNUSED void *arg) { } audio_game_loop_tick(); - config_gfx_pool(); + select_gfx_pool(); read_controller_inputs(); addr = level_script_execute(addr); + #if PUPPYPRINT_DEBUG == 0 && defined(VISUAL_DEBUG) + debug_box_input(); + #endif + #if PUPPYPRINT_DEBUG + profiler_update(scriptTime, lastTime); + if (benchmarkLoop > 0 && benchOption == 0) + { + benchmarkLoop--; + benchMark[benchmarkLoop] = osGetTime() - lastTime; + if (benchmarkLoop == 0) + { + puppyprint_profiler_finished(); + break; + } + } + else + break; + } + puppyprint_profiler_process(); + #endif display_and_vsync(); diff --git a/src/game/game_init.h b/src/game/game_init.h index 5bf056bf..7b1a7588 100644 --- a/src/game/game_init.h +++ b/src/game/game_init.h @@ -9,7 +9,7 @@ #include "types.h" #include "memory.h" -#define GFX_POOL_SIZE 6400 +#define GFX_POOL_SIZE 10000 // Size of how large the master display list (gDisplayListHead) can be struct GfxPool { Gfx buffer[GFX_POOL_SIZE]; @@ -28,14 +28,14 @@ extern struct Controller gControllers[3]; extern OSContStatus gControllerStatuses[4]; extern OSContPad gControllerPads[4]; extern OSMesgQueue gGameVblankQueue; -extern OSMesgQueue D_80339CB8; -extern OSMesg D_80339CD0; -extern OSMesg D_80339CD4; +extern OSMesgQueue gGfxVblankQueue; +extern OSMesg gGameMesgBuf[1]; +extern OSMesg gGfxMesgBuf[1]; extern struct VblankHandler gGameVblankHandler; extern uintptr_t gPhysicalFrameBuffers[3]; extern uintptr_t gPhysicalZBuffer; -extern void *D_80339CF0; -extern void *D_80339CF4; +extern void *gMarioAnimsMemAlloc; +extern void *gDemoInputsMemAlloc; extern struct SPTask *gGfxSPTask; extern Gfx *gDisplayListHead; extern u8 *gGfxPoolEnd; @@ -43,7 +43,11 @@ extern struct GfxPool *gGfxPool; extern u8 gControllerBits; extern u8 gIsConsole; #ifdef WIDE -extern u8 gWidescreen; +extern s16 gWidescreen; +#endif +extern u8 gBorderHeight; +#ifdef CUSTOM_DEBUG +extern u8 gCustomDebugMode; #endif extern u8 *gAreaSkyboxStart[7]; extern u8 *gAreaSkyboxEnd[7]; @@ -64,13 +68,13 @@ extern struct DemoInput gRecordedDemoInput; // this area is the demo input + the header. when the demo is loaded in, there is a header the size // of a single word next to the input list. this word is the current ID count. -extern struct MarioAnimation D_80339D10; -extern struct MarioAnimation gDemo; +extern struct DmaHandlerList gMarioAnimsBuf; +extern struct DmaHandlerList gDemoInputsBuf; extern u8 gMarioAnims[]; extern u8 gDemoInputs[]; -extern u16 frameBufferIndex; +extern u16 sRenderingFrameBuffer; extern u32 gGlobalTimer; void setup_game_memory(void); @@ -78,10 +82,10 @@ void thread5_game_loop(UNUSED void *arg); void clear_frame_buffer(s32 color); void clear_viewport(Vp *viewport, s32 color); void make_viewport_clip_rect(Vp *viewport); -void init_render_image(void); +void init_rcp(void); void end_master_display_list(void); -void rendering_init(void); -void config_gfx_pool(void); +void render_init(void); +void select_gfx_pool(void); void display_and_vsync(void); #endif // GAME_INIT_H diff --git a/src/game/geo_misc.c b/src/game/geo_misc.c index 2fb8c5ef..383f5fff 100644 --- a/src/game/geo_misc.c +++ b/src/game/geo_misc.c @@ -96,7 +96,7 @@ Gfx *geo_exec_inside_castle_light(s32 callContext, struct GraphNode *node, UNUSE } generatedNode = (struct GraphNodeGenerated *) node; - generatedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | 0x500; + generatedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | (LAYER_TRANSPARENT << 8); gSPDisplayList(displayListHead++, dl_castle_lobby_wing_cap_light); gSPEndDisplayList(displayListHead); @@ -149,7 +149,7 @@ Gfx *geo_exec_flying_carpet_create(s32 callContext, struct GraphNode *node, UNUS return NULL; } - generatedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | 0x100; + generatedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8); for (n = 0; n <= 20; n++) { row = n / 3; @@ -202,14 +202,17 @@ Gfx *geo_exec_cake_end_screen(s32 callContext, struct GraphNode *node, UNUSED f3 displayList = alloc_display_list(3 * sizeof(*displayList)); displayListHead = displayList; - generatedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | 0x100; + generatedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | (LAYER_OPAQUE << 8); #ifdef VERSION_EU gSPDisplayList(displayListHead++, dl_cake_end_screen); #else gSPDisplayList(displayListHead++, dl_proj_mtx_fullscreen); #endif #ifdef VERSION_EU - switch (eu_get_language()) { +#ifdef EU_CUSTOM_CAKE_FIX + gSPDisplayList(displayListHead++, dl_cake_end_screen_eu_fix); +#else + switch (eu_get_language()) { case LANGUAGE_ENGLISH: gSPDisplayList(displayListHead++, dl_cake_end_screen_eu_070296F8); break; @@ -220,6 +223,7 @@ Gfx *geo_exec_cake_end_screen(s32 callContext, struct GraphNode *node, UNUSED f3 gSPDisplayList(displayListHead++, dl_cake_end_screen_eu_070297D8); break; } +#endif #else gSPDisplayList(displayListHead++, dl_cake_end_screen); #endif diff --git a/src/game/hud.c b/src/game/hud.c index f11b626d..5106d7dd 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -14,6 +14,10 @@ #include "save_file.h" #include "print.h" #include "engine/surface_load.h" +#include "puppycam2.h" +#include "puppyprint.h" + +#include "config.h" /* @file hud.c * This file implements HUD rendering and power meter animations. @@ -48,11 +52,15 @@ f32 calculate_and_update_fps() void print_fps(s32 x, s32 y) { f32 fps = calculate_and_update_fps(); - char text[10]; - - sprintf(text, "%2.2f", fps); + char text[14]; + sprintf(text, "FPS %2.2f", fps); + #ifdef PUPPYPRINT + print_small_text(x, y, text, PRINT_TEXT_ALIGN_LEFT, PRINT_ALL); + #else print_text(x, y, text); + #endif + } // ------------ END OF FPS COUNER ----------------- @@ -90,7 +98,7 @@ static struct PowerMeterHUD sPowerMeterHUD = { // when the power meter is hidden. s32 sPowerMeterVisibleTimer = 0; -static struct UnusedHUDStruct sUnusedHUDValues = { 0x00, 0x0A, 0x00 }; +UNUSED static struct UnusedHUDStruct sUnusedHUDValues = { 0x00, 0x0A, 0x00 }; static struct CameraHUD sCameraHUD = { CAM_STATUS_NONE }; @@ -308,6 +316,18 @@ void render_hud_mario_lives(void) { print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(54), HUD_TOP_Y, "%d", gHudDisplay.lives); } +#ifdef CUSTOM_DEBUG +void render_debug_mode(void) { + print_text(180, 40, "DEBUG MODE"); + print_text_fmt_int(5, 20, "Z %d", gMarioState->pos[2]); + print_text_fmt_int(5, 40, "Y %d", gMarioState->pos[1]); + print_text_fmt_int(5, 60, "X %d", gMarioState->pos[0]); + print_text_fmt_int(10, 100, "SPD %d", (s32) gMarioState->forwardVel); + print_text_fmt_int(10, 120, "ANG 0*%04x", (u16) gMarioState->faceAngle[1]); + print_fps(10,80); +} +#endif + /** * Renders the amount of coins collected. */ @@ -506,7 +526,10 @@ void render_hud(void) { if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) { render_hud_power_meter(); - render_hud_camera_status(); + #ifdef PUPPYCAM + if (!gPuppyCam.enabled) + #endif + render_hud_camera_status(); } if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER) { @@ -521,5 +544,13 @@ void render_hud(void) { { print_text(10, 60, "SURFACE NODE POOL FULL"); } + #ifdef CUSTOM_DEBUG + if (gCustomDebugMode) { + render_debug_mode(); + } + #endif + #ifdef PUPPYPRINT + print_set_envcolour(255,255,255,255); + #endif } } diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 2966e6a8..7d3175b6 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -8,6 +8,7 @@ #include "dialog_ids.h" #include "engine/math_util.h" #include "eu_translation.h" +#include "segment_symbols.h" #include "game_init.h" #include "gfx_dimensions.h" #include "ingame_menu.h" @@ -23,6 +24,7 @@ #include "text_strings.h" #include "types.h" #include "config.h" +#include "puppycam2.h" u16 gDialogColorFadeTimer; s8 gLastDialogLineNum; @@ -31,14 +33,31 @@ u16 gDialogTextAlpha; s16 gCutsceneMsgXOffset; s16 gCutsceneMsgYOffset; s8 gRedCoinsCollected; -#ifdef WIDE +#if defined(WIDE) && !defined(PUPPYCAM) u8 textCurrRatio43[] = { TEXT_HUD_CURRENT_RATIO_43 }; u8 textCurrRatio169[] = { TEXT_HUD_CURRENT_RATIO_169 }; u8 textPressL[] = { TEXT_HUD_PRESS_L }; -u8 textWideInfo[] = { TEXT_HUD_WIDE_INFO }; -u8 textWideInfo2[] = { TEXT_HUD_WIDE_INFO2 }; #endif +#if MULTILANG +#define seg2_course_name_table course_name_table_eu_en +#define seg2_act_name_table act_name_table_eu_en +#define seg2_dialog_table dialog_table_eu_en +#endif + +s16 gInGameLanguage = 0; +s16 gLoadedLanguage = 0; + +void *languageTable[][3] = +{ + {&seg2_dialog_table, &seg2_course_name_table, &seg2_act_name_table}, //In EU, this is just mirroring English. + #if MULTILANG + {&dialog_table_eu_en, &course_name_table_eu_en, &act_name_table_eu_en}, + {&dialog_table_eu_fr, &course_name_table_eu_fr, &act_name_table_eu_fr}, + {&dialog_table_eu_de, &course_name_table_eu_de, &act_name_table_eu_de}, + #endif +}; + extern u8 gLastCompletedCourseNum; extern u8 gLastCompletedStarNum; @@ -65,6 +84,7 @@ enum DialogMark { DIALOG_MARK_NONE = 0, DIALOG_MARK_DAKUTEN = 1, DIALOG_MARK_HAN #define DEFAULT_DIALOG_BOX_ANGLE 90.0f #define DEFAULT_DIALOG_BOX_SCALE 19.0f +#if defined(VERSION_US) || defined(VERSION_EU) u8 gDialogCharWidths[256] = { // TODO: Is there a way to auto generate this? 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 5, 8, 8, 6, 6, 6, 6, 6, 5, 6, 6, @@ -72,31 +92,44 @@ u8 gDialogCharWidths[256] = { // TODO: Is there a way to auto generate this? 7, 5, 5, 5, 6, 5, 5, 5, 5, 5, 7, 7, 5, 5, 4, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 7, 7, 6, 7, 7, 0, 0, 0, 0, 0, 0, 0, +#ifdef VERSION_EU + 6, 6, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 4, + 5, 5, 5, 5, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 5, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 5, 6, + 0, 4, 4, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#else 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#endif 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#ifdef VERSION_EU + 7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 5, 5, 6, 5, 0, +#else 7, 5, 10, 5, 9, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#endif 0, 0, 5, 7, 7, 6, 6, 8, 0, 8, 10, 6, 4, 10, 0, 0 }; +#endif s8 gDialogBoxState = DIALOG_STATE_OPENING; f32 gDialogBoxOpenTimer = DEFAULT_DIALOG_BOX_ANGLE; f32 gDialogBoxScale = DEFAULT_DIALOG_BOX_SCALE; s16 gDialogScrollOffsetY = 0; s8 gDialogBoxType = DIALOG_TYPE_ROTATE; -s16 gDialogID = -1; +s16 gDialogID = DIALOG_NONE; s16 gLastDialogPageStrPos = 0; s16 gDialogTextPos = 0; s8 gDialogLineNum = 1; s8 gLastDialogResponse = 0; u8 gMenuHoldKeyIndex = 0; u8 gMenuHoldKeyTimer = 0; -s32 gDialogResponse = 0; +s32 gDialogResponse = DIALOG_RESPONSE_NONE; void create_dl_identity_matrix(void) { @@ -184,6 +217,9 @@ void create_dl_ortho_matrix(void) { gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH) } +#if !defined(VERSION_JP) && !defined(VERSION_SH) +UNUSED +#endif static u8 *alloc_ia8_text_from_i1(u16 *in, s16 width, s16 height) { s32 inPos; u16 bitMask; @@ -214,15 +250,50 @@ static u8 *alloc_ia8_text_from_i1(u16 *in, s16 width, s16 height) { return out; } +u8 *alloc_ia4_tex_from_i1(u8 *in, s16 width, s16 height) { + u32 size = (u32) width * (u32) height; + u8 *out; + s32 inPos; + s16 outPos; + u8 bitMask; + + outPos = 0; + out = (u8 *) alloc_display_list(size); + + if (out == NULL) { + return NULL; + } + + for (inPos = 0; inPos < (width * height) / 4; inPos++) { + bitMask = 0x80; + while (bitMask != 0) { + out[outPos] = (in[inPos] & bitMask) ? 0xF0 : 0x00; + bitMask /= 2; + out[outPos] = (in[inPos] & bitMask) ? out[outPos] + 0x0F : out[outPos]; + bitMask /= 2; + outPos++; + } + } + + return out; +} + void render_generic_char(u8 c) { void **fontLUT; void *packedTexture; + void *unpackedTexture; fontLUT = segmented_to_virtual(main_font_lut); packedTexture = segmented_to_virtual(fontLUT[c]); - + #ifdef VERSION_EU + unpackedTexture = alloc_ia4_tex_from_i1(packedTexture, 8, 8); + gDPPipeSync(gDisplayListHead++); + gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(unpackedTexture)); + #else gDPPipeSync(gDisplayListHead++); gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture)); + #endif + gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings); } @@ -267,10 +338,53 @@ void print_generic_string(s16 x, s16 y, const u8 *str) { s32 strPos = 0; u8 lineNum = 1; + s16 colorLoop; + u8 rgbaColors[4] = {0, 0, 0, 0}; + u8 customColor = FALSE; + u8 diffTmp = 0; + create_dl_translation_matrix(MENU_MTX_PUSH, x, y, 0.0f); while (str[strPos] != DIALOG_CHAR_TERMINATOR) { + if (customColor == TRUE) { + gDPSetEnvColor(gDisplayListHead++, rgbaColors[0], rgbaColors[1], rgbaColors[2], rgbaColors[3]); + } + else { + if (customColor == 2) { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); // TODO: Is it possible to retrieve the original color that was set before print_generic_string was called? + customColor = FALSE; + } + } + switch (str[strPos]) { + case DIALOG_CHAR_COLOR: + customColor = TRUE; + strPos++; + for (colorLoop = strPos + 8; strPos < colorLoop; ++strPos) { + diffTmp = 0; + if (str[strPos] >= 0x24 && str[strPos] <= 0x29) { + diffTmp = 0x1A; + } + else if (str[strPos] >= 0x10) { + customColor = 2; + strPos = colorLoop - 8; + for (diffTmp = 0; diffTmp < 8; ++diffTmp) { + if (str[strPos + diffTmp] != 0x9F) + break; + } + if (diffTmp == 8) + strPos += diffTmp; + break; + } + if ((8 - (colorLoop - strPos)) % 2 == 0) { + rgbaColors[(8 - (colorLoop - strPos)) / 2] = ((str[strPos] - diffTmp) & 0x0F) << 4; + } + else { + rgbaColors[(8 - (colorLoop - strPos)) / 2] += ((str[strPos] - diffTmp) & 0x0F); + } + } + strPos--; + break; case DIALOG_CHAR_DAKUTEN: mark = DIALOG_MARK_DAKUTEN; break; @@ -587,14 +701,14 @@ s16 get_dialog_id(void) { } void create_dialog_box(s16 dialog) { - if (gDialogID == -1) { + if (gDialogID == DIALOG_NONE) { gDialogID = dialog; gDialogBoxType = DIALOG_TYPE_ROTATE; } } void create_dialog_box_with_var(s16 dialog, s32 dialogVar) { - if (gDialogID == -1) { + if (gDialogID == DIALOG_NONE) { gDialogID = dialog; gDialogVariable = dialogVar; gDialogBoxType = DIALOG_TYPE_ROTATE; @@ -602,14 +716,14 @@ void create_dialog_box_with_var(s16 dialog, s32 dialogVar) { } void create_dialog_inverted_box(s16 dialog) { - if (gDialogID == -1) { + if (gDialogID == DIALOG_NONE) { gDialogID = dialog; gDialogBoxType = DIALOG_TYPE_ZOOM; } } void create_dialog_box_with_response(s16 dialog) { - if (gDialogID == -1) { + if (gDialogID == DIALOG_NONE) { gDialogID = dialog; gDialogBoxType = DIALOG_TYPE_ROTATE; gLastDialogResponse = 1; @@ -626,11 +740,11 @@ void reset_dialog_render_state(void) { gDialogBoxScale = 19.0f; gDialogBoxOpenTimer = 90.0f; gDialogBoxState = DIALOG_STATE_OPENING; - gDialogID = -1; + gDialogID = DIALOG_NONE; gDialogTextPos = 0; gLastDialogResponse = 0; gLastDialogPageStrPos = 0; - gDialogResponse = 0; + gDialogResponse = DIALOG_RESPONSE_NONE; } #define X_VAL1 -7.0f @@ -668,7 +782,7 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) { gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); } -void change_and_flash_dialog_text_color_lines(s8 colorMode, s8 lineNum) { +void change_and_flash_dialog_text_color_lines(s8 colorMode, s8 lineNum, u8 *customColor) { u8 colorFade; if (colorMode == 1) { @@ -685,6 +799,10 @@ void change_and_flash_dialog_text_color_lines(s8 colorMode, s8 lineNum) { } else { switch (gDialogBoxType) { case DIALOG_TYPE_ROTATE: + if (*customColor == 2) { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + *customColor = FALSE; + } break; case DIALOG_TYPE_ZOOM: gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255); @@ -777,6 +895,11 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l u8 strChar; + s16 colorLoop; + u8 rgbaColors[4] = {0, 0, 0, 0}; + u8 customColor = FALSE; + u8 diffTmp = 0; + u8 *str = segmented_to_virtual(dialog->str); s8 lineNum = 1; @@ -809,7 +932,12 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL3, 2 - lineNum * Y_VAL3, 0); while (pageState == DIALOG_PAGE_STATE_NONE) { - change_and_flash_dialog_text_color_lines(colorMode, lineNum); + if (customColor == TRUE) { + gDPSetEnvColor(gDisplayListHead++, rgbaColors[0], rgbaColors[1], rgbaColors[2], rgbaColors[3]); + } + else { + change_and_flash_dialog_text_color_lines(colorMode, lineNum, &customColor); + } strChar = str[strIdx]; switch (strChar) { @@ -817,6 +945,34 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l pageState = DIALOG_PAGE_STATE_END; gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); break; + case DIALOG_CHAR_COLOR: + customColor = TRUE; + strIdx++; + for (colorLoop = strIdx + 8; strIdx < colorLoop; ++strIdx) { + diffTmp = 0; + if (str[strIdx] >= 0x24 && str[strIdx] <= 0x29) { + diffTmp = 0x1A; + } + else if (str[strIdx] >= 0x10) { + customColor = 2; + strIdx = colorLoop - 8; + for (diffTmp = 0; diffTmp < 8; ++diffTmp) { + if (str[strIdx + diffTmp] != 0x9F) + break; + } + if (diffTmp == 8) + strIdx += diffTmp; + break; + } + if ((8 - (colorLoop - strIdx)) % 2 == 0) { + rgbaColors[(8 - (colorLoop - strIdx)) / 2] = ((str[strIdx] - diffTmp) & 0x0F) << 4; + } + else { + rgbaColors[(8 - (colorLoop - strIdx)) / 2] += ((str[strIdx] - diffTmp) & 0x0F); + } + } + strIdx--; + break; case DIALOG_CHAR_NEWLINE: lineNum++; handle_dialog_scroll_page_state(lineNum, totalLines, &pageState, &xMatrix, &linePos); @@ -926,18 +1082,18 @@ void render_dialog_string_color(s8 linesPerBox) { void handle_special_dialog_text(s16 dialogID) { // dialog ID tables, in order // King Bob-omb (Start), Whomp (Start), King Bob-omb (throw him out), Eyerock (Start), Wiggler (Start) - s16 dialogBossStart[] = { 17, 114, 128, 117, 150 }; + s16 dialogBossStart[] = { DIALOG_017, DIALOG_114, DIALOG_128, DIALOG_117, DIALOG_150 }; // Koopa the Quick (BOB), Koopa the Quick (THI), Penguin Race, Fat Penguin Race (120 stars) - s16 dialogRaceSound[] = { 5, 9, 55, 164 }; + s16 dialogRaceSound[] = { DIALOG_005, DIALOG_009, DIALOG_055, DIALOG_164 }; // Red Switch, Green Switch, Blue Switch, 100 coins star, Bowser Red Coin Star - s16 dialogStarSound[] = { 10, 11, 12, 13, 14 }; + s16 dialogStarSound[] = { DIALOG_010, DIALOG_011, DIALOG_012, DIALOG_013, DIALOG_014 }; // King Bob-omb (Start), Whomp (Defeated), King Bob-omb (Defeated, missing in JP), Eyerock (Defeated), Wiggler (Defeated) #if BUGFIX_KING_BOB_OMB_FADE_MUSIC - s16 dialogBossStop[] = { 17, 115, 116, 118, 152 }; + s16 dialogBossStop[] = { DIALOG_017, DIALOG_115, DIALOG_116, DIALOG_118, DIALOG_152 }; #else - //! @bug JP misses King Bob-omb defeated dialog "116", meaning that the boss music will still + //! @bug JP misses King Bob-omb defeated DIALOG_116, meaning that the boss music will still //! play after King Bob-omb is defeated until BOB loads it's music after the star cutscene - s16 dialogBossStop[] = { 17, 115, 118, 152 }; + s16 dialogBossStop[] = { DIALOG_017, DIALOG_115, DIALOG_118, DIALOG_152 }; #endif s16 i; @@ -971,7 +1127,7 @@ void handle_special_dialog_text(s16 dialogID) { // dialog ID tables, in order } } -s16 gMenuMode = -1; +s16 gMenuMode = MENU_MODE_NONE; u8 gEndCutsceneStrEn0[] = { TEXT_FILE_MARIO_EXCLAMATION }; u8 gEndCutsceneStrEn1[] = { TEXT_POWER_STARS_RESTORED }; @@ -1017,13 +1173,13 @@ s8 gDialogCourseActNum = 1; void render_dialog_entries(void) { void **dialogTable; struct DialogEntry *dialog; - s8 lowerBound; - dialogTable = segmented_to_virtual(seg2_dialog_table); + s8 lowerBound = 0; + dialogTable = segmented_to_virtual(languageTable[gInGameLanguage][0]); dialog = segmented_to_virtual(dialogTable[gDialogID]); // if the dialog entry is invalid, set the ID to -1. if (segmented_to_virtual(NULL) == dialog) { - gDialogID = -1; + gDialogID = DIALOG_NONE; return; } @@ -1091,11 +1247,11 @@ void render_dialog_entries(void) { if (gDialogBoxOpenTimer == DEFAULT_DIALOG_BOX_ANGLE) { gDialogBoxState = DIALOG_STATE_OPENING; - gDialogID = -1; + gDialogID = DIALOG_NONE; gDialogTextPos = 0; gLastDialogResponse = 0; gLastDialogPageStrPos = 0; - gDialogResponse = 0; + gDialogResponse = DIALOG_RESPONSE_NONE; } lowerBound = 1; break; @@ -1122,7 +1278,7 @@ void render_dialog_entries(void) { if (gLastDialogPageStrPos == -1 && gLastDialogResponse == 1) { render_dialog_triangle_choice(); } - gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 2, 2, SCREEN_WIDTH - BORDER_HEIGHT/2, SCREEN_HEIGHT - BORDER_HEIGHT/2); + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 2, 2, SCREEN_WIDTH - gBorderHeight/2, SCREEN_HEIGHT - gBorderHeight/2); if (gLastDialogPageStrPos != -1 && gDialogBoxState == DIALOG_STATE_VERTICAL) { render_dialog_string_color(dialog->linesPerBox); } @@ -1130,7 +1286,7 @@ void render_dialog_entries(void) { // Calls a gMenuMode value defined by render_menus_and_dialogs cases void set_menu_mode(s16 mode) { - if (gMenuMode == -1) { + if (gMenuMode == MENU_MODE_NONE) { gMenuMode = mode; } } @@ -1266,7 +1422,7 @@ void print_peach_letter_message(void) { void **dialogTable; struct DialogEntry *dialog; u8 *str; - dialogTable = segmented_to_virtual(seg2_dialog_table); + dialogTable = segmented_to_virtual(languageTable[gInGameLanguage][0]); dialog = segmented_to_virtual(dialogTable[gDialogID]); str = segmented_to_virtual(dialog->str); @@ -1305,7 +1461,7 @@ void print_peach_letter_message(void) { if (gCutsceneMsgTimer > (PEACH_MESSAGE_TIMER + 20)) { gCutsceneMsgIndex = -1; gCutsceneMsgFade = 0; //! uselessly reset since the next execution will just set it to 0 again. - gDialogID = -1; + gDialogID = DIALOG_NONE; gCutsceneMsgTimer = 0; return; // return to avoid incrementing the timer } @@ -1405,7 +1561,27 @@ void render_pause_red_coins(void) { print_animated_red_coin(GFX_DIMENSIONS_FROM_RIGHT_EDGE(30) - x * 20, 16); } } +///By default, not needed as puppycamera has an option, but should you wish to revert that, you are legally allowed. +#if defined(WIDE) && !defined(PUPPYCAM) +void render_widescreen_setting(void) { + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); + if (!gWidescreen) { + print_generic_string(10, 20, textCurrRatio43); + print_generic_string(10, 7, textPressL); + } + else { + print_generic_string(10, 20, textCurrRatio169); + print_generic_string(10, 7, textPressL); + } + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); + if (gPlayer1Controller->buttonPressed & L_TRIG){ + gWidescreen ^= 1; + save_file_set_widescreen_mode(gWidescreen); + } +} +#endif #define CRS_NUM_X1 100 #define TXT_STAR_X 98 @@ -1427,8 +1603,8 @@ void render_pause_my_score_coins(void) { u8 courseIndex; u8 starFlags; - courseNameTbl = segmented_to_virtual(seg2_course_name_table); - actNameTbl = segmented_to_virtual(seg2_act_name_table); + courseNameTbl = segmented_to_virtual(languageTable[gInGameLanguage][1]); + actNameTbl = segmented_to_virtual(languageTable[gInGameLanguage][2]); courseIndex = gCurrCourseNum - 1; starFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1); @@ -1457,18 +1633,6 @@ void render_pause_my_score_coins(void) { print_generic_string(63, 157, textCourse); int_to_str(gCurrCourseNum, strCourseNum); print_generic_string(CRS_NUM_X1, 157, strCourseNum); -#ifdef WIDE - if (!gWidescreen) { - print_generic_string(10, 20, textCurrRatio43); - print_generic_string(10, 7, textPressL); - } - else { - print_generic_string(10, 20, textCurrRatio169); - print_generic_string(10, 7, textPressL); - print_generic_string(10, 220, textWideInfo); - print_generic_string(10, 200, textWideInfo2); - } -#endif actName = segmented_to_virtual(actNameTbl[(gCurrCourseNum - 1) * 6 + gDialogCourseActNum - 1]); @@ -1507,17 +1671,17 @@ void render_pause_camera_options(s16 x, s16 y, s8 *index, s16 xIndex) { print_generic_string(x + TXT2_X, y - 13, textNormalFixed); gSPDisplayList(gDisplayListHead++, dl_ia_text_end); - create_dl_translation_matrix(MENU_MTX_PUSH, ((index[0] - 1) * xIndex) + x, y + Y_VAL7, 0); + create_dl_translation_matrix(MENU_MTX_PUSH, ((*index - 1) * xIndex) + x, y + Y_VAL7, 0); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); gSPDisplayList(gDisplayListHead++, dl_draw_triangle); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); - switch (index[0]) { - case 1: - cam_select_alt_mode(1); + switch (*index) { + case CAM_SELECTION_MARIO: + cam_select_alt_mode(CAM_SELECTION_MARIO); break; - case 2: - cam_select_alt_mode(2); + case CAM_SELECTION_FIXED: + cam_select_alt_mode(CAM_SELECTION_FIXED); break; } } @@ -1538,18 +1702,18 @@ void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) { print_generic_string(x + 10, y - 2, textContinue); print_generic_string(x + 10, y - 17, textExitCourse); - if (index[0] != 3) { + if (*index != MENU_OPT_CAMERA_ANGLE_R) { print_generic_string(x + 10, y - 33, textCameraAngleR); gSPDisplayList(gDisplayListHead++, dl_ia_text_end); - create_dl_translation_matrix(MENU_MTX_PUSH, x - X_VAL8, (y - ((index[0] - 1) * yIndex)) - Y_VAL8, 0); + create_dl_translation_matrix(MENU_MTX_PUSH, x - X_VAL8, (y - ((*index - 1) * yIndex)) - Y_VAL8, 0); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); gSPDisplayList(gDisplayListHead++, dl_draw_triangle); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); } - if (index[0] == 3) { + if (*index == MENU_OPT_CAMERA_ANGLE_R) { render_pause_camera_options(x - 42, y - 42, &gDialogCameraAngleIndex, 110); } } @@ -1641,7 +1805,7 @@ void render_pause_castle_course_stars(s16 x, s16 y, s16 fileNum, s16 courseNum) } void render_pause_castle_main_strings(s16 x, s16 y) { - void **courseNameTbl = segmented_to_virtual(seg2_course_name_table); + void **courseNameTbl = segmented_to_virtual(languageTable[gInGameLanguage][1]); u8 textCoin[] = { TEXT_COIN_X }; @@ -1675,25 +1839,9 @@ void render_pause_castle_main_strings(s16 x, s16 y) { } } } -#ifdef WIDE - if (gPlayer1Controller->buttonPressed & L_TRIG){ - gWidescreen ^= 1; - } -#endif + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); -#ifdef WIDE - if (!gWidescreen) { - print_generic_string(10, 20, textCurrRatio43); - print_generic_string(10, 7, textPressL); - } - else { - print_generic_string(10, 20, textCurrRatio169); - print_generic_string(10, 7, textPressL); - print_generic_string(10, 220, textWideInfo); - print_generic_string(10, 200, textWideInfo2); - } -#endif if (gDialogLineNum < COURSE_STAGES_COUNT) { courseName = segmented_to_virtual(courseNameTbl[gDialogLineNum]); render_pause_castle_course_stars(x, y, gCurrSaveFileNum - 1, gDialogLineNum); @@ -1719,12 +1867,16 @@ s32 gCourseCompleteCoins = 0; s8 gHudFlash = 0; s16 render_pause_courses_and_castle(void) { - s16 num; - + s16 index; + #ifdef PUPPYCAM + puppycam_check_pause_buttons(); + if (!gPCOptionOpen) + { + #endif switch (gDialogBoxState) { case DIALOG_STATE_OPENING: - gDialogLineNum = 1; + gDialogLineNum = MENU_OPT_DEFAULT; gDialogTextAlpha = 0; level_set_transition(-1, NULL); play_sound(SOUND_MENU_PAUSE_HIGHPRIO, gGlobalSoundSource); @@ -1741,16 +1893,6 @@ s16 render_pause_courses_and_castle(void) { shade_screen(); render_pause_my_score_coins(); render_pause_red_coins(); - #ifdef WIDE - if (gPlayer1Controller->buttonPressed & L_TRIG){ - if (!gWidescreen){ - gWidescreen = 1; - } - else{ - gWidescreen = 0; - } - } - #endif #ifndef EXIT_COURSE_WHILE_MOVING s32 exitCheck = gMarioStates[0].action & ACT_FLAG_PAUSE_EXIT; #else @@ -1767,15 +1909,15 @@ s16 render_pause_courses_and_castle(void) { level_set_transition(0, NULL); play_sound(SOUND_MENU_PAUSE_2, gGlobalSoundSource); gDialogBoxState = DIALOG_STATE_OPENING; - gMenuMode = -1; + gMenuMode = MENU_MODE_NONE; - if (gDialogLineNum == 2) { - num = gDialogLineNum; - } else { - num = 1; + if (gDialogLineNum == MENU_OPT_EXIT_COURSE) { + index = gDialogLineNum; + } else { // MENU_OPT_CONTINUE or MENU_OPT_CAMERA_ANGLE_R + index = MENU_OPT_DEFAULT; } - return num; + return index; } break; case DIALOG_STATE_HORIZONTAL: @@ -1789,19 +1931,30 @@ s16 render_pause_courses_and_castle(void) { { level_set_transition(0, NULL); play_sound(SOUND_MENU_PAUSE_2, gGlobalSoundSource); - gMenuMode = -1; + gMenuMode = MENU_MODE_NONE; gDialogBoxState = DIALOG_STATE_OPENING; - return 1; + return MENU_OPT_DEFAULT; } break; } - + #if defined(WIDE) && !defined(PUPPYCAM) + render_widescreen_setting(); + #endif if (gDialogTextAlpha < 250) { gDialogTextAlpha += 25; } + #ifdef PUPPYCAM + } + else + { + shade_screen(); + puppycam_display_options(); + } - return 0; + puppycam_render_option_text(); + #endif + return MENU_OPT_NONE; } #define TXT_HISCORE_X 109 @@ -1895,8 +2048,8 @@ void render_course_complete_lvl_info_and_hud_str(void) { u8 strCourseNum[4]; - actNameTbl = segmented_to_virtual(seg2_act_name_table); - courseNameTbl = segmented_to_virtual(seg2_course_name_table); + actNameTbl = segmented_to_virtual(languageTable[gInGameLanguage][2]); + courseNameTbl = segmented_to_virtual(languageTable[gInGameLanguage][1]); if (gLastCompletedCourseNum <= COURSE_STAGES_MAX) { print_hud_course_complete_coins(118, 103); @@ -1972,7 +2125,7 @@ void render_save_confirmation(s16 x, s16 y, s8 *index, s16 sp6e) gSPDisplayList(gDisplayListHead++, dl_ia_text_end); - create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL9, y - ((index[0] - 1) * sp6e), 0); + create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL9, y - ((*index - 1) * sp6e), 0); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); gSPDisplayList(gDisplayListHead++, dl_draw_triangle); @@ -1981,7 +2134,7 @@ void render_save_confirmation(s16 x, s16 y, s8 *index, s16 sp6e) } s16 render_course_complete_screen(void) { - s16 num; + s16 index; switch (gDialogBoxState) { case DIALOG_STATE_OPENING: @@ -1990,7 +2143,7 @@ s16 render_course_complete_screen(void) { gDialogBoxState = DIALOG_STATE_VERTICAL; level_set_transition(-1, NULL); gDialogTextAlpha = 0; - gDialogLineNum = 1; + gDialogLineNum = MENU_OPT_DEFAULT; } break; case DIALOG_STATE_VERTICAL: @@ -2005,14 +2158,14 @@ s16 render_course_complete_screen(void) { level_set_transition(0, NULL); play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource); gDialogBoxState = DIALOG_STATE_OPENING; - gMenuMode = -1; - num = gDialogLineNum; + gMenuMode = MENU_MODE_NONE; + index = gDialogLineNum; gCourseDoneMenuTimer = 0; gCourseCompleteCoins = 0; gCourseCompleteCoinsEqual = 0; gHudFlash = 0; - return num; + return index; } break; } @@ -2023,41 +2176,40 @@ s16 render_course_complete_screen(void) { gCourseDoneMenuTimer++; - return 0; + return MENU_OPT_NONE; } -// Only case 1 and 2 are used s16 render_menus_and_dialogs(void) { - s16 mode = 0; + s16 index = MENU_OPT_NONE; create_dl_ortho_matrix(); - if (gMenuMode != -1) { + if (gMenuMode != MENU_MODE_NONE) { switch (gMenuMode) { - case 0: - mode = render_pause_courses_and_castle(); + case MENU_MODE_UNUSED_0: + index = render_pause_courses_and_castle(); break; - case 1: - mode = render_pause_courses_and_castle(); + case MENU_MODE_RENDER_PAUSE_SCREEN: + index = render_pause_courses_and_castle(); break; - case 2: - mode = render_course_complete_screen(); + case MENU_MODE_RENDER_COURSE_COMPLETE_SCREEN: + index = render_course_complete_screen(); break; - case 3: - mode = render_course_complete_screen(); + case MENU_MODE_UNUSED_3: + index = render_course_complete_screen(); break; } gDialogColorFadeTimer = (s16) gDialogColorFadeTimer + 0x1000; - } else if (gDialogID != -1) { + } else if (gDialogID != DIALOG_NONE) { // The Peach "Dear Mario" message needs to be repositioned separately - if (gDialogID == 20) { + if (gDialogID == DIALOG_020) { print_peach_letter_message(); - return mode; + return index; } render_dialog_entries(); gDialogColorFadeTimer = (s16) gDialogColorFadeTimer + 0x1000; } - return mode; + return index; } diff --git a/src/game/ingame_menu.h b/src/game/ingame_menu.h index c0e60da1..30c17aa3 100644 --- a/src/game/ingame_menu.h +++ b/src/game/ingame_menu.h @@ -27,12 +27,17 @@ #define HUD_LUT_DIFF HUD_LUT_GLOBAL #endif -#define RENDER_PAUSE_SCREEN 1 -#define RENDER_COURSE_DONE_SCREEN 2 - +enum MenuMode { + MENU_MODE_NONE = -1, + MENU_MODE_UNUSED_0, + MENU_MODE_RENDER_PAUSE_SCREEN, + MENU_MODE_RENDER_COURSE_COMPLETE_SCREEN, + MENU_MODE_UNUSED_3 +}; extern s8 gDialogCourseActNum; extern s8 gHudFlash; +extern s16 gInGameLanguage; struct DialogEntry { @@ -94,6 +99,7 @@ enum DialogSpecialChars { #endif DIALOG_CHAR_PERIOD = 0x6E, DIALOG_CHAR_COMMA = 0x6F, + DIALOG_CHAR_COLOR = 0xDF, DIALOG_CHAR_SPACE = 0x9E, DIALOG_CHAR_STAR_COUNT = 0xE0, // number of stars DIALOG_CHAR_UMLAUT = 0xE9, @@ -105,6 +111,14 @@ enum DialogSpecialChars { DIALOG_CHAR_TERMINATOR = 0xFF }; +// gDialogResponse +enum DialogResponseDefines { + DIALOG_RESPONSE_NONE, + DIALOG_RESPONSE_YES, + DIALOG_RESPONSE_NO, + DIALOG_RESPONSE_NOT_DEFINED +}; + extern s32 gDialogResponse; extern u16 gDialogColorFadeTimer; extern s8 gLastDialogLineNum; diff --git a/src/game/interaction.c b/src/game/interaction.c index 8deabb20..4990d0d0 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -337,7 +337,7 @@ void mario_stop_riding_and_holding(struct MarioState *m) { mario_stop_riding_object(m); if (m->action == ACT_RIDING_HOOT) { - m->usedObj->oInteractStatus = 0; + m->usedObj->oInteractStatus = FALSE; m->usedObj->oHootMarioReleaseTime = gGlobalTimer; } } @@ -527,7 +527,7 @@ void hit_object_from_below(struct MarioState *m, UNUSED struct Object *o) { set_camera_shake_from_hit(SHAKE_HIT_FROM_BELOW); } -static u32 unused_determine_knockback_action(struct MarioState *m) { +UNUSED static u32 unused_determine_knockback_action(struct MarioState *m) { u32 bonkAction; s16 angleToObject = mario_obj_angle_to_object(m, m->interactObj); s16 facingDYaw = angleToObject - m->faceAngle[1]; @@ -1109,7 +1109,7 @@ u32 interact_tornado(struct MarioState *m, UNUSED u32 interactType, struct Objec marioObj->oMarioTornadoPosY = m->pos[1] - o->oPosY; play_sound(SOUND_MARIO_WAAAOOOW, m->marioObj->header.gfx.cameraToObject); -#ifdef VERSION_SH +#if ENABLE_RUMBLE queue_rumble_data(30, 60); #endif return set_mario_action(m, ACT_TORNADO_TWIRLING, m->action == ACT_TWIRLING); @@ -1310,7 +1310,7 @@ u32 interact_shock(struct MarioState *m, UNUSED u32 interactType, struct Object return FALSE; } -static u32 interact_stub(UNUSED struct MarioState *m, UNUSED u32 interactType, struct Object *o) { +UNUSED static u32 interact_stub(UNUSED struct MarioState *m, UNUSED u32 interactType, struct Object *o) { if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { sDelayInvincTimer = TRUE; } @@ -1575,7 +1575,8 @@ u32 interact_hoot(struct MarioState *m, UNUSED u32 interactType, struct Object * if (actionId >= 0x080 && actionId < 0x098 && (gGlobalTimer - m->usedObj->oHootMarioReleaseTime > 30)) { mario_stop_riding_and_holding(m); - o->oInteractStatus = INT_STATUS_HOOT_GRABBED_BY_MARIO; + + o->oInteractStatus = TRUE; //! Note: Not a flag, treated as a TRUE/FALSE statement m->interactObj = o; m->usedObj = o; @@ -1792,7 +1793,7 @@ void mario_process_interactions(struct MarioState *m) { if (!(m->action & ACT_FLAG_INTANGIBLE) && m->collidedObjInteractTypes != 0) { s32 i; - for (i = 0; i < 31; i++) { + for (i = 0; i < ARRAY_COUNT(sInteractionHandlers); i++) { u32 interactType = sInteractionHandlers[i].interactType; if (m->collidedObjInteractTypes & interactType) { struct Object *object = mario_get_collided_object(m, interactType); diff --git a/src/game/interaction.h b/src/game/interaction.h index dd27aad8..1b2457be 100644 --- a/src/game/interaction.h +++ b/src/game/interaction.h @@ -80,18 +80,25 @@ #define INT_STATUS_ATTACK_MASK 0x000000FF -#define INT_STATUS_HOOT_GRABBED_BY_MARIO (1 << 0) /* 0x00000001 */ -#define INT_STATUS_MARIO_UNK1 (1 << 1) /* 0x00000002 */ +// Mario Interaction Status +#define INT_STATUS_MARIO_STUNNED (1 << 0) /* 0x00000001 */ +#define INT_STATUS_MARIO_KNOCKBACK_DMG (1 << 1) /* 0x00000002 */ #define INT_STATUS_MARIO_UNK2 (1 << 2) /* 0x00000004 */ #define INT_STATUS_MARIO_DROP_OBJECT (1 << 3) /* 0x00000008 */ -#define INT_STATUS_HIT_BY_SHOCKWAVE (1 << 4) /* 0x00000010 */ +#define INT_STATUS_MARIO_SHOCKWAVE (1 << 4) /* 0x00000010 */ #define INT_STATUS_MARIO_UNK5 (1 << 5) /* 0x00000020 */ #define INT_STATUS_MARIO_UNK6 (1 << 6) /* 0x00000040 */ #define INT_STATUS_MARIO_UNK7 (1 << 7) /* 0x00000080 */ + +// Object Interaction Status #define INT_STATUS_GRABBED_MARIO (1 << 11) /* 0x00000800 */ #define INT_STATUS_ATTACKED_MARIO (1 << 13) /* 0x00002000 */ #define INT_STATUS_WAS_ATTACKED (1 << 14) /* 0x00004000 */ #define INT_STATUS_INTERACTED (1 << 15) /* 0x00008000 */ +#define INT_STATUS_DOOR_PULLED (1 << 16) /* 0x00010000 */ +#define INT_STATUS_DOOR_PUSHED (1 << 17) /* 0x00020000 */ +#define INT_STATUS_WARP_DOOR_PULLED (1 << 18) /* 0x00040000 */ +#define INT_STATUS_WARP_DOOR_PUSHED (1 << 19) /* 0x00080000 */ #define INT_STATUS_TRAP_TURN (1 << 20) /* 0x00100000 */ #define INT_STATUS_HIT_MINE (1 << 21) /* 0x00200000 */ #define INT_STATUS_STOP_RIDING (1 << 22) /* 0x00400000 */ diff --git a/src/game/level_geo.c b/src/game/level_geo.c index 1fc4b88e..113bcd1a 100644 --- a/src/game/level_geo.c +++ b/src/game/level_geo.c @@ -40,7 +40,7 @@ Gfx *geo_envfx_main(s32 callContext, struct GraphNode *node, Mat4 mtxf) { mtxf_to_mtx(mtx, mtxf); gSPMatrix(&gfx[0], VIRTUAL_TO_PHYSICAL(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); gSPBranchList(&gfx[1], VIRTUAL_TO_PHYSICAL(particleList)); - execNode->fnNode.node.flags = (execNode->fnNode.node.flags & 0xFF) | 0x400; + execNode->fnNode.node.flags = (execNode->fnNode.node.flags & 0xFF) | (LAYER_ALPHA << 8); } SET_HIGH_U16_OF_32(*params, gAreaUpdateCounter); } @@ -70,9 +70,11 @@ Gfx *geo_skybox_main(s32 callContext, struct GraphNode *node, UNUSED Mat4 *mtx) struct GraphNodePerspective *camFrustum = (struct GraphNodePerspective *) camNode->fnNode.node.parent; +#ifndef L3DEX2_ALONE gfx = create_skybox_facing_camera(0, backgroundNode->background, camFrustum->fov, gLakituState.pos[0], gLakituState.pos[1], gLakituState.pos[2], gLakituState.focus[0], gLakituState.focus[1], gLakituState.focus[2]); +#endif } return gfx; diff --git a/src/game/level_update.c b/src/game/level_update.c index 97722822..5d8e1bf5 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -20,7 +20,7 @@ #include "obj_behaviors.h" #include "save_file.h" #include "debug_course.h" -#ifdef VERSION_EU +#if MULTILANG #include "memory.h" #include "eu_translation.h" #include "segment_symbols.h" @@ -28,6 +28,8 @@ #include "level_table.h" #include "course_table.h" #include "rumble_init.h" +#include "puppycam2.h" +#include "puppyprint.h" #include "config.h" @@ -214,10 +216,10 @@ u16 level_control_timer(s32 timerOp) { } u32 pressed_pause(void) { - u32 val4 = get_dialog_id() >= 0; + u32 dialogActive = get_dialog_id() >= 0; u32 intangible = (gMarioState->action & ACT_FLAG_INTANGIBLE) != 0; - if (!intangible && !val4 && !gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE + if (!intangible && !dialogActive && !gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE && (gPlayer1Controller->buttonPressed & START_BUTTON)) { return TRUE; } @@ -268,7 +270,7 @@ void load_level_init_text(u32 arg) { gotAchievement = save_file_get_flags() & SAVE_FLAG_HAVE_WING_CAP; break; - case 255: + case (u8)DIALOG_NONE: // 255, cast value to u8 to match (-1) gotAchievement = TRUE; break; @@ -492,7 +494,7 @@ void warp_level(void) { } void warp_credits(void) { - s32 marioAction; + s32 marioAction = 0; switch (sWarpDest.nodeId) { case WARP_NODE_CREDITS_START: @@ -562,7 +564,7 @@ void check_instant_warp(void) { #ifdef INSTANT_WARP_OFFSET_FIX gMarioObject->header.gfx.pos[0] = gMarioState->pos[0]; gMarioObject->header.gfx.pos[1] = gMarioState->pos[1]; - gMarioObject->header.gfx.pos[2] = gMarioState->pos[2]; + gMarioObject->header.gfx.pos[2] = gMarioState->pos[2]; #endif cameraAngle = gMarioState->area->camera->yaw; @@ -640,6 +642,18 @@ void initiate_warp(s16 destLevel, s16 destArea, s16 destWarpNode, s32 arg3) { sWarpDest.areaIdx = destArea; sWarpDest.nodeId = destWarpNode; sWarpDest.arg = arg3; + + #ifdef PUPPYCAM + s32 i = 0; + if (sWarpDest.type != WARP_TYPE_SAME_AREA) + { + for (i = 0; i < gPuppyVolumeCount; i++) + { + mem_pool_free(gPuppyMemoryPool, sPuppyVolumeStack[i]); + } + gPuppyVolumeCount = 0; + } + #endif } // From Surface 0xD3 to 0xFC @@ -1029,15 +1043,13 @@ s32 play_mode_normal(void) { } s32 play_mode_paused(void) { - if (gPauseScreenMode == 0) { - set_menu_mode(RENDER_PAUSE_SCREEN); - } else if (gPauseScreenMode == 1) { + if (gMenuOptSelectIndex == MENU_OPT_NONE) { + set_menu_mode(MENU_MODE_RENDER_PAUSE_SCREEN); + } else if (gMenuOptSelectIndex == MENU_OPT_DEFAULT) { raise_background_noise(1); gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; set_play_mode(PLAY_MODE_NORMAL); - } else { - // Exit level - + } else { // MENU_OPT_EXIT_COURSE if (gDebugLevelSelect) { fade_into_special_warp(-9, 1); } else { @@ -1131,7 +1143,7 @@ s32 play_mode_change_level(void) { /** * Unused play mode. Doesn't call transition update and doesn't reset transition at the end. */ -static s32 play_mode_unused(void) { +UNUSED static s32 play_mode_unused(void) { if (--sTransitionTimer == -1) { gHudDisplay.flags = HUD_DISPLAY_NONE; @@ -1146,7 +1158,7 @@ static s32 play_mode_unused(void) { } s32 update_level(void) { - s32 changeLevel; + s32 changeLevel = FALSE; switch (sCurrPlayMode) { case PLAY_MODE_NORMAL: @@ -1176,6 +1188,10 @@ s32 update_level(void) { s32 init_level(void) { s32 val4 = 0; + #if PUPPYPRINT_DEBUG + char textBytes[64]; + OSTime first = osGetTime(); + #endif set_play_mode(PLAY_MODE_NORMAL); @@ -1249,6 +1265,10 @@ s32 init_level(void) { sound_banks_disable(SEQ_PLAYER_SFX, SOUND_BANKS_DISABLED_DURING_INTRO_CUTSCENE); } + #if PUPPYPRINT_DEBUG + sprintf(textBytes, "Level loaded in %dus", (s32)(OS_CYCLES_TO_USEC(osGetTime() - first))); + append_puppyprint_log(textBytes); + #endif return 1; } @@ -1270,23 +1290,28 @@ s32 lvl_init_or_update(s16 initOrUpdate, UNUSED s32 unused) { return result; } -s32 lvl_init_from_save_file(UNUSED s16 arg0, s32 levelNum) { -#ifdef VERSION_EU - s16 var = eu_get_language(); - switch (var) { +#if MULTILANG +void load_language_text(void) +{ + switch (gInGameLanguage-1) + { case LANGUAGE_ENGLISH: - load_segment_decompress(0x19, _translation_en_yay0SegmentRomStart, - _translation_en_yay0SegmentRomEnd); + load_segment_decompress(0x19, _translation_en_yay0SegmentRomStart, _translation_en_yay0SegmentRomEnd); break; case LANGUAGE_FRENCH: - load_segment_decompress(0x19, _translation_fr_yay0SegmentRomStart, - _translation_fr_yay0SegmentRomEnd); + load_segment_decompress(0x19, _translation_fr_yay0SegmentRomStart, _translation_fr_yay0SegmentRomEnd); break; case LANGUAGE_GERMAN: - load_segment_decompress(0x19, _translation_de_yay0SegmentRomStart, - _translation_de_yay0SegmentRomEnd); + load_segment_decompress(0x19, _translation_de_yay0SegmentRomStart, _translation_de_yay0SegmentRomEnd); break; } +} +#endif + +s32 lvl_init_from_save_file(UNUSED s16 arg0, s32 levelNum) { +#if MULTILANG + gInGameLanguage = eu_get_language()+1; + load_language_text(); #endif sWarpDest.type = WARP_TYPE_NOT_WARPING; sDelayedWarpOp = WARP_OP_NONE; diff --git a/src/game/level_update.h b/src/game/level_update.h index 521b4efe..8080d2dc 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -70,6 +70,7 @@ extern u16 D_80339ECA; extern s16 sTransitionTimer; extern void (*sTransitionUpdate)(s16 *); extern u8 unused3[4]; +extern void load_language_text(void); struct WarpDest { u8 type; diff --git a/src/game/macro_special_objects.c b/src/game/macro_special_objects.c index 7f03f97a..94dbac9a 100644 --- a/src/game/macro_special_objects.c +++ b/src/game/macro_special_objects.c @@ -79,7 +79,7 @@ void spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s newObj->oMacroUnk110 = (f32) unkC; } -static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 a1[]) { +UNUSED static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 a1[]) { struct Object *sp3C; s16 model; @@ -104,7 +104,7 @@ struct LoadedPreset { #define MACRO_OBJ_Z 3 #define MACRO_OBJ_PARAMS 4 -void spawn_macro_objects(s16 areaIndex, s16 *macroObjList) { +void spawn_macro_objects(s32 areaIndex, s16 *macroObjList) { UNUSED u32 pad5C; s32 presetID; @@ -171,7 +171,7 @@ void spawn_macro_objects(s16 areaIndex, s16 *macroObjList) { } } -void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList) { +void spawn_macro_objects_hardcoded(s32 areaIndex, s16 *macroObjList) { UNUSED u8 pad[8]; // This version of macroObjList has the preset and Y-Rotation separated, @@ -203,7 +203,7 @@ void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList) { // However, BBH doesn't use this function so this might just be an early test? switch (macroObjPreset) { case 0: - spawn_macro_abs_yrot_2params(MODEL_NONE, bhvBooBossSpawnedBridge, macroObjX, macroObjY, + spawn_macro_abs_yrot_2params(MODEL_NONE, bhvBooStaircase, macroObjX, macroObjY, macroObjZ, macroObjRY, 0); break; case 1: @@ -237,7 +237,7 @@ void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList) { } } -void spawn_special_objects(s16 areaIndex, s16 **specialObjList) { +void spawn_special_objects(s32 areaIndex, TerrainData **specialObjList) { s32 numOfSpecialObjects; s32 i; s32 offset; diff --git a/src/game/macro_special_objects.h b/src/game/macro_special_objects.h index d8bdc237..1996aac5 100644 --- a/src/game/macro_special_objects.h +++ b/src/game/macro_special_objects.h @@ -11,9 +11,9 @@ void spawn_macro_abs_yrot_2params(s32 model, const BehaviorScript *behavior, s16 void spawn_macro_abs_yrot_param1(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 ry, s16 params); void spawn_macro_abs_special(s32 model, const BehaviorScript *behavior, s16 x, s16 y, s16 z, s16 unkA, s16 unkB, s16 unkC); -void spawn_macro_objects(s16 areaIndex, s16 *macroObjList); -void spawn_macro_objects_hardcoded(s16 areaIndex, s16 *macroObjList); -void spawn_special_objects(s16 areaIndex, s16 **specialObjList); +void spawn_macro_objects(s32 areaIndex, s16 *macroObjList); +void spawn_macro_objects_hardcoded(s32 areaIndex, s16 *macroObjList); +void spawn_special_objects(s32 areaIndex, TerrainData **specialObjList); #ifdef NO_SEGMENTED_MEMORY u32 get_special_objects_size(s16 *data); #endif diff --git a/src/game/main.h b/src/game/main.h index 7fe41491..ddb7d02a 100644 --- a/src/game/main.h +++ b/src/game/main.h @@ -1,7 +1,7 @@ #ifndef MAIN_H #define MAIN_H -#include +#include "config.h" struct RumbleData { u8 unk00; @@ -46,7 +46,7 @@ extern OSMesg gSIEventMesgBuf[1]; extern OSMesg gIntrMesgBuf[16]; extern OSMesg gUnknownMesgBuf[16]; extern OSIoMesg gDmaIoMesg; -extern OSMesg D_80339BEC; +extern OSMesg gMainReceivedMesg; extern OSMesgQueue gDmaMesgQueue; extern OSMesgQueue gSIEventMesgQueue; #if ENABLE_RUMBLE @@ -62,13 +62,13 @@ extern struct VblankHandler *gVblankHandler2; extern struct SPTask *gActiveSPTask; extern u32 gNumVblanks; extern s8 gResetTimer; -extern s8 D_8032C648; +extern s8 gNmiResetBarsTimer; extern s8 gDebugLevelSelect; extern s8 gShowProfiler; extern s8 gShowDebugText; void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *queue, OSMesg *msg); void dispatch_audio_sptask(struct SPTask *spTask); -void send_display_list(struct SPTask *spTask); +void exec_display_list(struct SPTask *spTask); #endif // MAIN_H diff --git a/src/game/mario.c b/src/game/mario.c index 597ddc8d..31e97bce 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -63,9 +63,9 @@ s32 is_anim_past_end(struct MarioState *m) { */ s16 set_mario_animation(struct MarioState *m, s32 targetAnimID) { struct Object *o = m->marioObj; - struct Animation *targetAnim = m->animation->targetAnim; + struct Animation *targetAnim = m->animList->bufTarget; - if (load_patchable_table(m->animation, targetAnimID)) { + if (load_patchable_table(m->animList, targetAnimID)) { targetAnim->values = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->values); targetAnim->index = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->index); } @@ -96,9 +96,9 @@ s16 set_mario_animation(struct MarioState *m, s32 targetAnimID) { */ s16 set_mario_anim_with_accel(struct MarioState *m, s32 targetAnimID, s32 accel) { struct Object *o = m->marioObj; - struct Animation *targetAnim = m->animation->targetAnim; + struct Animation *targetAnim = m->animList->bufTarget; - if (load_patchable_table(m->animation, targetAnimID)) { + if (load_patchable_table(m->animList, targetAnimID)) { targetAnim->values = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->values); targetAnim->index = (void *) VIRTUAL_TO_PHYSICAL((u8 *) targetAnim + (uintptr_t) targetAnim->index); } @@ -1283,6 +1283,23 @@ void update_mario_button_inputs(struct MarioState *m) { m->input |= INPUT_A_DOWN; } +#ifdef CUSTOM_DEBUG + if (m->controller->buttonPressed & L_JPAD) { + gCustomDebugMode ^= 1; + } + if (gCustomDebugMode) { + if (m->controller->buttonPressed & R_JPAD) { + if (gMarioState->action == ACT_DEBUG_FREE_MOVE) { + set_mario_action(gMarioState, ACT_IDLE, 0); + } else { + set_mario_action(gMarioState, ACT_DEBUG_FREE_MOVE, 0); + } + } + } else if (gMarioState->action == ACT_DEBUG_FREE_MOVE) { + set_mario_action(gMarioState, ACT_IDLE, 0); + } +#endif + // Don't update for these buttons if squished. if (m->squishTimer == 0) { if (m->controller->buttonPressed & B_BUTTON) { @@ -1400,6 +1417,14 @@ void update_mario_inputs(struct MarioState *m) { m->collidedObjInteractTypes = m->marioObj->collidedObjInteractTypes; m->flags &= 0xFFFFFF; + #ifdef PUPPYCAM + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ENTER_FIRST_PERSON) + { + m->input = INPUT_FIRST_PERSON; + return; + } + #endif + update_mario_button_inputs(m); update_mario_joystick_inputs(m); update_mario_geometry_inputs(m); @@ -1418,9 +1443,10 @@ void update_mario_inputs(struct MarioState *m) { m->input |= INPUT_UNKNOWN_5; } + // These 3 flags are defined by Bowser stomping attacks if (m->marioObj->oInteractStatus - & (INT_STATUS_HOOT_GRABBED_BY_MARIO | INT_STATUS_MARIO_UNK1 | INT_STATUS_HIT_BY_SHOCKWAVE)) { - m->input |= INPUT_UNKNOWN_10; + & (INT_STATUS_MARIO_STUNNED | INT_STATUS_MARIO_KNOCKBACK_DMG | INT_STATUS_MARIO_SHOCKWAVE)) { + m->input |= INPUT_STOMPED; } // This function is located near other unused trampoline functions, @@ -1685,7 +1711,7 @@ void mario_update_hitbox_and_cap_model(struct MarioState *m) { * An unused and possibly a debug function. Z + another button input * sets Mario with a different cap. */ -static void debug_update_mario_cap(u16 button, s32 flags, u16 capTimer, u16 capMusic) { +UNUSED static void debug_update_mario_cap(u16 button, s32 flags, u16 capTimer, u16 capMusic) { // This checks for Z_TRIG instead of Z_DOWN flag // (which is also what other debug functions do), // so likely debug behavior rather than unused behavior. @@ -1899,7 +1925,7 @@ void init_mario_from_save_file(void) { gMarioState->statusForCamera = &gPlayerCameraState[0]; gMarioState->marioBodyState = &gBodyStates[0]; gMarioState->controller = &gControllers[0]; - gMarioState->animation = &D_80339D10; + gMarioState->animList = &gMarioAnimsBuf; gMarioState->numCoins = 0; gMarioState->numStars = diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 83a1ff7e..ce6467ef 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -61,14 +61,20 @@ s32 lava_boost_on_wall(struct MarioState *m) { } s32 check_fall_damage(struct MarioState *m, u32 hardFallAction) { -#ifndef NO_FALL_DAMAGE f32 fallHeight; f32 damageHeight; +#ifdef NO_FALL_DAMAGE + return FALSE; +#endif fallHeight = m->peakHeight - m->pos[1]; #pragma GCC diagnostic push +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" +#elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wtype-limits" +#endif //! Never true if (m->actionState == ACT_GROUND_POUND) { @@ -100,7 +106,7 @@ s32 check_fall_damage(struct MarioState *m, u32 hardFallAction) { } } } -#endif + return FALSE; } @@ -522,7 +528,7 @@ s32 act_backflip(struct MarioState *m) { } s32 act_freefall(struct MarioState *m) { - s32 animation; + s32 animation = 0; if (m->input & INPUT_B_PRESSED) { return set_mario_action(m, ACT_DIVE, 0); @@ -1030,7 +1036,7 @@ s32 act_burning_fall(struct MarioState *m) { } s32 act_crazy_box_bounce(struct MarioState *m) { - f32 minSpeed; + f32 minSpeed = 0.0f; if (m->actionTimer == 0) { switch (m->actionArg) { @@ -1515,11 +1521,11 @@ s32 act_hold_butt_slide_air(struct MarioState *m) { s32 act_lava_boost(struct MarioState *m) { #if ENABLE_RUMBLE if (!(m->flags & MARIO_MARIO_SOUND_PLAYED)) { +#endif play_sound_if_no_flag(m, SOUND_MARIO_ON_FIRE, MARIO_MARIO_SOUND_PLAYED); +#if ENABLE_RUMBLE queue_rumble_data(5, 80); } -#else - play_sound_if_no_flag(m, SOUND_MARIO_ON_FIRE, MARIO_MARIO_SOUND_PLAYED); #endif if (!(m->input & INPUT_NONZERO_ANALOG)) { @@ -2065,7 +2071,7 @@ s32 check_common_airborne_cancels(struct MarioState *m) { } s32 mario_execute_airborne_action(struct MarioState *m) { - u32 cancel; + u32 cancel = FALSE; if (check_common_airborne_cancels(m)) { return TRUE; diff --git a/src/game/mario_actions_automatic.c b/src/game/mario_actions_automatic.c index 769b653b..5a023eb8 100644 --- a/src/game/mario_actions_automatic.c +++ b/src/game/mario_actions_automatic.c @@ -17,6 +17,8 @@ #include "level_table.h" #include "rumble_init.h" +#include "config.h" + #define POLE_NONE 0 #define POLE_TOUCHED_FLOOR 1 #define POLE_FELL_OFF 2 @@ -345,7 +347,7 @@ s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) { s32 update_hang_moving(struct MarioState *m) { s32 stepResult; Vec3f nextPos; - f32 maxSpeed = 4.0f; + f32 maxSpeed = HANGING_SPEED; m->forwardVel += 1.0f; if (m->forwardVel > maxSpeed) { @@ -353,7 +355,11 @@ s32 update_hang_moving(struct MarioState *m) { } m->faceAngle[1] = + #ifdef TIGHTER_HANGING_CONTROLS + m->intendedYaw; + #else m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800); + #endif m->slideYaw = m->faceAngle[1]; m->slideVelX = m->forwardVel * sins(m->faceAngle[1]); @@ -563,8 +569,8 @@ s32 act_ledge_grab(struct MarioState *m) { return set_mario_action(m, ACT_LEDGE_CLIMB_FAST, 0); } - if (m->input & INPUT_UNKNOWN_10) { - if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK1) { + if (m->input & INPUT_STOMPED) { + if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_KNOCKBACK_DMG) { m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18; } return let_go_of_ledge(m); @@ -854,7 +860,7 @@ s32 check_common_automatic_cancels(struct MarioState *m) { } s32 mario_execute_automatic_action(struct MarioState *m) { - s32 cancel; + s32 cancel = FALSE; if (check_common_automatic_cancels(m)) { return TRUE; diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 1e6d7135..07458cff 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -18,6 +18,7 @@ #include "level_table.h" #include "level_update.h" #include "mario.h" +#include "mario_actions_cutscene.h" #include "mario_actions_moving.h" #include "mario_step.h" #include "moving_texture.h" @@ -28,9 +29,6 @@ #include "sound_init.h" #include "rumble_init.h" -// TODO: put this elsewhere -enum SaveOption { SAVE_OPT_SAVE_AND_CONTINUE = 1, SAVE_OPT_SAVE_AND_QUIT, SAVE_OPT_CONTINUE_DONT_SAVE }; - static struct Object *sIntroWarpPipeObj; static struct Object *sEndPeachObj; static struct Object *sEndRightToadObj; @@ -216,9 +214,9 @@ s32 geo_switch_peach_eyes(s32 run, struct GraphNode *node, UNUSED s32 a2) { } // unused -static void stub_is_textbox_active(u16 *a0) { - if (get_dialog_id() == -1) { - *a0 = 0; +UNUSED static void stub_is_textbox_active(u16 *arg) { + if (get_dialog_id() == DIALOG_NONE) { + *arg = 0; } } @@ -250,23 +248,23 @@ s32 get_star_collection_dialog(struct MarioState *m) { void handle_save_menu(struct MarioState *m) { s32 dialogID; // wait for the menu to show up - if (is_anim_past_end(m) && gSaveOptSelectIndex != 0) { + if (is_anim_past_end(m) && gSaveOptSelectIndex != MENU_OPT_NONE) { // save and continue / save and quit - if (gSaveOptSelectIndex == SAVE_OPT_SAVE_AND_CONTINUE || gSaveOptSelectIndex == SAVE_OPT_SAVE_AND_QUIT) { + if (gSaveOptSelectIndex == MENU_OPT_SAVE_AND_CONTINUE || gSaveOptSelectIndex == MENU_OPT_SAVE_AND_QUIT) { save_file_do_save(gCurrSaveFileNum - 1); - if (gSaveOptSelectIndex == SAVE_OPT_SAVE_AND_QUIT) { + if (gSaveOptSelectIndex == MENU_OPT_SAVE_AND_QUIT) { fade_into_special_warp(-2, 0); // reset game } } // not quitting - if (gSaveOptSelectIndex != SAVE_OPT_SAVE_AND_QUIT) { + if (gSaveOptSelectIndex != MENU_OPT_SAVE_AND_QUIT) { disable_time_stop(); m->faceAngle[1] += 0x8000; // figure out what dialog to show, if we should dialogID = get_star_collection_dialog(m); - if (dialogID != 0) { + if (dialogID) { play_peachs_jingle(); // look up for dialog set_mario_action(m, ACT_READING_AUTOMATIC_DIALOG, dialogID); @@ -345,24 +343,24 @@ s32 mario_ready_to_speak(void) { // 1 = starting dialog // 2 = speaking s32 set_mario_npc_dialog(s32 actionArg) { - s32 dialogState = 0; + s32 dialogState = MARIO_DIALOG_STATUS_NONE; // in dialog if (gMarioState->action == ACT_READING_NPC_DIALOG) { if (gMarioState->actionState < 8) { - dialogState = 1; // starting dialog + dialogState = MARIO_DIALOG_STATUS_START; // starting dialog } if (gMarioState->actionState == 8) { - if (actionArg == 0) { + if (actionArg == MARIO_DIALOG_STOP) { gMarioState->actionState++; // exit dialog } else { - dialogState = 2; + dialogState = MARIO_DIALOG_STATUS_SPEAK; } } } else if (actionArg != 0 && mario_ready_to_speak()) { gMarioState->usedObj = gCurrentObject; set_mario_action(gMarioState, ACT_READING_NPC_DIALOG, actionArg); - dialogState = 1; // starting dialog + dialogState = MARIO_DIALOG_STATUS_START; // starting dialog } return dialogState; @@ -381,10 +379,10 @@ s32 act_reading_npc_dialog(struct MarioState *m) { s32 headTurnAmount = 0; s16 angleToNPC; - if (m->actionArg == 2) { + if (m->actionArg == MARIO_DIALOG_LOOK_UP) { headTurnAmount = -1024; } - if (m->actionArg == 3) { + if (m->actionArg == MARIO_DIALOG_LOOK_DOWN) { headTurnAmount = 384; } @@ -621,8 +619,8 @@ void general_star_dance_handler(struct MarioState *m, s32 isInWater) { } break; } - } else if (m->actionState == 1 && gDialogResponse) { - if (gDialogResponse == 1) { + } else if (m->actionState == 1 && gDialogResponse != DIALOG_RESPONSE_NONE) { + if (gDialogResponse == DIALOG_RESPONSE_YES) { save_file_do_save(gCurrSaveFileNum - 1); } m->actionState = 2; @@ -630,7 +628,7 @@ void general_star_dance_handler(struct MarioState *m, s32 isInWater) { disable_time_stop(); enable_background_sound(); dialogID = get_star_collection_dialog(m); - if (dialogID != 0) { + if (dialogID) { // look up for dialog set_mario_action(m, ACT_READING_AUTOMATIC_DIALOG, dialogID); } else { @@ -863,7 +861,7 @@ s32 act_entering_star_door(struct MarioState *m) { s16 targetAngle; if (m->actionTimer++ == 0) { - m->interactObj->oInteractStatus = 0x00010000; + m->interactObj->oInteractStatus = INT_STATUS_DOOR_PULLED; // ~30 degrees / 1/12 rot targetAngle = m->usedObj->oMoveAngleYaw + 0x1555; @@ -921,10 +919,10 @@ s32 act_entering_star_door(struct MarioState *m) { s32 act_going_through_door(struct MarioState *m) { if (m->actionTimer == 0) { if (m->actionArg & 1) { - m->interactObj->oInteractStatus = 0x00010000; + m->interactObj->oInteractStatus = INT_STATUS_DOOR_PULLED; set_mario_animation(m, MARIO_ANIM_PULL_DOOR_WALK_IN); } else { - m->interactObj->oInteractStatus = 0x00020000; + m->interactObj->oInteractStatus = INT_STATUS_DOOR_PUSHED; set_mario_animation(m, MARIO_ANIM_PUSH_DOOR_WALK_IN); } } @@ -954,9 +952,9 @@ s32 act_warp_door_spawn(struct MarioState *m) { if (m->actionState == 0) { m->actionState = 1; if (m->actionArg & 1) { - m->usedObj->oInteractStatus = 0x00040000; + m->usedObj->oInteractStatus = INT_STATUS_WARP_DOOR_PULLED; } else { - m->usedObj->oInteractStatus = 0x00080000; + m->usedObj->oInteractStatus = INT_STATUS_WARP_DOOR_PUSHED; } } else if (m->usedObj->oAction == 0) { if (gNeverEnteredCastle == TRUE && gCurrLevelNum == LEVEL_CASTLE) { @@ -1087,8 +1085,8 @@ s32 act_exit_land_save_dialog(struct MarioState *m) { enable_time_stop(); } - set_menu_mode(RENDER_COURSE_DONE_SCREEN); - gSaveOptSelectIndex = 0; + set_menu_mode(MENU_MODE_RENDER_COURSE_COMPLETE_SCREEN); + gSaveOptSelectIndex = MENU_OPT_NONE; m->actionState = 3; // star exit with cap if (!(m->flags & MARIO_CAP_ON_HEAD)) { diff --git a/src/game/mario_actions_cutscene.h b/src/game/mario_actions_cutscene.h index 276826cf..31a8b5d3 100644 --- a/src/game/mario_actions_cutscene.h +++ b/src/game/mario_actions_cutscene.h @@ -6,6 +6,17 @@ #include "macros.h" #include "types.h" +// set_mario_npc_dialog +// actionArg +#define MARIO_DIALOG_STOP 0 +#define MARIO_DIALOG_LOOK_FRONT 1 // no head turn +#define MARIO_DIALOG_LOOK_UP 2 +#define MARIO_DIALOG_LOOK_DOWN 3 +// dialogState +#define MARIO_DIALOG_STATUS_NONE 0 +#define MARIO_DIALOG_STATUS_START 1 +#define MARIO_DIALOG_STATUS_SPEAK 2 + void print_displaying_credits_entry(void); void bhv_end_peach_loop(void); void bhv_end_toad_loop(void); diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 8e184d4e..b6248cbb 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -389,6 +389,7 @@ void update_shell_speed(struct MarioState *m) { m->faceAngle[1] = m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800); + apply_slope_accel(m); } @@ -460,9 +461,13 @@ void update_walking_speed(struct MarioState *m) { if (m->forwardVel > 48.0f) { m->forwardVel = 48.0f; } - + +#ifdef SUPER_RESPONSIVE_CONTROLS + m->faceAngle[1] = m->intendedYaw; +#else m->faceAngle[1] = m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800); +#endif apply_slope_accel(m); } @@ -1287,6 +1292,7 @@ s32 act_crawling(struct MarioState *m) { mario_set_forward_vel(m, 10.0f); } //! Possibly unintended missing break + // fall through case GROUND_STEP_NONE: align_with_floor(m); @@ -1957,7 +1963,7 @@ s32 check_common_moving_cancels(struct MarioState *m) { return set_water_plunge_action(m); } - if (!(m->action & ACT_FLAG_INVULNERABLE) && (m->input & INPUT_UNKNOWN_10)) { + if (!(m->action & ACT_FLAG_INVULNERABLE) && (m->input & INPUT_STOMPED)) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } diff --git a/src/game/mario_actions_object.c b/src/game/mario_actions_object.c index 50638024..91b04a31 100644 --- a/src/game/mario_actions_object.c +++ b/src/game/mario_actions_object.c @@ -37,7 +37,7 @@ s32 mario_update_punch_sequence(struct MarioState *m) { switch (m->actionArg) { case 0: play_sound(SOUND_MARIO_PUNCH_YAH, m->marioObj->header.gfx.cameraToObject); - // Fall-through: + // fall through case 1: set_mario_animation(m, MARIO_ANIM_FIRST_PUNCH); if (is_anim_past_end(m)) { @@ -77,7 +77,7 @@ s32 mario_update_punch_sequence(struct MarioState *m) { case 3: play_sound(SOUND_MARIO_PUNCH_WAH, m->marioObj->header.gfx.cameraToObject); - // Fall-through: + // fall through case 4: set_mario_animation(m, MARIO_ANIM_SECOND_PUNCH); if (is_anim_past_end(m)) { @@ -145,7 +145,7 @@ s32 mario_update_punch_sequence(struct MarioState *m) { } s32 act_punching(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -173,7 +173,7 @@ s32 act_punching(struct MarioState *m) { } s32 act_picking_up(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -211,7 +211,7 @@ s32 act_picking_up(struct MarioState *m) { } s32 act_dive_picking_up(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -231,7 +231,7 @@ s32 act_dive_picking_up(struct MarioState *m) { } s32 act_placing_down(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -252,7 +252,7 @@ s32 act_throwing(struct MarioState *m) { return set_mario_action(m, ACT_PLACING_DOWN, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -274,7 +274,7 @@ s32 act_throwing(struct MarioState *m) { } s32 act_heavy_throw(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -296,7 +296,7 @@ s32 act_heavy_throw(struct MarioState *m) { } s32 act_stomach_slide_stop(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -456,7 +456,7 @@ s32 check_common_object_cancels(struct MarioState *m) { } s32 mario_execute_object_action(struct MarioState *m) { - s32 cancel; + s32 cancel = FALSE; if (check_common_object_cancels(m)) { return TRUE; diff --git a/src/game/mario_actions_stationary.c b/src/game/mario_actions_stationary.c index 000b8839..b241c450 100644 --- a/src/game/mario_actions_stationary.c +++ b/src/game/mario_actions_stationary.c @@ -23,7 +23,7 @@ s32 check_common_idle_cancels(struct MarioState *m) { return mario_push_off_steep_floor(m, ACT_FREEFALL, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -70,7 +70,7 @@ s32 check_common_hold_idle_cancels(struct MarioState *m) { return set_mario_action(m, ACT_PLACING_DOWN, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -180,7 +180,7 @@ void play_anim_sound(struct MarioState *m, u32 actionState, s32 animFrame, u32 s s32 act_start_sleeping(struct MarioState *m) { #ifndef VERSION_JP - s32 animFrame; + s32 animFrame = 0; #endif if (check_common_idle_cancels(m)) { @@ -257,7 +257,7 @@ s32 act_sleeping(struct MarioState *m) { s32 animFrame; if (m->input & (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE - | INPUT_FIRST_PERSON | INPUT_UNKNOWN_10 | INPUT_B_PRESSED | INPUT_Z_PRESSED)) { + | INPUT_FIRST_PERSON | INPUT_STOMPED | INPUT_B_PRESSED | INPUT_Z_PRESSED)) { return set_mario_action(m, ACT_WAKING_UP, m->actionState); } @@ -333,7 +333,7 @@ s32 act_waking_up(struct MarioState *m) { raise_background_noise(2); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -361,7 +361,7 @@ s32 act_waking_up(struct MarioState *m) { s32 act_shivering(struct MarioState *m) { s32 animFrame; - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -375,7 +375,7 @@ s32 act_shivering(struct MarioState *m) { if (m->input & (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE - | INPUT_FIRST_PERSON | INPUT_UNKNOWN_10 | INPUT_B_PRESSED | INPUT_Z_PRESSED)) { + | INPUT_FIRST_PERSON | INPUT_STOMPED | INPUT_B_PRESSED | INPUT_Z_PRESSED)) { m->actionState = 2; } @@ -459,7 +459,7 @@ s32 act_hold_idle(struct MarioState *m) { } s32 act_hold_heavy_idle(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -485,7 +485,7 @@ s32 act_hold_heavy_idle(struct MarioState *m) { } s32 act_standing_against_wall(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -526,7 +526,7 @@ s32 act_in_quicksand(struct MarioState *m) { } s32 act_crouching(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -564,7 +564,7 @@ s32 act_crouching(struct MarioState *m) { } s32 act_panting(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -591,7 +591,7 @@ s32 act_hold_panting_unused(struct MarioState *m) { return drop_and_set_mario_action(m, ACT_PANTING, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -618,7 +618,7 @@ void stopping_step(struct MarioState *m, s32 animID, u32 action) { } s32 act_braking_stop(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -640,7 +640,7 @@ s32 act_braking_stop(struct MarioState *m) { } s32 act_butt_slide_stop(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -661,7 +661,7 @@ s32 act_hold_butt_slide_stop(struct MarioState *m) { return drop_and_set_mario_action(m, ACT_IDLE, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -678,7 +678,7 @@ s32 act_hold_butt_slide_stop(struct MarioState *m) { } s32 act_slide_kick_slide_stop(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -691,7 +691,7 @@ s32 act_slide_kick_slide_stop(struct MarioState *m) { } s32 act_start_crouching(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -716,7 +716,7 @@ s32 act_start_crouching(struct MarioState *m) { } s32 act_stop_crouching(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -749,7 +749,7 @@ s32 act_start_crawling(struct MarioState *m) { return set_mario_action(m, ACT_FREEFALL, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -767,7 +767,7 @@ s32 act_start_crawling(struct MarioState *m) { } s32 act_stop_crawling(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -791,7 +791,7 @@ s32 act_shockwave_bounce(struct MarioState *m) { s16 sp1E; f32 sp18; - if (m->marioObj->oInteractStatus & INT_STATUS_HIT_BY_SHOCKWAVE) { + if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_SHOCKWAVE) { #if ENABLE_RUMBLE queue_rumble_data(70, 40); #endif @@ -802,7 +802,7 @@ s32 act_shockwave_bounce(struct MarioState *m) { #if ENABLE_RUMBLE queue_rumble_data(70, 40); #endif - if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_UNK1) { + if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_KNOCKBACK_DMG) { return hurt_and_set_mario_action(m, ACT_BACKWARD_GROUND_KB, 0, 0xc); } } @@ -837,7 +837,7 @@ s32 landing_step(struct MarioState *m, s32 arg1, u32 action) { } s32 check_common_landing_cancels(struct MarioState *m, u32 action) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -951,7 +951,7 @@ s32 act_hold_jump_land_stop(struct MarioState *m) { return drop_and_set_mario_action(m, ACT_IDLE, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -972,7 +972,7 @@ s32 act_hold_freefall_land_stop(struct MarioState *m) { return drop_and_set_mario_action(m, ACT_IDLE, 0); } - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -988,7 +988,7 @@ s32 act_hold_freefall_land_stop(struct MarioState *m) { } s32 act_air_throw_land(struct MarioState *m) { - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -1006,7 +1006,7 @@ s32 act_air_throw_land(struct MarioState *m) { s32 act_twirl_land(struct MarioState *m) { m->actionState = 1; - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -1036,7 +1036,7 @@ s32 act_twirl_land(struct MarioState *m) { s32 act_ground_pound_land(struct MarioState *m) { m->actionState = 1; - if (m->input & INPUT_UNKNOWN_10) { + if (m->input & INPUT_STOMPED) { return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0); } @@ -1053,7 +1053,7 @@ s32 act_ground_pound_land(struct MarioState *m) { } s32 act_first_person(struct MarioState *m) { - s32 sp1C = (m->input & (INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE | INPUT_UNKNOWN_10)) != 0; + s32 sp1C = (m->input & (INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE | INPUT_STOMPED)) != 0; if (m->actionState == 0) { lower_background_noise(2); diff --git a/src/game/mario_actions_submerged.c b/src/game/mario_actions_submerged.c index 96d6c386..dc0572c1 100644 --- a/src/game/mario_actions_submerged.c +++ b/src/game/mario_actions_submerged.c @@ -24,9 +24,9 @@ static s16 sWasAtSurface = FALSE; static s16 sSwimStrength = MIN_SWIM_STRENGTH; static s16 sWaterCurrentSpeeds[] = { 28, 12, 8, 4 }; -static s16 D_80339FD0; -static s16 D_80339FD2; -static f32 D_80339FD4; +static s16 sBobTimer; +static s16 sBobIncrement; +static f32 sBobHeight; static void set_swimming_at_surface_particles(struct MarioState *m, u32 particleFlag) { s16 atSurface = m->pos[1] >= m->waterLevel - 130; @@ -416,21 +416,24 @@ static s32 act_hold_water_action_end(struct MarioState *m) { return FALSE; } -static void reset_float_globals(struct MarioState *m) { - D_80339FD0 = 0; - D_80339FD2 = 0x800; - D_80339FD4 = m->faceAngle[0] / 256.0f + 20.0f; +static void reset_bob_variables(struct MarioState *m) { + sBobTimer = 0; + sBobIncrement = 0x800; + sBobHeight = m->faceAngle[0] / 256.0f + 20.0f; } -static void float_surface_gfx(struct MarioState *m) { - if (D_80339FD2 != 0 && m->pos[1] > m->waterLevel - 85 && m->faceAngle[0] >= 0) { - if ((D_80339FD0 += D_80339FD2) >= 0) { - m->marioObj->header.gfx.pos[1] += D_80339FD4 * sins(D_80339FD0); +/** + * Controls the bobbing that happens when you swim near the surface. + */ +static void surface_swim_bob(struct MarioState *m) { + if (sBobIncrement != 0 && m->pos[1] > m->waterLevel - 85 && m->faceAngle[0] >= 0) { + if ((sBobTimer += sBobIncrement) >= 0) { + m->marioObj->header.gfx.pos[1] += sBobHeight * sins(sBobTimer); return; } } - D_80339FD2 = 0; + sBobIncrement = 0; } static void common_swimming_step(struct MarioState *m, s16 swimStrength) { @@ -475,7 +478,7 @@ static void common_swimming_step(struct MarioState *m, s16 swimStrength) { update_water_pitch(m); m->marioBodyState->headAngle[0] = approach_s32(m->marioBodyState->headAngle[0], 0, 0x200, 0x200); - float_surface_gfx(m); + surface_swim_bob(m); set_swimming_at_surface_particles(m, PARTICLE_WAVE_TRAIL); } @@ -551,7 +554,7 @@ static s32 act_breaststroke(struct MarioState *m) { if (m->actionTimer == 1) { play_sound(sSwimStrength == MIN_SWIM_STRENGTH ? SOUND_ACTION_SWIM : SOUND_ACTION_SWIM_FAST, m->marioObj->header.gfx.cameraToObject); - reset_float_globals(m); + reset_bob_variables(m); } #if ENABLE_RUMBLE @@ -675,7 +678,7 @@ static s32 act_hold_breaststroke(struct MarioState *m) { if (m->actionTimer == 1) { play_sound(SOUND_ACTION_SWIM, m->marioObj->header.gfx.cameraToObject); - reset_float_globals(m); + reset_bob_variables(m); } set_mario_animation(m, MARIO_ANIM_SWIM_WITH_OBJ_PART1); @@ -1006,7 +1009,7 @@ static s32 act_water_plunge(struct MarioState *m) { set_mario_action(m, ACT_HOLD_METAL_WATER_FALLING, 0); break; } - D_80339FD2 = 0; + sBobIncrement = 0; } switch (stateFlags) { diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index cbccf073..6eab1b69 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -15,6 +15,7 @@ #include "goddard/renderer.h" #include "interaction.h" #include "level_update.h" +#include "mario_actions_cutscene.h" #include "mario_misc.h" #include "memory.h" #include "object_helpers.h" @@ -23,6 +24,7 @@ #include "save_file.h" #include "skybox.h" #include "sound_init.h" +#include "puppycam2.h" #include "config.h" @@ -126,8 +128,8 @@ static void toad_message_opaque(void) { } static void toad_message_talking(void) { - if (cur_obj_update_dialog_with_cutscene(3, 1, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId) - != 0) { + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_DOWN, + DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId)) { gCurrentObject->oToadMessageRecentlyTalked = TRUE; gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADING; switch (gCurrentObject->oToadMessageDialogId) { @@ -313,7 +315,14 @@ static Gfx *make_gfx_mario_alpha(struct GraphNodeGenerated *node, s16 alpha) { node->fnNode.node.flags = (node->fnNode.node.flags & 0xFF) | (LAYER_TRANSPARENT << 8); gfxHead = alloc_display_list(3 * sizeof(*gfxHead)); gfx = gfxHead; - gDPSetAlphaCompare(gfx++, G_AC_DITHER); + if (gMarioState->flags & MARIO_VANISH_CAP) + { + gDPSetAlphaCompare(gfx++, G_AC_DITHER); + } + else + { + gDPSetAlphaCompare(gfx++, G_AC_NONE); + } } gDPSetEnvColor(gfx++, 255, 255, 255, alpha); gSPEndDisplayList(gfx); @@ -333,6 +342,13 @@ Gfx *geo_mirror_mario_set_alpha(s32 callContext, struct GraphNode *node, UNUSED if (callContext == GEO_CONTEXT_RENDER) { alpha = (bodyState->modelState & 0x100) ? (bodyState->modelState & 0xFF) : 255; + #ifdef PUPPYCAM + if (alpha > gPuppyCam.opacity) + { + alpha = gPuppyCam.opacity; + bodyState->modelState |= MODEL_STATE_NOISE_ALPHA; + } + #endif gfx = make_gfx_mario_alpha(asGenerated, alpha); } return gfx; diff --git a/src/game/memory.h b/src/game/memory.h index 7a51e590..592ab2c7 100644 --- a/src/game/memory.h +++ b/src/game/memory.h @@ -8,7 +8,6 @@ #define MEMORY_POOL_LEFT 0 #define MEMORY_POOL_RIGHT 1 - struct AllocOnlyPool { s32 totalSpace; @@ -19,6 +18,26 @@ struct AllocOnlyPool struct MemoryPool; +struct OffsetSizePair +{ + u32 offset; + u32 size; +}; + +struct DmaTable +{ + u32 count; + u8 *srcAddr; + struct OffsetSizePair anim[1]; // dynamic size +}; + +struct DmaHandlerList +{ + struct DmaTable *dmaTable; + void *currentAddr; + void *bufTarget; +}; + #ifndef INCLUDED_FROM_MEMORY_C // Declaring this variable extern puts it in the wrong place in the bss order // when this file is included from memory.c (first instead of last). Hence, @@ -41,7 +60,7 @@ u32 main_pool_push_state(void); u32 main_pool_pop_state(void); #ifndef NO_SEGMENTED_MEMORY -void *load_segment(s32 segment, u8 *srcStart, u8 *srcEnd, u32 side); +void *load_segment(s32 segment, u8 *srcStart, u8 *srcEnd, u32 side, u8 *bssStart, u8 *bssEnd); void *load_to_fixed_pool_addr(u8 *destAddr, u8 *srcStart, u8 *srcEnd); void *load_segment_decompress(s32 segment, u8 *srcStart, u8 *srcEnd); void *load_segment_decompress_heap(u32 segment, u8 *srcStart, u8 *srcEnd); @@ -63,7 +82,7 @@ void *mem_pool_alloc(struct MemoryPool *pool, u32 size); void mem_pool_free(struct MemoryPool *pool, void *addr); void *alloc_display_list(u32 size); -void func_80278A78(struct MarioAnimation *a, void *b, struct Animation *target); -s32 load_patchable_table(struct MarioAnimation *a, u32 b); +void setup_dma_table_list(struct DmaHandlerList *list, void *srcAddr, void *buffer); +s32 load_patchable_table(struct DmaHandlerList *list, s32 index); #endif // MEMORY_H diff --git a/src/game/moving_texture.c b/src/game/moving_texture.c index 268d7efd..8978fa5e 100644 --- a/src/game/moving_texture.c +++ b/src/game/moving_texture.c @@ -969,6 +969,8 @@ Gfx *geo_movtex_update_horizontal(s32 callContext, struct GraphNode *node, UNUSE case MOVTEX_TREADMILL_SMALL: movtexVerts = segmented_to_virtual(ttc_movtex_tris_small_surface_treadmill); break; + default: + return NULL; } update_moving_texture_offset(movtexVerts, MOVTEX_ATTR_COLORED_S); } diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index 64bb141e..4432645a 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -108,7 +108,7 @@ Gfx UNUSED *geo_obj_transparency_something(s32 callContext, struct GraphNode *no gfxHead = alloc_display_list(3 * sizeof(Gfx)); gfx = gfxHead; obj->header.gfx.node.flags = - (obj->header.gfx.node.flags & 0xFF) | (GRAPH_NODE_TYPE_FUNCTIONAL | GRAPH_NODE_TYPE_400); + (obj->header.gfx.node.flags & 0xFF) | (LAYER_TRANSPARENT << 8); gDPSetEnvColor(gfx++, 255, 255, 255, heldObject->oOpacity); @@ -685,14 +685,14 @@ s16 trigger_obj_dialog_when_facing(s32 *inDialog, s16 dialogID, f32 dist, s32 ac if ((is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, (s32) dist) == TRUE && obj_check_if_facing_toward_angle(o->oFaceAngleYaw, gMarioObject->header.gfx.angle[1] + 0x8000, 0x1000) == TRUE && obj_check_if_facing_toward_angle(o->oMoveAngleYaw, o->oAngleToMario, 0x1000) == TRUE) - || (*inDialog == 1)) { - *inDialog = 1; + || (*inDialog == TRUE)) { + *inDialog = TRUE; - if (set_mario_npc_dialog(actionArg) == 2) { //If Mario is speaking. + if (set_mario_npc_dialog(actionArg) == MARIO_DIALOG_STATUS_SPEAK) { //If Mario is speaking. dialogueResponse = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, dialogID); - if (dialogueResponse != 0) { - set_mario_npc_dialog(0); - *inDialog = 0; + if (dialogueResponse) { + set_mario_npc_dialog(MARIO_DIALOG_STOP); + *inDialog = FALSE; return dialogueResponse; } return 0; diff --git a/src/game/obj_behaviors_2.c b/src/game/obj_behaviors_2.c index 056d178a..ae01edce 100644 --- a/src/game/obj_behaviors_2.c +++ b/src/game/obj_behaviors_2.c @@ -15,6 +15,7 @@ #include "engine/surface_load.h" #include "game_init.h" #include "geo_misc.h" +#include "ingame_menu.h" #include "interaction.h" #include "level_table.h" #include "level_update.h" @@ -98,10 +99,11 @@ static s16 obj_get_pitch_from_vel(void) { */ static s32 obj_update_race_proposition_dialog(s16 dialogID) { s32 dialogResponse = - cur_obj_update_dialog_with_cutscene(2, DIALOG_UNK2_FLAG_0 | DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED, CUTSCENE_RACE_DIALOG, dialogID); + cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_UP, + (DIALOG_FLAG_TURN_TO_MARIO | DIALOG_FLAG_TIME_STOP_ENABLED), CUTSCENE_RACE_DIALOG, dialogID); - if (dialogResponse == 2) { - set_mario_npc_dialog(0); + if (dialogResponse == DIALOG_RESPONSE_NO) { + set_mario_npc_dialog(MARIO_DIALOG_STOP); disable_time_stop_including_mario(); } @@ -640,7 +642,7 @@ static void obj_die_if_health_non_positive(void) { } } -static void obj_unused_die(void) { +UNUSED static void obj_unused_die(void) { o->oHealth = 0; obj_die_if_health_non_positive(); } diff --git a/src/game/object_collision.c b/src/game/object_collision.c index c8d867ae..cf77768a 100644 --- a/src/game/object_collision.c +++ b/src/game/object_collision.c @@ -57,6 +57,9 @@ s32 detect_object_hitbox_overlap(struct Object *a, struct Object *b) { } //! no return value +#ifdef AVOID_UB + return 0; +#endif } s32 detect_object_hurtbox_overlap(struct Object *a, struct Object *b) { @@ -89,6 +92,9 @@ s32 detect_object_hurtbox_overlap(struct Object *a, struct Object *b) { } //! no return value +#ifdef AVOID_UB + return 0; +#endif } void clear_object_collision(struct Object *a) { diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 0e4fc295..eae57a85 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -27,8 +27,8 @@ #include "spawn_object.h" #include "spawn_sound.h" -s8 D_8032F0A0[] = { -8, 8, -4, 4 }; -s16 D_8032F0A4[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; +static s8 sBbhStairJiggleOffsets[] = { -8, 8, -4, 4 }; +static s16 sPowersOfTwo[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; static s8 sLevelsWithRooms[] = { LEVEL_BBH, LEVEL_CASTLE, LEVEL_HMC, -1 }; static s32 clear_move_flag(u32 *, s32); @@ -76,20 +76,20 @@ Gfx *geo_update_layer_transparency(s32 callContext, struct GraphNode *node, UNUS if (objectOpacity == 0xFF) { if (currentGraphNode->parameter == 20) { currentGraphNode->fnNode.node.flags = - 0x600 | (currentGraphNode->fnNode.node.flags & 0xFF); + (LAYER_TRANSPARENT_DECAL << 8) | (currentGraphNode->fnNode.node.flags & 0xFF); } else { currentGraphNode->fnNode.node.flags = - 0x100 | (currentGraphNode->fnNode.node.flags & 0xFF); + (LAYER_OPAQUE << 8) | (currentGraphNode->fnNode.node.flags & 0xFF); } objectGraphNode->oAnimState = 0; } else { if (currentGraphNode->parameter == 20) { currentGraphNode->fnNode.node.flags = - 0x600 | (currentGraphNode->fnNode.node.flags & 0xFF); + (LAYER_TRANSPARENT_DECAL << 8) | (currentGraphNode->fnNode.node.flags & 0xFF); } else { currentGraphNode->fnNode.node.flags = - 0x500 | (currentGraphNode->fnNode.node.flags & 0xFF); + (LAYER_TRANSPARENT << 8) | (currentGraphNode->fnNode.node.flags & 0xFF); } objectGraphNode->oAnimState = 1; @@ -394,7 +394,8 @@ s16 obj_angle_to_object(struct Object *obj1, struct Object *obj2) { s16 obj_turn_toward_object(struct Object *obj, struct Object *target, s16 angleIndex, s16 turnAmount) { f32 a, b, c, d; UNUSED s32 unused; - s16 targetAngle, startAngle; + s16 targetAngle = 0; + s16 startAngle; switch (angleIndex) { case O_MOVE_ANGLE_PITCH_INDEX: @@ -478,7 +479,7 @@ struct Object *spawn_object_rel_with_rot(struct Object *parent, u32 model, const struct Object *spawn_obj_with_transform_flags(struct Object *sp20, s32 model, const BehaviorScript *sp28) { struct Object *sp1C = spawn_object(sp20, model, sp28); - sp1C->oFlags |= OBJ_FLAG_0020 | OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM; + sp1C->oFlags |= OBJ_FLAG_UPDATE_TRANSFORM_FOR_THROW_MATRIX | OBJ_FLAG_SET_THROW_MATRIX_FROM_TRANSFORM; return sp1C; } @@ -790,7 +791,7 @@ void cur_obj_unused_init_on_floor(void) { cur_obj_enable_rendering(); o->oPosY = find_floor_height(o->oPosX, o->oPosY, o->oPosZ); - if (o->oPosY < -10000.0f) { + if (o->oPosY < FLOOR_LOWER_LIMIT_MISC) { cur_obj_set_pos_relative_to_parent(0, 0, -70); o->oPosY = find_floor_height(o->oPosX, o->oPosY, o->oPosZ); } @@ -1048,20 +1049,21 @@ s32 mario_is_dive_sliding(void) { } } -void cur_obj_set_y_vel_and_animation(f32 sp18, s32 sp1C) { - o->oVelY = sp18; - cur_obj_init_animation_with_sound(sp1C); +void cur_obj_set_y_vel_and_animation(f32 yVel, s32 animIndex) { + o->oVelY = yVel; + cur_obj_init_animation_with_sound(animIndex); } -void cur_obj_unrender_and_reset_state(s32 sp18, s32 sp1C) { +void cur_obj_unrender_set_action_and_anim(s32 animIndex, s32 action) { cur_obj_become_intangible(); cur_obj_disable_rendering(); - - if (sp18 >= 0) { - cur_obj_init_animation_with_sound(sp18); + + // only set animation if non-negative value + if (animIndex >= 0) { + cur_obj_init_animation_with_sound(animIndex); } - o->oAction = sp1C; + o->oAction = action; } static void cur_obj_move_after_thrown_or_dropped(f32 forwardVel, f32 velY) { @@ -1070,7 +1072,7 @@ static void cur_obj_move_after_thrown_or_dropped(f32 forwardVel, f32 velY) { if (o->oFloorHeight > o->oPosY) { o->oPosY = o->oFloorHeight; - } else if (o->oFloorHeight < -10000.0f) { + } else if (o->oFloorHeight < FLOOR_LOWER_LIMIT_MISC) { //! OoB failsafe obj_copy_pos(o, gMarioObject); o->oFloorHeight = find_floor_height(o->oPosX, o->oPosY, o->oPosZ); @@ -1218,7 +1220,7 @@ static s32 cur_obj_move_xz(f32 steepSlopeNormalY, s32 careAboutEdgesAndSteepSlop } } - if (intendedFloorHeight < -10000.0f) { + if (intendedFloorHeight < FLOOR_LOWER_LIMIT_MISC) { // Don't move into OoB o->oMoveFlags |= OBJ_MOVE_HIT_EDGE; return FALSE; @@ -1318,7 +1320,7 @@ static f32 cur_obj_move_y_and_get_water_level(f32 gravity, f32 buoyancy) { o->oPosY += o->oVelY; if (o->activeFlags & ACTIVE_FLAG_UNK10) { - waterLevel = -11000.0f; + waterLevel = FLOOR_LOWER_LIMIT; } else { waterLevel = find_water_level(o->oPosX, o->oPosZ); } @@ -1376,7 +1378,7 @@ void cur_obj_move_y(f32 gravity, f32 bounciness, f32 buoyancy) { } } -static void stub_obj_helpers_1(void) { +UNUSED static void stub_obj_helpers_1(void) { } static s32 clear_move_flag(u32 *bitSet, s32 flag) { @@ -1566,9 +1568,10 @@ void cur_obj_start_cam_event(UNUSED struct Object *obj, s32 cameraEvent) { gSecondCameraFocus = o; } -void set_mario_interact_hoot_if_in_range(UNUSED s32 sp0, UNUSED s32 sp4, f32 sp8) { - if (o->oDistanceToMario < sp8) { - gMarioObject->oInteractStatus = INT_STATUS_HOOT_GRABBED_BY_MARIO; +// unused, self explanatory, maybe oInteractStatus originally had TRUE/FALSE statements +void set_mario_interact_true_if_in_range(UNUSED s32 arg0, UNUSED s32 arg1, f32 range) { + if (o->oDistanceToMario < range) { + gMarioObject->oInteractStatus = TRUE; } } @@ -1675,7 +1678,7 @@ static s32 cur_obj_detect_steep_floor(s16 steepAngleDegrees) { intendedFloorHeight = find_floor(intendedX, o->oPosY, intendedZ, &intendedFloor); deltaFloorHeight = intendedFloorHeight - o->oFloorHeight; - if (intendedFloorHeight < -10000.0f) { + if (intendedFloorHeight < FLOOR_LOWER_LIMIT_MISC) { o->oWallAngle = o->oMoveAngleYaw + 0x8000; return 2; } else if (intendedFloor->normal.y < steepNormalY && deltaFloorHeight > 0 @@ -1823,7 +1826,7 @@ void cur_obj_move_standard(s16 steepSlopeAngleDegrees) { } } -static s32 cur_obj_within_12k_bounds(void) { +UNUSED static s32 cur_obj_within_12k_bounds(void) { if (o->oPosX < -12000.0f || 12000.0f < o->oPosX) { return FALSE; } @@ -1918,7 +1921,7 @@ void obj_build_transform_from_pos_and_angle(struct Object *obj, s16 posIndex, s1 } void obj_set_throw_matrix_from_transform(struct Object *obj) { - if (obj->oFlags & OBJ_FLAG_0020) { + if (obj->oFlags & OBJ_FLAG_UPDATE_TRANSFORM_FOR_THROW_MATRIX) { obj_build_transform_from_pos_and_angle(obj, O_POS_INDEX, O_FACE_ANGLE_INDEX); obj_apply_scale_to_transform(obj); } @@ -2055,14 +2058,15 @@ void obj_translate_xz_random(struct Object *obj, f32 rangeLength) { obj->oPosZ += random_float() * rangeLength - rangeLength * 0.5f; } -static void obj_build_vel_from_transform(struct Object *a0) { - f32 spC = a0->oUnkC0; - f32 sp8 = a0->oUnkBC; - f32 sp4 = a0->oForwardVel; +static void obj_build_vel_from_transform(struct Object *obj) { + f32 up = obj->oUpVel; + f32 left = obj->oLeftVel; + f32 forward = obj->oForwardVel; - a0->oVelX = a0->transform[0][0] * spC + a0->transform[1][0] * sp8 + a0->transform[2][0] * sp4; - a0->oVelY = a0->transform[0][1] * spC + a0->transform[1][1] * sp8 + a0->transform[2][1] * sp4; - a0->oVelZ = a0->transform[0][2] * spC + a0->transform[1][2] * sp8 + a0->transform[2][2] * sp4; + //! Typo, up and left should be swapped + obj->oVelX = obj->transform[0][0] * up + obj->transform[1][0] * left + obj->transform[2][0] * forward; + obj->oVelY = obj->transform[0][1] * up + obj->transform[1][1] * left + obj->transform[2][1] * forward; + obj->oVelZ = obj->transform[0][2] * up + obj->transform[1][2] * left + obj->transform[2][2] * forward; } void cur_obj_set_pos_via_transform(void) { @@ -2085,13 +2089,13 @@ void cur_obj_spawn_particles(struct SpawnParticlesInfo *info) { s32 numParticles = info->count; // If there are a lot of objects already, limit the number of particles - if (gPrevFrameObjectCount > 150 && numParticles > 10) { + if ((gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY - 90)) && numParticles > 10) { numParticles = 10; } // We're close to running out of object slots, so don't spawn particles at // all - if (gPrevFrameObjectCount > 210) { + if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY - 30)) { numParticles = 0; } @@ -2114,8 +2118,8 @@ void cur_obj_spawn_particles(struct SpawnParticlesInfo *info) { } void obj_set_hitbox(struct Object *obj, struct ObjectHitbox *hitbox) { - if (!(obj->oFlags & OBJ_FLAG_30)) { - obj->oFlags |= OBJ_FLAG_30; + if (!(obj->oFlags & OBJ_FLAG_HITBOX_WAS_SET)) { + obj->oFlags |= OBJ_FLAG_HITBOX_WAS_SET; obj->oInteractType = hitbox->interactType; obj->oDamageOrCoinValue = hitbox->damageOrCoinValue; @@ -2230,7 +2234,7 @@ void bhv_dust_smoke_loop(void) { o->oSmokeTimer++; } -static void stub_obj_helpers_2(void) { +UNUSED static void stub_obj_helpers_2(void) { } s32 cur_obj_set_direction_table(s8 *a0) { @@ -2308,12 +2312,12 @@ s32 cur_obj_shake_y_until(s32 cycles, s32 amount) { } } -s32 cur_obj_move_up_and_down(s32 a0) { +s32 jiggle_bbh_stair(s32 a0) { if (a0 >= 4 || a0 < 0) { return TRUE; } - o->oPosY += D_8032F0A0[a0]; + o->oPosY += sBbhStairJiggleOffsets[a0]; return FALSE; } @@ -2338,7 +2342,7 @@ void spawn_base_star_with_no_lvl_exit(void) { } s32 bit_shift_left(s32 a0) { - return D_8032F0A4[a0]; + return sPowersOfTwo[a0]; } s32 cur_obj_mario_far_away(void) { @@ -2378,7 +2382,7 @@ s32 is_item_in_array(s8 item, s8 *array) { return FALSE; } -static void stub_obj_helpers_5(void) { +UNUSED static void stub_obj_helpers_5(void) { } void bhv_init_room(void) { @@ -2459,7 +2463,7 @@ s32 cur_obj_set_hitbox_and_die_if_attacked(struct ObjectHitbox *hitbox, s32 deat void obj_explode_and_spawn_coins(f32 sp18, s32 sp1C) { spawn_mist_particles_variable(0, 0, sp18); - spawn_triangle_break_particles(30, 138, 3.0f, 4); + spawn_triangle_break_particles(30, MODEL_DIRT_ANIMATION, 3.0f, 4); obj_mark_for_deletion(o); if (sp1C == 1) { @@ -2560,29 +2564,18 @@ static void cur_obj_end_dialog(s32 dialogFlags, s32 dialogResult) { o->oDialogResponse = dialogResult; o->oDialogState++; - if (!(dialogFlags & DIALOG_UNK1_FLAG_4)) { - set_mario_npc_dialog(0); + if (!(dialogFlags & DIALOG_FLAG_TIME_STOP_ENABLED)) { + set_mario_npc_dialog(MARIO_DIALOG_STOP); } } s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s32 unused) { - s32 dialogResponse = 0; + s32 dialogResponse = DIALOG_RESPONSE_NONE; UNUSED s32 doneTurning = TRUE; switch (o->oDialogState) { -#ifdef VERSION_JP - case DIALOG_UNK1_ENABLE_TIME_STOP: - //! We enable time stop even if Mario is not ready to speak. This - // allows us to move during time stop as long as Mario never enters - // an action that can be interrupted with text. - if (gMarioState->health >= 0x100) { - gTimeStopState |= TIME_STOP_ENABLED; - o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; - o->oDialogState++; - } - break; -#else - case DIALOG_UNK1_ENABLE_TIME_STOP: +#if BUGFIX_DIALOG_TIME_STOP + case DIALOG_STATUS_ENABLE_TIME_STOP: // Patched :( // Wait for Mario to be ready to speak, and then enable time stop if (mario_ready_to_speak() || gMarioState->action == ACT_READING_NPC_DIALOG) { @@ -2594,48 +2587,67 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s } // Fall through so that Mario's action is interrupted immediately // after time is stopped +#else + case DIALOG_STATUS_ENABLE_TIME_STOP: + //! We enable time stop even if Mario is not ready to speak. This + // allows us to move during time stop as long as Mario never enters + // an action that can be interrupted with text. + if (gMarioState->health >= 0x100) { + gTimeStopState |= TIME_STOP_ENABLED; + o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; + o->oDialogState++; + } + break; #endif - - case DIALOG_UNK1_INTERRUPT_MARIO_ACTION: - if (set_mario_npc_dialog(actionArg) == 2) { + case DIALOG_STATUS_INTERRUPT: + // Interrupt until Mario is actually speaking with the NPC + if (set_mario_npc_dialog(actionArg) == MARIO_DIALOG_STATUS_SPEAK) { o->oDialogState++; } break; - case DIALOG_UNK1_BEGIN_DIALOG: - if (dialogFlags & DIALOG_UNK1_FLAG_RESPONSE) { + case DIALOG_STATUS_START_DIALOG: + // Starts dialog, depending of the flag defined, it calls + // a default dialog or a dialog with response. + if (dialogFlags & DIALOG_FLAG_TEXT_RESPONSE) { create_dialog_box_with_response(dialogID); - } else if (dialogFlags & DIALOG_UNK1_FLAG_DEFAULT) { + } else if (dialogFlags & DIALOG_FLAG_TEXT_DEFAULT) { create_dialog_box(dialogID); } o->oDialogState++; break; - case DIALOG_UNK1_AWAIT_DIALOG: - if (dialogFlags & DIALOG_UNK1_FLAG_RESPONSE) { - if (gDialogResponse != 0) { + case DIALOG_STATUS_STOP_DIALOG: + // Stops dialog, if the flag dialog response was called + // then it defines the value to let the object do the rest. + if (dialogFlags & DIALOG_FLAG_TEXT_RESPONSE) { + if (gDialogResponse != DIALOG_RESPONSE_NONE) { cur_obj_end_dialog(dialogFlags, gDialogResponse); } - } else if (dialogFlags & DIALOG_UNK1_FLAG_DEFAULT) { - if (get_dialog_id() == -1) { - cur_obj_end_dialog(dialogFlags, 3); + } else if (dialogFlags & DIALOG_FLAG_TEXT_DEFAULT) { + if (get_dialog_id() == DIALOG_NONE) { + cur_obj_end_dialog(dialogFlags, DIALOG_RESPONSE_NOT_DEFINED); } } else { - cur_obj_end_dialog(dialogFlags, 3); + cur_obj_end_dialog(dialogFlags, DIALOG_RESPONSE_NOT_DEFINED); } break; - case DIALOG_UNK1_DISABLE_TIME_STOP: - if (gMarioState->action != ACT_READING_NPC_DIALOG || (dialogFlags & DIALOG_UNK1_FLAG_4)) { + case DIALOG_STATUS_DISABLE_TIME_STOP: + // We disable time stop for a few seconds when Mario is no longer + // speaking or the flag is defined, then we enable it again. + // Usually, an object disables time stop using a separate function + // after a certain condition is met. + if (gMarioState->action != ACT_READING_NPC_DIALOG || (dialogFlags & DIALOG_FLAG_TIME_STOP_ENABLED)) { gTimeStopState &= ~TIME_STOP_ENABLED; o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; dialogResponse = o->oDialogResponse; - o->oDialogState = DIALOG_UNK1_ENABLE_TIME_STOP; + o->oDialogState = DIALOG_STATUS_ENABLE_TIME_STOP; } break; default: - o->oDialogState = DIALOG_UNK1_ENABLE_TIME_STOP; + o->oDialogState = DIALOG_STATUS_ENABLE_TIME_STOP; break; } @@ -2643,12 +2655,25 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s } s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cutsceneTable, s32 dialogID) { - s32 dialogResponse = 0; + s32 dialogResponse = DIALOG_RESPONSE_NONE; s32 doneTurning = TRUE; switch (o->oDialogState) { -#ifdef VERSION_JP - case DIALOG_UNK2_ENABLE_TIME_STOP: +#if BUGFIX_DIALOG_TIME_STOP + case DIALOG_STATUS_ENABLE_TIME_STOP: + // Wait for Mario to be ready to speak, and then enable time stop + if (mario_ready_to_speak() || gMarioState->action == ACT_READING_NPC_DIALOG) { + gTimeStopState |= TIME_STOP_ENABLED; + o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; + o->oDialogState++; + o->oDialogResponse = DIALOG_RESPONSE_NONE; + } else { + break; + } + // Fall through so that Mario's action is interrupted immediately + // after time is stopped +#else + case DIALOG_STATUS_ENABLE_TIME_STOP: //! We enable time stop even if Mario is not ready to speak. This // allows us to move during time stop as long as Mario never enters // an action that can be interrupted with text. @@ -2656,63 +2681,61 @@ s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cuts gTimeStopState |= TIME_STOP_ENABLED; o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; o->oDialogState++; - o->oDialogResponse = 0; + o->oDialogResponse = DIALOG_RESPONSE_NONE; } break; -#else - case DIALOG_UNK2_ENABLE_TIME_STOP: - // Wait for Mario to be ready to speak, and then enable time stop - if (mario_ready_to_speak() || gMarioState->action == ACT_READING_NPC_DIALOG) { - gTimeStopState |= TIME_STOP_ENABLED; - o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; - o->oDialogState++; - o->oDialogResponse = 0; - } else { - break; - } - // Fall through so that Mario's action is interrupted immediately - // after time is stopped #endif - - case DIALOG_UNK2_TURN_AND_INTERRUPT_MARIO_ACTION: - if (dialogFlags & DIALOG_UNK2_FLAG_0) { + case DIALOG_STATUS_INTERRUPT: + // Additional flag that makes the NPC rotate towards to Mario + if (dialogFlags & DIALOG_FLAG_TURN_TO_MARIO) { doneTurning = cur_obj_rotate_yaw_toward(obj_angle_to_object(o, gMarioObject), 0x800); + // Failsafe just in case it takes more than 33 frames somehow if (o->oDialogResponse >= 33) { doneTurning = TRUE; } } - - if (set_mario_npc_dialog(actionArg) == 2 && doneTurning) { + // Interrupt status until Mario is actually speaking with the NPC and if the + // object is done turning to Mario + if (set_mario_npc_dialog(actionArg) == MARIO_DIALOG_STATUS_SPEAK && doneTurning) { o->oDialogResponse = 0; o->oDialogState++; } else { - o->oDialogResponse++; + o->oDialogResponse++; // treated as a timer for the failsafe } break; - case DIALOG_UNK2_AWAIT_DIALOG: + case DIALOG_STATUS_START_DIALOG: + // Special check for Cap Switch cutscene since the cutscene itself + // handles what dialog should use if (cutsceneTable == CUTSCENE_CAP_SWITCH_PRESS) { - if ((o->oDialogResponse = cutscene_object_without_dialog(cutsceneTable, o)) != 0) { + if ((o->oDialogResponse = cutscene_object_without_dialog(cutsceneTable, o))) { o->oDialogState++; } } else { - if ((o->oDialogResponse = cutscene_object_with_dialog(cutsceneTable, o, dialogID)) != 0) { + // General dialog cutscene function, most of the time + // the "CUTSCENE_DIALOG" cutscene is called + if ((o->oDialogResponse = cutscene_object_with_dialog(cutsceneTable, o, dialogID))) { o->oDialogState++; } } break; - case DIALOG_UNK2_END_DIALOG: - if (dialogFlags & DIALOG_UNK2_LEAVE_TIME_STOP_ENABLED) { + case DIALOG_STATUS_STOP_DIALOG: + // If flag defined, keep time stop enabled until the object + // decided to disable it independently + if (dialogFlags & DIALOG_FLAG_TIME_STOP_ENABLED) { dialogResponse = o->oDialogResponse; - o->oDialogState = DIALOG_UNK2_ENABLE_TIME_STOP; + o->oDialogState = DIALOG_STATUS_ENABLE_TIME_STOP; } else if (gMarioState->action != ACT_READING_NPC_DIALOG) { + // Disable time stop, then enable time stop for a frame + // until the set_mario_npc_dialog function disables it gTimeStopState &= ~TIME_STOP_ENABLED; o->activeFlags &= ~ACTIVE_FLAG_INITIATED_TIME_STOP; dialogResponse = o->oDialogResponse; - o->oDialogState = DIALOG_UNK2_ENABLE_TIME_STOP; + o->oDialogState = DIALOG_STATUS_ENABLE_TIME_STOP; } else { - set_mario_npc_dialog(0); + // And finally stop Mario dialog status + set_mario_npc_dialog(MARIO_DIALOG_STOP); } break; } diff --git a/src/game/object_helpers.h b/src/game/object_helpers.h index cea3c071..fa83e8e1 100644 --- a/src/game/object_helpers.h +++ b/src/game/object_helpers.h @@ -154,7 +154,7 @@ s32 cur_obj_check_frame_prior_current_frame(s16 *a0); s32 mario_is_in_air_action(void); s32 mario_is_dive_sliding(void); void cur_obj_set_y_vel_and_animation(f32 sp18, s32 sp1C); -void cur_obj_unrender_and_reset_state(s32 sp18, s32 sp1C); +void cur_obj_unrender_set_action_and_anim(s32 sp18, s32 sp1C); void cur_obj_get_thrown_or_placed(f32 forwardVel, f32 velY, s32 thrownAction); void cur_obj_get_dropped(void); void cur_obj_set_model(s32 modelID); @@ -186,7 +186,7 @@ void cur_obj_set_pos_to_home(void); void cur_obj_set_pos_to_home_and_stop(void); void cur_obj_shake_y(f32 amount); void cur_obj_start_cam_event(UNUSED struct Object *obj, s32 cameraEvent); -void set_mario_interact_hoot_if_in_range(UNUSED s32 sp0, UNUSED s32 sp4, f32 sp8); +void set_mario_interact_true_if_in_range(UNUSED s32 sp0, UNUSED s32 sp4, f32 sp8); void obj_set_billboard(struct Object *obj); void cur_obj_set_hitbox_radius_and_height(f32 radius, f32 height); void cur_obj_set_hurtbox_radius_and_height(f32 radius, f32 height); @@ -252,7 +252,7 @@ void stub_obj_helpers_3(UNUSED s32 sp0, UNUSED s32 sp4); void cur_obj_scale_over_time(s32 a0, s32 a1, f32 sp10, f32 sp14); void cur_obj_set_pos_to_home_with_debug(void); s32 cur_obj_is_mario_on_platform(void); -s32 cur_obj_move_up_and_down(s32 a0); +s32 jiggle_bbh_stair(s32 a0); void cur_obj_call_action_function(void (*actionFunctions[])(void)); void spawn_base_star_with_no_lvl_exit(void); s32 bit_shift_left(s32 a0); diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 834cb59b..455190a3 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -19,6 +19,7 @@ #include "platform_displacement.h" #include "profiler.h" #include "spawn_object.h" +#include "puppyprint.h" /** @@ -146,9 +147,9 @@ struct MemoryPool *gObjectMemoryPool; s16 gCheckingSurfaceCollisionsForCamera; s16 gFindFloorIncludeSurfaceIntangible; -s16 *gEnvironmentRegions; +TerrainData *gEnvironmentRegions; s32 gEnvironmentLevels[20]; -s8 gDoorAdjacentRooms[60][2]; +RoomData gDoorAdjacentRooms[60][2]; s16 gMarioCurrentRoom; s16 D_8035FEE2; s16 D_8035FEE4; @@ -602,7 +603,7 @@ void unload_deactivated_objects(void) { /** * Unused profiling function. */ -static u16 unused_get_elapsed_time(u64 *cycleCounts, s32 index) { +UNUSED static u16 unused_get_elapsed_time(u64 *cycleCounts, s32 index) { u16 time; f64 cycles; @@ -625,6 +626,10 @@ static u16 unused_get_elapsed_time(u64 *cycleCounts, s32 index) { */ void update_objects(UNUSED s32 unused) { s64 cycleCounts[30]; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + OSTime colTime = collisionTime[perfIteration]; + #endif cycleCounts[0] = get_current_clock(); @@ -683,4 +688,8 @@ void update_objects(UNUSED s32 unused) { } gPrevFrameObjectCount = gObjectCounter; + #if PUPPYPRINT_DEBUG + profiler_update(behaviourTime, first); + behaviourTime[perfIteration] -= collisionTime[perfIteration]+colTime; + #endif } diff --git a/src/game/object_list_processor.h b/src/game/object_list_processor.h index e3884f34..f41550fa 100644 --- a/src/game/object_list_processor.h +++ b/src/game/object_list_processor.h @@ -100,9 +100,9 @@ extern struct MemoryPool *gObjectMemoryPool; extern s16 gCheckingSurfaceCollisionsForCamera; extern s16 gFindFloorIncludeSurfaceIntangible; -extern s16 *gEnvironmentRegions; +extern TerrainData *gEnvironmentRegions; extern s32 gEnvironmentLevels[20]; -extern s8 gDoorAdjacentRooms[60][2]; +extern RoomData gDoorAdjacentRooms[60][2]; extern s16 gMarioCurrentRoom; extern s16 D_8035FEE2; extern s16 D_8035FEE4; diff --git a/src/game/paintings.c b/src/game/paintings.c index 83bd2ce9..a1946f53 100644 --- a/src/game/paintings.c +++ b/src/game/paintings.c @@ -254,6 +254,9 @@ f32 painting_ripple_y(struct Painting *painting, s8 ySource) { return painting->size / 2.0; // some concentric ripples don't care about Mario break; } +#ifdef AVOID_UB + return 0.0f; +#endif } /** @@ -279,6 +282,9 @@ f32 painting_nearest_4th(struct Painting *painting) { } else if (painting->floorEntered & ENTER_RIGHT) { return thirdQuarter; } +#ifdef AVOID_UB + return 0.0f; +#endif } /** @@ -310,6 +316,9 @@ f32 painting_ripple_x(struct Painting *painting, s8 xSource) { return painting->size / 2.0; break; } +#ifdef AVOID_UB + return 0.0f; +#endif } /** @@ -1010,7 +1019,7 @@ Gfx *display_painting_rippling(struct Painting *painting) { s16 *neighborTris = segmented_to_virtual(seg2_painting_mesh_neighbor_tris); s16 numVtx = mesh[0]; s16 numTris = mesh[numVtx * 3 + 1]; - Gfx *dlist; + Gfx *dlist = NULL; // Generate the mesh and its lighting data painting_generate_mesh(painting, mesh, numVtx); diff --git a/src/game/platform_displacement.c b/src/game/platform_displacement.c index e42f4829..61859bf6 100644 --- a/src/game/platform_displacement.c +++ b/src/game/platform_displacement.c @@ -9,6 +9,7 @@ #include "platform_displacement.h" #include "types.h" #include "sm64.h" +#include "behavior_data.h" #include "config.h" @@ -144,6 +145,13 @@ void apply_platform_displacement(struct PlatformDisplacementInfo *displaceInfo, vec3f_sub(pos, platformPos); } + // Apply displacement specifically for TTC Treadmills + if (platform->behavior == segmented_to_virtual(bhvTTCTreadmill)) { + pos[0] += platform->oVelX; + pos[1] += platform->oVelY; + pos[2] += platform->oVelZ; + } + // Transform from world positions to relative positions for use next frame linear_mtxf_transpose_mul_vec3f(*platform->header.gfx.throwMatrix, scaledPos, pos); scale_vec3f(displaceInfo->prevTransformedPos, scaledPos, platform->header.gfx.scale, TRUE); diff --git a/src/game/puppycam2.c b/src/game/puppycam2.c new file mode 100644 index 00000000..6cc6ca59 --- /dev/null +++ b/src/game/puppycam2.c @@ -0,0 +1,1514 @@ +///Puppycam 2.2 by Fazana + +#include +#include +#include "sm64.h" +#include "types.h" +#include "level_update.h" +#include "puppycam2.h" +#include "audio/external.h" +#include "audio/data.h" +#include "game_init.h" +#include "engine/math_util.h" +#include "print.h" +#include "engine/surface_collision.h" +#include "engine/surface_load.h" +#include "include/text_strings.h" +#include "segment2.h" +#include "ingame_menu.h" +#include "memory.h" +#include "object_list_processor.h" +#include "object_helpers.h" +#include "behavior_data.h" +#include "save_file.h" +#include "mario.h" +#include "puppyprint.h" +#include "debug_box.h" + +#ifdef PUPPYCAM + +static inline float smooth(float x) { + x = CLAMP(x, 0, 1); + return x * x * (3.f - 2.f * x); +} + +static inline float softClamp(float x, float a, float b) { + return smooth((2.f / 3.f) * (x - a) / (b - a) + (1.f / 6.f)) * (b - a) + a; +} + +#define DECELERATION 0.66f +#define DEADZONE 20 +#define SCRIPT_MEMORY_POOL 0x1000 + +struct gPuppyStruct gPuppyCam; +struct sPuppyVolume *sPuppyVolumeStack[MAX_PUPPYCAM_VOLUMES]; +s16 sFloorHeight = 0; +u8 gPCOptionOpen = 0; +s8 gPCOptionSelected = 0; +s32 gPCOptionTimer = 0; +u8 gPCOptionIndex = 0; +u8 gPCOptionScroll = 0; +u16 gPuppyVolumeCount = 0; +struct MemoryPool *gPuppyMemoryPool; +s32 gPuppyError = 0; + +#if defined(VERSION_EU) +static unsigned char gPCOptionStringsFR[][64] = {{NC_ANALOGUE_FR}, {NC_CAMX_FR}, {NC_CAMY_FR}, {NC_INVERTX_FR}, {NC_INVERTY_FR}, {NC_CAMC_FR}, {NC_SCHEME_FR}, {NC_WIDE_FR}, {OPTION_LANGUAGE_FR}}; +static unsigned char gPCOptionStringsDE[][64] = {{NC_ANALOGUE_DE}, {NC_CAMX_DE}, {NC_CAMY_DE}, {NC_INVERTX_DE}, {NC_INVERTY_DE}, {NC_CAMC_DE}, {NC_SCHEME_DE}, {NC_WIDE_DE}, {OPTION_LANGUAGE_DE}}; +static unsigned char gPCFlagStringsFR[][64] = {{OPTION_DISABLED_FR}, {OPTION_ENABLED_FR}, {OPTION_SCHEME1_FR}, {OPTION_SCHEME2_FR}, {OPTION_SCHEME3_FR}, {TEXT_ENGLISH}, {TEXT_FRENCH}, {TEXT_GERMAN},}; +static unsigned char gPCFlagStringsDE[][64] = {{OPTION_DISABLED_DE}, {OPTION_ENABLED_DE}, {OPTION_SCHEME1_DE}, {OPTION_SCHEME2_DE}, {OPTION_SCHEME3_DE}, {TEXT_ENGLISH}, {TEXT_FRENCH}, {TEXT_GERMAN},}; +static unsigned char gPCToggleStringsFR[][64] = {{NC_BUTTON_FR}, {NC_BUTTON2_FR}, {NC_OPTION_FR}, {NC_HIGHLIGHT_L}, {NC_HIGHLIGHT_R},}; +static unsigned char gPCToggleStringsDE[][64] = {{NC_BUTTON_DE}, {NC_BUTTON2_DE}, {NC_OPTION_DE}, {NC_HIGHLIGHT_L}, {NC_HIGHLIGHT_R},}; +#endif +static unsigned char gPCOptionStringsEN[][64] = {{NC_ANALOGUE_EN}, {NC_CAMX_EN}, {NC_CAMY_EN}, {NC_INVERTX_EN}, {NC_INVERTY_EN}, {NC_CAMC_EN}, {NC_SCHEME_EN}, {NC_WIDE_EN}, {OPTION_LANGUAGE_EN}}; +static unsigned char gPCFlagStringsEN[][64] = {{OPTION_DISABLED_EN}, {OPTION_ENABLED_EN}, {OPTION_SCHEME1_EN}, {OPTION_SCHEME2_EN}, {OPTION_SCHEME3_EN}, {TEXT_ENGLISH}, {TEXT_FRENCH}, {TEXT_GERMAN},}; +static unsigned char gPCToggleStringsEN[][64] = {{NC_BUTTON_EN}, {NC_BUTTON2_EN}, {NC_OPTION_EN}, {NC_HIGHLIGHT_L}, {NC_HIGHLIGHT_R},}; + + +#define OPT 32 //Just a temp thing + +static unsigned char (*gPCOptionStringsPtr)[OPT][64] = &gPCOptionStringsEN; +static unsigned char (*gPCFlagStringsPtr)[OPT][64] = &gPCFlagStringsEN; +static unsigned char (*gPCToggleStringsPtr)[OPT][64] = &gPCToggleStringsEN; + + +static const struct gPCOptionStruct +{ + u8 gPCOptionName; //This is the position in the newcam_options text array. It doesn't have to directly correlate with its position in the struct + s16 *gPCOptionVar; //This is the value that the option is going to directly affect. + u8 gPCOptionStart; //This is where the text array will start. Set it to 255 to have it be ignored. + s32 gPCOptionMin; //The minimum value of the option. + s32 gPCOptionMax; //The maximum value of the option. +}; + +static const struct gPCOptionStruct gPCOptions[]= +{ //If the min and max are 0 and 1, then the value text is used, otherwise it's ignored. + #ifdef WIDE + {/*Option Name*/ 7, /*Option Variable*/ &gWidescreen, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, + #endif + #if MULTILANG + {/*Option Name*/ 8, /*Option Variable*/ &gInGameLanguage, /*Option Value Text Start*/ 4, /*Option Minimum*/ 1, /*Option Maximum*/ 3}, + #endif + {/*Option Name*/ 0, /*Option Variable*/ &gPuppyCam.options.analogue, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, + {/*Option Name*/ 6, /*Option Variable*/ &gPuppyCam.options.inputType, /*Option Value Text Start*/ 2, /*Option Minimum*/ 0, /*Option Maximum*/ 2}, + {/*Option Name*/ 1, /*Option Variable*/ &gPuppyCam.options.sensitivityX, /*Option Value Text Start*/ 255, /*Option Minimum*/ 10, /*Option Maximum*/ 500}, + {/*Option Name*/ 2, /*Option Variable*/ &gPuppyCam.options.sensitivityY, /*Option Value Text Start*/ 255, /*Option Minimum*/ 10, /*Option Maximum*/ 500}, + {/*Option Name*/ 3, /*Option Variable*/ &gPuppyCam.options.invertX, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, + {/*Option Name*/ 4, /*Option Variable*/ &gPuppyCam.options.invertY, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, + {/*Option Name*/ 5, /*Option Variable*/ &gPuppyCam.options.turnAggression, /*Option Value Text Start*/ 255, /*Option Minimum*/ 0, /*Option Maximum*/ 100}, +}; + +u8 gPCOptionCap = sizeof(gPCOptions) / sizeof(struct gPCOptionStruct); //How many options there are in newcam_uptions. + +s16 LENSIN(s16 length, s16 direction) +{ + return (length * sins(direction)); +} +s16 LENCOS(s16 length, s16 direction) +{ + return (length * coss(direction)); +} + +static void puppycam_analogue_stick(void) +{ + #ifdef TARGET_N64 + if (!gPuppyCam.options.analogue) + return; + + //I make the X axis negative, so that the movement reflects the Cbuttons. + gPuppyCam.stick2[0] = -gPlayer2Controller->rawStickX; + gPuppyCam.stick2[1] = gPlayer2Controller->rawStickY; + + if (ABS(gPuppyCam.stick2[0]) < DEADZONE) + { + gPuppyCam.stick2[0] = 0; + gPuppyCam.stickN[0] = 0; + } + if (ABS(gPuppyCam.stick2[1]) < DEADZONE) + { + gPuppyCam.stick2[1] = 0; + gPuppyCam.stickN[1] = 0; + } + #endif +} + +void puppycam_default_config(void) +{ + gPuppyCam.options.invertX = 1; + gPuppyCam.options.invertY = 1; + gPuppyCam.options.sensitivityX = 100; + gPuppyCam.options.sensitivityY = 100; + gPuppyCam.options.turnAggression = 50; + gPuppyCam.options.analogue = 0; + gPuppyCam.options.inputType = 1; +} + +//Initial setup. Ran at the beginning of the game and never again. +void puppycam_boot(void) +{ + gPuppyCam.zoomPoints[0] = 600; + gPuppyCam.zoomPoints[1] = 1000; + gPuppyCam.zoomPoints[2] = 1500; + gPuppyCam.povHeight = 125; + gPuppyCam.stick2[0] = 0; + gPuppyCam.stick2[1] = 0; + gPuppyCam.stickN[0] = 0; + gPuppyCam.stickN[1] = 0; + gPuppyMemoryPool = mem_pool_init(MAX_PUPPYCAM_VOLUMES * sizeof(struct sPuppyVolume), MEMORY_POOL_LEFT); + gPuppyVolumeCount = 0; + gPuppyCam.enabled = 1; + + puppycam_get_save(); +} + +//Called when an instant warp is done. +void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ) +{ + gPuppyCam.pos[0] += displacementX; + gPuppyCam.pos[1] += displacementY; + gPuppyCam.pos[2] += displacementZ; + gPuppyCam.targetFloorHeight += displacementY; + gPuppyCam.lastTargetFloorHeight += displacementY; + gPuppyCam.floorY[0] += displacementY; + gPuppyCam.floorY[1] += displacementY; +} + +#if MULTILANG +static void newcam_set_language(void) +{ + switch (gInGameLanguage-1) + { + case 0: + gPCOptionStringsPtr = &gPCOptionStringsEN; + gPCFlagStringsPtr = &gPCFlagStringsEN; + gPCToggleStringsPtr = &gPCToggleStringsEN; + break; + case 1: + gPCOptionStringsPtr = &gPCOptionStringsFR; + gPCFlagStringsPtr = &gPCFlagStringsFR; + gPCToggleStringsPtr = &gPCToggleStringsFR; + break; + case 2: + gPCOptionStringsPtr = &gPCOptionStringsDE; + gPCFlagStringsPtr = &gPCFlagStringsDE; + gPCToggleStringsPtr = &gPCToggleStringsDE; + break; + } +} +#endif + +///CUTSCENE + +void puppycam_activate_cutscene(s32 *scene, s32 lockinput) +{ + gPuppyCam.cutscene = 1; + gPuppyCam.sceneTimer = 0; + gPuppyCam.sceneFunc = scene; + gPuppyCam.sceneInput = lockinput; +} + +//If you've read camera.c this will look familiar. +//It takes the next 4 spline points and extrapolates a curvature based positioning of the camera vector that's passed through. +//It's a standard B spline +static void puppycam_evaluate_spline(f32 progress, Vec3s cameraPos, Vec3f spline1, Vec3f spline2, Vec3f spline3, Vec3f spline4) +{ + f32 tempP[4]; + + if (progress > 1.0f) { + progress = 1.0f; + } + + tempP[0] = (1.0f - progress) * (1.0f - progress) * (1.0f - progress) / 6.0f; + tempP[1] = progress * progress * progress / 2.0f - progress * progress + 0.6666667f; + tempP[2] = -progress * progress * progress / 2.0f + progress * progress / 2.0f + progress / 2.0f + 0.16666667f; + tempP[3] = progress * progress * progress / 6.0f; + + cameraPos[0] = tempP[0] * spline1[0] + tempP[1] * spline2[0] + tempP[2] * spline3[0] + tempP[3] * spline4[0]; + cameraPos[1] = tempP[0] * spline1[1] + tempP[1] * spline2[1] + tempP[2] * spline3[1] + tempP[3] * spline4[1]; + cameraPos[2] = tempP[0] * spline1[2] + tempP[1] * spline2[2] + tempP[2] * spline3[2] + tempP[3] * spline4[2]; +} + +s32 puppycam_move_spline(struct sPuppySpline splinePos[], struct sPuppySpline splineFocus[], s32 mode, s32 index) +{ + Vec3f tempPoints[4]; + f32 tempProgress[2] = {0.0f, 0.0f}; + f32 progChange = 0.0f; + s32 i; + Vec3f prevPos; + + if (gPuppyCam.splineIndex == 65000) + gPuppyCam.splineIndex = index; + + if (splinePos[gPuppyCam.splineIndex].index == -1 || splinePos[gPuppyCam.splineIndex + 1].index == -1 || splinePos[gPuppyCam.splineIndex + 2].index == -1) + return 1; + if (mode == PUPPYSPLINE_FOLLOW) + if (splineFocus[gPuppyCam.splineIndex].index == -1 || splineFocus[gPuppyCam.splineIndex + 1].index == -1 || splineFocus[gPuppyCam.splineIndex + 2].index == -1) + return 1; + + vec3f_set(prevPos, gPuppyCam.pos[0], gPuppyCam.pos[1], gPuppyCam.pos[2]); + + for (i = 0; i < 4; i++) + vec3f_set(tempPoints[i], splinePos[gPuppyCam.splineIndex + i].pos[0], splinePos[gPuppyCam.splineIndex + i].pos[1], splinePos[gPuppyCam.splineIndex + i].pos[2]); + puppycam_evaluate_spline(gPuppyCam.splineProgress, gPuppyCam.pos, tempPoints[0], tempPoints[1], tempPoints[2], tempPoints[3]); + if (mode == PUPPYSPLINE_FOLLOW) + { + for (i = 0; i < 4; i++) + vec3f_set(tempPoints[i], splineFocus[gPuppyCam.splineIndex + i].pos[0], splineFocus[gPuppyCam.splineIndex + i].pos[1], splineFocus[gPuppyCam.splineIndex + i].pos[2]); + puppycam_evaluate_spline(gPuppyCam.splineProgress, gPuppyCam.focus, tempPoints[0], tempPoints[1], tempPoints[2], tempPoints[3]); + } + + if (splinePos[gPuppyCam.splineIndex+1].speed != 0) { + tempProgress[0] = 1.0f / splinePos[gPuppyCam.splineIndex+1].speed; + } + if (splinePos[gPuppyCam.splineIndex+2].speed != 0) { + tempProgress[1] = 1.0f / splinePos[gPuppyCam.splineIndex+2].speed; + } + progChange = (tempProgress[1] - tempProgress[0]) * gPuppyCam.splineProgress + tempProgress[0]; + + gPuppyCam.splineProgress += progChange; + + if (gPuppyCam.splineProgress >= 1.0f) + { + gPuppyCam.splineIndex++; + if (splinePos[gPuppyCam.splineIndex+3].index == -1) + { + gPuppyCam.splineIndex = 0; + gPuppyCam.splineProgress = 0; + return 1; + } + gPuppyCam.splineProgress -=1; + } + + return 0; +} + +static void puppycam_process_cutscene(void) +{ + if (gPuppyCam.cutscene) + { + if ((gPuppyCam.sceneFunc)() == 1) + { + gPuppyCam.cutscene = 0; + gPuppyCam.sceneInput = 0; + gPuppyCam.flags = gPuppyCam.intendedFlags; + } + gPuppyCam.sceneTimer++; + } +} + +///MENU + +#define BLANK 0, 0, 0, ENVIRONMENT, 0, 0, 0, ENVIRONMENT + +static void puppycam_display_box(s32 x1, s32 y1, s32 x2, s32 y2, u8 r, u8 g, u8 b, u8 a) +{ + gDPSetCombineMode(gDisplayListHead++, BLANK, BLANK); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); + if (a !=255) + { + gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + } + else + { + gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF); + } + gDPSetEnvColor(gDisplayListHead++, r, g, b, a); + gDPFillRectangle(gDisplayListHead++, x1, y1, x2, y2); + gDPPipeSync(gDisplayListHead++); + gDPSetEnvColor(gDisplayListHead++,255,255,255,255); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); + gSPDisplayList(gDisplayListHead++,dl_hud_img_end); +} + +//I actually took the time to redo this, properly. Lmao. Please don't bully me over this anymore :( +void puppycam_change_setting(s8 toggle) +{ + if (gPlayer1Controller->buttonDown & A_BUTTON) + toggle*= 5; + if (gPlayer1Controller->buttonDown & B_BUTTON) + toggle*= 10; + + if (gPCOptions[gPCOptionSelected].gPCOptionMin == FALSE && gPCOptions[gPCOptionSelected].gPCOptionMax == TRUE) + { + *gPCOptions[gPCOptionSelected].gPCOptionVar ^= 1; + } + else + *gPCOptions[gPCOptionSelected].gPCOptionVar += toggle; + //Forgive me father, for I have sinned. I guess if you wanted a selling point for a 21:9 monitor though, "I can view this line in puppycam's code without scrolling!" can be added to it. + *gPCOptions[gPCOptionSelected].gPCOptionVar = CLAMP(*gPCOptions[gPCOptionSelected].gPCOptionVar, gPCOptions[gPCOptionSelected].gPCOptionMin, gPCOptions[gPCOptionSelected].gPCOptionMax); + + #if defined(VERSION_EU) + newcam_set_language(); + #endif +} + +void puppycam_print_text(s32 x, s32 y, unsigned char *str, s32 col) +{ + s32 textX; + textX = get_str_x_pos_from_center(x,str,10.0f); + gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255); + print_generic_string(textX+1,y-1,str); + if (col != 0) + { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + } + else + { + gDPSetEnvColor(gDisplayListHead++, 255, 32, 32, 255); + } + print_generic_string(textX,y,str); +} + +//Options menu +void puppycam_display_options() +{ + s32 i = 0; + unsigned char newstring[32]; + s32 scroll; + s32 scrollpos; + s16 var; + s32 vr; + s32 maxvar; + s32 minvar; + f32 newcam_sinpos; + + puppycam_display_box(47,83,281,84,0x0,0x0,0x0, 0xFF); + puppycam_display_box(47,218,281,219,0x0,0x0,0x0, 0xFF); + puppycam_display_box(47,83,48,219,0x0,0x0,0x0, 0xFF); + puppycam_display_box(280,83,281,219,0x0,0x0,0x0, 0xFF); + puppycam_display_box(271,83,272,219,0x0,0x0,0x0, 0xFF); + + puppycam_display_box(48,84,272,218,0x0,0x0,0x0, 0x50); + gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + print_hud_lut_string(HUD_LUT_GLOBAL, 112, 40, (*gPCToggleStringsPtr)[2]); + gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); + + if (gPCOptionCap>4) + { + puppycam_display_box(272,84,280,218,0x80,0x80,0x80, 0xFF); + scrollpos = (62)*((f32)gPCOptionScroll/(gPCOptionCap-4)); + puppycam_display_box(272,84+scrollpos,280,156+scrollpos,0xFF,0xFF,0xFF, 0xFF); + } + + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 80, SCREEN_WIDTH, SCREEN_HEIGHT); + for (i = 0; i < gPCOptionCap; i++) + { + scroll = 140-(32*i)+(gPCOptionScroll*32); + if (scroll <= 140 && scroll > 32) + { + puppycam_print_text(160,scroll,(*gPCOptionStringsPtr)[gPCOptions[i].gPCOptionName],gPCOptionSelected-i); + if (gPCOptions[i].gPCOptionStart != 255) + { + var = *gPCOptions[i].gPCOptionVar+gPCOptions[i].gPCOptionStart; + if (var < sizeof(gPCFlagStringsEN)) //Failsafe for if it somehow indexes an out of bounds array. + puppycam_print_text(160,scroll-12,(*gPCFlagStringsPtr)[var],gPCOptionSelected-i); + } + else + { + int_to_str(*gPCOptions[i].gPCOptionVar,newstring); + puppycam_print_text(160,scroll-12,newstring,gPCOptionSelected-i); + puppycam_display_box(96,111+(32*i)-(gPCOptionScroll*32),224,117+(32*i)-(gPCOptionScroll*32),0x80,0x80,0x80, 0xFF); + maxvar = gPCOptions[i].gPCOptionMax - gPCOptions[i].gPCOptionMin; + minvar = *gPCOptions[i].gPCOptionVar - gPCOptions[i].gPCOptionMin; + puppycam_display_box(96,111+(32*i)-(gPCOptionScroll*32),96+(((f32)minvar/maxvar)*128),117+(32*i)-(gPCOptionScroll*32),0xFF,0xFF,0xFF, 0xFF); + puppycam_display_box(94+(((f32)minvar/maxvar)*128),109+(32*i)-(gPCOptionScroll*32),98+(((f32)minvar/maxvar)*128),119+(32*i)-(gPCOptionScroll*32),0xFF,0x0,0x0, 0xFF); + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + } + } + } + newcam_sinpos = sins(gGlobalTimer*5000)*4; + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + print_generic_string(80-newcam_sinpos, 132-(32*(gPCOptionSelected-gPCOptionScroll)), (*gPCToggleStringsPtr)[3]); + print_generic_string(232+newcam_sinpos, 132-(32*(gPCOptionSelected-gPCOptionScroll)), (*gPCToggleStringsPtr)[4]); + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +//This has been separated for interesting reasons. Don't question it. +void puppycam_render_option_text(void) +{ + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + puppycam_print_text(278,212,(*gPCToggleStringsPtr)[gPCOptionOpen],1); + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +extern struct SaveBuffer gSaveBuffer; + +void puppycam_check_pause_buttons() +{ + if (gPlayer1Controller->buttonPressed & R_TRIG) + { + play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource); + if (gPCOptionOpen == 0) + { + gPCOptionOpen = 1; + #if MULTILANG + newcam_set_language(); + eu_set_language(gInGameLanguage-1); + #endif + } + else + { + gPCOptionOpen = 0; + #if MULTILANG + load_language_text(); + #endif + puppycam_set_save(); + } + } + + if (gPCOptionOpen) + { + if (ABS(gPlayer1Controller->rawStickY) > 60 || gPlayer1Controller->buttonDown & U_JPAD || gPlayer1Controller->buttonDown & D_JPAD) + { + gPCOptionTimer -= 1; + if (gPCOptionTimer <= 0) + { + switch (gPCOptionIndex) + { + case 0: gPCOptionIndex++; gPCOptionTimer += 10; break; + default: gPCOptionTimer += 5; break; + } + play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource); + if (gPlayer1Controller->rawStickY >= 60 || gPlayer1Controller->buttonDown & U_JPAD) + { + gPCOptionSelected--; + if (gPCOptionSelected < 0) + gPCOptionSelected = gPCOptionCap-1; + } + else + if (gPlayer1Controller->rawStickY <= -60 || gPlayer1Controller->buttonDown & D_JPAD) + { + gPCOptionSelected++; + if (gPCOptionSelected >= gPCOptionCap) + gPCOptionSelected = 0; + } + } + } + else + if (ABS(gPlayer1Controller->rawStickX) > 60 || gPlayer1Controller->buttonDown & L_JPAD || gPlayer1Controller->buttonDown & R_JPAD) + { + gPCOptionTimer -= 1; + if (gPCOptionTimer <= 0) + { + switch (gPCOptionIndex) + { + case 0: gPCOptionIndex++; gPCOptionTimer += 10; break; + default: gPCOptionTimer += 5; break; + } + play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource); + if (gPlayer1Controller->rawStickX >= 60 || gPlayer1Controller->buttonDown & R_JPAD) + puppycam_change_setting(1); + else + if (gPlayer1Controller->rawStickX <= -60 || gPlayer1Controller->buttonDown & L_JPAD) + puppycam_change_setting(-1); + } + } + else + { + gPCOptionTimer = 0; + gPCOptionIndex = 0; + } + + while (gPCOptionScroll - gPCOptionSelected < -3 && gPCOptionSelected > gPCOptionScroll) + gPCOptionScroll +=1; + while (gPCOptionScroll + gPCOptionSelected > 0 && gPCOptionSelected < gPCOptionScroll) + gPCOptionScroll -=1; + } +} + +///CORE + +//Just a function that sets a bunch of camera values to 0. It's a function because it's got shared functionality. +void puppycam_reset_values(void) +{ + gPuppyCam.swimPitch = 0; + gPuppyCam.edgePitch = 0; + gPuppyCam.moveZoom = 0; + gPuppyCam.floorY[0] = 0; + gPuppyCam.floorY[1] = 0; + gPuppyCam.terrainPitch = 0; + gPuppyCam.splineIndex = 0; + gPuppyCam.splineProgress = 0; +} + +//Set up values. Runs on level load. +void puppycam_init(void) +{ + if (gMarioState->marioObj) + gPuppyCam.targetObj = gMarioState->marioObj; + gPuppyCam.targetObj2 = NULL; + + gPuppyCam.intendedFlags = PUPPYCAM_BEHAVIOUR_DEFAULT; + + if (gCurrLevelNum == 27 || (gCurrLevelNum == 36 && gCurrAreaIndex == 2) || (gCurrLevelNum == 5 && gCurrAreaIndex == 2)) + gPuppyCam.intendedFlags |= PUPPYCAM_BEHAVIOUR_SLIDE_CORRECTION; + gPuppyCam.flags = gPuppyCam.intendedFlags; + gPuppyCam.zoom = gPuppyCam.zoomPoints[1]; + gPuppyCam.zoomSet = 1; + gPuppyCam.zoomTarget = gPuppyCam.zoom; + gPuppyCam.yaw = gMarioState->faceAngle[1]+0x8000; + gPuppyCam.yawTarget = gPuppyCam.yaw; + gPuppyCam.pitch = 0x3800; + gPuppyCam.pitchTarget = gPuppyCam.pitch; + gPuppyCam.yawAcceleration = 0; + gPuppyCam.pitchAcceleration = 0; + gPuppyCam.shakeFrames = 0; + gPuppyCam.shake[0] = 0; + gPuppyCam.shake[1] = 0; + gPuppyCam.shake[2] = 0; + gPuppyCam.pos[0] = 0; + gPuppyCam.pos[1] = 0; + gPuppyCam.pos[2] = 0; + gPuppyCam.focus[0] = 0; + gPuppyCam.focus[1] = 0; + gPuppyCam.focus[2] = 0; + gPuppyCam.pan[0] = 0; + gPuppyCam.pan[1] = 0; //gMarioState->pos[1]; + gPuppyCam.pan[2] = 0; + gPuppyCam.targetFloorHeight = gPuppyCam.pan[1]; + gPuppyCam.lastTargetFloorHeight = gMarioState->pos[1]; + gPuppyCam.opacity = 255; + gPuppyCam.framesSinceC[0] = 10; //This just exists to stop input type B being stupid. + gPuppyCam.framesSinceC[1] = 10; //This just exists to stop input type B being stupid. + gPuppyCam.mode3Flags = PUPPYCAM_MODE3_ZOOMED_MED; + puppycam_reset_values(); +} + +void puppycam_input_pitch(void) +{ + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PITCH_ROTATION) + { + //Handles vertical inputs. + if (gPlayer1Controller->buttonDown & U_CBUTTONS || gPuppyCam.stick2[1] != 0) + gPuppyCam.pitchAcceleration -= 50*(gPuppyCam.options.sensitivityY/100.f); + else + if (gPlayer1Controller->buttonDown & D_CBUTTONS || gPuppyCam.stick2[1] != 0) + gPuppyCam.pitchAcceleration += 50*(gPuppyCam.options.sensitivityY/100.f); + else + gPuppyCam.pitchAcceleration = 0; + + gPuppyCam.pitchAcceleration = CLAMP(gPuppyCam.pitchAcceleration, -100, 100); + + //When Mario's moving, his pitch is clamped pretty aggressively, so this exists so you can shift your view up and down momentarily at an actually usable range, rather than the otherwise baby range. + if (gMarioState->action & ACT_FLAG_MOVING && (gPuppyCam.pitch >= 0x3800 || gPuppyCam.pitch <= 0x2000)) + gPuppyCam.moveFlagAdd = 8; + } +} + +void puppycam_input_zoom(void) +{ + //Handles R button zooming. + if (gPlayer1Controller->buttonPressed & R_TRIG && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE) + { + gPuppyCam.zoomSet++; + + if (gPuppyCam.zoomSet >= 3) + gPuppyCam.zoomSet = 0; + + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[gPuppyCam.zoomSet]; + play_sound(SOUND_MENU_CLICK_CHANGE_VIEW,gGlobalSoundSource); + } +} + +void puppycam_input_centre(void) +{ + s32 inputDefault = L_TRIG; + if (gPuppyCam.options.inputType == 2) + inputDefault = R_TRIG; + //Handles L button centering. + if (gPlayer1Controller->buttonPressed & inputDefault && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION && + !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) && !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) && !(gPlayer1Controller->buttonDown & U_JPAD)) + { + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000; + play_sound(SOUND_MENU_CLICK_CHANGE_VIEW,gGlobalSoundSource); + } +} + +//The default control scheme. Hold the button down to turn the camera, and double tap to turn quickly. +static void puppycam_input_hold_preset1(f32 ivX) +{ + if (!gPuppyCam.options.analogue && gPlayer1Controller->buttonPressed & L_CBUTTONS && gPuppyCam.framesSinceC[0] <= 5) + { + gPuppyCam.yawTarget -= 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + else + if (!gPuppyCam.options.analogue && gPlayer1Controller->buttonPressed & R_CBUTTONS && gPuppyCam.framesSinceC[1] <= 5) + { + gPuppyCam.yawTarget += 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + + if ((gPlayer1Controller->buttonDown & L_CBUTTONS && !gPuppyCam.options.analogue) || gPuppyCam.stick2[0] != 0) + { + gPuppyCam.yawAcceleration -= 75*(gPuppyCam.options.sensitivityX/100.f); + gPuppyCam.framesSinceC[0] = 0; + } + else + if ((gPlayer1Controller->buttonDown & R_CBUTTONS && !gPuppyCam.options.analogue) || gPuppyCam.stick2[0] != 0) + { + gPuppyCam.yawAcceleration += 75*(gPuppyCam.options.sensitivityX/100.f); + gPuppyCam.framesSinceC[1] = 0; + } + else + gPuppyCam.yawAcceleration = 0; +} + +//An alternative control scheme, hold the button down to turn the camera, or press it once to turn it quickly. +static void puppycam_input_hold_preset2(f32 ivX) +{ + //These set the initial button press. + if (gPlayer1Controller->buttonPressed & L_CBUTTONS) + { + gPuppyCam.framesSinceC[0] = 0; + } + + if (gPlayer1Controller->buttonPressed & R_CBUTTONS) + { + gPuppyCam.framesSinceC[1] = 0; + } + + //These handle when you release the button + if ((!(gPlayer1Controller->buttonDown & L_CBUTTONS)) && gPuppyCam.framesSinceC[0] <= 5) + { + gPuppyCam.yawTarget -= 0x3000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + gPuppyCam.framesSinceC[0] = 6; + } + + if ((!(gPlayer1Controller->buttonDown & R_CBUTTONS)) && gPuppyCam.framesSinceC[1] <= 5) + { + gPuppyCam.yawTarget += 0x3000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + gPuppyCam.framesSinceC[1] = 6; + } + + //Handles continuous movement as normal, as long as the button's held. + if (gPlayer1Controller->buttonDown & L_CBUTTONS) + { + gPuppyCam.yawAcceleration -= 75*(gPuppyCam.options.sensitivityX/100.f); + } + else + if (gPlayer1Controller->buttonDown & R_CBUTTONS) + { + gPuppyCam.yawAcceleration += 75*(gPuppyCam.options.sensitivityX/100.f); + } + else + gPuppyCam.yawAcceleration = 0; +} + +//Another alternative control scheme. This one aims to mimic the parallel camera scheme down to the last bit from the original game. +static void puppycam_input_hold_preset3(void) +{ + f32 stickMag[2] = {gPlayer1Controller->rawStickX*0.65f, gPlayer1Controller->rawStickY*0.2f}; + //Just in case it happens to be nonzero. + gPuppyCam.yawAcceleration = 0; + + //In theory this shouldn't be necessary, but it's nice to cover all bases. + if (!(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION)) + return; + + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_IN) + { + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_COLLISION; + + //Handles continuous movement as normal, as long as the button's held. + if (ABS(gPlayer1Controller->rawStickX) > DEADZONE) + { + gPuppyCam.yawAcceleration -= (gPuppyCam.options.sensitivityX/100.f)*stickMag[0]; + } + else + gPuppyCam.yawAcceleration = 0; + + if (ABS(gPlayer1Controller->rawStickY) > DEADZONE) + { + gPuppyCam.pitchAcceleration -= (gPuppyCam.options.sensitivityY/100.f)*stickMag[1]; + } + else + gPuppyCam.pitchAcceleration = approach_f32_asymptotic(gPuppyCam.pitchAcceleration, 0, DECELERATION); + } + else + { + if (gPlayer1Controller->buttonPressed & L_TRIG) + { + if (gPuppyCam.yawTarget % 0x2000) + gPuppyCam.yawTarget += 0x2000 - gPuppyCam.yawTarget % 0x2000; + } + + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_MED) + gPuppyCam.pitchTarget = approach_s32(gPuppyCam.pitchTarget, 0x3800, 0x200, 0x200); + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_OUT) + gPuppyCam.pitchTarget = approach_s32(gPuppyCam.pitchTarget, 0x3000, 0x200, 0x200); + + if (gPlayer1Controller->buttonPressed & L_CBUTTONS) + { + gPuppyCam.yawTarget -= 0x2000; + play_sound(SOUND_MENU_CAMERA_TURN,gGlobalSoundSource); + } + if (gPlayer1Controller->buttonPressed & R_CBUTTONS) + { + gPuppyCam.yawTarget += 0x2000; + play_sound(SOUND_MENU_CAMERA_TURN,gGlobalSoundSource); + } + } + + //Handles zooming in. Works just like vanilla. + if (gPlayer1Controller->buttonPressed & U_CBUTTONS) + { + if ((gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_MED) && !(gMarioState->action & ACT_FLAG_AIR) && !(gMarioState->action & ACT_FLAG_SWIMMING)) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_IN; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.zoomTarget = 200; + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ENTER_FIRST_PERSON; + + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + else + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_OUT) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_OUT; + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[1]; + + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + } + else //Otherwise handle zooming out. + if (gPlayer1Controller->buttonPressed & D_CBUTTONS) + { + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_MED) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_OUT; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[2]; + + play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + } + if (gPlayer1Controller->buttonPressed & D_CBUTTONS || gPlayer1Controller->buttonPressed & B_BUTTON || gPlayer1Controller->buttonPressed & A_BUTTON) + { + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_IN) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_IN; + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[1]; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ENTER_FIRST_PERSON; + + play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + } +} + +//Handles C Button inputs for modes that have held inputs, rather than presses. +static void puppycam_input_hold(void) +{ + f32 ivX = ((gPuppyCam.options.invertX*2)-1)*(gPuppyCam.options.sensitivityX/100.f); + f32 ivY = ((gPuppyCam.options.invertY*2)-1)*(gPuppyCam.options.sensitivityY/100.f); + s8 stickMag[2] = {100, 100}; + + //Analogue Camera stuff. If it fails to find an input, then it just sets stickmag to 100, which after calculations means the value goes unchanged. + if (gPuppyCam.options.analogue && gPuppyCam.options.inputType != 2) + { + stickMag[0] = gPuppyCam.stick2[0]*1.25f; + stickMag[1] = gPuppyCam.stick2[1]*1.25f; + } + + //In theory this shouldn't be necessary, but it's nice to cover all bases. + if (!(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION)) + return; + + if (!gPuppyCam.options.analogue) + { + switch (gPuppyCam.options.inputType) + { + default: puppycam_input_hold_preset1(ivX); puppycam_input_pitch(); puppycam_input_zoom(); puppycam_input_centre(); break; + case 1: puppycam_input_hold_preset2(ivX); puppycam_input_pitch(); puppycam_input_zoom(); puppycam_input_centre(); break; + case 2: puppycam_input_hold_preset3(); puppycam_input_centre(); break; + } + } + else + { + puppycam_input_hold_preset1(ivX); + } + + gPuppyCam.framesSinceC[0]++; + gPuppyCam.framesSinceC[1]++; + + gPuppyCam.yawAcceleration = CLAMP(gPuppyCam.yawAcceleration, -100, 100); + + gPuppyCam.yawTarget += (12*gPuppyCam.yawAcceleration*ivX)*(stickMag[0]*0.01f); + gPuppyCam.pitchTarget += ((4+gPuppyCam.moveFlagAdd)*gPuppyCam.pitchAcceleration*ivY)*(stickMag[1]*0.01f); +} + +//Handles C Button inputs for modes that have pressed inputs, rather than held. +static void puppycam_input_press(void) +{ + f32 ivX = ((gPuppyCam.options.invertX*2)-1)*(gPuppyCam.options.sensitivityX/100.f); + f32 ivY = ((gPuppyCam.options.invertY*2)-1)*(gPuppyCam.options.sensitivityY/100.f); + s8 stickMag = 0; + + //Analogue Camera stuff. If it fails to find an input, then it just sets stickmag to 100, which after calculations means the value goes unchanged. + if (gPuppyCam.options.analogue) + stickMag = gPuppyCam.stick2[0]*1.25f; + else + stickMag = 100; + + //Just in case it happens to be nonzero. + gPuppyCam.yawAcceleration = 0; + + //In theory this shouldn't be necessary, but it's nice to cover all bases. + if (!(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION)) + return; + + if ((gPlayer1Controller->buttonPressed & L_CBUTTONS && !gPuppyCam.options.analogue) || (gPuppyCam.stickN[0] == 0 && gPuppyCam.stick2[0] < -DEADZONE)) + { + gPuppyCam.stickN[0] = 1; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) + gPuppyCam.yawTarget -= 0x2000*ivX; + else + gPuppyCam.yawTarget -= 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN,gGlobalSoundSource); + } + + if ((gPlayer1Controller->buttonPressed & R_CBUTTONS && !gPuppyCam.options.analogue) || (gPuppyCam.stickN[0] == 0 && gPuppyCam.stick2[0] > DEADZONE)) + { + gPuppyCam.stickN[0] = 1; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) + gPuppyCam.yawTarget += 0x2000*ivX; + else + gPuppyCam.yawTarget += 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN,gGlobalSoundSource); + } + puppycam_input_pitch(); + gPuppyCam.pitchTarget += ((4+gPuppyCam.moveFlagAdd)*gPuppyCam.pitchAcceleration*ivY)*(stickMag*0.01f); +} + +static void puppycam_view_panning(void) +{ + f32 panFloor, panMulti; + s32 expectedPanX, expectedPanZ; + s32 height = gPuppyCam.targetObj->oPosY; + s32 panEx = (gPuppyCam.zoomTarget >= 1000) * 160; //Removes the basic panning when idling if the zoom level is at the closest. + f32 slideSpeed = 1; + + panMulti = CLAMP(gPuppyCam.zoom/(f32)gPuppyCam.zoomPoints[2], 0.f, 1.f); + if (gPuppyCam.options.inputType == 2) + panMulti /= 2; + + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PANSHIFT && gMarioState->action != ACT_HOLDING_BOWSER && gMarioState->action != ACT_SLEEPING && gMarioState->action != ACT_START_SLEEPING) + { + if (gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE) + slideSpeed = 10; + + expectedPanX = LENSIN(panEx+(200*(gMarioState->forwardVel/320.f)), gMarioState->faceAngle[1])*panMulti; + expectedPanZ = LENCOS(panEx+(200*(gMarioState->forwardVel/320.f)), gMarioState->faceAngle[1])*panMulti; + + gPuppyCam.pan[0] = approach_f32_asymptotic(gPuppyCam.pan[0], expectedPanX, 0.02f*slideSpeed); + gPuppyCam.pan[2] = approach_f32_asymptotic(gPuppyCam.pan[2], expectedPanZ, 0.02f*slideSpeed); + if (gMarioState->vel[1] == 0.0f) + { + panFloor = CLAMP(find_floor_height((s16)(gPuppyCam.targetObj->oPosX+expectedPanX),(s16)(gPuppyCam.targetObj->oPosY + 200), + (s16)(gPuppyCam.targetObj->oPosZ+expectedPanZ)),gPuppyCam.targetObj->oPosY-50,gPuppyCam.targetObj->oPosY+50); + //If the floor is lower than 150 units below Mario, then ignore the Y value and tilt the camera instead. + if (panFloor <= gPuppyCam.targetObj->oPosY-150) + { + panFloor = gPuppyCam.targetObj->oPosY; + gPuppyCam.edgePitch = approach_s32(gPuppyCam.edgePitch, -0x2000, 0x80, 0x80); + } + else + { + gPuppyCam.edgePitch = approach_s32(gPuppyCam.edgePitch, 0, 0x100, 0x100); + } + + gPuppyCam.pan[1] = approach_f32_asymptotic(gPuppyCam.pan[1], panFloor-height, 0.025f); + } + else + gPuppyCam.pan[1] = approach_f32_asymptotic(gPuppyCam.pan[1], 0, 0.05f); + } + else + { + gPuppyCam.pan[0] = 0; + gPuppyCam.pan[1] = 0; + gPuppyCam.pan[2] = 0; + } +} + +void puppycam_terrain_angle(void) +{ + f32 adjustSpeed; + s32 floor2 = find_floor_height(gPuppyCam.pos[0], gPuppyCam.pos[1]+100, gPuppyCam.pos[2]); + s32 ceil = 20000;//find_ceil(gPuppyCam.pos[0], gPuppyCam.pos[1]+100, gPuppyCam.pos[2]); + s32 farFromSurface; + s16 floorPitch; + s32 gotTheOkay = FALSE; + + if (gMarioState->action & ACT_FLAG_SWIMMING || !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_HEIGHT_HELPER)) + { + gPuppyCam.intendedTerrainPitch = 0; + adjustSpeed = 0.25f; + farFromSurface = TRUE; + } + else + { + f32 x, z, floorHeight; + adjustSpeed = CLAMP(MAX(gMarioState->forwardVel/480.0f, gPuppyCam.yawAcceleration/100.0f), 0.05f, 1.0f); + + x = gPuppyCam.targetObj->oPosX - (10 * sins(gPuppyCam.yaw)); + z = gPuppyCam.targetObj->oPosZ - (10 * coss(gPuppyCam.yaw)); + + floorHeight = find_floor_height(x, gPuppyCam.targetObj->oPosY+100, z); + + if (ABS(gMarioState->floorHeight - floorHeight) > 350) + { + gPuppyCam.intendedTerrainPitch = 0; + } + else + { + floorPitch = -atan2s(30.0f, gMarioState->floorHeight - floorHeight); + gPuppyCam.intendedTerrainPitch = approach_f32_asymptotic(gPuppyCam.intendedTerrainPitch, floorPitch, adjustSpeed); + gotTheOkay = TRUE; + } + + //Ensures that the camera is below and above floors and ceilings. It ignores this rule for each if the camera's headed upwards anyway. + farFromSurface = ((gPuppyCam.pos[1] > floor2 + 50 || gPuppyCam.intendedTerrainPitch < gPuppyCam.terrainPitch) && (gPuppyCam.pos[1] < ceil - 50 || gPuppyCam.intendedTerrainPitch > gPuppyCam.terrainPitch)); + + //If the camera is too close to a vertical obstruction, it'll make the intended pitch much further away, making it swivel faster. + if (!farFromSurface && gotTheOkay) + gPuppyCam.intendedTerrainPitch = approach_f32_asymptotic(gPuppyCam.intendedTerrainPitch, floorPitch, adjustSpeed*3); + } + + if (farFromSurface) + gPuppyCam.terrainPitch = approach_f32_asymptotic(gPuppyCam.terrainPitch, gPuppyCam.intendedTerrainPitch, adjustSpeed); +} + +const struct sPuppyAngles puppyAnglesNull = +{ + {PUPPY_NULL, PUPPY_NULL, PUPPY_NULL}, + {PUPPY_NULL, PUPPY_NULL, PUPPY_NULL}, + PUPPY_NULL, + PUPPY_NULL, + PUPPY_NULL, +}; + +//Checks the bounding box of a puppycam volume. If it's inside, then set the pointer to the current index. +static s32 puppycam_check_volume_bounds(struct sPuppyVolume *volume, s32 index) +{ + s32 rel[3]; + s32 pos[2]; + f32 distCheck; + + if (sPuppyVolumeStack[index]->room != gMarioCurrentRoom && sPuppyVolumeStack[index]->room != -1) + return FALSE; + + if (sPuppyVolumeStack[index]->shape == PUPPYVOLUME_SHAPE_BOX) + { + //Fetch the relative position. to the triggeree. + rel[0] = sPuppyVolumeStack[index]->pos[0] - gPuppyCam.targetObj->oPosX; + rel[1] = sPuppyVolumeStack[index]->pos[1] - gPuppyCam.targetObj->oPosY; + rel[2] = sPuppyVolumeStack[index]->pos[2] - gPuppyCam.targetObj->oPosZ; + //Use the dark, forbidden arts of trig to rotate the volume. + pos[0] = rel[2] * sins(sPuppyVolumeStack[index]->rot) + rel[0] * coss(sPuppyVolumeStack[index]->rot); + pos[1] = rel[2] * coss(sPuppyVolumeStack[index]->rot) - rel[0] * sins(sPuppyVolumeStack[index]->rot); + #ifdef VISUAL_DEBUG + Vec3f debugPos[2]; + vec3f_set(debugPos[0], sPuppyVolumeStack[index]->pos[0], sPuppyVolumeStack[index]->pos[1], sPuppyVolumeStack[index]->pos[2]); + vec3f_set(debugPos[1], sPuppyVolumeStack[index]->radius[0], sPuppyVolumeStack[index]->radius[1], sPuppyVolumeStack[index]->radius[2]); + debug_box_color(0x0000FF00); + debug_box_rot(debugPos[0], debugPos[1], sPuppyVolumeStack[index]->rot, DEBUG_SHAPE_BOX); + #endif + //Now compare values. + if (-sPuppyVolumeStack[index]->radius[0] < pos[0] && pos[0] < sPuppyVolumeStack[index]->radius[0] && + -sPuppyVolumeStack[index]->radius[1] < rel[1] && rel[1] < sPuppyVolumeStack[index]->radius[1] && + -sPuppyVolumeStack[index]->radius[2] < pos[1] && pos[1] < sPuppyVolumeStack[index]->radius[2]) + { + *volume = *sPuppyVolumeStack[index]; + return TRUE; + } + } + else + if (sPuppyVolumeStack[index]->shape == PUPPYVOLUME_SHAPE_CYLINDER) + { + s16 dir; + f32 dist; + rel[0] = sPuppyVolumeStack[index]->pos[0] - gPuppyCam.targetObj->oPosX; + rel[1] = sPuppyVolumeStack[index]->pos[1] - gPuppyCam.targetObj->oPosY; + rel[2] = sPuppyVolumeStack[index]->pos[2] - gPuppyCam.targetObj->oPosZ; + dist = sqrtf((rel[0] * rel[0]) + (rel[2] * rel[2])); + #ifdef VISUAL_DEBUG + Vec3f debugPos[2]; + vec3f_set(debugPos[0], sPuppyVolumeStack[index]->pos[0], sPuppyVolumeStack[index]->pos[1], sPuppyVolumeStack[index]->pos[2]); + vec3f_set(debugPos[1], sPuppyVolumeStack[index]->radius[0], sPuppyVolumeStack[index]->radius[1], sPuppyVolumeStack[index]->radius[2]); + debug_box_color(0x0000FF00); + debug_box_rot(debugPos[0], debugPos[1], sPuppyVolumeStack[index]->rot, DEBUG_SHAPE_CYLINDER); + #endif + distCheck = (dist < sPuppyVolumeStack[index]->radius[0]); + + if (-sPuppyVolumeStack[index]->radius[1] < rel[1] && rel[1] < sPuppyVolumeStack[index]->radius[1] && distCheck) + { + *volume = *sPuppyVolumeStack[index]; + return TRUE; + } + + } + + return FALSE; +} + +//Handles wall adjustment when wall kicking. +void puppycam_wall_angle(void) +{ + struct Surface *wall; + struct WallCollisionData cData; + s16 wallYaw; + + if (!(gMarioState->action & ACT_WALL_KICK_AIR) || ((gMarioState->action & ACT_FLAG_AIR) && ABS(gMarioState->forwardVel) < 16.0f) || !(gMarioState->action & ACT_FLAG_AIR)) + return; + + cData.x = gPuppyCam.targetObj->oPosX; + cData.y = gPuppyCam.targetObj->oPosY; + cData.z = gPuppyCam.targetObj->oPosZ; + cData.radius = 150.0f; + cData.offsetY = 0; + + if (find_wall_collisions(&cData)) + wall = cData.walls[cData.numWalls - 1]; + else + return; + wallYaw = atan2s(wall->normal.z, wall->normal.x) + 0x4000; + + wallYaw -= gPuppyCam.yawTarget; + if (wallYaw % 0x4000) + wallYaw += 0x4000 - wallYaw % 0x4000; + + gPuppyCam.yawTarget = approach_s32(gPuppyCam.yawTarget, wallYaw, 0x200, 0x200); +} + +void puppycam_projection_behaviours(void) +{ + f32 turnRate = 1; + + //This will only be executed if Mario's the target. If it's not, it'll reset the + if (gPuppyCam.targetObj == gMarioState->marioObj) + { + if (gPuppyCam.options.turnAggression > 0 && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_TURN_HELPER && !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) && + gMarioState->vel[1] == 0.0f && !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) && gPuppyCam.options.inputType != 2) + {//Holy hell this is getting spicy. + //With turn aggression enabled, or if Mario's sliding, adjust the camera view behind mario. + if (gPuppyCam.options.turnAggression > 0 || gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE) + { + if (gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE) + turnRate = 4; //If he's sliding, do it 4x as fast. + //The deal here, is if Mario's moving, or he's sliding and the camera's within 90 degrees behind him, it'll auto focus behind him, with an intensity based on the camera's centre speed. + //It also scales with forward velocity, so it's a gradual effect as he speeds up. + if ((ABS(gPlayer1Controller->rawStickX) > 20 && !(gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE)) || + (gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE && + (s16)ABS(((gPuppyCam.yaw + 0x8000) % 0xFFFF - 0x8000) - ((gMarioState->faceAngle[1]) % 0xFFFF - 0x8000)) < 0x3000 )) + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000 - approach_s32((s16)(gMarioState->faceAngle[1]+0x8000 - gPuppyCam.yawTarget), 0, + ((gPuppyCam.options.turnAggression*10)*ABS(gMarioState->forwardVel/32) * ABS(gPlayer1Controller->rawStickX/80.0f)*turnRate), + ((gPuppyCam.options.turnAggression*10)*ABS(gMarioState->forwardVel/32) * ABS(gPlayer1Controller->rawStickX/80.0f)*turnRate)); + } + } + else + { //If none of the above is true, it'll attempt to do this instead. + //If the camera's in these modes, snap the yaw to prevent desync. + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) + { + if (gPuppyCam.yawTarget % 0x2000) + gPuppyCam.yawTarget += 0x2000 - gPuppyCam.yawTarget % 0x2000; + } + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) + { + if (gPuppyCam.yawTarget % 0x4000) + gPuppyCam.yawTarget += 0x4000 - gPuppyCam.yawTarget % 0x4000; + } + } + + //This is the base floor height when stood on the ground. It's used to set a baseline for where the camera sits while Mario remains a height from this point, so it keeps a consistent motion. + gPuppyCam.targetFloorHeight = CLAMP(find_floor_height(gPuppyCam.targetObj->oPosX, gPuppyCam.targetObj->oPosY, gPuppyCam.targetObj->oPosZ), gPuppyCam.targetObj->oPosY-350, gPuppyCam.targetObj->oPosY+300); + gPuppyCam.lastTargetFloorHeight = approach_f32_asymptotic(gPuppyCam.lastTargetFloorHeight + , gPuppyCam.targetFloorHeight + , CLAMP((absf(gMarioState->vel[1]) - 17.f) / 200.f, 0, 0.1f) + + CLAMP((absf(gPuppyCam.targetFloorHeight - gPuppyCam.lastTargetFloorHeight) - 30.f) / 300.f, 0, 0.1f)); + + if (gMarioState->action == ACT_SLEEPING || gMarioState->action == ACT_START_SLEEPING) + gPuppyCam.zoom = approach_f32_asymptotic(gPuppyCam.zoom,gPuppyCam.zoomPoints[0],0.01f); + else + if (gMarioState->action & ACT_FLAG_SWIMMING && gMarioState->waterLevel-100 - gMarioState->pos[1] > 5) + { + //When moving underwater, the camera will zoom in on Mayro. + gPuppyCam.zoom = approach_f32_asymptotic(gPuppyCam.zoom, MAX(gPuppyCam.zoomTarget/1.5f, gPuppyCam.zoomPoints[0]), 0.2f); + } + else + gPuppyCam.zoom = approach_f32_asymptotic(gPuppyCam.zoom,gPuppyCam.zoomTarget,0.2f); + + //Attempts at automatic adjustment that only apply when moving or jumping. + if (gMarioState->action & ACT_FLAG_MOVING || gMarioState->action & ACT_FLAG_AIR || (gMarioState->action & ACT_FLAG_SWIMMING && !gMarioState->waterLevel-100 - gMarioState->pos[1] > 5 && gMarioState->forwardVel != 0.0f)) + { + //Clamp the height when moving. You can still look up and down to a reasonable degree but it readjusts itself the second you let go. + if (gPuppyCam.pitchTarget > 0x3800) + gPuppyCam.pitchTarget = approach_f32_asymptotic(gPuppyCam.pitchTarget, 0x3800, 0.2f); + + if (gPuppyCam.pitchTarget < 0x2000) + gPuppyCam.pitchTarget = approach_f32_asymptotic(gPuppyCam.pitchTarget, 0x2000, 0.2f); + } + + //Applies a light outward zoom to the camera when moving. Sets it back to 0 when not moving. + if (gMarioState->forwardVel > 0) + { + gPuppyCam.moveZoom = approach_f32(gPuppyCam.moveZoom, 100.0f*(gMarioState->forwardVel/32.0f), gMarioState->forwardVel/10, gMarioState->forwardVel/10); + } + else + { + gPuppyCam.moveZoom = approach_f32(gPuppyCam.moveZoom, 0, 5, 5); + } + + //Zooms the camera in further when underwater. + if (gPuppyCam.pitch > 0x38C0 && ABS(gPuppyCam.swimPitch) < 100) + { + gPuppyCam.zoom = approach_f32_asymptotic((f32)gPuppyCam.zoom, 250.0f, CLAMP((f32)((gPuppyCam.pitch-0x38C0)/3072.0f), 0.0f, 1.0f)); + } + + if (!(gMarioState->action & ACT_FLAG_SWIMMING)) + { + gPuppyCam.floorY[0] = softClamp(gPuppyCam.targetObj->oPosY - gPuppyCam.lastTargetFloorHeight, -180, 300); + gPuppyCam.floorY[1] = softClamp(gPuppyCam.targetObj->oPosY - gPuppyCam.lastTargetFloorHeight, -180, 350); + gPuppyCam.swimPitch = approach_f32_asymptotic(gPuppyCam.swimPitch,0,0.2f); + } + else + { + gPuppyCam.floorY[0] = 0; + gPuppyCam.floorY[1] = 0; + gPuppyCam.targetFloorHeight = gPuppyCam.targetObj->oPosY; + gPuppyCam.lastTargetFloorHeight = gPuppyCam.targetObj->oPosY; + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000 - approach_s32((s16)(gMarioState->faceAngle[1]+0x8000 - gPuppyCam.yawTarget), 0, + 1000*(gMarioState->forwardVel/32), 1000*(gMarioState->forwardVel/32)); + if (gMarioState->waterLevel-100 - gMarioState->pos[1] > 5 && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PITCH_ROTATION) + gPuppyCam.swimPitch = approach_f32_asymptotic(gPuppyCam.swimPitch,gMarioState->faceAngle[0]/10,0.05f); + else + gPuppyCam.swimPitch = approach_f32_asymptotic(gPuppyCam.swimPitch,0,0.2f); + } + + //This sets the view offset from Mario. It accentuates a bit further when moving. + puppycam_view_panning(); + + //This sets a pseudo tilt offset based on the floor heights in front and behind mario. + puppycam_terrain_angle(); + + //This will shift the intended yaw when wall kicking, to align with the wall being kicked. + //puppycam_wall_angle(); + } + else + { + puppycam_reset_values(); + } +} + +void puppycam_shake(s16 x, s16 y, s16 z) +{ + +} + +///This is the highest level of the basic steps that go into the code. Anything above is called from these following functions. + +//The centrepiece behind the input side of PuppyCam. The C buttons branch off. +static void puppycam_input_core(void) +{ + puppycam_analogue_stick(); + gPuppyCam.moveFlagAdd = 0; + + //Decide which input for left and right C buttons to use based on behaviour type. + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_NORMAL) + puppycam_input_hold(); + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR || gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) + puppycam_input_press(); +} + +//Calculates the base position the camera should be, before any modification. +static void puppycam_projection(void) +{ + Vec3s targetPos, targetPos2, targetPos3; + s16 pitchTotal; + s32 panD = (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PANSHIFT)/8192; + + //Extra behaviours that get tacked onto the projection. Will be completely ignored if there is no target object. + puppycam_projection_behaviours(); + //These are what the base rotations aspire to be. + gPuppyCam.pitch = CLAMP(gPuppyCam.pitch,0x1000,0x7000); + gPuppyCam.pitchTarget = CLAMP(gPuppyCam.pitchTarget,0x1000,0x7000); + //These are the base rotations going to be used. + gPuppyCam.yaw = gPuppyCam.yawTarget - approach_f32_asymptotic((s16)(gPuppyCam.yawTarget - gPuppyCam.yaw), 0, 0.3335f); + gPuppyCam.pitch = gPuppyCam.pitchTarget - approach_f32_asymptotic((s16)(gPuppyCam.pitchTarget - gPuppyCam.pitch), 0, 0.3335f); + //This adds the pitch effect when underwater, which is capped so it doesn't get out of control. If you're not swimming, swimpitch is 0, so it's normal. + pitchTotal = CLAMP(gPuppyCam.pitch+(gPuppyCam.swimPitch*10)+gPuppyCam.edgePitch + gPuppyCam.terrainPitch, 800, 0x7800); + + if (gPuppyCam.targetObj) + { + vec3s_set(targetPos, gPuppyCam.targetObj->oPosX, gPuppyCam.targetObj->oPosY, gPuppyCam.targetObj->oPosZ); + vec3s_copy(targetPos3, targetPos); + if (gPuppyCam.targetObj2) + { + vec3s_set(targetPos2, gPuppyCam.targetObj2->oPosX, gPuppyCam.targetObj2->oPosY, gPuppyCam.targetObj2->oPosZ); + targetPos3[0] = (s16)approach_f32_asymptotic(targetPos[0], targetPos2[0], 0.5f); + targetPos3[1] = (s16)approach_f32_asymptotic(targetPos[1], targetPos2[1], 0.5f); + targetPos3[2] = (s16)approach_f32_asymptotic(targetPos[2], targetPos2[2], 0.5f); + gPuppyCam.targetDist[0] = approach_f32_asymptotic(gPuppyCam.targetDist[0],(ABS(LENCOS(sqrtf(((targetPos[0]-targetPos2[0])*(targetPos[0]-targetPos2[0]))+((targetPos[2]-targetPos2[2])*(targetPos[2]-targetPos2[2]))), + (s16)ABS(((gPuppyCam.yaw + 0x8000) % 0xFFFF - 0x8000) - (atan2s(targetPos[2]-targetPos2[2], targetPos[0]-targetPos2[0])) % 0xFFFF - 0x8000)+0x4000))), 0.2f); + } + else + { + gPuppyCam.targetDist[0] = approach_f32_asymptotic(gPuppyCam.targetDist[0], 0, 0.2f); + } + + gPuppyCam.targetDist[1] = gPuppyCam.targetDist[0] + gPuppyCam.zoom+gPuppyCam.moveZoom; + + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_X_MOVEMENT) + gPuppyCam.focus[0] = targetPos3[0] + gPuppyCam.shake[0] + (gPuppyCam.pan[0]*gPuppyCam.targetDist[1]/gPuppyCam.zoomPoints[2])*panD; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Y_MOVEMENT) + gPuppyCam.focus[1] = targetPos3[1] + gPuppyCam.shake[1] + (gPuppyCam.pan[1]*gPuppyCam.targetDist[1]/gPuppyCam.zoomPoints[2]) + gPuppyCam.povHeight - gPuppyCam.floorY[0] + (gPuppyCam.swimPitch/10); + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Z_MOVEMENT) + gPuppyCam.focus[2] = targetPos3[2] + gPuppyCam.shake[2] + (gPuppyCam.pan[2]*gPuppyCam.targetDist[1]/gPuppyCam.zoomPoints[2])*panD; + + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_X_MOVEMENT) + gPuppyCam.pos[0] = gPuppyCam.targetObj->oPosX + LENSIN(LENSIN(gPuppyCam.targetDist[1],pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[0]; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Y_MOVEMENT) + gPuppyCam.pos[1] = gPuppyCam.targetObj->oPosY + gPuppyCam.povHeight + LENCOS(gPuppyCam.targetDist[1],pitchTotal) + gPuppyCam.shake[1] - gPuppyCam.floorY[1]; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Z_MOVEMENT) + gPuppyCam.pos[2] = gPuppyCam.targetObj->oPosZ + LENCOS(LENSIN(gPuppyCam.targetDist[1],pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[2]; + } + +} + +//Calls any scripts to affect the camera, if applicable. +static void puppycam_script(void) +{ + u16 i = 0; + struct sPuppyVolume volume; + void (*func)(); + + if (gPuppyVolumeCount == 0 || !gPuppyCam.targetObj) + return; + + for (i = 0; i < gPuppyVolumeCount; i++) + { + if (puppycam_check_volume_bounds(&volume, i)) + { + //First applies pos and focus, for the most basic of volumes. + if (volume.angles != NULL) + { + if (volume.angles->pos[0] != PUPPY_NULL) + gPuppyCam.pos[0] = volume.angles->pos[0]; + if (volume.angles->pos[1] != PUPPY_NULL) + gPuppyCam.pos[1] = volume.angles->pos[1]; + if (volume.angles->pos[2] != PUPPY_NULL) + gPuppyCam.pos[2] = volume.angles->pos[2]; + + if (volume.angles->focus[0] != PUPPY_NULL) + gPuppyCam.focus[0] = volume.angles->focus[0]; + if (volume.angles->focus[1] != PUPPY_NULL) + gPuppyCam.focus[1] = volume.angles->focus[1]; + if (volume.angles->focus[2] != PUPPY_NULL) + gPuppyCam.focus[2] = volume.angles->focus[2]; + + if (volume.angles->yaw != PUPPY_NULL) + { + gPuppyCam.yawTarget = volume.angles->yaw; + gPuppyCam.yaw = volume.angles->yaw; + + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_YAW_ROTATION; + } + + if (volume.angles->pitch != PUPPY_NULL) + { + gPuppyCam.pitchTarget = volume.angles->pitch; + gPuppyCam.pitch = volume.angles->pitch; + + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_PITCH_ROTATION; + } + + if (volume.angles->zoom != PUPPY_NULL) + { + gPuppyCam.zoomTarget = volume.angles->zoom; + gPuppyCam.zoom = gPuppyCam.zoomTarget; + + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE; + } + } + + //Adds and removes behaviour flags, as set. + if (volume.flagsRemove) + gPuppyCam.flags &= ~volume.flagsRemove; + if (volume.flagsAdd) + gPuppyCam.flags |= volume.flagsAdd; + if (volume.flagPersistance == PUPPYCAM_BEHAVIOUR_PERMANENT) + { + //Adds and removes behaviour flags, as set. + if (volume.flagsRemove) + gPuppyCam.intendedFlags &= ~volume.flagsRemove; + if (volume.flagsAdd) + gPuppyCam.intendedFlags |= volume.flagsAdd; + } + + //Last and probably least, check if there's a function attached, and call it, if so. + if (volume.func) + { + func = volume.func; + (func)(); + } + } + } +} + +//Handles collision detection using ray casting. +static void puppycam_collision(void) +{ + struct Surface *surf[2]; + Vec3f camdir[2]; + Vec3f hitpos[2]; + Vec3f target[2]; + s16 pitchTotal = CLAMP(gPuppyCam.pitch+(gPuppyCam.swimPitch*10) + gPuppyCam.edgePitch + gPuppyCam.terrainPitch, 800, 0x7800); + s32 dist[2]; + + if (gPuppyCam.targetObj == NULL) + return; + + //The ray, starting from the top + target[0][0] = gPuppyCam.targetObj->oPosX; + target[0][1] = gPuppyCam.targetObj->oPosY + (gPuppyCam.povHeight) - CLAMP(gPuppyCam.targetObj->oPosY - gPuppyCam.targetFloorHeight, 0, 300); + target[0][2] = gPuppyCam.targetObj->oPosZ; + //The ray, starting from the bottom + target[1][0] = gPuppyCam.targetObj->oPosX; + target[1][1] = gPuppyCam.targetObj->oPosY + (gPuppyCam.povHeight *0.4f); + target[1][2] = gPuppyCam.targetObj->oPosZ; + + camdir[0][0] = LENSIN(LENSIN(gPuppyCam.zoomTarget,pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[0]; + camdir[0][1] = LENCOS(gPuppyCam.zoomTarget,pitchTotal) + gPuppyCam.shake[1]; + camdir[0][2] = LENCOS(LENSIN(gPuppyCam.zoomTarget,pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[2]; + + camdir[1][0] = camdir[0][0]; + camdir[1][1] = camdir[0][1]; + camdir[1][2] = camdir[0][2]; + + find_surface_on_ray(target[0], camdir[0], &surf[0], hitpos[0], RAYCAST_FIND_FLOOR | RAYCAST_FIND_CEIL | RAYCAST_FIND_WALL); + find_surface_on_ray(target[1], camdir[1], &surf[1], hitpos[1], RAYCAST_FIND_FLOOR | RAYCAST_FIND_CEIL | RAYCAST_FIND_WALL); + resolve_and_return_wall_collisions(hitpos[0], 0.0f, 25.0f); + resolve_and_return_wall_collisions(hitpos[1], 0.0f, 25.0f); + dist[0] = ((target[0][0] - hitpos[0][0]) * (target[0][0] - hitpos[0][0]) + (target[0][1] - hitpos[0][1]) * (target[0][1] - hitpos[0][1]) + (target[0][2] - hitpos[0][2]) * (target[0][2] - hitpos[0][2])); + dist[1] = ((target[1][0] - hitpos[1][0]) * (target[1][0] - hitpos[1][0]) + (target[1][1] - hitpos[1][1]) * (target[1][1] - hitpos[1][1]) + (target[1][2] - hitpos[1][2]) * (target[1][2] - hitpos[1][2])); + + gPuppyCam.collisionDistance = gPuppyCam.zoomTarget; + + if (surf[0] && surf[1]) + { + gPuppyCam.collisionDistance = sqrtf(MAX(dist[0], dist[1])); + if (gPuppyCam.zoom > gPuppyCam.collisionDistance) + { + gPuppyCam.zoom = MIN(gPuppyCam.collisionDistance, gPuppyCam.zoomTarget); + if (gPuppyCam.zoom - gPuppyCam.zoomTarget < 5) + { + if (dist[0] >= dist[1]) + { + gPuppyCam.pos[0] = hitpos[0][0]; + gPuppyCam.pos[1] = hitpos[0][1]; + gPuppyCam.pos[2] = hitpos[0][2]; + } + else + { + gPuppyCam.pos[0] = hitpos[1][0]; + gPuppyCam.pos[1] = hitpos[1][1] + (gPuppyCam.povHeight*0.6f); + gPuppyCam.pos[2] = hitpos[1][2]; + } + } + } + } + + #define START_DIST 500 + #define END_DIST 250 + gPuppyCam.opacity = CLAMP((f32)(((gPuppyCam.zoom-END_DIST)/255.0f)*(START_DIST-END_DIST)), 0, 255); +} + +extern Vec3f sOldPosition; +extern Vec3f sOldFocus; +extern struct PlayerGeometry sMarioGeometry; + +//Applies the PuppyCam values to the actual game's camera, giving the final product. +static void puppycam_apply(void) +{ + vec3f_set(gLakituState.pos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(gLakituState.goalPos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(gLakituState.curPos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(gCamera->pos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(sOldPosition, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + + vec3f_set(gLakituState.focus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(gLakituState.goalFocus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(gLakituState.curFocus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(gCamera->focus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(sOldFocus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + + gCamera->yaw = gPuppyCam.yaw; + gCamera->nextYaw = gPuppyCam.yaw; + + gLakituState.yaw = gPuppyCam.yaw; + gLakituState.nextYaw = gPuppyCam.yaw; + gLakituState.oldYaw = gPuppyCam.yaw; + + gLakituState.mode = gCamera->mode; + gLakituState.defMode = gCamera->defMode; + gLakituState.roll = approach_s32(gLakituState.roll, 0, 0x80, 0x80); + + //Commented out simply because vanilla SM64 has this always set sometimes, and relies on certain camera modes to apply secondary foci. + //Uncomment to have fun with certain angles. + /*if (gSecondCameraFocus != NULL) + { + gPuppyCam.targetObj2 = gSecondCameraFocus; + } + else + { + gPuppyCam.targetObj2 = NULL; + }*/ + + if (gMarioState->floor != NULL) + { + sMarioGeometry.currFloor = gMarioState->floor; + sMarioGeometry.currFloorHeight = gMarioState->floorHeight; + sMarioGeometry.currFloorType = gMarioState->floor->type; + } + + if (gMarioState->ceil != NULL) + { + sMarioGeometry.currCeil = gMarioState->ceil; + sMarioGeometry.currCeilHeight = gMarioState->ceilHeight; + sMarioGeometry.currCeilType = gMarioState->ceil->type; + } +} + +//The basic loop sequence, which is called outside. +void puppycam_loop(void) +{ + if (!gPuppyCam.cutscene && sDelayedWarpOp == 0) + { + //Sets this before going through any possible modifications. + gPuppyCam.flags = gPuppyCam.intendedFlags; + puppycam_input_core(); + puppycam_projection(); + puppycam_script(); + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_COLLISION) + puppycam_collision(); + else + gPuppyCam.opacity = 255; + } + else + if (gPuppyCam.cutscene) + { + gPuppyCam.opacity = 255; + puppycam_process_cutscene(); + } + + puppycam_apply(); +} + +#endif diff --git a/src/game/puppycam2.h b/src/game/puppycam2.h new file mode 100644 index 00000000..e094671c --- /dev/null +++ b/src/game/puppycam2.h @@ -0,0 +1,193 @@ +#ifndef PUPPYCAM2_H +#define PUPPYCAM2_H + +#ifdef PUPPYCAM + +//How many times to store the terrain pitch. This stores it over 10 frames to help smooth over changes in curvature. +#define NUM_PITCH_ITERATIONS 10 + +#define PUPPYCAM_FLAGS_CUTSCENE 0x0001 +#define PUPPYCAM_FLAGS_SMOOTH 0x0002 + +#define PUPPY_ERROR_POOL_FULL 0x1 + +#define PUPPY_NULL 15151 +#define MAX_PUPPYCAM_VOLUMES 128 + +#define PUPPYCAM_BEHAVIOUR_TEMPORARY 0x0 +#define PUPPYCAM_BEHAVIOUR_PERMANENT 0x1 + +#define PUPPYVOLUME_SHAPE_BOX 0x0 +#define PUPPYVOLUME_SHAPE_CYLINDER 0x1 + +#define PUPPYCAM_MODE3_ZOOMED_IN 0x1 +#define PUPPYCAM_MODE3_ZOOMED_MED 0x2 +#define PUPPYCAM_MODE3_ZOOMED_OUT 0x4 +#define PUPPYCAM_MODE3_ENTER_FIRST_PERSON 0x8 + +#define PUPPYSPLINE_NONE 1 //Will not write to focus at all. +#define PUPPYSPLINE_FOLLOW 2 //Focus will follow a separate spline, but will mirror the speed and progress of the pos. + +#include "include/command_macros_base.h" + +#define PUPPYVOLUME(x, y, z, length, height, width, yaw, functionptr, anglesptr, addflags, removeflags, flagpersistance, room, shape) \ + CMD_BBH(0x3D, 0x24, x), \ + CMD_HHHHHH(y, z, length, height, width, yaw), \ + CMD_PTR(functionptr), \ + CMD_PTR(anglesptr), \ + CMD_W(addflags), \ + CMD_W(removeflags), \ + CMD_BBH(flagpersistance, shape, room) + +struct gPuppyOptions +{ + s16 analogue; + s16 sensitivityX; + s16 sensitivityY; + s16 invertX; + s16 invertY; + s16 turnAggression; + s16 inputType; +}; + +struct gPuppyStruct +{ + s16 yaw; //Horizontal Direction the game reads as the active value. + s16 yawTarget; //Horizontal Direction that yaw tries to be. + f32 yawAcceleration; //Horizontal Direction that sets yawTarget. + s16 pitch; //Vertical Direction the game reads as the active value. + s16 pitchTarget; //Vertical Direction that pitch tries to be. + f32 pitchAcceleration; //Vertical Direction that sets pitchTarget. + s16 zoom; //How far the camera is currently zoomed out + u8 zoomSet; //The current setting of which zoompoint to set the target to. + s16 zoomTarget; //The value that zoom tries to be. + s16 zoomPoints[3]; //An array containing distances. + s16 targetFloorHeight; //Mario's current floor height + s16 lastTargetFloorHeight; //Mirror's mario's floor height when his velocity is not above 0. + Vec3s pos; //Where the camera is + Vec3s focus; //Where the camera's looking + Vec3s pan; //An offset of the camera's focus + s32 intendedFlags; //The flagset the camera tries to be when it's not held hostage. + s32 flags; //Behaviour flags that affect different properties of the camera's behaviour + Vec3s shake; //How much the camera's shaking + u8 shakeFrames; //How long the camera's shaking for + f32 shakeForce; //How violently the camera's shaking + s32 framesSinceC[2]; //Counts the number of frames since the last C left or right press, to track double presses. + s16 collisionDistance; //Tries to be zoom, but will be overwritten by collision detection + struct Object *targetObj; //The object that the focus will base its positioning off. Usually Mario. + struct Object *targetObj2; //This is the second focus point that the camera will focus on. It'll focus between them. + s16 povHeight; //An offset of the focus object's Y value. + s16 floorY[2]; //Floor offsets, to allow a grace period before following Mario into the air. + u8 opacity; //A value set by collision distance, to fade Mario out if you're too close. + s8 stick2[2];//The value that's set and read for analogue stick. + u8 stickN[2]; //This is set when the stick is neutral. It's to prevent rapidfire input. + u8 enabled; //A boolean that decides whether to use vanilla camera or puppy camera. + s16 swimPitch; //Pitch adjustment that's applied when swimming. All pitch adjustment is clamped. + s16 edgePitch; //Pitch adjustment that's applied when stood near an edge. All pitch adjustment is clamped. + s16 moveZoom; //A small zoom value that's added on top of the regular zoom when moving. It's pretty subtle, but gives the feeling of a bit of speed. + u8 mode3Flags; //A flagset for classic mode. + u8 moveFlagAdd; //A bit that multiplies movement rate of axes when moving, to centre them faster. + s16 targetDist[2]; //Used with secondary view targets to smooth out the between status. + s16 intendedTerrainPitch; //The pitch that the game wants the game to tilt towards, following the terrain. + s16 terrainPitch; //The pitch the game tilts towards, when following terrain inclines. + + u8 cutscene; //A boolean that decides whether a cutscene is active + s32 (*sceneFunc)(); + u8 sceneInput; //A boolean that decides whether the controller updates during the scene. + s32 sceneTimer; //The cutscene timer that goes up during a cutscene. + Vec3s scenePos; //Where the camera is during a cutscene + Vec3s sceneFocus; //Where the camera looks during a cutscene + u16 splineIndex; //Determines which point of the spline it's at. + f32 splineProgress; //Determines how far along the index the spline is. + + struct gPuppyOptions options; + +}; + +//A second container for bounds that have 2 pairs of coordinates. Optional. +struct sPuppyAngles +{ + Vec3s pos; + Vec3s focus; + s16 yaw; + s16 pitch; + s16 zoom; +}; + +//Structurally, it's exactly the same as CutsceneSplinePoint +struct sPuppySpline +{ + s8 index; //The index of the spline. Ends with -1 + u8 speed; //The amount of frames it takes to get through this index. + Vec3s pos; //The vector pos of the spline index itself. +}; + +//A bounding volume for activating puppycamera scripts and angles. +struct sPuppyVolume +{ + Vec3s pos; //The set position of the volume + Vec3s radius; //Where it extends. + s16 rot; //The rotational angle of the volume. + s32 *func; //a pointer to a function. Optional. + struct sPuppyAngles *angles; //A pointer to a gPuppyAngles struct. Optional + s32 flagsAdd; //Adds behaviour flags. + s32 flagsRemove; //Removes behaviour flags. + u8 flagPersistance; //Decides if adding or removing the flags is temporary or permanent. + u8 shape; + s16 room; +}; + +enum gPuppyCamBeh +{ + PUPPYCAM_BEHAVIOUR_X_MOVEMENT = 0x0001, + PUPPYCAM_BEHAVIOUR_Y_MOVEMENT = 0x0002, + PUPPYCAM_BEHAVIOUR_Z_MOVEMENT = 0x0004, + + PUPPYCAM_BEHAVIOUR_YAW_ROTATION = 0x0008, + PUPPYCAM_BEHAVIOUR_PITCH_ROTATION = 0x0010, + PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE = 0x0020, + + PUPPYCAM_BEHAVIOUR_INPUT_NORMAL = 0x0040, + PUPPYCAM_BEHAVIOUR_INPUT_8DIR = 0x0080, + PUPPYCAM_BEHAVIOUR_INPUT_4DIR = 0x0100, + PUPPYCAM_BEHAVIOUR_INPUT_2D = 0x0200, + + PUPPYCAM_BEHAVIOUR_SLIDE_CORRECTION = 0x0400, + PUPPYCAM_BEHAVIOUR_TURN_HELPER = 0x0800, + PUPPYCAM_BEHAVIOUR_HEIGHT_HELPER = 0x1000, + PUPPYCAM_BEHAVIOUR_PANSHIFT = 0x2000, + + PUPPYCAM_BEHAVIOUR_COLLISION = 0x4000, + + + PUPPYCAM_BEHAVIOUR_DEFAULT = PUPPYCAM_BEHAVIOUR_X_MOVEMENT | PUPPYCAM_BEHAVIOUR_Y_MOVEMENT | PUPPYCAM_BEHAVIOUR_Z_MOVEMENT | + PUPPYCAM_BEHAVIOUR_YAW_ROTATION | PUPPYCAM_BEHAVIOUR_PITCH_ROTATION | PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE | + PUPPYCAM_BEHAVIOUR_HEIGHT_HELPER | PUPPYCAM_BEHAVIOUR_TURN_HELPER | PUPPYCAM_BEHAVIOUR_INPUT_NORMAL | PUPPYCAM_BEHAVIOUR_PANSHIFT | PUPPYCAM_BEHAVIOUR_COLLISION +}; + +extern const struct sPuppyAngles puppyAnglesNull; +extern u8 gPCOptionOpen; +extern s32 gPuppyError; +extern struct gPuppyStruct gPuppyCam; +extern struct sPuppyVolume *sPuppyVolumeStack[MAX_PUPPYCAM_VOLUMES]; +extern u16 gPuppyVolumeCount; +extern struct MemoryPool *gPuppyMemoryPool; +extern void puppycam_boot(void); +extern void puppycam_init(void); +extern void puppycam_loop(void); +extern void puppycam_shake(s16 x, s16 y, s16 z); +extern f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier); +extern void puppycam_default_config(void); +extern s16 LENCOS(s16 length, s16 direction); +extern s16 LENSIN(s16 length, s16 direction); +extern void puppycam_display_options(void); +extern void puppycam_set_save(void); +extern void puppycam_check_pause_buttons(void); +extern void puppycam_activate_cutscene(s32 *scene, s32 lockinput); +extern void puppycam_render_option_text(); +extern void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ); +extern s32 puppycam_move_spline(struct sPuppySpline splinePos[], struct sPuppySpline splineFocus[], s32 mode, s32 index); + +#endif + +#endif // PUPPYCAM2_H diff --git a/src/game/puppyprint.c b/src/game/puppyprint.c new file mode 100644 index 00000000..dfca552f --- /dev/null +++ b/src/game/puppyprint.c @@ -0,0 +1,1060 @@ +/** +--------------Puppyprint 1.0 by Fazana-------------- +Includes a few printing functions to fit any purpose. +print_small_text is intended to replace print_generic_string in use, as it uses a far more optimised way of doing things, +supports real time ascii conversion, and also supports many fun effects to spice up the text. +Any usage of gDPSetEnvColor should ideally be replaced with print_set_envcolour because it helps with some optimisations. +render_multi_image can be used to draw large texture rectangles consisting of multiple images on the screen. +You only need have the single image in its full form, with no need for splitting it, and simply just load it. + +As for the profiler, you can hold dpad up, and press L to toggle the display. +Inside this display, if you press up on the dpad again, you can switch between performance, and memory view. +If you press dpad down, you can toggle the benchmarking display. +You can press dpad left or right to change which option, and you can measure game thread or audio thread performance by default. +There's also a custom option that's left blank. It runs benchmark_custom which can contain anything of your choice. +You can press dpad right to cycle between collision visuals, from surface collision, hitbox collision, both, or neither. +dpad left will toggle the logging view, which will display a number of strings you've sent through for debugging purposes, like +a modern game engine's developer's console. + +- Collision marks the time it takes to generate and process collision. +- Behaviour marks the time it takes for objects to perform their behaviours. This excludes collision. +- Graph measures the time it takes to process the node graphs, which is all the 3D geometry and rendering. +- Audio measures the time it takes to process the audio samples, this excludes time spent loading. +- DMA measures the time it takes to load things. In Vanilla, Mario's animations and audio samples are loaded from ROM as needed. +**/ + +#include + +#ifdef PUPPYPRINT + +#include "config.h" +#include "game_init.h" +#include "memory.h" +#include "print.h" +#include "segment2.h" +#include "string.h" +#include "engine/math_util.h" +#include "engine/behavior_script.h" +#include "camera.h" +#include "puppyprint.h" +#include "level_update.h" +#include "object_list_processor.h" +#include "engine/surface_load.h" +#include "audio/data.h" +#include "hud.h" +#include "debug_box.h" + +u8 currEnv[4]; +u8 fDebug = 0; + +#if PUPPYPRINT_DEBUG +s8 benchViewer = 0; +u8 benchOption = 0; +s8 logViewer = 0; +//Profiler values +s8 perfIteration = 0; +s16 benchmarkLoop = 0; +s32 benchmarkTimer = 0; +s32 benchmarkProgramTimer = 0; +s8 benchmarkType = 0; +//General +OSTime cpuTime = 0; +OSTime rspTime = 0; +OSTime rdpTime = 0; +OSTime ramTime = 0; +OSTime loadTime = 0; +OSTime gLastOSTime = 0; +OSTime rspDelta = 0; +s32 benchMark[NUM_BENCH_ITERATIONS+2]; +//CPU +OSTime collisionTime[NUM_PERF_ITERATIONS+1]; +OSTime behaviourTime[NUM_PERF_ITERATIONS+1]; +OSTime scriptTime[NUM_PERF_ITERATIONS+1]; +OSTime graphTime[NUM_PERF_ITERATIONS+1]; +OSTime audioTime[NUM_PERF_ITERATIONS+1]; +OSTime dmaTime[NUM_PERF_ITERATIONS+1]; +OSTime dmaAudioTime[NUM_PERF_ITERATIONS+1]; +//RSP +OSTime audioTime[NUM_PERF_ITERATIONS+1]; +OSTime rspGenTime[NUM_PERF_ITERATIONS+1]; +//RDP +OSTime bufferTime[NUM_PERF_ITERATIONS+1]; +OSTime tmemTime[NUM_PERF_ITERATIONS+1]; +OSTime busTime[NUM_PERF_ITERATIONS+1]; +//RAM +s8 ramViewer = 0; +s32 ramsizeSegment[33] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +s32 audioPool[12]; +s32 mempool; +//Collision +u8 collisionViewer = 0; +s32 numSurfaces = 0; + +extern u8 _mainSegmentStart[]; +extern u8 _mainSegmentEnd[]; +extern u8 _engineSegmentStart[]; +extern u8 _engineSegmentEnd[]; +extern u8 _framebuffersSegmentBssStart[]; +extern u8 _framebuffersSegmentBssEnd[]; +extern u8 _buffersSegmentBssStart[]; +extern u8 _buffersSegmentBssEnd[]; +extern u8 _goddardSegmentStart[]; +extern u8 _goddardSegmentEnd[]; + +//Here is stored the rom addresses of the global code segments. If you get rid of any, it's best to just write them as NULL. +s32 ramP[5][2] = { + {&_buffersSegmentBssStart, &_buffersSegmentBssEnd}, + {&_mainSegmentStart, &_mainSegmentEnd}, + {&_engineSegmentStart, &_engineSegmentEnd}, + {&_framebuffersSegmentBssStart, &_framebuffersSegmentBssEnd}, + {&_goddardSegmentStart, &_goddardSegmentEnd}, +}; + +void puppyprint_calculate_ram_usage(void) +{ + s32 temp[2]; + s32 i = 0; + + for (i = 0; i < 5; i++) + { + if (!ramP[i][0] || !ramP[i][1]) + continue; + temp[0] = ramP[i][0]; + temp[1] = ramP[i][1]; + ramsizeSegment[i] = temp[1] - temp[0]; + } + + //These are a bit hacky, but what can ye do eh? + //gEffectsMemoryPool is 0x4000, gObjectsMemoryPool is 0x800. Epic C limitations mean I can't just sizeof their values :) + ramsizeSegment[5] = 0x4000 + 0x800; + ramsizeSegment[6] = (SURFACE_NODE_POOL_SIZE * sizeof(struct SurfaceNode)) + (SURFACE_POOL_SIZE * sizeof(struct Surface)); + ramsizeSegment[7] = gAudioHeapSize + gAudioInitPoolSize; + ramsizeSegment[8] = audioPool[0] + audioPool[1] + audioPool[2] + audioPool[3] + audioPool[4] + audioPool[5] + + audioPool[6] + audioPool[7] + audioPool[8] + audioPool[9] + audioPool[10] + audioPool[11]; +} + +void puppyprint_profiler_finished(void) +{ + s32 i = 0; + benchMark[NUM_BENCH_ITERATIONS] = 0; + benchMark[NUM_BENCH_ITERATIONS+1] = 0; + benchmarkTimer = 300; + benchViewer = 0; + for (i = 0; i < NUM_BENCH_ITERATIONS-2; i++) + { + benchMark[NUM_BENCH_ITERATIONS] += benchMark[i]; + if (benchMark[i] > benchMark[NUM_BENCH_ITERATIONS+1]) + benchMark[NUM_BENCH_ITERATIONS+1] = benchMark[i]; + } + benchMark[NUM_BENCH_ITERATIONS] /= NUM_BENCH_ITERATIONS; + benchmarkProgramTimer = OS_CYCLES_TO_USEC(osGetTime() - benchmarkProgramTimer); +} + +//RGB colour lookup table for colouring all the funny ram prints. +u8 colourChart[33][3] = { + {255, 0, 0}, + {0, 0, 255}, + {0, 255, 0}, + {255, 255, 0}, + {255, 0, 255}, + {255, 127, 0}, + {0, 255, 255}, + {51, 255, 51}, + {255, 153, 153}, + {204, 0, 102}, + {0, 153, 153}, + {153, 255, 153}, + {0, 0, 128}, + {128, 0, 128}, + {218, 165, 32}, + {107, 142, 35}, + {188, 143, 143}, + {210, 105, 30}, + {154, 205, 50}, + {165, 42, 42}, + {255, 105, 180}, + {139, 69, 19}, + {250, 240, 230}, + {95, 158, 160}, + {60, 179, 113}, + {255, 69, 0}, + {128, 0, 0}, + {216, 191, 216}, + {244, 164, 96}, + {176, 196, 222}, + {255, 255, 255}}; + +//Change this to alter the width of the bar at the bottom. +#define BAR_LENGTH 200 + +void print_ram_bar(void) +{ + s32 i = 0; + f32 perfPercentage; + s32 graphPos = 0; + s32 prevGraph = 160-(BAR_LENGTH/2); + s32 ramsize = osGetMemSize(); + + prepare_blank_box(); + + for (i = 0; i < 32; i++) + { + if (ramsizeSegment[i] == 0) + continue; + perfPercentage = (f32)ramsizeSegment[i]/ramsize; + graphPos = prevGraph + CLAMP((BAR_LENGTH*perfPercentage), 1, 160+(BAR_LENGTH/2)); + render_blank_box(prevGraph, 210, graphPos, 218, colourChart[i][0], colourChart[i][1], colourChart[i][2], 255); + prevGraph = graphPos; + } + perfPercentage = (f32)ramsizeSegment[32]/ramsize; + graphPos = prevGraph + CLAMP((BAR_LENGTH*perfPercentage), 1, 160+(BAR_LENGTH/2)); + render_blank_box(prevGraph, 210, graphPos, 218, 255, 255, 255, 255); + prevGraph = graphPos; + + render_blank_box(prevGraph, 210, 160+(BAR_LENGTH/2), 218, 0, 0, 0, 255); + + finish_blank_box(); +} +//Another epic lookup table, for text this time. +const char ramNames[9][32] = { + "Buffers", + "Main", + "Engine", + "Framebuffers", + "Goddard", + "Pools", + "Collision", + "Audio Heap", + "Audio Pools", +}; + +s8 nameTable = sizeof(ramNames)/32; + +void print_ram_overview(void) +{ + s32 i = 0; + char textBytes[32]; + s32 x = 80; + s32 y = 16; + s32 drawn = 0; + prepare_blank_box(); + render_blank_box(0, 0, 320, 240, 0, 0, 0, 192); + finish_blank_box(); + + for (i = 0; i < 33; i++) + { + if (drawn == 16) + { + x = 240; + y = 16; + } + if (ramsizeSegment[i] == 0) + continue; + if (i < 9) + { + sprintf(textBytes, "%s: %X", ramNames[i], ramsizeSegment[i]); + } + else + { + sprintf(textBytes, "Segment %02X: %X",i-nameTable+2, ramsizeSegment[i]); + } + print_set_envcolour(colourChart[i][0], colourChart[i][1], colourChart[i][2], 255); + print_small_text(x, y, textBytes, PRINT_TEXT_ALIGN_CENTRE, PRINT_ALL); + y += 12; + drawn++; + } +} + +void benchmark_custom(void) +{ + if (benchmarkLoop == 0 || benchOption != 2) + return; + OSTime lastTime; + while (TRUE) + { + lastTime = osGetTime(); + //Insert your function here! + + if (benchmarkLoop > 0 && benchOption == 2) + { + benchmarkLoop--; + benchMark[benchmarkLoop] = osGetTime() - lastTime; + if (benchmarkLoop == 0) + { + puppyprint_profiler_finished(); + break; + } + } + else + break; + } +} + +const char benchNames[][32] = { + "Game Thread", + "Audio Thread", + "Custom", +}; + +void print_which_benchmark(void) +{ + char textBytes[40]; + + prepare_blank_box(); + render_blank_box(110, 115, 210, 160, 0, 0, 0, 255); + finish_blank_box(); + sprintf(textBytes, "Select Option#%s#L: Confirm", benchNames[benchOption]); + print_small_text(160,120, textBytes, PRINT_TEXT_ALIGN_CENTRE, PRINT_ALL); +} + +char consoleLogTable[LOG_BUFFER_SIZE][255]; + +void append_puppyprint_log(char str[255]) +{ + s32 i; + for (i = 0; i < LOG_BUFFER_SIZE-1; i++) + { + memcpy(consoleLogTable[i], consoleLogTable[i+1], 255); + } + memcpy(consoleLogTable[LOG_BUFFER_SIZE-1], str, 255); +} + +#define LINE_HEIGHT 8 + ((LOG_BUFFER_SIZE-1)*12) +void print_console_log(void) +{ + s32 i; + prepare_blank_box(); + render_blank_box(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 0, 96); + finish_blank_box(); + for (i = 0; i < LOG_BUFFER_SIZE; i++) + { + if (consoleLogTable[i] == NULL) + continue; + print_small_text(16, (LINE_HEIGHT)-(i*12), consoleLogTable[i], PRINT_TEXT_ALIGN_LEFT, PRINT_ALL); + } +} +#undef LINE_HEIGHT + +extern void print_fps(s32 x, s32 y); + +void puppyprint_render_profiler(void) +{ + s32 perfPercentage[5]; + s32 graphPos; + s32 prevGraph; + OSTime cpuCount = OS_CYCLES_TO_USEC(cpuTime+audioTime[NUM_PERF_ITERATIONS]+dmaAudioTime[NUM_PERF_ITERATIONS]); + char textBytes[80]; + + if (!fDebug) + return; + + sprintf(textBytes, "RAM: %06X /%06X (%d_)", main_pool_available(), mempool, (s32)(((f32)main_pool_available()/(f32)mempool)*100)); + print_small_text(160, 224, textBytes, PRINT_TEXT_ALIGN_CENTRE, PRINT_ALL); + + if (!ramViewer && !benchViewer && !logViewer) + { + print_fps(16,40); + sprintf(textBytes, "CPU: %dus (%d_)#RSP: %dus (%d_)#RDP: %dus (%d_)", (s32)cpuCount, (s32)OS_CYCLES_TO_USEC(cpuTime)/333, (s32)OS_CYCLES_TO_USEC(rspTime), (s32)OS_CYCLES_TO_USEC(rspTime)/333, (s32)OS_CYCLES_TO_USEC(rdpTime), (s32)OS_CYCLES_TO_USEC(rdpTime)/333); + print_small_text(16, 52, textBytes, PRINT_TEXT_ALIGN_LEFT, PRINT_ALL); + + sprintf(textBytes, "OBJ: %d/%d", gObjectCounter, OBJECT_POOL_CAPACITY); + print_small_text(16, 124, textBytes, PRINT_TEXT_ALIGN_LEFT, PRINT_ALL); + + //Very little point printing useless info if Mayro doesn't even exist. + if (gMarioState->marioObj) + { + sprintf(textBytes, "Mario Pos#X: %d#Y: %d#Z: %d#D: %X", (s32)(gMarioState->pos[0]), (s32)(gMarioState->pos[1]), (s32)(gMarioState->pos[2]), (u16)(gMarioState->faceAngle[1])); + print_small_text(16, 140, textBytes, PRINT_TEXT_ALIGN_LEFT, PRINT_ALL); + } + //Same for the camera, especially so because this will crash otherwise. + if (gCamera) + { + sprintf(textBytes, "Camera Pos#X: %d#Y: %d#Z: %d#D: %X", (s32)(gCamera->pos[0]), (s32)(gCamera->pos[1]), (s32)(gCamera->pos[2]), (u16)(gCamera->yaw)); + print_small_text(304, 140, textBytes, PRINT_TEXT_ALIGN_RIGHT, PRINT_ALL); + } + + if (benchmarkTimer > 0) + { + benchmarkTimer--; + prepare_blank_box(); + //sprintf(textBytes, "Benchmark: %dus#High: %dus", (s32)OS_CYCLES_TO_USEC(benchMark[NUM_BENCH_ITERATIONS]), (s32)OS_CYCLES_TO_USEC(benchMark[NUM_BENCH_ITERATIONS+1])); + sprintf(textBytes, "Done in %0.000f seconds#Benchmark: %dus#High: %dus", (f32)(benchmarkProgramTimer)*0.000001f, (s32)OS_CYCLES_TO_USEC(benchMark[NUM_BENCH_ITERATIONS]), (s32)OS_CYCLES_TO_USEC(benchMark[NUM_BENCH_ITERATIONS+1])); + render_blank_box(160-(get_text_width(textBytes)/2)-4, 158, 160+(get_text_width(textBytes)/2)+4, 196, 0, 0, 0, 255); + print_set_envcolour(255, 255, 255, 255); + print_small_text(160, 160, textBytes, PRINT_TEXT_ALIGN_CENTRE, PRINT_ALL); + finish_blank_box(); + } + + #define ADDTIMES MAX((collisionTime[NUM_PERF_ITERATIONS] + graphTime[NUM_PERF_ITERATIONS] + behaviourTime[NUM_PERF_ITERATIONS] + audioTime[NUM_PERF_ITERATIONS] + dmaTime[NUM_PERF_ITERATIONS])/80, 1) + perfPercentage[0] = MAX((collisionTime[NUM_PERF_ITERATIONS]/ADDTIMES), 1); + perfPercentage[1] = MAX((graphTime[NUM_PERF_ITERATIONS]/ADDTIMES), 1); + perfPercentage[2] = MAX((behaviourTime[NUM_PERF_ITERATIONS]/ADDTIMES), 1); + perfPercentage[3] = MAX((audioTime[NUM_PERF_ITERATIONS]/ADDTIMES), 1); + perfPercentage[4] = MAX((dmaTime[NUM_PERF_ITERATIONS]/ADDTIMES), 1); + #undef ADDTIMES + + sprintf(textBytes, "Collision: %dus", (s32)OS_CYCLES_TO_USEC(collisionTime[NUM_PERF_ITERATIONS])); + print_small_text(304, 40, textBytes, PRINT_TEXT_ALIGN_RIGHT, PRINT_ALL); + sprintf(textBytes, "Graph: %dus", (s32)OS_CYCLES_TO_USEC(graphTime[NUM_PERF_ITERATIONS])); + print_small_text(304, 52, textBytes, PRINT_TEXT_ALIGN_RIGHT, PRINT_ALL); + sprintf(textBytes, "Behaviour: %dus", (s32)OS_CYCLES_TO_USEC(behaviourTime[NUM_PERF_ITERATIONS])); + print_small_text(304, 64, textBytes, PRINT_TEXT_ALIGN_RIGHT, PRINT_ALL); + sprintf(textBytes, "Audio: %dus", (s32)OS_CYCLES_TO_USEC(audioTime[NUM_PERF_ITERATIONS])); + print_small_text(304, 76, textBytes, PRINT_TEXT_ALIGN_RIGHT, PRINT_ALL); + sprintf(textBytes, "DMA: %dus", (s32)OS_CYCLES_TO_USEC(dmaTime[NUM_PERF_ITERATIONS])); + print_small_text(304, 88, textBytes, PRINT_TEXT_ALIGN_RIGHT, PRINT_ALL); + + //Render CPU breakdown bar. + prepare_blank_box(); + graphPos = 224 + perfPercentage[0]; + render_blank_box(224, 104, graphPos, 112, 255, 0, 0, 255); + prevGraph = graphPos; + graphPos += perfPercentage[1]; + render_blank_box(prevGraph, 104, graphPos, 112, 0, 0, 255, 255); + prevGraph = graphPos; + graphPos += perfPercentage[2]; + render_blank_box(prevGraph, 104, graphPos, 112, 0, 255, 0, 255); + prevGraph = graphPos; + graphPos += perfPercentage[3]; + render_blank_box(prevGraph, 104, graphPos, 112, 255, 255, 0, 255); + prevGraph = graphPos; + graphPos += perfPercentage[4]; + render_blank_box(prevGraph, 104, 304, 112, 255, 0, 255, 255); + } + else + if (ramViewer) + print_ram_overview(); + else + if (logViewer) + print_console_log(); + else + if (benchViewer) + print_which_benchmark(); + + print_ram_bar(); +} + +void profiler_update(OSTime *time, OSTime time2) +{ + time[perfIteration] = osGetTime() - time2; +} + +void get_average_perf_time(OSTime *time) +{ + //This takes all but the last index of the timer array, and creates an average value, which is written to the last index. + s32 i = 0; + s32 total = 0; + for (i = 0; i < NUM_PERF_ITERATIONS-1; i++) + { + total += time[i]; + } + time[NUM_PERF_ITERATIONS] = total/NUM_PERF_ITERATIONS; +} + +void puppyprint_profiler_process(void) +{ + bufferTime[perfIteration] = (IO_READ(DPC_BUFBUSY_REG)); + tmemTime[perfIteration] = (IO_READ(DPC_TMEM_REG)); + busTime[perfIteration] = (IO_READ(DPC_PIPEBUSY_REG)); + OSTime newTime = osGetTime(); + + if (gGlobalTimer % 15 == 0) + { + get_average_perf_time(scriptTime); + get_average_perf_time(behaviourTime); + get_average_perf_time(collisionTime); + get_average_perf_time(graphTime); + get_average_perf_time(audioTime); + get_average_perf_time(dmaTime); + get_average_perf_time(dmaAudioTime); + + dmaTime[NUM_PERF_ITERATIONS] += dmaAudioTime[NUM_PERF_ITERATIONS]; + + get_average_perf_time(rspGenTime); + + get_average_perf_time(bufferTime); + get_average_perf_time(tmemTime); + get_average_perf_time(busTime); + + rdpTime = bufferTime[NUM_PERF_ITERATIONS]; + rdpTime = MAX(rdpTime, tmemTime[NUM_PERF_ITERATIONS]); + rdpTime = MAX(rdpTime, busTime[NUM_PERF_ITERATIONS]); + cpuTime = scriptTime[NUM_PERF_ITERATIONS]; + rspTime = rspGenTime[NUM_PERF_ITERATIONS]; + puppyprint_calculate_ram_usage(); + } + + gLastOSTime = newTime; + if (gGlobalTimer > 5) + IO_WRITE(DPC_STATUS_REG, DPC_CLR_CLOCK_CTR | DPC_CLR_CMD_CTR | DPC_CLR_PIPE_CTR | DPC_CLR_TMEM_CTR); + + if (fDebug) + { + if (gPlayer1Controller->buttonPressed & D_JPAD) + { + benchViewer ^= 1; + ramViewer = 0; + logViewer = 0; + } + else + if (gPlayer1Controller->buttonPressed & U_JPAD) + { + ramViewer ^= 1; + benchViewer = 0; + logViewer = 0; + } + else + if (gPlayer1Controller->buttonPressed & L_JPAD) + { + logViewer ^= 1; + ramViewer = 0; + benchViewer = 0; + } + #ifdef VISUAL_DEBUG + else + if (!benchViewer && !ramViewer && !logViewer) + { + debug_box_input(); + } + #endif + if (benchViewer) + { + if (gPlayer1Controller->buttonPressed & R_JPAD) + benchOption++; + if (gPlayer1Controller->buttonPressed & L_JPAD) + benchOption--; + if (benchOption == 255) + benchOption = 2; + if (benchOption > 2) + benchOption = 0; + if (gPlayer1Controller->buttonPressed & L_TRIG) + { + benchmarkLoop = NUM_BENCH_ITERATIONS; + benchmarkProgramTimer = osGetTime(); + } + } + benchmark_custom(); + } + if (gPlayer1Controller->buttonDown & U_JPAD && gPlayer1Controller->buttonPressed & L_TRIG) + { + ramViewer = 0; + benchViewer = 0; + fDebug ^= 1; + } + + + if (perfIteration++ == NUM_PERF_ITERATIONS-1) + perfIteration = 0; +} +#endif + +void print_set_envcolour(s32 r, s32 g, s32 b, s32 a) +{ + if (r != currEnv[0] || g != currEnv[1] || b != currEnv[2] || a != currEnv[3]) + { + gDPSetEnvColor(gDisplayListHead++, (u8)r, (u8)g, (u8)b, (u8)a); + currEnv[0] = r; + currEnv[1] = g; + currEnv[2] = b; + currEnv[3] = a; + } +} + +#define BLANK 0, 0, 0, ENVIRONMENT, 0, 0, 0, ENVIRONMENT + +void prepare_blank_box(void) +{ + gDPSetCombineMode(gDisplayListHead++, BLANK, BLANK); +} + +void finish_blank_box(void) +{ + print_set_envcolour(255, 255, 255, 255); + gSPDisplayList(gDisplayListHead++,dl_hud_img_end); +} + +//This does some epic shenanigans to figure out the optimal way to draw this. +//If the width is a multiple of 4, then use fillmode (fastest) +//Otherwise, if there's transparency, it uses that rendermode, which is slower than using opaque rendermodes. +void render_blank_box(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b, u8 a) +{ + s32 cycleadd = 0; + if (ABS(x1 - x2) % 4 == 0 && a == 255) + { + gDPSetCycleType(gDisplayListHead++, G_CYC_FILL); + gDPSetRenderMode(gDisplayListHead++, G_RM_NOOP, G_RM_NOOP); + cycleadd = 1; + } + else + { + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); + if (a == 255) + { + gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2); + } + else + { + gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + } + cycleadd = 0; + } + gDPPipeSync(gDisplayListHead++); + gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(r, g, b, 1) << 16 | GPACK_RGBA5551(r, g, b, 1)); + print_set_envcolour(r, g, b, a); + gDPFillRectangle(gDisplayListHead++, x1, y1, x2-cycleadd, y2-cycleadd); +} + + +u8 textLen[] = { + /*0*/ 6, /*1*/ 5, /*2*/ 7, /*3*/ 7, /*4*/ 7, /*5*/ 7, /*6*/ 8, /*7*/ 7, /*8*/ 7, /*9*/ 6, /*-*/ 8, /*+*/ 8, /*(*/ 5, /*)*/ 5, /*!*/ 4, /*?*/ 6, + /*A*/ 7, /*B*/ 7, /*C*/ 7, /*D*/ 7, /*E*/ 6, /*F*/ 5, /*G*/ 8, /*H*/ 6, /*I*/ 6, /*J*/ 5, /*K*/ 7, /*L*/ 6, /*M*/ 7, /*N*/ 7, /*O*/ 7, /*P*/ 6, + /*Q*/ 8, /*R*/ 6, /*S*/ 7, /*T*/ 7, /*U*/ 7, /*V*/ 7, /*W*/ 8, /*X*/ 7, /*Y*/ 7, /*Z*/ 7, /*"*/ 5, /*'*/ 2, /*:*/ 3, /*;*/ 3, /*.*/ 3, /*,*/ 3, + /*a*/ 7, /*b*/ 7, /*c*/ 6, /*d*/ 7, /*e*/ 7, /*f*/ 7, /*g*/ 7, /*h*/ 7, /*i*/ 3, /*j*/ 5, /*k*/ 8, /*l*/ 4, /*m*/ 7, /*n*/ 7, /*o*/ 7, /*p*/ 7, + /*q*/ 7, /*r*/ 6, /*s*/ 6, /*t*/ 6, /*u*/ 6, /*v*/ 7, /*w*/ 8, /*x*/ 6, /*y*/ 8, /*z*/ 7, /*~*/ 8, /*..*/ 7, /*^*/ 8, /*/*/ 8, /*%*/ 8, /*&*/ 8, +}; + +#include "level_update.h" + +void get_char_from_byte(u8 letter, s32 *textX, s32 *textY, s32 *spaceX, s32 *offsetY) +{ + *offsetY = 0; + //Line 1 + if (letter >= '0' && letter <= '9') + { + *textX = (letter - '0') * 4; + *textY = 0; + *spaceX = textLen[letter - '0']; + } + else + //Line 2 + if (letter >= 'A' && letter <= 'P') + { + *textX = ((letter - 'A') * 4); + *textY = 6; + *spaceX = textLen[letter - 'A'+16]; + } + else + //Line 3 + if (letter >= 'Q' && letter <= 'Z') + { + *textX = ((letter - 'Q') * 4); + *textY = 12; + *spaceX = textLen[letter - 'Q'+32]; + } + else + //Line 4 + if (letter >= 'a' && letter <= 'p') + { + *textX = ((letter - 'a') * 4); + *textY = 18; + *spaceX = textLen[letter - 'a'+48]; + } + else + //Line 5 + if (letter >= 'q' && letter <= 'z') + { + *textX = ((letter - 'q') * 4); + *textY = 24; + *spaceX = textLen[letter - 'q'+64]; + } + else + {//Space, the final frontier. + *textX = 128; + *textY = 0; + *spaceX = 2; + } + + switch (letter) + { + case '-': *textX = 40; *textY = 0; *spaceX = textLen[10]; break; //Hyphen + case '+': *textX = 44; *textY = 0; *spaceX = textLen[11]; break; //Plus + case '(': *textX = 48; *textY = 0; *spaceX = textLen[12]; break; //Open Bracket + case ')': *textX = 52; *textY = 0; *spaceX = textLen[13]; break; //Close Bracket + case '!': *textX = 56; *textY = 0; *spaceX = textLen[14]; break; //Exclamation mark + case '?': *textX = 60; *textY = 0; *spaceX = textLen[15]; break; //Question mark + + case '"': *textX = 40; *textY = 12; *spaceX = textLen[42]; break; //Speech mark + case 0x27: *textX = 44; *textY = 12; *spaceX = textLen[43]; break; //Apostrophe. + case ':': *textX = 48; *textY = 12; *spaceX = textLen[44]; break; //Colon + case ';': *textX = 52; *textY = 12; *spaceX = textLen[45]; break; //Semicolon + case '.': *textX = 56; *textY = 12; *spaceX = textLen[46]; break; //Full stop + case ',': *textX = 60; *textY = 12; *spaceX = textLen[47]; break; //Comma + + case '~': *textX = 40; *textY = 24; *spaceX = textLen[74]; break; //Tilde + case '@': *textX = 44; *textY = 24; *spaceX = textLen[75]; break; //Umlaut + case '^': *textX = 48; *textY = 24; *spaceX = textLen[76]; break; //Caret + case '/': *textX = 52; *textY = 24; *spaceX = textLen[77]; break; //Slash + case '_': *textX = 56; *textY = 24; *spaceX = textLen[78]; break; //Percent + case '&': *textX = 60; *textY = 24; *spaceX = textLen[79]; break; //Ampersand + + //This is for the letters that sit differently on the line. It just moves them down a bit. + case 'g': *offsetY = 1; break; + case 'q': *offsetY = 1; break; + case 'p': *offsetY = 3; break; + case 'y': *offsetY = 1; break; + } +} + +s8 shakeToggle = 0; +s8 waveToggle = 0; + +s32 text_iterate_command(const char *str, s32 i, s32 runCMD) +{ + s32 len = 0; + while (str[i+len] != '>' && i+len < (signed)strlen(str)) + len++; + len++; + + if (runCMD) + { + if (strncmp(str+i, "", 5) == 0) //Simple text colour effect. goes up to 99 for each, so 99000000 is red. + { + s32 r, g, b, a; + //Each value is taken from the strong. The first is multiplied by 10, because it's a larger significant value, then it adds the next digit onto it. + r = (str[i+5] - '0')*10; + r += str[i+6] - '0'; + g = (str[i+7] - '0')*10; + g += str[i+8] - '0'; + b = (str[i+9] - '0')*10; + b += str[i+10] - '0'; + a = (str[i+11] - '0')*10; + a += str[i+12] - '0'; + //Multiply each value afterwards by 2.575f to make 255. + print_set_envcolour(r*2.575f, g*2.575f, b*2.575f, a*2.575f); + } + else + if (strncmp(str+i, "", 6) == 0) //Same as above, except it fades between two colours. The third set of numbers is the speed it fades. + { + s32 r, g, b, a, r2, g2, b2, a2, spd, r3, g3, b3, a3, r4, g4, b4, a4; + r = (str[i+6] - '0')*10; + r += str[i+7] - '0'; + g = (str[i+8] - '0')*10; + g += str[i+9] - '0'; + b = (str[i+10] - '0')*10; + b += str[i+11] - '0'; + a = (str[i+12] - '0')*10; + a += str[i+13] - '0'; + r2 = (str[i+15] - '0')*10; + r2 += str[i+16] - '0'; + g2 = (str[i+17] - '0')*10; + g2 += str[i+18] - '0'; + b2 = (str[i+19] - '0')*10; + b2 += str[i+20] - '0'; + a2 = (str[i+21] - '0')*10; + a2 += str[i+22] - '0'; + spd = (str[i+24] - '0')*10; + spd += str[i+25] - '0'; + + //Find the median. + r3 = (r + r2)*1.2875f; + g3 = (g + g2)*1.2875f; + b3 = (b + b2)*1.2875f; + a3 = (a + a2)*1.2875f; + //Find the difference. + r4 = (r - r2)*1.2875f; + g4 = (g - g2)*1.2875f; + b4 = (b - b2)*1.2875f; + a4 = (a - a2)*1.2875f; + //Now start from the median, and wave from end to end with the difference, to create the fading effect. + print_set_envcolour(r3 + ((sins(gGlobalTimer*spd*50)) * r4), g3 + ((sins(gGlobalTimer*spd*50)) * g4), b3 + ((sins(gGlobalTimer*spd*50)) * b4), a3 + ((sins(gGlobalTimer*spd*50)) * a4)); + } + else + if (strncmp(str+i, "", 8) == 0) //Toggles the happy colours :o) Do it again to disable it. + { + s32 r, g, b; + r = (coss(gGlobalTimer*600)+1)*127; + g = (coss((gGlobalTimer*600)+21845)+1)*127; + b = (coss((gGlobalTimer*600)-21845)+1)*127; + print_set_envcolour(r, g, b, 255); + } + else + if (strncmp(str+i, "", 7) == 0) //Toggles text that shakes on the spot. Do it again to disable it. + { + shakeToggle^=1; + } + else + if (strncmp(str+i, "", 6) == 0) //Toggles text that waves around. Do it again to disable it. + { + waveToggle^=1; + } + + } + + return len; +} + +s32 get_text_width(const char *str) +{ + s32 i= 0; + s32 textPos = 0; + s32 wideX = 0; + s32 textX, textY, offsetY, spaceX; + + for (i = 0; i < (signed)strlen(str); i++) + { + if (str[i] == '#') + { + i++; + textPos = 0; + } + if (str[i] == '<') + { + i+= text_iterate_command(str, i, FALSE); + } + get_char_from_byte(str[i], &textX, &textY, &spaceX, &offsetY); + textPos+=spaceX+1; + wideX = MAX(textPos, wideX); + } + return wideX; +} + +s32 get_text_height(const char *str) +{ + s32 i= 0; + s32 textPos = 0; + + for (i = 0; i < (signed)strlen(str); i++) + { + if (str[i] == '#') + { + i++; + textPos+=12; + } + } + return textPos; +} + +void print_small_text(s32 x, s32 y, const char *str, s32 align, s32 amount) +{ + s32 textX = 0; + s32 textY = 0; + s32 offsetY = 0; + s32 i = 0; + s32 textPos[2] = {0,0}; + s32 spaceX = 0; + s32 wideX[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + s32 tx = amount; + s32 shakePos[2]; + s32 wavePos; + s32 lines = 0; + s32 xlu = currEnv[3]; + s32 prevxlu = 256; //Set out of bounds, so it will *always* be different at first. + + shakeToggle = 0; + waveToggle = 0; + + if (amount == PRINT_ALL) + tx = (signed)strlen(str); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); + gDPSetTexturePersp(gDisplayListHead++, G_TP_NONE); + gDPSetCombineMode(gDisplayListHead++, G_CC_FADEA, G_CC_FADEA); + gDPSetTextureFilter(gDisplayListHead++, G_TF_POINT); + if (align == PRINT_TEXT_ALIGN_CENTRE) + { + for (i = 0; i < (signed)strlen(str); i++) + { + if (str[i] == '#') + { + i++; + textPos[0] = 0; + lines++; + } + if (str[i] == '<') + { + i+= text_iterate_command(str, i, FALSE); + } + get_char_from_byte(str[i], &textX, &textY, &spaceX, &offsetY); + textPos[0]+=spaceX+1; + wideX[lines] = MAX(textPos[0], wideX[lines]); + } + textPos[0] = -(wideX[0]/2); + } + else + if (align == PRINT_TEXT_ALIGN_RIGHT) + { + for (i = 0; i < (signed)strlen(str); i++) + { + if (str[i] == '#') + { + i++; + textPos[0] = 0; + lines++; + } + else + { + textPos[0]+=spaceX+1; + } + if (str[i] == '<') + { + i+= text_iterate_command(str, i, FALSE); + } + get_char_from_byte(str[i], &textX, &textY, &spaceX, &offsetY); + + wideX[lines] = MAX(textPos[0], wideX[lines]); + } + textPos[0] = -wideX[0]; + } + lines = 0; + gDPLoadTextureBlock_4b(gDisplayListHead++, segmented_to_virtual(small_font), G_IM_FMT_I, 128, 60, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 0, 0, 0, 0, 0); + for (i = 0; i < tx; i++) + { + if (str[i] == '#') + { + i++; + lines++; + if (align == PRINT_TEXT_ALIGN_RIGHT) + textPos[0] = -(wideX[lines]); + else + textPos[0] = -(wideX[lines]/2); + textPos[1] += 12; + } + if (str[i] == '<') + { + i+= text_iterate_command(str, i, TRUE); + } + if (shakeToggle) + { + shakePos[0] = -1+(random_u16() % 2); + shakePos[1] = -1+(random_u16() % 2); + } + else + { + shakePos[0] = 0; + shakePos[1] = 0; + } + if (waveToggle) + { + wavePos = (sins((gGlobalTimer*3000)+(i*10000)))*2; + } + else + { + wavePos = 0; + } + get_char_from_byte(str[i], &textX, &textY, &spaceX, &offsetY); + if (xlu != prevxlu) + { + prevxlu = xlu; + if (xlu > 250) + { + gDPSetRenderMode(gDisplayListHead++, G_RM_TEX_EDGE, G_RM_TEX_EDGE2); + } + else + { + gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF); + } + } + gSPScisTextureRectangle(gDisplayListHead++, (x+shakePos[0]+textPos[0]) << 2, (y+shakePos[1]+offsetY+textPos[1]+wavePos) << 2, (x+textPos[0]+shakePos[0]+8) << 2, (y+wavePos+offsetY+shakePos[1]+12+textPos[1]) << 2, G_TX_RENDERTILE, textX << 6, textY << 6, 1 << 10, 1 << 10); + textPos[0]+=spaceX+1; + } + gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); +} + +void render_multi_image(Texture *image, s32 x, s32 y, s32 width, s32 height, s32 scaleX, s32 scaleY, s32 mode) +{ + s32 posW, posH, imW, imH, peakH, maskW, maskH, cycles, num, i, modeSC, mOne; + i = 0; + num = 256; + maskW = 1; + maskH = 1; + + if (mode == G_CYC_COPY) + { + gDPSetCycleType(gDisplayListHead++, mode); + gDPSetRenderMode(gDisplayListHead++, G_RM_NOOP, G_RM_NOOP2); + modeSC = 4; + mOne = 1; + } + else + { + gDPSetCycleType(gDisplayListHead++, mode); + gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + modeSC = 1; + mOne = 0; + } + + + //Find how best to seperate the horizontal. Keep going until it finds a whole value. + while (1) + { + f32 val = (f32)width/(f32)num; + + if ((s32)val == val && (s32) val >= 1) + { + imW = num; + break; + } + num /= 2; + if (num == 1) + { + print_text(32,32,"IMAGE WIDTH FAILURE"); + return; + } + } + //Find the tile height + imH = 64/(imW/32); //This gets the vertical amount. + + num = 2; + //Find the width mask + while (1) + { + if ((s32) num == imW) + break; + + num*=2; + maskW++; + if (maskW == 9) + { + print_text(32,32,"WIDTH MASK FAILURE"); + return; + } + } + num = 2; + //Find the height mask + while (1) + { + if ((s32) num == imH) + break; + + num*=2; + maskH++; + if (maskH == 9) + { + print_text(32,32,"HEIGHT MASK FAILURE"); + return; + } + } + num = height; + //Find the height remainder + peakH = height - (height % imH); + cycles = (width*peakH)/(imW*imH); + + //Pass 1 + for (i = 0; i < cycles; i++) + { + posW = 0; + posH = (i*imH); + while (posH >= peakH) + { + posW += imW; + posH -= peakH; + } + gDPLoadSync(gDisplayListHead++); + gDPLoadTextureTile(gDisplayListHead++, image, G_IM_FMT_RGBA, G_IM_SIZ_16b, width, height, posW, posH, posW+imW-1, posH+imH-1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, maskW, maskH, 0, 0); + gSPScisTextureRectangle(gDisplayListHead++, (x + posW) << 2, (y + posH) << 2, (x + posW+imW-mOne) << 2,(y + posH + imH-mOne) << 2, G_TX_RENDERTILE, 0, 0, modeSC << 10, 1 << 10); + } + //If there's a remainder on the vertical side, then it will cycle through that too. + if (height-peakH != 0) + { + posW = 0; + posH = peakH; + for (i = 0; i < (width/imW); i++) + { + posW = i*imW; + gDPLoadSync(gDisplayListHead++); + gDPLoadTextureTile(gDisplayListHead++, image, G_IM_FMT_RGBA, G_IM_SIZ_16b, width, height, posW, posH, posW+imW-1, height-1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, maskW, maskH, 0, 0); + gSPScisTextureRectangle(gDisplayListHead++, (x + posW) << 2, (y + posH) << 2, (x + posW+imW-mOne) << 2,(y + posH + imH-mOne) << 2, G_TX_RENDERTILE, 0, 0, modeSC << 10, 1 << 10); + } + } +} + +#endif diff --git a/src/game/puppyprint.h b/src/game/puppyprint.h new file mode 100644 index 00000000..3004ca3c --- /dev/null +++ b/src/game/puppyprint.h @@ -0,0 +1,75 @@ +#ifndef PUPPYPRINT_H +#define PUPPYPRINT_H + +#ifdef PUPPYPRINT + +//This is how many indexes of timers are saved at once. higher creates a smoother average, but naturally uses more RAM. 15's fine. +#define NUM_PERF_ITERATIONS 15 +#define NUM_BENCH_ITERATIONS 150 +#define LOG_BUFFER_SIZE 16 + +#define BENCHMARK_GAME 1 +#define BENCHMARK_AUDIO 2 +#define BENCHMARK_GRAPHICS 3 + +#define PRINT_TEXT_ALIGN_LEFT 0 +#define PRINT_TEXT_ALIGN_CENTRE 1 +#define PRINT_TEXT_ALIGN_RIGHT 2 +#define PRINT_ALL -1 + +extern Texture small_font[]; +extern s8 perfIteration; +extern s16 benchmarkLoop; +extern s32 benchmarkTimer; +extern u8 currEnv[4]; +extern s32 ramsizeSegment[33]; +extern s32 audioPool[12]; +extern s8 nameTable; +extern s32 mempool; +extern u8 benchOption; + +//General +extern OSTime cpuTime; +extern OSTime rspTime; +extern OSTime rdpTime; +extern OSTime ramTime; +extern OSTime loadTime; +extern OSTime rspDelta; +extern s32 benchMark[NUM_BENCH_ITERATIONS+2]; + +//CPU +extern OSTime collisionTime[NUM_PERF_ITERATIONS+1]; +extern OSTime behaviourTime[NUM_PERF_ITERATIONS+1]; +extern OSTime scriptTime[NUM_PERF_ITERATIONS+1]; +extern OSTime graphTime[NUM_PERF_ITERATIONS+1]; +extern OSTime audioTime[NUM_PERF_ITERATIONS+1]; +extern OSTime dmaTime[NUM_PERF_ITERATIONS+1]; +extern OSTime dmaAudioTime[NUM_PERF_ITERATIONS+1]; +//RSP +extern OSTime rspGenTime[NUM_PERF_ITERATIONS+1]; +//RDP +extern OSTime bufferTime[NUM_PERF_ITERATIONS+1]; +extern OSTime tmemTime[NUM_PERF_ITERATIONS+1]; +extern OSTime busTime[NUM_PERF_ITERATIONS+1]; + +extern void profiler_update(OSTime *time, OSTime time2); +extern void puppyprint_profiler_process(void); +extern void puppyprint_render_profiler(void); +extern void puppyprint_profiler_finished(void); +extern void print_set_envcolour(s32 r, s32 g, s32 b, s32 a); +extern void prepare_blank_box(void); +extern void finish_blank_box(void); +extern void render_blank_box(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b, u8 a); +extern void print_small_text(s32 x, s32 y, const char *str, s32 align, s32 amount); +extern void render_multi_image(Texture *image, s32 x, s32 y, s32 width, s32 height, s32 scaleX, s32 scaleY, s32 mode); +extern s32 get_text_height(const char *str); +extern s32 get_text_width(const char *str); +extern void prepare_blank_box(void); +extern void finish_blank_box(void); +extern void render_blank_box(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b, u8 a); +extern void append_puppyprint_log(char str[255]); +extern char consoleLogTable[LOG_BUFFER_SIZE][255]; + +#endif + +#endif // PUPPYPRINT_H diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 6c64325b..e4c96d0e 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -12,11 +12,11 @@ #include "sm64.h" #include "game_init.h" #include "engine/extended_bounds.h" +#include "puppyprint.h" +#include "debug_box.h" #include "config.h" -#define WIDESCREEN - /** * This file contains the code that processes the scene graph for rendering. * The scene graph is responsible for drawing everything except the HUD / text boxes. @@ -46,6 +46,7 @@ s16 gMatStackIndex; Mat4 gMatStack[32]; Mtx *gMatStackFixed[32]; f32 aspect; +f32 gWorldScale = 1.0f; /** * Animation nodes have state in global variables, so this struct captures @@ -79,52 +80,6 @@ struct RenderModeContainer { }; /* Rendermode settings for cycle 1 for all 8 layers. */ -#ifdef DISABLE_AA -struct RenderModeContainer renderModeTable_1Cycle[2] = { { { - G_RM_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_TEX_EDGE, - G_RM_AA_XLU_SURF, - G_RM_AA_XLU_SURF, - G_RM_AA_XLU_SURF, - } }, - { { - /* z-buffered */ - G_RM_ZB_OPA_SURF, - G_RM_ZB_OPA_SURF, - G_RM_ZB_OPA_DECAL, - G_RM_AA_ZB_OPA_INTER, - G_RM_AA_ZB_TEX_EDGE, - G_RM_ZB_XLU_SURF, - G_RM_ZB_XLU_DECAL, - G_RM_AA_ZB_XLU_INTER, - } } }; - -/* Rendermode settings for cycle 2 for all 8 layers. */ -struct RenderModeContainer renderModeTable_2Cycle[2] = { { { - G_RM_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_TEX_EDGE2, - G_RM_AA_XLU_SURF2, - G_RM_AA_XLU_SURF2, - G_RM_AA_XLU_SURF2, - } }, - { { - /* z-buffered */ - G_RM_ZB_OPA_SURF2, - G_RM_ZB_OPA_SURF2, - G_RM_ZB_OPA_DECAL2, - G_RM_AA_ZB_OPA_INTER2, - G_RM_AA_ZB_TEX_EDGE2, - G_RM_ZB_XLU_SURF2, - G_RM_ZB_XLU_DECAL2, - G_RM_AA_ZB_XLU_INTER2, - } } }; -#else struct RenderModeContainer renderModeTable_1Cycle[2] = { { { G_RM_OPA_SURF, G_RM_AA_OPA_SURF, @@ -169,7 +124,6 @@ struct RenderModeContainer renderModeTable_2Cycle[2] = { { { G_RM_AA_ZB_XLU_DECAL2, G_RM_AA_ZB_XLU_INTER2, } } }; -#endif struct GraphNodeRoot *gCurGraphNodeRoot = NULL; struct GraphNodeMasterList *gCurGraphNodeMasterList = NULL; @@ -297,17 +251,21 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { u16 perspNorm; Mtx *mtx = alloc_display_list(sizeof(*mtx)); #ifdef WIDE - if (gWidescreen){ + if (gWidescreen && (gCurrLevelNum != 0x01)){ aspect = 1.775f; - } - else{ + } else { aspect = 1.33333f; } #else aspect = 1.33333f; #endif - guPerspective(mtx, &perspNorm, node->fov, aspect, node->near / WORLD_SCALE, node->far / WORLD_SCALE, 1.0f); + if (gCamera) + gWorldScale = MAX(((gCamera->pos[0] * gCamera->pos[0]) + (gCamera->pos[1] * gCamera->pos[1]) + (gCamera->pos[2] * gCamera->pos[2]))/67108864, 1.0f); + else + gWorldScale = 1.0f; + + guPerspective(mtx, &perspNorm, node->fov, aspect, (node->far/300) / gWorldScale, node->far / gWorldScale, 1.0f); gSPPerspNormalize(gDisplayListHead++, perspNorm); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); @@ -335,7 +293,7 @@ static void geo_process_level_of_detail(struct GraphNodeLevelOfDetail *node) { #else distanceFromCam = -gMatStack[gMatStackIndex][3][2]; #endif - + if ((f32)node->minDistance <= distanceFromCam && distanceFromCam < (f32)node->maxDistance) { if (node->node.children != 0) { geo_process_node_and_siblings(node->node.children); @@ -591,13 +549,13 @@ static void geo_process_background(struct GraphNodeBackground *node) { gDPPipeSync(gfx++); gDPSetCycleType(gfx++, G_CYC_FILL); gDPSetFillColor(gfx++, node->background); - gDPFillRectangle(gfx++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), BORDER_HEIGHT, - GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - BORDER_HEIGHT - 1); + gDPFillRectangle(gfx++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), gBorderHeight, + GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - gBorderHeight - 1); gDPPipeSync(gfx++); gDPSetCycleType(gfx++, G_CYC_1CYCLE); gSPEndDisplayList(gfx++); - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(gfxStart), 0); + geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(gfxStart), LAYER_FORCE); } if (node->fnNode.node.children != NULL) { geo_process_node_and_siblings(node->fnNode.node.children); @@ -765,11 +723,11 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; if (gShadowAboveWaterOrLava == TRUE) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 4); + geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), LAYER_ALPHA); } else if (gMarioOnIceOrCarpet == 1 || gShadowAboveCustomWater == 1) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 5); + geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), LAYER_TRANSPARENT); } else { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 6); + geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), LAYER_TRANSPARENT_DECAL); } gMatStackIndex--; } @@ -832,11 +790,10 @@ static s32 obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { // the amount of units between the center of the screen and the horizontal edge // given the distance from the object to the camera. -#ifdef WIDESCREEN // This multiplication should really be performed on 4:3 as well, // but the issue will be more apparent on widescreen. + // HackerSM64: This multiplication is done regardless of aspect ratio to fix object pop-in on the edges of the screen (which happens at 4:3 too) hScreenEdge *= GFX_DIMENSIONS_ASPECT_RATIO; -#endif if (geo != NULL && geo->type == GRAPH_NODE_TYPE_CULLING_RADIUS) { cullingRadius = @@ -904,6 +861,33 @@ static void geo_process_object(struct Object *node) { mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; if (node->header.gfx.sharedChild != NULL) { + #ifdef VISUAL_DEBUG + if (hitboxView) + { + Vec3f bnds1; + Vec3f bnds2; + //This will create a cylinder that visualises their hitbox. + //If they do not have a hitbox, it will be a small white cube instead. + if (node->oIntangibleTimer != -1) + { + vec3f_set(bnds1, node->oPosX, node->oPosY - node->hitboxDownOffset, node->oPosZ); + vec3f_set(bnds2, node->hitboxRadius, node->hitboxHeight-node->hitboxDownOffset, node->hitboxRadius); + debug_box_color(0x800000FF); + debug_box(bnds1, bnds2, DEBUG_SHAPE_CYLINDER); + vec3f_set(bnds1, node->oPosX, node->oPosY - node->hitboxDownOffset, node->oPosZ); + vec3f_set(bnds2, node->hurtboxRadius, node->hurtboxHeight, node->hurtboxRadius); + debug_box_color(0x8FF00000); + debug_box(bnds1, bnds2, DEBUG_SHAPE_CYLINDER); + } + else + { + vec3f_set(bnds1, node->oPosX, node->oPosY - 15, node->oPosZ); + vec3f_set(bnds2, 30, 30, 30); + debug_box_color(0x80FFFFFF); + debug_box(bnds1, bnds2, DEBUG_SHAPE_BOX); + } + } + #endif gCurGraphNodeObject = (struct GraphNodeObject *) node; node->header.gfx.sharedChild->parent = &node->header.gfx.node; geo_process_node_and_siblings(node->header.gfx.sharedChild); @@ -1111,6 +1095,9 @@ void geo_process_node_and_siblings(struct GraphNode *firstNode) { */ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) { UNUSED s32 unused; + #if PUPPYPRINT_DEBUG + OSTime first = osGetTime(); + #endif if (node->node.flags & GRAPH_RENDER_ACTIVE) { Mtx *initialMatrix; @@ -1151,4 +1138,7 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) } main_pool_free(gDisplayListHeap); } + #if PUPPYPRINT_DEBUG + profiler_update(graphTime, first); + #endif } diff --git a/src/game/rendering_graph_node.h b/src/game/rendering_graph_node.h index 097c7876..8c37e512 100644 --- a/src/game/rendering_graph_node.h +++ b/src/game/rendering_graph_node.h @@ -12,6 +12,7 @@ extern struct GraphNodeCamera *gCurGraphNodeCamera; extern struct GraphNodeObject *gCurGraphNodeObject; extern struct GraphNodeHeldObject *gCurGraphNodeHeldObject; extern u16 gAreaUpdateCounter; +extern f32 gWorldScale; // after processing an object, the type is reset to this #define ANIM_TYPE_NONE 0 diff --git a/src/game/rumble_init.c b/src/game/rumble_init.c index b616cbc6..89de2368 100644 --- a/src/game/rumble_init.c +++ b/src/game/rumble_init.c @@ -22,8 +22,8 @@ OSMesgQueue gRumbleThreadVIMesgQueue; struct RumbleData gRumbleDataQueue[3]; struct StructSH8031D9B0 gCurrRumbleSettings; -s32 sRumblePakThreadActive = 0; -s32 sRumblePakActive = 0; +s32 sRumblePakThreadActive = FALSE; +s32 sRumblePakActive = FALSE; s32 sRumblePakErrorCount = 0; s32 gRumblePakTimer = 0; @@ -288,7 +288,7 @@ void create_thread_6(void) { } void rumble_thread_update_vi(void) { - if (sRumblePakThreadActive == FALSE) { + if (!sRumblePakThreadActive) { return; } diff --git a/src/game/rumble_init.h b/src/game/rumble_init.h index c421b059..cc47d75b 100644 --- a/src/game/rumble_init.h +++ b/src/game/rumble_init.h @@ -1,6 +1,10 @@ #ifndef RUMBLE_INIT_H #define RUMBLE_INIT_H +#include + +#include "config.h" + #if ENABLE_RUMBLE extern s32 gRumblePakTimer; diff --git a/src/game/save_file.c b/src/game/save_file.c index 21d419ac..bcdcdbaf 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -15,13 +15,14 @@ #ifdef SRAM #include "sram.h" #endif +#include "puppycam2.h" #define ALIGN4(val) (((val) + 0x3) & ~0x3) #define MENU_DATA_MAGIC 0x4849 #define SAVE_FILE_MAGIC 0x4441 -STATIC_ASSERT(sizeof(struct SaveBuffer) == EEPROM_SIZE, "eeprom buffer size must match"); +//STATIC_ASSERT(sizeof(struct SaveBuffer) == EEPROM_SIZE, "eeprom buffer size must match"); extern struct SaveBuffer gSaveBuffer; @@ -225,7 +226,7 @@ static void save_main_menu_data(void) { add_save_block_signature(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]), MENU_DATA_MAGIC); // Back up data - bcopy(&gSaveBuffer.menuData[0], &gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1])); + //bcopy(&gSaveBuffer.menuData[0], &gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1])); // Write to EEPROM write_eeprom_data(gSaveBuffer.menuData, sizeof(gSaveBuffer.menuData)); @@ -359,7 +360,7 @@ void save_file_load_all(void) { // Verify the main menu data and create a backup copy if only one of the slots is valid. validSlots = verify_save_block_signature(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]), MENU_DATA_MAGIC); - validSlots |= verify_save_block_signature(&gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1]),MENU_DATA_MAGIC) << 1; + //validSlots |= verify_save_block_signature(&gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1]),MENU_DATA_MAGIC) << 1; switch (validSlots) { case 0: // Neither copy is correct wipe_main_menu_data(); @@ -390,6 +391,44 @@ void save_file_load_all(void) { } } +#ifdef PUPPYCAM +void puppycam_check_save(void) +{ + if (gSaveBuffer.menuData[0].firstBoot != 4 || gSaveBuffer.menuData[0].saveOptions.sensitivityX < 5 || gSaveBuffer.menuData[0].saveOptions.sensitivityY < 5) + { + wipe_main_menu_data(); + gSaveBuffer.menuData[0].firstBoot = 4; + puppycam_default_config(); + } +} + +void puppycam_get_save(void) +{ + gPuppyCam.options = gSaveBuffer.menuData[0].saveOptions; + + gSaveBuffer.menuData[0].firstBoot = gSaveBuffer.menuData[0].firstBoot; + #ifdef WIDE + gWidescreen = save_file_get_widescreen_mode(); + #endif + + puppycam_check_save(); +} + +void puppycam_set_save(void) +{ + gSaveBuffer.menuData[0].saveOptions = gPuppyCam.options; + + gSaveBuffer.menuData[0].firstBoot = 4; + + #ifdef WIDE + save_file_set_widescreen_mode(gWidescreen); + #endif + + gMainMenuDataModified = TRUE; + save_main_menu_data(); +} +#endif + /** * Reload the current save file from its backup copy, which is effectively a * a cached copy of what has been written to EEPROM. @@ -629,6 +668,19 @@ void save_file_set_sound_mode(u16 mode) { save_main_menu_data(); } +#ifdef WIDE +u8 save_file_get_widescreen_mode(void) { + return gSaveBuffer.menuData[0].wideMode; +} + +void save_file_set_widescreen_mode(u8 mode) { + gSaveBuffer.menuData[0].wideMode = mode; + + gMainMenuDataModified = TRUE; + save_main_menu_data(); +} +#endif + u16 save_file_get_sound_mode(void) { return gSaveBuffer.menuData[0].soundMode; } diff --git a/src/game/save_file.h b/src/game/save_file.h index ae6fcf35..64cf0c63 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -5,10 +5,18 @@ #include "types.h" #include "area.h" +#include "puppycam2.h" #include "course_table.h" -#define EEPROM_SIZE 0x200 +#if defined(SRAM) + #define EEPROM_SIZE 0x8000 +#elif defined(EEP16K) + #define EEPROM_SIZE 0x800 +#else + #define EEPROM_SIZE 0x200 +#endif + #define NUM_SAVE_FILES 4 struct SaveBlockSignature @@ -51,18 +59,25 @@ struct MainMenuSaveData // the older the high score is. This is used for tie-breaking when displaying // on the high score screen. u32 coinScoreAges[NUM_SAVE_FILES]; - u16 soundMode; + u8 soundMode: 2; +#ifdef WIDE + u8 wideMode: 1; +#endif #ifdef VERSION_EU - u16 language; + u8 language: 2; #define SUBTRAHEND 8 #else #define SUBTRAHEND 6 #endif + u8 firstBoot; // Pad to match the EEPROM size of 0x200 (10 bytes on JP/US, 8 bytes on EU) - u8 filler[EEPROM_SIZE / 2 - SUBTRAHEND - NUM_SAVE_FILES * (4 + sizeof(struct SaveFile))]; + //u8 filler[EEPROM_SIZE / 2 - SUBTRAHEND - NUM_SAVE_FILES * (4 + sizeof(struct SaveFile))]; + #ifdef PUPPYCAM + struct gPuppyOptions saveOptions; + #endif struct SaveBlockSignature signature; }; @@ -71,9 +86,17 @@ struct SaveBuffer // Each of the four save files has two copies. If one is bad, the other is used as a backup. struct SaveFile files[NUM_SAVE_FILES][2]; // The main menu data has two copies. If one is bad, the other is used as a backup. - struct MainMenuSaveData menuData[2]; + struct MainMenuSaveData menuData[1]; }; +#ifdef PUPPYCAM +extern void puppycam_set_save(void); +extern void puppycam_get_save(void); +extern void puppycam_check_save(void); +#endif + +STATIC_ASSERT(sizeof(struct SaveBuffer) <= EEPROM_SIZE, "ERROR: Save struct too big for specified save type"); + extern u8 gLastCompletedCourseNum; extern u8 gLastCompletedStarNum; extern s8 sUnusedGotGlobalCoinHiScore; @@ -151,6 +174,10 @@ void save_file_set_cap_pos(s16 x, s16 y, s16 z); s32 save_file_get_cap_pos(Vec3s capPos); void save_file_set_sound_mode(u16 mode); u16 save_file_get_sound_mode(void); +#ifdef WIDE +u8 save_file_get_widescreen_mode(void); +void save_file_set_widescreen_mode(u8 mode); +#endif void save_file_move_cap_to_default_location(void); void disable_warp_checkpoint(void); diff --git a/src/game/screen_transition.c b/src/game/screen_transition.c index 190a436d..a2bf0018 100644 --- a/src/game/screen_transition.c +++ b/src/game/screen_transition.c @@ -30,7 +30,7 @@ s32 set_and_reset_transition_fade_timer(s8 fadeTimer, u8 transTime) { } u8 set_transition_color_fade_alpha(s8 fadeType, s8 fadeTimer, u8 transTime) { - u8 time; + u8 time = 0; switch (fadeType) { case 0: @@ -239,6 +239,9 @@ s32 render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct Wa return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR); break; } +#ifdef AVOID_UB + return 0; +#endif } Gfx *render_cannon_circle_base(void) { @@ -294,8 +297,10 @@ Gfx *geo_cannon_circle_base(s32 callContext, struct GraphNode *node, UNUSED Mat4 if (callContext == GEO_CONTEXT_RENDER && gCurrentArea != NULL && gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) { - graphNode->fnNode.node.flags = (graphNode->fnNode.node.flags & 0xFF) | 0x500; + graphNode->fnNode.node.flags = (graphNode->fnNode.node.flags & 0xFF) | (LAYER_TRANSPARENT << 8); +#ifndef L3DEX2_ALONE dlist = render_cannon_circle_base(); +#endif } return dlist; } diff --git a/src/game/shadow.c b/src/game/shadow.c index 8a978777..73f9fc6d 100644 --- a/src/game/shadow.c +++ b/src/game/shadow.c @@ -189,6 +189,9 @@ f32 get_water_level_below_shadow(struct Shadow *s, struct Surface **waterFloor) return waterLevel; //! @bug Missing return statement. This compiles to return `waterLevel` //! incidentally. +#ifdef AVOID_UB + return waterLevel; +#endif } /** @@ -307,7 +310,8 @@ void make_shadow_vertex_at_xyz(Vtx *vertices, s8 index, f32 relX, f32 relY, f32 s16 vtxX = round_float(relX); s16 vtxY = round_float(relY); s16 vtxZ = round_float(relZ); - s16 textureX, textureY; + s16 textureX = 0; + s16 textureY = 0; switch (shadowVertexType) { case SHADOW_WITH_9_VERTS: @@ -542,9 +546,6 @@ s8 correct_shadow_solidity_for_animations(s32 isLuigi, u8 initialSolidity, struc s16 animFrame; switch (isLuigi) { - case 0: - player = gMarioObject; - break; case 1: /** * This is evidence of a removed second player, likely Luigi. @@ -556,6 +557,10 @@ s8 correct_shadow_solidity_for_animations(s32 isLuigi, u8 initialSolidity, struc */ player = gLuigiObject; break; + case 0: + default: + player = gMarioObject; + break; } animFrame = player->header.gfx.animInfo.animFrame; @@ -609,7 +614,7 @@ Gfx *create_shadow_player(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 soli Vtx *verts; Gfx *displayList; struct Shadow shadow; - s8 ret; + s8 ret = 0; s32 i; // Update global variables about whether Mario is on a flying carpet. diff --git a/src/game/sound_init.c b/src/game/sound_init.c index eb11aa30..36492986 100644 --- a/src/game/sound_init.c +++ b/src/game/sound_init.c @@ -15,6 +15,7 @@ #include "sm64.h" #include "sound_init.h" #include "rumble_init.h" +#include "puppyprint.h" #define MUSIC_NONE 0xFFFF @@ -23,13 +24,15 @@ static OSMesgQueue sSoundMesgQueue; static OSMesg sSoundMesgBuf[1]; static struct VblankHandler sSoundVblankHandler; -static u8 D_8032C6C0 = 0; -static u8 D_8032C6C4 = 0; +// Only written to, never read. +static u8 sMusicVolume = 0; + +static u8 sBgMusicDisabled = FALSE; static u16 sCurrentMusic = MUSIC_NONE; static u16 sCurrentShellMusic = MUSIC_NONE; static u16 sCurrentCapMusic = MUSIC_NONE; static u8 sPlayingInfiniteStairs = FALSE; -static u8 unused8032C6D8[16] = { 0 }; +UNUSED static u8 unused8032C6D8[16] = { 0 }; static s16 sSoundMenuModeToSoundMode[] = { SOUND_MODE_STEREO, SOUND_MODE_MONO, SOUND_MODE_HEADSET }; // Only the 20th array element is used. static u32 sMenuSoundsExtra[] = { @@ -78,7 +81,7 @@ void play_menu_sounds_extra(s32 a, void *b); * Called from threads: thread5_game_loop */ void reset_volume(void) { - D_8032C6C0 = 0; + sMusicVolume = 0; } /** @@ -93,7 +96,7 @@ void lower_background_noise(s32 a) { seq_player_lower_volume(SEQ_PLAYER_LEVEL, 60, 40); break; } - D_8032C6C0 |= a; + sMusicVolume |= a; } /** @@ -108,15 +111,15 @@ void raise_background_noise(s32 a) { seq_player_unlower_volume(SEQ_PLAYER_LEVEL, 60); break; } - D_8032C6C0 &= ~a; + sMusicVolume &= ~a; } /** * Called from threads: thread5_game_loop */ void disable_background_sound(void) { - if (D_8032C6C4 == 0) { - D_8032C6C4 = 1; + if (sBgMusicDisabled == FALSE) { + sBgMusicDisabled = TRUE; sound_banks_disable(SEQ_PLAYER_SFX, SOUND_BANKS_BACKGROUND); } } @@ -125,8 +128,8 @@ void disable_background_sound(void) { * Called from threads: thread5_game_loop */ void enable_background_sound(void) { - if (D_8032C6C4 == 1) { - D_8032C6C4 = 0; + if (sBgMusicDisabled == TRUE) { + sBgMusicDisabled = FALSE; sound_banks_enable(SEQ_PLAYER_SFX, SOUND_BANKS_BACKGROUND); } } @@ -333,6 +336,9 @@ void audio_game_loop_tick(void) { void thread4_sound(UNUSED void *arg) { audio_init(); sound_init(); + #if PUPPYPRINT_DEBUG + OSTime lastTime; + #endif // Zero-out unused vector vec3f_copy(unused80339DC0, gVec3fZero); @@ -340,22 +346,44 @@ void thread4_sound(UNUSED void *arg) { osCreateMesgQueue(&sSoundMesgQueue, sSoundMesgBuf, ARRAY_COUNT(sSoundMesgBuf)); set_vblank_handler(1, &sSoundVblankHandler, &sSoundMesgQueue, (OSMesg) 512); - while (TRUE) { + while (TRUE) + { OSMesg msg; osRecvMesg(&sSoundMesgQueue, &msg, OS_MESG_BLOCK); - if (gResetTimer < 25) { - struct SPTask *spTask; - profiler_log_thread4_time(); -#ifdef VERSION_SH - spTask = func_sh_802f5a80(); // The function was probably just moved to a different file. Don't kill me. -#else - spTask = create_next_audio_frame_task(); -#endif - if (spTask != NULL) { - dispatch_audio_sptask(spTask); + #if PUPPYPRINT_DEBUG + while (TRUE) + { + lastTime = osGetTime(); + dmaAudioTime[perfIteration] = 0; + #endif + if (gResetTimer < 25) { + struct SPTask *spTask; + profiler_log_thread4_time(); + spTask = create_next_audio_frame_task(); + if (spTask != NULL) { + dispatch_audio_sptask(spTask); + } + profiler_log_thread4_time(); + #if PUPPYPRINT_DEBUG + profiler_update(audioTime, lastTime); + audioTime[perfIteration] -= dmaAudioTime[perfIteration]; + if (benchmarkLoop > 0 && benchOption == 1) + { + benchmarkLoop--; + benchMark[benchmarkLoop] = osGetTime() - lastTime; + if (benchmarkLoop == 0) + { + puppyprint_profiler_finished(); + break; + } + } + else + break; + #endif } - profiler_log_thread4_time(); + #if PUPPYPRINT_DEBUG } + #endif } } diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index b670751b..4cc1636b 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -163,7 +163,7 @@ void clear_object_lists(struct ObjectNode *objLists) { * This function looks broken, but it appears to attempt to delete the leaf * graph nodes under obj and obj's siblings. */ -static void unused_delete_leaf_nodes(struct Object *obj) { +UNUSED static void unused_delete_leaf_nodes(struct Object *obj) { struct Object *children; struct Object *sibling; struct Object *obj0 = obj; diff --git a/src/game/vc_check.c b/src/game/vc_check.c new file mode 100644 index 00000000..4029bd49 --- /dev/null +++ b/src/game/vc_check.c @@ -0,0 +1,9 @@ +#include "vc_check.h" + +u8 gIsVC = FALSE; + +// literally return what was passed +f32 round_double_to_float(f64 v) +{ + return v; +} diff --git a/src/game/vc_check.h b/src/game/vc_check.h new file mode 100644 index 00000000..c39ac722 --- /dev/null +++ b/src/game/vc_check.h @@ -0,0 +1,22 @@ +#ifndef VC_CHECK_H +#define VC_CHECK_H + +#include "sm64.h" + +extern u8 gIsVC; + +// This function must not be inlined by the compiler so I move it to a different C file +f32 round_double_to_float(f64); + +/* + * This check forces RTZ bug on vc + * If console is N64/adequate Emu round-to-nearest (RTN) rounding mode is used + * If console is VC round-to-zero (RTZ) mode is used + * + * The double value 0.9999999999999999 used is 0x3FEFFFFFFFFFFFFF in binary + * Exponent=01111111110, Mantissa=1111111111111111111111111111111111111111111111111111 + * RTZ will output not 1.0f, RTN will output exactly 1.0f + */ +#define IS_VC() (1.0f != round_double_to_float(0.9999999999999999)) + +#endif diff --git a/src/goddard/debug_utils.c b/src/goddard/debug_utils.c index 2e87b3d6..0d81d729 100644 --- a/src/goddard/debug_utils.c +++ b/src/goddard/debug_utils.c @@ -459,7 +459,11 @@ void fatal_printf(const char *fmt, ...) { gd_printf("%s", va_arg(vl, char *)); break; case 'c': +#ifdef AVOID_UB + gd_printf("%c", (char)va_arg(vl, int)); +#else gd_printf("%c", va_arg(vl, char)); +#endif break; case 'x': gd_printf("%x", va_arg(vl, s32)); diff --git a/src/goddard/draw_objects.c b/src/goddard/draw_objects.c index 48ce6d7c..ba1a402e 100644 --- a/src/goddard/draw_objects.c +++ b/src/goddard/draw_objects.c @@ -59,7 +59,7 @@ static struct GdColour sClrYellow = { 1.0, 1.0, 0.0 }; // @ 801A80DC static struct GdColour sLightColours[1] = { { 1.0, 1.0, 0.0 } }; // @ 801A80E8 static struct GdColour *sSelectedColour = &sClrRed; // @ 801A80F4 struct ObjCamera *gViewUpdateCamera = NULL; // @ 801A80F8 -static void *sUnref801A80FC = NULL; +UNUSED static void *sUnref801A80FC = NULL; static s32 sUnreadShapeFlag = 0; // @ 801A8100 struct GdColour *sColourPalette[5] = { // @ 801A8104 &sClrWhite, &sClrYellow, &sClrRed, &sClrBlack, &sClrBlack @@ -69,20 +69,20 @@ struct GdColour *sWhiteBlack[2] = { &sClrWhite, &sClrBlack, }; -static Mat4f sUnref801A8120 = { +UNUSED static Mat4f sUnref801A8120 = { { 1.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 } }; -static Mat4f sUnrefIden801A8160 = { +UNUSED static Mat4f sUnrefIden801A8160 = { { 1.0, 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 } }; static s32 sLightDlCounter = 1; // @ 801A81A0 -static s32 sUnref801A81A4[4] = { 0 }; +UNUSED static s32 sUnref801A81A4[4] = { 0 }; // bss u8 gUnref_801B9B30[0x88]; struct ObjGroup *gGdLightGroup; // @ 801B9BB8; is this the main light group? only light group? -static u8 sUnref_801B9BBC[0x40]; +UNUSED static u8 sUnref_801B9BBC[0x40]; static enum SceneType sSceneProcessType; // @ 801B9C00 static s32 sUseSelectedColor; // @ 801B9C04 static s16 sPickBuffer[100]; ///< buffer of objects near click diff --git a/src/goddard/gd_macros.h b/src/goddard/gd_macros.h index 9b65978d..a895b025 100644 --- a/src/goddard/gd_macros.h +++ b/src/goddard/gd_macros.h @@ -12,6 +12,8 @@ #define ABS(val) (((val) < 0 ? (-(val)) : (val))) #define SQ(val) ((val) * (val)) +#ifndef ALIGN #define ALIGN(VAL_, ALIGNMENT_) (((VAL_) + ((ALIGNMENT_) - 1)) & ~((ALIGNMENT_) - 1)) +#endif #endif // GD_MACROS_H diff --git a/src/goddard/gd_main.c b/src/goddard/gd_main.c index 8182096e..8d2c85e7 100644 --- a/src/goddard/gd_main.c +++ b/src/goddard/gd_main.c @@ -14,11 +14,11 @@ // data s32 gGdMoveScene = TRUE; // @ 801A8050 -static s32 sUnref801A8054 = TRUE; +UNUSED static s32 sUnref801A8054 = TRUE; f32 D_801A8058 = -600.0f; s32 gGdUseVtxNormal = TRUE; // @ 801A805C; instead of face normals -static s32 sUnrefScnWidth = 320; -static s32 sUnrefScnHeight = 240; +UNUSED static s32 sUnrefScnWidth = 320; +UNUSED static s32 sUnrefScnHeight = 240; // bss struct GdControl gGdCtrl; // @ 801B9920; processed controller info diff --git a/src/goddard/joints.c b/src/goddard/joints.c index 76830369..7fd60c5c 100644 --- a/src/goddard/joints.c +++ b/src/goddard/joints.c @@ -668,7 +668,7 @@ void func_80190574(s32 a0, struct ObjJoint *a1, struct ObjJoint *a2, f32 x, f32 UNUSED u32 pad268; UNUSED u32 sp264 = 0; UNUSED u32 sp258[3]; // unused vec? - struct GdVec3f sp24C; + struct GdVec3f sp24C = {0, 0, 0}; struct GdVec3f sp240; UNUSED u32 pad238[2]; s32 sp234; // i? diff --git a/src/goddard/old_menu.c b/src/goddard/old_menu.c index 10656eb7..e13faa59 100644 --- a/src/goddard/old_menu.c +++ b/src/goddard/old_menu.c @@ -21,9 +21,9 @@ */ // bss -static char sDefSettingsMenuStr[0x100]; +UNUSED static char sDefSettingsMenuStr[0x100]; static struct GdVec3f sStaticVec; -static struct GdVec3f unusedVec; +UNUSED static struct GdVec3f unusedVec; static struct ObjGadget *sCurGadgetPtr; // forward declarations diff --git a/src/goddard/particles.c b/src/goddard/particles.c index 9090eb43..adee570b 100644 --- a/src/goddard/particles.c +++ b/src/goddard/particles.c @@ -27,7 +27,7 @@ struct Connection { }; // data -static void *sUnused801A81D0 = NULL; +UNUSED static void *sUnused801A81D0 = NULL; static s32 D_801A81D4[25] = { /* ID? X Y Z */ 9, 3, 12, -14, 25, 5, 16, -25, 42, 4, 15, -39, 55, diff --git a/src/goddard/renderer.c b/src/goddard/renderer.c index 0b398613..6e8dd3a8 100644 --- a/src/goddard/renderer.c +++ b/src/goddard/renderer.c @@ -113,10 +113,10 @@ static u8 D_801BAEA0; static struct ObjGadget *sTimerGadgets[GD_NUM_TIMERS]; // @ 801BAEA8 static u32 D_801BAF28; // RAM addr offset? static s16 sTriangleBuf[13][8]; // [[s16; 8]; 13]? vert indices? -static u32 unref_801bb000[3]; +UNUSED static u32 unref_801bb000[3]; static u8 *sMemBlockPoolBase; // @ 801BB00C static u32 sAllocMemory; // @ 801BB010; malloc-ed bytes -static u32 unref_801bb014; +UNUSED static u32 unref_801bb014; static s32 D_801BB018; static s32 D_801BB01C; static void *sLoadedTextures[0x10]; // texture pointers @@ -136,11 +136,11 @@ static s32 sVertexBufStartIndex; // Vtx start in GD Dl static struct ObjView *sCarSceneView; // @ 801BB0D0 static s32 sUpdateYoshiScene; // @ 801BB0D4; update dl Vtx from ObjVertex? static s32 sUpdateMarioScene; // @ 801BB0D8; update dl Vtx from ObjVertex? -static u32 unref_801bb0dc; +UNUSED static u32 unref_801bb0dc; static s32 sUpdateCarScene; // @ 801BB0E0; guess, not really used -static u32 unref_801bb0e4; +UNUSED static u32 unref_801bb0e4; static struct GdVec3f sTextDrawPos; // position to draw text? only set in one function, never used -static u32 unref_801bb0f8[2]; +UNUSED static u32 unref_801bb0f8[2]; static Mtx sIdnMtx; // @ 801BB100 static Mat4f sInitIdnMat4; // @ 801BB140 static s8 sVtxCvrtNormBuf[3]; // @ 801BB180 @@ -153,7 +153,7 @@ static s32 sLightId; static Hilite sHilites[600]; static struct GdVec3f D_801BD758; static struct GdVec3f D_801BD768; // had to migrate earlier -static u32 D_801BD774; +UNUSED static u32 D_801BD774; static struct GdObj *sMenuGadgets[9]; // @ 801BD778; d_obj ptr storage? menu? static struct ObjView *sDebugViews[2]; // Seems to be a list of ObjViews for displaying debug info static struct GdDisplayList *sStaticDl; // @ 801BD7A8 @@ -170,21 +170,21 @@ static LookAt D_801BE7D0[3]; #if defined(VERSION_JP) || defined(VERSION_US) static OSMesgQueue D_801BE830; // controller msg queue static OSMesg D_801BE848[10]; -static u32 unref_801be870[16]; -static OSMesgQueue D_801BE8B0; +UNUSED static u32 unref_801be870[16]; +UNUSED static OSMesgQueue D_801BE8B0; static OSMesgQueue sGdDMAQueue; // @ 801BE8C8 -static u32 unref_801be8e0[25]; +UNUSED static u32 unref_801be8e0[25]; static OSMesg sGdMesgBuf[1]; // @ 801BE944 -static u32 unref_801be948[13]; +UNUSED static u32 unref_801be948[13]; static OSMesg sGdDMACompleteMsg; // msg buf for D_801BE8B0 queue static OSIoMesg sGdDMAReqMesg; static struct ObjView *D_801BE994; // store if View flag 0x40 set #endif // data -static u32 unref_801a8670 = 0; +UNUSED static u32 unref_801a8670 = 0; static s32 D_801A8674 = 0; -static u32 unref_801a8678 = 0; +UNUSED static u32 unref_801a8678 = 0; static s32 D_801A867C = 0; static s32 D_801A8680 = 0; static f32 sTracked1FrameTime = 0.0f; // @ 801A8684 @@ -199,13 +199,13 @@ static struct GdTimer *D_801A86A4 = NULL; // timer for dlgen, dynamics, or rcp static struct GdTimer *D_801A86A8 = NULL; // timer for dlgen, dynamics, or rcp static struct GdTimer *D_801A86AC = NULL; // timer for dlgen, dynamics, or rcp s32 gGdFrameBufNum = 0; // @ 801A86B0 -static u32 unref_801a86B4 = 0; +UNUSED static u32 unref_801a86B4 = 0; static struct ObjShape *sHandShape = NULL; // @ 801A86B8 static s32 D_801A86BC = 1; static s32 D_801A86C0 = 0; // gd_dl id for something? -static u32 unref_801a86C4 = 10; +UNUSED static u32 unref_801a86C4 = 10; static s32 sMtxParamType = G_MTX_PROJECTION; -static struct GdVec3f D_801A86CC = { 1.0f, 1.0f, 1.0f }; +UNUSED static struct GdVec3f D_801A86CC = { 1.0f, 1.0f, 1.0f }; static struct ObjView *sActiveView = NULL; // @ 801A86D8 current view? used when drawing dl static struct ObjView *sScreenView = NULL; // @ 801A86DC static struct ObjView *D_801A86E0 = NULL; @@ -214,7 +214,7 @@ static struct ObjView *sMenuView = NULL; // @ 801A86E8 static u32 sItemsInMenu = 0; // @ 801A86EC static s32 sDebugViewsCount = 0; // number of elements in the sDebugViews array static s32 sCurrDebugViewIndex = 0; // @ 801A86F4; timing activate cool down counter? -static u32 unref_801a86F8 = 0; +UNUSED static u32 unref_801a86F8 = 0; static struct GdDisplayList *sCurrentGdDl = NULL; // @ 801A86FC static u32 sGdDlCount = 0; // @ 801A8700 static struct DynListBankInfo sDynLists[] = { // @ 801A8704 @@ -225,7 +225,7 @@ static struct DynListBankInfo sDynLists[] = { // @ 801A8704 }; // textures and display list data -static Gfx gd_texture1_dummy_aligner1[] = { // @ 801A8728 +UNUSED static Gfx gd_texture1_dummy_aligner1[] = { // @ 801A8728 gsSPEndDisplayList(), }; @@ -233,7 +233,7 @@ ALIGNED8 static Texture gd_texture_hand_open[] = { #include "textures/intro_raw/hand_open.rgba16.inc.c" }; -static Gfx gd_texture2_dummy_aligner1[] = { +UNUSED static Gfx gd_texture2_dummy_aligner1[] = { gsSPEndDisplayList() }; @@ -494,7 +494,7 @@ ALIGNED8 static Texture gd_texture_sparkle_4[] = { //! No reference to this texture. Two DL's uses the same previous texture // instead of using this texture. -ALIGNED8 static Texture gd_texture_sparkle_5[] = { +UNUSED ALIGNED8 static Texture gd_texture_sparkle_5[] = { #include "textures/intro_raw/sparkle_5.rgba16.inc.c" }; @@ -649,7 +649,7 @@ static Gfx *gd_silver_sparkle_dl_array[] = { gd_dl_silver_sparkle_4_dup, }; -static Gfx gd_texture3_dummy_aligner1[] = { +UNUSED static Gfx gd_texture3_dummy_aligner1[] = { gsSPEndDisplayList(), }; @@ -694,13 +694,13 @@ static Gfx gd_dl_rdp_init[] = { gsSPEndDisplayList(), }; -static u32 gd_unused_pad1 = 0; +UNUSED static u32 gd_unused_pad1 = 0; float sGdPerspTimer = 1.0; -static u32 gd_unused_pad2 = 0; +UNUSED static u32 gd_unused_pad2 = 0; -static Gfx gd_texture4_dummy_aligner1[] = { +UNUSED static Gfx gd_texture4_dummy_aligner1[] = { gsDPPipeSync(), gsSPEndDisplayList(), }; @@ -717,7 +717,7 @@ static Vtx_t gd_unused_mesh_vertex_group2[] = { {{ 3, -7, 0}, 0, { 0, 0}, { 0xFF, 0x00, 0x00, 0xFF}}, }; -static Gfx gd_dl_unused_mesh[] = { +UNUSED static Gfx gd_dl_unused_mesh[] = { gsDPPipeSync(), gsDPSetRenderMode(G_RM_OPA_SURF, G_RM_OPA_SURF2), gsSPClearGeometryMode(0xFFFFFFFF), diff --git a/src/goddard/shape_helper.c b/src/goddard/shape_helper.c index 13577d51..18d1e866 100644 --- a/src/goddard/shape_helper.c +++ b/src/goddard/shape_helper.c @@ -35,24 +35,24 @@ static struct GdAnimTransform unusedAnimData1[] = { { {1.0, 1.0, 1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0} }, }; -static struct AnimDataInfo unusedAnim1 = { ARRAY_COUNT(unusedAnimData1), GD_ANIM_SCALE3F_ROT3F_POS3F_2, unusedAnimData1 }; +UNUSED static struct AnimDataInfo unusedAnim1 = { ARRAY_COUNT(unusedAnimData1), GD_ANIM_SCALE3F_ROT3F_POS3F_2, unusedAnimData1 }; static struct GdAnimTransform unusedAnimData2[] = { { {1.0, 1.0, 1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0} }, }; -static struct AnimDataInfo unusedAnim2 = { ARRAY_COUNT(unusedAnimData2), GD_ANIM_SCALE3F_ROT3F_POS3F_2, unusedAnimData2 }; +UNUSED static struct AnimDataInfo unusedAnim2 = { ARRAY_COUNT(unusedAnimData2), GD_ANIM_SCALE3F_ROT3F_POS3F_2, unusedAnimData2 }; static struct GdAnimTransform unusedAnimData3[] = { { {1.0, 1.0, 1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0} }, }; -static struct AnimDataInfo unusedAnim3 = { ARRAY_COUNT(unusedAnimData3), GD_ANIM_SCALE3F_ROT3F_POS3F_2, unusedAnimData3 }; +UNUSED static struct AnimDataInfo unusedAnim3 = { ARRAY_COUNT(unusedAnimData3), GD_ANIM_SCALE3F_ROT3F_POS3F_2, unusedAnimData3 }; -static s32 sUnref801A838C[6] = { 0 }; +UNUSED static s32 sUnref801A838C[6] = { 0 }; struct ObjShape *sSimpleShape = NULL; -static s32 sUnref801A83A8[31] = { 0 }; -static struct DynList sSimpleDylist[8] = { // unused +UNUSED static s32 sUnref801A83A8[31] = { 0 }; +UNUSED static struct DynList sSimpleDylist[8] = { // unused BeginList(), StartGroup("simpleg"), MakeDynObj(D_NET, "simple"), @@ -67,17 +67,17 @@ static struct DynList sDynlist801A84E4[3] = { SetFlag(0x1800), EndList(), }; -static struct DynList sDynlist801A85B3[5] = { +UNUSED static struct DynList sDynlist801A85B3[5] = { BeginList(), CallList(sDynlist801A84E4), SetFlag(0x400), SetFriction(0.04, 0.01, 0.01), EndList(), }; -static struct DynList sDynlist801A85A4[4] = { +UNUSED static struct DynList sDynlist801A85A4[4] = { BeginList(), CallList(sDynlist801A84E4), SetFriction(0.04, 0.01, 0.01), EndList(), }; -static struct DynList sDynlist801A8604[4] = { +UNUSED static struct DynList sDynlist801A8604[4] = { BeginList(), CallList(sDynlist801A84E4), SetFriction(0.005, 0.005, 0.005), @@ -86,35 +86,35 @@ static struct DynList sDynlist801A8604[4] = { static f64 D_801A8668 = 0.0; // bss -static u8 sUnrefSpaceB00[0x2C]; // @ 801BAB00 +UNUSED static u8 sUnrefSpaceB00[0x2C]; // @ 801BAB00 static struct ObjGroup *sCubeShapeGroup; // @ 801BAB2C -static u8 sUnrefSpaceB30[0xC]; // @ 801BAB30 +UNUSED static u8 sUnrefSpaceB30[0xC]; // @ 801BAB30 static struct ObjShape *sCubeShape; // @ 801BAB3C -static u8 sUnrefSpaceB40[0x8]; // @ 801BAB40 +UNUSED static u8 sUnrefSpaceB40[0x8]; // @ 801BAB40 static char sGdLineBuf[0x100]; // @ 801BAB48 static s32 sGdLineBufCsr; // @ 801BAC48 static struct GdFile *sGdShapeFile; // @ 801BAC4C static struct ObjShape *sGdShapeListHead; // @ 801BAC50 static u32 sGdShapeCount; // @ 801BAC54 -static u8 sUnrefSpaceC58[0x8]; // @ 801BAC58 +UNUSED static u8 sUnrefSpaceC58[0x8]; // @ 801BAC58 static struct GdVec3f D_801BAC60; -static u32 sUnrefSpaceC6C; // @ 801BAC6C -static u32 sUnrefSpaceC70; // @ 801BAC70 +UNUSED static u32 sUnrefSpaceC6C; // @ 801BAC6C +UNUSED static u32 sUnrefSpaceC70; // @ 801BAC70 static struct ObjPlane *D_801BAC74; static struct ObjPlane *D_801BAC78; // sShapeNetHead? -static u8 sUnrefSpaceC80[0x1C]; // @ 801BAC80 +UNUSED static u8 sUnrefSpaceC80[0x1C]; // @ 801BAC80 static struct ObjFace *D_801BAC9C; static struct ObjFace *D_801BACA0; -static u8 sUnrefSpaceCA8[0x10]; // @ 801BACA8 +UNUSED static u8 sUnrefSpaceCA8[0x10]; // @ 801BACA8 /// factor for scaling vertices in an `ObjShape` when calling `scale_verts_in_shape()` static struct GdVec3f sVertexScaleFactor; /// factor for translating vertices in an `ObjShape` when calling `translate_verts_in_shape()` static struct GdVec3f sVertexTranslateOffset; -static u8 sUnrefSpaceCD8[0x30]; // @ 801BACD8 +UNUSED static u8 sUnrefSpaceCD8[0x30]; // @ 801BACD8 static struct ObjGroup *D_801BAD08; // group of planes from make_netfromshape -static u8 sUnrefSpaceD10[0x20]; // @ 801BAD10 +UNUSED static u8 sUnrefSpaceD10[0x20]; // @ 801BAD10 static struct GdVec3f sShapeCenter; // printed with "c=" -static u8 sUnrefSpaceD40[0x120]; // @ 801BAD40 +UNUSED static u8 sUnrefSpaceD40[0x120]; // @ 801BAD40 // Forward Declarations struct ObjMaterial *find_or_add_new_mtl(struct ObjGroup *, s32, f32, f32, f32); diff --git a/src/menu/file_select.c b/src/menu/file_select.c index b6426eb2..7f7dfb9e 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -23,6 +23,13 @@ #include "text_strings.h" #include "eu_translation.h" +#if MULTILANG +#undef LANGUAGE_FUNCTION +#define LANGUAGE_FUNCTION sLanguageMode +s8 sLanguageMode = LANGUAGE_ENGLISH; +#endif + +extern void *languageTable[][3]; /** * @file file_select.c @@ -32,7 +39,7 @@ */ // The current sound mode is automatically centered on US and Shindou. -static s16 sSoundTextX; +s16 sSoundTextX; //! @Bug (UB Array Access) For EU, more buttons were added than the array was extended. //! This causes no currently known issues on console (as the other variables are not changed @@ -41,121 +48,128 @@ static s16 sSoundTextX; // Amount of main menu buttons defined in the code called by spawn_object_rel_with_rot. // See file_select.h for the names in MenuButtonTypes. -static struct Object *sMainMenuButtons[NUM_BUTTONS]; +struct Object *sMainMenuButtons[NUM_BUTTONS]; // Used to defined yes/no fade colors after a file is selected in the erase menu. // sYesNoColor[0]: YES | sYesNoColor[1]: NO -static u8 sYesNoColor[2]; +u8 sYesNoColor[2]; // The button that is selected when it is clicked. -static s8 sSelectedButtonID = MENU_BUTTON_NONE; +s8 sSelectedButtonID = MENU_BUTTON_NONE; // Whether we are on the main menu or one of the submenus. -static s8 sCurrentMenuLevel = MENU_LAYER_MAIN; +s8 sCurrentMenuLevel = MENU_LAYER_MAIN; // Used for text opacifying. If it is below 250, it is constantly incremented. -static u8 sTextBaseAlpha = 0; +u8 sTextBaseAlpha = 0; // 2D position of the cursor on the screen. // sCursorPos[0]: X | sCursorPos[1]: Y -static f32 sCursorPos[] = {0, 0}; +f32 sCursorPos[] = {0, 0}; // Determines which graphic to use for the cursor. -static s16 sCursorClickingTimer = 0; +s16 sCursorClickingTimer = 0; // Equal to sCursorPos if the cursor gets clicked, {-10000, -10000} otherwise. -static s16 sClickPos[] = {-10000, -10000}; +s16 sClickPos[] = {-10000, -10000}; // Used for determining which file has been selected during copying and erasing. -static s8 sSelectedFileIndex = -1; +s8 sSelectedFileIndex = -1; // Whether to fade out text or not. -static s8 sFadeOutText = FALSE; +s8 sFadeOutText = FALSE; // The message currently being displayed at the top of a menu. -static s8 sStatusMessageID = 0; +s8 sStatusMessageID = 0; // Used for text fading. The alpha value of text is calculated as // sTextBaseAlpha - sTextFadeAlpha. -static u8 sTextFadeAlpha = 0; +u8 sTextFadeAlpha = 0; // File select timer that keeps counting until it reaches 1000. // Used to prevent buttons from being clickable as soon as a menu loads. // Gets reset when you click an empty save, existing saves in copy and erase menus // and when you click yes/no in the erase confirmation prompt. -static s16 sMainMenuTimer = 0; +s16 sMainMenuTimer = 0; // Sound mode menu buttonID, has different values compared to gSoundMode in audio. // 0: gSoundMode = 0 (Stereo) | 1: gSoundMode = 3 (Mono) | 2: gSoundMode = 1 (Headset) -static s8 sSoundMode = 0; +s8 sSoundMode = 0; // Active language for EU arrays, values defined similar to sSoundMode // 0: English | 1: French | 2: German // Tracks which button will be pressed in the erase confirmation prompt (yes/no). -static s8 sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE; +s8 sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE; // Used for the copy menu, defines if the game as all 4 save slots with data. // if TRUE, it doesn't allow copying more files. -static s8 sAllFilesExist = FALSE; +s8 sAllFilesExist = FALSE; // Defines the value of the save slot selected in the menu. // Mario A: 1 | Mario B: 2 | Mario C: 3 | Mario D: 4 -static s8 sSelectedFileNum = 0; +s8 sSelectedFileNum = 0; // Which coin score mode to use when scoring files. 0 for local // coin high score, 1 for high score across all files. -static s8 sScoreFileCoinScoreMode = 0; +s8 sScoreFileCoinScoreMode = 0; // In EU, if no save file exists, open the language menu so the user can find it. -static unsigned char textReturn[] = { TEXT_RETURN }; +unsigned char textReturn[][8] = { {TEXT_RETURN}, }; -static unsigned char textViewScore[] = { TEXT_CHECK_SCORE }; +unsigned char textViewScore[] = { TEXT_CHECK_SCORE }; -static unsigned char textCopyFileButton[] = { TEXT_COPY_FILE_BUTTON }; +unsigned char textCopyFileButton[] = { TEXT_COPY_FILE_BUTTON }; -static unsigned char textEraseFileButton[] = { TEXT_ERASE_FILE_BUTTON }; +unsigned char textEraseFileButton[] = { TEXT_ERASE_FILE_BUTTON }; -static unsigned char textSoundModes[][8] = { { TEXT_STEREO }, { TEXT_MONO }, { TEXT_HEADSET } }; +unsigned char textSoundModes[][8] = { { TEXT_STEREO }, { TEXT_MONO }, { TEXT_HEADSET } }; -static unsigned char textMarioA[] = { TEXT_FILE_MARIO_A }; -static unsigned char textMarioB[] = { TEXT_FILE_MARIO_B }; -static unsigned char textMarioC[] = { TEXT_FILE_MARIO_C }; -static unsigned char textMarioD[] = { TEXT_FILE_MARIO_D }; +#if MULTILANG +unsigned char textLanguageSelect[][17] = { { TEXT_LANGUAGE_SELECT }}; +#endif -static unsigned char textNew[] = { TEXT_NEW }; -static unsigned char starIcon[] = { GLYPH_STAR, GLYPH_SPACE }; -static unsigned char xIcon[] = { GLYPH_MULTIPLY, GLYPH_SPACE }; +unsigned char textSoundSelect[][13] = { { TEXT_SOUND_SELECT },}; -static unsigned char textSelectFile[] = { TEXT_SELECT_FILE }; +unsigned char textMarioA[] = { TEXT_FILE_MARIO_A }; +unsigned char textMarioB[] = { TEXT_FILE_MARIO_B }; +unsigned char textMarioC[] = { TEXT_FILE_MARIO_C }; +unsigned char textMarioD[] = { TEXT_FILE_MARIO_D }; -static unsigned char textScore[] = { TEXT_SCORE }; +unsigned char textNew[] = { TEXT_NEW }; +unsigned char starIcon[] = { GLYPH_STAR, GLYPH_SPACE }; +unsigned char xIcon[] = { GLYPH_MULTIPLY, GLYPH_SPACE }; -static unsigned char textCopy[] = { TEXT_COPY }; +unsigned char textSelectFile[] = { TEXT_SELECT_FILE }; -static unsigned char textErase[] = { TEXT_ERASE }; +unsigned char textScore[] = { TEXT_SCORE }; +unsigned char textCopy[] = { TEXT_COPY }; -static unsigned char textCheckFile[] = { TEXT_CHECK_FILE }; +unsigned char textErase[] = { TEXT_ERASE }; -static unsigned char textNoSavedDataExists[] = { TEXT_NO_SAVED_DATA_EXISTS }; +unsigned char textLanguage[][9] = {{ TEXT_ENGLISH }, { TEXT_FRENCH }, { TEXT_GERMAN }}; -static unsigned char textCopyFile[] = { TEXT_COPY_FILE }; +unsigned char textCheckFile[] = { TEXT_CHECK_FILE }; -static unsigned char textCopyItToWhere[] = { TEXT_COPY_IT_TO_WHERE }; +unsigned char textNoSavedDataExists[] = { TEXT_NO_SAVED_DATA_EXISTS }; -static unsigned char textNoSavedDataExistsCopy[] = { TEXT_NO_SAVED_DATA_EXISTS }; +unsigned char textCopyFile[] = { TEXT_COPY_FILE }; -static unsigned char textCopyCompleted[] = { TEXT_COPYING_COMPLETED }; +unsigned char textCopyItToWhere[] = { TEXT_COPY_IT_TO_WHERE }; -static unsigned char textSavedDataExists[] = { TEXT_SAVED_DATA_EXISTS }; +unsigned char textNoSavedDataExistsCopy[] = { TEXT_NO_SAVED_DATA_EXISTS }; -static unsigned char textNoFileToCopyFrom[] = { TEXT_NO_FILE_TO_COPY_FROM }; +unsigned char textCopyCompleted[] = { TEXT_COPYING_COMPLETED }; -static unsigned char textYes[] = { TEXT_YES }; +unsigned char textSavedDataExists[] = { TEXT_SAVED_DATA_EXISTS }; -static unsigned char textNo[] = { TEXT_NO }; +unsigned char textNoFileToCopyFrom[] = { TEXT_NO_FILE_TO_COPY_FROM }; + +unsigned char textYes[] = { TEXT_YES }; + +unsigned char textNo[] = { TEXT_NO }; /** @@ -198,7 +212,7 @@ s32 check_clicked_button(s16 x, s16 y, f32 depth) { /** * Grow from main menu, used by selecting files and menus. */ -static void bhv_menu_button_growing_from_main_menu(struct Object *button) { +void bhv_menu_button_growing_from_main_menu(struct Object *button) { if (button->oMenuButtonTimer < 16) { button->oFaceAngleYaw += 0x800; } @@ -225,7 +239,7 @@ static void bhv_menu_button_growing_from_main_menu(struct Object *button) { /** * Shrink back to main menu, used to return back while inside menus. */ -static void bhv_menu_button_shrinking_to_main_menu(struct Object *button) { +void bhv_menu_button_shrinking_to_main_menu(struct Object *button) { if (button->oMenuButtonTimer < 16) { button->oFaceAngleYaw -= 0x800; } @@ -252,7 +266,7 @@ static void bhv_menu_button_shrinking_to_main_menu(struct Object *button) { /** * Grow from submenu, used by selecting a file in the score menu. */ -static void bhv_menu_button_growing_from_submenu(struct Object *button) { +void bhv_menu_button_growing_from_submenu(struct Object *button) { if (button->oMenuButtonTimer < 16) { button->oFaceAngleYaw += 0x800; } @@ -277,7 +291,7 @@ static void bhv_menu_button_growing_from_submenu(struct Object *button) { /** * Shrink back to submenu, used to return back while inside a score save menu. */ -static void bhv_menu_button_shrinking_to_submenu(struct Object *button) { +void bhv_menu_button_shrinking_to_submenu(struct Object *button) { if (button->oMenuButtonTimer < 16) { button->oFaceAngleYaw -= 0x800; } @@ -305,7 +319,7 @@ static void bhv_menu_button_shrinking_to_submenu(struct Object *button) { * A small increase and decrease in size. * Used by failed copy/erase/score operations and sound mode select. */ -static void bhv_menu_button_zoom_in_out(struct Object *button) { +void bhv_menu_button_zoom_in_out(struct Object *button) { if (sCurrentMenuLevel == MENU_LAYER_MAIN) { if (button->oMenuButtonTimer < 4) { button->oParentRelativePosZ -= 20.0f; @@ -332,7 +346,7 @@ static void bhv_menu_button_zoom_in_out(struct Object *button) { * A small temporary increase in size. * Used while selecting a target copy/erase file or yes/no erase confirmation prompt. */ -static void bhv_menu_button_zoom_in(struct Object *button) { +void bhv_menu_button_zoom_in(struct Object *button) { button->oMenuButtonScale += 0.0022; button->oMenuButtonTimer++; if (button->oMenuButtonTimer == 10) { @@ -346,7 +360,7 @@ static void bhv_menu_button_zoom_in(struct Object *button) { * Used after selecting a target copy/erase file or * yes/no erase confirmation prompt to undo the zoom in. */ -static void bhv_menu_button_zoom_out(struct Object *button) { +void bhv_menu_button_zoom_out(struct Object *button) { button->oMenuButtonScale -= 0.0022; button->oMenuButtonTimer++; if (button->oMenuButtonTimer == 10) { @@ -888,7 +902,11 @@ void check_erase_menu_clicked_buttons(struct Object *eraseButton) { #undef ACTION_TIMER #undef MAIN_RETURN_TIMER +#if MULTILANG + #define SOUND_BUTTON_Y 388 +#else #define SOUND_BUTTON_Y 0 +#endif /** * Render buttons for the sound mode menu. @@ -907,8 +925,28 @@ void render_sound_mode_menu_buttons(struct Object *soundModeButton) { soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, -533, SOUND_BUTTON_Y, -100, 0, -0x8000, 0); sMainMenuButtons[MENU_BUTTON_HEADSET]->oMenuButtonScale = 0.11111111f; + #if MULTILANG + // English option button + sMainMenuButtons[MENU_BUTTON_LANGUAGE_ENGLISH] = spawn_object_rel_with_rot( + soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, 533, -111, -100, 0, -0x8000, 0); + sMainMenuButtons[MENU_BUTTON_LANGUAGE_ENGLISH]->oMenuButtonScale = 0.11111111f; + // French option button + sMainMenuButtons[MENU_BUTTON_LANGUAGE_FRENCH] = spawn_object_rel_with_rot( + soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, 0, -111, -100, 0, -0x8000, 0); + sMainMenuButtons[MENU_BUTTON_LANGUAGE_FRENCH]->oMenuButtonScale = 0.11111111f; + // German option button + sMainMenuButtons[MENU_BUTTON_LANGUAGE_GERMAN] = spawn_object_rel_with_rot( + soundModeButton, MODEL_MAIN_MENU_GENERIC_BUTTON, bhvMenuButton, -533, -111, -100, 0, -0x8000, 0); + sMainMenuButtons[MENU_BUTTON_LANGUAGE_GERMAN]->oMenuButtonScale = 0.11111111f; + + // Return button + sMainMenuButtons[MENU_BUTTON_LANGUAGE_RETURN] = spawn_object_rel_with_rot( + soundModeButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 0, -533, -100, 0, -0x8000, 0); + sMainMenuButtons[MENU_BUTTON_LANGUAGE_RETURN]->oMenuButtonScale = 0.11111111f; +#else // Zoom in current selection sMainMenuButtons[MENU_BUTTON_OPTION_MIN + sSoundMode]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN; +#endif } #undef SOUND_BUTTON_Y @@ -934,13 +972,33 @@ void check_sound_mode_menu_clicked_buttons(struct Object *soundModeButton) { queue_rumble_data(5, 80); #endif sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT; +#if !MULTILANG // Sound menu buttons don't return to Main Menu in EU // because they don't have a case in bhv_menu_button_manager_loop sSelectedButtonID = buttonID; +#endif sSoundMode = buttonID - MENU_BUTTON_OPTION_MIN; save_file_set_sound_mode(sSoundMode); } } +#if MULTILANG + // If language mode button clicked, select it and change language + if (buttonID == MENU_BUTTON_LANGUAGE_ENGLISH || buttonID == MENU_BUTTON_LANGUAGE_FRENCH + || buttonID == MENU_BUTTON_LANGUAGE_GERMAN) { + if (soundModeButton->oMenuButtonActionPhase == SOUND_MODE_PHASE_MAIN) { + play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource); + sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT; + sLanguageMode = buttonID - MENU_BUTTON_LANGUAGE_MIN; + eu_set_language(sLanguageMode); + } + } + // If neither of the buttons above are pressed, return to main menu + if (buttonID == MENU_BUTTON_LANGUAGE_RETURN) { + play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource); + sMainMenuButtons[buttonID]->oMenuButtonState = MENU_BUTTON_STATE_ZOOM_IN_OUT; + sSelectedButtonID = buttonID; + } +#endif sCurrentMenuLevel = MENU_LAYER_SUBMENU; break; @@ -1386,6 +1444,11 @@ void bhv_menu_button_manager_loop(void) { check_sound_mode_menu_clicked_buttons(sMainMenuButtons[MENU_BUTTON_SOUND_MODE]); break; + #if MULTILANG + case MENU_BUTTON_LANGUAGE_RETURN: + return_to_main_menu(MENU_BUTTON_SOUND_MODE, sMainMenuButtons[MENU_BUTTON_LANGUAGE_RETURN]); + break; + #endif // STEREO, MONO and HEADSET buttons are undefined so they can be selected without // exiting the Options menu, as a result they added a return button case MENU_BUTTON_STEREO: @@ -1999,7 +2062,13 @@ void print_erase_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_end); } - #define SOUND_HUD_X 88 +#if MULTILANG + #define SOUND_HUD_X 96 + #define SOUND_HUD_Y 141 +#else + #define SOUND_HUD_X 47 + #define SOUND_HUD_Y 87 +#endif /** * Prints sound mode menu strings that shows on the purple background menu screen. @@ -2008,33 +2077,49 @@ void print_erase_menu_strings(void) { */ void print_sound_mode_menu_strings(void) { s32 mode; - - s16 textX; - - unsigned char textSoundSelect[] = { TEXT_SOUND_SELECT }; + s32 textX; // Print "SOUND SELECT" text gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); - print_hud_lut_string(HUD_LUT_DIFF, SOUND_HUD_X, 35, textSoundSelect); + print_hud_lut_string(HUD_LUT_DIFF, SOUND_HUD_X, 32, LANGUAGE_ARRAY(textSoundSelect)); + #if MULTILANG + print_hud_lut_string(HUD_LUT_DIFF, 47, 101, LANGUAGE_ARRAY(textLanguageSelect)); + #endif gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); // Print sound mode names - for (mode = 0; mode < 3; mode++) { + for (mode = 0, textX = 90; mode < 3; textX += 70, mode++) { if (mode == sSoundMode) { gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); } else { gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, sTextBaseAlpha); } - // Mode names are centered correctly on US and Shindou - textX = get_str_x_pos_from_center(mode * 74 + 87, textSoundModes[mode], 10.0f); - print_generic_string(textX, 87, textSoundModes[mode]); + print_generic_string( + get_str_x_pos_from_center(textX, LANGUAGE_ARRAY(textSoundModes[mode]), 10.0f), + SOUND_HUD_Y, LANGUAGE_ARRAY(textSoundModes[mode])); } + #if MULTILANG + // In EU, print language mode names + for (mode = 0, textX = 90; mode < 3; textX += 70, mode++) { + if (mode == LANGUAGE_FUNCTION) { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); + } else { + gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, sTextBaseAlpha); + } + print_generic_string( + get_str_x_pos_from_center(textX, textLanguage[mode], 10.0f), + 72, textLanguage[mode]); + } + + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); + print_generic_string(182, 29, LANGUAGE_ARRAY(textReturn)); + #endif gSPDisplayList(gDisplayListHead++, dl_ia_text_end); } @@ -2136,7 +2221,7 @@ void print_save_file_scores(s8 fileIndex) { unsigned char textHiScore[] = { TEXT_HI_SCORE }; unsigned char textMyScore[] = { TEXT_MY_SCORE }; unsigned char textFileLetter[] = { TEXT_ZERO }; - void **levelNameTable = segmented_to_virtual(seg2_course_name_table); + void **levelNameTable = segmented_to_virtual(languageTable[gInGameLanguage][1]); textFileLetter[0] = fileIndex + ASCII_TO_DIALOG('A'); // get letter of file selected @@ -2198,7 +2283,7 @@ void print_save_file_scores(s8 fileIndex) { * Prints file select strings depending on the menu selected. * Also checks if all saves exists and defines text and main menu timers. */ -static void print_file_select_strings(void) { +void print_file_select_strings(void) { UNUSED s32 unused1; UNUSED s32 unused2; @@ -2266,9 +2351,6 @@ Gfx *geo_file_select_strings_and_menu_cursor(s32 callContext, UNUSED struct Grap * either completing a course choosing "SAVE & QUIT" or having a game over. */ s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused) { -#ifdef WIDE - gWidescreen = 0; -#endif sSelectedButtonID = MENU_BUTTON_NONE; sCurrentMenuLevel = MENU_LAYER_MAIN; sTextBaseAlpha = 0; diff --git a/src/menu/file_select.h b/src/menu/file_select.h index d4d75b65..47f72844 100644 --- a/src/menu/file_select.h +++ b/src/menu/file_select.h @@ -78,7 +78,7 @@ enum MenuButtonTypes { MENU_BUTTON_MONO, MENU_BUTTON_HEADSET, -#ifdef VERSION_EU +#if MULTILANG // Language Menu MENU_BUTTON_LANGUAGE_MIN, MENU_BUTTON_LANGUAGE_ENGLISH = MENU_BUTTON_LANGUAGE_MIN, diff --git a/src/menu/intro_geo.c b/src/menu/intro_geo.c index e2e5bb92..48d53f8b 100644 --- a/src/menu/intro_geo.c +++ b/src/menu/intro_geo.c @@ -348,7 +348,7 @@ u16 *intro_sample_frame_buffer(s32 imageW, s32 imageH, s32 sampleW, s32 sampleH) s32 xOffset = 120; s32 yOffset = 80; - fb = sFrameBuffers[frameBufferIndex]; + fb = sFrameBuffers[sRenderingFrameBuffer]; image = alloc_display_list(imageW * imageH * sizeof(u16)); if (image == NULL) { @@ -439,6 +439,10 @@ Gfx *geo_intro_rumble_pak_graphic(s32 state, struct GraphNode *node, UNUSED void Gfx *dl; s32 introContext; s8 backgroundTileSix; +#ifdef AVOID_UB + dl = NULL; + backgroundTileSix = 0; +#endif if (state != 1) { dl = NULL; diff --git a/src/menu/level_select_menu.h b/src/menu/level_select_menu.h deleted file mode 100644 index fcb2b9ac..00000000 --- a/src/menu/level_select_menu.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef LEVEL_SELECT_MENU_H -#define LEVEL_SELECT_MENU_H - -#include - -#include "macros.h" - -s32 lvl_intro_update(s16 arg1, UNUSED s32 arg2); - -#endif // LEVEL_SELECT_MENU_H diff --git a/src/menu/star_select.c b/src/menu/star_select.c index af55ae76..8bfacca7 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -53,8 +53,7 @@ static s8 sSelectableStarIndex = 0; // Act Selector menu timer that keeps counting until you choose an act. static s32 sActSelectorMenuTimer = 0; -#ifdef WIDE -#endif + /** * Act Selector Star Type Loop Action * Defines a select type for a star in the act selector. @@ -95,11 +94,10 @@ void render_100_coin_star(u8 stars) { if (stars & (1 << 6)) { // If the 100 coin star has been collected, create a new star selector next to the coin score. #ifdef WIDE - if (gWidescreen){ + if (gWidescreen) { sStarSelectorModels[6] = spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_STAR, bhvActSelectorStarType, ((370*4.0f)/3), 24, -300, 0, 0, 0); - } - else{ + } else { sStarSelectorModels[6] = spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_STAR, bhvActSelectorStarType, 370, 24, -300, 0, 0, 0); } @@ -169,8 +167,7 @@ void bhv_act_selector_init(void) { (((75 + sVisibleStars * -75 + i * 152)*4.0f)/3), 248, -300, 0, 0, 0); sStarSelectorModels[i]->oStarSelectorSize = 1.0f; } - } - else { + } else { for (i = 0; i < sVisibleStars; i++) { sStarSelectorModels[i] = spawn_object_abs_with_rot(gCurrentObject, 0, selectorModelIDs[i], bhvActSelectorStarType, diff --git a/src/menu/level_select_menu.c b/src/menu/title_screen.c similarity index 55% rename from src/menu/level_select_menu.c rename to src/menu/title_screen.c index 22891290..e93e0b10 100644 --- a/src/menu/level_select_menu.c +++ b/src/menu/title_screen.c @@ -14,71 +14,81 @@ #include "level_table.h" #include "seq_ids.h" #include "sm64.h" +#include "title_screen.h" -#define PRESS_START_DEMO_TIMER 800 +/** + * @file title_screen.c + * This file implements how title screen functions. + * That includes playing demo sequences, introduction screens + * and a level select used for testing purposes. + */ #define STUB_LEVEL(textname, _1, _2, _3, _4, _5, _6, _7, _8) textname, #define DEFINE_LEVEL(textname, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) textname, -static char gLevelSelect_StageNamesText[64][16] = { +static char sLevelSelectStageNames[64][16] = { #include "levels/level_defines.h" }; #undef STUB_LEVEL #undef DEFINE_LEVEL -static u16 gDemoCountdown = 0; +static u16 sDemoCountdown = 0; #ifndef VERSION_JP -static s16 D_U_801A7C34 = 1; -static s16 gameOverNotPlayed = 1; +static s16 sPlayMarioGreeting = TRUE; +static s16 sPlayMarioGameOver = TRUE; #endif -// run the demo timer on the PRESS START screen. -// this function will return a non-0 timer once -// the demo starts, signaling to the subsystem that -// the demo needs to be ran. +#define PRESS_START_DEMO_TIMER 800 -// don't shift this function from being the first function in the segment. -// the level scripts assume this function is the first, so it cant be moved. -s32 run_press_start_demo_timer(s32 timer) { +/** + * Run the demo timer on the PRESS START screen after a number of frames. + * This function returns the level ID from the first byte of a demo file. + * It also returns the level ID from intro_regular (file select or level select menu) + */ +s32 run_level_id_or_demo(s32 level) { gCurrDemoInput = NULL; - if (timer == 0) { + if (level == LEVEL_NONE) { if (!gPlayer1Controller->buttonDown && !gPlayer1Controller->stickMag) { - if ((++gDemoCountdown) == PRESS_START_DEMO_TIMER) { - // start the demo. 800 frames has passed while - // player is idle on PRESS START screen. + // start the demo. 800 frames has passed while + // player is idle on PRESS START screen. + if ((++sDemoCountdown) == PRESS_START_DEMO_TIMER) { // start the Mario demo animation for the demo list. - load_patchable_table(&gDemo, gDemoInputListID); + load_patchable_table(&gDemoInputsBuf, gDemoInputListID); // if the next demo sequence ID is the count limit, reset it back to // the first sequence. - if (++gDemoInputListID == gDemo.animDmaTable->count) { + if (++gDemoInputListID == gDemoInputsBuf.dmaTable->count) { gDemoInputListID = 0; } - // add 1 (+4) to the pointer to skip the demoID. - gCurrDemoInput = ((struct DemoInput *) gDemo.targetAnim) + 1; - timer = (s8)((struct DemoInput *) gDemo.targetAnim)->timer; + // add 1 (+4) to the pointer to skip the first 4 bytes + // Use the first 4 bytes to store level ID, + // then use the rest of the values for inputs + gCurrDemoInput = ((struct DemoInput *) gDemoInputsBuf.bufTarget) + 1; + level = (s8)((struct DemoInput *) gDemoInputsBuf.bufTarget)->timer; gCurrSaveFileNum = 1; gCurrActNum = 1; } } else { // activity was detected, so reset the demo countdown. - gDemoCountdown = 0; + sDemoCountdown = 0; } } - return timer; + return level; } -// input loop for the level select menu. updates the selected stage -// count if an input was received. signals the stage to be started -// or the level select to be exited if start or the quit combo is -// pressed. - -s16 level_select_input_loop(void) { +/** + * Level select intro function, updates the selected stage + * count if an input was received. signals the stage to be started + * or the level select to be exited if start or the quit combo is pressed. + */ +s16 intro_level_select(void) { s32 stageChanged = FALSE; // perform the ID updates per each button press. + // runs into a loop so after a button is pressed + // stageChanged goes back to FALSE if (gPlayer1Controller->buttonPressed & A_BUTTON) { ++gCurrLevelNum, stageChanged = TRUE; } @@ -103,7 +113,6 @@ s16 level_select_input_loop(void) { play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource); } - // TODO: enum counts for the stage lists if (gCurrLevelNum > LEVEL_MAX) { gCurrLevelNum = LEVEL_MIN; // exceeded max. set to min. } @@ -112,12 +121,14 @@ s16 level_select_input_loop(void) { gCurrLevelNum = LEVEL_MAX; // exceeded min. set to max. } - gCurrSaveFileNum = 4; // file 4 is used for level select tests + // Use file 4 and last act as a test + gCurrSaveFileNum = 4; gCurrActNum = 6; + print_text_centered(160, 80, "SELECT STAGE"); print_text_centered(160, 30, "PRESS START BUTTON"); print_text_fmt_int(40, 60, "%2d", gCurrLevelNum); - print_text(80, 60, gLevelSelect_StageNamesText[gCurrLevelNum - 1]); // print stage name + print_text(80, 60, sLevelSelectStageNames[gCurrLevelNum - 1]); // print stage name #define QUIT_LEVEL_SELECT_COMBO (Z_TRIG | START_BUTTON | L_CBUTTONS | R_CBUTTONS) @@ -135,17 +146,24 @@ s16 level_select_input_loop(void) { return 0; } -s32 intro_default(void) { - s32 sp1C = 0; +/** + * Regular intro function that handles Mario's greeting voice and game start. + */ +s32 intro_regular(void) { + s32 level = LEVEL_NONE; #ifndef VERSION_JP - if (D_U_801A7C34 == 1) { - if (gGlobalTimer < 0x81) { + // When the game stars, gGlobalTimer is less than 129 frames, + // so Mario greets the player. After that, he will always say + // "press start to play" when it goes back to the title screen + // (using SAVE AND QUIT) + if (sPlayMarioGreeting == TRUE) { + if (gGlobalTimer < 129) { play_sound(SOUND_MARIO_HELLO, gGlobalSoundSource); } else { play_sound(SOUND_MARIO_PRESS_START_TO_PLAY, gGlobalSoundSource); } - D_U_801A7C34 = 0; + sPlayMarioGreeting = FALSE; } #endif print_intro_text(); @@ -156,21 +174,27 @@ s32 intro_default(void) { queue_rumble_data(60, 70); func_sh_8024C89C(1); #endif - sp1C = 100 + gDebugLevelSelect; + // calls level ID 100 (or 101 adding level select bool value) + // defined in level_intro_mario_head_regular JUMP_IF commands + // 100 is File Select - 101 is Level Select + level = 100 + gDebugLevelSelect; #ifndef VERSION_JP - D_U_801A7C34 = 1; + sPlayMarioGreeting = TRUE; #endif } - return run_press_start_demo_timer(sp1C); + return run_level_id_or_demo(level); } +/** + * Game over intro function that handles Mario's game over voice and game start. + */ s32 intro_game_over(void) { - s32 sp1C = 0; + s32 level = LEVEL_NONE; #ifndef VERSION_JP - if (gameOverNotPlayed == 1) { + if (sPlayMarioGameOver == TRUE) { play_sound(SOUND_MARIO_GAME_OVER, gGlobalSoundSource); - gameOverNotPlayed = 0; + sPlayMarioGameOver = FALSE; } #endif @@ -182,35 +206,43 @@ s32 intro_game_over(void) { queue_rumble_data(60, 70); func_sh_8024C89C(1); #endif - sp1C = 100 + gDebugLevelSelect; + // same criteria as intro_regular + level = 100 + gDebugLevelSelect; #ifndef VERSION_JP - gameOverNotPlayed = 1; + sPlayMarioGameOver = TRUE; #endif } - return run_press_start_demo_timer(sp1C); + return run_level_id_or_demo(level); } +/** + * Plays the casual "It's a me mario" when the game stars. + */ s32 intro_play_its_a_me_mario(void) { set_background_music(0, SEQ_SOUND_PLAYER, 0); play_sound(SOUND_MENU_COIN_ITS_A_ME_MARIO, gGlobalSoundSource); return 1; } -s32 lvl_intro_update(s16 arg1, UNUSED s32 arg2) { - s32 retVar; +/** + * Update intro functions to handle title screen actions. + * Returns a level ID after their criteria is met. + */ +s32 lvl_intro_update(s16 arg, UNUSED s32 unusedArg) { + s32 retVar = 0; - switch (arg1) { - case 0: + switch (arg) { + case LVL_INTRO_PLAY_ITS_A_ME_MARIO: retVar = intro_play_its_a_me_mario(); break; - case 1: - retVar = intro_default(); + case LVL_INTRO_REGULAR: + retVar = intro_regular(); break; - case 2: + case LVL_INTRO_GAME_OVER: retVar = intro_game_over(); break; - case 3: - retVar = level_select_input_loop(); + case LVL_INTRO_LEVEL_SELECT: + retVar = intro_level_select(); break; } return retVar; diff --git a/src/menu/title_screen.h b/src/menu/title_screen.h new file mode 100644 index 00000000..4893158f --- /dev/null +++ b/src/menu/title_screen.h @@ -0,0 +1,17 @@ +#ifndef TITLE_SCREEN_H +#define TITLE_SCREEN_H + +#include + +#include "macros.h" + +enum LevelScriptIntroArgs { + LVL_INTRO_PLAY_ITS_A_ME_MARIO, + LVL_INTRO_REGULAR, + LVL_INTRO_GAME_OVER, + LVL_INTRO_LEVEL_SELECT +}; + +s32 lvl_intro_update(s16 arg, UNUSED s32 unusedArg); + +#endif // TITLE_SCREEN_H diff --git a/text/us/dialogs.h b/text/us/dialogs.h index 34a18b20..00b89f48 100644 --- a/text/us/dialogs.h +++ b/text/us/dialogs.h @@ -5,7 +5,7 @@ #define PLASTERED "splattered" #define SCAM_ME "cheat!\n" #define SCRAM "get lost" -#define YOU_CANT_SWIM_IN_IT "Its too heavy to swim\nwith." +#define YOU_CANT_SWIM_IN_IT "It is too heavy to\nswim with." #define GIVE_UP "give up" #else #define COMRADES "comrades" diff --git a/textures/segment2/custom_text.i4.png b/textures/segment2/custom_text.i4.png new file mode 100644 index 00000000..02dd2d17 Binary files /dev/null and b/textures/segment2/custom_text.i4.png differ diff --git a/tools/.gitignore b/tools/.gitignore index eff01d1f..f0d34f02 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -7,7 +7,7 @@ /n64cksum /n64graphics /n64graphics_ci -/patch_libultra_math +/patch_elf_32bit /rncpack /slienc /skyconv diff --git a/tools/Makefile b/tools/Makefile index ceb243b5..458a0d15 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -7,7 +7,7 @@ CC := gcc CXX := g++ CFLAGS := -I. -O2 -s LDFLAGS := -lm -ALL_PROGRAMS := armips filesizer rncpack n64graphics n64graphics_ci mio0 slienc n64cksum textconv patch_libultra_math aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv +ALL_PROGRAMS := armips filesizer rncpack n64graphics n64graphics_ci mio0 slienc n64cksum textconv patch_elf_32bit aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv LIBAUDIOFILE := audiofile/libaudiofile.a # Only build armips from tools if it is not found on the system @@ -39,7 +39,7 @@ n64cksum_CFLAGS := -DN64CKSUM_STANDALONE textconv_SOURCES := textconv.c utf8.c hashtable.c -patch_libultra_math_SOURCES := patch_libultra_math.c +patch_elf_32bit_SOURCES := patch_elf_32bit.c aifc_decode_SOURCES := aifc_decode.c diff --git a/tools/aiff_extract_codebook.c b/tools/aiff_extract_codebook.c index 78864e38..c229139a 100644 --- a/tools/aiff_extract_codebook.c +++ b/tools/aiff_extract_codebook.c @@ -2,7 +2,6 @@ * Create an ADPCM codebook either by extracting it from an AIFF section, or * by executing tabledesign. */ -#define _XOPEN_SOURCE 500 #include #include #include diff --git a/tools/assemble_sound.py b/tools/assemble_sound.py index 9c6598f1..f4a81d26 100755 --- a/tools/assemble_sound.py +++ b/tools/assemble_sound.py @@ -659,7 +659,7 @@ def serialize_ctl(bank, base_ser, is_shindou): base_ser.add(ser.finish()) return pack( - "BBBB", bank.sample_bank.index, 0xFF, len(json["instrument_list"]), len(drums) + "hh", (bank.sample_bank.index << 8) | 0xFF, (len(json["instrument_list"]) << 8) | len(drums) ) @@ -704,7 +704,8 @@ def serialize_seqfile( ser = ReserveSerializer() ser.add(pack("H", len(entries))) ser.align(16) - sh_magic = 0x0204 if magic == TYPE_TBL else 0x0203 + medium = 0x02 # cartridge + sh_magic = 0x04 if magic == TYPE_TBL else 0x03 # Ignore entry_list and loop over all entries instead. This makes a # difference for sample banks, where US/JP/EU doesn't use a normal @@ -712,9 +713,9 @@ def serialize_seqfile( # sample bank offset/length. Shindou uses a normal header and makes the # mapping part of the sound bank header instead (part of entry_meta). for i in range(len(entries)): - ser.add(pack("PIH", entry_offsets[i], entry_lens[i], sh_magic)) + ser.add(pack("PIbb", entry_offsets[i], entry_lens[i], medium, sh_magic)) ser.add(entry_meta[i] or b"\0\0\0\0") - ser.align(16) + ser.align(WORD_BYTES) if out_header_filename: with open(out_header_filename, "wb") as f: diff --git a/tools/demo_data_converter.py b/tools/demo_data_converter.py index ab656bd7..86ea94c5 100755 --- a/tools/demo_data_converter.py +++ b/tools/demo_data_converter.py @@ -62,7 +62,7 @@ def main(): structdef.append("u8 " + item["name"] + "[" + str(len(demobytes)) + "];") structobj.append("{" + ",".join(hex(x) for x in demobytes) + "},") - print("#include \"types.h\"") + print("#include \"game/memory.h\"") print("#include ") print("") diff --git a/tools/filesizer.c b/tools/filesizer.c index e10d0f9b..c44d8a02 100644 --- a/tools/filesizer.c +++ b/tools/filesizer.c @@ -66,7 +66,7 @@ int main(int argc, char *argv[argc + 1]) return EXIT_FAILURE; } - fread(data, insize, 1, fin); + size_t fread_result = fread(data, insize, 1, fin); size_stored = data + outsize - 4; *size_stored = __bswap_32(atoi(argv[3])); diff --git a/tools/getGoddardSize.py b/tools/getGoddardSize.py new file mode 100644 index 00000000..c127fd56 --- /dev/null +++ b/tools/getGoddardSize.py @@ -0,0 +1,12 @@ +import sys, os + +with open(sys.argv[1]) as f: + for line in f: + if "GODDARD_SIZE" in line: + tokens=line.split() + with open("build/%s/goddard.txt" % sys.argv[2], "w+") as f: + sz = int(tokens[0], 16) + sz += 16 + sz &= 0xFFFFFFF0 + f.write("GODDARD_SIZE = 0x%X;" % sz) + \ No newline at end of file diff --git a/tools/mario_anims_converter.py b/tools/mario_anims_converter.py index 361662ae..fcf92a54 100755 --- a/tools/mario_anims_converter.py +++ b/tools/mario_anims_converter.py @@ -136,7 +136,7 @@ try: structdef.append("{} {}[{}];".format(type, name, len(arr))) structobj.append("{" + ",".join(arr) + "},") - print("#include \"types.h\"") + print("#include \"game/memory.h\"") print("#include ") print("") diff --git a/tools/output_level_headers.py b/tools/output_level_headers.py deleted file mode 100644 index a1ea4aa0..00000000 --- a/tools/output_level_headers.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python3 -import sys -for line in sys.stdin: - if line.strip(): - print('#include "{}"'.format(line.strip())) diff --git a/tools/patch_libultra_math.c b/tools/patch_elf_32bit.c similarity index 68% rename from tools/patch_libultra_math.c rename to tools/patch_elf_32bit.c index e6bdcc0c..8e529520 100644 --- a/tools/patch_libultra_math.c +++ b/tools/patch_elf_32bit.c @@ -3,6 +3,9 @@ #include #include +#define ARMAG "!\n" +#define SARMAG 8 + /* from elf.h */ /* Type for a 16-bit quantity. */ @@ -78,13 +81,36 @@ struct ar_header { //These constants found by inspecting output of objdump #define FLAGS_MIPS3 0x20 #define FLAGS_O32ABI 0x100000 -int main(int argc, char **argv) { - FILE *f = fopen(argv[1], "r+"); - if (f == NULL) { - printf("Failed to open file! %s\n", argv[1]); +int fix_mips_elf(FILE *f, size_t filesize) +{ + Elf32_Ehdr hdr; + if (filesize < sizeof(hdr) || (1 != fread(&hdr, sizeof(hdr), 1, f))) { + printf("Failed to read ELF header\n"); return -1; } + + if (strncmp((const char *) hdr.e_ident, ELFMAG, SELFMAG) == 0) { + // found an ELF file. + if (hdr.e_ident[EI_CLASS] != ELFCLASS32 || hdr.e_ident[EI_DATA] != ELFDATA2MSB) { + printf("Expected 32bit big endian object files\n"); + return -1; + } + + if ((hdr.e_flags & 0xFF) == FLAGS_MIPS3 && (hdr.e_flags & FLAGS_O32ABI) == 0) { + hdr.e_flags |= FLAGS_O32ABI; + fseek(f, -(long)sizeof(hdr), SEEK_CUR); + if (1 != fwrite(&hdr, sizeof(hdr), 1, f)) { + printf("Failed to write back ELF header after patching.\n"); + return -1; + } + } + } + return 0; +} + +int fix_mips_ar(FILE *f) +{ struct ar_header current_header; fseek(f, 0x8, SEEK_SET); // skip header, this is safe enough given that we check to make sure the // file header is valid @@ -95,32 +121,41 @@ int main(int argc, char **argv) { return -1; } size_t filesize = atoi(current_header.file_size_in_bytes); - Elf32_Ehdr hdr; - if (filesize < sizeof(hdr) || (1 != fread(&hdr, sizeof(hdr), 1, f))) { - printf("Failed to read ELF header\n"); + if (fix_mips_elf(f, filesize)) { return -1; } - - if (strncmp((const char *) hdr.e_ident, ELFMAG, SELFMAG) == 0) { - // found an ELF file. - if (hdr.e_ident[EI_CLASS] != ELFCLASS32 || hdr.e_ident[EI_DATA] != ELFDATA2MSB) { - printf("Expected 32bit big endian object files\n"); - return -1; - } - - if ((hdr.e_flags & 0xFF) == FLAGS_MIPS3 && (hdr.e_flags & FLAGS_O32ABI) == 0) { - hdr.e_flags |= FLAGS_O32ABI; - fseek(f, -sizeof(hdr), SEEK_CUR); - if (1 != fwrite(&hdr, sizeof(hdr), 1, f)) { - printf("Failed to write back ELF header after patching.\n"); - return -1; - } - } - } if (filesize % 2 == 1) filesize++; - fseek(f, filesize - sizeof(hdr), SEEK_CUR); + fseek(f, filesize - sizeof(Elf32_Ehdr), SEEK_CUR); } - fclose(f); return 0; } + +int main(int argc, char **argv) { + FILE *f = fopen(argv[1], "r+b"); + uint8_t magic[8]; + int status = 0; + + if (f == NULL) { + printf("Failed to open file! %s\n", argv[1]); + return -1; + } + if (1 != fread(&magic, sizeof(magic), 1, f)) { + printf("Failed to read file magic\n"); + return -1; + } + rewind(f); + if (!memcmp(ARMAG, magic, SARMAG)) { + status = fix_mips_ar(f); + } else if (!memcmp(ELFMAG, magic, SELFMAG)) { + fseek(f, 0, SEEK_END); + size_t filesize = ftell(f); + rewind(f); + status = fix_mips_elf(f, filesize); + } else { + printf("Unknown file magic: %02x%02x%02X%02X\n", magic[0], magic[1], magic[2], magic[3]); + status = -1; + } + fclose(f); + return status; +} diff --git a/tools/patch_libultra_math b/tools/patch_libultra_math new file mode 100755 index 00000000..5adb761d Binary files /dev/null and b/tools/patch_libultra_math differ diff --git a/tools/rncpack.c b/tools/rncpack.c index 1aa94974..31cd6c64 100644 --- a/tools/rncpack.c +++ b/tools/rncpack.c @@ -1641,10 +1641,10 @@ int parse_args(int argc, char **argv, vars_t *vars) int main(int argc, char *argv[]) { - printf("-= RNC ProPackED v1.5 [by Lab 313] (12/02/2020) =-\n"); - printf("-----------------------------\n"); if (argc <= 2) { + printf("-= RNC ProPackED v1.5 [by Lab 313] (12/02/2020) =-\n"); + printf("-----------------------------\n"); printf("Compression type: Huffman + LZ77\n"); printf("De/Compressor: Dr.MefistO\n"); printf("Coding: Dr. MefistO\n"); @@ -1684,7 +1684,7 @@ int main(int argc, char *argv[]) v->file_size = ftell(in) - v->read_start_offset; fseek(in, v->read_start_offset, SEEK_SET); v->input = (uint8*)malloc(v->file_size); - fread(v->input, v->file_size, 1, in); + size_t fread_result = fread(v->input, v->file_size, 1, in); fclose(in); v->output = (uint8*)malloc(MAX_BUF_SIZE); @@ -1725,8 +1725,8 @@ int main(int argc, char *argv[]) fwrite(v->output, v->output_offset, 1, out); fclose(out); - printf("File successfully %s!\n", ((v->puse_mode == 'p') ? "packed" : "unpacked")); - printf("Original/new size: %d/%zd bytes\n", (v->puse_mode == 'u') ? (v->packed_size + RNC_HEADER_SIZE) : v->file_size, v->output_offset); +// printf("File successfully %s!\n", ((v->puse_mode == 'p') ? "packed" : "unpacked")); +// printf("Original/new size: %d/%zd bytes\n", (v->puse_mode == 'u') ? (v->packed_size + RNC_HEADER_SIZE) : v->file_size, v->output_offset); } else { switch (error_code) { diff --git a/tools/seq_decoder.py b/tools/seq_decoder.py index ce238209..9329e702 100755 --- a/tools/seq_decoder.py +++ b/tools/seq_decoder.py @@ -162,8 +162,8 @@ if len(sys.argv) != 2: sys.exit(0) if sys.argv[1] == "--emit-asm-macros": - print("# Macros for disassembled sequence files. This file was automatically generated by seq_decoder.py.") - print("# To regenerate it, run: ./tools/seq_decoder.py --emit-asm-macros >seq_macros.inc") + print("// Macros for disassembled sequence files. This file was automatically generated by seq_decoder.py.") + print("// To regenerate it, run: ./tools/seq_decoder.py --emit-asm-macros > include/seq_macros.inc") print() def print_hword(x): print(f" .byte {x} >> 8, {x} & 0xff") @@ -219,7 +219,7 @@ if sys.argv[1] == "--emit-asm-macros": print(".endm\n") for key in ['seq', 'chan', 'layer']: - print(f"# {key} commands\n") + print(f"// {key} commands\n") if key == 'layer': cmds = commands['layer_large'] for op in sorted(commands['layer_small'].keys()): @@ -267,31 +267,31 @@ if sys.argv[1] == "--emit-asm-macros": emit_cmd(key, 0xc0, ['delay_long', 'var_long']) emit_cmd(key, 0x40, ['note1_long', 'bits:4', 'var_long', 'u8']) if eu_sh or us_jp or sh or non_sh: - print(".ifdef VERSION_SH\n") + print("#ifdef VERSION_SH\n") for (op, cmd) in eu_sh: emit_cmd(key, op, cmd) for (op, cmd) in sh: emit_cmd(key, op, cmd) - print(".else\n") + print("#else\n") for (op, cmd) in non_sh: emit_cmd(key, op, cmd) - print(".ifdef VERSION_EU\n") + print("#ifdef VERSION_EU\n") for (op, cmd) in eu_sh: emit_cmd(key, op, cmd) - print(".else\n") + print("#else\n") for (op, cmd) in us_jp: emit_cmd(key, op, cmd) - print(".endif\n") - print(".endif\n") + print("#endif\n") + print("#endif\n") - print("# envelope commands\n") + print("// envelope commands\n") emit_env_cmd(0, ['disable', 'u16']) emit_env_cmd(2**16-1, ['hang', 'u16:ign']) emit_env_cmd(2**16-2, ['goto', 'u16']) emit_env_cmd(2**16-3, ['restart', 'u16:ign']) emit_env_cmd(None, ['line', 'u16', 'u16']) - print("# other commands\n") + print("// other commands\n") print(".macro var_long x") print(" .byte (0x80 | (\\x & 0x7f00) >> 8), (\\x & 0xff)") print(".endm\n") diff --git a/tools/skyconv.c b/tools/skyconv.c index f4634ead..5db4419e 100644 --- a/tools/skyconv.c +++ b/tools/skyconv.c @@ -118,15 +118,18 @@ static void split_tile(int col, int row, rgba *image, bool expanded) { for (int x = 0; x < tileWidth; x++) { int ny = row * tileHeight + y; int nx = col * tileWidth + x; - if (nx < imageWidth && ny < imageHeight) - { + if(type == CakeEU) { tiles[row * numCols + col].px[y * expandedWidth + x] = image[(ny * imageWidth + nx)]; + } else { + if (nx < imageWidth && ny < imageHeight) + { + tiles[row * numCols + col].px[y * expandedWidth + x] = image[(ny * imageWidth + nx)]; + } + else + { + tiles[row * numCols + col].px[y * expandedWidth + x] = black; + } } - else - { - tiles[row * numCols + col].px[y * expandedWidth + x] = black; - } - } } } @@ -345,19 +348,24 @@ static void write_cake_c() { FILE *cFile = fopen(buffer, "w"); - const char *euSuffx = ""; + int numTiles = TABLE_DIMENSIONS[type].cols * TABLE_DIMENSIONS[type].rows; + if (type == CakeEU) { - euSuffx = "eu_"; + for (int i = 0; i < numTiles; ++i) { + fprintf(cFile, "ALIGNED8 static const Texture cake_end_texture_eu_%d[] = {\n", i); + print_raw_data(cFile, &tiles[i]); + fputs("};\n\n", cFile); + } + } else { + fprintf(cFile, "ALIGNED8 static const u8 cake_end_texture_data[] = {\n"); + for (int i = 0; i < numTiles; ++i) { + print_raw_data(cFile, &tiles[i]); + fputc(',', cFile); + fputc('\n', cFile); + } + fputs("};\n\n", cFile); } - int numTiles = TABLE_DIMENSIONS[type].cols * TABLE_DIMENSIONS[type].rows; - fprintf(cFile, "ALIGNED8 static const Texture cake_end_texture_%sdata[] = {\n", euSuffx); - for (int i = 0; i < numTiles; ++i) { - print_raw_data(cFile, &tiles[i]); - fputc(',', cFile); - fputc('\n', cFile); - } - fputs("};\n\n", cFile); fclose(cFile); } @@ -669,4 +677,4 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; -} +} \ No newline at end of file diff --git a/tools/slienc.c b/tools/slienc.c index e10fefba..ec44e519 100644 --- a/tools/slienc.c +++ b/tools/slienc.c @@ -53,7 +53,7 @@ int main(int argc, const char **argv, const char **envp) fseek(fp, 0, SEEK_SET); bz = malloc(insize); - fread(bz, 1, insize, fp); + size_t fread_result = fread(bz, 1, insize, fp); fclose(fp); for (int i = 0; src[i]; i++) @@ -199,7 +199,7 @@ void encode() } if ( v1 != 0x80000000 ) ++cp; - fprintf(stderr, "IN=%d OUT=%d\n", insize, dp + 2 * pp + 4 * cp + 16); + //fprintf(stderr, "IN=%d OUT=%d\n", insize, dp + 2 * pp + 4 * cp + 16); } void search(unsigned int a1, int a2, int *a3, unsigned int *a4) diff --git a/uncomprules.mk b/uncomprules.mk index 6c13f5fa..c9622675 100644 --- a/uncomprules.mk +++ b/uncomprules.mk @@ -1,4 +1,4 @@ # convert binary to object file $(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.bin $(call print,Converting BIN to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file + $(V)$(LD) -r -b binary $< -o $@ \ No newline at end of file diff --git a/yay0rules.mk b/yay0rules.mk index c75b4db3..aa4c9826 100644 --- a/yay0rules.mk +++ b/yay0rules.mk @@ -6,4 +6,4 @@ $(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin # convert binary szp to object file $(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp $(call print,Converting YAY0 to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file + $(V)$(LD) -r -b binary $< -o $@ \ No newline at end of file