From 57f85724b173395509fb5f1bb21d0b61182e712c Mon Sep 17 00:00:00 2001 From: Pseurae Date: Mon, 3 Jul 2023 22:56:36 +0530 Subject: [PATCH] Experiment with ASM more --- Makefile | 2 +- README.md | 1 + charmap.tbl | 1 + config.asm | 5 ++++ include/battle.h | 1 + include/bios.h | 23 ++++++++++++++ include/constants/gba.h | 56 ++++++++++++++++++++++++++++++++--- include/main.h | 45 ++++++++++++++++++++++++++++ include/menu.h | 2 ++ include/palette.h | 2 ++ include/text.h | 30 +++++++++++++++++++ include/types.h | 2 -- main.asm | 1 + rom.ld | 12 ++++++++ scripts/save_flash_failed.asm | 51 +++++++++++++++++++++++++++++++ src/save_failed_screen.c | 53 +++++++++++++++++++++++++++++++++ 16 files changed, 280 insertions(+), 7 deletions(-) create mode 100644 include/main.h create mode 100644 scripts/save_flash_failed.asm create mode 100644 src/save_failed_screen.c diff --git a/Makefile b/Makefile index 56784c0..44666e7 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ ARMIPS := armips .PHONY: all clean all: test.gba - $(ARMIPS) main.asm + $(ARMIPS) main.asm -sym2 output.map test.gba: snakewood.gba build/linked.o diff --git a/README.md b/README.md index b0228fd..7ccb089 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ This patch is mostly compatible with vanilla saves. The bag expansion patch **wi - Emerald style Save Prompt - Colored stat values based on nature - Repeated item usage +- Error screen for wrong save file type
diff --git a/charmap.tbl b/charmap.tbl index f47f1c7..ecbfc3f 100644 --- a/charmap.tbl +++ b/charmap.tbl @@ -71,6 +71,7 @@ B8=, B5=♂ B6=♀ AE=- +BA=/ FE=\n FA=\l FB=\p diff --git a/config.asm b/config.asm index bb5634b..015b77f 100644 --- a/config.asm +++ b/config.asm @@ -49,6 +49,11 @@ ; Use items repeatedly without going back to the bag each time. .definelabel REPEATED_ITEM, 1 +; On some emulators, the game just crashes on a white screen when the wrong +; save file type is selected. +; Enable this to show an error screen when loaded with the wrong save file type. +.definelabel WRONG_SAVE_TYPE_ERROR, 1 + ; Bugfixes ; -------- diff --git a/include/battle.h b/include/battle.h index 7239648..1db70cf 100644 --- a/include/battle.h +++ b/include/battle.h @@ -1,5 +1,6 @@ #pragma once +#include "main.h" #include "types.h" #include "berry.h" #include "pokemon.h" diff --git a/include/bios.h b/include/bios.h index 27f2aa5..b37a043 100644 --- a/include/bios.h +++ b/include/bios.h @@ -3,6 +3,7 @@ #include "types.h" void CpuFastSet(const void *src, void *dest, u32 control); +void LZ77UnCompVram(const void *src, void *dest); #define CPU_FAST_SET_SRC_FIXED 0x01000000 #define CpuFastCopy(src, dest, size) CpuFastSet(src, dest, ((size) / (32 / 8) & 0x1FFFFF)) @@ -11,3 +12,25 @@ void CpuFastSet(const void *src, void *dest, u32 control); vu32 tmp = (vu32)(value); \ CpuFastSet((void *)&tmp, dest, CPU_FAST_SET_SRC_FIXED | ((size) / (32 / 8) & 0x1FFFFF)); \ } + +#define DmaSet(dmaNum, src, dest, control) \ +{ \ + vu32 *dmaRegs = (vu32 *)REG_ADDR_DMA##dmaNum; \ + dmaRegs[0] = (vu32)(src); \ + dmaRegs[1] = (vu32)(dest); \ + dmaRegs[2] = (vu32)(control); \ + dmaRegs[2]; \ +} + +#define DMA_FILL(dmaNum, value, dest, size, bit) \ +{ \ + vu##bit tmp = (vu##bit)(value); \ + DmaSet(dmaNum, \ + &tmp, \ + dest, \ + (DMA_ENABLE | DMA_START_NOW | DMA_##bit##BIT | DMA_SRC_FIXED | DMA_DEST_INC) << 16 \ + | ((size)/(bit/8))); \ +} + +#define DmaFill16(dmaNum, value, dest, size) DMA_FILL(dmaNum, value, dest, size, 16) +#define DmaFill32(dmaNum, value, dest, size) DMA_FILL(dmaNum, value, dest, size, 32) diff --git a/include/constants/gba.h b/include/constants/gba.h index 893e95e..3af7017 100644 --- a/include/constants/gba.h +++ b/include/constants/gba.h @@ -1,8 +1,5 @@ #pragma once -#ifndef GUARD_GBA_IO_REG_H -#define GUARD_GBA_IO_REG_H - #define REG_BASE 0x4000000 // I/O register base address // I/O register offsets @@ -764,4 +761,55 @@ #define WAITCNT_AGB (0 << 15) #define WAITCNT_CGB (1 << 15) -#endif // GUARD_GBA_IO_REG_H +#define EWRAM 0x2000000 +#define IWRAM 0x3000000 + +#define PLTT 0x5000000 +#define PLTT_SIZE 0x400 + +#define BG_PLTT PLTT +#define BG_PLTT_SIZE 0x200 + +#define OBJ_PLTT (PLTT + 0x200) +#define OBJ_PLTT_SIZE 0x200 + +#define VRAM 0x6000000 +#define VRAM_SIZE 0x18000 + +#define BG_VRAM VRAM +#define BG_VRAM_SIZE 0x10000 +#define BG_CHAR_ADDR(n) (void *)(BG_VRAM + (0x4000 * (n))) +#define BG_SCREEN_ADDR(n) (void *)(BG_VRAM + (0x800 * (n))) +#define BG_TILE_ADDR(n) (void *)(BG_VRAM + (0x80 * (n))) + +// text-mode BG +#define OBJ_VRAM0 (void *)(VRAM + 0x10000) +#define OBJ_VRAM0_SIZE 0x8000 + +// bitmap-mode BG +#define OBJ_VRAM1 (void *)(VRAM + 0x14000) +#define OBJ_VRAM1_SIZE 0x4000 + +#define OAM 0x7000000 +#define OAM_SIZE 0x400 + +#define DISPLAY_WIDTH 240 +#define DISPLAY_HEIGHT 160 + +#define TILE_SIZE_4BPP 32 +#define TILE_SIZE_8BPP 64 + +#define TOTAL_OBJ_TILE_COUNT 1024 + +#define PLTT_SIZEOF(n) ((n) * sizeof(u16)) +#define PLTT_SIZE_4BPP PLTT_SIZEOF(16) +#define PLTT_SIZE_8BPP PLTT_SIZEOF(256) + +#define PLTT_OFFSET_4BPP(n) ((n) * PLTT_SIZE_4BPP) + +#define RGB(r, g, b) ((r) | ((g) << 5) | ((b) << 10)) + +#define RGB_BLACK RGB(0, 0, 0) +#define RGB_WHITE RGB(31, 31, 31) + +#define WIN_RANGE(a, b) (((a) << 8) | (b)) \ No newline at end of file diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..8b0525e --- /dev/null +++ b/include/main.h @@ -0,0 +1,45 @@ +#pragma once + +#include "sprite.h" + +typedef void (*MainCallback)(void); +typedef void (*IntrCallback)(void); +typedef void (*IntrFunc)(void); + +struct Main +{ + /*0x000*/ MainCallback callback1; + /*0x004*/ MainCallback callback2; + + /*0x008*/ MainCallback savedCallback; + + /*0x00C*/ IntrCallback vblankCallback; + /*0x010*/ IntrCallback hblankCallback; + /*0x014*/ IntrCallback vcountCallback; + /*0x018*/ IntrCallback serialCallback; + + /*0x01C*/ vu16 intrCheck; + + /*0x020*/ u32 vblankCounter1; + /*0x024*/ u32 vblankCounter2; + + /*0x028*/ u16 heldKeysRaw; // held keys without L=A remapping + /*0x02A*/ u16 newKeysRaw; // newly pressed keys without L=A remapping + /*0x02C*/ u16 heldKeys; // held keys with L=A remapping + /*0x02E*/ u16 newKeys; // newly pressed keys with L=A remapping + /*0x030*/ u16 newAndRepeatedKeys; // newly pressed keys plus key repeat + /*0x032*/ u16 keyRepeatCounter; // counts down to 0, triggering key repeat + /*0x034*/ bool16 watchedKeysPressed; // whether one of the watched keys was pressed + /*0x036*/ u16 watchedKeysMask; // bit mask for watched keys + + /*0x038*/ u8 objCount; + + /*0x03C*/ struct OamData oamBuffer[128]; + + /*0x43C*/ u8 state; + + /*0x43D*/ u8 oamLoadDisabled:1; + /*0x43D*/ u8 inBattle:1; +}; + +extern struct Main gMain; \ No newline at end of file diff --git a/include/menu.h b/include/menu.h index f42263d..e8232b2 100644 --- a/include/menu.h +++ b/include/menu.h @@ -1,10 +1,12 @@ #pragma once #include "types.h" +#include "text.h" extern void *gMenuWindowPtr; extern u16 gMenuTextTileOffset; +void InitMenuWindow(const struct WindowTemplate *); u8 *AlignStringInMenuWindow(u8 *, const u8 *, u8, u8); void Menu_PrintText(const u8 *str, u8 left, u8 top); u8 Menu_PrintTextPixelCoords(const u8 *text, u8 left, u16 top, u8 a4); diff --git a/include/palette.h b/include/palette.h index 6fea46e..934d87b 100644 --- a/include/palette.h +++ b/include/palette.h @@ -5,3 +5,5 @@ extern u16 gPlttBufferFaded[]; void LoadCompressedObjectPalette(const void *src); bool8 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u16 blendColor); +void LoadPalette(const void *, u16, u16); +void TransferPlttBuffer(void); diff --git a/include/text.h b/include/text.h index df04974..f9557f8 100644 --- a/include/text.h +++ b/include/text.h @@ -128,3 +128,33 @@ extern u8 gStringVar1[0x100]; extern u8 gStringVar2[0x100]; extern u8 gStringVar3[0x100]; extern u8 gStringVar4[0x100]; + +struct WindowTemplate +{ + u8 bgNum; + u8 charBaseBlock; + u8 screenBaseBlock; + u8 priority; + u8 paletteNum; + u8 foregroundColor; + u8 backgroundColor; + u8 shadowColor; + u8 fontNum; + u8 textMode; + u8 spacing; + u8 tilemapLeft; + u8 tilemapTop; + u8 width; + u8 height; + u8 *tileData; + u16 *tilemap; + u32 maybeUnused; +}; + +extern const struct WindowTemplate gWindowTemplate_81E6C3C; +extern const struct WindowTemplate gMenuTextWindowTemplate; + +void Text_LoadWindowTemplate(const struct WindowTemplate *winConfig); +void LoadFontDefaultPalette(const struct WindowTemplate *winTemplate); + +extern const u8 gFontDefaultPalette[]; diff --git a/include/types.h b/include/types.h index 37625f0..08dab95 100644 --- a/include/types.h +++ b/include/types.h @@ -37,8 +37,6 @@ struct UCoords16 #define PACKED __attribute__((packed)) #define NAKED __attribute__((naked)) -typedef void (*MainCallback)(void); - #define TRUE 1 #define FALSE 0 diff --git a/main.asm b/main.asm index cca5a94..ec1e0a7 100644 --- a/main.asm +++ b/main.asm @@ -60,6 +60,7 @@ .include "scripts/repeated_item.asm" .include "scripts/repel_prompt.asm" .include "scripts/reusable_tms.asm" +.include "scripts/save_flash_failed.asm" .include "scripts/summary_screen.asm" .close \ No newline at end of file diff --git a/rom.ld b/rom.ld index 48b7dc7..93d1eca 100644 --- a/rom.ld +++ b/rom.ld @@ -3,11 +3,14 @@ __umodsi3 = 0x81e0f08 | 1; __divsi3 = 0x81e0868 | 1; __udivsi3 = 0x81e0e90 | 1; CpuFastSet = 0x81e07e8 | 1; +LZ77UnCompVram = 0x81e07f0 | 1; memset = 0x815bb08 | 1; memcpy = 0x815b890 | 1; +gWindowTemplate_81E6C3C = 0x81E6C3C; gBattleMoves = 0x81fb12c; +gMain = 0x3001770; gItems = 0x83c5564; gSpecialVar_ItemId = 0x203855e; gNatureStatTable = 0x81fd070; @@ -81,6 +84,8 @@ gDecorations = 0x83eb6c4; gShadowVerticalOffsets = 0x8401e36; gFieldEffectObjectTemplatePointers = 0x836dfc0; gShadowEffectTemplateIds = 0x8401e32; +gFontDefaultPalette = 0x81e66b2; +gMenuTextWindowTemplate = 0x81e6ce4; gStringVar1 = 0x20231cc; gStringVar2 = 0x20232cc; @@ -272,3 +277,10 @@ HandleItemUsePartyMenu = 0x808B0C0 | 1; GetItemEffectType = 0x8070e48 | 1; PartyMenuEraseMsgBoxAndFrame = 0x806d5a4 | 1; GetNature = 0x803f464 | 1; +Text_LoadWindowTemplate = 0x8002a34 | 1; +TextWindow_LoadStdFrameGraphicsOverrideStyle = 0x8064f6c | 1; +LoadPalette = 0x8073a58 | 1; +LoadFontDefaultPalette = 0x8002a1c | 1; +TransferPlttBuffer = 0x8073ae0 | 1; +InitMenuWindow = 0x8071c4c | 1; +CB2_ShowDiploma = 0x8145d88 | 1; diff --git a/scripts/save_flash_failed.asm b/scripts/save_flash_failed.asm new file mode 100644 index 0000000..d60698d --- /dev/null +++ b/scripts/save_flash_failed.asm @@ -0,0 +1,51 @@ +.if WRONG_SAVE_TYPE_ERROR +.org 0x800028c +ldr r7, =(@NoFlashMemoryCallback | 1) +bx r7 +.pool + +.autoregion +.align 2 +@NoFlashMemoryCallback: +cmp r0, #1 +beq @return_to_main +ldr r0, =(@MainCBHook | 1) +ldr r7, =(0x80003cc | 1) +bl @linker + +@return_to_main: +ldr r7, =(0x8000294 | 1) +bx r7 + +@linker: +bx r7 +.pool + +@MainCBHook: +push {r0-r2, lr} +ldr r2, =(0x3001bac) +ldrb r1, [r2] + +cmp r1, #0x1 +beq @early_ret + +ldr r0, =(@ErrorText) + +push {r0-r7} +bl FlashNotDetectedScreen +pop {r0-r7} + +mov r1, #0x1 +strb r1, [r2] + +@early_ret: +pop {r0-r2, pc} +.pool + +@ErrorText: +.byte 0xFC, 0x01, 0x02 +.stringn "ERROR!\n" +.byte 0xFC, 0x01, 0x01 +.string "Flash memory not detected.\n\nSet your emulator's save type\nsetting to Flash 1MB / 128K\nand reload the rom." +.endautoregion +.endif \ No newline at end of file diff --git a/src/save_failed_screen.c b/src/save_failed_screen.c new file mode 100644 index 0000000..5b2eb24 --- /dev/null +++ b/src/save_failed_screen.c @@ -0,0 +1,53 @@ +#include "types.h" +#include "constants/gba.h" +#include "main.h" +#include "menu.h" +#include "palette.h" +#include "text.h" +#include "bios.h" + +void FlashNotDetectedScreen(const u8 *message) +{ + u32 savedIme; + + REG_DISPCNT = 0; + REG_BG3CNT = 0; + REG_BG2CNT = 0; + REG_BG1CNT = 0; + REG_BG0CNT = 0; + REG_BG3HOFS = 0; + REG_BG3VOFS = 0; + REG_BG2HOFS = 0; + REG_BG2VOFS = 0; + REG_BG1HOFS = 0; + REG_BG1VOFS = 0; + REG_BG0HOFS = 0; + REG_BG0VOFS = 0; + + DmaFill16(3, 0, VRAM, VRAM_SIZE); + DmaFill32(3, 0, OAM, OAM_SIZE); + DmaFill16(3, 0, PLTT, PLTT_SIZE); + + Text_LoadWindowTemplate(&gWindowTemplate_81E6C3C); + InitMenuWindow(&gMenuTextWindowTemplate); + + Menu_DrawStdWindowFrame(3, 3, 26, 16); + Menu_PrintText(message, 5, 4); + + savedIme = REG_IME; + REG_IME = 0; + REG_IE |= INTR_FLAG_VBLANK; + REG_IME = savedIme; + REG_DISPSTAT |= DISPSTAT_VBLANK_INTR; + + REG_BLDCNT = 0; + REG_BLDALPHA = 0; + REG_BLDY = 0; + REG_BG3CNT = BGCNT_PRIORITY(3) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(6) | BGCNT_16COLOR | BGCNT_TXT512x256; + REG_DISPCNT = DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_ON; + + TransferPlttBuffer(); + *(u16*)PLTT = RGB(17, 18, 31); + REG_SOUNDCNT_X = 0; + REG_SOUNDBIAS = 0; +} \ No newline at end of file