From 816ed0d963b757cfa2874f2587d12e006ddab132 Mon Sep 17 00:00:00 2001 From: khbsd Date: Sun, 16 Mar 2025 00:02:48 -0500 Subject: [PATCH] Low Health Beeps Configuration (#6328) --- audio_rules.mk | 7 ++- include/config/battle.h | 5 ++ tools/mid2agb/Makefile | 5 +- tools/mid2agb/agb.cpp | 111 ++++++++++++++++++++++++++++++++++++++++ tools/mid2agb/agb.h | 1 + tools/mid2agb/midi.cpp | 11 +++- 6 files changed, 136 insertions(+), 4 deletions(-) diff --git a/audio_rules.mk b/audio_rules.mk index 63a2e21add..3fce08ed3a 100644 --- a/audio_rules.mk +++ b/audio_rules.mk @@ -6,12 +6,15 @@ MID_ASM_DIR := $(MID_SUBDIR) CRY_BIN_DIR := $(CRY_SUBDIR) SOUND_BIN_DIR := sound +# Needs to recompile for B_NUM_LOW_HEALTH_BEEPS in battle.h +EXPANSION_BATTLE_CONFIG := include/config/battle.h + SPECIAL_OUTDIRS := $(MID_ASM_DIR) $(CRY_BIN_DIR) SPECIAL_OUTDIRS += $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/direct_sound_samples/phonemes $(SOUND_BIN_DIR)/direct_sound_samples/cries $(shell mkdir -p $(SPECIAL_OUTDIRS) ) # Assembly song compilation -$(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s +$(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s $(EXPANSION_BATTLE_CONFIG) $(AS) $(ASFLAGS) -I sound -o $@ $< $(MID_BUILDDIR)/%.o: $(MID_ASM_DIR)/%.s $(AS) $(ASFLAGS) -I sound -o $@ $< @@ -34,7 +37,7 @@ MID_CFG_PATH := $(MID_SUBDIR)/midi.cfg # $1: Source path no extension, $2 Options define MID_RULE -$(MID_ASM_DIR)/$1.s: $(MID_SUBDIR)/$1.mid $(MID_CFG_PATH) +$(MID_ASM_DIR)/$1.s: $(MID_SUBDIR)/$1.mid $(MID_CFG_PATH) $(EXPANSION_BATTLE_CONFIG) $(MID) $$< $$@ $2 endef # source path, remaining text (options) diff --git a/include/config/battle.h b/include/config/battle.h index 17c5daac45..33451ca4db 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -283,6 +283,11 @@ #define B_TRY_CATCH_TRAINER_BALL GEN_LATEST // In Gen4+, trying to catch a Trainer's Pokémon does not consume the Poké Ball. #define B_SLEEP_CLAUSE FALSE // Enables Sleep Clause all the time in every case, overriding B_FLAG_SLEEP_CLAUSE. Use that for modularity. +#define NUM_BEEPS_GEN_LATEST 4 // Loops 4 times +#define NUM_BEEPS_GEN_3 -1 // Loops infinitely +#define NUM_BEEPS_OFF 0 // Doesn't play at all +#define B_NUM_LOW_HEALTH_BEEPS NUM_BEEPS_GEN_LATEST // This controls the number of times the "low health" beep will loop. Setting this value to NUM_BEEPS_OFF will disable the beep, while NUM_BEEPS_GEN_3 will loop infinitely. You can set this to any number you want, the defines listed are just for ease of use. + // Animation Settings #define B_NEW_SWORD_PARTICLE FALSE // If set to TRUE, it updates Swords Dance's particle. #define B_NEW_LEECH_SEED_PARTICLE FALSE // If set to TRUE, it updates Leech Seed's animation particle. diff --git a/tools/mid2agb/Makefile b/tools/mid2agb/Makefile index 553b7859ed..7c1612dbb6 100644 --- a/tools/mid2agb/Makefile +++ b/tools/mid2agb/Makefile @@ -6,6 +6,9 @@ SRCS := agb.cpp error.cpp main.cpp midi.cpp tables.cpp HEADERS := agb.h error.h main.h midi.h tables.h +# Needs to recompile for B_NUM_LOW_HEALTH_BEEPS in battle.h +EXPANSION_BATTLE_CONFIG := ../../include/config/battle.h + ifeq ($(OS),Windows_NT) EXE := .exe else @@ -17,7 +20,7 @@ endif all: mid2agb$(EXE) @: -mid2agb$(EXE): $(SRCS) $(HEADERS) +mid2agb$(EXE): $(SRCS) $(HEADERS) $(EXPANSION_BATTLE_CONFIG) $(CXX) $(CXXFLAGS) $(SRCS) -o $@ $(LDFLAGS) clean: diff --git a/tools/mid2agb/agb.cpp b/tools/mid2agb/agb.cpp index caa6f0ecd9..3bc4f601ac 100644 --- a/tools/mid2agb/agb.cpp +++ b/tools/mid2agb/agb.cpp @@ -525,6 +525,117 @@ void PrintAgbTrack(std::vector& events) PrintByte("FINE"); } +void PrintAgbTrackLoop(std::vector& events, int trackLoops) +{ + std::fprintf(g_outputFile, "\n@**************** Track %u (Midi-Chn.%u) ****************@\n\n", g_agbTrack, g_midiChan + 1); + std::fprintf(g_outputFile, "%s_%u:\n", g_asmLabel.c_str(), g_agbTrack); + int wholeNoteCount = 0; + + ResetTrackVars(); + + bool foundVolBeforeNote = false; + + for (const Event& event : events) + { + if (event.type == EventType::Note) + break; + + if (event.type == EventType::Controller && event.param1 == 0x07) + { + foundVolBeforeNote = true; + break; + } + } + + if (!foundVolBeforeNote) + PrintByte("\tVOL , 127*%s_mvl/mxv", g_asmLabel.c_str()); + + PrintWait(g_initialWait); + if (trackLoops > 0) + PrintByte("KEYSH , %s_key%+d", g_asmLabel.c_str(), 0); + + for (int k = 0; k < trackLoops; k++) + { + for (unsigned i = 0; events[i].type != EventType::EndOfTrack; i++) + { + const Event& event = events[i]; + + if (IsPatternBoundary(event.type)) + { + if (s_inPattern) + PrintByte("PEND"); + s_inPattern = false; + } + + // added `&& (i % 2 == 0)` to cut down on excess comments created in the .s file + if ((event.type == EventType::WholeNoteMark || event.type == EventType::Pattern) && (i % 2 == 0)) + std::fprintf(g_outputFile, "@ %03d ----------------------------------------\n", wholeNoteCount++); + + switch (event.type) + { + case EventType::Note: + PrintNote(event); + break; + case EventType::EndOfTie: + PrintEndOfTieOp(event); + break; + case EventType::Label: + if (k == 0) + PrintSeqLoopLabel(event); + break; + case EventType::LoopEnd: + case EventType::LoopEndBegin: + break; + case EventType::LoopBegin: + if (k == 0) + PrintSeqLoopLabel(event); + break; + case EventType::WholeNoteMark: + if (event.param2 & 0x80000000) + { + std::fprintf(g_outputFile, "%s_%u_%03lu:\n", g_asmLabel.c_str(), g_agbTrack, (unsigned long)(event.param2 & 0x7FFFFFFF)); + ResetTrackVars(); + s_inPattern = true; + } + PrintWait(event.time); + break; + case EventType::Pattern: + PrintByte("PATT"); + PrintWord("%s_%u_%03lu", g_asmLabel.c_str(), g_agbTrack, event.param2); + + while (!IsPatternBoundary(events[i + 1].type)) + i++; + + ResetTrackVars(); + break; + case EventType::Tempo: + if (k == 0) + { + PrintByte("TEMPO , %u*%s_tbs/2", static_cast(round(60000000.0f / static_cast(event.param2))), g_asmLabel.c_str()); + PrintWait(event.time); + } + break; + case EventType::InstrumentChange: + if (k == 0) + PrintOp(event.time, "VOICE ", "%u", event.param1); + break; + case EventType::PitchBend: + PrintOp(event.time, "BEND ", "c_v%+d", event.param2 - 64); + break; + case EventType::Controller: + if (k == 0) + PrintControllerOp(event); + break; + default: + PrintWait(event.time); + break; + } + } + } + + PrintByte("FINE"); +} + void PrintAgbFooter() { int trackCount = g_agbTrack - 1; diff --git a/tools/mid2agb/agb.h b/tools/mid2agb/agb.h index 7eab3c1433..d096b1bc27 100644 --- a/tools/mid2agb/agb.h +++ b/tools/mid2agb/agb.h @@ -26,6 +26,7 @@ void PrintAgbHeader(); void PrintAgbTrack(std::vector& events); +void PrintAgbTrackLoop(std::vector& events, int trackLoops); void PrintAgbFooter(); extern int g_agbTrack; diff --git a/tools/mid2agb/midi.cpp b/tools/mid2agb/midi.cpp index fa7d9ce285..e2e7741cb3 100644 --- a/tools/mid2agb/midi.cpp +++ b/tools/mid2agb/midi.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,10 @@ #include "agb.h" #include "tables.h" +// expansion headers +#include "../../include/config/battle.h" +#include "../../include/config/general.h" + enum class MidiEventCategory { Control, @@ -916,6 +921,7 @@ void Compress(std::vector& events) void ReadMidiTracks() { long trackHeaderStart = 14; + int trackLoops = B_NUM_LOW_HEALTH_BEEPS; ReadMidiTrackHeader(trackHeaderStart); ReadSeqEvents(); @@ -955,7 +961,10 @@ void ReadMidiTracks() if (g_compressionEnabled) Compress(*events); - PrintAgbTrack(*events); + if ((strcmp(g_asmLabel.c_str(), "se_low_health") == 0) && trackLoops >= 0) + PrintAgbTrackLoop(*events, trackLoops); + else + PrintAgbTrack(*events); g_agbTrack++; }