From 265b49c47b5651d210f8b1f0ae0384786d40ae13 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 26 Apr 2021 14:41:15 -0400 Subject: Label missing sprite anims --- src/item_menu_icons.c | 4 ++-- src/pokeblock.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/item_menu_icons.c b/src/item_menu_icons.c index d15409226..c728a720f 100644 --- a/src/item_menu_icons.c +++ b/src/item_menu_icons.c @@ -244,7 +244,7 @@ static const struct OamData sBerryPicRotatingOamData = .affineParam = 0 }; -static const union AnimCmd sSpriteAnim_857FBD8[] = +static const union AnimCmd sAnim_BerryPic[] = { ANIMCMD_FRAME(0, 0), ANIMCMD_END @@ -252,7 +252,7 @@ static const union AnimCmd sSpriteAnim_857FBD8[] = static const union AnimCmd *const sBerryPicSpriteAnimTable[] = { - sSpriteAnim_857FBD8 + sAnim_BerryPic }; static const struct SpriteFrameImage sBerryPicSpriteImageTable[] = diff --git a/src/pokeblock.c b/src/pokeblock.c index daf50a612..fad6858ec 100644 --- a/src/pokeblock.c +++ b/src/pokeblock.c @@ -264,7 +264,7 @@ static const union AnimCmd *const sSpriteAnimTable_PokeblockCase[] = sSpriteAnim_PokeblockCase }; -static const union AffineAnimCmd sSpriteAffineAnim_85B26C8[] = +static const union AffineAnimCmd sAffineAnim_PokeblockCaseShake[] = { AFFINEANIMCMD_FRAME(0, 0, -2, 2), AFFINEANIMCMD_FRAME(0, 0, 2, 4), @@ -273,9 +273,9 @@ static const union AffineAnimCmd sSpriteAffineAnim_85B26C8[] = AFFINEANIMCMD_END }; -static const union AffineAnimCmd *const sSpriteAffineAnimTable_85B26F0[] = +static const union AffineAnimCmd *const sAffineAnims_PokeblockCaseShake[] = { - sSpriteAffineAnim_85B26C8 + sAffineAnim_PokeblockCaseShake }; const struct CompressedSpriteSheet gPokeblockCase_SpriteSheet = @@ -955,7 +955,7 @@ static void SpriteCB_ShakePokeblockCase(struct Sprite *sprite) { case 0: sprite->oam.affineMode = ST_OAM_AFFINE_NORMAL; - sprite->affineAnims = sSpriteAffineAnimTable_85B26F0; + sprite->affineAnims = sAffineAnims_PokeblockCaseShake; InitSpriteAffineAnim(sprite); sprite->sState = 1; sprite->sTimer = 0; -- cgit v1.2.3 From 4206359862da51e3cc3d6b36ab0a3280c1123b9e Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 4 May 2021 01:21:50 -0400 Subject: Fix some object lock names --- asm/macros/event.inc | 4 ++-- include/event_object_lock.h | 4 ++-- src/event_object_lock.c | 8 ++++++-- src/scrcmd.c | 10 +++++++--- src/union_room.c | 2 +- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/asm/macros/event.inc b/asm/macros/event.inc index f3f17c5d8..e25c76de4 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -812,12 +812,12 @@ .byte 0x68 .endm - @ Ceases movement for all Objects on-screen. + @ Freezes all objects immediately except the player. The player is frozen once their movement is finished. .macro lockall .byte 0x69 .endm - @ If the script was called by an Object, then that Object's movement will cease. + @ Freezes all objects immediately except the player and the selected object. The player and selected object are frozen once their movement is finished. .macro lock .byte 0x6a .endm diff --git a/include/event_object_lock.h b/include/event_object_lock.h index 9d31a25fd..0b1f5f098 100644 --- a/include/event_object_lock.h +++ b/include/event_object_lock.h @@ -2,9 +2,9 @@ #define GUARD_EVENT_OBJECT_LOCK_H bool8 IsFreezePlayerFinished(void); -void ScriptFreezeObjectEvents(void); bool8 IsFreezeSelectedObjectAndPlayerFinished(void); -void LockSelectedObjectEvent(void); +void FreezeObjects_WaitForPlayer(void); +void FreezeObjects_WaitForPlayerAndSelected(void); void FreezeForApproachingTrainers(void); bool8 IsFreezeObjectAndPlayerFinished(void); void ScriptUnfreezeObjectEvents(void); diff --git a/src/event_object_lock.c b/src/event_object_lock.c index dec2d7906..179c72813 100644 --- a/src/event_object_lock.c +++ b/src/event_object_lock.c @@ -40,7 +40,7 @@ bool8 IsFreezePlayerFinished(void) } -void ScriptFreezeObjectEvents(void) +void FreezeObjects_WaitForPlayer(void) { FreezeObjectEvents(); CreateTask(Task_FreezePlayer, 80); @@ -82,7 +82,9 @@ bool8 IsFreezeSelectedObjectAndPlayerFinished(void) } } -void LockSelectedObjectEvent(void) +// Freeze all objects immediately except the selected object and the player. +// The selected object and player are frozen once their movement is finished. +void FreezeObjects_WaitForPlayerAndSelected(void) { u8 taskId; FreezeObjectEventsExceptOne(gSelectedObjectEvent); @@ -144,6 +146,8 @@ static void Task_FreezeObjectAndPlayer(u8 taskId) DestroyTask(taskId); } +// Freeze all objects immediately except the player and the approaching trainers. +// The approaching trainers and player are frozen once their movement is finished void FreezeForApproachingTrainers(void) { u8 trainerObjectId1, trainerObjectId2, taskId; diff --git a/src/scrcmd.c b/src/scrcmd.c index 0ee20d1c6..f53483978 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -1203,6 +1203,8 @@ bool8 ScrCmd_turnvobject(struct ScriptContext *ctx) return FALSE; } +// lockall freezes all object events except the player immediately. +// The player is frozen after waiting for their current movement to finish. bool8 ScrCmd_lockall(struct ScriptContext *ctx) { if (IsUpdateLinkStateCBActive()) @@ -1211,12 +1213,14 @@ bool8 ScrCmd_lockall(struct ScriptContext *ctx) } else { - ScriptFreezeObjectEvents(); + FreezeObjects_WaitForPlayer(); SetupNativeScript(ctx, IsFreezePlayerFinished); return TRUE; } } +// lock freezes all object events except the player and the selected object immediately. +// The player and selected object are frozen after waiting for their current movement to finish. bool8 ScrCmd_lock(struct ScriptContext *ctx) { if (IsUpdateLinkStateCBActive()) @@ -1227,12 +1231,12 @@ bool8 ScrCmd_lock(struct ScriptContext *ctx) { if (gObjectEvents[gSelectedObjectEvent].active) { - LockSelectedObjectEvent(); + FreezeObjects_WaitForPlayerAndSelected(); SetupNativeScript(ctx, IsFreezeSelectedObjectAndPlayerFinished); } else { - ScriptFreezeObjectEvents(); + FreezeObjects_WaitForPlayer(); SetupNativeScript(ctx, IsFreezePlayerFinished); } return TRUE; diff --git a/src/union_room.c b/src/union_room.c index f41cfd45f..06d3321c3 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -4415,7 +4415,7 @@ static void HandleCancelActivity(bool32 setData) static void UR_EnableScriptContext2AndFreezeObjectEvents(void) { ScriptContext2_Enable(); - ScriptFreezeObjectEvents(); + FreezeObjects_WaitForPlayer(); } static u8 GetActivePartnerSpriteGenderParam(struct WirelessLink_URoom *data) -- cgit v1.2.3 From 8b59909ac5eb6e3540aeb78396943d57a9702e4d Mon Sep 17 00:00:00 2001 From: Kurausukun Date: Thu, 17 Jun 2021 22:09:48 -0400 Subject: remove gflib --- Makefile | 38 +- gflib/bg.c | 1248 ---------------------------------- gflib/bg.h | 85 --- gflib/blit.c | 209 ------ gflib/blit.h | 17 - gflib/dma3.h | 55 -- gflib/dma3_manager.c | 183 ----- gflib/gpu_regs.c | 195 ------ gflib/gpu_regs.h | 19 - gflib/io_reg.c | 36 - gflib/io_reg.h | 7 - gflib/malloc.c | 210 ------ gflib/malloc.h | 22 - gflib/sprite.c | 1775 ------------------------------------------------ gflib/sprite.h | 324 --------- gflib/string_util.c | 781 --------------------- gflib/string_util.h | 46 -- gflib/text.c | 1808 ------------------------------------------------- gflib/text.h | 436 ------------ gflib/window.c | 721 -------------------- gflib/window.h | 80 --- include/bg.h | 85 +++ include/blit.h | 17 + include/dma3.h | 55 ++ include/gpu_regs.h | 19 + include/io_reg.h | 7 + include/malloc.h | 22 + include/sprite.h | 324 +++++++++ include/string_util.h | 46 ++ include/text.h | 436 ++++++++++++ include/window.h | 80 +++ ld_script.txt | 30 +- ld_script_modern.txt | 5 - src/bg.c | 1248 ++++++++++++++++++++++++++++++++++ src/blit.c | 209 ++++++ src/dma3_manager.c | 183 +++++ src/gpu_regs.c | 195 ++++++ src/io_reg.c | 36 + src/malloc.c | 210 ++++++ src/sprite.c | 1775 ++++++++++++++++++++++++++++++++++++++++++++++++ src/string_util.c | 781 +++++++++++++++++++++ src/text.c | 1808 +++++++++++++++++++++++++++++++++++++++++++++++++ src/window.c | 721 ++++++++++++++++++++ sym_bss.txt | 12 +- sym_common.txt | 8 +- sym_ewram.txt | 8 +- 46 files changed, 8289 insertions(+), 8326 deletions(-) delete mode 100644 gflib/bg.c delete mode 100644 gflib/bg.h delete mode 100644 gflib/blit.c delete mode 100644 gflib/blit.h delete mode 100644 gflib/dma3.h delete mode 100644 gflib/dma3_manager.c delete mode 100644 gflib/gpu_regs.c delete mode 100644 gflib/gpu_regs.h delete mode 100644 gflib/io_reg.c delete mode 100644 gflib/io_reg.h delete mode 100644 gflib/malloc.c delete mode 100644 gflib/malloc.h delete mode 100644 gflib/sprite.c delete mode 100644 gflib/sprite.h delete mode 100644 gflib/string_util.c delete mode 100644 gflib/string_util.h delete mode 100644 gflib/text.c delete mode 100644 gflib/text.h delete mode 100644 gflib/window.c delete mode 100644 gflib/window.h create mode 100644 include/bg.h create mode 100644 include/blit.h create mode 100644 include/dma3.h create mode 100644 include/gpu_regs.h create mode 100644 include/io_reg.h create mode 100644 include/malloc.h create mode 100644 include/sprite.h create mode 100644 include/string_util.h create mode 100644 include/text.h create mode 100644 include/window.h create mode 100644 src/bg.c create mode 100644 src/blit.c create mode 100644 src/dma3_manager.c create mode 100644 src/gpu_regs.c create mode 100644 src/io_reg.c create mode 100644 src/malloc.c create mode 100644 src/sprite.c create mode 100644 src/string_util.c create mode 100644 src/text.c create mode 100644 src/window.c diff --git a/Makefile b/Makefile index d7d4b9566..95d6328ef 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,6 @@ ELF = $(ROM:.gba=.elf) MAP = $(ROM:.gba=.map) C_SUBDIR = src -GFLIB_SUBDIR = gflib ASM_SUBDIR = asm DATA_SRC_SUBDIR = src/data DATA_ASM_SUBDIR = data @@ -87,7 +86,6 @@ SAMPLE_SUBDIR = sound/direct_sound_samples CRY_SUBDIR = sound/direct_sound_samples/cries C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR) -GFLIB_BUILDDIR = $(OBJ_DIR)/$(GFLIB_SUBDIR) ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR) DATA_ASM_BUILDDIR = $(OBJ_DIR)/$(DATA_ASM_SUBDIR) SONG_BUILDDIR = $(OBJ_DIR)/$(SONG_SUBDIR) @@ -111,7 +109,7 @@ LIBPATH := -L "$(dir $(shell $(MODERNCC) -mthumb -print-file-name=libgcc.a))" -L LIB := $(LIBPATH) -lc -lnosys -lgcc -L../../libagbsyscall -lagbsyscall endif -CPPFLAGS := -iquote include -iquote $(GFLIB_SUBDIR) -Wno-trigraphs -DMODERN=$(MODERN) +CPPFLAGS := -iquote include -Wno-trigraphs -DMODERN=$(MODERN) ifneq ($(MODERN),1) CPPFLAGS += -I tools/agbcc/include -I tools/agbcc -nostdinc -undef endif @@ -177,9 +175,6 @@ C_SRCS_IN := $(wildcard $(C_SUBDIR)/*.c $(C_SUBDIR)/*/*.c $(C_SUBDIR)/*/*/*.c) C_SRCS := $(foreach src,$(C_SRCS_IN),$(if $(findstring .inc.c,$(src)),,$(src))) C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS)) -GFLIB_SRCS := $(wildcard $(GFLIB_SUBDIR)/*.c) -GFLIB_OBJS := $(patsubst $(GFLIB_SUBDIR)/%.c,$(GFLIB_BUILDDIR)/%.o,$(GFLIB_SRCS)) - C_ASM_SRCS += $(wildcard $(C_SUBDIR)/*.s $(C_SUBDIR)/*/*.s $(C_SUBDIR)/*/*/*.s) C_ASM_OBJS := $(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o,$(C_ASM_SRCS)) @@ -198,7 +193,7 @@ SONG_OBJS := $(patsubst $(SONG_SUBDIR)/%.s,$(SONG_BUILDDIR)/%.o,$(SONG_SRCS)) MID_SRCS := $(wildcard $(MID_SUBDIR)/*.mid) MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS)) -OBJS := $(C_OBJS) $(GFLIB_OBJS) $(C_ASM_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) +OBJS := $(C_OBJS) $(C_ASM_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS)) SUBDIRS := $(sort $(dir $(OBJS))) @@ -316,7 +311,7 @@ else endif else define C_DEP -$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2) +$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include $2) ifeq (,$$(KEEP_TEMPS)) @echo "$$(CC1) -o $$@ $$<" @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - @@ -330,33 +325,6 @@ endef $(foreach src, $(C_SRCS), $(eval $(call C_DEP,$(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(src)),$(src),$(patsubst $(C_SUBDIR)/%.c,%,$(src))))) endif -ifeq ($(NODEP),1) -$(GFLIB_BUILDDIR)/%.o: $(GFLIB_SUBDIR)/%.c $$(c_dep) -ifeq (,$(KEEP_TEMPS)) - @echo "$(CC1) -o $@ $<" - @$(CPP) $(CPPFLAGS) $< | $(PREPROC) $< charmap.txt -i | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ - -else - @$(CPP) $(CPPFLAGS) $< -o $(GFLIB_BUILDDIR)/$*.i - @$(PREPROC) $(GFLIB_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(GFLIB_BUILDDIR)/$*.s - @echo -e ".text\n\t.align\t2, 0\n" >> $(GFLIB_BUILDDIR)/$*.s - $(AS) $(ASFLAGS) -o $@ $(GFLIB_BUILDDIR)/$*.s -endif -else -define GFLIB_DEP -$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2) -ifeq (,$$(KEEP_TEMPS)) - @echo "$$(CC1) -o $$@ $$<" - @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - -else - @$$(CPP) $$(CPPFLAGS) $$< -o $$(GFLIB_BUILDDIR)/$3.i - @$$(PREPROC) $$(GFLIB_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(GFLIB_BUILDDIR)/$3.s - @echo -e ".text\n\t.align\t2, 0\n" >> $$(GFLIB_BUILDDIR)/$3.s - $$(AS) $$(ASFLAGS) -o $$@ $$(GFLIB_BUILDDIR)/$3.s -endif -endef -$(foreach src, $(GFLIB_SRCS), $(eval $(call GFLIB_DEP,$(patsubst $(GFLIB_SUBDIR)/%.c,$(GFLIB_BUILDDIR)/%.o, $(src)),$(src),$(patsubst $(GFLIB_SUBDIR)/%.c,%, $(src))))) -endif - ifeq ($(NODEP),1) $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@ diff --git a/gflib/bg.c b/gflib/bg.c deleted file mode 100644 index ec7c2113b..000000000 --- a/gflib/bg.c +++ /dev/null @@ -1,1248 +0,0 @@ -#include -#include "global.h" -#include "bg.h" -#include "dma3.h" -#include "gpu_regs.h" - -#define DISPCNT_ALL_BG_AND_MODE_BITS (DISPCNT_BG_ALL_ON | 0x7) - -struct BgControl -{ - struct BgConfig { - u8 visible:1; - u8 unknown_1:1; - u8 screenSize:2; - u8 priority:2; - u8 mosaic:1; - u8 wraparound:1; - - u8 charBaseIndex:2; - u8 mapBaseIndex:5; - u8 paletteMode:1; - - u8 unknown_2; // Assigned to but never read - u8 unknown_3; // Assigned to but never read - } configs[NUM_BACKGROUNDS]; - - u16 bgVisibilityAndMode; -}; - -struct BgConfig2 -{ - u32 baseTile:10; - u32 basePalette:4; - u32 unk_3:18; - - void* tilemap; - s32 bg_x; - s32 bg_y; -}; - -static struct BgControl sGpuBgConfigs; -static struct BgConfig2 sGpuBgConfigs2[NUM_BACKGROUNDS]; -static u32 sDmaBusyBitfield[NUM_BACKGROUNDS]; - -u32 gUnneededFireRedVariable; - -static const struct BgConfig sZeroedBgControlStruct = { 0 }; - -void ResetBgs(void) -{ - ResetBgControlStructs(); - sGpuBgConfigs.bgVisibilityAndMode = 0; - SetTextModeAndHideBgs(); -} - -static void SetBgModeInternal(u8 bgMode) -{ - sGpuBgConfigs.bgVisibilityAndMode &= ~0x7; - sGpuBgConfigs.bgVisibilityAndMode |= bgMode; -} - -u8 GetBgMode(void) -{ - return sGpuBgConfigs.bgVisibilityAndMode & 0x7; -} - -void ResetBgControlStructs(void) -{ - int i; - - for (i = 0; i < NUM_BACKGROUNDS; i++) - { - sGpuBgConfigs.configs[i] = sZeroedBgControlStruct; - } -} - -void Unused_ResetBgControlStruct(u8 bg) -{ - if (!IsInvalidBg(bg)) - { - sGpuBgConfigs.configs[bg] = sZeroedBgControlStruct; - } -} - -enum -{ - BG_CTRL_ATTR_VISIBLE = 1, - BG_CTRL_ATTR_CHARBASEINDEX = 2, - BG_CTRL_ATTR_MAPBASEINDEX = 3, - BG_CTRL_ATTR_SCREENSIZE = 4, - BG_CTRL_ATTR_PALETTEMODE = 5, - BG_CTRL_ATTR_PRIORITY = 6, - BG_CTRL_ATTR_MOSAIC = 7, - BG_CTRL_ATTR_WRAPAROUND = 8, -}; - -static void SetBgControlAttributes(u8 bg, u8 charBaseIndex, u8 mapBaseIndex, u8 screenSize, u8 paletteMode, u8 priority, u8 mosaic, u8 wraparound) -{ - if (!IsInvalidBg(bg)) - { - if (charBaseIndex != 0xFF) - { - sGpuBgConfigs.configs[bg].charBaseIndex = charBaseIndex; - } - - if (mapBaseIndex != 0xFF) - { - sGpuBgConfigs.configs[bg].mapBaseIndex = mapBaseIndex; - } - - if (screenSize != 0xFF) - { - sGpuBgConfigs.configs[bg].screenSize = screenSize; - } - - if (paletteMode != 0xFF) - { - sGpuBgConfigs.configs[bg].paletteMode = paletteMode; - } - - if (priority != 0xFF) - { - sGpuBgConfigs.configs[bg].priority = priority; - } - - if (mosaic != 0xFF) - { - sGpuBgConfigs.configs[bg].mosaic = mosaic; - } - - if (wraparound != 0xFF) - { - sGpuBgConfigs.configs[bg].wraparound = wraparound; - } - - sGpuBgConfigs.configs[bg].unknown_2 = 0; - sGpuBgConfigs.configs[bg].unknown_3 = 0; - - sGpuBgConfigs.configs[bg].visible = 1; - } -} - -static u16 GetBgControlAttribute(u8 bg, u8 attributeId) -{ - if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) - { - switch (attributeId) - { - case BG_CTRL_ATTR_VISIBLE: - return sGpuBgConfigs.configs[bg].visible; - case BG_CTRL_ATTR_CHARBASEINDEX: - return sGpuBgConfigs.configs[bg].charBaseIndex; - case BG_CTRL_ATTR_MAPBASEINDEX: - return sGpuBgConfigs.configs[bg].mapBaseIndex; - case BG_CTRL_ATTR_SCREENSIZE: - return sGpuBgConfigs.configs[bg].screenSize; - case BG_CTRL_ATTR_PALETTEMODE: - return sGpuBgConfigs.configs[bg].paletteMode; - case BG_CTRL_ATTR_PRIORITY: - return sGpuBgConfigs.configs[bg].priority; - case BG_CTRL_ATTR_MOSAIC: - return sGpuBgConfigs.configs[bg].mosaic; - case BG_CTRL_ATTR_WRAPAROUND: - return sGpuBgConfigs.configs[bg].wraparound; - } - } - - return 0xFF; -} - -u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode) -{ - u16 offset; - s8 cursor; - - if (IsInvalidBg(bg) || !sGpuBgConfigs.configs[bg].visible) - return -1; - - switch (mode) - { - case 0x1: - offset = sGpuBgConfigs.configs[bg].charBaseIndex * BG_CHAR_SIZE; - offset = destOffset + offset; - cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); - if (cursor == -1) - return -1; - break; - case 0x2: - offset = sGpuBgConfigs.configs[bg].mapBaseIndex * BG_SCREEN_SIZE; - offset = destOffset + offset; - cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); - if (cursor == -1) - return -1; - break; - default: - cursor = -1; - break; - } - - return cursor; -} - -static void ShowBgInternal(u8 bg) -{ - u16 value; - if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) - { - value = sGpuBgConfigs.configs[bg].priority | - (sGpuBgConfigs.configs[bg].charBaseIndex << 2) | - (sGpuBgConfigs.configs[bg].mosaic << 6) | - (sGpuBgConfigs.configs[bg].paletteMode << 7) | - (sGpuBgConfigs.configs[bg].mapBaseIndex << 8) | - (sGpuBgConfigs.configs[bg].wraparound << 13) | - (sGpuBgConfigs.configs[bg].screenSize << 14); - - SetGpuReg((bg << 1) + REG_OFFSET_BG0CNT, value); - - sGpuBgConfigs.bgVisibilityAndMode |= 1 << (bg + 8); - sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; - } -} - -static void HideBgInternal(u8 bg) -{ - if (!IsInvalidBg(bg)) - { - sGpuBgConfigs.bgVisibilityAndMode &= ~(1 << (bg + 8)); - sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; - } -} - -static void SyncBgVisibilityAndMode(void) -{ - SetGpuReg(REG_OFFSET_DISPCNT, (GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS) | sGpuBgConfigs.bgVisibilityAndMode); -} - -void SetTextModeAndHideBgs(void) -{ - SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS); -} - -static void SetBgAffineInternal(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) -{ - struct BgAffineSrcData src; - struct BgAffineDstData dest; - - switch (sGpuBgConfigs.bgVisibilityAndMode & 0x7) - { - default: - case 0: - return; - case 1: - if (bg != 2) - return; - break; - case 2: - if (bg != 2 && bg != 3) - return; - break; - } - - src.texX = srcCenterX; - src.texY = srcCenterY; - src.scrX = dispCenterX; - src.scrY = dispCenterY; - src.sx = scaleX; - src.sy = scaleY; - src.alpha = rotationAngle; - - BgAffineSet(&src, &dest, 1); - - SetGpuReg(REG_OFFSET_BG2PA, dest.pa); - SetGpuReg(REG_OFFSET_BG2PB, dest.pb); - SetGpuReg(REG_OFFSET_BG2PC, dest.pc); - SetGpuReg(REG_OFFSET_BG2PD, dest.pd); - SetGpuReg(REG_OFFSET_BG2PA, dest.pa); - SetGpuReg(REG_OFFSET_BG2X_L, (s16)(dest.dx)); - SetGpuReg(REG_OFFSET_BG2X_H, (s16)(dest.dx >> 16)); - SetGpuReg(REG_OFFSET_BG2Y_L, (s16)(dest.dy)); - SetGpuReg(REG_OFFSET_BG2Y_H, (s16)(dest.dy >> 16)); -} - -bool8 IsInvalidBg(u8 bg) -{ - if (bg >= NUM_BACKGROUNDS) - return TRUE; - else - return FALSE; -} - -int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4) -{ - return 0; -} - -void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable) -{ - int i; - ResetBgs(); - - for (i = 0; i < NUM_BACKGROUNDS; i++) - { - sDmaBusyBitfield[i] = 0; - } - - gUnneededFireRedVariable = leftoverFireRedLeafGreenVariable; -} - -void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates) -{ - int i; - u8 bg; - - SetBgModeInternal(bgMode); - ResetBgControlStructs(); - - for (i = 0; i < numTemplates; i++) - { - bg = templates[i].bg; - if (bg < NUM_BACKGROUNDS) - { - SetBgControlAttributes(bg, - templates[i].charBaseIndex, - templates[i].mapBaseIndex, - templates[i].screenSize, - templates[i].paletteMode, - templates[i].priority, - 0, - 0); - - sGpuBgConfigs2[bg].baseTile = templates[i].baseTile; - sGpuBgConfigs2[bg].basePalette = 0; - sGpuBgConfigs2[bg].unk_3 = 0; - - sGpuBgConfigs2[bg].tilemap = NULL; - sGpuBgConfigs2[bg].bg_x = 0; - sGpuBgConfigs2[bg].bg_y = 0; - } - } -} - -void InitBgFromTemplate(const struct BgTemplate *template) -{ - u8 bg = template->bg; - - if (bg < NUM_BACKGROUNDS) - { - SetBgControlAttributes(bg, - template->charBaseIndex, - template->mapBaseIndex, - template->screenSize, - template->paletteMode, - template->priority, - 0, - 0); - - sGpuBgConfigs2[bg].baseTile = template->baseTile; - sGpuBgConfigs2[bg].basePalette = 0; - sGpuBgConfigs2[bg].unk_3 = 0; - - sGpuBgConfigs2[bg].tilemap = NULL; - sGpuBgConfigs2[bg].bg_x = 0; - sGpuBgConfigs2[bg].bg_y = 0; - } -} - -void SetBgMode(u8 bgMode) -{ - SetBgModeInternal(bgMode); -} - -u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset) -{ - u16 tileOffset; - u8 cursor; - - if (GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE) == 0) - { - tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x20; - } - else - { - tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x40; - } - - cursor = LoadBgVram(bg, src, size, tileOffset, DISPCNT_MODE_1); - - if (cursor == 0xFF) - { - return -1; - } - - sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); - - if (gUnneededFireRedVariable == 1) - { - DummiedOutFireRedLeafGreenTileAllocFunc(bg, tileOffset / 0x20, size / 0x20, 1); - } - - return cursor; -} - -u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset) -{ - u8 cursor = LoadBgVram(bg, src, size, destOffset * 2, DISPCNT_MODE_2); - - if (cursor == 0xFF) - { - return -1; - } - - sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); - - return cursor; -} - -u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset) -{ - s8 cursor; - - if (!IsInvalidBg32(bg)) - { - u16 paletteOffset = (sGpuBgConfigs2[bg].basePalette * 0x20) + (destOffset * 2); - cursor = RequestDma3Copy(src, (void*)(paletteOffset + BG_PLTT), size, 0); - - if (cursor == -1) - { - return -1; - } - } - else - { - return -1; - } - - sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); - - return (u8)cursor; -} - -bool8 IsDma3ManagerBusyWithBgCopy(void) -{ - int i; - - for (i = 0; i < 0x80; i++) - { - u8 div = i / 0x20; - u8 mod = i % 0x20; - - if ((sDmaBusyBitfield[div] & (1 << mod))) - { - s8 reqSpace = CheckForSpaceForDma3Request(i); - if (reqSpace == -1) - { - return TRUE; - } - - sDmaBusyBitfield[div] &= ~(1 << mod); - } - } - - return FALSE; -} - -void ShowBg(u8 bg) -{ - ShowBgInternal(bg); - SyncBgVisibilityAndMode(); -} - -void HideBg(u8 bg) -{ - HideBgInternal(bg); - SyncBgVisibilityAndMode(); -} - -void SetBgAttribute(u8 bg, u8 attributeId, u8 value) -{ - switch (attributeId) - { - case BG_ATTR_CHARBASEINDEX: - SetBgControlAttributes(bg, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_MAPBASEINDEX: - SetBgControlAttributes(bg, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_SCREENSIZE: - SetBgControlAttributes(bg, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_PALETTEMODE: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_PRIORITY: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF); - break; - case BG_ATTR_MOSAIC: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF); - break; - case BG_ATTR_WRAPAROUND: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value); - break; - } -} - -u16 GetBgAttribute(u8 bg, u8 attributeId) -{ - switch (attributeId) - { - case BG_ATTR_CHARBASEINDEX: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_CHARBASEINDEX); - case BG_ATTR_MAPBASEINDEX: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_MAPBASEINDEX); - case BG_ATTR_SCREENSIZE: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - case BG_ATTR_PALETTEMODE: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE); - case BG_ATTR_PRIORITY: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_PRIORITY); - case BG_ATTR_MOSAIC: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_MOSAIC); - case BG_ATTR_WRAPAROUND: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_WRAPAROUND); - case BG_ATTR_METRIC: - switch (GetBgType(bg)) - { - case 0: - return GetBgMetricTextMode(bg, 0) * 0x800; - case 1: - return GetBgMetricAffineMode(bg, 0) * 0x100; - default: - return 0; - } - case BG_ATTR_TYPE: - return GetBgType(bg); - case BG_ATTR_BASETILE: - return sGpuBgConfigs2[bg].baseTile; - default: - return -1; - } -} - -s32 ChangeBgX(u8 bg, s32 value, u8 op) -{ - u8 mode; - u16 temp1; - u16 temp2; - - if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - return -1; - } - - switch (op) - { - case 0: - default: - sGpuBgConfigs2[bg].bg_x = value; - break; - case 1: - sGpuBgConfigs2[bg].bg_x += value; - break; - case 2: - sGpuBgConfigs2[bg].bg_x -= value; - break; - } - - mode = GetBgMode(); - - switch (bg) - { - case 0: - temp1 = sGpuBgConfigs2[0].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG0HOFS, temp1); - break; - case 1: - temp1 = sGpuBgConfigs2[1].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG1HOFS, temp1); - break; - case 2: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[2].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG2HOFS, temp1); - } - else - { - temp1 = sGpuBgConfigs2[2].bg_x >> 0x10; - temp2 = sGpuBgConfigs2[2].bg_x & 0xFFFF; - SetGpuReg(REG_OFFSET_BG2X_H, temp1); - SetGpuReg(REG_OFFSET_BG2X_L, temp2); - } - break; - case 3: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[3].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG3HOFS, temp1); - } - else if (mode == 2) - { - temp1 = sGpuBgConfigs2[3].bg_x >> 0x10; - temp2 = sGpuBgConfigs2[3].bg_x & 0xFFFF; - SetGpuReg(REG_OFFSET_BG3X_H, temp1); - SetGpuReg(REG_OFFSET_BG3X_L, temp2); - } - break; - } - - return sGpuBgConfigs2[bg].bg_x; -} - -s32 GetBgX(u8 bg) -{ - if (IsInvalidBg32(bg)) - return -1; - else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - return -1; - else - return sGpuBgConfigs2[bg].bg_x; -} - -s32 ChangeBgY(u8 bg, s32 value, u8 op) -{ - u8 mode; - u16 temp1; - u16 temp2; - - if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - return -1; - } - - switch (op) - { - case 0: - default: - sGpuBgConfigs2[bg].bg_y = value; - break; - case 1: - sGpuBgConfigs2[bg].bg_y += value; - break; - case 2: - sGpuBgConfigs2[bg].bg_y -= value; - break; - } - - mode = GetBgMode(); - - switch (bg) - { - case 0: - temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG0VOFS, temp1); - break; - case 1: - temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG1VOFS, temp1); - break; - case 2: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG2VOFS, temp1); - } - else - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; - SetGpuReg(REG_OFFSET_BG2Y_H, temp1); - SetGpuReg(REG_OFFSET_BG2Y_L, temp2); - } - break; - case 3: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG3VOFS, temp1); - } - else if (mode == 2) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; - SetGpuReg(REG_OFFSET_BG3Y_H, temp1); - SetGpuReg(REG_OFFSET_BG3Y_L, temp2); - } - break; - } - - return sGpuBgConfigs2[bg].bg_y; -} - -s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op) -{ - u8 mode; - u16 temp1; - u16 temp2; - - if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - return -1; - } - - switch (op) - { - case 0: - default: - sGpuBgConfigs2[bg].bg_y = value; - break; - case 1: - sGpuBgConfigs2[bg].bg_y += value; - break; - case 2: - sGpuBgConfigs2[bg].bg_y -= value; - break; - } - - mode = GetBgMode(); - - switch (bg) - { - case 0: - temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, temp1); - break; - case 1: - temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG1VOFS, temp1); - break; - case 2: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG2VOFS, temp1); - - } - else - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; - SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_H, temp1); - SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_L, temp2); - } - break; - case 3: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG3VOFS, temp1); - } - else if (mode == 2) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; - SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_H, temp1); - SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_L, temp2); - } - break; - } - - return sGpuBgConfigs2[bg].bg_y; -} - -s32 GetBgY(u8 bg) -{ - if (IsInvalidBg32(bg)) - return -1; - else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - return -1; - else - return sGpuBgConfigs2[bg].bg_y; -} - -void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) -{ - SetBgAffineInternal(bg, srcCenterX, srcCenterY, dispCenterX, dispCenterY, scaleX, scaleY, rotationAngle); -} - -u8 Unused_AdjustBgMosaic(u8 a1, u8 a2) -{ - u16 result = GetGpuReg(REG_OFFSET_MOSAIC); - s16 test1 = result & 0xF; - s16 test2 = (result >> 4) & 0xF; - - result &= 0xFF00; - - switch (a2) - { - case 0: - default: - test1 = a1 & 0xF; - test2 = a1 >> 0x4; - break; - case 1: - test1 = a1 & 0xF; - break; - case 2: - if ((test1 + a1) > 0xF) - { - test1 = 0xF; - } - else - { - test1 += a1; - } - break; - case 3: - if ((test1 - a1) < 0) - { - test1 = 0x0; - } - else - { - test1 -= a1; - } - break; - case 4: - test2 = a1 & 0xF; - break; - case 5: - if ((test2 + a1) > 0xF) - { - test2 = 0xF; - } - else - { - test2 += a1; - } - break; - case 6: - if ((test2 - a1) < 0) - { - test2 = 0x0; - } - else - { - test2 -= a1; - } - break; - } - - result |= ((test2 << 0x4) & 0xF0); - result |= (test1 & 0xF); - - SetGpuReg(REG_OFFSET_MOSAIC, result); - - return result; -} - -void SetBgTilemapBuffer(u8 bg, void *tilemap) -{ - if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - sGpuBgConfigs2[bg].tilemap = tilemap; - } -} - -void UnsetBgTilemapBuffer(u8 bg) -{ - if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - sGpuBgConfigs2[bg].tilemap = NULL; - } -} - -void* GetBgTilemapBuffer(u8 bg) -{ - if (IsInvalidBg32(bg)) - return NULL; - else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - return NULL; - else - return sGpuBgConfigs2[bg].tilemap; -} - -void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset) -{ - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - if (mode != 0) - CpuCopy16(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2)), mode); - else - LZ77UnCompWram(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2))); - } -} - -void CopyBgTilemapBufferToVram(u8 bg) -{ - u16 sizeToLoad; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - switch (GetBgType(bg)) - { - case 0: - sizeToLoad = GetBgMetricTextMode(bg, 0) * 0x800; - break; - case 1: - sizeToLoad = GetBgMetricAffineMode(bg, 0) * 0x100; - break; - default: - sizeToLoad = 0; - break; - } - LoadBgVram(bg, sGpuBgConfigs2[bg].tilemap, sizeToLoad, 0, 2); - } -} - -void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height) -{ - u16 destX16; - u16 destY16; - u16 mode; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - switch (GetBgType(bg)) - { - case 0: - { - const u16 * srcCopy = src; - for (destY16 = destY; destY16 < (destY + height); destY16++) - { - for (destX16 = destX; destX16 < (destX + width); destX16++) - { - ((u16*)sGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *srcCopy++; - } - } - break; - } - case 1: - { - const u8 * srcCopy = src; - mode = GetBgMetricAffineMode(bg, 0x1); - for (destY16 = destY; destY16 < (destY + height); destY16++) - { - for (destX16 = destX; destX16 < (destX + width); destX16++) - { - ((u8*)sGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *srcCopy++; - } - } - break; - } - } - } -} - -void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette) -{ - CopyRectToBgTilemapBufferRect(bg, src, 0, 0, rectWidth, rectHeight, destX, destY, rectWidth, rectHeight, palette, 0, 0); -} - -void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset) -{ - u16 screenWidth, screenHeight, screenSize; - u16 var; - const void *srcPtr; - u16 i, j; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - screenWidth = GetBgMetricTextMode(bg, 0x1) * 0x20; - screenHeight = GetBgMetricTextMode(bg, 0x2) * 0x20; - switch (GetBgType(bg)) - { - case 0: - srcPtr = src + ((srcY * srcWidth) + srcX) * 2; - for (i = destX; i < (destX + rectWidth); i++) - { - for (j = srcHeight; j < (srcHeight + destY); j++) - { - u16 index = GetTileMapIndexFromCoords(j, i, screenSize, screenWidth, screenHeight); - CopyTileMapEntry(srcPtr, sGpuBgConfigs2[bg].tilemap + (index * 2), rectHeight, palette1, tileOffset); - srcPtr += 2; - } - srcPtr += (srcWidth - destY) * 2; - } - break; - case 1: - srcPtr = src + ((srcY * srcWidth) + srcX); - var = GetBgMetricAffineMode(bg, 0x1); - for (i = destX; i < (destX + rectWidth); i++) - { - for (j = srcHeight; j < (srcHeight + destY); j++) - { - *(u8*)(sGpuBgConfigs2[bg].tilemap + ((var * i) + j)) = *(u8*)(srcPtr) + palette1; - srcPtr++; - } - srcPtr += (srcWidth - destY); - } - break; - } - } -} - -void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height) -{ - u16 x16; - u16 y16; - u16 mode; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - switch (GetBgType(bg)) - { - case 0: - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - ((u16*)sGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum; - } - } - break; - case 1: - mode = GetBgMetricAffineMode(bg, 0x1); - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - ((u8*)sGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum; - } - } - break; - } - } -} - -void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette) -{ - WriteSequenceToBgTilemapBuffer(bg, tileNum, x, y, width, height, palette, 0); -} - -void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta) -{ - u16 mode; - u16 mode2; - u16 attribute; - u16 mode3; - u16 x16, y16; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - mode = GetBgMetricTextMode(bg, 0x1) * 0x20; - mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20; - switch (GetBgType(bg)) - { - case 0: - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - CopyTileMapEntry(&firstTileNum, &((u16*)sGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0); - firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); - } - } - break; - case 1: - mode3 = GetBgMetricAffineMode(bg, 0x1); - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - ((u8*)sGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum; - firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); - } - } - break; - } - } -} - -u16 GetBgMetricTextMode(u8 bg, u8 whichMetric) -{ - u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - - switch (whichMetric) - { - case 0: - switch (screenSize) - { - case 0: - return 1; - case 1: - case 2: - return 2; - case 3: - return 4; - } - break; - case 1: - switch (screenSize) - { - case 0: - return 1; - case 1: - return 2; - case 2: - return 1; - case 3: - return 2; - } - break; - case 2: - switch (screenSize) - { - case 0: - case 1: - return 1; - case 2: - case 3: - return 2; - } - break; - } - return 0; -} - -u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric) -{ - u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - - switch (whichMetric) - { - case 0: - switch (screenSize) - { - case 0: - return 0x1; - case 1: - return 0x4; - case 2: - return 0x10; - case 3: - return 0x40; - } - break; - case 1: - case 2: - return 0x10 << screenSize; - } - return 0; -} - -u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight) -{ - x = x & (screenWidth - 1); - y = y & (screenHeight - 1); - - switch (screenSize) - { - case 0: - case 2: - break; - case 3: - if (y >= 0x20) - y += 0x20; - case 1: - if (x >= 0x20) - { - x -= 0x20; - y += 0x20; - } - break; - } - return (y * 0x20) + x; -} - -void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2) -{ - u16 var; - - switch (palette1) - { - case 0 ... 15: - var = ((*src + tileOffset) & 0xFFF) + ((palette1 + palette2) << 12); - break; - case 16: - var = *dest; - var &= 0xFC00; - var += palette2 << 12; - var |= (*src + tileOffset) & 0x3FF; - break; - default: - case 17 ... INT_MAX: - var = *src + tileOffset + (palette2 << 12); - break; - } - *dest = var; -} - -u32 GetBgType(u8 bg) -{ - u8 mode = GetBgMode(); - - switch (bg) - { - case 0: - case 1: - switch (mode) - { - case 0: - case 1: - return 0; - } - break; - case 2: - switch (mode) - { - case 0: - return 0; - case 1: - case 2: - return 1; - } - break; - case 3: - switch (mode) - { - case 0: - return 0; - case 2: - return 1; - } - break; - } - - return 0xFFFF; -} - -bool32 IsInvalidBg32(u8 bg) -{ - if (bg >= NUM_BACKGROUNDS) - return TRUE; - else - return FALSE; -} - -bool32 IsTileMapOutsideWram(u8 bg) -{ - if (sGpuBgConfigs2[bg].tilemap > (void*)IWRAM_END) - return TRUE; - else if (sGpuBgConfigs2[bg].tilemap == NULL) - return TRUE; - else - return FALSE; -} diff --git a/gflib/bg.h b/gflib/bg.h deleted file mode 100644 index 58fd1282c..000000000 --- a/gflib/bg.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef GUARD_BG_H -#define GUARD_BG_H - -struct BGCntrlBitfield // for the I/O registers -{ - volatile u16 priority:2; - volatile u16 charBaseBlock:2; - volatile u16 field_0_2:4; - volatile u16 field_1_0:5; - volatile u16 areaOverflowMode:1; - volatile u16 screenSize:2; -}; - -enum -{ - BG_ATTR_CHARBASEINDEX = 1, - BG_ATTR_MAPBASEINDEX, - BG_ATTR_SCREENSIZE, - BG_ATTR_PALETTEMODE, - BG_ATTR_MOSAIC, - BG_ATTR_WRAPAROUND, - BG_ATTR_PRIORITY, - BG_ATTR_METRIC, - BG_ATTR_TYPE, - BG_ATTR_BASETILE, -}; - -struct BgTemplate -{ - u16 bg:2; // 0x1, 0x2 -> 0x3 - u16 charBaseIndex:2; // 0x4, 0x8 -> 0xC - u16 mapBaseIndex:5; // 0x10, 0x20, 0x40, 0x80, 0x100 -> 0x1F0 - u16 screenSize:2; // 0x200, 0x400 -> 0x600 - u16 paletteMode:1; // 0x800 - u16 priority:2; // 0x1000, 0x2000 > 0x3000 - u16 baseTile:10; -}; - -void ResetBgs(void); -u8 GetBgMode(void); -void ResetBgControlStructs(void); -void Unused_ResetBgControlStruct(u8 bg); -u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode); -void SetTextModeAndHideBgs(void); -bool8 IsInvalidBg(u8 bg); -int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4); -void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); -void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates); -void InitBgFromTemplate(const struct BgTemplate *template); -void SetBgMode(u8 bgMode); -u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset); -u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset); -u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset); -bool8 IsDma3ManagerBusyWithBgCopy(void); -void ShowBg(u8 bg); -void HideBg(u8 bg); -void SetBgAttribute(u8 bg, u8 attributeId, u8 value); -u16 GetBgAttribute(u8 bg, u8 attributeId); -s32 ChangeBgX(u8 bg, s32 value, u8 op); -s32 GetBgX(u8 bg); -s32 ChangeBgY(u8 bg, s32 value, u8 op); -s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op); -s32 GetBgY(u8 bg); -void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle); -u8 Unused_AdjustBgMosaic(u8 a1, u8 a2); -void SetBgTilemapBuffer(u8 bg, void *tilemap); -void UnsetBgTilemapBuffer(u8 bg); -void* GetBgTilemapBuffer(u8 bg); -void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset); -void CopyBgTilemapBufferToVram(u8 bg); -void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height); -void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette); -void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset); -void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height); -void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette); -void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta); -u16 GetBgMetricTextMode(u8 bg, u8 whichMetric); -u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric); -u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight); -void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2); -u32 GetBgType(u8 bg); -bool32 IsInvalidBg32(u8 bg); -bool32 IsTileMapOutsideWram(u8 bg); - -#endif // GUARD_BG_H diff --git a/gflib/blit.c b/gflib/blit.c deleted file mode 100644 index bdbb2e2fd..000000000 --- a/gflib/blit.c +++ /dev/null @@ -1,209 +0,0 @@ -#include "global.h" -#include "blit.h" - -void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height) -{ - BlitBitmapRect4Bit(src, dst, srcX, srcY, dstX, dstY, width, height, 0xFF); -} - -void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey) -{ - s32 xEnd; - s32 yEnd; - s32 multiplierSrcY; - s32 multiplierDstY; - s32 loopSrcY, loopDstY; - s32 loopSrcX, loopDstX; - const u8 *pixelsSrc; - u8 *pixelsDst; - s32 toOrr; - s32 toAnd; - s32 toShift; - - if (dst->width - dstX < width) - xEnd = (dst->width - dstX) + srcX; - else - xEnd = srcX + width; - - if (dst->height - dstY < height) - yEnd = (dst->height - dstY) + srcY; - else - yEnd = height + srcY; - - multiplierSrcY = (src->width + (src->width & 7)) >> 3; - multiplierDstY = (dst->width + (dst->width & 7)) >> 3; - - if (colorKey == 0xFF) - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); - pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); - toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); - toShift = ((loopDstX & 1) << 2); - toOrr <<= toShift; - toAnd = 0xF0 >> (toShift); - *pixelsDst = toOrr | (*pixelsDst & toAnd); - } - } - } - else - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); - pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); - toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); - if (toOrr != colorKey) - { - toShift = ((loopDstX & 1) << 2); - toOrr <<= toShift; - toAnd = 0xF0 >> (toShift); - *pixelsDst = toOrr | (*pixelsDst & toAnd); - } - } - } - } -} - -void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) -{ - s32 xEnd; - s32 yEnd; - s32 multiplierY; - s32 loopX, loopY; - u8 toOrr1, toOrr2; - - xEnd = x + width; - if (xEnd > surface->width) - xEnd = surface->width; - - yEnd = y + height; - if (yEnd > surface->height) - yEnd = surface->height; - - multiplierY = (surface->width + (surface->width & 7)) >> 3; - toOrr1 = fillValue << 4; - toOrr2 = fillValue & 0xF; - - for (loopY = y; loopY < yEnd; loopY++) - { - for (loopX = x; loopX < xEnd; loopX++) - { - u8 *pixels = surface->pixels + ((loopX >> 1) & 3) + ((loopX >> 3) << 5) + (((loopY >> 3) * multiplierY) << 5) + ((u32)(loopY << 0x1d) >> 0x1B); - if ((loopX << 0x1F) != 0) - *pixels = toOrr1 | (*pixels & 0xF); - else - *pixels = toOrr2 | (*pixels & 0xF0); - } - } -} - -void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset) -{ - s32 palOffsetBits; - s32 xEnd; - s32 yEnd; - s32 multiplierSrcY; - s32 multiplierDstY; - s32 loopSrcY, loopDstY; - s32 loopSrcX, loopDstX; - const u8 *pixelsSrc; - u8 *pixelsDst; - s32 colorKeyBits; - - palOffsetBits = (u32)(paletteOffset << 0x1C) >> 0x18; - colorKeyBits = (u32)(colorKey << 0x1C) >> 0x18; - - if (dst->width - dstX < width) - xEnd = (dst->width - dstX) + srcX; - else - xEnd = width + srcX; - - if (dst->height - dstY < height) - yEnd = (srcY + dst->height) - dstY; - else - yEnd = srcY + height; - - multiplierSrcY = (src->width + (src->width & 7)) >> 3; - multiplierDstY = (dst->width + (dst->width & 7)) >> 3; - - if (colorKey == 0xFF) - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); - if (loopSrcX & 1) - { - *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); - } - else - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); - } - } - } - } - else - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - if (loopSrcX & 1) - { - if ((*pixelsSrc & 0xF0) != colorKeyBits) - { - pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); - *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); - } - } - else - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - if ((*pixelsSrc & 0xF) != colorKey) - { - pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); - *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); - } - } - } - } - } -} - -void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) -{ - s32 xEnd; - s32 yEnd; - s32 multiplierY; - s32 loopX, loopY; - - xEnd = x + width; - if (xEnd > surface->width) - xEnd = surface->width; - - yEnd = y + height; - if (yEnd > surface->height) - yEnd = surface->height; - - multiplierY = (surface->width + (surface->width & 7)) >> 3; - - for (loopY = y; loopY < yEnd; loopY++) - { - for (loopX = x; loopX < xEnd; loopX++) - { - u8 *pixels = surface->pixels + (loopX & 7) + ((loopX >> 3) << 6) + (((loopY >> 3) * multiplierY) << 6) + ((u32)(loopY << 0x1d) >> 0x1a); - *pixels = fillValue; - } - } -} diff --git a/gflib/blit.h b/gflib/blit.h deleted file mode 100644 index 78f67766e..000000000 --- a/gflib/blit.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef GUARD_BLIT_H -#define GUARD_BLIT_H - -struct Bitmap -{ - u8 *pixels; - u32 width:16; - u32 height:16; -}; - -void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height); -void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey); -void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); -void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset); -void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); - -#endif // GUARD_BLIT_H diff --git a/gflib/dma3.h b/gflib/dma3.h deleted file mode 100644 index 8eff34f55..000000000 --- a/gflib/dma3.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef GUARD_DMA3_H -#define GUARD_DMA3_H - -// Maximum amount of data we will transfer in one operation -#define MAX_DMA_BLOCK_SIZE 0x1000 - -#define Dma3CopyLarge_(src, dest, size, bit) \ -{ \ - const void *_src = src; \ - void *_dest = dest; \ - u32 _size = size; \ - while (1) \ - { \ - if (_size <= MAX_DMA_BLOCK_SIZE) \ - { \ - DmaCopy##bit(3, _src, _dest, _size); \ - break; \ - } \ - DmaCopy##bit(3, _src, _dest, MAX_DMA_BLOCK_SIZE); \ - _src += MAX_DMA_BLOCK_SIZE; \ - _dest += MAX_DMA_BLOCK_SIZE; \ - _size -= MAX_DMA_BLOCK_SIZE; \ - } \ -} - -#define Dma3CopyLarge16_(src, dest, size) Dma3CopyLarge_(src, dest, size, 16) -#define Dma3CopyLarge32_(src, dest, size) Dma3CopyLarge_(src, dest, size, 32) - -#define Dma3FillLarge_(value, dest, size, bit) \ -{ \ - void *_dest = dest; \ - u32 _size = size; \ - while (1) \ - { \ - if (_size <= MAX_DMA_BLOCK_SIZE) \ - { \ - DmaFill##bit(3, value, _dest, _size); \ - break; \ - } \ - DmaFill##bit(3, value, _dest, MAX_DMA_BLOCK_SIZE); \ - _dest += MAX_DMA_BLOCK_SIZE; \ - _size -= MAX_DMA_BLOCK_SIZE; \ - } \ -} - -#define Dma3FillLarge16_(value, dest, size) Dma3FillLarge_(value, dest, size, 16) -#define Dma3FillLarge32_(value, dest, size) Dma3FillLarge_(value, dest, size, 32) - -void ClearDma3Requests(void); -void ProcessDma3Requests(void); -s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode); -s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode); -s16 CheckForSpaceForDma3Request(s16 index); - -#endif // GUARD_DMA3_H diff --git a/gflib/dma3_manager.c b/gflib/dma3_manager.c deleted file mode 100644 index d774efe8c..000000000 --- a/gflib/dma3_manager.c +++ /dev/null @@ -1,183 +0,0 @@ -#include "global.h" -#include "dma3.h" - -#define MAX_DMA_REQUESTS 128 - -#define DMA_REQUEST_COPY32 1 -#define DMA_REQUEST_FILL32 2 -#define DMA_REQUEST_COPY16 3 -#define DMA_REQUEST_FILL16 4 - -struct Dma3Request -{ - const u8 *src; - u8 *dest; - u16 size; - u16 mode; - u32 value; -}; - -static struct Dma3Request sDma3Requests[MAX_DMA_REQUESTS]; - -static vbool8 sDma3ManagerLocked; -static u8 sDma3RequestCursor; - -void ClearDma3Requests(void) -{ - int i; - - sDma3ManagerLocked = TRUE; - sDma3RequestCursor = 0; - - for (i = 0; i < MAX_DMA_REQUESTS; i++) - { - sDma3Requests[i].size = 0; - sDma3Requests[i].src = NULL; - sDma3Requests[i].dest = NULL; - } - - sDma3ManagerLocked = FALSE; -} - -void ProcessDma3Requests(void) -{ - u16 bytesTransferred; - - if (sDma3ManagerLocked) - return; - - bytesTransferred = 0; - - // as long as there are DMA requests to process (unless size or vblank is an issue), do not exit - while (sDma3Requests[sDma3RequestCursor].size != 0) - { - bytesTransferred += sDma3Requests[sDma3RequestCursor].size; - - if (bytesTransferred > 40 * 1024) - return; // don't transfer more than 40 KiB - if (*(u8 *)REG_ADDR_VCOUNT > 224) - return; // we're about to leave vblank, stop - - switch (sDma3Requests[sDma3RequestCursor].mode) - { - case DMA_REQUEST_COPY32: // regular 32-bit copy - Dma3CopyLarge32_(sDma3Requests[sDma3RequestCursor].src, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - case DMA_REQUEST_FILL32: // repeat a single 32-bit value across RAM - Dma3FillLarge32_(sDma3Requests[sDma3RequestCursor].value, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - case DMA_REQUEST_COPY16: // regular 16-bit copy - Dma3CopyLarge16_(sDma3Requests[sDma3RequestCursor].src, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - case DMA_REQUEST_FILL16: // repeat a single 16-bit value across RAM - Dma3FillLarge16_(sDma3Requests[sDma3RequestCursor].value, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - } - - // Free the request - sDma3Requests[sDma3RequestCursor].src = NULL; - sDma3Requests[sDma3RequestCursor].dest = NULL; - sDma3Requests[sDma3RequestCursor].size = 0; - sDma3Requests[sDma3RequestCursor].mode = 0; - sDma3Requests[sDma3RequestCursor].value = 0; - sDma3RequestCursor++; - - if (sDma3RequestCursor >= MAX_DMA_REQUESTS) // loop back to the first DMA request - sDma3RequestCursor = 0; - } -} - -s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode) -{ - int cursor; - int i = 0; - - sDma3ManagerLocked = TRUE; - cursor = sDma3RequestCursor; - - while (i < MAX_DMA_REQUESTS) - { - if (sDma3Requests[cursor].size == 0) // an empty request was found. - { - sDma3Requests[cursor].src = src; - sDma3Requests[cursor].dest = dest; - sDma3Requests[cursor].size = size; - - if (mode == 1) - sDma3Requests[cursor].mode = DMA_REQUEST_COPY32; - else - sDma3Requests[cursor].mode = DMA_REQUEST_COPY16; - - sDma3ManagerLocked = FALSE; - return cursor; - } - if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. - cursor = 0; - i++; - } - sDma3ManagerLocked = FALSE; - return -1; // no free DMA request was found -} - -s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode) -{ - int cursor; - int i = 0; - - cursor = sDma3RequestCursor; - sDma3ManagerLocked = TRUE; - - while (i < MAX_DMA_REQUESTS) - { - if (sDma3Requests[cursor].size == 0) // an empty request was found. - { - sDma3Requests[cursor].dest = dest; - sDma3Requests[cursor].size = size; - sDma3Requests[cursor].mode = mode; - sDma3Requests[cursor].value = value; - - if(mode == 1) - sDma3Requests[cursor].mode = DMA_REQUEST_FILL32; - else - sDma3Requests[cursor].mode = DMA_REQUEST_FILL16; - - sDma3ManagerLocked = FALSE; - return cursor; - } - if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. - cursor = 0; - i++; - } - sDma3ManagerLocked = FALSE; - return -1; // no free DMA request was found -} - -s16 CheckForSpaceForDma3Request(s16 index) -{ - int i = 0; - - if (index == -1) // check if all requests are free - { - while (i < MAX_DMA_REQUESTS) - { - if (sDma3Requests[i].size != 0) - return -1; - i++; - } - return 0; - } - else // check the specified request - { - if (sDma3Requests[index].size != 0) - return -1; - return 0; - } -} diff --git a/gflib/gpu_regs.c b/gflib/gpu_regs.c deleted file mode 100644 index 3bcc4fd93..000000000 --- a/gflib/gpu_regs.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "global.h" -#include "gpu_regs.h" - -#define GPU_REG_BUF_SIZE 0x60 - -#define GPU_REG_BUF(offset) (*(u16 *)(&sGpuRegBuffer[offset])) -#define GPU_REG(offset) (*(vu16 *)(REG_BASE + offset)) - -#define EMPTY_SLOT 0xFF - -static u8 sGpuRegBuffer[GPU_REG_BUF_SIZE]; -static u8 sGpuRegWaitingList[GPU_REG_BUF_SIZE]; -static volatile bool8 sGpuRegBufferLocked; -static volatile bool8 sShouldSyncRegIE; -static vu16 sRegIE; - -static void CopyBufferedValueToGpuReg(u8 regOffset); -static void SyncRegIE(void); -static void UpdateRegDispstatIntrBits(u16 regIE); - -void InitGpuRegManager(void) -{ - s32 i; - - for (i = 0; i < GPU_REG_BUF_SIZE; i++) - { - sGpuRegBuffer[i] = 0; - sGpuRegWaitingList[i] = EMPTY_SLOT; - } - - sGpuRegBufferLocked = FALSE; - sShouldSyncRegIE = FALSE; - sRegIE = 0; -} - -static void CopyBufferedValueToGpuReg(u8 regOffset) -{ - if (regOffset == REG_OFFSET_DISPSTAT) - { - REG_DISPSTAT &= ~(DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); - REG_DISPSTAT |= GPU_REG_BUF(REG_OFFSET_DISPSTAT); - } - else - { - GPU_REG(regOffset) = GPU_REG_BUF(regOffset); - } -} - -void CopyBufferedValuesToGpuRegs(void) -{ - if (!sGpuRegBufferLocked) - { - s32 i; - - for (i = 0; i < GPU_REG_BUF_SIZE; i++) - { - u8 regOffset = sGpuRegWaitingList[i]; - if (regOffset == EMPTY_SLOT) - return; - CopyBufferedValueToGpuReg(regOffset); - sGpuRegWaitingList[i] = EMPTY_SLOT; - } - } -} - -void SetGpuReg(u8 regOffset, u16 value) -{ - if (regOffset < GPU_REG_BUF_SIZE) - { - u16 vcount; - - GPU_REG_BUF(regOffset) = value; - vcount = REG_VCOUNT & 0xFF; - - if ((vcount >= 161 && vcount <= 225) || (REG_DISPCNT & DISPCNT_FORCED_BLANK)) - { - CopyBufferedValueToGpuReg(regOffset); - } - else - { - s32 i; - - sGpuRegBufferLocked = TRUE; - - for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) - { - if (sGpuRegWaitingList[i] == regOffset) - { - sGpuRegBufferLocked = FALSE; - return; - } - } - - sGpuRegWaitingList[i] = regOffset; - sGpuRegBufferLocked = FALSE; - } - } -} - -void SetGpuReg_ForcedBlank(u8 regOffset, u16 value) -{ - if (regOffset < GPU_REG_BUF_SIZE) - { - GPU_REG_BUF(regOffset) = value; - - if (REG_DISPCNT & DISPCNT_FORCED_BLANK) - { - CopyBufferedValueToGpuReg(regOffset); - } - else - { - s32 i; - - sGpuRegBufferLocked = TRUE; - - for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) - { - if (sGpuRegWaitingList[i] == regOffset) - { - sGpuRegBufferLocked = FALSE; - return; - } - } - - sGpuRegWaitingList[i] = regOffset; - sGpuRegBufferLocked = FALSE; - } - } -} - -u16 GetGpuReg(u8 regOffset) -{ - if (regOffset == REG_OFFSET_DISPSTAT) - return REG_DISPSTAT; - - if (regOffset == REG_OFFSET_VCOUNT) - return REG_VCOUNT; - - return GPU_REG_BUF(regOffset); -} - -void SetGpuRegBits(u8 regOffset, u16 mask) -{ - u16 regValue = GPU_REG_BUF(regOffset); - SetGpuReg(regOffset, regValue | mask); -} - -void ClearGpuRegBits(u8 regOffset, u16 mask) -{ - u16 regValue = GPU_REG_BUF(regOffset); - SetGpuReg(regOffset, regValue & ~mask); -} - -static void SyncRegIE(void) -{ - if (sShouldSyncRegIE) - { - u16 temp = REG_IME; - REG_IME = 0; - REG_IE = sRegIE; - REG_IME = temp; - sShouldSyncRegIE = FALSE; - } -} - -void EnableInterrupts(u16 mask) -{ - sRegIE |= mask; - sShouldSyncRegIE = TRUE; - SyncRegIE(); - UpdateRegDispstatIntrBits(sRegIE); -} - -void DisableInterrupts(u16 mask) -{ - sRegIE &= ~mask; - sShouldSyncRegIE = TRUE; - SyncRegIE(); - UpdateRegDispstatIntrBits(sRegIE); -} - -static void UpdateRegDispstatIntrBits(u16 regIE) -{ - u16 oldValue = GetGpuReg(REG_OFFSET_DISPSTAT) & (DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); - u16 newValue = 0; - - if (regIE & INTR_FLAG_VBLANK) - newValue |= DISPSTAT_VBLANK_INTR; - - if (regIE & INTR_FLAG_HBLANK) - newValue |= DISPSTAT_HBLANK_INTR; - - if (oldValue != newValue) - SetGpuReg(REG_OFFSET_DISPSTAT, newValue); -} diff --git a/gflib/gpu_regs.h b/gflib/gpu_regs.h deleted file mode 100644 index 89e0cb64b..000000000 --- a/gflib/gpu_regs.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef GUARD_GPU_REGS_H -#define GUARD_GPU_REGS_H - -// Exported type declarations - -// Exported RAM declarations - -// Exported ROM declarations -void InitGpuRegManager(void); -void CopyBufferedValuesToGpuRegs(void); -void SetGpuReg(u8 regOffset, u16 value); -void SetGpuReg_ForcedBlank(u8 regOffset, u16 value); -u16 GetGpuReg(u8 regOffset); -void SetGpuRegBits(u8 regOffset, u16 mask); -void ClearGpuRegBits(u8 regOffset, u16 mask); -void EnableInterrupts(u16 mask); -void DisableInterrupts(u16 mask); - -#endif //GUARD_GPU_REGS_H diff --git a/gflib/io_reg.c b/gflib/io_reg.c deleted file mode 100644 index 44364349d..000000000 --- a/gflib/io_reg.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "global.h" -#include "io_reg.h" -#include "gba/io_reg.h" - -static const u32 sUnused[] = { - 0, - 0, - (1 << 26) | (1 << 3), - (1 << 26) | (1 << 3) | (1 << 1), - (1 << 26) | (1 << 3) | (1 << 2), - (1 << 26) | (1 << 3) | (1 << 2) | (1 << 1), - (1 << 26) | (1 << 4), - (1 << 26) | (1 << 4) | (1 << 2), - (1 << 26) | (1 << 4) | (1 << 3), - (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2), - (1 << 26) | (1 << 4) | (1 << 1), - (1 << 26) | (1 << 4) | (1 << 2) | (1 << 1), - (1 << 26) | (1 << 4) | (1 << 3) | (1 << 1), - (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1), - (1 << 25) | (1 << 8), - (1 << 27) | (1 << 10), -}; - -const u16 gOverworldBackgroundLayerFlags[] = { - BLDCNT_TGT2_BG0, - BLDCNT_TGT2_BG1, - BLDCNT_TGT2_BG2, - BLDCNT_TGT2_BG3, -}; - -const u16 gOrbEffectBackgroundLayerFlags[] = { - BLDCNT_TGT1_BG0, - BLDCNT_TGT1_BG1, - BLDCNT_TGT1_BG2, - BLDCNT_TGT1_BG3, -}; diff --git a/gflib/io_reg.h b/gflib/io_reg.h deleted file mode 100644 index 82d2fc5ed..000000000 --- a/gflib/io_reg.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef GUARD_IO_REG_H -#define GUARD_IO_REG_H - -extern const u16 gOverworldBackgroundLayerFlags[]; -extern const u16 gOrbEffectBackgroundLayerFlags[]; - -#endif // GUARD_IO_REG_H diff --git a/gflib/malloc.c b/gflib/malloc.c deleted file mode 100644 index 38fc8939e..000000000 --- a/gflib/malloc.c +++ /dev/null @@ -1,210 +0,0 @@ -#include "global.h" - -static void *sHeapStart; -static u32 sHeapSize; -static u32 sFiller; // needed to align dma3_manager.o(.bss) - -#define MALLOC_SYSTEM_ID 0xA3A3 - -struct MemBlock { - // Whether this block is currently allocated. - bool16 flag; - - // Magic number used for error checking. Should equal MALLOC_SYSTEM_ID. - u16 magic; - - // Size of the block (not including this header struct). - u32 size; - - // Previous block pointer. Equals sHeapStart if this is the first block. - struct MemBlock *prev; - - // Next block pointer. Equals sHeapStart if this is the last block. - struct MemBlock *next; - - // Data in the memory block. (Arrays of length 0 are a GNU extension.) - u8 data[0]; -}; - -void PutMemBlockHeader(void *block, struct MemBlock *prev, struct MemBlock *next, u32 size) -{ - struct MemBlock *header = (struct MemBlock *)block; - - header->flag = FALSE; - header->magic = MALLOC_SYSTEM_ID; - header->size = size; - header->prev = prev; - header->next = next; -} - -void PutFirstMemBlockHeader(void *block, u32 size) -{ - PutMemBlockHeader(block, (struct MemBlock *)block, (struct MemBlock *)block, size - sizeof(struct MemBlock)); -} - -void *AllocInternal(void *heapStart, u32 size) -{ - struct MemBlock *pos = (struct MemBlock *)heapStart; - struct MemBlock *head = pos; - struct MemBlock *splitBlock; - u32 foundBlockSize; - - // Alignment - if (size & 3) - size = 4 * ((size / 4) + 1); - - for (;;) { - // Loop through the blocks looking for unused block that's big enough. - - if (!pos->flag) { - foundBlockSize = pos->size; - - if (foundBlockSize >= size) { - if (foundBlockSize - size < 2 * sizeof(struct MemBlock)) { - // The block isn't much bigger than the requested size, - // so just use it. - pos->flag = TRUE; - } else { - // The block is significantly bigger than the requested - // size, so split the rest into a separate block. - foundBlockSize -= sizeof(struct MemBlock); - foundBlockSize -= size; - - splitBlock = (struct MemBlock *)(pos->data + size); - - pos->flag = TRUE; - pos->size = size; - - PutMemBlockHeader(splitBlock, pos, pos->next, foundBlockSize); - - pos->next = splitBlock; - - if (splitBlock->next != head) - splitBlock->next->prev = splitBlock; - } - - return pos->data; - } - } - - if (pos->next == head) - return NULL; - - pos = pos->next; - } -} - -void FreeInternal(void *heapStart, void *pointer) -{ - if (pointer) { - struct MemBlock *head = (struct MemBlock *)heapStart; - struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); - block->flag = FALSE; - - // If the freed block isn't the last one, merge with the next block - // if it's not in use. - if (block->next != head) { - if (!block->next->flag) { - block->size += sizeof(struct MemBlock) + block->next->size; - block->next->magic = 0; - block->next = block->next->next; - if (block->next != head) - block->next->prev = block; - } - } - - // If the freed block isn't the first one, merge with the previous block - // if it's not in use. - if (block != head) { - if (!block->prev->flag) { - block->prev->next = block->next; - - if (block->next != head) - block->next->prev = block->prev; - - block->magic = 0; - block->prev->size += sizeof(struct MemBlock) + block->size; - } - } - } -} - -void *AllocZeroedInternal(void *heapStart, u32 size) -{ - void *mem = AllocInternal(heapStart, size); - - if (mem != NULL) { - if (size & 3) - size = 4 * ((size / 4) + 1); - - CpuFill32(0, mem, size); - } - - return mem; -} - -bool32 CheckMemBlockInternal(void *heapStart, void *pointer) -{ - struct MemBlock *head = (struct MemBlock *)heapStart; - struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); - - if (block->magic != MALLOC_SYSTEM_ID) - return FALSE; - - if (block->next->magic != MALLOC_SYSTEM_ID) - return FALSE; - - if (block->next != head && block->next->prev != block) - return FALSE; - - if (block->prev->magic != MALLOC_SYSTEM_ID) - return FALSE; - - if (block->prev != head && block->prev->next != block) - return FALSE; - - if (block->next != head && block->next != (struct MemBlock *)(block->data + block->size)) - return FALSE; - - return TRUE; -} - -void InitHeap(void *heapStart, u32 heapSize) -{ - sHeapStart = heapStart; - sHeapSize = heapSize; - PutFirstMemBlockHeader(heapStart, heapSize); -} - -void *Alloc(u32 size) -{ - return AllocInternal(sHeapStart, size); -} - -void *AllocZeroed(u32 size) -{ - return AllocZeroedInternal(sHeapStart, size); -} - -void Free(void *pointer) -{ - FreeInternal(sHeapStart, pointer); -} - -bool32 CheckMemBlock(void *pointer) -{ - return CheckMemBlockInternal(sHeapStart, pointer); -} - -bool32 CheckHeap() -{ - struct MemBlock *pos = (struct MemBlock *)sHeapStart; - - do { - if (!CheckMemBlockInternal(sHeapStart, pos->data)) - return FALSE; - pos = pos->next; - } while (pos != (struct MemBlock *)sHeapStart); - - return TRUE; -} diff --git a/gflib/malloc.h b/gflib/malloc.h deleted file mode 100644 index f2dcf6d46..000000000 --- a/gflib/malloc.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef GUARD_ALLOC_H -#define GUARD_ALLOC_H - -#define HEAP_SIZE 0x1C000 -#define malloc Alloc -#define calloc(ct, sz) AllocZeroed((ct) * (sz)) -#define free Free - -#define FREE_AND_SET_NULL(ptr) \ -{ \ - free(ptr); \ - ptr = NULL; \ -} - -extern u8 gHeap[]; - -void *Alloc(u32 size); -void *AllocZeroed(u32 size); -void Free(void *pointer); -void InitHeap(void *pointer, u32 size); - -#endif // GUARD_ALLOC_H diff --git a/gflib/sprite.c b/gflib/sprite.c deleted file mode 100644 index f97ecc712..000000000 --- a/gflib/sprite.c +++ /dev/null @@ -1,1775 +0,0 @@ -#include "global.h" -#include "sprite.h" -#include "main.h" -#include "palette.h" - -#define MAX_SPRITE_COPY_REQUESTS 64 - -#define OAM_MATRIX_COUNT 32 - -#define SET_SPRITE_TILE_RANGE(index, start, count) \ -{ \ - sSpriteTileRanges[index * 2] = start; \ - (sSpriteTileRanges + 1)[index * 2] = count; \ -} - -#define ALLOC_SPRITE_TILE(n) \ -{ \ - sSpriteTileAllocBitmap[(n) / 8] |= (1 << ((n) % 8)); \ -} - -#define FREE_SPRITE_TILE(n) \ -{ \ - sSpriteTileAllocBitmap[(n) / 8] &= ~(1 << ((n) % 8)); \ -} - -#define SPRITE_TILE_IS_ALLOCATED(n) ((sSpriteTileAllocBitmap[(n) / 8] >> ((n) % 8)) & 1) - - -struct SpriteCopyRequest -{ - const u8 *src; - u8 *dest; - u16 size; -}; - -struct OamDimensions32 -{ - s32 width; - s32 height; -}; - -struct OamDimensions -{ - s8 width; - s8 height; -}; - -static void UpdateOamCoords(void); -static void BuildSpritePriorities(void); -static void SortSprites(void); -static void CopyMatricesToOamBuffer(void); -static void AddSpritesToOamBuffer(void); -static u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -static void ResetOamMatrices(void); -static void ResetSprite(struct Sprite *sprite); -static s16 AllocSpriteTiles(u16 tileCount); -static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); -static void ResetAllSprites(void); -static void BeginAnim(struct Sprite *sprite); -static void ContinueAnim(struct Sprite *sprite); -static void AnimCmd_frame(struct Sprite *sprite); -static void AnimCmd_end(struct Sprite *sprite); -static void AnimCmd_jump(struct Sprite *sprite); -static void AnimCmd_loop(struct Sprite *sprite); -static void BeginAnimLoop(struct Sprite *sprite); -static void ContinueAnimLoop(struct Sprite *sprite); -static void JumpToTopOfAnimLoop(struct Sprite *sprite); -static void BeginAffineAnim(struct Sprite *sprite); -static void ContinueAffineAnim(struct Sprite *sprite); -static void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite); -static void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); -static void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); -static void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite); -static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix); -static u8 GetSpriteMatrixNum(struct Sprite *sprite); -static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); -static void AffineAnimStateRestartAnim(u8 matrixNum); -static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum); -static void AffineAnimStateReset(u8 matrixNum); -static void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); -static void DecrementAnimDelayCounter(struct Sprite *sprite); -static bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum); -static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); -static s16 ConvertScaleParam(s16 scale); -static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); -static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); -static u8 IndexOfSpriteTileTag(u16 tag); -static void AllocSpriteTileRange(u16 tag, u16 start, u16 count); -static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset); -static void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2); - -typedef void (*AnimFunc)(struct Sprite *); -typedef void (*AnimCmdFunc)(struct Sprite *); -typedef void (*AffineAnimCmdFunc)(u8 matrixNum, struct Sprite *); - -#define DUMMY_OAM_DATA \ -{ \ - .y = 160, \ - .affineMode = 0, \ - .objMode = 0, \ - .mosaic = 0, \ - .bpp = 0, \ - .shape = SPRITE_SHAPE(8x8), \ - .x = 304, \ - .matrixNum = 0, \ - .size = SPRITE_SIZE(8x8), \ - .tileNum = 0, \ - .priority = 3, /* lowest priority */ \ - .paletteNum = 0, \ - .affineParam = 0 \ -} - -#define ANIM_END 0xFFFF -#define AFFINE_ANIM_END 0x7FFF - -// forward declarations -const union AnimCmd * const gDummySpriteAnimTable[]; -const union AffineAnimCmd * const gDummySpriteAffineAnimTable[]; -const struct SpriteTemplate gDummySpriteTemplate; - -// Unreferenced data. Also unreferenced in R/S. -static const u8 sUnknownData[24] = -{ - 0x01, 0x04, 0x10, 0x40, - 0x02, 0x04, 0x08, 0x20, - 0x02, 0x04, 0x08, 0x20, - 0x01, 0x04, 0x10, 0x40, - 0x02, 0x04, 0x08, 0x20, - 0x02, 0x04, 0x08, 0x20, -}; - -static const u8 sCenterToCornerVecTable[3][4][2] = -{ - { // square - { -4, -4 }, - { -8, -8 }, - { -16, -16 }, - { -32, -32 }, - }, - { // horizontal rectangle - { -8, -4 }, - { -16, -4 }, - { -16, -8 }, - { -32, -16 }, - }, - { // vertical rectangle - { -4, -8 }, - { -4, -16 }, - { -8, -16 }, - { -16, -32 }, - }, -}; - -static const struct Sprite sDummySprite = -{ - .oam = DUMMY_OAM_DATA, - .anims = gDummySpriteAnimTable, - .images = NULL, - .affineAnims = gDummySpriteAffineAnimTable, - .template = &gDummySpriteTemplate, - .subspriteTables = NULL, - .callback = SpriteCallbackDummy, - .pos1 = { 304, 160 }, - .pos2 = { 0, 0 }, - .centerToCornerVecX = 0, - .centerToCornerVecY = 0, - .animNum = 0, - .animCmdIndex = 0, - .animDelayCounter = 0, - .animPaused = 0, - .affineAnimPaused = 0, - .animLoopCounter = 0, - .data = {0, 0, 0, 0, 0, 0, 0}, - .inUse = 0, - .coordOffsetEnabled = 0, - .invisible = FALSE, - .flags_3 = 0, - .flags_4 = 0, - .flags_5 = 0, - .flags_6 = 0, - .flags_7 = 0, - .hFlip = 0, - .vFlip = 0, - .animBeginning = 0, - .affineAnimBeginning = 0, - .animEnded = 0, - .affineAnimEnded = 0, - .usingSheet = 0, - .flags_f = 0, - .sheetTileStart = 0, - .subspriteTableNum = 0, - .subspriteMode = 0, - .subpriority = 0xFF -}; - -const struct OamData gDummyOamData = DUMMY_OAM_DATA; - -static const union AnimCmd sDummyAnim = { ANIM_END }; - -const union AnimCmd * const gDummySpriteAnimTable[] = { &sDummyAnim }; - -static const union AffineAnimCmd sDummyAffineAnim = { AFFINE_ANIM_END }; - -const union AffineAnimCmd * const gDummySpriteAffineAnimTable[] = { &sDummyAffineAnim }; - -const struct SpriteTemplate gDummySpriteTemplate = -{ - .tileTag = 0, - .paletteTag = 0xFFFF, - .oam = &gDummyOamData, - .anims = gDummySpriteAnimTable, - .images = NULL, - .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCallbackDummy -}; - -static const AnimFunc sAnimFuncs[] = -{ - ContinueAnim, - BeginAnim, -}; - -static const AnimFunc sAffineAnimFuncs[] = -{ - ContinueAffineAnim, - BeginAffineAnim, -}; - -static const AnimCmdFunc sAnimCmdFuncs[] = -{ - AnimCmd_loop, - AnimCmd_jump, - AnimCmd_end, - AnimCmd_frame, -}; - -static const AffineAnimCmdFunc sAffineAnimCmdFuncs[] = -{ - AffineAnimCmd_loop, - AffineAnimCmd_jump, - AffineAnimCmd_end, - AffineAnimCmd_frame, -}; - -static const struct OamDimensions32 sOamDimensions32[3][4] = -{ - [ST_OAM_SQUARE] = - { - [SPRITE_SIZE(8x8)] = { 8, 8 }, - [SPRITE_SIZE(16x16)] = { 16, 16 }, - [SPRITE_SIZE(32x32)] = { 32, 32 }, - [SPRITE_SIZE(64x64)] = { 64, 64 }, - }, - [ST_OAM_H_RECTANGLE] = - { - [SPRITE_SIZE(16x8)] = { 16, 8 }, - [SPRITE_SIZE(32x8)] = { 32, 8 }, - [SPRITE_SIZE(32x16)] = { 32, 16 }, - [SPRITE_SIZE(64x32)] = { 64, 32 }, - }, - [ST_OAM_V_RECTANGLE] = - { - [SPRITE_SIZE(8x16)] = { 8, 16 }, - [SPRITE_SIZE(8x32)] = { 8, 32 }, - [SPRITE_SIZE(16x32)] = { 16, 32 }, - [SPRITE_SIZE(32x64)] = { 32, 64 }, - }, -}; - -static const struct OamDimensions sOamDimensions[3][4] = -{ - [ST_OAM_SQUARE] = - { - [SPRITE_SIZE(8x8)] = { 8, 8 }, - [SPRITE_SIZE(16x16)] = { 16, 16 }, - [SPRITE_SIZE(32x32)] = { 32, 32 }, - [SPRITE_SIZE(64x64)] = { 64, 64 }, - }, - [ST_OAM_H_RECTANGLE] = - { - [SPRITE_SIZE(16x8)] = { 16, 8 }, - [SPRITE_SIZE(32x8)] = { 32, 8 }, - [SPRITE_SIZE(32x16)] = { 32, 16 }, - [SPRITE_SIZE(64x32)] = { 64, 32 }, - }, - [ST_OAM_V_RECTANGLE] = - { - [SPRITE_SIZE(8x16)] = { 8, 16 }, - [SPRITE_SIZE(8x32)] = { 8, 32 }, - [SPRITE_SIZE(16x32)] = { 16, 32 }, - [SPRITE_SIZE(32x64)] = { 32, 64 }, - }, -}; - -// iwram bss -static u16 sSpriteTileRangeTags[MAX_SPRITES]; -static u16 sSpriteTileRanges[MAX_SPRITES * 2]; -static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; -static u16 sSpritePaletteTags[16]; - -// iwram common -u32 gOamMatrixAllocBitmap; -u8 gReservedSpritePaletteCount; - -EWRAM_DATA struct Sprite gSprites[MAX_SPRITES + 1] = {0}; -EWRAM_DATA static u16 sSpritePriorities[MAX_SPRITES] = {0}; -EWRAM_DATA static u8 sSpriteOrder[MAX_SPRITES] = {0}; -EWRAM_DATA static bool8 sShouldProcessSpriteCopyRequests = 0; -EWRAM_DATA static u8 sSpriteCopyRequestCount = 0; -EWRAM_DATA static struct SpriteCopyRequest sSpriteCopyRequests[MAX_SPRITES] = {0}; -EWRAM_DATA u8 gOamLimit = 0; -EWRAM_DATA u16 gReservedSpriteTileCount = 0; -EWRAM_DATA static u8 sSpriteTileAllocBitmap[128] = {0}; -EWRAM_DATA s16 gSpriteCoordOffsetX = 0; -EWRAM_DATA s16 gSpriteCoordOffsetY = 0; -EWRAM_DATA struct OamMatrix gOamMatrices[OAM_MATRIX_COUNT] = {0}; -EWRAM_DATA bool8 gAffineAnimsDisabled = FALSE; - -void ResetSpriteData(void) -{ - ResetOamRange(0, 128); - ResetAllSprites(); - ClearSpriteCopyRequests(); - ResetAffineAnimData(); - FreeSpriteTileRanges(); - gOamLimit = 64; - gReservedSpriteTileCount = 0; - AllocSpriteTiles(0); - gSpriteCoordOffsetX = 0; - gSpriteCoordOffsetY = 0; -} - -void AnimateSprites(void) -{ - u8 i; - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - - if (sprite->inUse) - { - sprite->callback(sprite); - - if (sprite->inUse) - AnimateSprite(sprite); - } - } -} - -void BuildOamBuffer(void) -{ - u8 temp; - UpdateOamCoords(); - BuildSpritePriorities(); - SortSprites(); - temp = gMain.oamLoadDisabled; - gMain.oamLoadDisabled = TRUE; - AddSpritesToOamBuffer(); - CopyMatricesToOamBuffer(); - gMain.oamLoadDisabled = temp; - sShouldProcessSpriteCopyRequests = TRUE; -} - -void UpdateOamCoords(void) -{ - u8 i; - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - if (sprite->inUse && !sprite->invisible) - { - if (sprite->coordOffsetEnabled) - { - sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX; - sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY; - } - else - { - sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX; - sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY; - } - } - } -} - -void BuildSpritePriorities(void) -{ - u16 i; - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - u16 priority = sprite->subpriority | (sprite->oam.priority << 8); - sSpritePriorities[i] = priority; - } -} - -void SortSprites(void) -{ - u8 i; - for (i = 1; i < MAX_SPRITES; i++) - { - u8 j = i; - struct Sprite *sprite1 = &gSprites[sSpriteOrder[i - 1]]; - struct Sprite *sprite2 = &gSprites[sSpriteOrder[i]]; - u16 sprite1Priority = sSpritePriorities[sSpriteOrder[i - 1]]; - u16 sprite2Priority = sSpritePriorities[sSpriteOrder[i]]; - s16 sprite1Y = sprite1->oam.y; - s16 sprite2Y = sprite2->oam.y; - - if (sprite1Y >= DISPLAY_HEIGHT) - sprite1Y = sprite1Y - 256; - - if (sprite2Y >= DISPLAY_HEIGHT) - sprite2Y = sprite2Y - 256; - - if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite1->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite1->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite1Y > 128) - sprite1Y = sprite1Y - 256; - } - } - - if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite2->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite2->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite2Y > 128) - sprite2Y = sprite2Y - 256; - } - } - - while (j > 0 - && ((sprite1Priority > sprite2Priority) - || (sprite1Priority == sprite2Priority && sprite1Y < sprite2Y))) - { - u8 temp = sSpriteOrder[j]; - sSpriteOrder[j] = sSpriteOrder[j - 1]; - sSpriteOrder[j - 1] = temp; - - // UB: If j equals 1, then j-- makes j equal 0. - // Then, sSpriteOrder[-1] gets accessed below. - // Although this doesn't result in a bug in the ROM, - // the behavior is undefined. - j--; -#ifdef UBFIX - if (j == 0) - break; -#endif - - sprite1 = &gSprites[sSpriteOrder[j - 1]]; - sprite2 = &gSprites[sSpriteOrder[j]]; - sprite1Priority = sSpritePriorities[sSpriteOrder[j - 1]]; - sprite2Priority = sSpritePriorities[sSpriteOrder[j]]; - sprite1Y = sprite1->oam.y; - sprite2Y = sprite2->oam.y; - - if (sprite1Y >= DISPLAY_HEIGHT) - sprite1Y = sprite1Y - 256; - - if (sprite2Y >= DISPLAY_HEIGHT) - sprite2Y = sprite2Y - 256; - - if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite1->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite1->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite1Y > 128) - sprite1Y = sprite1Y - 256; - } - } - - if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite2->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite2->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite2Y > 128) - sprite2Y = sprite2Y - 256; - } - } - } - } -} - -void CopyMatricesToOamBuffer(void) -{ - u8 i; - for (i = 0; i < OAM_MATRIX_COUNT; i++) - { - u32 base = 4 * i; - gMain.oamBuffer[base + 0].affineParam = gOamMatrices[i].a; - gMain.oamBuffer[base + 1].affineParam = gOamMatrices[i].b; - gMain.oamBuffer[base + 2].affineParam = gOamMatrices[i].c; - gMain.oamBuffer[base + 3].affineParam = gOamMatrices[i].d; - } -} - -void AddSpritesToOamBuffer(void) -{ - u8 i = 0; - u8 oamIndex = 0; - - while (i < MAX_SPRITES) - { - struct Sprite *sprite = &gSprites[sSpriteOrder[i]]; - if (sprite->inUse && !sprite->invisible && AddSpriteToOamBuffer(sprite, &oamIndex)) - return; - i++; - } - - while (oamIndex < gOamLimit) - { - gMain.oamBuffer[oamIndex] = gDummyOamData; - oamIndex++; - } -} - -u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - if (!gSprites[i].inUse) - return CreateSpriteAt(i, template, x, y, subpriority); - - return MAX_SPRITES; -} - -u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - s16 i; - - for (i = MAX_SPRITES - 1; i > -1; i--) - if (!gSprites[i].inUse) - return CreateSpriteAt(i, template, x, y, subpriority); - - return MAX_SPRITES; -} - -u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)) -{ - u8 index = CreateSprite(&gDummySpriteTemplate, 0, 0, 31); - - if (index == MAX_SPRITES) - { - return MAX_SPRITES; - } - else - { - gSprites[index].invisible = TRUE; - gSprites[index].callback = callback; - return index; - } -} - -u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - struct Sprite *sprite = &gSprites[index]; - - ResetSprite(sprite); - - sprite->inUse = TRUE; - sprite->animBeginning = TRUE; - sprite->affineAnimBeginning = TRUE; - sprite->usingSheet = TRUE; - - sprite->subpriority = subpriority; - sprite->oam = *template->oam; - sprite->anims = template->anims; - sprite->affineAnims = template->affineAnims; - sprite->template = template; - sprite->callback = template->callback; - sprite->pos1.x = x; - sprite->pos1.y = y; - - CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); - - if (template->tileTag == 0xFFFF) - { - s16 tileNum; - sprite->images = template->images; - tileNum = AllocSpriteTiles((u8)(sprite->images->size / TILE_SIZE_4BPP)); - if (tileNum == -1) - { - ResetSprite(sprite); - return MAX_SPRITES; - } - sprite->oam.tileNum = tileNum; - sprite->usingSheet = FALSE; - sprite->sheetTileStart = 0; - } - else - { - sprite->sheetTileStart = GetSpriteTileStartByTag(template->tileTag); - SetSpriteSheetFrameTileNum(sprite); - } - - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - InitSpriteAffineAnim(sprite); - - if (template->paletteTag != 0xFFFF) - sprite->oam.paletteNum = IndexOfSpritePaletteTag(template->paletteTag); - - return index; -} - -u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - - if (!gSprites[i].inUse) - { - u8 index = CreateSpriteAt(i, template, x, y, subpriority); - - if (index == MAX_SPRITES) - return MAX_SPRITES; - - gSprites[i].callback(sprite); - - if (gSprites[i].inUse) - AnimateSprite(sprite); - - return index; - } - } - - return MAX_SPRITES; -} - -void DestroySprite(struct Sprite *sprite) -{ - if (sprite->inUse) - { - if (!sprite->usingSheet) - { - u16 i; - u16 tileEnd = (sprite->images->size / TILE_SIZE_4BPP) + sprite->oam.tileNum; - for (i = sprite->oam.tileNum; i < tileEnd; i++) - FREE_SPRITE_TILE(i); - } - ResetSprite(sprite); - } -} - -void ResetOamRange(u8 a, u8 b) -{ - u8 i; - - for (i = a; i < b; i++) - { - gMain.oamBuffer[i] = *(struct OamData *)&gDummyOamData; - } -} - -void LoadOam(void) -{ - if (!gMain.oamLoadDisabled) - CpuCopy32(gMain.oamBuffer, (void *)OAM, sizeof(gMain.oamBuffer)); -} - -void ClearSpriteCopyRequests(void) -{ - u8 i; - - sShouldProcessSpriteCopyRequests = FALSE; - sSpriteCopyRequestCount = 0; - - for (i = 0; i < MAX_SPRITE_COPY_REQUESTS; i++) - { - sSpriteCopyRequests[i].src = 0; - sSpriteCopyRequests[i].dest = 0; - sSpriteCopyRequests[i].size = 0; - } -} - -void ResetOamMatrices(void) -{ - u8 i; - for (i = 0; i < OAM_MATRIX_COUNT; i++) - { - // set to identity matrix - gOamMatrices[i].a = 0x0100; - gOamMatrices[i].b = 0x0000; - gOamMatrices[i].c = 0x0000; - gOamMatrices[i].d = 0x0100; - } -} - -void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d) -{ - gOamMatrices[matrixNum].a = a; - gOamMatrices[matrixNum].b = b; - gOamMatrices[matrixNum].c = c; - gOamMatrices[matrixNum].d = d; -} - -void ResetSprite(struct Sprite *sprite) -{ - *sprite = sDummySprite; -} - -void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode) -{ - u8 x = sCenterToCornerVecTable[shape][size][0]; - u8 y = sCenterToCornerVecTable[shape][size][1]; - - if (affineMode & ST_OAM_AFFINE_DOUBLE_MASK) - { - x *= 2; - y *= 2; - } - - sprite->centerToCornerVecX = x; - sprite->centerToCornerVecY = y; -} - -s16 AllocSpriteTiles(u16 tileCount) -{ - u16 i; - s16 start; - u16 numTilesFound; - - if (tileCount == 0) - { - // Free all unreserved tiles if the tile count is 0. - for (i = gReservedSpriteTileCount; i < TOTAL_OBJ_TILE_COUNT; i++) - FREE_SPRITE_TILE(i); - - return 0; - } - - i = gReservedSpriteTileCount; - - for (;;) - { - while (SPRITE_TILE_IS_ALLOCATED(i)) - { - i++; - - if (i == TOTAL_OBJ_TILE_COUNT) - return -1; - } - - start = i; - numTilesFound = 1; - - while (numTilesFound != tileCount) - { - i++; - - if (i == TOTAL_OBJ_TILE_COUNT) - return -1; - - if (!SPRITE_TILE_IS_ALLOCATED(i)) - numTilesFound++; - else - break; - } - - if (numTilesFound == tileCount) - break; - } - - for (i = start; i < tileCount + start; i++) - ALLOC_SPRITE_TILE(i); - - return start; -} - -u8 SpriteTileAllocBitmapOp(u16 bit, u8 op) -{ - u8 index = bit / 8; - u8 shift = bit % 8; - u8 val = bit % 8; - u8 retVal = 0; - - if (op == 0) - { - val = ~(1 << val); - sSpriteTileAllocBitmap[index] &= val; - } - else if (op == 1) - { - val = (1 << val); - sSpriteTileAllocBitmap[index] |= val; - } - else - { - retVal = 1 << shift; - retVal &= sSpriteTileAllocBitmap[index]; - } - - return retVal; -} - -void SpriteCallbackDummy(struct Sprite *sprite) -{ -} - -void ProcessSpriteCopyRequests(void) -{ - if (sShouldProcessSpriteCopyRequests) - { - u8 i = 0; - - while (sSpriteCopyRequestCount > 0) - { - CpuCopy16(sSpriteCopyRequests[i].src, sSpriteCopyRequests[i].dest, sSpriteCopyRequests[i].size); - sSpriteCopyRequestCount--; - i++; - } - - sShouldProcessSpriteCopyRequests = FALSE; - } -} - -void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images) -{ - if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) - { - sSpriteCopyRequests[sSpriteCopyRequestCount].src = images[index].data; - sSpriteCopyRequests[sSpriteCopyRequestCount].dest = (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileNum; - sSpriteCopyRequests[sSpriteCopyRequestCount].size = images[index].size; - sSpriteCopyRequestCount++; - } -} - -void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size) -{ - if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) - { - sSpriteCopyRequests[sSpriteCopyRequestCount].src = src; - sSpriteCopyRequests[sSpriteCopyRequestCount].dest = dest; - sSpriteCopyRequests[sSpriteCopyRequestCount].size = size; - sSpriteCopyRequestCount++; - } -} - -void CopyFromSprites(u8 *dest) -{ - u32 i; - u8 *src = (u8 *)gSprites; - for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) - { - *dest = *src; - dest++; - src++; - } -} - -void CopyToSprites(u8 *src) -{ - u32 i; - u8 *dest = (u8 *)gSprites; - for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) - { - *dest = *src; - src++; - dest++; - } -} - -void ResetAllSprites(void) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - ResetSprite(&gSprites[i]); - sSpriteOrder[i] = i; - } - - ResetSprite(&gSprites[i]); -} - -// UB: template pointer may point to freed temporary storage -void FreeSpriteTiles(struct Sprite *sprite) -{ - if (sprite->template->tileTag != 0xFFFF) - FreeSpriteTilesByTag(sprite->template->tileTag); -} - -// UB: template pointer may point to freed temporary storage -void FreeSpritePalette(struct Sprite *sprite) -{ - FreeSpritePaletteByTag(sprite->template->paletteTag); -} - -void FreeSpriteOamMatrix(struct Sprite *sprite) -{ - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - { - FreeOamMatrix(sprite->oam.matrixNum); - sprite->oam.affineMode = ST_OAM_AFFINE_OFF; - } -} - -void DestroySpriteAndFreeResources(struct Sprite *sprite) -{ - FreeSpriteTiles(sprite); - FreeSpritePalette(sprite); - FreeSpriteOamMatrix(sprite); - DestroySprite(sprite); -} - -void AnimateSprite(struct Sprite *sprite) -{ - sAnimFuncs[sprite->animBeginning](sprite); - - if (!gAffineAnimsDisabled) - sAffineAnimFuncs[sprite->affineAnimBeginning](sprite); -} - -void BeginAnim(struct Sprite *sprite) -{ - s16 imageValue; - u8 duration; - u8 hFlip; - u8 vFlip; - - sprite->animCmdIndex = 0; - sprite->animEnded = FALSE; - sprite->animLoopCounter = 0; - imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - - if (imageValue != -1) - { - sprite->animBeginning = FALSE; - duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - - if (duration) - duration--; - - sprite->animDelayCounter = duration; - - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - - if (sprite->usingSheet) - sprite->oam.tileNum = sprite->sheetTileStart + imageValue; - else - RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); - } -} - -void ContinueAnim(struct Sprite *sprite) -{ - if (sprite->animDelayCounter) - { - u8 hFlip; - u8 vFlip; - DecrementAnimDelayCounter(sprite); - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - } - else if (!sprite->animPaused) - { - s16 type; - s16 funcIndex; - sprite->animCmdIndex++; - type = sprite->anims[sprite->animNum][sprite->animCmdIndex].type; - funcIndex = 3; - if (type < 0) - funcIndex = type + 3; - sAnimCmdFuncs[funcIndex](sprite); - } -} - -void AnimCmd_frame(struct Sprite *sprite) -{ - s16 imageValue; - u8 duration; - u8 hFlip; - u8 vFlip; - - imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - - if (duration) - duration--; - - sprite->animDelayCounter = duration; - - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - - if (sprite->usingSheet) - sprite->oam.tileNum = sprite->sheetTileStart + imageValue; - else - RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); -} - -void AnimCmd_end(struct Sprite *sprite) -{ - sprite->animCmdIndex--; - sprite->animEnded = TRUE; -} - -void AnimCmd_jump(struct Sprite *sprite) -{ - s16 imageValue; - u8 duration; - u8 hFlip; - u8 vFlip; - - sprite->animCmdIndex = sprite->anims[sprite->animNum][sprite->animCmdIndex].jump.target; - - imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - - if (duration) - duration--; - - sprite->animDelayCounter = duration; - - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - - if (sprite->usingSheet) - sprite->oam.tileNum = sprite->sheetTileStart + imageValue; - else - RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); -} - -void AnimCmd_loop(struct Sprite *sprite) -{ - if (sprite->animLoopCounter) - ContinueAnimLoop(sprite); - else - BeginAnimLoop(sprite); -} - -void BeginAnimLoop(struct Sprite *sprite) -{ - sprite->animLoopCounter = sprite->anims[sprite->animNum][sprite->animCmdIndex].loop.count; - JumpToTopOfAnimLoop(sprite); - ContinueAnim(sprite); -} - -void ContinueAnimLoop(struct Sprite *sprite) -{ - sprite->animLoopCounter--; - JumpToTopOfAnimLoop(sprite); - ContinueAnim(sprite); -} - -void JumpToTopOfAnimLoop(struct Sprite *sprite) -{ - if (sprite->animLoopCounter) - { - sprite->animCmdIndex--; - - while (sprite->anims[sprite->animNum][sprite->animCmdIndex - 1].type != -3) - { - if (sprite->animCmdIndex == 0) - break; - sprite->animCmdIndex--; - } - - sprite->animCmdIndex--; - } -} - -void BeginAffineAnim(struct Sprite *sprite) -{ - if ((sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) && sprite->affineAnims[0][0].type != 32767) - { - struct AffineAnimFrameCmd frameCmd; - u8 matrixNum = GetSpriteMatrixNum(sprite); - AffineAnimStateRestartAnim(matrixNum); - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - sprite->affineAnimBeginning = FALSE; - sprite->affineAnimEnded = FALSE; - ApplyAffineAnimFrame(matrixNum, &frameCmd); - sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; - if (sprite->flags_f) - obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); - } -} - -void ContinueAffineAnim(struct Sprite *sprite) -{ - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - { - u8 matrixNum = GetSpriteMatrixNum(sprite); - - if (sAffineAnimStates[matrixNum].delayCounter) - AffineAnimDelay(matrixNum, sprite); - else if (sprite->affineAnimPaused) - return; - else - { - s16 type; - s16 funcIndex; - sAffineAnimStates[matrixNum].animCmdIndex++; - type = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].type; - funcIndex = 3; - if (type >= 32765) - funcIndex = type - 32765; - sAffineAnimCmdFuncs[funcIndex](matrixNum, sprite); - } - if (sprite->flags_f) - obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); - } -} - -void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite) -{ - if (!DecrementAffineAnimDelayCounter(sprite, matrixNum)) - { - struct AffineAnimFrameCmd frameCmd; - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &frameCmd); - } -} - -void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite) -{ - if (sAffineAnimStates[matrixNum].loopCounter) - ContinueAffineAnimLoop(matrixNum, sprite); - else - BeginAffineAnimLoop(matrixNum, sprite); -} - -void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) -{ - sAffineAnimStates[matrixNum].loopCounter = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].loop.count; - JumpToTopOfAffineAnimLoop(matrixNum, sprite); - ContinueAffineAnim(sprite); -} - -void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) -{ - sAffineAnimStates[matrixNum].loopCounter--; - JumpToTopOfAffineAnimLoop(matrixNum, sprite); - ContinueAffineAnim(sprite); -} - -void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) -{ - if (sAffineAnimStates[matrixNum].loopCounter) - { - sAffineAnimStates[matrixNum].animCmdIndex--; - - while (sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex - 1].type != 32765) - { - if (sAffineAnimStates[matrixNum].animCmdIndex == 0) - break; - sAffineAnimStates[matrixNum].animCmdIndex--; - } - - sAffineAnimStates[matrixNum].animCmdIndex--; - } -} - -void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite) -{ - struct AffineAnimFrameCmd frameCmd; - sAffineAnimStates[matrixNum].animCmdIndex = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].jump.target; - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - ApplyAffineAnimFrame(matrixNum, &frameCmd); - sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; -} - -void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite) -{ - struct AffineAnimFrameCmd dummyFrameCmd = {0}; - sprite->affineAnimEnded = TRUE; - sAffineAnimStates[matrixNum].animCmdIndex--; - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); -} - -void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite) -{ - struct AffineAnimFrameCmd frameCmd; - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - ApplyAffineAnimFrame(matrixNum, &frameCmd); - sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; -} - -void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix) -{ - gOamMatrices[destMatrixIndex].a = srcMatrix->a; - gOamMatrices[destMatrixIndex].b = srcMatrix->b; - gOamMatrices[destMatrixIndex].c = srcMatrix->c; - gOamMatrices[destMatrixIndex].d = srcMatrix->d; -} - -u8 GetSpriteMatrixNum(struct Sprite *sprite) -{ - u8 matrixNum = 0; - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - matrixNum = sprite->oam.matrixNum; - return matrixNum; -} - -void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3) -{ - sprite->data[6] = a2; - sprite->data[7] = a3; - sprite->flags_f = 1; -} - -s32 sub_8007E28(s32 a0, s32 a1, s32 a2) -{ - s32 subResult, var1; - - subResult = a1 - a0; - if (subResult < 0) - var1 = -(subResult) >> 9; - else - var1 = -(subResult >> 9); - return a2 - ((u32)(a2 * a1) / (u32)(a0) + var1); -} - -void obj_update_pos2(struct Sprite *sprite, s32 a1, s32 a2) -{ - s32 var0, var1, var2; - - u32 matrixNum = sprite->oam.matrixNum; - if (a1 != 0x800) - { - var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].width; - var1 = var0 << 8; - var2 = (var0 << 16) / gOamMatrices[matrixNum].a; - sprite->pos2.x = sub_8007E28(var1, var2, a1); - } - if (a2 != 0x800) - { - var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].height; - var1 = var0 << 8; - var2 = (var0 << 16) / gOamMatrices[matrixNum].d; - sprite->pos2.y = sub_8007E28(var1, var2, a2); - } -} - -void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip) -{ - sprite->oam.matrixNum &= 0x7; - sprite->oam.matrixNum |= (((hFlip ^ sprite->hFlip) & 1) << 3); - sprite->oam.matrixNum |= (((vFlip ^ sprite->vFlip) & 1) << 4); -} - -void AffineAnimStateRestartAnim(u8 matrixNum) -{ - sAffineAnimStates[matrixNum].animCmdIndex = 0; - sAffineAnimStates[matrixNum].delayCounter = 0; - sAffineAnimStates[matrixNum].loopCounter = 0; -} - -void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum) -{ - sAffineAnimStates[matrixNum].animNum = animNum; - sAffineAnimStates[matrixNum].animCmdIndex = 0; - sAffineAnimStates[matrixNum].delayCounter = 0; - sAffineAnimStates[matrixNum].loopCounter = 0; - sAffineAnimStates[matrixNum].xScale = 0x0100; - sAffineAnimStates[matrixNum].yScale = 0x0100; - sAffineAnimStates[matrixNum].rotation = 0; -} - -void AffineAnimStateReset(u8 matrixNum) -{ - sAffineAnimStates[matrixNum].animNum = 0; - sAffineAnimStates[matrixNum].animCmdIndex = 0; - sAffineAnimStates[matrixNum].delayCounter = 0; - sAffineAnimStates[matrixNum].loopCounter = 0; - sAffineAnimStates[matrixNum].xScale = 0x0100; - sAffineAnimStates[matrixNum].yScale = 0x0100; - sAffineAnimStates[matrixNum].rotation = 0; -} - -void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) -{ - sAffineAnimStates[matrixNum].xScale = frameCmd->xScale; - sAffineAnimStates[matrixNum].yScale = frameCmd->yScale; - sAffineAnimStates[matrixNum].rotation = frameCmd->rotation << 8; -} - -void DecrementAnimDelayCounter(struct Sprite *sprite) -{ - if (!sprite->animPaused) - sprite->animDelayCounter--; -} - -bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum) -{ - if (!sprite->affineAnimPaused) - --sAffineAnimStates[matrixNum].delayCounter; - return sprite->affineAnimPaused; -} - -void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) -{ - struct ObjAffineSrcData srcData; - struct OamMatrix matrix; - sAffineAnimStates[matrixNum].xScale += frameCmd->xScale; - sAffineAnimStates[matrixNum].yScale += frameCmd->yScale; - sAffineAnimStates[matrixNum].rotation = (sAffineAnimStates[matrixNum].rotation + (frameCmd->rotation << 8)) & ~0xFF; - srcData.xScale = ConvertScaleParam(sAffineAnimStates[matrixNum].xScale); - srcData.yScale = ConvertScaleParam(sAffineAnimStates[matrixNum].yScale); - srcData.rotation = sAffineAnimStates[matrixNum].rotation; - ObjAffineSet(&srcData, &matrix, 1, 2); - CopyOamMatrix(matrixNum, &matrix); -} - -s16 ConvertScaleParam(s16 scale) -{ - s32 val = 0x10000; - return SAFE_DIV(val, scale); -} - -void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd) -{ - frameCmd->xScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.xScale; - frameCmd->yScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.yScale; - frameCmd->rotation = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.rotation; - frameCmd->duration = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.duration; -} - -void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) -{ - struct AffineAnimFrameCmd dummyFrameCmd = {0}; - - if (frameCmd->duration) - { - frameCmd->duration--; - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, frameCmd); - } - else - { - ApplyAffineAnimFrameAbsolute(matrixNum, frameCmd); - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); - } -} - -void StartSpriteAnim(struct Sprite *sprite, u8 animNum) -{ - sprite->animNum = animNum; - sprite->animBeginning = TRUE; - sprite->animEnded = FALSE; -} - -void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum) -{ - if (sprite->animNum != animNum) - StartSpriteAnim(sprite, animNum); -} - -void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex) -{ - u8 temp = sprite->animPaused; - sprite->animCmdIndex = animCmdIndex - 1; - sprite->animDelayCounter = 0; - sprite->animBeginning = FALSE; - sprite->animEnded = FALSE; - sprite->animPaused = FALSE; - ContinueAnim(sprite); - if (sprite->animDelayCounter) - sprite->animDelayCounter++; - sprite->animPaused = temp; -} - -void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - AffineAnimStateStartAnim(matrixNum, animNum); - sprite->affineAnimBeginning = TRUE; - sprite->affineAnimEnded = FALSE; -} - -void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - if (sAffineAnimStates[matrixNum].animNum != animNum) - StartSpriteAffineAnim(sprite, animNum); -} - -void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - sAffineAnimStates[matrixNum].animNum = animNum; - sprite->affineAnimBeginning = TRUE; - sprite->affineAnimEnded = FALSE; -} - -void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - if (sAffineAnimStates[matrixNum].animNum != animNum) - ChangeSpriteAffineAnim(sprite, animNum); -} - -void SetSpriteSheetFrameTileNum(struct Sprite *sprite) -{ - if (sprite->usingSheet) - { - s16 tileOffset = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - if (tileOffset < 0) - tileOffset = 0; - sprite->oam.tileNum = sprite->sheetTileStart + tileOffset; - } -} - -void ResetAffineAnimData(void) -{ - u8 i; - - gAffineAnimsDisabled = FALSE; - gOamMatrixAllocBitmap = 0; - - ResetOamMatrices(); - - for (i = 0; i < OAM_MATRIX_COUNT; i++) - AffineAnimStateReset(i); -} - -u8 AllocOamMatrix(void) -{ - u8 i = 0; - u32 bit = 1; - u32 bitmap = gOamMatrixAllocBitmap; - - while (i < OAM_MATRIX_COUNT) - { - if (!(bitmap & bit)) - { - gOamMatrixAllocBitmap |= bit; - return i; - } - - i++; - bit <<= 1; - } - - return 0xFF; -} - -void FreeOamMatrix(u8 matrixNum) -{ - u8 i = 0; - u32 bit = 1; - - while (i < matrixNum) - { - i++; - bit <<= 1; - } - - gOamMatrixAllocBitmap &= ~bit; - SetOamMatrix(matrixNum, 0x100, 0, 0, 0x100); -} - -void InitSpriteAffineAnim(struct Sprite *sprite) -{ - u8 matrixNum = AllocOamMatrix(); - if (matrixNum != 0xFF) - { - CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); - sprite->oam.matrixNum = matrixNum; - sprite->affineAnimBeginning = TRUE; - AffineAnimStateReset(matrixNum); - } -} - -void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation) -{ - struct ObjAffineSrcData srcData; - struct OamMatrix matrix; - srcData.xScale = ConvertScaleParam(xScale); - srcData.yScale = ConvertScaleParam(yScale); - srcData.rotation = rotation; - ObjAffineSet(&srcData, &matrix, 1, 2); - CopyOamMatrix(matrixNum, &matrix); -} - -u16 LoadSpriteSheet(const struct SpriteSheet *sheet) -{ - s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); - - if (tileStart < 0) - { - return 0; - } - else - { - AllocSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); - CpuCopy16(sheet->data, (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileStart, sheet->size); - return (u16)tileStart; - } -} - -void LoadSpriteSheets(const struct SpriteSheet *sheets) -{ - u8 i; - for (i = 0; sheets[i].data != NULL; i++) - LoadSpriteSheet(&sheets[i]); -} - -void FreeSpriteTilesByTag(u16 tag) -{ - u8 index = IndexOfSpriteTileTag(tag); - if (index != 0xFF) - { - u16 i; - u16 *rangeStarts; - u16 *rangeCounts; - u16 start; - u16 count; - rangeStarts = sSpriteTileRanges; - start = rangeStarts[index * 2]; - rangeCounts = sSpriteTileRanges + 1; - count = rangeCounts[index * 2]; - - for (i = start; i < start + count; i++) - FREE_SPRITE_TILE(i); - - sSpriteTileRangeTags[index] = 0xFFFF; - } -} - -void FreeSpriteTileRanges(void) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - sSpriteTileRangeTags[i] = 0xFFFF; - SET_SPRITE_TILE_RANGE(i, 0, 0); - } -} - -u16 GetSpriteTileStartByTag(u16 tag) -{ - u8 index = IndexOfSpriteTileTag(tag); - if (index == 0xFF) - return 0xFFFF; - return sSpriteTileRanges[index * 2]; -} - -u8 IndexOfSpriteTileTag(u16 tag) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - if (sSpriteTileRangeTags[i] == tag) - return i; - - return 0xFF; -} - -u16 GetSpriteTileTagByTileStart(u16 start) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - if (sSpriteTileRangeTags[i] != 0xFFFF && sSpriteTileRanges[i * 2] == start) - return sSpriteTileRangeTags[i]; - } - - return 0xFFFF; -} - -void AllocSpriteTileRange(u16 tag, u16 start, u16 count) -{ - u8 freeIndex = IndexOfSpriteTileTag(0xFFFF); - sSpriteTileRangeTags[freeIndex] = tag; - SET_SPRITE_TILE_RANGE(freeIndex, start, count); -} - -void FreeAllSpritePalettes(void) -{ - u8 i; - gReservedSpritePaletteCount = 0; - for (i = 0; i < 16; i++) - sSpritePaletteTags[i] = 0xFFFF; -} - -u8 LoadSpritePalette(const struct SpritePalette *palette) -{ - u8 index = IndexOfSpritePaletteTag(palette->tag); - - if (index != 0xFF) - return index; - - index = IndexOfSpritePaletteTag(0xFFFF); - - if (index == 0xFF) - { - return 0xFF; - } - else - { - sSpritePaletteTags[index] = palette->tag; - DoLoadSpritePalette(palette->data, index * 16); - return index; - } -} - -void LoadSpritePalettes(const struct SpritePalette *palettes) -{ - u8 i; - for (i = 0; palettes[i].data != NULL; i++) - if (LoadSpritePalette(&palettes[i]) == 0xFF) - break; -} - -void DoLoadSpritePalette(const u16 *src, u16 paletteOffset) -{ - LoadPalette(src, paletteOffset + 0x100, 32); -} - -u8 AllocSpritePalette(u16 tag) -{ - u8 index = IndexOfSpritePaletteTag(0xFFFF); - if (index == 0xFF) - { - return 0xFF; - } - else - { - sSpritePaletteTags[index] = tag; - return index; - } -} - -u8 IndexOfSpritePaletteTag(u16 tag) -{ - u8 i; - for (i = gReservedSpritePaletteCount; i < 16; i++) - if (sSpritePaletteTags[i] == tag) - return i; - - return 0xFF; -} - -u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum) -{ - return sSpritePaletteTags[paletteNum]; -} - -void FreeSpritePaletteByTag(u16 tag) -{ - u8 index = IndexOfSpritePaletteTag(tag); - if (index != 0xFF) - sSpritePaletteTags[index] = 0xFFFF; -} - -void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables) -{ - sprite->subspriteTables = subspriteTables; - sprite->subspriteTableNum = 0; - sprite->subspriteMode = SUBSPRITES_ON; -} - -bool8 AddSpriteToOamBuffer(struct Sprite *sprite, u8 *oamIndex) -{ - if (*oamIndex >= gOamLimit) - return 1; - - if (!sprite->subspriteTables || sprite->subspriteMode == SUBSPRITES_OFF) - { - gMain.oamBuffer[*oamIndex] = sprite->oam; - (*oamIndex)++; - return 0; - } - else - { - return AddSubspritesToOamBuffer(sprite, &gMain.oamBuffer[*oamIndex], oamIndex); - } -} - -bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex) -{ - const struct SubspriteTable *subspriteTable; - struct OamData *oam; - - if (*oamIndex >= gOamLimit) - return 1; - - subspriteTable = &sprite->subspriteTables[sprite->subspriteTableNum]; - oam = &sprite->oam; - - if (!subspriteTable || !subspriteTable->subsprites) - { - *destOam = *oam; - (*oamIndex)++; - return 0; - } - else - { - u16 tileNum; - u16 baseX; - u16 baseY; - u8 subspriteCount; - u8 hFlip; - u8 vFlip; - u8 i; - - tileNum = oam->tileNum; - subspriteCount = subspriteTable->subspriteCount; - hFlip = ((s32)oam->matrixNum >> 3) & 1; - vFlip = ((s32)oam->matrixNum >> 4) & 1; - baseX = oam->x - sprite->centerToCornerVecX; - baseY = oam->y - sprite->centerToCornerVecY; - - for (i = 0; i < subspriteCount; i++, (*oamIndex)++) - { - u16 x; - u16 y; - - if (*oamIndex >= gOamLimit) - return 1; - - x = subspriteTable->subsprites[i].x; - y = subspriteTable->subsprites[i].y; - - if (hFlip) - { - s8 width = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].width; - s16 right = x; - right += width; - x = right; - x = ~x + 1; - } - - if (vFlip) - { - s8 height = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].height; - s16 bottom = y; - bottom += height; - y = bottom; - y = ~y + 1; - } - - destOam[i] = *oam; - destOam[i].shape = subspriteTable->subsprites[i].shape; - destOam[i].size = subspriteTable->subsprites[i].size; - destOam[i].x = (s16)baseX + (s16)x; - destOam[i].y = baseY + y; - destOam[i].tileNum = tileNum + subspriteTable->subsprites[i].tileOffset; - - if (sprite->subspriteMode != SUBSPRITES_IGNORE_PRIORITY) - destOam[i].priority = subspriteTable->subsprites[i].priority; - } - } - - return 0; -} diff --git a/gflib/sprite.h b/gflib/sprite.h deleted file mode 100644 index 4a3b48225..000000000 --- a/gflib/sprite.h +++ /dev/null @@ -1,324 +0,0 @@ -#ifndef GUARD_SPRITE_H -#define GUARD_SPRITE_H - -#define MAX_SPRITES 64 -#define SPRITE_NONE 0xFF -#define SPRITE_INVALID_TAG 0xFFFF - -struct SpriteSheet -{ - const void *data; // Raw uncompressed pixel data - u16 size; - u16 tag; -}; - -struct CompressedSpriteSheet -{ - const u32 *data; // LZ77 compressed pixel data - u16 size; // Uncompressed size of pixel data - u16 tag; -}; - -struct SpriteFrameImage -{ - const void *data; - u16 size; -}; - -#define obj_frame_tiles(ptr) {.data = (u8 *)ptr, .size = sizeof ptr} - -#define overworld_frame(ptr, width, height, frame) {.data = (u8 *)ptr + (width * height * frame * 64)/2, .size = (width * height * 64)/2} - -struct SpritePalette -{ - const u16 *data; // Raw uncompressed palette data - u16 tag; -}; - -struct CompressedSpritePalette -{ - const u32 *data; // LZ77 compressed palette data - u16 tag; -}; - -struct AnimFrameCmd -{ - // If the sprite has an array of images, this is the array index. - // If the sprite has a sheet, this is the tile offset. - u32 imageValue:16; - - u32 duration:6; - u32 hFlip:1; - u32 vFlip:1; -}; - -struct AnimLoopCmd -{ - u32 type:16; - u32 count:6; -}; - -struct AnimJumpCmd -{ - u32 type:16; - u32 target:6; -}; - -// The first halfword of this union specifies the type of command. -// If it -2, then it is a jump command. If it is -1, then it is the end of the script. -// Otherwise, it is the imageValue for a frame command. -union AnimCmd -{ - s16 type; - struct AnimFrameCmd frame; - struct AnimLoopCmd loop; - struct AnimJumpCmd jump; -}; - -#define ANIMCMD_FRAME(...) \ - {.frame = {__VA_ARGS__}} -#define ANIMCMD_LOOP(_count) \ - {.loop = {.type = -3, .count = _count}} -#define ANIMCMD_JUMP(_target) \ - {.jump = {.type = -2, .target = _target}} -#define ANIMCMD_END \ - {.type = -1} - -struct AffineAnimFrameCmd -{ - s16 xScale; - s16 yScale; - u8 rotation; - u8 duration; -}; - -struct AffineAnimLoopCmd -{ - s16 type; - s16 count; -}; - -struct AffineAnimJumpCmd -{ - s16 type; - u16 target; -}; - -struct AffineAnimEndCmdAlt -{ - s16 type; - u16 val; -}; - -union AffineAnimCmd -{ - s16 type; - struct AffineAnimFrameCmd frame; - struct AffineAnimLoopCmd loop; - struct AffineAnimJumpCmd jump; - struct AffineAnimEndCmdAlt end; // unused in code -}; - -#define AFFINEANIMCMDTYPE_LOOP 0x7FFD -#define AFFINEANIMCMDTYPE_JUMP 0x7FFE -#define AFFINEANIMCMDTYPE_END 0x7FFF - -#define AFFINEANIMCMD_FRAME(_xScale, _yScale, _rotation, _duration) \ - {.frame = {.xScale = _xScale, .yScale = _yScale, .rotation = _rotation, .duration = _duration}} -#define AFFINEANIMCMD_LOOP(_count) \ - {.loop = {.type = AFFINEANIMCMDTYPE_LOOP, .count = _count}} -#define AFFINEANIMCMD_JUMP(_target) \ - {.jump = {.type = AFFINEANIMCMDTYPE_JUMP, .target = _target}} -#define AFFINEANIMCMD_END \ - {.type = AFFINEANIMCMDTYPE_END} -#define AFFINEANIMCMD_END_ALT(_val) \ - {.end = {.type = AFFINEANIMCMDTYPE_END, .val = _val}} - -struct AffineAnimState -{ - u8 animNum; - u8 animCmdIndex; - u8 delayCounter; - u8 loopCounter; - s16 xScale; - s16 yScale; - u16 rotation; -}; - -enum -{ - SUBSPRITES_OFF, - SUBSPRITES_ON, - SUBSPRITES_IGNORE_PRIORITY, // on but priority is ignored -}; - -struct Subsprite -{ - s8 x; // was u16 in R/S - s8 y; // was u16 in R/S - u16 shape:2; - u16 size:2; - u16 tileOffset:10; - u16 priority:2; -}; - -struct SubspriteTable -{ - u8 subspriteCount; - const struct Subsprite *subsprites; -}; - -struct Sprite; - -typedef void (*SpriteCallback)(struct Sprite *); - -struct SpriteTemplate -{ - u16 tileTag; - u16 paletteTag; - const struct OamData *oam; - const union AnimCmd *const *anims; - const struct SpriteFrameImage *images; - const union AffineAnimCmd *const *affineAnims; - SpriteCallback callback; -}; - -// UB: template pointer is often used to point to temporary storage, -// then later dereferenced after being freed. Usually this won't -// be visible in-game, but this is (part of) what causes the item -// icon palette to flicker when changing items in the bag. -struct Sprite -{ - /*0x00*/ struct OamData oam; - /*0x08*/ const union AnimCmd *const *anims; - /*0x0C*/ const struct SpriteFrameImage *images; - /*0x10*/ const union AffineAnimCmd *const *affineAnims; - /*0x14*/ const struct SpriteTemplate *template; - /*0x18*/ const struct SubspriteTable *subspriteTables; - /*0x1C*/ SpriteCallback callback; - - /*0x20*/ struct Coords16 pos1; - /*0x24*/ struct Coords16 pos2; - /*0x28*/ s8 centerToCornerVecX; - /*0x29*/ s8 centerToCornerVecY; - - /*0x2A*/ u8 animNum; - /*0x2B*/ u8 animCmdIndex; - /*0x2C*/ u8 animDelayCounter:6; - bool8 animPaused:1; - bool8 affineAnimPaused:1; - /*0x2D*/ u8 animLoopCounter; - - // general purpose data fields - /*0x2E*/ s16 data[8]; - - /*0x3E*/ bool16 inUse:1; //1 - bool16 coordOffsetEnabled:1; //2 - bool16 invisible:1; //4 - bool16 flags_3:1; //8 - bool16 flags_4:1; //0x10 - bool16 flags_5:1; //0x20 - bool16 flags_6:1; //0x40 - bool16 flags_7:1; //0x80 - /*0x3F*/ bool16 hFlip:1; //1 - bool16 vFlip:1; //2 - bool16 animBeginning:1; //4 - bool16 affineAnimBeginning:1; //8 - bool16 animEnded:1; //0x10 - bool16 affineAnimEnded:1; //0x20 - bool16 usingSheet:1; //0x40 - bool16 flags_f:1; //0x80 - - /*0x40*/ u16 sheetTileStart; - - /*0x42*/ u8 subspriteTableNum:6; - u8 subspriteMode:2; - - /*0x43*/ u8 subpriority; -}; - -struct OamMatrix -{ - s16 a; - s16 b; - s16 c; - s16 d; -}; - -extern const struct OamData gDummyOamData; -extern const union AnimCmd *const gDummySpriteAnimTable[]; -extern const union AffineAnimCmd *const gDummySpriteAffineAnimTable[]; -extern const struct SpriteTemplate gDummySpriteTemplate; - -extern u8 gReservedSpritePaletteCount; -extern struct Sprite gSprites[]; -extern u8 gOamLimit; -extern u16 gReservedSpriteTileCount; -extern s16 gSpriteCoordOffsetX; -extern s16 gSpriteCoordOffsetY; -extern struct OamMatrix gOamMatrices[]; -extern bool8 gAffineAnimsDisabled; - -void ResetSpriteData(void); -void AnimateSprites(void); -void BuildOamBuffer(void); -u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)); -u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -void DestroySprite(struct Sprite *sprite); -void ResetOamRange(u8 a, u8 b); -void LoadOam(void); -void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d); -void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode); -void SpriteCallbackDummy(struct Sprite *sprite); -void ProcessSpriteCopyRequests(void); -void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size); -void FreeSpriteTiles(struct Sprite *sprite); -void FreeSpritePalette(struct Sprite *sprite); -void FreeSpriteOamMatrix(struct Sprite *sprite); -void DestroySpriteAndFreeResources(struct Sprite *sprite); -void sub_800142C(u32 a1, u32 a2, u16 *a3, u16 a4, u32 a5); -void AnimateSprite(struct Sprite *sprite); -void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3); -void StartSpriteAnim(struct Sprite *sprite, u8 animNum); -void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum); -void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex); -void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum); -void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); -void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum); -void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); -void SetSpriteSheetFrameTileNum(struct Sprite *sprite); -u8 AllocOamMatrix(void); -void FreeOamMatrix(u8 matrixNum); -void InitSpriteAffineAnim(struct Sprite *sprite); -void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation); -u16 LoadSpriteSheet(const struct SpriteSheet *sheet); -void LoadSpriteSheets(const struct SpriteSheet *sheets); -u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet); -void AllocTilesForSpriteSheets(struct SpriteSheet *sheets); -void LoadTilesForSpriteSheet(const struct SpriteSheet *sheet); -void LoadTilesForSpriteSheets(struct SpriteSheet *sheets); -void FreeSpriteTilesByTag(u16 tag); -void FreeSpriteTileRanges(void); -u16 GetSpriteTileStartByTag(u16 tag); -u16 GetSpriteTileTagByTileStart(u16 start); -void RequestSpriteSheetCopy(const struct SpriteSheet *sheet); -u16 LoadSpriteSheetDeferred(const struct SpriteSheet *sheet); -void FreeAllSpritePalettes(void); -u8 LoadSpritePalette(const struct SpritePalette *palette); -void LoadSpritePalettes(const struct SpritePalette *palettes); -u8 AllocSpritePalette(u16 tag); -u8 IndexOfSpritePaletteTag(u16 tag); -u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum); -void FreeSpritePaletteByTag(u16 tag); -void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables); -bool8 AddSpriteToOamBuffer(struct Sprite *object, u8 *oamIndex); -bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex); -void CopyToSprites(u8 *src); -void CopyFromSprites(u8 *dest); -u8 SpriteTileAllocBitmapOp(u16 bit, u8 op); -void ClearSpriteCopyRequests(void); -void ResetAffineAnimData(void); - -#endif //GUARD_SPRITE_H diff --git a/gflib/string_util.c b/gflib/string_util.c deleted file mode 100644 index 92f8eea5a..000000000 --- a/gflib/string_util.c +++ /dev/null @@ -1,781 +0,0 @@ -#include "global.h" -#include "string_util.h" -#include "text.h" -#include "strings.h" - -EWRAM_DATA u8 gStringVar1[0x100] = {0}; -EWRAM_DATA u8 gStringVar2[0x100] = {0}; -EWRAM_DATA u8 gStringVar3[0x100] = {0}; -EWRAM_DATA u8 gStringVar4[0x3E8] = {0}; -EWRAM_DATA static u8 sUnknownStringVar[16] = {0}; - -static const u8 sDigits[] = __("0123456789ABCDEF"); - -static const s32 sPowersOfTen[] = -{ - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, -}; - -u8 *StringCopy10(u8 *dest, const u8 *src) -{ - u8 i; - u32 limit = 10; - - for (i = 0; i < limit; i++) - { - dest[i] = src[i]; - - if (dest[i] == EOS) - return &dest[i]; - } - - dest[i] = EOS; - return &dest[i]; -} - -u8 *StringGetEnd10(u8 *str) -{ - u8 i; - u32 limit = 10; - - for (i = 0; i < limit; i++) - if (str[i] == EOS) - return &str[i]; - - str[i] = EOS; - return &str[i]; -} - -u8 *StringCopy7(u8 *dest, const u8 *src) -{ - s32 i; - s32 limit = 7; - - for (i = 0; i < limit; i++) - { - dest[i] = src[i]; - - if (dest[i] == EOS) - return &dest[i]; - } - - dest[i] = EOS; - return &dest[i]; -} - -u8 *StringCopy(u8 *dest, const u8 *src) -{ - while (*src != EOS) - { - *dest = *src; - dest++; - src++; - } - - *dest = EOS; - return dest; -} - -u8 *StringAppend(u8 *dest, const u8 *src) -{ - while (*dest != EOS) - dest++; - - return StringCopy(dest, src); -} - -u8 *StringCopyN(u8 *dest, const u8 *src, u8 n) -{ - u16 i; - - for (i = 0; i < n; i++) - dest[i] = src[i]; - - return &dest[n]; -} - -u8 *StringAppendN(u8 *dest, const u8 *src, u8 n) -{ - while (*dest != EOS) - dest++; - - return StringCopyN(dest, src, n); -} - -u16 StringLength(const u8 *str) -{ - u16 length = 0; - - while (str[length] != EOS) - length++; - - return length; -} - -s32 StringCompare(const u8 *str1, const u8 *str2) -{ - while (*str1 == *str2) - { - if (*str1 == EOS) - return 0; - str1++; - str2++; - } - - return *str1 - *str2; -} - -s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n) -{ - while (*str1 == *str2) - { - if (*str1 == EOS) - return 0; - str1++; - str2++; - if (--n == 0) - return 0; - } - - return *str1 - *str2; -} - -bool8 IsStringLengthAtLeast(const u8 *str, s32 n) -{ - u8 i; - - for (i = 0; i < n; i++) - if (str[i] && str[i] != EOS) - return TRUE; - - return FALSE; -} - -u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) -{ - enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; - s32 powerOfTen; - s32 largestPowerOfTen = sPowersOfTen[n - 1]; - - state = WAITING_FOR_NONZERO_DIGIT; - - if (mode == STR_CONV_MODE_RIGHT_ALIGN) - state = WRITING_SPACES; - - if (mode == STR_CONV_MODE_LEADING_ZEROS) - state = WRITING_DIGITS; - - for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) - { - u8 c; - u16 digit = value / powerOfTen; - s32 temp = value - (powerOfTen * digit); - - if (state == WRITING_DIGITS) - { - u8 *out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (digit != 0 || powerOfTen == 1) - { - u8 *out; - state = WRITING_DIGITS; - out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (state == WRITING_SPACES) - { - *dest++ = 0x77; - } - - value = temp; - } - - *dest = EOS; - return dest; -} - -u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n) -{ - enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; - s32 powerOfTen; - s32 largestPowerOfTen = sPowersOfTen[n - 1]; - - state = WAITING_FOR_NONZERO_DIGIT; - - if (mode == STR_CONV_MODE_RIGHT_ALIGN) - state = WRITING_SPACES; - - if (mode == STR_CONV_MODE_LEADING_ZEROS) - state = WRITING_DIGITS; - - for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) - { - u8 c; - u16 digit = value / powerOfTen; - u32 temp = value - (powerOfTen * digit); - - if (state == WRITING_DIGITS) - { - u8 *out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (digit != 0 || powerOfTen == 1) - { - u8 *out; - state = WRITING_DIGITS; - out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (state == WRITING_SPACES) - { - *dest++ = 0x77; - } - - value = temp; - } - - *dest = EOS; - return dest; -} - -u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) -{ - enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; - u8 i; - s32 powerOfSixteen; - s32 largestPowerOfSixteen = 1; - - for (i = 1; i < n; i++) - largestPowerOfSixteen *= 16; - - state = WAITING_FOR_NONZERO_DIGIT; - - if (mode == STR_CONV_MODE_RIGHT_ALIGN) - state = WRITING_SPACES; - - if (mode == STR_CONV_MODE_LEADING_ZEROS) - state = WRITING_DIGITS; - - for (powerOfSixteen = largestPowerOfSixteen; powerOfSixteen > 0; powerOfSixteen /= 16) - { - u8 c; - u32 digit = value / powerOfSixteen; - s32 temp = value % powerOfSixteen; - - if (state == WRITING_DIGITS) - { - char *out = dest++; - - if (digit <= 0xF) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (digit != 0 || powerOfSixteen == 1) - { - char *out; - state = WRITING_DIGITS; - out = dest++; - - if (digit <= 0xF) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (state == WRITING_SPACES) - { - *dest++ = 0x77; - } - - value = temp; - } - - *dest = EOS; - return dest; -} - -u8 *StringExpandPlaceholders(u8 *dest, const u8 *src) -{ - for (;;) - { - u8 c = *src++; - u8 placeholderId; - const u8 *expandedString; - - switch (c) - { - case PLACEHOLDER_BEGIN: - placeholderId = *src++; - expandedString = GetExpandedPlaceholder(placeholderId); - dest = StringExpandPlaceholders(dest, expandedString); - break; - case EXT_CTRL_CODE_BEGIN: - *dest++ = c; - c = *src++; - *dest++ = c; - - switch (c) - { - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_FILL_WINDOW: - case EXT_CTRL_CODE_JPN: - case EXT_CTRL_CODE_ENG: - case EXT_CTRL_CODE_PAUSE_MUSIC: - case EXT_CTRL_CODE_RESUME_MUSIC: - break; - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - *dest++ = *src++; - case EXT_CTRL_CODE_PLAY_BGM: - *dest++ = *src++; - default: - *dest++ = *src++; - } - break; - case EOS: - *dest = EOS; - return dest; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - case CHAR_NEWLINE: - default: - *dest++ = c; - } - } -} - -u8 *StringBraille(u8 *dest, const u8 *src) -{ - const u8 setBrailleFont[] = { - EXT_CTRL_CODE_BEGIN, - EXT_CTRL_CODE_SIZE, - 6, - EOS - }; - const u8 gotoLine2[] = { - CHAR_NEWLINE, - EXT_CTRL_CODE_BEGIN, - EXT_CTRL_CODE_SHIFT_DOWN, - 2, - EOS - }; - - dest = StringCopy(dest, setBrailleFont); - - for (;;) - { - u8 c = *src++; - - switch (c) - { - case EOS: - *dest = c; - return dest; - case CHAR_NEWLINE: - dest = StringCopy(dest, gotoLine2); - break; - default: - *dest++ = c; - *dest++ = c + 0x40; - break; - } - } -} - -static const u8 *ExpandPlaceholder_UnknownStringVar(void) -{ - return sUnknownStringVar; -} - -static const u8 *ExpandPlaceholder_PlayerName(void) -{ - return gSaveBlock2Ptr->playerName; -} - -static const u8 *ExpandPlaceholder_StringVar1(void) -{ - return gStringVar1; -} - -static const u8 *ExpandPlaceholder_StringVar2(void) -{ - return gStringVar2; -} - -static const u8 *ExpandPlaceholder_StringVar3(void) -{ - return gStringVar3; -} - -static const u8 *ExpandPlaceholder_KunChan(void) -{ - if (gSaveBlock2Ptr->playerGender == MALE) - return gText_ExpandedPlaceholder_Kun; - else - return gText_ExpandedPlaceholder_Chan; -} - -static const u8 *ExpandPlaceholder_RivalName(void) -{ - if (gSaveBlock2Ptr->playerGender == MALE) - return gText_ExpandedPlaceholder_May; - else - return gText_ExpandedPlaceholder_Brendan; -} - -static const u8 *ExpandPlaceholder_Version(void) -{ - return gText_ExpandedPlaceholder_Emerald; -} - -static const u8 *ExpandPlaceholder_Aqua(void) -{ - return gText_ExpandedPlaceholder_Aqua; -} - -static const u8 *ExpandPlaceholder_Magma(void) -{ - return gText_ExpandedPlaceholder_Magma; -} - -static const u8 *ExpandPlaceholder_Archie(void) -{ - return gText_ExpandedPlaceholder_Archie; -} - -static const u8 *ExpandPlaceholder_Maxie(void) -{ - return gText_ExpandedPlaceholder_Maxie; -} - -static const u8 *ExpandPlaceholder_Kyogre(void) -{ - return gText_ExpandedPlaceholder_Kyogre; -} - -static const u8 *ExpandPlaceholder_Groudon(void) -{ - return gText_ExpandedPlaceholder_Groudon; -} - -const u8 *GetExpandedPlaceholder(u32 id) -{ - typedef const u8 *(*ExpandPlaceholderFunc)(void); - - static const ExpandPlaceholderFunc funcs[] = - { - [PLACEHOLDER_ID_UNKNOWN] = ExpandPlaceholder_UnknownStringVar, - [PLACEHOLDER_ID_PLAYER] = ExpandPlaceholder_PlayerName, - [PLACEHOLDER_ID_STRING_VAR_1] = ExpandPlaceholder_StringVar1, - [PLACEHOLDER_ID_STRING_VAR_2] = ExpandPlaceholder_StringVar2, - [PLACEHOLDER_ID_STRING_VAR_3] = ExpandPlaceholder_StringVar3, - [PLACEHOLDER_ID_KUN] = ExpandPlaceholder_KunChan, - [PLACEHOLDER_ID_RIVAL] = ExpandPlaceholder_RivalName, - [PLACEHOLDER_ID_VERSION] = ExpandPlaceholder_Version, - [PLACEHOLDER_ID_AQUA] = ExpandPlaceholder_Aqua, - [PLACEHOLDER_ID_MAGMA] = ExpandPlaceholder_Magma, - [PLACEHOLDER_ID_ARCHIE] = ExpandPlaceholder_Archie, - [PLACEHOLDER_ID_MAXIE] = ExpandPlaceholder_Maxie, - [PLACEHOLDER_ID_KYOGRE] = ExpandPlaceholder_Kyogre, - [PLACEHOLDER_ID_GROUDON] = ExpandPlaceholder_Groudon, - }; - - if (id >= ARRAY_COUNT(funcs)) - return gText_ExpandedPlaceholder_Empty; - else - return funcs[id](); -} - -u8 *StringFill(u8 *dest, u8 c, u16 n) -{ - u16 i; - - for (i = 0; i < n; i++) - *dest++ = c; - - *dest = EOS; - return dest; -} - -u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n) -{ - while (*src != EOS) - { - *dest++ = *src++; - - if (n) - n--; - } - - n--; - - while (n != (u16)-1) - { - *dest++ = c; - n--; - } - - *dest = EOS; - return dest; -} - -u8 *StringFillWithTerminator(u8 *dest, u16 n) -{ - return StringFill(dest, EOS, n); -} - -u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n) -{ - u32 i; - - for (i = n - 1; i != (u32)-1; i--) - { - if (*src == EOS) - { - break; - } - else - { - *dest++ = *src++; - if (*(src - 1) == CHAR_EXTRA_SYMBOL) - *dest++ = *src++; - } - } - - *dest = EOS; - return dest; -} - -u32 StringLength_Multibyte(const u8 *str) -{ - u32 length = 0; - - while (*str != EOS) - { - if (*str == CHAR_EXTRA_SYMBOL) - str++; - str++; - length++; - } - - return length; -} - -u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color) -{ - *dest = EXT_CTRL_CODE_BEGIN; - dest++; - - switch (colorType) - { - case 0: - *dest = EXT_CTRL_CODE_COLOR; - dest++; - break; - case 1: - *dest = EXT_CTRL_CODE_SHADOW; - dest++; - break; - case 2: - *dest = EXT_CTRL_CODE_HIGHLIGHT; - dest++; - break; - } - - *dest = color; - dest++; - *dest = EOS; - return dest; -} - -bool32 IsStringJapanese(u8 *str) -{ - while (*str != EOS) - { - if (*str < CHAR_0) - if (*str != CHAR_SPACE) - return TRUE; - str++; - } - - return FALSE; -} - -bool32 sub_800924C(u8 *str, s32 n) -{ - s32 i; - - for (i = 0; *str != EOS && i < n; i++) - { - if (*str < CHAR_0) - if (*str != CHAR_SPACE) - return TRUE; - str++; - } - - return FALSE; -} - -u8 GetExtCtrlCodeLength(u8 code) -{ - static const u8 lengths[] = - { - [0] = 1, - [EXT_CTRL_CODE_COLOR] = 2, - [EXT_CTRL_CODE_HIGHLIGHT] = 2, - [EXT_CTRL_CODE_SHADOW] = 2, - [EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW] = 4, - [EXT_CTRL_CODE_PALETTE] = 2, - [EXT_CTRL_CODE_SIZE] = 2, - [EXT_CTRL_CODE_RESET_SIZE] = 1, - [EXT_CTRL_CODE_PAUSE] = 2, - [EXT_CTRL_CODE_PAUSE_UNTIL_PRESS] = 1, - [EXT_CTRL_CODE_WAIT_SE] = 1, - [EXT_CTRL_CODE_PLAY_BGM] = 3, - [EXT_CTRL_CODE_ESCAPE] = 2, - [EXT_CTRL_CODE_SHIFT_TEXT] = 2, - [EXT_CTRL_CODE_SHIFT_DOWN] = 2, - [EXT_CTRL_CODE_FILL_WINDOW] = 1, - [EXT_CTRL_CODE_PLAY_SE] = 3, - [EXT_CTRL_CODE_CLEAR] = 2, - [EXT_CTRL_CODE_SKIP] = 2, - [EXT_CTRL_CODE_CLEAR_TO] = 2, - [EXT_CTRL_CODE_MIN_LETTER_SPACING] = 2, - [EXT_CTRL_CODE_JPN] = 1, - [EXT_CTRL_CODE_ENG] = 1, - [EXT_CTRL_CODE_PAUSE_MUSIC] = 1, - [EXT_CTRL_CODE_RESUME_MUSIC] = 1, - }; - - u8 length = 0; - if (code < ARRAY_COUNT(lengths)) - length = lengths[code]; - return length; -} - -static const u8 *SkipExtCtrlCode(const u8 *s) -{ - while (*s == EXT_CTRL_CODE_BEGIN) - { - s++; - s += GetExtCtrlCodeLength(*s); - } - - return s; -} - -s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2) -{ - s32 retVal = 0; - - while (1) - { - str1 = SkipExtCtrlCode(str1); - str2 = SkipExtCtrlCode(str2); - - if (*str1 > *str2) - break; - - if (*str1 < *str2) - { - retVal = -1; - if (*str2 == EOS) - retVal = 1; - } - - if (*str1 == EOS) - return retVal; - - str1++; - str2++; - } - - retVal = 1; - - if (*str1 == EOS) - retVal = -1; - - return retVal; -} - -void ConvertInternationalString(u8 *s, u8 language) -{ - if (language == LANGUAGE_JAPANESE) - { - u8 i; - - StripExtCtrlCodes(s); - i = StringLength(s); - s[i++] = EXT_CTRL_CODE_BEGIN; - s[i++] = EXT_CTRL_CODE_ENG; - s[i++] = EOS; - - i--; - - while (i != (u8)-1) - { - s[i + 2] = s[i]; - i--; - } - - s[0] = EXT_CTRL_CODE_BEGIN; - s[1] = EXT_CTRL_CODE_JPN; - } -} - -void StripExtCtrlCodes(u8 *str) -{ - u16 srcIndex = 0; - u16 destIndex = 0; - while (str[srcIndex] != EOS) - { - if (str[srcIndex] == EXT_CTRL_CODE_BEGIN) - { - srcIndex++; - srcIndex += GetExtCtrlCodeLength(str[srcIndex]); - } - else - { - str[destIndex++] = str[srcIndex++]; - } - } - str[destIndex] = EOS; -} diff --git a/gflib/string_util.h b/gflib/string_util.h deleted file mode 100644 index 229193d52..000000000 --- a/gflib/string_util.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef GUARD_STRING_UTIL_H -#define GUARD_STRING_UTIL_H - -extern u8 gStringVar1[0x100]; -extern u8 gStringVar2[0x100]; -extern u8 gStringVar3[0x100]; -extern u8 gStringVar4[0x3E8]; - -enum StringConvertMode -{ - STR_CONV_MODE_LEFT_ALIGN, - STR_CONV_MODE_RIGHT_ALIGN, - STR_CONV_MODE_LEADING_ZEROS -}; - -u8 *StringCopy10(u8 *dest, const u8 *src); -u8 *StringGetEnd10(u8 *str); -u8 *StringCopy7(u8 *dest, const u8 *src); -u8 *StringCopy(u8 *dest, const u8 *src); -u8 *StringAppend(u8 *dest, const u8 *src); -u8 *StringCopyN(u8 *dest, const u8 *src, u8 n); -u8 *StringAppendN(u8 *dest, const u8 *src, u8 n); -u16 StringLength(const u8 *str); -s32 StringCompare(const u8 *str1, const u8 *str2); -s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n); -bool8 IsStringLengthAtLeast(const u8 *str, s32 n); -u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); -u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n); -u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); -u8 *StringExpandPlaceholders(u8 *dest, const u8 *src); -u8 *StringBraille(u8 *dest, const u8 *src); -const u8 *GetExpandedPlaceholder(u32 id); -u8 *StringFill(u8 *dest, u8 c, u16 n); -u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n); -u8 *StringFillWithTerminator(u8 *dest, u16 n); -u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n); -u32 StringLength_Multibyte(const u8 *str); -u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color); -bool32 IsStringJapanese(u8 *str); -bool32 sub_800924C(u8 *str, s32 n); -u8 GetExtCtrlCodeLength(u8 code); -s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2); -void ConvertInternationalString(u8 *s, u8 language); -void StripExtCtrlCodes(u8 *str); - -#endif // GUARD_STRING_UTIL_H diff --git a/gflib/text.c b/gflib/text.c deleted file mode 100644 index eb993c421..000000000 --- a/gflib/text.c +++ /dev/null @@ -1,1808 +0,0 @@ -#include "global.h" -#include "battle.h" -#include "main.h" -#include "m4a.h" -#include "palette.h" -#include "sound.h" -#include "constants/songs.h" -#include "string_util.h" -#include "window.h" -#include "text.h" -#include "blit.h" -#include "menu.h" -#include "dynamic_placeholder_text_util.h" - -EWRAM_DATA struct TextPrinter gTempTextPrinter = {0}; -EWRAM_DATA struct TextPrinter gTextPrinters[NUM_TEXT_PRINTERS] = {0}; - -static u16 gFontHalfRowLookupTable[0x51]; -static u16 gLastTextBgColor; -static u16 gLastTextFgColor; -static u16 gLastTextShadowColor; - -const struct FontInfo *gFonts; -u8 gDisableTextPrinters; -struct TextGlyph gCurGlyph; -TextFlags gTextFlags; - -const u8 gFontHalfRowOffsets[] = -{ - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, - 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, - 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, - 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, - 0x24, 0x25, 0x26, 0x24, 0x27, 0x28, 0x29, 0x27, 0x2A, 0x2B, 0x2C, 0x2A, 0x24, 0x25, 0x26, 0x24, - 0x2D, 0x2E, 0x2F, 0x2D, 0x30, 0x31, 0x32, 0x30, 0x33, 0x34, 0x35, 0x33, 0x2D, 0x2E, 0x2F, 0x2D, - 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, - 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, - 0x3F, 0x40, 0x41, 0x3F, 0x42, 0x43, 0x44, 0x42, 0x45, 0x46, 0x47, 0x45, 0x3F, 0x40, 0x41, 0x3F, - 0x48, 0x49, 0x4A, 0x48, 0x4B, 0x4C, 0x4D, 0x4B, 0x4E, 0x4F, 0x50, 0x4E, 0x48, 0x49, 0x4A, 0x48, - 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, - 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, - 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00 -}; - -const u8 gDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow.4bpp"); -const u8 gDarkDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow_RS.4bpp"); -const u8 gUnusedFRLGBlankedDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_blanked_down_arrow.4bpp"); -const u8 gUnusedFRLGDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_down_arrow.4bpp"); -const u8 gDownArrowYCoords[] = { 0x0, 0x1, 0x2, 0x1 }; -const u8 gWindowVerticalScrollSpeeds[] = { 0x1, 0x2, 0x4, 0x0 }; - -const struct GlyphWidthFunc gGlyphWidthFuncs[] = -{ - { 0x0, GetGlyphWidthFont0 }, - { 0x1, GetGlyphWidthFont1 }, - { 0x2, GetGlyphWidthFont2 }, - { 0x3, GetGlyphWidthFont2 }, - { 0x4, GetGlyphWidthFont2 }, - { 0x5, GetGlyphWidthFont2 }, - { 0x6, GetGlyphWidthFont6 }, - { 0x7, GetGlyphWidthFont7 }, - { 0x8, GetGlyphWidthFont8 } -}; - -const struct KeypadIcon gKeypadIcons[] = -{ - [CHAR_A_BUTTON] = { 0x0, 0x8, 0xC }, - [CHAR_B_BUTTON] = { 0x1, 0x8, 0xC }, - [CHAR_L_BUTTON] = { 0x2, 0x10, 0xC }, - [CHAR_R_BUTTON] = { 0x4, 0x10, 0xC }, - [CHAR_START_BUTTON] = { 0x6, 0x18, 0xC }, - [CHAR_SELECT_BUTTON] = { 0x9, 0x18, 0xC }, - [CHAR_DPAD_UP] = { 0xC, 0x8, 0xC }, - [CHAR_DPAD_DOWN] = { 0xD, 0x8, 0xC }, - [CHAR_DPAD_LEFT] = { 0xE, 0x8, 0xC }, - [CHAR_DPAD_RIGHT] = { 0xF, 0x8, 0xC }, - [CHAR_DPAD_UPDOWN] = { 0x20, 0x8, 0xC }, - [CHAR_DPAD_LEFTRIGHT] = { 0x21, 0x8, 0xC }, - [CHAR_DPAD_NONE] = { 0x22, 0x8, 0xC } -}; - -const u8 gKeypadIconTiles[] = INCBIN_U8("graphics/fonts/keypad_icons.4bpp"); - -const struct FontInfo gFontInfos[] = -{ - { Font0Func, 0x5, 0xC, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font1Func, 0x6, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font2Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font3Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font4Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font5Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font6Func, 0x8, 0x10, 0x0, 0x8, 0x0, 0x2, 0x1, 0x3 }, - { Font7Func, 0x5, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font8Func, 0x5, 0x8, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { NULL, 0x8, 0x8, 0x0, 0x0, 0x0, 0x1, 0x2, 0xF } -}; - -const u8 gMenuCursorDimensions[][2] = -{ - { 0x8, 0xC }, - { 0x8, 0xF }, - { 0x8, 0xE }, - { 0x8, 0xE }, - { 0x8, 0xE }, - { 0x8, 0xE }, - { 0x8, 0x10 }, - { 0x8, 0xF }, - { 0x8, 0x8 }, - { 0x0, 0x0 } -}; - -const u16 gFont9JapaneseGlyphs[] = INCBIN_U16("graphics/fonts/font9.hwjpnfont"); - -extern const u16 gFont8LatinGlyphs[]; -extern const u8 gFont8LatinGlyphWidths[]; -extern const u16 gFont0LatinGlyphs[]; -extern const u8 gFont0LatinGlyphWidths[]; -extern const u16 gFont7LatinGlyphs[]; -extern const u8 gFont7LatinGlyphWidths[]; -extern const u16 gFont2LatinGlyphs[]; -extern const u8 gFont2LatinGlyphWidths[]; -extern const u16 gFont1LatinGlyphs[]; -extern const u8 gFont1LatinGlyphWidths[]; -extern const u16 gFont0JapaneseGlyphs[]; -extern const u16 gFont1JapaneseGlyphs[]; -extern const u16 gFont2JapaneseGlyphs[]; -extern const u8 gFont2JapaneseGlyphWidths[]; - -void SetFontsPointer(const struct FontInfo *fonts) -{ - gFonts = fonts; -} - -void DeactivateAllTextPrinters(void) -{ - int printer; - for (printer = 0; printer < NUM_TEXT_PRINTERS; ++printer) - gTextPrinters[printer].active = 0; -} - -u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) -{ - struct TextPrinterTemplate printerTemplate; - - printerTemplate.currentChar = str; - printerTemplate.windowId = windowId; - printerTemplate.fontId = fontId; - printerTemplate.x = x; - printerTemplate.y = y; - printerTemplate.currentX = x; - printerTemplate.currentY = y; - printerTemplate.letterSpacing = gFonts[fontId].letterSpacing; - printerTemplate.lineSpacing = gFonts[fontId].lineSpacing; - printerTemplate.unk = gFonts[fontId].unk; - printerTemplate.fgColor = gFonts[fontId].fgColor; - printerTemplate.bgColor = gFonts[fontId].bgColor; - printerTemplate.shadowColor = gFonts[fontId].shadowColor; - return AddTextPrinter(&printerTemplate, speed, callback); -} - -bool16 AddTextPrinter(struct TextPrinterTemplate *printerTemplate, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) -{ - int i; - u16 j; - - if (!gFonts) - return FALSE; - - gTempTextPrinter.active = 1; - gTempTextPrinter.state = 0; - gTempTextPrinter.textSpeed = speed; - gTempTextPrinter.delayCounter = 0; - gTempTextPrinter.scrollDistance = 0; - - for (i = 0; i < 7; i++) - { - gTempTextPrinter.subStructFields[i] = 0; - } - - gTempTextPrinter.printerTemplate = *printerTemplate; - gTempTextPrinter.callback = callback; - gTempTextPrinter.minLetterSpacing = 0; - gTempTextPrinter.japanese = 0; - - GenerateFontHalfRowLookupTable(printerTemplate->fgColor, printerTemplate->bgColor, printerTemplate->shadowColor); - if (speed != TEXT_SPEED_FF && speed != 0) - { - --gTempTextPrinter.textSpeed; - gTextPrinters[printerTemplate->windowId] = gTempTextPrinter; - } - else - { - gTempTextPrinter.textSpeed = 0; - for (j = 0; j < 0x400; ++j) - { - if (RenderFont(&gTempTextPrinter) == 1) - break; - } - - if (speed != TEXT_SPEED_FF) - CopyWindowToVram(gTempTextPrinter.printerTemplate.windowId, 2); - gTextPrinters[printerTemplate->windowId].active = 0; - } - gDisableTextPrinters = 0; - return TRUE; -} - -void RunTextPrinters(void) -{ - int i; - - if (gDisableTextPrinters == 0) - { - for (i = 0; i < NUM_TEXT_PRINTERS; ++i) - { - if (gTextPrinters[i].active) - { - u16 temp = RenderFont(&gTextPrinters[i]); - switch (temp) - { - case 0: - CopyWindowToVram(gTextPrinters[i].printerTemplate.windowId, 2); - case 3: - if (gTextPrinters[i].callback != 0) - gTextPrinters[i].callback(&gTextPrinters[i].printerTemplate, temp); - break; - case 1: - gTextPrinters[i].active = 0; - break; - } - } - } - } -} - -bool16 IsTextPrinterActive(u8 id) -{ - return gTextPrinters[id].active; -} - -u32 RenderFont(struct TextPrinter *textPrinter) -{ - u32 ret; - while (TRUE) - { - ret = gFonts[textPrinter->printerTemplate.fontId].fontFunction(textPrinter); - if (ret != 2) - return ret; - } -} - -void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor) -{ - u32 fg12, bg12, shadow12; - u32 temp; - - u16 *current = gFontHalfRowLookupTable; - - gLastTextBgColor = bgColor; - gLastTextFgColor = fgColor; - gLastTextShadowColor = shadowColor; - - bg12 = bgColor << 12; - fg12 = fgColor << 12; - shadow12 = shadowColor << 12; - - temp = (bgColor << 8) | (bgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (bgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (bgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (fgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (fgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (fgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (shadowColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (shadowColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (shadowColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (bgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (bgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (bgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (fgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (fgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (fgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (shadowColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (shadowColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (shadowColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (bgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (bgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (bgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (fgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (fgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (fgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (shadowColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (shadowColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (shadowColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; -} - -void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) -{ - *bgColor = gLastTextBgColor; - *fgColor = gLastTextFgColor; - *shadowColor = gLastTextShadowColor; -} - -void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) -{ - GenerateFontHalfRowLookupTable(*fgColor, *bgColor, *shadowColor); -} - -void DecompressGlyphTile(const void *src_, void *dest_) -{ - u32 temp; - const u16 *src = src_; - u32 *dest = dest_; - - temp = *(src++); - *(dest)++ = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); -} - -u8 GetLastTextColor(u8 colorType) -{ - switch (colorType) - { - case 0: - return gLastTextFgColor; - case 2: - return gLastTextBgColor; - case 1: - return gLastTextShadowColor; - default: - return 0; - } -} - -inline static void GLYPH_COPY(u8 *windowTiles, u32 widthOffset, u32 j, u32 i, u32 *glyphPixels, s32 width, s32 height) -{ - u32 xAdd, yAdd, pixelData, bits, toOrr, dummyX; - u8 *dst; - - xAdd = j + width; - yAdd = i + height; - dummyX = j; - for (; i < yAdd; i++) - { - pixelData = *glyphPixels++; - for (j = dummyX; j < xAdd; j++) - { - if ((toOrr = pixelData & 0xF)) - { - dst = windowTiles + ((j / 8) * 32) + ((j % 8) / 2) + ((i / 8) * widthOffset) + ((i % 8) * 4); - bits = ((j & 1) * 4); - *dst = (toOrr << bits) | (*dst & (0xF0 >> bits)); - } - pixelData >>= 4; - } - } -} - -void CopyGlyphToWindow(struct TextPrinter *textPrinter) -{ - struct Window *window; - struct WindowTemplate *template; - u32 *glyphPixels; - u32 currX, currY, widthOffset; - s32 glyphWidth, glyphHeight; - u8 *windowTiles; - - window = &gWindows[textPrinter->printerTemplate.windowId]; - template = &window->window; - - if ((glyphWidth = (template->width * 8) - textPrinter->printerTemplate.currentX) > gCurGlyph.width) - glyphWidth = gCurGlyph.width; - - if ((glyphHeight = (template->height * 8) - textPrinter->printerTemplate.currentY) > gCurGlyph.height) - glyphHeight = gCurGlyph.height; - - currX = textPrinter->printerTemplate.currentX; - currY = textPrinter->printerTemplate.currentY; - glyphPixels = gCurGlyph.gfxBufferTop; - windowTiles = window->tileData; - widthOffset = template->width * 32; - - if (glyphWidth < 9) - { - if (glyphHeight < 9) - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, glyphHeight); - } - else - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, 8); - GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, glyphWidth, glyphHeight - 8); - } - } - else - { - if (glyphHeight < 9) - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, glyphHeight); - GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, glyphHeight); - } - else - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, 8); - GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, 8); - GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, 8, glyphHeight - 8); - GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY + 8, glyphPixels + 24, glyphWidth - 8, glyphHeight - 8); - } - } -} - -void ClearTextSpan(struct TextPrinter *textPrinter, u32 width) -{ - struct Window *window; - struct Bitmap pixels_data; - struct TextGlyph *glyph; - u8* glyphHeight; - - if (gLastTextBgColor != 0) - { - window = &gWindows[textPrinter->printerTemplate.windowId]; - pixels_data.pixels = window->tileData; - pixels_data.width = window->window.width << 3; - pixels_data.height = window->window.height << 3; - - glyph = &gCurGlyph; - glyphHeight = &glyph->height; - - FillBitmapRect4Bit( - &pixels_data, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - width, - *glyphHeight, - gLastTextBgColor); - } -} - -u16 Font0Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 0; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font1Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 1; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font2Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 2; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font3Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 3; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font4Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 4; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font5Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 5; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font7Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 7; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font8Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 8; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (gTextFlags.autoScroll == 1) - { - subStruct->autoScrollDelay = 0; - } - else - { - subStruct->downArrowYPosIdx = 0; - subStruct->downArrowDelay = 0; - } -} - -void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - const u8 *arrowTiles; - - if (gTextFlags.autoScroll == 0) - { - if (subStruct->downArrowDelay != 0) - { - subStruct->downArrowDelay--; - } - else - { - FillWindowPixelRect( - textPrinter->printerTemplate.windowId, - textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - 8, - 16); - - switch (gTextFlags.useAlternateDownArrow) - { - case FALSE: - default: - arrowTiles = gDownArrowTiles; - break; - case TRUE: - arrowTiles = gDarkDownArrowTiles; - break; - } - - BlitBitmapRectToWindow( - textPrinter->printerTemplate.windowId, - arrowTiles, - 0, - gDownArrowYCoords[subStruct->downArrowYPosIdx], - 8, - 16, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - 8, - 16); - CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); - - subStruct->downArrowDelay = 8; - subStruct->downArrowYPosIdx++; - } - } -} - -void TextPrinterClearDownArrow(struct TextPrinter *textPrinter) -{ - FillWindowPixelRect( - textPrinter->printerTemplate.windowId, - textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - 8, - 16); - CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); -} - -bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->autoScrollDelay == 49) - { - return TRUE; - } - else - { - subStruct->autoScrollDelay++; - return FALSE; - } -} - -bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) -{ - bool8 result = FALSE; - if (gTextFlags.autoScroll != 0) - { - result = TextPrinterWaitAutoMode(textPrinter); - } - else - { - TextPrinterDrawDownArrow(textPrinter); - if (JOY_NEW(A_BUTTON | B_BUTTON)) - { - result = TRUE; - PlaySE(SE_SELECT); - } - } - return result; -} - -bool16 TextPrinterWait(struct TextPrinter *textPrinter) -{ - bool16 result = FALSE; - if (gTextFlags.autoScroll != 0) - { - result = TextPrinterWaitAutoMode(textPrinter); - } - else - { - if (JOY_NEW(A_BUTTON | B_BUTTON)) - { - result = TRUE; - PlaySE(SE_SELECT); - } - } - return result; -} - -void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex) -{ - const u8 *arrowTiles; - - if (*counter != 0) - { - --*counter; - } - else - { - FillWindowPixelRect(windowId, (bgColor << 4) | bgColor, x, y, 0x8, 0x10); - if (drawArrow == 0) - { - switch (gTextFlags.useAlternateDownArrow) - { - case 0: - default: - arrowTiles = gDownArrowTiles; - break; - case 1: - arrowTiles = gDarkDownArrowTiles; - break; - } - - BlitBitmapRectToWindow( - windowId, - arrowTiles, - 0, - gDownArrowYCoords[*yCoordIndex & 3], - 0x8, - 0x10, - x, - y - 2, - 0x8, - 0x10); - CopyWindowToVram(windowId, 0x2); - *counter = 8; - ++*yCoordIndex; - } - } -} - -u16 RenderText(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - u16 currChar; - s32 width; - s32 widthHelper; - - switch (textPrinter->state) - { - case 0: - if ((JOY_HELD(A_BUTTON | B_BUTTON)) && subStruct->hasPrintBeenSpedUp) - textPrinter->delayCounter = 0; - - if (textPrinter->delayCounter && textPrinter->textSpeed) - { - textPrinter->delayCounter--; - if (gTextFlags.canABSpeedUpPrint && (JOY_NEW(A_BUTTON | B_BUTTON))) - { - subStruct->hasPrintBeenSpedUp = TRUE; - textPrinter->delayCounter = 0; - } - return 3; - } - - if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED) && gTextFlags.autoScroll) - textPrinter->delayCounter = 3; - else - textPrinter->delayCounter = textPrinter->textSpeed; - - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - - switch (currChar) - { - case CHAR_NEWLINE: - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentY += (gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing); - return 2; - case PLACEHOLDER_BEGIN: - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_BEGIN: - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - switch (currChar) - { - case EXT_CTRL_CODE_COLOR: - textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_HIGHLIGHT: - textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_SHADOW: - textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_PALETTE: - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_SIZE: - subStruct->glyphId = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_RESET_SIZE: - return 2; - case EXT_CTRL_CODE_PAUSE: - textPrinter->delayCounter = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - textPrinter->state = 6; - return 2; - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - textPrinter->state = 1; - if (gTextFlags.autoScroll) - subStruct->autoScrollDelay = 0; - return 3; - case EXT_CTRL_CODE_WAIT_SE: - textPrinter->state = 5; - return 3; - case EXT_CTRL_CODE_PLAY_BGM: - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - currChar |= *textPrinter->printerTemplate.currentChar << 8; - textPrinter->printerTemplate.currentChar++; - PlayBGM(currChar); - return 2; - case EXT_CTRL_CODE_ESCAPE: - currChar = *textPrinter->printerTemplate.currentChar | 0x100; - textPrinter->printerTemplate.currentChar++; - break; - case EXT_CTRL_CODE_PLAY_SE: - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - currChar |= (*textPrinter->printerTemplate.currentChar << 8); - textPrinter->printerTemplate.currentChar++; - PlaySE(currChar); - return 2; - case EXT_CTRL_CODE_SHIFT_TEXT: - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x + *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_SHIFT_DOWN: - textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y + *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_FILL_WINDOW: - FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; - return 2; - case EXT_CTRL_CODE_PAUSE_MUSIC: - m4aMPlayStop(&gMPlayInfo_BGM); - return 2; - case EXT_CTRL_CODE_RESUME_MUSIC: - m4aMPlayContinue(&gMPlayInfo_BGM); - return 2; - case EXT_CTRL_CODE_CLEAR: - width = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - if (width > 0) - { - ClearTextSpan(textPrinter, width); - textPrinter->printerTemplate.currentX += width; - return 0; - } - return 2; - case EXT_CTRL_CODE_SKIP: - textPrinter->printerTemplate.currentX = *textPrinter->printerTemplate.currentChar + textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_CLEAR_TO: - { - widthHelper = *textPrinter->printerTemplate.currentChar; - widthHelper += textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentChar++; - width = widthHelper - textPrinter->printerTemplate.currentX; - if (width > 0) - { - ClearTextSpan(textPrinter, width); - textPrinter->printerTemplate.currentX += width; - return 0; - } - } - return 2; - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - textPrinter->minLetterSpacing = *textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_JPN: - textPrinter->japanese = 1; - return 2; - case EXT_CTRL_CODE_ENG: - textPrinter->japanese = 0; - return 2; - } - break; - case CHAR_PROMPT_CLEAR: - textPrinter->state = 2; - TextPrinterInitDownArrowCounters(textPrinter); - return 3; - case CHAR_PROMPT_SCROLL: - textPrinter->state = 3; - TextPrinterInitDownArrowCounters(textPrinter); - return 3; - case CHAR_EXTRA_SYMBOL: - currChar = *textPrinter->printerTemplate.currentChar | 0x100; - textPrinter->printerTemplate.currentChar++; - break; - case CHAR_KEYPAD_ICON: - currChar = *textPrinter->printerTemplate.currentChar++; - gCurGlyph.width = DrawKeypadIcon(textPrinter->printerTemplate.windowId, currChar, textPrinter->printerTemplate.currentX, textPrinter->printerTemplate.currentY); - textPrinter->printerTemplate.currentX += gCurGlyph.width + textPrinter->printerTemplate.letterSpacing; - return 0; - case EOS: - return 1; - } - - switch (subStruct->glyphId) - { - case 0: - DecompressGlyphFont0(currChar, textPrinter->japanese); - break; - case 1: - DecompressGlyphFont1(currChar, textPrinter->japanese); - break; - case 2: - case 3: - case 4: - case 5: - DecompressGlyphFont2(currChar, textPrinter->japanese); - break; - case 7: - DecompressGlyphFont7(currChar, textPrinter->japanese); - break; - case 8: - DecompressGlyphFont8(currChar, textPrinter->japanese); - break; - case 6: - break; - } - - CopyGlyphToWindow(textPrinter); - - if (textPrinter->minLetterSpacing) - { - textPrinter->printerTemplate.currentX += gCurGlyph.width; - width = textPrinter->minLetterSpacing - gCurGlyph.width; - if (width > 0) - { - ClearTextSpan(textPrinter, width); - textPrinter->printerTemplate.currentX += width; - } - } - else - { - if (textPrinter->japanese) - textPrinter->printerTemplate.currentX += (gCurGlyph.width + textPrinter->printerTemplate.letterSpacing); - else - textPrinter->printerTemplate.currentX += gCurGlyph.width; - } - return 0; - case 1: - if (TextPrinterWait(textPrinter)) - textPrinter->state = 0; - return 3; - case 2: - if (TextPrinterWaitWithDownArrow(textPrinter)) - { - FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; - textPrinter->state = 0; - } - return 3; - case 3: - if (TextPrinterWaitWithDownArrow(textPrinter)) - { - TextPrinterClearDownArrow(textPrinter); - textPrinter->scrollDistance = gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing; - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->state = 4; - } - return 3; - case 4: - if (textPrinter->scrollDistance) - { - int scrollSpeed = GetPlayerTextSpeed(); - int speed = gWindowVerticalScrollSpeeds[scrollSpeed]; - if (textPrinter->scrollDistance < speed) - { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance = 0; - } - else - { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, speed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance -= speed; - } - CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); - } - else - { - textPrinter->state = 0; - } - return 3; - case 5: - if (!IsSEPlaying()) - textPrinter->state = 0; - return 3; - case 6: - if (textPrinter->delayCounter != 0) - textPrinter->delayCounter--; - else - textPrinter->state = 0; - return 3; - } - - return 1; -} - -u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing) -{ - int i; - u8 width; - int temp; - int temp2; - u8 line; - int strPos; - u8 lineWidths[8]; - const u8 *strLocal; - - for (i = 0; i < 8; i++) - { - lineWidths[i] = 0; - } - - width = 0; - line = 0; - strLocal = str; - strPos = 0; - - do - { - temp = strLocal[strPos++]; - switch (temp) - { - case CHAR_NEWLINE: - case EOS: - lineWidths[line] = width; - width = 0; - line++; - break; - case EXT_CTRL_CODE_BEGIN: - temp2 = strLocal[strPos++]; - switch (temp2) - { - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - ++strPos; - case EXT_CTRL_CODE_PLAY_BGM: - case EXT_CTRL_CODE_PLAY_SE: - ++strPos; - case EXT_CTRL_CODE_COLOR: - case EXT_CTRL_CODE_HIGHLIGHT: - case EXT_CTRL_CODE_SHADOW: - case EXT_CTRL_CODE_PALETTE: - case EXT_CTRL_CODE_SIZE: - case EXT_CTRL_CODE_PAUSE: - case EXT_CTRL_CODE_ESCAPE: - case EXT_CTRL_CODE_SHIFT_TEXT: - case EXT_CTRL_CODE_SHIFT_DOWN: - case EXT_CTRL_CODE_CLEAR: - case EXT_CTRL_CODE_SKIP: - case EXT_CTRL_CODE_CLEAR_TO: - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - ++strPos; - break; - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_WAIT_SE: - case EXT_CTRL_CODE_FILL_WINDOW: - case EXT_CTRL_CODE_JPN: - case EXT_CTRL_CODE_ENG: - default: - break; - } - break; - case CHAR_DYNAMIC: - case PLACEHOLDER_BEGIN: - ++strPos; - break; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - break; - case CHAR_KEYPAD_ICON: - case CHAR_EXTRA_SYMBOL: - ++strPos; - default: - ++width; - break; - } - } while (temp != EOS); - - for (width = 0, strPos = 0; strPos < 8; ++strPos) - { - if (width < lineWidths[strPos]) - width = lineWidths[strPos]; - } - - return (u8)(GetFontAttribute(fontId, FONTATTR_MAX_LETTER_WIDTH) + letterSpacing) * width; -} - -u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32) -{ - u32 i; - - for (i = 0; i < 9; ++i) - { - if (glyphId == gGlyphWidthFuncs[i].fontId) - return gGlyphWidthFuncs[i].func; - } - - return NULL; -} - -s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing) -{ - bool8 isJapanese; - int minGlyphWidth; - u32 (*func)(u16 glyphId, bool32 isJapanese); - int localLetterSpacing; - u32 lineWidth; - const u8 *bufferPointer; - int glyphWidth; - s32 width; - - isJapanese = 0; - minGlyphWidth = 0; - - func = GetFontWidthFunc(fontId); - if (func == NULL) - return 0; - - if (letterSpacing == -1) - localLetterSpacing = GetFontAttribute(fontId, FONTATTR_LETTER_SPACING); - else - localLetterSpacing = letterSpacing; - - width = 0; - lineWidth = 0; - bufferPointer = 0; - - while (*str != EOS) - { - switch (*str) - { - case CHAR_NEWLINE: - if (lineWidth > width) - width = lineWidth; - lineWidth = 0; - break; - case PLACEHOLDER_BEGIN: - switch (*++str) - { - case PLACEHOLDER_ID_STRING_VAR_1: - bufferPointer = gStringVar1; - break; - case PLACEHOLDER_ID_STRING_VAR_2: - bufferPointer = gStringVar2; - break; - case PLACEHOLDER_ID_STRING_VAR_3: - bufferPointer = gStringVar3; - break; - default: - return 0; - } - case CHAR_DYNAMIC: - if (bufferPointer == NULL) - bufferPointer = DynamicPlaceholderTextUtil_GetPlaceholderPtr(*++str); - while (*bufferPointer != EOS) - { - glyphWidth = func(*bufferPointer++, isJapanese); - if (minGlyphWidth > 0) - { - if (glyphWidth < minGlyphWidth) - glyphWidth = minGlyphWidth; - lineWidth += glyphWidth; - } - else - { - lineWidth += glyphWidth; - if (isJapanese && str[1] != EOS) - lineWidth += localLetterSpacing; - } - } - bufferPointer = 0; - break; - case EXT_CTRL_CODE_BEGIN: - switch (*++str) - { - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - ++str; - case EXT_CTRL_CODE_PLAY_BGM: - case EXT_CTRL_CODE_PLAY_SE: - ++str; - case EXT_CTRL_CODE_COLOR: - case EXT_CTRL_CODE_HIGHLIGHT: - case EXT_CTRL_CODE_SHADOW: - case EXT_CTRL_CODE_PALETTE: - case EXT_CTRL_CODE_PAUSE: - case EXT_CTRL_CODE_ESCAPE: - case EXT_CTRL_CODE_SHIFT_TEXT: - case EXT_CTRL_CODE_SHIFT_DOWN: - ++str; - break; - case EXT_CTRL_CODE_SIZE: - func = GetFontWidthFunc(*++str); - if (func == NULL) - return 0; - if (letterSpacing == -1) - localLetterSpacing = GetFontAttribute(*str, FONTATTR_LETTER_SPACING); - break; - case EXT_CTRL_CODE_CLEAR: - glyphWidth = *++str; - lineWidth += glyphWidth; - break; - case EXT_CTRL_CODE_SKIP: - lineWidth = *++str; - break; - case EXT_CTRL_CODE_CLEAR_TO: - if (*++str > lineWidth) - lineWidth = *str; - break; - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - minGlyphWidth = *++str; - break; - case EXT_CTRL_CODE_JPN: - isJapanese = 1; - break; - case EXT_CTRL_CODE_ENG: - isJapanese = 0; - break; - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_WAIT_SE: - case EXT_CTRL_CODE_FILL_WINDOW: - default: - break; - } - break; - case CHAR_KEYPAD_ICON: - case CHAR_EXTRA_SYMBOL: - if (*str == CHAR_EXTRA_SYMBOL) - glyphWidth = func(*++str | 0x100, isJapanese); - else - glyphWidth = GetKeypadIconWidth(*++str); - - if (minGlyphWidth > 0) - { - if (glyphWidth < minGlyphWidth) - glyphWidth = minGlyphWidth; - lineWidth += glyphWidth; - } - else - { - lineWidth += glyphWidth; - if (isJapanese && str[1] != EOS) - lineWidth += localLetterSpacing; - } - break; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - break; - default: - glyphWidth = func(*str, isJapanese); - if (minGlyphWidth > 0) - { - if (glyphWidth < minGlyphWidth) - glyphWidth = minGlyphWidth; - lineWidth += glyphWidth; - } - else - { - lineWidth += glyphWidth; - if (isJapanese && str[1] != EOS) - lineWidth += localLetterSpacing; - } - break; - } - ++str; - } - - if (lineWidth > width) - return lineWidth; - return width; -} - -u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str) -{ - u8 shadowColor; - u8 *strLocal; - int strPos; - int temp; - int temp2; - u8 colorBackup[3]; - u8 fgColor; - u8 bgColor; - - SaveTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); - - fgColor = TEXT_COLOR_WHITE; - bgColor = TEXT_COLOR_TRANSPARENT; - shadowColor = TEXT_COLOR_LIGHT_GRAY; - - GenerateFontHalfRowLookupTable(TEXT_COLOR_WHITE, TEXT_COLOR_TRANSPARENT, TEXT_COLOR_LIGHT_GRAY); - strLocal = str; - strPos = 0; - - do - { - temp = strLocal[strPos++]; - switch (temp) - { - case EXT_CTRL_CODE_BEGIN: - temp2 = strLocal[strPos++]; - switch (temp2) - { - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - fgColor = strLocal[strPos++]; - bgColor = strLocal[strPos++]; - shadowColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_COLOR: - fgColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_HIGHLIGHT: - bgColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_SHADOW: - shadowColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_SIZE: - fontId = strLocal[strPos++]; - break; - case EXT_CTRL_CODE_PLAY_BGM: - case EXT_CTRL_CODE_PLAY_SE: - ++strPos; - case EXT_CTRL_CODE_PALETTE: - case EXT_CTRL_CODE_PAUSE: - case EXT_CTRL_CODE_ESCAPE: - case EXT_CTRL_CODE_SHIFT_TEXT: - case EXT_CTRL_CODE_SHIFT_DOWN: - case EXT_CTRL_CODE_CLEAR: - case EXT_CTRL_CODE_SKIP: - case EXT_CTRL_CODE_CLEAR_TO: - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - ++strPos; - break; - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_WAIT_SE: - case EXT_CTRL_CODE_FILL_WINDOW: - case EXT_CTRL_CODE_JPN: - case EXT_CTRL_CODE_ENG: - default: - continue; - } - break; - case CHAR_DYNAMIC: - case CHAR_KEYPAD_ICON: - case CHAR_EXTRA_SYMBOL: - case PLACEHOLDER_BEGIN: - ++strPos; - break; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - case CHAR_NEWLINE: - case EOS: - break; - default: - switch (fontId) - { - case 9: - DecompressGlyphFont9(temp); - break; - case 1: - default: - DecompressGlyphFont1(temp, 1); - break; - } - CpuCopy32(gCurGlyph.gfxBufferTop, pixels, 0x20); - CpuCopy32(gCurGlyph.gfxBufferBottom, pixels + 0x20, 0x20); - pixels += 0x40; - break; - } - } - while (temp != EOS); - - RestoreTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); - return 1; -} - -u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y) -{ - BlitBitmapRectToWindow( - windowId, - gKeypadIconTiles + (gKeypadIcons[keypadIconId].tileOffset * 0x20), - 0, - 0, - 0x80, - 0x80, - x, - y, - gKeypadIcons[keypadIconId].width, - gKeypadIcons[keypadIconId].height); - return gKeypadIcons[keypadIconId].width; -} - -u8 GetKeypadIconTileOffset(u8 keypadIconId) -{ - return gKeypadIcons[keypadIconId].tileOffset; -} - -u8 GetKeypadIconWidth(u8 keypadIconId) -{ - return gKeypadIcons[keypadIconId].width; -} - -u8 GetKeypadIconHeight(u8 keypadIconId) -{ - return gKeypadIcons[keypadIconId].height; -} - -void SetDefaultFontsPointer(void) -{ - SetFontsPointer(&gFontInfos[0]); -} - -u8 GetFontAttribute(u8 fontId, u8 attributeId) -{ - int result = 0; - switch (attributeId) - { - case FONTATTR_MAX_LETTER_WIDTH: - result = gFontInfos[fontId].maxLetterWidth; - break; - case FONTATTR_MAX_LETTER_HEIGHT: - result = gFontInfos[fontId].maxLetterHeight; - break; - case FONTATTR_LETTER_SPACING: - result = gFontInfos[fontId].letterSpacing; - break; - case FONTATTR_LINE_SPACING: - result = gFontInfos[fontId].lineSpacing; - break; - case FONTATTR_UNKNOWN: - result = gFontInfos[fontId].unk; - break; - case FONTATTR_COLOR_FOREGROUND: - result = gFontInfos[fontId].fgColor; - break; - case FONTATTR_COLOR_BACKGROUND: - result = gFontInfos[fontId].bgColor; - break; - case FONTATTR_COLOR_SHADOW: - result = gFontInfos[fontId].shadowColor; - break; - } - return result; -} - -u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension) -{ - return gMenuCursorDimensions[fontId][whichDimension]; -} - -void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == 1) - { - glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 12; - } - else - { - glyphs = gFont0LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont0LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 13; - } -} - -u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont0LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 15; - } - else - { - glyphs = gFont7LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont7LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 15; - } -} - -u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont7LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 12; - } - else - { - glyphs = gFont8LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont8LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 12; - } -} - -u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont8LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont2JapaneseGlyphs + (0x100 * (glyphId >> 0x3)) + (0x10 * (glyphId & 0x7)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); // gCurGlyph + 0x20 - DecompressGlyphTile(glyphs + 0x88, gCurGlyph.gfxBufferBottom + 8); // gCurGlyph + 0x60 - gCurGlyph.width = gFont2JapaneseGlyphWidths[glyphId]; - gCurGlyph.height = 14; - } - else - { - glyphs = gFont2LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont2LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 14; - } -} - -u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return gFont2JapaneseGlyphWidths[glyphId]; - else - return gFont2LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 15; - } - else - { - glyphs = gFont1LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont1LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 15; - } -} - -u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont1LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont9(u16 glyphId) -{ - const u16* glyphs; - - glyphs = gFont9JapaneseGlyphs + (0x100 * (glyphId >> 4)) + (0x8 * (glyphId & 0xF)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 12; -} diff --git a/gflib/text.h b/gflib/text.h deleted file mode 100644 index 3edd0fc62..000000000 --- a/gflib/text.h +++ /dev/null @@ -1,436 +0,0 @@ -#ifndef GUARD_TEXT_H -#define GUARD_TEXT_H - -#define CHAR_SPACE 0x00 -#define CHAR_A_GRAVE 0x01 -#define CHAR_A_ACUTE 0x02 -#define CHAR_A_CIRCUMFLEX 0x03 -#define CHAR_C_CEDILLA 0x04 -#define CHAR_E_GRAVE 0x05 -#define CHAR_E_ACUTE 0x06 -#define CHAR_E_CIRCUMFLEX 0x07 -#define CHAR_E_DIAERESIS 0x08 -#define CHAR_I_GRAVE 0x09 -//#define CHAR_I_ACUTE 0x0A // Is 0x5A instead -#define CHAR_I_CIRCUMFLEX 0x0B -#define CHAR_I_DIAERESIS 0x0C -#define CHAR_O_GRAVE 0x0D -#define CHAR_O_ACUTE 0x0E -#define CHAR_O_CIRCUMFLEX 0x0F -#define CHAR_OE 0x10 -#define CHAR_U_GRAVE 0x11 -#define CHAR_U_ACUTE 0x12 -#define CHAR_U_CIRCUMFLEX 0x13 -#define CHAR_N_TILDE 0x14 -#define CHAR_ESZETT 0x15 -#define CHAR_a_GRAVE 0x16 -#define CHAR_a_ACUTE 0x17 -//#define CHAR_a_CIRCUMFLEX 0x18 // Is 0x68 instead -#define CHAR_c_CEDILLA 0x19 -#define CHAR_e_GRAVE 0x1A -#define CHAR_e_ACUTE 0x1B -#define CHAR_e_CIRCUMFLEX 0x1C -#define CHAR_e_DIAERESIS 0x1D -#define CHAR_i_GRAVE 0x1E -//#define CHAR_i_ACUTE 0x1F // Is 0x6F instead -#define CHAR_i_CIRCUMFLEX 0x20 -#define CHAR_i_DIAERESIS 0x21 -#define CHAR_o_GRAVE 0x22 -#define CHAR_o_ACUTE 0x23 -#define CHAR_o_CIRCUMFLEX 0x24 -#define CHAR_oe 0x25 -#define CHAR_u_GRAVE 0x26 -#define CHAR_u_ACUTE 0x27 -#define CHAR_u_CIRCUMFLEX 0x28 -#define CHAR_n_TILDE 0x29 -#define CHAR_MASCULINE_ORDINAL 0x2A -#define CHAR_FEMININE_ORDINAL 0x2B -#define CHAR_SUPER_ER 0x2C -#define CHAR_AMPERSAND 0x2D -#define CHAR_PLUS 0x2E -// -#define CHAR_LV 0x34 -#define CHAR_EQUALS 0x35 -#define CHAR_SEMICOLON 0x36 -// -#define CHAR_INV_QUESTION_MARK 0x51 -#define CHAR_INV_EXCL_MARK 0x52 -#define CHAR_PK 0x53 -#define CHAR_MN 0x54 -#define CHAR_PO 0x55 -#define CHAR_KE 0x56 -#define CHAR_BLOCK_1 0x57 // Each of these 3 -#define CHAR_BLOCK_2 0x58 // chars contains 1/3 -#define CHAR_BLOCK_3 0x59 // of the word BLOCK -#define CHAR_I_ACUTE 0x5A -#define CHAR_PERCENT 0x5B -#define CHAR_LEFT_PAREN 0x5C -#define CHAR_RIGHT_PAREN 0x5D -// -#define CHAR_a_CIRCUMFLEX 0x68 -// -#define CHAR_i_ACUTE 0x6F -// -#define CHAR_GENDERLESS 0x77 // Empty space for lack of gender icon -// -#define CHAR_UP_ARROW 0x79 -#define CHAR_DOWN_ARROW 0x7A -#define CHAR_LEFT_ARROW 0x7B -#define CHAR_RIGHT_ARROW 0x7C -// -#define CHAR_SUPER_E 0x84 -#define CHAR_LESS_THAN 0x85 -#define CHAR_GREATER_THAN 0x86 -// -#define CHAR_SUPER_RE 0xA0 -#define CHAR_0 0xA1 -#define CHAR_1 0xA2 -#define CHAR_2 0xA3 -#define CHAR_3 0xA4 -#define CHAR_4 0xA5 -#define CHAR_5 0xA6 -#define CHAR_6 0xA7 -#define CHAR_7 0xA8 -#define CHAR_8 0xA9 -#define CHAR_9 0xAA -#define CHAR_EXCL_MARK 0xAB -#define CHAR_QUESTION_MARK 0xAC -#define CHAR_PERIOD 0xAD -#define CHAR_HYPHEN 0xAE -#define CHAR_BULLET 0xAF -#define CHAR_ELLIPSIS 0xB0 -#define CHAR_DBL_QUOT_LEFT 0xB1 -#define CHAR_DBL_QUOT_RIGHT 0xB2 -#define CHAR_SGL_QUOT_LEFT 0xB3 -#define CHAR_SGL_QUOT_RIGHT 0xB4 -#define CHAR_MALE 0xB5 -#define CHAR_FEMALE 0xB6 -#define CHAR_CURRENCY 0xB7 -#define CHAR_COMMA 0xB8 -#define CHAR_MULT_SIGN 0xB9 -#define CHAR_SLASH 0xBA -#define CHAR_A 0xBB -#define CHAR_B 0xBC -#define CHAR_C 0xBD -#define CHAR_D 0xBE -#define CHAR_E 0xBF -#define CHAR_F 0xC0 -#define CHAR_G 0xC1 -#define CHAR_H 0xC2 -#define CHAR_I 0xC3 -#define CHAR_J 0xC4 -#define CHAR_K 0xC5 -#define CHAR_L 0xC6 -#define CHAR_M 0xC7 -#define CHAR_N 0xC8 -#define CHAR_O 0xC9 -#define CHAR_P 0xCA -#define CHAR_Q 0xCB -#define CHAR_R 0xCC -#define CHAR_S 0xCD -#define CHAR_T 0xCE -#define CHAR_U 0xCF -#define CHAR_V 0xD0 -#define CHAR_W 0xD1 -#define CHAR_X 0xD2 -#define CHAR_Y 0xD3 -#define CHAR_Z 0xD4 -#define CHAR_a 0xD5 -#define CHAR_b 0xD6 -#define CHAR_c 0xD7 -#define CHAR_d 0xD8 -#define CHAR_e 0xD9 -#define CHAR_f 0xDA -#define CHAR_g 0xDB -#define CHAR_h 0xDC -#define CHAR_i 0xDD -#define CHAR_j 0xDE -#define CHAR_k 0xDF -#define CHAR_l 0xE0 -#define CHAR_m 0xE1 -#define CHAR_n 0xE2 -#define CHAR_o 0xE3 -#define CHAR_p 0xE4 -#define CHAR_q 0xE5 -#define CHAR_r 0xE6 -#define CHAR_s 0xE7 -#define CHAR_t 0xE8 -#define CHAR_u 0xE9 -#define CHAR_v 0xEA -#define CHAR_w 0xEB -#define CHAR_x 0xEC -#define CHAR_y 0xED -#define CHAR_z 0xEE -#define CHAR_BLACK_TRIANGLE 0xEF -#define CHAR_COLON 0xF0 -#define CHAR_A_DIAERESIS 0xF1 -#define CHAR_O_DIAERESIS 0xF2 -#define CHAR_U_DIAERESIS 0xF3 -#define CHAR_a_DIAERESIS 0xF4 -#define CHAR_o_DIAERESIS 0xF5 -#define CHAR_u_DIAERESIS 0xF6 -#define CHAR_DYNAMIC 0xF7 -#define CHAR_KEYPAD_ICON 0xF8 -#define CHAR_EXTRA_SYMBOL 0xF9 -#define CHAR_PROMPT_SCROLL 0xFA // waits for button press and scrolls dialog -#define CHAR_PROMPT_CLEAR 0xFB // waits for button press and clears dialog -#define EXT_CTRL_CODE_BEGIN 0xFC // extended control code -#define PLACEHOLDER_BEGIN 0xFD // string placeholder -#define CHAR_NEWLINE 0xFE -#define EOS 0xFF // end of string - -// CHAR_KEYPAD_ICON chars -#define CHAR_A_BUTTON 0x00 -#define CHAR_B_BUTTON 0x01 -#define CHAR_L_BUTTON 0x02 -#define CHAR_R_BUTTON 0x03 -#define CHAR_START_BUTTON 0x04 -#define CHAR_SELECT_BUTTON 0x05 -#define CHAR_DPAD_UP 0x06 -#define CHAR_DPAD_DOWN 0x07 -#define CHAR_DPAD_LEFT 0x08 -#define CHAR_DPAD_RIGHT 0x09 -#define CHAR_DPAD_UPDOWN 0x0A -#define CHAR_DPAD_LEFTRIGHT 0x0B -#define CHAR_DPAD_NONE 0x0C - -// CHAR_EXTRA_SYMBOL chars -#define CHAR_UP_ARROW_2 0x00 -#define CHAR_DOWN_ARROW_2 0x01 -#define CHAR_LEFT_ARROW_2 0x02 -#define CHAR_RIGHT_ARROW_2 0x03 -#define CHAR_PLUS_2 0x04 -#define CHAR_LV_2 0x05 -#define CHAR_PP 0x06 -#define CHAR_ID 0x07 -#define CHAR_NO 0x08 -#define CHAR_UNDERSCORE 0x09 - -#define EXT_CTRL_CODE_COLOR 0x01 -#define EXT_CTRL_CODE_HIGHLIGHT 0x02 -#define EXT_CTRL_CODE_SHADOW 0x03 -#define EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW 0x04 -#define EXT_CTRL_CODE_PALETTE 0x05 -#define EXT_CTRL_CODE_SIZE 0x06 -#define EXT_CTRL_CODE_RESET_SIZE 0x07 -#define EXT_CTRL_CODE_PAUSE 0x08 -#define EXT_CTRL_CODE_PAUSE_UNTIL_PRESS 0x09 -#define EXT_CTRL_CODE_WAIT_SE 0x0A -#define EXT_CTRL_CODE_PLAY_BGM 0x0B -#define EXT_CTRL_CODE_ESCAPE 0x0C -#define EXT_CTRL_CODE_SHIFT_TEXT 0x0D -#define EXT_CTRL_CODE_SHIFT_DOWN 0x0E -#define EXT_CTRL_CODE_FILL_WINDOW 0x0F -#define EXT_CTRL_CODE_PLAY_SE 0x10 -#define EXT_CTRL_CODE_CLEAR 0x11 -#define EXT_CTRL_CODE_SKIP 0x12 -#define EXT_CTRL_CODE_CLEAR_TO 0x13 -#define EXT_CTRL_CODE_MIN_LETTER_SPACING 0x14 -#define EXT_CTRL_CODE_JPN 0x15 -#define EXT_CTRL_CODE_ENG 0x16 -#define EXT_CTRL_CODE_PAUSE_MUSIC 0x17 -#define EXT_CTRL_CODE_RESUME_MUSIC 0x18 - -#define TEXT_COLOR_TRANSPARENT 0x0 -#define TEXT_COLOR_WHITE 0x1 -#define TEXT_COLOR_DARK_GRAY 0x2 -#define TEXT_COLOR_LIGHT_GRAY 0x3 -#define TEXT_COLOR_RED 0x4 -#define TEXT_COLOR_LIGHT_RED 0x5 -#define TEXT_COLOR_GREEN 0x6 -#define TEXT_COLOR_LIGHT_GREEN 0x7 -#define TEXT_COLOR_BLUE 0x8 -#define TEXT_COLOR_LIGHT_BLUE 0x9 -#define TEXT_DYNAMIC_COLOR_1 0xA // Usually white -#define TEXT_DYNAMIC_COLOR_2 0xB // Usually white w/ tinge of green -#define TEXT_DYNAMIC_COLOR_3 0xC // Usually white -#define TEXT_DYNAMIC_COLOR_4 0xD // Usually aquamarine -#define TEXT_DYNAMIC_COLOR_5 0xE // Usually blue-green -#define TEXT_DYNAMIC_COLOR_6 0xF // Usually cerulean - -#define PLACEHOLDER_ID_UNKNOWN 0x0 -#define PLACEHOLDER_ID_PLAYER 0x1 -#define PLACEHOLDER_ID_STRING_VAR_1 0x2 -#define PLACEHOLDER_ID_STRING_VAR_2 0x3 -#define PLACEHOLDER_ID_STRING_VAR_3 0x4 -#define PLACEHOLDER_ID_KUN 0x5 -#define PLACEHOLDER_ID_RIVAL 0x6 -#define PLACEHOLDER_ID_VERSION 0x7 -#define PLACEHOLDER_ID_AQUA 0x8 -#define PLACEHOLDER_ID_MAGMA 0x9 -#define PLACEHOLDER_ID_ARCHIE 0xA -#define PLACEHOLDER_ID_MAXIE 0xB -#define PLACEHOLDER_ID_KYOGRE 0xC -#define PLACEHOLDER_ID_GROUDON 0xD - -// battle placeholders are located in battle_message.h - -#define NUM_TEXT_PRINTERS 32 - -#define TEXT_SPEED_FF 0xFF - -enum -{ - FONTATTR_MAX_LETTER_WIDTH, - FONTATTR_MAX_LETTER_HEIGHT, - FONTATTR_LETTER_SPACING, - FONTATTR_LINE_SPACING, - FONTATTR_UNKNOWN, // dunno what this is yet - FONTATTR_COLOR_FOREGROUND, - FONTATTR_COLOR_BACKGROUND, - FONTATTR_COLOR_SHADOW -}; - -struct TextPrinterSubStruct -{ - u8 glyphId:4; // 0x14 - bool8 hasPrintBeenSpedUp:1; - u8 unk:3; - u8 downArrowDelay:5; - u8 downArrowYPosIdx:2; - bool8 hasGlyphIdBeenSet:1; - u8 autoScrollDelay; -}; - -struct TextPrinterTemplate -{ - const u8* currentChar; - u8 windowId; - u8 fontId; - u8 x; - u8 y; - u8 currentX; // 0x8 - u8 currentY; - u8 letterSpacing; - u8 lineSpacing; - u8 unk:4; // 0xC - u8 fgColor:4; - u8 bgColor:4; - u8 shadowColor:4; -}; - -struct TextPrinter -{ - struct TextPrinterTemplate printerTemplate; - - void (*callback)(struct TextPrinterTemplate *, u16); // 0x10 - - u8 subStructFields[7]; // always cast to struct TextPrinterSubStruct... so why bother - u8 active; - u8 state; // 0x1C - u8 textSpeed; - u8 delayCounter; - u8 scrollDistance; - u8 minLetterSpacing; // 0x20 - u8 japanese; -}; - -struct FontInfo -{ - u16 (*fontFunction)(struct TextPrinter *x); - u8 maxLetterWidth; - u8 maxLetterHeight; - u8 letterSpacing; - u8 lineSpacing; - u8 unk:4; - u8 fgColor:4; - u8 bgColor:4; - u8 shadowColor:4; -}; - -extern const struct FontInfo *gFonts; - -struct GlyphWidthFunc -{ - u32 fontId; - u32 (*func)(u16 glyphId, bool32 isJapanese); -}; - -struct KeypadIcon -{ - u16 tileOffset; - u8 width; - u8 height; -}; - -typedef struct { - bool8 canABSpeedUpPrint:1; - bool8 useAlternateDownArrow:1; - bool8 autoScroll:1; - bool8 forceMidTextSpeed:1; -} TextFlags; - -struct TextGlyph -{ - u32 gfxBufferTop[16]; - u32 gfxBufferBottom[16]; - u8 width; - u8 height; -}; - -extern TextFlags gTextFlags; - -extern u8 gDisableTextPrinters; -extern struct TextGlyph gCurGlyph; - -void SetFontsPointer(const struct FontInfo *fonts); -void DeactivateAllTextPrinters(void); -u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); -bool16 AddTextPrinter(struct TextPrinterTemplate *template, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); -void RunTextPrinters(void); -bool16 IsTextPrinterActive(u8 id); -u32 RenderFont(struct TextPrinter *textPrinter); -void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor); -void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); -void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); -void DecompressGlyphTile(const void *src_, void *dest_); -u8 GetLastTextColor(u8 colorType); -void CopyGlyphToWindow(struct TextPrinter *x); -void ClearTextSpan(struct TextPrinter *textPrinter, u32 width); -u8 GetMenuCursorDimensionByFont(u8, u8); - -u16 Font0Func(struct TextPrinter *textPrinter); -u16 Font1Func(struct TextPrinter *textPrinter); -u16 Font2Func(struct TextPrinter *textPrinter); -u16 Font3Func(struct TextPrinter *textPrinter); -u16 Font4Func(struct TextPrinter *textPrinter); -u16 Font5Func(struct TextPrinter *textPrinter); -u16 Font7Func(struct TextPrinter *textPrinter); -u16 Font8Func(struct TextPrinter *textPrinter); - -void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter); -void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter); -void TextPrinterClearDownArrow(struct TextPrinter *textPrinter); -bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter); -bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter); -bool16 TextPrinterWait(struct TextPrinter *textPrinter); -void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex); -u16 RenderText(struct TextPrinter *textPrinter); -u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing); -u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32); -s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing); -u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str); -u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y); -u8 GetKeypadIconTileOffset(u8 keypadIconId); -u8 GetKeypadIconWidth(u8 keypadIconId); -u8 GetKeypadIconHeight(u8 keypadIconId); -void SetDefaultFontsPointer(void); -u8 GetFontAttribute(u8 fontId, u8 attributeId); -u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension); -void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont9(u16 glyphId); - -// unk_text_util_2.c -u16 Font6Func(struct TextPrinter *textPrinter); -u32 GetGlyphWidthFont6(u16 glyphId, bool32 isJapanese); - -#endif // GUARD_TEXT_H diff --git a/gflib/window.c b/gflib/window.c deleted file mode 100644 index b03b513da..000000000 --- a/gflib/window.c +++ /dev/null @@ -1,721 +0,0 @@ -#include "global.h" -#include "window.h" -#include "malloc.h" -#include "bg.h" -#include "blit.h" - -u32 gUnusedWindowVar1; -u32 gUnusedWindowVar2; -// This global is set to 0 and never changed. -u8 gTransparentTileNumber; -u32 gUnusedWindowVar3; -void *gWindowBgTilemapBuffers[NUM_BACKGROUNDS]; -extern u32 gUnneededFireRedVariable; - -#define WINDOWS_MAX 32 - -EWRAM_DATA struct Window gWindows[WINDOWS_MAX] = {0}; -EWRAM_DATA static struct Window* sWindowPtr = NULL; -EWRAM_DATA static u16 sWindowSize = 0; - -static u8 GetNumActiveWindowsOnBg(u8 bgId); -static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId); - -static const struct WindowTemplate sDummyWindowTemplate = DUMMY_WIN_TEMPLATE; - -static void DummyWindowBgTilemap(void) -{ - -} - -bool16 InitWindows(const struct WindowTemplate *templates) -{ - int i; - void *bgTilemapBuffer; - int j; - u8 bgLayer; - u16 attrib; - u8* allocatedTilemapBuffer; - int allocatedBaseBlock; - - for (i = 0; i < NUM_BACKGROUNDS; ++i) - { - bgTilemapBuffer = GetBgTilemapBuffer(i); - if (bgTilemapBuffer != NULL) - gWindowBgTilemapBuffers[i] = DummyWindowBgTilemap; - else - gWindowBgTilemapBuffers[i] = bgTilemapBuffer; - } - - for (i = 0; i < WINDOWS_MAX; ++i) - { - gWindows[i].window = sDummyWindowTemplate; - gWindows[i].tileData = NULL; - } - - for (i = 0, allocatedBaseBlock = 0, bgLayer = templates[i].bg; bgLayer != 0xFF && i < WINDOWS_MAX; ++i, bgLayer = templates[i].bg) - { - if (gUnneededFireRedVariable == 1) - { - allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, templates[i].width * templates[i].height, 0); - if (allocatedBaseBlock == -1) - return FALSE; - } - - if (gWindowBgTilemapBuffers[bgLayer] == NULL) - { - attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); - - if (attrib != 0xFFFF) - { - allocatedTilemapBuffer = AllocZeroed(attrib); - - if (allocatedTilemapBuffer == NULL) - { - FreeAllWindowBuffers(); - return FALSE; - } - - for (j = 0; j < attrib; ++j) - allocatedTilemapBuffer[j] = 0; - - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); - } - } - - allocatedTilemapBuffer = AllocZeroed((u16)(32 * (templates[i].width * templates[i].height))); - - if (allocatedTilemapBuffer == NULL) - { - if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - } - - return FALSE; - } - - gWindows[i].tileData = allocatedTilemapBuffer; - gWindows[i].window = templates[i]; - - if (gUnneededFireRedVariable == 1) - { - gWindows[i].window.baseBlock = allocatedBaseBlock; - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, templates[i].width * templates[i].height, 1); - } - } - - gTransparentTileNumber = 0; - return TRUE; -} - -u16 AddWindow(const struct WindowTemplate *template) -{ - u16 win; - u8 bgLayer; - int allocatedBaseBlock; - u16 attrib; - u8 *allocatedTilemapBuffer; - int i; - - for (win = 0; win < WINDOWS_MAX; ++win) - { - if ((bgLayer = gWindows[win].window.bg) == 0xFF) - break; - } - - if (win == WINDOWS_MAX) - return WINDOW_NONE; - - bgLayer = template->bg; - allocatedBaseBlock = 0; - - if (gUnneededFireRedVariable == 1) - { - allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); - - if (allocatedBaseBlock == -1) - return WINDOW_NONE; - } - - if (gWindowBgTilemapBuffers[bgLayer] == NULL) - { - attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); - - if (attrib != 0xFFFF) - { - allocatedTilemapBuffer = AllocZeroed(attrib); - - if (allocatedTilemapBuffer == NULL) - return WINDOW_NONE; - - for (i = 0; i < attrib; ++i) - allocatedTilemapBuffer[i] = 0; - - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); - } - } - - allocatedTilemapBuffer = AllocZeroed((u16)(32 * (template->width * template->height))); - - if (allocatedTilemapBuffer == NULL) - { - if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - } - return WINDOW_NONE; - } - - gWindows[win].tileData = allocatedTilemapBuffer; - gWindows[win].window = *template; - - if (gUnneededFireRedVariable == 1) - { - gWindows[win].window.baseBlock = allocatedBaseBlock; - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); - } - - return win; -} - -int AddWindowWithoutTileMap(const struct WindowTemplate *template) -{ - u16 win; - u8 bgLayer; - int allocatedBaseBlock; - - for (win = 0; win < WINDOWS_MAX; ++win) - { - if (gWindows[win].window.bg == 0xFF) - break; - } - - if (win == WINDOWS_MAX) - return WINDOW_NONE; - - bgLayer = template->bg; - allocatedBaseBlock = 0; - - if (gUnneededFireRedVariable == 1) - { - allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); - - if (allocatedBaseBlock == -1) - return WINDOW_NONE; - } - - gWindows[win].window = *template; - - if (gUnneededFireRedVariable == 1) - { - gWindows[win].window.baseBlock = allocatedBaseBlock; - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); - } - - return win; -} - -void RemoveWindow(u8 windowId) -{ - u8 bgLayer = gWindows[windowId].window.bg; - - if (gUnneededFireRedVariable == 1) - { - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, gWindows[windowId].window.baseBlock, gWindows[windowId].window.width * gWindows[windowId].window.height, 2); - } - - gWindows[windowId].window = sDummyWindowTemplate; - - if (GetNumActiveWindowsOnBg(bgLayer) == 0) - { - if (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = NULL; - } - } - - if (gWindows[windowId].tileData != NULL) - { - Free(gWindows[windowId].tileData); - gWindows[windowId].tileData = NULL; - } -} - -void FreeAllWindowBuffers(void) -{ - int i; - - for (i = 0; i < NUM_BACKGROUNDS; ++i) - { - if (gWindowBgTilemapBuffers[i] != NULL && gWindowBgTilemapBuffers[i] != DummyWindowBgTilemap) - { - Free(gWindowBgTilemapBuffers[i]); - gWindowBgTilemapBuffers[i] = NULL; - } - } - - for (i = 0; i < WINDOWS_MAX; ++i) - { - if (gWindows[i].tileData != NULL) - { - Free(gWindows[i].tileData); - gWindows[i].tileData = NULL; - } - } -} - -void CopyWindowToVram(u8 windowId, u8 mode) -{ - struct Window windowLocal = gWindows[windowId]; - u16 windowSize = 32 * (windowLocal.window.width * windowLocal.window.height); - - switch (mode) - { - case 1: - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - case 2: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); - break; - case 3: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - } -} - -void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h) -{ - struct Window windowLocal; - int rectSize; - int rectPos; - - if (w != 0 && h != 0) - { - windowLocal = gWindows[windowId]; - - rectSize = ((h - 1) * windowLocal.window.width); - rectSize += (windowLocal.window.width - x); - rectSize -= (windowLocal.window.width - (x + w)); - rectSize *= 32; - - rectPos = (y * windowLocal.window.width) + x; - - switch (mode) - { - case 1: - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - case 2: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); - break; - case 3: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - } - } -} - -void PutWindowTilemap(u8 windowId) -{ - struct Window windowLocal = gWindows[windowId]; - - WriteSequenceToBgTilemapBuffer( - windowLocal.window.bg, - GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE) + windowLocal.window.baseBlock, - windowLocal.window.tilemapLeft, - windowLocal.window.tilemapTop, - windowLocal.window.width, - windowLocal.window.height, - windowLocal.window.paletteNum, - 1); -} - -void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette) -{ - struct Window windowLocal = gWindows[windowId]; - u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); - int i; - - for (i = 0; i < height; ++i) - { - WriteSequenceToBgTilemapBuffer( - windowLocal.window.bg, - currentRow, - windowLocal.window.tilemapLeft + x, - windowLocal.window.tilemapTop + y + i, - width, - 1, - palette, - 1); - - currentRow += windowLocal.window.width; - } -} - -// Fills a window with transparent tiles. -void ClearWindowTilemap(u8 windowId) -{ - struct Window windowLocal = gWindows[windowId]; - - FillBgTilemapBufferRect( - windowLocal.window.bg, - gTransparentTileNumber, - windowLocal.window.tilemapLeft, - windowLocal.window.tilemapTop, - windowLocal.window.width, - windowLocal.window.height, - windowLocal.window.paletteNum); -} - -void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) -{ - struct Window windowLocal = gWindows[windowId]; - u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); - int i; - - for (i = 0; i < height; ++i) - { - WriteSequenceToBgTilemapBuffer( - windowLocal.window.bg, - currentRow, - windowLocal.window.tilemapLeft + x, - windowLocal.window.tilemapTop + y + i, - width, - 1, - windowLocal.window.paletteNum, - 1); - - currentRow += windowLocal.window.width; - } -} - -void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height) -{ - BlitBitmapRectToWindow(windowId, pixels, 0, 0, width, height, x, y, width, height); -} - -void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight) -{ - struct Bitmap sourceRect; - struct Bitmap destRect; - - sourceRect.pixels = (u8*)pixels; - sourceRect.width = srcWidth; - sourceRect.height = srcHeight; - - destRect.pixels = gWindows[windowId].tileData; - destRect.width = 8 * gWindows[windowId].window.width; - destRect.height = 8 * gWindows[windowId].window.height; - - BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0); -} - -static void BlitBitmapRectToWindowWithColorKey(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 colorKey) -{ - struct Bitmap sourceRect; - struct Bitmap destRect; - - sourceRect.pixels = (u8*)pixels; - sourceRect.width = srcWidth; - sourceRect.height = srcHeight; - - destRect.pixels = gWindows[windowId].tileData; - destRect.width = 8 * gWindows[windowId].window.width; - destRect.height = 8 * gWindows[windowId].window.height; - - BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, colorKey); -} - -void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) -{ - struct Bitmap pixelRect; - - pixelRect.pixels = gWindows[windowId].tileData; - pixelRect.width = 8 * gWindows[windowId].window.width; - pixelRect.height = 8 * gWindows[windowId].window.height; - - FillBitmapRect4Bit(&pixelRect, x, y, width, height, fillValue); -} - -void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset) -{ - if (size != 0) - CpuCopy16(src, gWindows[windowId].tileData + (32 * tileOffset), size); - else - LZ77UnCompWram(src, gWindows[windowId].tileData + (32 * tileOffset)); -} - -// Sets all pixels within the window to the fillValue color. -void FillWindowPixelBuffer(u8 windowId, u8 fillValue) -{ - int fillSize = gWindows[windowId].window.width * gWindows[windowId].window.height; - CpuFastFill8(fillValue, gWindows[windowId].tileData, 32 * fillSize); -} - -#define MOVE_TILES_DOWN(a) \ -{ \ - destOffset = i + (a); \ - srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ - if (srcOffset < size) \ - *(u32*)(tileData + destOffset) = *(u32*)(tileData + srcOffset); \ - else \ - *(u32*)(tileData + destOffset) = fillValue32; \ - distanceLoop++; \ -} - -#define MOVE_TILES_UP(a) \ -{ \ - destOffset = i + (a); \ - srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ - if (srcOffset < size) \ - *(u32*)(tileData - destOffset) = *(u32*)(tileData - srcOffset); \ - else \ - *(u32*)(tileData - destOffset) = fillValue32; \ - distanceLoop++; \ -} - -void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue) -{ - struct WindowTemplate window = gWindows[windowId].window; - u8 *tileData = gWindows[windowId].tileData; - u32 fillValue32 = (fillValue << 24) | (fillValue << 16) | (fillValue << 8) | fillValue; - s32 size = window.height * window.width * 32; - u32 width = window.width; - s32 i; - s32 srcOffset, destOffset; - u32 distanceLoop; - - switch (direction) - { - case 0: - for (i = 0; i < size; i += 32) - { - distanceLoop = distance; - MOVE_TILES_DOWN(0) - MOVE_TILES_DOWN(4) - MOVE_TILES_DOWN(8) - MOVE_TILES_DOWN(12) - MOVE_TILES_DOWN(16) - MOVE_TILES_DOWN(20) - MOVE_TILES_DOWN(24) - MOVE_TILES_DOWN(28) - } - break; - case 1: - tileData += size - 4; - for (i = 0; i < size; i += 32) - { - distanceLoop = distance; - MOVE_TILES_UP(0) - MOVE_TILES_UP(4) - MOVE_TILES_UP(8) - MOVE_TILES_UP(12) - MOVE_TILES_UP(16) - MOVE_TILES_UP(20) - MOVE_TILES_UP(24) - MOVE_TILES_UP(28) - } - break; - case 2: - break; - } -} - -void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)) -{ - struct WindowTemplate window = gWindows[windowId].window; - func(window.bg, window.tilemapLeft, window.tilemapTop, window.width, window.height, window.paletteNum); -} - -bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value) -{ - switch (attributeId) - { - case WINDOW_TILEMAP_LEFT: - gWindows[windowId].window.tilemapLeft = value; - return FALSE; - case WINDOW_TILEMAP_TOP: - gWindows[windowId].window.tilemapTop = value; - return FALSE; - case WINDOW_PALETTE_NUM: - gWindows[windowId].window.paletteNum = value; - return FALSE; - case WINDOW_BASE_BLOCK: - gWindows[windowId].window.baseBlock = value; - return FALSE; - case WINDOW_TILE_DATA: - gWindows[windowId].tileData = (u8*)(value); - return TRUE; - case WINDOW_BG: - case WINDOW_WIDTH: - case WINDOW_HEIGHT: - default: - return TRUE; - } -} - -u32 GetWindowAttribute(u8 windowId, u8 attributeId) -{ - switch (attributeId) - { - case WINDOW_BG: - return gWindows[windowId].window.bg; - case WINDOW_TILEMAP_LEFT: - return gWindows[windowId].window.tilemapLeft; - case WINDOW_TILEMAP_TOP: - return gWindows[windowId].window.tilemapTop; - case WINDOW_WIDTH: - return gWindows[windowId].window.width; - case WINDOW_HEIGHT: - return gWindows[windowId].window.height; - case WINDOW_PALETTE_NUM: - return gWindows[windowId].window.paletteNum; - case WINDOW_BASE_BLOCK: - return gWindows[windowId].window.baseBlock; - case WINDOW_TILE_DATA: - return (u32)(gWindows[windowId].tileData); - default: - return 0; - } -} - -static u8 GetNumActiveWindowsOnBg(u8 bgId) -{ - u8 windowsNum = 0; - s32 i; - for (i = 0; i < WINDOWS_MAX; i++) - { - if (gWindows[i].window.bg == bgId) - windowsNum++; - } - return windowsNum; -} - -static void DummyWindowBgTilemap8Bit(void) -{ - -} - -u16 AddWindow8Bit(const struct WindowTemplate *template) -{ - u16 windowId; - u8* memAddress; - u8 bgLayer; - - for (windowId = 0; windowId < WINDOWS_MAX; windowId++) - { - if (gWindows[windowId].window.bg == 0xFF) - break; - } - if (windowId == WINDOWS_MAX) - return WINDOW_NONE; - bgLayer = template->bg; - if (gWindowBgTilemapBuffers[bgLayer] == NULL) - { - u16 attribute = GetBgAttribute(bgLayer, BG_ATTR_METRIC); - if (attribute != 0xFFFF) - { - s32 i; - memAddress = Alloc(attribute); - if (memAddress == NULL) - return WINDOW_NONE; - for (i = 0; i < attribute; i++) // if we're going to zero out the memory anyway, why not call AllocZeroed? - memAddress[i] = 0; - gWindowBgTilemapBuffers[bgLayer] = memAddress; - SetBgTilemapBuffer(bgLayer, memAddress); - } - } - memAddress = Alloc((u16)(64 * (template->width * template->height))); - if (memAddress == NULL) - { - if (GetNumActiveWindowsOnBg8Bit(bgLayer) == 0 && gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap8Bit) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = NULL; - } - return WINDOW_NONE; - } - else - { - gWindows[windowId].tileData = memAddress; - gWindows[windowId].window = *template; - return windowId; - } -} - -void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue) -{ - s32 i; - s32 size; - - size = (u16)(64 * (gWindows[windowId].window.width * gWindows[windowId].window.height)); - for (i = 0; i < size; i++) - gWindows[windowId].tileData[i] = fillValue; -} - -void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) -{ - struct Bitmap pixelRect; - - pixelRect.pixels = gWindows[windowId].tileData; - pixelRect.width = 8 * gWindows[windowId].window.width; - pixelRect.height = 8 * gWindows[windowId].window.height; - - FillBitmapRect8Bit(&pixelRect, x, y, width, height, fillValue); -} - -void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum) -{ - struct Bitmap sourceRect; - struct Bitmap destRect; - - sourceRect.pixels = (u8*) pixels; - sourceRect.width = srcWidth; - sourceRect.height = srcHeight; - - destRect.pixels = gWindows[windowId].tileData; - destRect.width = 8 * gWindows[windowId].window.width; - destRect.height = 8 * gWindows[windowId].window.height; - - BlitBitmapRect4BitTo8Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0, paletteNum); -} - -void CopyWindowToVram8Bit(u8 windowId, u8 mode) -{ - sWindowPtr = &gWindows[windowId]; - sWindowSize = 64 * (sWindowPtr->window.width * sWindowPtr->window.height); - - switch (mode) - { - case 1: - CopyBgTilemapBufferToVram(sWindowPtr->window.bg); - break; - case 2: - LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); - break; - case 3: - LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); - CopyBgTilemapBufferToVram(sWindowPtr->window.bg); - break; - } -} - -static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId) -{ - u8 windowsNum = 0; - s32 i; - for (i = 0; i < WINDOWS_MAX; i++) - { - if (gWindows[i].window.bg == bgId) - windowsNum++; - } - return windowsNum; -} diff --git a/gflib/window.h b/gflib/window.h deleted file mode 100644 index 3eac75a28..000000000 --- a/gflib/window.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef GUARD_WINDOW_H -#define GUARD_WINDOW_H - -#define PIXEL_FILL(num) ((num) | ((num) << 4)) - -enum -{ - WINDOW_BG, - WINDOW_TILEMAP_LEFT, - WINDOW_TILEMAP_TOP, - WINDOW_WIDTH, - WINDOW_HEIGHT, - WINDOW_PALETTE_NUM, - WINDOW_BASE_BLOCK, - WINDOW_TILE_DATA -}; - -struct WindowTemplate -{ - u8 bg; - u8 tilemapLeft; - u8 tilemapTop; - u8 width; - u8 height; - u8 paletteNum; - u16 baseBlock; -}; - -#define DUMMY_WIN_TEMPLATE \ -{ \ - 0xFF, \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ -} - -#define WINDOW_NONE 0xFF - -struct Window -{ - struct WindowTemplate window; - u8 *tileData; -}; - -bool16 InitWindows(const struct WindowTemplate *templates); -u16 AddWindow(const struct WindowTemplate *template); -int AddWindowWithoutTileMap(const struct WindowTemplate *template); -void RemoveWindow(u8 windowId); -void FreeAllWindowBuffers(void); -void CopyWindowToVram(u8 windowId, u8 mode); -void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h); -void PutWindowTilemap(u8 windowId); -void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette); -void ClearWindowTilemap(u8 windowId); -void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height); -void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height); -void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight); -void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); -void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset); -void FillWindowPixelBuffer(u8 windowId, u8 fillValue); -void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue); -void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)); -bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value); -u32 GetWindowAttribute(u8 windowId, u8 attributeId); -u16 AddWindow8Bit(const struct WindowTemplate *template); -void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue); -void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); -void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum); -void CopyWindowToVram8Bit(u8 windowId, u8 mode); - -extern struct Window gWindows[]; -extern void* gWindowBgTilemapBuffers[]; -extern u32 gUnusedWindowVar1; -extern u32 gUnusedWindowVar2; -extern u32 gUnusedWindowVar3; - -#endif // GUARD_WINDOW_H diff --git a/include/bg.h b/include/bg.h new file mode 100644 index 000000000..58fd1282c --- /dev/null +++ b/include/bg.h @@ -0,0 +1,85 @@ +#ifndef GUARD_BG_H +#define GUARD_BG_H + +struct BGCntrlBitfield // for the I/O registers +{ + volatile u16 priority:2; + volatile u16 charBaseBlock:2; + volatile u16 field_0_2:4; + volatile u16 field_1_0:5; + volatile u16 areaOverflowMode:1; + volatile u16 screenSize:2; +}; + +enum +{ + BG_ATTR_CHARBASEINDEX = 1, + BG_ATTR_MAPBASEINDEX, + BG_ATTR_SCREENSIZE, + BG_ATTR_PALETTEMODE, + BG_ATTR_MOSAIC, + BG_ATTR_WRAPAROUND, + BG_ATTR_PRIORITY, + BG_ATTR_METRIC, + BG_ATTR_TYPE, + BG_ATTR_BASETILE, +}; + +struct BgTemplate +{ + u16 bg:2; // 0x1, 0x2 -> 0x3 + u16 charBaseIndex:2; // 0x4, 0x8 -> 0xC + u16 mapBaseIndex:5; // 0x10, 0x20, 0x40, 0x80, 0x100 -> 0x1F0 + u16 screenSize:2; // 0x200, 0x400 -> 0x600 + u16 paletteMode:1; // 0x800 + u16 priority:2; // 0x1000, 0x2000 > 0x3000 + u16 baseTile:10; +}; + +void ResetBgs(void); +u8 GetBgMode(void); +void ResetBgControlStructs(void); +void Unused_ResetBgControlStruct(u8 bg); +u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode); +void SetTextModeAndHideBgs(void); +bool8 IsInvalidBg(u8 bg); +int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4); +void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); +void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates); +void InitBgFromTemplate(const struct BgTemplate *template); +void SetBgMode(u8 bgMode); +u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset); +u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset); +u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset); +bool8 IsDma3ManagerBusyWithBgCopy(void); +void ShowBg(u8 bg); +void HideBg(u8 bg); +void SetBgAttribute(u8 bg, u8 attributeId, u8 value); +u16 GetBgAttribute(u8 bg, u8 attributeId); +s32 ChangeBgX(u8 bg, s32 value, u8 op); +s32 GetBgX(u8 bg); +s32 ChangeBgY(u8 bg, s32 value, u8 op); +s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op); +s32 GetBgY(u8 bg); +void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle); +u8 Unused_AdjustBgMosaic(u8 a1, u8 a2); +void SetBgTilemapBuffer(u8 bg, void *tilemap); +void UnsetBgTilemapBuffer(u8 bg); +void* GetBgTilemapBuffer(u8 bg); +void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset); +void CopyBgTilemapBufferToVram(u8 bg); +void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height); +void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette); +void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset); +void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height); +void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette); +void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta); +u16 GetBgMetricTextMode(u8 bg, u8 whichMetric); +u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric); +u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight); +void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2); +u32 GetBgType(u8 bg); +bool32 IsInvalidBg32(u8 bg); +bool32 IsTileMapOutsideWram(u8 bg); + +#endif // GUARD_BG_H diff --git a/include/blit.h b/include/blit.h new file mode 100644 index 000000000..78f67766e --- /dev/null +++ b/include/blit.h @@ -0,0 +1,17 @@ +#ifndef GUARD_BLIT_H +#define GUARD_BLIT_H + +struct Bitmap +{ + u8 *pixels; + u32 width:16; + u32 height:16; +}; + +void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height); +void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey); +void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); +void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset); +void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); + +#endif // GUARD_BLIT_H diff --git a/include/dma3.h b/include/dma3.h new file mode 100644 index 000000000..8eff34f55 --- /dev/null +++ b/include/dma3.h @@ -0,0 +1,55 @@ +#ifndef GUARD_DMA3_H +#define GUARD_DMA3_H + +// Maximum amount of data we will transfer in one operation +#define MAX_DMA_BLOCK_SIZE 0x1000 + +#define Dma3CopyLarge_(src, dest, size, bit) \ +{ \ + const void *_src = src; \ + void *_dest = dest; \ + u32 _size = size; \ + while (1) \ + { \ + if (_size <= MAX_DMA_BLOCK_SIZE) \ + { \ + DmaCopy##bit(3, _src, _dest, _size); \ + break; \ + } \ + DmaCopy##bit(3, _src, _dest, MAX_DMA_BLOCK_SIZE); \ + _src += MAX_DMA_BLOCK_SIZE; \ + _dest += MAX_DMA_BLOCK_SIZE; \ + _size -= MAX_DMA_BLOCK_SIZE; \ + } \ +} + +#define Dma3CopyLarge16_(src, dest, size) Dma3CopyLarge_(src, dest, size, 16) +#define Dma3CopyLarge32_(src, dest, size) Dma3CopyLarge_(src, dest, size, 32) + +#define Dma3FillLarge_(value, dest, size, bit) \ +{ \ + void *_dest = dest; \ + u32 _size = size; \ + while (1) \ + { \ + if (_size <= MAX_DMA_BLOCK_SIZE) \ + { \ + DmaFill##bit(3, value, _dest, _size); \ + break; \ + } \ + DmaFill##bit(3, value, _dest, MAX_DMA_BLOCK_SIZE); \ + _dest += MAX_DMA_BLOCK_SIZE; \ + _size -= MAX_DMA_BLOCK_SIZE; \ + } \ +} + +#define Dma3FillLarge16_(value, dest, size) Dma3FillLarge_(value, dest, size, 16) +#define Dma3FillLarge32_(value, dest, size) Dma3FillLarge_(value, dest, size, 32) + +void ClearDma3Requests(void); +void ProcessDma3Requests(void); +s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode); +s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode); +s16 CheckForSpaceForDma3Request(s16 index); + +#endif // GUARD_DMA3_H diff --git a/include/gpu_regs.h b/include/gpu_regs.h new file mode 100644 index 000000000..89e0cb64b --- /dev/null +++ b/include/gpu_regs.h @@ -0,0 +1,19 @@ +#ifndef GUARD_GPU_REGS_H +#define GUARD_GPU_REGS_H + +// Exported type declarations + +// Exported RAM declarations + +// Exported ROM declarations +void InitGpuRegManager(void); +void CopyBufferedValuesToGpuRegs(void); +void SetGpuReg(u8 regOffset, u16 value); +void SetGpuReg_ForcedBlank(u8 regOffset, u16 value); +u16 GetGpuReg(u8 regOffset); +void SetGpuRegBits(u8 regOffset, u16 mask); +void ClearGpuRegBits(u8 regOffset, u16 mask); +void EnableInterrupts(u16 mask); +void DisableInterrupts(u16 mask); + +#endif //GUARD_GPU_REGS_H diff --git a/include/io_reg.h b/include/io_reg.h new file mode 100644 index 000000000..82d2fc5ed --- /dev/null +++ b/include/io_reg.h @@ -0,0 +1,7 @@ +#ifndef GUARD_IO_REG_H +#define GUARD_IO_REG_H + +extern const u16 gOverworldBackgroundLayerFlags[]; +extern const u16 gOrbEffectBackgroundLayerFlags[]; + +#endif // GUARD_IO_REG_H diff --git a/include/malloc.h b/include/malloc.h new file mode 100644 index 000000000..f2dcf6d46 --- /dev/null +++ b/include/malloc.h @@ -0,0 +1,22 @@ +#ifndef GUARD_ALLOC_H +#define GUARD_ALLOC_H + +#define HEAP_SIZE 0x1C000 +#define malloc Alloc +#define calloc(ct, sz) AllocZeroed((ct) * (sz)) +#define free Free + +#define FREE_AND_SET_NULL(ptr) \ +{ \ + free(ptr); \ + ptr = NULL; \ +} + +extern u8 gHeap[]; + +void *Alloc(u32 size); +void *AllocZeroed(u32 size); +void Free(void *pointer); +void InitHeap(void *pointer, u32 size); + +#endif // GUARD_ALLOC_H diff --git a/include/sprite.h b/include/sprite.h new file mode 100644 index 000000000..4a3b48225 --- /dev/null +++ b/include/sprite.h @@ -0,0 +1,324 @@ +#ifndef GUARD_SPRITE_H +#define GUARD_SPRITE_H + +#define MAX_SPRITES 64 +#define SPRITE_NONE 0xFF +#define SPRITE_INVALID_TAG 0xFFFF + +struct SpriteSheet +{ + const void *data; // Raw uncompressed pixel data + u16 size; + u16 tag; +}; + +struct CompressedSpriteSheet +{ + const u32 *data; // LZ77 compressed pixel data + u16 size; // Uncompressed size of pixel data + u16 tag; +}; + +struct SpriteFrameImage +{ + const void *data; + u16 size; +}; + +#define obj_frame_tiles(ptr) {.data = (u8 *)ptr, .size = sizeof ptr} + +#define overworld_frame(ptr, width, height, frame) {.data = (u8 *)ptr + (width * height * frame * 64)/2, .size = (width * height * 64)/2} + +struct SpritePalette +{ + const u16 *data; // Raw uncompressed palette data + u16 tag; +}; + +struct CompressedSpritePalette +{ + const u32 *data; // LZ77 compressed palette data + u16 tag; +}; + +struct AnimFrameCmd +{ + // If the sprite has an array of images, this is the array index. + // If the sprite has a sheet, this is the tile offset. + u32 imageValue:16; + + u32 duration:6; + u32 hFlip:1; + u32 vFlip:1; +}; + +struct AnimLoopCmd +{ + u32 type:16; + u32 count:6; +}; + +struct AnimJumpCmd +{ + u32 type:16; + u32 target:6; +}; + +// The first halfword of this union specifies the type of command. +// If it -2, then it is a jump command. If it is -1, then it is the end of the script. +// Otherwise, it is the imageValue for a frame command. +union AnimCmd +{ + s16 type; + struct AnimFrameCmd frame; + struct AnimLoopCmd loop; + struct AnimJumpCmd jump; +}; + +#define ANIMCMD_FRAME(...) \ + {.frame = {__VA_ARGS__}} +#define ANIMCMD_LOOP(_count) \ + {.loop = {.type = -3, .count = _count}} +#define ANIMCMD_JUMP(_target) \ + {.jump = {.type = -2, .target = _target}} +#define ANIMCMD_END \ + {.type = -1} + +struct AffineAnimFrameCmd +{ + s16 xScale; + s16 yScale; + u8 rotation; + u8 duration; +}; + +struct AffineAnimLoopCmd +{ + s16 type; + s16 count; +}; + +struct AffineAnimJumpCmd +{ + s16 type; + u16 target; +}; + +struct AffineAnimEndCmdAlt +{ + s16 type; + u16 val; +}; + +union AffineAnimCmd +{ + s16 type; + struct AffineAnimFrameCmd frame; + struct AffineAnimLoopCmd loop; + struct AffineAnimJumpCmd jump; + struct AffineAnimEndCmdAlt end; // unused in code +}; + +#define AFFINEANIMCMDTYPE_LOOP 0x7FFD +#define AFFINEANIMCMDTYPE_JUMP 0x7FFE +#define AFFINEANIMCMDTYPE_END 0x7FFF + +#define AFFINEANIMCMD_FRAME(_xScale, _yScale, _rotation, _duration) \ + {.frame = {.xScale = _xScale, .yScale = _yScale, .rotation = _rotation, .duration = _duration}} +#define AFFINEANIMCMD_LOOP(_count) \ + {.loop = {.type = AFFINEANIMCMDTYPE_LOOP, .count = _count}} +#define AFFINEANIMCMD_JUMP(_target) \ + {.jump = {.type = AFFINEANIMCMDTYPE_JUMP, .target = _target}} +#define AFFINEANIMCMD_END \ + {.type = AFFINEANIMCMDTYPE_END} +#define AFFINEANIMCMD_END_ALT(_val) \ + {.end = {.type = AFFINEANIMCMDTYPE_END, .val = _val}} + +struct AffineAnimState +{ + u8 animNum; + u8 animCmdIndex; + u8 delayCounter; + u8 loopCounter; + s16 xScale; + s16 yScale; + u16 rotation; +}; + +enum +{ + SUBSPRITES_OFF, + SUBSPRITES_ON, + SUBSPRITES_IGNORE_PRIORITY, // on but priority is ignored +}; + +struct Subsprite +{ + s8 x; // was u16 in R/S + s8 y; // was u16 in R/S + u16 shape:2; + u16 size:2; + u16 tileOffset:10; + u16 priority:2; +}; + +struct SubspriteTable +{ + u8 subspriteCount; + const struct Subsprite *subsprites; +}; + +struct Sprite; + +typedef void (*SpriteCallback)(struct Sprite *); + +struct SpriteTemplate +{ + u16 tileTag; + u16 paletteTag; + const struct OamData *oam; + const union AnimCmd *const *anims; + const struct SpriteFrameImage *images; + const union AffineAnimCmd *const *affineAnims; + SpriteCallback callback; +}; + +// UB: template pointer is often used to point to temporary storage, +// then later dereferenced after being freed. Usually this won't +// be visible in-game, but this is (part of) what causes the item +// icon palette to flicker when changing items in the bag. +struct Sprite +{ + /*0x00*/ struct OamData oam; + /*0x08*/ const union AnimCmd *const *anims; + /*0x0C*/ const struct SpriteFrameImage *images; + /*0x10*/ const union AffineAnimCmd *const *affineAnims; + /*0x14*/ const struct SpriteTemplate *template; + /*0x18*/ const struct SubspriteTable *subspriteTables; + /*0x1C*/ SpriteCallback callback; + + /*0x20*/ struct Coords16 pos1; + /*0x24*/ struct Coords16 pos2; + /*0x28*/ s8 centerToCornerVecX; + /*0x29*/ s8 centerToCornerVecY; + + /*0x2A*/ u8 animNum; + /*0x2B*/ u8 animCmdIndex; + /*0x2C*/ u8 animDelayCounter:6; + bool8 animPaused:1; + bool8 affineAnimPaused:1; + /*0x2D*/ u8 animLoopCounter; + + // general purpose data fields + /*0x2E*/ s16 data[8]; + + /*0x3E*/ bool16 inUse:1; //1 + bool16 coordOffsetEnabled:1; //2 + bool16 invisible:1; //4 + bool16 flags_3:1; //8 + bool16 flags_4:1; //0x10 + bool16 flags_5:1; //0x20 + bool16 flags_6:1; //0x40 + bool16 flags_7:1; //0x80 + /*0x3F*/ bool16 hFlip:1; //1 + bool16 vFlip:1; //2 + bool16 animBeginning:1; //4 + bool16 affineAnimBeginning:1; //8 + bool16 animEnded:1; //0x10 + bool16 affineAnimEnded:1; //0x20 + bool16 usingSheet:1; //0x40 + bool16 flags_f:1; //0x80 + + /*0x40*/ u16 sheetTileStart; + + /*0x42*/ u8 subspriteTableNum:6; + u8 subspriteMode:2; + + /*0x43*/ u8 subpriority; +}; + +struct OamMatrix +{ + s16 a; + s16 b; + s16 c; + s16 d; +}; + +extern const struct OamData gDummyOamData; +extern const union AnimCmd *const gDummySpriteAnimTable[]; +extern const union AffineAnimCmd *const gDummySpriteAffineAnimTable[]; +extern const struct SpriteTemplate gDummySpriteTemplate; + +extern u8 gReservedSpritePaletteCount; +extern struct Sprite gSprites[]; +extern u8 gOamLimit; +extern u16 gReservedSpriteTileCount; +extern s16 gSpriteCoordOffsetX; +extern s16 gSpriteCoordOffsetY; +extern struct OamMatrix gOamMatrices[]; +extern bool8 gAffineAnimsDisabled; + +void ResetSpriteData(void); +void AnimateSprites(void); +void BuildOamBuffer(void); +u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)); +u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +void DestroySprite(struct Sprite *sprite); +void ResetOamRange(u8 a, u8 b); +void LoadOam(void); +void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d); +void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode); +void SpriteCallbackDummy(struct Sprite *sprite); +void ProcessSpriteCopyRequests(void); +void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size); +void FreeSpriteTiles(struct Sprite *sprite); +void FreeSpritePalette(struct Sprite *sprite); +void FreeSpriteOamMatrix(struct Sprite *sprite); +void DestroySpriteAndFreeResources(struct Sprite *sprite); +void sub_800142C(u32 a1, u32 a2, u16 *a3, u16 a4, u32 a5); +void AnimateSprite(struct Sprite *sprite); +void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3); +void StartSpriteAnim(struct Sprite *sprite, u8 animNum); +void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum); +void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex); +void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum); +void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); +void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum); +void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); +void SetSpriteSheetFrameTileNum(struct Sprite *sprite); +u8 AllocOamMatrix(void); +void FreeOamMatrix(u8 matrixNum); +void InitSpriteAffineAnim(struct Sprite *sprite); +void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation); +u16 LoadSpriteSheet(const struct SpriteSheet *sheet); +void LoadSpriteSheets(const struct SpriteSheet *sheets); +u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet); +void AllocTilesForSpriteSheets(struct SpriteSheet *sheets); +void LoadTilesForSpriteSheet(const struct SpriteSheet *sheet); +void LoadTilesForSpriteSheets(struct SpriteSheet *sheets); +void FreeSpriteTilesByTag(u16 tag); +void FreeSpriteTileRanges(void); +u16 GetSpriteTileStartByTag(u16 tag); +u16 GetSpriteTileTagByTileStart(u16 start); +void RequestSpriteSheetCopy(const struct SpriteSheet *sheet); +u16 LoadSpriteSheetDeferred(const struct SpriteSheet *sheet); +void FreeAllSpritePalettes(void); +u8 LoadSpritePalette(const struct SpritePalette *palette); +void LoadSpritePalettes(const struct SpritePalette *palettes); +u8 AllocSpritePalette(u16 tag); +u8 IndexOfSpritePaletteTag(u16 tag); +u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum); +void FreeSpritePaletteByTag(u16 tag); +void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables); +bool8 AddSpriteToOamBuffer(struct Sprite *object, u8 *oamIndex); +bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex); +void CopyToSprites(u8 *src); +void CopyFromSprites(u8 *dest); +u8 SpriteTileAllocBitmapOp(u16 bit, u8 op); +void ClearSpriteCopyRequests(void); +void ResetAffineAnimData(void); + +#endif //GUARD_SPRITE_H diff --git a/include/string_util.h b/include/string_util.h new file mode 100644 index 000000000..229193d52 --- /dev/null +++ b/include/string_util.h @@ -0,0 +1,46 @@ +#ifndef GUARD_STRING_UTIL_H +#define GUARD_STRING_UTIL_H + +extern u8 gStringVar1[0x100]; +extern u8 gStringVar2[0x100]; +extern u8 gStringVar3[0x100]; +extern u8 gStringVar4[0x3E8]; + +enum StringConvertMode +{ + STR_CONV_MODE_LEFT_ALIGN, + STR_CONV_MODE_RIGHT_ALIGN, + STR_CONV_MODE_LEADING_ZEROS +}; + +u8 *StringCopy10(u8 *dest, const u8 *src); +u8 *StringGetEnd10(u8 *str); +u8 *StringCopy7(u8 *dest, const u8 *src); +u8 *StringCopy(u8 *dest, const u8 *src); +u8 *StringAppend(u8 *dest, const u8 *src); +u8 *StringCopyN(u8 *dest, const u8 *src, u8 n); +u8 *StringAppendN(u8 *dest, const u8 *src, u8 n); +u16 StringLength(const u8 *str); +s32 StringCompare(const u8 *str1, const u8 *str2); +s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n); +bool8 IsStringLengthAtLeast(const u8 *str, s32 n); +u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); +u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n); +u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); +u8 *StringExpandPlaceholders(u8 *dest, const u8 *src); +u8 *StringBraille(u8 *dest, const u8 *src); +const u8 *GetExpandedPlaceholder(u32 id); +u8 *StringFill(u8 *dest, u8 c, u16 n); +u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n); +u8 *StringFillWithTerminator(u8 *dest, u16 n); +u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n); +u32 StringLength_Multibyte(const u8 *str); +u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color); +bool32 IsStringJapanese(u8 *str); +bool32 sub_800924C(u8 *str, s32 n); +u8 GetExtCtrlCodeLength(u8 code); +s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2); +void ConvertInternationalString(u8 *s, u8 language); +void StripExtCtrlCodes(u8 *str); + +#endif // GUARD_STRING_UTIL_H diff --git a/include/text.h b/include/text.h new file mode 100644 index 000000000..3edd0fc62 --- /dev/null +++ b/include/text.h @@ -0,0 +1,436 @@ +#ifndef GUARD_TEXT_H +#define GUARD_TEXT_H + +#define CHAR_SPACE 0x00 +#define CHAR_A_GRAVE 0x01 +#define CHAR_A_ACUTE 0x02 +#define CHAR_A_CIRCUMFLEX 0x03 +#define CHAR_C_CEDILLA 0x04 +#define CHAR_E_GRAVE 0x05 +#define CHAR_E_ACUTE 0x06 +#define CHAR_E_CIRCUMFLEX 0x07 +#define CHAR_E_DIAERESIS 0x08 +#define CHAR_I_GRAVE 0x09 +//#define CHAR_I_ACUTE 0x0A // Is 0x5A instead +#define CHAR_I_CIRCUMFLEX 0x0B +#define CHAR_I_DIAERESIS 0x0C +#define CHAR_O_GRAVE 0x0D +#define CHAR_O_ACUTE 0x0E +#define CHAR_O_CIRCUMFLEX 0x0F +#define CHAR_OE 0x10 +#define CHAR_U_GRAVE 0x11 +#define CHAR_U_ACUTE 0x12 +#define CHAR_U_CIRCUMFLEX 0x13 +#define CHAR_N_TILDE 0x14 +#define CHAR_ESZETT 0x15 +#define CHAR_a_GRAVE 0x16 +#define CHAR_a_ACUTE 0x17 +//#define CHAR_a_CIRCUMFLEX 0x18 // Is 0x68 instead +#define CHAR_c_CEDILLA 0x19 +#define CHAR_e_GRAVE 0x1A +#define CHAR_e_ACUTE 0x1B +#define CHAR_e_CIRCUMFLEX 0x1C +#define CHAR_e_DIAERESIS 0x1D +#define CHAR_i_GRAVE 0x1E +//#define CHAR_i_ACUTE 0x1F // Is 0x6F instead +#define CHAR_i_CIRCUMFLEX 0x20 +#define CHAR_i_DIAERESIS 0x21 +#define CHAR_o_GRAVE 0x22 +#define CHAR_o_ACUTE 0x23 +#define CHAR_o_CIRCUMFLEX 0x24 +#define CHAR_oe 0x25 +#define CHAR_u_GRAVE 0x26 +#define CHAR_u_ACUTE 0x27 +#define CHAR_u_CIRCUMFLEX 0x28 +#define CHAR_n_TILDE 0x29 +#define CHAR_MASCULINE_ORDINAL 0x2A +#define CHAR_FEMININE_ORDINAL 0x2B +#define CHAR_SUPER_ER 0x2C +#define CHAR_AMPERSAND 0x2D +#define CHAR_PLUS 0x2E +// +#define CHAR_LV 0x34 +#define CHAR_EQUALS 0x35 +#define CHAR_SEMICOLON 0x36 +// +#define CHAR_INV_QUESTION_MARK 0x51 +#define CHAR_INV_EXCL_MARK 0x52 +#define CHAR_PK 0x53 +#define CHAR_MN 0x54 +#define CHAR_PO 0x55 +#define CHAR_KE 0x56 +#define CHAR_BLOCK_1 0x57 // Each of these 3 +#define CHAR_BLOCK_2 0x58 // chars contains 1/3 +#define CHAR_BLOCK_3 0x59 // of the word BLOCK +#define CHAR_I_ACUTE 0x5A +#define CHAR_PERCENT 0x5B +#define CHAR_LEFT_PAREN 0x5C +#define CHAR_RIGHT_PAREN 0x5D +// +#define CHAR_a_CIRCUMFLEX 0x68 +// +#define CHAR_i_ACUTE 0x6F +// +#define CHAR_GENDERLESS 0x77 // Empty space for lack of gender icon +// +#define CHAR_UP_ARROW 0x79 +#define CHAR_DOWN_ARROW 0x7A +#define CHAR_LEFT_ARROW 0x7B +#define CHAR_RIGHT_ARROW 0x7C +// +#define CHAR_SUPER_E 0x84 +#define CHAR_LESS_THAN 0x85 +#define CHAR_GREATER_THAN 0x86 +// +#define CHAR_SUPER_RE 0xA0 +#define CHAR_0 0xA1 +#define CHAR_1 0xA2 +#define CHAR_2 0xA3 +#define CHAR_3 0xA4 +#define CHAR_4 0xA5 +#define CHAR_5 0xA6 +#define CHAR_6 0xA7 +#define CHAR_7 0xA8 +#define CHAR_8 0xA9 +#define CHAR_9 0xAA +#define CHAR_EXCL_MARK 0xAB +#define CHAR_QUESTION_MARK 0xAC +#define CHAR_PERIOD 0xAD +#define CHAR_HYPHEN 0xAE +#define CHAR_BULLET 0xAF +#define CHAR_ELLIPSIS 0xB0 +#define CHAR_DBL_QUOT_LEFT 0xB1 +#define CHAR_DBL_QUOT_RIGHT 0xB2 +#define CHAR_SGL_QUOT_LEFT 0xB3 +#define CHAR_SGL_QUOT_RIGHT 0xB4 +#define CHAR_MALE 0xB5 +#define CHAR_FEMALE 0xB6 +#define CHAR_CURRENCY 0xB7 +#define CHAR_COMMA 0xB8 +#define CHAR_MULT_SIGN 0xB9 +#define CHAR_SLASH 0xBA +#define CHAR_A 0xBB +#define CHAR_B 0xBC +#define CHAR_C 0xBD +#define CHAR_D 0xBE +#define CHAR_E 0xBF +#define CHAR_F 0xC0 +#define CHAR_G 0xC1 +#define CHAR_H 0xC2 +#define CHAR_I 0xC3 +#define CHAR_J 0xC4 +#define CHAR_K 0xC5 +#define CHAR_L 0xC6 +#define CHAR_M 0xC7 +#define CHAR_N 0xC8 +#define CHAR_O 0xC9 +#define CHAR_P 0xCA +#define CHAR_Q 0xCB +#define CHAR_R 0xCC +#define CHAR_S 0xCD +#define CHAR_T 0xCE +#define CHAR_U 0xCF +#define CHAR_V 0xD0 +#define CHAR_W 0xD1 +#define CHAR_X 0xD2 +#define CHAR_Y 0xD3 +#define CHAR_Z 0xD4 +#define CHAR_a 0xD5 +#define CHAR_b 0xD6 +#define CHAR_c 0xD7 +#define CHAR_d 0xD8 +#define CHAR_e 0xD9 +#define CHAR_f 0xDA +#define CHAR_g 0xDB +#define CHAR_h 0xDC +#define CHAR_i 0xDD +#define CHAR_j 0xDE +#define CHAR_k 0xDF +#define CHAR_l 0xE0 +#define CHAR_m 0xE1 +#define CHAR_n 0xE2 +#define CHAR_o 0xE3 +#define CHAR_p 0xE4 +#define CHAR_q 0xE5 +#define CHAR_r 0xE6 +#define CHAR_s 0xE7 +#define CHAR_t 0xE8 +#define CHAR_u 0xE9 +#define CHAR_v 0xEA +#define CHAR_w 0xEB +#define CHAR_x 0xEC +#define CHAR_y 0xED +#define CHAR_z 0xEE +#define CHAR_BLACK_TRIANGLE 0xEF +#define CHAR_COLON 0xF0 +#define CHAR_A_DIAERESIS 0xF1 +#define CHAR_O_DIAERESIS 0xF2 +#define CHAR_U_DIAERESIS 0xF3 +#define CHAR_a_DIAERESIS 0xF4 +#define CHAR_o_DIAERESIS 0xF5 +#define CHAR_u_DIAERESIS 0xF6 +#define CHAR_DYNAMIC 0xF7 +#define CHAR_KEYPAD_ICON 0xF8 +#define CHAR_EXTRA_SYMBOL 0xF9 +#define CHAR_PROMPT_SCROLL 0xFA // waits for button press and scrolls dialog +#define CHAR_PROMPT_CLEAR 0xFB // waits for button press and clears dialog +#define EXT_CTRL_CODE_BEGIN 0xFC // extended control code +#define PLACEHOLDER_BEGIN 0xFD // string placeholder +#define CHAR_NEWLINE 0xFE +#define EOS 0xFF // end of string + +// CHAR_KEYPAD_ICON chars +#define CHAR_A_BUTTON 0x00 +#define CHAR_B_BUTTON 0x01 +#define CHAR_L_BUTTON 0x02 +#define CHAR_R_BUTTON 0x03 +#define CHAR_START_BUTTON 0x04 +#define CHAR_SELECT_BUTTON 0x05 +#define CHAR_DPAD_UP 0x06 +#define CHAR_DPAD_DOWN 0x07 +#define CHAR_DPAD_LEFT 0x08 +#define CHAR_DPAD_RIGHT 0x09 +#define CHAR_DPAD_UPDOWN 0x0A +#define CHAR_DPAD_LEFTRIGHT 0x0B +#define CHAR_DPAD_NONE 0x0C + +// CHAR_EXTRA_SYMBOL chars +#define CHAR_UP_ARROW_2 0x00 +#define CHAR_DOWN_ARROW_2 0x01 +#define CHAR_LEFT_ARROW_2 0x02 +#define CHAR_RIGHT_ARROW_2 0x03 +#define CHAR_PLUS_2 0x04 +#define CHAR_LV_2 0x05 +#define CHAR_PP 0x06 +#define CHAR_ID 0x07 +#define CHAR_NO 0x08 +#define CHAR_UNDERSCORE 0x09 + +#define EXT_CTRL_CODE_COLOR 0x01 +#define EXT_CTRL_CODE_HIGHLIGHT 0x02 +#define EXT_CTRL_CODE_SHADOW 0x03 +#define EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW 0x04 +#define EXT_CTRL_CODE_PALETTE 0x05 +#define EXT_CTRL_CODE_SIZE 0x06 +#define EXT_CTRL_CODE_RESET_SIZE 0x07 +#define EXT_CTRL_CODE_PAUSE 0x08 +#define EXT_CTRL_CODE_PAUSE_UNTIL_PRESS 0x09 +#define EXT_CTRL_CODE_WAIT_SE 0x0A +#define EXT_CTRL_CODE_PLAY_BGM 0x0B +#define EXT_CTRL_CODE_ESCAPE 0x0C +#define EXT_CTRL_CODE_SHIFT_TEXT 0x0D +#define EXT_CTRL_CODE_SHIFT_DOWN 0x0E +#define EXT_CTRL_CODE_FILL_WINDOW 0x0F +#define EXT_CTRL_CODE_PLAY_SE 0x10 +#define EXT_CTRL_CODE_CLEAR 0x11 +#define EXT_CTRL_CODE_SKIP 0x12 +#define EXT_CTRL_CODE_CLEAR_TO 0x13 +#define EXT_CTRL_CODE_MIN_LETTER_SPACING 0x14 +#define EXT_CTRL_CODE_JPN 0x15 +#define EXT_CTRL_CODE_ENG 0x16 +#define EXT_CTRL_CODE_PAUSE_MUSIC 0x17 +#define EXT_CTRL_CODE_RESUME_MUSIC 0x18 + +#define TEXT_COLOR_TRANSPARENT 0x0 +#define TEXT_COLOR_WHITE 0x1 +#define TEXT_COLOR_DARK_GRAY 0x2 +#define TEXT_COLOR_LIGHT_GRAY 0x3 +#define TEXT_COLOR_RED 0x4 +#define TEXT_COLOR_LIGHT_RED 0x5 +#define TEXT_COLOR_GREEN 0x6 +#define TEXT_COLOR_LIGHT_GREEN 0x7 +#define TEXT_COLOR_BLUE 0x8 +#define TEXT_COLOR_LIGHT_BLUE 0x9 +#define TEXT_DYNAMIC_COLOR_1 0xA // Usually white +#define TEXT_DYNAMIC_COLOR_2 0xB // Usually white w/ tinge of green +#define TEXT_DYNAMIC_COLOR_3 0xC // Usually white +#define TEXT_DYNAMIC_COLOR_4 0xD // Usually aquamarine +#define TEXT_DYNAMIC_COLOR_5 0xE // Usually blue-green +#define TEXT_DYNAMIC_COLOR_6 0xF // Usually cerulean + +#define PLACEHOLDER_ID_UNKNOWN 0x0 +#define PLACEHOLDER_ID_PLAYER 0x1 +#define PLACEHOLDER_ID_STRING_VAR_1 0x2 +#define PLACEHOLDER_ID_STRING_VAR_2 0x3 +#define PLACEHOLDER_ID_STRING_VAR_3 0x4 +#define PLACEHOLDER_ID_KUN 0x5 +#define PLACEHOLDER_ID_RIVAL 0x6 +#define PLACEHOLDER_ID_VERSION 0x7 +#define PLACEHOLDER_ID_AQUA 0x8 +#define PLACEHOLDER_ID_MAGMA 0x9 +#define PLACEHOLDER_ID_ARCHIE 0xA +#define PLACEHOLDER_ID_MAXIE 0xB +#define PLACEHOLDER_ID_KYOGRE 0xC +#define PLACEHOLDER_ID_GROUDON 0xD + +// battle placeholders are located in battle_message.h + +#define NUM_TEXT_PRINTERS 32 + +#define TEXT_SPEED_FF 0xFF + +enum +{ + FONTATTR_MAX_LETTER_WIDTH, + FONTATTR_MAX_LETTER_HEIGHT, + FONTATTR_LETTER_SPACING, + FONTATTR_LINE_SPACING, + FONTATTR_UNKNOWN, // dunno what this is yet + FONTATTR_COLOR_FOREGROUND, + FONTATTR_COLOR_BACKGROUND, + FONTATTR_COLOR_SHADOW +}; + +struct TextPrinterSubStruct +{ + u8 glyphId:4; // 0x14 + bool8 hasPrintBeenSpedUp:1; + u8 unk:3; + u8 downArrowDelay:5; + u8 downArrowYPosIdx:2; + bool8 hasGlyphIdBeenSet:1; + u8 autoScrollDelay; +}; + +struct TextPrinterTemplate +{ + const u8* currentChar; + u8 windowId; + u8 fontId; + u8 x; + u8 y; + u8 currentX; // 0x8 + u8 currentY; + u8 letterSpacing; + u8 lineSpacing; + u8 unk:4; // 0xC + u8 fgColor:4; + u8 bgColor:4; + u8 shadowColor:4; +}; + +struct TextPrinter +{ + struct TextPrinterTemplate printerTemplate; + + void (*callback)(struct TextPrinterTemplate *, u16); // 0x10 + + u8 subStructFields[7]; // always cast to struct TextPrinterSubStruct... so why bother + u8 active; + u8 state; // 0x1C + u8 textSpeed; + u8 delayCounter; + u8 scrollDistance; + u8 minLetterSpacing; // 0x20 + u8 japanese; +}; + +struct FontInfo +{ + u16 (*fontFunction)(struct TextPrinter *x); + u8 maxLetterWidth; + u8 maxLetterHeight; + u8 letterSpacing; + u8 lineSpacing; + u8 unk:4; + u8 fgColor:4; + u8 bgColor:4; + u8 shadowColor:4; +}; + +extern const struct FontInfo *gFonts; + +struct GlyphWidthFunc +{ + u32 fontId; + u32 (*func)(u16 glyphId, bool32 isJapanese); +}; + +struct KeypadIcon +{ + u16 tileOffset; + u8 width; + u8 height; +}; + +typedef struct { + bool8 canABSpeedUpPrint:1; + bool8 useAlternateDownArrow:1; + bool8 autoScroll:1; + bool8 forceMidTextSpeed:1; +} TextFlags; + +struct TextGlyph +{ + u32 gfxBufferTop[16]; + u32 gfxBufferBottom[16]; + u8 width; + u8 height; +}; + +extern TextFlags gTextFlags; + +extern u8 gDisableTextPrinters; +extern struct TextGlyph gCurGlyph; + +void SetFontsPointer(const struct FontInfo *fonts); +void DeactivateAllTextPrinters(void); +u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); +bool16 AddTextPrinter(struct TextPrinterTemplate *template, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); +void RunTextPrinters(void); +bool16 IsTextPrinterActive(u8 id); +u32 RenderFont(struct TextPrinter *textPrinter); +void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor); +void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); +void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); +void DecompressGlyphTile(const void *src_, void *dest_); +u8 GetLastTextColor(u8 colorType); +void CopyGlyphToWindow(struct TextPrinter *x); +void ClearTextSpan(struct TextPrinter *textPrinter, u32 width); +u8 GetMenuCursorDimensionByFont(u8, u8); + +u16 Font0Func(struct TextPrinter *textPrinter); +u16 Font1Func(struct TextPrinter *textPrinter); +u16 Font2Func(struct TextPrinter *textPrinter); +u16 Font3Func(struct TextPrinter *textPrinter); +u16 Font4Func(struct TextPrinter *textPrinter); +u16 Font5Func(struct TextPrinter *textPrinter); +u16 Font7Func(struct TextPrinter *textPrinter); +u16 Font8Func(struct TextPrinter *textPrinter); + +void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter); +void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter); +void TextPrinterClearDownArrow(struct TextPrinter *textPrinter); +bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter); +bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter); +bool16 TextPrinterWait(struct TextPrinter *textPrinter); +void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex); +u16 RenderText(struct TextPrinter *textPrinter); +u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing); +u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32); +s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing); +u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str); +u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y); +u8 GetKeypadIconTileOffset(u8 keypadIconId); +u8 GetKeypadIconWidth(u8 keypadIconId); +u8 GetKeypadIconHeight(u8 keypadIconId); +void SetDefaultFontsPointer(void); +u8 GetFontAttribute(u8 fontId, u8 attributeId); +u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension); +void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont9(u16 glyphId); + +// unk_text_util_2.c +u16 Font6Func(struct TextPrinter *textPrinter); +u32 GetGlyphWidthFont6(u16 glyphId, bool32 isJapanese); + +#endif // GUARD_TEXT_H diff --git a/include/window.h b/include/window.h new file mode 100644 index 000000000..3eac75a28 --- /dev/null +++ b/include/window.h @@ -0,0 +1,80 @@ +#ifndef GUARD_WINDOW_H +#define GUARD_WINDOW_H + +#define PIXEL_FILL(num) ((num) | ((num) << 4)) + +enum +{ + WINDOW_BG, + WINDOW_TILEMAP_LEFT, + WINDOW_TILEMAP_TOP, + WINDOW_WIDTH, + WINDOW_HEIGHT, + WINDOW_PALETTE_NUM, + WINDOW_BASE_BLOCK, + WINDOW_TILE_DATA +}; + +struct WindowTemplate +{ + u8 bg; + u8 tilemapLeft; + u8 tilemapTop; + u8 width; + u8 height; + u8 paletteNum; + u16 baseBlock; +}; + +#define DUMMY_WIN_TEMPLATE \ +{ \ + 0xFF, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ +} + +#define WINDOW_NONE 0xFF + +struct Window +{ + struct WindowTemplate window; + u8 *tileData; +}; + +bool16 InitWindows(const struct WindowTemplate *templates); +u16 AddWindow(const struct WindowTemplate *template); +int AddWindowWithoutTileMap(const struct WindowTemplate *template); +void RemoveWindow(u8 windowId); +void FreeAllWindowBuffers(void); +void CopyWindowToVram(u8 windowId, u8 mode); +void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h); +void PutWindowTilemap(u8 windowId); +void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette); +void ClearWindowTilemap(u8 windowId); +void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height); +void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height); +void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight); +void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); +void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset); +void FillWindowPixelBuffer(u8 windowId, u8 fillValue); +void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue); +void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)); +bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value); +u32 GetWindowAttribute(u8 windowId, u8 attributeId); +u16 AddWindow8Bit(const struct WindowTemplate *template); +void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue); +void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); +void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum); +void CopyWindowToVram8Bit(u8 windowId, u8 mode); + +extern struct Window gWindows[]; +extern void* gWindowBgTilemapBuffers[]; +extern u32 gUnusedWindowVar1; +extern u32 gUnusedWindowVar2; +extern u32 gUnusedWindowVar3; + +#endif // GUARD_WINDOW_H diff --git a/ld_script.txt b/ld_script.txt index 8c8f19015..5770b2cea 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -49,15 +49,15 @@ SECTIONS { { src/crt0.o(.text); src/main.o(.text); - gflib/malloc.o(.text); - gflib/dma3_manager.o(.text); - gflib/gpu_regs.o(.text); - gflib/bg.o(.text); - gflib/blit.o(.text); - gflib/window.o(.text); - gflib/text.o(.text); - gflib/sprite.o(.text); - gflib/string_util.o(.text); + src/malloc.o(.text); + src/dma3_manager.o(.text); + src/gpu_regs.o(.text); + src/bg.o(.text); + src/blit.o(.text); + src/window.o(.text); + src/text.o(.text); + src/sprite.o(.text); + src/string_util.o(.text); src/link.o(.text); src/AgbRfu_LinkManager.o(.text); src/link_rfu_3.o(.text); @@ -436,12 +436,12 @@ SECTIONS { ALIGN(4) { src/main.o(.rodata); - gflib/bg.o(.rodata); - gflib/window.o(.rodata); - gflib/text.o(.rodata); - gflib/sprite.o(.rodata); - gflib/io_reg.o(.rodata); - gflib/string_util.o(.rodata); + src/bg.o(.rodata); + src/window.o(.rodata); + src/text.o(.rodata); + src/sprite.o(.rodata); + src/io_reg.o(.rodata); + src/string_util.o(.rodata); src/link.o(.rodata); src/link.o(.rodata.str1.4); src/AgbRfu_LinkManager.o(.rodata); diff --git a/ld_script_modern.txt b/ld_script_modern.txt index 59d032bb2..72fb4dbc5 100644 --- a/ld_script_modern.txt +++ b/ld_script_modern.txt @@ -14,7 +14,6 @@ SECTIONS { . = 0x1C000; src/*.o(ewram_data); - gflib/*.o(ewram_data); . = 0x40000; } @@ -26,7 +25,6 @@ SECTIONS { { /* .bss starts at 0x3000000 */ src/*.o(.bss); - gflib/*.o(.bss); *libc.a:*.o(.bss*); *libnosys.a:*.o(.bss*); @@ -35,7 +33,6 @@ SECTIONS { /* COMMON starts at 0x30022A8 */ src/*.o(COMMON); - gflib/*.o(COMMON); *libc.a:*.o(COMMON); *libnosys.a:*.o(COMMON); end = .; @@ -49,7 +46,6 @@ SECTIONS { { src/crt0.o(.text*); src/*.o(.text*); - gflib/*.o(.text*); asm/*.o(.text*); } =0 @@ -84,7 +80,6 @@ SECTIONS { ALIGN(4) { src/*.o(.rodata*); - gflib/*.o(.rodata*); data/*.o(.rodata*); } =0 diff --git a/src/bg.c b/src/bg.c new file mode 100644 index 000000000..ec7c2113b --- /dev/null +++ b/src/bg.c @@ -0,0 +1,1248 @@ +#include +#include "global.h" +#include "bg.h" +#include "dma3.h" +#include "gpu_regs.h" + +#define DISPCNT_ALL_BG_AND_MODE_BITS (DISPCNT_BG_ALL_ON | 0x7) + +struct BgControl +{ + struct BgConfig { + u8 visible:1; + u8 unknown_1:1; + u8 screenSize:2; + u8 priority:2; + u8 mosaic:1; + u8 wraparound:1; + + u8 charBaseIndex:2; + u8 mapBaseIndex:5; + u8 paletteMode:1; + + u8 unknown_2; // Assigned to but never read + u8 unknown_3; // Assigned to but never read + } configs[NUM_BACKGROUNDS]; + + u16 bgVisibilityAndMode; +}; + +struct BgConfig2 +{ + u32 baseTile:10; + u32 basePalette:4; + u32 unk_3:18; + + void* tilemap; + s32 bg_x; + s32 bg_y; +}; + +static struct BgControl sGpuBgConfigs; +static struct BgConfig2 sGpuBgConfigs2[NUM_BACKGROUNDS]; +static u32 sDmaBusyBitfield[NUM_BACKGROUNDS]; + +u32 gUnneededFireRedVariable; + +static const struct BgConfig sZeroedBgControlStruct = { 0 }; + +void ResetBgs(void) +{ + ResetBgControlStructs(); + sGpuBgConfigs.bgVisibilityAndMode = 0; + SetTextModeAndHideBgs(); +} + +static void SetBgModeInternal(u8 bgMode) +{ + sGpuBgConfigs.bgVisibilityAndMode &= ~0x7; + sGpuBgConfigs.bgVisibilityAndMode |= bgMode; +} + +u8 GetBgMode(void) +{ + return sGpuBgConfigs.bgVisibilityAndMode & 0x7; +} + +void ResetBgControlStructs(void) +{ + int i; + + for (i = 0; i < NUM_BACKGROUNDS; i++) + { + sGpuBgConfigs.configs[i] = sZeroedBgControlStruct; + } +} + +void Unused_ResetBgControlStruct(u8 bg) +{ + if (!IsInvalidBg(bg)) + { + sGpuBgConfigs.configs[bg] = sZeroedBgControlStruct; + } +} + +enum +{ + BG_CTRL_ATTR_VISIBLE = 1, + BG_CTRL_ATTR_CHARBASEINDEX = 2, + BG_CTRL_ATTR_MAPBASEINDEX = 3, + BG_CTRL_ATTR_SCREENSIZE = 4, + BG_CTRL_ATTR_PALETTEMODE = 5, + BG_CTRL_ATTR_PRIORITY = 6, + BG_CTRL_ATTR_MOSAIC = 7, + BG_CTRL_ATTR_WRAPAROUND = 8, +}; + +static void SetBgControlAttributes(u8 bg, u8 charBaseIndex, u8 mapBaseIndex, u8 screenSize, u8 paletteMode, u8 priority, u8 mosaic, u8 wraparound) +{ + if (!IsInvalidBg(bg)) + { + if (charBaseIndex != 0xFF) + { + sGpuBgConfigs.configs[bg].charBaseIndex = charBaseIndex; + } + + if (mapBaseIndex != 0xFF) + { + sGpuBgConfigs.configs[bg].mapBaseIndex = mapBaseIndex; + } + + if (screenSize != 0xFF) + { + sGpuBgConfigs.configs[bg].screenSize = screenSize; + } + + if (paletteMode != 0xFF) + { + sGpuBgConfigs.configs[bg].paletteMode = paletteMode; + } + + if (priority != 0xFF) + { + sGpuBgConfigs.configs[bg].priority = priority; + } + + if (mosaic != 0xFF) + { + sGpuBgConfigs.configs[bg].mosaic = mosaic; + } + + if (wraparound != 0xFF) + { + sGpuBgConfigs.configs[bg].wraparound = wraparound; + } + + sGpuBgConfigs.configs[bg].unknown_2 = 0; + sGpuBgConfigs.configs[bg].unknown_3 = 0; + + sGpuBgConfigs.configs[bg].visible = 1; + } +} + +static u16 GetBgControlAttribute(u8 bg, u8 attributeId) +{ + if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) + { + switch (attributeId) + { + case BG_CTRL_ATTR_VISIBLE: + return sGpuBgConfigs.configs[bg].visible; + case BG_CTRL_ATTR_CHARBASEINDEX: + return sGpuBgConfigs.configs[bg].charBaseIndex; + case BG_CTRL_ATTR_MAPBASEINDEX: + return sGpuBgConfigs.configs[bg].mapBaseIndex; + case BG_CTRL_ATTR_SCREENSIZE: + return sGpuBgConfigs.configs[bg].screenSize; + case BG_CTRL_ATTR_PALETTEMODE: + return sGpuBgConfigs.configs[bg].paletteMode; + case BG_CTRL_ATTR_PRIORITY: + return sGpuBgConfigs.configs[bg].priority; + case BG_CTRL_ATTR_MOSAIC: + return sGpuBgConfigs.configs[bg].mosaic; + case BG_CTRL_ATTR_WRAPAROUND: + return sGpuBgConfigs.configs[bg].wraparound; + } + } + + return 0xFF; +} + +u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode) +{ + u16 offset; + s8 cursor; + + if (IsInvalidBg(bg) || !sGpuBgConfigs.configs[bg].visible) + return -1; + + switch (mode) + { + case 0x1: + offset = sGpuBgConfigs.configs[bg].charBaseIndex * BG_CHAR_SIZE; + offset = destOffset + offset; + cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); + if (cursor == -1) + return -1; + break; + case 0x2: + offset = sGpuBgConfigs.configs[bg].mapBaseIndex * BG_SCREEN_SIZE; + offset = destOffset + offset; + cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); + if (cursor == -1) + return -1; + break; + default: + cursor = -1; + break; + } + + return cursor; +} + +static void ShowBgInternal(u8 bg) +{ + u16 value; + if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) + { + value = sGpuBgConfigs.configs[bg].priority | + (sGpuBgConfigs.configs[bg].charBaseIndex << 2) | + (sGpuBgConfigs.configs[bg].mosaic << 6) | + (sGpuBgConfigs.configs[bg].paletteMode << 7) | + (sGpuBgConfigs.configs[bg].mapBaseIndex << 8) | + (sGpuBgConfigs.configs[bg].wraparound << 13) | + (sGpuBgConfigs.configs[bg].screenSize << 14); + + SetGpuReg((bg << 1) + REG_OFFSET_BG0CNT, value); + + sGpuBgConfigs.bgVisibilityAndMode |= 1 << (bg + 8); + sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; + } +} + +static void HideBgInternal(u8 bg) +{ + if (!IsInvalidBg(bg)) + { + sGpuBgConfigs.bgVisibilityAndMode &= ~(1 << (bg + 8)); + sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; + } +} + +static void SyncBgVisibilityAndMode(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, (GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS) | sGpuBgConfigs.bgVisibilityAndMode); +} + +void SetTextModeAndHideBgs(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS); +} + +static void SetBgAffineInternal(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) +{ + struct BgAffineSrcData src; + struct BgAffineDstData dest; + + switch (sGpuBgConfigs.bgVisibilityAndMode & 0x7) + { + default: + case 0: + return; + case 1: + if (bg != 2) + return; + break; + case 2: + if (bg != 2 && bg != 3) + return; + break; + } + + src.texX = srcCenterX; + src.texY = srcCenterY; + src.scrX = dispCenterX; + src.scrY = dispCenterY; + src.sx = scaleX; + src.sy = scaleY; + src.alpha = rotationAngle; + + BgAffineSet(&src, &dest, 1); + + SetGpuReg(REG_OFFSET_BG2PA, dest.pa); + SetGpuReg(REG_OFFSET_BG2PB, dest.pb); + SetGpuReg(REG_OFFSET_BG2PC, dest.pc); + SetGpuReg(REG_OFFSET_BG2PD, dest.pd); + SetGpuReg(REG_OFFSET_BG2PA, dest.pa); + SetGpuReg(REG_OFFSET_BG2X_L, (s16)(dest.dx)); + SetGpuReg(REG_OFFSET_BG2X_H, (s16)(dest.dx >> 16)); + SetGpuReg(REG_OFFSET_BG2Y_L, (s16)(dest.dy)); + SetGpuReg(REG_OFFSET_BG2Y_H, (s16)(dest.dy >> 16)); +} + +bool8 IsInvalidBg(u8 bg) +{ + if (bg >= NUM_BACKGROUNDS) + return TRUE; + else + return FALSE; +} + +int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4) +{ + return 0; +} + +void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable) +{ + int i; + ResetBgs(); + + for (i = 0; i < NUM_BACKGROUNDS; i++) + { + sDmaBusyBitfield[i] = 0; + } + + gUnneededFireRedVariable = leftoverFireRedLeafGreenVariable; +} + +void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates) +{ + int i; + u8 bg; + + SetBgModeInternal(bgMode); + ResetBgControlStructs(); + + for (i = 0; i < numTemplates; i++) + { + bg = templates[i].bg; + if (bg < NUM_BACKGROUNDS) + { + SetBgControlAttributes(bg, + templates[i].charBaseIndex, + templates[i].mapBaseIndex, + templates[i].screenSize, + templates[i].paletteMode, + templates[i].priority, + 0, + 0); + + sGpuBgConfigs2[bg].baseTile = templates[i].baseTile; + sGpuBgConfigs2[bg].basePalette = 0; + sGpuBgConfigs2[bg].unk_3 = 0; + + sGpuBgConfigs2[bg].tilemap = NULL; + sGpuBgConfigs2[bg].bg_x = 0; + sGpuBgConfigs2[bg].bg_y = 0; + } + } +} + +void InitBgFromTemplate(const struct BgTemplate *template) +{ + u8 bg = template->bg; + + if (bg < NUM_BACKGROUNDS) + { + SetBgControlAttributes(bg, + template->charBaseIndex, + template->mapBaseIndex, + template->screenSize, + template->paletteMode, + template->priority, + 0, + 0); + + sGpuBgConfigs2[bg].baseTile = template->baseTile; + sGpuBgConfigs2[bg].basePalette = 0; + sGpuBgConfigs2[bg].unk_3 = 0; + + sGpuBgConfigs2[bg].tilemap = NULL; + sGpuBgConfigs2[bg].bg_x = 0; + sGpuBgConfigs2[bg].bg_y = 0; + } +} + +void SetBgMode(u8 bgMode) +{ + SetBgModeInternal(bgMode); +} + +u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset) +{ + u16 tileOffset; + u8 cursor; + + if (GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE) == 0) + { + tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x20; + } + else + { + tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x40; + } + + cursor = LoadBgVram(bg, src, size, tileOffset, DISPCNT_MODE_1); + + if (cursor == 0xFF) + { + return -1; + } + + sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); + + if (gUnneededFireRedVariable == 1) + { + DummiedOutFireRedLeafGreenTileAllocFunc(bg, tileOffset / 0x20, size / 0x20, 1); + } + + return cursor; +} + +u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset) +{ + u8 cursor = LoadBgVram(bg, src, size, destOffset * 2, DISPCNT_MODE_2); + + if (cursor == 0xFF) + { + return -1; + } + + sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); + + return cursor; +} + +u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset) +{ + s8 cursor; + + if (!IsInvalidBg32(bg)) + { + u16 paletteOffset = (sGpuBgConfigs2[bg].basePalette * 0x20) + (destOffset * 2); + cursor = RequestDma3Copy(src, (void*)(paletteOffset + BG_PLTT), size, 0); + + if (cursor == -1) + { + return -1; + } + } + else + { + return -1; + } + + sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); + + return (u8)cursor; +} + +bool8 IsDma3ManagerBusyWithBgCopy(void) +{ + int i; + + for (i = 0; i < 0x80; i++) + { + u8 div = i / 0x20; + u8 mod = i % 0x20; + + if ((sDmaBusyBitfield[div] & (1 << mod))) + { + s8 reqSpace = CheckForSpaceForDma3Request(i); + if (reqSpace == -1) + { + return TRUE; + } + + sDmaBusyBitfield[div] &= ~(1 << mod); + } + } + + return FALSE; +} + +void ShowBg(u8 bg) +{ + ShowBgInternal(bg); + SyncBgVisibilityAndMode(); +} + +void HideBg(u8 bg) +{ + HideBgInternal(bg); + SyncBgVisibilityAndMode(); +} + +void SetBgAttribute(u8 bg, u8 attributeId, u8 value) +{ + switch (attributeId) + { + case BG_ATTR_CHARBASEINDEX: + SetBgControlAttributes(bg, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_MAPBASEINDEX: + SetBgControlAttributes(bg, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_SCREENSIZE: + SetBgControlAttributes(bg, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_PALETTEMODE: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_PRIORITY: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF); + break; + case BG_ATTR_MOSAIC: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF); + break; + case BG_ATTR_WRAPAROUND: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value); + break; + } +} + +u16 GetBgAttribute(u8 bg, u8 attributeId) +{ + switch (attributeId) + { + case BG_ATTR_CHARBASEINDEX: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_CHARBASEINDEX); + case BG_ATTR_MAPBASEINDEX: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_MAPBASEINDEX); + case BG_ATTR_SCREENSIZE: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + case BG_ATTR_PALETTEMODE: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE); + case BG_ATTR_PRIORITY: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_PRIORITY); + case BG_ATTR_MOSAIC: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_MOSAIC); + case BG_ATTR_WRAPAROUND: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_WRAPAROUND); + case BG_ATTR_METRIC: + switch (GetBgType(bg)) + { + case 0: + return GetBgMetricTextMode(bg, 0) * 0x800; + case 1: + return GetBgMetricAffineMode(bg, 0) * 0x100; + default: + return 0; + } + case BG_ATTR_TYPE: + return GetBgType(bg); + case BG_ATTR_BASETILE: + return sGpuBgConfigs2[bg].baseTile; + default: + return -1; + } +} + +s32 ChangeBgX(u8 bg, s32 value, u8 op) +{ + u8 mode; + u16 temp1; + u16 temp2; + + if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + return -1; + } + + switch (op) + { + case 0: + default: + sGpuBgConfigs2[bg].bg_x = value; + break; + case 1: + sGpuBgConfigs2[bg].bg_x += value; + break; + case 2: + sGpuBgConfigs2[bg].bg_x -= value; + break; + } + + mode = GetBgMode(); + + switch (bg) + { + case 0: + temp1 = sGpuBgConfigs2[0].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG0HOFS, temp1); + break; + case 1: + temp1 = sGpuBgConfigs2[1].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG1HOFS, temp1); + break; + case 2: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[2].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG2HOFS, temp1); + } + else + { + temp1 = sGpuBgConfigs2[2].bg_x >> 0x10; + temp2 = sGpuBgConfigs2[2].bg_x & 0xFFFF; + SetGpuReg(REG_OFFSET_BG2X_H, temp1); + SetGpuReg(REG_OFFSET_BG2X_L, temp2); + } + break; + case 3: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[3].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG3HOFS, temp1); + } + else if (mode == 2) + { + temp1 = sGpuBgConfigs2[3].bg_x >> 0x10; + temp2 = sGpuBgConfigs2[3].bg_x & 0xFFFF; + SetGpuReg(REG_OFFSET_BG3X_H, temp1); + SetGpuReg(REG_OFFSET_BG3X_L, temp2); + } + break; + } + + return sGpuBgConfigs2[bg].bg_x; +} + +s32 GetBgX(u8 bg) +{ + if (IsInvalidBg32(bg)) + return -1; + else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + return -1; + else + return sGpuBgConfigs2[bg].bg_x; +} + +s32 ChangeBgY(u8 bg, s32 value, u8 op) +{ + u8 mode; + u16 temp1; + u16 temp2; + + if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + return -1; + } + + switch (op) + { + case 0: + default: + sGpuBgConfigs2[bg].bg_y = value; + break; + case 1: + sGpuBgConfigs2[bg].bg_y += value; + break; + case 2: + sGpuBgConfigs2[bg].bg_y -= value; + break; + } + + mode = GetBgMode(); + + switch (bg) + { + case 0: + temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG0VOFS, temp1); + break; + case 1: + temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG1VOFS, temp1); + break; + case 2: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG2VOFS, temp1); + } + else + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; + SetGpuReg(REG_OFFSET_BG2Y_H, temp1); + SetGpuReg(REG_OFFSET_BG2Y_L, temp2); + } + break; + case 3: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG3VOFS, temp1); + } + else if (mode == 2) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; + SetGpuReg(REG_OFFSET_BG3Y_H, temp1); + SetGpuReg(REG_OFFSET_BG3Y_L, temp2); + } + break; + } + + return sGpuBgConfigs2[bg].bg_y; +} + +s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op) +{ + u8 mode; + u16 temp1; + u16 temp2; + + if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + return -1; + } + + switch (op) + { + case 0: + default: + sGpuBgConfigs2[bg].bg_y = value; + break; + case 1: + sGpuBgConfigs2[bg].bg_y += value; + break; + case 2: + sGpuBgConfigs2[bg].bg_y -= value; + break; + } + + mode = GetBgMode(); + + switch (bg) + { + case 0: + temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, temp1); + break; + case 1: + temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG1VOFS, temp1); + break; + case 2: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG2VOFS, temp1); + + } + else + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; + SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_H, temp1); + SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_L, temp2); + } + break; + case 3: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG3VOFS, temp1); + } + else if (mode == 2) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; + SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_H, temp1); + SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_L, temp2); + } + break; + } + + return sGpuBgConfigs2[bg].bg_y; +} + +s32 GetBgY(u8 bg) +{ + if (IsInvalidBg32(bg)) + return -1; + else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + return -1; + else + return sGpuBgConfigs2[bg].bg_y; +} + +void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) +{ + SetBgAffineInternal(bg, srcCenterX, srcCenterY, dispCenterX, dispCenterY, scaleX, scaleY, rotationAngle); +} + +u8 Unused_AdjustBgMosaic(u8 a1, u8 a2) +{ + u16 result = GetGpuReg(REG_OFFSET_MOSAIC); + s16 test1 = result & 0xF; + s16 test2 = (result >> 4) & 0xF; + + result &= 0xFF00; + + switch (a2) + { + case 0: + default: + test1 = a1 & 0xF; + test2 = a1 >> 0x4; + break; + case 1: + test1 = a1 & 0xF; + break; + case 2: + if ((test1 + a1) > 0xF) + { + test1 = 0xF; + } + else + { + test1 += a1; + } + break; + case 3: + if ((test1 - a1) < 0) + { + test1 = 0x0; + } + else + { + test1 -= a1; + } + break; + case 4: + test2 = a1 & 0xF; + break; + case 5: + if ((test2 + a1) > 0xF) + { + test2 = 0xF; + } + else + { + test2 += a1; + } + break; + case 6: + if ((test2 - a1) < 0) + { + test2 = 0x0; + } + else + { + test2 -= a1; + } + break; + } + + result |= ((test2 << 0x4) & 0xF0); + result |= (test1 & 0xF); + + SetGpuReg(REG_OFFSET_MOSAIC, result); + + return result; +} + +void SetBgTilemapBuffer(u8 bg, void *tilemap) +{ + if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + sGpuBgConfigs2[bg].tilemap = tilemap; + } +} + +void UnsetBgTilemapBuffer(u8 bg) +{ + if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + sGpuBgConfigs2[bg].tilemap = NULL; + } +} + +void* GetBgTilemapBuffer(u8 bg) +{ + if (IsInvalidBg32(bg)) + return NULL; + else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + return NULL; + else + return sGpuBgConfigs2[bg].tilemap; +} + +void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset) +{ + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + if (mode != 0) + CpuCopy16(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2)), mode); + else + LZ77UnCompWram(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2))); + } +} + +void CopyBgTilemapBufferToVram(u8 bg) +{ + u16 sizeToLoad; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + switch (GetBgType(bg)) + { + case 0: + sizeToLoad = GetBgMetricTextMode(bg, 0) * 0x800; + break; + case 1: + sizeToLoad = GetBgMetricAffineMode(bg, 0) * 0x100; + break; + default: + sizeToLoad = 0; + break; + } + LoadBgVram(bg, sGpuBgConfigs2[bg].tilemap, sizeToLoad, 0, 2); + } +} + +void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height) +{ + u16 destX16; + u16 destY16; + u16 mode; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + switch (GetBgType(bg)) + { + case 0: + { + const u16 * srcCopy = src; + for (destY16 = destY; destY16 < (destY + height); destY16++) + { + for (destX16 = destX; destX16 < (destX + width); destX16++) + { + ((u16*)sGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *srcCopy++; + } + } + break; + } + case 1: + { + const u8 * srcCopy = src; + mode = GetBgMetricAffineMode(bg, 0x1); + for (destY16 = destY; destY16 < (destY + height); destY16++) + { + for (destX16 = destX; destX16 < (destX + width); destX16++) + { + ((u8*)sGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *srcCopy++; + } + } + break; + } + } + } +} + +void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette) +{ + CopyRectToBgTilemapBufferRect(bg, src, 0, 0, rectWidth, rectHeight, destX, destY, rectWidth, rectHeight, palette, 0, 0); +} + +void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset) +{ + u16 screenWidth, screenHeight, screenSize; + u16 var; + const void *srcPtr; + u16 i, j; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + screenWidth = GetBgMetricTextMode(bg, 0x1) * 0x20; + screenHeight = GetBgMetricTextMode(bg, 0x2) * 0x20; + switch (GetBgType(bg)) + { + case 0: + srcPtr = src + ((srcY * srcWidth) + srcX) * 2; + for (i = destX; i < (destX + rectWidth); i++) + { + for (j = srcHeight; j < (srcHeight + destY); j++) + { + u16 index = GetTileMapIndexFromCoords(j, i, screenSize, screenWidth, screenHeight); + CopyTileMapEntry(srcPtr, sGpuBgConfigs2[bg].tilemap + (index * 2), rectHeight, palette1, tileOffset); + srcPtr += 2; + } + srcPtr += (srcWidth - destY) * 2; + } + break; + case 1: + srcPtr = src + ((srcY * srcWidth) + srcX); + var = GetBgMetricAffineMode(bg, 0x1); + for (i = destX; i < (destX + rectWidth); i++) + { + for (j = srcHeight; j < (srcHeight + destY); j++) + { + *(u8*)(sGpuBgConfigs2[bg].tilemap + ((var * i) + j)) = *(u8*)(srcPtr) + palette1; + srcPtr++; + } + srcPtr += (srcWidth - destY); + } + break; + } + } +} + +void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height) +{ + u16 x16; + u16 y16; + u16 mode; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + switch (GetBgType(bg)) + { + case 0: + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + ((u16*)sGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum; + } + } + break; + case 1: + mode = GetBgMetricAffineMode(bg, 0x1); + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + ((u8*)sGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum; + } + } + break; + } + } +} + +void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette) +{ + WriteSequenceToBgTilemapBuffer(bg, tileNum, x, y, width, height, palette, 0); +} + +void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta) +{ + u16 mode; + u16 mode2; + u16 attribute; + u16 mode3; + u16 x16, y16; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + mode = GetBgMetricTextMode(bg, 0x1) * 0x20; + mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20; + switch (GetBgType(bg)) + { + case 0: + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + CopyTileMapEntry(&firstTileNum, &((u16*)sGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0); + firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); + } + } + break; + case 1: + mode3 = GetBgMetricAffineMode(bg, 0x1); + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + ((u8*)sGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum; + firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); + } + } + break; + } + } +} + +u16 GetBgMetricTextMode(u8 bg, u8 whichMetric) +{ + u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + + switch (whichMetric) + { + case 0: + switch (screenSize) + { + case 0: + return 1; + case 1: + case 2: + return 2; + case 3: + return 4; + } + break; + case 1: + switch (screenSize) + { + case 0: + return 1; + case 1: + return 2; + case 2: + return 1; + case 3: + return 2; + } + break; + case 2: + switch (screenSize) + { + case 0: + case 1: + return 1; + case 2: + case 3: + return 2; + } + break; + } + return 0; +} + +u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric) +{ + u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + + switch (whichMetric) + { + case 0: + switch (screenSize) + { + case 0: + return 0x1; + case 1: + return 0x4; + case 2: + return 0x10; + case 3: + return 0x40; + } + break; + case 1: + case 2: + return 0x10 << screenSize; + } + return 0; +} + +u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight) +{ + x = x & (screenWidth - 1); + y = y & (screenHeight - 1); + + switch (screenSize) + { + case 0: + case 2: + break; + case 3: + if (y >= 0x20) + y += 0x20; + case 1: + if (x >= 0x20) + { + x -= 0x20; + y += 0x20; + } + break; + } + return (y * 0x20) + x; +} + +void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2) +{ + u16 var; + + switch (palette1) + { + case 0 ... 15: + var = ((*src + tileOffset) & 0xFFF) + ((palette1 + palette2) << 12); + break; + case 16: + var = *dest; + var &= 0xFC00; + var += palette2 << 12; + var |= (*src + tileOffset) & 0x3FF; + break; + default: + case 17 ... INT_MAX: + var = *src + tileOffset + (palette2 << 12); + break; + } + *dest = var; +} + +u32 GetBgType(u8 bg) +{ + u8 mode = GetBgMode(); + + switch (bg) + { + case 0: + case 1: + switch (mode) + { + case 0: + case 1: + return 0; + } + break; + case 2: + switch (mode) + { + case 0: + return 0; + case 1: + case 2: + return 1; + } + break; + case 3: + switch (mode) + { + case 0: + return 0; + case 2: + return 1; + } + break; + } + + return 0xFFFF; +} + +bool32 IsInvalidBg32(u8 bg) +{ + if (bg >= NUM_BACKGROUNDS) + return TRUE; + else + return FALSE; +} + +bool32 IsTileMapOutsideWram(u8 bg) +{ + if (sGpuBgConfigs2[bg].tilemap > (void*)IWRAM_END) + return TRUE; + else if (sGpuBgConfigs2[bg].tilemap == NULL) + return TRUE; + else + return FALSE; +} diff --git a/src/blit.c b/src/blit.c new file mode 100644 index 000000000..bdbb2e2fd --- /dev/null +++ b/src/blit.c @@ -0,0 +1,209 @@ +#include "global.h" +#include "blit.h" + +void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height) +{ + BlitBitmapRect4Bit(src, dst, srcX, srcY, dstX, dstY, width, height, 0xFF); +} + +void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierSrcY; + s32 multiplierDstY; + s32 loopSrcY, loopDstY; + s32 loopSrcX, loopDstX; + const u8 *pixelsSrc; + u8 *pixelsDst; + s32 toOrr; + s32 toAnd; + s32 toShift; + + if (dst->width - dstX < width) + xEnd = (dst->width - dstX) + srcX; + else + xEnd = srcX + width; + + if (dst->height - dstY < height) + yEnd = (dst->height - dstY) + srcY; + else + yEnd = height + srcY; + + multiplierSrcY = (src->width + (src->width & 7)) >> 3; + multiplierDstY = (dst->width + (dst->width & 7)) >> 3; + + if (colorKey == 0xFF) + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); + pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); + toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); + toShift = ((loopDstX & 1) << 2); + toOrr <<= toShift; + toAnd = 0xF0 >> (toShift); + *pixelsDst = toOrr | (*pixelsDst & toAnd); + } + } + } + else + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); + pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); + toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); + if (toOrr != colorKey) + { + toShift = ((loopDstX & 1) << 2); + toOrr <<= toShift; + toAnd = 0xF0 >> (toShift); + *pixelsDst = toOrr | (*pixelsDst & toAnd); + } + } + } + } +} + +void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierY; + s32 loopX, loopY; + u8 toOrr1, toOrr2; + + xEnd = x + width; + if (xEnd > surface->width) + xEnd = surface->width; + + yEnd = y + height; + if (yEnd > surface->height) + yEnd = surface->height; + + multiplierY = (surface->width + (surface->width & 7)) >> 3; + toOrr1 = fillValue << 4; + toOrr2 = fillValue & 0xF; + + for (loopY = y; loopY < yEnd; loopY++) + { + for (loopX = x; loopX < xEnd; loopX++) + { + u8 *pixels = surface->pixels + ((loopX >> 1) & 3) + ((loopX >> 3) << 5) + (((loopY >> 3) * multiplierY) << 5) + ((u32)(loopY << 0x1d) >> 0x1B); + if ((loopX << 0x1F) != 0) + *pixels = toOrr1 | (*pixels & 0xF); + else + *pixels = toOrr2 | (*pixels & 0xF0); + } + } +} + +void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset) +{ + s32 palOffsetBits; + s32 xEnd; + s32 yEnd; + s32 multiplierSrcY; + s32 multiplierDstY; + s32 loopSrcY, loopDstY; + s32 loopSrcX, loopDstX; + const u8 *pixelsSrc; + u8 *pixelsDst; + s32 colorKeyBits; + + palOffsetBits = (u32)(paletteOffset << 0x1C) >> 0x18; + colorKeyBits = (u32)(colorKey << 0x1C) >> 0x18; + + if (dst->width - dstX < width) + xEnd = (dst->width - dstX) + srcX; + else + xEnd = width + srcX; + + if (dst->height - dstY < height) + yEnd = (srcY + dst->height) - dstY; + else + yEnd = srcY + height; + + multiplierSrcY = (src->width + (src->width & 7)) >> 3; + multiplierDstY = (dst->width + (dst->width & 7)) >> 3; + + if (colorKey == 0xFF) + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + if (loopSrcX & 1) + { + *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); + } + else + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); + } + } + } + } + else + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + if (loopSrcX & 1) + { + if ((*pixelsSrc & 0xF0) != colorKeyBits) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); + } + } + else + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + if ((*pixelsSrc & 0xF) != colorKey) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); + } + } + } + } + } +} + +void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierY; + s32 loopX, loopY; + + xEnd = x + width; + if (xEnd > surface->width) + xEnd = surface->width; + + yEnd = y + height; + if (yEnd > surface->height) + yEnd = surface->height; + + multiplierY = (surface->width + (surface->width & 7)) >> 3; + + for (loopY = y; loopY < yEnd; loopY++) + { + for (loopX = x; loopX < xEnd; loopX++) + { + u8 *pixels = surface->pixels + (loopX & 7) + ((loopX >> 3) << 6) + (((loopY >> 3) * multiplierY) << 6) + ((u32)(loopY << 0x1d) >> 0x1a); + *pixels = fillValue; + } + } +} diff --git a/src/dma3_manager.c b/src/dma3_manager.c new file mode 100644 index 000000000..d774efe8c --- /dev/null +++ b/src/dma3_manager.c @@ -0,0 +1,183 @@ +#include "global.h" +#include "dma3.h" + +#define MAX_DMA_REQUESTS 128 + +#define DMA_REQUEST_COPY32 1 +#define DMA_REQUEST_FILL32 2 +#define DMA_REQUEST_COPY16 3 +#define DMA_REQUEST_FILL16 4 + +struct Dma3Request +{ + const u8 *src; + u8 *dest; + u16 size; + u16 mode; + u32 value; +}; + +static struct Dma3Request sDma3Requests[MAX_DMA_REQUESTS]; + +static vbool8 sDma3ManagerLocked; +static u8 sDma3RequestCursor; + +void ClearDma3Requests(void) +{ + int i; + + sDma3ManagerLocked = TRUE; + sDma3RequestCursor = 0; + + for (i = 0; i < MAX_DMA_REQUESTS; i++) + { + sDma3Requests[i].size = 0; + sDma3Requests[i].src = NULL; + sDma3Requests[i].dest = NULL; + } + + sDma3ManagerLocked = FALSE; +} + +void ProcessDma3Requests(void) +{ + u16 bytesTransferred; + + if (sDma3ManagerLocked) + return; + + bytesTransferred = 0; + + // as long as there are DMA requests to process (unless size or vblank is an issue), do not exit + while (sDma3Requests[sDma3RequestCursor].size != 0) + { + bytesTransferred += sDma3Requests[sDma3RequestCursor].size; + + if (bytesTransferred > 40 * 1024) + return; // don't transfer more than 40 KiB + if (*(u8 *)REG_ADDR_VCOUNT > 224) + return; // we're about to leave vblank, stop + + switch (sDma3Requests[sDma3RequestCursor].mode) + { + case DMA_REQUEST_COPY32: // regular 32-bit copy + Dma3CopyLarge32_(sDma3Requests[sDma3RequestCursor].src, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + case DMA_REQUEST_FILL32: // repeat a single 32-bit value across RAM + Dma3FillLarge32_(sDma3Requests[sDma3RequestCursor].value, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + case DMA_REQUEST_COPY16: // regular 16-bit copy + Dma3CopyLarge16_(sDma3Requests[sDma3RequestCursor].src, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + case DMA_REQUEST_FILL16: // repeat a single 16-bit value across RAM + Dma3FillLarge16_(sDma3Requests[sDma3RequestCursor].value, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + } + + // Free the request + sDma3Requests[sDma3RequestCursor].src = NULL; + sDma3Requests[sDma3RequestCursor].dest = NULL; + sDma3Requests[sDma3RequestCursor].size = 0; + sDma3Requests[sDma3RequestCursor].mode = 0; + sDma3Requests[sDma3RequestCursor].value = 0; + sDma3RequestCursor++; + + if (sDma3RequestCursor >= MAX_DMA_REQUESTS) // loop back to the first DMA request + sDma3RequestCursor = 0; + } +} + +s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode) +{ + int cursor; + int i = 0; + + sDma3ManagerLocked = TRUE; + cursor = sDma3RequestCursor; + + while (i < MAX_DMA_REQUESTS) + { + if (sDma3Requests[cursor].size == 0) // an empty request was found. + { + sDma3Requests[cursor].src = src; + sDma3Requests[cursor].dest = dest; + sDma3Requests[cursor].size = size; + + if (mode == 1) + sDma3Requests[cursor].mode = DMA_REQUEST_COPY32; + else + sDma3Requests[cursor].mode = DMA_REQUEST_COPY16; + + sDma3ManagerLocked = FALSE; + return cursor; + } + if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. + cursor = 0; + i++; + } + sDma3ManagerLocked = FALSE; + return -1; // no free DMA request was found +} + +s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode) +{ + int cursor; + int i = 0; + + cursor = sDma3RequestCursor; + sDma3ManagerLocked = TRUE; + + while (i < MAX_DMA_REQUESTS) + { + if (sDma3Requests[cursor].size == 0) // an empty request was found. + { + sDma3Requests[cursor].dest = dest; + sDma3Requests[cursor].size = size; + sDma3Requests[cursor].mode = mode; + sDma3Requests[cursor].value = value; + + if(mode == 1) + sDma3Requests[cursor].mode = DMA_REQUEST_FILL32; + else + sDma3Requests[cursor].mode = DMA_REQUEST_FILL16; + + sDma3ManagerLocked = FALSE; + return cursor; + } + if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. + cursor = 0; + i++; + } + sDma3ManagerLocked = FALSE; + return -1; // no free DMA request was found +} + +s16 CheckForSpaceForDma3Request(s16 index) +{ + int i = 0; + + if (index == -1) // check if all requests are free + { + while (i < MAX_DMA_REQUESTS) + { + if (sDma3Requests[i].size != 0) + return -1; + i++; + } + return 0; + } + else // check the specified request + { + if (sDma3Requests[index].size != 0) + return -1; + return 0; + } +} diff --git a/src/gpu_regs.c b/src/gpu_regs.c new file mode 100644 index 000000000..3bcc4fd93 --- /dev/null +++ b/src/gpu_regs.c @@ -0,0 +1,195 @@ +#include "global.h" +#include "gpu_regs.h" + +#define GPU_REG_BUF_SIZE 0x60 + +#define GPU_REG_BUF(offset) (*(u16 *)(&sGpuRegBuffer[offset])) +#define GPU_REG(offset) (*(vu16 *)(REG_BASE + offset)) + +#define EMPTY_SLOT 0xFF + +static u8 sGpuRegBuffer[GPU_REG_BUF_SIZE]; +static u8 sGpuRegWaitingList[GPU_REG_BUF_SIZE]; +static volatile bool8 sGpuRegBufferLocked; +static volatile bool8 sShouldSyncRegIE; +static vu16 sRegIE; + +static void CopyBufferedValueToGpuReg(u8 regOffset); +static void SyncRegIE(void); +static void UpdateRegDispstatIntrBits(u16 regIE); + +void InitGpuRegManager(void) +{ + s32 i; + + for (i = 0; i < GPU_REG_BUF_SIZE; i++) + { + sGpuRegBuffer[i] = 0; + sGpuRegWaitingList[i] = EMPTY_SLOT; + } + + sGpuRegBufferLocked = FALSE; + sShouldSyncRegIE = FALSE; + sRegIE = 0; +} + +static void CopyBufferedValueToGpuReg(u8 regOffset) +{ + if (regOffset == REG_OFFSET_DISPSTAT) + { + REG_DISPSTAT &= ~(DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); + REG_DISPSTAT |= GPU_REG_BUF(REG_OFFSET_DISPSTAT); + } + else + { + GPU_REG(regOffset) = GPU_REG_BUF(regOffset); + } +} + +void CopyBufferedValuesToGpuRegs(void) +{ + if (!sGpuRegBufferLocked) + { + s32 i; + + for (i = 0; i < GPU_REG_BUF_SIZE; i++) + { + u8 regOffset = sGpuRegWaitingList[i]; + if (regOffset == EMPTY_SLOT) + return; + CopyBufferedValueToGpuReg(regOffset); + sGpuRegWaitingList[i] = EMPTY_SLOT; + } + } +} + +void SetGpuReg(u8 regOffset, u16 value) +{ + if (regOffset < GPU_REG_BUF_SIZE) + { + u16 vcount; + + GPU_REG_BUF(regOffset) = value; + vcount = REG_VCOUNT & 0xFF; + + if ((vcount >= 161 && vcount <= 225) || (REG_DISPCNT & DISPCNT_FORCED_BLANK)) + { + CopyBufferedValueToGpuReg(regOffset); + } + else + { + s32 i; + + sGpuRegBufferLocked = TRUE; + + for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) + { + if (sGpuRegWaitingList[i] == regOffset) + { + sGpuRegBufferLocked = FALSE; + return; + } + } + + sGpuRegWaitingList[i] = regOffset; + sGpuRegBufferLocked = FALSE; + } + } +} + +void SetGpuReg_ForcedBlank(u8 regOffset, u16 value) +{ + if (regOffset < GPU_REG_BUF_SIZE) + { + GPU_REG_BUF(regOffset) = value; + + if (REG_DISPCNT & DISPCNT_FORCED_BLANK) + { + CopyBufferedValueToGpuReg(regOffset); + } + else + { + s32 i; + + sGpuRegBufferLocked = TRUE; + + for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) + { + if (sGpuRegWaitingList[i] == regOffset) + { + sGpuRegBufferLocked = FALSE; + return; + } + } + + sGpuRegWaitingList[i] = regOffset; + sGpuRegBufferLocked = FALSE; + } + } +} + +u16 GetGpuReg(u8 regOffset) +{ + if (regOffset == REG_OFFSET_DISPSTAT) + return REG_DISPSTAT; + + if (regOffset == REG_OFFSET_VCOUNT) + return REG_VCOUNT; + + return GPU_REG_BUF(regOffset); +} + +void SetGpuRegBits(u8 regOffset, u16 mask) +{ + u16 regValue = GPU_REG_BUF(regOffset); + SetGpuReg(regOffset, regValue | mask); +} + +void ClearGpuRegBits(u8 regOffset, u16 mask) +{ + u16 regValue = GPU_REG_BUF(regOffset); + SetGpuReg(regOffset, regValue & ~mask); +} + +static void SyncRegIE(void) +{ + if (sShouldSyncRegIE) + { + u16 temp = REG_IME; + REG_IME = 0; + REG_IE = sRegIE; + REG_IME = temp; + sShouldSyncRegIE = FALSE; + } +} + +void EnableInterrupts(u16 mask) +{ + sRegIE |= mask; + sShouldSyncRegIE = TRUE; + SyncRegIE(); + UpdateRegDispstatIntrBits(sRegIE); +} + +void DisableInterrupts(u16 mask) +{ + sRegIE &= ~mask; + sShouldSyncRegIE = TRUE; + SyncRegIE(); + UpdateRegDispstatIntrBits(sRegIE); +} + +static void UpdateRegDispstatIntrBits(u16 regIE) +{ + u16 oldValue = GetGpuReg(REG_OFFSET_DISPSTAT) & (DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); + u16 newValue = 0; + + if (regIE & INTR_FLAG_VBLANK) + newValue |= DISPSTAT_VBLANK_INTR; + + if (regIE & INTR_FLAG_HBLANK) + newValue |= DISPSTAT_HBLANK_INTR; + + if (oldValue != newValue) + SetGpuReg(REG_OFFSET_DISPSTAT, newValue); +} diff --git a/src/io_reg.c b/src/io_reg.c new file mode 100644 index 000000000..44364349d --- /dev/null +++ b/src/io_reg.c @@ -0,0 +1,36 @@ +#include "global.h" +#include "io_reg.h" +#include "gba/io_reg.h" + +static const u32 sUnused[] = { + 0, + 0, + (1 << 26) | (1 << 3), + (1 << 26) | (1 << 3) | (1 << 1), + (1 << 26) | (1 << 3) | (1 << 2), + (1 << 26) | (1 << 3) | (1 << 2) | (1 << 1), + (1 << 26) | (1 << 4), + (1 << 26) | (1 << 4) | (1 << 2), + (1 << 26) | (1 << 4) | (1 << 3), + (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2), + (1 << 26) | (1 << 4) | (1 << 1), + (1 << 26) | (1 << 4) | (1 << 2) | (1 << 1), + (1 << 26) | (1 << 4) | (1 << 3) | (1 << 1), + (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1), + (1 << 25) | (1 << 8), + (1 << 27) | (1 << 10), +}; + +const u16 gOverworldBackgroundLayerFlags[] = { + BLDCNT_TGT2_BG0, + BLDCNT_TGT2_BG1, + BLDCNT_TGT2_BG2, + BLDCNT_TGT2_BG3, +}; + +const u16 gOrbEffectBackgroundLayerFlags[] = { + BLDCNT_TGT1_BG0, + BLDCNT_TGT1_BG1, + BLDCNT_TGT1_BG2, + BLDCNT_TGT1_BG3, +}; diff --git a/src/malloc.c b/src/malloc.c new file mode 100644 index 000000000..38fc8939e --- /dev/null +++ b/src/malloc.c @@ -0,0 +1,210 @@ +#include "global.h" + +static void *sHeapStart; +static u32 sHeapSize; +static u32 sFiller; // needed to align dma3_manager.o(.bss) + +#define MALLOC_SYSTEM_ID 0xA3A3 + +struct MemBlock { + // Whether this block is currently allocated. + bool16 flag; + + // Magic number used for error checking. Should equal MALLOC_SYSTEM_ID. + u16 magic; + + // Size of the block (not including this header struct). + u32 size; + + // Previous block pointer. Equals sHeapStart if this is the first block. + struct MemBlock *prev; + + // Next block pointer. Equals sHeapStart if this is the last block. + struct MemBlock *next; + + // Data in the memory block. (Arrays of length 0 are a GNU extension.) + u8 data[0]; +}; + +void PutMemBlockHeader(void *block, struct MemBlock *prev, struct MemBlock *next, u32 size) +{ + struct MemBlock *header = (struct MemBlock *)block; + + header->flag = FALSE; + header->magic = MALLOC_SYSTEM_ID; + header->size = size; + header->prev = prev; + header->next = next; +} + +void PutFirstMemBlockHeader(void *block, u32 size) +{ + PutMemBlockHeader(block, (struct MemBlock *)block, (struct MemBlock *)block, size - sizeof(struct MemBlock)); +} + +void *AllocInternal(void *heapStart, u32 size) +{ + struct MemBlock *pos = (struct MemBlock *)heapStart; + struct MemBlock *head = pos; + struct MemBlock *splitBlock; + u32 foundBlockSize; + + // Alignment + if (size & 3) + size = 4 * ((size / 4) + 1); + + for (;;) { + // Loop through the blocks looking for unused block that's big enough. + + if (!pos->flag) { + foundBlockSize = pos->size; + + if (foundBlockSize >= size) { + if (foundBlockSize - size < 2 * sizeof(struct MemBlock)) { + // The block isn't much bigger than the requested size, + // so just use it. + pos->flag = TRUE; + } else { + // The block is significantly bigger than the requested + // size, so split the rest into a separate block. + foundBlockSize -= sizeof(struct MemBlock); + foundBlockSize -= size; + + splitBlock = (struct MemBlock *)(pos->data + size); + + pos->flag = TRUE; + pos->size = size; + + PutMemBlockHeader(splitBlock, pos, pos->next, foundBlockSize); + + pos->next = splitBlock; + + if (splitBlock->next != head) + splitBlock->next->prev = splitBlock; + } + + return pos->data; + } + } + + if (pos->next == head) + return NULL; + + pos = pos->next; + } +} + +void FreeInternal(void *heapStart, void *pointer) +{ + if (pointer) { + struct MemBlock *head = (struct MemBlock *)heapStart; + struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); + block->flag = FALSE; + + // If the freed block isn't the last one, merge with the next block + // if it's not in use. + if (block->next != head) { + if (!block->next->flag) { + block->size += sizeof(struct MemBlock) + block->next->size; + block->next->magic = 0; + block->next = block->next->next; + if (block->next != head) + block->next->prev = block; + } + } + + // If the freed block isn't the first one, merge with the previous block + // if it's not in use. + if (block != head) { + if (!block->prev->flag) { + block->prev->next = block->next; + + if (block->next != head) + block->next->prev = block->prev; + + block->magic = 0; + block->prev->size += sizeof(struct MemBlock) + block->size; + } + } + } +} + +void *AllocZeroedInternal(void *heapStart, u32 size) +{ + void *mem = AllocInternal(heapStart, size); + + if (mem != NULL) { + if (size & 3) + size = 4 * ((size / 4) + 1); + + CpuFill32(0, mem, size); + } + + return mem; +} + +bool32 CheckMemBlockInternal(void *heapStart, void *pointer) +{ + struct MemBlock *head = (struct MemBlock *)heapStart; + struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); + + if (block->magic != MALLOC_SYSTEM_ID) + return FALSE; + + if (block->next->magic != MALLOC_SYSTEM_ID) + return FALSE; + + if (block->next != head && block->next->prev != block) + return FALSE; + + if (block->prev->magic != MALLOC_SYSTEM_ID) + return FALSE; + + if (block->prev != head && block->prev->next != block) + return FALSE; + + if (block->next != head && block->next != (struct MemBlock *)(block->data + block->size)) + return FALSE; + + return TRUE; +} + +void InitHeap(void *heapStart, u32 heapSize) +{ + sHeapStart = heapStart; + sHeapSize = heapSize; + PutFirstMemBlockHeader(heapStart, heapSize); +} + +void *Alloc(u32 size) +{ + return AllocInternal(sHeapStart, size); +} + +void *AllocZeroed(u32 size) +{ + return AllocZeroedInternal(sHeapStart, size); +} + +void Free(void *pointer) +{ + FreeInternal(sHeapStart, pointer); +} + +bool32 CheckMemBlock(void *pointer) +{ + return CheckMemBlockInternal(sHeapStart, pointer); +} + +bool32 CheckHeap() +{ + struct MemBlock *pos = (struct MemBlock *)sHeapStart; + + do { + if (!CheckMemBlockInternal(sHeapStart, pos->data)) + return FALSE; + pos = pos->next; + } while (pos != (struct MemBlock *)sHeapStart); + + return TRUE; +} diff --git a/src/sprite.c b/src/sprite.c new file mode 100644 index 000000000..f97ecc712 --- /dev/null +++ b/src/sprite.c @@ -0,0 +1,1775 @@ +#include "global.h" +#include "sprite.h" +#include "main.h" +#include "palette.h" + +#define MAX_SPRITE_COPY_REQUESTS 64 + +#define OAM_MATRIX_COUNT 32 + +#define SET_SPRITE_TILE_RANGE(index, start, count) \ +{ \ + sSpriteTileRanges[index * 2] = start; \ + (sSpriteTileRanges + 1)[index * 2] = count; \ +} + +#define ALLOC_SPRITE_TILE(n) \ +{ \ + sSpriteTileAllocBitmap[(n) / 8] |= (1 << ((n) % 8)); \ +} + +#define FREE_SPRITE_TILE(n) \ +{ \ + sSpriteTileAllocBitmap[(n) / 8] &= ~(1 << ((n) % 8)); \ +} + +#define SPRITE_TILE_IS_ALLOCATED(n) ((sSpriteTileAllocBitmap[(n) / 8] >> ((n) % 8)) & 1) + + +struct SpriteCopyRequest +{ + const u8 *src; + u8 *dest; + u16 size; +}; + +struct OamDimensions32 +{ + s32 width; + s32 height; +}; + +struct OamDimensions +{ + s8 width; + s8 height; +}; + +static void UpdateOamCoords(void); +static void BuildSpritePriorities(void); +static void SortSprites(void); +static void CopyMatricesToOamBuffer(void); +static void AddSpritesToOamBuffer(void); +static u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +static void ResetOamMatrices(void); +static void ResetSprite(struct Sprite *sprite); +static s16 AllocSpriteTiles(u16 tileCount); +static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); +static void ResetAllSprites(void); +static void BeginAnim(struct Sprite *sprite); +static void ContinueAnim(struct Sprite *sprite); +static void AnimCmd_frame(struct Sprite *sprite); +static void AnimCmd_end(struct Sprite *sprite); +static void AnimCmd_jump(struct Sprite *sprite); +static void AnimCmd_loop(struct Sprite *sprite); +static void BeginAnimLoop(struct Sprite *sprite); +static void ContinueAnimLoop(struct Sprite *sprite); +static void JumpToTopOfAnimLoop(struct Sprite *sprite); +static void BeginAffineAnim(struct Sprite *sprite); +static void ContinueAffineAnim(struct Sprite *sprite); +static void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite); +static void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite); +static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix); +static u8 GetSpriteMatrixNum(struct Sprite *sprite); +static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); +static void AffineAnimStateRestartAnim(u8 matrixNum); +static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum); +static void AffineAnimStateReset(u8 matrixNum); +static void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static void DecrementAnimDelayCounter(struct Sprite *sprite); +static bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum); +static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static s16 ConvertScaleParam(s16 scale); +static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); +static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static u8 IndexOfSpriteTileTag(u16 tag); +static void AllocSpriteTileRange(u16 tag, u16 start, u16 count); +static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset); +static void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2); + +typedef void (*AnimFunc)(struct Sprite *); +typedef void (*AnimCmdFunc)(struct Sprite *); +typedef void (*AffineAnimCmdFunc)(u8 matrixNum, struct Sprite *); + +#define DUMMY_OAM_DATA \ +{ \ + .y = 160, \ + .affineMode = 0, \ + .objMode = 0, \ + .mosaic = 0, \ + .bpp = 0, \ + .shape = SPRITE_SHAPE(8x8), \ + .x = 304, \ + .matrixNum = 0, \ + .size = SPRITE_SIZE(8x8), \ + .tileNum = 0, \ + .priority = 3, /* lowest priority */ \ + .paletteNum = 0, \ + .affineParam = 0 \ +} + +#define ANIM_END 0xFFFF +#define AFFINE_ANIM_END 0x7FFF + +// forward declarations +const union AnimCmd * const gDummySpriteAnimTable[]; +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[]; +const struct SpriteTemplate gDummySpriteTemplate; + +// Unreferenced data. Also unreferenced in R/S. +static const u8 sUnknownData[24] = +{ + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, +}; + +static const u8 sCenterToCornerVecTable[3][4][2] = +{ + { // square + { -4, -4 }, + { -8, -8 }, + { -16, -16 }, + { -32, -32 }, + }, + { // horizontal rectangle + { -8, -4 }, + { -16, -4 }, + { -16, -8 }, + { -32, -16 }, + }, + { // vertical rectangle + { -4, -8 }, + { -4, -16 }, + { -8, -16 }, + { -16, -32 }, + }, +}; + +static const struct Sprite sDummySprite = +{ + .oam = DUMMY_OAM_DATA, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .template = &gDummySpriteTemplate, + .subspriteTables = NULL, + .callback = SpriteCallbackDummy, + .pos1 = { 304, 160 }, + .pos2 = { 0, 0 }, + .centerToCornerVecX = 0, + .centerToCornerVecY = 0, + .animNum = 0, + .animCmdIndex = 0, + .animDelayCounter = 0, + .animPaused = 0, + .affineAnimPaused = 0, + .animLoopCounter = 0, + .data = {0, 0, 0, 0, 0, 0, 0}, + .inUse = 0, + .coordOffsetEnabled = 0, + .invisible = FALSE, + .flags_3 = 0, + .flags_4 = 0, + .flags_5 = 0, + .flags_6 = 0, + .flags_7 = 0, + .hFlip = 0, + .vFlip = 0, + .animBeginning = 0, + .affineAnimBeginning = 0, + .animEnded = 0, + .affineAnimEnded = 0, + .usingSheet = 0, + .flags_f = 0, + .sheetTileStart = 0, + .subspriteTableNum = 0, + .subspriteMode = 0, + .subpriority = 0xFF +}; + +const struct OamData gDummyOamData = DUMMY_OAM_DATA; + +static const union AnimCmd sDummyAnim = { ANIM_END }; + +const union AnimCmd * const gDummySpriteAnimTable[] = { &sDummyAnim }; + +static const union AffineAnimCmd sDummyAffineAnim = { AFFINE_ANIM_END }; + +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[] = { &sDummyAffineAnim }; + +const struct SpriteTemplate gDummySpriteTemplate = +{ + .tileTag = 0, + .paletteTag = 0xFFFF, + .oam = &gDummyOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy +}; + +static const AnimFunc sAnimFuncs[] = +{ + ContinueAnim, + BeginAnim, +}; + +static const AnimFunc sAffineAnimFuncs[] = +{ + ContinueAffineAnim, + BeginAffineAnim, +}; + +static const AnimCmdFunc sAnimCmdFuncs[] = +{ + AnimCmd_loop, + AnimCmd_jump, + AnimCmd_end, + AnimCmd_frame, +}; + +static const AffineAnimCmdFunc sAffineAnimCmdFuncs[] = +{ + AffineAnimCmd_loop, + AffineAnimCmd_jump, + AffineAnimCmd_end, + AffineAnimCmd_frame, +}; + +static const struct OamDimensions32 sOamDimensions32[3][4] = +{ + [ST_OAM_SQUARE] = + { + [SPRITE_SIZE(8x8)] = { 8, 8 }, + [SPRITE_SIZE(16x16)] = { 16, 16 }, + [SPRITE_SIZE(32x32)] = { 32, 32 }, + [SPRITE_SIZE(64x64)] = { 64, 64 }, + }, + [ST_OAM_H_RECTANGLE] = + { + [SPRITE_SIZE(16x8)] = { 16, 8 }, + [SPRITE_SIZE(32x8)] = { 32, 8 }, + [SPRITE_SIZE(32x16)] = { 32, 16 }, + [SPRITE_SIZE(64x32)] = { 64, 32 }, + }, + [ST_OAM_V_RECTANGLE] = + { + [SPRITE_SIZE(8x16)] = { 8, 16 }, + [SPRITE_SIZE(8x32)] = { 8, 32 }, + [SPRITE_SIZE(16x32)] = { 16, 32 }, + [SPRITE_SIZE(32x64)] = { 32, 64 }, + }, +}; + +static const struct OamDimensions sOamDimensions[3][4] = +{ + [ST_OAM_SQUARE] = + { + [SPRITE_SIZE(8x8)] = { 8, 8 }, + [SPRITE_SIZE(16x16)] = { 16, 16 }, + [SPRITE_SIZE(32x32)] = { 32, 32 }, + [SPRITE_SIZE(64x64)] = { 64, 64 }, + }, + [ST_OAM_H_RECTANGLE] = + { + [SPRITE_SIZE(16x8)] = { 16, 8 }, + [SPRITE_SIZE(32x8)] = { 32, 8 }, + [SPRITE_SIZE(32x16)] = { 32, 16 }, + [SPRITE_SIZE(64x32)] = { 64, 32 }, + }, + [ST_OAM_V_RECTANGLE] = + { + [SPRITE_SIZE(8x16)] = { 8, 16 }, + [SPRITE_SIZE(8x32)] = { 8, 32 }, + [SPRITE_SIZE(16x32)] = { 16, 32 }, + [SPRITE_SIZE(32x64)] = { 32, 64 }, + }, +}; + +// iwram bss +static u16 sSpriteTileRangeTags[MAX_SPRITES]; +static u16 sSpriteTileRanges[MAX_SPRITES * 2]; +static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; +static u16 sSpritePaletteTags[16]; + +// iwram common +u32 gOamMatrixAllocBitmap; +u8 gReservedSpritePaletteCount; + +EWRAM_DATA struct Sprite gSprites[MAX_SPRITES + 1] = {0}; +EWRAM_DATA static u16 sSpritePriorities[MAX_SPRITES] = {0}; +EWRAM_DATA static u8 sSpriteOrder[MAX_SPRITES] = {0}; +EWRAM_DATA static bool8 sShouldProcessSpriteCopyRequests = 0; +EWRAM_DATA static u8 sSpriteCopyRequestCount = 0; +EWRAM_DATA static struct SpriteCopyRequest sSpriteCopyRequests[MAX_SPRITES] = {0}; +EWRAM_DATA u8 gOamLimit = 0; +EWRAM_DATA u16 gReservedSpriteTileCount = 0; +EWRAM_DATA static u8 sSpriteTileAllocBitmap[128] = {0}; +EWRAM_DATA s16 gSpriteCoordOffsetX = 0; +EWRAM_DATA s16 gSpriteCoordOffsetY = 0; +EWRAM_DATA struct OamMatrix gOamMatrices[OAM_MATRIX_COUNT] = {0}; +EWRAM_DATA bool8 gAffineAnimsDisabled = FALSE; + +void ResetSpriteData(void) +{ + ResetOamRange(0, 128); + ResetAllSprites(); + ClearSpriteCopyRequests(); + ResetAffineAnimData(); + FreeSpriteTileRanges(); + gOamLimit = 64; + gReservedSpriteTileCount = 0; + AllocSpriteTiles(0); + gSpriteCoordOffsetX = 0; + gSpriteCoordOffsetY = 0; +} + +void AnimateSprites(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (sprite->inUse) + { + sprite->callback(sprite); + + if (sprite->inUse) + AnimateSprite(sprite); + } + } +} + +void BuildOamBuffer(void) +{ + u8 temp; + UpdateOamCoords(); + BuildSpritePriorities(); + SortSprites(); + temp = gMain.oamLoadDisabled; + gMain.oamLoadDisabled = TRUE; + AddSpritesToOamBuffer(); + CopyMatricesToOamBuffer(); + gMain.oamLoadDisabled = temp; + sShouldProcessSpriteCopyRequests = TRUE; +} + +void UpdateOamCoords(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + if (sprite->inUse && !sprite->invisible) + { + if (sprite->coordOffsetEnabled) + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY; + } + else + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY; + } + } + } +} + +void BuildSpritePriorities(void) +{ + u16 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + u16 priority = sprite->subpriority | (sprite->oam.priority << 8); + sSpritePriorities[i] = priority; + } +} + +void SortSprites(void) +{ + u8 i; + for (i = 1; i < MAX_SPRITES; i++) + { + u8 j = i; + struct Sprite *sprite1 = &gSprites[sSpriteOrder[i - 1]]; + struct Sprite *sprite2 = &gSprites[sSpriteOrder[i]]; + u16 sprite1Priority = sSpritePriorities[sSpriteOrder[i - 1]]; + u16 sprite2Priority = sSpritePriorities[sSpriteOrder[i]]; + s16 sprite1Y = sprite1->oam.y; + s16 sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + + while (j > 0 + && ((sprite1Priority > sprite2Priority) + || (sprite1Priority == sprite2Priority && sprite1Y < sprite2Y))) + { + u8 temp = sSpriteOrder[j]; + sSpriteOrder[j] = sSpriteOrder[j - 1]; + sSpriteOrder[j - 1] = temp; + + // UB: If j equals 1, then j-- makes j equal 0. + // Then, sSpriteOrder[-1] gets accessed below. + // Although this doesn't result in a bug in the ROM, + // the behavior is undefined. + j--; +#ifdef UBFIX + if (j == 0) + break; +#endif + + sprite1 = &gSprites[sSpriteOrder[j - 1]]; + sprite2 = &gSprites[sSpriteOrder[j]]; + sprite1Priority = sSpritePriorities[sSpriteOrder[j - 1]]; + sprite2Priority = sSpritePriorities[sSpriteOrder[j]]; + sprite1Y = sprite1->oam.y; + sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + } + } +} + +void CopyMatricesToOamBuffer(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + u32 base = 4 * i; + gMain.oamBuffer[base + 0].affineParam = gOamMatrices[i].a; + gMain.oamBuffer[base + 1].affineParam = gOamMatrices[i].b; + gMain.oamBuffer[base + 2].affineParam = gOamMatrices[i].c; + gMain.oamBuffer[base + 3].affineParam = gOamMatrices[i].d; + } +} + +void AddSpritesToOamBuffer(void) +{ + u8 i = 0; + u8 oamIndex = 0; + + while (i < MAX_SPRITES) + { + struct Sprite *sprite = &gSprites[sSpriteOrder[i]]; + if (sprite->inUse && !sprite->invisible && AddSpriteToOamBuffer(sprite, &oamIndex)) + return; + i++; + } + + while (oamIndex < gOamLimit) + { + gMain.oamBuffer[oamIndex] = gDummyOamData; + oamIndex++; + } +} + +u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + s16 i; + + for (i = MAX_SPRITES - 1; i > -1; i--) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)) +{ + u8 index = CreateSprite(&gDummySpriteTemplate, 0, 0, 31); + + if (index == MAX_SPRITES) + { + return MAX_SPRITES; + } + else + { + gSprites[index].invisible = TRUE; + gSprites[index].callback = callback; + return index; + } +} + +u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + struct Sprite *sprite = &gSprites[index]; + + ResetSprite(sprite); + + sprite->inUse = TRUE; + sprite->animBeginning = TRUE; + sprite->affineAnimBeginning = TRUE; + sprite->usingSheet = TRUE; + + sprite->subpriority = subpriority; + sprite->oam = *template->oam; + sprite->anims = template->anims; + sprite->affineAnims = template->affineAnims; + sprite->template = template; + sprite->callback = template->callback; + sprite->pos1.x = x; + sprite->pos1.y = y; + + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + + if (template->tileTag == 0xFFFF) + { + s16 tileNum; + sprite->images = template->images; + tileNum = AllocSpriteTiles((u8)(sprite->images->size / TILE_SIZE_4BPP)); + if (tileNum == -1) + { + ResetSprite(sprite); + return MAX_SPRITES; + } + sprite->oam.tileNum = tileNum; + sprite->usingSheet = FALSE; + sprite->sheetTileStart = 0; + } + else + { + sprite->sheetTileStart = GetSpriteTileStartByTag(template->tileTag); + SetSpriteSheetFrameTileNum(sprite); + } + + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + InitSpriteAffineAnim(sprite); + + if (template->paletteTag != 0xFFFF) + sprite->oam.paletteNum = IndexOfSpritePaletteTag(template->paletteTag); + + return index; +} + +u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (!gSprites[i].inUse) + { + u8 index = CreateSpriteAt(i, template, x, y, subpriority); + + if (index == MAX_SPRITES) + return MAX_SPRITES; + + gSprites[i].callback(sprite); + + if (gSprites[i].inUse) + AnimateSprite(sprite); + + return index; + } + } + + return MAX_SPRITES; +} + +void DestroySprite(struct Sprite *sprite) +{ + if (sprite->inUse) + { + if (!sprite->usingSheet) + { + u16 i; + u16 tileEnd = (sprite->images->size / TILE_SIZE_4BPP) + sprite->oam.tileNum; + for (i = sprite->oam.tileNum; i < tileEnd; i++) + FREE_SPRITE_TILE(i); + } + ResetSprite(sprite); + } +} + +void ResetOamRange(u8 a, u8 b) +{ + u8 i; + + for (i = a; i < b; i++) + { + gMain.oamBuffer[i] = *(struct OamData *)&gDummyOamData; + } +} + +void LoadOam(void) +{ + if (!gMain.oamLoadDisabled) + CpuCopy32(gMain.oamBuffer, (void *)OAM, sizeof(gMain.oamBuffer)); +} + +void ClearSpriteCopyRequests(void) +{ + u8 i; + + sShouldProcessSpriteCopyRequests = FALSE; + sSpriteCopyRequestCount = 0; + + for (i = 0; i < MAX_SPRITE_COPY_REQUESTS; i++) + { + sSpriteCopyRequests[i].src = 0; + sSpriteCopyRequests[i].dest = 0; + sSpriteCopyRequests[i].size = 0; + } +} + +void ResetOamMatrices(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + // set to identity matrix + gOamMatrices[i].a = 0x0100; + gOamMatrices[i].b = 0x0000; + gOamMatrices[i].c = 0x0000; + gOamMatrices[i].d = 0x0100; + } +} + +void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d) +{ + gOamMatrices[matrixNum].a = a; + gOamMatrices[matrixNum].b = b; + gOamMatrices[matrixNum].c = c; + gOamMatrices[matrixNum].d = d; +} + +void ResetSprite(struct Sprite *sprite) +{ + *sprite = sDummySprite; +} + +void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode) +{ + u8 x = sCenterToCornerVecTable[shape][size][0]; + u8 y = sCenterToCornerVecTable[shape][size][1]; + + if (affineMode & ST_OAM_AFFINE_DOUBLE_MASK) + { + x *= 2; + y *= 2; + } + + sprite->centerToCornerVecX = x; + sprite->centerToCornerVecY = y; +} + +s16 AllocSpriteTiles(u16 tileCount) +{ + u16 i; + s16 start; + u16 numTilesFound; + + if (tileCount == 0) + { + // Free all unreserved tiles if the tile count is 0. + for (i = gReservedSpriteTileCount; i < TOTAL_OBJ_TILE_COUNT; i++) + FREE_SPRITE_TILE(i); + + return 0; + } + + i = gReservedSpriteTileCount; + + for (;;) + { + while (SPRITE_TILE_IS_ALLOCATED(i)) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + } + + start = i; + numTilesFound = 1; + + while (numTilesFound != tileCount) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + + if (!SPRITE_TILE_IS_ALLOCATED(i)) + numTilesFound++; + else + break; + } + + if (numTilesFound == tileCount) + break; + } + + for (i = start; i < tileCount + start; i++) + ALLOC_SPRITE_TILE(i); + + return start; +} + +u8 SpriteTileAllocBitmapOp(u16 bit, u8 op) +{ + u8 index = bit / 8; + u8 shift = bit % 8; + u8 val = bit % 8; + u8 retVal = 0; + + if (op == 0) + { + val = ~(1 << val); + sSpriteTileAllocBitmap[index] &= val; + } + else if (op == 1) + { + val = (1 << val); + sSpriteTileAllocBitmap[index] |= val; + } + else + { + retVal = 1 << shift; + retVal &= sSpriteTileAllocBitmap[index]; + } + + return retVal; +} + +void SpriteCallbackDummy(struct Sprite *sprite) +{ +} + +void ProcessSpriteCopyRequests(void) +{ + if (sShouldProcessSpriteCopyRequests) + { + u8 i = 0; + + while (sSpriteCopyRequestCount > 0) + { + CpuCopy16(sSpriteCopyRequests[i].src, sSpriteCopyRequests[i].dest, sSpriteCopyRequests[i].size); + sSpriteCopyRequestCount--; + i++; + } + + sShouldProcessSpriteCopyRequests = FALSE; + } +} + +void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images) +{ + if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + sSpriteCopyRequests[sSpriteCopyRequestCount].src = images[index].data; + sSpriteCopyRequests[sSpriteCopyRequestCount].dest = (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileNum; + sSpriteCopyRequests[sSpriteCopyRequestCount].size = images[index].size; + sSpriteCopyRequestCount++; + } +} + +void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size) +{ + if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + sSpriteCopyRequests[sSpriteCopyRequestCount].src = src; + sSpriteCopyRequests[sSpriteCopyRequestCount].dest = dest; + sSpriteCopyRequests[sSpriteCopyRequestCount].size = size; + sSpriteCopyRequestCount++; + } +} + +void CopyFromSprites(u8 *dest) +{ + u32 i; + u8 *src = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + dest++; + src++; + } +} + +void CopyToSprites(u8 *src) +{ + u32 i; + u8 *dest = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + src++; + dest++; + } +} + +void ResetAllSprites(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + ResetSprite(&gSprites[i]); + sSpriteOrder[i] = i; + } + + ResetSprite(&gSprites[i]); +} + +// UB: template pointer may point to freed temporary storage +void FreeSpriteTiles(struct Sprite *sprite) +{ + if (sprite->template->tileTag != 0xFFFF) + FreeSpriteTilesByTag(sprite->template->tileTag); +} + +// UB: template pointer may point to freed temporary storage +void FreeSpritePalette(struct Sprite *sprite) +{ + FreeSpritePaletteByTag(sprite->template->paletteTag); +} + +void FreeSpriteOamMatrix(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + FreeOamMatrix(sprite->oam.matrixNum); + sprite->oam.affineMode = ST_OAM_AFFINE_OFF; + } +} + +void DestroySpriteAndFreeResources(struct Sprite *sprite) +{ + FreeSpriteTiles(sprite); + FreeSpritePalette(sprite); + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); +} + +void AnimateSprite(struct Sprite *sprite) +{ + sAnimFuncs[sprite->animBeginning](sprite); + + if (!gAffineAnimsDisabled) + sAffineAnimFuncs[sprite->affineAnimBeginning](sprite); +} + +void BeginAnim(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = 0; + sprite->animEnded = FALSE; + sprite->animLoopCounter = 0; + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + + if (imageValue != -1) + { + sprite->animBeginning = FALSE; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); + } +} + +void ContinueAnim(struct Sprite *sprite) +{ + if (sprite->animDelayCounter) + { + u8 hFlip; + u8 vFlip; + DecrementAnimDelayCounter(sprite); + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + } + else if (!sprite->animPaused) + { + s16 type; + s16 funcIndex; + sprite->animCmdIndex++; + type = sprite->anims[sprite->animNum][sprite->animCmdIndex].type; + funcIndex = 3; + if (type < 0) + funcIndex = type + 3; + sAnimCmdFuncs[funcIndex](sprite); + } +} + +void AnimCmd_frame(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +void AnimCmd_end(struct Sprite *sprite) +{ + sprite->animCmdIndex--; + sprite->animEnded = TRUE; +} + +void AnimCmd_jump(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = sprite->anims[sprite->animNum][sprite->animCmdIndex].jump.target; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +void AnimCmd_loop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + ContinueAnimLoop(sprite); + else + BeginAnimLoop(sprite); +} + +void BeginAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter = sprite->anims[sprite->animNum][sprite->animCmdIndex].loop.count; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +void ContinueAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter--; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +void JumpToTopOfAnimLoop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + { + sprite->animCmdIndex--; + + while (sprite->anims[sprite->animNum][sprite->animCmdIndex - 1].type != -3) + { + if (sprite->animCmdIndex == 0) + break; + sprite->animCmdIndex--; + } + + sprite->animCmdIndex--; + } +} + +void BeginAffineAnim(struct Sprite *sprite) +{ + if ((sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) && sprite->affineAnims[0][0].type != 32767) + { + struct AffineAnimFrameCmd frameCmd; + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateRestartAnim(matrixNum); + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + sprite->affineAnimBeginning = FALSE; + sprite->affineAnimEnded = FALSE; + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; + if (sprite->flags_f) + obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); + } +} + +void ContinueAffineAnim(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + u8 matrixNum = GetSpriteMatrixNum(sprite); + + if (sAffineAnimStates[matrixNum].delayCounter) + AffineAnimDelay(matrixNum, sprite); + else if (sprite->affineAnimPaused) + return; + else + { + s16 type; + s16 funcIndex; + sAffineAnimStates[matrixNum].animCmdIndex++; + type = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].type; + funcIndex = 3; + if (type >= 32765) + funcIndex = type - 32765; + sAffineAnimCmdFuncs[funcIndex](matrixNum, sprite); + } + if (sprite->flags_f) + obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); + } +} + +void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite) +{ + if (!DecrementAffineAnimDelayCounter(sprite, matrixNum)) + { + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &frameCmd); + } +} + +void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + ContinueAffineAnimLoop(matrixNum, sprite); + else + BeginAffineAnimLoop(matrixNum, sprite); +} + +void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].loop.count; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter--; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + { + sAffineAnimStates[matrixNum].animCmdIndex--; + + while (sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex - 1].type != 32765) + { + if (sAffineAnimStates[matrixNum].animCmdIndex == 0) + break; + sAffineAnimStates[matrixNum].animCmdIndex--; + } + + sAffineAnimStates[matrixNum].animCmdIndex--; + } +} + +void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + sAffineAnimStates[matrixNum].animCmdIndex = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].jump.target; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + sprite->affineAnimEnded = TRUE; + sAffineAnimStates[matrixNum].animCmdIndex--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); +} + +void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix) +{ + gOamMatrices[destMatrixIndex].a = srcMatrix->a; + gOamMatrices[destMatrixIndex].b = srcMatrix->b; + gOamMatrices[destMatrixIndex].c = srcMatrix->c; + gOamMatrices[destMatrixIndex].d = srcMatrix->d; +} + +u8 GetSpriteMatrixNum(struct Sprite *sprite) +{ + u8 matrixNum = 0; + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + matrixNum = sprite->oam.matrixNum; + return matrixNum; +} + +void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3) +{ + sprite->data[6] = a2; + sprite->data[7] = a3; + sprite->flags_f = 1; +} + +s32 sub_8007E28(s32 a0, s32 a1, s32 a2) +{ + s32 subResult, var1; + + subResult = a1 - a0; + if (subResult < 0) + var1 = -(subResult) >> 9; + else + var1 = -(subResult >> 9); + return a2 - ((u32)(a2 * a1) / (u32)(a0) + var1); +} + +void obj_update_pos2(struct Sprite *sprite, s32 a1, s32 a2) +{ + s32 var0, var1, var2; + + u32 matrixNum = sprite->oam.matrixNum; + if (a1 != 0x800) + { + var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].width; + var1 = var0 << 8; + var2 = (var0 << 16) / gOamMatrices[matrixNum].a; + sprite->pos2.x = sub_8007E28(var1, var2, a1); + } + if (a2 != 0x800) + { + var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].height; + var1 = var0 << 8; + var2 = (var0 << 16) / gOamMatrices[matrixNum].d; + sprite->pos2.y = sub_8007E28(var1, var2, a2); + } +} + +void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip) +{ + sprite->oam.matrixNum &= 0x7; + sprite->oam.matrixNum |= (((hFlip ^ sprite->hFlip) & 1) << 3); + sprite->oam.matrixNum |= (((vFlip ^ sprite->vFlip) & 1) << 4); +} + +void AffineAnimStateRestartAnim(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; +} + +void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum) +{ + sAffineAnimStates[matrixNum].animNum = animNum; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +void AffineAnimStateReset(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animNum = 0; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + sAffineAnimStates[matrixNum].xScale = frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale = frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = frameCmd->rotation << 8; +} + +void DecrementAnimDelayCounter(struct Sprite *sprite) +{ + if (!sprite->animPaused) + sprite->animDelayCounter--; +} + +bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum) +{ + if (!sprite->affineAnimPaused) + --sAffineAnimStates[matrixNum].delayCounter; + return sprite->affineAnimPaused; +} + +void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + sAffineAnimStates[matrixNum].xScale += frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale += frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = (sAffineAnimStates[matrixNum].rotation + (frameCmd->rotation << 8)) & ~0xFF; + srcData.xScale = ConvertScaleParam(sAffineAnimStates[matrixNum].xScale); + srcData.yScale = ConvertScaleParam(sAffineAnimStates[matrixNum].yScale); + srcData.rotation = sAffineAnimStates[matrixNum].rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +s16 ConvertScaleParam(s16 scale) +{ + s32 val = 0x10000; + return SAFE_DIV(val, scale); +} + +void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd) +{ + frameCmd->xScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.xScale; + frameCmd->yScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.yScale; + frameCmd->rotation = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.rotation; + frameCmd->duration = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.duration; +} + +void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + + if (frameCmd->duration) + { + frameCmd->duration--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, frameCmd); + } + else + { + ApplyAffineAnimFrameAbsolute(matrixNum, frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); + } +} + +void StartSpriteAnim(struct Sprite *sprite, u8 animNum) +{ + sprite->animNum = animNum; + sprite->animBeginning = TRUE; + sprite->animEnded = FALSE; +} + +void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + if (sprite->animNum != animNum) + StartSpriteAnim(sprite, animNum); +} + +void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex) +{ + u8 temp = sprite->animPaused; + sprite->animCmdIndex = animCmdIndex - 1; + sprite->animDelayCounter = 0; + sprite->animBeginning = FALSE; + sprite->animEnded = FALSE; + sprite->animPaused = FALSE; + ContinueAnim(sprite); + if (sprite->animDelayCounter) + sprite->animDelayCounter++; + sprite->animPaused = temp; +} + +void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateStartAnim(matrixNum, animNum); + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + StartSpriteAffineAnim(sprite, animNum); +} + +void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + sAffineAnimStates[matrixNum].animNum = animNum; + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + ChangeSpriteAffineAnim(sprite, animNum); +} + +void SetSpriteSheetFrameTileNum(struct Sprite *sprite) +{ + if (sprite->usingSheet) + { + s16 tileOffset = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + if (tileOffset < 0) + tileOffset = 0; + sprite->oam.tileNum = sprite->sheetTileStart + tileOffset; + } +} + +void ResetAffineAnimData(void) +{ + u8 i; + + gAffineAnimsDisabled = FALSE; + gOamMatrixAllocBitmap = 0; + + ResetOamMatrices(); + + for (i = 0; i < OAM_MATRIX_COUNT; i++) + AffineAnimStateReset(i); +} + +u8 AllocOamMatrix(void) +{ + u8 i = 0; + u32 bit = 1; + u32 bitmap = gOamMatrixAllocBitmap; + + while (i < OAM_MATRIX_COUNT) + { + if (!(bitmap & bit)) + { + gOamMatrixAllocBitmap |= bit; + return i; + } + + i++; + bit <<= 1; + } + + return 0xFF; +} + +void FreeOamMatrix(u8 matrixNum) +{ + u8 i = 0; + u32 bit = 1; + + while (i < matrixNum) + { + i++; + bit <<= 1; + } + + gOamMatrixAllocBitmap &= ~bit; + SetOamMatrix(matrixNum, 0x100, 0, 0, 0x100); +} + +void InitSpriteAffineAnim(struct Sprite *sprite) +{ + u8 matrixNum = AllocOamMatrix(); + if (matrixNum != 0xFF) + { + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + sprite->oam.matrixNum = matrixNum; + sprite->affineAnimBeginning = TRUE; + AffineAnimStateReset(matrixNum); + } +} + +void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + srcData.xScale = ConvertScaleParam(xScale); + srcData.yScale = ConvertScaleParam(yScale); + srcData.rotation = rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +u16 LoadSpriteSheet(const struct SpriteSheet *sheet) +{ + s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); + + if (tileStart < 0) + { + return 0; + } + else + { + AllocSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); + CpuCopy16(sheet->data, (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileStart, sheet->size); + return (u16)tileStart; + } +} + +void LoadSpriteSheets(const struct SpriteSheet *sheets) +{ + u8 i; + for (i = 0; sheets[i].data != NULL; i++) + LoadSpriteSheet(&sheets[i]); +} + +void FreeSpriteTilesByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index != 0xFF) + { + u16 i; + u16 *rangeStarts; + u16 *rangeCounts; + u16 start; + u16 count; + rangeStarts = sSpriteTileRanges; + start = rangeStarts[index * 2]; + rangeCounts = sSpriteTileRanges + 1; + count = rangeCounts[index * 2]; + + for (i = start; i < start + count; i++) + FREE_SPRITE_TILE(i); + + sSpriteTileRangeTags[index] = 0xFFFF; + } +} + +void FreeSpriteTileRanges(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + sSpriteTileRangeTags[i] = 0xFFFF; + SET_SPRITE_TILE_RANGE(i, 0, 0); + } +} + +u16 GetSpriteTileStartByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index == 0xFF) + return 0xFFFF; + return sSpriteTileRanges[index * 2]; +} + +u8 IndexOfSpriteTileTag(u16 tag) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (sSpriteTileRangeTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpriteTileTagByTileStart(u16 start) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + if (sSpriteTileRangeTags[i] != 0xFFFF && sSpriteTileRanges[i * 2] == start) + return sSpriteTileRangeTags[i]; + } + + return 0xFFFF; +} + +void AllocSpriteTileRange(u16 tag, u16 start, u16 count) +{ + u8 freeIndex = IndexOfSpriteTileTag(0xFFFF); + sSpriteTileRangeTags[freeIndex] = tag; + SET_SPRITE_TILE_RANGE(freeIndex, start, count); +} + +void FreeAllSpritePalettes(void) +{ + u8 i; + gReservedSpritePaletteCount = 0; + for (i = 0; i < 16; i++) + sSpritePaletteTags[i] = 0xFFFF; +} + +u8 LoadSpritePalette(const struct SpritePalette *palette) +{ + u8 index = IndexOfSpritePaletteTag(palette->tag); + + if (index != 0xFF) + return index; + + index = IndexOfSpritePaletteTag(0xFFFF); + + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = palette->tag; + DoLoadSpritePalette(palette->data, index * 16); + return index; + } +} + +void LoadSpritePalettes(const struct SpritePalette *palettes) +{ + u8 i; + for (i = 0; palettes[i].data != NULL; i++) + if (LoadSpritePalette(&palettes[i]) == 0xFF) + break; +} + +void DoLoadSpritePalette(const u16 *src, u16 paletteOffset) +{ + LoadPalette(src, paletteOffset + 0x100, 32); +} + +u8 AllocSpritePalette(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(0xFFFF); + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = tag; + return index; + } +} + +u8 IndexOfSpritePaletteTag(u16 tag) +{ + u8 i; + for (i = gReservedSpritePaletteCount; i < 16; i++) + if (sSpritePaletteTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum) +{ + return sSpritePaletteTags[paletteNum]; +} + +void FreeSpritePaletteByTag(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(tag); + if (index != 0xFF) + sSpritePaletteTags[index] = 0xFFFF; +} + +void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables) +{ + sprite->subspriteTables = subspriteTables; + sprite->subspriteTableNum = 0; + sprite->subspriteMode = SUBSPRITES_ON; +} + +bool8 AddSpriteToOamBuffer(struct Sprite *sprite, u8 *oamIndex) +{ + if (*oamIndex >= gOamLimit) + return 1; + + if (!sprite->subspriteTables || sprite->subspriteMode == SUBSPRITES_OFF) + { + gMain.oamBuffer[*oamIndex] = sprite->oam; + (*oamIndex)++; + return 0; + } + else + { + return AddSubspritesToOamBuffer(sprite, &gMain.oamBuffer[*oamIndex], oamIndex); + } +} + +bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex) +{ + const struct SubspriteTable *subspriteTable; + struct OamData *oam; + + if (*oamIndex >= gOamLimit) + return 1; + + subspriteTable = &sprite->subspriteTables[sprite->subspriteTableNum]; + oam = &sprite->oam; + + if (!subspriteTable || !subspriteTable->subsprites) + { + *destOam = *oam; + (*oamIndex)++; + return 0; + } + else + { + u16 tileNum; + u16 baseX; + u16 baseY; + u8 subspriteCount; + u8 hFlip; + u8 vFlip; + u8 i; + + tileNum = oam->tileNum; + subspriteCount = subspriteTable->subspriteCount; + hFlip = ((s32)oam->matrixNum >> 3) & 1; + vFlip = ((s32)oam->matrixNum >> 4) & 1; + baseX = oam->x - sprite->centerToCornerVecX; + baseY = oam->y - sprite->centerToCornerVecY; + + for (i = 0; i < subspriteCount; i++, (*oamIndex)++) + { + u16 x; + u16 y; + + if (*oamIndex >= gOamLimit) + return 1; + + x = subspriteTable->subsprites[i].x; + y = subspriteTable->subsprites[i].y; + + if (hFlip) + { + s8 width = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].width; + s16 right = x; + right += width; + x = right; + x = ~x + 1; + } + + if (vFlip) + { + s8 height = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].height; + s16 bottom = y; + bottom += height; + y = bottom; + y = ~y + 1; + } + + destOam[i] = *oam; + destOam[i].shape = subspriteTable->subsprites[i].shape; + destOam[i].size = subspriteTable->subsprites[i].size; + destOam[i].x = (s16)baseX + (s16)x; + destOam[i].y = baseY + y; + destOam[i].tileNum = tileNum + subspriteTable->subsprites[i].tileOffset; + + if (sprite->subspriteMode != SUBSPRITES_IGNORE_PRIORITY) + destOam[i].priority = subspriteTable->subsprites[i].priority; + } + } + + return 0; +} diff --git a/src/string_util.c b/src/string_util.c new file mode 100644 index 000000000..92f8eea5a --- /dev/null +++ b/src/string_util.c @@ -0,0 +1,781 @@ +#include "global.h" +#include "string_util.h" +#include "text.h" +#include "strings.h" + +EWRAM_DATA u8 gStringVar1[0x100] = {0}; +EWRAM_DATA u8 gStringVar2[0x100] = {0}; +EWRAM_DATA u8 gStringVar3[0x100] = {0}; +EWRAM_DATA u8 gStringVar4[0x3E8] = {0}; +EWRAM_DATA static u8 sUnknownStringVar[16] = {0}; + +static const u8 sDigits[] = __("0123456789ABCDEF"); + +static const s32 sPowersOfTen[] = +{ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, +}; + +u8 *StringCopy10(u8 *dest, const u8 *src) +{ + u8 i; + u32 limit = 10; + + for (i = 0; i < limit; i++) + { + dest[i] = src[i]; + + if (dest[i] == EOS) + return &dest[i]; + } + + dest[i] = EOS; + return &dest[i]; +} + +u8 *StringGetEnd10(u8 *str) +{ + u8 i; + u32 limit = 10; + + for (i = 0; i < limit; i++) + if (str[i] == EOS) + return &str[i]; + + str[i] = EOS; + return &str[i]; +} + +u8 *StringCopy7(u8 *dest, const u8 *src) +{ + s32 i; + s32 limit = 7; + + for (i = 0; i < limit; i++) + { + dest[i] = src[i]; + + if (dest[i] == EOS) + return &dest[i]; + } + + dest[i] = EOS; + return &dest[i]; +} + +u8 *StringCopy(u8 *dest, const u8 *src) +{ + while (*src != EOS) + { + *dest = *src; + dest++; + src++; + } + + *dest = EOS; + return dest; +} + +u8 *StringAppend(u8 *dest, const u8 *src) +{ + while (*dest != EOS) + dest++; + + return StringCopy(dest, src); +} + +u8 *StringCopyN(u8 *dest, const u8 *src, u8 n) +{ + u16 i; + + for (i = 0; i < n; i++) + dest[i] = src[i]; + + return &dest[n]; +} + +u8 *StringAppendN(u8 *dest, const u8 *src, u8 n) +{ + while (*dest != EOS) + dest++; + + return StringCopyN(dest, src, n); +} + +u16 StringLength(const u8 *str) +{ + u16 length = 0; + + while (str[length] != EOS) + length++; + + return length; +} + +s32 StringCompare(const u8 *str1, const u8 *str2) +{ + while (*str1 == *str2) + { + if (*str1 == EOS) + return 0; + str1++; + str2++; + } + + return *str1 - *str2; +} + +s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n) +{ + while (*str1 == *str2) + { + if (*str1 == EOS) + return 0; + str1++; + str2++; + if (--n == 0) + return 0; + } + + return *str1 - *str2; +} + +bool8 IsStringLengthAtLeast(const u8 *str, s32 n) +{ + u8 i; + + for (i = 0; i < n; i++) + if (str[i] && str[i] != EOS) + return TRUE; + + return FALSE; +} + +u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + s32 powerOfTen; + s32 largestPowerOfTen = sPowersOfTen[n - 1]; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) + { + u8 c; + u16 digit = value / powerOfTen; + s32 temp = value - (powerOfTen * digit); + + if (state == WRITING_DIGITS) + { + u8 *out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfTen == 1) + { + u8 *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + s32 powerOfTen; + s32 largestPowerOfTen = sPowersOfTen[n - 1]; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) + { + u8 c; + u16 digit = value / powerOfTen; + u32 temp = value - (powerOfTen * digit); + + if (state == WRITING_DIGITS) + { + u8 *out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfTen == 1) + { + u8 *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + u8 i; + s32 powerOfSixteen; + s32 largestPowerOfSixteen = 1; + + for (i = 1; i < n; i++) + largestPowerOfSixteen *= 16; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfSixteen = largestPowerOfSixteen; powerOfSixteen > 0; powerOfSixteen /= 16) + { + u8 c; + u32 digit = value / powerOfSixteen; + s32 temp = value % powerOfSixteen; + + if (state == WRITING_DIGITS) + { + char *out = dest++; + + if (digit <= 0xF) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfSixteen == 1) + { + char *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 0xF) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *StringExpandPlaceholders(u8 *dest, const u8 *src) +{ + for (;;) + { + u8 c = *src++; + u8 placeholderId; + const u8 *expandedString; + + switch (c) + { + case PLACEHOLDER_BEGIN: + placeholderId = *src++; + expandedString = GetExpandedPlaceholder(placeholderId); + dest = StringExpandPlaceholders(dest, expandedString); + break; + case EXT_CTRL_CODE_BEGIN: + *dest++ = c; + c = *src++; + *dest++ = c; + + switch (c) + { + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_FILL_WINDOW: + case EXT_CTRL_CODE_JPN: + case EXT_CTRL_CODE_ENG: + case EXT_CTRL_CODE_PAUSE_MUSIC: + case EXT_CTRL_CODE_RESUME_MUSIC: + break; + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + *dest++ = *src++; + case EXT_CTRL_CODE_PLAY_BGM: + *dest++ = *src++; + default: + *dest++ = *src++; + } + break; + case EOS: + *dest = EOS; + return dest; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + case CHAR_NEWLINE: + default: + *dest++ = c; + } + } +} + +u8 *StringBraille(u8 *dest, const u8 *src) +{ + const u8 setBrailleFont[] = { + EXT_CTRL_CODE_BEGIN, + EXT_CTRL_CODE_SIZE, + 6, + EOS + }; + const u8 gotoLine2[] = { + CHAR_NEWLINE, + EXT_CTRL_CODE_BEGIN, + EXT_CTRL_CODE_SHIFT_DOWN, + 2, + EOS + }; + + dest = StringCopy(dest, setBrailleFont); + + for (;;) + { + u8 c = *src++; + + switch (c) + { + case EOS: + *dest = c; + return dest; + case CHAR_NEWLINE: + dest = StringCopy(dest, gotoLine2); + break; + default: + *dest++ = c; + *dest++ = c + 0x40; + break; + } + } +} + +static const u8 *ExpandPlaceholder_UnknownStringVar(void) +{ + return sUnknownStringVar; +} + +static const u8 *ExpandPlaceholder_PlayerName(void) +{ + return gSaveBlock2Ptr->playerName; +} + +static const u8 *ExpandPlaceholder_StringVar1(void) +{ + return gStringVar1; +} + +static const u8 *ExpandPlaceholder_StringVar2(void) +{ + return gStringVar2; +} + +static const u8 *ExpandPlaceholder_StringVar3(void) +{ + return gStringVar3; +} + +static const u8 *ExpandPlaceholder_KunChan(void) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + return gText_ExpandedPlaceholder_Kun; + else + return gText_ExpandedPlaceholder_Chan; +} + +static const u8 *ExpandPlaceholder_RivalName(void) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + return gText_ExpandedPlaceholder_May; + else + return gText_ExpandedPlaceholder_Brendan; +} + +static const u8 *ExpandPlaceholder_Version(void) +{ + return gText_ExpandedPlaceholder_Emerald; +} + +static const u8 *ExpandPlaceholder_Aqua(void) +{ + return gText_ExpandedPlaceholder_Aqua; +} + +static const u8 *ExpandPlaceholder_Magma(void) +{ + return gText_ExpandedPlaceholder_Magma; +} + +static const u8 *ExpandPlaceholder_Archie(void) +{ + return gText_ExpandedPlaceholder_Archie; +} + +static const u8 *ExpandPlaceholder_Maxie(void) +{ + return gText_ExpandedPlaceholder_Maxie; +} + +static const u8 *ExpandPlaceholder_Kyogre(void) +{ + return gText_ExpandedPlaceholder_Kyogre; +} + +static const u8 *ExpandPlaceholder_Groudon(void) +{ + return gText_ExpandedPlaceholder_Groudon; +} + +const u8 *GetExpandedPlaceholder(u32 id) +{ + typedef const u8 *(*ExpandPlaceholderFunc)(void); + + static const ExpandPlaceholderFunc funcs[] = + { + [PLACEHOLDER_ID_UNKNOWN] = ExpandPlaceholder_UnknownStringVar, + [PLACEHOLDER_ID_PLAYER] = ExpandPlaceholder_PlayerName, + [PLACEHOLDER_ID_STRING_VAR_1] = ExpandPlaceholder_StringVar1, + [PLACEHOLDER_ID_STRING_VAR_2] = ExpandPlaceholder_StringVar2, + [PLACEHOLDER_ID_STRING_VAR_3] = ExpandPlaceholder_StringVar3, + [PLACEHOLDER_ID_KUN] = ExpandPlaceholder_KunChan, + [PLACEHOLDER_ID_RIVAL] = ExpandPlaceholder_RivalName, + [PLACEHOLDER_ID_VERSION] = ExpandPlaceholder_Version, + [PLACEHOLDER_ID_AQUA] = ExpandPlaceholder_Aqua, + [PLACEHOLDER_ID_MAGMA] = ExpandPlaceholder_Magma, + [PLACEHOLDER_ID_ARCHIE] = ExpandPlaceholder_Archie, + [PLACEHOLDER_ID_MAXIE] = ExpandPlaceholder_Maxie, + [PLACEHOLDER_ID_KYOGRE] = ExpandPlaceholder_Kyogre, + [PLACEHOLDER_ID_GROUDON] = ExpandPlaceholder_Groudon, + }; + + if (id >= ARRAY_COUNT(funcs)) + return gText_ExpandedPlaceholder_Empty; + else + return funcs[id](); +} + +u8 *StringFill(u8 *dest, u8 c, u16 n) +{ + u16 i; + + for (i = 0; i < n; i++) + *dest++ = c; + + *dest = EOS; + return dest; +} + +u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n) +{ + while (*src != EOS) + { + *dest++ = *src++; + + if (n) + n--; + } + + n--; + + while (n != (u16)-1) + { + *dest++ = c; + n--; + } + + *dest = EOS; + return dest; +} + +u8 *StringFillWithTerminator(u8 *dest, u16 n) +{ + return StringFill(dest, EOS, n); +} + +u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n) +{ + u32 i; + + for (i = n - 1; i != (u32)-1; i--) + { + if (*src == EOS) + { + break; + } + else + { + *dest++ = *src++; + if (*(src - 1) == CHAR_EXTRA_SYMBOL) + *dest++ = *src++; + } + } + + *dest = EOS; + return dest; +} + +u32 StringLength_Multibyte(const u8 *str) +{ + u32 length = 0; + + while (*str != EOS) + { + if (*str == CHAR_EXTRA_SYMBOL) + str++; + str++; + length++; + } + + return length; +} + +u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color) +{ + *dest = EXT_CTRL_CODE_BEGIN; + dest++; + + switch (colorType) + { + case 0: + *dest = EXT_CTRL_CODE_COLOR; + dest++; + break; + case 1: + *dest = EXT_CTRL_CODE_SHADOW; + dest++; + break; + case 2: + *dest = EXT_CTRL_CODE_HIGHLIGHT; + dest++; + break; + } + + *dest = color; + dest++; + *dest = EOS; + return dest; +} + +bool32 IsStringJapanese(u8 *str) +{ + while (*str != EOS) + { + if (*str < CHAR_0) + if (*str != CHAR_SPACE) + return TRUE; + str++; + } + + return FALSE; +} + +bool32 sub_800924C(u8 *str, s32 n) +{ + s32 i; + + for (i = 0; *str != EOS && i < n; i++) + { + if (*str < CHAR_0) + if (*str != CHAR_SPACE) + return TRUE; + str++; + } + + return FALSE; +} + +u8 GetExtCtrlCodeLength(u8 code) +{ + static const u8 lengths[] = + { + [0] = 1, + [EXT_CTRL_CODE_COLOR] = 2, + [EXT_CTRL_CODE_HIGHLIGHT] = 2, + [EXT_CTRL_CODE_SHADOW] = 2, + [EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW] = 4, + [EXT_CTRL_CODE_PALETTE] = 2, + [EXT_CTRL_CODE_SIZE] = 2, + [EXT_CTRL_CODE_RESET_SIZE] = 1, + [EXT_CTRL_CODE_PAUSE] = 2, + [EXT_CTRL_CODE_PAUSE_UNTIL_PRESS] = 1, + [EXT_CTRL_CODE_WAIT_SE] = 1, + [EXT_CTRL_CODE_PLAY_BGM] = 3, + [EXT_CTRL_CODE_ESCAPE] = 2, + [EXT_CTRL_CODE_SHIFT_TEXT] = 2, + [EXT_CTRL_CODE_SHIFT_DOWN] = 2, + [EXT_CTRL_CODE_FILL_WINDOW] = 1, + [EXT_CTRL_CODE_PLAY_SE] = 3, + [EXT_CTRL_CODE_CLEAR] = 2, + [EXT_CTRL_CODE_SKIP] = 2, + [EXT_CTRL_CODE_CLEAR_TO] = 2, + [EXT_CTRL_CODE_MIN_LETTER_SPACING] = 2, + [EXT_CTRL_CODE_JPN] = 1, + [EXT_CTRL_CODE_ENG] = 1, + [EXT_CTRL_CODE_PAUSE_MUSIC] = 1, + [EXT_CTRL_CODE_RESUME_MUSIC] = 1, + }; + + u8 length = 0; + if (code < ARRAY_COUNT(lengths)) + length = lengths[code]; + return length; +} + +static const u8 *SkipExtCtrlCode(const u8 *s) +{ + while (*s == EXT_CTRL_CODE_BEGIN) + { + s++; + s += GetExtCtrlCodeLength(*s); + } + + return s; +} + +s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2) +{ + s32 retVal = 0; + + while (1) + { + str1 = SkipExtCtrlCode(str1); + str2 = SkipExtCtrlCode(str2); + + if (*str1 > *str2) + break; + + if (*str1 < *str2) + { + retVal = -1; + if (*str2 == EOS) + retVal = 1; + } + + if (*str1 == EOS) + return retVal; + + str1++; + str2++; + } + + retVal = 1; + + if (*str1 == EOS) + retVal = -1; + + return retVal; +} + +void ConvertInternationalString(u8 *s, u8 language) +{ + if (language == LANGUAGE_JAPANESE) + { + u8 i; + + StripExtCtrlCodes(s); + i = StringLength(s); + s[i++] = EXT_CTRL_CODE_BEGIN; + s[i++] = EXT_CTRL_CODE_ENG; + s[i++] = EOS; + + i--; + + while (i != (u8)-1) + { + s[i + 2] = s[i]; + i--; + } + + s[0] = EXT_CTRL_CODE_BEGIN; + s[1] = EXT_CTRL_CODE_JPN; + } +} + +void StripExtCtrlCodes(u8 *str) +{ + u16 srcIndex = 0; + u16 destIndex = 0; + while (str[srcIndex] != EOS) + { + if (str[srcIndex] == EXT_CTRL_CODE_BEGIN) + { + srcIndex++; + srcIndex += GetExtCtrlCodeLength(str[srcIndex]); + } + else + { + str[destIndex++] = str[srcIndex++]; + } + } + str[destIndex] = EOS; +} diff --git a/src/text.c b/src/text.c new file mode 100644 index 000000000..eb993c421 --- /dev/null +++ b/src/text.c @@ -0,0 +1,1808 @@ +#include "global.h" +#include "battle.h" +#include "main.h" +#include "m4a.h" +#include "palette.h" +#include "sound.h" +#include "constants/songs.h" +#include "string_util.h" +#include "window.h" +#include "text.h" +#include "blit.h" +#include "menu.h" +#include "dynamic_placeholder_text_util.h" + +EWRAM_DATA struct TextPrinter gTempTextPrinter = {0}; +EWRAM_DATA struct TextPrinter gTextPrinters[NUM_TEXT_PRINTERS] = {0}; + +static u16 gFontHalfRowLookupTable[0x51]; +static u16 gLastTextBgColor; +static u16 gLastTextFgColor; +static u16 gLastTextShadowColor; + +const struct FontInfo *gFonts; +u8 gDisableTextPrinters; +struct TextGlyph gCurGlyph; +TextFlags gTextFlags; + +const u8 gFontHalfRowOffsets[] = +{ + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, + 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, + 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, + 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, + 0x24, 0x25, 0x26, 0x24, 0x27, 0x28, 0x29, 0x27, 0x2A, 0x2B, 0x2C, 0x2A, 0x24, 0x25, 0x26, 0x24, + 0x2D, 0x2E, 0x2F, 0x2D, 0x30, 0x31, 0x32, 0x30, 0x33, 0x34, 0x35, 0x33, 0x2D, 0x2E, 0x2F, 0x2D, + 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, + 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, + 0x3F, 0x40, 0x41, 0x3F, 0x42, 0x43, 0x44, 0x42, 0x45, 0x46, 0x47, 0x45, 0x3F, 0x40, 0x41, 0x3F, + 0x48, 0x49, 0x4A, 0x48, 0x4B, 0x4C, 0x4D, 0x4B, 0x4E, 0x4F, 0x50, 0x4E, 0x48, 0x49, 0x4A, 0x48, + 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, + 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, + 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00 +}; + +const u8 gDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow.4bpp"); +const u8 gDarkDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow_RS.4bpp"); +const u8 gUnusedFRLGBlankedDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_blanked_down_arrow.4bpp"); +const u8 gUnusedFRLGDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_down_arrow.4bpp"); +const u8 gDownArrowYCoords[] = { 0x0, 0x1, 0x2, 0x1 }; +const u8 gWindowVerticalScrollSpeeds[] = { 0x1, 0x2, 0x4, 0x0 }; + +const struct GlyphWidthFunc gGlyphWidthFuncs[] = +{ + { 0x0, GetGlyphWidthFont0 }, + { 0x1, GetGlyphWidthFont1 }, + { 0x2, GetGlyphWidthFont2 }, + { 0x3, GetGlyphWidthFont2 }, + { 0x4, GetGlyphWidthFont2 }, + { 0x5, GetGlyphWidthFont2 }, + { 0x6, GetGlyphWidthFont6 }, + { 0x7, GetGlyphWidthFont7 }, + { 0x8, GetGlyphWidthFont8 } +}; + +const struct KeypadIcon gKeypadIcons[] = +{ + [CHAR_A_BUTTON] = { 0x0, 0x8, 0xC }, + [CHAR_B_BUTTON] = { 0x1, 0x8, 0xC }, + [CHAR_L_BUTTON] = { 0x2, 0x10, 0xC }, + [CHAR_R_BUTTON] = { 0x4, 0x10, 0xC }, + [CHAR_START_BUTTON] = { 0x6, 0x18, 0xC }, + [CHAR_SELECT_BUTTON] = { 0x9, 0x18, 0xC }, + [CHAR_DPAD_UP] = { 0xC, 0x8, 0xC }, + [CHAR_DPAD_DOWN] = { 0xD, 0x8, 0xC }, + [CHAR_DPAD_LEFT] = { 0xE, 0x8, 0xC }, + [CHAR_DPAD_RIGHT] = { 0xF, 0x8, 0xC }, + [CHAR_DPAD_UPDOWN] = { 0x20, 0x8, 0xC }, + [CHAR_DPAD_LEFTRIGHT] = { 0x21, 0x8, 0xC }, + [CHAR_DPAD_NONE] = { 0x22, 0x8, 0xC } +}; + +const u8 gKeypadIconTiles[] = INCBIN_U8("graphics/fonts/keypad_icons.4bpp"); + +const struct FontInfo gFontInfos[] = +{ + { Font0Func, 0x5, 0xC, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font1Func, 0x6, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font2Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font3Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font4Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font5Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font6Func, 0x8, 0x10, 0x0, 0x8, 0x0, 0x2, 0x1, 0x3 }, + { Font7Func, 0x5, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font8Func, 0x5, 0x8, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { NULL, 0x8, 0x8, 0x0, 0x0, 0x0, 0x1, 0x2, 0xF } +}; + +const u8 gMenuCursorDimensions[][2] = +{ + { 0x8, 0xC }, + { 0x8, 0xF }, + { 0x8, 0xE }, + { 0x8, 0xE }, + { 0x8, 0xE }, + { 0x8, 0xE }, + { 0x8, 0x10 }, + { 0x8, 0xF }, + { 0x8, 0x8 }, + { 0x0, 0x0 } +}; + +const u16 gFont9JapaneseGlyphs[] = INCBIN_U16("graphics/fonts/font9.hwjpnfont"); + +extern const u16 gFont8LatinGlyphs[]; +extern const u8 gFont8LatinGlyphWidths[]; +extern const u16 gFont0LatinGlyphs[]; +extern const u8 gFont0LatinGlyphWidths[]; +extern const u16 gFont7LatinGlyphs[]; +extern const u8 gFont7LatinGlyphWidths[]; +extern const u16 gFont2LatinGlyphs[]; +extern const u8 gFont2LatinGlyphWidths[]; +extern const u16 gFont1LatinGlyphs[]; +extern const u8 gFont1LatinGlyphWidths[]; +extern const u16 gFont0JapaneseGlyphs[]; +extern const u16 gFont1JapaneseGlyphs[]; +extern const u16 gFont2JapaneseGlyphs[]; +extern const u8 gFont2JapaneseGlyphWidths[]; + +void SetFontsPointer(const struct FontInfo *fonts) +{ + gFonts = fonts; +} + +void DeactivateAllTextPrinters(void) +{ + int printer; + for (printer = 0; printer < NUM_TEXT_PRINTERS; ++printer) + gTextPrinters[printer].active = 0; +} + +u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) +{ + struct TextPrinterTemplate printerTemplate; + + printerTemplate.currentChar = str; + printerTemplate.windowId = windowId; + printerTemplate.fontId = fontId; + printerTemplate.x = x; + printerTemplate.y = y; + printerTemplate.currentX = x; + printerTemplate.currentY = y; + printerTemplate.letterSpacing = gFonts[fontId].letterSpacing; + printerTemplate.lineSpacing = gFonts[fontId].lineSpacing; + printerTemplate.unk = gFonts[fontId].unk; + printerTemplate.fgColor = gFonts[fontId].fgColor; + printerTemplate.bgColor = gFonts[fontId].bgColor; + printerTemplate.shadowColor = gFonts[fontId].shadowColor; + return AddTextPrinter(&printerTemplate, speed, callback); +} + +bool16 AddTextPrinter(struct TextPrinterTemplate *printerTemplate, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) +{ + int i; + u16 j; + + if (!gFonts) + return FALSE; + + gTempTextPrinter.active = 1; + gTempTextPrinter.state = 0; + gTempTextPrinter.textSpeed = speed; + gTempTextPrinter.delayCounter = 0; + gTempTextPrinter.scrollDistance = 0; + + for (i = 0; i < 7; i++) + { + gTempTextPrinter.subStructFields[i] = 0; + } + + gTempTextPrinter.printerTemplate = *printerTemplate; + gTempTextPrinter.callback = callback; + gTempTextPrinter.minLetterSpacing = 0; + gTempTextPrinter.japanese = 0; + + GenerateFontHalfRowLookupTable(printerTemplate->fgColor, printerTemplate->bgColor, printerTemplate->shadowColor); + if (speed != TEXT_SPEED_FF && speed != 0) + { + --gTempTextPrinter.textSpeed; + gTextPrinters[printerTemplate->windowId] = gTempTextPrinter; + } + else + { + gTempTextPrinter.textSpeed = 0; + for (j = 0; j < 0x400; ++j) + { + if (RenderFont(&gTempTextPrinter) == 1) + break; + } + + if (speed != TEXT_SPEED_FF) + CopyWindowToVram(gTempTextPrinter.printerTemplate.windowId, 2); + gTextPrinters[printerTemplate->windowId].active = 0; + } + gDisableTextPrinters = 0; + return TRUE; +} + +void RunTextPrinters(void) +{ + int i; + + if (gDisableTextPrinters == 0) + { + for (i = 0; i < NUM_TEXT_PRINTERS; ++i) + { + if (gTextPrinters[i].active) + { + u16 temp = RenderFont(&gTextPrinters[i]); + switch (temp) + { + case 0: + CopyWindowToVram(gTextPrinters[i].printerTemplate.windowId, 2); + case 3: + if (gTextPrinters[i].callback != 0) + gTextPrinters[i].callback(&gTextPrinters[i].printerTemplate, temp); + break; + case 1: + gTextPrinters[i].active = 0; + break; + } + } + } + } +} + +bool16 IsTextPrinterActive(u8 id) +{ + return gTextPrinters[id].active; +} + +u32 RenderFont(struct TextPrinter *textPrinter) +{ + u32 ret; + while (TRUE) + { + ret = gFonts[textPrinter->printerTemplate.fontId].fontFunction(textPrinter); + if (ret != 2) + return ret; + } +} + +void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor) +{ + u32 fg12, bg12, shadow12; + u32 temp; + + u16 *current = gFontHalfRowLookupTable; + + gLastTextBgColor = bgColor; + gLastTextFgColor = fgColor; + gLastTextShadowColor = shadowColor; + + bg12 = bgColor << 12; + fg12 = fgColor << 12; + shadow12 = shadowColor << 12; + + temp = (bgColor << 8) | (bgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (bgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (bgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (fgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (fgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (fgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (shadowColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (shadowColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (shadowColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (bgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (bgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (bgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (fgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (fgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (fgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (shadowColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (shadowColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (shadowColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (bgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (bgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (bgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (fgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (fgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (fgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (shadowColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (shadowColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (shadowColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; +} + +void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) +{ + *bgColor = gLastTextBgColor; + *fgColor = gLastTextFgColor; + *shadowColor = gLastTextShadowColor; +} + +void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) +{ + GenerateFontHalfRowLookupTable(*fgColor, *bgColor, *shadowColor); +} + +void DecompressGlyphTile(const void *src_, void *dest_) +{ + u32 temp; + const u16 *src = src_; + u32 *dest = dest_; + + temp = *(src++); + *(dest)++ = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); +} + +u8 GetLastTextColor(u8 colorType) +{ + switch (colorType) + { + case 0: + return gLastTextFgColor; + case 2: + return gLastTextBgColor; + case 1: + return gLastTextShadowColor; + default: + return 0; + } +} + +inline static void GLYPH_COPY(u8 *windowTiles, u32 widthOffset, u32 j, u32 i, u32 *glyphPixels, s32 width, s32 height) +{ + u32 xAdd, yAdd, pixelData, bits, toOrr, dummyX; + u8 *dst; + + xAdd = j + width; + yAdd = i + height; + dummyX = j; + for (; i < yAdd; i++) + { + pixelData = *glyphPixels++; + for (j = dummyX; j < xAdd; j++) + { + if ((toOrr = pixelData & 0xF)) + { + dst = windowTiles + ((j / 8) * 32) + ((j % 8) / 2) + ((i / 8) * widthOffset) + ((i % 8) * 4); + bits = ((j & 1) * 4); + *dst = (toOrr << bits) | (*dst & (0xF0 >> bits)); + } + pixelData >>= 4; + } + } +} + +void CopyGlyphToWindow(struct TextPrinter *textPrinter) +{ + struct Window *window; + struct WindowTemplate *template; + u32 *glyphPixels; + u32 currX, currY, widthOffset; + s32 glyphWidth, glyphHeight; + u8 *windowTiles; + + window = &gWindows[textPrinter->printerTemplate.windowId]; + template = &window->window; + + if ((glyphWidth = (template->width * 8) - textPrinter->printerTemplate.currentX) > gCurGlyph.width) + glyphWidth = gCurGlyph.width; + + if ((glyphHeight = (template->height * 8) - textPrinter->printerTemplate.currentY) > gCurGlyph.height) + glyphHeight = gCurGlyph.height; + + currX = textPrinter->printerTemplate.currentX; + currY = textPrinter->printerTemplate.currentY; + glyphPixels = gCurGlyph.gfxBufferTop; + windowTiles = window->tileData; + widthOffset = template->width * 32; + + if (glyphWidth < 9) + { + if (glyphHeight < 9) + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, glyphHeight); + } + else + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, 8); + GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, glyphWidth, glyphHeight - 8); + } + } + else + { + if (glyphHeight < 9) + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, glyphHeight); + GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, glyphHeight); + } + else + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, 8); + GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, 8); + GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, 8, glyphHeight - 8); + GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY + 8, glyphPixels + 24, glyphWidth - 8, glyphHeight - 8); + } + } +} + +void ClearTextSpan(struct TextPrinter *textPrinter, u32 width) +{ + struct Window *window; + struct Bitmap pixels_data; + struct TextGlyph *glyph; + u8* glyphHeight; + + if (gLastTextBgColor != 0) + { + window = &gWindows[textPrinter->printerTemplate.windowId]; + pixels_data.pixels = window->tileData; + pixels_data.width = window->window.width << 3; + pixels_data.height = window->window.height << 3; + + glyph = &gCurGlyph; + glyphHeight = &glyph->height; + + FillBitmapRect4Bit( + &pixels_data, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + width, + *glyphHeight, + gLastTextBgColor); + } +} + +u16 Font0Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 0; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font1Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 1; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font2Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 2; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font3Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 3; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font4Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 4; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font5Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 5; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font7Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 7; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font8Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 8; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (gTextFlags.autoScroll == 1) + { + subStruct->autoScrollDelay = 0; + } + else + { + subStruct->downArrowYPosIdx = 0; + subStruct->downArrowDelay = 0; + } +} + +void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + const u8 *arrowTiles; + + if (gTextFlags.autoScroll == 0) + { + if (subStruct->downArrowDelay != 0) + { + subStruct->downArrowDelay--; + } + else + { + FillWindowPixelRect( + textPrinter->printerTemplate.windowId, + textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + 8, + 16); + + switch (gTextFlags.useAlternateDownArrow) + { + case FALSE: + default: + arrowTiles = gDownArrowTiles; + break; + case TRUE: + arrowTiles = gDarkDownArrowTiles; + break; + } + + BlitBitmapRectToWindow( + textPrinter->printerTemplate.windowId, + arrowTiles, + 0, + gDownArrowYCoords[subStruct->downArrowYPosIdx], + 8, + 16, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + 8, + 16); + CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); + + subStruct->downArrowDelay = 8; + subStruct->downArrowYPosIdx++; + } + } +} + +void TextPrinterClearDownArrow(struct TextPrinter *textPrinter) +{ + FillWindowPixelRect( + textPrinter->printerTemplate.windowId, + textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + 8, + 16); + CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); +} + +bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->autoScrollDelay == 49) + { + return TRUE; + } + else + { + subStruct->autoScrollDelay++; + return FALSE; + } +} + +bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) +{ + bool8 result = FALSE; + if (gTextFlags.autoScroll != 0) + { + result = TextPrinterWaitAutoMode(textPrinter); + } + else + { + TextPrinterDrawDownArrow(textPrinter); + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + result = TRUE; + PlaySE(SE_SELECT); + } + } + return result; +} + +bool16 TextPrinterWait(struct TextPrinter *textPrinter) +{ + bool16 result = FALSE; + if (gTextFlags.autoScroll != 0) + { + result = TextPrinterWaitAutoMode(textPrinter); + } + else + { + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + result = TRUE; + PlaySE(SE_SELECT); + } + } + return result; +} + +void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex) +{ + const u8 *arrowTiles; + + if (*counter != 0) + { + --*counter; + } + else + { + FillWindowPixelRect(windowId, (bgColor << 4) | bgColor, x, y, 0x8, 0x10); + if (drawArrow == 0) + { + switch (gTextFlags.useAlternateDownArrow) + { + case 0: + default: + arrowTiles = gDownArrowTiles; + break; + case 1: + arrowTiles = gDarkDownArrowTiles; + break; + } + + BlitBitmapRectToWindow( + windowId, + arrowTiles, + 0, + gDownArrowYCoords[*yCoordIndex & 3], + 0x8, + 0x10, + x, + y - 2, + 0x8, + 0x10); + CopyWindowToVram(windowId, 0x2); + *counter = 8; + ++*yCoordIndex; + } + } +} + +u16 RenderText(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + u16 currChar; + s32 width; + s32 widthHelper; + + switch (textPrinter->state) + { + case 0: + if ((JOY_HELD(A_BUTTON | B_BUTTON)) && subStruct->hasPrintBeenSpedUp) + textPrinter->delayCounter = 0; + + if (textPrinter->delayCounter && textPrinter->textSpeed) + { + textPrinter->delayCounter--; + if (gTextFlags.canABSpeedUpPrint && (JOY_NEW(A_BUTTON | B_BUTTON))) + { + subStruct->hasPrintBeenSpedUp = TRUE; + textPrinter->delayCounter = 0; + } + return 3; + } + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED) && gTextFlags.autoScroll) + textPrinter->delayCounter = 3; + else + textPrinter->delayCounter = textPrinter->textSpeed; + + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + + switch (currChar) + { + case CHAR_NEWLINE: + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentY += (gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing); + return 2; + case PLACEHOLDER_BEGIN: + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_BEGIN: + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + switch (currChar) + { + case EXT_CTRL_CODE_COLOR: + textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_HIGHLIGHT: + textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_SHADOW: + textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_PALETTE: + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_SIZE: + subStruct->glyphId = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_RESET_SIZE: + return 2; + case EXT_CTRL_CODE_PAUSE: + textPrinter->delayCounter = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + textPrinter->state = 6; + return 2; + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + textPrinter->state = 1; + if (gTextFlags.autoScroll) + subStruct->autoScrollDelay = 0; + return 3; + case EXT_CTRL_CODE_WAIT_SE: + textPrinter->state = 5; + return 3; + case EXT_CTRL_CODE_PLAY_BGM: + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + currChar |= *textPrinter->printerTemplate.currentChar << 8; + textPrinter->printerTemplate.currentChar++; + PlayBGM(currChar); + return 2; + case EXT_CTRL_CODE_ESCAPE: + currChar = *textPrinter->printerTemplate.currentChar | 0x100; + textPrinter->printerTemplate.currentChar++; + break; + case EXT_CTRL_CODE_PLAY_SE: + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + currChar |= (*textPrinter->printerTemplate.currentChar << 8); + textPrinter->printerTemplate.currentChar++; + PlaySE(currChar); + return 2; + case EXT_CTRL_CODE_SHIFT_TEXT: + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x + *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_SHIFT_DOWN: + textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y + *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_FILL_WINDOW: + FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; + return 2; + case EXT_CTRL_CODE_PAUSE_MUSIC: + m4aMPlayStop(&gMPlayInfo_BGM); + return 2; + case EXT_CTRL_CODE_RESUME_MUSIC: + m4aMPlayContinue(&gMPlayInfo_BGM); + return 2; + case EXT_CTRL_CODE_CLEAR: + width = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + if (width > 0) + { + ClearTextSpan(textPrinter, width); + textPrinter->printerTemplate.currentX += width; + return 0; + } + return 2; + case EXT_CTRL_CODE_SKIP: + textPrinter->printerTemplate.currentX = *textPrinter->printerTemplate.currentChar + textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_CLEAR_TO: + { + widthHelper = *textPrinter->printerTemplate.currentChar; + widthHelper += textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentChar++; + width = widthHelper - textPrinter->printerTemplate.currentX; + if (width > 0) + { + ClearTextSpan(textPrinter, width); + textPrinter->printerTemplate.currentX += width; + return 0; + } + } + return 2; + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + textPrinter->minLetterSpacing = *textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_JPN: + textPrinter->japanese = 1; + return 2; + case EXT_CTRL_CODE_ENG: + textPrinter->japanese = 0; + return 2; + } + break; + case CHAR_PROMPT_CLEAR: + textPrinter->state = 2; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case CHAR_PROMPT_SCROLL: + textPrinter->state = 3; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case CHAR_EXTRA_SYMBOL: + currChar = *textPrinter->printerTemplate.currentChar | 0x100; + textPrinter->printerTemplate.currentChar++; + break; + case CHAR_KEYPAD_ICON: + currChar = *textPrinter->printerTemplate.currentChar++; + gCurGlyph.width = DrawKeypadIcon(textPrinter->printerTemplate.windowId, currChar, textPrinter->printerTemplate.currentX, textPrinter->printerTemplate.currentY); + textPrinter->printerTemplate.currentX += gCurGlyph.width + textPrinter->printerTemplate.letterSpacing; + return 0; + case EOS: + return 1; + } + + switch (subStruct->glyphId) + { + case 0: + DecompressGlyphFont0(currChar, textPrinter->japanese); + break; + case 1: + DecompressGlyphFont1(currChar, textPrinter->japanese); + break; + case 2: + case 3: + case 4: + case 5: + DecompressGlyphFont2(currChar, textPrinter->japanese); + break; + case 7: + DecompressGlyphFont7(currChar, textPrinter->japanese); + break; + case 8: + DecompressGlyphFont8(currChar, textPrinter->japanese); + break; + case 6: + break; + } + + CopyGlyphToWindow(textPrinter); + + if (textPrinter->minLetterSpacing) + { + textPrinter->printerTemplate.currentX += gCurGlyph.width; + width = textPrinter->minLetterSpacing - gCurGlyph.width; + if (width > 0) + { + ClearTextSpan(textPrinter, width); + textPrinter->printerTemplate.currentX += width; + } + } + else + { + if (textPrinter->japanese) + textPrinter->printerTemplate.currentX += (gCurGlyph.width + textPrinter->printerTemplate.letterSpacing); + else + textPrinter->printerTemplate.currentX += gCurGlyph.width; + } + return 0; + case 1: + if (TextPrinterWait(textPrinter)) + textPrinter->state = 0; + return 3; + case 2: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; + textPrinter->state = 0; + } + return 3; + case 3: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + TextPrinterClearDownArrow(textPrinter); + textPrinter->scrollDistance = gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing; + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->state = 4; + } + return 3; + case 4: + if (textPrinter->scrollDistance) + { + int scrollSpeed = GetPlayerTextSpeed(); + int speed = gWindowVerticalScrollSpeeds[scrollSpeed]; + if (textPrinter->scrollDistance < speed) + { + ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance = 0; + } + else + { + ScrollWindow(textPrinter->printerTemplate.windowId, 0, speed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance -= speed; + } + CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); + } + else + { + textPrinter->state = 0; + } + return 3; + case 5: + if (!IsSEPlaying()) + textPrinter->state = 0; + return 3; + case 6: + if (textPrinter->delayCounter != 0) + textPrinter->delayCounter--; + else + textPrinter->state = 0; + return 3; + } + + return 1; +} + +u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing) +{ + int i; + u8 width; + int temp; + int temp2; + u8 line; + int strPos; + u8 lineWidths[8]; + const u8 *strLocal; + + for (i = 0; i < 8; i++) + { + lineWidths[i] = 0; + } + + width = 0; + line = 0; + strLocal = str; + strPos = 0; + + do + { + temp = strLocal[strPos++]; + switch (temp) + { + case CHAR_NEWLINE: + case EOS: + lineWidths[line] = width; + width = 0; + line++; + break; + case EXT_CTRL_CODE_BEGIN: + temp2 = strLocal[strPos++]; + switch (temp2) + { + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + ++strPos; + case EXT_CTRL_CODE_PLAY_BGM: + case EXT_CTRL_CODE_PLAY_SE: + ++strPos; + case EXT_CTRL_CODE_COLOR: + case EXT_CTRL_CODE_HIGHLIGHT: + case EXT_CTRL_CODE_SHADOW: + case EXT_CTRL_CODE_PALETTE: + case EXT_CTRL_CODE_SIZE: + case EXT_CTRL_CODE_PAUSE: + case EXT_CTRL_CODE_ESCAPE: + case EXT_CTRL_CODE_SHIFT_TEXT: + case EXT_CTRL_CODE_SHIFT_DOWN: + case EXT_CTRL_CODE_CLEAR: + case EXT_CTRL_CODE_SKIP: + case EXT_CTRL_CODE_CLEAR_TO: + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + ++strPos; + break; + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_WAIT_SE: + case EXT_CTRL_CODE_FILL_WINDOW: + case EXT_CTRL_CODE_JPN: + case EXT_CTRL_CODE_ENG: + default: + break; + } + break; + case CHAR_DYNAMIC: + case PLACEHOLDER_BEGIN: + ++strPos; + break; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + break; + case CHAR_KEYPAD_ICON: + case CHAR_EXTRA_SYMBOL: + ++strPos; + default: + ++width; + break; + } + } while (temp != EOS); + + for (width = 0, strPos = 0; strPos < 8; ++strPos) + { + if (width < lineWidths[strPos]) + width = lineWidths[strPos]; + } + + return (u8)(GetFontAttribute(fontId, FONTATTR_MAX_LETTER_WIDTH) + letterSpacing) * width; +} + +u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32) +{ + u32 i; + + for (i = 0; i < 9; ++i) + { + if (glyphId == gGlyphWidthFuncs[i].fontId) + return gGlyphWidthFuncs[i].func; + } + + return NULL; +} + +s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing) +{ + bool8 isJapanese; + int minGlyphWidth; + u32 (*func)(u16 glyphId, bool32 isJapanese); + int localLetterSpacing; + u32 lineWidth; + const u8 *bufferPointer; + int glyphWidth; + s32 width; + + isJapanese = 0; + minGlyphWidth = 0; + + func = GetFontWidthFunc(fontId); + if (func == NULL) + return 0; + + if (letterSpacing == -1) + localLetterSpacing = GetFontAttribute(fontId, FONTATTR_LETTER_SPACING); + else + localLetterSpacing = letterSpacing; + + width = 0; + lineWidth = 0; + bufferPointer = 0; + + while (*str != EOS) + { + switch (*str) + { + case CHAR_NEWLINE: + if (lineWidth > width) + width = lineWidth; + lineWidth = 0; + break; + case PLACEHOLDER_BEGIN: + switch (*++str) + { + case PLACEHOLDER_ID_STRING_VAR_1: + bufferPointer = gStringVar1; + break; + case PLACEHOLDER_ID_STRING_VAR_2: + bufferPointer = gStringVar2; + break; + case PLACEHOLDER_ID_STRING_VAR_3: + bufferPointer = gStringVar3; + break; + default: + return 0; + } + case CHAR_DYNAMIC: + if (bufferPointer == NULL) + bufferPointer = DynamicPlaceholderTextUtil_GetPlaceholderPtr(*++str); + while (*bufferPointer != EOS) + { + glyphWidth = func(*bufferPointer++, isJapanese); + if (minGlyphWidth > 0) + { + if (glyphWidth < minGlyphWidth) + glyphWidth = minGlyphWidth; + lineWidth += glyphWidth; + } + else + { + lineWidth += glyphWidth; + if (isJapanese && str[1] != EOS) + lineWidth += localLetterSpacing; + } + } + bufferPointer = 0; + break; + case EXT_CTRL_CODE_BEGIN: + switch (*++str) + { + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + ++str; + case EXT_CTRL_CODE_PLAY_BGM: + case EXT_CTRL_CODE_PLAY_SE: + ++str; + case EXT_CTRL_CODE_COLOR: + case EXT_CTRL_CODE_HIGHLIGHT: + case EXT_CTRL_CODE_SHADOW: + case EXT_CTRL_CODE_PALETTE: + case EXT_CTRL_CODE_PAUSE: + case EXT_CTRL_CODE_ESCAPE: + case EXT_CTRL_CODE_SHIFT_TEXT: + case EXT_CTRL_CODE_SHIFT_DOWN: + ++str; + break; + case EXT_CTRL_CODE_SIZE: + func = GetFontWidthFunc(*++str); + if (func == NULL) + return 0; + if (letterSpacing == -1) + localLetterSpacing = GetFontAttribute(*str, FONTATTR_LETTER_SPACING); + break; + case EXT_CTRL_CODE_CLEAR: + glyphWidth = *++str; + lineWidth += glyphWidth; + break; + case EXT_CTRL_CODE_SKIP: + lineWidth = *++str; + break; + case EXT_CTRL_CODE_CLEAR_TO: + if (*++str > lineWidth) + lineWidth = *str; + break; + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + minGlyphWidth = *++str; + break; + case EXT_CTRL_CODE_JPN: + isJapanese = 1; + break; + case EXT_CTRL_CODE_ENG: + isJapanese = 0; + break; + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_WAIT_SE: + case EXT_CTRL_CODE_FILL_WINDOW: + default: + break; + } + break; + case CHAR_KEYPAD_ICON: + case CHAR_EXTRA_SYMBOL: + if (*str == CHAR_EXTRA_SYMBOL) + glyphWidth = func(*++str | 0x100, isJapanese); + else + glyphWidth = GetKeypadIconWidth(*++str); + + if (minGlyphWidth > 0) + { + if (glyphWidth < minGlyphWidth) + glyphWidth = minGlyphWidth; + lineWidth += glyphWidth; + } + else + { + lineWidth += glyphWidth; + if (isJapanese && str[1] != EOS) + lineWidth += localLetterSpacing; + } + break; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + break; + default: + glyphWidth = func(*str, isJapanese); + if (minGlyphWidth > 0) + { + if (glyphWidth < minGlyphWidth) + glyphWidth = minGlyphWidth; + lineWidth += glyphWidth; + } + else + { + lineWidth += glyphWidth; + if (isJapanese && str[1] != EOS) + lineWidth += localLetterSpacing; + } + break; + } + ++str; + } + + if (lineWidth > width) + return lineWidth; + return width; +} + +u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str) +{ + u8 shadowColor; + u8 *strLocal; + int strPos; + int temp; + int temp2; + u8 colorBackup[3]; + u8 fgColor; + u8 bgColor; + + SaveTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); + + fgColor = TEXT_COLOR_WHITE; + bgColor = TEXT_COLOR_TRANSPARENT; + shadowColor = TEXT_COLOR_LIGHT_GRAY; + + GenerateFontHalfRowLookupTable(TEXT_COLOR_WHITE, TEXT_COLOR_TRANSPARENT, TEXT_COLOR_LIGHT_GRAY); + strLocal = str; + strPos = 0; + + do + { + temp = strLocal[strPos++]; + switch (temp) + { + case EXT_CTRL_CODE_BEGIN: + temp2 = strLocal[strPos++]; + switch (temp2) + { + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + fgColor = strLocal[strPos++]; + bgColor = strLocal[strPos++]; + shadowColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_COLOR: + fgColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_HIGHLIGHT: + bgColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_SHADOW: + shadowColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_SIZE: + fontId = strLocal[strPos++]; + break; + case EXT_CTRL_CODE_PLAY_BGM: + case EXT_CTRL_CODE_PLAY_SE: + ++strPos; + case EXT_CTRL_CODE_PALETTE: + case EXT_CTRL_CODE_PAUSE: + case EXT_CTRL_CODE_ESCAPE: + case EXT_CTRL_CODE_SHIFT_TEXT: + case EXT_CTRL_CODE_SHIFT_DOWN: + case EXT_CTRL_CODE_CLEAR: + case EXT_CTRL_CODE_SKIP: + case EXT_CTRL_CODE_CLEAR_TO: + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + ++strPos; + break; + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_WAIT_SE: + case EXT_CTRL_CODE_FILL_WINDOW: + case EXT_CTRL_CODE_JPN: + case EXT_CTRL_CODE_ENG: + default: + continue; + } + break; + case CHAR_DYNAMIC: + case CHAR_KEYPAD_ICON: + case CHAR_EXTRA_SYMBOL: + case PLACEHOLDER_BEGIN: + ++strPos; + break; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + case CHAR_NEWLINE: + case EOS: + break; + default: + switch (fontId) + { + case 9: + DecompressGlyphFont9(temp); + break; + case 1: + default: + DecompressGlyphFont1(temp, 1); + break; + } + CpuCopy32(gCurGlyph.gfxBufferTop, pixels, 0x20); + CpuCopy32(gCurGlyph.gfxBufferBottom, pixels + 0x20, 0x20); + pixels += 0x40; + break; + } + } + while (temp != EOS); + + RestoreTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); + return 1; +} + +u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y) +{ + BlitBitmapRectToWindow( + windowId, + gKeypadIconTiles + (gKeypadIcons[keypadIconId].tileOffset * 0x20), + 0, + 0, + 0x80, + 0x80, + x, + y, + gKeypadIcons[keypadIconId].width, + gKeypadIcons[keypadIconId].height); + return gKeypadIcons[keypadIconId].width; +} + +u8 GetKeypadIconTileOffset(u8 keypadIconId) +{ + return gKeypadIcons[keypadIconId].tileOffset; +} + +u8 GetKeypadIconWidth(u8 keypadIconId) +{ + return gKeypadIcons[keypadIconId].width; +} + +u8 GetKeypadIconHeight(u8 keypadIconId) +{ + return gKeypadIcons[keypadIconId].height; +} + +void SetDefaultFontsPointer(void) +{ + SetFontsPointer(&gFontInfos[0]); +} + +u8 GetFontAttribute(u8 fontId, u8 attributeId) +{ + int result = 0; + switch (attributeId) + { + case FONTATTR_MAX_LETTER_WIDTH: + result = gFontInfos[fontId].maxLetterWidth; + break; + case FONTATTR_MAX_LETTER_HEIGHT: + result = gFontInfos[fontId].maxLetterHeight; + break; + case FONTATTR_LETTER_SPACING: + result = gFontInfos[fontId].letterSpacing; + break; + case FONTATTR_LINE_SPACING: + result = gFontInfos[fontId].lineSpacing; + break; + case FONTATTR_UNKNOWN: + result = gFontInfos[fontId].unk; + break; + case FONTATTR_COLOR_FOREGROUND: + result = gFontInfos[fontId].fgColor; + break; + case FONTATTR_COLOR_BACKGROUND: + result = gFontInfos[fontId].bgColor; + break; + case FONTATTR_COLOR_SHADOW: + result = gFontInfos[fontId].shadowColor; + break; + } + return result; +} + +u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension) +{ + return gMenuCursorDimensions[fontId][whichDimension]; +} + +void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == 1) + { + glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 12; + } + else + { + glyphs = gFont0LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont0LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 13; + } +} + +u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont0LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 15; + } + else + { + glyphs = gFont7LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont7LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 15; + } +} + +u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont7LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 12; + } + else + { + glyphs = gFont8LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont8LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 12; + } +} + +u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont8LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont2JapaneseGlyphs + (0x100 * (glyphId >> 0x3)) + (0x10 * (glyphId & 0x7)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); // gCurGlyph + 0x20 + DecompressGlyphTile(glyphs + 0x88, gCurGlyph.gfxBufferBottom + 8); // gCurGlyph + 0x60 + gCurGlyph.width = gFont2JapaneseGlyphWidths[glyphId]; + gCurGlyph.height = 14; + } + else + { + glyphs = gFont2LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont2LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 14; + } +} + +u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return gFont2JapaneseGlyphWidths[glyphId]; + else + return gFont2LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 15; + } + else + { + glyphs = gFont1LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont1LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 15; + } +} + +u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont1LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont9(u16 glyphId) +{ + const u16* glyphs; + + glyphs = gFont9JapaneseGlyphs + (0x100 * (glyphId >> 4)) + (0x8 * (glyphId & 0xF)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 12; +} diff --git a/src/window.c b/src/window.c new file mode 100644 index 000000000..b03b513da --- /dev/null +++ b/src/window.c @@ -0,0 +1,721 @@ +#include "global.h" +#include "window.h" +#include "malloc.h" +#include "bg.h" +#include "blit.h" + +u32 gUnusedWindowVar1; +u32 gUnusedWindowVar2; +// This global is set to 0 and never changed. +u8 gTransparentTileNumber; +u32 gUnusedWindowVar3; +void *gWindowBgTilemapBuffers[NUM_BACKGROUNDS]; +extern u32 gUnneededFireRedVariable; + +#define WINDOWS_MAX 32 + +EWRAM_DATA struct Window gWindows[WINDOWS_MAX] = {0}; +EWRAM_DATA static struct Window* sWindowPtr = NULL; +EWRAM_DATA static u16 sWindowSize = 0; + +static u8 GetNumActiveWindowsOnBg(u8 bgId); +static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId); + +static const struct WindowTemplate sDummyWindowTemplate = DUMMY_WIN_TEMPLATE; + +static void DummyWindowBgTilemap(void) +{ + +} + +bool16 InitWindows(const struct WindowTemplate *templates) +{ + int i; + void *bgTilemapBuffer; + int j; + u8 bgLayer; + u16 attrib; + u8* allocatedTilemapBuffer; + int allocatedBaseBlock; + + for (i = 0; i < NUM_BACKGROUNDS; ++i) + { + bgTilemapBuffer = GetBgTilemapBuffer(i); + if (bgTilemapBuffer != NULL) + gWindowBgTilemapBuffers[i] = DummyWindowBgTilemap; + else + gWindowBgTilemapBuffers[i] = bgTilemapBuffer; + } + + for (i = 0; i < WINDOWS_MAX; ++i) + { + gWindows[i].window = sDummyWindowTemplate; + gWindows[i].tileData = NULL; + } + + for (i = 0, allocatedBaseBlock = 0, bgLayer = templates[i].bg; bgLayer != 0xFF && i < WINDOWS_MAX; ++i, bgLayer = templates[i].bg) + { + if (gUnneededFireRedVariable == 1) + { + allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, templates[i].width * templates[i].height, 0); + if (allocatedBaseBlock == -1) + return FALSE; + } + + if (gWindowBgTilemapBuffers[bgLayer] == NULL) + { + attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); + + if (attrib != 0xFFFF) + { + allocatedTilemapBuffer = AllocZeroed(attrib); + + if (allocatedTilemapBuffer == NULL) + { + FreeAllWindowBuffers(); + return FALSE; + } + + for (j = 0; j < attrib; ++j) + allocatedTilemapBuffer[j] = 0; + + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); + } + } + + allocatedTilemapBuffer = AllocZeroed((u16)(32 * (templates[i].width * templates[i].height))); + + if (allocatedTilemapBuffer == NULL) + { + if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + } + + return FALSE; + } + + gWindows[i].tileData = allocatedTilemapBuffer; + gWindows[i].window = templates[i]; + + if (gUnneededFireRedVariable == 1) + { + gWindows[i].window.baseBlock = allocatedBaseBlock; + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, templates[i].width * templates[i].height, 1); + } + } + + gTransparentTileNumber = 0; + return TRUE; +} + +u16 AddWindow(const struct WindowTemplate *template) +{ + u16 win; + u8 bgLayer; + int allocatedBaseBlock; + u16 attrib; + u8 *allocatedTilemapBuffer; + int i; + + for (win = 0; win < WINDOWS_MAX; ++win) + { + if ((bgLayer = gWindows[win].window.bg) == 0xFF) + break; + } + + if (win == WINDOWS_MAX) + return WINDOW_NONE; + + bgLayer = template->bg; + allocatedBaseBlock = 0; + + if (gUnneededFireRedVariable == 1) + { + allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); + + if (allocatedBaseBlock == -1) + return WINDOW_NONE; + } + + if (gWindowBgTilemapBuffers[bgLayer] == NULL) + { + attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); + + if (attrib != 0xFFFF) + { + allocatedTilemapBuffer = AllocZeroed(attrib); + + if (allocatedTilemapBuffer == NULL) + return WINDOW_NONE; + + for (i = 0; i < attrib; ++i) + allocatedTilemapBuffer[i] = 0; + + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); + } + } + + allocatedTilemapBuffer = AllocZeroed((u16)(32 * (template->width * template->height))); + + if (allocatedTilemapBuffer == NULL) + { + if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + } + return WINDOW_NONE; + } + + gWindows[win].tileData = allocatedTilemapBuffer; + gWindows[win].window = *template; + + if (gUnneededFireRedVariable == 1) + { + gWindows[win].window.baseBlock = allocatedBaseBlock; + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); + } + + return win; +} + +int AddWindowWithoutTileMap(const struct WindowTemplate *template) +{ + u16 win; + u8 bgLayer; + int allocatedBaseBlock; + + for (win = 0; win < WINDOWS_MAX; ++win) + { + if (gWindows[win].window.bg == 0xFF) + break; + } + + if (win == WINDOWS_MAX) + return WINDOW_NONE; + + bgLayer = template->bg; + allocatedBaseBlock = 0; + + if (gUnneededFireRedVariable == 1) + { + allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); + + if (allocatedBaseBlock == -1) + return WINDOW_NONE; + } + + gWindows[win].window = *template; + + if (gUnneededFireRedVariable == 1) + { + gWindows[win].window.baseBlock = allocatedBaseBlock; + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); + } + + return win; +} + +void RemoveWindow(u8 windowId) +{ + u8 bgLayer = gWindows[windowId].window.bg; + + if (gUnneededFireRedVariable == 1) + { + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, gWindows[windowId].window.baseBlock, gWindows[windowId].window.width * gWindows[windowId].window.height, 2); + } + + gWindows[windowId].window = sDummyWindowTemplate; + + if (GetNumActiveWindowsOnBg(bgLayer) == 0) + { + if (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = NULL; + } + } + + if (gWindows[windowId].tileData != NULL) + { + Free(gWindows[windowId].tileData); + gWindows[windowId].tileData = NULL; + } +} + +void FreeAllWindowBuffers(void) +{ + int i; + + for (i = 0; i < NUM_BACKGROUNDS; ++i) + { + if (gWindowBgTilemapBuffers[i] != NULL && gWindowBgTilemapBuffers[i] != DummyWindowBgTilemap) + { + Free(gWindowBgTilemapBuffers[i]); + gWindowBgTilemapBuffers[i] = NULL; + } + } + + for (i = 0; i < WINDOWS_MAX; ++i) + { + if (gWindows[i].tileData != NULL) + { + Free(gWindows[i].tileData); + gWindows[i].tileData = NULL; + } + } +} + +void CopyWindowToVram(u8 windowId, u8 mode) +{ + struct Window windowLocal = gWindows[windowId]; + u16 windowSize = 32 * (windowLocal.window.width * windowLocal.window.height); + + switch (mode) + { + case 1: + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + case 2: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); + break; + case 3: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + } +} + +void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h) +{ + struct Window windowLocal; + int rectSize; + int rectPos; + + if (w != 0 && h != 0) + { + windowLocal = gWindows[windowId]; + + rectSize = ((h - 1) * windowLocal.window.width); + rectSize += (windowLocal.window.width - x); + rectSize -= (windowLocal.window.width - (x + w)); + rectSize *= 32; + + rectPos = (y * windowLocal.window.width) + x; + + switch (mode) + { + case 1: + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + case 2: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); + break; + case 3: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + } + } +} + +void PutWindowTilemap(u8 windowId) +{ + struct Window windowLocal = gWindows[windowId]; + + WriteSequenceToBgTilemapBuffer( + windowLocal.window.bg, + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE) + windowLocal.window.baseBlock, + windowLocal.window.tilemapLeft, + windowLocal.window.tilemapTop, + windowLocal.window.width, + windowLocal.window.height, + windowLocal.window.paletteNum, + 1); +} + +void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette) +{ + struct Window windowLocal = gWindows[windowId]; + u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); + int i; + + for (i = 0; i < height; ++i) + { + WriteSequenceToBgTilemapBuffer( + windowLocal.window.bg, + currentRow, + windowLocal.window.tilemapLeft + x, + windowLocal.window.tilemapTop + y + i, + width, + 1, + palette, + 1); + + currentRow += windowLocal.window.width; + } +} + +// Fills a window with transparent tiles. +void ClearWindowTilemap(u8 windowId) +{ + struct Window windowLocal = gWindows[windowId]; + + FillBgTilemapBufferRect( + windowLocal.window.bg, + gTransparentTileNumber, + windowLocal.window.tilemapLeft, + windowLocal.window.tilemapTop, + windowLocal.window.width, + windowLocal.window.height, + windowLocal.window.paletteNum); +} + +void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) +{ + struct Window windowLocal = gWindows[windowId]; + u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); + int i; + + for (i = 0; i < height; ++i) + { + WriteSequenceToBgTilemapBuffer( + windowLocal.window.bg, + currentRow, + windowLocal.window.tilemapLeft + x, + windowLocal.window.tilemapTop + y + i, + width, + 1, + windowLocal.window.paletteNum, + 1); + + currentRow += windowLocal.window.width; + } +} + +void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height) +{ + BlitBitmapRectToWindow(windowId, pixels, 0, 0, width, height, x, y, width, height); +} + +void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight) +{ + struct Bitmap sourceRect; + struct Bitmap destRect; + + sourceRect.pixels = (u8*)pixels; + sourceRect.width = srcWidth; + sourceRect.height = srcHeight; + + destRect.pixels = gWindows[windowId].tileData; + destRect.width = 8 * gWindows[windowId].window.width; + destRect.height = 8 * gWindows[windowId].window.height; + + BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0); +} + +static void BlitBitmapRectToWindowWithColorKey(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 colorKey) +{ + struct Bitmap sourceRect; + struct Bitmap destRect; + + sourceRect.pixels = (u8*)pixels; + sourceRect.width = srcWidth; + sourceRect.height = srcHeight; + + destRect.pixels = gWindows[windowId].tileData; + destRect.width = 8 * gWindows[windowId].window.width; + destRect.height = 8 * gWindows[windowId].window.height; + + BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, colorKey); +} + +void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) +{ + struct Bitmap pixelRect; + + pixelRect.pixels = gWindows[windowId].tileData; + pixelRect.width = 8 * gWindows[windowId].window.width; + pixelRect.height = 8 * gWindows[windowId].window.height; + + FillBitmapRect4Bit(&pixelRect, x, y, width, height, fillValue); +} + +void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset) +{ + if (size != 0) + CpuCopy16(src, gWindows[windowId].tileData + (32 * tileOffset), size); + else + LZ77UnCompWram(src, gWindows[windowId].tileData + (32 * tileOffset)); +} + +// Sets all pixels within the window to the fillValue color. +void FillWindowPixelBuffer(u8 windowId, u8 fillValue) +{ + int fillSize = gWindows[windowId].window.width * gWindows[windowId].window.height; + CpuFastFill8(fillValue, gWindows[windowId].tileData, 32 * fillSize); +} + +#define MOVE_TILES_DOWN(a) \ +{ \ + destOffset = i + (a); \ + srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ + if (srcOffset < size) \ + *(u32*)(tileData + destOffset) = *(u32*)(tileData + srcOffset); \ + else \ + *(u32*)(tileData + destOffset) = fillValue32; \ + distanceLoop++; \ +} + +#define MOVE_TILES_UP(a) \ +{ \ + destOffset = i + (a); \ + srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ + if (srcOffset < size) \ + *(u32*)(tileData - destOffset) = *(u32*)(tileData - srcOffset); \ + else \ + *(u32*)(tileData - destOffset) = fillValue32; \ + distanceLoop++; \ +} + +void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue) +{ + struct WindowTemplate window = gWindows[windowId].window; + u8 *tileData = gWindows[windowId].tileData; + u32 fillValue32 = (fillValue << 24) | (fillValue << 16) | (fillValue << 8) | fillValue; + s32 size = window.height * window.width * 32; + u32 width = window.width; + s32 i; + s32 srcOffset, destOffset; + u32 distanceLoop; + + switch (direction) + { + case 0: + for (i = 0; i < size; i += 32) + { + distanceLoop = distance; + MOVE_TILES_DOWN(0) + MOVE_TILES_DOWN(4) + MOVE_TILES_DOWN(8) + MOVE_TILES_DOWN(12) + MOVE_TILES_DOWN(16) + MOVE_TILES_DOWN(20) + MOVE_TILES_DOWN(24) + MOVE_TILES_DOWN(28) + } + break; + case 1: + tileData += size - 4; + for (i = 0; i < size; i += 32) + { + distanceLoop = distance; + MOVE_TILES_UP(0) + MOVE_TILES_UP(4) + MOVE_TILES_UP(8) + MOVE_TILES_UP(12) + MOVE_TILES_UP(16) + MOVE_TILES_UP(20) + MOVE_TILES_UP(24) + MOVE_TILES_UP(28) + } + break; + case 2: + break; + } +} + +void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)) +{ + struct WindowTemplate window = gWindows[windowId].window; + func(window.bg, window.tilemapLeft, window.tilemapTop, window.width, window.height, window.paletteNum); +} + +bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value) +{ + switch (attributeId) + { + case WINDOW_TILEMAP_LEFT: + gWindows[windowId].window.tilemapLeft = value; + return FALSE; + case WINDOW_TILEMAP_TOP: + gWindows[windowId].window.tilemapTop = value; + return FALSE; + case WINDOW_PALETTE_NUM: + gWindows[windowId].window.paletteNum = value; + return FALSE; + case WINDOW_BASE_BLOCK: + gWindows[windowId].window.baseBlock = value; + return FALSE; + case WINDOW_TILE_DATA: + gWindows[windowId].tileData = (u8*)(value); + return TRUE; + case WINDOW_BG: + case WINDOW_WIDTH: + case WINDOW_HEIGHT: + default: + return TRUE; + } +} + +u32 GetWindowAttribute(u8 windowId, u8 attributeId) +{ + switch (attributeId) + { + case WINDOW_BG: + return gWindows[windowId].window.bg; + case WINDOW_TILEMAP_LEFT: + return gWindows[windowId].window.tilemapLeft; + case WINDOW_TILEMAP_TOP: + return gWindows[windowId].window.tilemapTop; + case WINDOW_WIDTH: + return gWindows[windowId].window.width; + case WINDOW_HEIGHT: + return gWindows[windowId].window.height; + case WINDOW_PALETTE_NUM: + return gWindows[windowId].window.paletteNum; + case WINDOW_BASE_BLOCK: + return gWindows[windowId].window.baseBlock; + case WINDOW_TILE_DATA: + return (u32)(gWindows[windowId].tileData); + default: + return 0; + } +} + +static u8 GetNumActiveWindowsOnBg(u8 bgId) +{ + u8 windowsNum = 0; + s32 i; + for (i = 0; i < WINDOWS_MAX; i++) + { + if (gWindows[i].window.bg == bgId) + windowsNum++; + } + return windowsNum; +} + +static void DummyWindowBgTilemap8Bit(void) +{ + +} + +u16 AddWindow8Bit(const struct WindowTemplate *template) +{ + u16 windowId; + u8* memAddress; + u8 bgLayer; + + for (windowId = 0; windowId < WINDOWS_MAX; windowId++) + { + if (gWindows[windowId].window.bg == 0xFF) + break; + } + if (windowId == WINDOWS_MAX) + return WINDOW_NONE; + bgLayer = template->bg; + if (gWindowBgTilemapBuffers[bgLayer] == NULL) + { + u16 attribute = GetBgAttribute(bgLayer, BG_ATTR_METRIC); + if (attribute != 0xFFFF) + { + s32 i; + memAddress = Alloc(attribute); + if (memAddress == NULL) + return WINDOW_NONE; + for (i = 0; i < attribute; i++) // if we're going to zero out the memory anyway, why not call AllocZeroed? + memAddress[i] = 0; + gWindowBgTilemapBuffers[bgLayer] = memAddress; + SetBgTilemapBuffer(bgLayer, memAddress); + } + } + memAddress = Alloc((u16)(64 * (template->width * template->height))); + if (memAddress == NULL) + { + if (GetNumActiveWindowsOnBg8Bit(bgLayer) == 0 && gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap8Bit) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = NULL; + } + return WINDOW_NONE; + } + else + { + gWindows[windowId].tileData = memAddress; + gWindows[windowId].window = *template; + return windowId; + } +} + +void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue) +{ + s32 i; + s32 size; + + size = (u16)(64 * (gWindows[windowId].window.width * gWindows[windowId].window.height)); + for (i = 0; i < size; i++) + gWindows[windowId].tileData[i] = fillValue; +} + +void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) +{ + struct Bitmap pixelRect; + + pixelRect.pixels = gWindows[windowId].tileData; + pixelRect.width = 8 * gWindows[windowId].window.width; + pixelRect.height = 8 * gWindows[windowId].window.height; + + FillBitmapRect8Bit(&pixelRect, x, y, width, height, fillValue); +} + +void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum) +{ + struct Bitmap sourceRect; + struct Bitmap destRect; + + sourceRect.pixels = (u8*) pixels; + sourceRect.width = srcWidth; + sourceRect.height = srcHeight; + + destRect.pixels = gWindows[windowId].tileData; + destRect.width = 8 * gWindows[windowId].window.width; + destRect.height = 8 * gWindows[windowId].window.height; + + BlitBitmapRect4BitTo8Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0, paletteNum); +} + +void CopyWindowToVram8Bit(u8 windowId, u8 mode) +{ + sWindowPtr = &gWindows[windowId]; + sWindowSize = 64 * (sWindowPtr->window.width * sWindowPtr->window.height); + + switch (mode) + { + case 1: + CopyBgTilemapBufferToVram(sWindowPtr->window.bg); + break; + case 2: + LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + break; + case 3: + LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + CopyBgTilemapBufferToVram(sWindowPtr->window.bg); + break; + } +} + +static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId) +{ + u8 windowsNum = 0; + s32 i; + for (i = 0; i < WINDOWS_MAX; i++) + { + if (gWindows[i].window.bg == bgId) + windowsNum++; + } + return windowsNum; +} diff --git a/sym_bss.txt b/sym_bss.txt index 3166aee45..7bdf99dd5 100644 --- a/sym_bss.txt +++ b/sym_bss.txt @@ -1,10 +1,10 @@ .include "src/main.o" - .include "gflib/malloc.o" - .include "gflib/dma3_manager.o" - .include "gflib/gpu_regs.o" - .include "gflib/bg.o" - .include "gflib/text.o" - .include "gflib/sprite.o" + .include "src/malloc.o" + .include "src/dma3_manager.o" + .include "src/gpu_regs.o" + .include "src/bg.o" + .include "src/text.o" + .include "src/sprite.o" .include "src/link.o" .include "src/AgbRfu_LinkManager.o" .include "src/link_rfu_3.o" diff --git a/sym_common.txt b/sym_common.txt index 1525d8aec..23a185e6f 100644 --- a/sym_common.txt +++ b/sym_common.txt @@ -1,17 +1,17 @@ .space 0x8 .include "main.o" - @ ../gflib/bg.o + @ bg.o .align 2 gUnneededFireRedVariable: .space 4 - @ ../gflib/window.o + @ window.o .align 4 gTransparentTileNumber: .space 1 .align 4 gWindowBgTilemapBuffers: .space 16 - @ ../gflib/text.o + @ text.o .align 4 gFonts: .space 4 @@ -24,7 +24,7 @@ gCurGlyph: .align 2 gTextFlags: .space 4 - @ ../gflib/sprite.o + @ sprite.o .align 2 gOamMatrixAllocBitmap: .space 4 diff --git a/sym_ewram.txt b/sym_ewram.txt index 88c4461cb..f461cfa10 100644 --- a/sym_ewram.txt +++ b/sym_ewram.txt @@ -1,9 +1,9 @@ .include "src/decompress.o" .include "src/main.o" - .include "gflib/window.o" - .include "gflib/text.o" - .include "gflib/sprite.o" - .include "gflib/string_util.o" + .include "src/window.o" + .include "src/text.o" + .include "src/sprite.o" + .include "src/string_util.o" .include "src/link.o" .include "src/AgbRfu_LinkManager.o" .include "src/link_rfu_3.o" -- cgit v1.2.3 From 10c80230c4b24074a8a9e46661db91fa8d465780 Mon Sep 17 00:00:00 2001 From: Kurausukun Date: Fri, 18 Jun 2021 00:15:45 -0400 Subject: change printItemFunc to use u32 instead of s32 also change a use of -2 to LIST_CANCEL --- include/list_menu.h | 2 +- src/battle_pyramid_bag.c | 4 ++-- src/daycare.c | 4 ++-- src/decoration.c | 6 +++--- src/item_menu.c | 4 ++-- src/menu_specialized.c | 2 +- src/player_pc.c | 8 ++++---- src/shop.c | 10 +++++----- src/union_room.c | 17 ++++++++--------- 9 files changed, 28 insertions(+), 29 deletions(-) diff --git a/include/list_menu.h b/include/list_menu.h index 0a54a069a..1c18f3dff 100644 --- a/include/list_menu.h +++ b/include/list_menu.h @@ -31,7 +31,7 @@ struct ListMenuTemplate { const struct ListMenuItem *items; void (* moveCursorFunc)(s32 itemIndex, bool8 onInit, struct ListMenu *list); - void (* itemPrintFunc)(u8 windowId, s32 itemId, u8 y); + void (* itemPrintFunc)(u8 windowId, u32 itemId, u8 y); u16 totalItems; u16 maxShowed; u8 windowId; diff --git a/src/battle_pyramid_bag.c b/src/battle_pyramid_bag.c index 0b13512ec..095cd2bdf 100644 --- a/src/battle_pyramid_bag.c +++ b/src/battle_pyramid_bag.c @@ -106,7 +106,7 @@ static void BagAction_Give(u8); static void BagAction_Cancel(u8); static void BagAction_UseInBattle(u8); static void BagCursorMoved(s32, bool8, struct ListMenu *); -static void PrintItemQuantity(u8, s32, u8); +static void PrintItemQuantity(u8 windowId, u32 itemId, u8 y); static void TossItem(u8); static void DontTossItem(u8); @@ -651,7 +651,7 @@ static void BagCursorMoved(s32 itemIndex, bool8 onInit, struct ListMenu *list) } } -static void PrintItemQuantity(u8 windowId, s32 itemIndex, u8 y) +static void PrintItemQuantity(u8 windowId, u32 itemIndex, u8 y) { s32 xAlign; if (itemIndex == LIST_CANCEL) diff --git a/src/daycare.c b/src/daycare.c index 4199bfda6..6a1715049 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -29,7 +29,7 @@ extern const struct Evolution gEvolutionTable[][EVOS_PER_MON]; static void ClearDaycareMonMail(struct DaycareMail *mail); static void SetInitialEggData(struct Pokemon *mon, u16 species, struct DayCare *daycare); static u8 GetDaycareCompatibilityScore(struct DayCare *daycare); -static void DaycarePrintMonInfo(u8 windowId, s32 daycareSlotId, u8 y); +static void DaycarePrintMonInfo(u8 windowId, u32 daycareSlotId, u8 y); // RAM buffers used to assist with BuildEggMoveset() EWRAM_DATA static u16 sHatchedEggLevelUpMoves[EGG_LVL_UP_MOVES_ARRAY_COUNT] = {0}; @@ -1226,7 +1226,7 @@ static void DaycarePrintMonLvl(struct DayCare *daycare, u8 windowId, u32 daycare DaycareAddTextPrinter(windowId, lvlText, x, y); } -static void DaycarePrintMonInfo(u8 windowId, s32 daycareSlotId, u8 y) +static void DaycarePrintMonInfo(u8 windowId, u32 daycareSlotId, u8 y) { if (daycareSlotId < (unsigned) DAYCARE_MON_COUNT) { diff --git a/src/decoration.c b/src/decoration.c index 6b6cf21e8..ebd7eb26c 100644 --- a/src/decoration.c +++ b/src/decoration.c @@ -147,7 +147,7 @@ static void ReturnToActionsMenuFromCategories(u8 taskId); static void ExitTraderDecorationMenu(u8 taskId); static void CopyDecorationMenuItemName(u8 *dest, u16 decoration); static void DecorationItemsMenu_OnCursorMove(s32 itemIndex, bool8 flag, struct ListMenu *menu); -static void DecorationItemsMenu_PrintDecorationInUse(u8 windowId, s32 itemIndex, u8 y); +static void DecorationItemsMenu_PrintDecorationInUse(u8 windowId, u32 itemIndex, u8 y); static void ShowDecorationItemsWindow(u8 taskId); static void HandleDecorationItemsMenuInput(u8 taskId); static void PrintDecorationItemDescription(s32 itemIndex); @@ -912,9 +912,9 @@ static void DecorationItemsMenu_OnCursorMove(s32 itemIndex, bool8 flag, struct L PrintDecorationItemDescription(itemIndex); } -static void DecorationItemsMenu_PrintDecorationInUse(u8 windowId, s32 itemIndex, u8 y) +static void DecorationItemsMenu_PrintDecorationInUse(u8 windowId, u32 itemIndex, u8 y) { - if (itemIndex != -2) + if (itemIndex != LIST_CANCEL) { if (IsDecorationIndexInSecretBase(itemIndex + 1) == TRUE) BlitMenuInfoIcon(windowId, MENU_INFO_ICON_BALL_RED, 92, y + 2); diff --git a/src/item_menu.c b/src/item_menu.c index de4d82e9b..39abf883a 100755 --- a/src/item_menu.c +++ b/src/item_menu.c @@ -133,7 +133,7 @@ void UpdatePocketScrollPositions(void); u8 CreateBagInputHandlerTask(u8); void sub_81AC23C(u8); void BagMenu_MoveCursorCallback(s32 a, bool8 b, struct ListMenu*); -void BagMenu_ItemPrintCallback(u8 windowId, s32 itemIndex, u8 a); +void BagMenu_ItemPrintCallback(u8 windowId, u32 itemIndex, u8 a); void ItemMenu_UseOutOfBattle(u8 taskId); void ItemMenu_Toss(u8 taskId); void ItemMenu_Register(u8 taskId); @@ -893,7 +893,7 @@ void BagMenu_MoveCursorCallback(s32 itemIndex, bool8 onInit, struct ListMenu *li } } -void BagMenu_ItemPrintCallback(u8 windowId, s32 itemIndex, u8 y) +void BagMenu_ItemPrintCallback(u8 windowId, u32 itemIndex, u8 y) { u16 itemId; u16 itemQuantity; diff --git a/src/menu_specialized.c b/src/menu_specialized.c index 4c4be57f0..2afcf51ca 100644 --- a/src/menu_specialized.c +++ b/src/menu_specialized.c @@ -253,7 +253,7 @@ static u8 sub_81D1D34(u8 a0) return sUnknown_0203CF48[a0]; } -static void sub_81D1D44(u8 windowId, s32 itemId, u8 y) +static void sub_81D1D44(u8 windowId, u32 itemId, u8 y) { u8 buffer[30]; u16 length; diff --git a/src/player_pc.c b/src/player_pc.c index a040ba5b6..946f0645c 100644 --- a/src/player_pc.c +++ b/src/player_pc.c @@ -119,7 +119,7 @@ static void sub_816C060(u16 itemId); static void sub_816BEF0(s32 id); static void sub_816B4DC(u8 taskId); static void ItemStorage_MoveCursor(s32 id, bool8 b, struct ListMenu * thisMenu); -static void fish4_goto_x5_or_x6(u8 windowId, s32 id, u8 yOffset); +static void fish4_goto_x5_or_x6(u8 windowId, u32 id, u8 yOffset); // EWRAM static EWRAM_DATA const u8 *gPcItemMenuOptionOrder = NULL; @@ -943,7 +943,7 @@ static void ItemStorage_MoveCursor(s32 id, bool8 b, struct ListMenu *thisMenu) if (gUnknown_0203BCC4->unk666 == 0xFF) { sub_816C0C8(); - if (id != -2) + if (id != LIST_CANCEL) sub_816C060(gSaveBlock1Ptr->pcItems[id].itemId); else sub_816C060(ITEMPC_GO_BACK_TO_PREV); @@ -951,9 +951,9 @@ static void ItemStorage_MoveCursor(s32 id, bool8 b, struct ListMenu *thisMenu) } } -static void fish4_goto_x5_or_x6(u8 windowId, s32 id, u8 yOffset) +static void fish4_goto_x5_or_x6(u8 windowId, u32 id, u8 yOffset) { - if (id != -2) + if (id != LIST_CANCEL) { if (gUnknown_0203BCC4->unk666 != 0xFF) { diff --git a/src/shop.c b/src/shop.c index 55b421928..2a30bea22 100755 --- a/src/shop.c +++ b/src/shop.c @@ -91,7 +91,7 @@ static void Task_ReturnToItemListAfterDecorationPurchase(u8 taskId); static void Task_HandleShopMenuBuy(u8 taskId); static void Task_HandleShopMenuSell(u8 taskId); static void BuyMenuPrintItemDescriptionAndShowItemIcon(s32 item, bool8 onInit, struct ListMenu *list); -static void BuyMenuPrintPriceInList(u8 windowId, s32 item, u8 y); +static void BuyMenuPrintPriceInList(u8 windowId, u32 itemId, u8 y); static const struct YesNoFuncTable sShopPurchaseYesNoFuncs = { @@ -552,17 +552,17 @@ static void BuyMenuPrintItemDescriptionAndShowItemIcon(s32 item, bool8 onInit, s BuyMenuPrint(2, description, 3, 1, 0, 0); } -static void BuyMenuPrintPriceInList(u8 windowId, s32 item, u8 y) +static void BuyMenuPrintPriceInList(u8 windowId, u32 itemId, u8 y) { u8 x; - if (item != LIST_CANCEL) + if (itemId != LIST_CANCEL) { if (sMartInfo.martType == MART_TYPE_NORMAL) { ConvertIntToDecimalStringN( gStringVar1, - ItemId_GetPrice(item) >> GetPriceReduction(POKENEWS_SLATEPORT), + ItemId_GetPrice(itemId) >> GetPriceReduction(POKENEWS_SLATEPORT), STR_CONV_MODE_LEFT_ALIGN, 5); } @@ -570,7 +570,7 @@ static void BuyMenuPrintPriceInList(u8 windowId, s32 item, u8 y) { ConvertIntToDecimalStringN( gStringVar1, - gDecorations[item].price, + gDecorations[itemId].price, STR_CONV_MODE_LEFT_ALIGN, 5); } diff --git a/src/union_room.c b/src/union_room.c index bd6b303b9..372792a13 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -253,10 +253,10 @@ static bool32 UR_PrintFieldMessage(const u8 *); static s32 GetChatLeaderActionRequestMessage(u8 *, u32, u16 *, struct WirelessLink_URoom *); static void Task_InitUnionRoom(u8 taskId); static bool8 AreGnameUnameDifferent(struct WirelessGnameUnamePair*, const struct WirelessGnameUnamePair*); -static void ItemPrintFunc_PossibleGroupMembers(u8, s32, u8); -static void ListMenuItemPrintFunc_UnionRoomGroups(u8, s32, u8); -static void TradeBoardListMenuItemPrintFunc(u8, s32, u8); -static void nullsub_14(u8, s32, u8); +static void ItemPrintFunc_PossibleGroupMembers(u8 windowId, u32 id, u8 y); +static void ListMenuItemPrintFunc_UnionRoomGroups(u8 windowId, u32 id, u8 y); +static void TradeBoardListMenuItemPrintFunc(u8 windowId, u32 id, u8 y); +static void nullsub_14(u8 windowId, u32 id, u8 y); #include "data/union_room.h" @@ -835,7 +835,7 @@ static bool8 Leader_SetStateIfMemberListChanged(struct WirelessLink_Leader *data return FALSE; } -static void ItemPrintFunc_PossibleGroupMembers(u8 windowId, s32 id, u8 y) +static void ItemPrintFunc_PossibleGroupMembers(u8 windowId, u32 id, u8 y) { struct WirelessLink_Leader *data = sWirelessLinkMain.leader; u8 colorIdx = UR_COLOR_DKE_WHT_LTE; @@ -1363,7 +1363,7 @@ static u8 URoomGroupListGetTextColor(struct WirelessLink_Group *data, u32 id) return UR_COLOR_DKE_WHT_LTE; } -static void ListMenuItemPrintFunc_UnionRoomGroups(u8 windowId, s32 id, u8 y) +static void ListMenuItemPrintFunc_UnionRoomGroups(u8 windowId, u32 id, u8 y) { struct WirelessLink_Group *data = sWirelessLinkMain.group; u8 colorId = URoomGroupListGetTextColor(data, id); @@ -4074,9 +4074,8 @@ static s32 UnionRoomGetPlayerInteractionResponse(struct UnkStruct_Main0 *main0, } } -void nullsub_14(u8 windowId, s32 itemId, u8 y) +void nullsub_14(u8 windowId, u32 itemId, u8 y) { - } static void TradeBoardPrintItemInfo(u8 windowId, u8 y, struct GFtgtGname * gname, const u8 * uname, u8 colorIdx) @@ -4100,7 +4099,7 @@ static void TradeBoardPrintItemInfo(u8 windowId, u8 y, struct GFtgtGname * gname } } -static void TradeBoardListMenuItemPrintFunc(u8 windowId, s32 itemId, u8 y) +static void TradeBoardListMenuItemPrintFunc(u8 windowId, u32 itemId, u8 y) { struct WirelessLink_Leader *data = sWirelessLinkMain.leader; struct GFtgtGname *rfu; -- cgit v1.2.3 From 10886a586b75eb80a68f341bcc61b7c0343ddfe2 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 27 Apr 2021 02:30:26 -0400 Subject: Clean up mirage tower --- data/maps/Route111/scripts.inc | 7 +- graphics/misc/fossil.png | Bin 298 -> 0 bytes include/constants/event_objects.h | 4 + src/mirage_tower.c | 384 ++++++++++++++++++++------------------ 4 files changed, 211 insertions(+), 184 deletions(-) delete mode 100644 graphics/misc/fossil.png diff --git a/data/maps/Route111/scripts.inc b/data/maps/Route111/scripts.inc index 322c9a2b7..9e6e4c8eb 100644 --- a/data/maps/Route111/scripts.inc +++ b/data/maps/Route111/scripts.inc @@ -2,9 +2,10 @@ .set LOCALID_VICTORIA, 2 .set LOCALID_VIVI, 3 .set LOCALID_VICKY, 4 -.set LOCALID_PLAYER_FALLING, 45 .set LOCALID_ROCK_SMASH_MAN, 46 +@ Note: LOCALID_ROUTE111_PLAYER_FALLING is used in mirage_tower.c, and is defined in event_objects.h + Route111_MapScripts:: @ 81F0CA7 map_script MAP_SCRIPT_ON_LOAD, Route111_OnLoad map_script MAP_SCRIPT_ON_TRANSITION, Route111_OnTransition @@ -127,11 +128,11 @@ Route111_EventScript_MirageTowerDisappear:: @ 81F0E60 waitstate delay 24 playse SE_FALL - addobject LOCALID_PLAYER_FALLING + addobject LOCALID_ROUTE111_PLAYER_FALLING special StartPlayerDescendMirageTower waitstate showobjectat OBJ_EVENT_ID_PLAYER, MAP_LITTLEROOT_TOWN - removeobject LOCALID_PLAYER_FALLING + removeobject LOCALID_ROUTE111_PLAYER_FALLING delay 16 turnobject OBJ_EVENT_ID_PLAYER, DIR_NORTH delay 16 diff --git a/graphics/misc/fossil.png b/graphics/misc/fossil.png deleted file mode 100644 index f92649e98..000000000 Binary files a/graphics/misc/fossil.png and /dev/null differ diff --git a/include/constants/event_objects.h b/include/constants/event_objects.h index 7a224940f..357251548 100644 --- a/include/constants/event_objects.h +++ b/include/constants/event_objects.h @@ -279,7 +279,11 @@ #define FIRST_DECORATION_SPRITE_GFX OBJ_EVENT_GFX_PICHU_DOLL +// Special object event local ids #define OBJ_EVENT_ID_PLAYER 0xFF #define OBJ_EVENT_ID_CAMERA 0x7F +// Object event local ids referenced in C files +#define LOCALID_ROUTE111_PLAYER_FALLING 45 + #endif // GUARD_CONSTANTS_EVENT_OBJECTS_H diff --git a/src/mirage_tower.c b/src/mirage_tower.c index d18ddcc0f..9f91dff50 100644 --- a/src/mirage_tower.c +++ b/src/mirage_tower.c @@ -14,12 +14,14 @@ #include "sprite.h" #include "task.h" #include "window.h" +#include "constants/event_objects.h" #include "constants/maps.h" #include "constants/rgb.h" #include "constants/songs.h" #include "constants/metatile_labels.h" -struct MirageTowerPulseBlend { +struct MirageTowerPulseBlend +{ u8 taskId; struct PulseBlend pulseBlend; }; @@ -37,59 +39,51 @@ struct BgRegOffsets u16 bgVOFS; }; -struct Struct203CF10 +struct FallAnim_Tower { - u8 *buffer; - u8 currIndex; + u8 *disintegrateRand; + u8 disintegrateIdx; }; -struct DynamicSpriteFrameImage -{ - u8 *data; - u16 size; -}; - -struct Struct203CF0C +struct FallAnim_Fossil { u8 *frameImageTiles; - struct DynamicSpriteFrameImage *frameImage; + struct SpriteFrameImage *frameImage; u8 spriteId; - u16 *unkC; - u16 unk10; + u16 *disintegrateRand; + u16 disintegrateIdx; }; +#define TAG_CEILING_CRUMBLE 4000 + #define MIRAGE_TOWER_GFX_LENGTH (sizeof(sBlankTile_Gfx) + sizeof(sMirageTower_Gfx)) -#define ROOT_FOSSIL_GFX_LENGTH sizeof(sRootFossil_Gfx) -#define ROOT_FOSSIL_GFX_RANDOMIZER_LENGTH 0x100 +#define FOSSIL_DISINTEGRATE_LENGTH 0x100 -// extern data -extern const struct SpriteSheet gMirageTowerCeilingCrumbleSpriteSheets[]; -extern const s16 sCeilingCrumblePositions[][3]; +static const struct SpriteSheet sCeilingCrumbleSpriteSheets[]; +static const s16 sCeilingCrumblePositions[][3]; -// static functions -static void PlayerDescendMirageTower(u8 taskId); -static void DoScreenShake(u8 taskId); +static void PlayerDescendMirageTower(u8); +static void DoScreenShake(u8); static void IncrementCeilingCrumbleFinishedCount(void); -static void WaitCeilingCrumble(u8 taskId); -static void FinishCeilingCrumbleTask(u8 taskId); +static void WaitCeilingCrumble(u8); +static void FinishCeilingCrumbleTask(u8); static void CreateCeilingCrumbleSprites(void); -static void MoveCeilingCrumbleSprite(struct Sprite* sprite); -static void DoMirageTowerDisintegration(u8 taskId); -static void InitMirageTowerShake(u8 taskId); -static void DoFossilFallAndSink(u8 taskId); -static void sub_81BF248(struct Sprite *); -static void sub_81BF2B8(u8* a, u16 b, u8 c, u8 d, u8 e); - -// rodata +static void SpriteCB_CeilingCrumble(struct Sprite*); +static void DoMirageTowerDisintegration(u8); +static void InitMirageTowerShake(u8); +static void Task_FossilFallAndSink(u8); +static void SpriteCB_FallingFossil(struct Sprite *); +static void UpdateDisintegrationEffect(u8*, u16, u8, u8, u8); + static const u8 sBlankTile_Gfx[32] = {0}; static const u8 sMirageTower_Gfx[] = INCBIN_U8("graphics/misc/mirage_tower.4bpp"); static const u16 sMirageTowerTilemap[] = INCBIN_U16("graphics/misc/mirage_tower.bin"); -static const u16 sRootFossil_Pal[] = INCBIN_U16("graphics/misc/fossil.gbapal"); -static const u8 sRootFossil_Gfx[] = INCBIN_U8("graphics/misc/fossil.4bpp"); +static const u16 sFossil_Pal[] = INCBIN_U16("graphics/object_events/pics/misc/fossil.gbapal"); // Unused +static const u8 sFossil_Gfx[] = INCBIN_U8("graphics/object_events/pics/misc/fossil.4bpp"); // Duplicate of gObjectEventPic_Fossil static const u8 sMirageTowerCrumbles_Gfx[] = INCBIN_U8("graphics/misc/mirage_tower_crumbles.4bpp"); static const u16 sMirageTowerCrumbles_Palette[] = INCBIN_U16("graphics/misc/mirage_tower_crumbles.gbapal"); -const s16 sCeilingCrumblePositions[][3] = +static const s16 sCeilingCrumblePositions[][3] = { { 0, 10, 65}, { 17, 3, 50}, @@ -101,10 +95,10 @@ const s16 sCeilingCrumblePositions[][3] = {-24, -4, 65}, }; -const struct SpriteSheet gMirageTowerCeilingCrumbleSpriteSheets[] = +static const struct SpriteSheet sCeilingCrumbleSpriteSheets[] = { - {sMirageTowerCrumbles_Gfx, 0x0080, 4000}, - {NULL} + {sMirageTowerCrumbles_Gfx, 0x80, TAG_CEILING_CRUMBLE}, + {} }; static const struct MetatileCoords sInvisibleMirageTowerMetatiles[] = @@ -129,13 +123,13 @@ static const struct MetatileCoords sInvisibleMirageTowerMetatiles[] = {20, 58, METATILE_General_SandPit_Center}, }; -static const union AnimCmd gSpriteAnim_8617DEC[] = +static const union AnimCmd sAnim_FallingFossil[] = { ANIMCMD_FRAME(0, 1), ANIMCMD_END, }; -static const struct OamData gOamData_8617DF4 = +static const struct OamData sOamData_FallingFossil = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, @@ -152,14 +146,20 @@ static const struct OamData gOamData_8617DF4 = .affineParam = 0, }; -static const union AnimCmd *const gSpriteAnimTable_8617DFC[] = +static const union AnimCmd *const sAnims_FallingFossil[] = { - gSpriteAnim_8617DEC, + sAnim_FallingFossil, }; -static const struct SpriteTemplate gUnknown_08617E00 = +static const struct SpriteTemplate sSpriteTemplate_FallingFossil = { - 0xFFFF, 0xFFFF, &gOamData_8617DF4, gSpriteAnimTable_8617DFC, NULL, gDummySpriteAffineAnimTable, SpriteCallbackDummy + .tileTag = 0xFFFF, + .paletteTag = 0xFFFF, + .oam = &sOamData_FallingFossil, + .anims = sAnims_FallingFossil, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy }; const struct PulseBlendSettings gMirageTowerPulseBlendSettings = { @@ -174,18 +174,18 @@ const struct PulseBlendSettings gMirageTowerPulseBlendSettings = { .unk7_7 = 1, }; -static const union AnimCmd sCeilingCrumble2AnimCmd[] = +static const union AnimCmd sAnim_CeilingCrumbleSmall[] = { ANIMCMD_FRAME(0, 12), ANIMCMD_JUMP(0), }; -static const union AnimCmd *const sCeilingCrumble2AnimCmds[] = +static const union AnimCmd *const sAnims_CeilingCrumbleSmall[] = { - sCeilingCrumble2AnimCmd, + sAnim_CeilingCrumbleSmall, }; -static const struct OamData sCeilingCrumble2OamData = +static const struct OamData sOamData_CeilingCrumbleSmall = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, @@ -202,28 +202,28 @@ static const struct OamData sCeilingCrumble2OamData = .affineParam = 0, }; -static const struct SpriteTemplate sCeilingCrumbleSpriteTemplate2 = { - .tileTag = 4000, +static const struct SpriteTemplate sSpriteTemplate_CeilingCrumbleSmall = { + .tileTag = TAG_CEILING_CRUMBLE, .paletteTag = 0xFFFF, - .oam = &sCeilingCrumble2OamData, - .anims = sCeilingCrumble2AnimCmds, + .oam = &sOamData_CeilingCrumbleSmall, + .anims = sAnims_CeilingCrumbleSmall, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, - .callback = MoveCeilingCrumbleSprite + .callback = SpriteCB_CeilingCrumble }; -static const union AnimCmd sCeilingCrumble1AnimCmd[] = +static const union AnimCmd sAnim_CeilingCrumbleLarge[] = { ANIMCMD_FRAME(0, 12), ANIMCMD_JUMP(0), }; -static const union AnimCmd *const sCeilingCrumble1AnimCmds[] = +static const union AnimCmd *const sAnims_CeilingCrumbleLarge[] = { - sCeilingCrumble1AnimCmd, + sAnim_CeilingCrumbleLarge, }; -static const struct OamData sCeilingCrumble1OamData = +static const struct OamData sOamData_CeilingCrumbleLarge = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, @@ -240,24 +240,26 @@ static const struct OamData sCeilingCrumble1OamData = .affineParam = 0, }; -static const struct SpriteTemplate sCeilingCrumbleSpriteTemplate1 = { - .tileTag = 4000, +static const struct SpriteTemplate sSpriteTemplate_CeilingCrumbleLarge = { + .tileTag = TAG_CEILING_CRUMBLE, .paletteTag = 0xFFFF, - .oam = &sCeilingCrumble1OamData, - .anims = sCeilingCrumble1AnimCmds, + .oam = &sOamData_CeilingCrumbleLarge, + .anims = sAnims_CeilingCrumbleLarge, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, - .callback = MoveCeilingCrumbleSprite + .callback = SpriteCB_CeilingCrumble }; EWRAM_DATA static u8* sMirageTowerGfxBuffer = NULL; EWRAM_DATA static u8* sMirageTowerTilemapBuffer = NULL; -EWRAM_DATA static struct Struct203CF0C *sUnknown_0203CF0C = NULL; -EWRAM_DATA static struct Struct203CF10 *sUnknown_0203CF10 = NULL; +EWRAM_DATA static struct FallAnim_Fossil *sFallingFossil = NULL; +EWRAM_DATA static struct FallAnim_Tower *sFallingTower = NULL; EWRAM_DATA static struct BgRegOffsets *sBgShakeOffsets = NULL; -EWRAM_DATA struct MirageTowerPulseBlend *sMirageTowerPulseBlend = NULL; +EWRAM_DATA static struct MirageTowerPulseBlend *sMirageTowerPulseBlend = NULL; -static u16 gUnknown_030012A8[8]; +// Holds data about the disintegration effect for Mirage Tower / the unchosen fossil. +// Never read, presumably for debugging +static u16 sDebug_DisintegrationData[8]; bool8 IsMirageTowerVisible(void) { @@ -319,6 +321,7 @@ void SetMirageTowerVisibility(void) if (VarGet(VAR_MIRAGE_TOWER_STATE)) { + // Mirage Tower event has already been completed, hide it FlagClear(FLAG_MIRAGE_TOWER_VISIBLE); return; } @@ -343,32 +346,40 @@ void StartPlayerDescendMirageTower(void) CreateTask(PlayerDescendMirageTower, 8); } +// As the tower disintegrates, a duplicate object event of the player +// is created at the top of the tower and moved down to show the player falling static void PlayerDescendMirageTower(u8 taskId) { u8 objectEventId; - struct ObjectEvent *fakePlayerObjectEvent; - struct ObjectEvent *playerObjectEvent; - - TryGetObjectEventIdByLocalIdAndMap(45, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId); - fakePlayerObjectEvent = &gObjectEvents[objectEventId]; - gSprites[fakePlayerObjectEvent->spriteId].pos2.y += 4; - playerObjectEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - if ((gSprites[fakePlayerObjectEvent->spriteId].pos1.y + gSprites[fakePlayerObjectEvent->spriteId].pos2.y) >= - (gSprites[playerObjectEvent->spriteId].pos1.y + gSprites[playerObjectEvent->spriteId].pos2.y)) + struct ObjectEvent *fallingPlayer; + struct ObjectEvent *player; + + TryGetObjectEventIdByLocalIdAndMap(LOCALID_ROUTE111_PLAYER_FALLING, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId); + fallingPlayer = &gObjectEvents[objectEventId]; + gSprites[fallingPlayer->spriteId].pos2.y += 4; + player = &gObjectEvents[gPlayerAvatar.objectEventId]; + if ((gSprites[fallingPlayer->spriteId].pos1.y + gSprites[fallingPlayer->spriteId].pos2.y) >= + (gSprites[player->spriteId].pos1.y + gSprites[player->spriteId].pos2.y)) { DestroyTask(taskId); EnableBothScriptContexts(); } } +#define tXShakeOffset data[0] +#define tTimer data[1] +#define tNumShakes data[2] +#define tShakeDelay data[3] +#define tYShakeOffset data[4] + static void StartScreenShake(u8 yShakeOffset, u8 xShakeOffset, u8 numShakes, u8 shakeDelay) { u8 taskId = CreateTask(DoScreenShake, 9); - gTasks[taskId].data[0] = xShakeOffset; - gTasks[taskId].data[1] = 0; - gTasks[taskId].data[2] = numShakes; - gTasks[taskId].data[3] = shakeDelay; - gTasks[taskId].data[4] = yShakeOffset; + gTasks[taskId].tXShakeOffset = xShakeOffset; + gTasks[taskId].tTimer = 0; + gTasks[taskId].tNumShakes = numShakes; + gTasks[taskId].tShakeDelay = shakeDelay; + gTasks[taskId].tYShakeOffset = yShakeOffset; SetCameraPanningCallback(NULL); PlaySE(SE_M_STRENGTH); } @@ -378,15 +389,15 @@ static void DoScreenShake(u8 taskId) s16 *data; data = gTasks[taskId].data; - data[1]++; - if (data[1] % data[3] == 0) + tTimer++; + if (tTimer % tShakeDelay == 0) { - data[1] = 0; - data[2]--; - data[0] = -data[0]; - data[4] = -data[4]; - SetCameraPanning(data[0], data[4]); - if (data[2] == 0) + tTimer = 0; + tNumShakes--; + tXShakeOffset = -tXShakeOffset; + tYShakeOffset = -tYShakeOffset; + SetCameraPanning(tXShakeOffset, tYShakeOffset); + if (tNumShakes == 0) { IncrementCeilingCrumbleFinishedCount(); DestroyTask(taskId); @@ -395,6 +406,12 @@ static void DoScreenShake(u8 taskId) } } +#undef tXShakeOffset +#undef tTimer +#undef tNumShakes +#undef tShakeDelay +#undef tYShakeOffset + static void IncrementCeilingCrumbleFinishedCount(void) { u8 taskId = FindTaskIdByFunc(WaitCeilingCrumble); @@ -404,7 +421,7 @@ static void IncrementCeilingCrumbleFinishedCount(void) void DoMirageTowerCeilingCrumble(void) { - LoadSpriteSheets(gMirageTowerCeilingCrumbleSpriteSheets); + LoadSpriteSheets(sCeilingCrumbleSpriteSheets); CreateCeilingCrumbleSprites(); CreateTask(WaitCeilingCrumble, 8); StartScreenShake(2, 1, 16, 3); @@ -421,7 +438,7 @@ static void WaitCeilingCrumble(u8 taskId) static void FinishCeilingCrumbleTask(u8 taskId) { - FreeSpriteTilesByTag(4000); + FreeSpriteTilesByTag(TAG_CEILING_CRUMBLE); DestroyTask(taskId); EnableBothScriptContexts(); } @@ -433,21 +450,21 @@ static void CreateCeilingCrumbleSprites(void) for (i = 0; i < 8; i++) { - spriteId = CreateSprite(&sCeilingCrumbleSpriteTemplate1, sCeilingCrumblePositions[i][0] + 120, sCeilingCrumblePositions[i][1], 8); + spriteId = CreateSprite(&sSpriteTemplate_CeilingCrumbleLarge, sCeilingCrumblePositions[i][0] + 120, sCeilingCrumblePositions[i][1], 8); gSprites[spriteId].oam.priority = 0; gSprites[spriteId].oam.paletteNum = 0; gSprites[spriteId].data[0] = i; } for (i = 0; i < 8; i++) { - spriteId = CreateSprite(&sCeilingCrumbleSpriteTemplate2, sCeilingCrumblePositions[i][0] + 115, sCeilingCrumblePositions[i][1] - 3, 8); + spriteId = CreateSprite(&sSpriteTemplate_CeilingCrumbleSmall, sCeilingCrumblePositions[i][0] + 115, sCeilingCrumblePositions[i][1] - 3, 8); gSprites[spriteId].oam.priority = 0; gSprites[spriteId].oam.paletteNum = 0; gSprites[spriteId].data[0] = i; } } -static void MoveCeilingCrumbleSprite(struct Sprite* sprite) +static void SpriteCB_CeilingCrumble(struct Sprite* sprite) { sprite->data[1] += 2; sprite->pos2.y = sprite->data[1] / 2; @@ -478,7 +495,7 @@ void StartMirageTowerShake(void) void StartMirageTowerFossilFallAndSink(void) { - CreateTask(DoFossilFallAndSink, 9); + CreateTask(Task_FossilFallAndSink, 9); } static void SetBgShakeOffsets(void) @@ -501,42 +518,44 @@ static void UpdateBgShake(u8 taskId) } } +#define tState data[0] + static void InitMirageTowerShake(u8 taskId) { u8 zero; - switch (gTasks[taskId].data[0]) + switch (gTasks[taskId].tState) { case 0: FreeAllWindowBuffers(); SetBgAttribute(0, BG_ATTR_PRIORITY, 2); - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; break; case 1: sMirageTowerGfxBuffer = (u8 *)AllocZeroed(MIRAGE_TOWER_GFX_LENGTH); sMirageTowerTilemapBuffer = (u8 *)AllocZeroed(BG_SCREEN_SIZE); ChangeBgX(0, 0, 0); ChangeBgY(0, 0, 0); - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; break; case 2: CpuSet(sBlankTile_Gfx, sMirageTowerGfxBuffer, MIRAGE_TOWER_GFX_LENGTH / 2); LoadBgTiles(0, sMirageTowerGfxBuffer, MIRAGE_TOWER_GFX_LENGTH, 0); - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; break; case 3: SetBgTilemapBuffer(0, sMirageTowerTilemapBuffer); CopyToBgTilemapBufferRect_ChangePalette(0, &sMirageTowerTilemap, 12, 29, 6, 12, 17); CopyBgTilemapBufferToVram(0); - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; break; case 4: ShowBg(0); - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; break; case 5: SetInvisibleMirageTowerMetatiles(); - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; break; case 6: sBgShakeOffsets = Alloc(sizeof(*sBgShakeOffsets)); @@ -558,27 +577,29 @@ static void DoMirageTowerDisintegration(u8 taskId) u16 i; u8 index; - switch (gTasks[taskId].data[0]) + switch (gTasks[taskId].tState) { case 1: - sUnknown_0203CF10 = AllocZeroed(OUTER_BUFFER_LENGTH * sizeof(struct Struct203CF10)); + sFallingTower = AllocZeroed(OUTER_BUFFER_LENGTH * sizeof(struct FallAnim_Tower)); break; case 3: if (gTasks[taskId].data[3] <= (OUTER_BUFFER_LENGTH - 1)) { if (gTasks[taskId].data[1] > 1) { + // Initialize disintegration pattern index = gTasks[taskId].data[3]; - sUnknown_0203CF10[index].buffer = Alloc(INNER_BUFFER_LENGTH); + sFallingTower[index].disintegrateRand = Alloc(INNER_BUFFER_LENGTH); for (i = 0; i <= (INNER_BUFFER_LENGTH - 1); i++) - sUnknown_0203CF10[index].buffer[i] = i; + sFallingTower[index].disintegrateRand[i] = i; + + // Randomize disintegration pattern for (i = 0; i <= (INNER_BUFFER_LENGTH - 1); i++) { u16 rand1, rand2, temp; - - rand1 = Random() % 0x30; - rand2 = Random() % 0x30; - SWAP(sUnknown_0203CF10[index].buffer[rand2], sUnknown_0203CF10[index].buffer[rand1], temp); + rand1 = Random() % INNER_BUFFER_LENGTH; + rand2 = Random() % INNER_BUFFER_LENGTH; + SWAP(sFallingTower[index].disintegrateRand[rand2], sFallingTower[index].disintegrateRand[rand1], temp); } if (gTasks[taskId].data[3] <= (OUTER_BUFFER_LENGTH - 1)) gTasks[taskId].data[3]++; @@ -591,20 +612,20 @@ static void DoMirageTowerDisintegration(u8 taskId) { for (j = 0; j < 1; j++) { - sub_81BF2B8(sMirageTowerGfxBuffer, - ((((OUTER_BUFFER_LENGTH - 1) - i) * INNER_BUFFER_LENGTH) + sUnknown_0203CF10[i].buffer[(sUnknown_0203CF10[i].currIndex)++]), + UpdateDisintegrationEffect(sMirageTowerGfxBuffer, + (OUTER_BUFFER_LENGTH - 1 - i) * INNER_BUFFER_LENGTH + sFallingTower[i].disintegrateRand[sFallingTower[i].disintegrateIdx++], 0, INNER_BUFFER_LENGTH, 1); } - if (sUnknown_0203CF10[i].currIndex > (INNER_BUFFER_LENGTH - 1)) + if (sFallingTower[i].disintegrateIdx > (INNER_BUFFER_LENGTH - 1)) { - FREE_AND_SET_NULL(sUnknown_0203CF10[i].buffer); + FREE_AND_SET_NULL(sFallingTower[i].disintegrateRand); gTasks[taskId].data[2]++; if ((i % 2) == 1) sBgShakeOffsets->bgVOFS--; } } LoadBgTiles(0, sMirageTowerGfxBuffer, MIRAGE_TOWER_GFX_LENGTH, 0); - if (sUnknown_0203CF10[OUTER_BUFFER_LENGTH - 1].currIndex > (INNER_BUFFER_LENGTH - 1)) + if (sFallingTower[OUTER_BUFFER_LENGTH - 1].disintegrateIdx > INNER_BUFFER_LENGTH - 1) break; return; case 4: @@ -617,7 +638,7 @@ static void DoMirageTowerDisintegration(u8 taskId) break; case 5: FREE_AND_SET_NULL(sBgShakeOffsets); - FREE_AND_SET_NULL(sUnknown_0203CF10); + FREE_AND_SET_NULL(sFallingTower); FREE_AND_SET_NULL(sMirageTowerGfxBuffer); FREE_AND_SET_NULL(sMirageTowerTilemapBuffer); break; @@ -635,127 +656,128 @@ static void DoMirageTowerDisintegration(u8 taskId) EnableBothScriptContexts(); break; } - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; } -static void DoFossilFallAndSink(u8 taskId) +static void Task_FossilFallAndSink(u8 taskId) { u16 i; u8 *buffer; - switch (gTasks[taskId].data[0]) + switch (gTasks[taskId].tState) { case 1: - sUnknown_0203CF0C = AllocZeroed(sizeof(*sUnknown_0203CF0C)); - sUnknown_0203CF0C->frameImageTiles = AllocZeroed(ROOT_FOSSIL_GFX_LENGTH); - sUnknown_0203CF0C->frameImage = AllocZeroed(sizeof(*sUnknown_0203CF0C->frameImage)); - sUnknown_0203CF0C->unkC = AllocZeroed(ROOT_FOSSIL_GFX_RANDOMIZER_LENGTH * sizeof(u16)); - sUnknown_0203CF0C->unk10 = 0; + sFallingFossil = AllocZeroed(sizeof(*sFallingFossil)); + sFallingFossil->frameImageTiles = AllocZeroed(sizeof(sFossil_Gfx)); + sFallingFossil->frameImage = AllocZeroed(sizeof(*sFallingFossil->frameImage)); + sFallingFossil->disintegrateRand = AllocZeroed(FOSSIL_DISINTEGRATE_LENGTH * sizeof(u16)); + sFallingFossil->disintegrateIdx = 0; break; case 2: - buffer = sUnknown_0203CF0C->frameImageTiles; - for (i = 0; i < ROOT_FOSSIL_GFX_LENGTH; i++, buffer++) - *buffer = sRootFossil_Gfx[i]; + buffer = sFallingFossil->frameImageTiles; + for (i = 0; i < sizeof(sFossil_Gfx); i++, buffer++) + *buffer = sFossil_Gfx[i]; break; case 3: - sUnknown_0203CF0C->frameImage->data = sUnknown_0203CF0C->frameImageTiles; - sUnknown_0203CF0C->frameImage->size = ROOT_FOSSIL_GFX_LENGTH; + sFallingFossil->frameImage->data = sFallingFossil->frameImageTiles; + sFallingFossil->frameImage->size = sizeof(sFossil_Gfx); break; case 4: { - struct SpriteTemplate fossilTemplate; - - fossilTemplate = gUnknown_08617E00; - fossilTemplate.images = (struct SpriteFrameImage *)(sUnknown_0203CF0C->frameImage); - sUnknown_0203CF0C->spriteId = CreateSprite(&fossilTemplate, 128, -16, 1); - gSprites[sUnknown_0203CF0C->spriteId].centerToCornerVecX = 0; - gSprites[sUnknown_0203CF0C->spriteId].data[0] = gSprites[sUnknown_0203CF0C->spriteId].pos1.x; - gSprites[sUnknown_0203CF0C->spriteId].data[1] = 1; + struct SpriteTemplate fossilTemplate = sSpriteTemplate_FallingFossil; + fossilTemplate.images = sFallingFossil->frameImage; + sFallingFossil->spriteId = CreateSprite(&fossilTemplate, 128, -16, 1); + gSprites[sFallingFossil->spriteId].centerToCornerVecX = 0; + gSprites[sFallingFossil->spriteId].data[0] = gSprites[sFallingFossil->spriteId].pos1.x; + gSprites[sFallingFossil->spriteId].data[1] = 1; } case 5: - for (i = 0; i < ROOT_FOSSIL_GFX_RANDOMIZER_LENGTH; i++) - sUnknown_0203CF0C->unkC[i] = i; + // Initialize disintegration pattern + for (i = 0; i < FOSSIL_DISINTEGRATE_LENGTH; i++) + sFallingFossil->disintegrateRand[i] = i; break; case 6: - for (i = 0; i < (ROOT_FOSSIL_GFX_RANDOMIZER_LENGTH * sizeof(u16)); i++) + // Randomize disintegration pattern + for (i = 0; i < FOSSIL_DISINTEGRATE_LENGTH * sizeof(u16); i++) { u16 rand1, rand2, temp; - - rand1 = Random() % 0x100; - rand2 = Random() % 0x100; - SWAP(sUnknown_0203CF0C->unkC[rand2], sUnknown_0203CF0C->unkC[rand1], temp); + rand1 = Random() % FOSSIL_DISINTEGRATE_LENGTH; + rand2 = Random() % FOSSIL_DISINTEGRATE_LENGTH; + SWAP(sFallingFossil->disintegrateRand[rand2], sFallingFossil->disintegrateRand[rand1], temp); } - gSprites[sUnknown_0203CF0C->spriteId].callback = sub_81BF248; + gSprites[sFallingFossil->spriteId].callback = SpriteCB_FallingFossil; break; case 7: - if (gSprites[sUnknown_0203CF0C->spriteId].callback != SpriteCallbackDummy) + // Wait for fossil to finish falling / disintegrating + if (gSprites[sFallingFossil->spriteId].callback != SpriteCallbackDummy) return; - DestroySprite(&gSprites[sUnknown_0203CF0C->spriteId]); - FREE_AND_SET_NULL(sUnknown_0203CF0C->unkC);; - FREE_AND_SET_NULL(sUnknown_0203CF0C->frameImage); - FREE_AND_SET_NULL(sUnknown_0203CF0C->frameImageTiles); - FREE_AND_SET_NULL(sUnknown_0203CF0C); + DestroySprite(&gSprites[sFallingFossil->spriteId]); + FREE_AND_SET_NULL(sFallingFossil->disintegrateRand);; + FREE_AND_SET_NULL(sFallingFossil->frameImage); + FREE_AND_SET_NULL(sFallingFossil->frameImageTiles); + FREE_AND_SET_NULL(sFallingFossil); break; case 8: EnableBothScriptContexts(); break; } - - gTasks[taskId].data[0]++; + gTasks[taskId].tState++; } -static void sub_81BF248(struct Sprite *sprite) +static void SpriteCB_FallingFossil(struct Sprite *sprite) { - if (sUnknown_0203CF0C->unk10 >= (ROOT_FOSSIL_GFX_RANDOMIZER_LENGTH)) + if (sFallingFossil->disintegrateIdx >= FOSSIL_DISINTEGRATE_LENGTH) { + // End animation sprite->callback = SpriteCallbackDummy; } else if (sprite->pos1.y >= 96) { + // Fossil has reached the ground, update disintegration animation u8 i; for (i = 0; i < 2; i++) - sub_81BF2B8(sUnknown_0203CF0C->frameImageTiles, sUnknown_0203CF0C->unkC[sUnknown_0203CF0C->unk10++], 0, 16, 0); + UpdateDisintegrationEffect(sFallingFossil->frameImageTiles, sFallingFossil->disintegrateRand[sFallingFossil->disintegrateIdx++], 0, 16, 0); StartSpriteAnim(sprite, 0); } else { + // Fossil is still falling sprite->pos1.y++; } } -static void sub_81BF2B8(u8* a, u16 b, u8 c, u8 d, u8 e) +static void UpdateDisintegrationEffect(u8* tiles, u16 randId, u8 c, u8 size, u8 offset) { - u8 r5, r4, r0, r2; - u16 var, var2; - u8 r2_1, r4_1; - u8 b2, c2; + u8 heightTiles, height, widthTiles, width; + u16 var, baseOffset; + u8 col, row; + u8 flag, tileMask; - r4 = b / d; - gUnknown_030012A8[0] = r4; + height = randId / size; + sDebug_DisintegrationData[0] = height; - r2 = b % d; - gUnknown_030012A8[1] = r2; + width = randId % size; + sDebug_DisintegrationData[1] = width; - r4_1 = r4 & 7; - r2_1 = r2 & 7; - gUnknown_030012A8[2] = r4 & 7; //should be using r4_1, but that doesn't match - gUnknown_030012A8[3] = r2 & 7; //" - - r0 = r2 / 8; - r5 = r4 / 8; + row = height & 7; + col = width & 7; + sDebug_DisintegrationData[2] = height & 7; + sDebug_DisintegrationData[3] = width & 7; - gUnknown_030012A8[4] = r2 / 8; //should be using r0, but that doesn't match - gUnknown_030012A8[5] = r4 / 8; //should be using r5, but that doesn't match + widthTiles = width / 8; + heightTiles = height / 8; + sDebug_DisintegrationData[4] = width / 8; + sDebug_DisintegrationData[5] = height / 8; - var = (d / 8) * (r5 * 64) + (r0 * 64); - gUnknown_030012A8[6] = var; + var = (size / 8) * (heightTiles * 64) + (widthTiles * 64); + sDebug_DisintegrationData[6] = var; - var2 = var + ((r4_1 * 8) + r2_1); - var2 /= 2; - gUnknown_030012A8[7] = var + ((r4_1 * 8) + r2_1); //should be using var2 with var2 being divided afterwards, but that doesn't match + baseOffset = var + ((row * 8) + col); + baseOffset /= 2; + sDebug_DisintegrationData[7] = var + ((row * 8) + col); - b2 = ((b % 2) ^ 1); - c2 = (c << (b2 << 2)) | 15 << (((b2 ^ 1) << 2)); - a[var2 + (e * 32)] &= c2; + flag = ((randId % 2) ^ 1); + tileMask = (c << (flag << 2)) | 15 << (((flag ^ 1) << 2)); + tiles[baseOffset + (offset * 32)] &= tileMask; } -- cgit v1.2.3 From fe89a4d1471413a03c1b24b8d5721b04b20b04ae Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 2 Jul 2021 00:52:36 -0400 Subject: Label remaining region_map symbols --- include/region_map.h | 2 +- src/pokenav_region_map.c | 4 +++- src/region_map.c | 18 ++++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/region_map.h b/include/region_map.h index 97364abd8..02d711afa 100644 --- a/include/region_map.h +++ b/include/region_map.h @@ -111,7 +111,7 @@ void PokedexAreaScreen_UpdateRegionMapVariablesAndVideoRegs(s16 x, s16 y); void CB2_OpenFlyMap(void); bool8 IsRegionMapZoomed(void); void TrySetPlayerIconBlink(void); -void sub_8123030(u16 color, u32 coeff); +void BlendRegionMap(u16 color, u32 coeff); void SetRegionMapDataForZoom(void); extern const struct RegionMapLocation gRegionMapEntries[]; diff --git a/src/pokenav_region_map.c b/src/pokenav_region_map.c index 2dd2e4408..3d53bc98a 100755 --- a/src/pokenav_region_map.c +++ b/src/pokenav_region_map.c @@ -327,7 +327,9 @@ static u32 LoopedTask_OpenRegionMap(s32 taskState) } else { - sub_8123030(RGB_BLACK, 6); + // Dim the region map when zoom is disabled + // (when the player is off the map) + BlendRegionMap(RGB_BLACK, 6); } return LT_INC_AND_PAUSE; case 2: diff --git a/src/region_map.c b/src/region_map.c index 27e035199..335323421 100644 --- a/src/region_map.c +++ b/src/region_map.c @@ -71,7 +71,7 @@ static EWRAM_DATA struct { bool8 choseFlyLocation; } *sFlyMap = NULL; -static bool32 gUnknown_03001180; +static bool32 sDrawFlyDestTextWindow; // Static ROM declarations @@ -621,7 +621,7 @@ bool8 LoadRegionMapGfx(void) return TRUE; } -void sub_8123030(u16 color, u32 coeff) +void BlendRegionMap(u16 color, u32 coeff) { BlendPalettes(0x380, coeff, color); CpuCopy16(gPlttBufferFaded + 0x70, gPlttBufferUnfaded + 0x70, 0x60); @@ -1696,7 +1696,7 @@ void CB2_OpenFlyMap(void) CreateRegionMapPlayerIcon(1, 1); sFlyMap->mapSecId = sFlyMap->regionMap.mapSecId; StringFill(sFlyMap->nameBuffer, CHAR_SPACE, MAP_NAME_LENGTH); - gUnknown_03001180 = TRUE; + sDrawFlyDestTextWindow = TRUE; DrawFlyDestTextWindow(); gMain.state++; break; @@ -1782,30 +1782,32 @@ static void DrawFlyDestTextWindow(void) name = sMultiNameFlyDestinations[i].name[sFlyMap->regionMap.posWithinMapSec]; AddTextPrinterParameterized(1, 1, name, GetStringRightAlignXOffset(1, name, 96), 17, 0, NULL); ScheduleBgCopyTilemapToVram(0); - gUnknown_03001180 = TRUE; + sDrawFlyDestTextWindow = TRUE; } break; } } if (!namePrinted) { - if (gUnknown_03001180 == TRUE) + if (sDrawFlyDestTextWindow == TRUE) { ClearStdWindowAndFrameToTransparent(1, FALSE); DrawStdFrameWithCustomTileAndPalette(0, FALSE, 101, 13); } else { + // Window is already drawn, just empty it FillWindowPixelBuffer(0, PIXEL_FILL(1)); } AddTextPrinterParameterized(0, 1, sFlyMap->regionMap.mapSecName, 0, 1, 0, NULL); ScheduleBgCopyTilemapToVram(0); - gUnknown_03001180 = FALSE; + sDrawFlyDestTextWindow = FALSE; } } else { - if (gUnknown_03001180 == TRUE) + // Selection is on MAPSECTYPE_NONE, draw empty fly destination text window + if (sDrawFlyDestTextWindow == TRUE) { ClearStdWindowAndFrameToTransparent(1, FALSE); DrawStdFrameWithCustomTileAndPalette(0, FALSE, 101, 13); @@ -1813,7 +1815,7 @@ static void DrawFlyDestTextWindow(void) FillWindowPixelBuffer(0, PIXEL_FILL(1)); CopyWindowToVram(0, 2); ScheduleBgCopyTilemapToVram(0); - gUnknown_03001180 = FALSE; + sDrawFlyDestTextWindow = FALSE; } } -- cgit v1.2.3 From d73b3c05c63eb4a5ed73f69edfaadf5666612825 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 2 Jul 2021 01:02:28 -0400 Subject: Label remaining hall_of_fame symbols --- src/hall_of_fame.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/hall_of_fame.c b/src/hall_of_fame.c index 3eb8d3f0a..5746260f3 100644 --- a/src/hall_of_fame.c +++ b/src/hall_of_fame.c @@ -66,13 +66,12 @@ static EWRAM_DATA struct HofGfx *sHofGfxPtr = NULL; extern struct MusicPlayerInfo gMPlayInfo_BGM; -// this file's functions static void ClearVramOamPltt_LoadHofPal(void); static void LoadHofGfx(void); static void InitHofBgs(void); static bool8 CreateHofConfettiSprite(void); static void StartCredits(void); -static bool8 sub_8175024(void); +static bool8 LoadHofBgs(void); static void Task_Hof_InitMonData(u8 taskId); static void Task_Hof_InitTeamSaveData(u8 taskId); static void Task_Hof_SetMonDisplayTask(u8 taskId); @@ -104,7 +103,6 @@ static void HallOfFame_PrintPlayerInfo(u8 unused1, u8 unused2); static void Task_DoDomeConfetti(u8 taskId); static void SpriteCB_HofConfetti(struct Sprite* sprite); -// const rom data static const struct BgTemplate sHof_BgTemplates[] = { { @@ -136,12 +134,19 @@ static const struct BgTemplate sHof_BgTemplates[] = }, }; -static const struct WindowTemplate sHof_WindowTemplate = {0, 2, 2, 0xE, 6, 0xE, 1}; +static const struct WindowTemplate sHof_WindowTemplate = { + .bg = 0, + .tilemapLeft = 2, + .tilemapTop = 2, + .width = 14, + .height = 6, + .paletteNum = 14, + .baseBlock = 1 +}; static const u8 sMonInfoTextColors[4] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY}; static const u8 sPlayerInfoTextColors[4] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}; - -static const u8 sUnused_085E538C[] = {4, 5, 0, 0}; +static const u8 sUnusedTextColors[4] = {TEXT_COLOR_RED, TEXT_COLOR_LIGHT_RED, TEXT_COLOR_TRANSPARENT}; static const struct CompressedSpriteSheet sSpriteSheet_Confetti[] = { @@ -383,7 +388,7 @@ static bool8 InitHallOfFameScreen(void) gMain.state++; break; case 3: - if (!sub_8175024()) + if (!LoadHofBgs()) { SetVBlankCallback(VBlankCB_HallOfFame); BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK); @@ -819,7 +824,7 @@ void CB2_DoHallOfFamePC(void) gMain.state++; break; case 3: - if (!sub_8175024()) + if (!LoadHofBgs()) { struct HallofFameTeam *fameTeam = (struct HallofFameTeam*)(gDecompressionBuffer); fameTeam->mon[0] = sDummyFameMon; @@ -1301,7 +1306,7 @@ static void InitHofBgs(void) ChangeBgY(3, 0, 0); } -static bool8 sub_8175024(void) +static bool8 LoadHofBgs(void) { switch (sHofGfxPtr->state) { -- cgit v1.2.3 From 8f43d1ebebfec0dd021fb2476d39979c2a77ce3c Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 2 Jul 2021 01:45:23 -0400 Subject: Document smart shopper TV show --- data/text/tv.inc | 26 ++++++------- include/constants/tv.h | 15 ++++++++ include/event_scripts.h | 26 ++++++------- src/tv.c | 99 ++++++++++++++++++++++++++----------------------- 4 files changed, 94 insertions(+), 72 deletions(-) diff --git a/data/text/tv.inc b/data/text/tv.inc index 287ce7f00..311f2ddd2 100644 --- a/data/text/tv.inc +++ b/data/text/tv.inc @@ -1027,7 +1027,7 @@ gTVPokemonTodaySuccessfulText11:: @ 08283A5F .string "BIG BRO: Remember, it could be your\n" .string "POKéMON in the spotlight next time!$" -gTVTodaysSmartShopperText00:: @ 08283B05 +SmartShopper_Text_Intro:: @ 08283B05 .string "Hello!\p" .string "It's time for TODAY'S SMART SHOPPER.\p" .string "INTERVIEWER: How are you, viewers?\p" @@ -1036,7 +1036,7 @@ gTVTodaysSmartShopperText00:: @ 08283B05 .string "Let's check on what the hot sellers\n" .string "have been recently.$" -gTVTodaysSmartShopperText01:: @ 08283BAF +SmartShopper_Text_ClerkNormal:: @ 08283BAF .string "Let's interview the clerk to get the\n" .string "lowdown.\p" .string "Hi, how's your business?\p" @@ -1046,7 +1046,7 @@ gTVTodaysSmartShopperText01:: @ 08283BAF .string "Why, just the other day a TRAINER\n" .string "named {STR_VAR_1} bought {STR_VAR_3}.$" -gTVTodaysSmartShopperText02:: @ 08283C81 +SmartShopper_Text_RandomComment1:: @ 08283C81 .string "INTERVIEWER: The TRAINER bought\n" .string "{STR_VAR_3} {STR_VAR_2}S? That's a haul!\p" .string "If I may say so, {STR_VAR_1} must have\n" @@ -1055,13 +1055,13 @@ gTVTodaysSmartShopperText02:: @ 08283C81 .string "For traveling, {STR_VAR_2}S are so\n" .string "important!$" -gTVTodaysSmartShopperText03:: @ 08283D32 +SmartShopper_Text_RandomComment2:: @ 08283D32 .string "INTERVIEWER: Speaking of the item\n" .string "{STR_VAR_2}, I just bought {STR_VAR_3} of\l" .string "them recently.\p" .string "After all, {STR_VAR_2}'s a great item!$" -gTVTodaysSmartShopperText04:: @ 08283D99 +SmartShopper_Text_RandomComment3:: @ 08283D99 .string "INTERVIEWER: {STR_VAR_2}?!\n" .string "But {STR_VAR_3} of them?!\p" .string "I didn't think there would be anyone\n" @@ -1069,7 +1069,7 @@ gTVTodaysSmartShopperText04:: @ 08283D99 .string "My goodness, I can only afford one or\n" .string "two at a time…$" -gTVTodaysSmartShopperText05:: @ 08283E28 +SmartShopper_Text_RandomComment4:: @ 08283E28 .string "INTERVIEWER: One time, I bought\n" .string "a whole lot of the item {STR_VAR_2}.\p" .string "But it turned out to be too many.\n" @@ -1079,21 +1079,21 @@ gTVTodaysSmartShopperText05:: @ 08283E28 .string "Oops!\p" .string "There's no point talking about me!$" -gTVTodaysSmartShopperText06:: @ 08283F01 +SmartShopper_Text_SecondItem:: @ 08283F01 .string "CLERK: {STR_VAR_1} also bought the item\n" .string "{STR_VAR_2} in bulk, taking {STR_VAR_3}.\p" .string "INTERVIEWER: Oh, that's smart.\n" .string "{STR_VAR_2}'s a very good item, too.$" -gTVTodaysSmartShopperText07:: @ 08283F72 +SmartShopper_Text_ThirdItem:: @ 08283F72 .string "CLERK: And, the TRAINER also bought\n" .string "{STR_VAR_3} of the item {STR_VAR_2}.$" -gTVTodaysSmartShopperText08:: @ 08283FA9 +SmartShopper_Text_DuringSale:: @ 08283FA9 .string "CLERK: Plus, it was during a big sale.\n" .string "That's smart shopping.$" -gTVTodaysSmartShopperText09:: @ 08283FE7 +SmartShopper_Text_OutroNormal:: @ 08283FE7 .string "INTERVIEWER: Hmm… {STR_VAR_1} sounds like\n" .string "quite the shrewd bargain hunter!\p" .string "In total, {STR_VAR_1}'s purchases came to…\p" @@ -1102,11 +1102,11 @@ gTVTodaysSmartShopperText09:: @ 08283FE7 .string "Oops! We're out of time!\n" .string "See you on our next broadcast!$" -gTVTodaysSmartShopperText10:: @ 0828409E +SmartShopper_Text_IsVIP:: @ 0828409E .string "CLERK: {STR_VAR_1} is a VIP customer,\n" .string "no doubt about it.$" -gTVTodaysSmartShopperText11:: @ 082840CE +SmartShopper_Text_ClerkMax:: @ 082840CE .string "Let's interview the clerk to get the\n" .string "lowdown.\p" .string "Hi, how's your business?\p" @@ -1127,7 +1127,7 @@ gTVTodaysSmartShopperText11:: @ 082840CE .string "CLERK: {STR_VAR_1} is a VIP customer,\n" .string "no doubt about it.$" -gTVTodaysSmartShopperText12:: @ 082842E6 +SmartShopper_Text_OutroMax:: @ 082842E6 .string "INTERVIEWER: Hmm…\n" .string "That is amazing.\p" .string "But why would the TRAINER need to buy\n" diff --git a/include/constants/tv.h b/include/constants/tv.h index 1b28f6e6e..095a6ddca 100644 --- a/include/constants/tv.h +++ b/include/constants/tv.h @@ -249,6 +249,21 @@ #define CONTESTLADYLIVE_STATE_LOST 2 #define CONTESTLADYLIVE_STATE_LOST_BADLY 3 +// TV Show states for Smart Shopper +#define SMARTSHOPPER_STATE_INTRO 0 +#define SMARTSHOPPER_STATE_CLERK_NORMAL 1 +#define SMARTSHOPPER_STATE_RAND_COMMENT_1 2 +#define SMARTSHOPPER_STATE_RAND_COMMENT_2 3 +#define SMARTSHOPPER_STATE_RAND_COMMENT_3 4 +#define SMARTSHOPPER_STATE_RAND_COMMENT_4 5 +#define SMARTSHOPPER_STATE_SECOND_ITEM 6 +#define SMARTSHOPPER_STATE_THIRD_ITEM 7 +#define SMARTSHOPPER_STATE_DURING_SALE 8 +#define SMARTSHOPPER_STATE_OUTRO_NORMAL 9 +#define SMARTSHOPPER_STATE_IS_VIP 10 +#define SMARTSHOPPER_STATE_CLERK_MAX 11 +#define SMARTSHOPPER_STATE_OUTRO_MAX 12 + #define SMARTSHOPPER_NUM_ITEMS 3 #endif //GUARD_CONSTANTS_TV_H diff --git a/include/event_scripts.h b/include/event_scripts.h index 925b4389d..3340da6f5 100644 --- a/include/event_scripts.h +++ b/include/event_scripts.h @@ -108,19 +108,19 @@ extern const u8 gTVPokemonTodaySuccessfulText08[]; extern const u8 gTVPokemonTodaySuccessfulText09[]; extern const u8 gTVPokemonTodaySuccessfulText10[]; extern const u8 gTVPokemonTodaySuccessfulText11[]; -extern const u8 gTVTodaysSmartShopperText00[]; -extern const u8 gTVTodaysSmartShopperText01[]; -extern const u8 gTVTodaysSmartShopperText02[]; -extern const u8 gTVTodaysSmartShopperText03[]; -extern const u8 gTVTodaysSmartShopperText04[]; -extern const u8 gTVTodaysSmartShopperText05[]; -extern const u8 gTVTodaysSmartShopperText06[]; -extern const u8 gTVTodaysSmartShopperText07[]; -extern const u8 gTVTodaysSmartShopperText08[]; -extern const u8 gTVTodaysSmartShopperText09[]; -extern const u8 gTVTodaysSmartShopperText10[]; -extern const u8 gTVTodaysSmartShopperText11[]; -extern const u8 gTVTodaysSmartShopperText12[]; +extern const u8 SmartShopper_Text_Intro[]; +extern const u8 SmartShopper_Text_ClerkNormal[]; +extern const u8 SmartShopper_Text_RandomComment1[]; +extern const u8 SmartShopper_Text_RandomComment2[]; +extern const u8 SmartShopper_Text_RandomComment3[]; +extern const u8 SmartShopper_Text_RandomComment4[]; +extern const u8 SmartShopper_Text_SecondItem[]; +extern const u8 SmartShopper_Text_ThirdItem[]; +extern const u8 SmartShopper_Text_DuringSale[]; +extern const u8 SmartShopper_Text_OutroNormal[]; +extern const u8 SmartShopper_Text_IsVIP[]; +extern const u8 SmartShopper_Text_ClerkMax[]; +extern const u8 SmartShopper_Text_OutroMax[]; extern const u8 gTVWorldOfMastersText00[]; extern const u8 gTVWorldOfMastersText01[]; extern const u8 gTVWorldOfMastersText02[]; diff --git a/src/tv.c b/src/tv.c index 50adde3f4..b7b490aa3 100644 --- a/src/tv.c +++ b/src/tv.c @@ -335,19 +335,19 @@ static const u8 *const sTVPokemonTodaySuccessfulTextGroup[] = { }; static const u8 *const sTVTodaysSmartShopperTextGroup[] = { - gTVTodaysSmartShopperText00, - gTVTodaysSmartShopperText01, - gTVTodaysSmartShopperText02, - gTVTodaysSmartShopperText03, - gTVTodaysSmartShopperText04, - gTVTodaysSmartShopperText05, - gTVTodaysSmartShopperText06, - gTVTodaysSmartShopperText07, - gTVTodaysSmartShopperText08, - gTVTodaysSmartShopperText09, - gTVTodaysSmartShopperText10, - gTVTodaysSmartShopperText11, - gTVTodaysSmartShopperText12 + [SMARTSHOPPER_STATE_INTRO] = SmartShopper_Text_Intro, + [SMARTSHOPPER_STATE_CLERK_NORMAL] = SmartShopper_Text_ClerkNormal, + [SMARTSHOPPER_STATE_RAND_COMMENT_1] = SmartShopper_Text_RandomComment1, + [SMARTSHOPPER_STATE_RAND_COMMENT_2] = SmartShopper_Text_RandomComment2, + [SMARTSHOPPER_STATE_RAND_COMMENT_3] = SmartShopper_Text_RandomComment3, + [SMARTSHOPPER_STATE_RAND_COMMENT_4] = SmartShopper_Text_RandomComment4, + [SMARTSHOPPER_STATE_SECOND_ITEM] = SmartShopper_Text_SecondItem, + [SMARTSHOPPER_STATE_THIRD_ITEM] = SmartShopper_Text_ThirdItem, + [SMARTSHOPPER_STATE_DURING_SALE] = SmartShopper_Text_DuringSale, + [SMARTSHOPPER_STATE_OUTRO_NORMAL] = SmartShopper_Text_OutroNormal, + [SMARTSHOPPER_STATE_IS_VIP] = SmartShopper_Text_IsVIP, + [SMARTSHOPPER_STATE_CLERK_MAX] = SmartShopper_Text_ClerkMax, + [SMARTSHOPPER_STATE_OUTRO_MAX] = SmartShopper_Text_OutroMax }; static const u8 *const sTVBravoTrainerTextGroup[] = { @@ -2785,7 +2785,7 @@ size_t CountDigits(int value) return 1; } -static void sub_80EF40C(u8 varIdx, TVShow *show) +static void SmartShopper_BufferPurchaseTotal(u8 varIdx, TVShow *show) { u8 i; int price; @@ -4460,78 +4460,85 @@ static void DoTVShowTodaysSmartShopper(void) state = sTVShowState; switch(state) { - case 0: + case SMARTSHOPPER_STATE_INTRO: TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); GetMapName(gStringVar2, show->smartshopperShow.shopLocation, 0); if (show->smartshopperShow.itemAmounts[0] >= 255) - sTVShowState = 11; + sTVShowState = SMARTSHOPPER_STATE_CLERK_MAX; else - sTVShowState = 1; + sTVShowState = SMARTSHOPPER_STATE_CLERK_NORMAL; break; - case 1: + case SMARTSHOPPER_STATE_CLERK_NORMAL: TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[0])); ConvertIntToDecimalString(2, show->smartshopperShow.itemAmounts[0]); - sTVShowState += 1 + (Random() % 4); + // Pick a random comment (SMARTSHOPPER_STATE_RAND_COMMENT_#) + sTVShowState += SMARTSHOPPER_STATE_CLERK_NORMAL + (Random() % (SMARTSHOPPER_STATE_RAND_COMMENT_4 - SMARTSHOPPER_STATE_RAND_COMMENT_1 + 1)); break; - case 2: - case 4: - case 5: + case SMARTSHOPPER_STATE_RAND_COMMENT_1: + case SMARTSHOPPER_STATE_RAND_COMMENT_3: + case SMARTSHOPPER_STATE_RAND_COMMENT_4: if (show->smartshopperShow.itemIds[1] != ITEM_NONE) - sTVShowState = 6; + sTVShowState = SMARTSHOPPER_STATE_SECOND_ITEM; else - sTVShowState = 10; + sTVShowState = SMARTSHOPPER_STATE_IS_VIP; break; - case 3: + case SMARTSHOPPER_STATE_RAND_COMMENT_2: ConvertIntToDecimalString(2, show->smartshopperShow.itemAmounts[0] + 1); if (show->smartshopperShow.itemIds[1] != ITEM_NONE) - sTVShowState = 6; + sTVShowState = SMARTSHOPPER_STATE_SECOND_ITEM; else - sTVShowState = 10; + sTVShowState = SMARTSHOPPER_STATE_IS_VIP; break; - case 6: + case SMARTSHOPPER_STATE_SECOND_ITEM: + // Clerk describes 2nd type of item player purchased StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[1])); ConvertIntToDecimalString(2, show->smartshopperShow.itemAmounts[1]); if (show->smartshopperShow.itemIds[2] != ITEM_NONE) - sTVShowState = 7; + sTVShowState = SMARTSHOPPER_STATE_THIRD_ITEM; else if (show->smartshopperShow.priceReduced == TRUE) - sTVShowState = 8; + sTVShowState = SMARTSHOPPER_STATE_DURING_SALE; else - sTVShowState = 9; + sTVShowState = SMARTSHOPPER_STATE_OUTRO_NORMAL; break; - case 7: + case SMARTSHOPPER_STATE_THIRD_ITEM: + // Clerk describes 3rd type of item player purchased StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[2])); ConvertIntToDecimalString(2, show->smartshopperShow.itemAmounts[2]); if (show->smartshopperShow.priceReduced == TRUE) - sTVShowState = 8; + sTVShowState = SMARTSHOPPER_STATE_DURING_SALE; else - sTVShowState = 9; + sTVShowState = SMARTSHOPPER_STATE_OUTRO_NORMAL; break; - case 8: + case SMARTSHOPPER_STATE_DURING_SALE: if (show->smartshopperShow.itemAmounts[0] >= 255) - sTVShowState = 12; + sTVShowState = SMARTSHOPPER_STATE_OUTRO_MAX; else - sTVShowState = 9; + sTVShowState = SMARTSHOPPER_STATE_OUTRO_NORMAL; break; - case 9: - sub_80EF40C(1, show); + case SMARTSHOPPER_STATE_OUTRO_NORMAL: + SmartShopper_BufferPurchaseTotal(1, show); TVShowDone(); break; - case 10: + case SMARTSHOPPER_STATE_IS_VIP: + // Clerk says customer is a VIP + // Said if player only purchased one type of item if (show->smartshopperShow.priceReduced == TRUE) - sTVShowState = 8; + sTVShowState = SMARTSHOPPER_STATE_DURING_SALE; else - sTVShowState = 9; + sTVShowState = SMARTSHOPPER_STATE_OUTRO_NORMAL; break; - case 11: + case SMARTSHOPPER_STATE_CLERK_MAX: + // Clerk's comments if player purchased maximum number of 1st item TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[0])); if (show->smartshopperShow.priceReduced == TRUE) - sTVShowState = 8; + sTVShowState = SMARTSHOPPER_STATE_DURING_SALE; else - sTVShowState = 12; + sTVShowState = SMARTSHOPPER_STATE_OUTRO_MAX; break; - case 12: + case SMARTSHOPPER_STATE_OUTRO_MAX: + // Outro comments if player purchased maximum number of 1st item TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language); TVShowDone(); break; -- cgit v1.2.3 From 64d06f4c8fe9710863a370911cc4dd3405992d31 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 2 Jul 2021 02:40:10 -0400 Subject: Condense battle AI scripts, minor clean up --- data/battle_ai_scripts.s | 255 +++++----------------------------------- include/constants/battle_ai.h | 28 ++--- src/battle_ai_script_commands.c | 29 +++-- 3 files changed, 60 insertions(+), 252 deletions(-) diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 56be92c5e..4867f4261 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -7,6 +7,7 @@ #include "constants/hold_effects.h" #include "constants/pokemon.h" .include "asm/macros/battle_ai_script.inc" + .include "constants/constants.inc" .section script_data, "aw", %progbits @@ -17,11 +18,11 @@ gBattleAI_ScriptsTable:: @ 82DBEF8 .4byte AI_CheckViability @ AI_SCRIPT_CHECK_VIABILITY .4byte AI_SetupFirstTurn @ AI_SCRIPT_SETUP_FIRST_TURN .4byte AI_Risky @ AI_SCRIPT_RISKY - .4byte AI_PreferStrongestMove @ AI_SCRIPT_PREFER_STRONGEST_MOVE + .4byte AI_PreferPowerExtremes @ AI_SCRIPT_PREFER_POWER_EXTREMES .4byte AI_PreferBatonPass @ AI_SCRIPT_PREFER_BATON_PASS .4byte AI_DoubleBattle @ AI_SCRIPT_DOUBLE_BATTLE .4byte AI_HPAware @ AI_SCRIPT_HP_AWARE - .4byte AI_Unknown @ AI_SCRIPT_UNKNOWN + .4byte AI_TrySunnyDayStart @ AI_SCRIPT_TRY_SUNNY_DAY_START .4byte AI_Ret .4byte AI_Ret .4byte AI_Ret @@ -50,8 +51,7 @@ AI_CheckBadMove: if_move MOVE_FISSURE, AI_CBM_CheckIfNegatesType if_move MOVE_HORN_DRILL, AI_CBM_CheckIfNegatesType get_how_powerful_move_is - if_equal 0, AI_CheckBadMove_CheckSoundproof - + if_equal MOVE_POWER_OTHER, AI_CheckBadMove_CheckSoundproof AI_CBM_CheckIfNegatesType: @ 82DBF92 if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 get_ability AI_TARGET @@ -84,11 +84,9 @@ CheckIfWonderGuardCancelsMove: @ 82DBFE4 CheckIfLevitateCancelsGroundMove: @ 82DBFEF get_curr_move_type if_equal_ TYPE_GROUND, Score_Minus10 - AI_CheckBadMove_CheckSoundproof_: @ 82DBFF7 get_how_powerful_move_is - if_equal 0, AI_CheckBadMove_CheckSoundproof - + if_equal MOVE_POWER_OTHER, AI_CheckBadMove_CheckSoundproof @ Pointless check AI_CheckBadMove_CheckSoundproof: @ 82DBFFE get_ability AI_TARGET if_not_equal ABILITY_SOUNDPROOF, AI_CheckBadMove_CheckEffect @@ -101,7 +99,6 @@ AI_CheckBadMove_CheckSoundproof: @ 82DBFFE if_move MOVE_UPROAR, Score_Minus10 if_move MOVE_METAL_SOUND, Score_Minus10 if_move MOVE_GRASS_WHISTLE, Score_Minus10 - AI_CheckBadMove_CheckEffect: @ 82DC045 if_effect EFFECT_SLEEP, AI_CBM_Sleep if_effect EFFECT_EXPLOSION, AI_CBM_Explosion @@ -247,7 +244,6 @@ AI_CBM_DreamEater: @ 82DC330 AI_CBM_BellyDrum: @ 82DC341 if_hp_less_than AI_USER, 51, Score_Minus10 - AI_CBM_AttackUp: @ 82DC348 if_stat_level_equal AI_USER, STAT_ATK, MAX_STAT_STAGE, Score_Minus10 end @@ -307,7 +303,6 @@ AI_CBM_AccDown: @ 82DC3D9 AI_CBM_EvasionDown: @ 82DC3EE if_stat_level_equal AI_TARGET, STAT_EVASION, MIN_STAT_STAGE, Score_Minus10 - CheckIfAbilityBlocksStatChange: @ 82DC3F6 get_ability AI_TARGET if_equal ABILITY_CLEAR_BODY, Score_Minus10 @@ -368,7 +363,6 @@ AI_CBM_OneHitKO: @ 82DC4D0 AI_CBM_Magnitude: @ 82DC4E5 get_ability AI_TARGET if_equal ABILITY_LEVITATE, Score_Minus10 - AI_CBM_HighRiskForDamage: @ 82DC4ED if_type_effectiveness AI_EFFECTIVENESS_x0, Score_Minus10 get_ability AI_TARGET @@ -486,7 +480,6 @@ AI_CBM_Safeguard: @ 82DC635 AI_CBM_Memento: @ 82DC640 if_stat_level_equal AI_TARGET, STAT_ATK, MIN_STAT_STAGE, Score_Minus10 if_stat_level_equal AI_TARGET, STAT_SPATK, MIN_STAT_STAGE, Score_Minus8 - AI_CBM_BatonPass: @ 82DC650 count_usable_party_mons AI_USER if_equal 0, Score_Minus10 @@ -510,7 +503,7 @@ AI_CBM_FutureSight: @ 82DC669 AI_CBM_FakeOut: @ 82DC680 is_first_turn_for AI_USER - if_equal 0, Score_Minus10 + if_equal FALSE, Score_Minus10 end AI_CBM_Stockpile: @ 82DC689 @@ -558,7 +551,7 @@ AI_CBM_Ingrain: @ 82DC6F4 AI_CBM_Recycle: @ 82DC6FF get_used_held_item AI_USER - if_equal 0, Score_Minus10 + if_equal ITEM_NONE, Score_Minus10 end AI_CBM_Imprison: @ 82DC708 @@ -788,7 +781,6 @@ AI_CV_Sleep: @ 82DCA92 AI_CV_SleepEncourageSlpDamage: @ 82DCAA5 if_random_less_than 128, AI_CV_Sleep_End score +1 - AI_CV_Sleep_End: @ 82DCAAD end @@ -800,7 +792,6 @@ AI_CV_Absorb: @ 82DCAAE AI_CV_AbsorbEncourageMaybe: @ 82DCABF if_random_less_than 50, AI_CV_Absorb_End score -3 - AI_CV_Absorb_End: @ 82DCAC7 end @@ -810,7 +801,6 @@ AI_CV_SelfKO: @ 82DCAC8 if_stat_level_less_than AI_TARGET, STAT_EVASION, 10, AI_CV_SelfKO_Encourage1 if_random_less_than 128, AI_CV_SelfKO_Encourage1 score -1 - AI_CV_SelfKO_Encourage1: @ 82DCAE2 if_hp_less_than AI_USER, 80, AI_CV_SelfKO_Encourage2 if_target_faster AI_CV_SelfKO_Encourage2 @@ -821,7 +811,6 @@ AI_CV_SelfKO_Encourage2: @ 82DCAFA if_hp_more_than AI_USER, 50, AI_CV_SelfKO_Encourage4 if_random_less_than 128, AI_CV_SelfKO_Encourage3 score +1 - AI_CV_SelfKO_Encourage3: @ 82DCB09 if_hp_more_than AI_USER, 30, AI_CV_SelfKO_End if_random_less_than 50, AI_CV_SelfKO_End @@ -831,7 +820,6 @@ AI_CV_SelfKO_Encourage3: @ 82DCB09 AI_CV_SelfKO_Encourage4: @ 82DCB1D if_random_less_than 50, AI_CV_SelfKO_End score -1 - AI_CV_SelfKO_End: @ 82DCB25 end @@ -842,7 +830,6 @@ AI_CV_DreamEater: @ 82DCB26 AI_CV_DreamEater_ScoreDown1: @ 82DCB37 score -1 - AI_CV_DreamEater_End: @ 82DCB39 end @@ -859,7 +846,6 @@ AI_CV_MirrorMove2: @ 82DCB58 if_in_hwords AI_CV_MirrorMove_EncouragedMovesToMirror, AI_CV_MirrorMove_End if_random_less_than 80, AI_CV_MirrorMove_End score -1 - AI_CV_MirrorMove_End: @ 82DCB6B end @@ -915,15 +901,12 @@ AI_CV_AttackUp2: @ 82DCBD1 if_hp_not_equal AI_USER, 100, AI_CV_AttackUp3 if_random_less_than 128, AI_CV_AttackUp3 score +2 - AI_CV_AttackUp3: @ 82DCBE0 if_hp_more_than AI_USER, 70, AI_CV_AttackUp_End if_hp_less_than AI_USER, 40, AI_CV_AttackUp_ScoreDown2 if_random_less_than 40, AI_CV_AttackUp_End - AI_CV_AttackUp_ScoreDown2: @ 82DCBF4 score -2 - AI_CV_AttackUp_End: @ 82DCBF6 end @@ -937,11 +920,9 @@ AI_CV_DefenseUp2: @ 82DCC0C if_hp_not_equal AI_USER, 100, AI_CV_DefenseUp3 if_random_less_than 128, AI_CV_DefenseUp3 score +2 - AI_CV_DefenseUp3: @ 82DCC1B if_hp_less_than AI_USER, 70, AI_CV_DefenseUp4 if_random_less_than 200, AI_CV_DefenseUp_End - AI_CV_DefenseUp4: @ 82DCC28 if_hp_less_than AI_USER, 40, AI_CV_DefenseUp_ScoreDown2 get_last_used_bank_move AI_TARGET @@ -951,13 +932,10 @@ AI_CV_DefenseUp4: @ 82DCC28 get_move_type_from_result if_not_in_bytes AI_CV_DefenseUp_PhysicalTypes, AI_CV_DefenseUp_ScoreDown2 if_random_less_than 60, AI_CV_DefenseUp_End - AI_CV_DefenseUp5: @ 82DCC4A if_random_less_than 60, AI_CV_DefenseUp_End - AI_CV_DefenseUp_ScoreDown2: @ 82DCC50 score -2 - AI_CV_DefenseUp_End: @ 82DCC52 end @@ -981,7 +959,6 @@ AI_CV_SpeedUp: @ 82DCC5D AI_CV_SpeedUp2: @ 82DCC6A if_random_less_than 70, AI_CV_SpeedUp_End score +3 - AI_CV_SpeedUp_End: @ 82DCC72 end @@ -995,15 +972,12 @@ AI_CV_SpAtkUp2: @ 82DCC88 if_hp_not_equal AI_USER, 100, AI_CV_SpAtkUp3 if_random_less_than 128, AI_CV_SpAtkUp3 score +2 - AI_CV_SpAtkUp3: @ 82DCC97 if_hp_more_than AI_USER, 70, AI_CV_SpAtkUp_End if_hp_less_than AI_USER, 40, AI_CV_SpAtkUp_ScoreDown2 if_random_less_than 70, AI_CV_SpAtkUp_End - AI_CV_SpAtkUp_ScoreDown2: @ 82DCCAB score -2 - AI_CV_SpAtkUp_End: @ 82DCCAD end @@ -1017,11 +991,9 @@ AI_CV_SpDefUp2: @ 82DCCC3 if_hp_not_equal AI_USER, 100, AI_CV_SpDefUp3 if_random_less_than 128, AI_CV_SpDefUp3 score +2 - AI_CV_SpDefUp3: @ 82DCCD2 if_hp_less_than AI_USER, 70, AI_CV_SpDefUp4 if_random_less_than 200, AI_CV_SpDefUp_End - AI_CV_SpDefUp4: @ 82DCCDF if_hp_less_than AI_USER, 40, AI_CV_SpDefUp_ScoreDown2 get_last_used_bank_move AI_TARGET @@ -1031,13 +1003,10 @@ AI_CV_SpDefUp4: @ 82DCCDF get_move_type_from_result if_in_bytes AI_CV_SpDefUp_PhysicalTypes, AI_CV_SpDefUp_ScoreDown2 if_random_less_than 60, AI_CV_SpDefUp_End - AI_CV_SpDefUp5: @ 82DCD01 if_random_less_than 60, AI_CV_SpDefUp_End - AI_CV_SpDefUp_ScoreDown2: @ 82DCD07 score -2 - AI_CV_SpDefUp_End: @ 82DCD09 end @@ -1057,11 +1026,9 @@ AI_CV_AccuracyUp: if_stat_level_less_than AI_USER, STAT_ACC, 9, AI_CV_AccuracyUp2 if_random_less_than 50, AI_CV_AccuracyUp2 score -2 - AI_CV_AccuracyUp2: if_hp_more_than AI_USER, 70, AI_CV_AccuracyUp_End score -2 - AI_CV_AccuracyUp_End: end @@ -1069,46 +1036,37 @@ AI_CV_EvasionUp: if_hp_less_than AI_USER, 90, AI_CV_EvasionUp2 if_random_less_than 100, AI_CV_EvasionUp2 score +3 - AI_CV_EvasionUp2: if_stat_level_less_than AI_USER, STAT_EVASION, 9, AI_CV_EvasionUp3 if_random_less_than 128, AI_CV_EvasionUp3 score -1 - AI_CV_EvasionUp3: if_not_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_EvasionUp5 if_hp_more_than AI_USER, 50, AI_CV_EvasionUp4 if_random_less_than 80, AI_CV_EvasionUp5 - AI_CV_EvasionUp4: if_random_less_than 50, AI_CV_EvasionUp5 score +3 - AI_CV_EvasionUp5: if_not_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_EvasionUp6 if_random_less_than 70, AI_CV_EvasionUp6 score +3 - AI_CV_EvasionUp6: if_not_status3 AI_USER, STATUS3_ROOTED, AI_CV_EvasionUp7 if_random_less_than 128, AI_CV_EvasionUp7 score +2 - AI_CV_EvasionUp7: if_not_status2 AI_TARGET, STATUS2_CURSED, AI_CV_EvasionUp8 if_random_less_than 70, AI_CV_EvasionUp8 score +3 - AI_CV_EvasionUp8: if_hp_more_than AI_USER, 70, AI_CV_EvasionUp_End if_stat_level_equal AI_USER, STAT_EVASION, DEFAULT_STAT_STAGE, AI_CV_EvasionUp_End if_hp_less_than AI_USER, 40, AI_CV_EvasionUp_ScoreDown2 if_hp_less_than AI_TARGET, 40, AI_CV_EvasionUp_ScoreDown2 if_random_less_than 70, AI_CV_EvasionUp_End - AI_CV_EvasionUp_ScoreDown2: score -2 - AI_CV_EvasionUp_End: end @@ -1121,11 +1079,9 @@ AI_CV_AlwaysHit: AI_CV_AlwaysHit_ScoreUp1: score +1 - AI_CV_AlwaysHit2: if_random_less_than 100, AI_CV_AlwaysHit_End score +1 - AI_CV_AlwaysHit_End: end @@ -1134,16 +1090,13 @@ AI_CV_AttackDown: @ 82DCDF8 score -1 if_hp_more_than AI_USER, 90, AI_CV_AttackDown2 score -1 - AI_CV_AttackDown2: @ 82DCE0B if_stat_level_more_than AI_TARGET, STAT_ATK, 3, AI_CV_AttackDown3 if_random_less_than 50, AI_CV_AttackDown3 score -2 - AI_CV_AttackDown3: @ 82DCE1B if_hp_more_than AI_TARGET, 70, AI_CV_AttackDown4 score -2 - AI_CV_AttackDown4: @ 82DCE24 get_target_type1 if_in_bytes AI_CV_AttackDown_UnknownTypeList, AI_CV_AttackDown_End @@ -1151,7 +1104,6 @@ AI_CV_AttackDown4: @ 82DCE24 if_in_bytes AI_CV_AttackDown_UnknownTypeList, AI_CV_AttackDown_End if_random_less_than 50, AI_CV_AttackDown_End score -2 - AI_CV_AttackDown_End: @ 82DCE42 end @@ -1167,15 +1119,12 @@ AI_CV_AttackDown_UnknownTypeList: AI_CV_DefenseDown: if_hp_less_than AI_USER, 70, AI_CV_DefenseDown2 if_stat_level_more_than AI_TARGET, STAT_DEF, 3, AI_CV_DefenseDown3 - AI_CV_DefenseDown2: if_random_less_than 50, AI_CV_DefenseDown3 score -2 - AI_CV_DefenseDown3: if_hp_more_than AI_TARGET, 70, AI_CV_DefenseDown_End score -2 - AI_CV_DefenseDown_End: end @@ -1193,7 +1142,6 @@ AI_CV_SpeedDown: @ 82DCE81 AI_CV_SpeedDown2: @ 82DCE8E if_random_less_than 70, AI_CV_SpeedDown_End score +2 - AI_CV_SpeedDown_End: @ 82DCE96 end @@ -1202,16 +1150,13 @@ AI_CV_SpAtkDown: score -1 if_hp_more_than AI_USER, 90, AI_CV_SpAtkDown2 score -1 - AI_CV_SpAtkDown2: if_stat_level_more_than AI_TARGET, STAT_SPATK, 3, AI_CV_SpAtkDown3 if_random_less_than 50, AI_CV_SpAtkDown3 score -2 - AI_CV_SpAtkDown3: if_hp_more_than AI_TARGET, 70, AI_CV_SpAtkDown4 score -2 - AI_CV_SpAtkDown4: get_target_type1 if_in_bytes AI_CV_SpAtkDown_SpecialTypeList, AI_CV_SpAtkDown_End @@ -1219,7 +1164,6 @@ AI_CV_SpAtkDown4: if_in_bytes AI_CV_SpAtkDown_SpecialTypeList, AI_CV_SpAtkDown_End if_random_less_than 50, AI_CV_SpAtkDown_End score -2 - AI_CV_SpAtkDown_End: @ 82DCEE1 end @@ -1237,76 +1181,61 @@ AI_CV_SpAtkDown_SpecialTypeList: @ 82DCEE2 AI_CV_SpDefDown: @ 82DCEEB if_hp_less_than AI_USER, 70, AI_CV_SpDefDown2 if_stat_level_more_than AI_TARGET, STAT_SPDEF, 3, AI_CV_SpDefDown3 - AI_CV_SpDefDown2: @ 82DCEFA if_random_less_than 50, AI_CV_SpDefDown3 score -2 - AI_CV_SpDefDown3: @ 82DCF02 if_hp_more_than AI_TARGET, 70, AI_CV_SpDefDown_End score -2 - AI_CV_SpDefDown_End: @ 82DCF0B end AI_CV_AccuracyDown: @ 82DCF0C if_hp_less_than AI_USER, 70, AI_CV_AccuracyDown2 if_hp_more_than AI_TARGET, 70, AI_CV_AccuracyDown3 - AI_CV_AccuracyDown2: if_random_less_than 100, AI_CV_AccuracyDown3 score -1 - AI_CV_AccuracyDown3: if_stat_level_more_than AI_USER, STAT_ACC, 4, AI_CV_AccuracyDown4 if_random_less_than 80, AI_CV_AccuracyDown4 score -2 - AI_CV_AccuracyDown4: if_not_status AI_TARGET, STATUS1_TOXIC_POISON, AI_CV_AccuracyDown5 if_random_less_than 70, AI_CV_AccuracyDown5 score +2 - AI_CV_AccuracyDown5: if_not_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_AccuracyDown6 if_random_less_than 70, AI_CV_AccuracyDown6 score +2 - AI_CV_AccuracyDown6: if_not_status3 AI_USER, STATUS3_ROOTED, AI_CV_AccuracyDown7 if_random_less_than 128, AI_CV_AccuracyDown7 score +1 - AI_CV_AccuracyDown7: if_not_status2 AI_TARGET, STATUS2_CURSED, AI_CV_AccuracyDown8 if_random_less_than 70, AI_CV_AccuracyDown8 score +2 - AI_CV_AccuracyDown8: if_hp_more_than AI_USER, 70, AI_CV_AccuracyDown_End if_stat_level_equal AI_TARGET, STAT_ACC, DEFAULT_STAT_STAGE, AI_CV_AccuracyDown_End if_hp_less_than AI_USER, 40, AI_CV_AccuracyDown_ScoreDown2 if_hp_less_than AI_TARGET, 40, AI_CV_AccuracyDown_ScoreDown2 if_random_less_than 70, AI_CV_AccuracyDown_End - AI_CV_AccuracyDown_ScoreDown2: score -2 - AI_CV_AccuracyDown_End: end AI_CV_EvasionDown: if_hp_less_than AI_USER, 70, AI_CV_EvasionDown2 if_stat_level_more_than AI_TARGET, STAT_EVASION, 3, AI_CV_EvasionDown3 - AI_CV_EvasionDown2: if_random_less_than 50, AI_CV_EvasionDown3 score -2 - AI_CV_EvasionDown3: if_hp_more_than AI_TARGET, 70, AI_CV_EvasionDown_End score -2 - AI_CV_EvasionDown_End: end @@ -1326,7 +1255,6 @@ AI_CV_Haze: AI_CV_Haze2: if_random_less_than 50, AI_CV_Haze3 score -3 - AI_CV_Haze3: if_stat_level_more_than AI_TARGET, STAT_ATK, 8, AI_CV_Haze4 if_stat_level_more_than AI_TARGET, STAT_DEF, 8, AI_CV_Haze4 @@ -1345,14 +1273,12 @@ AI_CV_Haze3: AI_CV_Haze4: if_random_less_than 50, AI_CV_Haze_End score +3 - AI_CV_Haze_End: end AI_CV_Bide: if_hp_more_than AI_USER, 90, AI_CV_Bide_End score -2 - AI_CV_Bide_End: end @@ -1368,19 +1294,16 @@ AI_CV_Roar: AI_CV_Roar2: if_random_less_than 128, AI_CV_Roar_End score +2 - AI_CV_Roar_End: end AI_CV_Conversion: if_hp_more_than AI_USER, 90, AI_CV_Conversion2 score -2 - AI_CV_Conversion2: get_turn_count if_equal 0, AI_CV_Conversion_End if_random_less_than 200, Score_Minus2 - AI_CV_Conversion_End: end @@ -1393,7 +1316,6 @@ AI_CV_HealWeather: AI_CV_HealWeather_ScoreDown2: score -2 - AI_CV_Heal: if_hp_equal AI_USER, 100, AI_CV_Heal3 if_target_faster AI_CV_Heal4 @@ -1404,7 +1326,6 @@ AI_CV_Heal2: if_hp_less_than AI_USER, 50, AI_CV_Heal5 if_hp_more_than AI_USER, 80, AI_CV_Heal3 if_random_less_than 70, AI_CV_Heal5 - AI_CV_Heal3: score -3 goto AI_CV_Heal_End @@ -1418,11 +1339,9 @@ AI_CV_Heal4: AI_CV_Heal5: if_doesnt_have_move_with_effect AI_TARGET, EFFECT_SNATCH, AI_CV_Heal6 if_random_less_than 100, AI_CV_Heal_End - AI_CV_Heal6: if_random_less_than 20, AI_CV_Heal_End score +2 - AI_CV_Heal_End: end @@ -1431,12 +1350,10 @@ AI_CV_Toxic: if_hp_more_than AI_USER, 50, AI_CV_Toxic2 if_random_less_than 50, AI_CV_Toxic2 score -3 - AI_CV_Toxic2: if_hp_more_than AI_TARGET, 50, AI_CV_Toxic3 if_random_less_than 50, AI_CV_Toxic3 score -3 - AI_CV_Toxic3: if_has_move_with_effect AI_USER, EFFECT_SPECIAL_DEFENSE_UP, AI_CV_Toxic4 if_has_move_with_effect AI_USER, EFFECT_PROTECT, AI_CV_Toxic4 @@ -1445,7 +1362,6 @@ AI_CV_Toxic3: AI_CV_Toxic4: if_random_less_than 60, AI_CV_Toxic_End score +2 - AI_CV_Toxic_End: end @@ -1456,10 +1372,8 @@ AI_CV_LightScreen: get_target_type2 if_in_bytes AI_CV_LightScreen_SpecialTypeList, AI_CV_LightScreen_End if_random_less_than 50, AI_CV_LightScreen_End - AI_CV_LightScreen_ScoreDown2: score -2 - AI_CV_LightScreen_End: end @@ -1484,7 +1398,6 @@ AI_CV_Rest2: if_hp_less_than AI_USER, 40, AI_CV_Rest6 if_hp_more_than AI_USER, 50, AI_CV_Rest3 if_random_less_than 70, AI_CV_Rest6 - AI_CV_Rest3: score -3 goto AI_CV_Rest_End @@ -1493,7 +1406,6 @@ AI_CV_Rest4: if_hp_less_than AI_USER, 60, AI_CV_Rest6 if_hp_more_than AI_USER, 70, AI_CV_Rest5 if_random_less_than 50, AI_CV_Rest6 - AI_CV_Rest5: score -3 goto AI_CV_Rest_End @@ -1501,11 +1413,9 @@ AI_CV_Rest5: AI_CV_Rest6: if_doesnt_have_move_with_effect AI_TARGET, EFFECT_SNATCH, AI_CV_Rest7 if_random_less_than 50, AI_CV_Rest_End - AI_CV_Rest7: if_random_less_than 10, AI_CV_Rest_End score +3 - AI_CV_Rest_End: end @@ -1515,7 +1425,6 @@ AI_CV_OneHitKO: AI_CV_SuperFang: if_hp_more_than AI_TARGET, 50, AI_CV_SuperFang_End score -1 - AI_CV_SuperFang_End: end @@ -1529,7 +1438,6 @@ AI_CV_Trap: AI_CV_Trap2: if_random_less_than 128, AI_CV_Trap_End score +1 - AI_CV_Trap_End: end @@ -1543,28 +1451,23 @@ AI_CV_HighCrit: AI_CV_HighCrit2: if_random_less_than 128, AI_CV_HighCrit_End score +1 - AI_CV_HighCrit_End: end AI_CV_Swagger: if_has_move AI_USER, MOVE_PSYCH_UP, AI_CV_SwaggerHasPsychUp - AI_CV_Flatter: if_random_less_than 128, AI_CV_Confuse score +1 - AI_CV_Confuse: if_hp_more_than AI_TARGET, 70, AI_CV_Confuse_End if_random_less_than 128, AI_CV_Confuse2 score -1 - AI_CV_Confuse2: if_hp_more_than AI_TARGET, 50, AI_CV_Confuse_End score -1 if_hp_more_than AI_TARGET, 30, AI_CV_Confuse_End score -1 - AI_CV_Confuse_End: end @@ -1578,7 +1481,6 @@ AI_CV_SwaggerHasPsychUp: AI_CV_SwaggerHasPsychUp_Minus5: score -5 - AI_CV_SwaggerHasPsychUp_End: end @@ -1589,10 +1491,8 @@ AI_CV_Reflect: get_target_type2 if_in_bytes AI_CV_Reflect_PhysicalTypeList, AI_CV_Reflect_End if_random_less_than 50, AI_CV_Reflect_End - AI_CV_Reflect_ScoreDown2: score -2 - AI_CV_Reflect_End: end @@ -1611,10 +1511,8 @@ AI_CV_Reflect_PhysicalTypeList: AI_CV_Poison: if_hp_less_than AI_USER, 50, AI_CV_Poison_ScoreDown1 if_hp_more_than AI_TARGET, 50, AI_CV_Poison_End - AI_CV_Poison_ScoreDown1: score -1 - AI_CV_Poison_End: end @@ -1627,7 +1525,6 @@ AI_CV_Paralyze: AI_CV_Paralyze2: if_random_less_than 20, AI_CV_Paralyze_End score +3 - AI_CV_Paralyze_End: end @@ -1636,11 +1533,9 @@ AI_CV_VitalThrow: if_hp_more_than AI_USER, 60, AI_CV_VitalThrow_End if_hp_less_than AI_USER, 40, AI_CV_VitalThrow2 if_random_less_than 180, AI_CV_VitalThrow_End - AI_CV_VitalThrow2: if_random_less_than 50, AI_CV_VitalThrow_End score -1 - AI_CV_VitalThrow_End: end @@ -1650,15 +1545,12 @@ AI_CV_Substitute: if_hp_more_than AI_USER, 50, AI_CV_Substitute2 if_random_less_than 100, AI_CV_Substitute2 score -1 - AI_CV_Substitute2: if_random_less_than 100, AI_CV_Substitute3 score -1 - AI_CV_Substitute3: if_random_less_than 100, AI_CV_Substitute4 score -1 - AI_CV_Substitute4: if_target_faster AI_CV_Substitute_End get_last_used_bank_move AI_TARGET @@ -1682,11 +1574,9 @@ AI_CV_Substitute6: AI_CV_Substitute7: if_status3 AI_TARGET, STATUS3_LEECHSEED, AI_CV_Substitute_End - AI_CV_Substitute8: if_random_less_than 100, AI_CV_Substitute_End score +1 - AI_CV_Substitute_End: end @@ -1699,10 +1589,8 @@ AI_CV_Recharge: AI_CV_Recharge2: if_hp_less_than AI_USER, 60, AI_CV_Recharge_End - AI_CV_Recharge_ScoreDown1: score -1 - AI_CV_Recharge_End: end @@ -1717,7 +1605,6 @@ AI_CV_Disable: AI_CV_Disable2: if_random_less_than 100, AI_CV_Disable_End score -1 - AI_CV_Disable_End: end @@ -1728,12 +1615,10 @@ AI_CV_Counter: if_hp_more_than AI_USER, 30, AI_CV_Counter2 if_random_less_than 10, AI_CV_Counter2 score -1 - AI_CV_Counter2: if_hp_more_than AI_USER, 50, AI_CV_Counter3 if_random_less_than 100, AI_CV_Counter3 score -1 - AI_CV_Counter3: if_has_move AI_USER, MOVE_MIRROR_COAT, AI_CV_Counter7 get_last_used_bank_move AI_TARGET @@ -1742,7 +1627,6 @@ AI_CV_Counter3: if_target_not_taunted AI_CV_Counter4 if_random_less_than 100, AI_CV_Counter4 score +1 - AI_CV_Counter4: get_last_used_bank_move AI_TARGET get_move_type_from_result @@ -1755,24 +1639,20 @@ AI_CV_Counter5: if_target_not_taunted AI_CV_Counter6 if_random_less_than 100, AI_CV_Counter6 score +1 - AI_CV_Counter6: get_target_type1 if_in_bytes AI_CV_Counter_PhysicalTypeList, AI_CV_Counter_End get_target_type2 if_in_bytes AI_CV_Counter_PhysicalTypeList, AI_CV_Counter_End if_random_less_than 50, AI_CV_Counter_End - AI_CV_Counter7: if_random_less_than 100, AI_CV_Counter8 score +4 - AI_CV_Counter8: end AI_CV_Counter_ScoreDown1: score -1 - AI_CV_Counter_End: end @@ -1794,7 +1674,6 @@ AI_CV_Encore: get_last_used_bank_move AI_TARGET get_move_effect_from_result if_not_in_bytes AI_CV_Encore_EncouragedMovesToEncore, AI_CV_Encore_ScoreDown2 - AI_CV_Encore2: if_random_less_than 30, AI_CV_Encore_End score +3 @@ -1802,7 +1681,6 @@ AI_CV_Encore2: AI_CV_Encore_ScoreDown2: score -2 - AI_CV_Encore_End: end @@ -1885,7 +1763,6 @@ AI_CV_PainSplit2: AI_CV_PainSplit_ScoreDown1: score -1 - AI_CV_PainSplit_End: end @@ -1896,7 +1773,6 @@ AI_CV_Snore: AI_CV_LockOn: if_random_less_than 128, AI_CV_LockOn_End score +2 - AI_CV_LockOn_End: end @@ -1911,17 +1787,14 @@ AI_CV_DestinyBond: if_hp_more_than AI_USER, 70, AI_CV_DestinyBond_End if_random_less_than 128, AI_CV_DestinyBond2 score +1 - AI_CV_DestinyBond2: if_hp_more_than AI_USER, 50, AI_CV_DestinyBond_End if_random_less_than 128, AI_CV_DestinyBond3 score +1 - AI_CV_DestinyBond3: if_hp_more_than AI_USER, 30, AI_CV_DestinyBond_End if_random_less_than 100, AI_CV_DestinyBond_End score +2 - AI_CV_DestinyBond_End: end @@ -1939,7 +1812,6 @@ AI_CV_Flail2: AI_CV_Flail_ScoreUp1: score +1 - AI_CV_Flail3: if_random_less_than 100, AI_CV_Flail_End score +1 @@ -1947,7 +1819,6 @@ AI_CV_Flail3: AI_CV_Flail_ScoreDown1: score -1 - AI_CV_Flail_End: end @@ -1955,7 +1826,6 @@ AI_CV_HealBell: if_status AI_TARGET, STATUS1_ANY, AI_CV_HealBell_End if_status_in_party AI_TARGET, STATUS1_ANY, AI_CV_HealBell_End score -5 - AI_CV_HealBell_End: end @@ -1968,7 +1838,6 @@ AI_CV_Thief: AI_CV_Thief_ScoreDown2: score -2 - AI_CV_Thief_End: end @@ -1990,12 +1859,10 @@ AI_CV_Curse: if_stat_level_more_than AI_USER, STAT_DEF, 9, AI_CV_Curse_End if_random_less_than 128, AI_CV_Curse2 score +1 - AI_CV_Curse2: if_stat_level_more_than AI_USER, STAT_DEF, 7, AI_CV_Curse_End if_random_less_than 128, AI_CV_Curse3 score +1 - AI_CV_Curse3: if_stat_level_more_than AI_USER, STAT_DEF, DEFAULT_STAT_STAGE, AI_CV_Curse_End if_random_less_than 128, AI_CV_Curse_End @@ -2005,7 +1872,6 @@ AI_CV_Curse3: AI_CV_Curse4: if_hp_more_than AI_USER, 80, AI_CV_Curse_End score -1 - AI_CV_Curse_End: end @@ -2033,11 +1899,9 @@ AI_CV_Protect: AI_CV_Protect_ScoreUp2: score +2 - AI_CV_Protect2: if_random_less_than 128, AI_CV_Protect4 score -1 - AI_CV_Protect4: get_protect_count AI_USER if_equal 0, AI_CV_Protect_End @@ -2050,10 +1914,8 @@ AI_CV_Protect3: get_last_used_bank_move AI_TARGET get_move_effect_from_result if_not_equal EFFECT_LOCK_ON, AI_CV_Protect_End - AI_CV_Protect_ScoreDown2: score -2 - AI_CV_Protect_End: end @@ -2078,18 +1940,15 @@ AI_CV_Foresight: AI_CV_Foresight2: if_random_less_than 80, AI_CV_Foresight_End - AI_CV_Foresight3: if_random_less_than 80, AI_CV_Foresight_End score +2 - AI_CV_Foresight_End: end AI_CV_Endure: if_hp_less_than AI_USER, 4, AI_CV_Endure2 if_hp_less_than AI_USER, 35, AI_CV_Endure3 - AI_CV_Endure2: score -1 goto AI_CV_Endure_End @@ -2097,7 +1956,6 @@ AI_CV_Endure2: AI_CV_Endure3: if_random_less_than 70, AI_CV_Endure_End score +1 - AI_CV_Endure_End: end @@ -2116,7 +1974,6 @@ AI_CV_BatonPass2: AI_CV_BatonPass3: if_hp_more_than AI_USER, 70, AI_CV_BatonPass_End - AI_CV_BatonPass4: if_random_less_than 80, AI_CV_BatonPass_End score +2 @@ -2137,10 +1994,8 @@ AI_CV_BatonPass7: AI_CV_BatonPass8: if_hp_less_than AI_USER, 70, AI_CV_BatonPass_End - AI_CV_BatonPass_ScoreDown2: score -2 - AI_CV_BatonPass_End: end @@ -2160,7 +2015,6 @@ AI_CV_Pursuit: AI_CV_Pursuit2: if_random_less_than 128, AI_CV_Pursuit_End score +1 - AI_CV_Pursuit_End: end @@ -2168,7 +2022,6 @@ AI_CV_RainDance: if_user_faster AI_CV_RainDance2 get_ability AI_USER if_equal ABILITY_SWIFT_SWIM, AI_CV_RainDance3 - AI_CV_RainDance2: if_hp_less_than AI_USER, 40, AI_CV_RainDance_ScoreDown1 get_weather @@ -2185,7 +2038,6 @@ AI_CV_RainDance3: AI_CV_RainDance_ScoreDown1: score -1 - AI_CV_RainDance_End: end @@ -2203,7 +2055,6 @@ AI_CV_SunnyDay2: AI_CV_SunnyDay_ScoreDown1: score -1 - AI_CV_SunnyDay_End: end @@ -2213,7 +2064,6 @@ AI_CV_BellyDrum: AI_CV_BellyDrum_ScoreDown2: score -2 - AI_CV_BellyDrum_End: end @@ -2236,14 +2086,12 @@ AI_CV_PsychUp2: AI_CV_PsychUp_ScoreUp1: score +1 - AI_CV_PsychUp3: score +1 end AI_CV_PsychUp_ScoreDown2: score -2 - AI_CV_PsychUp_End: end @@ -2254,12 +2102,10 @@ AI_CV_MirrorCoat: if_hp_more_than AI_USER, 30, AI_CV_MirrorCoat2 if_random_less_than 10, AI_CV_MirrorCoat2 score -1 - AI_CV_MirrorCoat2: if_hp_more_than AI_USER, 50, AI_CV_MirrorCoat3 if_random_less_than 100, AI_CV_MirrorCoat3 score -1 - AI_CV_MirrorCoat3: if_has_move AI_USER, MOVE_COUNTER, AI_CV_MirrorCoat_ScoreUp4 get_last_used_bank_move AI_TARGET @@ -2268,7 +2114,6 @@ AI_CV_MirrorCoat3: if_target_not_taunted AI_CV_MirrorCoat4 if_random_less_than 100, AI_CV_MirrorCoat4 score +1 - AI_CV_MirrorCoat4: get_last_used_bank_move AI_TARGET get_move_type_from_result @@ -2281,24 +2126,20 @@ AI_CV_MirrorCoat5: if_target_not_taunted AI_CV_MirrorCoat6 if_random_less_than 100, AI_CV_MirrorCoat6 score +1 - AI_CV_MirrorCoat6: get_target_type1 if_in_bytes AI_CV_MirrorCoat_SpecialTypeList, AI_CV_MirrorCoat_End get_target_type2 if_in_bytes AI_CV_MirrorCoat_SpecialTypeList, AI_CV_MirrorCoat_End if_random_less_than 50, AI_CV_MirrorCoat_End - AI_CV_MirrorCoat_ScoreUp4: if_random_less_than 100, AI_CV_MirrorCoat_ScoreUp4_End score +4 - AI_CV_MirrorCoat_ScoreUp4_End: end AI_CV_MirrorCoat_ScoreDown1: score -1 - AI_CV_MirrorCoat_End: end @@ -2323,7 +2164,6 @@ AI_CV_ChargeUpMove: AI_CV_ChargeUpMove_ScoreDown2: score -2 - AI_CV_ChargeUpMove_End: end @@ -2360,7 +2200,6 @@ AI_CV_SemiInvulnerable_CheckIceType: if_equal TYPE_ICE, AI_CV_SemiInvulnerable_TryEncourage get_user_type2 if_equal TYPE_ICE, AI_CV_SemiInvulnerable_TryEncourage - AI_CV_SemiInvulnerable5: if_target_faster AI_CV_SemiInvulnerable_End get_last_used_bank_move AI_TARGET @@ -2371,7 +2210,6 @@ AI_CV_SemiInvulnerable5: AI_CV_SemiInvulnerable_TryEncourage: if_random_less_than 80, AI_CV_SemiInvulnerable_End score +1 - AI_CV_SemiInvulnerable_End: end @@ -2390,7 +2228,6 @@ AI_CV_SpitUp: if_less_than 2, AI_CV_SpitUp_End if_random_less_than 80, AI_CV_SpitUp_End score +2 - AI_CV_SpitUp_End: end @@ -2408,7 +2245,6 @@ AI_CV_Hail2: AI_CV_Hail_ScoreDown1: score -1 - AI_CV_Hail_End: end @@ -2442,10 +2278,8 @@ AI_CV_FocusPunch2: AI_CV_FocusPunch3: if_random_less_than 100, AI_CV_FocusPunch_End if_status2 AI_USER, STATUS2_SUBSTITUTE, Score_Plus5 - AI_CV_FocusPunch_ScoreUp1: score +1 - AI_CV_FocusPunch_End: end @@ -2455,7 +2289,6 @@ AI_CV_SmellingSalt: AI_CV_SmellingSalt_ScoreUp1: score +1 - AI_CV_SmellingSalt_End: end @@ -2463,7 +2296,6 @@ AI_CV_Trick: get_hold_effect AI_USER if_in_bytes AI_CV_Trick_EffectsToEncourage2, AI_CV_Trick3 if_in_bytes AI_CV_Trick_EffectsToEncourage, AI_CV_Trick4 - AI_CV_Trick2: score -3 goto AI_CV_Trick_End @@ -2479,7 +2311,6 @@ AI_CV_Trick4: if_in_bytes AI_CV_Trick_EffectsToEncourage, AI_CV_Trick2 if_random_less_than 50, AI_CV_Trick_End score +2 - AI_CV_Trick_End: end @@ -2502,7 +2333,6 @@ AI_CV_ChangeSelfAbility: if_in_bytes AI_CV_ChangeSelfAbility_AbilitiesToEncourage, AI_CV_ChangeSelfAbility2 get_ability AI_TARGET if_in_bytes AI_CV_ChangeSelfAbility_AbilitiesToEncourage, AI_CV_ChangeSelfAbility3 - AI_CV_ChangeSelfAbility2: score -1 goto AI_CV_ChangeSelfAbility_End @@ -2510,7 +2340,6 @@ AI_CV_ChangeSelfAbility2: AI_CV_ChangeSelfAbility3: if_random_less_than 50, AI_CV_ChangeSelfAbility_End score +2 - AI_CV_ChangeSelfAbility_End: end @@ -2543,10 +2372,8 @@ AI_CV_Superpower: AI_CV_Superpower2: if_hp_less_than AI_USER, 60, AI_CV_Superpower_End - AI_CV_Superpower_ScoreDown1: score -1 - AI_CV_Superpower_End: end @@ -2554,21 +2381,18 @@ AI_CV_MagicCoat: if_hp_more_than AI_TARGET, 30, AI_CV_MagicCoat2 if_random_less_than 100, AI_CV_MagicCoat2 score -1 - AI_CV_MagicCoat2: is_first_turn_for AI_USER - if_equal 0, AI_CV_MagicCoat4 + if_equal FALSE, AI_CV_MagicCoat4 if_random_less_than 150, AI_CV_MagicCoat_End score +1 goto AI_CV_MagicCoat_End AI_CV_MagicCoat3: if_random_less_than 50, AI_CV_MagicCoat_End - AI_CV_MagicCoat4: if_random_less_than 30, AI_CV_MagicCoat_End score -1 - AI_CV_MagicCoat_End: end @@ -2581,7 +2405,6 @@ AI_CV_Recycle: AI_CV_Recycle_ScoreDown2: score -2 - AI_CV_Recycle_End: end @@ -2601,7 +2424,6 @@ AI_CV_Revenge: AI_CV_Revenge_ScoreDown2: score -2 - AI_CV_Revenge_End: end @@ -2611,7 +2433,6 @@ AI_CV_BrickBreak: AI_CV_BrickBreak_ScoreUp1: score +1 - AI_CV_BrickBreak_End: end @@ -2621,7 +2442,6 @@ AI_CV_KnockOff: if_more_than 0, AI_CV_KnockOff_End if_random_less_than 180, AI_CV_KnockOff_End score +1 - AI_CV_KnockOff_End: end @@ -2639,7 +2459,6 @@ AI_CV_Endeavor2: AI_CV_Endeavor_ScoreDown1: score -1 - AI_CV_Endeavor_End: end @@ -2652,10 +2471,8 @@ AI_CV_Eruption: AI_CV_Eruption2: if_hp_more_than AI_TARGET, 70, AI_CV_Eruption_End - AI_CV_Eruption_ScoreDown1: score -1 - AI_CV_Eruption_End: end @@ -2664,7 +2481,6 @@ AI_CV_Imprison: if_more_than 0, AI_CV_Imprison_End if_random_less_than 100, AI_CV_Imprison_End score +2 - AI_CV_Imprison_End: end @@ -2674,13 +2490,12 @@ AI_CV_Refresh: AI_CV_Refresh_ScoreDown1: score -1 - AI_CV_Refresh_End: end AI_CV_Snatch: is_first_turn_for AI_USER - if_equal 1, AI_CV_Snatch3 + if_equal TRUE, AI_CV_Snatch3 if_random_less_than 30, AI_CV_Snatch_End if_target_faster AI_CV_Snatch2 if_hp_not_equal AI_USER, 100, AI_CV_Snatch5 @@ -2707,7 +2522,6 @@ AI_CV_Snatch4: AI_CV_Snatch5: if_random_less_than 30, AI_CV_Snatch_End score -2 - AI_CV_Snatch_End: end @@ -2725,7 +2539,6 @@ AI_CV_MudSport2: AI_CV_MudSport_ScoreDown1: score -1 - AI_CV_MudSport_End: end @@ -2738,10 +2551,8 @@ AI_CV_Overheat: AI_CV_Overheat2: if_hp_more_than AI_USER, 80, AI_CV_Overheat_End - AI_CV_Overheat_ScoreDown1: score -1 - AI_CV_Overheat_End: end @@ -2759,7 +2570,6 @@ AI_CV_WaterSport2: AI_CV_WaterSport_ScoreDown1: score -1 - AI_CV_WaterSport_End: end @@ -2773,7 +2583,6 @@ AI_CV_DragonDance: AI_CV_DragonDance2: if_random_less_than 128, AI_CV_DragonDance_End score +1 - AI_CV_DragonDance_End: end @@ -2794,10 +2603,8 @@ AI_TryToFaint_TryToEncourageQuickAttack: if_effect EFFECT_EXPLOSION, AI_TryToFaint_End if_not_effect EFFECT_QUICK_ATTACK, AI_TryToFaint_ScoreUp4 score +2 - AI_TryToFaint_ScoreUp4: score +4 - AI_TryToFaint_End: end @@ -2809,7 +2616,6 @@ AI_SetupFirstTurn: if_not_in_bytes AI_SetupFirstTurn_SetupEffectsToEncourage, AI_SetupFirstTurn_End if_random_less_than 80, AI_SetupFirstTurn_End score +2 - AI_SetupFirstTurn_End: end @@ -2871,14 +2677,15 @@ AI_SetupFirstTurn_SetupEffectsToEncourage: .byte EFFECT_CAMOUFLAGE .byte -1 -AI_PreferStrongestMove: +@ ~60% chance to prefer moves that do 0 or 1 damage, or are in sIgnoredPowerfulMoveEffects +@ Oddly this group includes moves like Explosion and Eruption, so the AI strategy isn't very coherent +AI_PreferPowerExtremes: if_target_is_ally AI_Ret get_how_powerful_move_is - if_not_equal 0, AI_PreferStrongestMove_End - if_random_less_than 100, AI_PreferStrongestMove_End + if_not_equal MOVE_POWER_OTHER, AI_PreferPowerExtremes_End + if_random_less_than 100, AI_PreferPowerExtremes_End score +2 - -AI_PreferStrongestMove_End: +AI_PreferPowerExtremes_End: end AI_Risky: @@ -2887,7 +2694,6 @@ AI_Risky: if_not_in_bytes AI_Risky_EffectsToEncourage, AI_Risky_End if_random_less_than 128, AI_Risky_End score +2 - AI_Risky_End: end @@ -2918,10 +2724,9 @@ AI_PreferBatonPass: count_usable_party_mons AI_USER if_equal 0, AI_PreferBatonPassEnd get_how_powerful_move_is - if_not_equal 0, AI_PreferBatonPassEnd + if_not_equal MOVE_POWER_OTHER, AI_PreferBatonPassEnd if_has_move_with_effect AI_USER, EFFECT_BATON_PASS, AI_PreferBatonPass_GoForBatonPass if_random_less_than 80, AI_Risky_End - AI_PreferBatonPass_GoForBatonPass: if_move MOVE_SWORDS_DANCE, AI_PreferBatonPass2 if_move MOVE_DRAGON_DANCE, AI_PreferBatonPass2 @@ -2930,7 +2735,6 @@ AI_PreferBatonPass_GoForBatonPass: if_move MOVE_BATON_PASS, AI_PreferBatonPass_EncourageIfHighStats if_random_less_than 20, AI_Risky_End score +3 - AI_PreferBatonPass2: get_turn_count if_equal 0, Score_Plus5 @@ -2977,7 +2781,7 @@ AI_DoubleBattle: AI_DoubleBattlePartnerHasHelpingHand: get_how_powerful_move_is - if_not_equal 0, Score_Plus1 + if_not_equal MOVE_POWER_OTHER, Score_Plus1 end AI_DoubleBattleCheckUserStatus: @@ -2986,7 +2790,7 @@ AI_DoubleBattleCheckUserStatus: AI_DoubleBattleCheckUserStatus2: get_how_powerful_move_is - if_equal MOVE_POWER_DISCOURAGED, Score_Minus5 + if_equal MOVE_POWER_OTHER, Score_Minus5 score +1 if_equal MOVE_MOST_POWERFUL, Score_Plus2 end @@ -3013,7 +2817,6 @@ AI_DoubleBattleElectricMove: score -2 if_no_type AI_TARGET_PARTNER, TYPE_GROUND, AI_DoubleBattleElectricMoveEnd score -8 - AI_DoubleBattleElectricMoveEnd: end @@ -3026,10 +2829,9 @@ AI_DoubleBattleFireMove2: AI_TryOnAlly: get_how_powerful_move_is - if_equal 0, AI_TryStatusMoveOnAlly + if_equal MOVE_POWER_OTHER, AI_TryStatusMoveOnAlly get_curr_move_type if_equal TYPE_FIRE, AI_TryFireMoveOnAlly - AI_DiscourageOnAlly: goto Score_Minus30 @@ -3096,7 +2898,6 @@ AI_TrySwaggerOnAlly: AI_TrySwaggerOnAlly2: if_stat_level_more_than AI_TARGET, STAT_ATK, 7, AI_TrySwaggerOnAlly_End score +3 - AI_TrySwaggerOnAlly_End: end @@ -3125,7 +2926,6 @@ AI_HPAware_UserHasMediumHP: AI_HPAware_TryToDiscourage: if_random_less_than 50, AI_HPAware_ConsiderTarget score -2 - AI_HPAware_ConsiderTarget: if_hp_more_than AI_TARGET, 70, AI_HPAware_TargetHasHighHP if_hp_more_than AI_TARGET, 30, AI_HPAware_TargetHasMediumHP @@ -3146,7 +2946,6 @@ AI_HPAware_TargetHasMediumHP: AI_HPAware_TargetTryToDiscourage: if_random_less_than 50, AI_HPAware_End score -2 - AI_HPAware_End: end @@ -3368,15 +3167,18 @@ AI_HPAware_DiscouragedEffectsWhenTargetLowHP: @ 82DE2B1 .byte EFFECT_DRAGON_DANCE .byte -1 -AI_Unknown: +@ Given the AI_TryOnAlly at the beginning it's possible that this was the start of a more +@ comprehensive double battle AI script +AI_TrySunnyDayStart: if_target_is_ally AI_TryOnAlly - if_not_effect EFFECT_SUNNY_DAY, AI_Unknown_End - if_equal 0, AI_Unknown_End + if_not_effect EFFECT_SUNNY_DAY, AI_TrySunnyDayStart_End +.ifndef BUGFIX @ funcResult has not been set in this script yet, below call is nonsense + if_equal FALSE, AI_TrySunnyDayStart_End +.endif is_first_turn_for AI_USER - if_equal 0, AI_Unknown_End + if_equal FALSE, AI_TrySunnyDayStart_End score +5 - -AI_Unknown_End: @ 82DE308 +AI_TrySunnyDayStart_End: @ 82DE308 end AI_Roaming: @@ -3388,7 +3190,6 @@ AI_Roaming: if_equal ABILITY_LEVITATE, AI_Roaming_Flee get_ability AI_TARGET if_equal ABILITY_ARENA_TRAP, AI_Roaming_End - AI_Roaming_Flee: @ 82DE335 flee diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 4c3a45dc6..5ade58d50 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -29,24 +29,24 @@ #define AI_WEATHER_HAIL 3 // get_how_powerful_move_is -#define MOVE_POWER_DISCOURAGED 0 +#define MOVE_POWER_OTHER 0 #define MOVE_NOT_MOST_POWERFUL 1 #define MOVE_MOST_POWERFUL 2 // script's table id to bit -#define AI_SCRIPT_CHECK_BAD_MOVE (1 << 0) -#define AI_SCRIPT_TRY_TO_FAINT (1 << 1) -#define AI_SCRIPT_CHECK_VIABILITY (1 << 2) -#define AI_SCRIPT_SETUP_FIRST_TURN (1 << 3) -#define AI_SCRIPT_RISKY (1 << 4) -#define AI_SCRIPT_PREFER_STRONGEST_MOVE (1 << 5) -#define AI_SCRIPT_PREFER_BATON_PASS (1 << 6) -#define AI_SCRIPT_DOUBLE_BATTLE (1 << 7) -#define AI_SCRIPT_HP_AWARE (1 << 8) -#define AI_SCRIPT_UNKNOWN (1 << 9) +#define AI_SCRIPT_CHECK_BAD_MOVE (1 << 0) +#define AI_SCRIPT_TRY_TO_FAINT (1 << 1) +#define AI_SCRIPT_CHECK_VIABILITY (1 << 2) +#define AI_SCRIPT_SETUP_FIRST_TURN (1 << 3) +#define AI_SCRIPT_RISKY (1 << 4) +#define AI_SCRIPT_PREFER_POWER_EXTREMES (1 << 5) +#define AI_SCRIPT_PREFER_BATON_PASS (1 << 6) +#define AI_SCRIPT_DOUBLE_BATTLE (1 << 7) +#define AI_SCRIPT_HP_AWARE (1 << 8) +#define AI_SCRIPT_TRY_SUNNY_DAY_START (1 << 9) // 10 - 28 are not used -#define AI_SCRIPT_ROAMING (1 << 29) -#define AI_SCRIPT_SAFARI (1 << 30) -#define AI_SCRIPT_FIRST_BATTLE (1 << 31) +#define AI_SCRIPT_ROAMING (1 << 29) +#define AI_SCRIPT_SAFARI (1 << 30) +#define AI_SCRIPT_FIRST_BATTLE (1 << 31) #endif // GUARD_CONSTANTS_BATTLE_AI_H diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index b72875036..20705aa70 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -263,7 +263,10 @@ static const BattleAICmdFunc sBattleAICmdTable[] = Cmd_if_holds_item, // 0x62 }; -static const u16 sDiscouragedPowerfulMoveEffects[] = +// For the purposes of determing the most powerful move in a moveset, these +// moves are treated the same as having a power of 0 or 1 +#define IGNORED_MOVES_END 0xFFFF +static const u16 sIgnoredPowerfulMoveEffects[] = { EFFECT_EXPLOSION, EFFECT_DREAM_EATER, @@ -277,7 +280,7 @@ static const u16 sDiscouragedPowerfulMoveEffects[] = EFFECT_SUPERPOWER, EFFECT_ERUPTION, EFFECT_OVERHEAT, - 0xFFFF + IGNORED_MOVES_END }; // code @@ -1177,14 +1180,14 @@ static void Cmd_get_how_powerful_move_is(void) s32 i, checkedMove; s32 moveDmgs[MAX_MON_MOVES]; - for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) + for (i = 0; sIgnoredPowerfulMoveEffects[i] != IGNORED_MOVES_END; i++) { - if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == sDiscouragedPowerfulMoveEffects[i]) + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == sIgnoredPowerfulMoveEffects[i]) break; } if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power > 1 - && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF) + && sIgnoredPowerfulMoveEffects[i] == IGNORED_MOVES_END) { gDynamicBasePower = 0; *(&gBattleStruct->dynamicMoveType) = 0; @@ -1192,16 +1195,18 @@ static void Cmd_get_how_powerful_move_is(void) gMoveResultFlags = 0; gCritMultiplier = 1; + // Considered move has power and is not in sIgnoredPowerfulMoveEffects + // Check all other moves and calculate their power for (checkedMove = 0; checkedMove < MAX_MON_MOVES; checkedMove++) { - for (i = 0; sDiscouragedPowerfulMoveEffects[i] != 0xFFFF; i++) + for (i = 0; sIgnoredPowerfulMoveEffects[i] != IGNORED_MOVES_END; i++) { - if (gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].effect == sDiscouragedPowerfulMoveEffects[i]) + if (gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].effect == sIgnoredPowerfulMoveEffects[i]) break; } if (gBattleMons[sBattler_AI].moves[checkedMove] != MOVE_NONE - && sDiscouragedPowerfulMoveEffects[i] == 0xFFFF + && sIgnoredPowerfulMoveEffects[i] == IGNORED_MOVES_END && gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power > 1) { gCurrentMove = gBattleMons[sBattler_AI].moves[checkedMove]; @@ -1217,6 +1222,7 @@ static void Cmd_get_how_powerful_move_is(void) } } + // Is the considered move the most powerful move available? for (checkedMove = 0; checkedMove < MAX_MON_MOVES; checkedMove++) { if (moveDmgs[checkedMove] > moveDmgs[AI_THINKING_STRUCT->movesetIndex]) @@ -1224,13 +1230,14 @@ static void Cmd_get_how_powerful_move_is(void) } if (checkedMove == MAX_MON_MOVES) - AI_THINKING_STRUCT->funcResult = MOVE_MOST_POWERFUL; // Is the most powerful. + AI_THINKING_STRUCT->funcResult = MOVE_MOST_POWERFUL; else - AI_THINKING_STRUCT->funcResult = MOVE_NOT_MOST_POWERFUL; // Not the most powerful. + AI_THINKING_STRUCT->funcResult = MOVE_NOT_MOST_POWERFUL; } else { - AI_THINKING_STRUCT->funcResult = MOVE_POWER_DISCOURAGED; // Highly discouraged in terms of power. + // Move has a power of 0/1, or is in the group sIgnoredPowerfulMoveEffects + AI_THINKING_STRUCT->funcResult = MOVE_POWER_OTHER; } gAIScriptPtr++; -- cgit v1.2.3 From c42b5d783aeb90ea194d5cd72f8b180cc8878cb8 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 2 Jul 2021 03:26:50 -0400 Subject: Fix 'determining' typo --- src/battle_ai_script_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 20705aa70..bb615e497 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -263,7 +263,7 @@ static const BattleAICmdFunc sBattleAICmdTable[] = Cmd_if_holds_item, // 0x62 }; -// For the purposes of determing the most powerful move in a moveset, these +// For the purposes of determining the most powerful move in a moveset, these // moves are treated the same as having a power of 0 or 1 #define IGNORED_MOVES_END 0xFFFF static const u16 sIgnoredPowerfulMoveEffects[] = -- cgit v1.2.3 From 9fd27fe8552eb0716222e72bc92ffa7f7334c68d Mon Sep 17 00:00:00 2001 From: luckytyphlosion <10688458+luckytyphlosion@users.noreply.github.com> Date: Fri, 2 Jul 2021 12:52:31 -0400 Subject: Fix modern builds when devkitARM is not in PATH. --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a78949b3f..499553232 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ LD := $(PREFIX)ld # note: the makefile must be set up so MODERNCC is never called # if MODERN=0 MODERNCC := $(PREFIX)gcc +PATH_MODERNCC := PATH=$(TOOLCHAIN)/bin:PATH $(MODERNCC) ifeq ($(OS),Windows_NT) EXE := .exe @@ -95,11 +96,11 @@ OBJ_DIR := $(OBJ_DIR_NAME) LIBPATH := -L ../../tools/agbcc/lib LIB := $(LIBPATH) -lgcc -lc -L../../libagbsyscall -lagbsyscall else -CC1 = $(shell $(MODERNCC) --print-prog-name=cc1) -quiet +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 -g ROM := $(MODERN_ROM_NAME) OBJ_DIR := $(MODERN_OBJ_DIR_NAME) -LIBPATH := -L "$(dir $(shell $(MODERNCC) -mthumb -print-file-name=libgcc.a))" -L "$(dir $(shell $(MODERNCC) -mthumb -print-file-name=libnosys.a))" -L "$(dir $(shell $(MODERNCC) -mthumb -print-file-name=libc.a))" +LIBPATH := -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libgcc.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libnosys.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libc.a))" LIB := $(LIBPATH) -lc -lnosys -lgcc -L../../libagbsyscall -lagbsyscall endif -- cgit v1.2.3 From d2701b51ab08a3d099c378f6b1a8113a7bc45690 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 2 Jul 2021 15:32:05 -0400 Subject: Combine battle script labels, add EFFECT comments --- data/battle_scripts_1.s | 454 +++++++++++++++++++++++------------------------- 1 file changed, 215 insertions(+), 239 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index b15c29cfe..1577765cd 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -17,243 +17,221 @@ .align 2 gBattleScriptsForMoveEffects:: @ 82D86A8 - .4byte BattleScript_EffectHit - .4byte BattleScript_EffectSleep - .4byte BattleScript_EffectPoisonHit - .4byte BattleScript_EffectAbsorb - .4byte BattleScript_EffectBurnHit - .4byte BattleScript_EffectFreezeHit - .4byte BattleScript_EffectParalyzeHit - .4byte BattleScript_EffectExplosion - .4byte BattleScript_EffectDreamEater - .4byte BattleScript_EffectMirrorMove - .4byte BattleScript_EffectAttackUp - .4byte BattleScript_EffectDefenseUp - .4byte BattleScript_EffectSpeedUp - .4byte BattleScript_EffectSpecialAttackUp - .4byte BattleScript_EffectSpecialDefenseUp - .4byte BattleScript_EffectAccuracyUp - .4byte BattleScript_EffectEvasionUp - .4byte BattleScript_EffectAlwaysHit - .4byte BattleScript_EffectAttackDown - .4byte BattleScript_EffectDefenseDown - .4byte BattleScript_EffectSpeedDown - .4byte BattleScript_EffectSpecialAttackDown - .4byte BattleScript_EffectSpecialDefenseDown - .4byte BattleScript_EffectAccuracyDown - .4byte BattleScript_EffectEvasionDown - .4byte BattleScript_EffectHaze - .4byte BattleScript_EffectBide - .4byte BattleScript_EffectRampage - .4byte BattleScript_EffectRoar - .4byte BattleScript_EffectMultiHit - .4byte BattleScript_EffectConversion - .4byte BattleScript_EffectFlinchHit - .4byte BattleScript_EffectRestoreHp - .4byte BattleScript_EffectToxic - .4byte BattleScript_EffectPayDay - .4byte BattleScript_EffectLightScreen - .4byte BattleScript_EffectTriAttack - .4byte BattleScript_EffectRest - .4byte BattleScript_EffectOHKO - .4byte BattleScript_EffectRazorWind - .4byte BattleScript_EffectSuperFang - .4byte BattleScript_EffectDragonRage - .4byte BattleScript_EffectTrap - .4byte BattleScript_EffectHighCritical - .4byte BattleScript_EffectDoubleHit - .4byte BattleScript_EffectRecoilIfMiss - .4byte BattleScript_EffectMist - .4byte BattleScript_EffectFocusEnergy - .4byte BattleScript_EffectRecoil - .4byte BattleScript_EffectConfuse - .4byte BattleScript_EffectAttackUp2 - .4byte BattleScript_EffectDefenseUp2 - .4byte BattleScript_EffectSpeedUp2 - .4byte BattleScript_EffectSpecialAttackUp2 - .4byte BattleScript_EffectSpecialDefenseUp2 - .4byte BattleScript_EffectAccuracyUp2 - .4byte BattleScript_EffectEvasionUp2 - .4byte BattleScript_EffectTransform - .4byte BattleScript_EffectAttackDown2 - .4byte BattleScript_EffectDefenseDown2 - .4byte BattleScript_EffectSpeedDown2 - .4byte BattleScript_EffectSpecialAttackDown2 - .4byte BattleScript_EffectSpecialDefenseDown2 - .4byte BattleScript_EffectAccuracyDown2 - .4byte BattleScript_EffectEvasionDown2 - .4byte BattleScript_EffectReflect - .4byte BattleScript_EffectPoison - .4byte BattleScript_EffectParalyze - .4byte BattleScript_EffectAttackDownHit - .4byte BattleScript_EffectDefenseDownHit - .4byte BattleScript_EffectSpeedDownHit - .4byte BattleScript_EffectSpecialAttackDownHit - .4byte BattleScript_EffectSpecialDefenseDownHit - .4byte BattleScript_EffectAccuracyDownHit - .4byte BattleScript_EffectEvasionDownHit - .4byte BattleScript_EffectSkyAttack - .4byte BattleScript_EffectConfuseHit - .4byte BattleScript_EffectTwineedle - .4byte BattleScript_EffectVitalThrow - .4byte BattleScript_EffectSubstitute - .4byte BattleScript_EffectRecharge - .4byte BattleScript_EffectRage - .4byte BattleScript_EffectMimic - .4byte BattleScript_EffectMetronome - .4byte BattleScript_EffectLeechSeed - .4byte BattleScript_EffectSplash - .4byte BattleScript_EffectDisable - .4byte BattleScript_EffectLevelDamage - .4byte BattleScript_EffectPsywave - .4byte BattleScript_EffectCounter - .4byte BattleScript_EffectEncore - .4byte BattleScript_EffectPainSplit - .4byte BattleScript_EffectSnore - .4byte BattleScript_EffectConversion2 - .4byte BattleScript_EffectLockOn - .4byte BattleScript_EffectSketch - .4byte BattleScript_EffectUnused60//Thaw - .4byte BattleScript_EffectSleepTalk - .4byte BattleScript_EffectDestinyBond - .4byte BattleScript_EffectFlail - .4byte BattleScript_EffectSpite - .4byte BattleScript_EffectFalseSwipe - .4byte BattleScript_EffectHealBell - .4byte BattleScript_EffectQuickAttack - .4byte BattleScript_EffectTripleKick - .4byte BattleScript_EffectThief - .4byte BattleScript_EffectMeanLook - .4byte BattleScript_EffectNightmare - .4byte BattleScript_EffectMinimize - .4byte BattleScript_EffectCurse - .4byte BattleScript_EffectUnused6e - .4byte BattleScript_EffectProtect - .4byte BattleScript_EffectSpikes - .4byte BattleScript_EffectForesight - .4byte BattleScript_EffectPerishSong - .4byte BattleScript_EffectSandstorm - .4byte BattleScript_EffectEndure - .4byte BattleScript_EffectRollout - .4byte BattleScript_EffectSwagger - .4byte BattleScript_EffectFuryCutter - .4byte BattleScript_EffectAttract - .4byte BattleScript_EffectReturn - .4byte BattleScript_EffectPresent - .4byte BattleScript_EffectFrustration - .4byte BattleScript_EffectSafeguard - .4byte BattleScript_EffectThawHit - .4byte BattleScript_EffectMagnitude - .4byte BattleScript_EffectBatonPass - .4byte BattleScript_EffectPursuit - .4byte BattleScript_EffectRapidSpin - .4byte BattleScript_EffectSonicboom - .4byte BattleScript_EffectUnused83 - .4byte BattleScript_EffectMorningSun - .4byte BattleScript_EffectSynthesis - .4byte BattleScript_EffectMoonlight - .4byte BattleScript_EffectHiddenPower - .4byte BattleScript_EffectRainDance - .4byte BattleScript_EffectSunnyDay - .4byte BattleScript_EffectDefenseUpHit - .4byte BattleScript_EffectAttackUpHit - .4byte BattleScript_EffectAllStatsUpHit - .4byte BattleScript_EffectUnused8d - .4byte BattleScript_EffectBellyDrum - .4byte BattleScript_EffectPsychUp - .4byte BattleScript_EffectMirrorCoat - .4byte BattleScript_EffectSkullBash - .4byte BattleScript_EffectTwister - .4byte BattleScript_EffectEarthquake - .4byte BattleScript_EffectFutureSight - .4byte BattleScript_EffectGust - .4byte BattleScript_EffectStomp - .4byte BattleScript_EffectSolarbeam - .4byte BattleScript_EffectThunder - .4byte BattleScript_EffectTeleport - .4byte BattleScript_EffectBeatUp - .4byte BattleScript_EffectSemiInvulnerable - .4byte BattleScript_EffectDefenseCurl - .4byte BattleScript_EffectSoftboiled - .4byte BattleScript_EffectFakeOut - .4byte BattleScript_EffectUproar - .4byte BattleScript_EffectStockpile - .4byte BattleScript_EffectSpitUp - .4byte BattleScript_EffectSwallow - .4byte BattleScript_EffectUnusedA3 - .4byte BattleScript_EffectHail - .4byte BattleScript_EffectTorment - .4byte BattleScript_EffectFlatter - .4byte BattleScript_EffectWillOWisp - .4byte BattleScript_EffectMemento - .4byte BattleScript_EffectFacade - .4byte BattleScript_EffectFocusPunch - .4byte BattleScript_EffectSmellingsalt - .4byte BattleScript_EffectFollowMe - .4byte BattleScript_EffectNaturePower - .4byte BattleScript_EffectCharge - .4byte BattleScript_EffectTaunt - .4byte BattleScript_EffectHelpingHand - .4byte BattleScript_EffectTrick - .4byte BattleScript_EffectRolePlay - .4byte BattleScript_EffectWish - .4byte BattleScript_EffectAssist - .4byte BattleScript_EffectIngrain - .4byte BattleScript_EffectSuperpower - .4byte BattleScript_EffectMagicCoat - .4byte BattleScript_EffectRecycle - .4byte BattleScript_EffectRevenge - .4byte BattleScript_EffectBrickBreak - .4byte BattleScript_EffectYawn - .4byte BattleScript_EffectKnockOff - .4byte BattleScript_EffectEndeavor - .4byte BattleScript_EffectEruption - .4byte BattleScript_EffectSkillSwap - .4byte BattleScript_EffectImprison - .4byte BattleScript_EffectRefresh - .4byte BattleScript_EffectGrudge - .4byte BattleScript_EffectSnatch - .4byte BattleScript_EffectLowKick - .4byte BattleScript_EffectSecretPower - .4byte BattleScript_EffectDoubleEdge - .4byte BattleScript_EffectTeeterDance - .4byte BattleScript_EffectBlazeKick - .4byte BattleScript_EffectMudSport - .4byte BattleScript_EffectPoisonFang - .4byte BattleScript_EffectWeatherBall - .4byte BattleScript_EffectOverheat - .4byte BattleScript_EffectTickle - .4byte BattleScript_EffectCosmicPower - .4byte BattleScript_EffectSkyUppercut - .4byte BattleScript_EffectBulkUp - .4byte BattleScript_EffectPoisonTail - .4byte BattleScript_EffectWaterSport - .4byte BattleScript_EffectCalmMind - .4byte BattleScript_EffectDragonDance - .4byte BattleScript_EffectCamouflage - -BattleScript_EffectSpeedUp:: -BattleScript_EffectSpecialDefenseUp:: -BattleScript_EffectAccuracyUp:: -BattleScript_EffectAlwaysHit:: -BattleScript_EffectSpecialAttackDown:: -BattleScript_EffectSpecialDefenseDown:: -BattleScript_EffectHighCritical:: -BattleScript_EffectAccuracyUp2:: -BattleScript_EffectEvasionUp2:: -BattleScript_EffectSpecialAttackDown2:: -BattleScript_EffectAccuracyDown2:: -BattleScript_EffectEvasionDown2:: -BattleScript_EffectEvasionDownHit:: -BattleScript_EffectVitalThrow:: -BattleScript_EffectUnused60:: -BattleScript_EffectFalseSwipe:: -BattleScript_EffectQuickAttack:: -BattleScript_EffectUnused6e:: -BattleScript_EffectPursuit:: -BattleScript_EffectUnused83:: -BattleScript_EffectUnused8d:: -BattleScript_EffectUnusedA3:: + .4byte BattleScript_EffectHit @ EFFECT_HIT + .4byte BattleScript_EffectSleep @ EFFECT_SLEEP + .4byte BattleScript_EffectPoisonHit @ EFFECT_POISON_HIT + .4byte BattleScript_EffectAbsorb @ EFFECT_ABSORB + .4byte BattleScript_EffectBurnHit @ EFFECT_BURN_HIT + .4byte BattleScript_EffectFreezeHit @ EFFECT_FREEZE_HIT + .4byte BattleScript_EffectParalyzeHit @ EFFECT_PARALYZE_HIT + .4byte BattleScript_EffectExplosion @ EFFECT_EXPLOSION + .4byte BattleScript_EffectDreamEater @ EFFECT_DREAM_EATER + .4byte BattleScript_EffectMirrorMove @ EFFECT_MIRROR_MOVE + .4byte BattleScript_EffectAttackUp @ EFFECT_ATTACK_UP + .4byte BattleScript_EffectDefenseUp @ EFFECT_DEFENSE_UP + .4byte BattleScript_EffectHit @ EFFECT_SPEED_UP + .4byte BattleScript_EffectSpecialAttackUp @ EFFECT_SPECIAL_ATTACK_UP + .4byte BattleScript_EffectHit @ EFFECT_SPECIAL_DEFENSE_UP + .4byte BattleScript_EffectHit @ EFFECT_ACCURACY_UP + .4byte BattleScript_EffectEvasionUp @ EFFECT_EVASION_UP + .4byte BattleScript_EffectHit @ EFFECT_ALWAYS_HIT + .4byte BattleScript_EffectAttackDown @ EFFECT_ATTACK_DOWN + .4byte BattleScript_EffectDefenseDown @ EFFECT_DEFENSE_DOWN + .4byte BattleScript_EffectSpeedDown @ EFFECT_SPEED_DOWN + .4byte BattleScript_EffectHit @ EFFECT_SPECIAL_ATTACK_DOWN + .4byte BattleScript_EffectHit @ EFFECT_SPECIAL_DEFENSE_DOWN + .4byte BattleScript_EffectAccuracyDown @ EFFECT_ACCURACY_DOWN + .4byte BattleScript_EffectEvasionDown @ EFFECT_EVASION_DOWN + .4byte BattleScript_EffectHaze @ EFFECT_HAZE + .4byte BattleScript_EffectBide @ EFFECT_BIDE + .4byte BattleScript_EffectRampage @ EFFECT_RAMPAGE + .4byte BattleScript_EffectRoar @ EFFECT_ROAR + .4byte BattleScript_EffectMultiHit @ EFFECT_MULTI_HIT + .4byte BattleScript_EffectConversion @ EFFECT_CONVERSION + .4byte BattleScript_EffectFlinchHit @ EFFECT_FLINCH_HIT + .4byte BattleScript_EffectRestoreHp @ EFFECT_RESTORE_HP + .4byte BattleScript_EffectToxic @ EFFECT_TOXIC + .4byte BattleScript_EffectPayDay @ EFFECT_PAY_DAY + .4byte BattleScript_EffectLightScreen @ EFFECT_LIGHT_SCREEN + .4byte BattleScript_EffectTriAttack @ EFFECT_TRI_ATTACK + .4byte BattleScript_EffectRest @ EFFECT_REST + .4byte BattleScript_EffectOHKO @ EFFECT_OHKO + .4byte BattleScript_EffectRazorWind @ EFFECT_RAZOR_WIND + .4byte BattleScript_EffectSuperFang @ EFFECT_SUPER_FANG + .4byte BattleScript_EffectDragonRage @ EFFECT_DRAGON_RAGE + .4byte BattleScript_EffectTrap @ EFFECT_TRAP + .4byte BattleScript_EffectHit @ EFFECT_HIGH_CRITICAL + .4byte BattleScript_EffectDoubleHit @ EFFECT_DOUBLE_HIT + .4byte BattleScript_EffectRecoilIfMiss @ EFFECT_RECOIL_IF_MISS + .4byte BattleScript_EffectMist @ EFFECT_MIST + .4byte BattleScript_EffectFocusEnergy @ EFFECT_FOCUS_ENERGY + .4byte BattleScript_EffectRecoil @ EFFECT_RECOIL + .4byte BattleScript_EffectConfuse @ EFFECT_CONFUSE + .4byte BattleScript_EffectAttackUp2 @ EFFECT_ATTACK_UP_2 + .4byte BattleScript_EffectDefenseUp2 @ EFFECT_DEFENSE_UP_2 + .4byte BattleScript_EffectSpeedUp2 @ EFFECT_SPEED_UP_2 + .4byte BattleScript_EffectSpecialAttackUp2 @ EFFECT_SPECIAL_ATTACK_UP_2 + .4byte BattleScript_EffectSpecialDefenseUp2 @ EFFECT_SPECIAL_DEFENSE_UP_2 + .4byte BattleScript_EffectHit @ EFFECT_ACCURACY_UP_2 + .4byte BattleScript_EffectHit @ EFFECT_EVASION_UP_2 + .4byte BattleScript_EffectTransform @ EFFECT_TRANSFORM + .4byte BattleScript_EffectAttackDown2 @ EFFECT_ATTACK_DOWN_2 + .4byte BattleScript_EffectDefenseDown2 @ EFFECT_DEFENSE_DOWN_2 + .4byte BattleScript_EffectSpeedDown2 @ EFFECT_SPEED_DOWN_2 + .4byte BattleScript_EffectHit @ EFFECT_SPECIAL_ATTACK_DOWN_2 + .4byte BattleScript_EffectSpecialDefenseDown2 @ EFFECT_SPECIAL_DEFENSE_DOWN_2 + .4byte BattleScript_EffectHit @ EFFECT_ACCURACY_DOWN_2 + .4byte BattleScript_EffectHit @ EFFECT_EVASION_DOWN_2 + .4byte BattleScript_EffectReflect @ EFFECT_REFLECT + .4byte BattleScript_EffectPoison @ EFFECT_POISON + .4byte BattleScript_EffectParalyze @ EFFECT_PARALYZE + .4byte BattleScript_EffectAttackDownHit @ EFFECT_ATTACK_DOWN_HIT + .4byte BattleScript_EffectDefenseDownHit @ EFFECT_DEFENSE_DOWN_HIT + .4byte BattleScript_EffectSpeedDownHit @ EFFECT_SPEED_DOWN_HIT + .4byte BattleScript_EffectSpecialAttackDownHit @ EFFECT_SPECIAL_ATTACK_DOWN_HIT + .4byte BattleScript_EffectSpecialDefenseDownHit @ EFFECT_SPECIAL_DEFENSE_DOWN_HIT + .4byte BattleScript_EffectAccuracyDownHit @ EFFECT_ACCURACY_DOWN_HIT + .4byte BattleScript_EffectHit @ EFFECT_EVASION_DOWN_HIT + .4byte BattleScript_EffectSkyAttack @ EFFECT_SKY_ATTACK + .4byte BattleScript_EffectConfuseHit @ EFFECT_CONFUSE_HIT + .4byte BattleScript_EffectTwineedle @ EFFECT_TWINEEDLE + .4byte BattleScript_EffectHit @ EFFECT_VITAL_THROW + .4byte BattleScript_EffectSubstitute @ EFFECT_SUBSTITUTE + .4byte BattleScript_EffectRecharge @ EFFECT_RECHARGE + .4byte BattleScript_EffectRage @ EFFECT_RAGE + .4byte BattleScript_EffectMimic @ EFFECT_MIMIC + .4byte BattleScript_EffectMetronome @ EFFECT_METRONOME + .4byte BattleScript_EffectLeechSeed @ EFFECT_LEECH_SEED + .4byte BattleScript_EffectSplash @ EFFECT_SPLASH + .4byte BattleScript_EffectDisable @ EFFECT_DISABLE + .4byte BattleScript_EffectLevelDamage @ EFFECT_LEVEL_DAMAGE + .4byte BattleScript_EffectPsywave @ EFFECT_PSYWAVE + .4byte BattleScript_EffectCounter @ EFFECT_COUNTER + .4byte BattleScript_EffectEncore @ EFFECT_ENCORE + .4byte BattleScript_EffectPainSplit @ EFFECT_PAIN_SPLIT + .4byte BattleScript_EffectSnore @ EFFECT_SNORE + .4byte BattleScript_EffectConversion2 @ EFFECT_CONVERSION_2 + .4byte BattleScript_EffectLockOn @ EFFECT_LOCK_ON + .4byte BattleScript_EffectSketch @ EFFECT_SKETCH + .4byte BattleScript_EffectHit @ EFFECT_UNUSED_60 + .4byte BattleScript_EffectSleepTalk @ EFFECT_SLEEP_TALK + .4byte BattleScript_EffectDestinyBond @ EFFECT_DESTINY_BOND + .4byte BattleScript_EffectFlail @ EFFECT_FLAIL + .4byte BattleScript_EffectSpite @ EFFECT_SPITE + .4byte BattleScript_EffectHit @ EFFECT_FALSE_SWIPE + .4byte BattleScript_EffectHealBell @ EFFECT_HEAL_BELL + .4byte BattleScript_EffectHit @ EFFECT_QUICK_ATTACK + .4byte BattleScript_EffectTripleKick @ EFFECT_TRIPLE_KICK + .4byte BattleScript_EffectThief @ EFFECT_THIEF + .4byte BattleScript_EffectMeanLook @ EFFECT_MEAN_LOOK + .4byte BattleScript_EffectNightmare @ EFFECT_NIGHTMARE + .4byte BattleScript_EffectMinimize @ EFFECT_MINIMIZE + .4byte BattleScript_EffectCurse @ EFFECT_CURSE + .4byte BattleScript_EffectHit @ EFFECT_UNUSED_6E + .4byte BattleScript_EffectProtect @ EFFECT_PROTECT + .4byte BattleScript_EffectSpikes @ EFFECT_SPIKES + .4byte BattleScript_EffectForesight @ EFFECT_FORESIGHT + .4byte BattleScript_EffectPerishSong @ EFFECT_PERISH_SONG + .4byte BattleScript_EffectSandstorm @ EFFECT_SANDSTORM + .4byte BattleScript_EffectEndure @ EFFECT_ENDURE + .4byte BattleScript_EffectRollout @ EFFECT_ROLLOUT + .4byte BattleScript_EffectSwagger @ EFFECT_SWAGGER + .4byte BattleScript_EffectFuryCutter @ EFFECT_FURY_CUTTER + .4byte BattleScript_EffectAttract @ EFFECT_ATTRACT + .4byte BattleScript_EffectReturn @ EFFECT_RETURN + .4byte BattleScript_EffectPresent @ EFFECT_PRESENT + .4byte BattleScript_EffectFrustration @ EFFECT_FRUSTRATION + .4byte BattleScript_EffectSafeguard @ EFFECT_SAFEGUARD + .4byte BattleScript_EffectThawHit @ EFFECT_THAW_HIT + .4byte BattleScript_EffectMagnitude @ EFFECT_MAGNITUDE + .4byte BattleScript_EffectBatonPass @ EFFECT_BATON_PASS + .4byte BattleScript_EffectHit @ EFFECT_PURSUIT + .4byte BattleScript_EffectRapidSpin @ EFFECT_RAPID_SPIN + .4byte BattleScript_EffectSonicboom @ EFFECT_SONICBOOM + .4byte BattleScript_EffectHit @ EFFECT_UNUSED_83 + .4byte BattleScript_EffectMorningSun @ EFFECT_MORNING_SUN + .4byte BattleScript_EffectSynthesis @ EFFECT_SYNTHESIS + .4byte BattleScript_EffectMoonlight @ EFFECT_MOONLIGHT + .4byte BattleScript_EffectHiddenPower @ EFFECT_HIDDEN_POWER + .4byte BattleScript_EffectRainDance @ EFFECT_RAIN_DANCE + .4byte BattleScript_EffectSunnyDay @ EFFECT_SUNNY_DAY + .4byte BattleScript_EffectDefenseUpHit @ EFFECT_DEFENSE_UP_HIT + .4byte BattleScript_EffectAttackUpHit @ EFFECT_ATTACK_UP_HIT + .4byte BattleScript_EffectAllStatsUpHit @ EFFECT_ALL_STATS_UP_HIT + .4byte BattleScript_EffectHit @ EFFECT_UNUSED_8D + .4byte BattleScript_EffectBellyDrum @ EFFECT_BELLY_DRUM + .4byte BattleScript_EffectPsychUp @ EFFECT_PSYCH_UP + .4byte BattleScript_EffectMirrorCoat @ EFFECT_MIRROR_COAT + .4byte BattleScript_EffectSkullBash @ EFFECT_SKULL_BASH + .4byte BattleScript_EffectTwister @ EFFECT_TWISTER + .4byte BattleScript_EffectEarthquake @ EFFECT_EARTHQUAKE + .4byte BattleScript_EffectFutureSight @ EFFECT_FUTURE_SIGHT + .4byte BattleScript_EffectGust @ EFFECT_GUST + .4byte BattleScript_EffectStomp @ EFFECT_FLINCH_MINIMIZE_HIT + .4byte BattleScript_EffectSolarbeam @ EFFECT_SOLARBEAM + .4byte BattleScript_EffectThunder @ EFFECT_THUNDER + .4byte BattleScript_EffectTeleport @ EFFECT_TELEPORT + .4byte BattleScript_EffectBeatUp @ EFFECT_BEAT_UP + .4byte BattleScript_EffectSemiInvulnerable @ EFFECT_SEMI_INVULNERABLE + .4byte BattleScript_EffectDefenseCurl @ EFFECT_DEFENSE_CURL + .4byte BattleScript_EffectSoftboiled @ EFFECT_SOFTBOILED + .4byte BattleScript_EffectFakeOut @ EFFECT_FAKE_OUT + .4byte BattleScript_EffectUproar @ EFFECT_UPROAR + .4byte BattleScript_EffectStockpile @ EFFECT_STOCKPILE + .4byte BattleScript_EffectSpitUp @ EFFECT_SPIT_UP + .4byte BattleScript_EffectSwallow @ EFFECT_SWALLOW + .4byte BattleScript_EffectHit @ EFFECT_UNUSED_A3 + .4byte BattleScript_EffectHail @ EFFECT_HAIL + .4byte BattleScript_EffectTorment @ EFFECT_TORMENT + .4byte BattleScript_EffectFlatter @ EFFECT_FLATTER + .4byte BattleScript_EffectWillOWisp @ EFFECT_WILL_O_WISP + .4byte BattleScript_EffectMemento @ EFFECT_MEMENTO + .4byte BattleScript_EffectFacade @ EFFECT_FACADE + .4byte BattleScript_EffectFocusPunch @ EFFECT_FOCUS_PUNCH + .4byte BattleScript_EffectSmellingsalt @ EFFECT_SMELLINGSALT + .4byte BattleScript_EffectFollowMe @ EFFECT_FOLLOW_ME + .4byte BattleScript_EffectNaturePower @ EFFECT_NATURE_POWER + .4byte BattleScript_EffectCharge @ EFFECT_CHARGE + .4byte BattleScript_EffectTaunt @ EFFECT_TAUNT + .4byte BattleScript_EffectHelpingHand @ EFFECT_HELPING_HAND + .4byte BattleScript_EffectTrick @ EFFECT_TRICK + .4byte BattleScript_EffectRolePlay @ EFFECT_ROLE_PLAY + .4byte BattleScript_EffectWish @ EFFECT_WISH + .4byte BattleScript_EffectAssist @ EFFECT_ASSIST + .4byte BattleScript_EffectIngrain @ EFFECT_INGRAIN + .4byte BattleScript_EffectSuperpower @ EFFECT_SUPERPOWER + .4byte BattleScript_EffectMagicCoat @ EFFECT_MAGIC_COAT + .4byte BattleScript_EffectRecycle @ EFFECT_RECYCLE + .4byte BattleScript_EffectRevenge @ EFFECT_REVENGE + .4byte BattleScript_EffectBrickBreak @ EFFECT_BRICK_BREAK + .4byte BattleScript_EffectYawn @ EFFECT_YAWN + .4byte BattleScript_EffectKnockOff @ EFFECT_KNOCK_OFF + .4byte BattleScript_EffectEndeavor @ EFFECT_ENDEAVOR + .4byte BattleScript_EffectEruption @ EFFECT_ERUPTION + .4byte BattleScript_EffectSkillSwap @ EFFECT_SKILL_SWAP + .4byte BattleScript_EffectImprison @ EFFECT_IMPRISON + .4byte BattleScript_EffectRefresh @ EFFECT_REFRESH + .4byte BattleScript_EffectGrudge @ EFFECT_GRUDGE + .4byte BattleScript_EffectSnatch @ EFFECT_SNATCH + .4byte BattleScript_EffectLowKick @ EFFECT_LOW_KICK + .4byte BattleScript_EffectSecretPower @ EFFECT_SECRET_POWER + .4byte BattleScript_EffectDoubleEdge @ EFFECT_DOUBLE_EDGE + .4byte BattleScript_EffectTeeterDance @ EFFECT_TEETER_DANCE + .4byte BattleScript_EffectBurnHit @ EFFECT_BLAZE_KICK + .4byte BattleScript_EffectMudSport @ EFFECT_MUD_SPORT + .4byte BattleScript_EffectPoisonFang @ EFFECT_POISON_FANG + .4byte BattleScript_EffectWeatherBall @ EFFECT_WEATHER_BALL + .4byte BattleScript_EffectOverheat @ EFFECT_OVERHEAT + .4byte BattleScript_EffectTickle @ EFFECT_TICKLE + .4byte BattleScript_EffectCosmicPower @ EFFECT_COSMIC_POWER + .4byte BattleScript_EffectSkyUppercut @ EFFECT_SKY_UPPERCUT + .4byte BattleScript_EffectBulkUp @ EFFECT_BULK_UP + .4byte BattleScript_EffectPoisonHit @ EFFECT_POISON_TAIL + .4byte BattleScript_EffectWaterSport @ EFFECT_WATER_SPORT + .4byte BattleScript_EffectCalmMind @ EFFECT_CALM_MIND + .4byte BattleScript_EffectDragonDance @ EFFECT_DRAGON_DANCE + .4byte BattleScript_EffectCamouflage @ EFFECT_CAMOUFLAGE + BattleScript_EffectHit:: jumpifnotmove MOVE_SURF, BattleScript_HitFromAtkCanceler jumpifnostatus3 BS_TARGET, STATUS3_UNDERWATER, BattleScript_HitFromAtkCanceler @@ -338,7 +316,6 @@ BattleScript_CantMakeAsleep:: goto BattleScript_MoveEnd BattleScript_EffectPoisonHit:: -BattleScript_EffectPoisonTail:: setmoveeffect MOVE_EFFECT_POISON goto BattleScript_EffectHit @@ -382,7 +359,6 @@ BattleScript_AbsorbTryFainting:: goto BattleScript_MoveEnd BattleScript_EffectBurnHit:: -BattleScript_EffectBlazeKick:: setmoveeffect MOVE_EFFECT_BURN goto BattleScript_EffectHit -- cgit v1.2.3 From 43c5107e4d7cd9eda386253906a5939fe4226bf6 Mon Sep 17 00:00:00 2001 From: SnorlaxMonster Date: Sat, 3 Jul 2021 22:38:22 +1000 Subject: Correct card lines in Battle Dome comments The comments regarding the lines that Trainer information is displayed on the Battle Dome Trainer Card were off-by-one. --- src/battle_dome.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/battle_dome.c b/src/battle_dome.c index 59e418a06..ea1e5abba 100644 --- a/src/battle_dome.c +++ b/src/battle_dome.c @@ -1211,8 +1211,8 @@ static const u8 gUnknown_0860D1A0[DOME_TOURNAMENT_TRAINERS_COUNT / 2][DOME_ROUND static const u8 gUnknown_0860D1C0[DOME_TOURNAMENT_TRAINERS_COUNT] = {0, 15, 8, 7, 3, 12, 11, 4, 1, 14, 9, 6, 2, 13, 10, 5}; -// Each tourney trainer has a text describing their potential to win, depending on their seed ranking for the current tourney -// Dome Ace Tucker has their own separate potential text +// The first line of text on a trainers info card. It describes their potential to win, based on their seed in the tournament tree. +// Dome Ace Tucker has their own separate potential text. static const u8 *const sBattleDomePotentialTexts[DOME_TOURNAMENT_TRAINERS_COUNT + 1] = { BattleDome_Text_Potential1, // Highest potential @@ -1234,7 +1234,7 @@ static const u8 *const sBattleDomePotentialTexts[DOME_TOURNAMENT_TRAINERS_COUNT BattleDome_Text_PotentialDomeAceTucker, }; -// The first line of text on a trainers info card that gives information about their battle style (dependent on their party's moves) +// The second line of text on a trainers info card. It gives information about their battle style (dependent on their party's moves). static const u8 *const sBattleDomeOpponentStyleTexts[NUM_BATTLE_STYLES] = { [DOME_BATTLE_STYLE_RISKY] = BattleDome_Text_StyleRiskDisaster, @@ -1271,7 +1271,7 @@ static const u8 *const sBattleDomeOpponentStyleTexts[NUM_BATTLE_STYLES] = [DOME_BATTLE_STYLE_UNUSED4] = BattleDome_Text_StyleSampleMessage4, }; -// The second line of text on a trainers info card that gives information about their party's stat spread +// The third line of text on a trainers info card. It that gives information about their party's stat spread (based on their Pokémon's effort values and Nature). static const u8 *const sBattleDomeOpponentStatsTexts[] = { BattleDome_Text_EmphasizesHPAndAtk, // DOME_TEXT_TWO_GOOD_STATS and DOME_TEXT_HP start here -- cgit v1.2.3 From 42730a8315be6abceeb95bc1cd29f4c54077bd2e Mon Sep 17 00:00:00 2001 From: Kurausukun Date: Sat, 3 Jul 2021 17:39:33 -0400 Subject: Revert "remove gflib" This reverts commit 8b59909ac5eb6e3540aeb78396943d57a9702e4d. --- Makefile | 38 +- gflib/bg.c | 1248 ++++++++++++++++++++++++++++++++++ gflib/bg.h | 85 +++ gflib/blit.c | 209 ++++++ gflib/blit.h | 17 + gflib/dma3.h | 55 ++ gflib/dma3_manager.c | 183 +++++ gflib/gpu_regs.c | 195 ++++++ gflib/gpu_regs.h | 19 + gflib/io_reg.c | 36 + gflib/io_reg.h | 7 + gflib/malloc.c | 210 ++++++ gflib/malloc.h | 22 + gflib/sprite.c | 1775 ++++++++++++++++++++++++++++++++++++++++++++++++ gflib/sprite.h | 324 +++++++++ gflib/string_util.c | 781 +++++++++++++++++++++ gflib/string_util.h | 46 ++ gflib/text.c | 1808 +++++++++++++++++++++++++++++++++++++++++++++++++ gflib/text.h | 436 ++++++++++++ gflib/window.c | 721 ++++++++++++++++++++ gflib/window.h | 80 +++ include/bg.h | 85 --- include/blit.h | 17 - include/dma3.h | 55 -- include/gpu_regs.h | 19 - include/io_reg.h | 7 - include/malloc.h | 22 - include/sprite.h | 324 --------- include/string_util.h | 46 -- include/text.h | 436 ------------ include/window.h | 80 --- ld_script.txt | 30 +- ld_script_modern.txt | 5 + src/bg.c | 1248 ---------------------------------- src/blit.c | 209 ------ src/dma3_manager.c | 183 ----- src/gpu_regs.c | 195 ------ src/io_reg.c | 36 - src/malloc.c | 210 ------ src/sprite.c | 1775 ------------------------------------------------ src/string_util.c | 781 --------------------- src/text.c | 1808 ------------------------------------------------- src/window.c | 721 -------------------- sym_bss.txt | 12 +- sym_common.txt | 8 +- sym_ewram.txt | 8 +- 46 files changed, 8326 insertions(+), 8289 deletions(-) create mode 100644 gflib/bg.c create mode 100644 gflib/bg.h create mode 100644 gflib/blit.c create mode 100644 gflib/blit.h create mode 100644 gflib/dma3.h create mode 100644 gflib/dma3_manager.c create mode 100644 gflib/gpu_regs.c create mode 100644 gflib/gpu_regs.h create mode 100644 gflib/io_reg.c create mode 100644 gflib/io_reg.h create mode 100644 gflib/malloc.c create mode 100644 gflib/malloc.h create mode 100644 gflib/sprite.c create mode 100644 gflib/sprite.h create mode 100644 gflib/string_util.c create mode 100644 gflib/string_util.h create mode 100644 gflib/text.c create mode 100644 gflib/text.h create mode 100644 gflib/window.c create mode 100644 gflib/window.h delete mode 100644 include/bg.h delete mode 100644 include/blit.h delete mode 100644 include/dma3.h delete mode 100644 include/gpu_regs.h delete mode 100644 include/io_reg.h delete mode 100644 include/malloc.h delete mode 100644 include/sprite.h delete mode 100644 include/string_util.h delete mode 100644 include/text.h delete mode 100644 include/window.h delete mode 100644 src/bg.c delete mode 100644 src/blit.c delete mode 100644 src/dma3_manager.c delete mode 100644 src/gpu_regs.c delete mode 100644 src/io_reg.c delete mode 100644 src/malloc.c delete mode 100644 src/sprite.c delete mode 100644 src/string_util.c delete mode 100644 src/text.c delete mode 100644 src/window.c diff --git a/Makefile b/Makefile index 95d6328ef..d7d4b9566 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,7 @@ ELF = $(ROM:.gba=.elf) MAP = $(ROM:.gba=.map) C_SUBDIR = src +GFLIB_SUBDIR = gflib ASM_SUBDIR = asm DATA_SRC_SUBDIR = src/data DATA_ASM_SUBDIR = data @@ -86,6 +87,7 @@ SAMPLE_SUBDIR = sound/direct_sound_samples CRY_SUBDIR = sound/direct_sound_samples/cries C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR) +GFLIB_BUILDDIR = $(OBJ_DIR)/$(GFLIB_SUBDIR) ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR) DATA_ASM_BUILDDIR = $(OBJ_DIR)/$(DATA_ASM_SUBDIR) SONG_BUILDDIR = $(OBJ_DIR)/$(SONG_SUBDIR) @@ -109,7 +111,7 @@ LIBPATH := -L "$(dir $(shell $(MODERNCC) -mthumb -print-file-name=libgcc.a))" -L LIB := $(LIBPATH) -lc -lnosys -lgcc -L../../libagbsyscall -lagbsyscall endif -CPPFLAGS := -iquote include -Wno-trigraphs -DMODERN=$(MODERN) +CPPFLAGS := -iquote include -iquote $(GFLIB_SUBDIR) -Wno-trigraphs -DMODERN=$(MODERN) ifneq ($(MODERN),1) CPPFLAGS += -I tools/agbcc/include -I tools/agbcc -nostdinc -undef endif @@ -175,6 +177,9 @@ C_SRCS_IN := $(wildcard $(C_SUBDIR)/*.c $(C_SUBDIR)/*/*.c $(C_SUBDIR)/*/*/*.c) C_SRCS := $(foreach src,$(C_SRCS_IN),$(if $(findstring .inc.c,$(src)),,$(src))) C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS)) +GFLIB_SRCS := $(wildcard $(GFLIB_SUBDIR)/*.c) +GFLIB_OBJS := $(patsubst $(GFLIB_SUBDIR)/%.c,$(GFLIB_BUILDDIR)/%.o,$(GFLIB_SRCS)) + C_ASM_SRCS += $(wildcard $(C_SUBDIR)/*.s $(C_SUBDIR)/*/*.s $(C_SUBDIR)/*/*/*.s) C_ASM_OBJS := $(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o,$(C_ASM_SRCS)) @@ -193,7 +198,7 @@ SONG_OBJS := $(patsubst $(SONG_SUBDIR)/%.s,$(SONG_BUILDDIR)/%.o,$(SONG_SRCS)) MID_SRCS := $(wildcard $(MID_SUBDIR)/*.mid) MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS)) -OBJS := $(C_OBJS) $(C_ASM_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) +OBJS := $(C_OBJS) $(GFLIB_OBJS) $(C_ASM_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS)) SUBDIRS := $(sort $(dir $(OBJS))) @@ -311,7 +316,7 @@ else endif else define C_DEP -$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include $2) +$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2) ifeq (,$$(KEEP_TEMPS)) @echo "$$(CC1) -o $$@ $$<" @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - @@ -325,6 +330,33 @@ endef $(foreach src, $(C_SRCS), $(eval $(call C_DEP,$(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(src)),$(src),$(patsubst $(C_SUBDIR)/%.c,%,$(src))))) endif +ifeq ($(NODEP),1) +$(GFLIB_BUILDDIR)/%.o: $(GFLIB_SUBDIR)/%.c $$(c_dep) +ifeq (,$(KEEP_TEMPS)) + @echo "$(CC1) -o $@ $<" + @$(CPP) $(CPPFLAGS) $< | $(PREPROC) $< charmap.txt -i | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ - +else + @$(CPP) $(CPPFLAGS) $< -o $(GFLIB_BUILDDIR)/$*.i + @$(PREPROC) $(GFLIB_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(GFLIB_BUILDDIR)/$*.s + @echo -e ".text\n\t.align\t2, 0\n" >> $(GFLIB_BUILDDIR)/$*.s + $(AS) $(ASFLAGS) -o $@ $(GFLIB_BUILDDIR)/$*.s +endif +else +define GFLIB_DEP +$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2) +ifeq (,$$(KEEP_TEMPS)) + @echo "$$(CC1) -o $$@ $$<" + @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - +else + @$$(CPP) $$(CPPFLAGS) $$< -o $$(GFLIB_BUILDDIR)/$3.i + @$$(PREPROC) $$(GFLIB_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(GFLIB_BUILDDIR)/$3.s + @echo -e ".text\n\t.align\t2, 0\n" >> $$(GFLIB_BUILDDIR)/$3.s + $$(AS) $$(ASFLAGS) -o $$@ $$(GFLIB_BUILDDIR)/$3.s +endif +endef +$(foreach src, $(GFLIB_SRCS), $(eval $(call GFLIB_DEP,$(patsubst $(GFLIB_SUBDIR)/%.c,$(GFLIB_BUILDDIR)/%.o, $(src)),$(src),$(patsubst $(GFLIB_SUBDIR)/%.c,%, $(src))))) +endif + ifeq ($(NODEP),1) $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@ diff --git a/gflib/bg.c b/gflib/bg.c new file mode 100644 index 000000000..ec7c2113b --- /dev/null +++ b/gflib/bg.c @@ -0,0 +1,1248 @@ +#include +#include "global.h" +#include "bg.h" +#include "dma3.h" +#include "gpu_regs.h" + +#define DISPCNT_ALL_BG_AND_MODE_BITS (DISPCNT_BG_ALL_ON | 0x7) + +struct BgControl +{ + struct BgConfig { + u8 visible:1; + u8 unknown_1:1; + u8 screenSize:2; + u8 priority:2; + u8 mosaic:1; + u8 wraparound:1; + + u8 charBaseIndex:2; + u8 mapBaseIndex:5; + u8 paletteMode:1; + + u8 unknown_2; // Assigned to but never read + u8 unknown_3; // Assigned to but never read + } configs[NUM_BACKGROUNDS]; + + u16 bgVisibilityAndMode; +}; + +struct BgConfig2 +{ + u32 baseTile:10; + u32 basePalette:4; + u32 unk_3:18; + + void* tilemap; + s32 bg_x; + s32 bg_y; +}; + +static struct BgControl sGpuBgConfigs; +static struct BgConfig2 sGpuBgConfigs2[NUM_BACKGROUNDS]; +static u32 sDmaBusyBitfield[NUM_BACKGROUNDS]; + +u32 gUnneededFireRedVariable; + +static const struct BgConfig sZeroedBgControlStruct = { 0 }; + +void ResetBgs(void) +{ + ResetBgControlStructs(); + sGpuBgConfigs.bgVisibilityAndMode = 0; + SetTextModeAndHideBgs(); +} + +static void SetBgModeInternal(u8 bgMode) +{ + sGpuBgConfigs.bgVisibilityAndMode &= ~0x7; + sGpuBgConfigs.bgVisibilityAndMode |= bgMode; +} + +u8 GetBgMode(void) +{ + return sGpuBgConfigs.bgVisibilityAndMode & 0x7; +} + +void ResetBgControlStructs(void) +{ + int i; + + for (i = 0; i < NUM_BACKGROUNDS; i++) + { + sGpuBgConfigs.configs[i] = sZeroedBgControlStruct; + } +} + +void Unused_ResetBgControlStruct(u8 bg) +{ + if (!IsInvalidBg(bg)) + { + sGpuBgConfigs.configs[bg] = sZeroedBgControlStruct; + } +} + +enum +{ + BG_CTRL_ATTR_VISIBLE = 1, + BG_CTRL_ATTR_CHARBASEINDEX = 2, + BG_CTRL_ATTR_MAPBASEINDEX = 3, + BG_CTRL_ATTR_SCREENSIZE = 4, + BG_CTRL_ATTR_PALETTEMODE = 5, + BG_CTRL_ATTR_PRIORITY = 6, + BG_CTRL_ATTR_MOSAIC = 7, + BG_CTRL_ATTR_WRAPAROUND = 8, +}; + +static void SetBgControlAttributes(u8 bg, u8 charBaseIndex, u8 mapBaseIndex, u8 screenSize, u8 paletteMode, u8 priority, u8 mosaic, u8 wraparound) +{ + if (!IsInvalidBg(bg)) + { + if (charBaseIndex != 0xFF) + { + sGpuBgConfigs.configs[bg].charBaseIndex = charBaseIndex; + } + + if (mapBaseIndex != 0xFF) + { + sGpuBgConfigs.configs[bg].mapBaseIndex = mapBaseIndex; + } + + if (screenSize != 0xFF) + { + sGpuBgConfigs.configs[bg].screenSize = screenSize; + } + + if (paletteMode != 0xFF) + { + sGpuBgConfigs.configs[bg].paletteMode = paletteMode; + } + + if (priority != 0xFF) + { + sGpuBgConfigs.configs[bg].priority = priority; + } + + if (mosaic != 0xFF) + { + sGpuBgConfigs.configs[bg].mosaic = mosaic; + } + + if (wraparound != 0xFF) + { + sGpuBgConfigs.configs[bg].wraparound = wraparound; + } + + sGpuBgConfigs.configs[bg].unknown_2 = 0; + sGpuBgConfigs.configs[bg].unknown_3 = 0; + + sGpuBgConfigs.configs[bg].visible = 1; + } +} + +static u16 GetBgControlAttribute(u8 bg, u8 attributeId) +{ + if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) + { + switch (attributeId) + { + case BG_CTRL_ATTR_VISIBLE: + return sGpuBgConfigs.configs[bg].visible; + case BG_CTRL_ATTR_CHARBASEINDEX: + return sGpuBgConfigs.configs[bg].charBaseIndex; + case BG_CTRL_ATTR_MAPBASEINDEX: + return sGpuBgConfigs.configs[bg].mapBaseIndex; + case BG_CTRL_ATTR_SCREENSIZE: + return sGpuBgConfigs.configs[bg].screenSize; + case BG_CTRL_ATTR_PALETTEMODE: + return sGpuBgConfigs.configs[bg].paletteMode; + case BG_CTRL_ATTR_PRIORITY: + return sGpuBgConfigs.configs[bg].priority; + case BG_CTRL_ATTR_MOSAIC: + return sGpuBgConfigs.configs[bg].mosaic; + case BG_CTRL_ATTR_WRAPAROUND: + return sGpuBgConfigs.configs[bg].wraparound; + } + } + + return 0xFF; +} + +u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode) +{ + u16 offset; + s8 cursor; + + if (IsInvalidBg(bg) || !sGpuBgConfigs.configs[bg].visible) + return -1; + + switch (mode) + { + case 0x1: + offset = sGpuBgConfigs.configs[bg].charBaseIndex * BG_CHAR_SIZE; + offset = destOffset + offset; + cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); + if (cursor == -1) + return -1; + break; + case 0x2: + offset = sGpuBgConfigs.configs[bg].mapBaseIndex * BG_SCREEN_SIZE; + offset = destOffset + offset; + cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); + if (cursor == -1) + return -1; + break; + default: + cursor = -1; + break; + } + + return cursor; +} + +static void ShowBgInternal(u8 bg) +{ + u16 value; + if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) + { + value = sGpuBgConfigs.configs[bg].priority | + (sGpuBgConfigs.configs[bg].charBaseIndex << 2) | + (sGpuBgConfigs.configs[bg].mosaic << 6) | + (sGpuBgConfigs.configs[bg].paletteMode << 7) | + (sGpuBgConfigs.configs[bg].mapBaseIndex << 8) | + (sGpuBgConfigs.configs[bg].wraparound << 13) | + (sGpuBgConfigs.configs[bg].screenSize << 14); + + SetGpuReg((bg << 1) + REG_OFFSET_BG0CNT, value); + + sGpuBgConfigs.bgVisibilityAndMode |= 1 << (bg + 8); + sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; + } +} + +static void HideBgInternal(u8 bg) +{ + if (!IsInvalidBg(bg)) + { + sGpuBgConfigs.bgVisibilityAndMode &= ~(1 << (bg + 8)); + sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; + } +} + +static void SyncBgVisibilityAndMode(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, (GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS) | sGpuBgConfigs.bgVisibilityAndMode); +} + +void SetTextModeAndHideBgs(void) +{ + SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS); +} + +static void SetBgAffineInternal(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) +{ + struct BgAffineSrcData src; + struct BgAffineDstData dest; + + switch (sGpuBgConfigs.bgVisibilityAndMode & 0x7) + { + default: + case 0: + return; + case 1: + if (bg != 2) + return; + break; + case 2: + if (bg != 2 && bg != 3) + return; + break; + } + + src.texX = srcCenterX; + src.texY = srcCenterY; + src.scrX = dispCenterX; + src.scrY = dispCenterY; + src.sx = scaleX; + src.sy = scaleY; + src.alpha = rotationAngle; + + BgAffineSet(&src, &dest, 1); + + SetGpuReg(REG_OFFSET_BG2PA, dest.pa); + SetGpuReg(REG_OFFSET_BG2PB, dest.pb); + SetGpuReg(REG_OFFSET_BG2PC, dest.pc); + SetGpuReg(REG_OFFSET_BG2PD, dest.pd); + SetGpuReg(REG_OFFSET_BG2PA, dest.pa); + SetGpuReg(REG_OFFSET_BG2X_L, (s16)(dest.dx)); + SetGpuReg(REG_OFFSET_BG2X_H, (s16)(dest.dx >> 16)); + SetGpuReg(REG_OFFSET_BG2Y_L, (s16)(dest.dy)); + SetGpuReg(REG_OFFSET_BG2Y_H, (s16)(dest.dy >> 16)); +} + +bool8 IsInvalidBg(u8 bg) +{ + if (bg >= NUM_BACKGROUNDS) + return TRUE; + else + return FALSE; +} + +int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4) +{ + return 0; +} + +void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable) +{ + int i; + ResetBgs(); + + for (i = 0; i < NUM_BACKGROUNDS; i++) + { + sDmaBusyBitfield[i] = 0; + } + + gUnneededFireRedVariable = leftoverFireRedLeafGreenVariable; +} + +void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates) +{ + int i; + u8 bg; + + SetBgModeInternal(bgMode); + ResetBgControlStructs(); + + for (i = 0; i < numTemplates; i++) + { + bg = templates[i].bg; + if (bg < NUM_BACKGROUNDS) + { + SetBgControlAttributes(bg, + templates[i].charBaseIndex, + templates[i].mapBaseIndex, + templates[i].screenSize, + templates[i].paletteMode, + templates[i].priority, + 0, + 0); + + sGpuBgConfigs2[bg].baseTile = templates[i].baseTile; + sGpuBgConfigs2[bg].basePalette = 0; + sGpuBgConfigs2[bg].unk_3 = 0; + + sGpuBgConfigs2[bg].tilemap = NULL; + sGpuBgConfigs2[bg].bg_x = 0; + sGpuBgConfigs2[bg].bg_y = 0; + } + } +} + +void InitBgFromTemplate(const struct BgTemplate *template) +{ + u8 bg = template->bg; + + if (bg < NUM_BACKGROUNDS) + { + SetBgControlAttributes(bg, + template->charBaseIndex, + template->mapBaseIndex, + template->screenSize, + template->paletteMode, + template->priority, + 0, + 0); + + sGpuBgConfigs2[bg].baseTile = template->baseTile; + sGpuBgConfigs2[bg].basePalette = 0; + sGpuBgConfigs2[bg].unk_3 = 0; + + sGpuBgConfigs2[bg].tilemap = NULL; + sGpuBgConfigs2[bg].bg_x = 0; + sGpuBgConfigs2[bg].bg_y = 0; + } +} + +void SetBgMode(u8 bgMode) +{ + SetBgModeInternal(bgMode); +} + +u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset) +{ + u16 tileOffset; + u8 cursor; + + if (GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE) == 0) + { + tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x20; + } + else + { + tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x40; + } + + cursor = LoadBgVram(bg, src, size, tileOffset, DISPCNT_MODE_1); + + if (cursor == 0xFF) + { + return -1; + } + + sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); + + if (gUnneededFireRedVariable == 1) + { + DummiedOutFireRedLeafGreenTileAllocFunc(bg, tileOffset / 0x20, size / 0x20, 1); + } + + return cursor; +} + +u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset) +{ + u8 cursor = LoadBgVram(bg, src, size, destOffset * 2, DISPCNT_MODE_2); + + if (cursor == 0xFF) + { + return -1; + } + + sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); + + return cursor; +} + +u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset) +{ + s8 cursor; + + if (!IsInvalidBg32(bg)) + { + u16 paletteOffset = (sGpuBgConfigs2[bg].basePalette * 0x20) + (destOffset * 2); + cursor = RequestDma3Copy(src, (void*)(paletteOffset + BG_PLTT), size, 0); + + if (cursor == -1) + { + return -1; + } + } + else + { + return -1; + } + + sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); + + return (u8)cursor; +} + +bool8 IsDma3ManagerBusyWithBgCopy(void) +{ + int i; + + for (i = 0; i < 0x80; i++) + { + u8 div = i / 0x20; + u8 mod = i % 0x20; + + if ((sDmaBusyBitfield[div] & (1 << mod))) + { + s8 reqSpace = CheckForSpaceForDma3Request(i); + if (reqSpace == -1) + { + return TRUE; + } + + sDmaBusyBitfield[div] &= ~(1 << mod); + } + } + + return FALSE; +} + +void ShowBg(u8 bg) +{ + ShowBgInternal(bg); + SyncBgVisibilityAndMode(); +} + +void HideBg(u8 bg) +{ + HideBgInternal(bg); + SyncBgVisibilityAndMode(); +} + +void SetBgAttribute(u8 bg, u8 attributeId, u8 value) +{ + switch (attributeId) + { + case BG_ATTR_CHARBASEINDEX: + SetBgControlAttributes(bg, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_MAPBASEINDEX: + SetBgControlAttributes(bg, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_SCREENSIZE: + SetBgControlAttributes(bg, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_PALETTEMODE: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF); + break; + case BG_ATTR_PRIORITY: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF); + break; + case BG_ATTR_MOSAIC: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF); + break; + case BG_ATTR_WRAPAROUND: + SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value); + break; + } +} + +u16 GetBgAttribute(u8 bg, u8 attributeId) +{ + switch (attributeId) + { + case BG_ATTR_CHARBASEINDEX: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_CHARBASEINDEX); + case BG_ATTR_MAPBASEINDEX: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_MAPBASEINDEX); + case BG_ATTR_SCREENSIZE: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + case BG_ATTR_PALETTEMODE: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE); + case BG_ATTR_PRIORITY: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_PRIORITY); + case BG_ATTR_MOSAIC: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_MOSAIC); + case BG_ATTR_WRAPAROUND: + return GetBgControlAttribute(bg, BG_CTRL_ATTR_WRAPAROUND); + case BG_ATTR_METRIC: + switch (GetBgType(bg)) + { + case 0: + return GetBgMetricTextMode(bg, 0) * 0x800; + case 1: + return GetBgMetricAffineMode(bg, 0) * 0x100; + default: + return 0; + } + case BG_ATTR_TYPE: + return GetBgType(bg); + case BG_ATTR_BASETILE: + return sGpuBgConfigs2[bg].baseTile; + default: + return -1; + } +} + +s32 ChangeBgX(u8 bg, s32 value, u8 op) +{ + u8 mode; + u16 temp1; + u16 temp2; + + if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + return -1; + } + + switch (op) + { + case 0: + default: + sGpuBgConfigs2[bg].bg_x = value; + break; + case 1: + sGpuBgConfigs2[bg].bg_x += value; + break; + case 2: + sGpuBgConfigs2[bg].bg_x -= value; + break; + } + + mode = GetBgMode(); + + switch (bg) + { + case 0: + temp1 = sGpuBgConfigs2[0].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG0HOFS, temp1); + break; + case 1: + temp1 = sGpuBgConfigs2[1].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG1HOFS, temp1); + break; + case 2: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[2].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG2HOFS, temp1); + } + else + { + temp1 = sGpuBgConfigs2[2].bg_x >> 0x10; + temp2 = sGpuBgConfigs2[2].bg_x & 0xFFFF; + SetGpuReg(REG_OFFSET_BG2X_H, temp1); + SetGpuReg(REG_OFFSET_BG2X_L, temp2); + } + break; + case 3: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[3].bg_x >> 0x8; + SetGpuReg(REG_OFFSET_BG3HOFS, temp1); + } + else if (mode == 2) + { + temp1 = sGpuBgConfigs2[3].bg_x >> 0x10; + temp2 = sGpuBgConfigs2[3].bg_x & 0xFFFF; + SetGpuReg(REG_OFFSET_BG3X_H, temp1); + SetGpuReg(REG_OFFSET_BG3X_L, temp2); + } + break; + } + + return sGpuBgConfigs2[bg].bg_x; +} + +s32 GetBgX(u8 bg) +{ + if (IsInvalidBg32(bg)) + return -1; + else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + return -1; + else + return sGpuBgConfigs2[bg].bg_x; +} + +s32 ChangeBgY(u8 bg, s32 value, u8 op) +{ + u8 mode; + u16 temp1; + u16 temp2; + + if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + return -1; + } + + switch (op) + { + case 0: + default: + sGpuBgConfigs2[bg].bg_y = value; + break; + case 1: + sGpuBgConfigs2[bg].bg_y += value; + break; + case 2: + sGpuBgConfigs2[bg].bg_y -= value; + break; + } + + mode = GetBgMode(); + + switch (bg) + { + case 0: + temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG0VOFS, temp1); + break; + case 1: + temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG1VOFS, temp1); + break; + case 2: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG2VOFS, temp1); + } + else + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; + SetGpuReg(REG_OFFSET_BG2Y_H, temp1); + SetGpuReg(REG_OFFSET_BG2Y_L, temp2); + } + break; + case 3: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; + SetGpuReg(REG_OFFSET_BG3VOFS, temp1); + } + else if (mode == 2) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; + SetGpuReg(REG_OFFSET_BG3Y_H, temp1); + SetGpuReg(REG_OFFSET_BG3Y_L, temp2); + } + break; + } + + return sGpuBgConfigs2[bg].bg_y; +} + +s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op) +{ + u8 mode; + u16 temp1; + u16 temp2; + + if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + return -1; + } + + switch (op) + { + case 0: + default: + sGpuBgConfigs2[bg].bg_y = value; + break; + case 1: + sGpuBgConfigs2[bg].bg_y += value; + break; + case 2: + sGpuBgConfigs2[bg].bg_y -= value; + break; + } + + mode = GetBgMode(); + + switch (bg) + { + case 0: + temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, temp1); + break; + case 1: + temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG1VOFS, temp1); + break; + case 2: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG2VOFS, temp1); + + } + else + { + temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; + SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_H, temp1); + SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_L, temp2); + } + break; + case 3: + if (mode == 0) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; + SetGpuReg_ForcedBlank(REG_OFFSET_BG3VOFS, temp1); + } + else if (mode == 2) + { + temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; + temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; + SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_H, temp1); + SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_L, temp2); + } + break; + } + + return sGpuBgConfigs2[bg].bg_y; +} + +s32 GetBgY(u8 bg) +{ + if (IsInvalidBg32(bg)) + return -1; + else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + return -1; + else + return sGpuBgConfigs2[bg].bg_y; +} + +void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) +{ + SetBgAffineInternal(bg, srcCenterX, srcCenterY, dispCenterX, dispCenterY, scaleX, scaleY, rotationAngle); +} + +u8 Unused_AdjustBgMosaic(u8 a1, u8 a2) +{ + u16 result = GetGpuReg(REG_OFFSET_MOSAIC); + s16 test1 = result & 0xF; + s16 test2 = (result >> 4) & 0xF; + + result &= 0xFF00; + + switch (a2) + { + case 0: + default: + test1 = a1 & 0xF; + test2 = a1 >> 0x4; + break; + case 1: + test1 = a1 & 0xF; + break; + case 2: + if ((test1 + a1) > 0xF) + { + test1 = 0xF; + } + else + { + test1 += a1; + } + break; + case 3: + if ((test1 - a1) < 0) + { + test1 = 0x0; + } + else + { + test1 -= a1; + } + break; + case 4: + test2 = a1 & 0xF; + break; + case 5: + if ((test2 + a1) > 0xF) + { + test2 = 0xF; + } + else + { + test2 += a1; + } + break; + case 6: + if ((test2 - a1) < 0) + { + test2 = 0x0; + } + else + { + test2 -= a1; + } + break; + } + + result |= ((test2 << 0x4) & 0xF0); + result |= (test1 & 0xF); + + SetGpuReg(REG_OFFSET_MOSAIC, result); + + return result; +} + +void SetBgTilemapBuffer(u8 bg, void *tilemap) +{ + if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + sGpuBgConfigs2[bg].tilemap = tilemap; + } +} + +void UnsetBgTilemapBuffer(u8 bg) +{ + if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + { + sGpuBgConfigs2[bg].tilemap = NULL; + } +} + +void* GetBgTilemapBuffer(u8 bg) +{ + if (IsInvalidBg32(bg)) + return NULL; + else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) + return NULL; + else + return sGpuBgConfigs2[bg].tilemap; +} + +void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset) +{ + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + if (mode != 0) + CpuCopy16(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2)), mode); + else + LZ77UnCompWram(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2))); + } +} + +void CopyBgTilemapBufferToVram(u8 bg) +{ + u16 sizeToLoad; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + switch (GetBgType(bg)) + { + case 0: + sizeToLoad = GetBgMetricTextMode(bg, 0) * 0x800; + break; + case 1: + sizeToLoad = GetBgMetricAffineMode(bg, 0) * 0x100; + break; + default: + sizeToLoad = 0; + break; + } + LoadBgVram(bg, sGpuBgConfigs2[bg].tilemap, sizeToLoad, 0, 2); + } +} + +void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height) +{ + u16 destX16; + u16 destY16; + u16 mode; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + switch (GetBgType(bg)) + { + case 0: + { + const u16 * srcCopy = src; + for (destY16 = destY; destY16 < (destY + height); destY16++) + { + for (destX16 = destX; destX16 < (destX + width); destX16++) + { + ((u16*)sGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *srcCopy++; + } + } + break; + } + case 1: + { + const u8 * srcCopy = src; + mode = GetBgMetricAffineMode(bg, 0x1); + for (destY16 = destY; destY16 < (destY + height); destY16++) + { + for (destX16 = destX; destX16 < (destX + width); destX16++) + { + ((u8*)sGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *srcCopy++; + } + } + break; + } + } + } +} + +void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette) +{ + CopyRectToBgTilemapBufferRect(bg, src, 0, 0, rectWidth, rectHeight, destX, destY, rectWidth, rectHeight, palette, 0, 0); +} + +void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset) +{ + u16 screenWidth, screenHeight, screenSize; + u16 var; + const void *srcPtr; + u16 i, j; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + screenWidth = GetBgMetricTextMode(bg, 0x1) * 0x20; + screenHeight = GetBgMetricTextMode(bg, 0x2) * 0x20; + switch (GetBgType(bg)) + { + case 0: + srcPtr = src + ((srcY * srcWidth) + srcX) * 2; + for (i = destX; i < (destX + rectWidth); i++) + { + for (j = srcHeight; j < (srcHeight + destY); j++) + { + u16 index = GetTileMapIndexFromCoords(j, i, screenSize, screenWidth, screenHeight); + CopyTileMapEntry(srcPtr, sGpuBgConfigs2[bg].tilemap + (index * 2), rectHeight, palette1, tileOffset); + srcPtr += 2; + } + srcPtr += (srcWidth - destY) * 2; + } + break; + case 1: + srcPtr = src + ((srcY * srcWidth) + srcX); + var = GetBgMetricAffineMode(bg, 0x1); + for (i = destX; i < (destX + rectWidth); i++) + { + for (j = srcHeight; j < (srcHeight + destY); j++) + { + *(u8*)(sGpuBgConfigs2[bg].tilemap + ((var * i) + j)) = *(u8*)(srcPtr) + palette1; + srcPtr++; + } + srcPtr += (srcWidth - destY); + } + break; + } + } +} + +void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height) +{ + u16 x16; + u16 y16; + u16 mode; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + switch (GetBgType(bg)) + { + case 0: + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + ((u16*)sGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum; + } + } + break; + case 1: + mode = GetBgMetricAffineMode(bg, 0x1); + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + ((u8*)sGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum; + } + } + break; + } + } +} + +void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette) +{ + WriteSequenceToBgTilemapBuffer(bg, tileNum, x, y, width, height, palette, 0); +} + +void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta) +{ + u16 mode; + u16 mode2; + u16 attribute; + u16 mode3; + u16 x16, y16; + + if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) + { + attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + mode = GetBgMetricTextMode(bg, 0x1) * 0x20; + mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20; + switch (GetBgType(bg)) + { + case 0: + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + CopyTileMapEntry(&firstTileNum, &((u16*)sGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0); + firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); + } + } + break; + case 1: + mode3 = GetBgMetricAffineMode(bg, 0x1); + for (y16 = y; y16 < (y + height); y16++) + { + for (x16 = x; x16 < (x + width); x16++) + { + ((u8*)sGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum; + firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); + } + } + break; + } + } +} + +u16 GetBgMetricTextMode(u8 bg, u8 whichMetric) +{ + u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + + switch (whichMetric) + { + case 0: + switch (screenSize) + { + case 0: + return 1; + case 1: + case 2: + return 2; + case 3: + return 4; + } + break; + case 1: + switch (screenSize) + { + case 0: + return 1; + case 1: + return 2; + case 2: + return 1; + case 3: + return 2; + } + break; + case 2: + switch (screenSize) + { + case 0: + case 1: + return 1; + case 2: + case 3: + return 2; + } + break; + } + return 0; +} + +u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric) +{ + u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); + + switch (whichMetric) + { + case 0: + switch (screenSize) + { + case 0: + return 0x1; + case 1: + return 0x4; + case 2: + return 0x10; + case 3: + return 0x40; + } + break; + case 1: + case 2: + return 0x10 << screenSize; + } + return 0; +} + +u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight) +{ + x = x & (screenWidth - 1); + y = y & (screenHeight - 1); + + switch (screenSize) + { + case 0: + case 2: + break; + case 3: + if (y >= 0x20) + y += 0x20; + case 1: + if (x >= 0x20) + { + x -= 0x20; + y += 0x20; + } + break; + } + return (y * 0x20) + x; +} + +void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2) +{ + u16 var; + + switch (palette1) + { + case 0 ... 15: + var = ((*src + tileOffset) & 0xFFF) + ((palette1 + palette2) << 12); + break; + case 16: + var = *dest; + var &= 0xFC00; + var += palette2 << 12; + var |= (*src + tileOffset) & 0x3FF; + break; + default: + case 17 ... INT_MAX: + var = *src + tileOffset + (palette2 << 12); + break; + } + *dest = var; +} + +u32 GetBgType(u8 bg) +{ + u8 mode = GetBgMode(); + + switch (bg) + { + case 0: + case 1: + switch (mode) + { + case 0: + case 1: + return 0; + } + break; + case 2: + switch (mode) + { + case 0: + return 0; + case 1: + case 2: + return 1; + } + break; + case 3: + switch (mode) + { + case 0: + return 0; + case 2: + return 1; + } + break; + } + + return 0xFFFF; +} + +bool32 IsInvalidBg32(u8 bg) +{ + if (bg >= NUM_BACKGROUNDS) + return TRUE; + else + return FALSE; +} + +bool32 IsTileMapOutsideWram(u8 bg) +{ + if (sGpuBgConfigs2[bg].tilemap > (void*)IWRAM_END) + return TRUE; + else if (sGpuBgConfigs2[bg].tilemap == NULL) + return TRUE; + else + return FALSE; +} diff --git a/gflib/bg.h b/gflib/bg.h new file mode 100644 index 000000000..58fd1282c --- /dev/null +++ b/gflib/bg.h @@ -0,0 +1,85 @@ +#ifndef GUARD_BG_H +#define GUARD_BG_H + +struct BGCntrlBitfield // for the I/O registers +{ + volatile u16 priority:2; + volatile u16 charBaseBlock:2; + volatile u16 field_0_2:4; + volatile u16 field_1_0:5; + volatile u16 areaOverflowMode:1; + volatile u16 screenSize:2; +}; + +enum +{ + BG_ATTR_CHARBASEINDEX = 1, + BG_ATTR_MAPBASEINDEX, + BG_ATTR_SCREENSIZE, + BG_ATTR_PALETTEMODE, + BG_ATTR_MOSAIC, + BG_ATTR_WRAPAROUND, + BG_ATTR_PRIORITY, + BG_ATTR_METRIC, + BG_ATTR_TYPE, + BG_ATTR_BASETILE, +}; + +struct BgTemplate +{ + u16 bg:2; // 0x1, 0x2 -> 0x3 + u16 charBaseIndex:2; // 0x4, 0x8 -> 0xC + u16 mapBaseIndex:5; // 0x10, 0x20, 0x40, 0x80, 0x100 -> 0x1F0 + u16 screenSize:2; // 0x200, 0x400 -> 0x600 + u16 paletteMode:1; // 0x800 + u16 priority:2; // 0x1000, 0x2000 > 0x3000 + u16 baseTile:10; +}; + +void ResetBgs(void); +u8 GetBgMode(void); +void ResetBgControlStructs(void); +void Unused_ResetBgControlStruct(u8 bg); +u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode); +void SetTextModeAndHideBgs(void); +bool8 IsInvalidBg(u8 bg); +int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4); +void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); +void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates); +void InitBgFromTemplate(const struct BgTemplate *template); +void SetBgMode(u8 bgMode); +u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset); +u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset); +u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset); +bool8 IsDma3ManagerBusyWithBgCopy(void); +void ShowBg(u8 bg); +void HideBg(u8 bg); +void SetBgAttribute(u8 bg, u8 attributeId, u8 value); +u16 GetBgAttribute(u8 bg, u8 attributeId); +s32 ChangeBgX(u8 bg, s32 value, u8 op); +s32 GetBgX(u8 bg); +s32 ChangeBgY(u8 bg, s32 value, u8 op); +s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op); +s32 GetBgY(u8 bg); +void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle); +u8 Unused_AdjustBgMosaic(u8 a1, u8 a2); +void SetBgTilemapBuffer(u8 bg, void *tilemap); +void UnsetBgTilemapBuffer(u8 bg); +void* GetBgTilemapBuffer(u8 bg); +void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset); +void CopyBgTilemapBufferToVram(u8 bg); +void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height); +void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette); +void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset); +void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height); +void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette); +void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta); +u16 GetBgMetricTextMode(u8 bg, u8 whichMetric); +u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric); +u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight); +void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2); +u32 GetBgType(u8 bg); +bool32 IsInvalidBg32(u8 bg); +bool32 IsTileMapOutsideWram(u8 bg); + +#endif // GUARD_BG_H diff --git a/gflib/blit.c b/gflib/blit.c new file mode 100644 index 000000000..bdbb2e2fd --- /dev/null +++ b/gflib/blit.c @@ -0,0 +1,209 @@ +#include "global.h" +#include "blit.h" + +void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height) +{ + BlitBitmapRect4Bit(src, dst, srcX, srcY, dstX, dstY, width, height, 0xFF); +} + +void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierSrcY; + s32 multiplierDstY; + s32 loopSrcY, loopDstY; + s32 loopSrcX, loopDstX; + const u8 *pixelsSrc; + u8 *pixelsDst; + s32 toOrr; + s32 toAnd; + s32 toShift; + + if (dst->width - dstX < width) + xEnd = (dst->width - dstX) + srcX; + else + xEnd = srcX + width; + + if (dst->height - dstY < height) + yEnd = (dst->height - dstY) + srcY; + else + yEnd = height + srcY; + + multiplierSrcY = (src->width + (src->width & 7)) >> 3; + multiplierDstY = (dst->width + (dst->width & 7)) >> 3; + + if (colorKey == 0xFF) + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); + pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); + toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); + toShift = ((loopDstX & 1) << 2); + toOrr <<= toShift; + toAnd = 0xF0 >> (toShift); + *pixelsDst = toOrr | (*pixelsDst & toAnd); + } + } + } + else + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); + pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); + toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); + if (toOrr != colorKey) + { + toShift = ((loopDstX & 1) << 2); + toOrr <<= toShift; + toAnd = 0xF0 >> (toShift); + *pixelsDst = toOrr | (*pixelsDst & toAnd); + } + } + } + } +} + +void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierY; + s32 loopX, loopY; + u8 toOrr1, toOrr2; + + xEnd = x + width; + if (xEnd > surface->width) + xEnd = surface->width; + + yEnd = y + height; + if (yEnd > surface->height) + yEnd = surface->height; + + multiplierY = (surface->width + (surface->width & 7)) >> 3; + toOrr1 = fillValue << 4; + toOrr2 = fillValue & 0xF; + + for (loopY = y; loopY < yEnd; loopY++) + { + for (loopX = x; loopX < xEnd; loopX++) + { + u8 *pixels = surface->pixels + ((loopX >> 1) & 3) + ((loopX >> 3) << 5) + (((loopY >> 3) * multiplierY) << 5) + ((u32)(loopY << 0x1d) >> 0x1B); + if ((loopX << 0x1F) != 0) + *pixels = toOrr1 | (*pixels & 0xF); + else + *pixels = toOrr2 | (*pixels & 0xF0); + } + } +} + +void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset) +{ + s32 palOffsetBits; + s32 xEnd; + s32 yEnd; + s32 multiplierSrcY; + s32 multiplierDstY; + s32 loopSrcY, loopDstY; + s32 loopSrcX, loopDstX; + const u8 *pixelsSrc; + u8 *pixelsDst; + s32 colorKeyBits; + + palOffsetBits = (u32)(paletteOffset << 0x1C) >> 0x18; + colorKeyBits = (u32)(colorKey << 0x1C) >> 0x18; + + if (dst->width - dstX < width) + xEnd = (dst->width - dstX) + srcX; + else + xEnd = width + srcX; + + if (dst->height - dstY < height) + yEnd = (srcY + dst->height) - dstY; + else + yEnd = srcY + height; + + multiplierSrcY = (src->width + (src->width & 7)) >> 3; + multiplierDstY = (dst->width + (dst->width & 7)) >> 3; + + if (colorKey == 0xFF) + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + if (loopSrcX & 1) + { + *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); + } + else + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); + } + } + } + } + else + { + for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) + { + pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) + { + if (loopSrcX & 1) + { + if ((*pixelsSrc & 0xF0) != colorKeyBits) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); + } + } + else + { + pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); + if ((*pixelsSrc & 0xF) != colorKey) + { + pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); + *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); + } + } + } + } + } +} + +void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) +{ + s32 xEnd; + s32 yEnd; + s32 multiplierY; + s32 loopX, loopY; + + xEnd = x + width; + if (xEnd > surface->width) + xEnd = surface->width; + + yEnd = y + height; + if (yEnd > surface->height) + yEnd = surface->height; + + multiplierY = (surface->width + (surface->width & 7)) >> 3; + + for (loopY = y; loopY < yEnd; loopY++) + { + for (loopX = x; loopX < xEnd; loopX++) + { + u8 *pixels = surface->pixels + (loopX & 7) + ((loopX >> 3) << 6) + (((loopY >> 3) * multiplierY) << 6) + ((u32)(loopY << 0x1d) >> 0x1a); + *pixels = fillValue; + } + } +} diff --git a/gflib/blit.h b/gflib/blit.h new file mode 100644 index 000000000..78f67766e --- /dev/null +++ b/gflib/blit.h @@ -0,0 +1,17 @@ +#ifndef GUARD_BLIT_H +#define GUARD_BLIT_H + +struct Bitmap +{ + u8 *pixels; + u32 width:16; + u32 height:16; +}; + +void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height); +void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey); +void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); +void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset); +void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); + +#endif // GUARD_BLIT_H diff --git a/gflib/dma3.h b/gflib/dma3.h new file mode 100644 index 000000000..8eff34f55 --- /dev/null +++ b/gflib/dma3.h @@ -0,0 +1,55 @@ +#ifndef GUARD_DMA3_H +#define GUARD_DMA3_H + +// Maximum amount of data we will transfer in one operation +#define MAX_DMA_BLOCK_SIZE 0x1000 + +#define Dma3CopyLarge_(src, dest, size, bit) \ +{ \ + const void *_src = src; \ + void *_dest = dest; \ + u32 _size = size; \ + while (1) \ + { \ + if (_size <= MAX_DMA_BLOCK_SIZE) \ + { \ + DmaCopy##bit(3, _src, _dest, _size); \ + break; \ + } \ + DmaCopy##bit(3, _src, _dest, MAX_DMA_BLOCK_SIZE); \ + _src += MAX_DMA_BLOCK_SIZE; \ + _dest += MAX_DMA_BLOCK_SIZE; \ + _size -= MAX_DMA_BLOCK_SIZE; \ + } \ +} + +#define Dma3CopyLarge16_(src, dest, size) Dma3CopyLarge_(src, dest, size, 16) +#define Dma3CopyLarge32_(src, dest, size) Dma3CopyLarge_(src, dest, size, 32) + +#define Dma3FillLarge_(value, dest, size, bit) \ +{ \ + void *_dest = dest; \ + u32 _size = size; \ + while (1) \ + { \ + if (_size <= MAX_DMA_BLOCK_SIZE) \ + { \ + DmaFill##bit(3, value, _dest, _size); \ + break; \ + } \ + DmaFill##bit(3, value, _dest, MAX_DMA_BLOCK_SIZE); \ + _dest += MAX_DMA_BLOCK_SIZE; \ + _size -= MAX_DMA_BLOCK_SIZE; \ + } \ +} + +#define Dma3FillLarge16_(value, dest, size) Dma3FillLarge_(value, dest, size, 16) +#define Dma3FillLarge32_(value, dest, size) Dma3FillLarge_(value, dest, size, 32) + +void ClearDma3Requests(void); +void ProcessDma3Requests(void); +s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode); +s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode); +s16 CheckForSpaceForDma3Request(s16 index); + +#endif // GUARD_DMA3_H diff --git a/gflib/dma3_manager.c b/gflib/dma3_manager.c new file mode 100644 index 000000000..d774efe8c --- /dev/null +++ b/gflib/dma3_manager.c @@ -0,0 +1,183 @@ +#include "global.h" +#include "dma3.h" + +#define MAX_DMA_REQUESTS 128 + +#define DMA_REQUEST_COPY32 1 +#define DMA_REQUEST_FILL32 2 +#define DMA_REQUEST_COPY16 3 +#define DMA_REQUEST_FILL16 4 + +struct Dma3Request +{ + const u8 *src; + u8 *dest; + u16 size; + u16 mode; + u32 value; +}; + +static struct Dma3Request sDma3Requests[MAX_DMA_REQUESTS]; + +static vbool8 sDma3ManagerLocked; +static u8 sDma3RequestCursor; + +void ClearDma3Requests(void) +{ + int i; + + sDma3ManagerLocked = TRUE; + sDma3RequestCursor = 0; + + for (i = 0; i < MAX_DMA_REQUESTS; i++) + { + sDma3Requests[i].size = 0; + sDma3Requests[i].src = NULL; + sDma3Requests[i].dest = NULL; + } + + sDma3ManagerLocked = FALSE; +} + +void ProcessDma3Requests(void) +{ + u16 bytesTransferred; + + if (sDma3ManagerLocked) + return; + + bytesTransferred = 0; + + // as long as there are DMA requests to process (unless size or vblank is an issue), do not exit + while (sDma3Requests[sDma3RequestCursor].size != 0) + { + bytesTransferred += sDma3Requests[sDma3RequestCursor].size; + + if (bytesTransferred > 40 * 1024) + return; // don't transfer more than 40 KiB + if (*(u8 *)REG_ADDR_VCOUNT > 224) + return; // we're about to leave vblank, stop + + switch (sDma3Requests[sDma3RequestCursor].mode) + { + case DMA_REQUEST_COPY32: // regular 32-bit copy + Dma3CopyLarge32_(sDma3Requests[sDma3RequestCursor].src, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + case DMA_REQUEST_FILL32: // repeat a single 32-bit value across RAM + Dma3FillLarge32_(sDma3Requests[sDma3RequestCursor].value, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + case DMA_REQUEST_COPY16: // regular 16-bit copy + Dma3CopyLarge16_(sDma3Requests[sDma3RequestCursor].src, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + case DMA_REQUEST_FILL16: // repeat a single 16-bit value across RAM + Dma3FillLarge16_(sDma3Requests[sDma3RequestCursor].value, + sDma3Requests[sDma3RequestCursor].dest, + sDma3Requests[sDma3RequestCursor].size); + break; + } + + // Free the request + sDma3Requests[sDma3RequestCursor].src = NULL; + sDma3Requests[sDma3RequestCursor].dest = NULL; + sDma3Requests[sDma3RequestCursor].size = 0; + sDma3Requests[sDma3RequestCursor].mode = 0; + sDma3Requests[sDma3RequestCursor].value = 0; + sDma3RequestCursor++; + + if (sDma3RequestCursor >= MAX_DMA_REQUESTS) // loop back to the first DMA request + sDma3RequestCursor = 0; + } +} + +s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode) +{ + int cursor; + int i = 0; + + sDma3ManagerLocked = TRUE; + cursor = sDma3RequestCursor; + + while (i < MAX_DMA_REQUESTS) + { + if (sDma3Requests[cursor].size == 0) // an empty request was found. + { + sDma3Requests[cursor].src = src; + sDma3Requests[cursor].dest = dest; + sDma3Requests[cursor].size = size; + + if (mode == 1) + sDma3Requests[cursor].mode = DMA_REQUEST_COPY32; + else + sDma3Requests[cursor].mode = DMA_REQUEST_COPY16; + + sDma3ManagerLocked = FALSE; + return cursor; + } + if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. + cursor = 0; + i++; + } + sDma3ManagerLocked = FALSE; + return -1; // no free DMA request was found +} + +s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode) +{ + int cursor; + int i = 0; + + cursor = sDma3RequestCursor; + sDma3ManagerLocked = TRUE; + + while (i < MAX_DMA_REQUESTS) + { + if (sDma3Requests[cursor].size == 0) // an empty request was found. + { + sDma3Requests[cursor].dest = dest; + sDma3Requests[cursor].size = size; + sDma3Requests[cursor].mode = mode; + sDma3Requests[cursor].value = value; + + if(mode == 1) + sDma3Requests[cursor].mode = DMA_REQUEST_FILL32; + else + sDma3Requests[cursor].mode = DMA_REQUEST_FILL16; + + sDma3ManagerLocked = FALSE; + return cursor; + } + if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. + cursor = 0; + i++; + } + sDma3ManagerLocked = FALSE; + return -1; // no free DMA request was found +} + +s16 CheckForSpaceForDma3Request(s16 index) +{ + int i = 0; + + if (index == -1) // check if all requests are free + { + while (i < MAX_DMA_REQUESTS) + { + if (sDma3Requests[i].size != 0) + return -1; + i++; + } + return 0; + } + else // check the specified request + { + if (sDma3Requests[index].size != 0) + return -1; + return 0; + } +} diff --git a/gflib/gpu_regs.c b/gflib/gpu_regs.c new file mode 100644 index 000000000..3bcc4fd93 --- /dev/null +++ b/gflib/gpu_regs.c @@ -0,0 +1,195 @@ +#include "global.h" +#include "gpu_regs.h" + +#define GPU_REG_BUF_SIZE 0x60 + +#define GPU_REG_BUF(offset) (*(u16 *)(&sGpuRegBuffer[offset])) +#define GPU_REG(offset) (*(vu16 *)(REG_BASE + offset)) + +#define EMPTY_SLOT 0xFF + +static u8 sGpuRegBuffer[GPU_REG_BUF_SIZE]; +static u8 sGpuRegWaitingList[GPU_REG_BUF_SIZE]; +static volatile bool8 sGpuRegBufferLocked; +static volatile bool8 sShouldSyncRegIE; +static vu16 sRegIE; + +static void CopyBufferedValueToGpuReg(u8 regOffset); +static void SyncRegIE(void); +static void UpdateRegDispstatIntrBits(u16 regIE); + +void InitGpuRegManager(void) +{ + s32 i; + + for (i = 0; i < GPU_REG_BUF_SIZE; i++) + { + sGpuRegBuffer[i] = 0; + sGpuRegWaitingList[i] = EMPTY_SLOT; + } + + sGpuRegBufferLocked = FALSE; + sShouldSyncRegIE = FALSE; + sRegIE = 0; +} + +static void CopyBufferedValueToGpuReg(u8 regOffset) +{ + if (regOffset == REG_OFFSET_DISPSTAT) + { + REG_DISPSTAT &= ~(DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); + REG_DISPSTAT |= GPU_REG_BUF(REG_OFFSET_DISPSTAT); + } + else + { + GPU_REG(regOffset) = GPU_REG_BUF(regOffset); + } +} + +void CopyBufferedValuesToGpuRegs(void) +{ + if (!sGpuRegBufferLocked) + { + s32 i; + + for (i = 0; i < GPU_REG_BUF_SIZE; i++) + { + u8 regOffset = sGpuRegWaitingList[i]; + if (regOffset == EMPTY_SLOT) + return; + CopyBufferedValueToGpuReg(regOffset); + sGpuRegWaitingList[i] = EMPTY_SLOT; + } + } +} + +void SetGpuReg(u8 regOffset, u16 value) +{ + if (regOffset < GPU_REG_BUF_SIZE) + { + u16 vcount; + + GPU_REG_BUF(regOffset) = value; + vcount = REG_VCOUNT & 0xFF; + + if ((vcount >= 161 && vcount <= 225) || (REG_DISPCNT & DISPCNT_FORCED_BLANK)) + { + CopyBufferedValueToGpuReg(regOffset); + } + else + { + s32 i; + + sGpuRegBufferLocked = TRUE; + + for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) + { + if (sGpuRegWaitingList[i] == regOffset) + { + sGpuRegBufferLocked = FALSE; + return; + } + } + + sGpuRegWaitingList[i] = regOffset; + sGpuRegBufferLocked = FALSE; + } + } +} + +void SetGpuReg_ForcedBlank(u8 regOffset, u16 value) +{ + if (regOffset < GPU_REG_BUF_SIZE) + { + GPU_REG_BUF(regOffset) = value; + + if (REG_DISPCNT & DISPCNT_FORCED_BLANK) + { + CopyBufferedValueToGpuReg(regOffset); + } + else + { + s32 i; + + sGpuRegBufferLocked = TRUE; + + for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) + { + if (sGpuRegWaitingList[i] == regOffset) + { + sGpuRegBufferLocked = FALSE; + return; + } + } + + sGpuRegWaitingList[i] = regOffset; + sGpuRegBufferLocked = FALSE; + } + } +} + +u16 GetGpuReg(u8 regOffset) +{ + if (regOffset == REG_OFFSET_DISPSTAT) + return REG_DISPSTAT; + + if (regOffset == REG_OFFSET_VCOUNT) + return REG_VCOUNT; + + return GPU_REG_BUF(regOffset); +} + +void SetGpuRegBits(u8 regOffset, u16 mask) +{ + u16 regValue = GPU_REG_BUF(regOffset); + SetGpuReg(regOffset, regValue | mask); +} + +void ClearGpuRegBits(u8 regOffset, u16 mask) +{ + u16 regValue = GPU_REG_BUF(regOffset); + SetGpuReg(regOffset, regValue & ~mask); +} + +static void SyncRegIE(void) +{ + if (sShouldSyncRegIE) + { + u16 temp = REG_IME; + REG_IME = 0; + REG_IE = sRegIE; + REG_IME = temp; + sShouldSyncRegIE = FALSE; + } +} + +void EnableInterrupts(u16 mask) +{ + sRegIE |= mask; + sShouldSyncRegIE = TRUE; + SyncRegIE(); + UpdateRegDispstatIntrBits(sRegIE); +} + +void DisableInterrupts(u16 mask) +{ + sRegIE &= ~mask; + sShouldSyncRegIE = TRUE; + SyncRegIE(); + UpdateRegDispstatIntrBits(sRegIE); +} + +static void UpdateRegDispstatIntrBits(u16 regIE) +{ + u16 oldValue = GetGpuReg(REG_OFFSET_DISPSTAT) & (DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); + u16 newValue = 0; + + if (regIE & INTR_FLAG_VBLANK) + newValue |= DISPSTAT_VBLANK_INTR; + + if (regIE & INTR_FLAG_HBLANK) + newValue |= DISPSTAT_HBLANK_INTR; + + if (oldValue != newValue) + SetGpuReg(REG_OFFSET_DISPSTAT, newValue); +} diff --git a/gflib/gpu_regs.h b/gflib/gpu_regs.h new file mode 100644 index 000000000..89e0cb64b --- /dev/null +++ b/gflib/gpu_regs.h @@ -0,0 +1,19 @@ +#ifndef GUARD_GPU_REGS_H +#define GUARD_GPU_REGS_H + +// Exported type declarations + +// Exported RAM declarations + +// Exported ROM declarations +void InitGpuRegManager(void); +void CopyBufferedValuesToGpuRegs(void); +void SetGpuReg(u8 regOffset, u16 value); +void SetGpuReg_ForcedBlank(u8 regOffset, u16 value); +u16 GetGpuReg(u8 regOffset); +void SetGpuRegBits(u8 regOffset, u16 mask); +void ClearGpuRegBits(u8 regOffset, u16 mask); +void EnableInterrupts(u16 mask); +void DisableInterrupts(u16 mask); + +#endif //GUARD_GPU_REGS_H diff --git a/gflib/io_reg.c b/gflib/io_reg.c new file mode 100644 index 000000000..44364349d --- /dev/null +++ b/gflib/io_reg.c @@ -0,0 +1,36 @@ +#include "global.h" +#include "io_reg.h" +#include "gba/io_reg.h" + +static const u32 sUnused[] = { + 0, + 0, + (1 << 26) | (1 << 3), + (1 << 26) | (1 << 3) | (1 << 1), + (1 << 26) | (1 << 3) | (1 << 2), + (1 << 26) | (1 << 3) | (1 << 2) | (1 << 1), + (1 << 26) | (1 << 4), + (1 << 26) | (1 << 4) | (1 << 2), + (1 << 26) | (1 << 4) | (1 << 3), + (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2), + (1 << 26) | (1 << 4) | (1 << 1), + (1 << 26) | (1 << 4) | (1 << 2) | (1 << 1), + (1 << 26) | (1 << 4) | (1 << 3) | (1 << 1), + (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1), + (1 << 25) | (1 << 8), + (1 << 27) | (1 << 10), +}; + +const u16 gOverworldBackgroundLayerFlags[] = { + BLDCNT_TGT2_BG0, + BLDCNT_TGT2_BG1, + BLDCNT_TGT2_BG2, + BLDCNT_TGT2_BG3, +}; + +const u16 gOrbEffectBackgroundLayerFlags[] = { + BLDCNT_TGT1_BG0, + BLDCNT_TGT1_BG1, + BLDCNT_TGT1_BG2, + BLDCNT_TGT1_BG3, +}; diff --git a/gflib/io_reg.h b/gflib/io_reg.h new file mode 100644 index 000000000..82d2fc5ed --- /dev/null +++ b/gflib/io_reg.h @@ -0,0 +1,7 @@ +#ifndef GUARD_IO_REG_H +#define GUARD_IO_REG_H + +extern const u16 gOverworldBackgroundLayerFlags[]; +extern const u16 gOrbEffectBackgroundLayerFlags[]; + +#endif // GUARD_IO_REG_H diff --git a/gflib/malloc.c b/gflib/malloc.c new file mode 100644 index 000000000..38fc8939e --- /dev/null +++ b/gflib/malloc.c @@ -0,0 +1,210 @@ +#include "global.h" + +static void *sHeapStart; +static u32 sHeapSize; +static u32 sFiller; // needed to align dma3_manager.o(.bss) + +#define MALLOC_SYSTEM_ID 0xA3A3 + +struct MemBlock { + // Whether this block is currently allocated. + bool16 flag; + + // Magic number used for error checking. Should equal MALLOC_SYSTEM_ID. + u16 magic; + + // Size of the block (not including this header struct). + u32 size; + + // Previous block pointer. Equals sHeapStart if this is the first block. + struct MemBlock *prev; + + // Next block pointer. Equals sHeapStart if this is the last block. + struct MemBlock *next; + + // Data in the memory block. (Arrays of length 0 are a GNU extension.) + u8 data[0]; +}; + +void PutMemBlockHeader(void *block, struct MemBlock *prev, struct MemBlock *next, u32 size) +{ + struct MemBlock *header = (struct MemBlock *)block; + + header->flag = FALSE; + header->magic = MALLOC_SYSTEM_ID; + header->size = size; + header->prev = prev; + header->next = next; +} + +void PutFirstMemBlockHeader(void *block, u32 size) +{ + PutMemBlockHeader(block, (struct MemBlock *)block, (struct MemBlock *)block, size - sizeof(struct MemBlock)); +} + +void *AllocInternal(void *heapStart, u32 size) +{ + struct MemBlock *pos = (struct MemBlock *)heapStart; + struct MemBlock *head = pos; + struct MemBlock *splitBlock; + u32 foundBlockSize; + + // Alignment + if (size & 3) + size = 4 * ((size / 4) + 1); + + for (;;) { + // Loop through the blocks looking for unused block that's big enough. + + if (!pos->flag) { + foundBlockSize = pos->size; + + if (foundBlockSize >= size) { + if (foundBlockSize - size < 2 * sizeof(struct MemBlock)) { + // The block isn't much bigger than the requested size, + // so just use it. + pos->flag = TRUE; + } else { + // The block is significantly bigger than the requested + // size, so split the rest into a separate block. + foundBlockSize -= sizeof(struct MemBlock); + foundBlockSize -= size; + + splitBlock = (struct MemBlock *)(pos->data + size); + + pos->flag = TRUE; + pos->size = size; + + PutMemBlockHeader(splitBlock, pos, pos->next, foundBlockSize); + + pos->next = splitBlock; + + if (splitBlock->next != head) + splitBlock->next->prev = splitBlock; + } + + return pos->data; + } + } + + if (pos->next == head) + return NULL; + + pos = pos->next; + } +} + +void FreeInternal(void *heapStart, void *pointer) +{ + if (pointer) { + struct MemBlock *head = (struct MemBlock *)heapStart; + struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); + block->flag = FALSE; + + // If the freed block isn't the last one, merge with the next block + // if it's not in use. + if (block->next != head) { + if (!block->next->flag) { + block->size += sizeof(struct MemBlock) + block->next->size; + block->next->magic = 0; + block->next = block->next->next; + if (block->next != head) + block->next->prev = block; + } + } + + // If the freed block isn't the first one, merge with the previous block + // if it's not in use. + if (block != head) { + if (!block->prev->flag) { + block->prev->next = block->next; + + if (block->next != head) + block->next->prev = block->prev; + + block->magic = 0; + block->prev->size += sizeof(struct MemBlock) + block->size; + } + } + } +} + +void *AllocZeroedInternal(void *heapStart, u32 size) +{ + void *mem = AllocInternal(heapStart, size); + + if (mem != NULL) { + if (size & 3) + size = 4 * ((size / 4) + 1); + + CpuFill32(0, mem, size); + } + + return mem; +} + +bool32 CheckMemBlockInternal(void *heapStart, void *pointer) +{ + struct MemBlock *head = (struct MemBlock *)heapStart; + struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); + + if (block->magic != MALLOC_SYSTEM_ID) + return FALSE; + + if (block->next->magic != MALLOC_SYSTEM_ID) + return FALSE; + + if (block->next != head && block->next->prev != block) + return FALSE; + + if (block->prev->magic != MALLOC_SYSTEM_ID) + return FALSE; + + if (block->prev != head && block->prev->next != block) + return FALSE; + + if (block->next != head && block->next != (struct MemBlock *)(block->data + block->size)) + return FALSE; + + return TRUE; +} + +void InitHeap(void *heapStart, u32 heapSize) +{ + sHeapStart = heapStart; + sHeapSize = heapSize; + PutFirstMemBlockHeader(heapStart, heapSize); +} + +void *Alloc(u32 size) +{ + return AllocInternal(sHeapStart, size); +} + +void *AllocZeroed(u32 size) +{ + return AllocZeroedInternal(sHeapStart, size); +} + +void Free(void *pointer) +{ + FreeInternal(sHeapStart, pointer); +} + +bool32 CheckMemBlock(void *pointer) +{ + return CheckMemBlockInternal(sHeapStart, pointer); +} + +bool32 CheckHeap() +{ + struct MemBlock *pos = (struct MemBlock *)sHeapStart; + + do { + if (!CheckMemBlockInternal(sHeapStart, pos->data)) + return FALSE; + pos = pos->next; + } while (pos != (struct MemBlock *)sHeapStart); + + return TRUE; +} diff --git a/gflib/malloc.h b/gflib/malloc.h new file mode 100644 index 000000000..f2dcf6d46 --- /dev/null +++ b/gflib/malloc.h @@ -0,0 +1,22 @@ +#ifndef GUARD_ALLOC_H +#define GUARD_ALLOC_H + +#define HEAP_SIZE 0x1C000 +#define malloc Alloc +#define calloc(ct, sz) AllocZeroed((ct) * (sz)) +#define free Free + +#define FREE_AND_SET_NULL(ptr) \ +{ \ + free(ptr); \ + ptr = NULL; \ +} + +extern u8 gHeap[]; + +void *Alloc(u32 size); +void *AllocZeroed(u32 size); +void Free(void *pointer); +void InitHeap(void *pointer, u32 size); + +#endif // GUARD_ALLOC_H diff --git a/gflib/sprite.c b/gflib/sprite.c new file mode 100644 index 000000000..f97ecc712 --- /dev/null +++ b/gflib/sprite.c @@ -0,0 +1,1775 @@ +#include "global.h" +#include "sprite.h" +#include "main.h" +#include "palette.h" + +#define MAX_SPRITE_COPY_REQUESTS 64 + +#define OAM_MATRIX_COUNT 32 + +#define SET_SPRITE_TILE_RANGE(index, start, count) \ +{ \ + sSpriteTileRanges[index * 2] = start; \ + (sSpriteTileRanges + 1)[index * 2] = count; \ +} + +#define ALLOC_SPRITE_TILE(n) \ +{ \ + sSpriteTileAllocBitmap[(n) / 8] |= (1 << ((n) % 8)); \ +} + +#define FREE_SPRITE_TILE(n) \ +{ \ + sSpriteTileAllocBitmap[(n) / 8] &= ~(1 << ((n) % 8)); \ +} + +#define SPRITE_TILE_IS_ALLOCATED(n) ((sSpriteTileAllocBitmap[(n) / 8] >> ((n) % 8)) & 1) + + +struct SpriteCopyRequest +{ + const u8 *src; + u8 *dest; + u16 size; +}; + +struct OamDimensions32 +{ + s32 width; + s32 height; +}; + +struct OamDimensions +{ + s8 width; + s8 height; +}; + +static void UpdateOamCoords(void); +static void BuildSpritePriorities(void); +static void SortSprites(void); +static void CopyMatricesToOamBuffer(void); +static void AddSpritesToOamBuffer(void); +static u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +static void ResetOamMatrices(void); +static void ResetSprite(struct Sprite *sprite); +static s16 AllocSpriteTiles(u16 tileCount); +static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); +static void ResetAllSprites(void); +static void BeginAnim(struct Sprite *sprite); +static void ContinueAnim(struct Sprite *sprite); +static void AnimCmd_frame(struct Sprite *sprite); +static void AnimCmd_end(struct Sprite *sprite); +static void AnimCmd_jump(struct Sprite *sprite); +static void AnimCmd_loop(struct Sprite *sprite); +static void BeginAnimLoop(struct Sprite *sprite); +static void ContinueAnimLoop(struct Sprite *sprite); +static void JumpToTopOfAnimLoop(struct Sprite *sprite); +static void BeginAffineAnim(struct Sprite *sprite); +static void ContinueAffineAnim(struct Sprite *sprite); +static void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite); +static void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite); +static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix); +static u8 GetSpriteMatrixNum(struct Sprite *sprite); +static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); +static void AffineAnimStateRestartAnim(u8 matrixNum); +static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum); +static void AffineAnimStateReset(u8 matrixNum); +static void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static void DecrementAnimDelayCounter(struct Sprite *sprite); +static bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum); +static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static s16 ConvertScaleParam(s16 scale); +static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); +static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static u8 IndexOfSpriteTileTag(u16 tag); +static void AllocSpriteTileRange(u16 tag, u16 start, u16 count); +static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset); +static void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2); + +typedef void (*AnimFunc)(struct Sprite *); +typedef void (*AnimCmdFunc)(struct Sprite *); +typedef void (*AffineAnimCmdFunc)(u8 matrixNum, struct Sprite *); + +#define DUMMY_OAM_DATA \ +{ \ + .y = 160, \ + .affineMode = 0, \ + .objMode = 0, \ + .mosaic = 0, \ + .bpp = 0, \ + .shape = SPRITE_SHAPE(8x8), \ + .x = 304, \ + .matrixNum = 0, \ + .size = SPRITE_SIZE(8x8), \ + .tileNum = 0, \ + .priority = 3, /* lowest priority */ \ + .paletteNum = 0, \ + .affineParam = 0 \ +} + +#define ANIM_END 0xFFFF +#define AFFINE_ANIM_END 0x7FFF + +// forward declarations +const union AnimCmd * const gDummySpriteAnimTable[]; +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[]; +const struct SpriteTemplate gDummySpriteTemplate; + +// Unreferenced data. Also unreferenced in R/S. +static const u8 sUnknownData[24] = +{ + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, +}; + +static const u8 sCenterToCornerVecTable[3][4][2] = +{ + { // square + { -4, -4 }, + { -8, -8 }, + { -16, -16 }, + { -32, -32 }, + }, + { // horizontal rectangle + { -8, -4 }, + { -16, -4 }, + { -16, -8 }, + { -32, -16 }, + }, + { // vertical rectangle + { -4, -8 }, + { -4, -16 }, + { -8, -16 }, + { -16, -32 }, + }, +}; + +static const struct Sprite sDummySprite = +{ + .oam = DUMMY_OAM_DATA, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .template = &gDummySpriteTemplate, + .subspriteTables = NULL, + .callback = SpriteCallbackDummy, + .pos1 = { 304, 160 }, + .pos2 = { 0, 0 }, + .centerToCornerVecX = 0, + .centerToCornerVecY = 0, + .animNum = 0, + .animCmdIndex = 0, + .animDelayCounter = 0, + .animPaused = 0, + .affineAnimPaused = 0, + .animLoopCounter = 0, + .data = {0, 0, 0, 0, 0, 0, 0}, + .inUse = 0, + .coordOffsetEnabled = 0, + .invisible = FALSE, + .flags_3 = 0, + .flags_4 = 0, + .flags_5 = 0, + .flags_6 = 0, + .flags_7 = 0, + .hFlip = 0, + .vFlip = 0, + .animBeginning = 0, + .affineAnimBeginning = 0, + .animEnded = 0, + .affineAnimEnded = 0, + .usingSheet = 0, + .flags_f = 0, + .sheetTileStart = 0, + .subspriteTableNum = 0, + .subspriteMode = 0, + .subpriority = 0xFF +}; + +const struct OamData gDummyOamData = DUMMY_OAM_DATA; + +static const union AnimCmd sDummyAnim = { ANIM_END }; + +const union AnimCmd * const gDummySpriteAnimTable[] = { &sDummyAnim }; + +static const union AffineAnimCmd sDummyAffineAnim = { AFFINE_ANIM_END }; + +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[] = { &sDummyAffineAnim }; + +const struct SpriteTemplate gDummySpriteTemplate = +{ + .tileTag = 0, + .paletteTag = 0xFFFF, + .oam = &gDummyOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy +}; + +static const AnimFunc sAnimFuncs[] = +{ + ContinueAnim, + BeginAnim, +}; + +static const AnimFunc sAffineAnimFuncs[] = +{ + ContinueAffineAnim, + BeginAffineAnim, +}; + +static const AnimCmdFunc sAnimCmdFuncs[] = +{ + AnimCmd_loop, + AnimCmd_jump, + AnimCmd_end, + AnimCmd_frame, +}; + +static const AffineAnimCmdFunc sAffineAnimCmdFuncs[] = +{ + AffineAnimCmd_loop, + AffineAnimCmd_jump, + AffineAnimCmd_end, + AffineAnimCmd_frame, +}; + +static const struct OamDimensions32 sOamDimensions32[3][4] = +{ + [ST_OAM_SQUARE] = + { + [SPRITE_SIZE(8x8)] = { 8, 8 }, + [SPRITE_SIZE(16x16)] = { 16, 16 }, + [SPRITE_SIZE(32x32)] = { 32, 32 }, + [SPRITE_SIZE(64x64)] = { 64, 64 }, + }, + [ST_OAM_H_RECTANGLE] = + { + [SPRITE_SIZE(16x8)] = { 16, 8 }, + [SPRITE_SIZE(32x8)] = { 32, 8 }, + [SPRITE_SIZE(32x16)] = { 32, 16 }, + [SPRITE_SIZE(64x32)] = { 64, 32 }, + }, + [ST_OAM_V_RECTANGLE] = + { + [SPRITE_SIZE(8x16)] = { 8, 16 }, + [SPRITE_SIZE(8x32)] = { 8, 32 }, + [SPRITE_SIZE(16x32)] = { 16, 32 }, + [SPRITE_SIZE(32x64)] = { 32, 64 }, + }, +}; + +static const struct OamDimensions sOamDimensions[3][4] = +{ + [ST_OAM_SQUARE] = + { + [SPRITE_SIZE(8x8)] = { 8, 8 }, + [SPRITE_SIZE(16x16)] = { 16, 16 }, + [SPRITE_SIZE(32x32)] = { 32, 32 }, + [SPRITE_SIZE(64x64)] = { 64, 64 }, + }, + [ST_OAM_H_RECTANGLE] = + { + [SPRITE_SIZE(16x8)] = { 16, 8 }, + [SPRITE_SIZE(32x8)] = { 32, 8 }, + [SPRITE_SIZE(32x16)] = { 32, 16 }, + [SPRITE_SIZE(64x32)] = { 64, 32 }, + }, + [ST_OAM_V_RECTANGLE] = + { + [SPRITE_SIZE(8x16)] = { 8, 16 }, + [SPRITE_SIZE(8x32)] = { 8, 32 }, + [SPRITE_SIZE(16x32)] = { 16, 32 }, + [SPRITE_SIZE(32x64)] = { 32, 64 }, + }, +}; + +// iwram bss +static u16 sSpriteTileRangeTags[MAX_SPRITES]; +static u16 sSpriteTileRanges[MAX_SPRITES * 2]; +static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; +static u16 sSpritePaletteTags[16]; + +// iwram common +u32 gOamMatrixAllocBitmap; +u8 gReservedSpritePaletteCount; + +EWRAM_DATA struct Sprite gSprites[MAX_SPRITES + 1] = {0}; +EWRAM_DATA static u16 sSpritePriorities[MAX_SPRITES] = {0}; +EWRAM_DATA static u8 sSpriteOrder[MAX_SPRITES] = {0}; +EWRAM_DATA static bool8 sShouldProcessSpriteCopyRequests = 0; +EWRAM_DATA static u8 sSpriteCopyRequestCount = 0; +EWRAM_DATA static struct SpriteCopyRequest sSpriteCopyRequests[MAX_SPRITES] = {0}; +EWRAM_DATA u8 gOamLimit = 0; +EWRAM_DATA u16 gReservedSpriteTileCount = 0; +EWRAM_DATA static u8 sSpriteTileAllocBitmap[128] = {0}; +EWRAM_DATA s16 gSpriteCoordOffsetX = 0; +EWRAM_DATA s16 gSpriteCoordOffsetY = 0; +EWRAM_DATA struct OamMatrix gOamMatrices[OAM_MATRIX_COUNT] = {0}; +EWRAM_DATA bool8 gAffineAnimsDisabled = FALSE; + +void ResetSpriteData(void) +{ + ResetOamRange(0, 128); + ResetAllSprites(); + ClearSpriteCopyRequests(); + ResetAffineAnimData(); + FreeSpriteTileRanges(); + gOamLimit = 64; + gReservedSpriteTileCount = 0; + AllocSpriteTiles(0); + gSpriteCoordOffsetX = 0; + gSpriteCoordOffsetY = 0; +} + +void AnimateSprites(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (sprite->inUse) + { + sprite->callback(sprite); + + if (sprite->inUse) + AnimateSprite(sprite); + } + } +} + +void BuildOamBuffer(void) +{ + u8 temp; + UpdateOamCoords(); + BuildSpritePriorities(); + SortSprites(); + temp = gMain.oamLoadDisabled; + gMain.oamLoadDisabled = TRUE; + AddSpritesToOamBuffer(); + CopyMatricesToOamBuffer(); + gMain.oamLoadDisabled = temp; + sShouldProcessSpriteCopyRequests = TRUE; +} + +void UpdateOamCoords(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + if (sprite->inUse && !sprite->invisible) + { + if (sprite->coordOffsetEnabled) + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY; + } + else + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY; + } + } + } +} + +void BuildSpritePriorities(void) +{ + u16 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + u16 priority = sprite->subpriority | (sprite->oam.priority << 8); + sSpritePriorities[i] = priority; + } +} + +void SortSprites(void) +{ + u8 i; + for (i = 1; i < MAX_SPRITES; i++) + { + u8 j = i; + struct Sprite *sprite1 = &gSprites[sSpriteOrder[i - 1]]; + struct Sprite *sprite2 = &gSprites[sSpriteOrder[i]]; + u16 sprite1Priority = sSpritePriorities[sSpriteOrder[i - 1]]; + u16 sprite2Priority = sSpritePriorities[sSpriteOrder[i]]; + s16 sprite1Y = sprite1->oam.y; + s16 sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + + while (j > 0 + && ((sprite1Priority > sprite2Priority) + || (sprite1Priority == sprite2Priority && sprite1Y < sprite2Y))) + { + u8 temp = sSpriteOrder[j]; + sSpriteOrder[j] = sSpriteOrder[j - 1]; + sSpriteOrder[j - 1] = temp; + + // UB: If j equals 1, then j-- makes j equal 0. + // Then, sSpriteOrder[-1] gets accessed below. + // Although this doesn't result in a bug in the ROM, + // the behavior is undefined. + j--; +#ifdef UBFIX + if (j == 0) + break; +#endif + + sprite1 = &gSprites[sSpriteOrder[j - 1]]; + sprite2 = &gSprites[sSpriteOrder[j]]; + sprite1Priority = sSpritePriorities[sSpriteOrder[j - 1]]; + sprite2Priority = sSpritePriorities[sSpriteOrder[j]]; + sprite1Y = sprite1->oam.y; + sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == ST_OAM_SIZE_3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + } + } +} + +void CopyMatricesToOamBuffer(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + u32 base = 4 * i; + gMain.oamBuffer[base + 0].affineParam = gOamMatrices[i].a; + gMain.oamBuffer[base + 1].affineParam = gOamMatrices[i].b; + gMain.oamBuffer[base + 2].affineParam = gOamMatrices[i].c; + gMain.oamBuffer[base + 3].affineParam = gOamMatrices[i].d; + } +} + +void AddSpritesToOamBuffer(void) +{ + u8 i = 0; + u8 oamIndex = 0; + + while (i < MAX_SPRITES) + { + struct Sprite *sprite = &gSprites[sSpriteOrder[i]]; + if (sprite->inUse && !sprite->invisible && AddSpriteToOamBuffer(sprite, &oamIndex)) + return; + i++; + } + + while (oamIndex < gOamLimit) + { + gMain.oamBuffer[oamIndex] = gDummyOamData; + oamIndex++; + } +} + +u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + s16 i; + + for (i = MAX_SPRITES - 1; i > -1; i--) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)) +{ + u8 index = CreateSprite(&gDummySpriteTemplate, 0, 0, 31); + + if (index == MAX_SPRITES) + { + return MAX_SPRITES; + } + else + { + gSprites[index].invisible = TRUE; + gSprites[index].callback = callback; + return index; + } +} + +u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + struct Sprite *sprite = &gSprites[index]; + + ResetSprite(sprite); + + sprite->inUse = TRUE; + sprite->animBeginning = TRUE; + sprite->affineAnimBeginning = TRUE; + sprite->usingSheet = TRUE; + + sprite->subpriority = subpriority; + sprite->oam = *template->oam; + sprite->anims = template->anims; + sprite->affineAnims = template->affineAnims; + sprite->template = template; + sprite->callback = template->callback; + sprite->pos1.x = x; + sprite->pos1.y = y; + + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + + if (template->tileTag == 0xFFFF) + { + s16 tileNum; + sprite->images = template->images; + tileNum = AllocSpriteTiles((u8)(sprite->images->size / TILE_SIZE_4BPP)); + if (tileNum == -1) + { + ResetSprite(sprite); + return MAX_SPRITES; + } + sprite->oam.tileNum = tileNum; + sprite->usingSheet = FALSE; + sprite->sheetTileStart = 0; + } + else + { + sprite->sheetTileStart = GetSpriteTileStartByTag(template->tileTag); + SetSpriteSheetFrameTileNum(sprite); + } + + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + InitSpriteAffineAnim(sprite); + + if (template->paletteTag != 0xFFFF) + sprite->oam.paletteNum = IndexOfSpritePaletteTag(template->paletteTag); + + return index; +} + +u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (!gSprites[i].inUse) + { + u8 index = CreateSpriteAt(i, template, x, y, subpriority); + + if (index == MAX_SPRITES) + return MAX_SPRITES; + + gSprites[i].callback(sprite); + + if (gSprites[i].inUse) + AnimateSprite(sprite); + + return index; + } + } + + return MAX_SPRITES; +} + +void DestroySprite(struct Sprite *sprite) +{ + if (sprite->inUse) + { + if (!sprite->usingSheet) + { + u16 i; + u16 tileEnd = (sprite->images->size / TILE_SIZE_4BPP) + sprite->oam.tileNum; + for (i = sprite->oam.tileNum; i < tileEnd; i++) + FREE_SPRITE_TILE(i); + } + ResetSprite(sprite); + } +} + +void ResetOamRange(u8 a, u8 b) +{ + u8 i; + + for (i = a; i < b; i++) + { + gMain.oamBuffer[i] = *(struct OamData *)&gDummyOamData; + } +} + +void LoadOam(void) +{ + if (!gMain.oamLoadDisabled) + CpuCopy32(gMain.oamBuffer, (void *)OAM, sizeof(gMain.oamBuffer)); +} + +void ClearSpriteCopyRequests(void) +{ + u8 i; + + sShouldProcessSpriteCopyRequests = FALSE; + sSpriteCopyRequestCount = 0; + + for (i = 0; i < MAX_SPRITE_COPY_REQUESTS; i++) + { + sSpriteCopyRequests[i].src = 0; + sSpriteCopyRequests[i].dest = 0; + sSpriteCopyRequests[i].size = 0; + } +} + +void ResetOamMatrices(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + // set to identity matrix + gOamMatrices[i].a = 0x0100; + gOamMatrices[i].b = 0x0000; + gOamMatrices[i].c = 0x0000; + gOamMatrices[i].d = 0x0100; + } +} + +void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d) +{ + gOamMatrices[matrixNum].a = a; + gOamMatrices[matrixNum].b = b; + gOamMatrices[matrixNum].c = c; + gOamMatrices[matrixNum].d = d; +} + +void ResetSprite(struct Sprite *sprite) +{ + *sprite = sDummySprite; +} + +void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode) +{ + u8 x = sCenterToCornerVecTable[shape][size][0]; + u8 y = sCenterToCornerVecTable[shape][size][1]; + + if (affineMode & ST_OAM_AFFINE_DOUBLE_MASK) + { + x *= 2; + y *= 2; + } + + sprite->centerToCornerVecX = x; + sprite->centerToCornerVecY = y; +} + +s16 AllocSpriteTiles(u16 tileCount) +{ + u16 i; + s16 start; + u16 numTilesFound; + + if (tileCount == 0) + { + // Free all unreserved tiles if the tile count is 0. + for (i = gReservedSpriteTileCount; i < TOTAL_OBJ_TILE_COUNT; i++) + FREE_SPRITE_TILE(i); + + return 0; + } + + i = gReservedSpriteTileCount; + + for (;;) + { + while (SPRITE_TILE_IS_ALLOCATED(i)) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + } + + start = i; + numTilesFound = 1; + + while (numTilesFound != tileCount) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + + if (!SPRITE_TILE_IS_ALLOCATED(i)) + numTilesFound++; + else + break; + } + + if (numTilesFound == tileCount) + break; + } + + for (i = start; i < tileCount + start; i++) + ALLOC_SPRITE_TILE(i); + + return start; +} + +u8 SpriteTileAllocBitmapOp(u16 bit, u8 op) +{ + u8 index = bit / 8; + u8 shift = bit % 8; + u8 val = bit % 8; + u8 retVal = 0; + + if (op == 0) + { + val = ~(1 << val); + sSpriteTileAllocBitmap[index] &= val; + } + else if (op == 1) + { + val = (1 << val); + sSpriteTileAllocBitmap[index] |= val; + } + else + { + retVal = 1 << shift; + retVal &= sSpriteTileAllocBitmap[index]; + } + + return retVal; +} + +void SpriteCallbackDummy(struct Sprite *sprite) +{ +} + +void ProcessSpriteCopyRequests(void) +{ + if (sShouldProcessSpriteCopyRequests) + { + u8 i = 0; + + while (sSpriteCopyRequestCount > 0) + { + CpuCopy16(sSpriteCopyRequests[i].src, sSpriteCopyRequests[i].dest, sSpriteCopyRequests[i].size); + sSpriteCopyRequestCount--; + i++; + } + + sShouldProcessSpriteCopyRequests = FALSE; + } +} + +void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images) +{ + if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + sSpriteCopyRequests[sSpriteCopyRequestCount].src = images[index].data; + sSpriteCopyRequests[sSpriteCopyRequestCount].dest = (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileNum; + sSpriteCopyRequests[sSpriteCopyRequestCount].size = images[index].size; + sSpriteCopyRequestCount++; + } +} + +void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size) +{ + if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + sSpriteCopyRequests[sSpriteCopyRequestCount].src = src; + sSpriteCopyRequests[sSpriteCopyRequestCount].dest = dest; + sSpriteCopyRequests[sSpriteCopyRequestCount].size = size; + sSpriteCopyRequestCount++; + } +} + +void CopyFromSprites(u8 *dest) +{ + u32 i; + u8 *src = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + dest++; + src++; + } +} + +void CopyToSprites(u8 *src) +{ + u32 i; + u8 *dest = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + src++; + dest++; + } +} + +void ResetAllSprites(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + ResetSprite(&gSprites[i]); + sSpriteOrder[i] = i; + } + + ResetSprite(&gSprites[i]); +} + +// UB: template pointer may point to freed temporary storage +void FreeSpriteTiles(struct Sprite *sprite) +{ + if (sprite->template->tileTag != 0xFFFF) + FreeSpriteTilesByTag(sprite->template->tileTag); +} + +// UB: template pointer may point to freed temporary storage +void FreeSpritePalette(struct Sprite *sprite) +{ + FreeSpritePaletteByTag(sprite->template->paletteTag); +} + +void FreeSpriteOamMatrix(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + FreeOamMatrix(sprite->oam.matrixNum); + sprite->oam.affineMode = ST_OAM_AFFINE_OFF; + } +} + +void DestroySpriteAndFreeResources(struct Sprite *sprite) +{ + FreeSpriteTiles(sprite); + FreeSpritePalette(sprite); + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); +} + +void AnimateSprite(struct Sprite *sprite) +{ + sAnimFuncs[sprite->animBeginning](sprite); + + if (!gAffineAnimsDisabled) + sAffineAnimFuncs[sprite->affineAnimBeginning](sprite); +} + +void BeginAnim(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = 0; + sprite->animEnded = FALSE; + sprite->animLoopCounter = 0; + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + + if (imageValue != -1) + { + sprite->animBeginning = FALSE; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); + } +} + +void ContinueAnim(struct Sprite *sprite) +{ + if (sprite->animDelayCounter) + { + u8 hFlip; + u8 vFlip; + DecrementAnimDelayCounter(sprite); + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + } + else if (!sprite->animPaused) + { + s16 type; + s16 funcIndex; + sprite->animCmdIndex++; + type = sprite->anims[sprite->animNum][sprite->animCmdIndex].type; + funcIndex = 3; + if (type < 0) + funcIndex = type + 3; + sAnimCmdFuncs[funcIndex](sprite); + } +} + +void AnimCmd_frame(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +void AnimCmd_end(struct Sprite *sprite) +{ + sprite->animCmdIndex--; + sprite->animEnded = TRUE; +} + +void AnimCmd_jump(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = sprite->anims[sprite->animNum][sprite->animCmdIndex].jump.target; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +void AnimCmd_loop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + ContinueAnimLoop(sprite); + else + BeginAnimLoop(sprite); +} + +void BeginAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter = sprite->anims[sprite->animNum][sprite->animCmdIndex].loop.count; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +void ContinueAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter--; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +void JumpToTopOfAnimLoop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + { + sprite->animCmdIndex--; + + while (sprite->anims[sprite->animNum][sprite->animCmdIndex - 1].type != -3) + { + if (sprite->animCmdIndex == 0) + break; + sprite->animCmdIndex--; + } + + sprite->animCmdIndex--; + } +} + +void BeginAffineAnim(struct Sprite *sprite) +{ + if ((sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) && sprite->affineAnims[0][0].type != 32767) + { + struct AffineAnimFrameCmd frameCmd; + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateRestartAnim(matrixNum); + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + sprite->affineAnimBeginning = FALSE; + sprite->affineAnimEnded = FALSE; + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; + if (sprite->flags_f) + obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); + } +} + +void ContinueAffineAnim(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + u8 matrixNum = GetSpriteMatrixNum(sprite); + + if (sAffineAnimStates[matrixNum].delayCounter) + AffineAnimDelay(matrixNum, sprite); + else if (sprite->affineAnimPaused) + return; + else + { + s16 type; + s16 funcIndex; + sAffineAnimStates[matrixNum].animCmdIndex++; + type = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].type; + funcIndex = 3; + if (type >= 32765) + funcIndex = type - 32765; + sAffineAnimCmdFuncs[funcIndex](matrixNum, sprite); + } + if (sprite->flags_f) + obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); + } +} + +void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite) +{ + if (!DecrementAffineAnimDelayCounter(sprite, matrixNum)) + { + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &frameCmd); + } +} + +void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + ContinueAffineAnimLoop(matrixNum, sprite); + else + BeginAffineAnimLoop(matrixNum, sprite); +} + +void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].loop.count; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter--; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + { + sAffineAnimStates[matrixNum].animCmdIndex--; + + while (sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex - 1].type != 32765) + { + if (sAffineAnimStates[matrixNum].animCmdIndex == 0) + break; + sAffineAnimStates[matrixNum].animCmdIndex--; + } + + sAffineAnimStates[matrixNum].animCmdIndex--; + } +} + +void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + sAffineAnimStates[matrixNum].animCmdIndex = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].jump.target; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + sprite->affineAnimEnded = TRUE; + sAffineAnimStates[matrixNum].animCmdIndex--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); +} + +void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix) +{ + gOamMatrices[destMatrixIndex].a = srcMatrix->a; + gOamMatrices[destMatrixIndex].b = srcMatrix->b; + gOamMatrices[destMatrixIndex].c = srcMatrix->c; + gOamMatrices[destMatrixIndex].d = srcMatrix->d; +} + +u8 GetSpriteMatrixNum(struct Sprite *sprite) +{ + u8 matrixNum = 0; + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + matrixNum = sprite->oam.matrixNum; + return matrixNum; +} + +void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3) +{ + sprite->data[6] = a2; + sprite->data[7] = a3; + sprite->flags_f = 1; +} + +s32 sub_8007E28(s32 a0, s32 a1, s32 a2) +{ + s32 subResult, var1; + + subResult = a1 - a0; + if (subResult < 0) + var1 = -(subResult) >> 9; + else + var1 = -(subResult >> 9); + return a2 - ((u32)(a2 * a1) / (u32)(a0) + var1); +} + +void obj_update_pos2(struct Sprite *sprite, s32 a1, s32 a2) +{ + s32 var0, var1, var2; + + u32 matrixNum = sprite->oam.matrixNum; + if (a1 != 0x800) + { + var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].width; + var1 = var0 << 8; + var2 = (var0 << 16) / gOamMatrices[matrixNum].a; + sprite->pos2.x = sub_8007E28(var1, var2, a1); + } + if (a2 != 0x800) + { + var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].height; + var1 = var0 << 8; + var2 = (var0 << 16) / gOamMatrices[matrixNum].d; + sprite->pos2.y = sub_8007E28(var1, var2, a2); + } +} + +void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip) +{ + sprite->oam.matrixNum &= 0x7; + sprite->oam.matrixNum |= (((hFlip ^ sprite->hFlip) & 1) << 3); + sprite->oam.matrixNum |= (((vFlip ^ sprite->vFlip) & 1) << 4); +} + +void AffineAnimStateRestartAnim(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; +} + +void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum) +{ + sAffineAnimStates[matrixNum].animNum = animNum; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +void AffineAnimStateReset(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animNum = 0; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + sAffineAnimStates[matrixNum].xScale = frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale = frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = frameCmd->rotation << 8; +} + +void DecrementAnimDelayCounter(struct Sprite *sprite) +{ + if (!sprite->animPaused) + sprite->animDelayCounter--; +} + +bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum) +{ + if (!sprite->affineAnimPaused) + --sAffineAnimStates[matrixNum].delayCounter; + return sprite->affineAnimPaused; +} + +void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + sAffineAnimStates[matrixNum].xScale += frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale += frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = (sAffineAnimStates[matrixNum].rotation + (frameCmd->rotation << 8)) & ~0xFF; + srcData.xScale = ConvertScaleParam(sAffineAnimStates[matrixNum].xScale); + srcData.yScale = ConvertScaleParam(sAffineAnimStates[matrixNum].yScale); + srcData.rotation = sAffineAnimStates[matrixNum].rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +s16 ConvertScaleParam(s16 scale) +{ + s32 val = 0x10000; + return SAFE_DIV(val, scale); +} + +void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd) +{ + frameCmd->xScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.xScale; + frameCmd->yScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.yScale; + frameCmd->rotation = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.rotation; + frameCmd->duration = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.duration; +} + +void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + + if (frameCmd->duration) + { + frameCmd->duration--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, frameCmd); + } + else + { + ApplyAffineAnimFrameAbsolute(matrixNum, frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); + } +} + +void StartSpriteAnim(struct Sprite *sprite, u8 animNum) +{ + sprite->animNum = animNum; + sprite->animBeginning = TRUE; + sprite->animEnded = FALSE; +} + +void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + if (sprite->animNum != animNum) + StartSpriteAnim(sprite, animNum); +} + +void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex) +{ + u8 temp = sprite->animPaused; + sprite->animCmdIndex = animCmdIndex - 1; + sprite->animDelayCounter = 0; + sprite->animBeginning = FALSE; + sprite->animEnded = FALSE; + sprite->animPaused = FALSE; + ContinueAnim(sprite); + if (sprite->animDelayCounter) + sprite->animDelayCounter++; + sprite->animPaused = temp; +} + +void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateStartAnim(matrixNum, animNum); + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + StartSpriteAffineAnim(sprite, animNum); +} + +void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + sAffineAnimStates[matrixNum].animNum = animNum; + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + ChangeSpriteAffineAnim(sprite, animNum); +} + +void SetSpriteSheetFrameTileNum(struct Sprite *sprite) +{ + if (sprite->usingSheet) + { + s16 tileOffset = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + if (tileOffset < 0) + tileOffset = 0; + sprite->oam.tileNum = sprite->sheetTileStart + tileOffset; + } +} + +void ResetAffineAnimData(void) +{ + u8 i; + + gAffineAnimsDisabled = FALSE; + gOamMatrixAllocBitmap = 0; + + ResetOamMatrices(); + + for (i = 0; i < OAM_MATRIX_COUNT; i++) + AffineAnimStateReset(i); +} + +u8 AllocOamMatrix(void) +{ + u8 i = 0; + u32 bit = 1; + u32 bitmap = gOamMatrixAllocBitmap; + + while (i < OAM_MATRIX_COUNT) + { + if (!(bitmap & bit)) + { + gOamMatrixAllocBitmap |= bit; + return i; + } + + i++; + bit <<= 1; + } + + return 0xFF; +} + +void FreeOamMatrix(u8 matrixNum) +{ + u8 i = 0; + u32 bit = 1; + + while (i < matrixNum) + { + i++; + bit <<= 1; + } + + gOamMatrixAllocBitmap &= ~bit; + SetOamMatrix(matrixNum, 0x100, 0, 0, 0x100); +} + +void InitSpriteAffineAnim(struct Sprite *sprite) +{ + u8 matrixNum = AllocOamMatrix(); + if (matrixNum != 0xFF) + { + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + sprite->oam.matrixNum = matrixNum; + sprite->affineAnimBeginning = TRUE; + AffineAnimStateReset(matrixNum); + } +} + +void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + srcData.xScale = ConvertScaleParam(xScale); + srcData.yScale = ConvertScaleParam(yScale); + srcData.rotation = rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +u16 LoadSpriteSheet(const struct SpriteSheet *sheet) +{ + s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); + + if (tileStart < 0) + { + return 0; + } + else + { + AllocSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); + CpuCopy16(sheet->data, (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileStart, sheet->size); + return (u16)tileStart; + } +} + +void LoadSpriteSheets(const struct SpriteSheet *sheets) +{ + u8 i; + for (i = 0; sheets[i].data != NULL; i++) + LoadSpriteSheet(&sheets[i]); +} + +void FreeSpriteTilesByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index != 0xFF) + { + u16 i; + u16 *rangeStarts; + u16 *rangeCounts; + u16 start; + u16 count; + rangeStarts = sSpriteTileRanges; + start = rangeStarts[index * 2]; + rangeCounts = sSpriteTileRanges + 1; + count = rangeCounts[index * 2]; + + for (i = start; i < start + count; i++) + FREE_SPRITE_TILE(i); + + sSpriteTileRangeTags[index] = 0xFFFF; + } +} + +void FreeSpriteTileRanges(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + sSpriteTileRangeTags[i] = 0xFFFF; + SET_SPRITE_TILE_RANGE(i, 0, 0); + } +} + +u16 GetSpriteTileStartByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index == 0xFF) + return 0xFFFF; + return sSpriteTileRanges[index * 2]; +} + +u8 IndexOfSpriteTileTag(u16 tag) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (sSpriteTileRangeTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpriteTileTagByTileStart(u16 start) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + if (sSpriteTileRangeTags[i] != 0xFFFF && sSpriteTileRanges[i * 2] == start) + return sSpriteTileRangeTags[i]; + } + + return 0xFFFF; +} + +void AllocSpriteTileRange(u16 tag, u16 start, u16 count) +{ + u8 freeIndex = IndexOfSpriteTileTag(0xFFFF); + sSpriteTileRangeTags[freeIndex] = tag; + SET_SPRITE_TILE_RANGE(freeIndex, start, count); +} + +void FreeAllSpritePalettes(void) +{ + u8 i; + gReservedSpritePaletteCount = 0; + for (i = 0; i < 16; i++) + sSpritePaletteTags[i] = 0xFFFF; +} + +u8 LoadSpritePalette(const struct SpritePalette *palette) +{ + u8 index = IndexOfSpritePaletteTag(palette->tag); + + if (index != 0xFF) + return index; + + index = IndexOfSpritePaletteTag(0xFFFF); + + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = palette->tag; + DoLoadSpritePalette(palette->data, index * 16); + return index; + } +} + +void LoadSpritePalettes(const struct SpritePalette *palettes) +{ + u8 i; + for (i = 0; palettes[i].data != NULL; i++) + if (LoadSpritePalette(&palettes[i]) == 0xFF) + break; +} + +void DoLoadSpritePalette(const u16 *src, u16 paletteOffset) +{ + LoadPalette(src, paletteOffset + 0x100, 32); +} + +u8 AllocSpritePalette(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(0xFFFF); + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = tag; + return index; + } +} + +u8 IndexOfSpritePaletteTag(u16 tag) +{ + u8 i; + for (i = gReservedSpritePaletteCount; i < 16; i++) + if (sSpritePaletteTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum) +{ + return sSpritePaletteTags[paletteNum]; +} + +void FreeSpritePaletteByTag(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(tag); + if (index != 0xFF) + sSpritePaletteTags[index] = 0xFFFF; +} + +void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables) +{ + sprite->subspriteTables = subspriteTables; + sprite->subspriteTableNum = 0; + sprite->subspriteMode = SUBSPRITES_ON; +} + +bool8 AddSpriteToOamBuffer(struct Sprite *sprite, u8 *oamIndex) +{ + if (*oamIndex >= gOamLimit) + return 1; + + if (!sprite->subspriteTables || sprite->subspriteMode == SUBSPRITES_OFF) + { + gMain.oamBuffer[*oamIndex] = sprite->oam; + (*oamIndex)++; + return 0; + } + else + { + return AddSubspritesToOamBuffer(sprite, &gMain.oamBuffer[*oamIndex], oamIndex); + } +} + +bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex) +{ + const struct SubspriteTable *subspriteTable; + struct OamData *oam; + + if (*oamIndex >= gOamLimit) + return 1; + + subspriteTable = &sprite->subspriteTables[sprite->subspriteTableNum]; + oam = &sprite->oam; + + if (!subspriteTable || !subspriteTable->subsprites) + { + *destOam = *oam; + (*oamIndex)++; + return 0; + } + else + { + u16 tileNum; + u16 baseX; + u16 baseY; + u8 subspriteCount; + u8 hFlip; + u8 vFlip; + u8 i; + + tileNum = oam->tileNum; + subspriteCount = subspriteTable->subspriteCount; + hFlip = ((s32)oam->matrixNum >> 3) & 1; + vFlip = ((s32)oam->matrixNum >> 4) & 1; + baseX = oam->x - sprite->centerToCornerVecX; + baseY = oam->y - sprite->centerToCornerVecY; + + for (i = 0; i < subspriteCount; i++, (*oamIndex)++) + { + u16 x; + u16 y; + + if (*oamIndex >= gOamLimit) + return 1; + + x = subspriteTable->subsprites[i].x; + y = subspriteTable->subsprites[i].y; + + if (hFlip) + { + s8 width = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].width; + s16 right = x; + right += width; + x = right; + x = ~x + 1; + } + + if (vFlip) + { + s8 height = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].height; + s16 bottom = y; + bottom += height; + y = bottom; + y = ~y + 1; + } + + destOam[i] = *oam; + destOam[i].shape = subspriteTable->subsprites[i].shape; + destOam[i].size = subspriteTable->subsprites[i].size; + destOam[i].x = (s16)baseX + (s16)x; + destOam[i].y = baseY + y; + destOam[i].tileNum = tileNum + subspriteTable->subsprites[i].tileOffset; + + if (sprite->subspriteMode != SUBSPRITES_IGNORE_PRIORITY) + destOam[i].priority = subspriteTable->subsprites[i].priority; + } + } + + return 0; +} diff --git a/gflib/sprite.h b/gflib/sprite.h new file mode 100644 index 000000000..4a3b48225 --- /dev/null +++ b/gflib/sprite.h @@ -0,0 +1,324 @@ +#ifndef GUARD_SPRITE_H +#define GUARD_SPRITE_H + +#define MAX_SPRITES 64 +#define SPRITE_NONE 0xFF +#define SPRITE_INVALID_TAG 0xFFFF + +struct SpriteSheet +{ + const void *data; // Raw uncompressed pixel data + u16 size; + u16 tag; +}; + +struct CompressedSpriteSheet +{ + const u32 *data; // LZ77 compressed pixel data + u16 size; // Uncompressed size of pixel data + u16 tag; +}; + +struct SpriteFrameImage +{ + const void *data; + u16 size; +}; + +#define obj_frame_tiles(ptr) {.data = (u8 *)ptr, .size = sizeof ptr} + +#define overworld_frame(ptr, width, height, frame) {.data = (u8 *)ptr + (width * height * frame * 64)/2, .size = (width * height * 64)/2} + +struct SpritePalette +{ + const u16 *data; // Raw uncompressed palette data + u16 tag; +}; + +struct CompressedSpritePalette +{ + const u32 *data; // LZ77 compressed palette data + u16 tag; +}; + +struct AnimFrameCmd +{ + // If the sprite has an array of images, this is the array index. + // If the sprite has a sheet, this is the tile offset. + u32 imageValue:16; + + u32 duration:6; + u32 hFlip:1; + u32 vFlip:1; +}; + +struct AnimLoopCmd +{ + u32 type:16; + u32 count:6; +}; + +struct AnimJumpCmd +{ + u32 type:16; + u32 target:6; +}; + +// The first halfword of this union specifies the type of command. +// If it -2, then it is a jump command. If it is -1, then it is the end of the script. +// Otherwise, it is the imageValue for a frame command. +union AnimCmd +{ + s16 type; + struct AnimFrameCmd frame; + struct AnimLoopCmd loop; + struct AnimJumpCmd jump; +}; + +#define ANIMCMD_FRAME(...) \ + {.frame = {__VA_ARGS__}} +#define ANIMCMD_LOOP(_count) \ + {.loop = {.type = -3, .count = _count}} +#define ANIMCMD_JUMP(_target) \ + {.jump = {.type = -2, .target = _target}} +#define ANIMCMD_END \ + {.type = -1} + +struct AffineAnimFrameCmd +{ + s16 xScale; + s16 yScale; + u8 rotation; + u8 duration; +}; + +struct AffineAnimLoopCmd +{ + s16 type; + s16 count; +}; + +struct AffineAnimJumpCmd +{ + s16 type; + u16 target; +}; + +struct AffineAnimEndCmdAlt +{ + s16 type; + u16 val; +}; + +union AffineAnimCmd +{ + s16 type; + struct AffineAnimFrameCmd frame; + struct AffineAnimLoopCmd loop; + struct AffineAnimJumpCmd jump; + struct AffineAnimEndCmdAlt end; // unused in code +}; + +#define AFFINEANIMCMDTYPE_LOOP 0x7FFD +#define AFFINEANIMCMDTYPE_JUMP 0x7FFE +#define AFFINEANIMCMDTYPE_END 0x7FFF + +#define AFFINEANIMCMD_FRAME(_xScale, _yScale, _rotation, _duration) \ + {.frame = {.xScale = _xScale, .yScale = _yScale, .rotation = _rotation, .duration = _duration}} +#define AFFINEANIMCMD_LOOP(_count) \ + {.loop = {.type = AFFINEANIMCMDTYPE_LOOP, .count = _count}} +#define AFFINEANIMCMD_JUMP(_target) \ + {.jump = {.type = AFFINEANIMCMDTYPE_JUMP, .target = _target}} +#define AFFINEANIMCMD_END \ + {.type = AFFINEANIMCMDTYPE_END} +#define AFFINEANIMCMD_END_ALT(_val) \ + {.end = {.type = AFFINEANIMCMDTYPE_END, .val = _val}} + +struct AffineAnimState +{ + u8 animNum; + u8 animCmdIndex; + u8 delayCounter; + u8 loopCounter; + s16 xScale; + s16 yScale; + u16 rotation; +}; + +enum +{ + SUBSPRITES_OFF, + SUBSPRITES_ON, + SUBSPRITES_IGNORE_PRIORITY, // on but priority is ignored +}; + +struct Subsprite +{ + s8 x; // was u16 in R/S + s8 y; // was u16 in R/S + u16 shape:2; + u16 size:2; + u16 tileOffset:10; + u16 priority:2; +}; + +struct SubspriteTable +{ + u8 subspriteCount; + const struct Subsprite *subsprites; +}; + +struct Sprite; + +typedef void (*SpriteCallback)(struct Sprite *); + +struct SpriteTemplate +{ + u16 tileTag; + u16 paletteTag; + const struct OamData *oam; + const union AnimCmd *const *anims; + const struct SpriteFrameImage *images; + const union AffineAnimCmd *const *affineAnims; + SpriteCallback callback; +}; + +// UB: template pointer is often used to point to temporary storage, +// then later dereferenced after being freed. Usually this won't +// be visible in-game, but this is (part of) what causes the item +// icon palette to flicker when changing items in the bag. +struct Sprite +{ + /*0x00*/ struct OamData oam; + /*0x08*/ const union AnimCmd *const *anims; + /*0x0C*/ const struct SpriteFrameImage *images; + /*0x10*/ const union AffineAnimCmd *const *affineAnims; + /*0x14*/ const struct SpriteTemplate *template; + /*0x18*/ const struct SubspriteTable *subspriteTables; + /*0x1C*/ SpriteCallback callback; + + /*0x20*/ struct Coords16 pos1; + /*0x24*/ struct Coords16 pos2; + /*0x28*/ s8 centerToCornerVecX; + /*0x29*/ s8 centerToCornerVecY; + + /*0x2A*/ u8 animNum; + /*0x2B*/ u8 animCmdIndex; + /*0x2C*/ u8 animDelayCounter:6; + bool8 animPaused:1; + bool8 affineAnimPaused:1; + /*0x2D*/ u8 animLoopCounter; + + // general purpose data fields + /*0x2E*/ s16 data[8]; + + /*0x3E*/ bool16 inUse:1; //1 + bool16 coordOffsetEnabled:1; //2 + bool16 invisible:1; //4 + bool16 flags_3:1; //8 + bool16 flags_4:1; //0x10 + bool16 flags_5:1; //0x20 + bool16 flags_6:1; //0x40 + bool16 flags_7:1; //0x80 + /*0x3F*/ bool16 hFlip:1; //1 + bool16 vFlip:1; //2 + bool16 animBeginning:1; //4 + bool16 affineAnimBeginning:1; //8 + bool16 animEnded:1; //0x10 + bool16 affineAnimEnded:1; //0x20 + bool16 usingSheet:1; //0x40 + bool16 flags_f:1; //0x80 + + /*0x40*/ u16 sheetTileStart; + + /*0x42*/ u8 subspriteTableNum:6; + u8 subspriteMode:2; + + /*0x43*/ u8 subpriority; +}; + +struct OamMatrix +{ + s16 a; + s16 b; + s16 c; + s16 d; +}; + +extern const struct OamData gDummyOamData; +extern const union AnimCmd *const gDummySpriteAnimTable[]; +extern const union AffineAnimCmd *const gDummySpriteAffineAnimTable[]; +extern const struct SpriteTemplate gDummySpriteTemplate; + +extern u8 gReservedSpritePaletteCount; +extern struct Sprite gSprites[]; +extern u8 gOamLimit; +extern u16 gReservedSpriteTileCount; +extern s16 gSpriteCoordOffsetX; +extern s16 gSpriteCoordOffsetY; +extern struct OamMatrix gOamMatrices[]; +extern bool8 gAffineAnimsDisabled; + +void ResetSpriteData(void); +void AnimateSprites(void); +void BuildOamBuffer(void); +u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)); +u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +void DestroySprite(struct Sprite *sprite); +void ResetOamRange(u8 a, u8 b); +void LoadOam(void); +void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d); +void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode); +void SpriteCallbackDummy(struct Sprite *sprite); +void ProcessSpriteCopyRequests(void); +void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size); +void FreeSpriteTiles(struct Sprite *sprite); +void FreeSpritePalette(struct Sprite *sprite); +void FreeSpriteOamMatrix(struct Sprite *sprite); +void DestroySpriteAndFreeResources(struct Sprite *sprite); +void sub_800142C(u32 a1, u32 a2, u16 *a3, u16 a4, u32 a5); +void AnimateSprite(struct Sprite *sprite); +void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3); +void StartSpriteAnim(struct Sprite *sprite, u8 animNum); +void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum); +void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex); +void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum); +void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); +void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum); +void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); +void SetSpriteSheetFrameTileNum(struct Sprite *sprite); +u8 AllocOamMatrix(void); +void FreeOamMatrix(u8 matrixNum); +void InitSpriteAffineAnim(struct Sprite *sprite); +void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation); +u16 LoadSpriteSheet(const struct SpriteSheet *sheet); +void LoadSpriteSheets(const struct SpriteSheet *sheets); +u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet); +void AllocTilesForSpriteSheets(struct SpriteSheet *sheets); +void LoadTilesForSpriteSheet(const struct SpriteSheet *sheet); +void LoadTilesForSpriteSheets(struct SpriteSheet *sheets); +void FreeSpriteTilesByTag(u16 tag); +void FreeSpriteTileRanges(void); +u16 GetSpriteTileStartByTag(u16 tag); +u16 GetSpriteTileTagByTileStart(u16 start); +void RequestSpriteSheetCopy(const struct SpriteSheet *sheet); +u16 LoadSpriteSheetDeferred(const struct SpriteSheet *sheet); +void FreeAllSpritePalettes(void); +u8 LoadSpritePalette(const struct SpritePalette *palette); +void LoadSpritePalettes(const struct SpritePalette *palettes); +u8 AllocSpritePalette(u16 tag); +u8 IndexOfSpritePaletteTag(u16 tag); +u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum); +void FreeSpritePaletteByTag(u16 tag); +void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables); +bool8 AddSpriteToOamBuffer(struct Sprite *object, u8 *oamIndex); +bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex); +void CopyToSprites(u8 *src); +void CopyFromSprites(u8 *dest); +u8 SpriteTileAllocBitmapOp(u16 bit, u8 op); +void ClearSpriteCopyRequests(void); +void ResetAffineAnimData(void); + +#endif //GUARD_SPRITE_H diff --git a/gflib/string_util.c b/gflib/string_util.c new file mode 100644 index 000000000..92f8eea5a --- /dev/null +++ b/gflib/string_util.c @@ -0,0 +1,781 @@ +#include "global.h" +#include "string_util.h" +#include "text.h" +#include "strings.h" + +EWRAM_DATA u8 gStringVar1[0x100] = {0}; +EWRAM_DATA u8 gStringVar2[0x100] = {0}; +EWRAM_DATA u8 gStringVar3[0x100] = {0}; +EWRAM_DATA u8 gStringVar4[0x3E8] = {0}; +EWRAM_DATA static u8 sUnknownStringVar[16] = {0}; + +static const u8 sDigits[] = __("0123456789ABCDEF"); + +static const s32 sPowersOfTen[] = +{ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, +}; + +u8 *StringCopy10(u8 *dest, const u8 *src) +{ + u8 i; + u32 limit = 10; + + for (i = 0; i < limit; i++) + { + dest[i] = src[i]; + + if (dest[i] == EOS) + return &dest[i]; + } + + dest[i] = EOS; + return &dest[i]; +} + +u8 *StringGetEnd10(u8 *str) +{ + u8 i; + u32 limit = 10; + + for (i = 0; i < limit; i++) + if (str[i] == EOS) + return &str[i]; + + str[i] = EOS; + return &str[i]; +} + +u8 *StringCopy7(u8 *dest, const u8 *src) +{ + s32 i; + s32 limit = 7; + + for (i = 0; i < limit; i++) + { + dest[i] = src[i]; + + if (dest[i] == EOS) + return &dest[i]; + } + + dest[i] = EOS; + return &dest[i]; +} + +u8 *StringCopy(u8 *dest, const u8 *src) +{ + while (*src != EOS) + { + *dest = *src; + dest++; + src++; + } + + *dest = EOS; + return dest; +} + +u8 *StringAppend(u8 *dest, const u8 *src) +{ + while (*dest != EOS) + dest++; + + return StringCopy(dest, src); +} + +u8 *StringCopyN(u8 *dest, const u8 *src, u8 n) +{ + u16 i; + + for (i = 0; i < n; i++) + dest[i] = src[i]; + + return &dest[n]; +} + +u8 *StringAppendN(u8 *dest, const u8 *src, u8 n) +{ + while (*dest != EOS) + dest++; + + return StringCopyN(dest, src, n); +} + +u16 StringLength(const u8 *str) +{ + u16 length = 0; + + while (str[length] != EOS) + length++; + + return length; +} + +s32 StringCompare(const u8 *str1, const u8 *str2) +{ + while (*str1 == *str2) + { + if (*str1 == EOS) + return 0; + str1++; + str2++; + } + + return *str1 - *str2; +} + +s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n) +{ + while (*str1 == *str2) + { + if (*str1 == EOS) + return 0; + str1++; + str2++; + if (--n == 0) + return 0; + } + + return *str1 - *str2; +} + +bool8 IsStringLengthAtLeast(const u8 *str, s32 n) +{ + u8 i; + + for (i = 0; i < n; i++) + if (str[i] && str[i] != EOS) + return TRUE; + + return FALSE; +} + +u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + s32 powerOfTen; + s32 largestPowerOfTen = sPowersOfTen[n - 1]; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) + { + u8 c; + u16 digit = value / powerOfTen; + s32 temp = value - (powerOfTen * digit); + + if (state == WRITING_DIGITS) + { + u8 *out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfTen == 1) + { + u8 *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + s32 powerOfTen; + s32 largestPowerOfTen = sPowersOfTen[n - 1]; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) + { + u8 c; + u16 digit = value / powerOfTen; + u32 temp = value - (powerOfTen * digit); + + if (state == WRITING_DIGITS) + { + u8 *out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfTen == 1) + { + u8 *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + u8 i; + s32 powerOfSixteen; + s32 largestPowerOfSixteen = 1; + + for (i = 1; i < n; i++) + largestPowerOfSixteen *= 16; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfSixteen = largestPowerOfSixteen; powerOfSixteen > 0; powerOfSixteen /= 16) + { + u8 c; + u32 digit = value / powerOfSixteen; + s32 temp = value % powerOfSixteen; + + if (state == WRITING_DIGITS) + { + char *out = dest++; + + if (digit <= 0xF) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfSixteen == 1) + { + char *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 0xF) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *StringExpandPlaceholders(u8 *dest, const u8 *src) +{ + for (;;) + { + u8 c = *src++; + u8 placeholderId; + const u8 *expandedString; + + switch (c) + { + case PLACEHOLDER_BEGIN: + placeholderId = *src++; + expandedString = GetExpandedPlaceholder(placeholderId); + dest = StringExpandPlaceholders(dest, expandedString); + break; + case EXT_CTRL_CODE_BEGIN: + *dest++ = c; + c = *src++; + *dest++ = c; + + switch (c) + { + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_FILL_WINDOW: + case EXT_CTRL_CODE_JPN: + case EXT_CTRL_CODE_ENG: + case EXT_CTRL_CODE_PAUSE_MUSIC: + case EXT_CTRL_CODE_RESUME_MUSIC: + break; + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + *dest++ = *src++; + case EXT_CTRL_CODE_PLAY_BGM: + *dest++ = *src++; + default: + *dest++ = *src++; + } + break; + case EOS: + *dest = EOS; + return dest; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + case CHAR_NEWLINE: + default: + *dest++ = c; + } + } +} + +u8 *StringBraille(u8 *dest, const u8 *src) +{ + const u8 setBrailleFont[] = { + EXT_CTRL_CODE_BEGIN, + EXT_CTRL_CODE_SIZE, + 6, + EOS + }; + const u8 gotoLine2[] = { + CHAR_NEWLINE, + EXT_CTRL_CODE_BEGIN, + EXT_CTRL_CODE_SHIFT_DOWN, + 2, + EOS + }; + + dest = StringCopy(dest, setBrailleFont); + + for (;;) + { + u8 c = *src++; + + switch (c) + { + case EOS: + *dest = c; + return dest; + case CHAR_NEWLINE: + dest = StringCopy(dest, gotoLine2); + break; + default: + *dest++ = c; + *dest++ = c + 0x40; + break; + } + } +} + +static const u8 *ExpandPlaceholder_UnknownStringVar(void) +{ + return sUnknownStringVar; +} + +static const u8 *ExpandPlaceholder_PlayerName(void) +{ + return gSaveBlock2Ptr->playerName; +} + +static const u8 *ExpandPlaceholder_StringVar1(void) +{ + return gStringVar1; +} + +static const u8 *ExpandPlaceholder_StringVar2(void) +{ + return gStringVar2; +} + +static const u8 *ExpandPlaceholder_StringVar3(void) +{ + return gStringVar3; +} + +static const u8 *ExpandPlaceholder_KunChan(void) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + return gText_ExpandedPlaceholder_Kun; + else + return gText_ExpandedPlaceholder_Chan; +} + +static const u8 *ExpandPlaceholder_RivalName(void) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + return gText_ExpandedPlaceholder_May; + else + return gText_ExpandedPlaceholder_Brendan; +} + +static const u8 *ExpandPlaceholder_Version(void) +{ + return gText_ExpandedPlaceholder_Emerald; +} + +static const u8 *ExpandPlaceholder_Aqua(void) +{ + return gText_ExpandedPlaceholder_Aqua; +} + +static const u8 *ExpandPlaceholder_Magma(void) +{ + return gText_ExpandedPlaceholder_Magma; +} + +static const u8 *ExpandPlaceholder_Archie(void) +{ + return gText_ExpandedPlaceholder_Archie; +} + +static const u8 *ExpandPlaceholder_Maxie(void) +{ + return gText_ExpandedPlaceholder_Maxie; +} + +static const u8 *ExpandPlaceholder_Kyogre(void) +{ + return gText_ExpandedPlaceholder_Kyogre; +} + +static const u8 *ExpandPlaceholder_Groudon(void) +{ + return gText_ExpandedPlaceholder_Groudon; +} + +const u8 *GetExpandedPlaceholder(u32 id) +{ + typedef const u8 *(*ExpandPlaceholderFunc)(void); + + static const ExpandPlaceholderFunc funcs[] = + { + [PLACEHOLDER_ID_UNKNOWN] = ExpandPlaceholder_UnknownStringVar, + [PLACEHOLDER_ID_PLAYER] = ExpandPlaceholder_PlayerName, + [PLACEHOLDER_ID_STRING_VAR_1] = ExpandPlaceholder_StringVar1, + [PLACEHOLDER_ID_STRING_VAR_2] = ExpandPlaceholder_StringVar2, + [PLACEHOLDER_ID_STRING_VAR_3] = ExpandPlaceholder_StringVar3, + [PLACEHOLDER_ID_KUN] = ExpandPlaceholder_KunChan, + [PLACEHOLDER_ID_RIVAL] = ExpandPlaceholder_RivalName, + [PLACEHOLDER_ID_VERSION] = ExpandPlaceholder_Version, + [PLACEHOLDER_ID_AQUA] = ExpandPlaceholder_Aqua, + [PLACEHOLDER_ID_MAGMA] = ExpandPlaceholder_Magma, + [PLACEHOLDER_ID_ARCHIE] = ExpandPlaceholder_Archie, + [PLACEHOLDER_ID_MAXIE] = ExpandPlaceholder_Maxie, + [PLACEHOLDER_ID_KYOGRE] = ExpandPlaceholder_Kyogre, + [PLACEHOLDER_ID_GROUDON] = ExpandPlaceholder_Groudon, + }; + + if (id >= ARRAY_COUNT(funcs)) + return gText_ExpandedPlaceholder_Empty; + else + return funcs[id](); +} + +u8 *StringFill(u8 *dest, u8 c, u16 n) +{ + u16 i; + + for (i = 0; i < n; i++) + *dest++ = c; + + *dest = EOS; + return dest; +} + +u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n) +{ + while (*src != EOS) + { + *dest++ = *src++; + + if (n) + n--; + } + + n--; + + while (n != (u16)-1) + { + *dest++ = c; + n--; + } + + *dest = EOS; + return dest; +} + +u8 *StringFillWithTerminator(u8 *dest, u16 n) +{ + return StringFill(dest, EOS, n); +} + +u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n) +{ + u32 i; + + for (i = n - 1; i != (u32)-1; i--) + { + if (*src == EOS) + { + break; + } + else + { + *dest++ = *src++; + if (*(src - 1) == CHAR_EXTRA_SYMBOL) + *dest++ = *src++; + } + } + + *dest = EOS; + return dest; +} + +u32 StringLength_Multibyte(const u8 *str) +{ + u32 length = 0; + + while (*str != EOS) + { + if (*str == CHAR_EXTRA_SYMBOL) + str++; + str++; + length++; + } + + return length; +} + +u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color) +{ + *dest = EXT_CTRL_CODE_BEGIN; + dest++; + + switch (colorType) + { + case 0: + *dest = EXT_CTRL_CODE_COLOR; + dest++; + break; + case 1: + *dest = EXT_CTRL_CODE_SHADOW; + dest++; + break; + case 2: + *dest = EXT_CTRL_CODE_HIGHLIGHT; + dest++; + break; + } + + *dest = color; + dest++; + *dest = EOS; + return dest; +} + +bool32 IsStringJapanese(u8 *str) +{ + while (*str != EOS) + { + if (*str < CHAR_0) + if (*str != CHAR_SPACE) + return TRUE; + str++; + } + + return FALSE; +} + +bool32 sub_800924C(u8 *str, s32 n) +{ + s32 i; + + for (i = 0; *str != EOS && i < n; i++) + { + if (*str < CHAR_0) + if (*str != CHAR_SPACE) + return TRUE; + str++; + } + + return FALSE; +} + +u8 GetExtCtrlCodeLength(u8 code) +{ + static const u8 lengths[] = + { + [0] = 1, + [EXT_CTRL_CODE_COLOR] = 2, + [EXT_CTRL_CODE_HIGHLIGHT] = 2, + [EXT_CTRL_CODE_SHADOW] = 2, + [EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW] = 4, + [EXT_CTRL_CODE_PALETTE] = 2, + [EXT_CTRL_CODE_SIZE] = 2, + [EXT_CTRL_CODE_RESET_SIZE] = 1, + [EXT_CTRL_CODE_PAUSE] = 2, + [EXT_CTRL_CODE_PAUSE_UNTIL_PRESS] = 1, + [EXT_CTRL_CODE_WAIT_SE] = 1, + [EXT_CTRL_CODE_PLAY_BGM] = 3, + [EXT_CTRL_CODE_ESCAPE] = 2, + [EXT_CTRL_CODE_SHIFT_TEXT] = 2, + [EXT_CTRL_CODE_SHIFT_DOWN] = 2, + [EXT_CTRL_CODE_FILL_WINDOW] = 1, + [EXT_CTRL_CODE_PLAY_SE] = 3, + [EXT_CTRL_CODE_CLEAR] = 2, + [EXT_CTRL_CODE_SKIP] = 2, + [EXT_CTRL_CODE_CLEAR_TO] = 2, + [EXT_CTRL_CODE_MIN_LETTER_SPACING] = 2, + [EXT_CTRL_CODE_JPN] = 1, + [EXT_CTRL_CODE_ENG] = 1, + [EXT_CTRL_CODE_PAUSE_MUSIC] = 1, + [EXT_CTRL_CODE_RESUME_MUSIC] = 1, + }; + + u8 length = 0; + if (code < ARRAY_COUNT(lengths)) + length = lengths[code]; + return length; +} + +static const u8 *SkipExtCtrlCode(const u8 *s) +{ + while (*s == EXT_CTRL_CODE_BEGIN) + { + s++; + s += GetExtCtrlCodeLength(*s); + } + + return s; +} + +s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2) +{ + s32 retVal = 0; + + while (1) + { + str1 = SkipExtCtrlCode(str1); + str2 = SkipExtCtrlCode(str2); + + if (*str1 > *str2) + break; + + if (*str1 < *str2) + { + retVal = -1; + if (*str2 == EOS) + retVal = 1; + } + + if (*str1 == EOS) + return retVal; + + str1++; + str2++; + } + + retVal = 1; + + if (*str1 == EOS) + retVal = -1; + + return retVal; +} + +void ConvertInternationalString(u8 *s, u8 language) +{ + if (language == LANGUAGE_JAPANESE) + { + u8 i; + + StripExtCtrlCodes(s); + i = StringLength(s); + s[i++] = EXT_CTRL_CODE_BEGIN; + s[i++] = EXT_CTRL_CODE_ENG; + s[i++] = EOS; + + i--; + + while (i != (u8)-1) + { + s[i + 2] = s[i]; + i--; + } + + s[0] = EXT_CTRL_CODE_BEGIN; + s[1] = EXT_CTRL_CODE_JPN; + } +} + +void StripExtCtrlCodes(u8 *str) +{ + u16 srcIndex = 0; + u16 destIndex = 0; + while (str[srcIndex] != EOS) + { + if (str[srcIndex] == EXT_CTRL_CODE_BEGIN) + { + srcIndex++; + srcIndex += GetExtCtrlCodeLength(str[srcIndex]); + } + else + { + str[destIndex++] = str[srcIndex++]; + } + } + str[destIndex] = EOS; +} diff --git a/gflib/string_util.h b/gflib/string_util.h new file mode 100644 index 000000000..229193d52 --- /dev/null +++ b/gflib/string_util.h @@ -0,0 +1,46 @@ +#ifndef GUARD_STRING_UTIL_H +#define GUARD_STRING_UTIL_H + +extern u8 gStringVar1[0x100]; +extern u8 gStringVar2[0x100]; +extern u8 gStringVar3[0x100]; +extern u8 gStringVar4[0x3E8]; + +enum StringConvertMode +{ + STR_CONV_MODE_LEFT_ALIGN, + STR_CONV_MODE_RIGHT_ALIGN, + STR_CONV_MODE_LEADING_ZEROS +}; + +u8 *StringCopy10(u8 *dest, const u8 *src); +u8 *StringGetEnd10(u8 *str); +u8 *StringCopy7(u8 *dest, const u8 *src); +u8 *StringCopy(u8 *dest, const u8 *src); +u8 *StringAppend(u8 *dest, const u8 *src); +u8 *StringCopyN(u8 *dest, const u8 *src, u8 n); +u8 *StringAppendN(u8 *dest, const u8 *src, u8 n); +u16 StringLength(const u8 *str); +s32 StringCompare(const u8 *str1, const u8 *str2); +s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n); +bool8 IsStringLengthAtLeast(const u8 *str, s32 n); +u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); +u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n); +u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); +u8 *StringExpandPlaceholders(u8 *dest, const u8 *src); +u8 *StringBraille(u8 *dest, const u8 *src); +const u8 *GetExpandedPlaceholder(u32 id); +u8 *StringFill(u8 *dest, u8 c, u16 n); +u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n); +u8 *StringFillWithTerminator(u8 *dest, u16 n); +u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n); +u32 StringLength_Multibyte(const u8 *str); +u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color); +bool32 IsStringJapanese(u8 *str); +bool32 sub_800924C(u8 *str, s32 n); +u8 GetExtCtrlCodeLength(u8 code); +s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2); +void ConvertInternationalString(u8 *s, u8 language); +void StripExtCtrlCodes(u8 *str); + +#endif // GUARD_STRING_UTIL_H diff --git a/gflib/text.c b/gflib/text.c new file mode 100644 index 000000000..eb993c421 --- /dev/null +++ b/gflib/text.c @@ -0,0 +1,1808 @@ +#include "global.h" +#include "battle.h" +#include "main.h" +#include "m4a.h" +#include "palette.h" +#include "sound.h" +#include "constants/songs.h" +#include "string_util.h" +#include "window.h" +#include "text.h" +#include "blit.h" +#include "menu.h" +#include "dynamic_placeholder_text_util.h" + +EWRAM_DATA struct TextPrinter gTempTextPrinter = {0}; +EWRAM_DATA struct TextPrinter gTextPrinters[NUM_TEXT_PRINTERS] = {0}; + +static u16 gFontHalfRowLookupTable[0x51]; +static u16 gLastTextBgColor; +static u16 gLastTextFgColor; +static u16 gLastTextShadowColor; + +const struct FontInfo *gFonts; +u8 gDisableTextPrinters; +struct TextGlyph gCurGlyph; +TextFlags gTextFlags; + +const u8 gFontHalfRowOffsets[] = +{ + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, + 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, + 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, + 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, + 0x24, 0x25, 0x26, 0x24, 0x27, 0x28, 0x29, 0x27, 0x2A, 0x2B, 0x2C, 0x2A, 0x24, 0x25, 0x26, 0x24, + 0x2D, 0x2E, 0x2F, 0x2D, 0x30, 0x31, 0x32, 0x30, 0x33, 0x34, 0x35, 0x33, 0x2D, 0x2E, 0x2F, 0x2D, + 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, + 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, + 0x3F, 0x40, 0x41, 0x3F, 0x42, 0x43, 0x44, 0x42, 0x45, 0x46, 0x47, 0x45, 0x3F, 0x40, 0x41, 0x3F, + 0x48, 0x49, 0x4A, 0x48, 0x4B, 0x4C, 0x4D, 0x4B, 0x4E, 0x4F, 0x50, 0x4E, 0x48, 0x49, 0x4A, 0x48, + 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, + 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, + 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, + 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00 +}; + +const u8 gDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow.4bpp"); +const u8 gDarkDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow_RS.4bpp"); +const u8 gUnusedFRLGBlankedDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_blanked_down_arrow.4bpp"); +const u8 gUnusedFRLGDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_down_arrow.4bpp"); +const u8 gDownArrowYCoords[] = { 0x0, 0x1, 0x2, 0x1 }; +const u8 gWindowVerticalScrollSpeeds[] = { 0x1, 0x2, 0x4, 0x0 }; + +const struct GlyphWidthFunc gGlyphWidthFuncs[] = +{ + { 0x0, GetGlyphWidthFont0 }, + { 0x1, GetGlyphWidthFont1 }, + { 0x2, GetGlyphWidthFont2 }, + { 0x3, GetGlyphWidthFont2 }, + { 0x4, GetGlyphWidthFont2 }, + { 0x5, GetGlyphWidthFont2 }, + { 0x6, GetGlyphWidthFont6 }, + { 0x7, GetGlyphWidthFont7 }, + { 0x8, GetGlyphWidthFont8 } +}; + +const struct KeypadIcon gKeypadIcons[] = +{ + [CHAR_A_BUTTON] = { 0x0, 0x8, 0xC }, + [CHAR_B_BUTTON] = { 0x1, 0x8, 0xC }, + [CHAR_L_BUTTON] = { 0x2, 0x10, 0xC }, + [CHAR_R_BUTTON] = { 0x4, 0x10, 0xC }, + [CHAR_START_BUTTON] = { 0x6, 0x18, 0xC }, + [CHAR_SELECT_BUTTON] = { 0x9, 0x18, 0xC }, + [CHAR_DPAD_UP] = { 0xC, 0x8, 0xC }, + [CHAR_DPAD_DOWN] = { 0xD, 0x8, 0xC }, + [CHAR_DPAD_LEFT] = { 0xE, 0x8, 0xC }, + [CHAR_DPAD_RIGHT] = { 0xF, 0x8, 0xC }, + [CHAR_DPAD_UPDOWN] = { 0x20, 0x8, 0xC }, + [CHAR_DPAD_LEFTRIGHT] = { 0x21, 0x8, 0xC }, + [CHAR_DPAD_NONE] = { 0x22, 0x8, 0xC } +}; + +const u8 gKeypadIconTiles[] = INCBIN_U8("graphics/fonts/keypad_icons.4bpp"); + +const struct FontInfo gFontInfos[] = +{ + { Font0Func, 0x5, 0xC, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font1Func, 0x6, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font2Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font3Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font4Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font5Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font6Func, 0x8, 0x10, 0x0, 0x8, 0x0, 0x2, 0x1, 0x3 }, + { Font7Func, 0x5, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { Font8Func, 0x5, 0x8, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, + { NULL, 0x8, 0x8, 0x0, 0x0, 0x0, 0x1, 0x2, 0xF } +}; + +const u8 gMenuCursorDimensions[][2] = +{ + { 0x8, 0xC }, + { 0x8, 0xF }, + { 0x8, 0xE }, + { 0x8, 0xE }, + { 0x8, 0xE }, + { 0x8, 0xE }, + { 0x8, 0x10 }, + { 0x8, 0xF }, + { 0x8, 0x8 }, + { 0x0, 0x0 } +}; + +const u16 gFont9JapaneseGlyphs[] = INCBIN_U16("graphics/fonts/font9.hwjpnfont"); + +extern const u16 gFont8LatinGlyphs[]; +extern const u8 gFont8LatinGlyphWidths[]; +extern const u16 gFont0LatinGlyphs[]; +extern const u8 gFont0LatinGlyphWidths[]; +extern const u16 gFont7LatinGlyphs[]; +extern const u8 gFont7LatinGlyphWidths[]; +extern const u16 gFont2LatinGlyphs[]; +extern const u8 gFont2LatinGlyphWidths[]; +extern const u16 gFont1LatinGlyphs[]; +extern const u8 gFont1LatinGlyphWidths[]; +extern const u16 gFont0JapaneseGlyphs[]; +extern const u16 gFont1JapaneseGlyphs[]; +extern const u16 gFont2JapaneseGlyphs[]; +extern const u8 gFont2JapaneseGlyphWidths[]; + +void SetFontsPointer(const struct FontInfo *fonts) +{ + gFonts = fonts; +} + +void DeactivateAllTextPrinters(void) +{ + int printer; + for (printer = 0; printer < NUM_TEXT_PRINTERS; ++printer) + gTextPrinters[printer].active = 0; +} + +u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) +{ + struct TextPrinterTemplate printerTemplate; + + printerTemplate.currentChar = str; + printerTemplate.windowId = windowId; + printerTemplate.fontId = fontId; + printerTemplate.x = x; + printerTemplate.y = y; + printerTemplate.currentX = x; + printerTemplate.currentY = y; + printerTemplate.letterSpacing = gFonts[fontId].letterSpacing; + printerTemplate.lineSpacing = gFonts[fontId].lineSpacing; + printerTemplate.unk = gFonts[fontId].unk; + printerTemplate.fgColor = gFonts[fontId].fgColor; + printerTemplate.bgColor = gFonts[fontId].bgColor; + printerTemplate.shadowColor = gFonts[fontId].shadowColor; + return AddTextPrinter(&printerTemplate, speed, callback); +} + +bool16 AddTextPrinter(struct TextPrinterTemplate *printerTemplate, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) +{ + int i; + u16 j; + + if (!gFonts) + return FALSE; + + gTempTextPrinter.active = 1; + gTempTextPrinter.state = 0; + gTempTextPrinter.textSpeed = speed; + gTempTextPrinter.delayCounter = 0; + gTempTextPrinter.scrollDistance = 0; + + for (i = 0; i < 7; i++) + { + gTempTextPrinter.subStructFields[i] = 0; + } + + gTempTextPrinter.printerTemplate = *printerTemplate; + gTempTextPrinter.callback = callback; + gTempTextPrinter.minLetterSpacing = 0; + gTempTextPrinter.japanese = 0; + + GenerateFontHalfRowLookupTable(printerTemplate->fgColor, printerTemplate->bgColor, printerTemplate->shadowColor); + if (speed != TEXT_SPEED_FF && speed != 0) + { + --gTempTextPrinter.textSpeed; + gTextPrinters[printerTemplate->windowId] = gTempTextPrinter; + } + else + { + gTempTextPrinter.textSpeed = 0; + for (j = 0; j < 0x400; ++j) + { + if (RenderFont(&gTempTextPrinter) == 1) + break; + } + + if (speed != TEXT_SPEED_FF) + CopyWindowToVram(gTempTextPrinter.printerTemplate.windowId, 2); + gTextPrinters[printerTemplate->windowId].active = 0; + } + gDisableTextPrinters = 0; + return TRUE; +} + +void RunTextPrinters(void) +{ + int i; + + if (gDisableTextPrinters == 0) + { + for (i = 0; i < NUM_TEXT_PRINTERS; ++i) + { + if (gTextPrinters[i].active) + { + u16 temp = RenderFont(&gTextPrinters[i]); + switch (temp) + { + case 0: + CopyWindowToVram(gTextPrinters[i].printerTemplate.windowId, 2); + case 3: + if (gTextPrinters[i].callback != 0) + gTextPrinters[i].callback(&gTextPrinters[i].printerTemplate, temp); + break; + case 1: + gTextPrinters[i].active = 0; + break; + } + } + } + } +} + +bool16 IsTextPrinterActive(u8 id) +{ + return gTextPrinters[id].active; +} + +u32 RenderFont(struct TextPrinter *textPrinter) +{ + u32 ret; + while (TRUE) + { + ret = gFonts[textPrinter->printerTemplate.fontId].fontFunction(textPrinter); + if (ret != 2) + return ret; + } +} + +void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor) +{ + u32 fg12, bg12, shadow12; + u32 temp; + + u16 *current = gFontHalfRowLookupTable; + + gLastTextBgColor = bgColor; + gLastTextFgColor = fgColor; + gLastTextShadowColor = shadowColor; + + bg12 = bgColor << 12; + fg12 = fgColor << 12; + shadow12 = shadowColor << 12; + + temp = (bgColor << 8) | (bgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (bgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (bgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (fgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (fgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (fgColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (shadowColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (shadowColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (shadowColor << 4) | bgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (bgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (bgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (bgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (fgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (fgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (fgColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (shadowColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (shadowColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (shadowColor << 4) | fgColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (bgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (bgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (bgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (fgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (fgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (fgColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (bgColor << 8) | (shadowColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (fgColor << 8) | (shadowColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; + + temp = (shadowColor << 8) | (shadowColor << 4) | shadowColor; + *(current++) = (bg12) | temp; + *(current++) = (fg12) | temp; + *(current++) = (shadow12) | temp; +} + +void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) +{ + *bgColor = gLastTextBgColor; + *fgColor = gLastTextFgColor; + *shadowColor = gLastTextShadowColor; +} + +void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) +{ + GenerateFontHalfRowLookupTable(*fgColor, *bgColor, *shadowColor); +} + +void DecompressGlyphTile(const void *src_, void *dest_) +{ + u32 temp; + const u16 *src = src_; + u32 *dest = dest_; + + temp = *(src++); + *(dest)++ = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); + + temp = *(src++); + *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); +} + +u8 GetLastTextColor(u8 colorType) +{ + switch (colorType) + { + case 0: + return gLastTextFgColor; + case 2: + return gLastTextBgColor; + case 1: + return gLastTextShadowColor; + default: + return 0; + } +} + +inline static void GLYPH_COPY(u8 *windowTiles, u32 widthOffset, u32 j, u32 i, u32 *glyphPixels, s32 width, s32 height) +{ + u32 xAdd, yAdd, pixelData, bits, toOrr, dummyX; + u8 *dst; + + xAdd = j + width; + yAdd = i + height; + dummyX = j; + for (; i < yAdd; i++) + { + pixelData = *glyphPixels++; + for (j = dummyX; j < xAdd; j++) + { + if ((toOrr = pixelData & 0xF)) + { + dst = windowTiles + ((j / 8) * 32) + ((j % 8) / 2) + ((i / 8) * widthOffset) + ((i % 8) * 4); + bits = ((j & 1) * 4); + *dst = (toOrr << bits) | (*dst & (0xF0 >> bits)); + } + pixelData >>= 4; + } + } +} + +void CopyGlyphToWindow(struct TextPrinter *textPrinter) +{ + struct Window *window; + struct WindowTemplate *template; + u32 *glyphPixels; + u32 currX, currY, widthOffset; + s32 glyphWidth, glyphHeight; + u8 *windowTiles; + + window = &gWindows[textPrinter->printerTemplate.windowId]; + template = &window->window; + + if ((glyphWidth = (template->width * 8) - textPrinter->printerTemplate.currentX) > gCurGlyph.width) + glyphWidth = gCurGlyph.width; + + if ((glyphHeight = (template->height * 8) - textPrinter->printerTemplate.currentY) > gCurGlyph.height) + glyphHeight = gCurGlyph.height; + + currX = textPrinter->printerTemplate.currentX; + currY = textPrinter->printerTemplate.currentY; + glyphPixels = gCurGlyph.gfxBufferTop; + windowTiles = window->tileData; + widthOffset = template->width * 32; + + if (glyphWidth < 9) + { + if (glyphHeight < 9) + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, glyphHeight); + } + else + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, 8); + GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, glyphWidth, glyphHeight - 8); + } + } + else + { + if (glyphHeight < 9) + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, glyphHeight); + GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, glyphHeight); + } + else + { + GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, 8); + GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, 8); + GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, 8, glyphHeight - 8); + GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY + 8, glyphPixels + 24, glyphWidth - 8, glyphHeight - 8); + } + } +} + +void ClearTextSpan(struct TextPrinter *textPrinter, u32 width) +{ + struct Window *window; + struct Bitmap pixels_data; + struct TextGlyph *glyph; + u8* glyphHeight; + + if (gLastTextBgColor != 0) + { + window = &gWindows[textPrinter->printerTemplate.windowId]; + pixels_data.pixels = window->tileData; + pixels_data.width = window->window.width << 3; + pixels_data.height = window->window.height << 3; + + glyph = &gCurGlyph; + glyphHeight = &glyph->height; + + FillBitmapRect4Bit( + &pixels_data, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + width, + *glyphHeight, + gLastTextBgColor); + } +} + +u16 Font0Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 0; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font1Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 1; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font2Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 2; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font3Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 3; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font4Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 4; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font5Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 5; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font7Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 7; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +u16 Font8Func(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasGlyphIdBeenSet == FALSE) + { + subStruct->glyphId = 8; + subStruct->hasGlyphIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (gTextFlags.autoScroll == 1) + { + subStruct->autoScrollDelay = 0; + } + else + { + subStruct->downArrowYPosIdx = 0; + subStruct->downArrowDelay = 0; + } +} + +void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + const u8 *arrowTiles; + + if (gTextFlags.autoScroll == 0) + { + if (subStruct->downArrowDelay != 0) + { + subStruct->downArrowDelay--; + } + else + { + FillWindowPixelRect( + textPrinter->printerTemplate.windowId, + textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + 8, + 16); + + switch (gTextFlags.useAlternateDownArrow) + { + case FALSE: + default: + arrowTiles = gDownArrowTiles; + break; + case TRUE: + arrowTiles = gDarkDownArrowTiles; + break; + } + + BlitBitmapRectToWindow( + textPrinter->printerTemplate.windowId, + arrowTiles, + 0, + gDownArrowYCoords[subStruct->downArrowYPosIdx], + 8, + 16, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + 8, + 16); + CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); + + subStruct->downArrowDelay = 8; + subStruct->downArrowYPosIdx++; + } + } +} + +void TextPrinterClearDownArrow(struct TextPrinter *textPrinter) +{ + FillWindowPixelRect( + textPrinter->printerTemplate.windowId, + textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, + textPrinter->printerTemplate.currentX, + textPrinter->printerTemplate.currentY, + 8, + 16); + CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); +} + +bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->autoScrollDelay == 49) + { + return TRUE; + } + else + { + subStruct->autoScrollDelay++; + return FALSE; + } +} + +bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) +{ + bool8 result = FALSE; + if (gTextFlags.autoScroll != 0) + { + result = TextPrinterWaitAutoMode(textPrinter); + } + else + { + TextPrinterDrawDownArrow(textPrinter); + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + result = TRUE; + PlaySE(SE_SELECT); + } + } + return result; +} + +bool16 TextPrinterWait(struct TextPrinter *textPrinter) +{ + bool16 result = FALSE; + if (gTextFlags.autoScroll != 0) + { + result = TextPrinterWaitAutoMode(textPrinter); + } + else + { + if (JOY_NEW(A_BUTTON | B_BUTTON)) + { + result = TRUE; + PlaySE(SE_SELECT); + } + } + return result; +} + +void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex) +{ + const u8 *arrowTiles; + + if (*counter != 0) + { + --*counter; + } + else + { + FillWindowPixelRect(windowId, (bgColor << 4) | bgColor, x, y, 0x8, 0x10); + if (drawArrow == 0) + { + switch (gTextFlags.useAlternateDownArrow) + { + case 0: + default: + arrowTiles = gDownArrowTiles; + break; + case 1: + arrowTiles = gDarkDownArrowTiles; + break; + } + + BlitBitmapRectToWindow( + windowId, + arrowTiles, + 0, + gDownArrowYCoords[*yCoordIndex & 3], + 0x8, + 0x10, + x, + y - 2, + 0x8, + 0x10); + CopyWindowToVram(windowId, 0x2); + *counter = 8; + ++*yCoordIndex; + } + } +} + +u16 RenderText(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + u16 currChar; + s32 width; + s32 widthHelper; + + switch (textPrinter->state) + { + case 0: + if ((JOY_HELD(A_BUTTON | B_BUTTON)) && subStruct->hasPrintBeenSpedUp) + textPrinter->delayCounter = 0; + + if (textPrinter->delayCounter && textPrinter->textSpeed) + { + textPrinter->delayCounter--; + if (gTextFlags.canABSpeedUpPrint && (JOY_NEW(A_BUTTON | B_BUTTON))) + { + subStruct->hasPrintBeenSpedUp = TRUE; + textPrinter->delayCounter = 0; + } + return 3; + } + + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED) && gTextFlags.autoScroll) + textPrinter->delayCounter = 3; + else + textPrinter->delayCounter = textPrinter->textSpeed; + + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + + switch (currChar) + { + case CHAR_NEWLINE: + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentY += (gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing); + return 2; + case PLACEHOLDER_BEGIN: + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_BEGIN: + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + switch (currChar) + { + case EXT_CTRL_CODE_COLOR: + textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_HIGHLIGHT: + textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_SHADOW: + textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); + return 2; + case EXT_CTRL_CODE_PALETTE: + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_SIZE: + subStruct->glyphId = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_RESET_SIZE: + return 2; + case EXT_CTRL_CODE_PAUSE: + textPrinter->delayCounter = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + textPrinter->state = 6; + return 2; + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + textPrinter->state = 1; + if (gTextFlags.autoScroll) + subStruct->autoScrollDelay = 0; + return 3; + case EXT_CTRL_CODE_WAIT_SE: + textPrinter->state = 5; + return 3; + case EXT_CTRL_CODE_PLAY_BGM: + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + currChar |= *textPrinter->printerTemplate.currentChar << 8; + textPrinter->printerTemplate.currentChar++; + PlayBGM(currChar); + return 2; + case EXT_CTRL_CODE_ESCAPE: + currChar = *textPrinter->printerTemplate.currentChar | 0x100; + textPrinter->printerTemplate.currentChar++; + break; + case EXT_CTRL_CODE_PLAY_SE: + currChar = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + currChar |= (*textPrinter->printerTemplate.currentChar << 8); + textPrinter->printerTemplate.currentChar++; + PlaySE(currChar); + return 2; + case EXT_CTRL_CODE_SHIFT_TEXT: + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x + *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_SHIFT_DOWN: + textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y + *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_FILL_WINDOW: + FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; + return 2; + case EXT_CTRL_CODE_PAUSE_MUSIC: + m4aMPlayStop(&gMPlayInfo_BGM); + return 2; + case EXT_CTRL_CODE_RESUME_MUSIC: + m4aMPlayContinue(&gMPlayInfo_BGM); + return 2; + case EXT_CTRL_CODE_CLEAR: + width = *textPrinter->printerTemplate.currentChar; + textPrinter->printerTemplate.currentChar++; + if (width > 0) + { + ClearTextSpan(textPrinter, width); + textPrinter->printerTemplate.currentX += width; + return 0; + } + return 2; + case EXT_CTRL_CODE_SKIP: + textPrinter->printerTemplate.currentX = *textPrinter->printerTemplate.currentChar + textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_CLEAR_TO: + { + widthHelper = *textPrinter->printerTemplate.currentChar; + widthHelper += textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentChar++; + width = widthHelper - textPrinter->printerTemplate.currentX; + if (width > 0) + { + ClearTextSpan(textPrinter, width); + textPrinter->printerTemplate.currentX += width; + return 0; + } + } + return 2; + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + textPrinter->minLetterSpacing = *textPrinter->printerTemplate.currentChar++; + return 2; + case EXT_CTRL_CODE_JPN: + textPrinter->japanese = 1; + return 2; + case EXT_CTRL_CODE_ENG: + textPrinter->japanese = 0; + return 2; + } + break; + case CHAR_PROMPT_CLEAR: + textPrinter->state = 2; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case CHAR_PROMPT_SCROLL: + textPrinter->state = 3; + TextPrinterInitDownArrowCounters(textPrinter); + return 3; + case CHAR_EXTRA_SYMBOL: + currChar = *textPrinter->printerTemplate.currentChar | 0x100; + textPrinter->printerTemplate.currentChar++; + break; + case CHAR_KEYPAD_ICON: + currChar = *textPrinter->printerTemplate.currentChar++; + gCurGlyph.width = DrawKeypadIcon(textPrinter->printerTemplate.windowId, currChar, textPrinter->printerTemplate.currentX, textPrinter->printerTemplate.currentY); + textPrinter->printerTemplate.currentX += gCurGlyph.width + textPrinter->printerTemplate.letterSpacing; + return 0; + case EOS: + return 1; + } + + switch (subStruct->glyphId) + { + case 0: + DecompressGlyphFont0(currChar, textPrinter->japanese); + break; + case 1: + DecompressGlyphFont1(currChar, textPrinter->japanese); + break; + case 2: + case 3: + case 4: + case 5: + DecompressGlyphFont2(currChar, textPrinter->japanese); + break; + case 7: + DecompressGlyphFont7(currChar, textPrinter->japanese); + break; + case 8: + DecompressGlyphFont8(currChar, textPrinter->japanese); + break; + case 6: + break; + } + + CopyGlyphToWindow(textPrinter); + + if (textPrinter->minLetterSpacing) + { + textPrinter->printerTemplate.currentX += gCurGlyph.width; + width = textPrinter->minLetterSpacing - gCurGlyph.width; + if (width > 0) + { + ClearTextSpan(textPrinter, width); + textPrinter->printerTemplate.currentX += width; + } + } + else + { + if (textPrinter->japanese) + textPrinter->printerTemplate.currentX += (gCurGlyph.width + textPrinter->printerTemplate.letterSpacing); + else + textPrinter->printerTemplate.currentX += gCurGlyph.width; + } + return 0; + case 1: + if (TextPrinterWait(textPrinter)) + textPrinter->state = 0; + return 3; + case 2: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; + textPrinter->state = 0; + } + return 3; + case 3: + if (TextPrinterWaitWithDownArrow(textPrinter)) + { + TextPrinterClearDownArrow(textPrinter); + textPrinter->scrollDistance = gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing; + textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; + textPrinter->state = 4; + } + return 3; + case 4: + if (textPrinter->scrollDistance) + { + int scrollSpeed = GetPlayerTextSpeed(); + int speed = gWindowVerticalScrollSpeeds[scrollSpeed]; + if (textPrinter->scrollDistance < speed) + { + ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance = 0; + } + else + { + ScrollWindow(textPrinter->printerTemplate.windowId, 0, speed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance -= speed; + } + CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); + } + else + { + textPrinter->state = 0; + } + return 3; + case 5: + if (!IsSEPlaying()) + textPrinter->state = 0; + return 3; + case 6: + if (textPrinter->delayCounter != 0) + textPrinter->delayCounter--; + else + textPrinter->state = 0; + return 3; + } + + return 1; +} + +u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing) +{ + int i; + u8 width; + int temp; + int temp2; + u8 line; + int strPos; + u8 lineWidths[8]; + const u8 *strLocal; + + for (i = 0; i < 8; i++) + { + lineWidths[i] = 0; + } + + width = 0; + line = 0; + strLocal = str; + strPos = 0; + + do + { + temp = strLocal[strPos++]; + switch (temp) + { + case CHAR_NEWLINE: + case EOS: + lineWidths[line] = width; + width = 0; + line++; + break; + case EXT_CTRL_CODE_BEGIN: + temp2 = strLocal[strPos++]; + switch (temp2) + { + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + ++strPos; + case EXT_CTRL_CODE_PLAY_BGM: + case EXT_CTRL_CODE_PLAY_SE: + ++strPos; + case EXT_CTRL_CODE_COLOR: + case EXT_CTRL_CODE_HIGHLIGHT: + case EXT_CTRL_CODE_SHADOW: + case EXT_CTRL_CODE_PALETTE: + case EXT_CTRL_CODE_SIZE: + case EXT_CTRL_CODE_PAUSE: + case EXT_CTRL_CODE_ESCAPE: + case EXT_CTRL_CODE_SHIFT_TEXT: + case EXT_CTRL_CODE_SHIFT_DOWN: + case EXT_CTRL_CODE_CLEAR: + case EXT_CTRL_CODE_SKIP: + case EXT_CTRL_CODE_CLEAR_TO: + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + ++strPos; + break; + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_WAIT_SE: + case EXT_CTRL_CODE_FILL_WINDOW: + case EXT_CTRL_CODE_JPN: + case EXT_CTRL_CODE_ENG: + default: + break; + } + break; + case CHAR_DYNAMIC: + case PLACEHOLDER_BEGIN: + ++strPos; + break; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + break; + case CHAR_KEYPAD_ICON: + case CHAR_EXTRA_SYMBOL: + ++strPos; + default: + ++width; + break; + } + } while (temp != EOS); + + for (width = 0, strPos = 0; strPos < 8; ++strPos) + { + if (width < lineWidths[strPos]) + width = lineWidths[strPos]; + } + + return (u8)(GetFontAttribute(fontId, FONTATTR_MAX_LETTER_WIDTH) + letterSpacing) * width; +} + +u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32) +{ + u32 i; + + for (i = 0; i < 9; ++i) + { + if (glyphId == gGlyphWidthFuncs[i].fontId) + return gGlyphWidthFuncs[i].func; + } + + return NULL; +} + +s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing) +{ + bool8 isJapanese; + int minGlyphWidth; + u32 (*func)(u16 glyphId, bool32 isJapanese); + int localLetterSpacing; + u32 lineWidth; + const u8 *bufferPointer; + int glyphWidth; + s32 width; + + isJapanese = 0; + minGlyphWidth = 0; + + func = GetFontWidthFunc(fontId); + if (func == NULL) + return 0; + + if (letterSpacing == -1) + localLetterSpacing = GetFontAttribute(fontId, FONTATTR_LETTER_SPACING); + else + localLetterSpacing = letterSpacing; + + width = 0; + lineWidth = 0; + bufferPointer = 0; + + while (*str != EOS) + { + switch (*str) + { + case CHAR_NEWLINE: + if (lineWidth > width) + width = lineWidth; + lineWidth = 0; + break; + case PLACEHOLDER_BEGIN: + switch (*++str) + { + case PLACEHOLDER_ID_STRING_VAR_1: + bufferPointer = gStringVar1; + break; + case PLACEHOLDER_ID_STRING_VAR_2: + bufferPointer = gStringVar2; + break; + case PLACEHOLDER_ID_STRING_VAR_3: + bufferPointer = gStringVar3; + break; + default: + return 0; + } + case CHAR_DYNAMIC: + if (bufferPointer == NULL) + bufferPointer = DynamicPlaceholderTextUtil_GetPlaceholderPtr(*++str); + while (*bufferPointer != EOS) + { + glyphWidth = func(*bufferPointer++, isJapanese); + if (minGlyphWidth > 0) + { + if (glyphWidth < minGlyphWidth) + glyphWidth = minGlyphWidth; + lineWidth += glyphWidth; + } + else + { + lineWidth += glyphWidth; + if (isJapanese && str[1] != EOS) + lineWidth += localLetterSpacing; + } + } + bufferPointer = 0; + break; + case EXT_CTRL_CODE_BEGIN: + switch (*++str) + { + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + ++str; + case EXT_CTRL_CODE_PLAY_BGM: + case EXT_CTRL_CODE_PLAY_SE: + ++str; + case EXT_CTRL_CODE_COLOR: + case EXT_CTRL_CODE_HIGHLIGHT: + case EXT_CTRL_CODE_SHADOW: + case EXT_CTRL_CODE_PALETTE: + case EXT_CTRL_CODE_PAUSE: + case EXT_CTRL_CODE_ESCAPE: + case EXT_CTRL_CODE_SHIFT_TEXT: + case EXT_CTRL_CODE_SHIFT_DOWN: + ++str; + break; + case EXT_CTRL_CODE_SIZE: + func = GetFontWidthFunc(*++str); + if (func == NULL) + return 0; + if (letterSpacing == -1) + localLetterSpacing = GetFontAttribute(*str, FONTATTR_LETTER_SPACING); + break; + case EXT_CTRL_CODE_CLEAR: + glyphWidth = *++str; + lineWidth += glyphWidth; + break; + case EXT_CTRL_CODE_SKIP: + lineWidth = *++str; + break; + case EXT_CTRL_CODE_CLEAR_TO: + if (*++str > lineWidth) + lineWidth = *str; + break; + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + minGlyphWidth = *++str; + break; + case EXT_CTRL_CODE_JPN: + isJapanese = 1; + break; + case EXT_CTRL_CODE_ENG: + isJapanese = 0; + break; + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_WAIT_SE: + case EXT_CTRL_CODE_FILL_WINDOW: + default: + break; + } + break; + case CHAR_KEYPAD_ICON: + case CHAR_EXTRA_SYMBOL: + if (*str == CHAR_EXTRA_SYMBOL) + glyphWidth = func(*++str | 0x100, isJapanese); + else + glyphWidth = GetKeypadIconWidth(*++str); + + if (minGlyphWidth > 0) + { + if (glyphWidth < minGlyphWidth) + glyphWidth = minGlyphWidth; + lineWidth += glyphWidth; + } + else + { + lineWidth += glyphWidth; + if (isJapanese && str[1] != EOS) + lineWidth += localLetterSpacing; + } + break; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + break; + default: + glyphWidth = func(*str, isJapanese); + if (minGlyphWidth > 0) + { + if (glyphWidth < minGlyphWidth) + glyphWidth = minGlyphWidth; + lineWidth += glyphWidth; + } + else + { + lineWidth += glyphWidth; + if (isJapanese && str[1] != EOS) + lineWidth += localLetterSpacing; + } + break; + } + ++str; + } + + if (lineWidth > width) + return lineWidth; + return width; +} + +u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str) +{ + u8 shadowColor; + u8 *strLocal; + int strPos; + int temp; + int temp2; + u8 colorBackup[3]; + u8 fgColor; + u8 bgColor; + + SaveTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); + + fgColor = TEXT_COLOR_WHITE; + bgColor = TEXT_COLOR_TRANSPARENT; + shadowColor = TEXT_COLOR_LIGHT_GRAY; + + GenerateFontHalfRowLookupTable(TEXT_COLOR_WHITE, TEXT_COLOR_TRANSPARENT, TEXT_COLOR_LIGHT_GRAY); + strLocal = str; + strPos = 0; + + do + { + temp = strLocal[strPos++]; + switch (temp) + { + case EXT_CTRL_CODE_BEGIN: + temp2 = strLocal[strPos++]; + switch (temp2) + { + case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: + fgColor = strLocal[strPos++]; + bgColor = strLocal[strPos++]; + shadowColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_COLOR: + fgColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_HIGHLIGHT: + bgColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_SHADOW: + shadowColor = strLocal[strPos++]; + GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); + continue; + case EXT_CTRL_CODE_SIZE: + fontId = strLocal[strPos++]; + break; + case EXT_CTRL_CODE_PLAY_BGM: + case EXT_CTRL_CODE_PLAY_SE: + ++strPos; + case EXT_CTRL_CODE_PALETTE: + case EXT_CTRL_CODE_PAUSE: + case EXT_CTRL_CODE_ESCAPE: + case EXT_CTRL_CODE_SHIFT_TEXT: + case EXT_CTRL_CODE_SHIFT_DOWN: + case EXT_CTRL_CODE_CLEAR: + case EXT_CTRL_CODE_SKIP: + case EXT_CTRL_CODE_CLEAR_TO: + case EXT_CTRL_CODE_MIN_LETTER_SPACING: + ++strPos; + break; + case EXT_CTRL_CODE_RESET_SIZE: + case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: + case EXT_CTRL_CODE_WAIT_SE: + case EXT_CTRL_CODE_FILL_WINDOW: + case EXT_CTRL_CODE_JPN: + case EXT_CTRL_CODE_ENG: + default: + continue; + } + break; + case CHAR_DYNAMIC: + case CHAR_KEYPAD_ICON: + case CHAR_EXTRA_SYMBOL: + case PLACEHOLDER_BEGIN: + ++strPos; + break; + case CHAR_PROMPT_SCROLL: + case CHAR_PROMPT_CLEAR: + case CHAR_NEWLINE: + case EOS: + break; + default: + switch (fontId) + { + case 9: + DecompressGlyphFont9(temp); + break; + case 1: + default: + DecompressGlyphFont1(temp, 1); + break; + } + CpuCopy32(gCurGlyph.gfxBufferTop, pixels, 0x20); + CpuCopy32(gCurGlyph.gfxBufferBottom, pixels + 0x20, 0x20); + pixels += 0x40; + break; + } + } + while (temp != EOS); + + RestoreTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); + return 1; +} + +u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y) +{ + BlitBitmapRectToWindow( + windowId, + gKeypadIconTiles + (gKeypadIcons[keypadIconId].tileOffset * 0x20), + 0, + 0, + 0x80, + 0x80, + x, + y, + gKeypadIcons[keypadIconId].width, + gKeypadIcons[keypadIconId].height); + return gKeypadIcons[keypadIconId].width; +} + +u8 GetKeypadIconTileOffset(u8 keypadIconId) +{ + return gKeypadIcons[keypadIconId].tileOffset; +} + +u8 GetKeypadIconWidth(u8 keypadIconId) +{ + return gKeypadIcons[keypadIconId].width; +} + +u8 GetKeypadIconHeight(u8 keypadIconId) +{ + return gKeypadIcons[keypadIconId].height; +} + +void SetDefaultFontsPointer(void) +{ + SetFontsPointer(&gFontInfos[0]); +} + +u8 GetFontAttribute(u8 fontId, u8 attributeId) +{ + int result = 0; + switch (attributeId) + { + case FONTATTR_MAX_LETTER_WIDTH: + result = gFontInfos[fontId].maxLetterWidth; + break; + case FONTATTR_MAX_LETTER_HEIGHT: + result = gFontInfos[fontId].maxLetterHeight; + break; + case FONTATTR_LETTER_SPACING: + result = gFontInfos[fontId].letterSpacing; + break; + case FONTATTR_LINE_SPACING: + result = gFontInfos[fontId].lineSpacing; + break; + case FONTATTR_UNKNOWN: + result = gFontInfos[fontId].unk; + break; + case FONTATTR_COLOR_FOREGROUND: + result = gFontInfos[fontId].fgColor; + break; + case FONTATTR_COLOR_BACKGROUND: + result = gFontInfos[fontId].bgColor; + break; + case FONTATTR_COLOR_SHADOW: + result = gFontInfos[fontId].shadowColor; + break; + } + return result; +} + +u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension) +{ + return gMenuCursorDimensions[fontId][whichDimension]; +} + +void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == 1) + { + glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 12; + } + else + { + glyphs = gFont0LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont0LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 13; + } +} + +u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont0LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 15; + } + else + { + glyphs = gFont7LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont7LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 15; + } +} + +u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont7LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 12; + } + else + { + glyphs = gFont8LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont8LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 12; + } +} + +u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont8LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont2JapaneseGlyphs + (0x100 * (glyphId >> 0x3)) + (0x10 * (glyphId & 0x7)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); // gCurGlyph + 0x20 + DecompressGlyphTile(glyphs + 0x88, gCurGlyph.gfxBufferBottom + 8); // gCurGlyph + 0x60 + gCurGlyph.width = gFont2JapaneseGlyphWidths[glyphId]; + gCurGlyph.height = 14; + } + else + { + glyphs = gFont2LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont2LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 14; + } +} + +u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return gFont2JapaneseGlyphWidths[glyphId]; + else + return gFont2LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese) +{ + const u16* glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 15; + } + else + { + glyphs = gFont1LatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFont1LatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 15; + } +} + +u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFont1LatinGlyphWidths[glyphId]; +} + +void DecompressGlyphFont9(u16 glyphId) +{ + const u16* glyphs; + + glyphs = gFont9JapaneseGlyphs + (0x100 * (glyphId >> 4)) + (0x8 * (glyphId & 0xF)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 12; +} diff --git a/gflib/text.h b/gflib/text.h new file mode 100644 index 000000000..3edd0fc62 --- /dev/null +++ b/gflib/text.h @@ -0,0 +1,436 @@ +#ifndef GUARD_TEXT_H +#define GUARD_TEXT_H + +#define CHAR_SPACE 0x00 +#define CHAR_A_GRAVE 0x01 +#define CHAR_A_ACUTE 0x02 +#define CHAR_A_CIRCUMFLEX 0x03 +#define CHAR_C_CEDILLA 0x04 +#define CHAR_E_GRAVE 0x05 +#define CHAR_E_ACUTE 0x06 +#define CHAR_E_CIRCUMFLEX 0x07 +#define CHAR_E_DIAERESIS 0x08 +#define CHAR_I_GRAVE 0x09 +//#define CHAR_I_ACUTE 0x0A // Is 0x5A instead +#define CHAR_I_CIRCUMFLEX 0x0B +#define CHAR_I_DIAERESIS 0x0C +#define CHAR_O_GRAVE 0x0D +#define CHAR_O_ACUTE 0x0E +#define CHAR_O_CIRCUMFLEX 0x0F +#define CHAR_OE 0x10 +#define CHAR_U_GRAVE 0x11 +#define CHAR_U_ACUTE 0x12 +#define CHAR_U_CIRCUMFLEX 0x13 +#define CHAR_N_TILDE 0x14 +#define CHAR_ESZETT 0x15 +#define CHAR_a_GRAVE 0x16 +#define CHAR_a_ACUTE 0x17 +//#define CHAR_a_CIRCUMFLEX 0x18 // Is 0x68 instead +#define CHAR_c_CEDILLA 0x19 +#define CHAR_e_GRAVE 0x1A +#define CHAR_e_ACUTE 0x1B +#define CHAR_e_CIRCUMFLEX 0x1C +#define CHAR_e_DIAERESIS 0x1D +#define CHAR_i_GRAVE 0x1E +//#define CHAR_i_ACUTE 0x1F // Is 0x6F instead +#define CHAR_i_CIRCUMFLEX 0x20 +#define CHAR_i_DIAERESIS 0x21 +#define CHAR_o_GRAVE 0x22 +#define CHAR_o_ACUTE 0x23 +#define CHAR_o_CIRCUMFLEX 0x24 +#define CHAR_oe 0x25 +#define CHAR_u_GRAVE 0x26 +#define CHAR_u_ACUTE 0x27 +#define CHAR_u_CIRCUMFLEX 0x28 +#define CHAR_n_TILDE 0x29 +#define CHAR_MASCULINE_ORDINAL 0x2A +#define CHAR_FEMININE_ORDINAL 0x2B +#define CHAR_SUPER_ER 0x2C +#define CHAR_AMPERSAND 0x2D +#define CHAR_PLUS 0x2E +// +#define CHAR_LV 0x34 +#define CHAR_EQUALS 0x35 +#define CHAR_SEMICOLON 0x36 +// +#define CHAR_INV_QUESTION_MARK 0x51 +#define CHAR_INV_EXCL_MARK 0x52 +#define CHAR_PK 0x53 +#define CHAR_MN 0x54 +#define CHAR_PO 0x55 +#define CHAR_KE 0x56 +#define CHAR_BLOCK_1 0x57 // Each of these 3 +#define CHAR_BLOCK_2 0x58 // chars contains 1/3 +#define CHAR_BLOCK_3 0x59 // of the word BLOCK +#define CHAR_I_ACUTE 0x5A +#define CHAR_PERCENT 0x5B +#define CHAR_LEFT_PAREN 0x5C +#define CHAR_RIGHT_PAREN 0x5D +// +#define CHAR_a_CIRCUMFLEX 0x68 +// +#define CHAR_i_ACUTE 0x6F +// +#define CHAR_GENDERLESS 0x77 // Empty space for lack of gender icon +// +#define CHAR_UP_ARROW 0x79 +#define CHAR_DOWN_ARROW 0x7A +#define CHAR_LEFT_ARROW 0x7B +#define CHAR_RIGHT_ARROW 0x7C +// +#define CHAR_SUPER_E 0x84 +#define CHAR_LESS_THAN 0x85 +#define CHAR_GREATER_THAN 0x86 +// +#define CHAR_SUPER_RE 0xA0 +#define CHAR_0 0xA1 +#define CHAR_1 0xA2 +#define CHAR_2 0xA3 +#define CHAR_3 0xA4 +#define CHAR_4 0xA5 +#define CHAR_5 0xA6 +#define CHAR_6 0xA7 +#define CHAR_7 0xA8 +#define CHAR_8 0xA9 +#define CHAR_9 0xAA +#define CHAR_EXCL_MARK 0xAB +#define CHAR_QUESTION_MARK 0xAC +#define CHAR_PERIOD 0xAD +#define CHAR_HYPHEN 0xAE +#define CHAR_BULLET 0xAF +#define CHAR_ELLIPSIS 0xB0 +#define CHAR_DBL_QUOT_LEFT 0xB1 +#define CHAR_DBL_QUOT_RIGHT 0xB2 +#define CHAR_SGL_QUOT_LEFT 0xB3 +#define CHAR_SGL_QUOT_RIGHT 0xB4 +#define CHAR_MALE 0xB5 +#define CHAR_FEMALE 0xB6 +#define CHAR_CURRENCY 0xB7 +#define CHAR_COMMA 0xB8 +#define CHAR_MULT_SIGN 0xB9 +#define CHAR_SLASH 0xBA +#define CHAR_A 0xBB +#define CHAR_B 0xBC +#define CHAR_C 0xBD +#define CHAR_D 0xBE +#define CHAR_E 0xBF +#define CHAR_F 0xC0 +#define CHAR_G 0xC1 +#define CHAR_H 0xC2 +#define CHAR_I 0xC3 +#define CHAR_J 0xC4 +#define CHAR_K 0xC5 +#define CHAR_L 0xC6 +#define CHAR_M 0xC7 +#define CHAR_N 0xC8 +#define CHAR_O 0xC9 +#define CHAR_P 0xCA +#define CHAR_Q 0xCB +#define CHAR_R 0xCC +#define CHAR_S 0xCD +#define CHAR_T 0xCE +#define CHAR_U 0xCF +#define CHAR_V 0xD0 +#define CHAR_W 0xD1 +#define CHAR_X 0xD2 +#define CHAR_Y 0xD3 +#define CHAR_Z 0xD4 +#define CHAR_a 0xD5 +#define CHAR_b 0xD6 +#define CHAR_c 0xD7 +#define CHAR_d 0xD8 +#define CHAR_e 0xD9 +#define CHAR_f 0xDA +#define CHAR_g 0xDB +#define CHAR_h 0xDC +#define CHAR_i 0xDD +#define CHAR_j 0xDE +#define CHAR_k 0xDF +#define CHAR_l 0xE0 +#define CHAR_m 0xE1 +#define CHAR_n 0xE2 +#define CHAR_o 0xE3 +#define CHAR_p 0xE4 +#define CHAR_q 0xE5 +#define CHAR_r 0xE6 +#define CHAR_s 0xE7 +#define CHAR_t 0xE8 +#define CHAR_u 0xE9 +#define CHAR_v 0xEA +#define CHAR_w 0xEB +#define CHAR_x 0xEC +#define CHAR_y 0xED +#define CHAR_z 0xEE +#define CHAR_BLACK_TRIANGLE 0xEF +#define CHAR_COLON 0xF0 +#define CHAR_A_DIAERESIS 0xF1 +#define CHAR_O_DIAERESIS 0xF2 +#define CHAR_U_DIAERESIS 0xF3 +#define CHAR_a_DIAERESIS 0xF4 +#define CHAR_o_DIAERESIS 0xF5 +#define CHAR_u_DIAERESIS 0xF6 +#define CHAR_DYNAMIC 0xF7 +#define CHAR_KEYPAD_ICON 0xF8 +#define CHAR_EXTRA_SYMBOL 0xF9 +#define CHAR_PROMPT_SCROLL 0xFA // waits for button press and scrolls dialog +#define CHAR_PROMPT_CLEAR 0xFB // waits for button press and clears dialog +#define EXT_CTRL_CODE_BEGIN 0xFC // extended control code +#define PLACEHOLDER_BEGIN 0xFD // string placeholder +#define CHAR_NEWLINE 0xFE +#define EOS 0xFF // end of string + +// CHAR_KEYPAD_ICON chars +#define CHAR_A_BUTTON 0x00 +#define CHAR_B_BUTTON 0x01 +#define CHAR_L_BUTTON 0x02 +#define CHAR_R_BUTTON 0x03 +#define CHAR_START_BUTTON 0x04 +#define CHAR_SELECT_BUTTON 0x05 +#define CHAR_DPAD_UP 0x06 +#define CHAR_DPAD_DOWN 0x07 +#define CHAR_DPAD_LEFT 0x08 +#define CHAR_DPAD_RIGHT 0x09 +#define CHAR_DPAD_UPDOWN 0x0A +#define CHAR_DPAD_LEFTRIGHT 0x0B +#define CHAR_DPAD_NONE 0x0C + +// CHAR_EXTRA_SYMBOL chars +#define CHAR_UP_ARROW_2 0x00 +#define CHAR_DOWN_ARROW_2 0x01 +#define CHAR_LEFT_ARROW_2 0x02 +#define CHAR_RIGHT_ARROW_2 0x03 +#define CHAR_PLUS_2 0x04 +#define CHAR_LV_2 0x05 +#define CHAR_PP 0x06 +#define CHAR_ID 0x07 +#define CHAR_NO 0x08 +#define CHAR_UNDERSCORE 0x09 + +#define EXT_CTRL_CODE_COLOR 0x01 +#define EXT_CTRL_CODE_HIGHLIGHT 0x02 +#define EXT_CTRL_CODE_SHADOW 0x03 +#define EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW 0x04 +#define EXT_CTRL_CODE_PALETTE 0x05 +#define EXT_CTRL_CODE_SIZE 0x06 +#define EXT_CTRL_CODE_RESET_SIZE 0x07 +#define EXT_CTRL_CODE_PAUSE 0x08 +#define EXT_CTRL_CODE_PAUSE_UNTIL_PRESS 0x09 +#define EXT_CTRL_CODE_WAIT_SE 0x0A +#define EXT_CTRL_CODE_PLAY_BGM 0x0B +#define EXT_CTRL_CODE_ESCAPE 0x0C +#define EXT_CTRL_CODE_SHIFT_TEXT 0x0D +#define EXT_CTRL_CODE_SHIFT_DOWN 0x0E +#define EXT_CTRL_CODE_FILL_WINDOW 0x0F +#define EXT_CTRL_CODE_PLAY_SE 0x10 +#define EXT_CTRL_CODE_CLEAR 0x11 +#define EXT_CTRL_CODE_SKIP 0x12 +#define EXT_CTRL_CODE_CLEAR_TO 0x13 +#define EXT_CTRL_CODE_MIN_LETTER_SPACING 0x14 +#define EXT_CTRL_CODE_JPN 0x15 +#define EXT_CTRL_CODE_ENG 0x16 +#define EXT_CTRL_CODE_PAUSE_MUSIC 0x17 +#define EXT_CTRL_CODE_RESUME_MUSIC 0x18 + +#define TEXT_COLOR_TRANSPARENT 0x0 +#define TEXT_COLOR_WHITE 0x1 +#define TEXT_COLOR_DARK_GRAY 0x2 +#define TEXT_COLOR_LIGHT_GRAY 0x3 +#define TEXT_COLOR_RED 0x4 +#define TEXT_COLOR_LIGHT_RED 0x5 +#define TEXT_COLOR_GREEN 0x6 +#define TEXT_COLOR_LIGHT_GREEN 0x7 +#define TEXT_COLOR_BLUE 0x8 +#define TEXT_COLOR_LIGHT_BLUE 0x9 +#define TEXT_DYNAMIC_COLOR_1 0xA // Usually white +#define TEXT_DYNAMIC_COLOR_2 0xB // Usually white w/ tinge of green +#define TEXT_DYNAMIC_COLOR_3 0xC // Usually white +#define TEXT_DYNAMIC_COLOR_4 0xD // Usually aquamarine +#define TEXT_DYNAMIC_COLOR_5 0xE // Usually blue-green +#define TEXT_DYNAMIC_COLOR_6 0xF // Usually cerulean + +#define PLACEHOLDER_ID_UNKNOWN 0x0 +#define PLACEHOLDER_ID_PLAYER 0x1 +#define PLACEHOLDER_ID_STRING_VAR_1 0x2 +#define PLACEHOLDER_ID_STRING_VAR_2 0x3 +#define PLACEHOLDER_ID_STRING_VAR_3 0x4 +#define PLACEHOLDER_ID_KUN 0x5 +#define PLACEHOLDER_ID_RIVAL 0x6 +#define PLACEHOLDER_ID_VERSION 0x7 +#define PLACEHOLDER_ID_AQUA 0x8 +#define PLACEHOLDER_ID_MAGMA 0x9 +#define PLACEHOLDER_ID_ARCHIE 0xA +#define PLACEHOLDER_ID_MAXIE 0xB +#define PLACEHOLDER_ID_KYOGRE 0xC +#define PLACEHOLDER_ID_GROUDON 0xD + +// battle placeholders are located in battle_message.h + +#define NUM_TEXT_PRINTERS 32 + +#define TEXT_SPEED_FF 0xFF + +enum +{ + FONTATTR_MAX_LETTER_WIDTH, + FONTATTR_MAX_LETTER_HEIGHT, + FONTATTR_LETTER_SPACING, + FONTATTR_LINE_SPACING, + FONTATTR_UNKNOWN, // dunno what this is yet + FONTATTR_COLOR_FOREGROUND, + FONTATTR_COLOR_BACKGROUND, + FONTATTR_COLOR_SHADOW +}; + +struct TextPrinterSubStruct +{ + u8 glyphId:4; // 0x14 + bool8 hasPrintBeenSpedUp:1; + u8 unk:3; + u8 downArrowDelay:5; + u8 downArrowYPosIdx:2; + bool8 hasGlyphIdBeenSet:1; + u8 autoScrollDelay; +}; + +struct TextPrinterTemplate +{ + const u8* currentChar; + u8 windowId; + u8 fontId; + u8 x; + u8 y; + u8 currentX; // 0x8 + u8 currentY; + u8 letterSpacing; + u8 lineSpacing; + u8 unk:4; // 0xC + u8 fgColor:4; + u8 bgColor:4; + u8 shadowColor:4; +}; + +struct TextPrinter +{ + struct TextPrinterTemplate printerTemplate; + + void (*callback)(struct TextPrinterTemplate *, u16); // 0x10 + + u8 subStructFields[7]; // always cast to struct TextPrinterSubStruct... so why bother + u8 active; + u8 state; // 0x1C + u8 textSpeed; + u8 delayCounter; + u8 scrollDistance; + u8 minLetterSpacing; // 0x20 + u8 japanese; +}; + +struct FontInfo +{ + u16 (*fontFunction)(struct TextPrinter *x); + u8 maxLetterWidth; + u8 maxLetterHeight; + u8 letterSpacing; + u8 lineSpacing; + u8 unk:4; + u8 fgColor:4; + u8 bgColor:4; + u8 shadowColor:4; +}; + +extern const struct FontInfo *gFonts; + +struct GlyphWidthFunc +{ + u32 fontId; + u32 (*func)(u16 glyphId, bool32 isJapanese); +}; + +struct KeypadIcon +{ + u16 tileOffset; + u8 width; + u8 height; +}; + +typedef struct { + bool8 canABSpeedUpPrint:1; + bool8 useAlternateDownArrow:1; + bool8 autoScroll:1; + bool8 forceMidTextSpeed:1; +} TextFlags; + +struct TextGlyph +{ + u32 gfxBufferTop[16]; + u32 gfxBufferBottom[16]; + u8 width; + u8 height; +}; + +extern TextFlags gTextFlags; + +extern u8 gDisableTextPrinters; +extern struct TextGlyph gCurGlyph; + +void SetFontsPointer(const struct FontInfo *fonts); +void DeactivateAllTextPrinters(void); +u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); +bool16 AddTextPrinter(struct TextPrinterTemplate *template, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); +void RunTextPrinters(void); +bool16 IsTextPrinterActive(u8 id); +u32 RenderFont(struct TextPrinter *textPrinter); +void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor); +void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); +void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); +void DecompressGlyphTile(const void *src_, void *dest_); +u8 GetLastTextColor(u8 colorType); +void CopyGlyphToWindow(struct TextPrinter *x); +void ClearTextSpan(struct TextPrinter *textPrinter, u32 width); +u8 GetMenuCursorDimensionByFont(u8, u8); + +u16 Font0Func(struct TextPrinter *textPrinter); +u16 Font1Func(struct TextPrinter *textPrinter); +u16 Font2Func(struct TextPrinter *textPrinter); +u16 Font3Func(struct TextPrinter *textPrinter); +u16 Font4Func(struct TextPrinter *textPrinter); +u16 Font5Func(struct TextPrinter *textPrinter); +u16 Font7Func(struct TextPrinter *textPrinter); +u16 Font8Func(struct TextPrinter *textPrinter); + +void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter); +void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter); +void TextPrinterClearDownArrow(struct TextPrinter *textPrinter); +bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter); +bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter); +bool16 TextPrinterWait(struct TextPrinter *textPrinter); +void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex); +u16 RenderText(struct TextPrinter *textPrinter); +u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing); +u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32); +s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing); +u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str); +u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y); +u8 GetKeypadIconTileOffset(u8 keypadIconId); +u8 GetKeypadIconWidth(u8 keypadIconId); +u8 GetKeypadIconHeight(u8 keypadIconId); +void SetDefaultFontsPointer(void); +u8 GetFontAttribute(u8 fontId, u8 attributeId); +u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension); +void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese); +u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese); +void DecompressGlyphFont9(u16 glyphId); + +// unk_text_util_2.c +u16 Font6Func(struct TextPrinter *textPrinter); +u32 GetGlyphWidthFont6(u16 glyphId, bool32 isJapanese); + +#endif // GUARD_TEXT_H diff --git a/gflib/window.c b/gflib/window.c new file mode 100644 index 000000000..b03b513da --- /dev/null +++ b/gflib/window.c @@ -0,0 +1,721 @@ +#include "global.h" +#include "window.h" +#include "malloc.h" +#include "bg.h" +#include "blit.h" + +u32 gUnusedWindowVar1; +u32 gUnusedWindowVar2; +// This global is set to 0 and never changed. +u8 gTransparentTileNumber; +u32 gUnusedWindowVar3; +void *gWindowBgTilemapBuffers[NUM_BACKGROUNDS]; +extern u32 gUnneededFireRedVariable; + +#define WINDOWS_MAX 32 + +EWRAM_DATA struct Window gWindows[WINDOWS_MAX] = {0}; +EWRAM_DATA static struct Window* sWindowPtr = NULL; +EWRAM_DATA static u16 sWindowSize = 0; + +static u8 GetNumActiveWindowsOnBg(u8 bgId); +static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId); + +static const struct WindowTemplate sDummyWindowTemplate = DUMMY_WIN_TEMPLATE; + +static void DummyWindowBgTilemap(void) +{ + +} + +bool16 InitWindows(const struct WindowTemplate *templates) +{ + int i; + void *bgTilemapBuffer; + int j; + u8 bgLayer; + u16 attrib; + u8* allocatedTilemapBuffer; + int allocatedBaseBlock; + + for (i = 0; i < NUM_BACKGROUNDS; ++i) + { + bgTilemapBuffer = GetBgTilemapBuffer(i); + if (bgTilemapBuffer != NULL) + gWindowBgTilemapBuffers[i] = DummyWindowBgTilemap; + else + gWindowBgTilemapBuffers[i] = bgTilemapBuffer; + } + + for (i = 0; i < WINDOWS_MAX; ++i) + { + gWindows[i].window = sDummyWindowTemplate; + gWindows[i].tileData = NULL; + } + + for (i = 0, allocatedBaseBlock = 0, bgLayer = templates[i].bg; bgLayer != 0xFF && i < WINDOWS_MAX; ++i, bgLayer = templates[i].bg) + { + if (gUnneededFireRedVariable == 1) + { + allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, templates[i].width * templates[i].height, 0); + if (allocatedBaseBlock == -1) + return FALSE; + } + + if (gWindowBgTilemapBuffers[bgLayer] == NULL) + { + attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); + + if (attrib != 0xFFFF) + { + allocatedTilemapBuffer = AllocZeroed(attrib); + + if (allocatedTilemapBuffer == NULL) + { + FreeAllWindowBuffers(); + return FALSE; + } + + for (j = 0; j < attrib; ++j) + allocatedTilemapBuffer[j] = 0; + + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); + } + } + + allocatedTilemapBuffer = AllocZeroed((u16)(32 * (templates[i].width * templates[i].height))); + + if (allocatedTilemapBuffer == NULL) + { + if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + } + + return FALSE; + } + + gWindows[i].tileData = allocatedTilemapBuffer; + gWindows[i].window = templates[i]; + + if (gUnneededFireRedVariable == 1) + { + gWindows[i].window.baseBlock = allocatedBaseBlock; + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, templates[i].width * templates[i].height, 1); + } + } + + gTransparentTileNumber = 0; + return TRUE; +} + +u16 AddWindow(const struct WindowTemplate *template) +{ + u16 win; + u8 bgLayer; + int allocatedBaseBlock; + u16 attrib; + u8 *allocatedTilemapBuffer; + int i; + + for (win = 0; win < WINDOWS_MAX; ++win) + { + if ((bgLayer = gWindows[win].window.bg) == 0xFF) + break; + } + + if (win == WINDOWS_MAX) + return WINDOW_NONE; + + bgLayer = template->bg; + allocatedBaseBlock = 0; + + if (gUnneededFireRedVariable == 1) + { + allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); + + if (allocatedBaseBlock == -1) + return WINDOW_NONE; + } + + if (gWindowBgTilemapBuffers[bgLayer] == NULL) + { + attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); + + if (attrib != 0xFFFF) + { + allocatedTilemapBuffer = AllocZeroed(attrib); + + if (allocatedTilemapBuffer == NULL) + return WINDOW_NONE; + + for (i = 0; i < attrib; ++i) + allocatedTilemapBuffer[i] = 0; + + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); + } + } + + allocatedTilemapBuffer = AllocZeroed((u16)(32 * (template->width * template->height))); + + if (allocatedTilemapBuffer == NULL) + { + if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; + } + return WINDOW_NONE; + } + + gWindows[win].tileData = allocatedTilemapBuffer; + gWindows[win].window = *template; + + if (gUnneededFireRedVariable == 1) + { + gWindows[win].window.baseBlock = allocatedBaseBlock; + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); + } + + return win; +} + +int AddWindowWithoutTileMap(const struct WindowTemplate *template) +{ + u16 win; + u8 bgLayer; + int allocatedBaseBlock; + + for (win = 0; win < WINDOWS_MAX; ++win) + { + if (gWindows[win].window.bg == 0xFF) + break; + } + + if (win == WINDOWS_MAX) + return WINDOW_NONE; + + bgLayer = template->bg; + allocatedBaseBlock = 0; + + if (gUnneededFireRedVariable == 1) + { + allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); + + if (allocatedBaseBlock == -1) + return WINDOW_NONE; + } + + gWindows[win].window = *template; + + if (gUnneededFireRedVariable == 1) + { + gWindows[win].window.baseBlock = allocatedBaseBlock; + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); + } + + return win; +} + +void RemoveWindow(u8 windowId) +{ + u8 bgLayer = gWindows[windowId].window.bg; + + if (gUnneededFireRedVariable == 1) + { + DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, gWindows[windowId].window.baseBlock, gWindows[windowId].window.width * gWindows[windowId].window.height, 2); + } + + gWindows[windowId].window = sDummyWindowTemplate; + + if (GetNumActiveWindowsOnBg(bgLayer) == 0) + { + if (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = NULL; + } + } + + if (gWindows[windowId].tileData != NULL) + { + Free(gWindows[windowId].tileData); + gWindows[windowId].tileData = NULL; + } +} + +void FreeAllWindowBuffers(void) +{ + int i; + + for (i = 0; i < NUM_BACKGROUNDS; ++i) + { + if (gWindowBgTilemapBuffers[i] != NULL && gWindowBgTilemapBuffers[i] != DummyWindowBgTilemap) + { + Free(gWindowBgTilemapBuffers[i]); + gWindowBgTilemapBuffers[i] = NULL; + } + } + + for (i = 0; i < WINDOWS_MAX; ++i) + { + if (gWindows[i].tileData != NULL) + { + Free(gWindows[i].tileData); + gWindows[i].tileData = NULL; + } + } +} + +void CopyWindowToVram(u8 windowId, u8 mode) +{ + struct Window windowLocal = gWindows[windowId]; + u16 windowSize = 32 * (windowLocal.window.width * windowLocal.window.height); + + switch (mode) + { + case 1: + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + case 2: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); + break; + case 3: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + } +} + +void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h) +{ + struct Window windowLocal; + int rectSize; + int rectPos; + + if (w != 0 && h != 0) + { + windowLocal = gWindows[windowId]; + + rectSize = ((h - 1) * windowLocal.window.width); + rectSize += (windowLocal.window.width - x); + rectSize -= (windowLocal.window.width - (x + w)); + rectSize *= 32; + + rectPos = (y * windowLocal.window.width) + x; + + switch (mode) + { + case 1: + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + case 2: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); + break; + case 3: + LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); + CopyBgTilemapBufferToVram(windowLocal.window.bg); + break; + } + } +} + +void PutWindowTilemap(u8 windowId) +{ + struct Window windowLocal = gWindows[windowId]; + + WriteSequenceToBgTilemapBuffer( + windowLocal.window.bg, + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE) + windowLocal.window.baseBlock, + windowLocal.window.tilemapLeft, + windowLocal.window.tilemapTop, + windowLocal.window.width, + windowLocal.window.height, + windowLocal.window.paletteNum, + 1); +} + +void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette) +{ + struct Window windowLocal = gWindows[windowId]; + u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); + int i; + + for (i = 0; i < height; ++i) + { + WriteSequenceToBgTilemapBuffer( + windowLocal.window.bg, + currentRow, + windowLocal.window.tilemapLeft + x, + windowLocal.window.tilemapTop + y + i, + width, + 1, + palette, + 1); + + currentRow += windowLocal.window.width; + } +} + +// Fills a window with transparent tiles. +void ClearWindowTilemap(u8 windowId) +{ + struct Window windowLocal = gWindows[windowId]; + + FillBgTilemapBufferRect( + windowLocal.window.bg, + gTransparentTileNumber, + windowLocal.window.tilemapLeft, + windowLocal.window.tilemapTop, + windowLocal.window.width, + windowLocal.window.height, + windowLocal.window.paletteNum); +} + +void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) +{ + struct Window windowLocal = gWindows[windowId]; + u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); + int i; + + for (i = 0; i < height; ++i) + { + WriteSequenceToBgTilemapBuffer( + windowLocal.window.bg, + currentRow, + windowLocal.window.tilemapLeft + x, + windowLocal.window.tilemapTop + y + i, + width, + 1, + windowLocal.window.paletteNum, + 1); + + currentRow += windowLocal.window.width; + } +} + +void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height) +{ + BlitBitmapRectToWindow(windowId, pixels, 0, 0, width, height, x, y, width, height); +} + +void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight) +{ + struct Bitmap sourceRect; + struct Bitmap destRect; + + sourceRect.pixels = (u8*)pixels; + sourceRect.width = srcWidth; + sourceRect.height = srcHeight; + + destRect.pixels = gWindows[windowId].tileData; + destRect.width = 8 * gWindows[windowId].window.width; + destRect.height = 8 * gWindows[windowId].window.height; + + BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0); +} + +static void BlitBitmapRectToWindowWithColorKey(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 colorKey) +{ + struct Bitmap sourceRect; + struct Bitmap destRect; + + sourceRect.pixels = (u8*)pixels; + sourceRect.width = srcWidth; + sourceRect.height = srcHeight; + + destRect.pixels = gWindows[windowId].tileData; + destRect.width = 8 * gWindows[windowId].window.width; + destRect.height = 8 * gWindows[windowId].window.height; + + BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, colorKey); +} + +void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) +{ + struct Bitmap pixelRect; + + pixelRect.pixels = gWindows[windowId].tileData; + pixelRect.width = 8 * gWindows[windowId].window.width; + pixelRect.height = 8 * gWindows[windowId].window.height; + + FillBitmapRect4Bit(&pixelRect, x, y, width, height, fillValue); +} + +void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset) +{ + if (size != 0) + CpuCopy16(src, gWindows[windowId].tileData + (32 * tileOffset), size); + else + LZ77UnCompWram(src, gWindows[windowId].tileData + (32 * tileOffset)); +} + +// Sets all pixels within the window to the fillValue color. +void FillWindowPixelBuffer(u8 windowId, u8 fillValue) +{ + int fillSize = gWindows[windowId].window.width * gWindows[windowId].window.height; + CpuFastFill8(fillValue, gWindows[windowId].tileData, 32 * fillSize); +} + +#define MOVE_TILES_DOWN(a) \ +{ \ + destOffset = i + (a); \ + srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ + if (srcOffset < size) \ + *(u32*)(tileData + destOffset) = *(u32*)(tileData + srcOffset); \ + else \ + *(u32*)(tileData + destOffset) = fillValue32; \ + distanceLoop++; \ +} + +#define MOVE_TILES_UP(a) \ +{ \ + destOffset = i + (a); \ + srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ + if (srcOffset < size) \ + *(u32*)(tileData - destOffset) = *(u32*)(tileData - srcOffset); \ + else \ + *(u32*)(tileData - destOffset) = fillValue32; \ + distanceLoop++; \ +} + +void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue) +{ + struct WindowTemplate window = gWindows[windowId].window; + u8 *tileData = gWindows[windowId].tileData; + u32 fillValue32 = (fillValue << 24) | (fillValue << 16) | (fillValue << 8) | fillValue; + s32 size = window.height * window.width * 32; + u32 width = window.width; + s32 i; + s32 srcOffset, destOffset; + u32 distanceLoop; + + switch (direction) + { + case 0: + for (i = 0; i < size; i += 32) + { + distanceLoop = distance; + MOVE_TILES_DOWN(0) + MOVE_TILES_DOWN(4) + MOVE_TILES_DOWN(8) + MOVE_TILES_DOWN(12) + MOVE_TILES_DOWN(16) + MOVE_TILES_DOWN(20) + MOVE_TILES_DOWN(24) + MOVE_TILES_DOWN(28) + } + break; + case 1: + tileData += size - 4; + for (i = 0; i < size; i += 32) + { + distanceLoop = distance; + MOVE_TILES_UP(0) + MOVE_TILES_UP(4) + MOVE_TILES_UP(8) + MOVE_TILES_UP(12) + MOVE_TILES_UP(16) + MOVE_TILES_UP(20) + MOVE_TILES_UP(24) + MOVE_TILES_UP(28) + } + break; + case 2: + break; + } +} + +void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)) +{ + struct WindowTemplate window = gWindows[windowId].window; + func(window.bg, window.tilemapLeft, window.tilemapTop, window.width, window.height, window.paletteNum); +} + +bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value) +{ + switch (attributeId) + { + case WINDOW_TILEMAP_LEFT: + gWindows[windowId].window.tilemapLeft = value; + return FALSE; + case WINDOW_TILEMAP_TOP: + gWindows[windowId].window.tilemapTop = value; + return FALSE; + case WINDOW_PALETTE_NUM: + gWindows[windowId].window.paletteNum = value; + return FALSE; + case WINDOW_BASE_BLOCK: + gWindows[windowId].window.baseBlock = value; + return FALSE; + case WINDOW_TILE_DATA: + gWindows[windowId].tileData = (u8*)(value); + return TRUE; + case WINDOW_BG: + case WINDOW_WIDTH: + case WINDOW_HEIGHT: + default: + return TRUE; + } +} + +u32 GetWindowAttribute(u8 windowId, u8 attributeId) +{ + switch (attributeId) + { + case WINDOW_BG: + return gWindows[windowId].window.bg; + case WINDOW_TILEMAP_LEFT: + return gWindows[windowId].window.tilemapLeft; + case WINDOW_TILEMAP_TOP: + return gWindows[windowId].window.tilemapTop; + case WINDOW_WIDTH: + return gWindows[windowId].window.width; + case WINDOW_HEIGHT: + return gWindows[windowId].window.height; + case WINDOW_PALETTE_NUM: + return gWindows[windowId].window.paletteNum; + case WINDOW_BASE_BLOCK: + return gWindows[windowId].window.baseBlock; + case WINDOW_TILE_DATA: + return (u32)(gWindows[windowId].tileData); + default: + return 0; + } +} + +static u8 GetNumActiveWindowsOnBg(u8 bgId) +{ + u8 windowsNum = 0; + s32 i; + for (i = 0; i < WINDOWS_MAX; i++) + { + if (gWindows[i].window.bg == bgId) + windowsNum++; + } + return windowsNum; +} + +static void DummyWindowBgTilemap8Bit(void) +{ + +} + +u16 AddWindow8Bit(const struct WindowTemplate *template) +{ + u16 windowId; + u8* memAddress; + u8 bgLayer; + + for (windowId = 0; windowId < WINDOWS_MAX; windowId++) + { + if (gWindows[windowId].window.bg == 0xFF) + break; + } + if (windowId == WINDOWS_MAX) + return WINDOW_NONE; + bgLayer = template->bg; + if (gWindowBgTilemapBuffers[bgLayer] == NULL) + { + u16 attribute = GetBgAttribute(bgLayer, BG_ATTR_METRIC); + if (attribute != 0xFFFF) + { + s32 i; + memAddress = Alloc(attribute); + if (memAddress == NULL) + return WINDOW_NONE; + for (i = 0; i < attribute; i++) // if we're going to zero out the memory anyway, why not call AllocZeroed? + memAddress[i] = 0; + gWindowBgTilemapBuffers[bgLayer] = memAddress; + SetBgTilemapBuffer(bgLayer, memAddress); + } + } + memAddress = Alloc((u16)(64 * (template->width * template->height))); + if (memAddress == NULL) + { + if (GetNumActiveWindowsOnBg8Bit(bgLayer) == 0 && gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap8Bit) + { + Free(gWindowBgTilemapBuffers[bgLayer]); + gWindowBgTilemapBuffers[bgLayer] = NULL; + } + return WINDOW_NONE; + } + else + { + gWindows[windowId].tileData = memAddress; + gWindows[windowId].window = *template; + return windowId; + } +} + +void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue) +{ + s32 i; + s32 size; + + size = (u16)(64 * (gWindows[windowId].window.width * gWindows[windowId].window.height)); + for (i = 0; i < size; i++) + gWindows[windowId].tileData[i] = fillValue; +} + +void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) +{ + struct Bitmap pixelRect; + + pixelRect.pixels = gWindows[windowId].tileData; + pixelRect.width = 8 * gWindows[windowId].window.width; + pixelRect.height = 8 * gWindows[windowId].window.height; + + FillBitmapRect8Bit(&pixelRect, x, y, width, height, fillValue); +} + +void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum) +{ + struct Bitmap sourceRect; + struct Bitmap destRect; + + sourceRect.pixels = (u8*) pixels; + sourceRect.width = srcWidth; + sourceRect.height = srcHeight; + + destRect.pixels = gWindows[windowId].tileData; + destRect.width = 8 * gWindows[windowId].window.width; + destRect.height = 8 * gWindows[windowId].window.height; + + BlitBitmapRect4BitTo8Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0, paletteNum); +} + +void CopyWindowToVram8Bit(u8 windowId, u8 mode) +{ + sWindowPtr = &gWindows[windowId]; + sWindowSize = 64 * (sWindowPtr->window.width * sWindowPtr->window.height); + + switch (mode) + { + case 1: + CopyBgTilemapBufferToVram(sWindowPtr->window.bg); + break; + case 2: + LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + break; + case 3: + LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + CopyBgTilemapBufferToVram(sWindowPtr->window.bg); + break; + } +} + +static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId) +{ + u8 windowsNum = 0; + s32 i; + for (i = 0; i < WINDOWS_MAX; i++) + { + if (gWindows[i].window.bg == bgId) + windowsNum++; + } + return windowsNum; +} diff --git a/gflib/window.h b/gflib/window.h new file mode 100644 index 000000000..3eac75a28 --- /dev/null +++ b/gflib/window.h @@ -0,0 +1,80 @@ +#ifndef GUARD_WINDOW_H +#define GUARD_WINDOW_H + +#define PIXEL_FILL(num) ((num) | ((num) << 4)) + +enum +{ + WINDOW_BG, + WINDOW_TILEMAP_LEFT, + WINDOW_TILEMAP_TOP, + WINDOW_WIDTH, + WINDOW_HEIGHT, + WINDOW_PALETTE_NUM, + WINDOW_BASE_BLOCK, + WINDOW_TILE_DATA +}; + +struct WindowTemplate +{ + u8 bg; + u8 tilemapLeft; + u8 tilemapTop; + u8 width; + u8 height; + u8 paletteNum; + u16 baseBlock; +}; + +#define DUMMY_WIN_TEMPLATE \ +{ \ + 0xFF, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ +} + +#define WINDOW_NONE 0xFF + +struct Window +{ + struct WindowTemplate window; + u8 *tileData; +}; + +bool16 InitWindows(const struct WindowTemplate *templates); +u16 AddWindow(const struct WindowTemplate *template); +int AddWindowWithoutTileMap(const struct WindowTemplate *template); +void RemoveWindow(u8 windowId); +void FreeAllWindowBuffers(void); +void CopyWindowToVram(u8 windowId, u8 mode); +void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h); +void PutWindowTilemap(u8 windowId); +void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette); +void ClearWindowTilemap(u8 windowId); +void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height); +void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height); +void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight); +void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); +void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset); +void FillWindowPixelBuffer(u8 windowId, u8 fillValue); +void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue); +void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)); +bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value); +u32 GetWindowAttribute(u8 windowId, u8 attributeId); +u16 AddWindow8Bit(const struct WindowTemplate *template); +void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue); +void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); +void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum); +void CopyWindowToVram8Bit(u8 windowId, u8 mode); + +extern struct Window gWindows[]; +extern void* gWindowBgTilemapBuffers[]; +extern u32 gUnusedWindowVar1; +extern u32 gUnusedWindowVar2; +extern u32 gUnusedWindowVar3; + +#endif // GUARD_WINDOW_H diff --git a/include/bg.h b/include/bg.h deleted file mode 100644 index 58fd1282c..000000000 --- a/include/bg.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef GUARD_BG_H -#define GUARD_BG_H - -struct BGCntrlBitfield // for the I/O registers -{ - volatile u16 priority:2; - volatile u16 charBaseBlock:2; - volatile u16 field_0_2:4; - volatile u16 field_1_0:5; - volatile u16 areaOverflowMode:1; - volatile u16 screenSize:2; -}; - -enum -{ - BG_ATTR_CHARBASEINDEX = 1, - BG_ATTR_MAPBASEINDEX, - BG_ATTR_SCREENSIZE, - BG_ATTR_PALETTEMODE, - BG_ATTR_MOSAIC, - BG_ATTR_WRAPAROUND, - BG_ATTR_PRIORITY, - BG_ATTR_METRIC, - BG_ATTR_TYPE, - BG_ATTR_BASETILE, -}; - -struct BgTemplate -{ - u16 bg:2; // 0x1, 0x2 -> 0x3 - u16 charBaseIndex:2; // 0x4, 0x8 -> 0xC - u16 mapBaseIndex:5; // 0x10, 0x20, 0x40, 0x80, 0x100 -> 0x1F0 - u16 screenSize:2; // 0x200, 0x400 -> 0x600 - u16 paletteMode:1; // 0x800 - u16 priority:2; // 0x1000, 0x2000 > 0x3000 - u16 baseTile:10; -}; - -void ResetBgs(void); -u8 GetBgMode(void); -void ResetBgControlStructs(void); -void Unused_ResetBgControlStruct(u8 bg); -u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode); -void SetTextModeAndHideBgs(void); -bool8 IsInvalidBg(u8 bg); -int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4); -void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); -void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates); -void InitBgFromTemplate(const struct BgTemplate *template); -void SetBgMode(u8 bgMode); -u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset); -u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset); -u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset); -bool8 IsDma3ManagerBusyWithBgCopy(void); -void ShowBg(u8 bg); -void HideBg(u8 bg); -void SetBgAttribute(u8 bg, u8 attributeId, u8 value); -u16 GetBgAttribute(u8 bg, u8 attributeId); -s32 ChangeBgX(u8 bg, s32 value, u8 op); -s32 GetBgX(u8 bg); -s32 ChangeBgY(u8 bg, s32 value, u8 op); -s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op); -s32 GetBgY(u8 bg); -void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle); -u8 Unused_AdjustBgMosaic(u8 a1, u8 a2); -void SetBgTilemapBuffer(u8 bg, void *tilemap); -void UnsetBgTilemapBuffer(u8 bg); -void* GetBgTilemapBuffer(u8 bg); -void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset); -void CopyBgTilemapBufferToVram(u8 bg); -void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height); -void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette); -void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset); -void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height); -void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette); -void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta); -u16 GetBgMetricTextMode(u8 bg, u8 whichMetric); -u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric); -u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight); -void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2); -u32 GetBgType(u8 bg); -bool32 IsInvalidBg32(u8 bg); -bool32 IsTileMapOutsideWram(u8 bg); - -#endif // GUARD_BG_H diff --git a/include/blit.h b/include/blit.h deleted file mode 100644 index 78f67766e..000000000 --- a/include/blit.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef GUARD_BLIT_H -#define GUARD_BLIT_H - -struct Bitmap -{ - u8 *pixels; - u32 width:16; - u32 height:16; -}; - -void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height); -void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey); -void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); -void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset); -void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); - -#endif // GUARD_BLIT_H diff --git a/include/dma3.h b/include/dma3.h deleted file mode 100644 index 8eff34f55..000000000 --- a/include/dma3.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef GUARD_DMA3_H -#define GUARD_DMA3_H - -// Maximum amount of data we will transfer in one operation -#define MAX_DMA_BLOCK_SIZE 0x1000 - -#define Dma3CopyLarge_(src, dest, size, bit) \ -{ \ - const void *_src = src; \ - void *_dest = dest; \ - u32 _size = size; \ - while (1) \ - { \ - if (_size <= MAX_DMA_BLOCK_SIZE) \ - { \ - DmaCopy##bit(3, _src, _dest, _size); \ - break; \ - } \ - DmaCopy##bit(3, _src, _dest, MAX_DMA_BLOCK_SIZE); \ - _src += MAX_DMA_BLOCK_SIZE; \ - _dest += MAX_DMA_BLOCK_SIZE; \ - _size -= MAX_DMA_BLOCK_SIZE; \ - } \ -} - -#define Dma3CopyLarge16_(src, dest, size) Dma3CopyLarge_(src, dest, size, 16) -#define Dma3CopyLarge32_(src, dest, size) Dma3CopyLarge_(src, dest, size, 32) - -#define Dma3FillLarge_(value, dest, size, bit) \ -{ \ - void *_dest = dest; \ - u32 _size = size; \ - while (1) \ - { \ - if (_size <= MAX_DMA_BLOCK_SIZE) \ - { \ - DmaFill##bit(3, value, _dest, _size); \ - break; \ - } \ - DmaFill##bit(3, value, _dest, MAX_DMA_BLOCK_SIZE); \ - _dest += MAX_DMA_BLOCK_SIZE; \ - _size -= MAX_DMA_BLOCK_SIZE; \ - } \ -} - -#define Dma3FillLarge16_(value, dest, size) Dma3FillLarge_(value, dest, size, 16) -#define Dma3FillLarge32_(value, dest, size) Dma3FillLarge_(value, dest, size, 32) - -void ClearDma3Requests(void); -void ProcessDma3Requests(void); -s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode); -s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode); -s16 CheckForSpaceForDma3Request(s16 index); - -#endif // GUARD_DMA3_H diff --git a/include/gpu_regs.h b/include/gpu_regs.h deleted file mode 100644 index 89e0cb64b..000000000 --- a/include/gpu_regs.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef GUARD_GPU_REGS_H -#define GUARD_GPU_REGS_H - -// Exported type declarations - -// Exported RAM declarations - -// Exported ROM declarations -void InitGpuRegManager(void); -void CopyBufferedValuesToGpuRegs(void); -void SetGpuReg(u8 regOffset, u16 value); -void SetGpuReg_ForcedBlank(u8 regOffset, u16 value); -u16 GetGpuReg(u8 regOffset); -void SetGpuRegBits(u8 regOffset, u16 mask); -void ClearGpuRegBits(u8 regOffset, u16 mask); -void EnableInterrupts(u16 mask); -void DisableInterrupts(u16 mask); - -#endif //GUARD_GPU_REGS_H diff --git a/include/io_reg.h b/include/io_reg.h deleted file mode 100644 index 82d2fc5ed..000000000 --- a/include/io_reg.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef GUARD_IO_REG_H -#define GUARD_IO_REG_H - -extern const u16 gOverworldBackgroundLayerFlags[]; -extern const u16 gOrbEffectBackgroundLayerFlags[]; - -#endif // GUARD_IO_REG_H diff --git a/include/malloc.h b/include/malloc.h deleted file mode 100644 index f2dcf6d46..000000000 --- a/include/malloc.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef GUARD_ALLOC_H -#define GUARD_ALLOC_H - -#define HEAP_SIZE 0x1C000 -#define malloc Alloc -#define calloc(ct, sz) AllocZeroed((ct) * (sz)) -#define free Free - -#define FREE_AND_SET_NULL(ptr) \ -{ \ - free(ptr); \ - ptr = NULL; \ -} - -extern u8 gHeap[]; - -void *Alloc(u32 size); -void *AllocZeroed(u32 size); -void Free(void *pointer); -void InitHeap(void *pointer, u32 size); - -#endif // GUARD_ALLOC_H diff --git a/include/sprite.h b/include/sprite.h deleted file mode 100644 index 4a3b48225..000000000 --- a/include/sprite.h +++ /dev/null @@ -1,324 +0,0 @@ -#ifndef GUARD_SPRITE_H -#define GUARD_SPRITE_H - -#define MAX_SPRITES 64 -#define SPRITE_NONE 0xFF -#define SPRITE_INVALID_TAG 0xFFFF - -struct SpriteSheet -{ - const void *data; // Raw uncompressed pixel data - u16 size; - u16 tag; -}; - -struct CompressedSpriteSheet -{ - const u32 *data; // LZ77 compressed pixel data - u16 size; // Uncompressed size of pixel data - u16 tag; -}; - -struct SpriteFrameImage -{ - const void *data; - u16 size; -}; - -#define obj_frame_tiles(ptr) {.data = (u8 *)ptr, .size = sizeof ptr} - -#define overworld_frame(ptr, width, height, frame) {.data = (u8 *)ptr + (width * height * frame * 64)/2, .size = (width * height * 64)/2} - -struct SpritePalette -{ - const u16 *data; // Raw uncompressed palette data - u16 tag; -}; - -struct CompressedSpritePalette -{ - const u32 *data; // LZ77 compressed palette data - u16 tag; -}; - -struct AnimFrameCmd -{ - // If the sprite has an array of images, this is the array index. - // If the sprite has a sheet, this is the tile offset. - u32 imageValue:16; - - u32 duration:6; - u32 hFlip:1; - u32 vFlip:1; -}; - -struct AnimLoopCmd -{ - u32 type:16; - u32 count:6; -}; - -struct AnimJumpCmd -{ - u32 type:16; - u32 target:6; -}; - -// The first halfword of this union specifies the type of command. -// If it -2, then it is a jump command. If it is -1, then it is the end of the script. -// Otherwise, it is the imageValue for a frame command. -union AnimCmd -{ - s16 type; - struct AnimFrameCmd frame; - struct AnimLoopCmd loop; - struct AnimJumpCmd jump; -}; - -#define ANIMCMD_FRAME(...) \ - {.frame = {__VA_ARGS__}} -#define ANIMCMD_LOOP(_count) \ - {.loop = {.type = -3, .count = _count}} -#define ANIMCMD_JUMP(_target) \ - {.jump = {.type = -2, .target = _target}} -#define ANIMCMD_END \ - {.type = -1} - -struct AffineAnimFrameCmd -{ - s16 xScale; - s16 yScale; - u8 rotation; - u8 duration; -}; - -struct AffineAnimLoopCmd -{ - s16 type; - s16 count; -}; - -struct AffineAnimJumpCmd -{ - s16 type; - u16 target; -}; - -struct AffineAnimEndCmdAlt -{ - s16 type; - u16 val; -}; - -union AffineAnimCmd -{ - s16 type; - struct AffineAnimFrameCmd frame; - struct AffineAnimLoopCmd loop; - struct AffineAnimJumpCmd jump; - struct AffineAnimEndCmdAlt end; // unused in code -}; - -#define AFFINEANIMCMDTYPE_LOOP 0x7FFD -#define AFFINEANIMCMDTYPE_JUMP 0x7FFE -#define AFFINEANIMCMDTYPE_END 0x7FFF - -#define AFFINEANIMCMD_FRAME(_xScale, _yScale, _rotation, _duration) \ - {.frame = {.xScale = _xScale, .yScale = _yScale, .rotation = _rotation, .duration = _duration}} -#define AFFINEANIMCMD_LOOP(_count) \ - {.loop = {.type = AFFINEANIMCMDTYPE_LOOP, .count = _count}} -#define AFFINEANIMCMD_JUMP(_target) \ - {.jump = {.type = AFFINEANIMCMDTYPE_JUMP, .target = _target}} -#define AFFINEANIMCMD_END \ - {.type = AFFINEANIMCMDTYPE_END} -#define AFFINEANIMCMD_END_ALT(_val) \ - {.end = {.type = AFFINEANIMCMDTYPE_END, .val = _val}} - -struct AffineAnimState -{ - u8 animNum; - u8 animCmdIndex; - u8 delayCounter; - u8 loopCounter; - s16 xScale; - s16 yScale; - u16 rotation; -}; - -enum -{ - SUBSPRITES_OFF, - SUBSPRITES_ON, - SUBSPRITES_IGNORE_PRIORITY, // on but priority is ignored -}; - -struct Subsprite -{ - s8 x; // was u16 in R/S - s8 y; // was u16 in R/S - u16 shape:2; - u16 size:2; - u16 tileOffset:10; - u16 priority:2; -}; - -struct SubspriteTable -{ - u8 subspriteCount; - const struct Subsprite *subsprites; -}; - -struct Sprite; - -typedef void (*SpriteCallback)(struct Sprite *); - -struct SpriteTemplate -{ - u16 tileTag; - u16 paletteTag; - const struct OamData *oam; - const union AnimCmd *const *anims; - const struct SpriteFrameImage *images; - const union AffineAnimCmd *const *affineAnims; - SpriteCallback callback; -}; - -// UB: template pointer is often used to point to temporary storage, -// then later dereferenced after being freed. Usually this won't -// be visible in-game, but this is (part of) what causes the item -// icon palette to flicker when changing items in the bag. -struct Sprite -{ - /*0x00*/ struct OamData oam; - /*0x08*/ const union AnimCmd *const *anims; - /*0x0C*/ const struct SpriteFrameImage *images; - /*0x10*/ const union AffineAnimCmd *const *affineAnims; - /*0x14*/ const struct SpriteTemplate *template; - /*0x18*/ const struct SubspriteTable *subspriteTables; - /*0x1C*/ SpriteCallback callback; - - /*0x20*/ struct Coords16 pos1; - /*0x24*/ struct Coords16 pos2; - /*0x28*/ s8 centerToCornerVecX; - /*0x29*/ s8 centerToCornerVecY; - - /*0x2A*/ u8 animNum; - /*0x2B*/ u8 animCmdIndex; - /*0x2C*/ u8 animDelayCounter:6; - bool8 animPaused:1; - bool8 affineAnimPaused:1; - /*0x2D*/ u8 animLoopCounter; - - // general purpose data fields - /*0x2E*/ s16 data[8]; - - /*0x3E*/ bool16 inUse:1; //1 - bool16 coordOffsetEnabled:1; //2 - bool16 invisible:1; //4 - bool16 flags_3:1; //8 - bool16 flags_4:1; //0x10 - bool16 flags_5:1; //0x20 - bool16 flags_6:1; //0x40 - bool16 flags_7:1; //0x80 - /*0x3F*/ bool16 hFlip:1; //1 - bool16 vFlip:1; //2 - bool16 animBeginning:1; //4 - bool16 affineAnimBeginning:1; //8 - bool16 animEnded:1; //0x10 - bool16 affineAnimEnded:1; //0x20 - bool16 usingSheet:1; //0x40 - bool16 flags_f:1; //0x80 - - /*0x40*/ u16 sheetTileStart; - - /*0x42*/ u8 subspriteTableNum:6; - u8 subspriteMode:2; - - /*0x43*/ u8 subpriority; -}; - -struct OamMatrix -{ - s16 a; - s16 b; - s16 c; - s16 d; -}; - -extern const struct OamData gDummyOamData; -extern const union AnimCmd *const gDummySpriteAnimTable[]; -extern const union AffineAnimCmd *const gDummySpriteAffineAnimTable[]; -extern const struct SpriteTemplate gDummySpriteTemplate; - -extern u8 gReservedSpritePaletteCount; -extern struct Sprite gSprites[]; -extern u8 gOamLimit; -extern u16 gReservedSpriteTileCount; -extern s16 gSpriteCoordOffsetX; -extern s16 gSpriteCoordOffsetY; -extern struct OamMatrix gOamMatrices[]; -extern bool8 gAffineAnimsDisabled; - -void ResetSpriteData(void); -void AnimateSprites(void); -void BuildOamBuffer(void); -u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)); -u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -void DestroySprite(struct Sprite *sprite); -void ResetOamRange(u8 a, u8 b); -void LoadOam(void); -void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d); -void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode); -void SpriteCallbackDummy(struct Sprite *sprite); -void ProcessSpriteCopyRequests(void); -void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size); -void FreeSpriteTiles(struct Sprite *sprite); -void FreeSpritePalette(struct Sprite *sprite); -void FreeSpriteOamMatrix(struct Sprite *sprite); -void DestroySpriteAndFreeResources(struct Sprite *sprite); -void sub_800142C(u32 a1, u32 a2, u16 *a3, u16 a4, u32 a5); -void AnimateSprite(struct Sprite *sprite); -void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3); -void StartSpriteAnim(struct Sprite *sprite, u8 animNum); -void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum); -void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex); -void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum); -void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); -void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum); -void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum); -void SetSpriteSheetFrameTileNum(struct Sprite *sprite); -u8 AllocOamMatrix(void); -void FreeOamMatrix(u8 matrixNum); -void InitSpriteAffineAnim(struct Sprite *sprite); -void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation); -u16 LoadSpriteSheet(const struct SpriteSheet *sheet); -void LoadSpriteSheets(const struct SpriteSheet *sheets); -u16 AllocTilesForSpriteSheet(struct SpriteSheet *sheet); -void AllocTilesForSpriteSheets(struct SpriteSheet *sheets); -void LoadTilesForSpriteSheet(const struct SpriteSheet *sheet); -void LoadTilesForSpriteSheets(struct SpriteSheet *sheets); -void FreeSpriteTilesByTag(u16 tag); -void FreeSpriteTileRanges(void); -u16 GetSpriteTileStartByTag(u16 tag); -u16 GetSpriteTileTagByTileStart(u16 start); -void RequestSpriteSheetCopy(const struct SpriteSheet *sheet); -u16 LoadSpriteSheetDeferred(const struct SpriteSheet *sheet); -void FreeAllSpritePalettes(void); -u8 LoadSpritePalette(const struct SpritePalette *palette); -void LoadSpritePalettes(const struct SpritePalette *palettes); -u8 AllocSpritePalette(u16 tag); -u8 IndexOfSpritePaletteTag(u16 tag); -u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum); -void FreeSpritePaletteByTag(u16 tag); -void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables); -bool8 AddSpriteToOamBuffer(struct Sprite *object, u8 *oamIndex); -bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex); -void CopyToSprites(u8 *src); -void CopyFromSprites(u8 *dest); -u8 SpriteTileAllocBitmapOp(u16 bit, u8 op); -void ClearSpriteCopyRequests(void); -void ResetAffineAnimData(void); - -#endif //GUARD_SPRITE_H diff --git a/include/string_util.h b/include/string_util.h deleted file mode 100644 index 229193d52..000000000 --- a/include/string_util.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef GUARD_STRING_UTIL_H -#define GUARD_STRING_UTIL_H - -extern u8 gStringVar1[0x100]; -extern u8 gStringVar2[0x100]; -extern u8 gStringVar3[0x100]; -extern u8 gStringVar4[0x3E8]; - -enum StringConvertMode -{ - STR_CONV_MODE_LEFT_ALIGN, - STR_CONV_MODE_RIGHT_ALIGN, - STR_CONV_MODE_LEADING_ZEROS -}; - -u8 *StringCopy10(u8 *dest, const u8 *src); -u8 *StringGetEnd10(u8 *str); -u8 *StringCopy7(u8 *dest, const u8 *src); -u8 *StringCopy(u8 *dest, const u8 *src); -u8 *StringAppend(u8 *dest, const u8 *src); -u8 *StringCopyN(u8 *dest, const u8 *src, u8 n); -u8 *StringAppendN(u8 *dest, const u8 *src, u8 n); -u16 StringLength(const u8 *str); -s32 StringCompare(const u8 *str1, const u8 *str2); -s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n); -bool8 IsStringLengthAtLeast(const u8 *str, s32 n); -u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); -u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n); -u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n); -u8 *StringExpandPlaceholders(u8 *dest, const u8 *src); -u8 *StringBraille(u8 *dest, const u8 *src); -const u8 *GetExpandedPlaceholder(u32 id); -u8 *StringFill(u8 *dest, u8 c, u16 n); -u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n); -u8 *StringFillWithTerminator(u8 *dest, u16 n); -u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n); -u32 StringLength_Multibyte(const u8 *str); -u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color); -bool32 IsStringJapanese(u8 *str); -bool32 sub_800924C(u8 *str, s32 n); -u8 GetExtCtrlCodeLength(u8 code); -s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2); -void ConvertInternationalString(u8 *s, u8 language); -void StripExtCtrlCodes(u8 *str); - -#endif // GUARD_STRING_UTIL_H diff --git a/include/text.h b/include/text.h deleted file mode 100644 index 3edd0fc62..000000000 --- a/include/text.h +++ /dev/null @@ -1,436 +0,0 @@ -#ifndef GUARD_TEXT_H -#define GUARD_TEXT_H - -#define CHAR_SPACE 0x00 -#define CHAR_A_GRAVE 0x01 -#define CHAR_A_ACUTE 0x02 -#define CHAR_A_CIRCUMFLEX 0x03 -#define CHAR_C_CEDILLA 0x04 -#define CHAR_E_GRAVE 0x05 -#define CHAR_E_ACUTE 0x06 -#define CHAR_E_CIRCUMFLEX 0x07 -#define CHAR_E_DIAERESIS 0x08 -#define CHAR_I_GRAVE 0x09 -//#define CHAR_I_ACUTE 0x0A // Is 0x5A instead -#define CHAR_I_CIRCUMFLEX 0x0B -#define CHAR_I_DIAERESIS 0x0C -#define CHAR_O_GRAVE 0x0D -#define CHAR_O_ACUTE 0x0E -#define CHAR_O_CIRCUMFLEX 0x0F -#define CHAR_OE 0x10 -#define CHAR_U_GRAVE 0x11 -#define CHAR_U_ACUTE 0x12 -#define CHAR_U_CIRCUMFLEX 0x13 -#define CHAR_N_TILDE 0x14 -#define CHAR_ESZETT 0x15 -#define CHAR_a_GRAVE 0x16 -#define CHAR_a_ACUTE 0x17 -//#define CHAR_a_CIRCUMFLEX 0x18 // Is 0x68 instead -#define CHAR_c_CEDILLA 0x19 -#define CHAR_e_GRAVE 0x1A -#define CHAR_e_ACUTE 0x1B -#define CHAR_e_CIRCUMFLEX 0x1C -#define CHAR_e_DIAERESIS 0x1D -#define CHAR_i_GRAVE 0x1E -//#define CHAR_i_ACUTE 0x1F // Is 0x6F instead -#define CHAR_i_CIRCUMFLEX 0x20 -#define CHAR_i_DIAERESIS 0x21 -#define CHAR_o_GRAVE 0x22 -#define CHAR_o_ACUTE 0x23 -#define CHAR_o_CIRCUMFLEX 0x24 -#define CHAR_oe 0x25 -#define CHAR_u_GRAVE 0x26 -#define CHAR_u_ACUTE 0x27 -#define CHAR_u_CIRCUMFLEX 0x28 -#define CHAR_n_TILDE 0x29 -#define CHAR_MASCULINE_ORDINAL 0x2A -#define CHAR_FEMININE_ORDINAL 0x2B -#define CHAR_SUPER_ER 0x2C -#define CHAR_AMPERSAND 0x2D -#define CHAR_PLUS 0x2E -// -#define CHAR_LV 0x34 -#define CHAR_EQUALS 0x35 -#define CHAR_SEMICOLON 0x36 -// -#define CHAR_INV_QUESTION_MARK 0x51 -#define CHAR_INV_EXCL_MARK 0x52 -#define CHAR_PK 0x53 -#define CHAR_MN 0x54 -#define CHAR_PO 0x55 -#define CHAR_KE 0x56 -#define CHAR_BLOCK_1 0x57 // Each of these 3 -#define CHAR_BLOCK_2 0x58 // chars contains 1/3 -#define CHAR_BLOCK_3 0x59 // of the word BLOCK -#define CHAR_I_ACUTE 0x5A -#define CHAR_PERCENT 0x5B -#define CHAR_LEFT_PAREN 0x5C -#define CHAR_RIGHT_PAREN 0x5D -// -#define CHAR_a_CIRCUMFLEX 0x68 -// -#define CHAR_i_ACUTE 0x6F -// -#define CHAR_GENDERLESS 0x77 // Empty space for lack of gender icon -// -#define CHAR_UP_ARROW 0x79 -#define CHAR_DOWN_ARROW 0x7A -#define CHAR_LEFT_ARROW 0x7B -#define CHAR_RIGHT_ARROW 0x7C -// -#define CHAR_SUPER_E 0x84 -#define CHAR_LESS_THAN 0x85 -#define CHAR_GREATER_THAN 0x86 -// -#define CHAR_SUPER_RE 0xA0 -#define CHAR_0 0xA1 -#define CHAR_1 0xA2 -#define CHAR_2 0xA3 -#define CHAR_3 0xA4 -#define CHAR_4 0xA5 -#define CHAR_5 0xA6 -#define CHAR_6 0xA7 -#define CHAR_7 0xA8 -#define CHAR_8 0xA9 -#define CHAR_9 0xAA -#define CHAR_EXCL_MARK 0xAB -#define CHAR_QUESTION_MARK 0xAC -#define CHAR_PERIOD 0xAD -#define CHAR_HYPHEN 0xAE -#define CHAR_BULLET 0xAF -#define CHAR_ELLIPSIS 0xB0 -#define CHAR_DBL_QUOT_LEFT 0xB1 -#define CHAR_DBL_QUOT_RIGHT 0xB2 -#define CHAR_SGL_QUOT_LEFT 0xB3 -#define CHAR_SGL_QUOT_RIGHT 0xB4 -#define CHAR_MALE 0xB5 -#define CHAR_FEMALE 0xB6 -#define CHAR_CURRENCY 0xB7 -#define CHAR_COMMA 0xB8 -#define CHAR_MULT_SIGN 0xB9 -#define CHAR_SLASH 0xBA -#define CHAR_A 0xBB -#define CHAR_B 0xBC -#define CHAR_C 0xBD -#define CHAR_D 0xBE -#define CHAR_E 0xBF -#define CHAR_F 0xC0 -#define CHAR_G 0xC1 -#define CHAR_H 0xC2 -#define CHAR_I 0xC3 -#define CHAR_J 0xC4 -#define CHAR_K 0xC5 -#define CHAR_L 0xC6 -#define CHAR_M 0xC7 -#define CHAR_N 0xC8 -#define CHAR_O 0xC9 -#define CHAR_P 0xCA -#define CHAR_Q 0xCB -#define CHAR_R 0xCC -#define CHAR_S 0xCD -#define CHAR_T 0xCE -#define CHAR_U 0xCF -#define CHAR_V 0xD0 -#define CHAR_W 0xD1 -#define CHAR_X 0xD2 -#define CHAR_Y 0xD3 -#define CHAR_Z 0xD4 -#define CHAR_a 0xD5 -#define CHAR_b 0xD6 -#define CHAR_c 0xD7 -#define CHAR_d 0xD8 -#define CHAR_e 0xD9 -#define CHAR_f 0xDA -#define CHAR_g 0xDB -#define CHAR_h 0xDC -#define CHAR_i 0xDD -#define CHAR_j 0xDE -#define CHAR_k 0xDF -#define CHAR_l 0xE0 -#define CHAR_m 0xE1 -#define CHAR_n 0xE2 -#define CHAR_o 0xE3 -#define CHAR_p 0xE4 -#define CHAR_q 0xE5 -#define CHAR_r 0xE6 -#define CHAR_s 0xE7 -#define CHAR_t 0xE8 -#define CHAR_u 0xE9 -#define CHAR_v 0xEA -#define CHAR_w 0xEB -#define CHAR_x 0xEC -#define CHAR_y 0xED -#define CHAR_z 0xEE -#define CHAR_BLACK_TRIANGLE 0xEF -#define CHAR_COLON 0xF0 -#define CHAR_A_DIAERESIS 0xF1 -#define CHAR_O_DIAERESIS 0xF2 -#define CHAR_U_DIAERESIS 0xF3 -#define CHAR_a_DIAERESIS 0xF4 -#define CHAR_o_DIAERESIS 0xF5 -#define CHAR_u_DIAERESIS 0xF6 -#define CHAR_DYNAMIC 0xF7 -#define CHAR_KEYPAD_ICON 0xF8 -#define CHAR_EXTRA_SYMBOL 0xF9 -#define CHAR_PROMPT_SCROLL 0xFA // waits for button press and scrolls dialog -#define CHAR_PROMPT_CLEAR 0xFB // waits for button press and clears dialog -#define EXT_CTRL_CODE_BEGIN 0xFC // extended control code -#define PLACEHOLDER_BEGIN 0xFD // string placeholder -#define CHAR_NEWLINE 0xFE -#define EOS 0xFF // end of string - -// CHAR_KEYPAD_ICON chars -#define CHAR_A_BUTTON 0x00 -#define CHAR_B_BUTTON 0x01 -#define CHAR_L_BUTTON 0x02 -#define CHAR_R_BUTTON 0x03 -#define CHAR_START_BUTTON 0x04 -#define CHAR_SELECT_BUTTON 0x05 -#define CHAR_DPAD_UP 0x06 -#define CHAR_DPAD_DOWN 0x07 -#define CHAR_DPAD_LEFT 0x08 -#define CHAR_DPAD_RIGHT 0x09 -#define CHAR_DPAD_UPDOWN 0x0A -#define CHAR_DPAD_LEFTRIGHT 0x0B -#define CHAR_DPAD_NONE 0x0C - -// CHAR_EXTRA_SYMBOL chars -#define CHAR_UP_ARROW_2 0x00 -#define CHAR_DOWN_ARROW_2 0x01 -#define CHAR_LEFT_ARROW_2 0x02 -#define CHAR_RIGHT_ARROW_2 0x03 -#define CHAR_PLUS_2 0x04 -#define CHAR_LV_2 0x05 -#define CHAR_PP 0x06 -#define CHAR_ID 0x07 -#define CHAR_NO 0x08 -#define CHAR_UNDERSCORE 0x09 - -#define EXT_CTRL_CODE_COLOR 0x01 -#define EXT_CTRL_CODE_HIGHLIGHT 0x02 -#define EXT_CTRL_CODE_SHADOW 0x03 -#define EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW 0x04 -#define EXT_CTRL_CODE_PALETTE 0x05 -#define EXT_CTRL_CODE_SIZE 0x06 -#define EXT_CTRL_CODE_RESET_SIZE 0x07 -#define EXT_CTRL_CODE_PAUSE 0x08 -#define EXT_CTRL_CODE_PAUSE_UNTIL_PRESS 0x09 -#define EXT_CTRL_CODE_WAIT_SE 0x0A -#define EXT_CTRL_CODE_PLAY_BGM 0x0B -#define EXT_CTRL_CODE_ESCAPE 0x0C -#define EXT_CTRL_CODE_SHIFT_TEXT 0x0D -#define EXT_CTRL_CODE_SHIFT_DOWN 0x0E -#define EXT_CTRL_CODE_FILL_WINDOW 0x0F -#define EXT_CTRL_CODE_PLAY_SE 0x10 -#define EXT_CTRL_CODE_CLEAR 0x11 -#define EXT_CTRL_CODE_SKIP 0x12 -#define EXT_CTRL_CODE_CLEAR_TO 0x13 -#define EXT_CTRL_CODE_MIN_LETTER_SPACING 0x14 -#define EXT_CTRL_CODE_JPN 0x15 -#define EXT_CTRL_CODE_ENG 0x16 -#define EXT_CTRL_CODE_PAUSE_MUSIC 0x17 -#define EXT_CTRL_CODE_RESUME_MUSIC 0x18 - -#define TEXT_COLOR_TRANSPARENT 0x0 -#define TEXT_COLOR_WHITE 0x1 -#define TEXT_COLOR_DARK_GRAY 0x2 -#define TEXT_COLOR_LIGHT_GRAY 0x3 -#define TEXT_COLOR_RED 0x4 -#define TEXT_COLOR_LIGHT_RED 0x5 -#define TEXT_COLOR_GREEN 0x6 -#define TEXT_COLOR_LIGHT_GREEN 0x7 -#define TEXT_COLOR_BLUE 0x8 -#define TEXT_COLOR_LIGHT_BLUE 0x9 -#define TEXT_DYNAMIC_COLOR_1 0xA // Usually white -#define TEXT_DYNAMIC_COLOR_2 0xB // Usually white w/ tinge of green -#define TEXT_DYNAMIC_COLOR_3 0xC // Usually white -#define TEXT_DYNAMIC_COLOR_4 0xD // Usually aquamarine -#define TEXT_DYNAMIC_COLOR_5 0xE // Usually blue-green -#define TEXT_DYNAMIC_COLOR_6 0xF // Usually cerulean - -#define PLACEHOLDER_ID_UNKNOWN 0x0 -#define PLACEHOLDER_ID_PLAYER 0x1 -#define PLACEHOLDER_ID_STRING_VAR_1 0x2 -#define PLACEHOLDER_ID_STRING_VAR_2 0x3 -#define PLACEHOLDER_ID_STRING_VAR_3 0x4 -#define PLACEHOLDER_ID_KUN 0x5 -#define PLACEHOLDER_ID_RIVAL 0x6 -#define PLACEHOLDER_ID_VERSION 0x7 -#define PLACEHOLDER_ID_AQUA 0x8 -#define PLACEHOLDER_ID_MAGMA 0x9 -#define PLACEHOLDER_ID_ARCHIE 0xA -#define PLACEHOLDER_ID_MAXIE 0xB -#define PLACEHOLDER_ID_KYOGRE 0xC -#define PLACEHOLDER_ID_GROUDON 0xD - -// battle placeholders are located in battle_message.h - -#define NUM_TEXT_PRINTERS 32 - -#define TEXT_SPEED_FF 0xFF - -enum -{ - FONTATTR_MAX_LETTER_WIDTH, - FONTATTR_MAX_LETTER_HEIGHT, - FONTATTR_LETTER_SPACING, - FONTATTR_LINE_SPACING, - FONTATTR_UNKNOWN, // dunno what this is yet - FONTATTR_COLOR_FOREGROUND, - FONTATTR_COLOR_BACKGROUND, - FONTATTR_COLOR_SHADOW -}; - -struct TextPrinterSubStruct -{ - u8 glyphId:4; // 0x14 - bool8 hasPrintBeenSpedUp:1; - u8 unk:3; - u8 downArrowDelay:5; - u8 downArrowYPosIdx:2; - bool8 hasGlyphIdBeenSet:1; - u8 autoScrollDelay; -}; - -struct TextPrinterTemplate -{ - const u8* currentChar; - u8 windowId; - u8 fontId; - u8 x; - u8 y; - u8 currentX; // 0x8 - u8 currentY; - u8 letterSpacing; - u8 lineSpacing; - u8 unk:4; // 0xC - u8 fgColor:4; - u8 bgColor:4; - u8 shadowColor:4; -}; - -struct TextPrinter -{ - struct TextPrinterTemplate printerTemplate; - - void (*callback)(struct TextPrinterTemplate *, u16); // 0x10 - - u8 subStructFields[7]; // always cast to struct TextPrinterSubStruct... so why bother - u8 active; - u8 state; // 0x1C - u8 textSpeed; - u8 delayCounter; - u8 scrollDistance; - u8 minLetterSpacing; // 0x20 - u8 japanese; -}; - -struct FontInfo -{ - u16 (*fontFunction)(struct TextPrinter *x); - u8 maxLetterWidth; - u8 maxLetterHeight; - u8 letterSpacing; - u8 lineSpacing; - u8 unk:4; - u8 fgColor:4; - u8 bgColor:4; - u8 shadowColor:4; -}; - -extern const struct FontInfo *gFonts; - -struct GlyphWidthFunc -{ - u32 fontId; - u32 (*func)(u16 glyphId, bool32 isJapanese); -}; - -struct KeypadIcon -{ - u16 tileOffset; - u8 width; - u8 height; -}; - -typedef struct { - bool8 canABSpeedUpPrint:1; - bool8 useAlternateDownArrow:1; - bool8 autoScroll:1; - bool8 forceMidTextSpeed:1; -} TextFlags; - -struct TextGlyph -{ - u32 gfxBufferTop[16]; - u32 gfxBufferBottom[16]; - u8 width; - u8 height; -}; - -extern TextFlags gTextFlags; - -extern u8 gDisableTextPrinters; -extern struct TextGlyph gCurGlyph; - -void SetFontsPointer(const struct FontInfo *fonts); -void DeactivateAllTextPrinters(void); -u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); -bool16 AddTextPrinter(struct TextPrinterTemplate *template, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); -void RunTextPrinters(void); -bool16 IsTextPrinterActive(u8 id); -u32 RenderFont(struct TextPrinter *textPrinter); -void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor); -void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); -void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor); -void DecompressGlyphTile(const void *src_, void *dest_); -u8 GetLastTextColor(u8 colorType); -void CopyGlyphToWindow(struct TextPrinter *x); -void ClearTextSpan(struct TextPrinter *textPrinter, u32 width); -u8 GetMenuCursorDimensionByFont(u8, u8); - -u16 Font0Func(struct TextPrinter *textPrinter); -u16 Font1Func(struct TextPrinter *textPrinter); -u16 Font2Func(struct TextPrinter *textPrinter); -u16 Font3Func(struct TextPrinter *textPrinter); -u16 Font4Func(struct TextPrinter *textPrinter); -u16 Font5Func(struct TextPrinter *textPrinter); -u16 Font7Func(struct TextPrinter *textPrinter); -u16 Font8Func(struct TextPrinter *textPrinter); - -void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter); -void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter); -void TextPrinterClearDownArrow(struct TextPrinter *textPrinter); -bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter); -bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter); -bool16 TextPrinterWait(struct TextPrinter *textPrinter); -void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex); -u16 RenderText(struct TextPrinter *textPrinter); -u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing); -u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32); -s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing); -u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str); -u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y); -u8 GetKeypadIconTileOffset(u8 keypadIconId); -u8 GetKeypadIconWidth(u8 keypadIconId); -u8 GetKeypadIconHeight(u8 keypadIconId); -void SetDefaultFontsPointer(void); -u8 GetFontAttribute(u8 fontId, u8 attributeId); -u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension); -void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese); -u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese); -void DecompressGlyphFont9(u16 glyphId); - -// unk_text_util_2.c -u16 Font6Func(struct TextPrinter *textPrinter); -u32 GetGlyphWidthFont6(u16 glyphId, bool32 isJapanese); - -#endif // GUARD_TEXT_H diff --git a/include/window.h b/include/window.h deleted file mode 100644 index 3eac75a28..000000000 --- a/include/window.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef GUARD_WINDOW_H -#define GUARD_WINDOW_H - -#define PIXEL_FILL(num) ((num) | ((num) << 4)) - -enum -{ - WINDOW_BG, - WINDOW_TILEMAP_LEFT, - WINDOW_TILEMAP_TOP, - WINDOW_WIDTH, - WINDOW_HEIGHT, - WINDOW_PALETTE_NUM, - WINDOW_BASE_BLOCK, - WINDOW_TILE_DATA -}; - -struct WindowTemplate -{ - u8 bg; - u8 tilemapLeft; - u8 tilemapTop; - u8 width; - u8 height; - u8 paletteNum; - u16 baseBlock; -}; - -#define DUMMY_WIN_TEMPLATE \ -{ \ - 0xFF, \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ -} - -#define WINDOW_NONE 0xFF - -struct Window -{ - struct WindowTemplate window; - u8 *tileData; -}; - -bool16 InitWindows(const struct WindowTemplate *templates); -u16 AddWindow(const struct WindowTemplate *template); -int AddWindowWithoutTileMap(const struct WindowTemplate *template); -void RemoveWindow(u8 windowId); -void FreeAllWindowBuffers(void); -void CopyWindowToVram(u8 windowId, u8 mode); -void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h); -void PutWindowTilemap(u8 windowId); -void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette); -void ClearWindowTilemap(u8 windowId); -void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height); -void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height); -void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight); -void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); -void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset); -void FillWindowPixelBuffer(u8 windowId, u8 fillValue); -void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue); -void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)); -bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value); -u32 GetWindowAttribute(u8 windowId, u8 attributeId); -u16 AddWindow8Bit(const struct WindowTemplate *template); -void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue); -void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); -void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum); -void CopyWindowToVram8Bit(u8 windowId, u8 mode); - -extern struct Window gWindows[]; -extern void* gWindowBgTilemapBuffers[]; -extern u32 gUnusedWindowVar1; -extern u32 gUnusedWindowVar2; -extern u32 gUnusedWindowVar3; - -#endif // GUARD_WINDOW_H diff --git a/ld_script.txt b/ld_script.txt index 5770b2cea..8c8f19015 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -49,15 +49,15 @@ SECTIONS { { src/crt0.o(.text); src/main.o(.text); - src/malloc.o(.text); - src/dma3_manager.o(.text); - src/gpu_regs.o(.text); - src/bg.o(.text); - src/blit.o(.text); - src/window.o(.text); - src/text.o(.text); - src/sprite.o(.text); - src/string_util.o(.text); + gflib/malloc.o(.text); + gflib/dma3_manager.o(.text); + gflib/gpu_regs.o(.text); + gflib/bg.o(.text); + gflib/blit.o(.text); + gflib/window.o(.text); + gflib/text.o(.text); + gflib/sprite.o(.text); + gflib/string_util.o(.text); src/link.o(.text); src/AgbRfu_LinkManager.o(.text); src/link_rfu_3.o(.text); @@ -436,12 +436,12 @@ SECTIONS { ALIGN(4) { src/main.o(.rodata); - src/bg.o(.rodata); - src/window.o(.rodata); - src/text.o(.rodata); - src/sprite.o(.rodata); - src/io_reg.o(.rodata); - src/string_util.o(.rodata); + gflib/bg.o(.rodata); + gflib/window.o(.rodata); + gflib/text.o(.rodata); + gflib/sprite.o(.rodata); + gflib/io_reg.o(.rodata); + gflib/string_util.o(.rodata); src/link.o(.rodata); src/link.o(.rodata.str1.4); src/AgbRfu_LinkManager.o(.rodata); diff --git a/ld_script_modern.txt b/ld_script_modern.txt index 72fb4dbc5..59d032bb2 100644 --- a/ld_script_modern.txt +++ b/ld_script_modern.txt @@ -14,6 +14,7 @@ SECTIONS { . = 0x1C000; src/*.o(ewram_data); + gflib/*.o(ewram_data); . = 0x40000; } @@ -25,6 +26,7 @@ SECTIONS { { /* .bss starts at 0x3000000 */ src/*.o(.bss); + gflib/*.o(.bss); *libc.a:*.o(.bss*); *libnosys.a:*.o(.bss*); @@ -33,6 +35,7 @@ SECTIONS { /* COMMON starts at 0x30022A8 */ src/*.o(COMMON); + gflib/*.o(COMMON); *libc.a:*.o(COMMON); *libnosys.a:*.o(COMMON); end = .; @@ -46,6 +49,7 @@ SECTIONS { { src/crt0.o(.text*); src/*.o(.text*); + gflib/*.o(.text*); asm/*.o(.text*); } =0 @@ -80,6 +84,7 @@ SECTIONS { ALIGN(4) { src/*.o(.rodata*); + gflib/*.o(.rodata*); data/*.o(.rodata*); } =0 diff --git a/src/bg.c b/src/bg.c deleted file mode 100644 index ec7c2113b..000000000 --- a/src/bg.c +++ /dev/null @@ -1,1248 +0,0 @@ -#include -#include "global.h" -#include "bg.h" -#include "dma3.h" -#include "gpu_regs.h" - -#define DISPCNT_ALL_BG_AND_MODE_BITS (DISPCNT_BG_ALL_ON | 0x7) - -struct BgControl -{ - struct BgConfig { - u8 visible:1; - u8 unknown_1:1; - u8 screenSize:2; - u8 priority:2; - u8 mosaic:1; - u8 wraparound:1; - - u8 charBaseIndex:2; - u8 mapBaseIndex:5; - u8 paletteMode:1; - - u8 unknown_2; // Assigned to but never read - u8 unknown_3; // Assigned to but never read - } configs[NUM_BACKGROUNDS]; - - u16 bgVisibilityAndMode; -}; - -struct BgConfig2 -{ - u32 baseTile:10; - u32 basePalette:4; - u32 unk_3:18; - - void* tilemap; - s32 bg_x; - s32 bg_y; -}; - -static struct BgControl sGpuBgConfigs; -static struct BgConfig2 sGpuBgConfigs2[NUM_BACKGROUNDS]; -static u32 sDmaBusyBitfield[NUM_BACKGROUNDS]; - -u32 gUnneededFireRedVariable; - -static const struct BgConfig sZeroedBgControlStruct = { 0 }; - -void ResetBgs(void) -{ - ResetBgControlStructs(); - sGpuBgConfigs.bgVisibilityAndMode = 0; - SetTextModeAndHideBgs(); -} - -static void SetBgModeInternal(u8 bgMode) -{ - sGpuBgConfigs.bgVisibilityAndMode &= ~0x7; - sGpuBgConfigs.bgVisibilityAndMode |= bgMode; -} - -u8 GetBgMode(void) -{ - return sGpuBgConfigs.bgVisibilityAndMode & 0x7; -} - -void ResetBgControlStructs(void) -{ - int i; - - for (i = 0; i < NUM_BACKGROUNDS; i++) - { - sGpuBgConfigs.configs[i] = sZeroedBgControlStruct; - } -} - -void Unused_ResetBgControlStruct(u8 bg) -{ - if (!IsInvalidBg(bg)) - { - sGpuBgConfigs.configs[bg] = sZeroedBgControlStruct; - } -} - -enum -{ - BG_CTRL_ATTR_VISIBLE = 1, - BG_CTRL_ATTR_CHARBASEINDEX = 2, - BG_CTRL_ATTR_MAPBASEINDEX = 3, - BG_CTRL_ATTR_SCREENSIZE = 4, - BG_CTRL_ATTR_PALETTEMODE = 5, - BG_CTRL_ATTR_PRIORITY = 6, - BG_CTRL_ATTR_MOSAIC = 7, - BG_CTRL_ATTR_WRAPAROUND = 8, -}; - -static void SetBgControlAttributes(u8 bg, u8 charBaseIndex, u8 mapBaseIndex, u8 screenSize, u8 paletteMode, u8 priority, u8 mosaic, u8 wraparound) -{ - if (!IsInvalidBg(bg)) - { - if (charBaseIndex != 0xFF) - { - sGpuBgConfigs.configs[bg].charBaseIndex = charBaseIndex; - } - - if (mapBaseIndex != 0xFF) - { - sGpuBgConfigs.configs[bg].mapBaseIndex = mapBaseIndex; - } - - if (screenSize != 0xFF) - { - sGpuBgConfigs.configs[bg].screenSize = screenSize; - } - - if (paletteMode != 0xFF) - { - sGpuBgConfigs.configs[bg].paletteMode = paletteMode; - } - - if (priority != 0xFF) - { - sGpuBgConfigs.configs[bg].priority = priority; - } - - if (mosaic != 0xFF) - { - sGpuBgConfigs.configs[bg].mosaic = mosaic; - } - - if (wraparound != 0xFF) - { - sGpuBgConfigs.configs[bg].wraparound = wraparound; - } - - sGpuBgConfigs.configs[bg].unknown_2 = 0; - sGpuBgConfigs.configs[bg].unknown_3 = 0; - - sGpuBgConfigs.configs[bg].visible = 1; - } -} - -static u16 GetBgControlAttribute(u8 bg, u8 attributeId) -{ - if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) - { - switch (attributeId) - { - case BG_CTRL_ATTR_VISIBLE: - return sGpuBgConfigs.configs[bg].visible; - case BG_CTRL_ATTR_CHARBASEINDEX: - return sGpuBgConfigs.configs[bg].charBaseIndex; - case BG_CTRL_ATTR_MAPBASEINDEX: - return sGpuBgConfigs.configs[bg].mapBaseIndex; - case BG_CTRL_ATTR_SCREENSIZE: - return sGpuBgConfigs.configs[bg].screenSize; - case BG_CTRL_ATTR_PALETTEMODE: - return sGpuBgConfigs.configs[bg].paletteMode; - case BG_CTRL_ATTR_PRIORITY: - return sGpuBgConfigs.configs[bg].priority; - case BG_CTRL_ATTR_MOSAIC: - return sGpuBgConfigs.configs[bg].mosaic; - case BG_CTRL_ATTR_WRAPAROUND: - return sGpuBgConfigs.configs[bg].wraparound; - } - } - - return 0xFF; -} - -u8 LoadBgVram(u8 bg, const void *src, u16 size, u16 destOffset, u8 mode) -{ - u16 offset; - s8 cursor; - - if (IsInvalidBg(bg) || !sGpuBgConfigs.configs[bg].visible) - return -1; - - switch (mode) - { - case 0x1: - offset = sGpuBgConfigs.configs[bg].charBaseIndex * BG_CHAR_SIZE; - offset = destOffset + offset; - cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); - if (cursor == -1) - return -1; - break; - case 0x2: - offset = sGpuBgConfigs.configs[bg].mapBaseIndex * BG_SCREEN_SIZE; - offset = destOffset + offset; - cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0); - if (cursor == -1) - return -1; - break; - default: - cursor = -1; - break; - } - - return cursor; -} - -static void ShowBgInternal(u8 bg) -{ - u16 value; - if (!IsInvalidBg(bg) && sGpuBgConfigs.configs[bg].visible) - { - value = sGpuBgConfigs.configs[bg].priority | - (sGpuBgConfigs.configs[bg].charBaseIndex << 2) | - (sGpuBgConfigs.configs[bg].mosaic << 6) | - (sGpuBgConfigs.configs[bg].paletteMode << 7) | - (sGpuBgConfigs.configs[bg].mapBaseIndex << 8) | - (sGpuBgConfigs.configs[bg].wraparound << 13) | - (sGpuBgConfigs.configs[bg].screenSize << 14); - - SetGpuReg((bg << 1) + REG_OFFSET_BG0CNT, value); - - sGpuBgConfigs.bgVisibilityAndMode |= 1 << (bg + 8); - sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; - } -} - -static void HideBgInternal(u8 bg) -{ - if (!IsInvalidBg(bg)) - { - sGpuBgConfigs.bgVisibilityAndMode &= ~(1 << (bg + 8)); - sGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS; - } -} - -static void SyncBgVisibilityAndMode(void) -{ - SetGpuReg(REG_OFFSET_DISPCNT, (GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS) | sGpuBgConfigs.bgVisibilityAndMode); -} - -void SetTextModeAndHideBgs(void) -{ - SetGpuReg(REG_OFFSET_DISPCNT, GetGpuReg(REG_OFFSET_DISPCNT) & ~DISPCNT_ALL_BG_AND_MODE_BITS); -} - -static void SetBgAffineInternal(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) -{ - struct BgAffineSrcData src; - struct BgAffineDstData dest; - - switch (sGpuBgConfigs.bgVisibilityAndMode & 0x7) - { - default: - case 0: - return; - case 1: - if (bg != 2) - return; - break; - case 2: - if (bg != 2 && bg != 3) - return; - break; - } - - src.texX = srcCenterX; - src.texY = srcCenterY; - src.scrX = dispCenterX; - src.scrY = dispCenterY; - src.sx = scaleX; - src.sy = scaleY; - src.alpha = rotationAngle; - - BgAffineSet(&src, &dest, 1); - - SetGpuReg(REG_OFFSET_BG2PA, dest.pa); - SetGpuReg(REG_OFFSET_BG2PB, dest.pb); - SetGpuReg(REG_OFFSET_BG2PC, dest.pc); - SetGpuReg(REG_OFFSET_BG2PD, dest.pd); - SetGpuReg(REG_OFFSET_BG2PA, dest.pa); - SetGpuReg(REG_OFFSET_BG2X_L, (s16)(dest.dx)); - SetGpuReg(REG_OFFSET_BG2X_H, (s16)(dest.dx >> 16)); - SetGpuReg(REG_OFFSET_BG2Y_L, (s16)(dest.dy)); - SetGpuReg(REG_OFFSET_BG2Y_H, (s16)(dest.dy >> 16)); -} - -bool8 IsInvalidBg(u8 bg) -{ - if (bg >= NUM_BACKGROUNDS) - return TRUE; - else - return FALSE; -} - -int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4) -{ - return 0; -} - -void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable) -{ - int i; - ResetBgs(); - - for (i = 0; i < NUM_BACKGROUNDS; i++) - { - sDmaBusyBitfield[i] = 0; - } - - gUnneededFireRedVariable = leftoverFireRedLeafGreenVariable; -} - -void InitBgsFromTemplates(u8 bgMode, const struct BgTemplate *templates, u8 numTemplates) -{ - int i; - u8 bg; - - SetBgModeInternal(bgMode); - ResetBgControlStructs(); - - for (i = 0; i < numTemplates; i++) - { - bg = templates[i].bg; - if (bg < NUM_BACKGROUNDS) - { - SetBgControlAttributes(bg, - templates[i].charBaseIndex, - templates[i].mapBaseIndex, - templates[i].screenSize, - templates[i].paletteMode, - templates[i].priority, - 0, - 0); - - sGpuBgConfigs2[bg].baseTile = templates[i].baseTile; - sGpuBgConfigs2[bg].basePalette = 0; - sGpuBgConfigs2[bg].unk_3 = 0; - - sGpuBgConfigs2[bg].tilemap = NULL; - sGpuBgConfigs2[bg].bg_x = 0; - sGpuBgConfigs2[bg].bg_y = 0; - } - } -} - -void InitBgFromTemplate(const struct BgTemplate *template) -{ - u8 bg = template->bg; - - if (bg < NUM_BACKGROUNDS) - { - SetBgControlAttributes(bg, - template->charBaseIndex, - template->mapBaseIndex, - template->screenSize, - template->paletteMode, - template->priority, - 0, - 0); - - sGpuBgConfigs2[bg].baseTile = template->baseTile; - sGpuBgConfigs2[bg].basePalette = 0; - sGpuBgConfigs2[bg].unk_3 = 0; - - sGpuBgConfigs2[bg].tilemap = NULL; - sGpuBgConfigs2[bg].bg_x = 0; - sGpuBgConfigs2[bg].bg_y = 0; - } -} - -void SetBgMode(u8 bgMode) -{ - SetBgModeInternal(bgMode); -} - -u16 LoadBgTiles(u8 bg, const void* src, u16 size, u16 destOffset) -{ - u16 tileOffset; - u8 cursor; - - if (GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE) == 0) - { - tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x20; - } - else - { - tileOffset = (sGpuBgConfigs2[bg].baseTile + destOffset) * 0x40; - } - - cursor = LoadBgVram(bg, src, size, tileOffset, DISPCNT_MODE_1); - - if (cursor == 0xFF) - { - return -1; - } - - sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); - - if (gUnneededFireRedVariable == 1) - { - DummiedOutFireRedLeafGreenTileAllocFunc(bg, tileOffset / 0x20, size / 0x20, 1); - } - - return cursor; -} - -u16 LoadBgTilemap(u8 bg, const void *src, u16 size, u16 destOffset) -{ - u8 cursor = LoadBgVram(bg, src, size, destOffset * 2, DISPCNT_MODE_2); - - if (cursor == 0xFF) - { - return -1; - } - - sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); - - return cursor; -} - -u16 Unused_LoadBgPalette(u8 bg, const void *src, u16 size, u16 destOffset) -{ - s8 cursor; - - if (!IsInvalidBg32(bg)) - { - u16 paletteOffset = (sGpuBgConfigs2[bg].basePalette * 0x20) + (destOffset * 2); - cursor = RequestDma3Copy(src, (void*)(paletteOffset + BG_PLTT), size, 0); - - if (cursor == -1) - { - return -1; - } - } - else - { - return -1; - } - - sDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20)); - - return (u8)cursor; -} - -bool8 IsDma3ManagerBusyWithBgCopy(void) -{ - int i; - - for (i = 0; i < 0x80; i++) - { - u8 div = i / 0x20; - u8 mod = i % 0x20; - - if ((sDmaBusyBitfield[div] & (1 << mod))) - { - s8 reqSpace = CheckForSpaceForDma3Request(i); - if (reqSpace == -1) - { - return TRUE; - } - - sDmaBusyBitfield[div] &= ~(1 << mod); - } - } - - return FALSE; -} - -void ShowBg(u8 bg) -{ - ShowBgInternal(bg); - SyncBgVisibilityAndMode(); -} - -void HideBg(u8 bg) -{ - HideBgInternal(bg); - SyncBgVisibilityAndMode(); -} - -void SetBgAttribute(u8 bg, u8 attributeId, u8 value) -{ - switch (attributeId) - { - case BG_ATTR_CHARBASEINDEX: - SetBgControlAttributes(bg, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_MAPBASEINDEX: - SetBgControlAttributes(bg, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_SCREENSIZE: - SetBgControlAttributes(bg, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_PALETTEMODE: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF); - break; - case BG_ATTR_PRIORITY: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF); - break; - case BG_ATTR_MOSAIC: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF); - break; - case BG_ATTR_WRAPAROUND: - SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value); - break; - } -} - -u16 GetBgAttribute(u8 bg, u8 attributeId) -{ - switch (attributeId) - { - case BG_ATTR_CHARBASEINDEX: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_CHARBASEINDEX); - case BG_ATTR_MAPBASEINDEX: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_MAPBASEINDEX); - case BG_ATTR_SCREENSIZE: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - case BG_ATTR_PALETTEMODE: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE); - case BG_ATTR_PRIORITY: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_PRIORITY); - case BG_ATTR_MOSAIC: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_MOSAIC); - case BG_ATTR_WRAPAROUND: - return GetBgControlAttribute(bg, BG_CTRL_ATTR_WRAPAROUND); - case BG_ATTR_METRIC: - switch (GetBgType(bg)) - { - case 0: - return GetBgMetricTextMode(bg, 0) * 0x800; - case 1: - return GetBgMetricAffineMode(bg, 0) * 0x100; - default: - return 0; - } - case BG_ATTR_TYPE: - return GetBgType(bg); - case BG_ATTR_BASETILE: - return sGpuBgConfigs2[bg].baseTile; - default: - return -1; - } -} - -s32 ChangeBgX(u8 bg, s32 value, u8 op) -{ - u8 mode; - u16 temp1; - u16 temp2; - - if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - return -1; - } - - switch (op) - { - case 0: - default: - sGpuBgConfigs2[bg].bg_x = value; - break; - case 1: - sGpuBgConfigs2[bg].bg_x += value; - break; - case 2: - sGpuBgConfigs2[bg].bg_x -= value; - break; - } - - mode = GetBgMode(); - - switch (bg) - { - case 0: - temp1 = sGpuBgConfigs2[0].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG0HOFS, temp1); - break; - case 1: - temp1 = sGpuBgConfigs2[1].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG1HOFS, temp1); - break; - case 2: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[2].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG2HOFS, temp1); - } - else - { - temp1 = sGpuBgConfigs2[2].bg_x >> 0x10; - temp2 = sGpuBgConfigs2[2].bg_x & 0xFFFF; - SetGpuReg(REG_OFFSET_BG2X_H, temp1); - SetGpuReg(REG_OFFSET_BG2X_L, temp2); - } - break; - case 3: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[3].bg_x >> 0x8; - SetGpuReg(REG_OFFSET_BG3HOFS, temp1); - } - else if (mode == 2) - { - temp1 = sGpuBgConfigs2[3].bg_x >> 0x10; - temp2 = sGpuBgConfigs2[3].bg_x & 0xFFFF; - SetGpuReg(REG_OFFSET_BG3X_H, temp1); - SetGpuReg(REG_OFFSET_BG3X_L, temp2); - } - break; - } - - return sGpuBgConfigs2[bg].bg_x; -} - -s32 GetBgX(u8 bg) -{ - if (IsInvalidBg32(bg)) - return -1; - else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - return -1; - else - return sGpuBgConfigs2[bg].bg_x; -} - -s32 ChangeBgY(u8 bg, s32 value, u8 op) -{ - u8 mode; - u16 temp1; - u16 temp2; - - if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - return -1; - } - - switch (op) - { - case 0: - default: - sGpuBgConfigs2[bg].bg_y = value; - break; - case 1: - sGpuBgConfigs2[bg].bg_y += value; - break; - case 2: - sGpuBgConfigs2[bg].bg_y -= value; - break; - } - - mode = GetBgMode(); - - switch (bg) - { - case 0: - temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG0VOFS, temp1); - break; - case 1: - temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG1VOFS, temp1); - break; - case 2: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG2VOFS, temp1); - } - else - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; - SetGpuReg(REG_OFFSET_BG2Y_H, temp1); - SetGpuReg(REG_OFFSET_BG2Y_L, temp2); - } - break; - case 3: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; - SetGpuReg(REG_OFFSET_BG3VOFS, temp1); - } - else if (mode == 2) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; - SetGpuReg(REG_OFFSET_BG3Y_H, temp1); - SetGpuReg(REG_OFFSET_BG3Y_L, temp2); - } - break; - } - - return sGpuBgConfigs2[bg].bg_y; -} - -s32 ChangeBgY_ScreenOff(u8 bg, s32 value, u8 op) -{ - u8 mode; - u16 temp1; - u16 temp2; - - if (IsInvalidBg32(bg) || !GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - return -1; - } - - switch (op) - { - case 0: - default: - sGpuBgConfigs2[bg].bg_y = value; - break; - case 1: - sGpuBgConfigs2[bg].bg_y += value; - break; - case 2: - sGpuBgConfigs2[bg].bg_y -= value; - break; - } - - mode = GetBgMode(); - - switch (bg) - { - case 0: - temp1 = sGpuBgConfigs2[0].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, temp1); - break; - case 1: - temp1 = sGpuBgConfigs2[1].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG1VOFS, temp1); - break; - case 2: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG2VOFS, temp1); - - } - else - { - temp1 = sGpuBgConfigs2[2].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[2].bg_y & 0xFFFF; - SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_H, temp1); - SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_L, temp2); - } - break; - case 3: - if (mode == 0) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x8; - SetGpuReg_ForcedBlank(REG_OFFSET_BG3VOFS, temp1); - } - else if (mode == 2) - { - temp1 = sGpuBgConfigs2[3].bg_y >> 0x10; - temp2 = sGpuBgConfigs2[3].bg_y & 0xFFFF; - SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_H, temp1); - SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_L, temp2); - } - break; - } - - return sGpuBgConfigs2[bg].bg_y; -} - -s32 GetBgY(u8 bg) -{ - if (IsInvalidBg32(bg)) - return -1; - else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - return -1; - else - return sGpuBgConfigs2[bg].bg_y; -} - -void SetBgAffine(u8 bg, s32 srcCenterX, s32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle) -{ - SetBgAffineInternal(bg, srcCenterX, srcCenterY, dispCenterX, dispCenterY, scaleX, scaleY, rotationAngle); -} - -u8 Unused_AdjustBgMosaic(u8 a1, u8 a2) -{ - u16 result = GetGpuReg(REG_OFFSET_MOSAIC); - s16 test1 = result & 0xF; - s16 test2 = (result >> 4) & 0xF; - - result &= 0xFF00; - - switch (a2) - { - case 0: - default: - test1 = a1 & 0xF; - test2 = a1 >> 0x4; - break; - case 1: - test1 = a1 & 0xF; - break; - case 2: - if ((test1 + a1) > 0xF) - { - test1 = 0xF; - } - else - { - test1 += a1; - } - break; - case 3: - if ((test1 - a1) < 0) - { - test1 = 0x0; - } - else - { - test1 -= a1; - } - break; - case 4: - test2 = a1 & 0xF; - break; - case 5: - if ((test2 + a1) > 0xF) - { - test2 = 0xF; - } - else - { - test2 += a1; - } - break; - case 6: - if ((test2 - a1) < 0) - { - test2 = 0x0; - } - else - { - test2 -= a1; - } - break; - } - - result |= ((test2 << 0x4) & 0xF0); - result |= (test1 & 0xF); - - SetGpuReg(REG_OFFSET_MOSAIC, result); - - return result; -} - -void SetBgTilemapBuffer(u8 bg, void *tilemap) -{ - if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - sGpuBgConfigs2[bg].tilemap = tilemap; - } -} - -void UnsetBgTilemapBuffer(u8 bg) -{ - if (!IsInvalidBg32(bg) && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - { - sGpuBgConfigs2[bg].tilemap = NULL; - } -} - -void* GetBgTilemapBuffer(u8 bg) -{ - if (IsInvalidBg32(bg)) - return NULL; - else if (!GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE)) - return NULL; - else - return sGpuBgConfigs2[bg].tilemap; -} - -void CopyToBgTilemapBuffer(u8 bg, const void *src, u16 mode, u16 destOffset) -{ - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - if (mode != 0) - CpuCopy16(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2)), mode); - else - LZ77UnCompWram(src, (void *)(sGpuBgConfigs2[bg].tilemap + (destOffset * 2))); - } -} - -void CopyBgTilemapBufferToVram(u8 bg) -{ - u16 sizeToLoad; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - switch (GetBgType(bg)) - { - case 0: - sizeToLoad = GetBgMetricTextMode(bg, 0) * 0x800; - break; - case 1: - sizeToLoad = GetBgMetricAffineMode(bg, 0) * 0x100; - break; - default: - sizeToLoad = 0; - break; - } - LoadBgVram(bg, sGpuBgConfigs2[bg].tilemap, sizeToLoad, 0, 2); - } -} - -void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height) -{ - u16 destX16; - u16 destY16; - u16 mode; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - switch (GetBgType(bg)) - { - case 0: - { - const u16 * srcCopy = src; - for (destY16 = destY; destY16 < (destY + height); destY16++) - { - for (destX16 = destX; destX16 < (destX + width); destX16++) - { - ((u16*)sGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *srcCopy++; - } - } - break; - } - case 1: - { - const u8 * srcCopy = src; - mode = GetBgMetricAffineMode(bg, 0x1); - for (destY16 = destY; destY16 < (destY + height); destY16++) - { - for (destX16 = destX; destX16 < (destX + width); destX16++) - { - ((u8*)sGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *srcCopy++; - } - } - break; - } - } - } -} - -void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, const void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette) -{ - CopyRectToBgTilemapBufferRect(bg, src, 0, 0, rectWidth, rectHeight, destX, destY, rectWidth, rectHeight, palette, 0, 0); -} - -void CopyRectToBgTilemapBufferRect(u8 bg, const void *src, u8 srcX, u8 srcY, u8 srcWidth, u8 unused, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, s16 palette1, s16 tileOffset) -{ - u16 screenWidth, screenHeight, screenSize; - u16 var; - const void *srcPtr; - u16 i, j; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - screenWidth = GetBgMetricTextMode(bg, 0x1) * 0x20; - screenHeight = GetBgMetricTextMode(bg, 0x2) * 0x20; - switch (GetBgType(bg)) - { - case 0: - srcPtr = src + ((srcY * srcWidth) + srcX) * 2; - for (i = destX; i < (destX + rectWidth); i++) - { - for (j = srcHeight; j < (srcHeight + destY); j++) - { - u16 index = GetTileMapIndexFromCoords(j, i, screenSize, screenWidth, screenHeight); - CopyTileMapEntry(srcPtr, sGpuBgConfigs2[bg].tilemap + (index * 2), rectHeight, palette1, tileOffset); - srcPtr += 2; - } - srcPtr += (srcWidth - destY) * 2; - } - break; - case 1: - srcPtr = src + ((srcY * srcWidth) + srcX); - var = GetBgMetricAffineMode(bg, 0x1); - for (i = destX; i < (destX + rectWidth); i++) - { - for (j = srcHeight; j < (srcHeight + destY); j++) - { - *(u8*)(sGpuBgConfigs2[bg].tilemap + ((var * i) + j)) = *(u8*)(srcPtr) + palette1; - srcPtr++; - } - srcPtr += (srcWidth - destY); - } - break; - } - } -} - -void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height) -{ - u16 x16; - u16 y16; - u16 mode; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - switch (GetBgType(bg)) - { - case 0: - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - ((u16*)sGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum; - } - } - break; - case 1: - mode = GetBgMetricAffineMode(bg, 0x1); - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - ((u8*)sGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum; - } - } - break; - } - } -} - -void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette) -{ - WriteSequenceToBgTilemapBuffer(bg, tileNum, x, y, width, height, palette, 0); -} - -void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta) -{ - u16 mode; - u16 mode2; - u16 attribute; - u16 mode3; - u16 x16, y16; - - if (!IsInvalidBg32(bg) && !IsTileMapOutsideWram(bg)) - { - attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - mode = GetBgMetricTextMode(bg, 0x1) * 0x20; - mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20; - switch (GetBgType(bg)) - { - case 0: - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - CopyTileMapEntry(&firstTileNum, &((u16*)sGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0); - firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); - } - } - break; - case 1: - mode3 = GetBgMetricAffineMode(bg, 0x1); - for (y16 = y; y16 < (y + height); y16++) - { - for (x16 = x; x16 < (x + width); x16++) - { - ((u8*)sGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum; - firstTileNum = (firstTileNum & (METATILE_COLLISION_MASK | METATILE_ELEVATION_MASK)) + ((firstTileNum + tileNumDelta) & METATILE_ID_MASK); - } - } - break; - } - } -} - -u16 GetBgMetricTextMode(u8 bg, u8 whichMetric) -{ - u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - - switch (whichMetric) - { - case 0: - switch (screenSize) - { - case 0: - return 1; - case 1: - case 2: - return 2; - case 3: - return 4; - } - break; - case 1: - switch (screenSize) - { - case 0: - return 1; - case 1: - return 2; - case 2: - return 1; - case 3: - return 2; - } - break; - case 2: - switch (screenSize) - { - case 0: - case 1: - return 1; - case 2: - case 3: - return 2; - } - break; - } - return 0; -} - -u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric) -{ - u8 screenSize = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE); - - switch (whichMetric) - { - case 0: - switch (screenSize) - { - case 0: - return 0x1; - case 1: - return 0x4; - case 2: - return 0x10; - case 3: - return 0x40; - } - break; - case 1: - case 2: - return 0x10 << screenSize; - } - return 0; -} - -u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight) -{ - x = x & (screenWidth - 1); - y = y & (screenHeight - 1); - - switch (screenSize) - { - case 0: - case 2: - break; - case 3: - if (y >= 0x20) - y += 0x20; - case 1: - if (x >= 0x20) - { - x -= 0x20; - y += 0x20; - } - break; - } - return (y * 0x20) + x; -} - -void CopyTileMapEntry(const u16 *src, u16 *dest, s32 palette1, s32 tileOffset, s32 palette2) -{ - u16 var; - - switch (palette1) - { - case 0 ... 15: - var = ((*src + tileOffset) & 0xFFF) + ((palette1 + palette2) << 12); - break; - case 16: - var = *dest; - var &= 0xFC00; - var += palette2 << 12; - var |= (*src + tileOffset) & 0x3FF; - break; - default: - case 17 ... INT_MAX: - var = *src + tileOffset + (palette2 << 12); - break; - } - *dest = var; -} - -u32 GetBgType(u8 bg) -{ - u8 mode = GetBgMode(); - - switch (bg) - { - case 0: - case 1: - switch (mode) - { - case 0: - case 1: - return 0; - } - break; - case 2: - switch (mode) - { - case 0: - return 0; - case 1: - case 2: - return 1; - } - break; - case 3: - switch (mode) - { - case 0: - return 0; - case 2: - return 1; - } - break; - } - - return 0xFFFF; -} - -bool32 IsInvalidBg32(u8 bg) -{ - if (bg >= NUM_BACKGROUNDS) - return TRUE; - else - return FALSE; -} - -bool32 IsTileMapOutsideWram(u8 bg) -{ - if (sGpuBgConfigs2[bg].tilemap > (void*)IWRAM_END) - return TRUE; - else if (sGpuBgConfigs2[bg].tilemap == NULL) - return TRUE; - else - return FALSE; -} diff --git a/src/blit.c b/src/blit.c deleted file mode 100644 index bdbb2e2fd..000000000 --- a/src/blit.c +++ /dev/null @@ -1,209 +0,0 @@ -#include "global.h" -#include "blit.h" - -void BlitBitmapRect4BitWithoutColorKey(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height) -{ - BlitBitmapRect4Bit(src, dst, srcX, srcY, dstX, dstY, width, height, 0xFF); -} - -void BlitBitmapRect4Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey) -{ - s32 xEnd; - s32 yEnd; - s32 multiplierSrcY; - s32 multiplierDstY; - s32 loopSrcY, loopDstY; - s32 loopSrcX, loopDstX; - const u8 *pixelsSrc; - u8 *pixelsDst; - s32 toOrr; - s32 toAnd; - s32 toShift; - - if (dst->width - dstX < width) - xEnd = (dst->width - dstX) + srcX; - else - xEnd = srcX + width; - - if (dst->height - dstY < height) - yEnd = (dst->height - dstY) + srcY; - else - yEnd = height + srcY; - - multiplierSrcY = (src->width + (src->width & 7)) >> 3; - multiplierDstY = (dst->width + (dst->width & 7)) >> 3; - - if (colorKey == 0xFF) - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); - pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); - toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); - toShift = ((loopDstX & 1) << 2); - toOrr <<= toShift; - toAnd = 0xF0 >> (toShift); - *pixelsDst = toOrr | (*pixelsDst & toAnd); - } - } - } - else - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1B); - pixelsDst = dst->pixels + ((loopDstX >> 1) & 3) + ((loopDstX >> 3) << 5) + (((loopDstY >> 3) * multiplierDstY) << 5) + ((u32)(loopDstY << 0x1d) >> 0x1B); - toOrr = ((*pixelsSrc >> ((loopSrcX & 1) << 2)) & 0xF); - if (toOrr != colorKey) - { - toShift = ((loopDstX & 1) << 2); - toOrr <<= toShift; - toAnd = 0xF0 >> (toShift); - *pixelsDst = toOrr | (*pixelsDst & toAnd); - } - } - } - } -} - -void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) -{ - s32 xEnd; - s32 yEnd; - s32 multiplierY; - s32 loopX, loopY; - u8 toOrr1, toOrr2; - - xEnd = x + width; - if (xEnd > surface->width) - xEnd = surface->width; - - yEnd = y + height; - if (yEnd > surface->height) - yEnd = surface->height; - - multiplierY = (surface->width + (surface->width & 7)) >> 3; - toOrr1 = fillValue << 4; - toOrr2 = fillValue & 0xF; - - for (loopY = y; loopY < yEnd; loopY++) - { - for (loopX = x; loopX < xEnd; loopX++) - { - u8 *pixels = surface->pixels + ((loopX >> 1) & 3) + ((loopX >> 3) << 5) + (((loopY >> 3) * multiplierY) << 5) + ((u32)(loopY << 0x1d) >> 0x1B); - if ((loopX << 0x1F) != 0) - *pixels = toOrr1 | (*pixels & 0xF); - else - *pixels = toOrr2 | (*pixels & 0xF0); - } - } -} - -void BlitBitmapRect4BitTo8Bit(const struct Bitmap *src, struct Bitmap *dst, u16 srcX, u16 srcY, u16 dstX, u16 dstY, u16 width, u16 height, u8 colorKey, u8 paletteOffset) -{ - s32 palOffsetBits; - s32 xEnd; - s32 yEnd; - s32 multiplierSrcY; - s32 multiplierDstY; - s32 loopSrcY, loopDstY; - s32 loopSrcX, loopDstX; - const u8 *pixelsSrc; - u8 *pixelsDst; - s32 colorKeyBits; - - palOffsetBits = (u32)(paletteOffset << 0x1C) >> 0x18; - colorKeyBits = (u32)(colorKey << 0x1C) >> 0x18; - - if (dst->width - dstX < width) - xEnd = (dst->width - dstX) + srcX; - else - xEnd = width + srcX; - - if (dst->height - dstY < height) - yEnd = (srcY + dst->height) - dstY; - else - yEnd = srcY + height; - - multiplierSrcY = (src->width + (src->width & 7)) >> 3; - multiplierDstY = (dst->width + (dst->width & 7)) >> 3; - - if (colorKey == 0xFF) - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); - if (loopSrcX & 1) - { - *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); - } - else - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); - } - } - } - } - else - { - for (loopSrcY = srcY, loopDstY = dstY; loopSrcY < yEnd; loopSrcY++, loopDstY++) - { - pixelsSrc = src->pixels + ((srcX >> 1) & 3) + ((srcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - for (loopSrcX = srcX, loopDstX = dstX; loopSrcX < xEnd; loopSrcX++, loopDstX++) - { - if (loopSrcX & 1) - { - if ((*pixelsSrc & 0xF0) != colorKeyBits) - { - pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); - *pixelsDst = palOffsetBits + (*pixelsSrc >> 4); - } - } - else - { - pixelsSrc = src->pixels + ((loopSrcX >> 1) & 3) + ((loopSrcX >> 3) << 5) + (((loopSrcY >> 3) * multiplierSrcY) << 5) + ((u32)(loopSrcY << 0x1d) >> 0x1b); - if ((*pixelsSrc & 0xF) != colorKey) - { - pixelsDst = dst->pixels + (loopDstX & 7) + ((loopDstX >> 3) << 6) + (((loopDstY >> 3) * multiplierDstY) << 6) + ((u32)(loopDstY << 0x1d) >> 0x1a); - *pixelsDst = palOffsetBits + (*pixelsSrc & 0xF); - } - } - } - } - } -} - -void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue) -{ - s32 xEnd; - s32 yEnd; - s32 multiplierY; - s32 loopX, loopY; - - xEnd = x + width; - if (xEnd > surface->width) - xEnd = surface->width; - - yEnd = y + height; - if (yEnd > surface->height) - yEnd = surface->height; - - multiplierY = (surface->width + (surface->width & 7)) >> 3; - - for (loopY = y; loopY < yEnd; loopY++) - { - for (loopX = x; loopX < xEnd; loopX++) - { - u8 *pixels = surface->pixels + (loopX & 7) + ((loopX >> 3) << 6) + (((loopY >> 3) * multiplierY) << 6) + ((u32)(loopY << 0x1d) >> 0x1a); - *pixels = fillValue; - } - } -} diff --git a/src/dma3_manager.c b/src/dma3_manager.c deleted file mode 100644 index d774efe8c..000000000 --- a/src/dma3_manager.c +++ /dev/null @@ -1,183 +0,0 @@ -#include "global.h" -#include "dma3.h" - -#define MAX_DMA_REQUESTS 128 - -#define DMA_REQUEST_COPY32 1 -#define DMA_REQUEST_FILL32 2 -#define DMA_REQUEST_COPY16 3 -#define DMA_REQUEST_FILL16 4 - -struct Dma3Request -{ - const u8 *src; - u8 *dest; - u16 size; - u16 mode; - u32 value; -}; - -static struct Dma3Request sDma3Requests[MAX_DMA_REQUESTS]; - -static vbool8 sDma3ManagerLocked; -static u8 sDma3RequestCursor; - -void ClearDma3Requests(void) -{ - int i; - - sDma3ManagerLocked = TRUE; - sDma3RequestCursor = 0; - - for (i = 0; i < MAX_DMA_REQUESTS; i++) - { - sDma3Requests[i].size = 0; - sDma3Requests[i].src = NULL; - sDma3Requests[i].dest = NULL; - } - - sDma3ManagerLocked = FALSE; -} - -void ProcessDma3Requests(void) -{ - u16 bytesTransferred; - - if (sDma3ManagerLocked) - return; - - bytesTransferred = 0; - - // as long as there are DMA requests to process (unless size or vblank is an issue), do not exit - while (sDma3Requests[sDma3RequestCursor].size != 0) - { - bytesTransferred += sDma3Requests[sDma3RequestCursor].size; - - if (bytesTransferred > 40 * 1024) - return; // don't transfer more than 40 KiB - if (*(u8 *)REG_ADDR_VCOUNT > 224) - return; // we're about to leave vblank, stop - - switch (sDma3Requests[sDma3RequestCursor].mode) - { - case DMA_REQUEST_COPY32: // regular 32-bit copy - Dma3CopyLarge32_(sDma3Requests[sDma3RequestCursor].src, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - case DMA_REQUEST_FILL32: // repeat a single 32-bit value across RAM - Dma3FillLarge32_(sDma3Requests[sDma3RequestCursor].value, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - case DMA_REQUEST_COPY16: // regular 16-bit copy - Dma3CopyLarge16_(sDma3Requests[sDma3RequestCursor].src, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - case DMA_REQUEST_FILL16: // repeat a single 16-bit value across RAM - Dma3FillLarge16_(sDma3Requests[sDma3RequestCursor].value, - sDma3Requests[sDma3RequestCursor].dest, - sDma3Requests[sDma3RequestCursor].size); - break; - } - - // Free the request - sDma3Requests[sDma3RequestCursor].src = NULL; - sDma3Requests[sDma3RequestCursor].dest = NULL; - sDma3Requests[sDma3RequestCursor].size = 0; - sDma3Requests[sDma3RequestCursor].mode = 0; - sDma3Requests[sDma3RequestCursor].value = 0; - sDma3RequestCursor++; - - if (sDma3RequestCursor >= MAX_DMA_REQUESTS) // loop back to the first DMA request - sDma3RequestCursor = 0; - } -} - -s16 RequestDma3Copy(const void *src, void *dest, u16 size, u8 mode) -{ - int cursor; - int i = 0; - - sDma3ManagerLocked = TRUE; - cursor = sDma3RequestCursor; - - while (i < MAX_DMA_REQUESTS) - { - if (sDma3Requests[cursor].size == 0) // an empty request was found. - { - sDma3Requests[cursor].src = src; - sDma3Requests[cursor].dest = dest; - sDma3Requests[cursor].size = size; - - if (mode == 1) - sDma3Requests[cursor].mode = DMA_REQUEST_COPY32; - else - sDma3Requests[cursor].mode = DMA_REQUEST_COPY16; - - sDma3ManagerLocked = FALSE; - return cursor; - } - if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. - cursor = 0; - i++; - } - sDma3ManagerLocked = FALSE; - return -1; // no free DMA request was found -} - -s16 RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode) -{ - int cursor; - int i = 0; - - cursor = sDma3RequestCursor; - sDma3ManagerLocked = TRUE; - - while (i < MAX_DMA_REQUESTS) - { - if (sDma3Requests[cursor].size == 0) // an empty request was found. - { - sDma3Requests[cursor].dest = dest; - sDma3Requests[cursor].size = size; - sDma3Requests[cursor].mode = mode; - sDma3Requests[cursor].value = value; - - if(mode == 1) - sDma3Requests[cursor].mode = DMA_REQUEST_FILL32; - else - sDma3Requests[cursor].mode = DMA_REQUEST_FILL16; - - sDma3ManagerLocked = FALSE; - return cursor; - } - if (++cursor >= MAX_DMA_REQUESTS) // loop back to start. - cursor = 0; - i++; - } - sDma3ManagerLocked = FALSE; - return -1; // no free DMA request was found -} - -s16 CheckForSpaceForDma3Request(s16 index) -{ - int i = 0; - - if (index == -1) // check if all requests are free - { - while (i < MAX_DMA_REQUESTS) - { - if (sDma3Requests[i].size != 0) - return -1; - i++; - } - return 0; - } - else // check the specified request - { - if (sDma3Requests[index].size != 0) - return -1; - return 0; - } -} diff --git a/src/gpu_regs.c b/src/gpu_regs.c deleted file mode 100644 index 3bcc4fd93..000000000 --- a/src/gpu_regs.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "global.h" -#include "gpu_regs.h" - -#define GPU_REG_BUF_SIZE 0x60 - -#define GPU_REG_BUF(offset) (*(u16 *)(&sGpuRegBuffer[offset])) -#define GPU_REG(offset) (*(vu16 *)(REG_BASE + offset)) - -#define EMPTY_SLOT 0xFF - -static u8 sGpuRegBuffer[GPU_REG_BUF_SIZE]; -static u8 sGpuRegWaitingList[GPU_REG_BUF_SIZE]; -static volatile bool8 sGpuRegBufferLocked; -static volatile bool8 sShouldSyncRegIE; -static vu16 sRegIE; - -static void CopyBufferedValueToGpuReg(u8 regOffset); -static void SyncRegIE(void); -static void UpdateRegDispstatIntrBits(u16 regIE); - -void InitGpuRegManager(void) -{ - s32 i; - - for (i = 0; i < GPU_REG_BUF_SIZE; i++) - { - sGpuRegBuffer[i] = 0; - sGpuRegWaitingList[i] = EMPTY_SLOT; - } - - sGpuRegBufferLocked = FALSE; - sShouldSyncRegIE = FALSE; - sRegIE = 0; -} - -static void CopyBufferedValueToGpuReg(u8 regOffset) -{ - if (regOffset == REG_OFFSET_DISPSTAT) - { - REG_DISPSTAT &= ~(DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); - REG_DISPSTAT |= GPU_REG_BUF(REG_OFFSET_DISPSTAT); - } - else - { - GPU_REG(regOffset) = GPU_REG_BUF(regOffset); - } -} - -void CopyBufferedValuesToGpuRegs(void) -{ - if (!sGpuRegBufferLocked) - { - s32 i; - - for (i = 0; i < GPU_REG_BUF_SIZE; i++) - { - u8 regOffset = sGpuRegWaitingList[i]; - if (regOffset == EMPTY_SLOT) - return; - CopyBufferedValueToGpuReg(regOffset); - sGpuRegWaitingList[i] = EMPTY_SLOT; - } - } -} - -void SetGpuReg(u8 regOffset, u16 value) -{ - if (regOffset < GPU_REG_BUF_SIZE) - { - u16 vcount; - - GPU_REG_BUF(regOffset) = value; - vcount = REG_VCOUNT & 0xFF; - - if ((vcount >= 161 && vcount <= 225) || (REG_DISPCNT & DISPCNT_FORCED_BLANK)) - { - CopyBufferedValueToGpuReg(regOffset); - } - else - { - s32 i; - - sGpuRegBufferLocked = TRUE; - - for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) - { - if (sGpuRegWaitingList[i] == regOffset) - { - sGpuRegBufferLocked = FALSE; - return; - } - } - - sGpuRegWaitingList[i] = regOffset; - sGpuRegBufferLocked = FALSE; - } - } -} - -void SetGpuReg_ForcedBlank(u8 regOffset, u16 value) -{ - if (regOffset < GPU_REG_BUF_SIZE) - { - GPU_REG_BUF(regOffset) = value; - - if (REG_DISPCNT & DISPCNT_FORCED_BLANK) - { - CopyBufferedValueToGpuReg(regOffset); - } - else - { - s32 i; - - sGpuRegBufferLocked = TRUE; - - for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) - { - if (sGpuRegWaitingList[i] == regOffset) - { - sGpuRegBufferLocked = FALSE; - return; - } - } - - sGpuRegWaitingList[i] = regOffset; - sGpuRegBufferLocked = FALSE; - } - } -} - -u16 GetGpuReg(u8 regOffset) -{ - if (regOffset == REG_OFFSET_DISPSTAT) - return REG_DISPSTAT; - - if (regOffset == REG_OFFSET_VCOUNT) - return REG_VCOUNT; - - return GPU_REG_BUF(regOffset); -} - -void SetGpuRegBits(u8 regOffset, u16 mask) -{ - u16 regValue = GPU_REG_BUF(regOffset); - SetGpuReg(regOffset, regValue | mask); -} - -void ClearGpuRegBits(u8 regOffset, u16 mask) -{ - u16 regValue = GPU_REG_BUF(regOffset); - SetGpuReg(regOffset, regValue & ~mask); -} - -static void SyncRegIE(void) -{ - if (sShouldSyncRegIE) - { - u16 temp = REG_IME; - REG_IME = 0; - REG_IE = sRegIE; - REG_IME = temp; - sShouldSyncRegIE = FALSE; - } -} - -void EnableInterrupts(u16 mask) -{ - sRegIE |= mask; - sShouldSyncRegIE = TRUE; - SyncRegIE(); - UpdateRegDispstatIntrBits(sRegIE); -} - -void DisableInterrupts(u16 mask) -{ - sRegIE &= ~mask; - sShouldSyncRegIE = TRUE; - SyncRegIE(); - UpdateRegDispstatIntrBits(sRegIE); -} - -static void UpdateRegDispstatIntrBits(u16 regIE) -{ - u16 oldValue = GetGpuReg(REG_OFFSET_DISPSTAT) & (DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR); - u16 newValue = 0; - - if (regIE & INTR_FLAG_VBLANK) - newValue |= DISPSTAT_VBLANK_INTR; - - if (regIE & INTR_FLAG_HBLANK) - newValue |= DISPSTAT_HBLANK_INTR; - - if (oldValue != newValue) - SetGpuReg(REG_OFFSET_DISPSTAT, newValue); -} diff --git a/src/io_reg.c b/src/io_reg.c deleted file mode 100644 index 44364349d..000000000 --- a/src/io_reg.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "global.h" -#include "io_reg.h" -#include "gba/io_reg.h" - -static const u32 sUnused[] = { - 0, - 0, - (1 << 26) | (1 << 3), - (1 << 26) | (1 << 3) | (1 << 1), - (1 << 26) | (1 << 3) | (1 << 2), - (1 << 26) | (1 << 3) | (1 << 2) | (1 << 1), - (1 << 26) | (1 << 4), - (1 << 26) | (1 << 4) | (1 << 2), - (1 << 26) | (1 << 4) | (1 << 3), - (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2), - (1 << 26) | (1 << 4) | (1 << 1), - (1 << 26) | (1 << 4) | (1 << 2) | (1 << 1), - (1 << 26) | (1 << 4) | (1 << 3) | (1 << 1), - (1 << 26) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1), - (1 << 25) | (1 << 8), - (1 << 27) | (1 << 10), -}; - -const u16 gOverworldBackgroundLayerFlags[] = { - BLDCNT_TGT2_BG0, - BLDCNT_TGT2_BG1, - BLDCNT_TGT2_BG2, - BLDCNT_TGT2_BG3, -}; - -const u16 gOrbEffectBackgroundLayerFlags[] = { - BLDCNT_TGT1_BG0, - BLDCNT_TGT1_BG1, - BLDCNT_TGT1_BG2, - BLDCNT_TGT1_BG3, -}; diff --git a/src/malloc.c b/src/malloc.c deleted file mode 100644 index 38fc8939e..000000000 --- a/src/malloc.c +++ /dev/null @@ -1,210 +0,0 @@ -#include "global.h" - -static void *sHeapStart; -static u32 sHeapSize; -static u32 sFiller; // needed to align dma3_manager.o(.bss) - -#define MALLOC_SYSTEM_ID 0xA3A3 - -struct MemBlock { - // Whether this block is currently allocated. - bool16 flag; - - // Magic number used for error checking. Should equal MALLOC_SYSTEM_ID. - u16 magic; - - // Size of the block (not including this header struct). - u32 size; - - // Previous block pointer. Equals sHeapStart if this is the first block. - struct MemBlock *prev; - - // Next block pointer. Equals sHeapStart if this is the last block. - struct MemBlock *next; - - // Data in the memory block. (Arrays of length 0 are a GNU extension.) - u8 data[0]; -}; - -void PutMemBlockHeader(void *block, struct MemBlock *prev, struct MemBlock *next, u32 size) -{ - struct MemBlock *header = (struct MemBlock *)block; - - header->flag = FALSE; - header->magic = MALLOC_SYSTEM_ID; - header->size = size; - header->prev = prev; - header->next = next; -} - -void PutFirstMemBlockHeader(void *block, u32 size) -{ - PutMemBlockHeader(block, (struct MemBlock *)block, (struct MemBlock *)block, size - sizeof(struct MemBlock)); -} - -void *AllocInternal(void *heapStart, u32 size) -{ - struct MemBlock *pos = (struct MemBlock *)heapStart; - struct MemBlock *head = pos; - struct MemBlock *splitBlock; - u32 foundBlockSize; - - // Alignment - if (size & 3) - size = 4 * ((size / 4) + 1); - - for (;;) { - // Loop through the blocks looking for unused block that's big enough. - - if (!pos->flag) { - foundBlockSize = pos->size; - - if (foundBlockSize >= size) { - if (foundBlockSize - size < 2 * sizeof(struct MemBlock)) { - // The block isn't much bigger than the requested size, - // so just use it. - pos->flag = TRUE; - } else { - // The block is significantly bigger than the requested - // size, so split the rest into a separate block. - foundBlockSize -= sizeof(struct MemBlock); - foundBlockSize -= size; - - splitBlock = (struct MemBlock *)(pos->data + size); - - pos->flag = TRUE; - pos->size = size; - - PutMemBlockHeader(splitBlock, pos, pos->next, foundBlockSize); - - pos->next = splitBlock; - - if (splitBlock->next != head) - splitBlock->next->prev = splitBlock; - } - - return pos->data; - } - } - - if (pos->next == head) - return NULL; - - pos = pos->next; - } -} - -void FreeInternal(void *heapStart, void *pointer) -{ - if (pointer) { - struct MemBlock *head = (struct MemBlock *)heapStart; - struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); - block->flag = FALSE; - - // If the freed block isn't the last one, merge with the next block - // if it's not in use. - if (block->next != head) { - if (!block->next->flag) { - block->size += sizeof(struct MemBlock) + block->next->size; - block->next->magic = 0; - block->next = block->next->next; - if (block->next != head) - block->next->prev = block; - } - } - - // If the freed block isn't the first one, merge with the previous block - // if it's not in use. - if (block != head) { - if (!block->prev->flag) { - block->prev->next = block->next; - - if (block->next != head) - block->next->prev = block->prev; - - block->magic = 0; - block->prev->size += sizeof(struct MemBlock) + block->size; - } - } - } -} - -void *AllocZeroedInternal(void *heapStart, u32 size) -{ - void *mem = AllocInternal(heapStart, size); - - if (mem != NULL) { - if (size & 3) - size = 4 * ((size / 4) + 1); - - CpuFill32(0, mem, size); - } - - return mem; -} - -bool32 CheckMemBlockInternal(void *heapStart, void *pointer) -{ - struct MemBlock *head = (struct MemBlock *)heapStart; - struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); - - if (block->magic != MALLOC_SYSTEM_ID) - return FALSE; - - if (block->next->magic != MALLOC_SYSTEM_ID) - return FALSE; - - if (block->next != head && block->next->prev != block) - return FALSE; - - if (block->prev->magic != MALLOC_SYSTEM_ID) - return FALSE; - - if (block->prev != head && block->prev->next != block) - return FALSE; - - if (block->next != head && block->next != (struct MemBlock *)(block->data + block->size)) - return FALSE; - - return TRUE; -} - -void InitHeap(void *heapStart, u32 heapSize) -{ - sHeapStart = heapStart; - sHeapSize = heapSize; - PutFirstMemBlockHeader(heapStart, heapSize); -} - -void *Alloc(u32 size) -{ - return AllocInternal(sHeapStart, size); -} - -void *AllocZeroed(u32 size) -{ - return AllocZeroedInternal(sHeapStart, size); -} - -void Free(void *pointer) -{ - FreeInternal(sHeapStart, pointer); -} - -bool32 CheckMemBlock(void *pointer) -{ - return CheckMemBlockInternal(sHeapStart, pointer); -} - -bool32 CheckHeap() -{ - struct MemBlock *pos = (struct MemBlock *)sHeapStart; - - do { - if (!CheckMemBlockInternal(sHeapStart, pos->data)) - return FALSE; - pos = pos->next; - } while (pos != (struct MemBlock *)sHeapStart); - - return TRUE; -} diff --git a/src/sprite.c b/src/sprite.c deleted file mode 100644 index f97ecc712..000000000 --- a/src/sprite.c +++ /dev/null @@ -1,1775 +0,0 @@ -#include "global.h" -#include "sprite.h" -#include "main.h" -#include "palette.h" - -#define MAX_SPRITE_COPY_REQUESTS 64 - -#define OAM_MATRIX_COUNT 32 - -#define SET_SPRITE_TILE_RANGE(index, start, count) \ -{ \ - sSpriteTileRanges[index * 2] = start; \ - (sSpriteTileRanges + 1)[index * 2] = count; \ -} - -#define ALLOC_SPRITE_TILE(n) \ -{ \ - sSpriteTileAllocBitmap[(n) / 8] |= (1 << ((n) % 8)); \ -} - -#define FREE_SPRITE_TILE(n) \ -{ \ - sSpriteTileAllocBitmap[(n) / 8] &= ~(1 << ((n) % 8)); \ -} - -#define SPRITE_TILE_IS_ALLOCATED(n) ((sSpriteTileAllocBitmap[(n) / 8] >> ((n) % 8)) & 1) - - -struct SpriteCopyRequest -{ - const u8 *src; - u8 *dest; - u16 size; -}; - -struct OamDimensions32 -{ - s32 width; - s32 height; -}; - -struct OamDimensions -{ - s8 width; - s8 height; -}; - -static void UpdateOamCoords(void); -static void BuildSpritePriorities(void); -static void SortSprites(void); -static void CopyMatricesToOamBuffer(void); -static void AddSpritesToOamBuffer(void); -static u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); -static void ResetOamMatrices(void); -static void ResetSprite(struct Sprite *sprite); -static s16 AllocSpriteTiles(u16 tileCount); -static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); -static void ResetAllSprites(void); -static void BeginAnim(struct Sprite *sprite); -static void ContinueAnim(struct Sprite *sprite); -static void AnimCmd_frame(struct Sprite *sprite); -static void AnimCmd_end(struct Sprite *sprite); -static void AnimCmd_jump(struct Sprite *sprite); -static void AnimCmd_loop(struct Sprite *sprite); -static void BeginAnimLoop(struct Sprite *sprite); -static void ContinueAnimLoop(struct Sprite *sprite); -static void JumpToTopOfAnimLoop(struct Sprite *sprite); -static void BeginAffineAnim(struct Sprite *sprite); -static void ContinueAffineAnim(struct Sprite *sprite); -static void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite); -static void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); -static void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); -static void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite); -static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite); -static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix); -static u8 GetSpriteMatrixNum(struct Sprite *sprite); -static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); -static void AffineAnimStateRestartAnim(u8 matrixNum); -static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum); -static void AffineAnimStateReset(u8 matrixNum); -static void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); -static void DecrementAnimDelayCounter(struct Sprite *sprite); -static bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum); -static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); -static s16 ConvertScaleParam(s16 scale); -static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); -static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); -static u8 IndexOfSpriteTileTag(u16 tag); -static void AllocSpriteTileRange(u16 tag, u16 start, u16 count); -static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset); -static void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2); - -typedef void (*AnimFunc)(struct Sprite *); -typedef void (*AnimCmdFunc)(struct Sprite *); -typedef void (*AffineAnimCmdFunc)(u8 matrixNum, struct Sprite *); - -#define DUMMY_OAM_DATA \ -{ \ - .y = 160, \ - .affineMode = 0, \ - .objMode = 0, \ - .mosaic = 0, \ - .bpp = 0, \ - .shape = SPRITE_SHAPE(8x8), \ - .x = 304, \ - .matrixNum = 0, \ - .size = SPRITE_SIZE(8x8), \ - .tileNum = 0, \ - .priority = 3, /* lowest priority */ \ - .paletteNum = 0, \ - .affineParam = 0 \ -} - -#define ANIM_END 0xFFFF -#define AFFINE_ANIM_END 0x7FFF - -// forward declarations -const union AnimCmd * const gDummySpriteAnimTable[]; -const union AffineAnimCmd * const gDummySpriteAffineAnimTable[]; -const struct SpriteTemplate gDummySpriteTemplate; - -// Unreferenced data. Also unreferenced in R/S. -static const u8 sUnknownData[24] = -{ - 0x01, 0x04, 0x10, 0x40, - 0x02, 0x04, 0x08, 0x20, - 0x02, 0x04, 0x08, 0x20, - 0x01, 0x04, 0x10, 0x40, - 0x02, 0x04, 0x08, 0x20, - 0x02, 0x04, 0x08, 0x20, -}; - -static const u8 sCenterToCornerVecTable[3][4][2] = -{ - { // square - { -4, -4 }, - { -8, -8 }, - { -16, -16 }, - { -32, -32 }, - }, - { // horizontal rectangle - { -8, -4 }, - { -16, -4 }, - { -16, -8 }, - { -32, -16 }, - }, - { // vertical rectangle - { -4, -8 }, - { -4, -16 }, - { -8, -16 }, - { -16, -32 }, - }, -}; - -static const struct Sprite sDummySprite = -{ - .oam = DUMMY_OAM_DATA, - .anims = gDummySpriteAnimTable, - .images = NULL, - .affineAnims = gDummySpriteAffineAnimTable, - .template = &gDummySpriteTemplate, - .subspriteTables = NULL, - .callback = SpriteCallbackDummy, - .pos1 = { 304, 160 }, - .pos2 = { 0, 0 }, - .centerToCornerVecX = 0, - .centerToCornerVecY = 0, - .animNum = 0, - .animCmdIndex = 0, - .animDelayCounter = 0, - .animPaused = 0, - .affineAnimPaused = 0, - .animLoopCounter = 0, - .data = {0, 0, 0, 0, 0, 0, 0}, - .inUse = 0, - .coordOffsetEnabled = 0, - .invisible = FALSE, - .flags_3 = 0, - .flags_4 = 0, - .flags_5 = 0, - .flags_6 = 0, - .flags_7 = 0, - .hFlip = 0, - .vFlip = 0, - .animBeginning = 0, - .affineAnimBeginning = 0, - .animEnded = 0, - .affineAnimEnded = 0, - .usingSheet = 0, - .flags_f = 0, - .sheetTileStart = 0, - .subspriteTableNum = 0, - .subspriteMode = 0, - .subpriority = 0xFF -}; - -const struct OamData gDummyOamData = DUMMY_OAM_DATA; - -static const union AnimCmd sDummyAnim = { ANIM_END }; - -const union AnimCmd * const gDummySpriteAnimTable[] = { &sDummyAnim }; - -static const union AffineAnimCmd sDummyAffineAnim = { AFFINE_ANIM_END }; - -const union AffineAnimCmd * const gDummySpriteAffineAnimTable[] = { &sDummyAffineAnim }; - -const struct SpriteTemplate gDummySpriteTemplate = -{ - .tileTag = 0, - .paletteTag = 0xFFFF, - .oam = &gDummyOamData, - .anims = gDummySpriteAnimTable, - .images = NULL, - .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCallbackDummy -}; - -static const AnimFunc sAnimFuncs[] = -{ - ContinueAnim, - BeginAnim, -}; - -static const AnimFunc sAffineAnimFuncs[] = -{ - ContinueAffineAnim, - BeginAffineAnim, -}; - -static const AnimCmdFunc sAnimCmdFuncs[] = -{ - AnimCmd_loop, - AnimCmd_jump, - AnimCmd_end, - AnimCmd_frame, -}; - -static const AffineAnimCmdFunc sAffineAnimCmdFuncs[] = -{ - AffineAnimCmd_loop, - AffineAnimCmd_jump, - AffineAnimCmd_end, - AffineAnimCmd_frame, -}; - -static const struct OamDimensions32 sOamDimensions32[3][4] = -{ - [ST_OAM_SQUARE] = - { - [SPRITE_SIZE(8x8)] = { 8, 8 }, - [SPRITE_SIZE(16x16)] = { 16, 16 }, - [SPRITE_SIZE(32x32)] = { 32, 32 }, - [SPRITE_SIZE(64x64)] = { 64, 64 }, - }, - [ST_OAM_H_RECTANGLE] = - { - [SPRITE_SIZE(16x8)] = { 16, 8 }, - [SPRITE_SIZE(32x8)] = { 32, 8 }, - [SPRITE_SIZE(32x16)] = { 32, 16 }, - [SPRITE_SIZE(64x32)] = { 64, 32 }, - }, - [ST_OAM_V_RECTANGLE] = - { - [SPRITE_SIZE(8x16)] = { 8, 16 }, - [SPRITE_SIZE(8x32)] = { 8, 32 }, - [SPRITE_SIZE(16x32)] = { 16, 32 }, - [SPRITE_SIZE(32x64)] = { 32, 64 }, - }, -}; - -static const struct OamDimensions sOamDimensions[3][4] = -{ - [ST_OAM_SQUARE] = - { - [SPRITE_SIZE(8x8)] = { 8, 8 }, - [SPRITE_SIZE(16x16)] = { 16, 16 }, - [SPRITE_SIZE(32x32)] = { 32, 32 }, - [SPRITE_SIZE(64x64)] = { 64, 64 }, - }, - [ST_OAM_H_RECTANGLE] = - { - [SPRITE_SIZE(16x8)] = { 16, 8 }, - [SPRITE_SIZE(32x8)] = { 32, 8 }, - [SPRITE_SIZE(32x16)] = { 32, 16 }, - [SPRITE_SIZE(64x32)] = { 64, 32 }, - }, - [ST_OAM_V_RECTANGLE] = - { - [SPRITE_SIZE(8x16)] = { 8, 16 }, - [SPRITE_SIZE(8x32)] = { 8, 32 }, - [SPRITE_SIZE(16x32)] = { 16, 32 }, - [SPRITE_SIZE(32x64)] = { 32, 64 }, - }, -}; - -// iwram bss -static u16 sSpriteTileRangeTags[MAX_SPRITES]; -static u16 sSpriteTileRanges[MAX_SPRITES * 2]; -static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; -static u16 sSpritePaletteTags[16]; - -// iwram common -u32 gOamMatrixAllocBitmap; -u8 gReservedSpritePaletteCount; - -EWRAM_DATA struct Sprite gSprites[MAX_SPRITES + 1] = {0}; -EWRAM_DATA static u16 sSpritePriorities[MAX_SPRITES] = {0}; -EWRAM_DATA static u8 sSpriteOrder[MAX_SPRITES] = {0}; -EWRAM_DATA static bool8 sShouldProcessSpriteCopyRequests = 0; -EWRAM_DATA static u8 sSpriteCopyRequestCount = 0; -EWRAM_DATA static struct SpriteCopyRequest sSpriteCopyRequests[MAX_SPRITES] = {0}; -EWRAM_DATA u8 gOamLimit = 0; -EWRAM_DATA u16 gReservedSpriteTileCount = 0; -EWRAM_DATA static u8 sSpriteTileAllocBitmap[128] = {0}; -EWRAM_DATA s16 gSpriteCoordOffsetX = 0; -EWRAM_DATA s16 gSpriteCoordOffsetY = 0; -EWRAM_DATA struct OamMatrix gOamMatrices[OAM_MATRIX_COUNT] = {0}; -EWRAM_DATA bool8 gAffineAnimsDisabled = FALSE; - -void ResetSpriteData(void) -{ - ResetOamRange(0, 128); - ResetAllSprites(); - ClearSpriteCopyRequests(); - ResetAffineAnimData(); - FreeSpriteTileRanges(); - gOamLimit = 64; - gReservedSpriteTileCount = 0; - AllocSpriteTiles(0); - gSpriteCoordOffsetX = 0; - gSpriteCoordOffsetY = 0; -} - -void AnimateSprites(void) -{ - u8 i; - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - - if (sprite->inUse) - { - sprite->callback(sprite); - - if (sprite->inUse) - AnimateSprite(sprite); - } - } -} - -void BuildOamBuffer(void) -{ - u8 temp; - UpdateOamCoords(); - BuildSpritePriorities(); - SortSprites(); - temp = gMain.oamLoadDisabled; - gMain.oamLoadDisabled = TRUE; - AddSpritesToOamBuffer(); - CopyMatricesToOamBuffer(); - gMain.oamLoadDisabled = temp; - sShouldProcessSpriteCopyRequests = TRUE; -} - -void UpdateOamCoords(void) -{ - u8 i; - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - if (sprite->inUse && !sprite->invisible) - { - if (sprite->coordOffsetEnabled) - { - sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX; - sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY; - } - else - { - sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX; - sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY; - } - } - } -} - -void BuildSpritePriorities(void) -{ - u16 i; - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - u16 priority = sprite->subpriority | (sprite->oam.priority << 8); - sSpritePriorities[i] = priority; - } -} - -void SortSprites(void) -{ - u8 i; - for (i = 1; i < MAX_SPRITES; i++) - { - u8 j = i; - struct Sprite *sprite1 = &gSprites[sSpriteOrder[i - 1]]; - struct Sprite *sprite2 = &gSprites[sSpriteOrder[i]]; - u16 sprite1Priority = sSpritePriorities[sSpriteOrder[i - 1]]; - u16 sprite2Priority = sSpritePriorities[sSpriteOrder[i]]; - s16 sprite1Y = sprite1->oam.y; - s16 sprite2Y = sprite2->oam.y; - - if (sprite1Y >= DISPLAY_HEIGHT) - sprite1Y = sprite1Y - 256; - - if (sprite2Y >= DISPLAY_HEIGHT) - sprite2Y = sprite2Y - 256; - - if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite1->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite1->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite1Y > 128) - sprite1Y = sprite1Y - 256; - } - } - - if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite2->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite2->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite2Y > 128) - sprite2Y = sprite2Y - 256; - } - } - - while (j > 0 - && ((sprite1Priority > sprite2Priority) - || (sprite1Priority == sprite2Priority && sprite1Y < sprite2Y))) - { - u8 temp = sSpriteOrder[j]; - sSpriteOrder[j] = sSpriteOrder[j - 1]; - sSpriteOrder[j - 1] = temp; - - // UB: If j equals 1, then j-- makes j equal 0. - // Then, sSpriteOrder[-1] gets accessed below. - // Although this doesn't result in a bug in the ROM, - // the behavior is undefined. - j--; -#ifdef UBFIX - if (j == 0) - break; -#endif - - sprite1 = &gSprites[sSpriteOrder[j - 1]]; - sprite2 = &gSprites[sSpriteOrder[j]]; - sprite1Priority = sSpritePriorities[sSpriteOrder[j - 1]]; - sprite2Priority = sSpritePriorities[sSpriteOrder[j]]; - sprite1Y = sprite1->oam.y; - sprite2Y = sprite2->oam.y; - - if (sprite1Y >= DISPLAY_HEIGHT) - sprite1Y = sprite1Y - 256; - - if (sprite2Y >= DISPLAY_HEIGHT) - sprite2Y = sprite2Y - 256; - - if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite1->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite1->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite1Y > 128) - sprite1Y = sprite1Y - 256; - } - } - - if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE - && sprite2->oam.size == ST_OAM_SIZE_3) - { - u32 shape = sprite2->oam.shape; - if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) - { - if (sprite2Y > 128) - sprite2Y = sprite2Y - 256; - } - } - } - } -} - -void CopyMatricesToOamBuffer(void) -{ - u8 i; - for (i = 0; i < OAM_MATRIX_COUNT; i++) - { - u32 base = 4 * i; - gMain.oamBuffer[base + 0].affineParam = gOamMatrices[i].a; - gMain.oamBuffer[base + 1].affineParam = gOamMatrices[i].b; - gMain.oamBuffer[base + 2].affineParam = gOamMatrices[i].c; - gMain.oamBuffer[base + 3].affineParam = gOamMatrices[i].d; - } -} - -void AddSpritesToOamBuffer(void) -{ - u8 i = 0; - u8 oamIndex = 0; - - while (i < MAX_SPRITES) - { - struct Sprite *sprite = &gSprites[sSpriteOrder[i]]; - if (sprite->inUse && !sprite->invisible && AddSpriteToOamBuffer(sprite, &oamIndex)) - return; - i++; - } - - while (oamIndex < gOamLimit) - { - gMain.oamBuffer[oamIndex] = gDummyOamData; - oamIndex++; - } -} - -u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - if (!gSprites[i].inUse) - return CreateSpriteAt(i, template, x, y, subpriority); - - return MAX_SPRITES; -} - -u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - s16 i; - - for (i = MAX_SPRITES - 1; i > -1; i--) - if (!gSprites[i].inUse) - return CreateSpriteAt(i, template, x, y, subpriority); - - return MAX_SPRITES; -} - -u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)) -{ - u8 index = CreateSprite(&gDummySpriteTemplate, 0, 0, 31); - - if (index == MAX_SPRITES) - { - return MAX_SPRITES; - } - else - { - gSprites[index].invisible = TRUE; - gSprites[index].callback = callback; - return index; - } -} - -u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - struct Sprite *sprite = &gSprites[index]; - - ResetSprite(sprite); - - sprite->inUse = TRUE; - sprite->animBeginning = TRUE; - sprite->affineAnimBeginning = TRUE; - sprite->usingSheet = TRUE; - - sprite->subpriority = subpriority; - sprite->oam = *template->oam; - sprite->anims = template->anims; - sprite->affineAnims = template->affineAnims; - sprite->template = template; - sprite->callback = template->callback; - sprite->pos1.x = x; - sprite->pos1.y = y; - - CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); - - if (template->tileTag == 0xFFFF) - { - s16 tileNum; - sprite->images = template->images; - tileNum = AllocSpriteTiles((u8)(sprite->images->size / TILE_SIZE_4BPP)); - if (tileNum == -1) - { - ResetSprite(sprite); - return MAX_SPRITES; - } - sprite->oam.tileNum = tileNum; - sprite->usingSheet = FALSE; - sprite->sheetTileStart = 0; - } - else - { - sprite->sheetTileStart = GetSpriteTileStartByTag(template->tileTag); - SetSpriteSheetFrameTileNum(sprite); - } - - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - InitSpriteAffineAnim(sprite); - - if (template->paletteTag != 0xFFFF) - sprite->oam.paletteNum = IndexOfSpritePaletteTag(template->paletteTag); - - return index; -} - -u8 CreateSpriteAndAnimate(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - struct Sprite *sprite = &gSprites[i]; - - if (!gSprites[i].inUse) - { - u8 index = CreateSpriteAt(i, template, x, y, subpriority); - - if (index == MAX_SPRITES) - return MAX_SPRITES; - - gSprites[i].callback(sprite); - - if (gSprites[i].inUse) - AnimateSprite(sprite); - - return index; - } - } - - return MAX_SPRITES; -} - -void DestroySprite(struct Sprite *sprite) -{ - if (sprite->inUse) - { - if (!sprite->usingSheet) - { - u16 i; - u16 tileEnd = (sprite->images->size / TILE_SIZE_4BPP) + sprite->oam.tileNum; - for (i = sprite->oam.tileNum; i < tileEnd; i++) - FREE_SPRITE_TILE(i); - } - ResetSprite(sprite); - } -} - -void ResetOamRange(u8 a, u8 b) -{ - u8 i; - - for (i = a; i < b; i++) - { - gMain.oamBuffer[i] = *(struct OamData *)&gDummyOamData; - } -} - -void LoadOam(void) -{ - if (!gMain.oamLoadDisabled) - CpuCopy32(gMain.oamBuffer, (void *)OAM, sizeof(gMain.oamBuffer)); -} - -void ClearSpriteCopyRequests(void) -{ - u8 i; - - sShouldProcessSpriteCopyRequests = FALSE; - sSpriteCopyRequestCount = 0; - - for (i = 0; i < MAX_SPRITE_COPY_REQUESTS; i++) - { - sSpriteCopyRequests[i].src = 0; - sSpriteCopyRequests[i].dest = 0; - sSpriteCopyRequests[i].size = 0; - } -} - -void ResetOamMatrices(void) -{ - u8 i; - for (i = 0; i < OAM_MATRIX_COUNT; i++) - { - // set to identity matrix - gOamMatrices[i].a = 0x0100; - gOamMatrices[i].b = 0x0000; - gOamMatrices[i].c = 0x0000; - gOamMatrices[i].d = 0x0100; - } -} - -void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d) -{ - gOamMatrices[matrixNum].a = a; - gOamMatrices[matrixNum].b = b; - gOamMatrices[matrixNum].c = c; - gOamMatrices[matrixNum].d = d; -} - -void ResetSprite(struct Sprite *sprite) -{ - *sprite = sDummySprite; -} - -void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode) -{ - u8 x = sCenterToCornerVecTable[shape][size][0]; - u8 y = sCenterToCornerVecTable[shape][size][1]; - - if (affineMode & ST_OAM_AFFINE_DOUBLE_MASK) - { - x *= 2; - y *= 2; - } - - sprite->centerToCornerVecX = x; - sprite->centerToCornerVecY = y; -} - -s16 AllocSpriteTiles(u16 tileCount) -{ - u16 i; - s16 start; - u16 numTilesFound; - - if (tileCount == 0) - { - // Free all unreserved tiles if the tile count is 0. - for (i = gReservedSpriteTileCount; i < TOTAL_OBJ_TILE_COUNT; i++) - FREE_SPRITE_TILE(i); - - return 0; - } - - i = gReservedSpriteTileCount; - - for (;;) - { - while (SPRITE_TILE_IS_ALLOCATED(i)) - { - i++; - - if (i == TOTAL_OBJ_TILE_COUNT) - return -1; - } - - start = i; - numTilesFound = 1; - - while (numTilesFound != tileCount) - { - i++; - - if (i == TOTAL_OBJ_TILE_COUNT) - return -1; - - if (!SPRITE_TILE_IS_ALLOCATED(i)) - numTilesFound++; - else - break; - } - - if (numTilesFound == tileCount) - break; - } - - for (i = start; i < tileCount + start; i++) - ALLOC_SPRITE_TILE(i); - - return start; -} - -u8 SpriteTileAllocBitmapOp(u16 bit, u8 op) -{ - u8 index = bit / 8; - u8 shift = bit % 8; - u8 val = bit % 8; - u8 retVal = 0; - - if (op == 0) - { - val = ~(1 << val); - sSpriteTileAllocBitmap[index] &= val; - } - else if (op == 1) - { - val = (1 << val); - sSpriteTileAllocBitmap[index] |= val; - } - else - { - retVal = 1 << shift; - retVal &= sSpriteTileAllocBitmap[index]; - } - - return retVal; -} - -void SpriteCallbackDummy(struct Sprite *sprite) -{ -} - -void ProcessSpriteCopyRequests(void) -{ - if (sShouldProcessSpriteCopyRequests) - { - u8 i = 0; - - while (sSpriteCopyRequestCount > 0) - { - CpuCopy16(sSpriteCopyRequests[i].src, sSpriteCopyRequests[i].dest, sSpriteCopyRequests[i].size); - sSpriteCopyRequestCount--; - i++; - } - - sShouldProcessSpriteCopyRequests = FALSE; - } -} - -void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images) -{ - if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) - { - sSpriteCopyRequests[sSpriteCopyRequestCount].src = images[index].data; - sSpriteCopyRequests[sSpriteCopyRequestCount].dest = (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileNum; - sSpriteCopyRequests[sSpriteCopyRequestCount].size = images[index].size; - sSpriteCopyRequestCount++; - } -} - -void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size) -{ - if (sSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) - { - sSpriteCopyRequests[sSpriteCopyRequestCount].src = src; - sSpriteCopyRequests[sSpriteCopyRequestCount].dest = dest; - sSpriteCopyRequests[sSpriteCopyRequestCount].size = size; - sSpriteCopyRequestCount++; - } -} - -void CopyFromSprites(u8 *dest) -{ - u32 i; - u8 *src = (u8 *)gSprites; - for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) - { - *dest = *src; - dest++; - src++; - } -} - -void CopyToSprites(u8 *src) -{ - u32 i; - u8 *dest = (u8 *)gSprites; - for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) - { - *dest = *src; - src++; - dest++; - } -} - -void ResetAllSprites(void) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - ResetSprite(&gSprites[i]); - sSpriteOrder[i] = i; - } - - ResetSprite(&gSprites[i]); -} - -// UB: template pointer may point to freed temporary storage -void FreeSpriteTiles(struct Sprite *sprite) -{ - if (sprite->template->tileTag != 0xFFFF) - FreeSpriteTilesByTag(sprite->template->tileTag); -} - -// UB: template pointer may point to freed temporary storage -void FreeSpritePalette(struct Sprite *sprite) -{ - FreeSpritePaletteByTag(sprite->template->paletteTag); -} - -void FreeSpriteOamMatrix(struct Sprite *sprite) -{ - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - { - FreeOamMatrix(sprite->oam.matrixNum); - sprite->oam.affineMode = ST_OAM_AFFINE_OFF; - } -} - -void DestroySpriteAndFreeResources(struct Sprite *sprite) -{ - FreeSpriteTiles(sprite); - FreeSpritePalette(sprite); - FreeSpriteOamMatrix(sprite); - DestroySprite(sprite); -} - -void AnimateSprite(struct Sprite *sprite) -{ - sAnimFuncs[sprite->animBeginning](sprite); - - if (!gAffineAnimsDisabled) - sAffineAnimFuncs[sprite->affineAnimBeginning](sprite); -} - -void BeginAnim(struct Sprite *sprite) -{ - s16 imageValue; - u8 duration; - u8 hFlip; - u8 vFlip; - - sprite->animCmdIndex = 0; - sprite->animEnded = FALSE; - sprite->animLoopCounter = 0; - imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - - if (imageValue != -1) - { - sprite->animBeginning = FALSE; - duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - - if (duration) - duration--; - - sprite->animDelayCounter = duration; - - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - - if (sprite->usingSheet) - sprite->oam.tileNum = sprite->sheetTileStart + imageValue; - else - RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); - } -} - -void ContinueAnim(struct Sprite *sprite) -{ - if (sprite->animDelayCounter) - { - u8 hFlip; - u8 vFlip; - DecrementAnimDelayCounter(sprite); - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - } - else if (!sprite->animPaused) - { - s16 type; - s16 funcIndex; - sprite->animCmdIndex++; - type = sprite->anims[sprite->animNum][sprite->animCmdIndex].type; - funcIndex = 3; - if (type < 0) - funcIndex = type + 3; - sAnimCmdFuncs[funcIndex](sprite); - } -} - -void AnimCmd_frame(struct Sprite *sprite) -{ - s16 imageValue; - u8 duration; - u8 hFlip; - u8 vFlip; - - imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - - if (duration) - duration--; - - sprite->animDelayCounter = duration; - - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - - if (sprite->usingSheet) - sprite->oam.tileNum = sprite->sheetTileStart + imageValue; - else - RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); -} - -void AnimCmd_end(struct Sprite *sprite) -{ - sprite->animCmdIndex--; - sprite->animEnded = TRUE; -} - -void AnimCmd_jump(struct Sprite *sprite) -{ - s16 imageValue; - u8 duration; - u8 hFlip; - u8 vFlip; - - sprite->animCmdIndex = sprite->anims[sprite->animNum][sprite->animCmdIndex].jump.target; - - imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; - hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; - vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; - - if (duration) - duration--; - - sprite->animDelayCounter = duration; - - if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) - SetSpriteOamFlipBits(sprite, hFlip, vFlip); - - if (sprite->usingSheet) - sprite->oam.tileNum = sprite->sheetTileStart + imageValue; - else - RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); -} - -void AnimCmd_loop(struct Sprite *sprite) -{ - if (sprite->animLoopCounter) - ContinueAnimLoop(sprite); - else - BeginAnimLoop(sprite); -} - -void BeginAnimLoop(struct Sprite *sprite) -{ - sprite->animLoopCounter = sprite->anims[sprite->animNum][sprite->animCmdIndex].loop.count; - JumpToTopOfAnimLoop(sprite); - ContinueAnim(sprite); -} - -void ContinueAnimLoop(struct Sprite *sprite) -{ - sprite->animLoopCounter--; - JumpToTopOfAnimLoop(sprite); - ContinueAnim(sprite); -} - -void JumpToTopOfAnimLoop(struct Sprite *sprite) -{ - if (sprite->animLoopCounter) - { - sprite->animCmdIndex--; - - while (sprite->anims[sprite->animNum][sprite->animCmdIndex - 1].type != -3) - { - if (sprite->animCmdIndex == 0) - break; - sprite->animCmdIndex--; - } - - sprite->animCmdIndex--; - } -} - -void BeginAffineAnim(struct Sprite *sprite) -{ - if ((sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) && sprite->affineAnims[0][0].type != 32767) - { - struct AffineAnimFrameCmd frameCmd; - u8 matrixNum = GetSpriteMatrixNum(sprite); - AffineAnimStateRestartAnim(matrixNum); - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - sprite->affineAnimBeginning = FALSE; - sprite->affineAnimEnded = FALSE; - ApplyAffineAnimFrame(matrixNum, &frameCmd); - sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; - if (sprite->flags_f) - obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); - } -} - -void ContinueAffineAnim(struct Sprite *sprite) -{ - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - { - u8 matrixNum = GetSpriteMatrixNum(sprite); - - if (sAffineAnimStates[matrixNum].delayCounter) - AffineAnimDelay(matrixNum, sprite); - else if (sprite->affineAnimPaused) - return; - else - { - s16 type; - s16 funcIndex; - sAffineAnimStates[matrixNum].animCmdIndex++; - type = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].type; - funcIndex = 3; - if (type >= 32765) - funcIndex = type - 32765; - sAffineAnimCmdFuncs[funcIndex](matrixNum, sprite); - } - if (sprite->flags_f) - obj_update_pos2(sprite, sprite->data[6], sprite->data[7]); - } -} - -void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite) -{ - if (!DecrementAffineAnimDelayCounter(sprite, matrixNum)) - { - struct AffineAnimFrameCmd frameCmd; - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &frameCmd); - } -} - -void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite) -{ - if (sAffineAnimStates[matrixNum].loopCounter) - ContinueAffineAnimLoop(matrixNum, sprite); - else - BeginAffineAnimLoop(matrixNum, sprite); -} - -void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) -{ - sAffineAnimStates[matrixNum].loopCounter = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].loop.count; - JumpToTopOfAffineAnimLoop(matrixNum, sprite); - ContinueAffineAnim(sprite); -} - -void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) -{ - sAffineAnimStates[matrixNum].loopCounter--; - JumpToTopOfAffineAnimLoop(matrixNum, sprite); - ContinueAffineAnim(sprite); -} - -void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) -{ - if (sAffineAnimStates[matrixNum].loopCounter) - { - sAffineAnimStates[matrixNum].animCmdIndex--; - - while (sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex - 1].type != 32765) - { - if (sAffineAnimStates[matrixNum].animCmdIndex == 0) - break; - sAffineAnimStates[matrixNum].animCmdIndex--; - } - - sAffineAnimStates[matrixNum].animCmdIndex--; - } -} - -void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite) -{ - struct AffineAnimFrameCmd frameCmd; - sAffineAnimStates[matrixNum].animCmdIndex = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].jump.target; - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - ApplyAffineAnimFrame(matrixNum, &frameCmd); - sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; -} - -void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite) -{ - struct AffineAnimFrameCmd dummyFrameCmd = {0}; - sprite->affineAnimEnded = TRUE; - sAffineAnimStates[matrixNum].animCmdIndex--; - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); -} - -void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite) -{ - struct AffineAnimFrameCmd frameCmd; - GetAffineAnimFrame(matrixNum, sprite, &frameCmd); - ApplyAffineAnimFrame(matrixNum, &frameCmd); - sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; -} - -void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix) -{ - gOamMatrices[destMatrixIndex].a = srcMatrix->a; - gOamMatrices[destMatrixIndex].b = srcMatrix->b; - gOamMatrices[destMatrixIndex].c = srcMatrix->c; - gOamMatrices[destMatrixIndex].d = srcMatrix->d; -} - -u8 GetSpriteMatrixNum(struct Sprite *sprite) -{ - u8 matrixNum = 0; - if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) - matrixNum = sprite->oam.matrixNum; - return matrixNum; -} - -void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3) -{ - sprite->data[6] = a2; - sprite->data[7] = a3; - sprite->flags_f = 1; -} - -s32 sub_8007E28(s32 a0, s32 a1, s32 a2) -{ - s32 subResult, var1; - - subResult = a1 - a0; - if (subResult < 0) - var1 = -(subResult) >> 9; - else - var1 = -(subResult >> 9); - return a2 - ((u32)(a2 * a1) / (u32)(a0) + var1); -} - -void obj_update_pos2(struct Sprite *sprite, s32 a1, s32 a2) -{ - s32 var0, var1, var2; - - u32 matrixNum = sprite->oam.matrixNum; - if (a1 != 0x800) - { - var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].width; - var1 = var0 << 8; - var2 = (var0 << 16) / gOamMatrices[matrixNum].a; - sprite->pos2.x = sub_8007E28(var1, var2, a1); - } - if (a2 != 0x800) - { - var0 = sOamDimensions32[sprite->oam.shape][sprite->oam.size].height; - var1 = var0 << 8; - var2 = (var0 << 16) / gOamMatrices[matrixNum].d; - sprite->pos2.y = sub_8007E28(var1, var2, a2); - } -} - -void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip) -{ - sprite->oam.matrixNum &= 0x7; - sprite->oam.matrixNum |= (((hFlip ^ sprite->hFlip) & 1) << 3); - sprite->oam.matrixNum |= (((vFlip ^ sprite->vFlip) & 1) << 4); -} - -void AffineAnimStateRestartAnim(u8 matrixNum) -{ - sAffineAnimStates[matrixNum].animCmdIndex = 0; - sAffineAnimStates[matrixNum].delayCounter = 0; - sAffineAnimStates[matrixNum].loopCounter = 0; -} - -void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum) -{ - sAffineAnimStates[matrixNum].animNum = animNum; - sAffineAnimStates[matrixNum].animCmdIndex = 0; - sAffineAnimStates[matrixNum].delayCounter = 0; - sAffineAnimStates[matrixNum].loopCounter = 0; - sAffineAnimStates[matrixNum].xScale = 0x0100; - sAffineAnimStates[matrixNum].yScale = 0x0100; - sAffineAnimStates[matrixNum].rotation = 0; -} - -void AffineAnimStateReset(u8 matrixNum) -{ - sAffineAnimStates[matrixNum].animNum = 0; - sAffineAnimStates[matrixNum].animCmdIndex = 0; - sAffineAnimStates[matrixNum].delayCounter = 0; - sAffineAnimStates[matrixNum].loopCounter = 0; - sAffineAnimStates[matrixNum].xScale = 0x0100; - sAffineAnimStates[matrixNum].yScale = 0x0100; - sAffineAnimStates[matrixNum].rotation = 0; -} - -void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) -{ - sAffineAnimStates[matrixNum].xScale = frameCmd->xScale; - sAffineAnimStates[matrixNum].yScale = frameCmd->yScale; - sAffineAnimStates[matrixNum].rotation = frameCmd->rotation << 8; -} - -void DecrementAnimDelayCounter(struct Sprite *sprite) -{ - if (!sprite->animPaused) - sprite->animDelayCounter--; -} - -bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum) -{ - if (!sprite->affineAnimPaused) - --sAffineAnimStates[matrixNum].delayCounter; - return sprite->affineAnimPaused; -} - -void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) -{ - struct ObjAffineSrcData srcData; - struct OamMatrix matrix; - sAffineAnimStates[matrixNum].xScale += frameCmd->xScale; - sAffineAnimStates[matrixNum].yScale += frameCmd->yScale; - sAffineAnimStates[matrixNum].rotation = (sAffineAnimStates[matrixNum].rotation + (frameCmd->rotation << 8)) & ~0xFF; - srcData.xScale = ConvertScaleParam(sAffineAnimStates[matrixNum].xScale); - srcData.yScale = ConvertScaleParam(sAffineAnimStates[matrixNum].yScale); - srcData.rotation = sAffineAnimStates[matrixNum].rotation; - ObjAffineSet(&srcData, &matrix, 1, 2); - CopyOamMatrix(matrixNum, &matrix); -} - -s16 ConvertScaleParam(s16 scale) -{ - s32 val = 0x10000; - return SAFE_DIV(val, scale); -} - -void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd) -{ - frameCmd->xScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.xScale; - frameCmd->yScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.yScale; - frameCmd->rotation = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.rotation; - frameCmd->duration = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.duration; -} - -void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) -{ - struct AffineAnimFrameCmd dummyFrameCmd = {0}; - - if (frameCmd->duration) - { - frameCmd->duration--; - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, frameCmd); - } - else - { - ApplyAffineAnimFrameAbsolute(matrixNum, frameCmd); - ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); - } -} - -void StartSpriteAnim(struct Sprite *sprite, u8 animNum) -{ - sprite->animNum = animNum; - sprite->animBeginning = TRUE; - sprite->animEnded = FALSE; -} - -void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum) -{ - if (sprite->animNum != animNum) - StartSpriteAnim(sprite, animNum); -} - -void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex) -{ - u8 temp = sprite->animPaused; - sprite->animCmdIndex = animCmdIndex - 1; - sprite->animDelayCounter = 0; - sprite->animBeginning = FALSE; - sprite->animEnded = FALSE; - sprite->animPaused = FALSE; - ContinueAnim(sprite); - if (sprite->animDelayCounter) - sprite->animDelayCounter++; - sprite->animPaused = temp; -} - -void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - AffineAnimStateStartAnim(matrixNum, animNum); - sprite->affineAnimBeginning = TRUE; - sprite->affineAnimEnded = FALSE; -} - -void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - if (sAffineAnimStates[matrixNum].animNum != animNum) - StartSpriteAffineAnim(sprite, animNum); -} - -void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - sAffineAnimStates[matrixNum].animNum = animNum; - sprite->affineAnimBeginning = TRUE; - sprite->affineAnimEnded = FALSE; -} - -void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) -{ - u8 matrixNum = GetSpriteMatrixNum(sprite); - if (sAffineAnimStates[matrixNum].animNum != animNum) - ChangeSpriteAffineAnim(sprite, animNum); -} - -void SetSpriteSheetFrameTileNum(struct Sprite *sprite) -{ - if (sprite->usingSheet) - { - s16 tileOffset = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; - if (tileOffset < 0) - tileOffset = 0; - sprite->oam.tileNum = sprite->sheetTileStart + tileOffset; - } -} - -void ResetAffineAnimData(void) -{ - u8 i; - - gAffineAnimsDisabled = FALSE; - gOamMatrixAllocBitmap = 0; - - ResetOamMatrices(); - - for (i = 0; i < OAM_MATRIX_COUNT; i++) - AffineAnimStateReset(i); -} - -u8 AllocOamMatrix(void) -{ - u8 i = 0; - u32 bit = 1; - u32 bitmap = gOamMatrixAllocBitmap; - - while (i < OAM_MATRIX_COUNT) - { - if (!(bitmap & bit)) - { - gOamMatrixAllocBitmap |= bit; - return i; - } - - i++; - bit <<= 1; - } - - return 0xFF; -} - -void FreeOamMatrix(u8 matrixNum) -{ - u8 i = 0; - u32 bit = 1; - - while (i < matrixNum) - { - i++; - bit <<= 1; - } - - gOamMatrixAllocBitmap &= ~bit; - SetOamMatrix(matrixNum, 0x100, 0, 0, 0x100); -} - -void InitSpriteAffineAnim(struct Sprite *sprite) -{ - u8 matrixNum = AllocOamMatrix(); - if (matrixNum != 0xFF) - { - CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); - sprite->oam.matrixNum = matrixNum; - sprite->affineAnimBeginning = TRUE; - AffineAnimStateReset(matrixNum); - } -} - -void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation) -{ - struct ObjAffineSrcData srcData; - struct OamMatrix matrix; - srcData.xScale = ConvertScaleParam(xScale); - srcData.yScale = ConvertScaleParam(yScale); - srcData.rotation = rotation; - ObjAffineSet(&srcData, &matrix, 1, 2); - CopyOamMatrix(matrixNum, &matrix); -} - -u16 LoadSpriteSheet(const struct SpriteSheet *sheet) -{ - s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); - - if (tileStart < 0) - { - return 0; - } - else - { - AllocSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); - CpuCopy16(sheet->data, (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileStart, sheet->size); - return (u16)tileStart; - } -} - -void LoadSpriteSheets(const struct SpriteSheet *sheets) -{ - u8 i; - for (i = 0; sheets[i].data != NULL; i++) - LoadSpriteSheet(&sheets[i]); -} - -void FreeSpriteTilesByTag(u16 tag) -{ - u8 index = IndexOfSpriteTileTag(tag); - if (index != 0xFF) - { - u16 i; - u16 *rangeStarts; - u16 *rangeCounts; - u16 start; - u16 count; - rangeStarts = sSpriteTileRanges; - start = rangeStarts[index * 2]; - rangeCounts = sSpriteTileRanges + 1; - count = rangeCounts[index * 2]; - - for (i = start; i < start + count; i++) - FREE_SPRITE_TILE(i); - - sSpriteTileRangeTags[index] = 0xFFFF; - } -} - -void FreeSpriteTileRanges(void) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - sSpriteTileRangeTags[i] = 0xFFFF; - SET_SPRITE_TILE_RANGE(i, 0, 0); - } -} - -u16 GetSpriteTileStartByTag(u16 tag) -{ - u8 index = IndexOfSpriteTileTag(tag); - if (index == 0xFF) - return 0xFFFF; - return sSpriteTileRanges[index * 2]; -} - -u8 IndexOfSpriteTileTag(u16 tag) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - if (sSpriteTileRangeTags[i] == tag) - return i; - - return 0xFF; -} - -u16 GetSpriteTileTagByTileStart(u16 start) -{ - u8 i; - - for (i = 0; i < MAX_SPRITES; i++) - { - if (sSpriteTileRangeTags[i] != 0xFFFF && sSpriteTileRanges[i * 2] == start) - return sSpriteTileRangeTags[i]; - } - - return 0xFFFF; -} - -void AllocSpriteTileRange(u16 tag, u16 start, u16 count) -{ - u8 freeIndex = IndexOfSpriteTileTag(0xFFFF); - sSpriteTileRangeTags[freeIndex] = tag; - SET_SPRITE_TILE_RANGE(freeIndex, start, count); -} - -void FreeAllSpritePalettes(void) -{ - u8 i; - gReservedSpritePaletteCount = 0; - for (i = 0; i < 16; i++) - sSpritePaletteTags[i] = 0xFFFF; -} - -u8 LoadSpritePalette(const struct SpritePalette *palette) -{ - u8 index = IndexOfSpritePaletteTag(palette->tag); - - if (index != 0xFF) - return index; - - index = IndexOfSpritePaletteTag(0xFFFF); - - if (index == 0xFF) - { - return 0xFF; - } - else - { - sSpritePaletteTags[index] = palette->tag; - DoLoadSpritePalette(palette->data, index * 16); - return index; - } -} - -void LoadSpritePalettes(const struct SpritePalette *palettes) -{ - u8 i; - for (i = 0; palettes[i].data != NULL; i++) - if (LoadSpritePalette(&palettes[i]) == 0xFF) - break; -} - -void DoLoadSpritePalette(const u16 *src, u16 paletteOffset) -{ - LoadPalette(src, paletteOffset + 0x100, 32); -} - -u8 AllocSpritePalette(u16 tag) -{ - u8 index = IndexOfSpritePaletteTag(0xFFFF); - if (index == 0xFF) - { - return 0xFF; - } - else - { - sSpritePaletteTags[index] = tag; - return index; - } -} - -u8 IndexOfSpritePaletteTag(u16 tag) -{ - u8 i; - for (i = gReservedSpritePaletteCount; i < 16; i++) - if (sSpritePaletteTags[i] == tag) - return i; - - return 0xFF; -} - -u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum) -{ - return sSpritePaletteTags[paletteNum]; -} - -void FreeSpritePaletteByTag(u16 tag) -{ - u8 index = IndexOfSpritePaletteTag(tag); - if (index != 0xFF) - sSpritePaletteTags[index] = 0xFFFF; -} - -void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables) -{ - sprite->subspriteTables = subspriteTables; - sprite->subspriteTableNum = 0; - sprite->subspriteMode = SUBSPRITES_ON; -} - -bool8 AddSpriteToOamBuffer(struct Sprite *sprite, u8 *oamIndex) -{ - if (*oamIndex >= gOamLimit) - return 1; - - if (!sprite->subspriteTables || sprite->subspriteMode == SUBSPRITES_OFF) - { - gMain.oamBuffer[*oamIndex] = sprite->oam; - (*oamIndex)++; - return 0; - } - else - { - return AddSubspritesToOamBuffer(sprite, &gMain.oamBuffer[*oamIndex], oamIndex); - } -} - -bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex) -{ - const struct SubspriteTable *subspriteTable; - struct OamData *oam; - - if (*oamIndex >= gOamLimit) - return 1; - - subspriteTable = &sprite->subspriteTables[sprite->subspriteTableNum]; - oam = &sprite->oam; - - if (!subspriteTable || !subspriteTable->subsprites) - { - *destOam = *oam; - (*oamIndex)++; - return 0; - } - else - { - u16 tileNum; - u16 baseX; - u16 baseY; - u8 subspriteCount; - u8 hFlip; - u8 vFlip; - u8 i; - - tileNum = oam->tileNum; - subspriteCount = subspriteTable->subspriteCount; - hFlip = ((s32)oam->matrixNum >> 3) & 1; - vFlip = ((s32)oam->matrixNum >> 4) & 1; - baseX = oam->x - sprite->centerToCornerVecX; - baseY = oam->y - sprite->centerToCornerVecY; - - for (i = 0; i < subspriteCount; i++, (*oamIndex)++) - { - u16 x; - u16 y; - - if (*oamIndex >= gOamLimit) - return 1; - - x = subspriteTable->subsprites[i].x; - y = subspriteTable->subsprites[i].y; - - if (hFlip) - { - s8 width = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].width; - s16 right = x; - right += width; - x = right; - x = ~x + 1; - } - - if (vFlip) - { - s8 height = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].height; - s16 bottom = y; - bottom += height; - y = bottom; - y = ~y + 1; - } - - destOam[i] = *oam; - destOam[i].shape = subspriteTable->subsprites[i].shape; - destOam[i].size = subspriteTable->subsprites[i].size; - destOam[i].x = (s16)baseX + (s16)x; - destOam[i].y = baseY + y; - destOam[i].tileNum = tileNum + subspriteTable->subsprites[i].tileOffset; - - if (sprite->subspriteMode != SUBSPRITES_IGNORE_PRIORITY) - destOam[i].priority = subspriteTable->subsprites[i].priority; - } - } - - return 0; -} diff --git a/src/string_util.c b/src/string_util.c deleted file mode 100644 index 92f8eea5a..000000000 --- a/src/string_util.c +++ /dev/null @@ -1,781 +0,0 @@ -#include "global.h" -#include "string_util.h" -#include "text.h" -#include "strings.h" - -EWRAM_DATA u8 gStringVar1[0x100] = {0}; -EWRAM_DATA u8 gStringVar2[0x100] = {0}; -EWRAM_DATA u8 gStringVar3[0x100] = {0}; -EWRAM_DATA u8 gStringVar4[0x3E8] = {0}; -EWRAM_DATA static u8 sUnknownStringVar[16] = {0}; - -static const u8 sDigits[] = __("0123456789ABCDEF"); - -static const s32 sPowersOfTen[] = -{ - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, -}; - -u8 *StringCopy10(u8 *dest, const u8 *src) -{ - u8 i; - u32 limit = 10; - - for (i = 0; i < limit; i++) - { - dest[i] = src[i]; - - if (dest[i] == EOS) - return &dest[i]; - } - - dest[i] = EOS; - return &dest[i]; -} - -u8 *StringGetEnd10(u8 *str) -{ - u8 i; - u32 limit = 10; - - for (i = 0; i < limit; i++) - if (str[i] == EOS) - return &str[i]; - - str[i] = EOS; - return &str[i]; -} - -u8 *StringCopy7(u8 *dest, const u8 *src) -{ - s32 i; - s32 limit = 7; - - for (i = 0; i < limit; i++) - { - dest[i] = src[i]; - - if (dest[i] == EOS) - return &dest[i]; - } - - dest[i] = EOS; - return &dest[i]; -} - -u8 *StringCopy(u8 *dest, const u8 *src) -{ - while (*src != EOS) - { - *dest = *src; - dest++; - src++; - } - - *dest = EOS; - return dest; -} - -u8 *StringAppend(u8 *dest, const u8 *src) -{ - while (*dest != EOS) - dest++; - - return StringCopy(dest, src); -} - -u8 *StringCopyN(u8 *dest, const u8 *src, u8 n) -{ - u16 i; - - for (i = 0; i < n; i++) - dest[i] = src[i]; - - return &dest[n]; -} - -u8 *StringAppendN(u8 *dest, const u8 *src, u8 n) -{ - while (*dest != EOS) - dest++; - - return StringCopyN(dest, src, n); -} - -u16 StringLength(const u8 *str) -{ - u16 length = 0; - - while (str[length] != EOS) - length++; - - return length; -} - -s32 StringCompare(const u8 *str1, const u8 *str2) -{ - while (*str1 == *str2) - { - if (*str1 == EOS) - return 0; - str1++; - str2++; - } - - return *str1 - *str2; -} - -s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n) -{ - while (*str1 == *str2) - { - if (*str1 == EOS) - return 0; - str1++; - str2++; - if (--n == 0) - return 0; - } - - return *str1 - *str2; -} - -bool8 IsStringLengthAtLeast(const u8 *str, s32 n) -{ - u8 i; - - for (i = 0; i < n; i++) - if (str[i] && str[i] != EOS) - return TRUE; - - return FALSE; -} - -u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) -{ - enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; - s32 powerOfTen; - s32 largestPowerOfTen = sPowersOfTen[n - 1]; - - state = WAITING_FOR_NONZERO_DIGIT; - - if (mode == STR_CONV_MODE_RIGHT_ALIGN) - state = WRITING_SPACES; - - if (mode == STR_CONV_MODE_LEADING_ZEROS) - state = WRITING_DIGITS; - - for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) - { - u8 c; - u16 digit = value / powerOfTen; - s32 temp = value - (powerOfTen * digit); - - if (state == WRITING_DIGITS) - { - u8 *out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (digit != 0 || powerOfTen == 1) - { - u8 *out; - state = WRITING_DIGITS; - out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (state == WRITING_SPACES) - { - *dest++ = 0x77; - } - - value = temp; - } - - *dest = EOS; - return dest; -} - -u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n) -{ - enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; - s32 powerOfTen; - s32 largestPowerOfTen = sPowersOfTen[n - 1]; - - state = WAITING_FOR_NONZERO_DIGIT; - - if (mode == STR_CONV_MODE_RIGHT_ALIGN) - state = WRITING_SPACES; - - if (mode == STR_CONV_MODE_LEADING_ZEROS) - state = WRITING_DIGITS; - - for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) - { - u8 c; - u16 digit = value / powerOfTen; - u32 temp = value - (powerOfTen * digit); - - if (state == WRITING_DIGITS) - { - u8 *out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (digit != 0 || powerOfTen == 1) - { - u8 *out; - state = WRITING_DIGITS; - out = dest++; - - if (digit <= 9) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (state == WRITING_SPACES) - { - *dest++ = 0x77; - } - - value = temp; - } - - *dest = EOS; - return dest; -} - -u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) -{ - enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; - u8 i; - s32 powerOfSixteen; - s32 largestPowerOfSixteen = 1; - - for (i = 1; i < n; i++) - largestPowerOfSixteen *= 16; - - state = WAITING_FOR_NONZERO_DIGIT; - - if (mode == STR_CONV_MODE_RIGHT_ALIGN) - state = WRITING_SPACES; - - if (mode == STR_CONV_MODE_LEADING_ZEROS) - state = WRITING_DIGITS; - - for (powerOfSixteen = largestPowerOfSixteen; powerOfSixteen > 0; powerOfSixteen /= 16) - { - u8 c; - u32 digit = value / powerOfSixteen; - s32 temp = value % powerOfSixteen; - - if (state == WRITING_DIGITS) - { - char *out = dest++; - - if (digit <= 0xF) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (digit != 0 || powerOfSixteen == 1) - { - char *out; - state = WRITING_DIGITS; - out = dest++; - - if (digit <= 0xF) - c = sDigits[digit]; - else - c = CHAR_QUESTION_MARK; - - *out = c; - } - else if (state == WRITING_SPACES) - { - *dest++ = 0x77; - } - - value = temp; - } - - *dest = EOS; - return dest; -} - -u8 *StringExpandPlaceholders(u8 *dest, const u8 *src) -{ - for (;;) - { - u8 c = *src++; - u8 placeholderId; - const u8 *expandedString; - - switch (c) - { - case PLACEHOLDER_BEGIN: - placeholderId = *src++; - expandedString = GetExpandedPlaceholder(placeholderId); - dest = StringExpandPlaceholders(dest, expandedString); - break; - case EXT_CTRL_CODE_BEGIN: - *dest++ = c; - c = *src++; - *dest++ = c; - - switch (c) - { - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_FILL_WINDOW: - case EXT_CTRL_CODE_JPN: - case EXT_CTRL_CODE_ENG: - case EXT_CTRL_CODE_PAUSE_MUSIC: - case EXT_CTRL_CODE_RESUME_MUSIC: - break; - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - *dest++ = *src++; - case EXT_CTRL_CODE_PLAY_BGM: - *dest++ = *src++; - default: - *dest++ = *src++; - } - break; - case EOS: - *dest = EOS; - return dest; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - case CHAR_NEWLINE: - default: - *dest++ = c; - } - } -} - -u8 *StringBraille(u8 *dest, const u8 *src) -{ - const u8 setBrailleFont[] = { - EXT_CTRL_CODE_BEGIN, - EXT_CTRL_CODE_SIZE, - 6, - EOS - }; - const u8 gotoLine2[] = { - CHAR_NEWLINE, - EXT_CTRL_CODE_BEGIN, - EXT_CTRL_CODE_SHIFT_DOWN, - 2, - EOS - }; - - dest = StringCopy(dest, setBrailleFont); - - for (;;) - { - u8 c = *src++; - - switch (c) - { - case EOS: - *dest = c; - return dest; - case CHAR_NEWLINE: - dest = StringCopy(dest, gotoLine2); - break; - default: - *dest++ = c; - *dest++ = c + 0x40; - break; - } - } -} - -static const u8 *ExpandPlaceholder_UnknownStringVar(void) -{ - return sUnknownStringVar; -} - -static const u8 *ExpandPlaceholder_PlayerName(void) -{ - return gSaveBlock2Ptr->playerName; -} - -static const u8 *ExpandPlaceholder_StringVar1(void) -{ - return gStringVar1; -} - -static const u8 *ExpandPlaceholder_StringVar2(void) -{ - return gStringVar2; -} - -static const u8 *ExpandPlaceholder_StringVar3(void) -{ - return gStringVar3; -} - -static const u8 *ExpandPlaceholder_KunChan(void) -{ - if (gSaveBlock2Ptr->playerGender == MALE) - return gText_ExpandedPlaceholder_Kun; - else - return gText_ExpandedPlaceholder_Chan; -} - -static const u8 *ExpandPlaceholder_RivalName(void) -{ - if (gSaveBlock2Ptr->playerGender == MALE) - return gText_ExpandedPlaceholder_May; - else - return gText_ExpandedPlaceholder_Brendan; -} - -static const u8 *ExpandPlaceholder_Version(void) -{ - return gText_ExpandedPlaceholder_Emerald; -} - -static const u8 *ExpandPlaceholder_Aqua(void) -{ - return gText_ExpandedPlaceholder_Aqua; -} - -static const u8 *ExpandPlaceholder_Magma(void) -{ - return gText_ExpandedPlaceholder_Magma; -} - -static const u8 *ExpandPlaceholder_Archie(void) -{ - return gText_ExpandedPlaceholder_Archie; -} - -static const u8 *ExpandPlaceholder_Maxie(void) -{ - return gText_ExpandedPlaceholder_Maxie; -} - -static const u8 *ExpandPlaceholder_Kyogre(void) -{ - return gText_ExpandedPlaceholder_Kyogre; -} - -static const u8 *ExpandPlaceholder_Groudon(void) -{ - return gText_ExpandedPlaceholder_Groudon; -} - -const u8 *GetExpandedPlaceholder(u32 id) -{ - typedef const u8 *(*ExpandPlaceholderFunc)(void); - - static const ExpandPlaceholderFunc funcs[] = - { - [PLACEHOLDER_ID_UNKNOWN] = ExpandPlaceholder_UnknownStringVar, - [PLACEHOLDER_ID_PLAYER] = ExpandPlaceholder_PlayerName, - [PLACEHOLDER_ID_STRING_VAR_1] = ExpandPlaceholder_StringVar1, - [PLACEHOLDER_ID_STRING_VAR_2] = ExpandPlaceholder_StringVar2, - [PLACEHOLDER_ID_STRING_VAR_3] = ExpandPlaceholder_StringVar3, - [PLACEHOLDER_ID_KUN] = ExpandPlaceholder_KunChan, - [PLACEHOLDER_ID_RIVAL] = ExpandPlaceholder_RivalName, - [PLACEHOLDER_ID_VERSION] = ExpandPlaceholder_Version, - [PLACEHOLDER_ID_AQUA] = ExpandPlaceholder_Aqua, - [PLACEHOLDER_ID_MAGMA] = ExpandPlaceholder_Magma, - [PLACEHOLDER_ID_ARCHIE] = ExpandPlaceholder_Archie, - [PLACEHOLDER_ID_MAXIE] = ExpandPlaceholder_Maxie, - [PLACEHOLDER_ID_KYOGRE] = ExpandPlaceholder_Kyogre, - [PLACEHOLDER_ID_GROUDON] = ExpandPlaceholder_Groudon, - }; - - if (id >= ARRAY_COUNT(funcs)) - return gText_ExpandedPlaceholder_Empty; - else - return funcs[id](); -} - -u8 *StringFill(u8 *dest, u8 c, u16 n) -{ - u16 i; - - for (i = 0; i < n; i++) - *dest++ = c; - - *dest = EOS; - return dest; -} - -u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n) -{ - while (*src != EOS) - { - *dest++ = *src++; - - if (n) - n--; - } - - n--; - - while (n != (u16)-1) - { - *dest++ = c; - n--; - } - - *dest = EOS; - return dest; -} - -u8 *StringFillWithTerminator(u8 *dest, u16 n) -{ - return StringFill(dest, EOS, n); -} - -u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n) -{ - u32 i; - - for (i = n - 1; i != (u32)-1; i--) - { - if (*src == EOS) - { - break; - } - else - { - *dest++ = *src++; - if (*(src - 1) == CHAR_EXTRA_SYMBOL) - *dest++ = *src++; - } - } - - *dest = EOS; - return dest; -} - -u32 StringLength_Multibyte(const u8 *str) -{ - u32 length = 0; - - while (*str != EOS) - { - if (*str == CHAR_EXTRA_SYMBOL) - str++; - str++; - length++; - } - - return length; -} - -u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color) -{ - *dest = EXT_CTRL_CODE_BEGIN; - dest++; - - switch (colorType) - { - case 0: - *dest = EXT_CTRL_CODE_COLOR; - dest++; - break; - case 1: - *dest = EXT_CTRL_CODE_SHADOW; - dest++; - break; - case 2: - *dest = EXT_CTRL_CODE_HIGHLIGHT; - dest++; - break; - } - - *dest = color; - dest++; - *dest = EOS; - return dest; -} - -bool32 IsStringJapanese(u8 *str) -{ - while (*str != EOS) - { - if (*str < CHAR_0) - if (*str != CHAR_SPACE) - return TRUE; - str++; - } - - return FALSE; -} - -bool32 sub_800924C(u8 *str, s32 n) -{ - s32 i; - - for (i = 0; *str != EOS && i < n; i++) - { - if (*str < CHAR_0) - if (*str != CHAR_SPACE) - return TRUE; - str++; - } - - return FALSE; -} - -u8 GetExtCtrlCodeLength(u8 code) -{ - static const u8 lengths[] = - { - [0] = 1, - [EXT_CTRL_CODE_COLOR] = 2, - [EXT_CTRL_CODE_HIGHLIGHT] = 2, - [EXT_CTRL_CODE_SHADOW] = 2, - [EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW] = 4, - [EXT_CTRL_CODE_PALETTE] = 2, - [EXT_CTRL_CODE_SIZE] = 2, - [EXT_CTRL_CODE_RESET_SIZE] = 1, - [EXT_CTRL_CODE_PAUSE] = 2, - [EXT_CTRL_CODE_PAUSE_UNTIL_PRESS] = 1, - [EXT_CTRL_CODE_WAIT_SE] = 1, - [EXT_CTRL_CODE_PLAY_BGM] = 3, - [EXT_CTRL_CODE_ESCAPE] = 2, - [EXT_CTRL_CODE_SHIFT_TEXT] = 2, - [EXT_CTRL_CODE_SHIFT_DOWN] = 2, - [EXT_CTRL_CODE_FILL_WINDOW] = 1, - [EXT_CTRL_CODE_PLAY_SE] = 3, - [EXT_CTRL_CODE_CLEAR] = 2, - [EXT_CTRL_CODE_SKIP] = 2, - [EXT_CTRL_CODE_CLEAR_TO] = 2, - [EXT_CTRL_CODE_MIN_LETTER_SPACING] = 2, - [EXT_CTRL_CODE_JPN] = 1, - [EXT_CTRL_CODE_ENG] = 1, - [EXT_CTRL_CODE_PAUSE_MUSIC] = 1, - [EXT_CTRL_CODE_RESUME_MUSIC] = 1, - }; - - u8 length = 0; - if (code < ARRAY_COUNT(lengths)) - length = lengths[code]; - return length; -} - -static const u8 *SkipExtCtrlCode(const u8 *s) -{ - while (*s == EXT_CTRL_CODE_BEGIN) - { - s++; - s += GetExtCtrlCodeLength(*s); - } - - return s; -} - -s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2) -{ - s32 retVal = 0; - - while (1) - { - str1 = SkipExtCtrlCode(str1); - str2 = SkipExtCtrlCode(str2); - - if (*str1 > *str2) - break; - - if (*str1 < *str2) - { - retVal = -1; - if (*str2 == EOS) - retVal = 1; - } - - if (*str1 == EOS) - return retVal; - - str1++; - str2++; - } - - retVal = 1; - - if (*str1 == EOS) - retVal = -1; - - return retVal; -} - -void ConvertInternationalString(u8 *s, u8 language) -{ - if (language == LANGUAGE_JAPANESE) - { - u8 i; - - StripExtCtrlCodes(s); - i = StringLength(s); - s[i++] = EXT_CTRL_CODE_BEGIN; - s[i++] = EXT_CTRL_CODE_ENG; - s[i++] = EOS; - - i--; - - while (i != (u8)-1) - { - s[i + 2] = s[i]; - i--; - } - - s[0] = EXT_CTRL_CODE_BEGIN; - s[1] = EXT_CTRL_CODE_JPN; - } -} - -void StripExtCtrlCodes(u8 *str) -{ - u16 srcIndex = 0; - u16 destIndex = 0; - while (str[srcIndex] != EOS) - { - if (str[srcIndex] == EXT_CTRL_CODE_BEGIN) - { - srcIndex++; - srcIndex += GetExtCtrlCodeLength(str[srcIndex]); - } - else - { - str[destIndex++] = str[srcIndex++]; - } - } - str[destIndex] = EOS; -} diff --git a/src/text.c b/src/text.c deleted file mode 100644 index eb993c421..000000000 --- a/src/text.c +++ /dev/null @@ -1,1808 +0,0 @@ -#include "global.h" -#include "battle.h" -#include "main.h" -#include "m4a.h" -#include "palette.h" -#include "sound.h" -#include "constants/songs.h" -#include "string_util.h" -#include "window.h" -#include "text.h" -#include "blit.h" -#include "menu.h" -#include "dynamic_placeholder_text_util.h" - -EWRAM_DATA struct TextPrinter gTempTextPrinter = {0}; -EWRAM_DATA struct TextPrinter gTextPrinters[NUM_TEXT_PRINTERS] = {0}; - -static u16 gFontHalfRowLookupTable[0x51]; -static u16 gLastTextBgColor; -static u16 gLastTextFgColor; -static u16 gLastTextShadowColor; - -const struct FontInfo *gFonts; -u8 gDisableTextPrinters; -struct TextGlyph gCurGlyph; -TextFlags gTextFlags; - -const u8 gFontHalfRowOffsets[] = -{ - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, - 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, - 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, - 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, - 0x24, 0x25, 0x26, 0x24, 0x27, 0x28, 0x29, 0x27, 0x2A, 0x2B, 0x2C, 0x2A, 0x24, 0x25, 0x26, 0x24, - 0x2D, 0x2E, 0x2F, 0x2D, 0x30, 0x31, 0x32, 0x30, 0x33, 0x34, 0x35, 0x33, 0x2D, 0x2E, 0x2F, 0x2D, - 0x1B, 0x1C, 0x1D, 0x1B, 0x1E, 0x1F, 0x20, 0x1E, 0x21, 0x22, 0x23, 0x21, 0x1B, 0x1C, 0x1D, 0x1B, - 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, - 0x3F, 0x40, 0x41, 0x3F, 0x42, 0x43, 0x44, 0x42, 0x45, 0x46, 0x47, 0x45, 0x3F, 0x40, 0x41, 0x3F, - 0x48, 0x49, 0x4A, 0x48, 0x4B, 0x4C, 0x4D, 0x4B, 0x4E, 0x4F, 0x50, 0x4E, 0x48, 0x49, 0x4A, 0x48, - 0x36, 0x37, 0x38, 0x36, 0x39, 0x3A, 0x3B, 0x39, 0x3C, 0x3D, 0x3E, 0x3C, 0x36, 0x37, 0x38, 0x36, - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00, - 0x09, 0x0A, 0x0B, 0x09, 0x0C, 0x0D, 0x0E, 0x0C, 0x0F, 0x10, 0x11, 0x0F, 0x09, 0x0A, 0x0B, 0x09, - 0x12, 0x13, 0x14, 0x12, 0x15, 0x16, 0x17, 0x15, 0x18, 0x19, 0x1A, 0x18, 0x12, 0x13, 0x14, 0x12, - 0x00, 0x01, 0x02, 0x00, 0x03, 0x04, 0x05, 0x03, 0x06, 0x07, 0x08, 0x06, 0x00, 0x01, 0x02, 0x00 -}; - -const u8 gDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow.4bpp"); -const u8 gDarkDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow_RS.4bpp"); -const u8 gUnusedFRLGBlankedDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_blanked_down_arrow.4bpp"); -const u8 gUnusedFRLGDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_down_arrow.4bpp"); -const u8 gDownArrowYCoords[] = { 0x0, 0x1, 0x2, 0x1 }; -const u8 gWindowVerticalScrollSpeeds[] = { 0x1, 0x2, 0x4, 0x0 }; - -const struct GlyphWidthFunc gGlyphWidthFuncs[] = -{ - { 0x0, GetGlyphWidthFont0 }, - { 0x1, GetGlyphWidthFont1 }, - { 0x2, GetGlyphWidthFont2 }, - { 0x3, GetGlyphWidthFont2 }, - { 0x4, GetGlyphWidthFont2 }, - { 0x5, GetGlyphWidthFont2 }, - { 0x6, GetGlyphWidthFont6 }, - { 0x7, GetGlyphWidthFont7 }, - { 0x8, GetGlyphWidthFont8 } -}; - -const struct KeypadIcon gKeypadIcons[] = -{ - [CHAR_A_BUTTON] = { 0x0, 0x8, 0xC }, - [CHAR_B_BUTTON] = { 0x1, 0x8, 0xC }, - [CHAR_L_BUTTON] = { 0x2, 0x10, 0xC }, - [CHAR_R_BUTTON] = { 0x4, 0x10, 0xC }, - [CHAR_START_BUTTON] = { 0x6, 0x18, 0xC }, - [CHAR_SELECT_BUTTON] = { 0x9, 0x18, 0xC }, - [CHAR_DPAD_UP] = { 0xC, 0x8, 0xC }, - [CHAR_DPAD_DOWN] = { 0xD, 0x8, 0xC }, - [CHAR_DPAD_LEFT] = { 0xE, 0x8, 0xC }, - [CHAR_DPAD_RIGHT] = { 0xF, 0x8, 0xC }, - [CHAR_DPAD_UPDOWN] = { 0x20, 0x8, 0xC }, - [CHAR_DPAD_LEFTRIGHT] = { 0x21, 0x8, 0xC }, - [CHAR_DPAD_NONE] = { 0x22, 0x8, 0xC } -}; - -const u8 gKeypadIconTiles[] = INCBIN_U8("graphics/fonts/keypad_icons.4bpp"); - -const struct FontInfo gFontInfos[] = -{ - { Font0Func, 0x5, 0xC, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font1Func, 0x6, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font2Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font3Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font4Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font5Func, 0x6, 0xE, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font6Func, 0x8, 0x10, 0x0, 0x8, 0x0, 0x2, 0x1, 0x3 }, - { Font7Func, 0x5, 0x10, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { Font8Func, 0x5, 0x8, 0x0, 0x0, 0x0, 0x2, 0x1, 0x3 }, - { NULL, 0x8, 0x8, 0x0, 0x0, 0x0, 0x1, 0x2, 0xF } -}; - -const u8 gMenuCursorDimensions[][2] = -{ - { 0x8, 0xC }, - { 0x8, 0xF }, - { 0x8, 0xE }, - { 0x8, 0xE }, - { 0x8, 0xE }, - { 0x8, 0xE }, - { 0x8, 0x10 }, - { 0x8, 0xF }, - { 0x8, 0x8 }, - { 0x0, 0x0 } -}; - -const u16 gFont9JapaneseGlyphs[] = INCBIN_U16("graphics/fonts/font9.hwjpnfont"); - -extern const u16 gFont8LatinGlyphs[]; -extern const u8 gFont8LatinGlyphWidths[]; -extern const u16 gFont0LatinGlyphs[]; -extern const u8 gFont0LatinGlyphWidths[]; -extern const u16 gFont7LatinGlyphs[]; -extern const u8 gFont7LatinGlyphWidths[]; -extern const u16 gFont2LatinGlyphs[]; -extern const u8 gFont2LatinGlyphWidths[]; -extern const u16 gFont1LatinGlyphs[]; -extern const u8 gFont1LatinGlyphWidths[]; -extern const u16 gFont0JapaneseGlyphs[]; -extern const u16 gFont1JapaneseGlyphs[]; -extern const u16 gFont2JapaneseGlyphs[]; -extern const u8 gFont2JapaneseGlyphWidths[]; - -void SetFontsPointer(const struct FontInfo *fonts) -{ - gFonts = fonts; -} - -void DeactivateAllTextPrinters(void) -{ - int printer; - for (printer = 0; printer < NUM_TEXT_PRINTERS; ++printer) - gTextPrinters[printer].active = 0; -} - -u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) -{ - struct TextPrinterTemplate printerTemplate; - - printerTemplate.currentChar = str; - printerTemplate.windowId = windowId; - printerTemplate.fontId = fontId; - printerTemplate.x = x; - printerTemplate.y = y; - printerTemplate.currentX = x; - printerTemplate.currentY = y; - printerTemplate.letterSpacing = gFonts[fontId].letterSpacing; - printerTemplate.lineSpacing = gFonts[fontId].lineSpacing; - printerTemplate.unk = gFonts[fontId].unk; - printerTemplate.fgColor = gFonts[fontId].fgColor; - printerTemplate.bgColor = gFonts[fontId].bgColor; - printerTemplate.shadowColor = gFonts[fontId].shadowColor; - return AddTextPrinter(&printerTemplate, speed, callback); -} - -bool16 AddTextPrinter(struct TextPrinterTemplate *printerTemplate, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) -{ - int i; - u16 j; - - if (!gFonts) - return FALSE; - - gTempTextPrinter.active = 1; - gTempTextPrinter.state = 0; - gTempTextPrinter.textSpeed = speed; - gTempTextPrinter.delayCounter = 0; - gTempTextPrinter.scrollDistance = 0; - - for (i = 0; i < 7; i++) - { - gTempTextPrinter.subStructFields[i] = 0; - } - - gTempTextPrinter.printerTemplate = *printerTemplate; - gTempTextPrinter.callback = callback; - gTempTextPrinter.minLetterSpacing = 0; - gTempTextPrinter.japanese = 0; - - GenerateFontHalfRowLookupTable(printerTemplate->fgColor, printerTemplate->bgColor, printerTemplate->shadowColor); - if (speed != TEXT_SPEED_FF && speed != 0) - { - --gTempTextPrinter.textSpeed; - gTextPrinters[printerTemplate->windowId] = gTempTextPrinter; - } - else - { - gTempTextPrinter.textSpeed = 0; - for (j = 0; j < 0x400; ++j) - { - if (RenderFont(&gTempTextPrinter) == 1) - break; - } - - if (speed != TEXT_SPEED_FF) - CopyWindowToVram(gTempTextPrinter.printerTemplate.windowId, 2); - gTextPrinters[printerTemplate->windowId].active = 0; - } - gDisableTextPrinters = 0; - return TRUE; -} - -void RunTextPrinters(void) -{ - int i; - - if (gDisableTextPrinters == 0) - { - for (i = 0; i < NUM_TEXT_PRINTERS; ++i) - { - if (gTextPrinters[i].active) - { - u16 temp = RenderFont(&gTextPrinters[i]); - switch (temp) - { - case 0: - CopyWindowToVram(gTextPrinters[i].printerTemplate.windowId, 2); - case 3: - if (gTextPrinters[i].callback != 0) - gTextPrinters[i].callback(&gTextPrinters[i].printerTemplate, temp); - break; - case 1: - gTextPrinters[i].active = 0; - break; - } - } - } - } -} - -bool16 IsTextPrinterActive(u8 id) -{ - return gTextPrinters[id].active; -} - -u32 RenderFont(struct TextPrinter *textPrinter) -{ - u32 ret; - while (TRUE) - { - ret = gFonts[textPrinter->printerTemplate.fontId].fontFunction(textPrinter); - if (ret != 2) - return ret; - } -} - -void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor) -{ - u32 fg12, bg12, shadow12; - u32 temp; - - u16 *current = gFontHalfRowLookupTable; - - gLastTextBgColor = bgColor; - gLastTextFgColor = fgColor; - gLastTextShadowColor = shadowColor; - - bg12 = bgColor << 12; - fg12 = fgColor << 12; - shadow12 = shadowColor << 12; - - temp = (bgColor << 8) | (bgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (bgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (bgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (fgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (fgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (fgColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (shadowColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (shadowColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (shadowColor << 4) | bgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (bgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (bgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (bgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (fgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (fgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (fgColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (shadowColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (shadowColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (shadowColor << 4) | fgColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (bgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (bgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (bgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (fgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (fgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (fgColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (bgColor << 8) | (shadowColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (fgColor << 8) | (shadowColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; - - temp = (shadowColor << 8) | (shadowColor << 4) | shadowColor; - *(current++) = (bg12) | temp; - *(current++) = (fg12) | temp; - *(current++) = (shadow12) | temp; -} - -void SaveTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) -{ - *bgColor = gLastTextBgColor; - *fgColor = gLastTextFgColor; - *shadowColor = gLastTextShadowColor; -} - -void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) -{ - GenerateFontHalfRowLookupTable(*fgColor, *bgColor, *shadowColor); -} - -void DecompressGlyphTile(const void *src_, void *dest_) -{ - u32 temp; - const u16 *src = src_; - u32 *dest = dest_; - - temp = *(src++); - *(dest)++ = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); - - temp = *(src++); - *(dest++) = ((gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]]) << 16) | (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]); -} - -u8 GetLastTextColor(u8 colorType) -{ - switch (colorType) - { - case 0: - return gLastTextFgColor; - case 2: - return gLastTextBgColor; - case 1: - return gLastTextShadowColor; - default: - return 0; - } -} - -inline static void GLYPH_COPY(u8 *windowTiles, u32 widthOffset, u32 j, u32 i, u32 *glyphPixels, s32 width, s32 height) -{ - u32 xAdd, yAdd, pixelData, bits, toOrr, dummyX; - u8 *dst; - - xAdd = j + width; - yAdd = i + height; - dummyX = j; - for (; i < yAdd; i++) - { - pixelData = *glyphPixels++; - for (j = dummyX; j < xAdd; j++) - { - if ((toOrr = pixelData & 0xF)) - { - dst = windowTiles + ((j / 8) * 32) + ((j % 8) / 2) + ((i / 8) * widthOffset) + ((i % 8) * 4); - bits = ((j & 1) * 4); - *dst = (toOrr << bits) | (*dst & (0xF0 >> bits)); - } - pixelData >>= 4; - } - } -} - -void CopyGlyphToWindow(struct TextPrinter *textPrinter) -{ - struct Window *window; - struct WindowTemplate *template; - u32 *glyphPixels; - u32 currX, currY, widthOffset; - s32 glyphWidth, glyphHeight; - u8 *windowTiles; - - window = &gWindows[textPrinter->printerTemplate.windowId]; - template = &window->window; - - if ((glyphWidth = (template->width * 8) - textPrinter->printerTemplate.currentX) > gCurGlyph.width) - glyphWidth = gCurGlyph.width; - - if ((glyphHeight = (template->height * 8) - textPrinter->printerTemplate.currentY) > gCurGlyph.height) - glyphHeight = gCurGlyph.height; - - currX = textPrinter->printerTemplate.currentX; - currY = textPrinter->printerTemplate.currentY; - glyphPixels = gCurGlyph.gfxBufferTop; - windowTiles = window->tileData; - widthOffset = template->width * 32; - - if (glyphWidth < 9) - { - if (glyphHeight < 9) - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, glyphHeight); - } - else - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, glyphWidth, 8); - GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, glyphWidth, glyphHeight - 8); - } - } - else - { - if (glyphHeight < 9) - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, glyphHeight); - GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, glyphHeight); - } - else - { - GLYPH_COPY(windowTiles, widthOffset, currX, currY, glyphPixels, 8, 8); - GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY, glyphPixels + 8, glyphWidth - 8, 8); - GLYPH_COPY(windowTiles, widthOffset, currX, currY + 8, glyphPixels + 16, 8, glyphHeight - 8); - GLYPH_COPY(windowTiles, widthOffset, currX + 8, currY + 8, glyphPixels + 24, glyphWidth - 8, glyphHeight - 8); - } - } -} - -void ClearTextSpan(struct TextPrinter *textPrinter, u32 width) -{ - struct Window *window; - struct Bitmap pixels_data; - struct TextGlyph *glyph; - u8* glyphHeight; - - if (gLastTextBgColor != 0) - { - window = &gWindows[textPrinter->printerTemplate.windowId]; - pixels_data.pixels = window->tileData; - pixels_data.width = window->window.width << 3; - pixels_data.height = window->window.height << 3; - - glyph = &gCurGlyph; - glyphHeight = &glyph->height; - - FillBitmapRect4Bit( - &pixels_data, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - width, - *glyphHeight, - gLastTextBgColor); - } -} - -u16 Font0Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 0; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font1Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 1; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font2Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 2; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font3Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 3; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font4Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 4; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font5Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 5; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font7Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 7; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -u16 Font8Func(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->hasGlyphIdBeenSet == FALSE) - { - subStruct->glyphId = 8; - subStruct->hasGlyphIdBeenSet = TRUE; - } - return RenderText(textPrinter); -} - -void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (gTextFlags.autoScroll == 1) - { - subStruct->autoScrollDelay = 0; - } - else - { - subStruct->downArrowYPosIdx = 0; - subStruct->downArrowDelay = 0; - } -} - -void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - const u8 *arrowTiles; - - if (gTextFlags.autoScroll == 0) - { - if (subStruct->downArrowDelay != 0) - { - subStruct->downArrowDelay--; - } - else - { - FillWindowPixelRect( - textPrinter->printerTemplate.windowId, - textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - 8, - 16); - - switch (gTextFlags.useAlternateDownArrow) - { - case FALSE: - default: - arrowTiles = gDownArrowTiles; - break; - case TRUE: - arrowTiles = gDarkDownArrowTiles; - break; - } - - BlitBitmapRectToWindow( - textPrinter->printerTemplate.windowId, - arrowTiles, - 0, - gDownArrowYCoords[subStruct->downArrowYPosIdx], - 8, - 16, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - 8, - 16); - CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); - - subStruct->downArrowDelay = 8; - subStruct->downArrowYPosIdx++; - } - } -} - -void TextPrinterClearDownArrow(struct TextPrinter *textPrinter) -{ - FillWindowPixelRect( - textPrinter->printerTemplate.windowId, - textPrinter->printerTemplate.bgColor << 4 | textPrinter->printerTemplate.bgColor, - textPrinter->printerTemplate.currentX, - textPrinter->printerTemplate.currentY, - 8, - 16); - CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); -} - -bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - - if (subStruct->autoScrollDelay == 49) - { - return TRUE; - } - else - { - subStruct->autoScrollDelay++; - return FALSE; - } -} - -bool16 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) -{ - bool8 result = FALSE; - if (gTextFlags.autoScroll != 0) - { - result = TextPrinterWaitAutoMode(textPrinter); - } - else - { - TextPrinterDrawDownArrow(textPrinter); - if (JOY_NEW(A_BUTTON | B_BUTTON)) - { - result = TRUE; - PlaySE(SE_SELECT); - } - } - return result; -} - -bool16 TextPrinterWait(struct TextPrinter *textPrinter) -{ - bool16 result = FALSE; - if (gTextFlags.autoScroll != 0) - { - result = TextPrinterWaitAutoMode(textPrinter); - } - else - { - if (JOY_NEW(A_BUTTON | B_BUTTON)) - { - result = TRUE; - PlaySE(SE_SELECT); - } - } - return result; -} - -void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex) -{ - const u8 *arrowTiles; - - if (*counter != 0) - { - --*counter; - } - else - { - FillWindowPixelRect(windowId, (bgColor << 4) | bgColor, x, y, 0x8, 0x10); - if (drawArrow == 0) - { - switch (gTextFlags.useAlternateDownArrow) - { - case 0: - default: - arrowTiles = gDownArrowTiles; - break; - case 1: - arrowTiles = gDarkDownArrowTiles; - break; - } - - BlitBitmapRectToWindow( - windowId, - arrowTiles, - 0, - gDownArrowYCoords[*yCoordIndex & 3], - 0x8, - 0x10, - x, - y - 2, - 0x8, - 0x10); - CopyWindowToVram(windowId, 0x2); - *counter = 8; - ++*yCoordIndex; - } - } -} - -u16 RenderText(struct TextPrinter *textPrinter) -{ - struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); - u16 currChar; - s32 width; - s32 widthHelper; - - switch (textPrinter->state) - { - case 0: - if ((JOY_HELD(A_BUTTON | B_BUTTON)) && subStruct->hasPrintBeenSpedUp) - textPrinter->delayCounter = 0; - - if (textPrinter->delayCounter && textPrinter->textSpeed) - { - textPrinter->delayCounter--; - if (gTextFlags.canABSpeedUpPrint && (JOY_NEW(A_BUTTON | B_BUTTON))) - { - subStruct->hasPrintBeenSpedUp = TRUE; - textPrinter->delayCounter = 0; - } - return 3; - } - - if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED) && gTextFlags.autoScroll) - textPrinter->delayCounter = 3; - else - textPrinter->delayCounter = textPrinter->textSpeed; - - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - - switch (currChar) - { - case CHAR_NEWLINE: - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentY += (gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing); - return 2; - case PLACEHOLDER_BEGIN: - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_BEGIN: - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - switch (currChar) - { - case EXT_CTRL_CODE_COLOR: - textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_HIGHLIGHT: - textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_SHADOW: - textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - textPrinter->printerTemplate.fgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - textPrinter->printerTemplate.bgColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - textPrinter->printerTemplate.shadowColor = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - GenerateFontHalfRowLookupTable(textPrinter->printerTemplate.fgColor, textPrinter->printerTemplate.bgColor, textPrinter->printerTemplate.shadowColor); - return 2; - case EXT_CTRL_CODE_PALETTE: - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_SIZE: - subStruct->glyphId = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_RESET_SIZE: - return 2; - case EXT_CTRL_CODE_PAUSE: - textPrinter->delayCounter = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - textPrinter->state = 6; - return 2; - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - textPrinter->state = 1; - if (gTextFlags.autoScroll) - subStruct->autoScrollDelay = 0; - return 3; - case EXT_CTRL_CODE_WAIT_SE: - textPrinter->state = 5; - return 3; - case EXT_CTRL_CODE_PLAY_BGM: - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - currChar |= *textPrinter->printerTemplate.currentChar << 8; - textPrinter->printerTemplate.currentChar++; - PlayBGM(currChar); - return 2; - case EXT_CTRL_CODE_ESCAPE: - currChar = *textPrinter->printerTemplate.currentChar | 0x100; - textPrinter->printerTemplate.currentChar++; - break; - case EXT_CTRL_CODE_PLAY_SE: - currChar = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - currChar |= (*textPrinter->printerTemplate.currentChar << 8); - textPrinter->printerTemplate.currentChar++; - PlaySE(currChar); - return 2; - case EXT_CTRL_CODE_SHIFT_TEXT: - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x + *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_SHIFT_DOWN: - textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y + *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_FILL_WINDOW: - FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; - return 2; - case EXT_CTRL_CODE_PAUSE_MUSIC: - m4aMPlayStop(&gMPlayInfo_BGM); - return 2; - case EXT_CTRL_CODE_RESUME_MUSIC: - m4aMPlayContinue(&gMPlayInfo_BGM); - return 2; - case EXT_CTRL_CODE_CLEAR: - width = *textPrinter->printerTemplate.currentChar; - textPrinter->printerTemplate.currentChar++; - if (width > 0) - { - ClearTextSpan(textPrinter, width); - textPrinter->printerTemplate.currentX += width; - return 0; - } - return 2; - case EXT_CTRL_CODE_SKIP: - textPrinter->printerTemplate.currentX = *textPrinter->printerTemplate.currentChar + textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_CLEAR_TO: - { - widthHelper = *textPrinter->printerTemplate.currentChar; - widthHelper += textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentChar++; - width = widthHelper - textPrinter->printerTemplate.currentX; - if (width > 0) - { - ClearTextSpan(textPrinter, width); - textPrinter->printerTemplate.currentX += width; - return 0; - } - } - return 2; - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - textPrinter->minLetterSpacing = *textPrinter->printerTemplate.currentChar++; - return 2; - case EXT_CTRL_CODE_JPN: - textPrinter->japanese = 1; - return 2; - case EXT_CTRL_CODE_ENG: - textPrinter->japanese = 0; - return 2; - } - break; - case CHAR_PROMPT_CLEAR: - textPrinter->state = 2; - TextPrinterInitDownArrowCounters(textPrinter); - return 3; - case CHAR_PROMPT_SCROLL: - textPrinter->state = 3; - TextPrinterInitDownArrowCounters(textPrinter); - return 3; - case CHAR_EXTRA_SYMBOL: - currChar = *textPrinter->printerTemplate.currentChar | 0x100; - textPrinter->printerTemplate.currentChar++; - break; - case CHAR_KEYPAD_ICON: - currChar = *textPrinter->printerTemplate.currentChar++; - gCurGlyph.width = DrawKeypadIcon(textPrinter->printerTemplate.windowId, currChar, textPrinter->printerTemplate.currentX, textPrinter->printerTemplate.currentY); - textPrinter->printerTemplate.currentX += gCurGlyph.width + textPrinter->printerTemplate.letterSpacing; - return 0; - case EOS: - return 1; - } - - switch (subStruct->glyphId) - { - case 0: - DecompressGlyphFont0(currChar, textPrinter->japanese); - break; - case 1: - DecompressGlyphFont1(currChar, textPrinter->japanese); - break; - case 2: - case 3: - case 4: - case 5: - DecompressGlyphFont2(currChar, textPrinter->japanese); - break; - case 7: - DecompressGlyphFont7(currChar, textPrinter->japanese); - break; - case 8: - DecompressGlyphFont8(currChar, textPrinter->japanese); - break; - case 6: - break; - } - - CopyGlyphToWindow(textPrinter); - - if (textPrinter->minLetterSpacing) - { - textPrinter->printerTemplate.currentX += gCurGlyph.width; - width = textPrinter->minLetterSpacing - gCurGlyph.width; - if (width > 0) - { - ClearTextSpan(textPrinter, width); - textPrinter->printerTemplate.currentX += width; - } - } - else - { - if (textPrinter->japanese) - textPrinter->printerTemplate.currentX += (gCurGlyph.width + textPrinter->printerTemplate.letterSpacing); - else - textPrinter->printerTemplate.currentX += gCurGlyph.width; - } - return 0; - case 1: - if (TextPrinterWait(textPrinter)) - textPrinter->state = 0; - return 3; - case 2: - if (TextPrinterWaitWithDownArrow(textPrinter)) - { - FillWindowPixelBuffer(textPrinter->printerTemplate.windowId, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->printerTemplate.currentY = textPrinter->printerTemplate.y; - textPrinter->state = 0; - } - return 3; - case 3: - if (TextPrinterWaitWithDownArrow(textPrinter)) - { - TextPrinterClearDownArrow(textPrinter); - textPrinter->scrollDistance = gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing; - textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; - textPrinter->state = 4; - } - return 3; - case 4: - if (textPrinter->scrollDistance) - { - int scrollSpeed = GetPlayerTextSpeed(); - int speed = gWindowVerticalScrollSpeeds[scrollSpeed]; - if (textPrinter->scrollDistance < speed) - { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance = 0; - } - else - { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, speed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance -= speed; - } - CopyWindowToVram(textPrinter->printerTemplate.windowId, 2); - } - else - { - textPrinter->state = 0; - } - return 3; - case 5: - if (!IsSEPlaying()) - textPrinter->state = 0; - return 3; - case 6: - if (textPrinter->delayCounter != 0) - textPrinter->delayCounter--; - else - textPrinter->state = 0; - return 3; - } - - return 1; -} - -u32 GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 letterSpacing) -{ - int i; - u8 width; - int temp; - int temp2; - u8 line; - int strPos; - u8 lineWidths[8]; - const u8 *strLocal; - - for (i = 0; i < 8; i++) - { - lineWidths[i] = 0; - } - - width = 0; - line = 0; - strLocal = str; - strPos = 0; - - do - { - temp = strLocal[strPos++]; - switch (temp) - { - case CHAR_NEWLINE: - case EOS: - lineWidths[line] = width; - width = 0; - line++; - break; - case EXT_CTRL_CODE_BEGIN: - temp2 = strLocal[strPos++]; - switch (temp2) - { - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - ++strPos; - case EXT_CTRL_CODE_PLAY_BGM: - case EXT_CTRL_CODE_PLAY_SE: - ++strPos; - case EXT_CTRL_CODE_COLOR: - case EXT_CTRL_CODE_HIGHLIGHT: - case EXT_CTRL_CODE_SHADOW: - case EXT_CTRL_CODE_PALETTE: - case EXT_CTRL_CODE_SIZE: - case EXT_CTRL_CODE_PAUSE: - case EXT_CTRL_CODE_ESCAPE: - case EXT_CTRL_CODE_SHIFT_TEXT: - case EXT_CTRL_CODE_SHIFT_DOWN: - case EXT_CTRL_CODE_CLEAR: - case EXT_CTRL_CODE_SKIP: - case EXT_CTRL_CODE_CLEAR_TO: - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - ++strPos; - break; - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_WAIT_SE: - case EXT_CTRL_CODE_FILL_WINDOW: - case EXT_CTRL_CODE_JPN: - case EXT_CTRL_CODE_ENG: - default: - break; - } - break; - case CHAR_DYNAMIC: - case PLACEHOLDER_BEGIN: - ++strPos; - break; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - break; - case CHAR_KEYPAD_ICON: - case CHAR_EXTRA_SYMBOL: - ++strPos; - default: - ++width; - break; - } - } while (temp != EOS); - - for (width = 0, strPos = 0; strPos < 8; ++strPos) - { - if (width < lineWidths[strPos]) - width = lineWidths[strPos]; - } - - return (u8)(GetFontAttribute(fontId, FONTATTR_MAX_LETTER_WIDTH) + letterSpacing) * width; -} - -u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32) -{ - u32 i; - - for (i = 0; i < 9; ++i) - { - if (glyphId == gGlyphWidthFuncs[i].fontId) - return gGlyphWidthFuncs[i].func; - } - - return NULL; -} - -s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing) -{ - bool8 isJapanese; - int minGlyphWidth; - u32 (*func)(u16 glyphId, bool32 isJapanese); - int localLetterSpacing; - u32 lineWidth; - const u8 *bufferPointer; - int glyphWidth; - s32 width; - - isJapanese = 0; - minGlyphWidth = 0; - - func = GetFontWidthFunc(fontId); - if (func == NULL) - return 0; - - if (letterSpacing == -1) - localLetterSpacing = GetFontAttribute(fontId, FONTATTR_LETTER_SPACING); - else - localLetterSpacing = letterSpacing; - - width = 0; - lineWidth = 0; - bufferPointer = 0; - - while (*str != EOS) - { - switch (*str) - { - case CHAR_NEWLINE: - if (lineWidth > width) - width = lineWidth; - lineWidth = 0; - break; - case PLACEHOLDER_BEGIN: - switch (*++str) - { - case PLACEHOLDER_ID_STRING_VAR_1: - bufferPointer = gStringVar1; - break; - case PLACEHOLDER_ID_STRING_VAR_2: - bufferPointer = gStringVar2; - break; - case PLACEHOLDER_ID_STRING_VAR_3: - bufferPointer = gStringVar3; - break; - default: - return 0; - } - case CHAR_DYNAMIC: - if (bufferPointer == NULL) - bufferPointer = DynamicPlaceholderTextUtil_GetPlaceholderPtr(*++str); - while (*bufferPointer != EOS) - { - glyphWidth = func(*bufferPointer++, isJapanese); - if (minGlyphWidth > 0) - { - if (glyphWidth < minGlyphWidth) - glyphWidth = minGlyphWidth; - lineWidth += glyphWidth; - } - else - { - lineWidth += glyphWidth; - if (isJapanese && str[1] != EOS) - lineWidth += localLetterSpacing; - } - } - bufferPointer = 0; - break; - case EXT_CTRL_CODE_BEGIN: - switch (*++str) - { - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - ++str; - case EXT_CTRL_CODE_PLAY_BGM: - case EXT_CTRL_CODE_PLAY_SE: - ++str; - case EXT_CTRL_CODE_COLOR: - case EXT_CTRL_CODE_HIGHLIGHT: - case EXT_CTRL_CODE_SHADOW: - case EXT_CTRL_CODE_PALETTE: - case EXT_CTRL_CODE_PAUSE: - case EXT_CTRL_CODE_ESCAPE: - case EXT_CTRL_CODE_SHIFT_TEXT: - case EXT_CTRL_CODE_SHIFT_DOWN: - ++str; - break; - case EXT_CTRL_CODE_SIZE: - func = GetFontWidthFunc(*++str); - if (func == NULL) - return 0; - if (letterSpacing == -1) - localLetterSpacing = GetFontAttribute(*str, FONTATTR_LETTER_SPACING); - break; - case EXT_CTRL_CODE_CLEAR: - glyphWidth = *++str; - lineWidth += glyphWidth; - break; - case EXT_CTRL_CODE_SKIP: - lineWidth = *++str; - break; - case EXT_CTRL_CODE_CLEAR_TO: - if (*++str > lineWidth) - lineWidth = *str; - break; - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - minGlyphWidth = *++str; - break; - case EXT_CTRL_CODE_JPN: - isJapanese = 1; - break; - case EXT_CTRL_CODE_ENG: - isJapanese = 0; - break; - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_WAIT_SE: - case EXT_CTRL_CODE_FILL_WINDOW: - default: - break; - } - break; - case CHAR_KEYPAD_ICON: - case CHAR_EXTRA_SYMBOL: - if (*str == CHAR_EXTRA_SYMBOL) - glyphWidth = func(*++str | 0x100, isJapanese); - else - glyphWidth = GetKeypadIconWidth(*++str); - - if (minGlyphWidth > 0) - { - if (glyphWidth < minGlyphWidth) - glyphWidth = minGlyphWidth; - lineWidth += glyphWidth; - } - else - { - lineWidth += glyphWidth; - if (isJapanese && str[1] != EOS) - lineWidth += localLetterSpacing; - } - break; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - break; - default: - glyphWidth = func(*str, isJapanese); - if (minGlyphWidth > 0) - { - if (glyphWidth < minGlyphWidth) - glyphWidth = minGlyphWidth; - lineWidth += glyphWidth; - } - else - { - lineWidth += glyphWidth; - if (isJapanese && str[1] != EOS) - lineWidth += localLetterSpacing; - } - break; - } - ++str; - } - - if (lineWidth > width) - return lineWidth; - return width; -} - -u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str) -{ - u8 shadowColor; - u8 *strLocal; - int strPos; - int temp; - int temp2; - u8 colorBackup[3]; - u8 fgColor; - u8 bgColor; - - SaveTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); - - fgColor = TEXT_COLOR_WHITE; - bgColor = TEXT_COLOR_TRANSPARENT; - shadowColor = TEXT_COLOR_LIGHT_GRAY; - - GenerateFontHalfRowLookupTable(TEXT_COLOR_WHITE, TEXT_COLOR_TRANSPARENT, TEXT_COLOR_LIGHT_GRAY); - strLocal = str; - strPos = 0; - - do - { - temp = strLocal[strPos++]; - switch (temp) - { - case EXT_CTRL_CODE_BEGIN: - temp2 = strLocal[strPos++]; - switch (temp2) - { - case EXT_CTRL_CODE_COLOR_HIGHLIGHT_SHADOW: - fgColor = strLocal[strPos++]; - bgColor = strLocal[strPos++]; - shadowColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_COLOR: - fgColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_HIGHLIGHT: - bgColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_SHADOW: - shadowColor = strLocal[strPos++]; - GenerateFontHalfRowLookupTable(fgColor, bgColor, shadowColor); - continue; - case EXT_CTRL_CODE_SIZE: - fontId = strLocal[strPos++]; - break; - case EXT_CTRL_CODE_PLAY_BGM: - case EXT_CTRL_CODE_PLAY_SE: - ++strPos; - case EXT_CTRL_CODE_PALETTE: - case EXT_CTRL_CODE_PAUSE: - case EXT_CTRL_CODE_ESCAPE: - case EXT_CTRL_CODE_SHIFT_TEXT: - case EXT_CTRL_CODE_SHIFT_DOWN: - case EXT_CTRL_CODE_CLEAR: - case EXT_CTRL_CODE_SKIP: - case EXT_CTRL_CODE_CLEAR_TO: - case EXT_CTRL_CODE_MIN_LETTER_SPACING: - ++strPos; - break; - case EXT_CTRL_CODE_RESET_SIZE: - case EXT_CTRL_CODE_PAUSE_UNTIL_PRESS: - case EXT_CTRL_CODE_WAIT_SE: - case EXT_CTRL_CODE_FILL_WINDOW: - case EXT_CTRL_CODE_JPN: - case EXT_CTRL_CODE_ENG: - default: - continue; - } - break; - case CHAR_DYNAMIC: - case CHAR_KEYPAD_ICON: - case CHAR_EXTRA_SYMBOL: - case PLACEHOLDER_BEGIN: - ++strPos; - break; - case CHAR_PROMPT_SCROLL: - case CHAR_PROMPT_CLEAR: - case CHAR_NEWLINE: - case EOS: - break; - default: - switch (fontId) - { - case 9: - DecompressGlyphFont9(temp); - break; - case 1: - default: - DecompressGlyphFont1(temp, 1); - break; - } - CpuCopy32(gCurGlyph.gfxBufferTop, pixels, 0x20); - CpuCopy32(gCurGlyph.gfxBufferBottom, pixels + 0x20, 0x20); - pixels += 0x40; - break; - } - } - while (temp != EOS); - - RestoreTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); - return 1; -} - -u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y) -{ - BlitBitmapRectToWindow( - windowId, - gKeypadIconTiles + (gKeypadIcons[keypadIconId].tileOffset * 0x20), - 0, - 0, - 0x80, - 0x80, - x, - y, - gKeypadIcons[keypadIconId].width, - gKeypadIcons[keypadIconId].height); - return gKeypadIcons[keypadIconId].width; -} - -u8 GetKeypadIconTileOffset(u8 keypadIconId) -{ - return gKeypadIcons[keypadIconId].tileOffset; -} - -u8 GetKeypadIconWidth(u8 keypadIconId) -{ - return gKeypadIcons[keypadIconId].width; -} - -u8 GetKeypadIconHeight(u8 keypadIconId) -{ - return gKeypadIcons[keypadIconId].height; -} - -void SetDefaultFontsPointer(void) -{ - SetFontsPointer(&gFontInfos[0]); -} - -u8 GetFontAttribute(u8 fontId, u8 attributeId) -{ - int result = 0; - switch (attributeId) - { - case FONTATTR_MAX_LETTER_WIDTH: - result = gFontInfos[fontId].maxLetterWidth; - break; - case FONTATTR_MAX_LETTER_HEIGHT: - result = gFontInfos[fontId].maxLetterHeight; - break; - case FONTATTR_LETTER_SPACING: - result = gFontInfos[fontId].letterSpacing; - break; - case FONTATTR_LINE_SPACING: - result = gFontInfos[fontId].lineSpacing; - break; - case FONTATTR_UNKNOWN: - result = gFontInfos[fontId].unk; - break; - case FONTATTR_COLOR_FOREGROUND: - result = gFontInfos[fontId].fgColor; - break; - case FONTATTR_COLOR_BACKGROUND: - result = gFontInfos[fontId].bgColor; - break; - case FONTATTR_COLOR_SHADOW: - result = gFontInfos[fontId].shadowColor; - break; - } - return result; -} - -u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension) -{ - return gMenuCursorDimensions[fontId][whichDimension]; -} - -void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == 1) - { - glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 12; - } - else - { - glyphs = gFont0LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont0LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 13; - } -} - -u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont0LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 15; - } - else - { - glyphs = gFont7LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont7LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 15; - } -} - -u32 GetGlyphWidthFont7(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont7LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont0JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId & 0xF)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 12; - } - else - { - glyphs = gFont8LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont8LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 12; - } -} - -u32 GetGlyphWidthFont8(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont8LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont2JapaneseGlyphs + (0x100 * (glyphId >> 0x3)) + (0x10 * (glyphId & 0x7)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); // gCurGlyph + 0x20 - DecompressGlyphTile(glyphs + 0x88, gCurGlyph.gfxBufferBottom + 8); // gCurGlyph + 0x60 - gCurGlyph.width = gFont2JapaneseGlyphWidths[glyphId]; - gCurGlyph.height = 14; - } - else - { - glyphs = gFont2LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont2LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 14; - } -} - -u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return gFont2JapaneseGlyphWidths[glyphId]; - else - return gFont2LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese) -{ - const u16* glyphs; - - if (isJapanese == TRUE) - { - glyphs = gFont1JapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 15; - } - else - { - glyphs = gFont1LatinGlyphs + (0x20 * glyphId); - gCurGlyph.width = gFont1LatinGlyphWidths[glyphId]; - - if (gCurGlyph.width <= 8) - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - } - else - { - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); - DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); - DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); - } - - gCurGlyph.height = 15; - } -} - -u32 GetGlyphWidthFont1(u16 glyphId, bool32 isJapanese) -{ - if (isJapanese == TRUE) - return 8; - else - return gFont1LatinGlyphWidths[glyphId]; -} - -void DecompressGlyphFont9(u16 glyphId) -{ - const u16* glyphs; - - glyphs = gFont9JapaneseGlyphs + (0x100 * (glyphId >> 4)) + (0x8 * (glyphId & 0xF)); - DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); - DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); - gCurGlyph.width = 8; - gCurGlyph.height = 12; -} diff --git a/src/window.c b/src/window.c deleted file mode 100644 index b03b513da..000000000 --- a/src/window.c +++ /dev/null @@ -1,721 +0,0 @@ -#include "global.h" -#include "window.h" -#include "malloc.h" -#include "bg.h" -#include "blit.h" - -u32 gUnusedWindowVar1; -u32 gUnusedWindowVar2; -// This global is set to 0 and never changed. -u8 gTransparentTileNumber; -u32 gUnusedWindowVar3; -void *gWindowBgTilemapBuffers[NUM_BACKGROUNDS]; -extern u32 gUnneededFireRedVariable; - -#define WINDOWS_MAX 32 - -EWRAM_DATA struct Window gWindows[WINDOWS_MAX] = {0}; -EWRAM_DATA static struct Window* sWindowPtr = NULL; -EWRAM_DATA static u16 sWindowSize = 0; - -static u8 GetNumActiveWindowsOnBg(u8 bgId); -static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId); - -static const struct WindowTemplate sDummyWindowTemplate = DUMMY_WIN_TEMPLATE; - -static void DummyWindowBgTilemap(void) -{ - -} - -bool16 InitWindows(const struct WindowTemplate *templates) -{ - int i; - void *bgTilemapBuffer; - int j; - u8 bgLayer; - u16 attrib; - u8* allocatedTilemapBuffer; - int allocatedBaseBlock; - - for (i = 0; i < NUM_BACKGROUNDS; ++i) - { - bgTilemapBuffer = GetBgTilemapBuffer(i); - if (bgTilemapBuffer != NULL) - gWindowBgTilemapBuffers[i] = DummyWindowBgTilemap; - else - gWindowBgTilemapBuffers[i] = bgTilemapBuffer; - } - - for (i = 0; i < WINDOWS_MAX; ++i) - { - gWindows[i].window = sDummyWindowTemplate; - gWindows[i].tileData = NULL; - } - - for (i = 0, allocatedBaseBlock = 0, bgLayer = templates[i].bg; bgLayer != 0xFF && i < WINDOWS_MAX; ++i, bgLayer = templates[i].bg) - { - if (gUnneededFireRedVariable == 1) - { - allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, templates[i].width * templates[i].height, 0); - if (allocatedBaseBlock == -1) - return FALSE; - } - - if (gWindowBgTilemapBuffers[bgLayer] == NULL) - { - attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); - - if (attrib != 0xFFFF) - { - allocatedTilemapBuffer = AllocZeroed(attrib); - - if (allocatedTilemapBuffer == NULL) - { - FreeAllWindowBuffers(); - return FALSE; - } - - for (j = 0; j < attrib; ++j) - allocatedTilemapBuffer[j] = 0; - - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); - } - } - - allocatedTilemapBuffer = AllocZeroed((u16)(32 * (templates[i].width * templates[i].height))); - - if (allocatedTilemapBuffer == NULL) - { - if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - } - - return FALSE; - } - - gWindows[i].tileData = allocatedTilemapBuffer; - gWindows[i].window = templates[i]; - - if (gUnneededFireRedVariable == 1) - { - gWindows[i].window.baseBlock = allocatedBaseBlock; - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, templates[i].width * templates[i].height, 1); - } - } - - gTransparentTileNumber = 0; - return TRUE; -} - -u16 AddWindow(const struct WindowTemplate *template) -{ - u16 win; - u8 bgLayer; - int allocatedBaseBlock; - u16 attrib; - u8 *allocatedTilemapBuffer; - int i; - - for (win = 0; win < WINDOWS_MAX; ++win) - { - if ((bgLayer = gWindows[win].window.bg) == 0xFF) - break; - } - - if (win == WINDOWS_MAX) - return WINDOW_NONE; - - bgLayer = template->bg; - allocatedBaseBlock = 0; - - if (gUnneededFireRedVariable == 1) - { - allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); - - if (allocatedBaseBlock == -1) - return WINDOW_NONE; - } - - if (gWindowBgTilemapBuffers[bgLayer] == NULL) - { - attrib = GetBgAttribute(bgLayer, BG_ATTR_METRIC); - - if (attrib != 0xFFFF) - { - allocatedTilemapBuffer = AllocZeroed(attrib); - - if (allocatedTilemapBuffer == NULL) - return WINDOW_NONE; - - for (i = 0; i < attrib; ++i) - allocatedTilemapBuffer[i] = 0; - - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); - } - } - - allocatedTilemapBuffer = AllocZeroed((u16)(32 * (template->width * template->height))); - - if (allocatedTilemapBuffer == NULL) - { - if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap)) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = allocatedTilemapBuffer; - } - return WINDOW_NONE; - } - - gWindows[win].tileData = allocatedTilemapBuffer; - gWindows[win].window = *template; - - if (gUnneededFireRedVariable == 1) - { - gWindows[win].window.baseBlock = allocatedBaseBlock; - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); - } - - return win; -} - -int AddWindowWithoutTileMap(const struct WindowTemplate *template) -{ - u16 win; - u8 bgLayer; - int allocatedBaseBlock; - - for (win = 0; win < WINDOWS_MAX; ++win) - { - if (gWindows[win].window.bg == 0xFF) - break; - } - - if (win == WINDOWS_MAX) - return WINDOW_NONE; - - bgLayer = template->bg; - allocatedBaseBlock = 0; - - if (gUnneededFireRedVariable == 1) - { - allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); - - if (allocatedBaseBlock == -1) - return WINDOW_NONE; - } - - gWindows[win].window = *template; - - if (gUnneededFireRedVariable == 1) - { - gWindows[win].window.baseBlock = allocatedBaseBlock; - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, gWindows[win].window.width * gWindows[win].window.height, 1); - } - - return win; -} - -void RemoveWindow(u8 windowId) -{ - u8 bgLayer = gWindows[windowId].window.bg; - - if (gUnneededFireRedVariable == 1) - { - DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, gWindows[windowId].window.baseBlock, gWindows[windowId].window.width * gWindows[windowId].window.height, 2); - } - - gWindows[windowId].window = sDummyWindowTemplate; - - if (GetNumActiveWindowsOnBg(bgLayer) == 0) - { - if (gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = NULL; - } - } - - if (gWindows[windowId].tileData != NULL) - { - Free(gWindows[windowId].tileData); - gWindows[windowId].tileData = NULL; - } -} - -void FreeAllWindowBuffers(void) -{ - int i; - - for (i = 0; i < NUM_BACKGROUNDS; ++i) - { - if (gWindowBgTilemapBuffers[i] != NULL && gWindowBgTilemapBuffers[i] != DummyWindowBgTilemap) - { - Free(gWindowBgTilemapBuffers[i]); - gWindowBgTilemapBuffers[i] = NULL; - } - } - - for (i = 0; i < WINDOWS_MAX; ++i) - { - if (gWindows[i].tileData != NULL) - { - Free(gWindows[i].tileData); - gWindows[i].tileData = NULL; - } - } -} - -void CopyWindowToVram(u8 windowId, u8 mode) -{ - struct Window windowLocal = gWindows[windowId]; - u16 windowSize = 32 * (windowLocal.window.width * windowLocal.window.height); - - switch (mode) - { - case 1: - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - case 2: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); - break; - case 3: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData, windowSize, windowLocal.window.baseBlock); - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - } -} - -void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h) -{ - struct Window windowLocal; - int rectSize; - int rectPos; - - if (w != 0 && h != 0) - { - windowLocal = gWindows[windowId]; - - rectSize = ((h - 1) * windowLocal.window.width); - rectSize += (windowLocal.window.width - x); - rectSize -= (windowLocal.window.width - (x + w)); - rectSize *= 32; - - rectPos = (y * windowLocal.window.width) + x; - - switch (mode) - { - case 1: - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - case 2: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); - break; - case 3: - LoadBgTiles(windowLocal.window.bg, windowLocal.tileData + (rectPos * 32), rectSize, windowLocal.window.baseBlock + rectPos); - CopyBgTilemapBufferToVram(windowLocal.window.bg); - break; - } - } -} - -void PutWindowTilemap(u8 windowId) -{ - struct Window windowLocal = gWindows[windowId]; - - WriteSequenceToBgTilemapBuffer( - windowLocal.window.bg, - GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE) + windowLocal.window.baseBlock, - windowLocal.window.tilemapLeft, - windowLocal.window.tilemapTop, - windowLocal.window.width, - windowLocal.window.height, - windowLocal.window.paletteNum, - 1); -} - -void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 height, u8 palette) -{ - struct Window windowLocal = gWindows[windowId]; - u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); - int i; - - for (i = 0; i < height; ++i) - { - WriteSequenceToBgTilemapBuffer( - windowLocal.window.bg, - currentRow, - windowLocal.window.tilemapLeft + x, - windowLocal.window.tilemapTop + y + i, - width, - 1, - palette, - 1); - - currentRow += windowLocal.window.width; - } -} - -// Fills a window with transparent tiles. -void ClearWindowTilemap(u8 windowId) -{ - struct Window windowLocal = gWindows[windowId]; - - FillBgTilemapBufferRect( - windowLocal.window.bg, - gTransparentTileNumber, - windowLocal.window.tilemapLeft, - windowLocal.window.tilemapTop, - windowLocal.window.width, - windowLocal.window.height, - windowLocal.window.paletteNum); -} - -void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) -{ - struct Window windowLocal = gWindows[windowId]; - u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.bg, BG_ATTR_BASETILE); - int i; - - for (i = 0; i < height; ++i) - { - WriteSequenceToBgTilemapBuffer( - windowLocal.window.bg, - currentRow, - windowLocal.window.tilemapLeft + x, - windowLocal.window.tilemapTop + y + i, - width, - 1, - windowLocal.window.paletteNum, - 1); - - currentRow += windowLocal.window.width; - } -} - -void BlitBitmapToWindow(u8 windowId, const u8 *pixels, u16 x, u16 y, u16 width, u16 height) -{ - BlitBitmapRectToWindow(windowId, pixels, 0, 0, width, height, x, y, width, height); -} - -void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight) -{ - struct Bitmap sourceRect; - struct Bitmap destRect; - - sourceRect.pixels = (u8*)pixels; - sourceRect.width = srcWidth; - sourceRect.height = srcHeight; - - destRect.pixels = gWindows[windowId].tileData; - destRect.width = 8 * gWindows[windowId].window.width; - destRect.height = 8 * gWindows[windowId].window.height; - - BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0); -} - -static void BlitBitmapRectToWindowWithColorKey(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 colorKey) -{ - struct Bitmap sourceRect; - struct Bitmap destRect; - - sourceRect.pixels = (u8*)pixels; - sourceRect.width = srcWidth; - sourceRect.height = srcHeight; - - destRect.pixels = gWindows[windowId].tileData; - destRect.width = 8 * gWindows[windowId].window.width; - destRect.height = 8 * gWindows[windowId].window.height; - - BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, colorKey); -} - -void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) -{ - struct Bitmap pixelRect; - - pixelRect.pixels = gWindows[windowId].tileData; - pixelRect.width = 8 * gWindows[windowId].window.width; - pixelRect.height = 8 * gWindows[windowId].window.height; - - FillBitmapRect4Bit(&pixelRect, x, y, width, height, fillValue); -} - -void CopyToWindowPixelBuffer(u8 windowId, const void *src, u16 size, u16 tileOffset) -{ - if (size != 0) - CpuCopy16(src, gWindows[windowId].tileData + (32 * tileOffset), size); - else - LZ77UnCompWram(src, gWindows[windowId].tileData + (32 * tileOffset)); -} - -// Sets all pixels within the window to the fillValue color. -void FillWindowPixelBuffer(u8 windowId, u8 fillValue) -{ - int fillSize = gWindows[windowId].window.width * gWindows[windowId].window.height; - CpuFastFill8(fillValue, gWindows[windowId].tileData, 32 * fillSize); -} - -#define MOVE_TILES_DOWN(a) \ -{ \ - destOffset = i + (a); \ - srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ - if (srcOffset < size) \ - *(u32*)(tileData + destOffset) = *(u32*)(tileData + srcOffset); \ - else \ - *(u32*)(tileData + destOffset) = fillValue32; \ - distanceLoop++; \ -} - -#define MOVE_TILES_UP(a) \ -{ \ - destOffset = i + (a); \ - srcOffset = i + (((width * (distanceLoop & ~7)) | (distanceLoop & 7)) * 4); \ - if (srcOffset < size) \ - *(u32*)(tileData - destOffset) = *(u32*)(tileData - srcOffset); \ - else \ - *(u32*)(tileData - destOffset) = fillValue32; \ - distanceLoop++; \ -} - -void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue) -{ - struct WindowTemplate window = gWindows[windowId].window; - u8 *tileData = gWindows[windowId].tileData; - u32 fillValue32 = (fillValue << 24) | (fillValue << 16) | (fillValue << 8) | fillValue; - s32 size = window.height * window.width * 32; - u32 width = window.width; - s32 i; - s32 srcOffset, destOffset; - u32 distanceLoop; - - switch (direction) - { - case 0: - for (i = 0; i < size; i += 32) - { - distanceLoop = distance; - MOVE_TILES_DOWN(0) - MOVE_TILES_DOWN(4) - MOVE_TILES_DOWN(8) - MOVE_TILES_DOWN(12) - MOVE_TILES_DOWN(16) - MOVE_TILES_DOWN(20) - MOVE_TILES_DOWN(24) - MOVE_TILES_DOWN(28) - } - break; - case 1: - tileData += size - 4; - for (i = 0; i < size; i += 32) - { - distanceLoop = distance; - MOVE_TILES_UP(0) - MOVE_TILES_UP(4) - MOVE_TILES_UP(8) - MOVE_TILES_UP(12) - MOVE_TILES_UP(16) - MOVE_TILES_UP(20) - MOVE_TILES_UP(24) - MOVE_TILES_UP(28) - } - break; - case 2: - break; - } -} - -void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)) -{ - struct WindowTemplate window = gWindows[windowId].window; - func(window.bg, window.tilemapLeft, window.tilemapTop, window.width, window.height, window.paletteNum); -} - -bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value) -{ - switch (attributeId) - { - case WINDOW_TILEMAP_LEFT: - gWindows[windowId].window.tilemapLeft = value; - return FALSE; - case WINDOW_TILEMAP_TOP: - gWindows[windowId].window.tilemapTop = value; - return FALSE; - case WINDOW_PALETTE_NUM: - gWindows[windowId].window.paletteNum = value; - return FALSE; - case WINDOW_BASE_BLOCK: - gWindows[windowId].window.baseBlock = value; - return FALSE; - case WINDOW_TILE_DATA: - gWindows[windowId].tileData = (u8*)(value); - return TRUE; - case WINDOW_BG: - case WINDOW_WIDTH: - case WINDOW_HEIGHT: - default: - return TRUE; - } -} - -u32 GetWindowAttribute(u8 windowId, u8 attributeId) -{ - switch (attributeId) - { - case WINDOW_BG: - return gWindows[windowId].window.bg; - case WINDOW_TILEMAP_LEFT: - return gWindows[windowId].window.tilemapLeft; - case WINDOW_TILEMAP_TOP: - return gWindows[windowId].window.tilemapTop; - case WINDOW_WIDTH: - return gWindows[windowId].window.width; - case WINDOW_HEIGHT: - return gWindows[windowId].window.height; - case WINDOW_PALETTE_NUM: - return gWindows[windowId].window.paletteNum; - case WINDOW_BASE_BLOCK: - return gWindows[windowId].window.baseBlock; - case WINDOW_TILE_DATA: - return (u32)(gWindows[windowId].tileData); - default: - return 0; - } -} - -static u8 GetNumActiveWindowsOnBg(u8 bgId) -{ - u8 windowsNum = 0; - s32 i; - for (i = 0; i < WINDOWS_MAX; i++) - { - if (gWindows[i].window.bg == bgId) - windowsNum++; - } - return windowsNum; -} - -static void DummyWindowBgTilemap8Bit(void) -{ - -} - -u16 AddWindow8Bit(const struct WindowTemplate *template) -{ - u16 windowId; - u8* memAddress; - u8 bgLayer; - - for (windowId = 0; windowId < WINDOWS_MAX; windowId++) - { - if (gWindows[windowId].window.bg == 0xFF) - break; - } - if (windowId == WINDOWS_MAX) - return WINDOW_NONE; - bgLayer = template->bg; - if (gWindowBgTilemapBuffers[bgLayer] == NULL) - { - u16 attribute = GetBgAttribute(bgLayer, BG_ATTR_METRIC); - if (attribute != 0xFFFF) - { - s32 i; - memAddress = Alloc(attribute); - if (memAddress == NULL) - return WINDOW_NONE; - for (i = 0; i < attribute; i++) // if we're going to zero out the memory anyway, why not call AllocZeroed? - memAddress[i] = 0; - gWindowBgTilemapBuffers[bgLayer] = memAddress; - SetBgTilemapBuffer(bgLayer, memAddress); - } - } - memAddress = Alloc((u16)(64 * (template->width * template->height))); - if (memAddress == NULL) - { - if (GetNumActiveWindowsOnBg8Bit(bgLayer) == 0 && gWindowBgTilemapBuffers[bgLayer] != DummyWindowBgTilemap8Bit) - { - Free(gWindowBgTilemapBuffers[bgLayer]); - gWindowBgTilemapBuffers[bgLayer] = NULL; - } - return WINDOW_NONE; - } - else - { - gWindows[windowId].tileData = memAddress; - gWindows[windowId].window = *template; - return windowId; - } -} - -void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue) -{ - s32 i; - s32 size; - - size = (u16)(64 * (gWindows[windowId].window.width * gWindows[windowId].window.height)); - for (i = 0; i < size; i++) - gWindows[windowId].tileData[i] = fillValue; -} - -void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) -{ - struct Bitmap pixelRect; - - pixelRect.pixels = gWindows[windowId].tileData; - pixelRect.width = 8 * gWindows[windowId].window.width; - pixelRect.height = 8 * gWindows[windowId].window.height; - - FillBitmapRect8Bit(&pixelRect, x, y, width, height, fillValue); -} - -void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum) -{ - struct Bitmap sourceRect; - struct Bitmap destRect; - - sourceRect.pixels = (u8*) pixels; - sourceRect.width = srcWidth; - sourceRect.height = srcHeight; - - destRect.pixels = gWindows[windowId].tileData; - destRect.width = 8 * gWindows[windowId].window.width; - destRect.height = 8 * gWindows[windowId].window.height; - - BlitBitmapRect4BitTo8Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0, paletteNum); -} - -void CopyWindowToVram8Bit(u8 windowId, u8 mode) -{ - sWindowPtr = &gWindows[windowId]; - sWindowSize = 64 * (sWindowPtr->window.width * sWindowPtr->window.height); - - switch (mode) - { - case 1: - CopyBgTilemapBufferToVram(sWindowPtr->window.bg); - break; - case 2: - LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); - break; - case 3: - LoadBgTiles(sWindowPtr->window.bg, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); - CopyBgTilemapBufferToVram(sWindowPtr->window.bg); - break; - } -} - -static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId) -{ - u8 windowsNum = 0; - s32 i; - for (i = 0; i < WINDOWS_MAX; i++) - { - if (gWindows[i].window.bg == bgId) - windowsNum++; - } - return windowsNum; -} diff --git a/sym_bss.txt b/sym_bss.txt index 7bdf99dd5..3166aee45 100644 --- a/sym_bss.txt +++ b/sym_bss.txt @@ -1,10 +1,10 @@ .include "src/main.o" - .include "src/malloc.o" - .include "src/dma3_manager.o" - .include "src/gpu_regs.o" - .include "src/bg.o" - .include "src/text.o" - .include "src/sprite.o" + .include "gflib/malloc.o" + .include "gflib/dma3_manager.o" + .include "gflib/gpu_regs.o" + .include "gflib/bg.o" + .include "gflib/text.o" + .include "gflib/sprite.o" .include "src/link.o" .include "src/AgbRfu_LinkManager.o" .include "src/link_rfu_3.o" diff --git a/sym_common.txt b/sym_common.txt index 23a185e6f..1525d8aec 100644 --- a/sym_common.txt +++ b/sym_common.txt @@ -1,17 +1,17 @@ .space 0x8 .include "main.o" - @ bg.o + @ ../gflib/bg.o .align 2 gUnneededFireRedVariable: .space 4 - @ window.o + @ ../gflib/window.o .align 4 gTransparentTileNumber: .space 1 .align 4 gWindowBgTilemapBuffers: .space 16 - @ text.o + @ ../gflib/text.o .align 4 gFonts: .space 4 @@ -24,7 +24,7 @@ gCurGlyph: .align 2 gTextFlags: .space 4 - @ sprite.o + @ ../gflib/sprite.o .align 2 gOamMatrixAllocBitmap: .space 4 diff --git a/sym_ewram.txt b/sym_ewram.txt index f461cfa10..88c4461cb 100644 --- a/sym_ewram.txt +++ b/sym_ewram.txt @@ -1,9 +1,9 @@ .include "src/decompress.o" .include "src/main.o" - .include "src/window.o" - .include "src/text.o" - .include "src/sprite.o" - .include "src/string_util.o" + .include "gflib/window.o" + .include "gflib/text.o" + .include "gflib/sprite.o" + .include "gflib/string_util.o" .include "src/link.o" .include "src/AgbRfu_LinkManager.o" .include "src/link_rfu_3.o" -- cgit v1.2.3 From 0f538102d9f1327cb699261bde969c89e02b3503 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 5 Jul 2021 13:54:43 -0400 Subject: Add local id constants for C --- .../scripts.inc | 2 +- .../BattleFrontier_BattleTowerLobby/scripts.inc | 2 ++ data/maps/BirthIsland_Exterior/scripts.inc | 9 +++--- data/maps/FarawayIsland_Interior/scripts.inc | 22 +++++++-------- data/maps/Route111/scripts.inc | 2 +- data/maps/UnionRoom/scripts.inc | 25 ++++++---------- include/constants/event_objects.h | 26 +++++++++++++++++ src/faraway_island.c | 2 +- src/field_special_scene.c | 30 ++++++++++---------- src/field_specials.c | 32 ++++++++++----------- src/tv.c | 3 +- src/union_room_player_avatar.c | 33 ++++++++++++++-------- 12 files changed, 110 insertions(+), 78 deletions(-) diff --git a/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc b/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc index b01d5314b..f9cc466a2 100644 --- a/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc +++ b/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc @@ -563,7 +563,7 @@ BattleFrontier_BattleDomeBattleRoom_EventScript_AddSemifinalAudience:: @ 824C594 createvobject OBJ_EVENT_GFX_HEX_MANIAC, 28, 5, 2, 3, DIR_SOUTH createvobject OBJ_EVENT_GFX_SCHOOL_KID_M, 29, 5, 1, 3, DIR_SOUTH createvobject OBJ_EVENT_GFX_MART_EMPLOYEE, 30, 6, 2, 3, DIR_SOUTH - createvobject OBJ_EVENT_GFX_WOMAN_5, 31, 8, 2, 3, 1 + createvobject OBJ_EVENT_GFX_WOMAN_5, 31, 8, 2, 3, DIR_SOUTH return BattleFrontier_BattleDomeBattleRoom_EventScript_AddFinalAudience:: @ 824C652 diff --git a/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc b/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc index 465b04f78..5bc18e000 100644 --- a/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc +++ b/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc @@ -3,6 +3,8 @@ .set LOCALID_ATTENDANT_MULTIS, 8 .set LOCALID_ATTENDANT_LINK_MULTIS, 9 +@ Note: LOCALID_BATTLE_TOWER_LOBBY_REPORTER is a local id for this map used elsewhere. It's defined in event_objects.h + BattleFrontier_BattleTowerLobby_MapScripts:: @ 823E67B map_script MAP_SCRIPT_ON_RESUME, BattleFrontier_BattleTowerLobby_OnResume map_script MAP_SCRIPT_ON_TRANSITION, BattleFrontier_BattleTowerLobby_OnTransition diff --git a/data/maps/BirthIsland_Exterior/scripts.inc b/data/maps/BirthIsland_Exterior/scripts.inc index c20de3798..3509e0326 100644 --- a/data/maps/BirthIsland_Exterior/scripts.inc +++ b/data/maps/BirthIsland_Exterior/scripts.inc @@ -1,6 +1,7 @@ -.set LOCALID_DEOXYS_ROCK, 1 .set LOCALID_DEOXYS, 2 +@ Note: LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK is a local id for this map used elsewhere. It's defined in event_objects.h + BirthIsland_Exterior_MapScripts:: @ 8267F15 map_script MAP_SCRIPT_ON_TRANSITION, BirthIsland_Exterior_OnTransition map_script MAP_SCRIPT_ON_RESUME, BirthIsland_Exterior_OnResume @@ -68,9 +69,9 @@ BirthIsland_Exterior_EventScript_NotSolved3:: @ 8267FBF BirthIsland_Exterior_EventScript_Deoxys:: @ 8267FC1 waitse - setfieldeffectargument 0, LOCALID_DEOXYS_ROCK - setfieldeffectargument 1, 58 - setfieldeffectargument 2, 26 + setfieldeffectargument 0, LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK + setfieldeffectargument 1, MAP_NUM(BIRTH_ISLAND_EXTERIOR) + setfieldeffectargument 2, MAP_GROUP(BIRTH_ISLAND_EXTERIOR) dofieldeffect FLDEFF_DESTROY_DEOXYS_ROCK playbgm MUS_RG_ENCOUNTER_DEOXYS, 0 waitfieldeffect FLDEFF_DESTROY_DEOXYS_ROCK diff --git a/data/maps/FarawayIsland_Interior/scripts.inc b/data/maps/FarawayIsland_Interior/scripts.inc index 108bc12e6..59a90e357 100644 --- a/data/maps/FarawayIsland_Interior/scripts.inc +++ b/data/maps/FarawayIsland_Interior/scripts.inc @@ -1,4 +1,4 @@ -.set LOCALID_MEW, 1 +@ Note: LOCALID_FARAWAY_ISLAND_MEW is a local id for this map used elsewhere. It's defined in event_objects.h FarawayIsland_Interior_MapScripts:: @ 8267CFA map_script MAP_SCRIPT_ON_RESUME, FarawayIsland_Interior_OnResume @@ -58,13 +58,13 @@ FarawayIsland_Interior_OnFrame: @ 8267D98 FarawayIsland_Interior_EventScript_FindMew:: @ 8267DA2 lockall playse SE_PIN - applymovement LOCALID_MEW, Common_Movement_ExclamationMark + applymovement LOCALID_FARAWAY_ISLAND_MEW, Common_Movement_ExclamationMark waitmovement 0 - applymovement LOCALID_MEW, Common_Movement_Delay48 + applymovement LOCALID_FARAWAY_ISLAND_MEW, Common_Movement_Delay48 waitmovement 0 - applymovement LOCALID_MEW, FarawayIsland_Interior_Movement_MewMoveAndHide + applymovement LOCALID_FARAWAY_ISLAND_MEW, FarawayIsland_Interior_Movement_MewMoveAndHide waitmovement 0 - copyobjectxytoperm LOCALID_MEW + copyobjectxytoperm LOCALID_FARAWAY_ISLAND_MEW setvar VAR_TEMP_1, 1 releaseall end @@ -120,7 +120,7 @@ FarawayIsland_Interior_Movement_MewFloatUpEast: @ 8267DEB FarawayIsland_Interior_EventScript_Mew:: @ 8267DF2 lock faceplayer - applymovement LOCALID_MEW, FarawayIsland_Interior_Movement_MewAppear + applymovement LOCALID_FARAWAY_ISLAND_MEW, FarawayIsland_Interior_Movement_MewAppear waitmovement 0 setvar VAR_0x8004, 0 special SetMewAboveGrass @@ -171,22 +171,22 @@ FarawayIsland_Interior_EventScript_PlayerOrMewRan:: @ 8267EA4 end FarawayIsland_Interior_EventScript_FoundMewNorth:: @ 8267EAF - applymovement LOCALID_MEW, FarawayIsland_Interior_Movement_MewFloatUpNorth + applymovement LOCALID_FARAWAY_ISLAND_MEW, FarawayIsland_Interior_Movement_MewFloatUpNorth waitmovement 0 return FarawayIsland_Interior_EventScript_FoundMewSouth:: @ 8267EBA - applymovement LOCALID_MEW, FarawayIsland_Interior_Movement_MewFloatUpSouth + applymovement LOCALID_FARAWAY_ISLAND_MEW, FarawayIsland_Interior_Movement_MewFloatUpSouth waitmovement 0 return FarawayIsland_Interior_EventScript_FoundMewWest:: @ 8267EC5 - applymovement LOCALID_MEW, FarawayIsland_Interior_Movement_MewFloatUpWest + applymovement LOCALID_FARAWAY_ISLAND_MEW, FarawayIsland_Interior_Movement_MewFloatUpWest waitmovement 0 return FarawayIsland_Interior_EventScript_FoundMewEast:: @ 8267ED0 - applymovement LOCALID_MEW, FarawayIsland_Interior_Movement_MewFloatUpEast + applymovement LOCALID_FARAWAY_ISLAND_MEW, FarawayIsland_Interior_Movement_MewFloatUpEast waitmovement 0 return @@ -194,7 +194,7 @@ FarawayIsland_Interior_EventScript_HideMewWhenGrassCut:: @ 8267EDB lockall fadescreenswapbuffers FADE_TO_BLACK setflag FLAG_HIDE_MEW - removeobject LOCALID_MEW + removeobject LOCALID_FARAWAY_ISLAND_MEW fadescreenswapbuffers FADE_FROM_BLACK msgbox FarawayIsland_Interior_Text_TheFeelingOfBeingWatchedFaded, MSGBOX_DEFAULT closemessage diff --git a/data/maps/Route111/scripts.inc b/data/maps/Route111/scripts.inc index 9e6e4c8eb..428011645 100644 --- a/data/maps/Route111/scripts.inc +++ b/data/maps/Route111/scripts.inc @@ -4,7 +4,7 @@ .set LOCALID_VICKY, 4 .set LOCALID_ROCK_SMASH_MAN, 46 -@ Note: LOCALID_ROUTE111_PLAYER_FALLING is used in mirage_tower.c, and is defined in event_objects.h +@ Note: LOCALID_ROUTE111_PLAYER_FALLING is a local id for this map used elsewhere. It's defined in event_objects.h Route111_MapScripts:: @ 81F0CA7 map_script MAP_SCRIPT_ON_LOAD, Route111_OnLoad diff --git a/data/maps/UnionRoom/scripts.inc b/data/maps/UnionRoom/scripts.inc index f25e7acb6..13d7e1007 100644 --- a/data/maps/UnionRoom/scripts.inc +++ b/data/maps/UnionRoom/scripts.inc @@ -1,11 +1,4 @@ -.set LOCALID_UR_PLAYER_4, 2 -.set LOCALID_UR_PLAYER_8, 3 -.set LOCALID_UR_PLAYER_7, 4 -.set LOCALID_UR_PLAYER_6, 5 -.set LOCALID_UR_PLAYER_5, 6 -.set LOCALID_UR_PLAYER_3, 7 -.set LOCALID_UR_PLAYER_2, 8 -.set LOCALID_UR_PLAYER_1, 9 +@ Note: LOCALID_UNION_ROOM_PLAYER_# are local ids for this map used elsewhere. They're defined in event_objects.h UnionRoom_MapScripts:: @ 823D1A6 map_script MAP_SCRIPT_ON_RESUME, UnionRoom_OnResume @@ -21,14 +14,14 @@ UnionRoom_OnResume: @ 823D1B1 setflag FLAG_HIDE_UNION_ROOM_PLAYER_6 setflag FLAG_HIDE_UNION_ROOM_PLAYER_7 setflag FLAG_HIDE_UNION_ROOM_PLAYER_8 - removeobject LOCALID_UR_PLAYER_1 - removeobject LOCALID_UR_PLAYER_2 - removeobject LOCALID_UR_PLAYER_3 - removeobject LOCALID_UR_PLAYER_4 - removeobject LOCALID_UR_PLAYER_5 - removeobject LOCALID_UR_PLAYER_6 - removeobject LOCALID_UR_PLAYER_7 - removeobject LOCALID_UR_PLAYER_8 + removeobject LOCALID_UNION_ROOM_PLAYER_1 + removeobject LOCALID_UNION_ROOM_PLAYER_2 + removeobject LOCALID_UNION_ROOM_PLAYER_3 + removeobject LOCALID_UNION_ROOM_PLAYER_4 + removeobject LOCALID_UNION_ROOM_PLAYER_5 + removeobject LOCALID_UNION_ROOM_PLAYER_6 + removeobject LOCALID_UNION_ROOM_PLAYER_7 + removeobject LOCALID_UNION_ROOM_PLAYER_8 special RunUnionRoom end diff --git a/include/constants/event_objects.h b/include/constants/event_objects.h index 357251548..1958c792e 100644 --- a/include/constants/event_objects.h +++ b/include/constants/event_objects.h @@ -285,5 +285,31 @@ // Object event local ids referenced in C files #define LOCALID_ROUTE111_PLAYER_FALLING 45 +#define LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK 1 +#define LOCALID_FARAWAY_ISLAND_MEW 1 +#define LOCALID_UNION_ROOM_PLAYER_4 2 +#define LOCALID_UNION_ROOM_PLAYER_8 3 +#define LOCALID_UNION_ROOM_PLAYER_7 4 +#define LOCALID_UNION_ROOM_PLAYER_6 5 +#define LOCALID_UNION_ROOM_PLAYER_5 6 +#define LOCALID_UNION_ROOM_PLAYER_3 7 +#define LOCALID_UNION_ROOM_PLAYER_2 8 +#define LOCALID_UNION_ROOM_PLAYER_1 9 +#define LOCALID_BATTLE_TOWER_LOBBY_REPORTER 5 +#define LOCALID_TRUCK_BOX_TOP 1 +#define LOCALID_TRUCK_BOX_BOTTOM_L 2 +#define LOCALID_TRUCK_BOX_BOTTOM_R 3 +#define LOCALID_OLDALE_MART_CLERK 1 +#define LOCALID_LAVARIDGE_MART_CLERK 1 +#define LOCALID_FALLARBOR_MART_CLERK 1 +#define LOCALID_VERDANTURF_MART_CLERK 1 +#define LOCALID_PETALBURG_MART_CLERK 1 +#define LOCALID_SLATEPORT_MART_CLERK 1 +#define LOCALID_MAUVILLE_MART_CLERK 1 +#define LOCALID_RUSTBORO_MART_CLERK 1 +#define LOCALID_FORTREE_MART_CLERK 1 +#define LOCALID_MOSSDEEP_MART_CLERK 1 +#define LOCALID_SOOTOPOLIS_MART_CLERK 1 +#define LOCALID_BATTLE_FRONTIER_MART_CLERK 1 #endif // GUARD_CONSTANTS_EVENT_OBJECTS_H diff --git a/src/faraway_island.c b/src/faraway_island.c index bc0814652..51ab8def4 100755 --- a/src/faraway_island.c +++ b/src/faraway_island.c @@ -38,7 +38,7 @@ static const s16 sFarawayIslandRockCoords[4][2] = static u8 GetMewObjectEventId(void) { u8 objectEventId; - TryGetObjectEventIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId); + TryGetObjectEventIdByLocalIdAndMap(LOCALID_FARAWAY_ISLAND_MEW, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId); return objectEventId; } diff --git a/src/field_special_scene.c b/src/field_special_scene.c index 6b41c5423..3c7016bd1 100644 --- a/src/field_special_scene.c +++ b/src/field_special_scene.c @@ -72,12 +72,12 @@ void Task_Truck1(u8 taskId) s16 cameraXpan = 0, cameraYpan = 0; s16 box1, box2, box3; - box1 = GetTruckBoxMovement(data[0] + 30) * 4; // top box. - SetObjectEventSpritePosByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, box1 + 3); - box2 = GetTruckBoxMovement(data[0]) * 2; // bottom left box. - SetObjectEventSpritePosByLocalIdAndMap(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, box2 - 3); - box3 = GetTruckBoxMovement(data[0]) * 4; // bottom right box. - SetObjectEventSpritePosByLocalIdAndMap(3, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, box3); + box1 = GetTruckBoxMovement(data[0] + 30) * 4; + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, box1 + 3); + box2 = GetTruckBoxMovement(data[0]) * 2; + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, box2 - 3); + box3 = GetTruckBoxMovement(data[0]) * 4; + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, box3); if (++data[0] == SECONDS(500)) // this will never run data[0] = 0; // reset the timer if it gets stuck. @@ -116,11 +116,11 @@ void Task_Truck2(u8 taskId) cameraYpan = GetTruckCameraBobbingY(data[2]); SetCameraPanning(cameraXpan, cameraYpan); box1 = GetTruckBoxMovement(data[2] + 30) * 4; - SetObjectEventSpritePosByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, box1 + 3); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, box1 + 3); box2 = GetTruckBoxMovement(data[2]) * 2; - SetObjectEventSpritePosByLocalIdAndMap(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, box2 - 3); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, box2 - 3); box3 = GetTruckBoxMovement(data[2]) * 4; - SetObjectEventSpritePosByLocalIdAndMap(3, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, box3); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, box3); } } @@ -147,9 +147,9 @@ static void Task_Truck3(u8 taskId) cameraXpan = gTruckCamera_HorizontalTable[data[1]]; cameraYpan = 0; SetCameraPanning(cameraXpan, 0); - SetObjectEventSpritePosByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, cameraYpan + 3); - SetObjectEventSpritePosByLocalIdAndMap(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, cameraYpan - 3); - SetObjectEventSpritePosByLocalIdAndMap(3, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, cameraYpan); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3 - cameraXpan, cameraYpan + 3); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -cameraXpan, cameraYpan - 3); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3 - cameraXpan, cameraYpan); } } @@ -242,9 +242,9 @@ void EndTruckSequence(u8 taskId) { if (!FuncIsActiveTask(Task_HandleTruckSequence)) { - SetObjectEventSpritePosByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3, 3); - SetObjectEventSpritePosByLocalIdAndMap(2, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 0, -3); - SetObjectEventSpritePosByLocalIdAndMap(3, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3, 0); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 3, 3); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, 0, -3); + SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, -3, 0); } } diff --git a/src/field_specials.c b/src/field_specials.c index df16583ed..f85de29f5 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -3430,7 +3430,7 @@ static void ChangeDeoxysRockLevel(u8 rockLevel) { u8 objectEventId; LoadPalette(&sDeoxysRockPalettes[rockLevel], 0x1A0, 8); - TryGetObjectEventIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId); + TryGetObjectEventIdByLocalIdAndMap(LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId); if (rockLevel == 0) PlaySE(SE_M_CONFUSE_RAY); @@ -3438,9 +3438,9 @@ static void ChangeDeoxysRockLevel(u8 rockLevel) PlaySE(SE_RG_DEOXYS_MOVE); CreateTask(WaitForDeoxysRockMovement, 8); - gFieldEffectArguments[0] = 1; - gFieldEffectArguments[1] = 58; - gFieldEffectArguments[2] = 26; + gFieldEffectArguments[0] = LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK; + gFieldEffectArguments[1] = MAP_NUM(BIRTH_ISLAND_EXTERIOR); + gFieldEffectArguments[2] = MAP_GROUP(BIRTH_ISLAND_EXTERIOR); gFieldEffectArguments[3] = sDeoxysRockCoords[rockLevel][0]; gFieldEffectArguments[4] = sDeoxysRockCoords[rockLevel][1]; @@ -3687,18 +3687,18 @@ u32 GetMartEmployeeObjectEventId(void) { static const u8 sPokeMarts[][3] = { - { MAP_GROUP(OLDALE_TOWN_MART), MAP_NUM(OLDALE_TOWN_MART), 1 }, - { MAP_GROUP(LAVARIDGE_TOWN_MART), MAP_NUM(LAVARIDGE_TOWN_MART), 1 }, - { MAP_GROUP(FALLARBOR_TOWN_MART), MAP_NUM(FALLARBOR_TOWN_MART), 1 }, - { MAP_GROUP(VERDANTURF_TOWN_MART), MAP_NUM(VERDANTURF_TOWN_MART), 1 }, - { MAP_GROUP(PETALBURG_CITY_MART), MAP_NUM(PETALBURG_CITY_MART), 1 }, - { MAP_GROUP(SLATEPORT_CITY_MART), MAP_NUM(SLATEPORT_CITY_MART), 1 }, - { MAP_GROUP(MAUVILLE_CITY_MART), MAP_NUM(MAUVILLE_CITY_MART), 1 }, - { MAP_GROUP(RUSTBORO_CITY_MART), MAP_NUM(RUSTBORO_CITY_MART), 1 }, - { MAP_GROUP(FORTREE_CITY_MART), MAP_NUM(FORTREE_CITY_MART), 1 }, - { MAP_GROUP(MOSSDEEP_CITY_MART), MAP_NUM(MOSSDEEP_CITY_MART), 1 }, - { MAP_GROUP(SOOTOPOLIS_CITY_MART), MAP_NUM(SOOTOPOLIS_CITY_MART), 1 }, - { MAP_GROUP(BATTLE_FRONTIER_MART), MAP_NUM(BATTLE_FRONTIER_MART), 1 } + { MAP_GROUP(OLDALE_TOWN_MART), MAP_NUM(OLDALE_TOWN_MART), LOCALID_OLDALE_MART_CLERK }, + { MAP_GROUP(LAVARIDGE_TOWN_MART), MAP_NUM(LAVARIDGE_TOWN_MART), LOCALID_LAVARIDGE_MART_CLERK }, + { MAP_GROUP(FALLARBOR_TOWN_MART), MAP_NUM(FALLARBOR_TOWN_MART), LOCALID_FALLARBOR_MART_CLERK }, + { MAP_GROUP(VERDANTURF_TOWN_MART), MAP_NUM(VERDANTURF_TOWN_MART), LOCALID_VERDANTURF_MART_CLERK }, + { MAP_GROUP(PETALBURG_CITY_MART), MAP_NUM(PETALBURG_CITY_MART), LOCALID_PETALBURG_MART_CLERK }, + { MAP_GROUP(SLATEPORT_CITY_MART), MAP_NUM(SLATEPORT_CITY_MART), LOCALID_SLATEPORT_MART_CLERK }, + { MAP_GROUP(MAUVILLE_CITY_MART), MAP_NUM(MAUVILLE_CITY_MART), LOCALID_MAUVILLE_MART_CLERK }, + { MAP_GROUP(RUSTBORO_CITY_MART), MAP_NUM(RUSTBORO_CITY_MART), LOCALID_RUSTBORO_MART_CLERK }, + { MAP_GROUP(FORTREE_CITY_MART), MAP_NUM(FORTREE_CITY_MART), LOCALID_FORTREE_MART_CLERK }, + { MAP_GROUP(MOSSDEEP_CITY_MART), MAP_NUM(MOSSDEEP_CITY_MART), LOCALID_MOSSDEEP_MART_CLERK }, + { MAP_GROUP(SOOTOPOLIS_CITY_MART), MAP_NUM(SOOTOPOLIS_CITY_MART), LOCALID_SOOTOPOLIS_MART_CLERK }, + { MAP_GROUP(BATTLE_FRONTIER_MART), MAP_NUM(BATTLE_FRONTIER_MART), LOCALID_BATTLE_FRONTIER_MART_CLERK } }; u8 i; diff --git a/src/tv.c b/src/tv.c index 0466ee713..95baa0d0e 100644 --- a/src/tv.c +++ b/src/tv.c @@ -36,6 +36,7 @@ #include "data.h" #include "constants/battle_frontier.h" #include "constants/contest.h" +#include "constants/event_objects.h" #include "constants/items.h" #include "constants/layouts.h" #include "constants/lilycove_lady.h" @@ -3586,7 +3587,7 @@ void GetMomOrDadStringForTVMessage(void) void HideBattleTowerReporter(void) { VarSet(VAR_BRAVO_TRAINER_BATTLE_TOWER_ON, 0); - RemoveObjectEventByLocalIdAndMap(5, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); + RemoveObjectEventByLocalIdAndMap(LOCALID_BATTLE_TOWER_LOBBY_REPORTER, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); FlagSet(FLAG_HIDE_BATTLE_TOWER_REPORTER); } diff --git a/src/union_room_player_avatar.c b/src/union_room_player_avatar.c index c012fd84d..671290e21 100644 --- a/src/union_room_player_avatar.c +++ b/src/union_room_player_avatar.c @@ -77,18 +77,27 @@ static const u8 sNextFacingDirection[] = { [DIR_EAST] = DIR_NORTH }; -// Local id 1 is the Nurse/Attendant, 2-9 are link players -static const u8 sUnionRoomLocalIds[] = { 9, 8, 7, 2, 6, 5, 4, 3 }; - -static const u16 sUnknown[] = { - 0x2BF, - 0x2C0, - 0x2C1, - 0x2C2, - 0x2C3, - 0x2C4, - 0x2C5, - 0x2C6 +static const u8 sUnionRoomLocalIds[] = { + LOCALID_UNION_ROOM_PLAYER_1, + LOCALID_UNION_ROOM_PLAYER_2, + LOCALID_UNION_ROOM_PLAYER_3, + LOCALID_UNION_ROOM_PLAYER_4, + LOCALID_UNION_ROOM_PLAYER_5, + LOCALID_UNION_ROOM_PLAYER_6, + LOCALID_UNION_ROOM_PLAYER_7, + LOCALID_UNION_ROOM_PLAYER_8 +}; + +// Unused +static const u16 sHidePlayerFlags[] = { + FLAG_HIDE_UNION_ROOM_PLAYER_1, + FLAG_HIDE_UNION_ROOM_PLAYER_2, + FLAG_HIDE_UNION_ROOM_PLAYER_3, + FLAG_HIDE_UNION_ROOM_PLAYER_4, + FLAG_HIDE_UNION_ROOM_PLAYER_5, + FLAG_HIDE_UNION_ROOM_PLAYER_6, + FLAG_HIDE_UNION_ROOM_PLAYER_7, + FLAG_HIDE_UNION_ROOM_PLAYER_8 }; static const u8 sMovement_UnionPlayerExit[2] = { -- cgit v1.2.3 From 2f1a9974400a00bd0ff5394bf8ee797361a3fd9a Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 8 Jul 2021 00:49:27 -0400 Subject: Use PR title for symbols branch commits --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index de3a35c40..a8bd016cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,4 +71,4 @@ jobs: branch: symbols cwd: "./symbols" add: "*.sym" - message: ${{ github.event.commits[0].message }} + message: ${{ github.event.pull_request.title }} -- cgit v1.2.3 From eab1d7b5b11d9325ebe8f67fa4a7430eb05cf461 Mon Sep 17 00:00:00 2001 From: Collin Styles Date: Sun, 11 Jul 2021 13:21:20 -0700 Subject: Use the `IS_TYPE_PHYSICAL` macro in `AddMovePoints` --- src/battle_tv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_tv.c b/src/battle_tv.c index a61f5ff29..8c1f8044a 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -1246,7 +1246,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) break; case PTS_REFLECT: // If hit Reflect with damaging physical move - if (type < TYPE_MYSTERY && power != 0 && tvPtr->side[defSide].reflectMonId != 0) + if (IS_TYPE_PHYSICAL(type) && power != 0 && tvPtr->side[defSide].reflectMonId != 0) { u32 id = (tvPtr->side[defSide].reflectMonId - 1) * 4; movePoints->points[defSide][id + tvPtr->side[defSide].reflectMoveSlot] += sPointsArray[caseId][0]; @@ -1254,7 +1254,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) break; case PTS_LIGHT_SCREEN: // If hit Light Screen with damaging special move - if (type >= TYPE_MYSTERY && power != 0 && tvPtr->side[defSide].lightScreenMonId != 0) + if (!IS_TYPE_PHYSICAL(type) && power != 0 && tvPtr->side[defSide].lightScreenMonId != 0) { u32 id = (tvPtr->side[defSide].lightScreenMonId - 1) * 4; movePoints->points[defSide][id + tvPtr->side[defSide].lightScreenMoveSlot] += sPointsArray[caseId][0]; -- cgit v1.2.3