diff --git a/Makefile b/Makefile index cf11e3a255e4..d7d6955e3720 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ MODERN ?= 1 TEST ?= 0 ANALYZE ?= 0 UNUSED_ERROR ?= 0 +DEBUG ?= 0 ifeq (agbcc,$(MAKECMDGOALS)) MODERN := 0 @@ -53,6 +54,10 @@ ifeq (check,$(MAKECMDGOALS)) TEST := 1 endif +ifeq (debug,$(MAKECMDGOALS)) + DEBUG := 1 +endif + # use arm-none-eabi-cpp for macOS # as macOS's default compiler is clang # and clang's preprocessor will warn on \u @@ -89,10 +94,15 @@ SYM = $(ROM:.gba=.sym) TEST_OBJ_DIR_NAME_MODERN := build/modern-test TEST_OBJ_DIR_NAME_AGBCC := build/test +DEBUG_OBJ_DIR_NAME_MODERN := build/modern-debug +DEBUG_OBJ_DIR_NAME_AGBCC := build/debug + ifeq ($(MODERN),0) TEST_OBJ_DIR_NAME := $(TEST_OBJ_DIR_NAME_AGBCC) +DEBUG_OBJ_DIR_NAME := $(DEBUG_OBJ_DIR_NAME_AGBCC) else TEST_OBJ_DIR_NAME := $(TEST_OBJ_DIR_NAME_MODERN) +DEBUG_OBJ_DIR_NAME := $(DEBUG_OBJ_DIR_NAME_MODERN) endif TESTELF = $(ROM:.gba=-test.elf) HEADLESSELF = $(ROM:.gba=-test-headless.elf) @@ -120,14 +130,14 @@ ASFLAGS := -mcpu=arm7tdmi --defsym MODERN=$(MODERN) ifeq ($(MODERN),0) CC1 := tools/agbcc/bin/agbcc$(EXE) -override CFLAGS += -mthumb-interwork -Wimplicit -Wparentheses -Werror -O2 -fhex-asm -g +override CFLAGS += -mthumb-interwork -Wimplicit -Wparentheses -Werror -fhex-asm ROM := $(ROM_NAME) OBJ_DIR := $(OBJ_DIR_NAME) LIBPATH := -L ../../tools/agbcc/lib LIB := $(LIBPATH) -lgcc -lc -L../../libagbsyscall -lagbsyscall else CC1 = $(shell $(PATH_MODERNCC) --print-prog-name=cc1) -quiet -override CFLAGS += -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init +override CFLAGS += -mthumb -mthumb-interwork -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init ifeq ($(ANALYZE),1) override CFLAGS += -fanalyzer endif @@ -143,6 +153,16 @@ LIBPATH := -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libgcc.a) LIB := $(LIBPATH) -lc -lnosys -lgcc -L../../libagbsyscall -lagbsyscall endif +ifeq ($(DEBUG),1) +ifeq ($(MODERN),1) +override CFLAGS += -Og -g +else +override CFLAGS += -O1 -g +endif +else +override CFLAGS += -O2 +endif + ifeq ($(TESTELF),$(MAKECMDGOALS)) TEST := 1 endif @@ -150,12 +170,20 @@ endif ifeq ($(TEST),1) OBJ_DIR := $(TEST_OBJ_DIR_NAME) endif +ifeq ($(DEBUG),1) +OBJ_DIR := $(DEBUG_OBJ_DIR_NAME) +endif + CPPFLAGS := -iquote include -iquote $(GFLIB_SUBDIR) -Wno-trigraphs -DMODERN=$(MODERN) -DTESTING=$(TEST) ifneq ($(MODERN),1) CPPFLAGS += -I tools/agbcc/include -I tools/agbcc -nostdinc -undef endif +ifeq ($(DEBUG),1) +CPPFLAGS += -DDEBUG_TARGET +endif + SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c GFX := tools/gbagfx/gbagfx$(EXE) AIF := tools/aif2pcm/aif2pcm$(EXE) @@ -191,7 +219,7 @@ MAKEFLAGS += --no-print-directory # Secondary expansion is required for dependency variables in object rules. .SECONDEXPANSION: -.PHONY: all rom clean compare tidy tools check-tools mostlyclean clean-tools clean-check-tools $(TOOLDIRS) $(CHECKTOOLDIRS) libagbsyscall agbcc modern tidymodern tidynonmodern check history +.PHONY: all rom clean compare tidy tools check-tools mostlyclean clean-tools clean-check-tools $(TOOLDIRS) $(CHECKTOOLDIRS) libagbsyscall agbcc modern tidymodern tidynonmodern check history debug infoshell = $(foreach line, $(shell $1 | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line)))) @@ -199,7 +227,7 @@ infoshell = $(foreach line, $(shell $1 | sed "s/ /__SPACE__/g"), $(info $(subst # Disable dependency scanning for clean/tidy/tools # Use a separate minimal makefile for speed # Since we don't need to reload most of this makefile -ifeq (,$(filter-out all rom compare agbcc modern check libagbsyscall syms $(TESTELF),$(MAKECMDGOALS))) +ifeq (,$(filter-out all rom compare agbcc modern check libagbsyscall syms $(TESTELF) debug,$(MAKECMDGOALS))) $(call infoshell, $(MAKE) -f make_tools.mk) else NODEP ?= 1 @@ -291,17 +319,17 @@ clean-tools: clean-check-tools: @$(foreach tooldir,$(CHECKTOOLDIRS),$(MAKE) clean -C $(tooldir);) -mostlyclean: tidynonmodern tidymodern tidycheck +mostlyclean: tidynonmodern tidymodern tidycheck tidydebug find sound -iname '*.bin' -exec rm {} + rm -f $(MID_SUBDIR)/*.s find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.rl' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} + rm -f $(DATA_ASM_SUBDIR)/layouts/layouts.inc $(DATA_ASM_SUBDIR)/layouts/layouts_table.inc - rm -f $(DATA_ASM_SUBDIR)/maps/connections.inc $(DATA_ASM_SUBDIR)/maps/events.inc $(DATA_ASM_SUBDIR)/maps/groups.inc $(DATA_ASM_SUBDIR)/maps/headers.inc + rm -f $(DATA_ASM_SUBDIR)/maps/connections.inc $(DATA_ASM_SUBDIR)/maps/events.inc $(DATA_ASM_SUBDIR)/maps/groups.inc $(DATA_ASM_SUBDIR)/maps/headers.inc $(DATA_SRC_SUBDIR)/map_group_count.h find $(DATA_ASM_SUBDIR)/maps \( -iname 'connections.inc' -o -iname 'events.inc' -o -iname 'header.inc' \) -exec rm {} + rm -f $(AUTO_GEN_TARGETS) @$(MAKE) clean -C libagbsyscall -tidy: tidynonmodern tidymodern tidycheck +tidy: tidynonmodern tidymodern tidycheck tidydebug tidynonmodern: rm -f $(ROM_NAME) $(ELF_NAME) $(MAP_NAME) @@ -317,6 +345,10 @@ tidycheck: rm -rf $(TEST_OBJ_DIR_NAME_AGBCC) +tidydebug: + rm -rf $(DEBUG_OBJ_DIR_NAME_MODERN) + rm -rf $(DEBUG_OBJ_DIR_NAME_AGBCC) + ifneq ($(MODERN),0) $(C_BUILDDIR)/berry_crush.o: override CFLAGS += -Wno-address-of-packed-member endif @@ -375,6 +407,15 @@ ifeq ($(DINFO),1) override CFLAGS += -g endif +ifeq ($(NOOPT),1) +override CFLAGS := $(filter-out -O1 -Og -O2,$(CFLAGS)) +override CFLAGS += -O0 +endif + +ifeq ($(DPRINT),1) +override CPPFLAGS += -DDEBUG_TARGET +endif + # The dep rules have to be explicit or else missing files won't be reported. # As a side effect, they're evaluated immediately instead of when the rule is invoked. # It doesn't look like $(shell) can be deferred so there might not be a better way. @@ -513,6 +554,8 @@ agbcc: all modern: all +debug: all + LD_SCRIPT_TEST := ld_script_test.ld $(OBJ_DIR)/ld_script_test.ld: $(LD_SCRIPT_TEST) $(LD_SCRIPT_DEPS) diff --git a/README.md b/README.md index 18b497a212f7..fabb3f86c6ae 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,14 @@ Based off RHH's pokeemerald-expansion v1.8.0 https://github.com/rh-hideout/pokee - [Nature Colors](https://github.com/DizzyEggg/pokeemerald/tree/nature_color) in summary screen by @DizzyEggg - [Dynamic Multichoice](https://github.com/SBird1337/pokeemerald/tree/feature/dynmulti) by @SBird1337 - [Saveblock Cleansing](https://github.com/ghoulslash/pokeemerald/tree/saveblock) by @ghoulslash + - [Followers & Expanded IDs](https://github.com/aarant/pokeemerald/tree/followers-expanded-id) by @aarant + - May be disabled. + - Includes Pokémon followers like in HGSS, including interactions. + - ***Expands the amount of possible object event IDs beyond 255.*** + - ***Includes an implementation of dynamic overworld palettes (DOWP).*** + - **Additional features**: + - *Pokémon overworld sprites up to Generation 8.* + - *Integration with our Pokémon Sprite Visualizer, allowing users to browse through the follower sprites alongside battle sprites.* - ***Other features*** - Pressing B while holding a Pokémon drops them like in modern games (configurable). - Running indoors (configurable). diff --git a/asm/macros/event.inc b/asm/macros/event.inc index a518b7be2c26..e2bf9a06e822 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -776,6 +776,16 @@ trainerbattle TRAINER_BATTLE_SINGLE_NO_INTRO_TEXT, \trainer, 0, \lose_text .endm + @ Starts a double battle with the player against two trainers + @ Takes two trainers and defeat text for each + .macro trainerbattle_two_trainers trainer_a:req, lose_text_a:req, trainer_b:req, lose_text_b:req + .byte 0x5c + .byte TRAINER_BATTLE_TWO_TRAINERS_NO_INTRO + .2byte \trainer_a + .4byte \lose_text_a + .2byte \trainer_b + .4byte \lose_text_b + .endm @ Starts a trainer battle using the battle information stored in RAM (usually by the scripts in trainer_battle.inc, which @ are run by trainerbattle), and blocks script execution until the battle finishes. @@ -2095,7 +2105,7 @@ setvar VAR_0x8002, \tryMultiple special TrySpecialOverworldEvo .endm - + .macro ai_vs_ai_battle trainer1:req, trainer2:req setflag B_FLAG_AI_VS_AI_BATTLE setvar VAR_0x8004, \trainer1 diff --git a/data/scripts/debug.inc b/data/scripts/debug.inc index 09ae1404c4a4..9aa43edcc8bb 100644 --- a/data/scripts/debug.inc +++ b/data/scripts/debug.inc @@ -1,4 +1,3 @@ -.if DEBUG_OVERWORLD_MENU == TRUE Debug_MessageEnd: waitmessage waitbuttonpress @@ -430,5 +429,3 @@ Debug_EventScript_InflictStatus1_Text_Freeze: Debug_EventScript_InflictStatus1_Text_Frostbite: .string "Frostbite$" - -.endif diff --git a/graphics/map_popup/bw/black.pal b/graphics/map_popup/bw/black.pal new file mode 100644 index 000000000000..ef4da4d29cfe --- /dev/null +++ b/graphics/map_popup/bw/black.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +0 0 0 +0 0 0 +255 255 255 +84 85 89 +0 0 0 +238 230 238 +189 180 197 +139 139 164 +90 90 123 +41 49 90 +27 27 27 +40 40 40 +51 51 51 +62 62 62 +0 0 0 +0 0 0 diff --git a/graphics/map_popup/bw/bw_primary.png b/graphics/map_popup/bw/bw_primary.png new file mode 100644 index 000000000000..9dd681ff0abb Binary files /dev/null and b/graphics/map_popup/bw/bw_primary.png differ diff --git a/graphics/map_popup/bw/bw_secondary.png b/graphics/map_popup/bw/bw_secondary.png new file mode 100644 index 000000000000..b63ce95311a8 Binary files /dev/null and b/graphics/map_popup/bw/bw_secondary.png differ diff --git a/graphics/map_popup/bw/white.pal b/graphics/map_popup/bw/white.pal new file mode 100644 index 000000000000..8706c80d4e0b --- /dev/null +++ b/graphics/map_popup/bw/white.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +0 0 0 +255 255 255 +0 0 0 +158 158 158 +0 0 0 +238 230 238 +189 180 197 +139 139 164 +90 90 123 +41 49 90 +228 228 228 +215 215 215 +204 204 204 +193 193 193 +0 0 0 +0 0 0 diff --git a/include/battle.h b/include/battle.h index 15e8d2636647..7b08c25b0905 100644 --- a/include/battle.h +++ b/include/battle.h @@ -718,6 +718,7 @@ struct BattleStruct } multiBuffer; u8 wishPerishSongState; u8 wishPerishSongBattlerId; + u8 aiCalcInProgress:1; u8 overworldWeatherDone:1; u8 startingStatusDone:1; u8 isAtkCancelerForCalledMove:1; // Certain cases in atk canceler should only be checked once, when the original move is called, however others need to be checked the twice. diff --git a/include/config.h b/include/config.h index 0f1b64bd13fe..c4edd4719fc5 100644 --- a/include/config.h +++ b/include/config.h @@ -8,6 +8,10 @@ // Ruby's actual debug build does not use the AGBPrint features. #define NDEBUG +#ifdef DEBUG_TARGET +#undef NDEBUG +#endif + // To enable printf debugging, comment out "#define NDEBUG". This allows // the various AGBPrint functions to be used. (See include/gba/isagbprint.h). // See below for enabling different pretty printing versions. diff --git a/include/config/battle.h b/include/config/battle.h index c072cb79937b..1af7e0c68aa1 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -120,6 +120,7 @@ #define B_ALLY_SWITCH_FAIL_CHANCE GEN_LATEST // In Gen9, using Ally Switch consecutively decreases the chance of success for each consecutive use. #define B_SKETCH_BANS GEN_LATEST // In Gen9+, Sketch is unable to copy more moves than in previous generations. #define B_KNOCK_OFF_REMOVAL GEN_LATEST // In Gen5+, Knock Off removes the foe's item instead of rendering it unusable. +#define B_HEAL_BELL_SOUNDPROOF GEN_LATEST // In Gen5, Heal Bell affects all mons with Soundproof. In Gen6-8 it affects inactive mons, but not battlers. In Gen9 it always affects the user. // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. diff --git a/include/config/debug.h b/include/config/debug.h index eea676b3070c..f9d559d1ff09 100644 --- a/include/config/debug.h +++ b/include/config/debug.h @@ -2,16 +2,28 @@ #define GUARD_CONFIG_DEBUG_H // Overworld Debug -#define DEBUG_OVERWORLD_MENU TRUE // Enables an overworld debug menu to change flags, variables, giving pokemon and more, accessed by holding R and pressing START while in the overworld by default. +#define DEBUG_OVERWORLD_MENU FALSE // Enables an overworld debug menu to change flags, variables, giving pokemon and more, accessed by holding R and pressing START while in the overworld by default. #define DEBUG_OVERWORLD_HELD_KEYS (R_BUTTON) // The keys required to be held to open the debug menu. #define DEBUG_OVERWORLD_TRIGGER_EVENT pressedStartButton // The event that opens the menu when holding the key(s) defined in DEBUG_OVERWORLD_HELD_KEYS. #define DEBUG_OVERWORLD_IN_MENU FALSE // Replaces the overworld debug menu button combination with a start menu entry (above Pokédex). // Battle Debug Menu -#define DEBUG_BATTLE_MENU TRUE // If set to TRUE, enables a debug menu to use in battles by pressing the Select button. +#define DEBUG_BATTLE_MENU FALSE // If set to TRUE, enables a debug menu to use in battles by pressing the Select button. #define DEBUG_AI_DELAY_TIMER FALSE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. // Pokémon Debug -#define DEBUG_POKEMON_MENU TRUE // Enables a debug menu for pokemon sprites and icons, accessed by pressing SELECT in the summary screen. +#define DEBUG_POKEMON_SPRITE_VISUALIZER FALSE // Enables a debug menu for Pokémon sprites and icons, accessed by pressing Select in the summary screen. + +// Automatically enable all debug menus if building with debug target +#ifdef DEBUG_TARGET +#undef DEBUG_OVERWORLD_MENU +#define DEBUG_OVERWORLD_MENU TRUE + +#undef DEBUG_BATTLE_MENU +#define DEBUG_BATTLE_MENU TRUE + +#undef DEBUG_POKEMON_SPRITE_VISUALIZER +#define DEBUG_POKEMON_SPRITE_VISUALIZER TRUE +#endif #endif // GUARD_CONFIG_DEBUG_H diff --git a/include/config/overworld.h b/include/config/overworld.h index f1a7ff660fdd..6b4bca75b6d3 100644 --- a/include/config/overworld.h +++ b/include/config/overworld.h @@ -65,4 +65,22 @@ #define BATTLE_PYRAMID_RANDOM_ENCOUNTERS FALSE // If set to TRUE, battle pyramid Pokemon will be generated randomly based on the round's challenge instead of hardcoded in src/data/battle_frontier/battle_pyramid_level_50_wild_mons.h (or open_level_wild_mons.h) +// Map pop-up config +#define OW_POPUP_GENERATION GEN_3 // Different generations display location names in overworld pop-ups differently. + // Only choies are currently GEN_3 and GEN_5, all others will default to Gen3 pop-ups. + +// Gen5 map pop-up config +// Constants +#define OW_POPUP_BW_TIME_NONE 0 // Don't show the time +#define OW_POPUP_BW_TIME_12_HR 1 // Use 12 hour (AM/PM) time +#define OW_POPUP_BW_TIME_24_HR 2 // Use 24 hour time + +#define OW_POPUP_BW_COLOR_BLACK 0 // Black pop-up from B2 +#define OW_POPUP_BW_COLOR_WHITE 1 // White pop-up from W2 + +// Configuration +#define OW_POPUP_BW_COLOR OW_POPUP_BW_COLOR_BLACK // B2W2 use different colors for their map pop-ups. +#define OW_POPUP_BW_TIME_MODE OW_POPUP_BW_TIME_NONE // Determines what type of time is shown. +#define OW_POPUP_BW_ALPHA_BLEND FALSE // Enables alpha blending/transparency for the pop-ups. Mainly intended to be used with the black color option. + #endif // GUARD_CONFIG_OVERWORLD_H diff --git a/include/constants/battle_setup.h b/include/constants/battle_setup.h index d825c88bc314..bb7f9adefaf5 100644 --- a/include/constants/battle_setup.h +++ b/include/constants/battle_setup.h @@ -14,5 +14,6 @@ #define TRAINER_BATTLE_SET_TRAINER_A 10 #define TRAINER_BATTLE_SET_TRAINER_B 11 #define TRAINER_BATTLE_HILL 12 +#define TRAINER_BATTLE_TWO_TRAINERS_NO_INTRO 13 #endif // GUARD_CONSTANTS_BATTLE_SETUP_H diff --git a/include/constants/pokemon_debug.h b/include/constants/pokemon_sprite_visualizer.h similarity index 75% rename from include/constants/pokemon_debug.h rename to include/constants/pokemon_sprite_visualizer.h index d68eab15d134..36afdb5b87b4 100644 --- a/include/constants/pokemon_debug.h +++ b/include/constants/pokemon_sprite_visualizer.h @@ -1,15 +1,13 @@ -#ifndef GUARD_CONSTANTS_POKEMON_DEBUG_H -#define GUARD_CONSTANTS_POKEMON_DEBUG_H +#ifndef GUARD_CONSTANTS_POKEMON_SPRITE_VISUALIZER_H +#define GUARD_CONSTANTS_POKEMON_SPRITE_VISUALIZER_H //Defines -#define DEBUG_MON_BACK_X 62 -#define DEBUG_MON_BACK_Y 80 -#define DEBUG_ICON_X 224 -#define DEBUG_ICON_Y 144 -#define DEBUG_MON_SHINY 0 -#define DEBUG_MON_NORMAL 9 -#define DEBUG_FOLLOWER_X 176 -#define DEBUG_FOLLOWER_Y 128 +#define VISUALIZER_MON_BACK_X 62 +#define VISUALIZER_MON_BACK_Y 80 +#define VISUALIZER_ICON_X 224 +#define VISUALIZER_ICON_Y 144 +#define VISUALIZER_FOLLOWER_X 176 +#define VISUALIZER_FOLLOWER_Y 128 #define MODIFY_DIGITS_MAX 4 #define MODIFY_DIGITS_ARROW_X 129 @@ -52,4 +50,4 @@ #define MAP_BATTLE_SCENE_KYOGRE 12 #define MAP_BATTLE_SCENE_RAYQUAZA 13 -#endif // GUARD_CONSTANTS_POKEMON_DEBUG_H \ No newline at end of file +#endif // GUARD_CONSTANTS_POKEMON_SPRITE_VISUALIZER_H diff --git a/include/field_weather.h b/include/field_weather.h index b354d500e306..9805dc491d35 100644 --- a/include/field_weather.h +++ b/include/field_weather.h @@ -170,6 +170,7 @@ void SetWeatherScreenFadeOut(void); void SetWeatherPalStateIdle(void); void PreservePaletteInWeather(u8 preservedPalIndex); void ResetPreservedPalettesInWeather(void); +bool32 IsWeatherAlphaBlend(void); // field_weather_effect.c void Clouds_InitVars(void); diff --git a/include/list_menu.h b/include/list_menu.h index 1e6c0f95facc..413b97822721 100644 --- a/include/list_menu.h +++ b/include/list_menu.h @@ -40,9 +40,9 @@ struct ListMenuTemplate const struct ListMenuItem *items; void (* moveCursorFunc)(s32 itemIndex, bool8 onInit, struct ListMenu *list); void (* itemPrintFunc)(u8 windowId, u32 itemId, u8 y); - u16 totalItems:12; - u16 maxShowed:12; - u16 textNarrowWidth:8; + u32 totalItems:12; + u32 maxShowed:12; + u32 textNarrowWidth:8; u8 windowId; u8 header_X; u8 item_X; diff --git a/include/menu.h b/include/menu.h index 0b0a42423d74..fac4ef1b65a5 100644 --- a/include/menu.h +++ b/include/menu.h @@ -41,6 +41,7 @@ struct MenuAction }; extern const u16 gStandardMenuPalette[]; +extern EWRAM_DATA u8 gPopupTaskId; void FreeAllOverworldWindowBuffers(void); void InitStandardTextBoxWindows(void); @@ -124,5 +125,9 @@ void AddTextPrinterWithCustomSpeedForMessage(bool8 allowSkippingDelayWithButtonP void EraseYesNoWindow(void); void PrintMenuActionTextsAtPos(u8 windowId, u8 fontId, u8 left, u8 top, u8 lineHeight, u8 itemCount, const struct MenuAction *strs); void Menu_LoadStdPal(void); +u8 AddSecondaryPopUpWindow(void); +u8 GetSecondaryPopUpWindowId(void); +void RemoveSecondaryPopUpWindow(void); +void HBlankCB_DoublePopupWindow(void); #endif // GUARD_MENU_H diff --git a/include/pokemon_debug.h b/include/pokemon_sprite_visualizer.h similarity index 64% rename from include/pokemon_debug.h rename to include/pokemon_sprite_visualizer.h index e2fc349edb2e..946c2f37f625 100644 --- a/include/pokemon_debug.h +++ b/include/pokemon_sprite_visualizer.h @@ -1,10 +1,10 @@ -#ifndef GUARD_POKEMON_DEBUG_H -#define GUARD_POKEMON_DEBUG_H +#ifndef GUARD_POKEMON_SPRITE_VISUALIZER_H +#define GUARD_POKEMON_SPRITE_VISUALIZER_H -#include "constants/pokemon_debug.h" +#include "constants/pokemon_sprite_visualizer.h" //Structs -struct PokemonDebugModifyArrows +struct PokemonSpriteVisualizerModifyArrows { u8 arrowSpriteId[2]; u16 minValue; @@ -17,13 +17,13 @@ struct PokemonDebugModifyArrows u8 typeOfVal; }; -struct PokemonDebugOptionArrows +struct PokemonSpriteVisualizerOptionArrows { u8 arrowSpriteId[1]; u8 currentDigit; }; -struct PokemonDebugYPosModifiyArrows +struct PokemonSpriteVisualizerYPosModifiyArrows { u8 arrowSpriteId[1]; u8 currentDigit; @@ -43,7 +43,7 @@ struct PokemonSpriteOffsets s8 offset_front_elevation; }; -struct PokemonDebugMenu +struct PokemonSpriteVisualizer { u16 currentmonId; u8 currentmonWindowId; @@ -55,9 +55,9 @@ struct PokemonDebugMenu u8 frontShadowSpriteId; bool8 isShiny; bool8 isFemale; - struct PokemonDebugModifyArrows modifyArrows; - struct PokemonDebugOptionArrows optionArrows; - struct PokemonDebugYPosModifiyArrows yPosModifyArrows; + struct PokemonSpriteVisualizerModifyArrows modifyArrows; + struct PokemonSpriteVisualizerOptionArrows optionArrows; + struct PokemonSpriteVisualizerYPosModifiyArrows yPosModifyArrows; struct PokemonSpriteConstValues constSpriteValues; struct PokemonSpriteOffsets offsetsSpriteValues; u8 animIdBack; @@ -68,7 +68,7 @@ struct PokemonDebugMenu u8 submenuYpos[3]; }; -void CB2_Debug_Pokemon(void); +void CB2_Pokemon_Sprite_Visualizer(void); -#endif // GUARD_POKEMON_DEBUG_H \ No newline at end of file +#endif // GUARD_POKEMON_SPRITE_VISUALIZER_H diff --git a/include/rtc.h b/include/rtc.h index 9882d702b6fb..bf8ff9aa936d 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -118,5 +118,6 @@ void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds); void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2); u32 RtcGetMinuteCount(void); u32 RtcGetLocalDayCount(void); +void FormatDecimalTimeWithoutSeconds(u8 *dest, s8 hour, s8 minute, bool32 is24Hour); #endif // GUARD_RTC_UTIL_H diff --git a/include/strings.h b/include/strings.h index af0ee0bbba14..359184cbf405 100644 --- a/include/strings.h +++ b/include/strings.h @@ -3061,4 +3061,8 @@ extern const u8 gText_BasePointsResetToZero[]; extern const u8 gText_Fertilize[]; extern const u8 gText_PlantBerry[]; +// Map name pop-up +extern const u8 gText_AM[]; +extern const u8 gText_PM[]; + #endif // GUARD_STRINGS_H diff --git a/ld_script.ld b/ld_script.ld index 296131204868..a0c069c96574 100644 --- a/ld_script.ld +++ b/ld_script.ld @@ -358,7 +358,7 @@ SECTIONS { src/gym_leader_rematch.o(.text); src/battle_transition_frontier.o(.text); src/international_string_util.o(.text); - src/pokemon_debug.o(.text); + src/pokemon_sprite_visualizer.o(.text); src/expansion_intro.o(.text); } > ROM =0 @@ -726,7 +726,7 @@ SECTIONS { data/mystery_gift.o(.rodata); src/m4a_tables.o(.rodata); data/sound_data.o(.rodata); - src/pokemon_debug.o(.rodata); + src/pokemon_sprite_visualizer.o(.rodata); src/expansion_intro.o(.rodata); } > ROM =0 diff --git a/map_data_rules.mk b/map_data_rules.mk index 626cd4724080..a045d1d42061 100755 --- a/map_data_rules.mk +++ b/map_data_rules.mk @@ -23,6 +23,7 @@ $(MAPS_DIR)/groups.inc: $(MAPS_DIR)/map_groups.json $(MAPS_DIR)/connections.inc: $(MAPS_DIR)/groups.inc ; $(MAPS_DIR)/events.inc: $(MAPS_DIR)/connections.inc ; $(MAPS_DIR)/headers.inc: $(MAPS_DIR)/events.inc ; +$(DATA_SRC_SUBDIR)/map_group_count.h: $(MAPS_DIR)/headers.inc ; include/constants/map_groups.h: $(MAPS_DIR)/headers.inc ; $(LAYOUTS_DIR)/layouts.inc: $(LAYOUTS_DIR)/layouts.json diff --git a/migration_scripts/item_ball_refactor.py b/migration_scripts/1.8/item_ball_refactor.py similarity index 100% rename from migration_scripts/item_ball_refactor.py rename to migration_scripts/1.8/item_ball_refactor.py diff --git a/migration_scripts/battle_anim_moves_refactor.py b/migration_scripts/1.9/battle_anim_moves_refactor.py similarity index 100% rename from migration_scripts/battle_anim_moves_refactor.py rename to migration_scripts/1.9/battle_anim_moves_refactor.py diff --git a/migration_scripts/convert_item_icons.py b/migration_scripts/1.9/convert_item_icons.py similarity index 100% rename from migration_scripts/convert_item_icons.py rename to migration_scripts/1.9/convert_item_icons.py diff --git a/migration_scripts/convert_partner_parties.py b/migration_scripts/1.9/convert_partner_parties.py similarity index 100% rename from migration_scripts/convert_partner_parties.py rename to migration_scripts/1.9/convert_partner_parties.py diff --git a/migration_scripts/convert_trainer_parties.py b/migration_scripts/1.9/convert_trainer_parties.py similarity index 100% rename from migration_scripts/convert_trainer_parties.py rename to migration_scripts/1.9/convert_trainer_parties.py diff --git a/migration_scripts/egg_move_refactor.py b/migration_scripts/1.9/egg_move_refactor.py similarity index 100% rename from migration_scripts/egg_move_refactor.py rename to migration_scripts/1.9/egg_move_refactor.py diff --git a/migration_scripts/README.md b/migration_scripts/README.md index 5845348cdfa1..cfa1d23638ca 100644 --- a/migration_scripts/README.md +++ b/migration_scripts/README.md @@ -17,9 +17,293 @@ python3 migration_scripts/*.py ; #run the migration script `*` will need to be replaced with the name of the appropriate script. +## 1.8.x to 1.9.x+ + +### Battle Anim Moves + +* Filepath [`migration_scripts/1.9/battle_anim_moves_refactor.py`](1.9/battle_anim_moves_refactor.py) +* Introduced in [Refactor move animations #4683](https://github.com/rh-hideout/pokeemerald-expansion/pull/4683) + +Refactors all battle animation move scripts, removing the list from `data/battle_anim_scripts.s` and linking them to the moves in `gMovesInfo` for easier maintaining. Only necessary if new moves have been added. + +#### [data/battle_anim_scripts.h](../data/battle_anim_scripts.s) +```diff +- .4byte Move_POUND +``` + +#### [include/battle_anim_scripts.h](../include/battle_anim_scripts.h) +```diff ++ extern const u8 Move_POUND[]; +``` + +#### [src/data/moves_info.h](../src/data/moves_info.h) +```diff + [MOVE_POUND] = + { + .name = COMPOUND_STRING("Pound"), + .description = COMPOUND_STRING( + "Pounds the foe with\n" + "forelegs or tail."), + .effect = EFFECT_HIT, + .power = 40, + .type = TYPE_NORMAL, + .accuracy = 100, + .pp = 35, + .target = MOVE_TARGET_SELECTED, + .priority = 0, + .category = DAMAGE_CATEGORY_PHYSICAL, + .makesContact = TRUE, + .ignoresKingsRock = B_UPDATED_MOVE_FLAGS == GEN_4, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestComboStarterId = COMBO_STARTER_POUND, +- .contestComboMoves = {0} ++ .contestComboMoves = {0}, ++ .battleAnimScript = Move_POUND, + }, +``` + +### Item Icons + +* Filepath [`migration_scripts/1.9/convert_item_icons.py`](1.9/convert_item_icons.py) +* Introduced in [Get rid of gItemIconTable #4579](https://github.com/rh-hideout/pokeemerald-expansion/pull/4579) + +Moves all information from `gItemIconTable` to `gItemsInfo`. + +#### [src/data/item_icon_table.h](..src/data/item_icon_table.h) +```diff +- [ITEM_POKE_BALL] = {gItemIcon_PokeBall, gItemIconPalette_PokeBall}, +``` + +#### [src/data/items.h](..src/data/items.h) +```diff + [ITEM_POKE_BALL] = + { + .name = _("Poké Ball"), + .price = 200, + .description = COMPOUND_STRING( + "A tool used for\n" + "catching wild\n" + "Pokémon."), + .pocket = POCKET_POKE_BALLS, + .type = ITEM_USE_BAG_MENU, + .battleUsage = EFFECT_ITEM_THROW_BALL, + .secondaryId = ITEM_POKE_BALL - FIRST_BALL, ++ .iconSprite = gItemIcon_PokeBall, ++ .iconPalette = gItemIconPalette_PokeBall, + }, +``` + +### Partner & Trainer Parties + +* Filepaths [`migration_scripts/1.9/convert_trainer_parties.py`](1.9/convert_trainer_parties.py) and [`migration_scripts/1.9/convert_partner_parties.py`](1.9/convert_trainer_parties.py) +* Introduced in [Competitive-formatted parties #3545](https://github.com/rh-hideout/pokeemerald-expansion/pull/3545) and [Make trainerproc compatible with partners #4421](https://github.com/rh-hideout/pokeemerald-expansion/pull/4421) + +Converts trainer data (for `convert_trainer_parties.py`) and partner data (for `convert_partner_data.py`) to the new `.party` format. Not necessary if `COMPETITIVE_PARTY_SYNTAX` is turned off. + +#### [src/data/trainer_parties.h](..src/data/trainer_parties.h) +```diff +-static const struct TrainerMon sParty_Sawyer1[] = { +- { +- .lvl = 21, +- .species = SPECIES_GEODUDE, +- } +-}; +``` + +#### [src/data/trainers.party](..src/data/trainers.party) +```diff ++=== TRAINER_SAWYER_1 === ++Name: SAWYER ++Class: Hiker ++Pic: Hiker ++Gender: Male ++Music: Hiker ++Double Battle: No ++AI: Check Bad Move / Try To Faint / Check Viability ++ ++Geodude ++Level: 21 ++IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe +``` + +#### [src/data/partner_parties.h](..src/data/partner_parties.h) +```diff +-static const struct TrainerMon sParty_StevenPartner[] = { +- { +- .species = SPECIES_METANG, +- .lvl = 42, +- .nature = NATURE_BRAVE, +- .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +- .ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0), +- .moves = {MOVE_LIGHT_SCREEN, MOVE_PSYCHIC, MOVE_REFLECT, MOVE_METAL_CLAW}, +- }, +- { +- .species = SPECIES_SKARMORY, +- .lvl = 43, +- .nature = NATURE_IMPISH, +- .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +- .ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252), +- .moves = {MOVE_TOXIC, MOVE_AERIAL_ACE, MOVE_PROTECT, MOVE_STEEL_WING}, +- }, +- { +- .species = SPECIES_AGGRON, +- .lvl = 44, +- .nature = NATURE_ADAMANT, +- .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +- .ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6), +- .moves = {MOVE_THUNDER, MOVE_PROTECT, MOVE_SOLAR_BEAM, MOVE_DRAGON_CLAW}, +- } +-}; +``` + +#### [src/data/battle_partners.party](..src/data/battle_partners.party) +```diff ++=== PARTNER_STEVEN === ++Name: STEVEN ++Class: Rival ++Pic: Steven ++Gender: Male ++Music: Male ++ ++Metang ++Brave Nature ++Level: 42 ++IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe ++EVs: 252 Atk / 252 Def / 6 SpA ++- Light Screen ++- Psychic ++- Reflect ++- Metal Claw ++ ++Skarmory ++Impish Nature ++Level: 43 ++IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe ++EVs: 252 HP / 6 SpA / 252 SpD ++- Toxic ++- Aerial Ace ++- Protect ++- Steel Wing ++ ++Aggron ++Adamant Nature ++Level: 44 ++IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe ++EVs: 252 Atk / 252 SpA / 6 SpD ++- Thunder ++- Protect ++- Solar Beam ++- Dragon Claw +``` + +### Egg Move Refactor + +* Filepaths [`migration_scripts/1.9/egg_move_refactor.py`](1.9/egg_move_refactor.py) +* Introduced in [Egg Move Refactor #4534](https://github.com/rh-hideout/pokeemerald-expansion/pull/4534) + +Updates egg moves to the refactored format. Only necessary if new species have been added or if egg moves of an existing species was altered. + +#### [src/data/pokemon/egg_moves.h](..src/data/pokemon/egg_moves.h) +```diff +- egg_moves(BULBASAUR, +- MOVE_SKULL_BASH, +- MOVE_CHARM, +- MOVE_PETAL_DANCE, +- MOVE_MAGICAL_LEAF, +- MOVE_GRASS_WHISTLE, +- MOVE_CURSE, +- MOVE_INGRAIN, +- MOVE_NATURE_POWER, +- MOVE_AMNESIA, +- MOVE_LEAF_STORM, +- MOVE_POWER_WHIP, +- MOVE_SLUDGE, +- MOVE_ENDURE, +- MOVE_GIGA_DRAIN, +- MOVE_GRASSY_TERRAIN), ++static const u16 sBulbasaurEggMoveLearnset[] = { ++ MOVE_SKULL_BASH, ++ MOVE_CHARM, ++ MOVE_PETAL_DANCE, ++ MOVE_MAGICAL_LEAF, ++ MOVE_GRASS_WHISTLE, ++ MOVE_CURSE, ++ MOVE_INGRAIN, ++ MOVE_NATURE_POWER, ++ MOVE_AMNESIA, ++ MOVE_LEAF_STORM, ++ MOVE_POWER_WHIP, ++ MOVE_SLUDGE, ++ MOVE_ENDURE, ++ MOVE_GIGA_DRAIN, ++ MOVE_GRASSY_TERRAIN, ++ MOVE_UNAVAILABLE, +}; +``` + +#### [src/data/pokemon/species_info/gen_1_families.h](..src/data/pokemon/species_info/gen_1_families.h) +```diff + [SPECIES_BULBASAUR] = + { + .baseHP = 45, + .baseAttack = 49, + .baseDefense = 49, + .baseSpeed = 45, + .baseSpAttack = 65, + .baseSpDefense = 65, + .types = MON_TYPES(TYPE_GRASS, TYPE_POISON), + .catchRate = 45, + .expYield = 64, + .evYield_SpAttack = 1, + .genderRatio = PERCENT_FEMALE(12.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MONSTER, EGG_GROUP_GRASS), + .abilities = { ABILITY_OVERGROW, ABILITY_NONE, ABILITY_CHLOROPHYLL }, + .bodyColor = BODY_COLOR_GREEN, + .speciesName = _("Bulbasaur"), + .cryId = CRY_BULBASAUR, + .natDexNum = NATIONAL_DEX_BULBASAUR, + .categoryName = _("Seed"), + .height = 7, + .weight = 69, + .description = COMPOUND_STRING( + "Bulbasaur can be seen napping in bright\n" + "sunlight. There is a seed on its back.\n" + "By soaking up the sun's rays, the seed\n" + "grows progressively larger."), + .pokemonScale = 356, + .pokemonOffset = 17, + .trainerScale = 256, + .trainerOffset = 0, + .frontPic = gMonFrontPic_Bulbasaur, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 13, + .frontAnimFrames = sAnims_Bulbasaur, + .frontAnimId = ANIM_V_JUMPS_H_JUMPS, + .backPic = gMonBackPic_Bulbasaur, + .backPicSize = MON_COORDS_SIZE(56, 40), + .backPicYOffset = 13, + .backAnimId = BACK_ANIM_DIP_RIGHT_SIDE, + .palette = gMonPalette_Bulbasaur, + .shinyPalette = gMonShinyPalette_Bulbasaur, + .iconSprite = gMonIcon_Bulbasaur, + .iconPalIndex = 4, + FOOTPRINT(Bulbasaur) + .levelUpLearnset = sBulbasaurLevelUpLearnset, + .teachableLearnset = sBulbasaurTeachableLearnset, ++ .eggMoveLearnset = sBulbasaurEggMoveLearnset, + .evolutions = EVOLUTION({EVO_LEVEL, 16, SPECIES_IVYSAUR}), + }, +``` + +## 1.7.x to 1.8.x+ + ### Item Balls -* Filepath [`migration_scripts/item_ball_refactor.py`](item_ball_refactor.py) +* Filepath [`migration_scripts/1.8/item_ball_refactor.py`](1.8/item_ball_refactor.py) * Introduced in [Item Ball refactor / Pluralize item names for giveitem and finditem #3942](https://github.com/rh-hideout/pokeemerald-expansion/pull/3942) Modifies all item ball scripts defined using to original Game Freak method to the new refactored method. diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 10ad41d1fcc0..d75964a5ce56 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -190,14 +190,12 @@ void BattleAI_SetupFlags(void) else AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI -#if DEBUG_OVERWORLD_MENU == TRUE - if (gIsDebugBattle) + if (DEBUG_OVERWORLD_MENU && gIsDebugBattle) { AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags; AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags; return; } -#endif if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))) { @@ -570,7 +568,7 @@ static bool32 AI_ShouldSwitchIfBadMoves(u32 battler, bool32 doubleBattle) // Consider switching if your mon with truant is bodied by Protect spam. // Or is using a double turn semi invulnerable move(such as Fly) and is faster. - if (GetBattlerAbility(battler) == ABILITY_TRUANT + if (AI_DATA->abilities[battler] == ABILITY_TRUANT && IsTruantMonVulnerable(battler, gBattlerTarget) && gDisableStructs[battler].truantCounter && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2 diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 77552ccae980..63690220561a 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -73,7 +73,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult) //Variable initialization u8 opposingPosition, atkType1, atkType2, defType1, defType2, effectiveness; s32 i, damageDealt = 0, maxDamageDealt = 0, damageTaken = 0, maxDamageTaken = 0; - u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = GetBattlerAbility(battler), opposingBattler, weather = AI_GetWeather(AI_DATA); + u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = AI_DATA->abilities[battler], opposingBattler, weather = AI_GetWeather(AI_DATA); bool32 getsOneShot = FALSE, hasStatusMove = FALSE, hasSuperEffectiveMove = FALSE; u16 typeEffectiveness = UQ_4_12(1.0), aiMoveEffect; //baseline typing damage @@ -247,7 +247,7 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler, bool32 emitResult) opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); - if (GetBattlerAbility(GetBattlerAtPosition(opposingPosition)) != ABILITY_WONDER_GUARD) + if (AI_DATA->abilities[GetBattlerAtPosition(opposingPosition)] != ABILITY_WONDER_GUARD) return FALSE; // Check if Pokémon has a super effective move. @@ -837,7 +837,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler) { u32 battlerIn1, battlerIn2; u32 hazardDamage = 0, battlerHp = gBattleMons[battler].hp; - u32 ability = GetBattlerAbility(battler), aiMove; + u32 ability = AI_DATA->abilities[battler], aiMove; s32 firstId, lastId, i, j; struct Pokemon *party; @@ -1742,7 +1742,7 @@ static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent) return FALSE; else if (ability == ABILITY_SHADOW_TAG) { - if (B_SHADOW_TAG_ESCAPE >= GEN_4 && GetBattlerAbility(opponent) == ABILITY_SHADOW_TAG) // Check if ability exists in species + if (B_SHADOW_TAG_ESCAPE >= GEN_4 && AI_DATA->abilities[opponent] == ABILITY_SHADOW_TAG) // Check if ability exists in species return FALSE; else return TRUE; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 7efee7ae05f5..162649d4b103 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -33,6 +33,7 @@ return FALSE static u32 AI_GetEffectiveness(uq4_12_t multiplier); +u32 AI_GetBattlerAbility(u32); // Functions bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move) @@ -413,7 +414,7 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef) // Battler doesn't see partners Ability for some reason. // This is a small hack to avoid the issue but should be investigated if (battlerDef == BATTLE_PARTNER(battlerAtk)) - battlerDefAbility = GetBattlerAbility(battlerDef); + battlerDefAbility = AI_GetBattlerAbility(battlerDef); switch (battlerDefAbility) { @@ -499,6 +500,7 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes bool32 toggledDynamax = FALSE; bool32 toggledTera = FALSE; struct AiLogicData *aiData = AI_DATA; + gBattleStruct->aiCalcInProgress = TRUE; // Temporarily enable Z-Moves for damage calcs if (considerZPower && IsViableZMove(battlerAtk, move)) @@ -649,6 +651,7 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes // convert multiper to AI_EFFECTIVENESS_xX *typeEffectiveness = AI_GetEffectiveness(effectivenessMultiplier); + gBattleStruct->aiCalcInProgress = FALSE; gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->zmove.active = FALSE; gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE; @@ -2954,18 +2957,41 @@ bool32 IsWakeupTurn(u32 battler) bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof) { struct Pokemon *party; - u32 i; + u32 i, battlerOnField1, battlerOnField2; if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) party = gPlayerParty; else party = gEnemyParty; + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + battlerOnField1 = gBattlerPartyIndexes[battlerId]; + battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))]; + // Check partner's status + if ((B_HEAL_BELL_SOUNDPROOF == GEN_5 || AI_DATA->abilities[BATTLE_PARTNER(battlerId)] != ABILITY_SOUNDPROOF || !checkSoundproof) + && GetMonData(&party[battlerOnField2], MON_DATA_STATUS) != STATUS1_NONE) + return TRUE; + } + else // In singles there's only one battlerId by side. + { + battlerOnField1 = gBattlerPartyIndexes[battlerId]; + battlerOnField2 = gBattlerPartyIndexes[battlerId]; + } + + // Check attacker's status + if ((B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_9 + || AI_DATA->abilities[battlerId] != ABILITY_SOUNDPROOF || !checkSoundproof) + && GetMonData(&party[battlerOnField1], MON_DATA_STATUS) != STATUS1_NONE) + return TRUE; + + // Check inactive party mons' status for (i = 0; i < PARTY_SIZE; i++) { - if (checkSoundproof && GetMonAbility(&party[i]) == ABILITY_SOUNDPROOF) + if (i == battlerOnField1 || i == battlerOnField2) + continue; + if (B_HEAL_BELL_SOUNDPROOF < GEN_5 && checkSoundproof && GetMonAbility(&party[i]) == ABILITY_SOUNDPROOF) continue; - if (GetMonData(&party[i], MON_DATA_STATUS) != STATUS1_NONE) return TRUE; } @@ -3219,7 +3245,7 @@ bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move) u32 i; s32 firstId, lastId; struct Pokemon* party; - bool32 hasStatus = FALSE; + bool32 hasStatus = AnyPartyMemberStatused(battlerAtk, gMovesInfo[move].soundMove); bool32 needHealing = FALSE; GetAIPartyIndexes(battlerAtk, &firstId, &lastId); @@ -3245,12 +3271,6 @@ bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move) { needHealing = TRUE; } - - if (GetMonData(&party[i], MON_DATA_STATUS, NULL) != STATUS1_NONE) - { - if (move != MOVE_HEAL_BELL || GetMonAbility(&party[i]) != ABILITY_SOUNDPROOF) - hasStatus = TRUE; - } } } diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 5bf12e2cc70e..4315c692695b 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -413,13 +413,11 @@ static void HandleInputChooseAction(u32 battler) { SwapHpBarsWithHpText(); } -#if DEBUG_BATTLE_MENU == TRUE - else if (JOY_NEW(SELECT_BUTTON)) + else if (DEBUG_BATTLE_MENU && JOY_NEW(SELECT_BUTTON)) { BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_DEBUG, 0); PlayerBufferExecCompleted(battler); } -#endif #if B_LAST_USED_BALL == TRUE && B_LAST_USED_BALL_CYCLE == FALSE else if (JOY_NEW(B_LAST_USED_BALL_BUTTON) && CanThrowLastUsedBall()) { diff --git a/src/battle_main.c b/src/battle_main.c index 8c2d5b7de7f2..abadc81f424c 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -515,9 +515,7 @@ static void CB2_InitBattleInternal(void) gBattle_BG3_X = 0; gBattle_BG3_Y = 0; -#if DEBUG_OVERWORLD_MENU == TRUE - if (!gIsDebugBattle) -#endif + if (!DEBUG_OVERWORLD_MENU || (DEBUG_OVERWORLD_MENU && !gIsDebugBattle)) { gBattleTerrain = BattleSetup_GetTerrainId(); } @@ -550,9 +548,7 @@ static void CB2_InitBattleInternal(void) else SetMainCallback2(CB2_HandleStartBattle); -#if DEBUG_OVERWORLD_MENU == TRUE - if (!gIsDebugBattle) -#endif + if (!DEBUG_OVERWORLD_MENU || (DEBUG_OVERWORLD_MENU && !gIsDebugBattle)) { if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED))) { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 40038aa951fc..ceb42205238c 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -13168,7 +13168,7 @@ static void Cmd_healpartystatus(void) CMD_ARGS(); u32 zero = 0; - u32 battler; + u32 partner = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); u8 toHeal = 0; if (gCurrentMove == MOVE_HEAL_BELL) @@ -13178,7 +13178,8 @@ static void Cmd_healpartystatus(void) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_BELL; - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF) + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF + || B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_9) { gBattleMons[gBattlerAttacker].status1 = 0; gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; @@ -13189,19 +13190,18 @@ static void Cmd_healpartystatus(void) gBattleCommunication[MULTISTRING_CHOOSER] |= B_MSG_BELL_SOUNDPROOF_ATTACKER; } - battler = gBattleScripting.battler = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); + gBattleScripting.battler = partner; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && !(gAbsentBattlerFlags & gBitTable[battler])) + if (IsBattlerAlive(partner)) { - if (GetBattlerAbility(battler) != ABILITY_SOUNDPROOF) + if (GetBattlerAbility(partner) != ABILITY_SOUNDPROOF || B_HEAL_BELL_SOUNDPROOF == GEN_5) { - gBattleMons[battler].status1 = 0; - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[partner].status1 = 0; + gBattleMons[partner].status2 &= ~STATUS2_NIGHTMARE; } else { - RecordAbilityBattle(battler, gBattleMons[battler].ability); + RecordAbilityBattle(partner, gBattleMons[partner].ability); gBattleCommunication[MULTISTRING_CHOOSER] |= B_MSG_BELL_SOUNDPROOF_PARTNER; } } @@ -13216,13 +13216,17 @@ static void Cmd_healpartystatus(void) if (species != SPECIES_NONE && species != SPECIES_EGG) { u16 ability; - - if (gBattlerPartyIndexes[gBattlerAttacker] == i) + bool32 isAttacker = gBattlerPartyIndexes[gBattlerAttacker] == i; + bool32 isDoublesPartner = gBattlerPartyIndexes[partner] == i && IsBattlerAlive(partner); + + if (B_HEAL_BELL_SOUNDPROOF == GEN_5 || (isAttacker && B_HEAL_BELL_SOUNDPROOF >= GEN_9)) + ability = ABILITY_NONE; + else if (B_HEAL_BELL_SOUNDPROOF > GEN_5 && !isAttacker && !isDoublesPartner) + ability = ABILITY_NONE; + else if (isAttacker) ability = GetBattlerAbility(gBattlerAttacker); - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && gBattlerPartyIndexes[battler] == i - && !(gAbsentBattlerFlags & gBitTable[battler])) - ability = GetBattlerAbility(battler); + else if (isDoublesPartner) + ability = GetBattlerAbility(partner); else ability = GetAbilityBySpecies(species, abilityNum); @@ -13239,12 +13243,11 @@ static void Cmd_healpartystatus(void) gBattleMons[gBattlerAttacker].status1 = 0; gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; - battler = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && !(gAbsentBattlerFlags & gBitTable[battler])) + && !(gAbsentBattlerFlags & gBitTable[partner])) { - gBattleMons[battler].status1 = 0; - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[partner].status1 = 0; + gBattleMons[partner].status2 &= ~STATUS2_NIGHTMARE; } } diff --git a/src/battle_setup.c b/src/battle_setup.c index 92fc2bea250c..e92b32d4c98f 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -254,6 +254,23 @@ static const struct TrainerBattleParameter sTrainerBContinueScriptBattleParams[] {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, }; +// two trainers, each with a defeat speech +static const struct TrainerBattleParameter sTrainerTwoTrainerBattleParams[] = +{ + {&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT}, + {&sTrainerObjectEventLocalId, TRAINER_PARAM_CLEAR_VAL_16BIT}, + {&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerAIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT}, + {&sTrainerBIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT}, + {&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT}, + {&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR}, +}; + #define REMATCH(trainer1, trainer2, trainer3, trainer4, trainer5, map) \ { \ .trainerIds = {trainer1, trainer2, trainer3, trainer4, trainer5}, \ @@ -1230,6 +1247,11 @@ const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data) gTrainerBattleOpponent_B = LocalIdToHillTrainerId(gSpecialVar_LastTalked); } return EventScript_TryDoNormalTrainerBattle; + case TRAINER_BATTLE_TWO_TRAINERS_NO_INTRO: + gNoOfApproachingTrainers = 2; // set TWO_OPPONENTS gBattleTypeFlags + gApproachingTrainerId = 1; // prevent trainer approach + TrainerBattleLoadArgs(sTrainerTwoTrainerBattleParams, data); + return EventScript_DoNoIntroTrainerBattle; default: if (gApproachingTrainerId == 0) { diff --git a/src/battle_util.c b/src/battle_util.c index 6b5e489691ab..5d40b4508bf1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1001,11 +1001,20 @@ void MarkBattlerReceivedLinkData(u32 battler) const u8* CancelMultiTurnMoves(u32 battler) { const u8 *result = NULL; - gBattleMons[battler].status2 &= ~(STATUS2_MULTIPLETURNS); - gBattleMons[battler].status2 &= ~(STATUS2_LOCK_CONFUSE); gBattleMons[battler].status2 &= ~(STATUS2_UPROAR); gBattleMons[battler].status2 &= ~(STATUS2_BIDE); + if (B_RAMPAGE_CANCELLING < GEN_5) + { + gBattleMons[battler].status2 &= ~(STATUS2_MULTIPLETURNS); + gBattleMons[battler].status2 &= ~(STATUS2_LOCK_CONFUSE); + } + else if (!(gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE) + || ((gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE) > STATUS2_LOCK_CONFUSE_TURN(1))) + { + gBattleMons[battler].status2 &= ~(STATUS2_MULTIPLETURNS); + } + // Clear battler's semi-invulnerable bits if they are not held by Sky Drop. if (!(gStatuses3[battler] & STATUS3_SKY_DROPPED)) gStatuses3[battler] &= ~(STATUS3_SEMI_INVULNERABLE); @@ -5352,9 +5361,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS && IsMoveMakingContact(move, gBattlerAttacker) && gBattleStruct->overwrittenAbilities[gBattlerAttacker] != GetBattlerAbility(gBattlerTarget) - && gBattleMons[gBattlerTarget].ability != ABILITY_MUMMY - && gBattleMons[gBattlerTarget].ability != ABILITY_LINGERING_AROMA - && !gAbilitiesInfo[gBattleMons[gBattlerTarget].ability].cantBeSuppressed) + && gBattleMons[gBattlerAttacker].ability != ABILITY_MUMMY + && gBattleMons[gBattlerAttacker].ability != ABILITY_LINGERING_AROMA + && !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSuppressed) { if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) { @@ -10163,7 +10172,7 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move mod = UQ_4_12(1.0); } - if (gBattleStruct->distortedTypeMatchups & gBitTable[battlerDef]) + if (gBattleStruct->distortedTypeMatchups & gBitTable[battlerDef] || (gBattleStruct->aiCalcInProgress && ShouldTeraShellDistortTypeMatchups(move, battlerDef))) { mod = UQ_4_12(0.5); if (recordAbilities) diff --git a/src/data/map_group_count.h b/src/data/map_group_count.h deleted file mode 100644 index 4fe8a21b3b91..000000000000 --- a/src/data/map_group_count.h +++ /dev/null @@ -1 +0,0 @@ -static const u8 MAP_GROUP_COUNT[] = {57, 5, 5, 6, 7, 8, 9, 7, 7, 14, 8, 17, 10, 23, 13, 15, 15, 2, 2, 2, 3, 1, 1, 1, 108, 61, 89, 2, 1, 13, 1, 1, 3, 1, 0}; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 2a4846955df7..a1fd2f18f825 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -5477,7 +5477,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .type = TYPE_NORMAL, .accuracy = 0, .pp = 5, - .target = MOVE_TARGET_USER | MOVE_TARGET_ALLY, + .target = MOVE_TARGET_USER, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_RECOVER_HP }, @@ -7912,7 +7912,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .type = TYPE_GRASS, .accuracy = 0, .pp = 5, - .target = MOVE_TARGET_USER | MOVE_TARGET_ALLY, + .target = MOVE_TARGET_USER, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_RECOVER_HP }, diff --git a/src/debug.c b/src/debug.c index 049e2f0ed865..06e47e466bad 100644 --- a/src/debug.c +++ b/src/debug.c @@ -68,7 +68,6 @@ #include "constants/weather.h" #include "save.h" -#if DEBUG_OVERWORLD_MENU == TRUE // ******************************* enum DebugMenu { @@ -5112,5 +5111,3 @@ static void DebugAction_Party_ClearParty(u8 taskId) ScriptContext_Enable(); Debug_DestroyMenu_Full(taskId); } - -#endif //DEBUG_OVERWORLD_MENU == TRUE diff --git a/src/decompress.c b/src/decompress.c index 4c34ea2cffa7..30337f5a8dc3 100644 --- a/src/decompress.c +++ b/src/decompress.c @@ -3,7 +3,7 @@ #include "data.h" #include "decompress.h" #include "pokemon.h" -#include "pokemon_debug.h" +#include "pokemon_sprite_visualizer.h" #include "text.h" EWRAM_DATA ALIGNED(4) u8 gDecompressionBuffer[0x4000] = {0}; diff --git a/src/field_control_avatar.c b/src/field_control_avatar.c index d5c252415df9..11757d175611 100644 --- a/src/field_control_avatar.c +++ b/src/field_control_avatar.c @@ -134,13 +134,14 @@ void FieldGetPlayerInput(struct FieldInput *input, u16 newKeys, u16 heldKeys) else if (heldKeys & DPAD_RIGHT) input->dpadDirection = DIR_EAST; -#if DEBUG_OVERWORLD_MENU == TRUE && DEBUG_OVERWORLD_IN_MENU == FALSE - if ((heldKeys & DEBUG_OVERWORLD_HELD_KEYS) && input->DEBUG_OVERWORLD_TRIGGER_EVENT) + if(DEBUG_OVERWORLD_MENU && !DEBUG_OVERWORLD_IN_MENU) { - input->input_field_1_2 = TRUE; - input->DEBUG_OVERWORLD_TRIGGER_EVENT = FALSE; + if ((heldKeys & DEBUG_OVERWORLD_HELD_KEYS) && input->DEBUG_OVERWORLD_TRIGGER_EVENT) + { + input->input_field_1_2 = TRUE; + input->DEBUG_OVERWORLD_TRIGGER_EVENT = FALSE; + } } -#endif } int ProcessPlayerFieldInput(struct FieldInput *input) @@ -200,15 +201,13 @@ int ProcessPlayerFieldInput(struct FieldInput *input) if (input->pressedSelectButton && UseRegisteredKeyItemOnField() == TRUE) return TRUE; -#if DEBUG_OVERWORLD_MENU == TRUE && DEBUG_OVERWORLD_IN_MENU == FALSE - if (input->input_field_1_2) + if(input->input_field_1_2 && DEBUG_OVERWORLD_MENU && !DEBUG_OVERWORLD_IN_MENU) { PlaySE(SE_WIN_OPEN); FreezeObjectEvents(); Debug_ShowMainMenu(); return TRUE; } -#endif return FALSE; } diff --git a/src/field_weather.c b/src/field_weather.c index fea1e30358a0..3c9f642faf02 100644 --- a/src/field_weather.c +++ b/src/field_weather.c @@ -1105,3 +1105,11 @@ void ResetPreservedPalettesInWeather(void) { sPaletteColorMapTypes = sBasePaletteColorMapTypes; } + +bool32 IsWeatherAlphaBlend(void) +{ + return (gWeatherPtr->currWeather == WEATHER_FOG_HORIZONTAL + || gWeatherPtr->currWeather == WEATHER_FOG_DIAGONAL + || gWeatherPtr->currWeather == WEATHER_UNDERWATER_BUBBLES + || gWeatherPtr->currWeather == WEATHER_UNDERWATER); +} diff --git a/src/librfu_rfu.c b/src/librfu_rfu.c index 152bb716e92a..cd7cb6cc5a35 100644 --- a/src/librfu_rfu.c +++ b/src/librfu_rfu.c @@ -762,7 +762,7 @@ static void rfu_CB_pollConnectParent(u8 reqCommand, u16 reqResult) u16 id; u8 slot; u8 bm_slot_flag, i; - struct RfuTgtData *target_p; + struct RfuTgtData *target_p = NULL; struct RfuTgtData target_local; if (reqResult == 0) diff --git a/src/map_name_popup.c b/src/map_name_popup.c index 725bb80838e4..4da57a26ee68 100644 --- a/src/map_name_popup.c +++ b/src/map_name_popup.c @@ -2,12 +2,16 @@ #include "battle_pyramid.h" #include "bg.h" #include "event_data.h" +#include "field_weather.h" #include "gpu_regs.h" +#include "graphics.h" #include "international_string_util.h" +#include "main.h" #include "menu.h" #include "map_name_popup.h" #include "palette.h" #include "region_map.h" +#include "rtc.h" #include "start_menu.h" #include "string_util.h" #include "task.h" @@ -16,6 +20,8 @@ #include "constants/layouts.h" #include "constants/region_map_sections.h" #include "constants/weather.h" +#include "config/overworld.h" +#include "config.h" // enums enum MapPopUp_Themes @@ -28,13 +34,18 @@ enum MapPopUp_Themes MAPPOPUP_THEME_STONE2, }; +enum MapPopUp_Themes_BW +{ + MAPPOPUP_THEME_BW_DEFAULT, +}; + // static functions static void Task_MapNamePopUpWindow(u8 taskId); static void ShowMapNamePopUpWindow(void); static void LoadMapNamePopUpWindowBg(void); // EWRAM -static EWRAM_DATA u8 sPopupTaskId = 0; +EWRAM_DATA u8 gPopupTaskId = 0; // .rodata static const u8 sMapPopUp_Table[][960] = @@ -177,6 +188,127 @@ static const u8 sRegionMapSectionId_To_PopUpThemeIdMapping[] = [MAPSEC_TRAINER_HILL - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_MARBLE }; +#if OW_POPUP_GENERATION == GEN_5 +// Gen5 assets +static const u8 sMapPopUpTilesPrimary_BW[] = INCBIN_U8("graphics/map_popup/bw/bw_primary.4bpp"); +static const u8 sMapPopUpTilesSecondary_BW[] = INCBIN_U8("graphics/map_popup/bw/bw_secondary.4bpp"); +static const u16 sMapPopUpTilesPalette_BW_Black[16] = INCBIN_U16("graphics/map_popup/bw/black.gbapal"); +static const u16 sMapPopUpTilesPalette_BW_White[16] = INCBIN_U16("graphics/map_popup/bw/white.gbapal"); +#else +static const u8 sMapPopUpTilesPrimary_BW[] = {0}; +static const u8 sMapPopUpTilesSecondary_BW[] = {0}; +static const u16 sMapPopUpTilesPalette_BW_Black[] = {0}; +static const u16 sMapPopUpTilesPalette_BW_White[] = {0}; +#endif + +static const u8 sRegionMapSectionId_To_PopUpThemeIdMapping_BW[] = +{ + [MAPSEC_LITTLEROOT_TOWN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_OLDALE_TOWN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_DEWFORD_TOWN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_LAVARIDGE_TOWN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_FALLARBOR_TOWN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_VERDANTURF_TOWN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_PACIFIDLOG_TOWN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_PETALBURG_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SLATEPORT_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MAUVILLE_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_RUSTBORO_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_FORTREE_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_LILYCOVE_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MOSSDEEP_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SOOTOPOLIS_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_EVER_GRANDE_CITY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_101] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_102] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_103] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_104] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_105] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_106] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_107] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_108] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_109] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_110] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_111] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_112] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_113] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_114] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_115] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_116] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_117] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_118] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_119] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_120] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_121] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_122] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_123] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_124] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_125] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_126] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_127] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_128] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_129] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_130] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_131] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_132] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_133] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ROUTE_134] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_124] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_126] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_127] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_128] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_SOOTOPOLIS] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_GRANITE_CAVE] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MT_CHIMNEY] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SAFARI_ZONE] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_BATTLE_FRONTIER] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_PETALBURG_WOODS] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_RUSTURF_TUNNEL] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ABANDONED_SHIP] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_NEW_MAUVILLE] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_METEOR_FALLS] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_METEOR_FALLS2] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MT_PYRE] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_AQUA_HIDEOUT_OLD] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SHOAL_CAVE] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SEAFLOOR_CAVERN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_SEAFLOOR_CAVERN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_VICTORY_ROAD] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MIRAGE_ISLAND] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_CAVE_OF_ORIGIN] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SOUTHERN_ISLAND] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_FIERY_PATH] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_FIERY_PATH2] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_JAGGED_PASS] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_JAGGED_PASS2] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SEALED_CHAMBER] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_SEALED_CHAMBER] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SCORCHED_SLAB] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ISLAND_CAVE] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_DESERT_RUINS] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ANCIENT_TOMB] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_INSIDE_OF_TRUCK] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SKY_PILLAR] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_SECRET_BASE] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_DYNAMIC] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_AQUA_HIDEOUT - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MAGMA_HIDEOUT - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MIRAGE_TOWER - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_BIRTH_ISLAND - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_FARAWAY_ISLAND - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ARTISAN_CAVE - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_MARINE_CAVE - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_MARINE_CAVE - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_TERRA_CAVE - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_105 - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_125 - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_UNDERWATER_129 - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_DESERT_UNDERPASS - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_ALTERING_CAVE - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_NAVEL_ROCK - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, + [MAPSEC_TRAINER_HILL - KANTO_MAPSEC_COUNT] = MAPPOPUP_THEME_BW_DEFAULT, +}; + static const u8 sText_PyramidFloor1[] = _("PYRAMID FLOOR 1"); static const u8 sText_PyramidFloor2[] = _("PYRAMID FLOOR 2"); static const u8 sText_PyramidFloor3[] = _("PYRAMID FLOOR 3"); @@ -216,7 +348,7 @@ enum { STATE_PRINT, // For some reason the first state is numerically last. }; -#define POPUP_OFFSCREEN_Y 40 +#define POPUP_OFFSCREEN_Y ((OW_POPUP_GENERATION == GEN_5) ? 24 : 40) #define POPUP_SLIDE_SPEED 2 #define tState data[0] @@ -232,18 +364,29 @@ void ShowMapNamePopup(void) if (!FuncIsActiveTask(Task_MapNamePopUpWindow)) { // New pop up window - sPopupTaskId = CreateTask(Task_MapNamePopUpWindow, 90); - SetGpuReg(REG_OFFSET_BG0VOFS, POPUP_OFFSCREEN_Y); - gTasks[sPopupTaskId].tState = STATE_PRINT; - gTasks[sPopupTaskId].tYOffset = POPUP_OFFSCREEN_Y; + if (OW_POPUP_GENERATION == GEN_5) + { + gPopupTaskId = CreateTask(Task_MapNamePopUpWindow, 100); + + if (OW_POPUP_BW_ALPHA_BLEND && !IsWeatherAlphaBlend()) + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_TGT2_ALL | BLDCNT_EFFECT_BLEND); + } + else + { + gPopupTaskId = CreateTask(Task_MapNamePopUpWindow, 90); + SetGpuReg(REG_OFFSET_BG0VOFS, POPUP_OFFSCREEN_Y); + } + + gTasks[gPopupTaskId].tState = STATE_PRINT; + gTasks[gPopupTaskId].tYOffset = POPUP_OFFSCREEN_Y; } else { // There's already a pop up window running. // Hurry the old pop up offscreen so the new one can appear. - if (gTasks[sPopupTaskId].tState != STATE_SLIDE_OUT) - gTasks[sPopupTaskId].tState = STATE_SLIDE_OUT; - gTasks[sPopupTaskId].tIncomingPopUp = TRUE; + if (gTasks[gPopupTaskId].tState != STATE_SLIDE_OUT) + gTasks[gPopupTaskId].tState = STATE_SLIDE_OUT; + gTasks[gPopupTaskId].tIncomingPopUp = TRUE; } } } @@ -261,6 +404,11 @@ static void Task_MapNamePopUpWindow(u8 taskId) task->tState = STATE_SLIDE_IN; task->tPrintTimer = 0; ShowMapNamePopUpWindow(); + if (OW_POPUP_GENERATION == GEN_5) + { + EnableInterrupts(INTR_FLAG_HBLANK); + SetHBlankCallback(HBlankCB_DoublePopupWindow); + } } break; case STATE_SLIDE_IN: @@ -270,7 +418,7 @@ static void Task_MapNamePopUpWindow(u8 taskId) { task->tYOffset = 0; task->tState = STATE_WAIT; - gTasks[sPopupTaskId].data[1] = 0; + gTasks[gPopupTaskId].tOnscreenTimer = 0; } break; case STATE_WAIT: @@ -304,13 +452,16 @@ static void Task_MapNamePopUpWindow(u8 taskId) break; case STATE_ERASE: ClearStdWindowAndFrame(GetMapNamePopUpWindowId(), TRUE); + if (OW_POPUP_GENERATION == GEN_5) + ClearStdWindowAndFrame(GetSecondaryPopUpWindowId(), TRUE); task->tState = STATE_END; break; case STATE_END: HideMapNamePopUpWindow(); return; } - SetGpuReg(REG_OFFSET_BG0VOFS, task->tYOffset); + if (OW_POPUP_GENERATION != GEN_5) + SetGpuReg(REG_OFFSET_BG0VOFS, task->tYOffset); } void HideMapNamePopUpWindow(void) @@ -324,8 +475,28 @@ void HideMapNamePopUpWindow(void) ClearStdWindowAndFrame(GetMapNamePopUpWindowId(), TRUE); RemoveMapNamePopUpWindow(); } + + if (OW_POPUP_GENERATION == GEN_5) + { + if (GetSecondaryPopUpWindowId() != WINDOW_NONE) + { + ClearStdWindowAndFrame(GetSecondaryPopUpWindowId(), TRUE); + RemoveSecondaryPopUpWindow(); + } + + DisableInterrupts(INTR_FLAG_HBLANK); + SetHBlankCallback(NULL); + + if (OW_POPUP_BW_ALPHA_BLEND && !IsWeatherAlphaBlend()) + { + SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ); + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_BG1 | BLDCNT_TGT2_BG2 | BLDCNT_TGT2_BG3 | BLDCNT_TGT2_OBJ | BLDCNT_EFFECT_BLEND); + SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(8, 10)); + } + } + SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, 0); - DestroyTask(sPopupTaskId); + DestroyTask(gPopupTaskId); } } @@ -335,6 +506,7 @@ static void ShowMapNamePopUpWindow(void) u8 *withoutPrefixPtr; u8 x; const u8 *mapDisplayHeaderSource; + u8 mapNamePopUpWindowId, secondaryPopUpWindowId; if (InBattlePyramid()) { @@ -355,14 +527,46 @@ static void ShowMapNamePopUpWindow(void) withoutPrefixPtr = &(mapDisplayHeader[3]); GetMapName(withoutPrefixPtr, gMapHeader.regionMapSectionId, 0); } - AddMapNamePopUpWindow(); + + if (OW_POPUP_GENERATION == GEN_5) + { + if (OW_POPUP_BW_ALPHA_BLEND && !IsWeatherAlphaBlend()) + SetGpuRegBits(REG_OFFSET_WININ, WININ_WIN0_CLR); + + mapNamePopUpWindowId = AddMapNamePopUpWindow(); + secondaryPopUpWindowId = AddSecondaryPopUpWindow(); + } + else + { + AddMapNamePopUpWindow(); + } + LoadMapNamePopUpWindowBg(); - x = GetStringCenterAlignXOffset(FONT_NARROW, withoutPrefixPtr, 80); + mapDisplayHeader[0] = EXT_CTRL_CODE_BEGIN; mapDisplayHeader[1] = EXT_CTRL_CODE_HIGHLIGHT; mapDisplayHeader[2] = TEXT_COLOR_TRANSPARENT; - AddTextPrinterParameterized(GetMapNamePopUpWindowId(), FONT_NARROW, mapDisplayHeader, x, 3, TEXT_SKIP_DRAW, NULL); - CopyWindowToVram(GetMapNamePopUpWindowId(), COPYWIN_FULL); + + if (OW_POPUP_GENERATION == GEN_5) + { + AddTextPrinterParameterized(mapNamePopUpWindowId, FONT_SHORT, mapDisplayHeader, 8, 2, TEXT_SKIP_DRAW, NULL); + + if (OW_POPUP_BW_TIME_MODE != OW_POPUP_BW_TIME_NONE) + { + RtcCalcLocalTime(); + FormatDecimalTimeWithoutSeconds(withoutPrefixPtr, gLocalTime.hours, gLocalTime.minutes, OW_POPUP_BW_TIME_MODE == OW_POPUP_BW_TIME_24_HR); + AddTextPrinterParameterized(secondaryPopUpWindowId, FONT_SMALL, mapDisplayHeader, GetStringRightAlignXOffset(FONT_SMALL, mapDisplayHeader, DISPLAY_WIDTH) - 5, 8, TEXT_SKIP_DRAW, NULL); + } + + CopyWindowToVram(mapNamePopUpWindowId, COPYWIN_FULL); + CopyWindowToVram(secondaryPopUpWindowId, COPYWIN_FULL); + } + else + { + x = GetStringCenterAlignXOffset(FONT_NARROW, withoutPrefixPtr, 80); + AddTextPrinterParameterized(GetMapNamePopUpWindowId(), FONT_NARROW, mapDisplayHeader, x, 3, TEXT_SKIP_DRAW, NULL); + CopyWindowToVram(GetMapNamePopUpWindowId(), COPYWIN_FULL); + } } #define TILE_TOP_EDGE_START 0x21D @@ -402,6 +606,10 @@ static void LoadMapNamePopUpWindowBg(void) u8 popUpThemeId; u8 popupWindowId = GetMapNamePopUpWindowId(); u16 regionMapSectionId = gMapHeader.regionMapSectionId; + u8 secondaryPopUpWindowId; + + if (OW_POPUP_GENERATION == GEN_5) + secondaryPopUpWindowId = GetSecondaryPopUpWindowId(); if (regionMapSectionId >= KANTO_MAPSEC_START) { @@ -410,14 +618,37 @@ static void LoadMapNamePopUpWindowBg(void) else regionMapSectionId = 0; // Discard kanto region sections; } - popUpThemeId = sRegionMapSectionId_To_PopUpThemeIdMapping[regionMapSectionId]; - LoadBgTiles(GetWindowAttribute(popupWindowId, WINDOW_BG), sMapPopUp_OutlineTable[popUpThemeId], 0x400, 0x21D); - CallWindowFunction(popupWindowId, DrawMapNamePopUpFrame); - PutWindowTilemap(popupWindowId); - if (gMapHeader.weather == WEATHER_UNDERWATER_BUBBLES) - LoadPalette(&sMapPopUp_Palette_Underwater, BG_PLTT_ID(14), sizeof(sMapPopUp_Palette_Underwater)); + if (OW_POPUP_GENERATION == GEN_5) + { + popUpThemeId = sRegionMapSectionId_To_PopUpThemeIdMapping_BW[regionMapSectionId]; + switch (popUpThemeId) + { + // add additional gen 5-style pop-up themes as cases here + case MAPPOPUP_THEME_BW_DEFAULT: + if (OW_POPUP_BW_COLOR == OW_POPUP_BW_COLOR_WHITE) + LoadPalette(sMapPopUpTilesPalette_BW_White, BG_PLTT_ID(14), sizeof(sMapPopUpTilesPalette_BW_White)); + else + LoadPalette(sMapPopUpTilesPalette_BW_Black, BG_PLTT_ID(14), sizeof(sMapPopUpTilesPalette_BW_Black)); + + CopyToWindowPixelBuffer(popupWindowId, sMapPopUpTilesPrimary_BW, sizeof(sMapPopUpTilesPrimary_BW), 0); + CopyToWindowPixelBuffer(secondaryPopUpWindowId, sMapPopUpTilesSecondary_BW, sizeof(sMapPopUpTilesSecondary_BW), 0); + break; + } + + PutWindowTilemap(popupWindowId); + PutWindowTilemap(secondaryPopUpWindowId); + } else - LoadPalette(sMapPopUp_PaletteTable[popUpThemeId], BG_PLTT_ID(14), sizeof(sMapPopUp_PaletteTable[0])); - BlitBitmapToWindow(popupWindowId, sMapPopUp_Table[popUpThemeId], 0, 0, 80, 24); + { + popUpThemeId = sRegionMapSectionId_To_PopUpThemeIdMapping[regionMapSectionId]; + LoadBgTiles(GetWindowAttribute(popupWindowId, WINDOW_BG), sMapPopUp_OutlineTable[popUpThemeId], 0x400, 0x21D); + CallWindowFunction(popupWindowId, DrawMapNamePopUpFrame); + PutWindowTilemap(popupWindowId); + if (gMapHeader.weather == WEATHER_UNDERWATER_BUBBLES) + LoadPalette(&sMapPopUp_Palette_Underwater, BG_PLTT_ID(14), sizeof(sMapPopUp_Palette_Underwater)); + else + LoadPalette(sMapPopUp_PaletteTable[popUpThemeId], BG_PLTT_ID(14), sizeof(sMapPopUp_PaletteTable[0])); + BlitBitmapToWindow(popupWindowId, sMapPopUp_Table[popUpThemeId], 0, 0, 80, 24); + } } diff --git a/src/menu.c b/src/menu.c index 1952ec5ed49a..ff1970c3f14f 100644 --- a/src/menu.c +++ b/src/menu.c @@ -4,8 +4,10 @@ #include "blit.h" #include "dma3.h" #include "event_data.h" +#include "field_weather.h" #include "graphics.h" #include "main.h" +#include "map_name_popup.h" #include "menu.h" #include "menu_helpers.h" #include "palette.h" @@ -18,6 +20,7 @@ #include "task.h" #include "text_window.h" #include "window.h" +#include "config/overworld.h" #include "constants/songs.h" #define DLG_WINDOW_PALETTE_NUM 15 @@ -62,6 +65,7 @@ static void task_free_buf_after_copying_tile_data_to_vram(u8 taskId); static EWRAM_DATA u8 sStartMenuWindowId = 0; static EWRAM_DATA u8 sMapNamePopupWindowId = 0; +static EWRAM_DATA u8 sSecondaryPopupWindowId = 0; static EWRAM_DATA struct Menu sMenu = {0}; static EWRAM_DATA u16 sTileNum = 0; static EWRAM_DATA u8 sPaletteNum = 0; @@ -146,6 +150,8 @@ void InitStandardTextBoxWindows(void) InitWindows(sStandardTextBox_WindowTemplates); sStartMenuWindowId = WINDOW_NONE; sMapNamePopupWindowId = WINDOW_NONE; + if (OW_POPUP_GENERATION == GEN_5) + sSecondaryPopupWindowId = WINDOW_NONE; } void FreeAllOverworldWindowBuffers(void) @@ -522,7 +528,12 @@ static u16 UNUSED GetStandardFrameBaseTileNum(void) u8 AddMapNamePopUpWindow(void) { if (sMapNamePopupWindowId == WINDOW_NONE) - sMapNamePopupWindowId = AddWindowParameterized(0, 1, 1, 10, 3, 14, 0x107); + { + if (OW_POPUP_GENERATION == GEN_5) + sMapNamePopupWindowId = AddWindowParameterized(0, 0, 0, 30, 3, 14, 0x107); + else + sMapNamePopupWindowId = AddWindowParameterized(0, 1, 1, 10, 3, 14, 0x107); + } return sMapNamePopupWindowId; } @@ -2146,3 +2157,42 @@ void BufferSaveMenuText(u8 textId, u8 *dest, u8 color) break; } } + +// BW map pop-ups +u8 AddSecondaryPopUpWindow(void) +{ + if (sSecondaryPopupWindowId == WINDOW_NONE) + sSecondaryPopupWindowId = AddWindowParameterized(0, 0, 17, 30, 3, 14, 0x161); + return sSecondaryPopupWindowId; +} + +u8 GetSecondaryPopUpWindowId(void) +{ + return sSecondaryPopupWindowId; +} + +void RemoveSecondaryPopUpWindow(void) +{ + if (sSecondaryPopupWindowId != WINDOW_NONE) + { + RemoveWindow(sSecondaryPopupWindowId); + sSecondaryPopupWindowId = WINDOW_NONE; + } +} + +void HBlankCB_DoublePopupWindow(void) +{ + u16 offset = gTasks[gPopupTaskId].data[2]; + u16 scanline = REG_VCOUNT; + + if (scanline < 80 || scanline > 160) + { + REG_BG0VOFS = offset; + if(OW_POPUP_BW_ALPHA_BLEND && !IsWeatherAlphaBlend()) + REG_BLDALPHA = BLDALPHA_BLEND(15, 5); + } + else + { + REG_BG0VOFS = 512 - offset; + } +} diff --git a/src/pokemon_icon.c b/src/pokemon_icon.c index d7f9e24029e2..639f24327a77 100644 --- a/src/pokemon_icon.c +++ b/src/pokemon_icon.c @@ -2,7 +2,7 @@ #include "graphics.h" #include "mail.h" #include "palette.h" -#include "pokemon_debug.h" +#include "pokemon_sprite_visualizer.h" #include "pokemon_icon.h" #include "sprite.h" #include "data.h" diff --git a/src/pokemon_debug.c b/src/pokemon_sprite_visualizer.c similarity index 93% rename from src/pokemon_debug.c rename to src/pokemon_sprite_visualizer.c index 40456380abb6..a0b7ddabc262 100644 --- a/src/pokemon_debug.c +++ b/src/pokemon_sprite_visualizer.c @@ -25,7 +25,7 @@ #include "pokedex.h" #include "pokemon.h" #include "pokemon_animation.h" -#include "pokemon_debug.h" +#include "pokemon_sprite_visualizer.h" #include "pokemon_icon.h" #include "reset_rtc_screen.h" #include "scanline_effect.h" @@ -41,7 +41,6 @@ #include "constants/items.h" #include "constants/event_objects.h" -#if DEBUG_POKEMON_MENU == TRUE extern const struct BattleBackground sBattleTerrainTable[]; extern const struct CompressedSpriteSheet gSpriteSheet_EnemyShadow; extern const struct SpriteTemplate gSpriteTemplate_EnemyShadow; @@ -49,11 +48,11 @@ extern const struct SpritePalette sSpritePalettes_HealthBoxHealthBar[2]; extern const struct UCoords8 sBattlerCoords[][MAX_BATTLERS_COUNT] ; static const u16 sBgColor[] = {RGB_WHITE}; -static struct PokemonDebugMenu *GetStructPtr(u8 taskId) +static struct PokemonSpriteVisualizer *GetStructPtr(u8 taskId) { u8 *taskDataPtr = (u8 *)(&gTasks[taskId].data[0]); - return (struct PokemonDebugMenu*)(T1_READ_PTR(taskDataPtr)); + return (struct PokemonSpriteVisualizer*)(T1_READ_PTR(taskDataPtr)); } static const union AnimCmd sAnim_Follower_1[] = @@ -129,7 +128,7 @@ static const struct BgTemplate sBgTemplates[] = }; //WindowTemplates -static const struct WindowTemplate sPokemonDebugWindowTemplate[] = +static const struct WindowTemplate sPokemonSpriteVisualizerWindowTemplate[] = { [WIN_NAME_NUMBERS] = { .bg = 0, @@ -398,16 +397,16 @@ const u8 gBattleBackgroundTerrainNames[][26] = [BATTLE_TERRAIN_PLAIN] = _("NORMAL - PLAIN "), }; //Function declarations -static void PrintDigitChars(struct PokemonDebugMenu *data); -static void SetUpModifyArrows(struct PokemonDebugMenu *data); -static void UpdateBattlerValue(struct PokemonDebugMenu *data); +static void PrintDigitChars(struct PokemonSpriteVisualizer *data); +static void SetUpModifyArrows(struct PokemonSpriteVisualizer *data); +static void UpdateBattlerValue(struct PokemonSpriteVisualizer *data); static void ValueToCharDigits(u8 *charDigits, u32 newValue, u8 maxDigits); -static bool32 TryMoveDigit(struct PokemonDebugModifyArrows *modArrows, bool32 moveUp); -static void CB2_Debug_Runner(void); -static void ResetBGs_Debug_Menu(u16); -static void Handle_Input_Debug_Pokemon(u8); -static void ReloadPokemonSprites(struct PokemonDebugMenu *data); -static void Exit_Debug_Pokemon(u8); +static bool32 TryMoveDigit(struct PokemonSpriteVisualizerModifyArrows *modArrows, bool32 moveUp); +static void CB2_PokemonSpriteVisualizerRunner(void); +static void ResetBGs_PokemonSpriteVisualizer(u16); +static void HandleInput_PokemonSpriteVisualizer(u8); +static void ReloadPokemonSprites(struct PokemonSpriteVisualizer *data); +static void Exit_PokemonSpriteVisualizer(u8); //Text handling functions static void UNUSED PadString(const u8 *src, u8 *dst) @@ -423,7 +422,7 @@ static void UNUSED PadString(const u8 *src, u8 *dst) dst[i] = EOS; } -static void PrintInstructionsOnWindow(struct PokemonDebugMenu *data) +static void PrintInstructionsOnWindow(struct PokemonSpriteVisualizer *data) { u8 fontId = 0; u8 x = 2; @@ -503,7 +502,7 @@ static void SetStructPtr(u8 taskId, void *ptr) //Digit and arrow functions #define VAL_U16 0 -static void PrintDigitChars(struct PokemonDebugMenu *data) +static void PrintDigitChars(struct PokemonSpriteVisualizer *data) { s32 i; u16 species = data->modifyArrows.currValue; @@ -572,7 +571,7 @@ static void ValueToCharDigits(u8 *charDigits, u32 newValue, u8 maxDigits) charDigits[i] = valueDigits[i] + CHAR_0; } -static void SetArrowInvisibility(struct PokemonDebugMenu *data) +static void SetArrowInvisibility(struct PokemonSpriteVisualizer *data) { switch (data->currentSubmenu) { @@ -597,7 +596,7 @@ static void SetArrowInvisibility(struct PokemonDebugMenu *data) } } -static void SetUpModifyArrows(struct PokemonDebugMenu *data) +static void SetUpModifyArrows(struct PokemonSpriteVisualizer *data) { LoadSpritePalette(&gSpritePalette_Arrow); data->modifyArrows.arrowSpriteId[0] = CreateSprite(&gSpriteTemplate_Arrow, MODIFY_DIGITS_ARROW_X, MODIFY_DIGITS_ARROW1_Y, 0); @@ -615,7 +614,7 @@ static void SetUpModifyArrows(struct PokemonDebugMenu *data) ValueToCharDigits(data->modifyArrows.charDigits, data->modifyArrows.currValue, data->modifyArrows.maxDigits); } -static void SetUpOptionArrows(struct PokemonDebugMenu *data) +static void SetUpOptionArrows(struct PokemonSpriteVisualizer *data) { LoadSpritePalette(&gSpritePalette_Arrow); data->optionArrows.arrowSpriteId[0] = CreateSprite(&gSpriteTemplate_Arrow, OPTIONS_ARROW_1_X, OPTIONS_ARROW_Y, 0); @@ -626,7 +625,7 @@ static void SetUpOptionArrows(struct PokemonDebugMenu *data) gSprites[data->optionArrows.arrowSpriteId[0]].invisible = TRUE; } -static void SetUpYPosModifyArrows(struct PokemonDebugMenu *data) +static void SetUpYPosModifyArrows(struct PokemonSpriteVisualizer *data) { LoadSpritePalette(&gSpritePalette_Arrow); data->yPosModifyArrows.arrowSpriteId[0] = CreateSprite(&gSpriteTemplate_Arrow, OPTIONS_ARROW_1_X, OPTIONS_ARROW_Y, 0); @@ -637,7 +636,7 @@ static void SetUpYPosModifyArrows(struct PokemonDebugMenu *data) gSprites[data->yPosModifyArrows.arrowSpriteId[0]].invisible = TRUE; } -static bool32 TryMoveDigit(struct PokemonDebugModifyArrows *modArrows, bool32 moveUp) +static bool32 TryMoveDigit(struct PokemonSpriteVisualizerModifyArrows *modArrows, bool32 moveUp) { s32 i; u8 charDigits[MODIFY_DIGITS_MAX]; @@ -701,7 +700,7 @@ static bool32 TryMoveDigit(struct PokemonDebugModifyArrows *modArrows, bool32 mo } } -static void UpdateBattlerValue(struct PokemonDebugMenu *data) +static void UpdateBattlerValue(struct PokemonSpriteVisualizer *data) { switch (data->modifyArrows.typeOfVal) { @@ -721,7 +720,7 @@ static void BattleLoadOpponentMonSpriteGfxCustom(u16 species, bool8 isFemale, bo LoadPalette(gDecompressionBuffer, BG_PLTT_ID(8) + BG_PLTT_ID(battlerId), PLTT_SIZE_4BPP); } -static void SetConstSpriteValues(struct PokemonDebugMenu *data) +static void SetConstSpriteValues(struct PokemonSpriteVisualizer *data) { u16 species = data->currentmonId; data->constSpriteValues.frontPicCoords = gSpeciesInfo[species].frontPicYOffset; @@ -729,7 +728,7 @@ static void SetConstSpriteValues(struct PokemonDebugMenu *data) data->constSpriteValues.backPicCoords = gSpeciesInfo[species].backPicYOffset; } -static void ResetOffsetSpriteValues(struct PokemonDebugMenu *data) +static void ResetOffsetSpriteValues(struct PokemonSpriteVisualizer *data) { data->offsetsSpriteValues.offset_back_picCoords = 0; data->offsetsSpriteValues.offset_front_picCoords = 0; @@ -757,7 +756,7 @@ static u8 GetBattlerSpriteFinal_YCustom(u16 species, s8 offset_picCoords, s8 off return y; } -static void UpdateShadowSpriteInvisible(struct PokemonDebugMenu *data) +static void UpdateShadowSpriteInvisible(struct PokemonSpriteVisualizer *data) { if (data->constSpriteValues.frontElevation + data->offsetsSpriteValues.offset_front_elevation == 0) gSprites[data->frontShadowSpriteId].invisible = TRUE; @@ -803,7 +802,7 @@ static void SpriteCB_Follower(struct Sprite *sprite) } } -static void LoadAndCreateEnemyShadowSpriteCustom(struct PokemonDebugMenu *data, u16 species) +static void LoadAndCreateEnemyShadowSpriteCustom(struct PokemonSpriteVisualizer *data, u16 species) { u8 x, y; bool8 invisible = FALSE; @@ -903,7 +902,7 @@ static void LoadBattleBg(u8 battleBgType, u8 battleTerrain) } static void PrintBattleBgName(u8 taskId) { - struct PokemonDebugMenu *data = GetStructPtr(taskId); + struct PokemonSpriteVisualizer *data = GetStructPtr(taskId); u8 fontId = 0; u8 text[30+1]; @@ -915,7 +914,7 @@ static void PrintBattleBgName(u8 taskId) } static void UpdateBattleBg(u8 taskId, bool8 increment) { - struct PokemonDebugMenu *data = GetStructPtr(taskId); + struct PokemonSpriteVisualizer *data = GetStructPtr(taskId); if (data->battleBgType == MAP_BATTLE_SCENE_NORMAL) { @@ -971,7 +970,7 @@ static void UpdateBattleBg(u8 taskId, bool8 increment) // Main functions static void UpdateMonAnimNames(u8 taskId) { - struct PokemonDebugMenu *data = GetStructPtr(taskId); + struct PokemonSpriteVisualizer *data = GetStructPtr(taskId); u8 frontAnim = data->animIdFront; u8 backAnim = data->animIdBack; u8 text[34]; @@ -994,7 +993,7 @@ static void UpdateMonAnimNames(u8 taskId) PrintBattleBgName(taskId); } -static void UpdateYPosOffsetText(struct PokemonDebugMenu *data) +static void UpdateYPosOffsetText(struct PokemonSpriteVisualizer *data) { u8 text[34]; u8 fontId = 0; @@ -1045,12 +1044,12 @@ static void UpdateYPosOffsetText(struct PokemonDebugMenu *data) AddTextPrinterParameterized(WIN_BOTTOM_RIGHT, fontId, text, x_new_val, y, 0, NULL); } -static void ResetPokemonDebugWindows(void) +static void ResetPokemonSpriteVisualizerWindows(void) { u8 i; FreeAllWindowBuffers(); - InitWindows(sPokemonDebugWindowTemplate); + InitWindows(sPokemonSpriteVisualizerWindowTemplate); for (i = 0; i < WIN_END + 1; i++) { @@ -1063,11 +1062,11 @@ static void ResetPokemonDebugWindows(void) #define MALE_PERSONALITY 0xFE #define FEMALE_PERSONALITY 0X0 -void CB2_Debug_Pokemon(void) +void CB2_Pokemon_Sprite_Visualizer(void) { u8 taskId; const u32 *palette; - struct PokemonDebugMenu *data; + struct PokemonSpriteVisualizer *data; u16 species; s16 offset_y; u8 front_x = sBattlerCoords[0][1].x; @@ -1079,7 +1078,7 @@ void CB2_Debug_Pokemon(void) default: SetVBlankCallback(NULL); FreeMonSpritesGfx(); - ResetBGs_Debug_Menu(0); + ResetBGs_PokemonSpriteVisualizer(0); DmaFillLarge16(3, 0, (u8 *)VRAM, VRAM_SIZE, 0x1000) DmaClear32(3, OAM, OAM_SIZE); DmaClear16(3, PLTT, PLTT_SIZE); @@ -1103,7 +1102,7 @@ void CB2_Debug_Pokemon(void) gMain.state++; break; case 2: - ResetPokemonDebugWindows(); + ResetPokemonSpriteVisualizerWindows(); gMain.state++; break; case 3: @@ -1119,9 +1118,9 @@ void CB2_Debug_Pokemon(void) ShowBg(3); //input task handler - taskId = CreateTask(Handle_Input_Debug_Pokemon, 0); + taskId = CreateTask(HandleInput_PokemonSpriteVisualizer, 0); - data = AllocZeroed(sizeof(struct PokemonDebugMenu)); + data = AllocZeroed(sizeof(struct PokemonSpriteVisualizer)); SetStructPtr(taskId, data); data->currentmonId = SPECIES_BULBASAUR; @@ -1153,17 +1152,17 @@ void CB2_Debug_Pokemon(void) BattleLoadOpponentMonSpriteGfxCustom(species, data->isFemale, data->isShiny, 4); SetMultiuseSpriteTemplateToPokemon(species, 2); offset_y = gSpeciesInfo[species].backPicYOffset; - data->backspriteId = CreateSprite(&gMultiuseSpriteTemplate, DEBUG_MON_BACK_X, DEBUG_MON_BACK_Y + offset_y, 0); + data->backspriteId = CreateSprite(&gMultiuseSpriteTemplate, VISUALIZER_MON_BACK_X, VISUALIZER_MON_BACK_Y + offset_y, 0); gSprites[data->backspriteId].oam.paletteNum = 4; gSprites[data->backspriteId].callback = SpriteCallbackDummy; gSprites[data->backspriteId].oam.priority = 0; //Icon Sprite - data->iconspriteId = CreateMonIcon(species, SpriteCB_MonIcon, DEBUG_ICON_X, DEBUG_ICON_Y, 4, (data->isFemale ? FEMALE_PERSONALITY : MALE_PERSONALITY)); + data->iconspriteId = CreateMonIcon(species, SpriteCB_MonIcon, VISUALIZER_ICON_X, VISUALIZER_ICON_Y, 4, (data->isFemale ? FEMALE_PERSONALITY : MALE_PERSONALITY)); gSprites[data->iconspriteId].oam.priority = 0; //Follower Sprite - data->followerspriteId = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MON_BASE + species, SpriteCB_Follower, DEBUG_FOLLOWER_X, DEBUG_FOLLOWER_Y, 0); + data->followerspriteId = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MON_BASE + species, SpriteCB_Follower, VISUALIZER_FOLLOWER_X, VISUALIZER_FOLLOWER_Y, 0); gSprites[data->followerspriteId].oam.priority = 0; gSprites[data->followerspriteId].anims = sAnims_Follower; @@ -1194,13 +1193,13 @@ void CB2_Debug_Pokemon(void) case 4: EnableInterrupts(1); SetVBlankCallback(VBlankCB); - SetMainCallback2(CB2_Debug_Runner); + SetMainCallback2(CB2_PokemonSpriteVisualizerRunner); m4aMPlayVolumeControl(&gMPlayInfo_BGM, 0xFFFF, 0x80); break; } } -static void CB2_Debug_Runner(void) +static void CB2_PokemonSpriteVisualizerRunner(void) { RunTasks(); AnimateSprites(); @@ -1208,7 +1207,7 @@ static void CB2_Debug_Runner(void) UpdatePaletteFade(); } -static void ResetBGs_Debug_Menu(u16 a) +static void ResetBGs_PokemonSpriteVisualizer(u16 a) { if (!(a & DISPCNT_BG0_ON)) { @@ -1247,11 +1246,11 @@ static void ResetBGs_Debug_Menu(u16 a) } } -static void ApplyOffsetSpriteValues(struct PokemonDebugMenu *data) +static void ApplyOffsetSpriteValues(struct PokemonSpriteVisualizer *data) { u16 species = data->currentmonId; //Back - gSprites[data->backspriteId].y = DEBUG_MON_BACK_Y + gSpeciesInfo[species].backPicYOffset + data->offsetsSpriteValues.offset_back_picCoords; + gSprites[data->backspriteId].y = VISUALIZER_MON_BACK_Y + gSpeciesInfo[species].backPicYOffset + data->offsetsSpriteValues.offset_back_picCoords; //Front gSprites[data->frontspriteId].y = GetBattlerSpriteFinal_YCustom(species, data->offsetsSpriteValues.offset_front_picCoords, data->offsetsSpriteValues.offset_front_elevation); @@ -1261,7 +1260,7 @@ static void ApplyOffsetSpriteValues(struct PokemonDebugMenu *data) static void UpdateSubmenuOneOptionValue(u8 taskId, bool8 increment) { - struct PokemonDebugMenu *data = GetStructPtr(taskId); + struct PokemonSpriteVisualizer *data = GetStructPtr(taskId); u8 option = data->submenuYpos[1]; switch (option) @@ -1306,7 +1305,7 @@ static void UpdateSubmenuOneOptionValue(u8 taskId, bool8 increment) case 3: if (GetSpeciesFormTable(data->currentmonId) != NULL) { - struct PokemonDebugModifyArrows *modArrows = &data->modifyArrows; + struct PokemonSpriteVisualizerModifyArrows *modArrows = &data->modifyArrows; u8 formId = GetFormIdFromFormSpeciesId(data->currentmonId); const u16 *formTable = GetSpeciesFormTable(data->currentmonId); if (increment) @@ -1349,7 +1348,7 @@ static void UpdateSubmenuOneOptionValue(u8 taskId, bool8 increment) static void UpdateSubmenuTwoOptionValue(u8 taskId, bool8 increment) { - struct PokemonDebugMenu *data = GetStructPtr(taskId); + struct PokemonSpriteVisualizer *data = GetStructPtr(taskId); u16 species = data->currentmonId; u8 option = data->submenuYpos[2]; s8 offset; @@ -1374,7 +1373,7 @@ static void UpdateSubmenuTwoOptionValue(u8 taskId, bool8 increment) offset -= 1; } data->offsetsSpriteValues.offset_back_picCoords = offset; - gSprites[data->backspriteId].y = DEBUG_MON_BACK_Y + gSpeciesInfo[species].backPicYOffset + offset; + gSprites[data->backspriteId].y = VISUALIZER_MON_BACK_Y + gSpeciesInfo[species].backPicYOffset + offset; break; case 1: //Front picCoords offset = data->offsetsSpriteValues.offset_front_picCoords; @@ -1445,9 +1444,9 @@ static void Task_AnimateAfterDelay(u8 taskId) } } -static void Handle_Input_Debug_Pokemon(u8 taskId) +static void HandleInput_PokemonSpriteVisualizer(u8 taskId) { - struct PokemonDebugMenu *data = GetStructPtr(taskId); + struct PokemonSpriteVisualizer *data = GetStructPtr(taskId); struct Sprite *Frontsprite = &gSprites[data->frontspriteId]; struct Sprite *Backsprite = &gSprites[data->backspriteId]; @@ -1508,7 +1507,7 @@ static void Handle_Input_Debug_Pokemon(u8 taskId) else if (JOY_NEW(B_BUTTON)) { BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); - gTasks[taskId].func = Exit_Debug_Pokemon; + gTasks[taskId].func = Exit_PokemonSpriteVisualizer; PlaySE(SE_PC_OFF); } else if (JOY_NEW(DPAD_DOWN)) @@ -1662,7 +1661,7 @@ static void Handle_Input_Debug_Pokemon(u8 taskId) #undef sDelay #undef sAnimId -static void ReloadPokemonSprites(struct PokemonDebugMenu *data) +static void ReloadPokemonSprites(struct PokemonSpriteVisualizer *data) { const u32 *palette; u16 species = data->currentmonId; @@ -1709,20 +1708,20 @@ static void ReloadPokemonSprites(struct PokemonDebugMenu *data) BattleLoadOpponentMonSpriteGfxCustom(species, data->isFemale, data->isShiny, 5); SetMultiuseSpriteTemplateToPokemon(species, 2); offset_y = gSpeciesInfo[species].backPicYOffset; - data->backspriteId = CreateSprite(&gMultiuseSpriteTemplate, DEBUG_MON_BACK_X, DEBUG_MON_BACK_Y + offset_y, 0); + data->backspriteId = CreateSprite(&gMultiuseSpriteTemplate, VISUALIZER_MON_BACK_X, VISUALIZER_MON_BACK_Y + offset_y, 0); gSprites[data->backspriteId].oam.paletteNum = 5; gSprites[data->backspriteId].callback = SpriteCallbackDummy; gSprites[data->backspriteId].oam.priority = 0; //Icon Sprite - data->iconspriteId = CreateMonIcon(species, SpriteCB_MonIcon, DEBUG_ICON_X, DEBUG_ICON_Y, 4, (data->isFemale ? FEMALE_PERSONALITY : MALE_PERSONALITY)); + data->iconspriteId = CreateMonIcon(species, SpriteCB_MonIcon, VISUALIZER_ICON_X, VISUALIZER_ICON_Y, 4, (data->isFemale ? FEMALE_PERSONALITY : MALE_PERSONALITY)); gSprites[data->iconspriteId].oam.priority = 0; //Follower Sprite data->followerspriteId = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MON_BASE + species + (data->isShiny ? SPECIES_SHINY_TAG : 0), SpriteCB_Follower, - DEBUG_FOLLOWER_X, - DEBUG_FOLLOWER_Y, + VISUALIZER_FOLLOWER_X, + VISUALIZER_FOLLOWER_Y, 0); gSprites[data->followerspriteId].oam.priority = 0; gSprites[data->followerspriteId].anims = sAnims_Follower; @@ -1751,11 +1750,11 @@ static void ReloadPokemonSprites(struct PokemonDebugMenu *data) CopyWindowToVram(WIN_FOOTPRINT, COPYWIN_GFX); } -static void Exit_Debug_Pokemon(u8 taskId) +static void Exit_PokemonSpriteVisualizer(u8 taskId) { if (!gPaletteFade.active) { - struct PokemonDebugMenu *data = GetStructPtr(taskId); + struct PokemonSpriteVisualizer *data = GetStructPtr(taskId); Free(data); FreeMonSpritesGfx(); DestroyTask(taskId); @@ -1763,5 +1762,3 @@ static void Exit_Debug_Pokemon(u8 taskId) m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100); } } - -#endif diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index 70b82a3edc75..49bca478ccee 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -28,7 +28,7 @@ #include "palette.h" #include "pokeball.h" #include "pokemon.h" -#include "pokemon_debug.h" +#include "pokemon_sprite_visualizer.h" #include "pokemon_storage_system.h" #include "pokemon_summary_screen.h" #include "region_map.h" @@ -1640,15 +1640,13 @@ static void Task_HandleInput(u8 taskId) PlaySE(SE_SELECT); BeginCloseSummaryScreen(taskId); } - #if DEBUG_POKEMON_MENU == TRUE - else if (JOY_NEW(SELECT_BUTTON) && !gMain.inBattle) + else if (DEBUG_POKEMON_SPRITE_VISUALIZER && JOY_NEW(SELECT_BUTTON) && !gMain.inBattle) { - sMonSummaryScreen->callback = CB2_Debug_Pokemon; + sMonSummaryScreen->callback = CB2_Pokemon_Sprite_Visualizer; StopPokemonAnimations(); PlaySE(SE_SELECT); CloseSummaryScreen(taskId); } - #endif } } diff --git a/src/rtc.c b/src/rtc.c index a90c9aa89b64..a53d5e1fd8ba 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -1,6 +1,7 @@ #include "global.h" #include "rtc.h" #include "string_util.h" +#include "strings.h" #include "text.h" // iwram bss @@ -364,3 +365,33 @@ u32 RtcGetLocalDayCount(void) { return RtcGetDayCount(&sRtc); } + +void FormatDecimalTimeWithoutSeconds(u8 *txtPtr, s8 hour, s8 minute, bool32 is24Hour) +{ + if (is24Hour) + { + txtPtr = ConvertIntToDecimalStringN(txtPtr, hour, STR_CONV_MODE_LEADING_ZEROS, 2); + *txtPtr++ = CHAR_COLON; + txtPtr = ConvertIntToDecimalStringN(txtPtr, minute, STR_CONV_MODE_LEADING_ZEROS, 2); + } + else + { + if (hour == 0) + txtPtr = ConvertIntToDecimalStringN(txtPtr, 12, STR_CONV_MODE_LEADING_ZEROS, 2); + else if (hour < 13) + txtPtr = ConvertIntToDecimalStringN(txtPtr, hour, STR_CONV_MODE_LEADING_ZEROS, 2); + else + txtPtr = ConvertIntToDecimalStringN(txtPtr, hour - 12, STR_CONV_MODE_LEADING_ZEROS, 2); + + *txtPtr++ = CHAR_COLON; + txtPtr = ConvertIntToDecimalStringN(txtPtr, minute, STR_CONV_MODE_LEADING_ZEROS, 2); + txtPtr = StringAppend(txtPtr, gText_Space); + if (hour < 12) + txtPtr = StringAppend(txtPtr, gText_AM); + else + txtPtr = StringAppend(txtPtr, gText_PM); + } + + *txtPtr++ = EOS; + *txtPtr = EOS; +} diff --git a/src/start_menu.c b/src/start_menu.c index 0525ccf70d7c..71ab87363c9d 100644 --- a/src/start_menu.c +++ b/src/start_menu.c @@ -784,10 +784,11 @@ static bool8 StartMenuDebugCallback(void) RemoveExtraStartMenuWindows(); HideStartMenuDebug(); // Hide start menu without enabling movement -#if DEBUG_OVERWORLD_MENU == TRUE - FreezeObjectEvents(); - Debug_ShowMainMenu(); -#endif + if (DEBUG_OVERWORLD_MENU) + { + FreezeObjectEvents(); + Debug_ShowMainMenu(); + } return TRUE; } diff --git a/src/strings.c b/src/strings.c index c9be317a095c..4b577bb96332 100644 --- a/src/strings.c +++ b/src/strings.c @@ -1849,3 +1849,5 @@ const u8 gText_ExpShareOff[] = _("The Exp. Share has been turned off.{PAUSE_UNTI const u8 gText_BasePointsResetToZero[] = _("{STR_VAR_1}'s base points\nwere all reset to zero!{PAUSE_UNTIL_PRESS}"); const u8 gText_Fertilize[] = _("FERTILIZE"); const u8 gText_PlantBerry[] = _("PLANT BERRY"); +const u8 gText_AM[] = _("AM"); +const u8 gText_PM[] = _("PM"); diff --git a/test/battle/ability/lingering_aroma.c b/test/battle/ability/lingering_aroma.c new file mode 100644 index 000000000000..a4ef5fc48fa2 --- /dev/null +++ b/test/battle/ability/lingering_aroma.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +// Tests for Lingering Aroma are handled in test/battle/ability/mummy.c diff --git a/test/battle/ability/mummy.c b/test/battle/ability/mummy.c new file mode 100644 index 000000000000..ed80a178e6f4 --- /dev/null +++ b/test/battle/ability/mummy.c @@ -0,0 +1,98 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Mummy/Lingering Aroma replace the attacker's ability on contact") +{ + u32 move, ability, species; + + PARAMETRIZE { move = MOVE_AQUA_JET; ability = ABILITY_MUMMY; species = SPECIES_YAMASK; } + PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_MUMMY; species = SPECIES_YAMASK;} + PARAMETRIZE { move = MOVE_AQUA_JET; ability = ABILITY_LINGERING_AROMA; species = SPECIES_OINKOLOGNE; } + PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_LINGERING_AROMA; species = SPECIES_OINKOLOGNE; } + GIVEN { + ASSUME(gMovesInfo[MOVE_AQUA_JET].makesContact); + ASSUME(!gMovesInfo[MOVE_WATER_GUN].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + if (gMovesInfo[move].makesContact) { + ABILITY_POPUP(opponent, ability); + if (ability == ABILITY_MUMMY) + MESSAGE("Wobbuffet acquired Mummy!"); + else + MESSAGE("Wobbuffet acquired Lingering Aroma!"); + } else { + NONE_OF { + ABILITY_POPUP(opponent, ability); + if (ability == ABILITY_MUMMY) + MESSAGE("Wobbuffet acquired Mummy!"); + else + MESSAGE("Wobbuffet acquired Lingering Aroma!"); + } + } + } +} + +SINGLE_BATTLE_TEST("Mummy and Lingering Aroma don't replace each other") +{ + u32 ability1, species1, ability2, species2; + + PARAMETRIZE { ability1 = ability2 = ABILITY_MUMMY; species1 = species2 = SPECIES_YAMASK; } + PARAMETRIZE { ability1 = ABILITY_MUMMY; species1 = SPECIES_YAMASK; ability2 = ABILITY_LINGERING_AROMA; species2 = SPECIES_OINKOLOGNE; } + PARAMETRIZE { ability1 = ability2 = ABILITY_LINGERING_AROMA; species1 = species2 = SPECIES_OINKOLOGNE; } + GIVEN { + ASSUME(gMovesInfo[MOVE_AQUA_JET].makesContact); + PLAYER(species1) { Ability(ability1); Speed(2); } + OPPONENT(species2) { Ability(ability2); Speed(1); } + } WHEN { + TURN { MOVE(player, MOVE_AQUA_JET); MOVE(opponent, MOVE_AQUA_JET); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_JET, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_JET, opponent); + NONE_OF { + ABILITY_POPUP(player, ability1); + ABILITY_POPUP(player, ability2); + ABILITY_POPUP(opponent, ability1); + ABILITY_POPUP(opponent, ability2); + MESSAGE("Yamask acquired Mummy!"); + MESSAGE("Yamask acquired Lingering Aroma!"); + MESSAGE("Oinkologne acquired Mummy!"); + MESSAGE("Oinkologne acquired Lingering Aroma!"); + } + } +} + +SINGLE_BATTLE_TEST("Mummy doesn't replace abilities that can't be suppressed") +{ + u32 species, ability; + + PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } + PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; } + PARAMETRIZE { species = SPECIES_WISHIWASHI; ability = ABILITY_SCHOOLING; } + PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; } + PARAMETRIZE { species = SPECIES_MINIOR; ability = ABILITY_SHIELDS_DOWN; } + PARAMETRIZE { species = SPECIES_MIMIKYU; ability = ABILITY_DISGUISE; } + PARAMETRIZE { species = SPECIES_SILVALLY; ability = ABILITY_RKS_SYSTEM; } + PARAMETRIZE { species = SPECIES_GRENINJA_BATTLE_BOND; ability = ABILITY_BATTLE_BOND; } + PARAMETRIZE { species = SPECIES_ZYGARDE; ability = ABILITY_POWER_CONSTRUCT; } + PARAMETRIZE { species = SPECIES_EISCUE; ability = ABILITY_ICE_FACE; } + PARAMETRIZE { species = SPECIES_CRAMORANT; ability = ABILITY_GULP_MISSILE; } + PARAMETRIZE { species = SPECIES_PALAFIN_ZERO; ability = ABILITY_ZERO_TO_HERO; } + PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_COMMANDER; } + PARAMETRIZE { species = SPECIES_CALYREX_SHADOW_RIDER; ability = ABILITY_AS_ONE_SHADOW_RIDER; } + PARAMETRIZE { species = SPECIES_CALYREX_ICE_RIDER; ability = ABILITY_AS_ONE_ICE_RIDER; } + + GIVEN { + PLAYER(SPECIES_YAMASK); + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_AQUA_JET); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_JET, opponent); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_MUMMY); + } + } +} diff --git a/test/battle/ai_check_viability.c b/test/battle/ai_check_viability.c index dcbcf8dbec08..2e75f3190399 100644 --- a/test/battle/ai_check_viability.c +++ b/test/battle/ai_check_viability.c @@ -191,3 +191,51 @@ AI_SINGLE_BATTLE_TEST("AI chooses moves with secondary effect that have a 100% c TURN { EXPECT_MOVES(opponent, MOVE_OCTAZOOKA); } } } + +AI_DOUBLE_BATTLE_TEST("AI chooses moves that cure self or partner") +{ + u32 status1_0, status1_1, partnerAbility; + + PARAMETRIZE { status1_0 = STATUS1_NONE; status1_1 = STATUS1_NONE; partnerAbility = ABILITY_SCRAPPY; } + PARAMETRIZE { status1_0 = STATUS1_TOXIC_POISON; status1_1 = STATUS1_NONE; partnerAbility = ABILITY_SCRAPPY; } + PARAMETRIZE { status1_0 = STATUS1_NONE; status1_1 = STATUS1_PARALYSIS; partnerAbility = ABILITY_SCRAPPY; } + PARAMETRIZE { status1_0 = STATUS1_NONE; status1_1 = STATUS1_PARALYSIS; partnerAbility = ABILITY_SOUNDPROOF; } + + GIVEN { + ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); + ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_9); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_REGIROCK) { Moves(MOVE_ROCK_SLIDE, MOVE_HEAL_BELL, MOVE_ACID); Status1(status1_0); } + OPPONENT(SPECIES_EXPLOUD) { Status1(status1_1); Ability(partnerAbility); } + } WHEN { + if (status1_0 != STATUS1_NONE || (status1_1 != STATUS1_NONE && partnerAbility != ABILITY_SOUNDPROOF)) + TURN { EXPECT_MOVE(opponentLeft, MOVE_HEAL_BELL); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_ROCK_SLIDE); } + } +} + +AI_SINGLE_BATTLE_TEST("AI chooses moves that cure inactive party members") +{ + u32 status, ability; + + PARAMETRIZE { status = STATUS1_TOXIC_POISON; ability = ABILITY_SCRAPPY; } + PARAMETRIZE { status = STATUS1_NONE; ability = ABILITY_SCRAPPY; } + PARAMETRIZE { status = STATUS1_TOXIC_POISON; ability = ABILITY_SOUNDPROOF; } + + GIVEN { + ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); + ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_5); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_REGIROCK) { Moves(MOVE_BODY_PRESS, MOVE_HEAL_BELL); } + OPPONENT(SPECIES_EXPLOUD) { Status1(status); Ability(ability); } + } WHEN { + if (status == STATUS1_NONE) + TURN { EXPECT_MOVE(opponent, MOVE_BODY_PRESS); } + else + TURN { EXPECT_MOVE(opponent, MOVE_HEAL_BELL); } + } +} diff --git a/test/battle/move_effect/heal_bell.c b/test/battle/move_effect/heal_bell.c new file mode 100644 index 000000000000..7c01d0cfd3f9 --- /dev/null +++ b/test/battle/move_effect/heal_bell.c @@ -0,0 +1,102 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); + ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL); +} + +DOUBLE_BATTLE_TEST("Heal Bell cures the entire party") +{ + u32 move; + + PARAMETRIZE { move = MOVE_HEAL_BELL; } + PARAMETRIZE { move = MOVE_AROMATHERAPY; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, move, target: playerLeft); } + TURN { SWITCH(playerLeft, 2); SWITCH(playerRight, 3); } + } SCENE { + int i; + + ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); + NOT MESSAGE("Wobbuffet is hurt by poison!"); + for (i = 0; i < 6; i++) + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_STATUS), STATUS1_NONE); + } +} + +DOUBLE_BATTLE_TEST("Heal Bell does not cure soundproof partners") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SCRAPPY; } + PARAMETRIZE { ability = ABILITY_SOUNDPROOF; } + + ASSUME(B_HEAL_BELL_SOUNDPROOF != GEN_5); + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_EXPLOUD) { Ability(ability); Status1(STATUS1_POISON); } + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_HEAL_BELL, target: playerLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAL_BELL, playerLeft); + if (ability == ABILITY_SOUNDPROOF) { + MESSAGE("Exploud is hurt by poison!"); + } else { + NOT MESSAGE("Exploud is hurt by poison!"); + } + } +} + +SINGLE_BATTLE_TEST("Heal Bell cures inactive soundproof Pokemon") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SCRAPPY; } + PARAMETRIZE { ability = ABILITY_SOUNDPROOF; } + + ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_5); + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + PLAYER(SPECIES_EXPLOUD) { Ability(ability); Status1(STATUS1_POISON); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_HEAL_BELL, target: player); } + TURN { SWITCH(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAL_BELL, player); + SEND_IN_MESSAGE("Exploud"); + NOT MESSAGE("Exploud is hurt by poison!"); + } +} + + +SINGLE_BATTLE_TEST("Heal Bell cures a soundproof user") +{ + ASSUME(B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_9); + + GIVEN { + PLAYER(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); Status1(STATUS1_POISON); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_HEAL_BELL, target: player); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAL_BELL, player); + NOT MESSAGE("Exploud is hurt by poison!"); + } +} diff --git a/test/battle/move_effect_secondary/thrash.c b/test/battle/move_effect_secondary/thrash.c index 5ceb56f6dc4c..83a49554d741 100644 --- a/test/battle/move_effect_secondary/thrash.c +++ b/test/battle/move_effect_secondary/thrash.c @@ -46,7 +46,6 @@ SINGLE_BATTLE_TEST("Thrash confuses the user after it finishes") SINGLE_BATTLE_TEST("Thrash does not confuse the user if it is canceled on turn 1 of 3") { GIVEN { - ASSUME(B_RAMPAGE_CANCELLING >= GEN_5); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -61,7 +60,6 @@ SINGLE_BATTLE_TEST("Thrash does not confuse the user if it is canceled on turn 1 SINGLE_BATTLE_TEST("Thrash does not confuse the user if it is canceled on turn 2 of 3") { GIVEN { - ASSUME(B_RAMPAGE_CANCELLING >= GEN_5); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -73,9 +71,8 @@ SINGLE_BATTLE_TEST("Thrash does not confuse the user if it is canceled on turn 2 } } -SINGLE_BATTLE_TEST("Thrash confuses the user if it is canceled on turn 3 of 3") +SINGLE_BATTLE_TEST("Thrash confuses the user if it is canceled on turn 3 of 3, Protect") { - KNOWN_FAILING; GIVEN { ASSUME(B_RAMPAGE_CANCELLING >= GEN_5); PLAYER(SPECIES_WOBBUFFET); @@ -89,6 +86,22 @@ SINGLE_BATTLE_TEST("Thrash confuses the user if it is canceled on turn 3 of 3") } } +SINGLE_BATTLE_TEST("Thrash confuses the user if it is canceled on turn 3 of 3, Immunity") +{ + GIVEN { + ASSUME(B_RAMPAGE_CANCELLING >= GEN_5); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GENGAR); + } WHEN { + TURN { MOVE(player, MOVE_THRASH); } + TURN { SKIP_TURN(player); } + TURN { SWITCH(opponent, 1); SKIP_TURN(player); } + } SCENE { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, player); + } +} + SINGLE_BATTLE_TEST("Petal Dance does not lock mons that copy the move with Dancer") { GIVEN {