├── fe6.sha1 ├── include ├── msg.h ├── gba │ ├── gba.h │ └── defines.h ├── gold.h ├── movepath.h ├── asm_macros.inc ├── constants │ ├── videoalloc_banim.h │ ├── videoalloc_wm.h │ ├── chapters.h │ ├── jids.h │ └── terrains.h ├── trademenu.h ├── unitrearrange.h ├── ai_phase.h ├── sioerror.h ├── icon.h ├── prepphase.h ├── supply.h ├── ai_perform.h ├── irq.h ├── random.h ├── ai_order.h ├── gbasram.h ├── move.h ├── bmio.h ├── battlepreview.h ├── savelayout.h ├── faction.h ├── masseffect.h ├── save.h ├── attributes.h ├── chapterinfo.h ├── chapter.h ├── unitpanel.h ├── itemaction.h ├── debugtext.h ├── ui.h ├── subtitlehelp.h ├── gamecontroller.h ├── prelude.h ├── playerphase.h ├── arena.h ├── map.h ├── ai_decide.h ├── ai_battle.h ├── ai_data.h ├── sound.h ├── sprite.h ├── mapwork.h ├── support.h ├── bmfx.h ├── save_multiarena.h ├── types.h ├── save_xmap.h ├── spriteanim.h ├── save_core.h ├── armfunc.h ├── action.h ├── minimap.h ├── banim_ekrdragon.h ├── menuinfo.h ├── save_stats.h └── trap.h ├── data ├── data_mapchangeinfo.s ├── data_dbgfont.s ├── data-code-mu.s ├── rodata_msg.s ├── rodata_trig.s ├── data-banim.s ├── data_textglyphs.s ├── rodata_3273E4.s ├── rodata_icon.s ├── chapters │ ├── trial_a │ │ ├── eventscript.h │ │ └── eventinfo.h │ ├── trial_b │ │ └── eventscript.h │ ├── trial_d │ │ ├── eventscript.h │ │ └── eventinfo.h │ ├── trial_e │ │ ├── eventscript.h │ │ └── eventinfo.h │ ├── trial_c │ │ ├── eventscript.h │ │ └── eventinfo.h │ ├── final │ │ └── eventinfo.h │ ├── chapter20x_i │ │ ├── eventinfo.h │ │ └── eventscript.h │ ├── chapter8x │ │ └── eventinfo.h │ ├── chapter14x │ │ └── eventinfo.h │ ├── chapter16x │ │ └── eventinfo.h │ ├── chapter21x │ │ └── eventinfo.h │ ├── chapter20x_s │ │ └── eventinfo.h │ ├── chapter12x │ │ ├── eventscript.h │ │ └── eventinfo.h │ ├── chapter1 │ │ └── eventinfo.h │ ├── chapter2 │ │ └── eventinfo.h │ ├── tutorial │ │ └── eventinfo.h │ ├── chapter19_i │ │ └── eventinfo.h │ ├── chapter5 │ │ └── eventinfo.h │ ├── chapter24 │ │ └── eventinfo.h │ ├── chapter23 │ │ └── eventinfo.h │ ├── chapter17_i │ │ └── eventinfo.h │ ├── chapter15 │ │ └── eventinfo.h │ ├── chapter17_s │ │ └── eventinfo.h │ ├── chapter3 │ │ └── eventinfo.h │ ├── chapter21 │ │ └── eventinfo.h │ ├── chapter9 │ │ └── eventinfo.h │ ├── chapter10_a │ │ └── eventinfo.h │ └── chapter18_s │ │ └── eventinfo.h ├── rodata_lib.s ├── data_66618C.s ├── rodata_3278AC.s └── rodata_327254.s ├── .gitattributes ├── tools ├── scripts │ ├── sjb-print.py │ ├── msgs!.py │ ├── asm2casm.py │ ├── rename.sh │ ├── to-tm-offset.py │ ├── symbols.py │ ├── sjb-decode.py │ ├── dump_shops.py │ ├── find-pointers.py │ ├── dump-int-array.py │ ├── dump-pointers.py │ ├── fix-file-encoding.py │ ├── dump-ai-script.py │ ├── sjb-tab-dump.py │ ├── findiwrams.py │ ├── dump-system-labels.py │ ├── dump_unitlistpagefield.py │ ├── sjb_tab_dump_inl.py │ ├── dump_all_chapter_event_info.sh │ ├── dump-ai-escape-points.py │ ├── extract-bgs.py │ ├── dump-ai-attack-config.py │ ├── datasplit.py │ └── dump_helpinfo.py ├── stats │ └── calcstats.sh └── install_agbcc.sh ├── bindiff.sh ├── asmdiff.sh ├── src ├── code_sio.c ├── chapterunits.c ├── msg.c ├── gold.c ├── irq.c ├── gamedata.c ├── banim_ekrlvupfan.c ├── unitrearrange.c ├── chapterinfo.c ├── main.c ├── faction.c ├── supply.c ├── ai_phase.c ├── ramfunc.c ├── move.c ├── oam.c └── sioerror.c ├── TODO ├── .github └── workflows │ └── build.yml ├── asm ├── code_linker_stubs.s ├── include │ └── macro.inc └── gbasyscall.s ├── docs ├── DECOMPILING-NOTES.md ├── NONMATCHING.md └── GLOSSARY.md └── README.md /fe6.sha1: -------------------------------------------------------------------------------- 1 | a57095da867de4d585c33d4394712986245fe6ca fe6.gba 2 | -------------------------------------------------------------------------------- /include/msg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | char * DecodeMsg(int id); 6 | -------------------------------------------------------------------------------- /data/data_mapchangeinfo.s: -------------------------------------------------------------------------------- 1 | .data 2 | 3 | .incbin "fe6-base.gba", 0x68784C, (0x689DD8 - 0x68784C) @ length: 258C 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c linguist-language=c 2 | *.h linguist-language=c 3 | *.s linguist-language=gas 4 | *.inc linguist-language=gas 5 | -------------------------------------------------------------------------------- /data/data_dbgfont.s: -------------------------------------------------------------------------------- 1 | 2 | .data 3 | 4 | .global Img_DebugFont 5 | Img_DebugFont: @ 858E62C 6 | .incbin "fe6-base.gba", 0x58E62C, (0x58EE2C - 0x58E62C) 7 | -------------------------------------------------------------------------------- /data/data-code-mu.s: -------------------------------------------------------------------------------- 1 | 2 | .data 3 | 4 | .global MuInfoTable 5 | MuInfoTable: @ 086649B4 6 | .incbin "fe6-base.gba", 0x6649B4, (0x664C0C - 0x6649B4) @ length: 0258 7 | -------------------------------------------------------------------------------- /include/gba/gba.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gba/defines.h" 4 | #include "../types.h" 5 | #include "../gbaio.h" 6 | #include "../gbasvc.h" 7 | #include "gba/macro.h" 8 | -------------------------------------------------------------------------------- /include/gold.h: -------------------------------------------------------------------------------- 1 | #ifndef GOLD_H 2 | #define GOLD_H 3 | 4 | #include "prelude.h" 5 | 6 | int GetGold(void); 7 | void SetGold(int amount); 8 | void AddGold(int amount); 9 | 10 | #endif // GOLD_H 11 | -------------------------------------------------------------------------------- /tools/scripts/sjb-print.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def main(args): 5 | data = bytes(int(s, base = 0) for s in args) 6 | print(data.decode("sjis")) 7 | 8 | if __name__ == '__main__': 9 | main(sys.argv[1:]) 10 | -------------------------------------------------------------------------------- /data/rodata_msg.s: -------------------------------------------------------------------------------- 1 | 2 | .section .rodata 3 | 4 | .incbin "fe6-base.gba", 0x09FAC0, (0x0F635C - 0x09FAC0) 5 | 6 | .global gMsgTable 7 | gMsgTable: @ 080F635C 8 | .incbin "fe6-base.gba", 0x0F635C, (0x0F9794 - 0x0F635C) 9 | -------------------------------------------------------------------------------- /include/movepath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | void GenMovePathFromMoveScript(void); 6 | void GenMoveScriptFromMovePath(void); 7 | void InitMovePath(bool display_only); 8 | void RefreshMovePath(void); 9 | -------------------------------------------------------------------------------- /tools/scripts/msgs!.py: -------------------------------------------------------------------------------- 1 | print("#pragma once") 2 | print("") 3 | print("enum") 4 | print("{") 5 | for i in range(0xD0D): 6 | msg = i + 1 7 | print(f" MSG_{msg:03X} = 0x{msg:03X},") 8 | 9 | print("};") 10 | -------------------------------------------------------------------------------- /include/asm_macros.inc: -------------------------------------------------------------------------------- 1 | .macro function name 2 | .align 2, 0 3 | .global \name 4 | .type \name , function 5 | .endm 6 | 7 | .macro endfunction name 8 | .size \name , . - \name 9 | .endm 10 | -------------------------------------------------------------------------------- /include/constants/videoalloc_banim.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "constants/videoalloc_global.h" 4 | 5 | enum 6 | { 7 | OBCHR_BANIM_FACE = 0x40, 8 | }; 9 | 10 | enum 11 | { 12 | OBPAL_BANIM_FACE = 3, 13 | }; 14 | -------------------------------------------------------------------------------- /bindiff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # from https://superuser.com/questions/125376/how-do-i-compare-binary-files-in-linux because I'm newb 4 | cmp -l fe6-base.gba fe6.gba | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}' | more 5 | -------------------------------------------------------------------------------- /include/trademenu.h: -------------------------------------------------------------------------------- 1 | #ifndef TRADEMENU_H 2 | #define TRADEMENU_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "proc.h" 7 | 8 | ProcPtr StartTradeMenu(struct Unit * unit_a, struct Unit * unit_b, int unused); 9 | 10 | #endif // TRADEMENU_H 11 | -------------------------------------------------------------------------------- /data/rodata_trig.s: -------------------------------------------------------------------------------- 1 | 2 | .section .rodata 3 | 4 | BEGIN = 0x0F9998 5 | END = 0x0F9C18 6 | 7 | @ TODO: extract that into a C file, included into hardware.c 8 | 9 | .global gSinLut 10 | gSinLut: @ 080F9998 11 | .incbin "fe6-base.gba", BEGIN, (END - BEGIN) 12 | -------------------------------------------------------------------------------- /include/unitrearrange.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "unit.h" 6 | 7 | void UnitRearrangeInit(struct Unit * buf); 8 | void UnitRearrangeAdd(struct Unit * unit); 9 | void UnitRearrangeApply(void); 10 | void UnitRearrangeApply2(void); 11 | -------------------------------------------------------------------------------- /data/data-banim.s: -------------------------------------------------------------------------------- 1 | 2 | .data 3 | 4 | BEGIN = 0x6A0000 5 | END = 0x7FF0A4 6 | 7 | .global banim_number 8 | banim_number: 9 | .incbin "fe6-base.gba", BEGIN, 8 10 | 11 | .global banim_data 12 | banim_data: 13 | .incbin "fe6-base.gba", BEGIN + 8, (END - BEGIN - 8) 14 | -------------------------------------------------------------------------------- /asmdiff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OBJDUMP="$DEVKITARM/bin/arm-none-eabi-objdump -D -bbinary -marmv4t -Mforce-thumb" 4 | OPTIONS="--start-address=$(($1)) --stop-address=$(($1 + $2))" 5 | $OBJDUMP $OPTIONS fe6-base.gba > fe6-base.dump 6 | $OBJDUMP $OPTIONS fe6.gba > fe6.dump 7 | diff fe6-base.dump fe6.dump 8 | -------------------------------------------------------------------------------- /src/code_sio.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | #include "constants/songs.h" 4 | 5 | struct Unk_0810DBBC 6 | { 7 | u16 song; 8 | }; 9 | 10 | struct Unk_0810DBBC const gUnk_0810DBBC[] = 11 | { 12 | { SONG_6C }, 13 | { SONG_6C }, 14 | { SONG_6C }, 15 | { SONG_6C }, 16 | }; 17 | -------------------------------------------------------------------------------- /include/ai_phase.h: -------------------------------------------------------------------------------- 1 | #ifndef AI_PHASE_H 2 | #define AI_PHASE_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "proc.h" 7 | #include "ai.h" 8 | 9 | extern struct ProcScr CONST_DATA ProcScr_AiPhase[]; 10 | extern struct ProcScr CONST_DATA ProcScr_AiPhase_Berserk[]; 11 | 12 | #endif // AI_PHASE_H 13 | -------------------------------------------------------------------------------- /tools/scripts/asm2casm.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def main(): 5 | print('asm("\\') 6 | print('\t.syntax unified\\n\\') 7 | 8 | for line in sys.stdin: 9 | print('{}\\n\\'.format(line[:-1])) 10 | 11 | print('\t.syntax divided\\n\\') 12 | print('");') 13 | 14 | if __name__ == '__main__': 15 | main() 16 | -------------------------------------------------------------------------------- /src/chapterunits.c: -------------------------------------------------------------------------------- 1 | #include "chapterunits.h" 2 | 3 | #include "event.h" 4 | #include "eventscript.h" 5 | #include "unit.h" 6 | #include "faction.h" 7 | #include "ai.h" 8 | 9 | #include "constants/pids.h" 10 | #include "constants/jids.h" 11 | #include "constants/iids.h" 12 | 13 | #include "data/chapterunits_data.h" 14 | -------------------------------------------------------------------------------- /include/sioerror.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | // TODO: is this good name? 6 | // what is this error screen actually? 7 | 8 | void OnVBlank_SioError(void); 9 | void OnMain_SioErrorWait(void); 10 | void PutSioErrorMessage(void); 11 | void OnMain_SioError(void); 12 | void StartSioErrorScreen(void); 13 | -------------------------------------------------------------------------------- /include/icon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gba/gba.h" 4 | 5 | void InitIcons(void); 6 | void ClearIcons(void); 7 | void ApplyIconPalettes(int palid); 8 | void ApplyIconPalette(int num, int palid); 9 | void PutIcon(u16 * tm, int icon, int tileref); 10 | void ClearIcon(int icon); 11 | void PutIconObjImg(int icon, int chr); 12 | -------------------------------------------------------------------------------- /include/prepphase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "proc.h" 6 | #include "menu.h" 7 | 8 | fu8 PrepMapMenuConfirm(struct MenuProc * menu, struct MenuEntProc * ent); 9 | void func_fe6_0802B784(void); 10 | void func_fe6_0802B7E4(void); 11 | 12 | extern struct ProcScr CONST_DATA ProcScr_PrepPhase[]; 13 | -------------------------------------------------------------------------------- /tools/stats/calcstats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage: ./calcstats.sh ELF MAP 4 | 5 | if [[ ! $# -eq 2 ]] 6 | then 7 | echo "Usage: $0 ELF MAP" 8 | exit 1 9 | fi 10 | 11 | temp=$(mktemp) 12 | 13 | arm-none-eabi-nm $1 > $temp 14 | python $(dirname "$(readlink -f "$0")")/calcstats.py $2 $temp 15 | 16 | rm -f $temp 17 | -------------------------------------------------------------------------------- /tools/scripts/rename.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -ne "2" ]; 4 | then 5 | echo "usage: $0 " 6 | exit 1 7 | fi 8 | 9 | echo "Rename $1 to $2?" 10 | read 11 | 12 | grep -rl "$1" asm/*.s asm/*/*.s src/*.c src/*/*.c include/*.h include/*/*.h data/*.s data/*/*.h ldscr.txt | xargs sed -i "s/\b$1\b/$2/g" 13 | -------------------------------------------------------------------------------- /include/supply.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | enum { SUPPLY_ITEM_COUNT = 100 }; 6 | 7 | u16 * GetSupplyItems(void); 8 | void ClearSupplyItems(void); 9 | void SquashSupplyItems(void); 10 | int CountSupplyItems(void); 11 | int AddSupplyItem(int item); 12 | void RemoveSupplyItem(int slot); 13 | int FindSupplyItem(int item); 14 | -------------------------------------------------------------------------------- /include/ai_perform.h: -------------------------------------------------------------------------------- 1 | #ifndef AI_PERFORM_H 2 | #define AI_PERFORM_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "proc.h" 7 | #include "ai.h" 8 | 9 | void AiStartActionCursor(int x, int y, int kind, ProcPtr parent); 10 | void AiEndMuAndRefreshUnits(void); 11 | 12 | extern struct ProcScr CONST_DATA ProcScr_AiPerform[]; 13 | 14 | #endif // AI_PERFORM_H 15 | -------------------------------------------------------------------------------- /tools/install_agbcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | here=$(dirname "$(readlink -f "$0")")/.. 4 | temp=$(mktemp -d) 5 | 6 | agbcc_repo="https://github.com/StanHash/agbcc.git" 7 | agbcc_branch="tpcs_frame" 8 | 9 | git clone $agbcc_repo $temp 10 | 11 | cd $temp 12 | git checkout origin/$agbcc_branch 13 | ./build.sh 14 | ./install.sh $here 15 | 16 | rm -fr $temp 17 | -------------------------------------------------------------------------------- /include/irq.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gba/gba.h" 4 | 5 | enum 6 | { 7 | // TODO: INT constants 8 | 9 | INT_VBLANK = 0, 10 | INT_HBLANK = 1, 11 | INT_VCOUNT = 2, 12 | 13 | INT_COUNT = 14, 14 | }; 15 | 16 | typedef void (* IrqFunc)(void); 17 | 18 | void IrqMain(void); 19 | 20 | void IrqInit(void); 21 | void SetIrqFunc(int num, IrqFunc func); 22 | -------------------------------------------------------------------------------- /include/constants/videoalloc_wm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "constants/videoalloc_global.h" 4 | 5 | enum 6 | { 7 | OBCHR_WM_FACE_A = 0x200, 8 | OBCHR_WM_FACE_B = 0x288, 9 | 10 | OBCHR_WM_TEXT = 0x340, 11 | }; 12 | 13 | enum 14 | { 15 | OBPAL_WM_TEXTBOX = 9, 16 | OBPAL_WM_TEXT = 13, 17 | 18 | OBPAL_WM_FACE_A = 14, 19 | OBPAL_WM_FACE_B = 15, 20 | }; 21 | -------------------------------------------------------------------------------- /include/random.h: -------------------------------------------------------------------------------- 1 | #ifndef RANDOM_H 2 | #define RANDOM_H 3 | 4 | #include "prelude.h" 5 | 6 | void RandInit(int seed); 7 | 8 | void RandSetSt(u16 const * st); 9 | void RandGetSt(u16 * st); 10 | 11 | int RandNext_100(void); 12 | int RandNext(int max); 13 | bool RandRoll(int threshold); 14 | bool RandRoll2Rn(int threshold); 15 | 16 | void RandInitB(int seed); 17 | u32 RandNextB(void); 18 | 19 | #endif // RANDOM_H 20 | -------------------------------------------------------------------------------- /tools/scripts/to-tm-offset.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def main(args): 5 | try: 6 | offset = int(args[0], base = 0) 7 | 8 | except IndexError: 9 | sys.exit(f"Usage: {sys.argv[0]} ") 10 | 11 | index = offset // 2 12 | 13 | y = index // 0x20 14 | x = index % 0x20 15 | 16 | print(f"TM_OFFSET({x}, {y})") 17 | 18 | if __name__ == "__main__": 19 | main(sys.argv[1:]) 20 | -------------------------------------------------------------------------------- /src/msg.c: -------------------------------------------------------------------------------- 1 | #include "msg.h" 2 | 3 | #include "armfunc.h" 4 | 5 | extern u8 const * const gMsgTable[]; 6 | 7 | static char EWRAM_DATA sMsgString[0x1000] = {}; 8 | static int EWRAM_DATA sActiveMsg = 0; 9 | 10 | char * DecodeMsg(int id) 11 | { 12 | if (id == sActiveMsg) 13 | return sMsgString; 14 | 15 | DecodeString(gMsgTable[id], sMsgString); 16 | sActiveMsg = id; 17 | 18 | return sMsgString; 19 | } 20 | -------------------------------------------------------------------------------- /data/data_textglyphs.s: -------------------------------------------------------------------------------- 1 | 2 | .data 3 | 4 | .global TextGlyphs_System 5 | TextGlyphs_System: @ 0859027C 6 | .incbin "fe6-base.gba", 0x59027C, (0x5A8204 - 0x59027C) 7 | 8 | .global TextGlyphs_Special 9 | TextGlyphs_Special: @ 085A8204 10 | .incbin "fe6-base.gba", 0x5A8204, (0x5A82B0 - 0x5A8204) 11 | 12 | .global TextGlyphs_Talk 13 | TextGlyphs_Talk: @ 085A82B0 14 | .incbin "fe6-base.gba", 0x5A82B0, (0x5C39A0 - 0x5A82B0) 15 | -------------------------------------------------------------------------------- /data/rodata_3273E4.s: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | 3 | .global gUnk_083273E4 4 | gUnk_083273E4: @ 083273E4 5 | .incbin "fe6-base.gba", 0x3273E4, (0x3277BC - 0x3273E4) @ length: 03D8 6 | 7 | .global gUnk_083277BC 8 | gUnk_083277BC: @ 083277BC 9 | .incbin "fe6-base.gba", 0x3277BC, (0x3277DC - 0x3277BC) @ length: 0020 10 | 11 | .global gUnk_083277DC 12 | gUnk_083277DC: @ 083277DC 13 | .incbin "fe6-base.gba", 0x3277DC, (0x32785C - 0x3277DC) @ length: 0080 14 | -------------------------------------------------------------------------------- /include/ai_order.h: -------------------------------------------------------------------------------- 1 | #ifndef AI_ORDER_H 2 | #define AI_ORDER_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "proc.h" 7 | #include "ai.h" 8 | 9 | int GetUnitBattleAiScore(struct Unit * unit); 10 | int GetUnitAiScore(struct Unit * unit); 11 | int BuildAiUnitList(void); 12 | void SortAiUnitList(int count); 13 | 14 | extern struct ProcScr CONST_DATA ProcScr_AiOrder[]; 15 | extern struct ProcScr CONST_DATA ProcScr_AiOrder_Berserk[]; 16 | 17 | #endif // AI_ORDER_H 18 | -------------------------------------------------------------------------------- /src/gold.c: -------------------------------------------------------------------------------- 1 | #include "gold.h" 2 | 3 | #include "bm.h" 4 | 5 | enum { MAX_GOLD = 999999 }; 6 | 7 | int GetGold(void) 8 | { 9 | return gPlaySt.gold; 10 | } 11 | 12 | void SetGold(int amount) 13 | { 14 | gPlaySt.gold = amount; 15 | 16 | if (gPlaySt.gold > MAX_GOLD) 17 | gPlaySt.gold = MAX_GOLD; 18 | } 19 | 20 | void AddGold(int amount) 21 | { 22 | gPlaySt.gold += amount; 23 | 24 | if (gPlaySt.gold > MAX_GOLD) 25 | gPlaySt.gold = MAX_GOLD; 26 | } 27 | -------------------------------------------------------------------------------- /include/gbasram.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | void SetSramFastFunc(void); 6 | void WriteSramFast(u8 const * src, u8 * dest, u32 size); 7 | u32 WriteAndVerifySramFast(void const * src, void * dest, u32 size); 8 | extern u32 (* VerifySramFast)(void const * src, void * dest, u32 size); 9 | extern void (* ReadSramFast)(void const * src, void * dest, u32 size); 10 | 11 | #define CART_SRAM_ADDR 0x0E000000 12 | #define CART_SRAM_SIZE 0x00008000 13 | #define CART_SRAM ((void *) CART_SRAM_ADDR) 14 | -------------------------------------------------------------------------------- /tools/scripts/symbols.py: -------------------------------------------------------------------------------- 1 | 2 | def from_elf(f): 3 | from elftools.elf.elffile import ELFFile 4 | from elftools.elf.sections import SymbolTableSection 5 | 6 | elf = ELFFile(f) 7 | section = elf.get_section_by_name('.symtab') 8 | 9 | if section == None or not isinstance(section, SymbolTableSection): 10 | return 11 | 12 | for sym in section.iter_symbols(): 13 | if sym.entry.st_info.bind != 'STB_GLOBAL': 14 | continue 15 | 16 | yield (sym.entry.st_value, sym.name) 17 | -------------------------------------------------------------------------------- /src/irq.c: -------------------------------------------------------------------------------- 1 | #include "irq.h" 2 | 3 | extern IrqFunc gIrqFuncs[INT_COUNT]; 4 | extern u32 IntrMainRam[0x200]; 5 | 6 | static void DummyFunc(void); 7 | 8 | void IrqInit(void) 9 | { 10 | int i; 11 | 12 | for (i = 0; i < INT_COUNT; ++i) 13 | gIrqFuncs[i] = DummyFunc; 14 | 15 | CpuFastCopy(IrqMain, IntrMainRam, sizeof IntrMainRam); 16 | INTR_VECTOR = IntrMainRam; 17 | } 18 | 19 | static void DummyFunc(void) 20 | { 21 | } 22 | 23 | void SetIrqFunc(int num, IrqFunc func) 24 | { 25 | gIrqFuncs[num] = func; 26 | } 27 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - clean up: ai_080326C4, manim, eventfunctions, statusscreen 2 | - dump: gamedata 3 | - tools: msg, face, unitinfo, banim 4 | - decomp: unitlistscreen needs matches and finish. 5 | 6 | - flatten dir structure (include/gba -> include) 7 | - name remaining ewram symbols 8 | - clean up hard asm (not decompilable) in asm/ and move them to src/ (NOTE: port from fe7_us) 9 | 10 | rename move.h/move.c 11 | remove static funcs 12 | remove most static objects (except .bss) 13 | videoalloc constants in a single file 14 | every lz object: u8 -> u32 15 | -------------------------------------------------------------------------------- /data/rodata_icon.s: -------------------------------------------------------------------------------- 1 | 2 | .section .rodata 3 | 4 | .global Img_Icons 5 | Img_Icons: @ 080F9D80 6 | .incbin "fe6-base.gba", 0x0F9D80, (0x0FED80 - 0x0F9D80) 7 | 8 | .global Pal_Icons 9 | Pal_Icons: @ 080FED80 10 | .incbin "fe6-base.gba", 0x0FED80, (0x0FEDC0 - 0x0FED80) 11 | 12 | .global Img_FactionMiniCard 13 | Img_FactionMiniCard: @ 080FEDC0 14 | .incbin "fe6-base.gba", 0x0FEDC0, (0x0FFBC0 - 0x0FEDC0) 15 | 16 | .global Pal_FactionMiniCard 17 | Pal_FactionMiniCard: @ 080FFBC0 18 | .incbin "fe6-base.gba", 0x0FFBC0, (0x0FFC00 - 0x0FFBC0) 19 | -------------------------------------------------------------------------------- /include/move.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | void RegisterDataMove(void const * src, void * dst, int size); 6 | void RegisterDataFill(u32 value, void * dst, int size); 7 | void ApplyDataMoves(void); 8 | 9 | #define RegisterVramMove(src, offset, size) \ 10 | RegisterDataMove( \ 11 | (src), \ 12 | (void *) VRAM + (0x1FFFF & (offset)), \ 13 | (size)) 14 | 15 | #define RegisterVramFill(value, offset, size) \ 16 | RegisterDataFill( \ 17 | (value), \ 18 | (void *) VRAM + (0x1FFFF & (offset)), \ 19 | (size)) 20 | -------------------------------------------------------------------------------- /src/gamedata.c: -------------------------------------------------------------------------------- 1 | #include "gamedata.h" 2 | 3 | #include "item.h" 4 | #include "unit.h" 5 | #include "support.h" 6 | 7 | #include "constants/pids.h" 8 | #include "constants/jids.h" 9 | #include "constants/iids.h" 10 | #include "constants/msg.h" 11 | #include "constants/faces.h" 12 | #include "constants/banim_pal.h" 13 | #include "constants/unitsprites.h" 14 | #include "constants/icons.h" 15 | #include "constants/terrains.h" 16 | 17 | #include "data/gamedata/pinfo.h" 18 | #include "data/gamedata/jinfo.h" 19 | #include "data/gamedata/iinfo.h" 20 | #include "data/gamedata/terrain_info.h" 21 | -------------------------------------------------------------------------------- /data/chapters/trial_a/eventscript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventScr @ 08675FF0 4 | EventScr CONST_DATA EventScr_Unk_08675FF0[] = 5 | { 6 | EvtClearSkip 7 | EvtEnd 8 | }; 9 | 10 | // EventScr @ 08675FF8 11 | EventScr CONST_DATA EventScr_Unk_08675FF8[] = 12 | { 13 | EvtNextChapter(CHAPTER_TRIAL_A) 14 | EvtSleep(1) 15 | EvtKill 16 | EvtClearSkip 17 | EvtEnd 18 | }; 19 | 20 | // EventScr @ 08676014 21 | EventScr CONST_DATA EventScr_Unk_08676014[] = 22 | { 23 | EvtNextChapter(0) 24 | EvtSleep(1) 25 | EvtKill 26 | EvtClearSkip 27 | EvtEnd 28 | }; 29 | -------------------------------------------------------------------------------- /data/chapters/trial_b/eventscript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventScr @ 08676030 4 | EventScr CONST_DATA EventScr_Unk_08676030[] = 5 | { 6 | EvtClearSkip 7 | EvtEnd 8 | }; 9 | 10 | // EventScr @ 08676038 11 | EventScr CONST_DATA EventScr_Unk_08676038[] = 12 | { 13 | EvtSleep(64) 14 | EvtNextChapter(CHAPTER_TRIAL_B) 15 | EvtSleep(1) 16 | EvtKill 17 | EvtClearSkip 18 | EvtEnd 19 | }; 20 | 21 | // EventScr @ 0867605C 22 | EventScr CONST_DATA EventScr_Unk_0867605C[] = 23 | { 24 | EvtSleep(64) 25 | EvtNextChapter(0) 26 | EvtSleep(1) 27 | EvtKill 28 | EvtClearSkip 29 | EvtEnd 30 | }; 31 | -------------------------------------------------------------------------------- /data/chapters/trial_d/eventscript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventScr @ 086760FC 4 | EventScr CONST_DATA EventScr_Unk_086760FC[] = 5 | { 6 | EvtClearSkip 7 | EvtEnd 8 | }; 9 | 10 | // EventScr @ 08676104 11 | EventScr CONST_DATA EventScr_Unk_08676104[] = 12 | { 13 | EvtSleep(64) 14 | EvtNextChapter(CHAPTER_TRIAL_D) 15 | EvtSleep(1) 16 | EvtKill 17 | EvtClearSkip 18 | EvtEnd 19 | }; 20 | 21 | // EventScr @ 08676128 22 | EventScr CONST_DATA EventScr_Unk_08676128[] = 23 | { 24 | EvtSleep(64) 25 | EvtNextChapter(0) 26 | EvtSleep(1) 27 | EvtKill 28 | EvtClearSkip 29 | EvtEnd 30 | }; 31 | -------------------------------------------------------------------------------- /include/bmio.h: -------------------------------------------------------------------------------- 1 | #ifndef BMIO_H 2 | #define BMIO_H 3 | 4 | #include "prelude.h" 5 | 6 | void StartBmVSync(void); 7 | void EndBmVSync(void); 8 | void LockBmDisplay(void); 9 | void UnlockBmDisplay(void); 10 | void AllocWeatherParticles(int weather); 11 | void ApplyFlamesWeatherGradient(void); 12 | void WeatherInit(void); 13 | void WeatherVBlank(void); 14 | void WeatherUpdate(void); 15 | void DisableTilesetPalAnim(void); 16 | void EnableTilesetPalAnim(void); 17 | void SetWeather(int weather); 18 | 19 | extern struct ProcScr CONST_DATA ProcScr_BmVSync[]; 20 | extern struct ProcScr CONST_DATA ProcScr_MapTask[]; 21 | 22 | #endif // BMIO_H 23 | -------------------------------------------------------------------------------- /data/chapters/trial_e/eventscript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventScr @ 0867614C 4 | EventScr CONST_DATA EventScr_TrialE_Opening[] = 5 | { 6 | EvtClearSkip 7 | EvtEnd 8 | }; 9 | 10 | // EventScr @ 08676154 11 | EventScr CONST_DATA EventScr_TrialE_Victory[] = 12 | { 13 | EvtSleep(64) 14 | EvtNextChapter(CHAPTER_TRIAL_E) 15 | EvtSleep(1) 16 | EvtKill 17 | EvtClearSkip 18 | EvtEnd 19 | }; 20 | 21 | // EventScr @ 08676178 22 | EventScr CONST_DATA EventScr_TrialE_Failure[] = 23 | { 24 | EvtSleep(64) 25 | EvtNextChapter(0) 26 | EvtSleep(1) 27 | EvtKill 28 | EvtClearSkip 29 | EvtEnd 30 | }; 31 | -------------------------------------------------------------------------------- /include/battlepreview.h: -------------------------------------------------------------------------------- 1 | #ifndef BATTLE_PREVIEW_H 2 | #define BATTLE_PREVIEW_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "proc.h" 7 | #include "helpbox.h" 8 | 9 | void StartBattlePreview(struct MapSelectProc * proc); 10 | void UpdateBattlePreviewContents(void); 11 | void CloseBattlePreview(void); 12 | fu8 StartBattlePreviewHelpBox(struct MapSelectProc * proc, struct SelectTarget * target); 13 | 14 | void HelpBoxPopulateBattlePreviewAdvantageA(struct HelpBoxProc * proc); 15 | void HelpBoxPopulateBattlePreviewAdvantageB(struct HelpBoxProc * proc); 16 | 17 | extern struct ProcScr CONST_DATA ProcScr_BattlePreview[]; 18 | 19 | #endif // BATTLE_PREVIEW_H 20 | -------------------------------------------------------------------------------- /include/savelayout.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | #include "save.h" 5 | 6 | #include "save_core.h" 7 | #include "save_stats.h" 8 | #include "save_game.h" 9 | #include "save_multiarena.h" 10 | #include "save_xmap.h" 11 | 12 | #include "gbasram.h" 13 | 14 | struct SramMain 15 | { 16 | struct GlobalSaveInfo head; 17 | struct SaveBlockInfo block_info[SAVE_COUNT]; 18 | struct SuspendSaveBlock suspend; 19 | struct SuspendSaveBlock suspend_alt; 20 | struct GameSaveBlock game_0; 21 | struct GameSaveBlock game_1; 22 | struct GameSaveBlock game_2; 23 | struct MultiArenaSaveBlock multi_arena; 24 | }; 25 | 26 | STATIC_ASSERT(CART_SRAM_SIZE - SRAM_XMAP_SIZE >= sizeof(struct SramMain)); 27 | -------------------------------------------------------------------------------- /data/rodata_lib.s: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | 3 | .incbin "fe6-base.gba", 0x381254, (0x57A61C - 0x381254) @ length: 1F93C8 4 | 5 | .global Song_Unk_0857A61C 6 | Song_Unk_0857A61C: @ 0857A61C 7 | .incbin "fe6-base.gba", 0x57A61C, (0x57B774 - 0x57A61C) @ length: 1158 8 | 9 | .global Song_Unk_0857B774 10 | Song_Unk_0857B774: @ 0857B774 11 | .incbin "fe6-base.gba", 0x57B774, (0x57C1E4 - 0x57B774) @ length: 0A70 12 | 13 | .global Song_Unk_0857C1E4 14 | Song_Unk_0857C1E4: @ 0857C1E4 15 | .incbin "fe6-base.gba", 0x57C1E4, (0x57C95C - 0x57C1E4) @ length: 0778 16 | 17 | .global Song_Unk_0857C95C 18 | Song_Unk_0857C95C: @ 0857C95C 19 | .incbin "fe6-base.gba", 0x57C95C, (0x58E578 - 0x57C95C) @ length: 11C1C 20 | -------------------------------------------------------------------------------- /include/faction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | // TODO: those constants could go in units also 6 | // would be more convenient 7 | 8 | enum 9 | { 10 | FACTION_BLUE = 0x00, 11 | FACTION_RED = 0x80, 12 | FACTION_GREEN = 0x40, 13 | FACTION_PURPLE = 0xC0, 14 | }; 15 | 16 | enum 17 | { 18 | FACTION_ID_BLUE = 0, 19 | FACTION_ID_GREEN = 1, 20 | FACTION_ID_RED = 2, 21 | FACTION_ID_PURPLE = 3, 22 | }; 23 | 24 | int CountFactionMoveableUnits(int faction); 25 | int CountFactionUnitsWithoutFlags(int faction, int prohibited_flags); 26 | bool AreUnitIdsAllied(int uidA, int uidB); 27 | bool AreUnitIdsSameFaction(int uidA, int uidB); 28 | int GetActiveFactionAlliance(void); 29 | int GetActiveFactionOpposingAlliance(void); 30 | -------------------------------------------------------------------------------- /tools/scripts/sjb-decode.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def read_int(f, count, signed = False): 5 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 6 | 7 | def read_sjis_string(f): 8 | array = bytearray(b'') 9 | 10 | while True: 11 | byte = f.read(1)[0] 12 | 13 | if byte == 0: 14 | break 15 | 16 | array.append(byte) 17 | 18 | return array.decode("sjis") 19 | 20 | def main(args): 21 | try: 22 | romName = args[0] 23 | offset = int(args[1], base = 0) & 0x1FFFFFF 24 | 25 | except IndexError: 26 | sys.exit("usage: {} ".format(sys.argv[0])) 27 | 28 | with open(romName, 'rb') as f: 29 | f.seek(offset) 30 | print(f"\"{read_sjis_string(f)}\"") 31 | 32 | if __name__ == '__main__': 33 | main(sys.argv[1:]) 34 | -------------------------------------------------------------------------------- /data/chapters/trial_c/eventscript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventScr @ 08676080 4 | EventScr CONST_DATA EventScr_Unk_08676080[] = 5 | { 6 | EvtClearSkip 7 | EvtEnd 8 | }; 9 | 10 | // EventScr @ 08676088 11 | EventScr CONST_DATA EventScr_Unk_08676088[] = 12 | { 13 | EvtSleep(64) 14 | EvtNextChapter(CHAPTER_TRIAL_C) 15 | EvtSleep(1) 16 | EvtKill 17 | EvtClearSkip 18 | EvtEnd 19 | }; 20 | 21 | // EventScr @ 086760AC 22 | EventScr CONST_DATA EventScr_Unk_086760AC[] = 23 | { 24 | EvtGotoIfFunc(3, IsRedPhase) 25 | 26 | EvtClearFlag(FLAG_3) 27 | EvtGoto(9) 28 | 29 | EvtLabel(3) 30 | EvtSleep(64) 31 | EvtNextChapter(0) 32 | EvtSleep(1) 33 | EvtKill 34 | 35 | EvtLabel(9) 36 | EvtClearSkip 37 | EvtEnd 38 | }; 39 | -------------------------------------------------------------------------------- /include/masseffect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | void ApplyHazardHealing(ProcPtr proc, struct Unit * unit, int arg_2, int arg_3); 6 | void BeginUnitHealAnim(struct Unit * unit, int hp); 7 | void BeginPoisonDamageAnim(struct Unit * unit, int damage); 8 | void BeginUnitTrapDamageAnim(struct Unit * unit, int damage); 9 | void StartStatusHealEffect(struct Unit * unit, ProcPtr parent); 10 | void FinishDamageDisplay(ProcPtr proc); 11 | 12 | extern struct ProcScr CONST_DATA ProcScr_Unused_KillAllRedUnits[]; 13 | extern struct ProcScr CONST_DATA ProcScr_TerrainHealDisplay[]; 14 | extern struct ProcScr CONST_DATA ProcScr_PoisonDamageDisplay[]; 15 | extern struct ProcScr CONST_DATA ProcScr_StatusDecayDisplay[]; 16 | extern struct ProcScr CONST_DATA ProcScr_TrapDamageDisplay[]; 17 | -------------------------------------------------------------------------------- /include/save.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | enum 6 | { 7 | SAVE_GAME0, 8 | SAVE_GAME1, 9 | SAVE_GAME2, 10 | SAVE_SUSPEND, 11 | SAVE_SUSPEND_ALT, 12 | SAVE_MULTIARENA, 13 | SAVE_XMAP, 14 | SAVE_COUNT, 15 | }; 16 | 17 | enum 18 | { 19 | SAVE_KIND_GAME, 20 | SAVE_KIND_SUSPEND, 21 | SAVE_KIND_MULTIARENA, 22 | SAVE_KIND_XMAP, 23 | 24 | SAVE_KIND_INVALID = UINT8_MAX, 25 | }; 26 | 27 | enum 28 | { 29 | SAVE_MAGIC32 = 0x11217, 30 | SAVE_MAGIC32_MULTIARENA = 0x20112, 31 | SAVE_MAGIC32_XMAP = 0x20223, 32 | SAVE_MAGIC16 = 0x200A, 33 | }; 34 | 35 | // forward type declaration 36 | struct GlobalSaveInfo; 37 | struct SaveBlockInfo; 38 | struct GameSaveBlock; 39 | struct SuspendSaveBlock; 40 | struct MultiArenaSaveBlock; 41 | -------------------------------------------------------------------------------- /src/banim_ekrlvupfan.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | #include "proc.h" 3 | #include "sound.h" 4 | #include "banim_sprite.h" 5 | #include "banim.h" 6 | 7 | struct ProcScr CONST_DATA ProcScr_EkrLvupFan[] = 8 | { 9 | PROC_19, 10 | PROC_REPEAT(EkrLvupFanMain), 11 | PROC_END, 12 | }; 13 | 14 | void NewEkrLvlupFan(void) 15 | { 16 | struct ProcEfx * proc = SpawnProc(ProcScr_EkrLvupFan, PROC_TREE_3); 17 | proc->timer = 0; 18 | SetBgmVolume(0x80); 19 | } 20 | 21 | void EkrLvupFanMain(struct ProcEfx * proc) 22 | { 23 | int timer = ++proc->timer; 24 | if (timer == 0x10) 25 | { 26 | EfxPlaySE(0x5B, 0x100); 27 | M4aPlayWithPostionCtrl(0x5B, 0x78, 0); 28 | } 29 | else if (timer == 0x74) 30 | { 31 | SetBgmVolume(0x100); 32 | Proc_Break(proc); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /include/attributes.h: -------------------------------------------------------------------------------- 1 | #ifndef ATTRIBUTES_H 2 | #define ATTRIBUTES_H 3 | 4 | #include 5 | 6 | #define SECTION(name) __attribute__((section(name))) 7 | 8 | #define IWRAM_DATA SECTION("iwram_data") 9 | #define EWRAM_DATA SECTION("ewram_data") 10 | #define EWRAM_OVERLAY(id) SECTION("ewram_overlay_" # id) 11 | 12 | #define ALIGNED(n) __attribute__((aligned(n))) 13 | #define NAKEDFUNC __attribute__((naked)) 14 | 15 | #if defined(MODERN) && MODERN 16 | # define CONST_DATA const 17 | # define COMMON_DATA(name) SECTION(".bss") 18 | # define SHOULD_BE_STATIC static 19 | # define SHOULD_BE_CONST const 20 | #else 21 | # define CONST_DATA SECTION(".data") 22 | # define COMMON_DATA(name) SECTION("COMMON." # name) 23 | # define SHOULD_BE_STATIC 24 | # define SHOULD_BE_CONST 25 | #endif 26 | 27 | #endif // ATTRIBUTES_H 28 | -------------------------------------------------------------------------------- /include/chapterinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "event.h" 6 | #include "unit.h" 7 | #include "eventinfo.h" 8 | 9 | struct ChapterEventInfo 10 | { 11 | /* 00 */ EventListScr const * event_list_turn; 12 | /* 04 */ EventListScr const * event_list_talk; 13 | /* 08 */ EventListScr const * event_list_tile; 14 | /* 0C */ EventListScr const * event_list_move; 15 | /* 10 */ struct UnitInfo const * units_red; 16 | /* 14 */ struct UnitInfo const * units_blue; 17 | /* 18 */ EventScr const * event_script_victory; 18 | }; 19 | 20 | struct ChapterInfo const * GetChapterInfo(int chapter); 21 | u8 const * GetChapterMap(int chapter); 22 | struct MapChangeInfo const * GetChapterMapChanges(int chapter); 23 | struct ChapterEventInfo const * GetChapterEventInfo(int chapter); 24 | char const * GetChapterUnk_0802BBD0(int chapter); 25 | -------------------------------------------------------------------------------- /include/chapter.h: -------------------------------------------------------------------------------- 1 | #ifndef CHAPTER_H 2 | #define CHAPTER_H 3 | 4 | #include "prelude.h" 5 | 6 | int GetTextPrintDelay(void); 7 | int IsFirstPlaythrough(void); 8 | void InitPlayConfig(int is_hard); 9 | void ResetBmSt(void); 10 | void StartChapter(struct GenericProc * parent); 11 | void func_fe6_08029084(void); 12 | void ResumeChapterFromSuspend(struct GenericProc * parent); 13 | void func_fe6_08029240(void); 14 | void func_fe6_080292B8(void); 15 | void InitBmDisplay(void); 16 | ProcPtr StartMapMain(struct GenericProc * parent); 17 | void EndMapMain(void); 18 | void CleanupUnitsBeforeChapter(void); 19 | void ResumeMapMainDuringPhase(ProcPtr mapmain); 20 | void ResumeMapMainDuringAction(ProcPtr mapmain); 21 | void ResumeMapMainDuringBerserk(ProcPtr mapmain); 22 | void ResumeMapMainDuringArena(ProcPtr mapmain); 23 | void ResumeMapMainDuringPhaseChange(ProcPtr mapmain); 24 | void func_fe6_08029654(void); 25 | 26 | #endif // CHAPTER_H 27 | -------------------------------------------------------------------------------- /data/data_66618C.s: -------------------------------------------------------------------------------- 1 | .data 2 | 3 | .global gBattleTalkList 4 | gBattleTalkList: @ 0866618C 5 | .incbin "fe6-base.gba", 0x66618C, (0x6663CC - 0x66618C) @ length: 0240 6 | 7 | .global gBattleTalkExtList 8 | gBattleTalkExtList: @ 086663CC 9 | .incbin "fe6-base.gba", 0x6663CC, (0x666528 - 0x6663CC) @ length: 015C 10 | 11 | .global gTriangleAttackTalkList 12 | gTriangleAttackTalkList: @ 08666528 13 | .incbin "fe6-base.gba", 0x666528, (0x666598 - 0x666528) @ length: 0070 14 | 15 | .global gBattleDefeatTalkList 16 | gBattleDefeatTalkList: @ 08666598 17 | .incbin "fe6-base.gba", 0x666598, (0x666C78 - 0x666598) @ length: 06E0 18 | 19 | .global gHardModeBonusLevelsOverrideList 20 | gHardModeBonusLevelsOverrideList: @ 08666C78 21 | .incbin "fe6-base.gba", 0x666C78, (0x666CF8 - 0x666C78) @ length: 0080 22 | 23 | .global gSupportTalkList 24 | gSupportTalkList: @ 08666CF8 25 | .incbin "fe6-base.gba", 0x666CF8, (0x667640 - 0x666CF8) @ length: 0948 26 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build_stats: 10 | name: Build 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Dependencies 15 | run: sudo apt update && sudo apt install -y build-essential gcc-arm-none-eabi binutils-arm-none-eabi && python -m pip install requests argparse 16 | 17 | - uses: actions/checkout@v3 18 | 19 | - name: Install agbcc 20 | run: tools/install_agbcc.sh 21 | 22 | - name: Generate dummy base ROM 23 | run: head -c 8M /dev/urandom > fe6-base.gba 24 | 25 | - name: Build target ROM 26 | run: make -j fe6.gba 27 | 28 | - name: Build stats 29 | run: tools/stats/calcstats.sh fe6.elf fe6.map > stats.txt 30 | 31 | - name: Upload stats 32 | run: python tools/stats/upload_stats.py -b https://progress.deco.mp -a ${{secrets.FROGRESS_API_KEY}} -p fireemblem6 -v jp stats.txt 33 | -------------------------------------------------------------------------------- /asm/code_linker_stubs.s: -------------------------------------------------------------------------------- 1 | .include "macro.inc" 2 | 3 | @ modern ld doesn't generate the same sequences 4 | @ so we can't use it to replace this file in matching builds 5 | 6 | thumb_func_start ClearOam_thm 7 | ClearOam_thm: @ 0x0809FA90 8 | bx pc 9 | .align 10 | .arm 11 | b ClearOam 12 | 13 | thumb_func_start TmApplyTsa_thm 14 | TmApplyTsa_thm: @ 0x0809FA98 15 | bx pc 16 | .align 17 | .arm 18 | b TmApplyTsa 19 | 20 | thumb_func_start TmFillRect_thm 21 | TmFillRect_thm: @ 0x0809FAA0 22 | bx pc 23 | .align 24 | .arm 25 | b TmFillRect 26 | 27 | thumb_func_start ColorFadeTick_thm 28 | ColorFadeTick_thm: @ 0x0809FAA8 29 | bx pc 30 | .align 31 | .arm 32 | b ColorFadeTick 33 | 34 | thumb_func_start TmCopyRect_thm 35 | TmCopyRect_thm: @ 0x0809FAB0 36 | bx pc 37 | .align 38 | .arm 39 | b TmCopyRect 40 | 41 | thumb_func_start Checksum32_thm 42 | Checksum32_thm: @ 0x0809FAB8 43 | bx pc 44 | .align 45 | .arm 46 | b Checksum32 47 | -------------------------------------------------------------------------------- /asm/include/macro.inc: -------------------------------------------------------------------------------- 1 | 2 | .MACRO ARM_FUNC_START name 3 | .ALIGN 2, 0 4 | .GLOBAL \name 5 | .ARM 6 | .TYPE \name, function 7 | .ENDM 8 | 9 | .MACRO ARM_FUNC_END name 10 | .SIZE \name, .-\name 11 | .ENDM 12 | 13 | .set NULL, 0 14 | 15 | .MACRO THUMB_FUNC_START name 16 | .ALIGN 2, 0 17 | .GLOBAL \name 18 | .THUMB 19 | .THUMB_FUNC 20 | .TYPE \name, function 21 | .ENDM 22 | 23 | .MACRO THUMB_FUNC_END name 24 | .SIZE \name, .-\name 25 | .ENDM 26 | 27 | 28 | @ Generates a glue function to be used when calling 29 | @ the specified ARM function from THUMB code. 30 | .MACRO THUMB_INTERWORK_VENEER name 31 | .SECTION .glue_7t 32 | .GLOBAL \name\()_t 33 | .THUMB 34 | .ALIGN 2, 0 35 | \name\()_t: 36 | bx pc @ Use a bx instruction to switch into ARM mode. The value of PC is 37 | nop @ 4 bytes ahead of the current instruction, so we pad with a nop. 38 | .ARM 39 | b \name @ Now in ARM mode, jump to the actual function 40 | .SECTION .text 41 | .ENDM 42 | -------------------------------------------------------------------------------- /include/unitpanel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | void StartUnitInventoryPanel(ProcPtr parent); 6 | void RefreshUnitInventoryPanel(struct Unit * unit); 7 | void RefreshUnitStealInventoryPanel(struct Unit * unit); 8 | void RefreshUnitRepairInventoryPanel(struct Unit * unit); 9 | void StartUnitHpPanel(ProcPtr parent); 10 | void RefreshUnitHpPanel(struct Unit * unit); 11 | void StartUnitHpStatusPanel(ProcPtr proc); 12 | void RefreshUnitHpStatusPanel(struct Unit * unit); 13 | void StartUnitResChangePanel(ProcPtr proc); 14 | void RefreshUnitResChangePanel(struct Unit * unit); 15 | void StartUnitStaffOffensePanel(ProcPtr proc); 16 | void RefreshUnitStaffOffensePanel(struct Unit * unit, int accuracy); 17 | void RefreshUnitTakeRescuePanels(ProcPtr proc); 18 | void RefreshUnitRescuePanels(struct Unit * unit); 19 | void RefreshUnitTakePanels(struct Unit * unit); 20 | void StartUnitGiveRescuePanels(ProcPtr parent); 21 | void RefreshUnitGivePanels(struct Unit * unit); 22 | -------------------------------------------------------------------------------- /include/itemaction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | void DoItemHealStaffAction(ProcPtr proc); 6 | void DoItemRestoreStaffAction(ProcPtr proc); 7 | void DoItemBarrierStaffAction(ProcPtr proc); 8 | void DoItemRescueStaffAction(ProcPtr proc); 9 | void DoItemWarpStaffAction(ProcPtr proc); 10 | void DoItemAttackStaffAction(ProcPtr proc); 11 | void DoItemFortifyStaffAction(ProcPtr proc); 12 | void DoItemUnlockStaffAction(ProcPtr proc); 13 | void DoItemRepairStaffAction(ProcPtr proc); 14 | void DoItemSaintStaffAction(ProcPtr proc); 15 | void DoItemHealSelfAction(ProcPtr proc, int amount); 16 | void DoItemElixirAction(ProcPtr proc); 17 | void DoItemPureWaterAction(ProcPtr proc); 18 | void DoItemTorchAction(ProcPtr proc); 19 | void DoItemAntitoxinAction(ProcPtr proc); 20 | void DoItemKeyAction(void); 21 | void DoItemPromoteAction(void); 22 | void func_fe6_08027DB4(struct Unit * unit, int item); 23 | void DoItemStatBoostAction(ProcPtr proc); 24 | void DoItemAction(ProcPtr proc); 25 | -------------------------------------------------------------------------------- /include/debugtext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | void DebugInitBg(int bg, int vramOffset); 6 | void DebugPutStr(u16 * tm, char const * str); 7 | void DebugPutFmt(u16 * tm, char const * fmt, ...); 8 | 9 | void GenNumberStr(int number); 10 | void GenNumberOrBlankStr(int number); 11 | void GenNumberHexStr(int number); 12 | 13 | void DebugScreenInit(void); 14 | void DebugPrintFmt(char const * fmt, ...); 15 | void DebugPrintNumber(int number, int length); 16 | void DebugPrintNumberHex(int number, int length); 17 | void DebugPrintStr(char const * str); 18 | void DebugPutScreen(void); 19 | bool DebugUpdateScreen(u16 held, u16 pressed); 20 | 21 | void DebugInitObj(int offset, int palid); 22 | void DebugPutObjStr(int x, int y, char const * str); 23 | void DebugPutObjNumber(int x, int y, int number, int length); 24 | void DebugPutObjNumberHex(int x, int y, int number, int length); 25 | 26 | // 8 characters + '\0'. least significant digit always at + 7 27 | extern char EWRAM_DATA gNumberStr[9]; 28 | -------------------------------------------------------------------------------- /tools/scripts/dump_shops.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from fe6db import IID_DICT 3 | 4 | START_ADDR = 0x0866A81C 5 | END_ADDR = 0x0866AAF8 6 | 7 | def main(args): 8 | try: 9 | rom_path = args[1] 10 | 11 | except IndexError: 12 | sys.exit(f"Usage: {args[0]} ROM") 13 | 14 | with open(rom_path, 'rb') as f: 15 | rom_data = f.read() 16 | 17 | off = START_ADDR - 0x08000000 18 | 19 | while off < END_ADDR - 0x08000000: 20 | print() 21 | print(f"// ShopItems @ {off + 0x08000000:08X}") 22 | print(f"u16 CONST_DATA ShopItems_Unk_{off + 0x08000000:08X}[] =") 23 | print("{") 24 | 25 | while True: 26 | iid = int.from_bytes(rom_data[off:off + 2], 'little') 27 | off = off + 2 28 | 29 | if iid == 0: 30 | print(' 0, // end') 31 | break 32 | 33 | iid_name = IID_DICT[iid] 34 | print(f" {iid_name},") 35 | 36 | print("};") 37 | 38 | if __name__ == '__main__': 39 | main(sys.argv) 40 | -------------------------------------------------------------------------------- /include/ui.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | enum 6 | { 7 | // window_theme (including PlaySt::config_window_theme) 8 | 9 | UI_WINDOW_THEME_BLUE, 10 | UI_WINDOW_THEME_RED, 11 | UI_WINDOW_THEME_GRAY, 12 | UI_WINDOW_THEME_GREEN, 13 | }; 14 | 15 | enum 16 | { 17 | // PutUiWindowFrame param window_kind 18 | 19 | UI_WINDOW_REGULAR, 20 | UI_WINDOW_FILL, 21 | UI_WINDOW_SABLE, 22 | }; 23 | 24 | void ApplyUiWindowFramePal(int palid); 25 | void UnpackUiWindowFrameImg(void * vram); 26 | void ApplyUiStatBarPal(int palid); 27 | void UnpackUiWindowFrameGraphics2(int window_theme); 28 | void PutUiWindowFrame(int x, int y, int width, int height, int window_kind); 29 | void PutUiHand(int x, int y); 30 | void PutFrozenUiHand(int x, int y); 31 | int GetUiHandPrevX(void); 32 | int GetUiHandPrevY(void); 33 | void ClearUi(void); 34 | void PutUiEntryHover(int x, int y, int width); 35 | void RemoveUiEntryHover(int x, int y, int width); 36 | void UnpackUiUnitNameFrameGraphics(void * vram, int palid, int palcount); 37 | void UnpackUiWindowFrameGraphics(void); 38 | -------------------------------------------------------------------------------- /src/unitrearrange.c: -------------------------------------------------------------------------------- 1 | #include "unitrearrange.h" 2 | 3 | #include "unit.h" 4 | 5 | static struct Unit * EWRAM_DATA sUnitBuf = NULL; 6 | static struct Unit * EWRAM_DATA sUnitBufIt = NULL; 7 | static u8 EWRAM_DATA sNextId = 0; 8 | 9 | void UnitRearrangeInit(struct Unit * buf) 10 | { 11 | sUnitBuf = sUnitBufIt = buf; 12 | sNextId = 1; 13 | } 14 | 15 | void UnitRearrangeAdd(struct Unit * unit) 16 | { 17 | sUnitBufIt->pinfo = NULL; 18 | CopyUnit(unit, sUnitBufIt); 19 | sUnitBufIt->id = sNextId; 20 | 21 | unit->max_hp = 0; 22 | 23 | sNextId++; 24 | sUnitBufIt++; 25 | } 26 | 27 | void UnitRearrangeApply(void) 28 | { 29 | int i; 30 | 31 | for (i = 0; i < UNIT_AMOUNT_BLUE; ++i) 32 | ClearUnit(gUnitArrayBlue + i); 33 | 34 | CpuCopy16(sUnitBuf, gUnitArrayBlue, ((int) sUnitBufIt) - ((int) sUnitBuf)); 35 | } 36 | 37 | void UnitRearrangeApply2(void) 38 | { 39 | int i; 40 | 41 | for (i = 0; i < UNIT_AMOUNT_BLUE; ++i) 42 | ClearUnit(gUnitArrayBlue + i); 43 | 44 | CpuCopy16(sUnitBuf, gUnitArrayBlue, ((int) sUnitBufIt) - ((int) sUnitBuf)); 45 | } 46 | -------------------------------------------------------------------------------- /tools/scripts/find-pointers.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def read_rom_words(rom_filename): 5 | words = [] 6 | 7 | with open(rom_filename, 'rb') as rom: 8 | while True: 9 | word = rom.read(4) 10 | 11 | if word == b'': 12 | break 13 | 14 | words.append(word) 15 | 16 | return words 17 | 18 | def pointer_iter(rom_filename, value): 19 | target = value.to_bytes(4, 'little') 20 | words = read_rom_words(rom_filename) 21 | 22 | return (i * 4 for i, word in enumerate(words) if word == target) 23 | 24 | def pointer_offsets(rom_filename, value): 25 | return tuple(pointer_iter(rom_filename, value)) 26 | 27 | def main(args): 28 | rom_addr_base = 0x08000000 29 | 30 | try: 31 | rom = args[0] # rom file name 32 | target = rom_addr_base + (int(args[1], base = 0) & 0x01FFFFFF) # pointer (int) 33 | 34 | except IndexError: 35 | sys.exit(f"Usage: {sys.argv[0]} ROM ADDR") 36 | 37 | for offset in pointer_offsets(rom, target): 38 | print(f"{(rom_addr_base + offset):08X}") 39 | 40 | if __name__ == '__main__': 41 | main(sys.argv[1:]) 42 | -------------------------------------------------------------------------------- /tools/scripts/dump-int-array.py: -------------------------------------------------------------------------------- 1 | 2 | import sys, os 3 | 4 | def read_int(f, count, signed = False): 5 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 6 | 7 | def main(args): 8 | try: 9 | rom = args[0] 10 | offset = int(args[1], base = 0) & 0x1FFFFFF 11 | intSize = int(args[2], base = 0) 12 | count = int(args[3], base = 0) 13 | 14 | except IndexError: 15 | sys.exit("Usage: {} ".format(sys.argv[0])) 16 | 17 | with open(rom, 'rb') as f: 18 | print("u{} CONST_DATA gUnk_{:08X}[] =".format(intSize*8, offset + 0x8000000)) 19 | print("{") 20 | 21 | f.seek(offset) 22 | 23 | if count == 0: 24 | while True: 25 | value = read_int(f, intSize) 26 | 27 | print("\t0x{:X},".format(value)) 28 | 29 | if value == 0: 30 | break 31 | 32 | else: 33 | for _ in range(count): 34 | print("\t0x{:X},".format(read_int(f, intSize))) 35 | 36 | print("};") 37 | 38 | if __name__ == '__main__': 39 | main(sys.argv[1:]) 40 | -------------------------------------------------------------------------------- /tools/scripts/dump-pointers.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import symbols 4 | 5 | def read_int(f, count, signed = False): 6 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 7 | 8 | def main(args): 9 | try: 10 | elf_name = args[0] 11 | rom_name = args[1] 12 | offset = 0x1FFFFFF & int(args[2], base = 0) 13 | ptr_count = int(args[3], base = 0) 14 | 15 | except IndexError: 16 | sys.exit(f"Usage: {sys.argv[0]} ELF ROM OFFSET COUNT") 17 | 18 | with open(elf_name, 'rb') as f: 19 | syms = { addr: name for addr, name in symbols.from_elf(f) } 20 | 21 | addr = offset + 0x08000000 22 | name = syms[addr] if addr in syms else f'gUnk_{offset + 0x08000000:08X}' 23 | 24 | print(f"void * CONST_DATA {name}[] =") 25 | print("{") 26 | 27 | with open(rom_name, 'rb') as f: 28 | f.seek(offset) 29 | 30 | for _ in range(ptr_count): 31 | ptr = read_int(f, 4) 32 | sym = syms[ptr] if ptr in syms else f"0x{ptr:08X}" 33 | 34 | print(f" {sym},") 35 | 36 | print("};") 37 | 38 | if __name__ == '__main__': 39 | main(sys.argv[1:]) 40 | -------------------------------------------------------------------------------- /data/chapters/final/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08669698 4 | EventListScr CONST_DATA EventListScr_Unk_08669698[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08672BE4, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_08672D10, 1, 255, FACTION_RED) 8 | EvtListEnd 9 | }; 10 | 11 | // EventListScr @ 086696B4 12 | EventListScr CONST_DATA EventListScr_Unk_086696B4[] = 13 | { 14 | EvtListEnd 15 | }; 16 | 17 | // EventListScr @ 086696B8 18 | EventListScr CONST_DATA EventListScr_Unk_086696B8[] = 19 | { 20 | EvtListEnd 21 | }; 22 | 23 | // EventListScr @ 086696BC 24 | EventListScr CONST_DATA EventListScr_Unk_086696BC[] = 25 | { 26 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 27 | EvtListEnd 28 | }; 29 | 30 | // ChapterEventInfo @ 086696CC 31 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_086696CC = 32 | { 33 | .event_list_turn = EventListScr_Unk_08669698, 34 | .event_list_talk = EventListScr_Unk_086696B4, 35 | .event_list_tile = EventListScr_Unk_086696B8, 36 | .event_list_move = EventListScr_Unk_086696BC, 37 | .units_red = UnitInfo_Unk_08681DB4, 38 | .units_blue = UnitInfo_Unk_08681D04, 39 | .event_script_victory = EventScr_Unk_08672E0C, 40 | }; 41 | -------------------------------------------------------------------------------- /data/chapters/chapter20x_i/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A1A0 4 | EventListScr CONST_DATA EventListScr_Unk_0866A1A0[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_0867557C, 1, 0, FACTION_BLUE) 7 | EvtListEnd 8 | }; 9 | 10 | // EventListScr @ 0866A1B0 11 | EventListScr CONST_DATA EventListScr_Unk_0866A1B0[] = 12 | { 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 0866A1B4 17 | EventListScr CONST_DATA EventListScr_Unk_0866A1B4[] = 18 | { 19 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 16, 1, TILE_COMMAND_SEIZE) 20 | EvtListEnd 21 | }; 22 | 23 | // EventListScr @ 0866A1C4 24 | EventListScr CONST_DATA EventListScr_Unk_0866A1C4[] = 25 | { 26 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 27 | EvtListEnd 28 | }; 29 | 30 | // ChapterEventInfo @ 0866A1D4 31 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A1D4 = 32 | { 33 | .event_list_turn = EventListScr_Unk_0866A1A0, 34 | .event_list_talk = EventListScr_Unk_0866A1B0, 35 | .event_list_tile = EventListScr_Unk_0866A1B4, 36 | .event_list_move = EventListScr_Unk_0866A1C4, 37 | .units_red = UnitInfo_Unk_086851E0, 38 | .units_blue = UnitInfo_Unk_08685100, 39 | .event_script_victory = EventScr_Unk_086756A8, 40 | }; 41 | -------------------------------------------------------------------------------- /data/chapters/chapter8x/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08669F94 4 | EventListScr CONST_DATA EventListScr_Unk_08669F94[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08674B2C, 1, 0, FACTION_BLUE) 7 | EvtListEnd 8 | }; 9 | 10 | // EventListScr @ 08669FA4 11 | EventListScr CONST_DATA EventListScr_Unk_08669FA4[] = 12 | { 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 08669FA8 17 | EventListScr CONST_DATA EventListScr_Unk_08669FA8[] = 18 | { 19 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 3, 2, TILE_COMMAND_SEIZE) 20 | EvtListEnd 21 | }; 22 | 23 | // EventListScr @ 08669FB8 24 | EventListScr CONST_DATA EventListScr_Unk_08669FB8[] = 25 | { 26 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 27 | EvtListEnd 28 | }; 29 | 30 | // ChapterEventInfo @ 08669FC8 31 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_08669FC8 = 32 | { 33 | .event_list_turn = EventListScr_Unk_08669F94, 34 | .event_list_talk = EventListScr_Unk_08669FA4, 35 | .event_list_tile = EventListScr_Unk_08669FA8, 36 | .event_list_move = EventListScr_Unk_08669FB8, 37 | .units_red = UnitInfo_Unk_086842FC, 38 | .units_blue = UnitInfo_Unk_0868424C, 39 | .event_script_victory = EventScr_Unk_08674BB0, 40 | }; 41 | -------------------------------------------------------------------------------- /data/chapters/chapter14x/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A0C4 4 | EventListScr CONST_DATA EventListScr_Unk_0866A0C4[] = 5 | { 6 | EvtListTurn(0, EventScr_Chapter14X_Opening, 1, 0, FACTION_BLUE) 7 | EvtListEnd 8 | }; 9 | 10 | // EventListScr @ 0866A0D4 11 | EventListScr CONST_DATA EventListScr_Unk_0866A0D4[] = 12 | { 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 0866A0D8 17 | EventListScr CONST_DATA EventListScr_Unk_0866A0D8[] = 18 | { 19 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 13, 12, TILE_COMMAND_SEIZE) 20 | EvtListEnd 21 | }; 22 | 23 | // EventListScr @ 0866A0E8 24 | EventListScr CONST_DATA EventListScr_Unk_0866A0E8[] = 25 | { 26 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 27 | EvtListEnd 28 | }; 29 | 30 | // ChapterEventInfo @ 0866A0F8 31 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A0F8 = 32 | { 33 | .event_list_turn = EventListScr_Unk_0866A0C4, 34 | .event_list_talk = EventListScr_Unk_0866A0D4, 35 | .event_list_tile = EventListScr_Unk_0866A0D8, 36 | .event_list_move = EventListScr_Unk_0866A0E8, 37 | .units_red = UnitInfo_Unk_08684B44, 38 | .units_blue = UnitInfo_Unk_08684A94, 39 | .event_script_victory = EventScr_Chapter14X_Victory, 40 | }; 41 | -------------------------------------------------------------------------------- /include/subtitlehelp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "proc.h" 6 | #include "text.h" 7 | 8 | struct SubtitleHelpProc 9 | { 10 | /* 00 */ PROC_HEADER; 11 | 12 | /* 2C */ char const * string; 13 | /* 30 */ struct Font font; 14 | /* 48 */ struct Text text[2]; 15 | /* 58 */ i16 text_offset; 16 | /* 5A */ i16 text_show_clock; 17 | /* 5C */ i16 text_num; 18 | /* 5E */ i16 text_count; 19 | }; 20 | 21 | void PutSubtitleHelpText(struct SubtitleHelpProc * proc, int y); 22 | void InitSubtitleHelpText(struct SubtitleHelpProc * proc); 23 | void SubtitleHelpDarkenerOnHBlank(void); 24 | 25 | void SubtitleHelpDarkener_Init(ProcPtr proc); 26 | void SubtitleHelpDarkener_FadeIn(ProcPtr proc); 27 | void SubtitleHelpDarkener_FadeOut(ProcPtr proc); 28 | 29 | void SubtitleHelp_Init(struct SubtitleHelpProc * proc); 30 | void SubtitleHelp_OnEnd(struct SubtitleHelpProc * proc); 31 | void SubtitleHelp_Loop(struct SubtitleHelpProc * proc); 32 | 33 | void StartSubtitleHelp(ProcPtr parent, char const * str); 34 | void EndSubtitleHelp(void); 35 | bool IsSubtitleHelpActive(void); 36 | 37 | extern struct ProcScr CONST_DATA ProcScr_SubtitleHelpDarkener[]; 38 | extern struct ProcScr CONST_DATA ProcScr_SubtitleHelp[]; 39 | -------------------------------------------------------------------------------- /include/gamecontroller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | #include "proc.h" 5 | 6 | enum 7 | { 8 | // TODO: those have different meanings depending on the state of the game controller 9 | 10 | GAME_ACTION_0, 11 | GAME_ACTION_1, 12 | GAME_ACTION_2, 13 | GAME_ACTION_3, 14 | GAME_ACTION_4, 15 | GAME_ACTION_5, 16 | GAME_ACTION_6, 17 | GAME_ACTION_7, 18 | GAME_ACTION_8, 19 | }; 20 | 21 | enum 22 | { 23 | L_GAMECTRL_OPENINGSEQ, 24 | L_GAMECTRL_CLASSDEMO, 25 | L_GAMECTRL_SCENEDEMO, 26 | L_GAMECTRL_TITLE, 27 | L_GAMECTRL_MAINMENU, 28 | L_GAMECTRL_CHAPTER, 29 | L_GAMECTRL_LOADSUSPEND, 30 | L_GAMECTRL_POSTCHAPTER, 31 | L_GAMECTRL_POSTTRIAL, 32 | L_GAMECTRL_TUTORIAL, 33 | L_GAMECTRL_LINK, 34 | L_GAMECTRL_TRIAL, 35 | L_GAMECTRL_PREENDING, 36 | L_GAMECTRL_ENDING, 37 | L_GAMECTRL_SRAMRESET, 38 | }; 39 | 40 | void CleanupGame(ProcPtr proc); 41 | void StartGame(void); 42 | void SetNextGameAction(int action); 43 | void SetNextChapter(int chapter); 44 | bool HasNextChapter(void); 45 | void RestartGameAndChapter(void); 46 | void RestartGameAndLoadSuspend(void); 47 | void ForceEnableSounds(void); 48 | void func_fe6_08013A64(void); 49 | 50 | extern struct ProcScr CONST_DATA ProcScr_GameController[]; 51 | -------------------------------------------------------------------------------- /src/chapterinfo.c: -------------------------------------------------------------------------------- 1 | #include "chapterinfo.h" 2 | 3 | #include "hardware.h" 4 | #include "msg.h" 5 | #include "save_xmap.h" 6 | #include "gbasram.h" 7 | 8 | struct ChapterInfo const * GetChapterInfo(int chapter) 9 | { 10 | if (chapter < 0) 11 | return gExtraMapInfo->chapter_info; 12 | 13 | return ChapterInfoTable + chapter; 14 | } 15 | 16 | u8 const * GetChapterMap(int chapter) 17 | { 18 | if (chapter >= 0) 19 | return ChapterAssets[GetChapterInfo(chapter)->asset_map]; 20 | 21 | ReadSramFast(GetExtraMapMapReadAddr(), gBuf, GetExtraMapMapSize()); 22 | return gBuf; 23 | } 24 | 25 | struct MapChangeInfo const * GetChapterMapChanges(int chapter) 26 | { 27 | if (chapter >= 0) 28 | return ChapterAssets[GetChapterInfo(chapter)->asset_map_changes]; 29 | 30 | return gExtraMapInfo->map_change_info; 31 | } 32 | 33 | struct ChapterEventInfo const * GetChapterEventInfo(int chapter) 34 | { 35 | if (chapter >= 0) 36 | return ChapterAssets[GetChapterInfo(chapter)->asset_event_info]; 37 | 38 | return gExtraMapInfo->event_info; 39 | } 40 | 41 | char const * GetChapterUnk_0802BBD0(int chapter) 42 | { 43 | if (chapter >= 0) 44 | return DecodeMsg(GetChapterInfo(chapter)->msg_38); 45 | 46 | return gExtraMapInfo->msg_0C; 47 | } 48 | -------------------------------------------------------------------------------- /docs/DECOMPILING-NOTES.md: -------------------------------------------------------------------------------- 1 | 2 | # Decompilation notes 3 | 4 | ## O0 for vs while 5 | 6 | ```c 7 | while (1) { /* body */ } 8 | ``` 9 | 10 | ```arm 11 | lop: 12 | continue: 13 | b _ 14 | b break 15 | _: 16 | @ body 17 | b lop 18 | break: 19 | @ ... 20 | ``` 21 | 22 | --- 23 | 24 | ```c 25 | for (;;) { /* body */ } 26 | ``` 27 | 28 | ```arm 29 | lop: 30 | @ body 31 | continue: 32 | b lop 33 | break: 34 | @ ... 35 | ``` 36 | 37 | --- 38 | 39 | ```c 40 | for (;1;) { /* body */ } 41 | ``` 42 | 43 | ```arm 44 | lop: 45 | b _ 46 | b break 47 | _: 48 | @ body 49 | continue: 50 | b lop 51 | break: 52 | @ ... 53 | ``` 54 | 55 | ## variables 56 | 57 | extern vs defined vars can produce different asm when referenced. If we need extern behavior but also define the var in the current file, we can put the definition after the problematic function. 58 | 59 | ```c 60 | extern int const var[]; 61 | 62 | int func(int i) 63 | { 64 | return var[i]; 65 | } 66 | 67 | int const var[] = { 1, 2, 776 }; 68 | ``` 69 | 70 | ## `i8` or 0xFF vs mov -1 71 | 72 | ```c 73 | int func(i8 * var) 74 | { 75 | if (*var == 0) 76 | *var = -1; // orr var, 0xFF 77 | } 78 | ``` 79 | 80 | ```c 81 | int func(i8 * var) 82 | { 83 | if (*var == 0) 84 | *var |= 0xFF; // mov var, -1 85 | } 86 | ``` 87 | 88 | funny 89 | -------------------------------------------------------------------------------- /include/prelude.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(MODERN) && MODERN 4 | # ifndef MODERN 5 | # define MODERN 6 | # endif 7 | # ifdef NONMATCHING 8 | # undef NONMATCHING 9 | # endif // NONMATCHING 10 | # ifdef BUGFIX 11 | # undef BUGFIX 12 | # endif // BUGFIX 13 | # define NONMATCHING 1 14 | # define BUGFIX 1 15 | #endif // MODERN 16 | 17 | #include 18 | #include 19 | 20 | #include "gba/gba.h" 21 | 22 | #include "attributes.h" 23 | #include "types.h" 24 | 25 | #include "unknown_types.h" 26 | #include "unknown_funcs.h" 27 | #include "unknown_objects.h" 28 | 29 | // use to pad a struct that contains unused space 30 | // TODO: use this everywere 31 | 32 | #if !MODERN 33 | # define STRUCT_PAD(from, to) unsigned char _pad_ ## from[(to) - (from)] 34 | #else 35 | # define STRUCT_PAD(from, to) 36 | #endif 37 | 38 | #define ARRAY_COUNT(array) (sizeof(array) / sizeof((array)[0])) 39 | 40 | #define ABS(val) ((val) >= 0 ? (val) : -(val)) 41 | 42 | #define RECT_DISTANCE(xa, ya, xb, yb) (ABS((xa) - (xb)) + ABS((ya) - (yb))) 43 | 44 | // For translate-able strings. 45 | #define JTEXT(orig) (orig) 46 | #define TEXT(orig, english) (orig) 47 | 48 | #if defined(MODERN) && MODERN 49 | # define STATIC_ASSERT(expr) _Static_assert(expr) 50 | #else 51 | # define STATIC_ASSERT(expr) 52 | #endif 53 | -------------------------------------------------------------------------------- /include/playerphase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "proc.h" 6 | #include "unit.h" 7 | 8 | enum 9 | { 10 | L_PLAYERPHASE_BEGIN, 11 | L_PLAYERPHASE_MOVE, 12 | L_PLAYERPHASE_ACTION_SELECT, 13 | L_PLAYERPHASE_END, 14 | L_PLAYERPHASE_MAPFADE_MOVE, 15 | L_PLAYERPHASE_5, 16 | L_PLAYERPHASE_6, 17 | L_PLAYERPHASE_ACTION, 18 | L_PLAYERPHASE_8, 19 | L_PLAYERPHASE_IDLE, 20 | L_PLAYERPHASE_10, 21 | L_PLAYERPHASE_SEE_RANGE, 22 | }; 23 | 24 | enum 25 | { 26 | PLAYER_SELECT_NOUNIT, 27 | PLAYER_SELECT_TURNENDED, 28 | PLAYER_SELECT_CONTROL, 29 | PLAYER_SELECT_NOCONTROL, 30 | PLAYER_SELECT_4, 31 | }; 32 | 33 | enum 34 | { 35 | LIMITVIEW_BLUE = (1 << 0), 36 | LIMITVIEW_RED = (1 << 1), 37 | LIMITVIEW_GREEN = (1 << 2), 38 | }; 39 | 40 | void HandlePlayerMapCursor(void); 41 | void DisplayUnitActionRange(struct Unit * unit); 42 | int GetPlayerSelectKind(struct Unit * unit); 43 | void StartLimitView(int flags); 44 | void EndLimitView(void); 45 | void TrySwitchViewedUnit(int x, int y); 46 | 47 | void PlayerPhase_BeginSeeActionRange(ProcPtr proc); 48 | void PlayerPhase_MoveSelectLoop(ProcPtr proc); 49 | bool StartAvailableMoveEvents(ProcPtr proc); 50 | void PlayerPhase_0801BC84(ProcPtr proc); 51 | 52 | extern struct ProcScr CONST_DATA ProcScr_PlayerPhase[]; 53 | -------------------------------------------------------------------------------- /tools/scripts/fix-file-encoding.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def val2hex(val): 4 | if val >= 10: 5 | return ord('A') + (val - 10) 6 | 7 | return ord('0') + val 8 | 9 | def main(args): 10 | try: 11 | filenames = args[1:] 12 | 13 | except IndexError: 14 | sys.exit(f"USAGE: {args[0]} FILENAME...") 15 | 16 | for filename in filenames: 17 | data = bytearray() 18 | 19 | with open(filename, 'rb') as f: 20 | while True: 21 | byte = f.read(1) 22 | 23 | if byte == b'': 24 | break 25 | 26 | byte = byte[0] 27 | 28 | if byte >= 0x80: 29 | data.append(ord('\\')) 30 | data.append(ord('x')) 31 | data.append(val2hex((byte & 0xF0) >> 4)) 32 | data.append(val2hex((byte & 0x0F))) 33 | byte = f.read(1)[0] 34 | data.append(ord('\\')) 35 | data.append(ord('x')) 36 | data.append(val2hex((byte & 0xF0) >> 4)) 37 | data.append(val2hex((byte & 0x0F))) 38 | else: 39 | data.append(byte) 40 | 41 | with open(filename, 'wb') as f: 42 | f.write(data) 43 | 44 | if __name__ == '__main__': 45 | main(sys.argv) 46 | -------------------------------------------------------------------------------- /include/arena.h: -------------------------------------------------------------------------------- 1 | #ifndef ARENA_H 2 | #define ARENA_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "unit.h" 7 | 8 | enum 9 | { 10 | ARENA_RESULT_0, 11 | ARENA_RESULT_1, // player victory? 12 | ARENA_RESULT_2, // enemy victory? 13 | ARENA_RESULT_3, // ??? 14 | ARENA_RESULT_4, // backed out? 15 | }; 16 | 17 | struct ArenaSt 18 | { 19 | /* 00 */ struct Unit * player; 20 | /* 04 */ struct Unit * opponent; 21 | /* 08 */ short matchup_gold_value; 22 | /* 0A */ u8 result; 23 | /* 0B */ u8 unk_0B; 24 | /* 0C */ u8 range; 25 | /* 0D */ u8 player_weapon_kind; 26 | /* 0E */ u8 opponent_weapon_kind; 27 | /* 0F */ u8 player_jid; 28 | /* 10 */ u8 opponent_jid; 29 | /* 11 */ u8 player_level; 30 | /* 12 */ u8 opponent_level; 31 | /* 13 */ i8 player_is_magic; 32 | /* 14 */ i8 opponent_is_magic; 33 | /* 16 */ u16 player_power_ranking; 34 | /* 18 */ u16 opponent_power_ranking; 35 | /* 1A */ u16 player_weapon; 36 | /* 1C */ u16 opponent_weapon; 37 | }; 38 | 39 | void ArenaBegin(struct Unit * unit); 40 | void ArenaResume(struct Unit * unit); 41 | int ArenaGetMatchupGoldValue(void); 42 | int ArenaGetResult(void); 43 | void ArenaSetResult(int result); 44 | void ArenaContinueBattle(void); 45 | bool ArenaIsUnitAllowed(struct Unit * unit); 46 | 47 | extern struct ArenaSt gArenaSt; 48 | 49 | #endif // ARENA_H 50 | -------------------------------------------------------------------------------- /include/map.h: -------------------------------------------------------------------------------- 1 | #ifndef MAP_H 2 | #define MAP_H 3 | 4 | #include "prelude.h" 5 | 6 | void InitMapForChapter(int chapter); 7 | void InitMapForMinimap(int chapter); 8 | void func_fe6_080187EC(void); 9 | void func_fe6_080188F4(void); 10 | void MapFill(u8 ** map, int value); 11 | void MapSetEdges(u8 ** map, u8 value); 12 | void ApplyChapterMapGraphics(int chapter); 13 | void ApplyChapterMapPalettes(void); 14 | void RefreshTerrainMap(void); 15 | void PutMapMetatile(u16 * tm, int x_tm, int y_tm, int x, int y); 16 | void func_fe6_08018CDC(void); 17 | void PutLimitViewSquare(u16 * tm, int x, int y, int x_tm, int y_tm); 18 | void RenderMap(void); 19 | void RenderMapForFade(void); 20 | void UpdateRenderMap(void); 21 | void RefreshEntityMaps(void); 22 | char const * GetTerrainName(int terrain); 23 | int GetTerrainHealAmount(int terrain); 24 | bool DoesTerrainHealStatus(int terrain); 25 | void func_fe6_080192E4(void); 26 | 27 | extern struct Vec2i gMapSize; 28 | 29 | extern u8 ** gMapUnit; 30 | extern u8 ** gMapTerrain; 31 | extern u8 ** gMapMovement; 32 | extern u8 ** gMapRange; 33 | extern u8 ** gMapFog; 34 | extern u8 ** gMapHidden; 35 | extern u8 ** gMapOther; 36 | 37 | extern u8 * CONST_DATA gMetatilesTerrainLut; 38 | extern u16 ** CONST_DATA gMapMetatiles; 39 | 40 | #define gMapRangeSigned ((i8 **) gMapRange) 41 | #define gMapMovementSigned ((i8 **) gMapMovement) 42 | 43 | #endif // MAP_H 44 | -------------------------------------------------------------------------------- /include/constants/chapters.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum 4 | { 5 | CHAPTER_TUTORIAL = 0x00, 6 | CHAPTER_1 = 0x01, 7 | CHAPTER_2 = 0x02, 8 | CHAPTER_3 = 0x03, 9 | CHAPTER_4 = 0x04, 10 | CHAPTER_5 = 0x05, 11 | CHAPTER_6 = 0x06, 12 | CHAPTER_7 = 0x07, 13 | CHAPTER_8 = 0x08, 14 | CHAPTER_9 = 0x09, 15 | CHAPTER_10_A = 0x0A, 16 | CHAPTER_11_A = 0x0B, 17 | CHAPTER_12 = 0x0C, 18 | CHAPTER_13 = 0x0D, 19 | CHAPTER_14 = 0x0E, 20 | CHAPTER_15 = 0x0F, 21 | CHAPTER_16 = 0x10, 22 | CHAPTER_17_I = 0x11, 23 | CHAPTER_18_I = 0x12, 24 | CHAPTER_19_I = 0x13, 25 | CHAPTER_20_I = 0x14, 26 | CHAPTER_21 = 0x15, 27 | CHAPTER_22 = 0x16, 28 | CHAPTER_23 = 0x17, 29 | CHAPTER_24 = 0x18, 30 | CHAPTER_FINAL = 0x19, 31 | CHAPTER_10_B = 0x1A, 32 | CHAPTER_11_B = 0x1B, 33 | CHAPTER_17_S = 0x1C, 34 | CHAPTER_18_S = 0x1D, 35 | CHAPTER_19_S = 0x1E, 36 | CHAPTER_20_S = 0x1F, 37 | CHAPTER_8X = 0x20, 38 | CHAPTER_12X = 0x21, 39 | CHAPTER_14X = 0x22, 40 | CHAPTER_16X = 0x23, 41 | CHAPTER_20X_I = 0x24, 42 | CHAPTER_20X_S = 0x25, 43 | CHAPTER_21X = 0x26, 44 | CHAPTER_MULTIARENA = 0x27, 45 | CHAPTER_TRIAL_A = 0x28, 46 | CHAPTER_TRIAL_B = 0x29, 47 | CHAPTER_TRIAL_C = 0x2A, 48 | CHAPTER_TRIAL_D = 0x2B, 49 | CHAPTER_TRIAL_E = 0x2C, 50 | 51 | CHAPTER_COUNT = 0x2D, 52 | }; 53 | -------------------------------------------------------------------------------- /include/ai_decide.h: -------------------------------------------------------------------------------- 1 | #ifndef AI_DECIDE_H 2 | #define AI_DECIDE_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "proc.h" 7 | #include "ai.h" 8 | 9 | enum 10 | { 11 | AI_ACTION_NONE, // move only 12 | AI_ACTION_COMBAT, 13 | AI_ACTION_ESCAPE, 14 | AI_ACTION_STEAL, 15 | AI_ACTION_PILLAGE, 16 | AI_ACTION_STAFF, 17 | AI_ACTION_USEITEM, 18 | AI_ACTION_REFRESH, 19 | AI_ACTION_TALK, 20 | }; 21 | 22 | struct AiDecision 23 | { 24 | /* 00 */ u8 action_id; 25 | 26 | /* 01 */ u8 unit_id; 27 | /* 02 */ u8 x_move; 28 | /* 03 */ u8 y_move; 29 | /* 04 */ u8 unk_04; 30 | /* 05 */ u8 unk_05; 31 | /* 06 */ u8 target_id; 32 | /* 07 */ u8 item_slot; 33 | /* 08 */ u8 x_target; 34 | /* 09 */ u8 y_target; 35 | 36 | /* 0A */ bool8 action_performed; 37 | }; 38 | 39 | void AiClearDecision(void); 40 | void AiSetDecision(short x_move, short y_move, u8 action_id, u8 target_id, u8 item_slot, u8 x_target, u8 y_target); 41 | void AiUpdateDecision(u8 action_id, u8 target_id, u8 item_slot, u8 x_target, u8 y_target); 42 | 43 | void AiDecideAll(void); 44 | void AiDecideHealOrEscape(void); 45 | void AiDecideSpecialItems(void); 46 | void AiDecideScriptA(void); 47 | void AiDecideScriptB(void); 48 | 49 | extern struct AiDecision EWRAM_DATA gAiDecision; 50 | 51 | extern void (*AiDecideFunc)(void); 52 | 53 | extern struct ProcScr CONST_DATA ProcScr_AiDecide[]; 54 | 55 | #endif // AI_DECIDE_H 56 | -------------------------------------------------------------------------------- /include/ai_battle.h: -------------------------------------------------------------------------------- 1 | #ifndef AI_BATTLE_H 2 | #define AI_BATTLE_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "ai.h" 7 | 8 | struct AiCombatSimulationSt 9 | { 10 | /* 00 */ u8 x_move, y_move; 11 | /* 02 */ u8 target_id; 12 | /* 04 */ u16 item_slot; 13 | /* 08 */ u32 score; 14 | }; 15 | 16 | bool AiAttemptOffensiveAction(bool (* is_enemy)(struct Unit * unit)); 17 | bool AiAttemptCombatWithinMovement(bool (* is_enemy)(struct Unit * unit)); 18 | void AiFillReversedAttackRangeMap(struct Unit * unit, u16 item); 19 | void AiFloodMovementAndRange(struct Unit * unit, u16 move, u16 item); 20 | bool AiAttemptBallistaCombat(bool (* is_enemy)(struct Unit * unit), struct AiCombatSimulationSt * st); 21 | bool AiAttemptStealActionWithinMovement(void); 22 | bool AiSimulateBestBattleAgainstTarget(struct AiCombatSimulationSt * st); 23 | bool AiSimulateBestBallistaBattleAgainstTarget(struct AiCombatSimulationSt * st, u16 item); 24 | u32 AiGetCombatPositionScore(int x, int y, struct AiCombatSimulationSt * st); 25 | bool AiIsBadFight(struct AiCombatSimulationSt * st); 26 | bool AiSimulateBattleAgainstTargetAtPosition(struct AiCombatSimulationSt * st); 27 | void AiComputeCombatScore(struct AiCombatSimulationSt * st); 28 | int AiGetInRangeCombatPositionScoreComponent(int x, int y, struct Unit * unit); 29 | int AiGetTerrainCombatPositionScoreComponent(int x, int y); 30 | int AiGetFriendZoneCombatPositionScoreComponent(int x, int y); 31 | 32 | #endif // AI_BATTLE_H 33 | -------------------------------------------------------------------------------- /tools/scripts/dump-ai-script.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import symbols 4 | 5 | def read_int(f, count, signed = False): 6 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 7 | 8 | class AiScr: 9 | 10 | def __init__(self, input): 11 | self.code = read_int(input, 1) 12 | self.sarg0 = read_int(input, 1) 13 | self.sarg1 = read_int(input, 1) 14 | self.sarg2 = read_int(input, 1) 15 | 16 | self.larg0 = read_int(input, 4) 17 | self.larg1 = read_int(input, 4) 18 | self.larg2 = read_int(input, 4) 19 | 20 | def __str__(self): 21 | return f"{{ 0x{self.code:X}, 0x{self.sarg0:X}, 0x{self.sarg1:X}, 0x{self.sarg2:X}, 0x{self.larg0:X}, 0x{self.larg1:X}, 0x{self.larg2:X} }}" 22 | 23 | def main(args): 24 | try: 25 | elf_name = args[0] 26 | rom_name = args[1] 27 | offset = 0x1FFFFFF & int(args[2], base = 0) 28 | count = int(args[3], base = 0) 29 | 30 | except IndexError: 31 | sys.exit(f"Usage: {sys.argv[0]} ELF ROM OFFSET COUNT") 32 | 33 | #with open(elf_name, 'rb') as f: 34 | # syms = { addr: name for addr, name in symbols.from_elf(f) } 35 | 36 | print(f"struct AiScr CONST_DATA AiScr_Unk_{offset + 0x08000000:08X}[] =") 37 | print("{") 38 | 39 | with open(rom_name, 'rb') as f: 40 | f.seek(offset) 41 | 42 | for _ in range(count): 43 | ai_scr = AiScr(f) 44 | 45 | print(f" {ai_scr},") 46 | 47 | print("};") 48 | 49 | if __name__ == '__main__': 50 | main(sys.argv[1:]) 51 | -------------------------------------------------------------------------------- /data/chapters/trial_a/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A314 4 | EventListScr CONST_DATA EventListScr_Unk_0866A314[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08675FF0, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686318, 5, 0, FACTION_RED) 8 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686358, 10, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686398, 15, 0, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_086863D8, 20, 0, FACTION_RED) 11 | EvtListEnd 12 | }; 13 | 14 | // EventListScr @ 0866A354 15 | EventListScr CONST_DATA EventListScr_Unk_0866A354[] = 16 | { 17 | EvtListEnd 18 | }; 19 | 20 | // EventListScr @ 0866A358 21 | EventListScr CONST_DATA EventListScr_Unk_0866A358[] = 22 | { 23 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 2, 3, TILE_COMMAND_SEIZE) 24 | EvtListEnd 25 | }; 26 | 27 | // EventListScr @ 0866A368 28 | EventListScr CONST_DATA EventListScr_Unk_0866A368[] = 29 | { 30 | EvtListFlag(FLAG_3, EventScr_Unk_08676014, FLAG_101) 31 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 32 | EvtListEnd 33 | }; 34 | 35 | // ChapterEventInfo @ 0866A384 36 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A384 = 37 | { 38 | .event_list_turn = EventListScr_Unk_0866A314, 39 | .event_list_talk = EventListScr_Unk_0866A354, 40 | .event_list_tile = EventListScr_Unk_0866A358, 41 | .event_list_move = EventListScr_Unk_0866A368, 42 | .units_red = UnitInfo_Unk_08686168, 43 | .units_blue = UnitInfo_Unk_086860B8, 44 | .event_script_victory = EventScr_Unk_08675FF8, 45 | }; 46 | -------------------------------------------------------------------------------- /tools/scripts/sjb-tab-dump.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def read_int(f, count, signed = False): 5 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 6 | 7 | def read_sjis_string(f): 8 | array = bytearray(b'') 9 | 10 | while True: 11 | byte = f.read(1)[0] 12 | 13 | if byte == 0: 14 | break 15 | 16 | array.append(byte) 17 | 18 | return array 19 | 20 | def main(args): 21 | try: 22 | romName = args[0] 23 | offset = int(args[1], base = 0) & 0x1FFFFFF 24 | tabsize = int(args[2], base = 0) 25 | outputName = args[3] 26 | 27 | except IndexError: 28 | sys.exit("usage: {} ".format(sys.argv[0])) 29 | 30 | with open(outputName, 'wb') as out: 31 | with open(romName, 'rb') as f: 32 | names = [] 33 | 34 | out.write(b'\n') 35 | 36 | for i in range(tabsize): 37 | f.seek(offset + 4*i) 38 | stroff = read_int(f, 4) 39 | 40 | namebytes = "String_{:08X}".format(stroff).encode("sjis") 41 | 42 | f.seek(stroff & 0x1FFFFFF) 43 | 44 | out.write(b'char const ') 45 | out.write(namebytes) 46 | out.write(b'[] = "') 47 | out.write(read_sjis_string(f)) 48 | out.write(b'";\n') 49 | 50 | names.append(namebytes) 51 | 52 | out.write(b'\n') 53 | out.write('char const * CONST_DATA gUnk_{:08X}[] =\n'.format(offset + 0x08000000).encode("sjis")) 54 | out.write(b'{\n') 55 | 56 | for name in names: 57 | out.write(b' ') 58 | out.write(name) 59 | out.write(b',\n') 60 | 61 | out.write(b'};\n') 62 | 63 | if __name__ == '__main__': 64 | main(sys.argv[1:]) 65 | -------------------------------------------------------------------------------- /data/chapters/chapter16x/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A114 4 | EventListScr CONST_DATA EventListScr_Unk_0866A114[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08675324, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_LoadUnits_Unk_08685034, 8, 0, FACTION_RED) 8 | EvtListTurn(0, EventScr_LoadUnits_Unk_08685054, 10, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_Unk_08685034, 18, 0, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_08685054, 20, 0, FACTION_RED) 11 | EvtListTurn(0, EventScr_Unk_086753E0, 25, 0, FACTION_RED) 12 | EvtListEnd 13 | }; 14 | 15 | // EventListScr @ 0866A160 16 | EventListScr CONST_DATA EventListScr_Unk_0866A160[] = 17 | { 18 | EvtListEnd 19 | }; 20 | 21 | // EventListScr @ 0866A164 22 | EventListScr CONST_DATA EventListScr_Unk_0866A164[] = 23 | { 24 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 15, 2, TILE_COMMAND_SEIZE) 25 | EvtListEnd 26 | }; 27 | 28 | // EventListScr @ 0866A174 29 | EventListScr CONST_DATA EventListScr_Unk_0866A174[] = 30 | { 31 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 32 | EvtListEnd 33 | }; 34 | 35 | // ChapterEventInfo @ 0866A184 36 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A184 = 37 | { 38 | .event_list_turn = EventListScr_Unk_0866A114, 39 | .event_list_talk = EventListScr_Unk_0866A160, 40 | .event_list_tile = EventListScr_Unk_0866A164, 41 | .event_list_move = EventListScr_Unk_0866A174, 42 | .units_red = UnitInfo_Unk_08684E34, 43 | .units_blue = UnitInfo_Unk_08684D84, 44 | .event_script_victory = EventScr_Unk_08675410, 45 | }; 46 | -------------------------------------------------------------------------------- /include/gba/defines.h: -------------------------------------------------------------------------------- 1 | #ifndef GUARD_GBA_DEFINES 2 | #define GUARD_GBA_DEFINES 3 | 4 | #include 5 | 6 | #define SOUND_INFO_PTR (*(struct SoundInfo **)0x3007FF0) 7 | #define INTR_CHECK (*(u16 *)0x3007FF8) 8 | #define INTR_VECTOR (*(void **)0x3007FFC) 9 | 10 | #define EWRAM_START 0x02000000 11 | #define IWRAM_START 0x03000000 12 | 13 | #define PLTT 0x5000000 14 | #define PLTT_SIZE 0x400 15 | 16 | #define BG_PLTT PLTT 17 | #define BG_PLTT_SIZE 0x200 18 | 19 | #define OBJ_PLTT (PLTT + 0x200) 20 | #define OBJ_PLTT_SIZE 0x200 21 | 22 | #define VRAM 0x6000000 23 | #define VRAM_SIZE 0x18000 24 | 25 | #define BG_VRAM VRAM 26 | #define BG_VRAM_SIZE 0x10000 27 | #define BG_CHAR_ADDR(n) (void *)(BG_VRAM + (0x4000 * (n))) 28 | #define BG_SCREEN_ADDR(n) (void *)(BG_VRAM + (0x800 * (n))) 29 | #define BG_TILE_ADDR(n) (void *)(BG_VRAM + (0x80 * (n))) 30 | 31 | // text-mode BG 32 | #define OBJ_VRAM0 (void *)(VRAM + 0x10000) 33 | #define OBJ_VRAM0_SIZE 0x8000 34 | 35 | // bitmap-mode BG 36 | #define OBJ_VRAM1 (void *)(VRAM + 0x14000) 37 | #define OBJ_VRAM1_SIZE 0x4000 38 | 39 | #define OAM 0x7000000 40 | #define OAM_SIZE 0x400 41 | 42 | #define DISPLAY_WIDTH 240 43 | #define DISPLAY_HEIGHT 160 44 | 45 | #define TILE_SIZE_4BPP 32 46 | #define TILE_SIZE_8BPP 64 47 | 48 | #define TOTAL_OBJ_TILE_COUNT 1024 49 | 50 | #define RGB(r, g, b) (((b) << 10) + ((g) << 5) + (r)) 51 | 52 | #define RGB_BLACK RGB(0, 0, 0) 53 | #define RGB_WHITE RGB(31, 31, 31) 54 | 55 | #define WIN_RANGE(a, b) (((a) << 8) + (b)) 56 | 57 | #endif // GUARD_GBA_DEFINES 58 | -------------------------------------------------------------------------------- /include/ai_data.h: -------------------------------------------------------------------------------- 1 | #ifndef AI_DATA_H 2 | #define AI_DATA_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "ai.h" 7 | #include "ai_script.h" 8 | 9 | struct AiCombatScoreCoefficients 10 | { 11 | /* 00 */ u8 coef_damage_dealt; 12 | /* 01 */ u8 coef_low_hp_opponent; 13 | /* 02 */ u8 coef_friend_zone; 14 | /* 03 */ u8 coef_job_rank_bonus; 15 | /* 04 */ u8 coef_turn_number; 16 | /* 05 */ u8 coef_damage_taken; 17 | /* 06 */ u8 coef_danger; 18 | /* 07 */ u8 coef_low_hp_self; 19 | /* 08 */ u8 job_rank_bonuses[9]; 20 | }; 21 | 22 | struct AiEscapePt 23 | { 24 | /* 00 */ u8 x, y; 25 | /* 02 */ u8 facing; 26 | }; 27 | 28 | struct AiHealThreshold 29 | { 30 | u8 exit_threshold; 31 | u8 enter_threshold; 32 | }; 33 | 34 | extern u8 CONST_DATA gAiPillageTerrainsNoLoot[]; 35 | extern u8 CONST_DATA gAiPillageTerrainsWithLoot[]; 36 | extern struct AiScr CONST_DATA AiScr_FallbackA[]; 37 | extern struct AiScr CONST_DATA AiScr_FallbackB[]; 38 | extern u8 const * CONST_DATA gAiJobRankLists[]; 39 | extern struct AiCombatScoreCoefficients const gAiCombatScoreCoefficientTable[]; 40 | extern struct AiEscapePt const * CONST_DATA gAiRedEscapePoints[]; 41 | extern struct AiEscapePt const * CONST_DATA gAiGreenEscapePoints[]; 42 | extern struct AiHealThreshold CONST_DATA gAiHealThresholds[]; 43 | extern u16 CONST_DATA gUnk_085C8834[]; 44 | extern u32 const AiItemConfigTable[]; 45 | extern struct AiScr const * const * CONST_DATA gAiScriptLutB[]; 46 | extern struct AiScr const * const * CONST_DATA gAiScriptLutA[]; 47 | extern struct Vec2i const * const * CONST_DATA gUnk_085C8878; 48 | 49 | #endif // AI_DATA_H 50 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "prelude.h" 2 | 3 | #include "irq.h" 4 | #include "random.h" 5 | #include "hardware.h" 6 | #include "armfunc.h" 7 | #include "proc.h" 8 | #include "spriteanim.h" 9 | #include "debugtext.h" 10 | #include "gamecontroller.h" 11 | #include "bm.h" 12 | #include "mu.h" 13 | #include "save_core.h" 14 | 15 | #include "m4a.h" 16 | 17 | void SramInit(void); 18 | void InitGlobalSaveInfo(void); 19 | 20 | void AgbMain(void) 21 | { 22 | // clear RAM 23 | DmaFill32(3, 0, (void *) IWRAM_START, 0x7F80); 24 | CpuFastFill(0, (void *) EWRAM_START, 0x40000); 25 | 26 | REG_WAITCNT = WAITCNT_SRAM_4 27 | | WAITCNT_WS0_N_3 | WAITCNT_WS0_S_1 28 | | WAITCNT_WS1_N_3 | WAITCNT_WS1_S_1 29 | | WAITCNT_WS2_N_3 | WAITCNT_WS2_S_1 30 | | WAITCNT_PHI_OUT_NONE 31 | | WAITCNT_PREFETCH_ENABLE; 32 | 33 | IrqInit(); 34 | SetOnVBlank(NULL); 35 | 36 | REG_DISPSTAT = 8; 37 | REG_IME = 1; 38 | 39 | InitKeySt(gKeySt); 40 | RefreshKeySt(gKeySt); 41 | 42 | InitRamFuncs(); 43 | SramInit(); 44 | InitProcs(); 45 | InitSpriteAnims(); 46 | InitMus(); 47 | 48 | RandInitB(0x42D690E9); 49 | RandInit(RandNextB()); 50 | 51 | if (!ReadGlobalSaveInfo(NULL)) 52 | InitGlobalSaveInfo(); 53 | 54 | m4aSoundInit(); 55 | SetOnVBlank(OnVBlank); 56 | 57 | StartGame(); 58 | 59 | while (TRUE) 60 | { 61 | RunMainFunc(); 62 | SoftResetIfKeyCombo(); 63 | } 64 | } 65 | 66 | void PutBuildInfo(u16 * tm) 67 | { 68 | DebugPutStr(tm + TM_OFFSET(0, 0), "2002/03/02(SAT) 11:15:03"); 69 | DebugPutStr(tm - TM_OFFSET(0, 1), "NARIHIRO"); 70 | } 71 | -------------------------------------------------------------------------------- /include/sound.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "proc.h" 6 | #include "bm.h" 7 | 8 | #include "m4a.h" 9 | 10 | extern struct MusicPlayer gMusicPlayer_03006530; 11 | extern struct MusicPlayer gMusicPlayer_03006600; 12 | extern struct MusicPlayer gMusicPlayer_03006570; 13 | extern struct MusicPlayer gMusicPlayer_03006260; 14 | extern struct MusicPlayer gMusicPlayer_030062A0; 15 | extern struct MusicPlayer gMusicPlayer_030064B0; 16 | extern struct MusicPlayer gMusicPlayer_FightBgm; 17 | extern struct MusicPlayer gMusicPlayer_MainBgm; 18 | 19 | int GetCurrentBgmSong(void); 20 | bool IsBgmPlaying(void); 21 | void func_fe6_08002F9C(int volume); 22 | void SetBgmVolume(int volume); 23 | void FadeBgmOut(int speed); 24 | void func_fe6_080030B4(int speed); 25 | void StartBgmCore(int song, struct MusicPlayer * music_player); 26 | void StartOrChangeBgm(int song, int speed, struct MusicPlayer * music_player); 27 | void StartBgm(int song, struct MusicPlayer * music_player); 28 | void StartBgmExt(int song, int speed, struct MusicPlayer * music_player); 29 | void StartBgmFadeIn(int song, int b, struct MusicPlayer * music_player); 30 | void OverrideBgm(int song); 31 | void RestoreBgm(void); 32 | void MakeBgmOverridePersist(void); 33 | void StartBgmVolumeChange(int volume_from, int volume_to, int duration, ProcPtr parent); 34 | 35 | #define PlaySe(id) \ 36 | if (!gPlaySt.config_se_disable) \ 37 | m4aSongNumStart((id)) 38 | 39 | // TODO: move 40 | 41 | extern struct Song const Song_Unk_0857A61C; 42 | extern struct Song const Song_Unk_0857B774; 43 | extern struct Song const Song_Unk_0857C1E4; 44 | extern struct Song const Song_Unk_0857C95C; 45 | -------------------------------------------------------------------------------- /data/chapters/chapter21x/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A27C 4 | EventListScr CONST_DATA EventListScr_Unk_0866A27C[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08675BA8, 1, 0, FACTION_BLUE) 7 | EvtListEnd 8 | }; 9 | 10 | // EventListScr @ 0866A28C 11 | EventListScr CONST_DATA EventListScr_Unk_0866A28C[] = 12 | { 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 0866A290 17 | EventListScr CONST_DATA EventListScr_Unk_0866A290[] = 18 | { 19 | EvtListTile(0, EventScr_Unk_08675CF4, 3, 1, TILE_COMMAND_CHEST) 20 | EvtListTile(0, EventScr_Unk_08675D38, 6, 1, TILE_COMMAND_CHEST) 21 | EvtListTile(0, EventScr_Unk_08675D7C, 14, 12, TILE_COMMAND_CHEST) 22 | EvtListTile(0, EventScr_Unk_08675DC0, 16, 12, TILE_COMMAND_CHEST) 23 | EvtListTile(0, EventScr_Unk_08675E04, 25, 1, TILE_COMMAND_CHEST) 24 | EvtListTile(0, EventScr_Unk_08675E48, 29, 1, TILE_COMMAND_CHEST) 25 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 15, 1, TILE_COMMAND_SEIZE) 26 | EvtListEnd 27 | }; 28 | 29 | // EventListScr @ 0866A2E8 30 | EventListScr CONST_DATA EventListScr_Unk_0866A2E8[] = 31 | { 32 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 33 | EvtListEnd 34 | }; 35 | 36 | // ChapterEventInfo @ 0866A2F8 37 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A2F8 = 38 | { 39 | .event_list_turn = EventListScr_Unk_0866A27C, 40 | .event_list_talk = EventListScr_Unk_0866A28C, 41 | .event_list_tile = EventListScr_Unk_0866A290, 42 | .event_list_move = EventListScr_Unk_0866A2E8, 43 | .units_red = UnitInfo_Unk_08685C70, 44 | .units_blue = UnitInfo_Unk_08685BC0, 45 | .event_script_victory = EventScr_Unk_08675E8C, 46 | }; 47 | -------------------------------------------------------------------------------- /tools/scripts/findiwrams.py: -------------------------------------------------------------------------------- 1 | import sys, re 2 | from typing import List 3 | import symbols 4 | 5 | RE = re.compile(r'\.L08[0-9A-F]{6}:\s+\.4byte\s+0x(?P03[0-9A-F]{6})') 6 | RE_REPLACE = re.compile(r'0x(?P03[0-9A-F]{6})') 7 | 8 | def main(args: List[str]): 9 | try: 10 | elf_name = args[1] 11 | asm_names = args[2:] 12 | 13 | except IndexError: 14 | sys.exit(f"Usage: [python 3] {args[0]} ELF ASM...") 15 | 16 | with open(elf_name, 'rb') as f: 17 | syms = { addr: name for addr, name in symbols.from_elf(f) } 18 | 19 | addr_map = {} 20 | 21 | for asm_name in asm_names: 22 | with open(asm_name, 'r') as f: 23 | for line in f.readlines(): 24 | m = RE.match(line) 25 | 26 | if m == None: 27 | continue 28 | 29 | addr = int(m.group('addr'), base = 16) 30 | 31 | if addr < 0x03007E00: 32 | addr_map[addr] = syms[addr] if addr in syms else f"gUnk_{addr:08X}" 33 | 34 | # for addr in sorted(addr_map.keys()): 35 | # print(f"{addr:08X} {addr_map[addr]}") 36 | 37 | def repl_func(m): 38 | addr = int(m.group('addr'), base = 16) 39 | if addr in addr_map: 40 | return addr_map[addr] 41 | return f'0x{addr:08X}' 42 | 43 | for asm_name in asm_names: 44 | lines = [] 45 | 46 | with open(asm_name, 'r') as f: 47 | for line in f.readlines(): 48 | lines.append(re.sub(RE_REPLACE, repl_func, line)) 49 | 50 | with open(asm_name, 'w') as f: 51 | f.writelines(lines) 52 | 53 | if __name__ == '__main__': 54 | main(sys.argv) 55 | -------------------------------------------------------------------------------- /data/chapters/chapter20x_s/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A1F0 4 | EventListScr CONST_DATA EventListScr_Unk_0866A1F0[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08675768, 1, 0, FACTION_BLUE) 7 | EvtListEnd 8 | }; 9 | 10 | // EventListScr @ 0866A200 11 | EventListScr CONST_DATA EventListScr_Unk_0866A200[] = 12 | { 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 0866A204 17 | EventListScr CONST_DATA EventListScr_Unk_0866A204[] = 18 | { 19 | EvtListTile(FLAG_CHAPTER20XS_4, EventScr_Unk_086758D4, 3, 10, TILE_COMMAND_SEIZE) 20 | EvtListTile(FLAG_CHAPTER20XS_5, EventScr_Unk_0867592C, 8, 14, TILE_COMMAND_SEIZE) 21 | EvtListTile(FLAG_CHAPTER20XS_6, EventScr_Unk_08675984, 3, 24, TILE_COMMAND_SEIZE) 22 | EvtListTile(FLAG_CHAPTER20XS_7, EventScr_Unk_086759DC, 12, 26, TILE_COMMAND_SEIZE) 23 | EvtListTile(FLAG_CHAPTER20XS_8, EventScr_Unk_08675A34, 17, 8, TILE_COMMAND_SEIZE) 24 | EvtListTile(FLAG_CHAPTER20XS_9, EventScr_Unk_08675A8C, 21, 15, TILE_COMMAND_SEIZE) 25 | EvtListEnd 26 | }; 27 | 28 | // EventListScr @ 0866A250 29 | EventListScr CONST_DATA EventListScr_Unk_0866A250[] = 30 | { 31 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 32 | EvtListEnd 33 | }; 34 | 35 | // ChapterEventInfo @ 0866A260 36 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A260 = 37 | { 38 | .event_list_turn = EventListScr_Unk_0866A1F0, 39 | .event_list_talk = EventListScr_Unk_0866A200, 40 | .event_list_tile = EventListScr_Unk_0866A204, 41 | .event_list_move = EventListScr_Unk_0866A250, 42 | .units_red = UnitInfo_Unk_08685590, 43 | .units_blue = UnitInfo_Unk_086854A0, 44 | .event_script_victory = EventScr_Unk_08675AE4, 45 | }; 46 | -------------------------------------------------------------------------------- /include/sprite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gba/gba.h" 4 | 5 | #include "proc.h" 6 | 7 | // TODO: sync with mgfembp 8 | 9 | struct SpriteProc 10 | { 11 | /* 00 */ PROC_HEADER; 12 | 13 | /* 2C */ int x; 14 | /* 30 */ int y; 15 | 16 | /* 34 */ u8 pad_34[0x50 - 0x34]; 17 | 18 | /* 50 */ i16 layer; 19 | /* 52 */ u16 tileref; 20 | /* 54 */ u16 const * object; 21 | }; 22 | 23 | extern u16 CONST_DATA Sprite_8x8[]; 24 | extern u16 CONST_DATA Sprite_16x16[]; 25 | extern u16 CONST_DATA Sprite_32x32[]; 26 | extern u16 CONST_DATA Sprite_64x64[]; 27 | extern u16 CONST_DATA Sprite_8x16[]; 28 | extern u16 CONST_DATA Sprite_16x32[]; 29 | extern u16 CONST_DATA Sprite_32x64[]; 30 | extern u16 CONST_DATA Sprite_16x8[]; 31 | extern u16 CONST_DATA Sprite_32x16[]; 32 | extern u16 CONST_DATA Sprite_64x32[]; 33 | extern u16 CONST_DATA Sprite_32x8[]; 34 | extern u16 CONST_DATA Sprite_8x32[]; 35 | extern u16 CONST_DATA Sprite_32x8_VFlipped[]; 36 | extern u16 CONST_DATA Sprite_8x16_HFlipped[]; 37 | extern u16 CONST_DATA Sprite_8x8_HFlipped[]; 38 | extern u16 CONST_DATA Sprite_8x8_VFlipped[]; 39 | extern u16 CONST_DATA Sprite_8x8_HFlipped_VFlipped[]; 40 | extern u16 CONST_DATA Sprite_16x16_VFlipped[]; 41 | 42 | void PutSpriteAffine(int id, short pa, short pb, short pc, short pd); 43 | void ClearSprites(void); 44 | void PutSprite(int layer, int x, int y, u16 const * object, int oam2); 45 | void PutSpriteExt(int layer, int x_oam1, int y_oam0, u16 const * object, int oam2); 46 | void PutSpriteLayerOam(int layer); 47 | 48 | struct SpriteProc * StartSpriteRefresher(ProcPtr parent, int layer, int x, int y, u16 const * object, int tileref); 49 | void MoveSpriteRefresher(struct SpriteProc * proc, int x, int y); 50 | -------------------------------------------------------------------------------- /data/chapters/chapter12x/eventscript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventScr @ 08674F00 4 | EventScr CONST_DATA EventScr_Unk_08674F00[] = 5 | { 6 | EvtFunc(AddChapter12xGasTraps) 7 | EvtFadeToBlack(16) 8 | EvtExitMap 9 | EvtBackground(BACKGROUND_17) 10 | EvtFadeFromBlack(16) 11 | EvtEnterMap 12 | EvtTalk(MSG_BD9) 13 | EvtClearTalk 14 | EvtSetBgm(SONG_0F) 15 | EvtLoadUnitsParty(UnitInfo_Unk_08684824) 16 | EvtMoveWait 17 | EvtCameraUnit(PID_ROY) 18 | EvtFadeToBlack(16) 19 | EvtExitMap 20 | EvtBackground(BACKGROUND_17) 21 | EvtFadeFromBlack(16) 22 | EvtEnterMap 23 | EvtTalk(MSG_BDA) 24 | EvtClearTalk 25 | EvtClearSkip 26 | EvtEnd 27 | }; 28 | 29 | // EventScr @ 08674F84 30 | EventScr CONST_DATA EventScr_Unk_08674F84[] = 31 | { 32 | EvtSetBgm(SONG_28) 33 | EvtGotoIfFunc(1, IsElffinBlue) 34 | 35 | EvtGotoIfNotFlag(3, FLAG_106) 36 | 37 | EvtLabel(1) 38 | EvtFadeToBlack(16) 39 | EvtExitMap 40 | EvtBackground(BACKGROUND_17) 41 | EvtFadeFromBlack(16) 42 | EvtEnterMap 43 | EvtTalk(MSG_BDD) 44 | EvtClearTalk 45 | EvtGoto(5) 46 | 47 | EvtLabel(3) 48 | EvtFadeToBlack(16) 49 | EvtExitMap 50 | EvtBackground(BACKGROUND_17) 51 | EvtFadeFromBlack(16) 52 | EvtEnterMap 53 | EvtTalk(MSG_BDE) 54 | EvtClearTalk 55 | 56 | EvtLabel(5) 57 | EvtFadeToBlack(16) 58 | EvtExitMap 59 | EvtBackground(BACKGROUND_17) 60 | EvtFadeFromBlack(16) 61 | EvtEnterMap 62 | EvtTalk(MSG_115) 63 | EvtClearTalk 64 | EvtNoSkip 65 | EvtGiveItemTo(IID_ARMADS, PID_ROY) 66 | EvtSleep(64) 67 | EvtNextChapter(CHAPTER_13) 68 | EvtSleep(1) 69 | EvtKill 70 | EvtClearSkip 71 | EvtEnd 72 | }; 73 | -------------------------------------------------------------------------------- /tools/scripts/dump-system-labels.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def read_int(f, count, signed = False): 4 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 5 | 6 | def read_sjis_string(f) -> str: 7 | array = bytearray(b'') 8 | 9 | while True: 10 | byte = f.read(1)[0] 11 | 12 | if byte == 0: 13 | break 14 | 15 | array.append(byte) 16 | 17 | return array.decode("cp932") 18 | 19 | def main(args): 20 | try: 21 | romName = args[0] 22 | beg_offset = int(args[1], base = 0) & 0x1FFFFFF 23 | end_offset = int(args[2], base = 0) & 0x1FFFFFF 24 | 25 | except IndexError: 26 | sys.exit("usage: {} ".format(sys.argv[0])) 27 | 28 | names = [] 29 | 30 | with open(romName, 'rb') as f: 31 | for offset in range(beg_offset, end_offset, 8): 32 | f.seek(offset) 33 | addr_jp = read_int(f, 4) 34 | addr_en = read_int(f, 4) 35 | 36 | f.seek(addr_jp & 0x1FFFFFF) 37 | str_jp = read_sjis_string(f) 38 | 39 | f.seek(addr_en & 0x1FFFFFF) 40 | str_en = read_sjis_string(f) 41 | 42 | name = f"SystemLabel_{0x08000000 + offset:08X}" 43 | names.append(name) 44 | 45 | print(f"char const * CONST_DATA {name}[] =") 46 | print("{") 47 | print(f" [LANG_JAPANESE] = JTEXT(\"{str_jp}\"),") 48 | print(f" [LANG_ENGLISH] = TEXT(\"{str_en}\", \"{str_en}\"),") 49 | print("};") 50 | print() 51 | 52 | for name in names: 53 | print(f"extern char const * CONST_DATA {name}[];") 54 | 55 | if __name__ == '__main__': 56 | main(sys.argv[1:]) 57 | -------------------------------------------------------------------------------- /src/faction.c: -------------------------------------------------------------------------------- 1 | #include "faction.h" 2 | 3 | #include "bm.h" 4 | #include "unit.h" 5 | 6 | int CountFactionMoveableUnits(int faction) 7 | { 8 | int i, count = 0; 9 | 10 | for (i = faction + 1; i < faction + 0x40; ++i) 11 | { 12 | struct Unit * unit = GetUnit(i); 13 | 14 | if (!unit) 15 | continue; 16 | 17 | if (!unit->pinfo) 18 | continue; 19 | 20 | if (unit->flags & (UNIT_FLAG_TURN_ENDED | UNIT_FLAG_DEAD | UNIT_FLAG_NOT_DEPLOYED | UNIT_FLAG_RESCUED | UNIT_FLAG_UNDER_ROOF)) 21 | continue; 22 | 23 | if (unit->status == UNIT_STATUS_SLEEP || unit->status == UNIT_STATUS_BERSERK) 24 | continue; 25 | 26 | count++; 27 | } 28 | 29 | return count; 30 | } 31 | 32 | int CountFactionUnitsWithoutFlags(int faction, int prohibited_flags) 33 | { 34 | int i, count = 0; 35 | 36 | for (i = faction + 1; i < faction + 0x40; ++i) 37 | { 38 | struct Unit * unit = GetUnit(i); 39 | 40 | if (!unit) 41 | continue; 42 | 43 | if (!unit->pinfo) 44 | continue; 45 | 46 | if (unit->flags & prohibited_flags) 47 | continue; 48 | 49 | count++; 50 | } 51 | 52 | return count; 53 | } 54 | 55 | bool AreUnitIdsAllied(int uidA, int uidB) 56 | { 57 | uidA &= 0x80; 58 | uidB &= 0x80; 59 | 60 | return uidA == uidB; 61 | } 62 | 63 | bool AreUnitIdsSameFaction(int uidA, int uidB) 64 | { 65 | uidA &= 0xC0; 66 | uidB &= 0xC0; 67 | 68 | return uidA == uidB; 69 | } 70 | 71 | int GetActiveFactionAlliance(void) 72 | { 73 | return gPlaySt.faction & 0x80; 74 | } 75 | 76 | int GetActiveFactionOpposingAlliance(void) 77 | { 78 | return (gPlaySt.faction & 0x80) ^ 0x80; 79 | } 80 | -------------------------------------------------------------------------------- /data/chapters/trial_e/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A778 4 | EventListScr CONST_DATA EventListScr_TrialE_Turn[] = 5 | { 6 | EvtListTurn(0, EventScr_TrialE_Opening, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_LoadUnits_TrialE_Turn10Extra, 10, 22, FACTION_RED) 8 | EvtListTurn(0, EventScr_LoadUnits_TrialE_Turn12Extra, 12, 24, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_TrialE_Turn14Extra, 14, 26, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_TrialE_Turn16Extra, 16, 28, FACTION_RED) 11 | EvtListTurn(0, EventScr_LoadUnits_TrialE_Turn18Extra, 18, 30, FACTION_RED) 12 | EvtListTurn(0, EventScr_LoadUnits_TrialE_Turn20Extra, 20, 32, FACTION_RED) 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 0866A7D0 17 | EventListScr CONST_DATA EventListScr_TrialE_Talk[] = 18 | { 19 | EvtListEnd 20 | }; 21 | 22 | // EventListScr @ 0866A7D4 23 | EventListScr CONST_DATA EventListScr_TrialE_Tile[] = 24 | { 25 | EvtListEnd 26 | }; 27 | 28 | // EventListScr @ 0866A7D8 29 | EventListScr CONST_DATA EventListScr_TrialE_Move[] = 30 | { 31 | EvtListFunc(FLAG_3, EventScr_TrialE_Victory, func_fe6_0806C2F8) 32 | EvtListFlag(FLAG_3, EventScr_TrialE_Failure, FLAG_101) 33 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 34 | EvtListEnd 35 | }; 36 | 37 | // ChapterEventInfo @ 0866A800 38 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A800 = 39 | { 40 | .event_list_turn = EventListScr_TrialE_Turn, 41 | .event_list_talk = EventListScr_TrialE_Talk, 42 | .event_list_tile = EventListScr_TrialE_Tile, 43 | .event_list_move = EventListScr_TrialE_Move, 44 | .units_red = UnitInfo_TrialE_Red, 45 | .units_blue = UnitInfo_TrialE_Deploy, 46 | .event_script_victory = EventScr_TrialE_Victory, 47 | }; 48 | -------------------------------------------------------------------------------- /docs/NONMATCHING.md: -------------------------------------------------------------------------------- 1 | # Nonmatching functions and function bits 2 | 3 | This is a matching decompilation, which means that we are rewriting functions such that the resulting compiled code is the same as the one we started from. 4 | 5 | Sometimes, we fail at getting that, in which case we have a nonmatch (a function which doesn't produce identical code to what we started with). To keep the rest of the disassembly matching, we substitue nonmatching bits of code with the original asm. Defining `NONMATCHING` to 1 will build the nonmatching bits instead. 6 | 7 | Some functions are only matching thanks to "hacks" such as register variables. Those are "fake-matching" functions. 8 | 9 | ## List of non-matching functions in fe6 10 | 11 | | File | Function | Opt. Level | Notes 12 | | ------------ | ------------------ | ---------- | ----- 13 | | `unitlistscreen.c` | `func_fe6_08075E94` | `O2` | https://decomp.me/scratch/sjiAE - reg swap + wrong loop constant load order 14 | | `unitlistscreen.c` | `func_fe6_08076060` | `O2` | https://decomp.me/scratch/j9zM3 15 | 16 | ## List of fake-matching functions in fe6 17 | 18 | | File | Function | Opt. Level | Notes 19 | | -------------- | ----------------- | ---------- | ----- 20 | | `util.c` | `Interpolate` | `O2` | stole it from fe8 21 | | `ai-utility.c` | `func_fe6_08030968` | `O2` | need to load constant before useless function call 22 | | `eventinfo.c` | `EvtListCmd_Door` | `O2` | `asm("":::"memory");` needed (in multiple functions after this also) 23 | | `eventinfo.c` | `StartAvailableTileEvent` | `O2` | somehow theres a couple `nop`s in here. 24 | | `statusscreen.c` | `StatusScreenSprites_Loop`| `O2` | register asm("r4") 25 | | `minimap.c` | `Minimap_ApplyViewportFlashColor` | `O2` | register asm("r3") 26 | -------------------------------------------------------------------------------- /data/chapters/chapter1/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | EventListScr CONST_DATA EventListScr_Chapter1_Turn[] = 4 | { 5 | EvtListTurn(0, EventScr_Chapter1_Opening, 1, 0, FACTION_BLUE) 6 | EvtListTurn(FLAG_CHAPTER1_TURN1, EventScr_Chapter1_FirstRedTurn, 1, 0, FACTION_RED) 7 | EvtListEnd 8 | }; 9 | 10 | EventListScr CONST_DATA EventListScr_Chapter1_Talk[] = 11 | { 12 | EvtListEnd 13 | }; 14 | 15 | EventListScr CONST_DATA EventListScr_Chapter1_Tile[] = 16 | { 17 | EvtListTileMapChange(FLAG_CHAPTER1_VILLAGE, EventScr_Chapter1_Village, 12, 19, TILE_COMMAND_VISIT) 18 | EvtListTile(FLAG_CHAPTER1_VILLAGE, EVENT_NOSCRIPT, 12, 18, TILE_COMMAND_PILLAGE) 19 | EvtListTileMapChange(FLAG_CHAPTER1_TOPVILLAGE, EventScr_Chapter1_TopVillageDummy, 4, 9, TILE_COMMAND_VISIT) 20 | EvtListTile(FLAG_CHAPTER1_TOPVILLAGE, EVENT_NOSCRIPT, 4, 8, TILE_COMMAND_PILLAGE) 21 | EvtListTile(0, EventScr_Chapter1_HouseA, 12, 15, TILE_COMMAND_VISIT) 22 | EvtListTile(0, EventScr_Chapter1_HouseB, 9, 16, TILE_COMMAND_VISIT) 23 | EvtListTile(0, EventScr_Chapter1_HouseC, 9, 19, TILE_COMMAND_VISIT) 24 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 5, 4, TILE_COMMAND_SEIZE) 25 | EvtListEnd 26 | }; 27 | 28 | EventListScr CONST_DATA EventListScr_Chapter1_Move[] = 29 | { 30 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 31 | EvtListEnd 32 | }; 33 | 34 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Chapter1 = 35 | { 36 | .event_list_turn = EventListScr_Chapter1_Turn, 37 | .event_list_talk = EventListScr_Chapter1_Talk, 38 | .event_list_tile = EventListScr_Chapter1_Tile, 39 | .event_list_move = EventListScr_Chapter1_Move, 40 | .units_red = UnitInfo_Chapter1_RedDummy, 41 | .units_blue = UnitInfo_Chapter1_BlueA, 42 | .event_script_victory = EventScr_Chapter1_Victory, 43 | }; 44 | -------------------------------------------------------------------------------- /data/chapters/trial_c/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A5D0 4 | EventListScr CONST_DATA EventListScr_Unk_0866A5D0[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08676080, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686C9C, 4, 0, FACTION_RED) 8 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686CEC, 8, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686D3C, 12, 0, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686D8C, 12, 0, FACTION_RED) 11 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686DDC, 16, 0, FACTION_RED) 12 | EvtListTurn(0, EventScr_LoadUnits_Unk_08686E2C, 18, 0, FACTION_RED) 13 | EvtListTurn(0, EventScr_Unk_08676088, 21, 0, FACTION_BLUE) 14 | EvtListEnd 15 | }; 16 | 17 | // EventListScr @ 0866A634 18 | EventListScr CONST_DATA EventListScr_Unk_0866A634[] = 19 | { 20 | EvtListEnd 21 | }; 22 | 23 | // EventListScr @ 0866A638 24 | EventListScr CONST_DATA EventListScr_Unk_0866A638[] = 25 | { 26 | EvtListEnd 27 | }; 28 | 29 | // EventListScr @ 0866A63C 30 | EventListScr CONST_DATA EventListScr_Unk_0866A63C[] = 31 | { 32 | EvtListFunc(FLAG_3, EventScr_Unk_086760AC, func_fe6_0806BEEC) 33 | EvtListFlag(FLAG_3, EventScr_Unk_086760AC, FLAG_101) 34 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 35 | EvtListEnd 36 | }; 37 | 38 | // ChapterEventInfo @ 0866A664 39 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A664 = 40 | { 41 | .event_list_turn = EventListScr_Unk_0866A5D0, 42 | .event_list_talk = EventListScr_Unk_0866A634, 43 | .event_list_tile = EventListScr_Unk_0866A638, 44 | .event_list_move = EventListScr_Unk_0866A63C, 45 | .units_red = UnitInfo_Unk_08686AFC, 46 | .units_blue = UnitInfo_Unk_08686A4C, 47 | .event_script_victory = EventScr_Unk_08676088, 48 | }; 49 | -------------------------------------------------------------------------------- /src/supply.c: -------------------------------------------------------------------------------- 1 | 2 | #include "supply.h" 3 | 4 | #include "hardware.h" 5 | #include "bm.h" 6 | #include "item.h" 7 | 8 | static u16 EWRAM_DATA sSupplyItems[SUPPLY_ITEM_COUNT] = {}; 9 | 10 | u16 * GetSupplyItems(void) 11 | { 12 | return sSupplyItems; 13 | } 14 | 15 | void ClearSupplyItems(void) 16 | { 17 | CpuFill16(0, sSupplyItems, sizeof(sSupplyItems)); 18 | } 19 | 20 | void SquashSupplyItems(void) 21 | { 22 | u16 i; 23 | 24 | u16 * buf = (u16 *) gBuf; 25 | 26 | u16 * ot = buf; 27 | u16 * it = GetSupplyItems(); 28 | 29 | for (i = 0; i < SUPPLY_ITEM_COUNT; ++it, ++i) 30 | { 31 | if (*it != 0) 32 | *ot++ = *it; 33 | } 34 | 35 | *ot = 0; 36 | 37 | ClearSupplyItems(); 38 | CpuCopy16(buf, GetSupplyItems(), sizeof(u16)*i); 39 | } 40 | 41 | int CountSupplyItems(void) 42 | { 43 | int i, result = 0; 44 | 45 | for (i = 0; i < SUPPLY_ITEM_COUNT; ++i) 46 | { 47 | if (sSupplyItems[i] != 0) 48 | result++; 49 | } 50 | 51 | return result; 52 | } 53 | 54 | int AddSupplyItem(int item) 55 | { 56 | int i; 57 | 58 | gBmSt.convoy_item_overflow = 0; 59 | 60 | for (i = 0; i < SUPPLY_ITEM_COUNT; ++i) 61 | { 62 | if (sSupplyItems[i] == 0) 63 | { 64 | sSupplyItems[i] = item; 65 | return i; 66 | } 67 | } 68 | 69 | gBmSt.convoy_item_overflow = item; 70 | return -1; 71 | } 72 | 73 | void RemoveSupplyItem(int slot) 74 | { 75 | sSupplyItems[slot] = 0; 76 | SquashSupplyItems(); 77 | } 78 | 79 | int FindSupplyItem(int item) 80 | { 81 | int i; 82 | 83 | item = GetItemIid(item); 84 | 85 | for (i = 0; i < SUPPLY_ITEM_COUNT; ++i) 86 | { 87 | if (item == ITEM_IID(sSupplyItems[i])) 88 | return i; 89 | } 90 | 91 | return -1; 92 | } 93 | -------------------------------------------------------------------------------- /tools/scripts/dump_unitlistpagefield.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | OFFSET = 0x678840 4 | LENGTH = 0x5A0 5 | 6 | def decode_sjis_string(rom, offset): 7 | offset = offset & 0x01FFFFFF 8 | end_offs = offset 9 | 10 | while True: 11 | if rom[end_offs] == 0: 12 | break 13 | 14 | end_offs = end_offs + 1 15 | 16 | array = rom[offset:end_offs + 1] 17 | return array.decode("sjis") 18 | 19 | def main(args): 20 | try: 21 | rom_path = args[1] 22 | 23 | except: 24 | return f"Usage: {args[0]} ROM" 25 | 26 | with open(rom_path, 'rb') as f: 27 | rom = f.read() 28 | 29 | print("{") 30 | 31 | for i in range(10): 32 | page_offset = OFFSET + 9 * 0x10 * i 33 | page_name = f"UNITLIST_PAGE_{i}" 34 | 35 | print(f" [{page_name}] =") 36 | print(" {") 37 | 38 | for j in range(9): 39 | offset = page_offset + 0x10 * j 40 | ent = rom[offset:offset+0x10] 41 | 42 | print(" {") 43 | 44 | sort_key = ent[0] 45 | label_string_addr = int.from_bytes(ent[4:8], byteorder='little') 46 | x_column = ent[8] 47 | msg_help = int.from_bytes(ent[12:16], byteorder='little') 48 | 49 | print(f" .sort_key = UNITLIST_SORTKEY_{sort_key},") 50 | 51 | if label_string_addr != 0: 52 | label_string = decode_sjis_string(rom, label_string_addr) 53 | print(f" .label_string = \"{label_string}\",") 54 | 55 | print(f" .x_column = 0x{x_column:02X},") 56 | print(f" .msg_help = MSG_{msg_help:03X},") 57 | print(" },") 58 | 59 | print(" },") 60 | 61 | print("};") 62 | 63 | if __name__ == '__main__': 64 | sys.exit(main(sys.argv)) 65 | -------------------------------------------------------------------------------- /src/ai_phase.c: -------------------------------------------------------------------------------- 1 | #include "ai_phase.h" 2 | 3 | #include "bm.h" 4 | #include "ai_order.h" 5 | #include "ai_utility.h" 6 | #include "ai_data.h" 7 | #include "ai_unk.h" 8 | 9 | struct AiSt EWRAM_DATA gAiSt = {}; 10 | 11 | static void AiPhase_Begin(ProcPtr proc); 12 | static void AiPhase_Finish(ProcPtr proc); 13 | 14 | struct ProcScr CONST_DATA ProcScr_AiPhase[] = 15 | { 16 | PROC_19, 17 | 18 | PROC_CALL(AiPhase_Begin), 19 | PROC_SLEEP(0), 20 | 21 | PROC_CALL(AiPhase_Finish), 22 | 23 | PROC_END, 24 | }; 25 | 26 | static void AiPhase_Berserk_Begin(ProcPtr proc); 27 | 28 | struct ProcScr CONST_DATA ProcScr_AiPhase_Berserk[] = 29 | { 30 | PROC_19, 31 | 32 | PROC_CALL(AiPhase_Berserk_Begin), 33 | PROC_SLEEP(0), 34 | 35 | PROC_CALL(AiPhase_Finish), 36 | 37 | PROC_END, 38 | }; 39 | 40 | static void AiPhase_Begin(ProcPtr proc) 41 | { 42 | int i; 43 | 44 | gAiSt.flags = AI_FLAG_0; 45 | gAiSt.danger_threshold = -1; 46 | 47 | gAiSt.order_state = 0; 48 | 49 | for (i = 0; i < 8; ++i) 50 | gAiSt.cmd_result[i] = 0; 51 | 52 | gAiSt.special_item_flags = AiItemConfigTable[gPlaySt.chapter]; 53 | gAiSt.unk_84 = 0; 54 | 55 | AiUpdateUnitsSeekHealing(); 56 | func_fe6_080308B0(); 57 | 58 | SpawnProcLocking(ProcScr_AiOrder, proc); 59 | } 60 | 61 | static void AiPhase_Berserk_Begin(ProcPtr proc) 62 | { 63 | int i; 64 | 65 | gAiSt.flags = AI_FLAG_BERSERKED; 66 | gAiSt.danger_threshold = -1; 67 | 68 | for (i = 0; i < 8; ++i) 69 | gAiSt.cmd_result[i] = 0; 70 | 71 | gAiSt.special_item_flags = AiItemConfigTable[gPlaySt.chapter]; 72 | 73 | AiUpdateUnitsSeekHealing(); 74 | func_fe6_080308B0(); 75 | 76 | SpawnProcLocking(ProcScr_AiOrder_Berserk, proc); 77 | } 78 | 79 | static void AiPhase_Finish(ProcPtr proc) 80 | { 81 | gAiSt.flags = AI_FLAGS_NONE; 82 | } 83 | -------------------------------------------------------------------------------- /include/constants/jids.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum 4 | { 5 | JID_NONE, 6 | JID_ROY, 7 | JID_MERCENARY, 8 | JID_MERCENARY_F, 9 | JID_HERO, 10 | JID_HERO_F, 11 | JID_MYRMIDON, 12 | JID_MYRMIDON_F, 13 | JID_SWORDMASTER, 14 | JID_SWORDMASTER_F, 15 | JID_FIGHTER, 16 | JID_WARRIOR, 17 | JID_ARMOR, 18 | JID_ARMOR_F, 19 | JID_GENERAL, 20 | JID_GENERAL_F, 21 | JID_ARCHER, 22 | JID_ARCHER_F, 23 | JID_SNIPER, 24 | JID_SNIPER_F, 25 | JID_PRIEST, 26 | JID_CLERIC, 27 | JID_BISHOP, 28 | JID_BISHOP_F, 29 | JID_MAGE, 30 | JID_MAGE_F, 31 | JID_SAGE, 32 | JID_SAGE_F, 33 | JID_SHAMAN, 34 | JID_SHAMAN_F, 35 | JID_DRUID, 36 | JID_DRUID_F, 37 | JID_CAVALIER, 38 | JID_CAVALIER_F, 39 | JID_PALADIN, 40 | JID_PALADIN_F, 41 | JID_TROUBADOUR, 42 | JID_VALKYRIE, 43 | JID_NOMAD, 44 | JID_NOMAD_F, 45 | JID_NOMADTROOPER, 46 | JID_NOMADTROOPER_F, 47 | JID_PEGASUSKNIGHT, 48 | JID_FALCONKNIGHT, 49 | JID_WYVERNRIDER, 50 | JID_WYVERNRIDER_F, 51 | JID_WYVERNLORD, 52 | JID_WYVERNLORD_F, 53 | JID_SOLDIER, 54 | JID_BRIGAND, 55 | JID_PIRATE, 56 | JID_BERSERKER, 57 | JID_THIEF, 58 | JID_THIEF_F, 59 | JID_BARD, 60 | JID_DANCER, 61 | JID_MANAKETE, 62 | JID_MANAKETE_F, 63 | JID_FIREDRAGON, 64 | JID_DIVINEDRAGON, 65 | JID_DEMONDRAGON, 66 | JID_KING, 67 | JID_CIVILIAN, 68 | JID_CIVILIAN_F, 69 | JID_CHILD, 70 | JID_CHILD_F, 71 | JID_SUPPLY, 72 | JID_ROY_PROMOTED, 73 | JID_ARCHER_BALLISTA, 74 | JID_ARCHER_LONGBALLISTA, 75 | JID_ARCHER_KILLERBALLISTA, 76 | JID_BALLISTA, 77 | JID_LONGBALLISTA, 78 | JID_KILLERBALLISTA, 79 | JID_DISMOUNTED, 80 | JID_DISMOUNTED_F, 81 | 82 | MAX_JIDS, 83 | 84 | JID_OBSTACLE = JID_ROY, 85 | }; 86 | -------------------------------------------------------------------------------- /data/chapters/chapter2/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | EventListScr CONST_DATA EventListScr_Chapter2_Turn[] = 4 | { 5 | EvtListTurn(0, EventScr_Chapter2_Opening, 1, 0, FACTION_BLUE) 6 | EvtListTurn(0, EventScr_Chapter2_DieckComes, 2, 0, FACTION_BLUE) 7 | EvtListEnd 8 | }; 9 | 10 | EventListScr CONST_DATA EventListScr_Chapter2_Talk[] = 11 | { 12 | EvtListTalk(FLAG_CHAPTER2_ROYDIECKTALK, EventScr_Chapter2_DieckTalk, PID_ROY, PID_DIECK) 13 | EvtListTalk(FLAG_CHAPTER2_ROYDIECKTALK, EventScr_Chapter2_DieckTalk, PID_DIECK, PID_ROY) 14 | EvtListEnd 15 | }; 16 | 17 | EventListScr CONST_DATA EventListScr_Chapter2_Tile[] = 18 | { 19 | EvtListShop(0, ShopItems_Chapter2_Vendor, 7, 9, TILE_COMMAND_VENDOR) 20 | EvtListShop(0, ShopItems_Chapter2_Armory, 6, 1, TILE_COMMAND_ARMORY) 21 | EvtListTileMapChange(0, EventScr_Chapter2_Village, 3, 4, TILE_COMMAND_VISIT) 22 | EvtListTile(0, EVENT_NOSCRIPT, 3, 3, TILE_COMMAND_PILLAGE) 23 | EvtListTile(0, EventScr_Chapter2_HouseA, 6, 7, TILE_COMMAND_VISIT) 24 | EvtListTile(0, EventScr_Chapter2_HouseB, 0, 4, TILE_COMMAND_VISIT) 25 | EvtListTile(0, EventScr_Chapter2_HouseC, 5, 7, TILE_COMMAND_VISIT) 26 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 16, 3, TILE_COMMAND_SEIZE) 27 | EvtListEnd 28 | }; 29 | 30 | EventListScr CONST_DATA EventListScr_Chapter2_Move[] = 31 | { 32 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 33 | EvtListEnd 34 | }; 35 | 36 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Chapter2 = 37 | { 38 | .event_list_turn = EventListScr_Chapter2_Turn, 39 | .event_list_talk = EventListScr_Chapter2_Talk, 40 | .event_list_tile = EventListScr_Chapter2_Tile, 41 | .event_list_move = EventListScr_Chapter2_Move, 42 | .units_red = UnitInfo_Chapter2_RedDummy, 43 | .units_blue = UnitInfo_Chapter2_Blue, 44 | .event_script_victory = EventScr_Chapter2_Victory, 45 | }; 46 | -------------------------------------------------------------------------------- /tools/scripts/sjb_tab_dump_inl.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def read_int(f, count, signed = False): 4 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 5 | 6 | def read_sjis_string(f): 7 | array = bytearray(b'') 8 | 9 | while True: 10 | byte = f.read(1)[0] 11 | 12 | if byte == 0: 13 | break 14 | 15 | array.append(byte) 16 | 17 | return array 18 | 19 | def main(args): 20 | try: 21 | romName = args[0] 22 | offset = int(args[1], base = 0) & 0x1FFFFFF 23 | tabsize = int(args[2], base = 0) 24 | outputName = args[3] 25 | 26 | except IndexError: 27 | sys.exit("usage: {} ".format(sys.argv[0])) 28 | 29 | with open(outputName, 'wb') as out: 30 | with open(romName, 'rb') as f: 31 | names = [] 32 | lo_off = 0xFFFFFFFF 33 | hi_off = 0 34 | 35 | out.write(b'\n') 36 | 37 | for i in range(tabsize): 38 | f.seek(offset + 4*i) 39 | stroff = read_int(f, 4) & 0x01FFFFFF 40 | lo_off = min(stroff, lo_off) 41 | hi_off = max(stroff, hi_off) 42 | 43 | f.seek(stroff & 0x1FFFFFF) 44 | 45 | names.append(read_sjis_string(f)) 46 | 47 | out.write(f'// strings: {lo_off + 0x08000000:08X}-{hi_off + 0x08000000:08X}'.encode("sjis")) 48 | 49 | out.write(b'\n') 50 | out.write('char const * CONST_DATA gUnk_{:08X}[] =\n'.format(offset + 0x08000000).encode("sjis")) 51 | out.write(b'{\n') 52 | 53 | for name in names: 54 | out.write(b' \"') 55 | out.write(name) 56 | out.write(b'\",\n') 57 | 58 | out.write(b'};\n') 59 | 60 | if __name__ == '__main__': 61 | main(sys.argv[1:]) 62 | -------------------------------------------------------------------------------- /include/mapwork.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | struct MapFloodSquareEnt 6 | { 7 | /* 00 */ i8 x; 8 | /* 01 */ i8 y; 9 | /* 02 */ u8 connect; 10 | /* 03 */ u8 least_mov; 11 | }; 12 | 13 | struct MapFloodSt 14 | { 15 | /* 00 */ struct MapFloodSquareEnt * active_queue; 16 | /* 04 */ struct MapFloodSquareEnt * waiting_queue; 17 | /* 08 */ bool8 has_unit; 18 | /* 09 */ u8 move; 19 | /* 0A */ u8 uid; 20 | /* 0B */ u8 edge_move; 21 | }; 22 | 23 | void SetWorkingMap(u8 ** map); 24 | void MapFlood_UpToMove(struct Unit * unit); 25 | void MapFlood_UpTo(struct Unit * unit, i8 move); 26 | void MapFlood_Pass(struct Unit * unit); 27 | void MapFloodRange_Unitless(int x, int y, i8 const * mov_table); 28 | void MapFlood_Unitless(int x, int y, i8 const * mov_table); 29 | void MapFloodWorkingMap_From_UpTo(struct Unit * unit, int x, int y, int move); 30 | void SetWorkingMovTable(i8 const * mov_table); 31 | void BeginMapFlood(int x, int y, int move, int uid); 32 | void BuildBestMoveScript(int x, int y, u8 * output); 33 | void ApplyWorkingMovScriptToAction(int x, int y); 34 | void MapMovementMarkFloodEdges(void); 35 | void MapMarkFloodEdges(void); 36 | void MapAddInRange(int x, int y, int range, int value); 37 | void MapIncInBoundedRange(short x, short y, short min_range, short max_range); 38 | void BuildUnitCompleteAttackRange(struct Unit * unit); 39 | void BuildUnitStandingRangeForReach(struct Unit * unit, int reach); 40 | void BuildUnitCompleteStaffRange(struct Unit * unit); 41 | i8 const * GetWorkingMovTable(void); 42 | 43 | extern struct MapFloodSt gMapFloodSt; 44 | extern struct MapFloodSquareEnt gMapFloodSquareBufA[]; 45 | extern struct MapFloodSquareEnt gMapFloodSquareBufB[]; 46 | 47 | extern u8 ** gWorkingMap; 48 | extern i8 gWorkingMovTable[]; 49 | 50 | extern u8 gWorkingMoveScr[MOVE_SCRIPT_MAX_LENGTH]; 51 | 52 | #define gWorkingMapSigned ((i8 **) gWorkingMap) 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fire Emblem: The Binding Blade 2 | 3 | This is a decompilation of Fire Emblem: Fūin no Tsurugi (a.k.a. Fire Emblem: The Binding Blade). 4 | 5 | It builds the following ROM: 6 | 7 | * **[fe6.gba]** `sha1: a57095da867de4d585c33d4394712986245fe6ca` 8 | 9 | GBAFE decompilation progress history can be found on [laqieer's FE decomp portal][fe-decomp-portal]. 10 | 11 | [fe6.gba]: https://datomatic.no-intro.org/index.php?page=show_record&s=23&n=0367 12 | [fe-decomp-portal]: https://laqieer.github.io/fe-decomp-portal/ 13 | 14 | ## Quick setup 15 | 16 | - get a `arm-none-eabi` binutils toolchain (devkitARM works). 17 | - get a copy of the original rom (still required for every build for now), put it in this folder and name it `fe6-base.gba`. 18 | - run [tools/install-agbcc.sh](tools/install-agbcc.sh) or get an agbcc another way. 19 | - `make compare` 20 | 21 | In the future, a native GCC or GCC-like C compiler (such as clang) will be required to build tools, there is just no tool to build yet. 22 | 23 | ## Contributing 24 | 25 | Please do. I'm going to be pretty strict on what I accept though, so mind your formatting and naming conventions. 26 | 27 | You can also consider porting stuff between fe6 and fe8. 28 | 29 | ## See also 30 | 31 | * [**StanHash/fe1**](https://github.com/StanHash/fe1), a disassembly of Fire Emblem: Ankoku Ryu to Hikari no Tsurugi (dormant) 32 | * [**ZaneAvernathy/FireEmblem5**](https://github.com/ZaneAvernathy/FireEmblem5), a disassembly of Fire Emblem: Thracia 776 33 | * [**MokhaLeee/FireEmblem7J**](https://github.com/MokhaLeee/FireEmblem7J), a decompilation of Fire Emblem: Rekka no Ken (JP) 34 | * [**FireEmblemUniverse/fireemblem8u**](https://github.com/FireEmblemUniverse/fireemblem8u), a decompilation of Fire Emblem: The Sacred Stones (US) 35 | 36 | ## Contact 37 | 38 | You can find me over at the [Fire Emblem Universe Discord](https://feuniverse.us/t/feu-discord-server/1480?u=stanh) under the handle `nat_776`. 39 | -------------------------------------------------------------------------------- /asm/gbasyscall.s: -------------------------------------------------------------------------------- 1 | .include "macro.inc" 2 | .include "asm_gbaio.inc" 3 | 4 | .syntax unified 5 | 6 | THUMB_FUNC_START ArcTan2 7 | ArcTan2: @ 0x080D166C 8 | swi #0xa 9 | bx lr 10 | 11 | THUMB_FUNC_START BgAffineSet 12 | BgAffineSet: @ 0x080D1670 13 | swi #0xe 14 | bx lr 15 | 16 | THUMB_FUNC_START CpuFastSet 17 | CpuFastSet: @ 0x080D1674 18 | swi #0xc 19 | bx lr 20 | 21 | THUMB_FUNC_START CpuSet 22 | CpuSet: @ 0x080D1678 23 | swi #0xb 24 | bx lr 25 | 26 | THUMB_FUNC_START Div 27 | Div: @ 0x080D167C 28 | swi #6 29 | bx lr 30 | 31 | THUMB_FUNC_START DivRem 32 | DivRem: @ 0x080D1684 33 | swi #6 34 | adds r0, r1, #0 35 | bx lr 36 | 37 | THUMB_FUNC_START HuffUnComp 38 | HuffUnComp: @ 0x080D168C 39 | swi #0x13 40 | bx lr 41 | 42 | THUMB_FUNC_START LZ77UnCompVram 43 | LZ77UnCompVram: @ 0x080D1690 44 | swi #0x12 45 | bx lr 46 | 47 | THUMB_FUNC_START LZ77UnCompWram 48 | LZ77UnCompWram: @ 0x080D1694 49 | swi #0x11 50 | bx lr 51 | 52 | THUMB_FUNC_START ObjAffineSet 53 | ObjAffineSet: @ 0x080D16A0 54 | swi #0xf 55 | bx lr 56 | 57 | THUMB_FUNC_START RLUnCompVram 58 | RLUnCompVram: @ 0x080D16A4 59 | swi #0x15 60 | bx lr 61 | 62 | THUMB_FUNC_START RLUnCompWram 63 | RLUnCompWram: @ 0x080D16A8 64 | swi #0x14 65 | bx lr 66 | 67 | THUMB_FUNC_START SoftReset 68 | SoftReset: @ 0x080D16B0 69 | ldr r3, =REG_IME 70 | movs r2, #0 71 | strb r2, [r3] 72 | ldr r1, =0x03007F00 73 | mov sp, r1 74 | swi #1 75 | swi #0 76 | 77 | .pool 78 | 79 | THUMB_FUNC_START SoundBiasReset 80 | SoundBiasReset: @ 0x080D16C8 81 | movs r0, #0 82 | swi #0x19 83 | bx lr 84 | 85 | THUMB_FUNC_START SoundBiasSet 86 | SoundBiasSet: @ 0x080D16D0 87 | movs r0, #1 88 | swi #0x19 89 | bx lr 90 | 91 | THUMB_FUNC_START Sqrt 92 | Sqrt: @ 0x080D16D8 93 | swi #8 94 | bx lr 95 | 96 | THUMB_FUNC_START VBlankIntrWait 97 | VBlankIntrWait: @ 0x080D16DC 98 | movs r2, #0 99 | swi #5 100 | bx lr 101 | 102 | .align 2, 0 103 | -------------------------------------------------------------------------------- /include/support.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "unit.h" 6 | 7 | enum { MAX_SIMULTANEOUS_SUPPORT_COUNT_PER_UNIT = 5 }; 8 | 9 | enum 10 | { 11 | SUPPORT_LEVEL_NONE, 12 | SUPPORT_LEVEL_C, 13 | SUPPORT_LEVEL_B, 14 | SUPPORT_LEVEL_A, 15 | }; 16 | 17 | enum 18 | { 19 | SUPPORT_EXP_C = 61, 20 | SUPPORT_EXP_B = 121, 21 | SUPPORT_EXP_A = 201, 22 | }; 23 | 24 | enum 25 | { 26 | AFFINITY_1 = 1, 27 | AFFINITY_2 = 2, 28 | AFFINITY_3 = 3, 29 | AFFINITY_4 = 4, 30 | AFFINITY_5 = 5, 31 | AFFINITY_6 = 6, 32 | AFFINITY_7 = 7, 33 | }; 34 | 35 | struct SupportInfo 36 | { 37 | /* 00 */ u8 pids[UNIT_SUPPORT_COUNT]; 38 | /* 0A */ u8 exp_base[UNIT_SUPPORT_COUNT]; 39 | /* 14 */ u8 exp_growth[UNIT_SUPPORT_COUNT]; 40 | /* 1E */ u8 count; 41 | }; 42 | 43 | struct SupportBonuses 44 | { 45 | /* 00 */ u8 affinity; 46 | 47 | /* 01 */ u8 bonus_attack; 48 | /* 02 */ u8 bonus_defense; 49 | /* 03 */ u8 bonus_hit; 50 | /* 04 */ u8 bonus_avoid; 51 | /* 05 */ u8 bonus_crit; 52 | /* 06 */ u8 bonus_dodge; 53 | }; 54 | 55 | int GetUnitSupportCount(struct Unit * unit); 56 | fu8 GetUnitSupportPid(struct Unit * unit, int num); 57 | struct Unit * GetUnitSupportUnit(struct Unit * unit, int num); 58 | int GetUnitSupportLevel(struct Unit * unit, int num); 59 | int GetUnitTotalSupportLevel(struct Unit * unit); 60 | void UnitGainSupportExp(struct Unit * unit, int num); 61 | void UnitGainSupportLevel(struct Unit * unit, int num); 62 | bool CanUnitSupportNow(struct Unit * unit, int num); 63 | int GetUnitInitialSupportExp(struct Unit * unit, int num); 64 | int GetUnitSupportNumByPid(struct Unit * unit, u8 pid); 65 | void ClearUnitSupports(struct Unit * unit); 66 | void DoTurnSupportExp(void); 67 | int GetUnitSupportBonuses(struct Unit * unit, struct SupportBonuses * bonuses); 68 | int GetUnitAffinityIcon(struct Unit * unit); 69 | int GetAffinityIconByPid(int pid); 70 | int GetSupportLevelSpecialChar(int level); 71 | char const * GetAffinityName(int affinity); 72 | -------------------------------------------------------------------------------- /data/chapters/chapter12x/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08669FE4 4 | EventListScr CONST_DATA EventListScr_Unk_08669FE4[] = 5 | { 6 | EvtListChest(0, IID_ELIXIR, 0, 12, 24, TILE_COMMAND_CHEST) 7 | EvtListChest(0, IID_ANTITOXIN, 0, 3, 17, TILE_COMMAND_CHEST) 8 | EvtListChest(0, IID_TORCH, 0, 7, 8, TILE_COMMAND_CHEST) 9 | EvtListChest(0, IID_ANTITOXIN, 0, 18, 16, TILE_COMMAND_CHEST) 10 | EvtListChest(0, IID_ELIXIR, 0, 19, 9, TILE_COMMAND_CHEST) 11 | EvtListChest(0, IID_LOCKPICK, 0, 11, 4, TILE_COMMAND_CHEST) 12 | EvtListChest(0, IID_REDGEM, 0, 25, 12, TILE_COMMAND_CHEST) 13 | EvtListChest(0, IID_ANTITOXIN, 0, 25, 20, TILE_COMMAND_CHEST) 14 | EvtListChest(0, IID_ANTITOXIN, 0, 26, 24, TILE_COMMAND_CHEST) 15 | EvtListChest(0, IID_CHESTKEY, 0, 1, 3, TILE_COMMAND_CHEST) 16 | EvtListChest(0, IID_ELIXIR, 0, 13, 15, TILE_COMMAND_CHEST) 17 | EvtListChest(0, IID_WHITEGEM, 0, 13, 0, TILE_COMMAND_CHEST) 18 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 25, 1, TILE_COMMAND_SEIZE) 19 | EvtListEnd 20 | }; 21 | 22 | // EventListScr @ 0866A084 23 | EventListScr CONST_DATA EventListScr_Unk_0866A084[] = 24 | { 25 | EvtListTurn(0, EventScr_Unk_08674F00, 1, 0, FACTION_BLUE) 26 | EvtListEnd 27 | }; 28 | 29 | // EventListScr @ 0866A094 30 | EventListScr CONST_DATA EventListScr_Unk_0866A094[] = 31 | { 32 | EvtListEnd 33 | }; 34 | 35 | // EventListScr @ 0866A098 36 | EventListScr CONST_DATA EventListScr_Unk_0866A098[] = 37 | { 38 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 39 | EvtListEnd 40 | }; 41 | 42 | // ChapterEventInfo @ 0866A0A8 43 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A0A8 = 44 | { 45 | .event_list_turn = EventListScr_Unk_0866A084, 46 | .event_list_talk = EventListScr_Unk_0866A094, 47 | .event_list_tile = EventListScr_Unk_08669FE4, 48 | .event_list_move = EventListScr_Unk_0866A098, 49 | .units_red = UnitInfo_Unk_086848B4, 50 | .units_blue = UnitInfo_Unk_08684824, 51 | .event_script_victory = EventScr_Unk_08674F84, 52 | }; 53 | -------------------------------------------------------------------------------- /include/bmfx.h: -------------------------------------------------------------------------------- 1 | #ifndef BMFX_H 2 | #define BMFX_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "proc.h" 7 | #include "unit.h" 8 | #include "menu.h" 9 | 10 | int GetRescueTransferFacing(int xa, int ya, int xb, int yb); 11 | void StartRescueTransferAnim(struct Unit * unit, int facing, bool arg_2, ProcPtr parent); 12 | void StartRescueTransferAnimParentless(struct Unit * unit, int facing); 13 | void StartMapFade(bool locks_game); 14 | bool IsMapFadeActive(void); 15 | void HandleGiveUnitItem(struct Unit * unit, int item, ProcPtr parent); 16 | u32 DiscardItemMenu_InventoryEntry_Display(struct MenuProc * menu, struct MenuEntProc * ent); 17 | u32 DiscardItemMenu_ExtraEntry_Display(struct MenuProc * menu, struct MenuEntProc * ent); 18 | fu8 DiscardItemMenu_InventoryEntry_Select(struct MenuProc * menu, struct MenuEntProc * ent); 19 | fu8 DiscardItemMenu_ExtraEntry_Select(struct MenuProc * menu, struct MenuEntProc * ent); 20 | void SetFogVision(int vision); 21 | void BuildWarpDestinationMap(struct Unit * actor, struct Unit * target); 22 | void StartEquipInfoWindow(ProcPtr parent, struct Unit * unit, int x, int y); 23 | void UpdateEquipInfoWindow(int item_slot); 24 | void EndEquipInfoWindow(void); 25 | void StartUnitPrepSwapAnim(ProcPtr parent, struct Unit * unit, int x, int y); 26 | void MakeActiveMuWatchPosition(int x, int y); 27 | void StartGasTrapAnim(ProcPtr parent, int x, int y, int facing); 28 | void StartFireTrapAnim(ProcPtr parent, int x, int y); 29 | void StartArrowTrapAnim(ProcPtr parent, int x); 30 | void StartTimedMapChangeAnim(ProcPtr parent, int unused, int trapid); 31 | void StartPikeTrapAnim(ProcPtr parent, int x, int y, int facing); 32 | void func_fe6_0801DA54(ProcPtr parent, int icon, char const * str); 33 | void StartGameOverScreen(ProcPtr parent); 34 | 35 | extern struct ProcScr CONST_DATA ProcScr_InitPhaseCursor[]; 36 | extern struct ProcScr CONST_DATA ProcScr_ReturnFromStatScreen[]; 37 | extern struct ProcScr CONST_DATA ProcScr_PhaseIntro[]; 38 | extern struct ProcScr CONST_DATA ProcScr_ChapterIntro[]; 39 | 40 | #endif // BMFX_H 41 | -------------------------------------------------------------------------------- /data/chapters/tutorial/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08667640 4 | EventListScr CONST_DATA EventListScr_Unk_08667640[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_0866AD18, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_0866AE10, 1, 0, FACTION_BLUE) 8 | EvtListTurn(0, EventScr_Unk_0866AE60, 2, 0, FACTION_BLUE) 9 | EvtListTurn(0, EventScr_Unk_0866AD78, 3, 0, FACTION_BLUE) 10 | EvtListTurn(0, EventScr_Unk_0866AE78, 4, 0, FACTION_BLUE) 11 | EvtListTurn(0, EventScr_Unk_0866AE90, 7, 0, FACTION_BLUE) 12 | EvtListTurn(0, EventScr_Unk_0866ADE4, 5, 0, FACTION_BLUE) 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 08667698 17 | EventListScr CONST_DATA EventListScr_Unk_08667698[] = 18 | { 19 | EvtListEnd 20 | }; 21 | 22 | // EventListScr @ 0866769C 23 | EventListScr CONST_DATA EventListScr_Unk_0866769C[] = 24 | { 25 | EvtListTileMapChange(FLAG_TUTORIAL_13, EventScr_Unk_0866B2FC, 12, 3, TILE_COMMAND_VISIT) 26 | EvtListTile(FLAG_TUTORIAL_13, EVENT_NOSCRIPT, 12, 2, TILE_COMMAND_PILLAGE) 27 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 22, 4, TILE_COMMAND_SEIZE) 28 | EvtListEnd 29 | }; 30 | 31 | // EventListScr @ 086676C4 32 | EventListScr CONST_DATA EventListScr_Unk_086676C4[] = 33 | { 34 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 35 | EvtListArea(0, EventScr_Unk_0866B350, 0, 0, 26, 9) 36 | EvtListEnd 37 | }; 38 | 39 | // EventListScr @ 086676E0 40 | EventListScr CONST_DATA EventListScr_Tutorial_ActionSelect[] = 41 | { 42 | EvtListFlag(0, EventScr_Unk_0866B14C, FLAG_TUTORIAL_4) 43 | EvtListEnd 44 | }; 45 | 46 | // ChapterEventInfo @ 086676F0 47 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_086676F0 = 48 | { 49 | .event_list_turn = EventListScr_Unk_08667640, 50 | .event_list_talk = EventListScr_Unk_08667698, 51 | .event_list_tile = EventListScr_Unk_0866769C, 52 | .event_list_move = EventListScr_Unk_086676C4, 53 | .units_red = UnitInfo_Unk_086799D4, 54 | .units_blue = UnitInfo_Unk_08679974, 55 | .event_script_victory = EventScr_Unk_0866B5A0, 56 | }; 57 | -------------------------------------------------------------------------------- /tools/scripts/dump_all_chapter_event_info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function dump_chapter 4 | { 5 | echo $1 6 | mkdir -p data/chapters/$1 7 | mv data/chapterevents/$1.h data/chapters/$1/eventscript.h 8 | echo "#pragma once" > data/chapters/$1/eventinfo.h 9 | python tools/scripts/dump_chapter_event_info.py fe6.gba $2 >> data/chapters/$1/eventinfo.h 10 | } 11 | 12 | dump_chapter tutorial 0x086676F0 13 | dump_chapter chapter1 0x086677A0 14 | dump_chapter chapter2 0x08667868 15 | dump_chapter chapter3 0x08667960 16 | dump_chapter chapter4 0x08667ADC 17 | dump_chapter chapter5 0x08667BBC 18 | dump_chapter chapter6 0x08667D5C 19 | dump_chapter chapter7 0x08667FA4 20 | dump_chapter chapter8 0x0866812C 21 | dump_chapter chapter9 0x08668248 22 | dump_chapter chapter10_a 0x08668364 23 | dump_chapter chapter11_a 0x08668588 24 | dump_chapter chapter12 0x08668728 25 | dump_chapter chapter13 0x086688B0 26 | dump_chapter chapter14 0x086689FC 27 | dump_chapter chapter15 0x08668AF4 28 | dump_chapter chapter16 0x08668C94 29 | dump_chapter chapter17_i 0x08668D8C 30 | dump_chapter chapter18_i 0x08668F2C 31 | dump_chapter chapter19_i 0x0866900C 32 | dump_chapter chapter20_i 0x086691DC 33 | dump_chapter chapter21 0x086692F8 34 | dump_chapter chapter22 0x086694BC 35 | dump_chapter chapter23 0x0866959C 36 | dump_chapter chapter24 0x0866967C 37 | dump_chapter final 0x086696CC 38 | dump_chapter chapter10_b 0x086698D8 39 | dump_chapter chapter11_b 0x08669A54 40 | dump_chapter chapter17_s 0x08669B58 41 | dump_chapter chapter18_s 0x08669C80 42 | dump_chapter chapter19_s 0x08669E14 43 | dump_chapter chapter20_s 0x08669F78 44 | dump_chapter chapter8x 0x08669FC8 45 | dump_chapter chapter12x 0x0866A0A8 46 | dump_chapter chapter14x 0x0866A0F8 47 | dump_chapter chapter16x 0x0866A184 48 | dump_chapter chapter20x_i 0x0866A1D4 49 | dump_chapter chapter20x_s 0x0866A260 50 | dump_chapter chapter21x 0x0866A2F8 51 | dump_chapter trial_a 0x0866A384 52 | dump_chapter trial_b 0x0866A5B4 53 | dump_chapter trial_c 0x0866A664 54 | dump_chapter trial_d 0x0866A75C 55 | dump_chapter trial_e 0x0866A800 56 | -------------------------------------------------------------------------------- /include/save_multiarena.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | #include "save.h" 5 | 6 | #include "save_game.h" 7 | 8 | enum 9 | { 10 | MULTIARENA_CONFIG_SHOWUNITS = 1 << 0, 11 | MULTIARENA_CONFIG_SURVIVALMODE = 1 << 1, 12 | MULTIARENA_CONFIG_AUTOEQUIPOFF = 1 << 2, 13 | MULTIARENA_CONFIG_3 = 1 << 3, 14 | }; 15 | 16 | // 7 sjis characters 17 | #define MULTIARENA_TEAMNAME_SIZE 14 18 | 19 | #define MULTIARENA_UNITS_PER_TEAM 5 20 | #define MULTIARENA_MAX_TEAMS 10 21 | #define MULTIARENA_MAX_RANKINGS 10 22 | 23 | struct MultiArenaRankingEnt 24 | { 25 | /* 00 */ u32 ranking : 2; 26 | /* */ u32 player_count : 2; 27 | /* */ u32 mode : 1; 28 | /* */ u32 points : 27; 29 | /* 04 */ char name[MULTIARENA_TEAMNAME_SIZE + 1]; 30 | }; 31 | 32 | struct MultiArenaSaveTeam 33 | { 34 | /* 00 */ char name[MULTIARENA_TEAMNAME_SIZE + 1]; 35 | /* 10 */ struct GameSavePackedUnit units[MULTIARENA_UNITS_PER_TEAM]; 36 | }; 37 | 38 | struct MultiArenaSaveBlock 39 | { 40 | /* 000 */ struct MultiArenaSaveTeam teams[MULTIARENA_MAX_TEAMS]; 41 | /* 870 */ u16 config; 42 | /* 874 */ struct MultiArenaRankingEnt rankings[MULTIARENA_MAX_RANKINGS]; 43 | }; 44 | 45 | bool IsMultiArenaSaveValid(int save_id); 46 | void WriteNewMultiArenaSave(void); 47 | bool ReadMultiArenaSaveTeamRaw(int team, struct MultiArenaSaveTeam * dst); 48 | bool ReadMultiArenaSaveTeamName(int team, char * dst); 49 | void WipeMultiArenaSaveTeam(int team); 50 | void CopyMultiArenaSaveTeam(int team_src, int team_dst); 51 | void SwapMultiArenaSaveTeams(int team_a, int team_b); 52 | void WriteMultiArenaSaveTeam(int team, struct Unit * units_src, char const * name_src); 53 | bool ReadMultiArenaSaveTeam(int team, struct Unit * units_dst, char * name_dst); 54 | void WriteMultiArenaSaveRankings(struct MultiArenaRankingEnt const * src); 55 | void ReadMultiArenaSaveRankings(struct MultiArenaRankingEnt * dst); 56 | void WriteMultiArenaSaveConfig(u16 const * config_src); 57 | void ReadMultiArenaSaveConfig(u16 * config_dst); 58 | bool IsMultiArenaSaveReady(void); 59 | -------------------------------------------------------------------------------- /tools/scripts/dump-ai-escape-points.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def read_int(f, count, signed = False): 5 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 6 | 7 | FACING_CONSTANTS = [ 8 | "FACING_LEFT", 9 | "FACING_RIGHT", 10 | "FACING_DOWN", 11 | "FACING_UP"] 12 | 13 | def main(args): 14 | try: 15 | rom_name = args[0] 16 | offset = 0x1FFFFFF & int(args[1], base = 0) 17 | count = int(args[2], base = 0) 18 | 19 | except IndexError: 20 | sys.exit(f"Usage: {sys.argv[0]} ROM OFFSET COUNT") 21 | 22 | with open(rom_name, 'rb') as f: 23 | f.seek(offset) 24 | 25 | addr_list = [] 26 | 27 | for _ in range(count): 28 | addr_list.append(read_int(f, 4)) 29 | 30 | end_offset = f.tell() 31 | 32 | unique_addr_list = sorted(set(addr_list)) 33 | addr_to_chapter = { addr: i for i, addr in enumerate(addr_list) } 34 | 35 | for addr in unique_addr_list: 36 | print(f"struct AiEscapePt const AiEscapePts_{addr_to_chapter[addr]}[] =") 37 | print(f"{{") 38 | 39 | f.seek(addr & 0x01FFFFFF) 40 | 41 | while True: 42 | x = read_int(f, 1, True) 43 | y = read_int(f, 1, True) 44 | facing = read_int(f, 1) 45 | 46 | read_int(f, 1) # discard padding 47 | 48 | print(f" {{ {x}, {y}, {facing} }},") 49 | 50 | if x == -1: 51 | break 52 | 53 | print(f"}};") 54 | print(f"") 55 | 56 | print(f"// ends at {0x08000000 + f.tell():08X}") 57 | print(f"") 58 | 59 | print(f"struct AiEscapePt CONST_DATA gAiEscapePts_{offset + 0x08000000:08X}[] =") 60 | print(f"{{") 61 | 62 | for addr in addr_list: 63 | print(f" AiEscapePts_{addr_to_chapter[addr]},") 64 | 65 | print(f"}};") 66 | 67 | print(f"// ends at {0x08000000 + end_offset:08X}") 68 | 69 | if __name__ == '__main__': 70 | main(sys.argv[1:]) 71 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #include 5 | #include 6 | 7 | typedef uint8_t u8; 8 | typedef uint16_t u16; 9 | typedef uint32_t u32; 10 | typedef uint64_t u64; 11 | typedef int8_t i8; 12 | typedef int16_t i16; 13 | typedef int32_t i32; 14 | typedef int64_t i64; 15 | 16 | typedef float f32; 17 | typedef double f64; 18 | 19 | #if defined(MODERN) && MODERN 20 | 21 | typedef i32 fi8; 22 | typedef i32 fi16; 23 | typedef u32 fu8; 24 | typedef u32 fu16; 25 | 26 | #else 27 | 28 | typedef i8 fi8; 29 | typedef i16 fi16; 30 | typedef u8 fu8; 31 | typedef u16 fu16; 32 | 33 | #endif 34 | 35 | typedef u8 volatile vu8; 36 | typedef u16 volatile vu16; 37 | typedef u32 volatile vu32; 38 | typedef u64 volatile vu64; 39 | typedef i8 volatile vi8; 40 | typedef i16 volatile vi16; 41 | typedef i32 volatile vi32; 42 | typedef i64 volatile vi64; 43 | 44 | typedef intptr_t iptr; 45 | typedef uintptr_t uptr; 46 | 47 | enum { FALSE, TRUE }; 48 | 49 | #if !defined(__cplusplus) && !defined(bool) 50 | typedef fi8 bool; 51 | #endif 52 | typedef i8 bool8; 53 | 54 | // TODO: move types below 55 | 56 | typedef void (* Func)(void); 57 | 58 | enum glb_pos 59 | { 60 | POS_L = 0, 61 | POS_R = 1, 62 | POS_INVALID = -1 63 | }; 64 | 65 | struct Vec2i 66 | { 67 | i16 x, y; 68 | }; 69 | 70 | struct Vec2u 71 | { 72 | u16 x, y; 73 | }; 74 | 75 | // Forward decls for common types 76 | // TODO: move 77 | 78 | struct FaceInfo; 79 | 80 | struct BmSt; 81 | struct PlaySt; 82 | 83 | struct Unit; 84 | struct UnitInfo; 85 | struct UnitSprite; 86 | struct SupportInfo; 87 | 88 | struct BattleUnit; 89 | struct BattleHit; 90 | 91 | struct HelpBoxInfo; 92 | struct HelpBoxProc; 93 | 94 | struct SelectTarget; 95 | struct MapSelectInfo; 96 | struct MapSelectProc; 97 | 98 | struct MenuProc; 99 | struct MenuEntProc; 100 | struct MenuEntInfo; 101 | 102 | // TODO: move 103 | struct ChapterEventInfo; 104 | struct EventInfo; 105 | 106 | #endif // TYPES_H 107 | -------------------------------------------------------------------------------- /data/chapters/chapter20x_i/eventscript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventScr @ 0867557C 4 | EventScr CONST_DATA EventScr_Unk_0867557C[] = 5 | { 6 | EvtCamera(16, 1) 7 | EvtFlashCursor(16, 1) 8 | EvtFadeToBlack(16) 9 | EvtExitMap 10 | EvtBackground(BACKGROUND_13) 11 | EvtFadeFromBlack(16) 12 | EvtEnterMap 13 | EvtTalk(MSG_BEE) 14 | EvtClearTalk 15 | EvtSetBgm(SONG_0F) 16 | EvtLoadUnitsParty(UnitInfo_Unk_08685100) 17 | EvtMoveWait 18 | EvtCameraUnit(PID_ROY) 19 | EvtFlashCursorUnit(PID_ROY) 20 | EvtGotoIfFunc(1, IsZelotBlueDeployed) 21 | 22 | EvtGotoIfFunc(2, IsJunoBlueDeployed) 23 | 24 | EvtFadeToBlack(16) 25 | EvtExitMap 26 | EvtBackground(BACKGROUND_13) 27 | EvtFadeFromBlack(16) 28 | EvtEnterMap 29 | EvtTalk(MSG_BF2) 30 | EvtClearTalk 31 | EvtGoto(9) 32 | 33 | EvtLabel(1) 34 | EvtFadeToBlack(16) 35 | EvtExitMap 36 | EvtBackground(BACKGROUND_13) 37 | EvtFadeFromBlack(16) 38 | EvtEnterMap 39 | EvtTalk(MSG_BF0) 40 | EvtClearTalk 41 | EvtGoto(9) 42 | 43 | EvtLabel(2) 44 | EvtFadeToBlack(16) 45 | EvtExitMap 46 | EvtBackground(BACKGROUND_13) 47 | EvtFadeFromBlack(16) 48 | EvtEnterMap 49 | EvtTalk(MSG_BF1) 50 | EvtClearTalk 51 | 52 | EvtLabel(9) 53 | EvtClearSkip 54 | EvtEnd 55 | }; 56 | 57 | // EventScr @ 086756A8 58 | EventScr CONST_DATA EventScr_Unk_086756A8[] = 59 | { 60 | EvtSetBgm(SONG_27) 61 | EvtFadeToBlack(16) 62 | EvtExitMap 63 | EvtBackground(BACKGROUND_13) 64 | EvtFadeFromBlack(16) 65 | EvtEnterMap 66 | EvtTalk(MSG_BF5) 67 | EvtClearTalk 68 | EvtNoSkip 69 | EvtGiveItemTo(IID_MALTET, PID_ROY) 70 | EvtSetBgm(SONG_2B) 71 | EvtFadeToBlack(16) 72 | EvtExitMap 73 | EvtBackground(BACKGROUND_13) 74 | EvtFadeFromBlack(16) 75 | EvtEnterMap 76 | EvtTalk(MSG_1AE) 77 | EvtSetBgm(SONG_3C) 78 | EvtTalkContinue 79 | EvtClearTalk 80 | EvtSleep(64) 81 | EvtNextChapter(CHAPTER_21) 82 | EvtSleep(1) 83 | EvtKill 84 | EvtClearSkip 85 | EvtEnd 86 | }; 87 | -------------------------------------------------------------------------------- /include/save_xmap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | #include "save.h" 5 | 6 | #include "gbasram.h" 7 | 8 | struct ExtraMapSaveHead 9 | { 10 | /* 00 */ u32 xmap_magic; 11 | /* 04 */ u16 xmap_size; 12 | /* 06 */ u16 xmap_checksum; 13 | /* 08 */ u32 save_magic32; 14 | /* 0C */ u32 unused_0C; 15 | /* 10 */ void const * map_sram; 16 | /* 14 */ i16 map_size; 17 | /* 16 */ i16 info_size; 18 | /* 18 */ void const * info_sram; 19 | }; 20 | 21 | struct ExtraMapInfo 22 | { 23 | /* 00 */ struct ChapterInfo const * chapter_info; 24 | /* 04 */ struct MapChangeInfo const * map_change_info; 25 | /* 08 */ struct ChapterEventInfo const * event_info; 26 | /* 0C */ char const * msg_0C; 27 | /* 10 */ char const * msg_10; 28 | /* 14 */ char const * msg_14; 29 | /* 18 */ struct PlaySt * play_st; 30 | /* 1C */ struct BmSt * bm_st; 31 | /* 20 */ struct Unit ** active_unit; 32 | /* 24 */ struct Unit * const * unit_lut; 33 | /* 28 */ struct BattleUnit * bu_a; 34 | /* 2C */ struct BattleUnit * bu_b; 35 | /* 30 */ struct BattleHit * battle_hits; 36 | /* 34 */ struct Trap * traps; 37 | /* 38 */ u8 * permanent_flags; 38 | /* 3C */ u8 * chapter_frags; 39 | }; 40 | 41 | bool ReadExtraMapSaveHead(void); 42 | void const * GetExtraMapMapReadAddr(void); 43 | u32 GetExtraMapMapSize(void); 44 | void const * GetExtraMapInfoReadAddr(void); 45 | u32 GetExtraMapInfoSize(void); 46 | u16 ExtraMapChecksum(void const * data, int size); 47 | bool IsExtraMapAvailable(void); 48 | void ReadExtraMapInfo(void); 49 | bool ListAvailableTrialChapters(i8 * list_out); 50 | char const * func_fe6_080867F0(int chapter); 51 | char const * func_fe6_080867FC(int chapter); 52 | char const * func_fe6_08086910(int chapter); 53 | void CreateTrialChapterBonusUnits(void); 54 | struct ChapterStats * func_fe6_08086AAC(void); 55 | 56 | extern struct ExtraMapInfo * CONST_DATA gExtraMapInfo; 57 | 58 | #define XMAP_MAGIC 0x50414D58 // 'XMAP' 59 | 60 | #define SRAM_XMAP_SIZE 0x1000u 61 | #define SRAM_XMAP_ADDR (CART_SRAM + CART_SRAM_SIZE - SRAM_XMAP_SIZE) 62 | -------------------------------------------------------------------------------- /data/chapters/chapter19_i/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08668F48 4 | EventListScr CONST_DATA EventListScr_Unk_08668F48[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08671340, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_086713D4, 13, 0, FACTION_RED) 8 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867FDB8, 11, 15, FACTION_RED) 9 | EvtListTurn(0, EventScr_Unk_08671434, 16, 20, FACTION_RED) 10 | EvtListEnd 11 | }; 12 | 13 | // EventListScr @ 08668F7C 14 | EventListScr CONST_DATA EventListScr_Unk_08668F7C[] = 15 | { 16 | EvtListEnd 17 | }; 18 | 19 | // EventListScr @ 08668F80 20 | EventListScr CONST_DATA EventListScr_Unk_08668F80[] = 21 | { 22 | EvtListTileMapChange(0, EventScr_Unk_08671460, 10, 14, TILE_COMMAND_VISIT) 23 | EvtListTile(0, EVENT_NOSCRIPT, 10, 13, TILE_COMMAND_PILLAGE) 24 | EvtListTileMapChange(0, EventScr_Unk_086714A8, 29, 14, TILE_COMMAND_VISIT) 25 | EvtListTile(0, EVENT_NOSCRIPT, 29, 13, TILE_COMMAND_PILLAGE) 26 | EvtListShop(0, ShopItems_Unk_0866A956, 4, 18, TILE_COMMAND_VENDOR) 27 | EvtListTile(0, EventScr_Unk_086715A4, 1, 19, TILE_COMMAND_VISIT) 28 | EvtListTile(0, EventScr_Unk_08671568, 3, 17, TILE_COMMAND_VISIT) 29 | EvtListTile(0, EventScr_Unk_0867152C, 1, 14, TILE_COMMAND_VISIT) 30 | EvtListTile(0, EventScr_Unk_086714F0, 3, 11, TILE_COMMAND_VISIT) 31 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 28, 3, TILE_COMMAND_SEIZE) 32 | EvtListEnd 33 | }; 34 | 35 | // EventListScr @ 08668FFC 36 | EventListScr CONST_DATA EventListScr_Unk_08668FFC[] = 37 | { 38 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 39 | EvtListEnd 40 | }; 41 | 42 | // ChapterEventInfo @ 0866900C 43 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866900C = 44 | { 45 | .event_list_turn = EventListScr_Unk_08668F48, 46 | .event_list_talk = EventListScr_Unk_08668F7C, 47 | .event_list_tile = EventListScr_Unk_08668F80, 48 | .event_list_move = EventListScr_Unk_08668FFC, 49 | .units_red = UnitInfo_Unk_0867FB58, 50 | .units_blue = UnitInfo_Unk_0867FA58, 51 | .event_script_victory = EventScr_Unk_086715E0, 52 | }; 53 | -------------------------------------------------------------------------------- /data/rodata_3278AC.s: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | 3 | .global gUnk_083278AC 4 | gUnk_083278AC: @ 083278AC 5 | .incbin "fe6-base.gba", 0x3278AC, (0x3278EC - 0x3278AC) @ length: 0040 6 | 7 | .global gUnk_083278EC 8 | gUnk_083278EC: @ 083278EC 9 | .incbin "fe6-base.gba", 0x3278EC, (0x3280B0 - 0x3278EC) @ length: 07C4 10 | 11 | .global gUnk_083280B0 12 | gUnk_083280B0: @ 083280B0 13 | .incbin "fe6-base.gba", 0x3280B0, (0x32A130 - 0x3280B0) @ length: 2080 14 | 15 | .global gUnk_0832A130 16 | gUnk_0832A130: @ 0832A130 17 | .incbin "fe6-base.gba", 0x32A130, (0x32A29C - 0x32A130) @ length: 016C 18 | 19 | .global gUnk_0832A29C 20 | gUnk_0832A29C: @ 0832A29C 21 | .incbin "fe6-base.gba", 0x32A29C, (0x32B554 - 0x32A29C) @ length: 12B8 22 | 23 | .global gUnk_0832B554 24 | gUnk_0832B554: @ 0832B554 25 | .incbin "fe6-base.gba", 0x32B554, (0x32BDE8 - 0x32B554) @ length: 0894 26 | 27 | .global gUnk_0832BDE8 28 | gUnk_0832BDE8: @ 0832BDE8 29 | .incbin "fe6-base.gba", 0x32BDE8, (0x32BF28 - 0x32BDE8) @ length: 0140 30 | 31 | .global gUnk_0832BF28 32 | gUnk_0832BF28: @ 0832BF28 33 | .incbin "fe6-base.gba", 0x32BF28, (0x32C33C - 0x32BF28) @ length: 0414 34 | 35 | .global gUnk_0832C33C 36 | gUnk_0832C33C: @ 0832C33C 37 | .incbin "fe6-base.gba", 0x32C33C, (0x32C35C - 0x32C33C) @ length: 0020 38 | 39 | .global gUnk_0832C35C 40 | gUnk_0832C35C: @ 0832C35C 41 | .incbin "fe6-base.gba", 0x32C35C, (0x32C39C - 0x32C35C) @ length: 0040 42 | 43 | .global gUnk_0832C39C 44 | gUnk_0832C39C: @ 0832C39C 45 | .incbin "fe6-base.gba", 0x32C39C, (0x32C5E8 - 0x32C39C) @ length: 024C 46 | 47 | .global gUnk_0832C5E8 48 | gUnk_0832C5E8: @ 0832C5E8 49 | .incbin "fe6-base.gba", 0x32C5E8, (0x32CA9C - 0x32C5E8) @ length: 04B4 50 | 51 | .global gUnk_0832CA9C 52 | gUnk_0832CA9C: @ 0832CA9C 53 | .incbin "fe6-base.gba", 0x32CA9C, (0x32CAFC - 0x32CA9C) @ length: 0060 54 | 55 | .global gUnk_0832CAFC 56 | gUnk_0832CAFC: @ 0832CAFC 57 | .incbin "fe6-base.gba", 0x32CAFC, (0x32CC90 - 0x32CAFC) @ length: 0194 58 | 59 | .global gUnk_0832CC90 60 | gUnk_0832CC90: @ 0832CC90 61 | .incbin "fe6-base.gba", 0x32CC90, (0x336C60 - 0x32CC90) @ length: 9FD0 62 | -------------------------------------------------------------------------------- /data/chapters/chapter5/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | EventListScr CONST_DATA EventListScr_Chapter5_Turn[] = 4 | { 5 | EvtListTurn(0, EventScr_Chapter5_Opening, 1, 0, FACTION_BLUE) 6 | EvtListTurn(0, EventScr_LoadUnits_Chapter5_BackFortBrigands, 12, 15, FACTION_RED) 7 | EvtListTurn(FLAG_CHAPTER5_4, EventScr_Chapter5_SaulDorothyScene, 1, 0, FACTION_GREEN) 8 | EvtListTurnHard(0, EventScr_LoadUnits_Chapter5_BackFortBrigands, 16, 18, FACTION_RED) 9 | EvtListTurnHard(0, EventScr_LoadUnits_Chapter5_FrontFortBrigands, 15, 20, FACTION_RED) 10 | EvtListTurnHard(0, EventScr_LoadUnits_Chapter5_FrontFortBrigands, 15, 20, FACTION_RED) 11 | EvtListEnd 12 | }; 13 | 14 | EventListScr CONST_DATA EventListScr_Chapter5_Talk[] = 15 | { 16 | EvtListEnd 17 | }; 18 | 19 | EventListScr CONST_DATA EventListScr_Chapter5_Tile[] = 20 | { 21 | EvtListShop(0, ShopItems_Chapter5_Vendor, 7, 2, TILE_COMMAND_VENDOR) 22 | EvtListTileMapChange(FLAG_CHAPTER5_VILLAGE, EventScr_Chapter5_Village, 10, 2, TILE_COMMAND_VISIT) 23 | EvtListTile(FLAG_CHAPTER5_VILLAGE, EVENT_NOSCRIPT, 10, 1, TILE_COMMAND_PILLAGE) 24 | EvtListTile(0, EventScr_Chapter5_HouseA, 11, 20, TILE_COMMAND_VISIT) 25 | EvtListTile(0, EventScr_Chapter5_HouseB, 12, 20, TILE_COMMAND_VISIT) 26 | EvtListTile(0, EventScr_Chapter5_HouseC, 8, 19, TILE_COMMAND_VISIT) 27 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 2, 14, TILE_COMMAND_SEIZE) 28 | EvtListEnd 29 | }; 30 | 31 | EventListScr CONST_DATA EventListScr_Chapter5_Move[] = 32 | { 33 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 34 | EvtListArea(FLAG_CHAPTER5_BARRIER, EventScr_Chapter5_OpenBarrier, 7, 16, 7, 17) 35 | EvtListEnd 36 | }; 37 | 38 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Chapter5 = 39 | { 40 | .event_list_turn = EventListScr_Chapter5_Turn, 41 | .event_list_talk = EventListScr_Chapter5_Talk, 42 | .event_list_tile = EventListScr_Chapter5_Tile, 43 | .event_list_move = EventListScr_Chapter5_Move, 44 | .units_red = UnitInfo_Chapter5_Red, 45 | .units_blue = UnitInfo_Chapter5_Blue, 46 | .event_script_victory = EventScr_Chapter5_Victory, 47 | }; 48 | -------------------------------------------------------------------------------- /data/chapters/chapter24/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 086695B8 4 | EventListScr CONST_DATA EventListScr_Unk_086695B8[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08672818, 1, 0, FACTION_BLUE) 7 | EvtListFunc(0, EventScr_Unk_08672874, func_fe6_0806BC5C) 8 | EvtListFunc(0, EventScr_Unk_08672890, func_fe6_0806BCA4) 9 | EvtListFunc(0, EventScr_Unk_086728AC, func_fe6_0806BCEC) 10 | EvtListFunc(0, EventScr_Unk_086728C8, func_fe6_0806BD34) 11 | EvtListFunc(0, EventScr_Unk_086728E4, func_fe6_0806BD7C) 12 | EvtListFunc(0, EventScr_Unk_08672900, func_fe6_0806BDC4) 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 08669610 17 | EventListScr CONST_DATA EventListScr_Unk_08669610[] = 18 | { 19 | EvtListEnd 20 | }; 21 | 22 | // EventListScr @ 08669614 23 | EventListScr CONST_DATA EventListScr_Unk_08669614[] = 24 | { 25 | EvtListTile(FLAG_CHAPTER24_4, EventScr_Unk_0867291C, 18, 36, TILE_COMMAND_SEIZE) 26 | EvtListTile(FLAG_CHAPTER24_5, EventScr_Unk_0867296C, 7, 35, TILE_COMMAND_SEIZE) 27 | EvtListTile(FLAG_CHAPTER24_6, EventScr_Unk_086729BC, 5, 23, TILE_COMMAND_SEIZE) 28 | EvtListTile(FLAG_CHAPTER24_7, EventScr_Unk_08672A0C, 16, 21, TILE_COMMAND_SEIZE) 29 | EvtListTile(FLAG_CHAPTER24_8, EventScr_Unk_08672A5C, 27, 14, TILE_COMMAND_SEIZE) 30 | EvtListTile(FLAG_CHAPTER24_9, EventScr_Unk_08672AAC, 18, 6, TILE_COMMAND_SEIZE) 31 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 6, 3, TILE_COMMAND_SEIZE) 32 | EvtListEnd 33 | }; 34 | 35 | // EventListScr @ 0866966C 36 | EventListScr CONST_DATA EventListScr_Unk_0866966C[] = 37 | { 38 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 39 | EvtListEnd 40 | }; 41 | 42 | // ChapterEventInfo @ 0866967C 43 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866967C = 44 | { 45 | .event_list_turn = EventListScr_Unk_086695B8, 46 | .event_list_talk = EventListScr_Unk_08669610, 47 | .event_list_tile = EventListScr_Unk_08669614, 48 | .event_list_move = EventListScr_Unk_0866966C, 49 | .units_red = UnitInfo_Unk_086819A8, 50 | .units_blue = UnitInfo_Unk_086818F8, 51 | .event_script_victory = EventScr_Unk_08672B28, 52 | }; 53 | -------------------------------------------------------------------------------- /include/spriteanim.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "proc.h" 6 | 7 | struct SpriteAnim 8 | { 9 | /* 00 */ u16 const * info; // address of info 10 | /* 04 */ u16 const * sprites; // address of sprite array 11 | /* 08 */ u16 const * script; // address of script start (where we go back on loop) 12 | /* 0C */ u16 const * script_pc; // address of script pc (where we are now) 13 | /* 10 */ u16 const * current_sprite; // address of current sprite 14 | /* 14 */ u16 const * current_affine; // address of current affine 15 | /* 18 */ i16 clock; // Cycle Timer 16 | /* 1A */ u16 clock_interval_q8; // Cycle Time Step 17 | /* 1C */ u16 clock_decimal_q8; // Sub frame time offset or something 18 | /* 1E */ u16 layer; // sprite layer 19 | /* 20 */ u8 need_sync_img_b; // bool defining whether gfx needs update 20 | /* 21 */ u8 affine_slot; // Rotation/Scale OAM Index 21 | /* 22 */ u16 oam2; // OAM Extra Data (Tile Index Root & OAM2 Stuff) 22 | /* 24 */ u8 const * img; // address of graphics (if any) 23 | }; 24 | 25 | void InitSpriteAnims(void); 26 | struct SpriteAnim * StartSpriteAnim(u16 const * info, u16 layer); 27 | void EndSpriteAnim(struct SpriteAnim * anim); 28 | bool DisplaySpriteAnim(struct SpriteAnim * anim, int x, int y); 29 | void SetSpriteAnimId(struct SpriteAnim * anim, int id); 30 | void SetSpriteAnimInfo(struct SpriteAnim * anim, u16 const * info); 31 | struct SpriteAnim * FindSpriteAnim(u16 const * info); 32 | ProcPtr StartSpriteAnimProc(u16 const * info, int x, int y, int oam2, int animid, int layer); 33 | void SetSpriteAnimProcParameters(ProcPtr proc, int x, int y, int oam2); 34 | void EndSpriteAnimProc(ProcPtr proc); 35 | void EndEachSpriteAnimProc(void); 36 | bool SpriteAnimProcExists(void); 37 | 38 | #define ResetSpriteAnimClock(anim) \ 39 | (anim)->clock = 0; \ 40 | (anim)->clock_interval_q8 = 0x100 41 | 42 | #define FreezeSpriteAnim(anim) \ 43 | (anim)->clock = 0; \ 44 | (anim)->clock_interval_q8 = 0 45 | -------------------------------------------------------------------------------- /include/save_core.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #define MAX_CLEARED_PLAYTHROUGHS 12 6 | 7 | struct GlobalSaveInfo 8 | { 9 | /* 00 */ char name[8]; 10 | /* 08 */ u32 magic32; 11 | /* 0C */ u16 magic16; 12 | /* 0E */ u16 completed : 1; 13 | /* */ u16 completed_hard : 1; 14 | /* */ u16 completed_true : 1; 15 | /* */ u16 completed_true_hard : 1; 16 | /* */ u16 unk_0E_4 : 12; 17 | /* 10 */ u8 cleared_playthroughs[MAX_CLEARED_PLAYTHROUGHS]; 18 | /* 1C */ u16 checksum; 19 | /* 1E */ u8 last_game_save_id; 20 | /* 1F */ u8 last_suspend_slot; 21 | }; 22 | 23 | // up to checksum offset, aligned to 2 (nearest down) 24 | #define GLOBALSIZEINFO_SIZE_FOR_CHECKSUM (offsetof(struct GlobalSaveInfo, checksum) & ~1) 25 | 26 | struct SaveBlockInfo 27 | { 28 | /* 00 */ u32 magic32; 29 | /* 04 */ u16 magic16; 30 | /* 06 */ u8 kind; 31 | /* 08 */ u16 offset; 32 | /* 0A */ u16 size; 33 | /* 0C */ u32 checksum32; 34 | }; 35 | 36 | void SramInit(void); 37 | bool IsSramWorking(void); 38 | void WipeSram(void); 39 | u16 Checksum16(void const * data, int size); 40 | bool ReadGlobalSaveInfo(struct GlobalSaveInfo * info); 41 | void WriteGlobalSaveInfo(struct GlobalSaveInfo * info); 42 | void WriteGlobalSaveInfoNoChecksum(struct GlobalSaveInfo * info); 43 | void InitGlobalSaveInfo(void); 44 | void * SramOffsetToAddr(u16 off); 45 | u16 SramAddrToOffset(void * addr); 46 | bool ReadSaveBlockInfo(struct SaveBlockInfo * block_info, int save_id); 47 | void WriteSaveBlockInfo(struct SaveBlockInfo * block_info, int save_id); 48 | void * GetSaveWriteAddr(int save_id); 49 | void * GetSaveReadAddr(int save_id); 50 | void WriteChapterFlags(void * sram_dst); 51 | void WritePermanentFlags(void * sram_dst); 52 | void ReadChapterFlags(void const * sram_src); 53 | void ReadPermanentFlags(void const * sram_src); 54 | void WriteSupplyItems(void * sram_dst); 55 | void ReadSupplyItems(void const * sram_src); 56 | bool IsNotFirstPlaythrough(void); 57 | bool func_fe6_08084714(void); 58 | bool IsMultiArenaAvailable(void); 59 | bool IsNotFirstPlaythrough_2(void); 60 | bool CheckHasCompletedSave(void); 61 | -------------------------------------------------------------------------------- /include/armfunc.h: -------------------------------------------------------------------------------- 1 | #ifndef ARMFUNC_H 2 | #define ARMFUNC_H 3 | 4 | #include "prelude.h" 5 | 6 | extern u8 const ArmCodeStart[]; 7 | extern u8 const ArmCodeEnd[]; 8 | 9 | // armfunc 10 | void ColorFadeTick(void); 11 | void ClearOam(void * oam, int count); 12 | u32 Checksum32(void const * buf, int size); 13 | void TmApplyTsa(u16 * tm, u8 const * tsa, u16 tileref); 14 | void TmCopyRect(u16 const * src, u16 * dst, int width, int height); 15 | void TmFillRect(u16 * tm, int width, int height, u16 tileref); 16 | void DrawGlyph(u16 const * cvtLut, void * chr, u32 const * glyph, int offset); 17 | void DecodeString(char const * src, char * dst); 18 | void PutOamHi(int x, int y, u16 const * oam_list, int oam2); 19 | void PutOamLo(int x, int y, u16 const * oam_list, int oam2); 20 | void MapFloodCoreStep(int connect, int x, int y); 21 | void MapFloodCore(void); 22 | 23 | // ramfunc 24 | void InitRamFuncs(void); 25 | void DrawGlyphRam(u16 const * cvtLut, void * chr, u32 const * glyph, int offset); 26 | void DecodeStringRam(char const * src, char * dst); 27 | void PutOamHiRam(int x, int y, u16 const * oam_list, int oam2); 28 | void PutOamLoRam(int x, int y, u16 const * oam_list, int oam2); 29 | void MapFloodCoreStepRam(int connect, int x, int y); 30 | void MapFloodCoreRam(void); 31 | 32 | // linker stubs 33 | void ClearOam_thm(void * oam, int count); 34 | void TmApplyTsa_thm(u16 * tm, u8 const * tsa, u16 tileref); 35 | void TmFillRect_thm(u16 * tm, int width, int height, u16 tileref); 36 | void ColorFadeTick_thm(void); 37 | void TmCopyRect_thm(u16 const * src, u16 * dst, int width, int height); 38 | u32 Checksum32_thm(void const * buf, int size); 39 | 40 | // helper macros 41 | #define ColorFadeTick ColorFadeTick_thm 42 | #define ClearOam ClearOam_thm 43 | #define Checksum32 Checksum32_thm 44 | #define TmApplyTsa TmApplyTsa_thm 45 | #define TmCopyRect TmCopyRect_thm 46 | #define TmFillRect TmFillRect_thm 47 | #define DrawGlyph DrawGlyphRam 48 | #define DecodeString DecodeStringRam 49 | #define PutOamHi PutOamHiRam 50 | #define PutOamLo PutOamLoRam 51 | #define MapFloodCoreStep MapFloodCoreStepRam 52 | #define MapFloodCore MapFloodCoreRam 53 | 54 | #endif // ARMFUNC_H 55 | -------------------------------------------------------------------------------- /data/chapters/chapter23/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 086694D8 4 | EventListScr CONST_DATA EventListScr_Unk_086694D8[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08672560, 1, 0, FACTION_BLUE) 7 | EvtListTurn(FLAG_CHAPTER23_4, EventScr_Unk_08672638, 1, 0, FACTION_RED) 8 | EvtListEnd 9 | }; 10 | 11 | // EventListScr @ 086694F4 12 | EventListScr CONST_DATA EventListScr_Unk_086694F4[] = 13 | { 14 | EvtListTalk(FLAG_CHAPTER23_5, EventScr_Unk_0867276C, PID_FIR, PID_KAREL) 15 | EvtListTalk(FLAG_CHAPTER23_5, EventScr_Unk_0867276C, PID_KAREL, PID_FIR) 16 | EvtListTalk(FLAG_CHAPTER23_6, EventScr_Unk_08672788, PID_BARTRE, PID_KAREL) 17 | EvtListTalk(FLAG_CHAPTER23_6, EventScr_Unk_08672788, PID_KAREL, PID_BARTRE) 18 | EvtListTalk(FLAG_CHAPTER23_7, EventScr_Unk_086727A4, PID_ROY, PID_KAREL) 19 | EvtListTalk(FLAG_CHAPTER23_7, EventScr_Unk_086727A4, PID_KAREL, PID_ROY) 20 | EvtListEnd 21 | }; 22 | 23 | // EventListScr @ 08669540 24 | EventListScr CONST_DATA EventListScr_Unk_08669540[] = 25 | { 26 | EvtListShop(0, ShopItems_Unk_0866A9EC, 16, 26, TILE_COMMAND_ARMORY) 27 | EvtListShop(0, ShopItems_Unk_0866AA12, 17, 25, TILE_COMMAND_ARMORY) 28 | EvtListShop(0, ShopItems_Unk_0866AA2A, 0, 6, TILE_COMMAND_VENDOR) 29 | EvtListShop(0, ShopItems_Unk_0866AA3C, 15, 26, TILE_COMMAND_VENDOR) 30 | EvtListTile(0, EventScr_Unk_08672684, 22, 23, TILE_COMMAND_VISIT) 31 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 5, 1, TILE_COMMAND_SEIZE) 32 | EvtListEnd 33 | }; 34 | 35 | // EventListScr @ 0866958C 36 | EventListScr CONST_DATA EventListScr_Unk_0866958C[] = 37 | { 38 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 39 | EvtListEnd 40 | }; 41 | 42 | // ChapterEventInfo @ 0866959C 43 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866959C = 44 | { 45 | .event_list_turn = EventListScr_Unk_086694D8, 46 | .event_list_talk = EventListScr_Unk_086694F4, 47 | .event_list_tile = EventListScr_Unk_08669540, 48 | .event_list_move = EventListScr_Unk_0866958C, 49 | .units_red = UnitInfo_Unk_086815C0, 50 | .units_blue = UnitInfo_Unk_086814B0, 51 | .event_script_victory = EventScr_Unk_086727C0, 52 | }; 53 | -------------------------------------------------------------------------------- /tools/scripts/extract-bgs.py: -------------------------------------------------------------------------------- 1 | 2 | import sys, os 3 | 4 | def read_int(f, count, signed = False): 5 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 6 | 7 | def main(args): 8 | try: 9 | rom = args[0] 10 | offset = int(args[1], base=0) & 0x1FFFFFF 11 | count = int(args[2], base=0) 12 | 13 | except IndexError: 14 | sys.exit("Usage: {} ".format(sys.argv[0])) 15 | 16 | # background entries 17 | entries = [] 18 | 19 | with open(rom, 'rb') as f: 20 | for i in range(count): 21 | f.seek(offset + i*12) 22 | 23 | imgAddr = read_int(f, 4) 24 | tsaAddr = read_int(f, 4) 25 | palAddr = read_int(f, 4) 26 | 27 | entries.append((imgAddr, tsaAddr, palAddr)) 28 | 29 | # address to name dict 30 | names = {} 31 | 32 | for imgAddr, tsaAddr, palAddr in entries: 33 | names[imgAddr] = 'Img_Background_{:08X}'.format(imgAddr) 34 | names[tsaAddr] = 'Tsa_Background_{:08X}'.format(tsaAddr) 35 | names[palAddr] = 'Pal_Background_{:08X}'.format(palAddr) 36 | 37 | # sorted address list 38 | addresses = sorted(names.keys()) 39 | 40 | print('@?ASM') 41 | print('') 42 | 43 | for i in range(len(addresses)): 44 | address = addresses[i] 45 | addressNext = addresses[i+1] if i+1 < len(addresses) else 0xFFFFFFFF 46 | name = names[address] 47 | 48 | print('\t.global {}'.format(name)) 49 | print('{}: @ {:08X}'.format(name, address)) 50 | print('\t.incbin "fe6-base.gba", 0x{0:X}, (0x{1:X} - 0x{0:X})'.format( 51 | address & 0x1FFFFFF, addressNext & 0x1FFFFFF)) 52 | print('') 53 | 54 | print('// C') 55 | print('') 56 | 57 | for address in addresses: 58 | typename = 'u16' if names[address].startswith('Pal') else 'u8' 59 | 60 | print('extern {} const {}[];'.format(typename, names[address])) 61 | 62 | print('') 63 | 64 | print('struct BackgroundEnt CONST_DATA gBackgroundTable[] =') 65 | print('{') 66 | 67 | for i, (imgAddr, tsaAddr, palAddr) in enumerate(entries): 68 | print(' [BACKGROUND_{}] = {{ {}, {}, {} }},'.format(i, names[imgAddr], names[tsaAddr], names[palAddr])) 69 | 70 | print('};') 71 | print('') 72 | 73 | if __name__ == '__main__': 74 | main(sys.argv[1:]) 75 | -------------------------------------------------------------------------------- /src/ramfunc.c: -------------------------------------------------------------------------------- 1 | #include "armfunc.h" 2 | 3 | #undef DrawGlyph 4 | #undef DecodeString 5 | #undef PutOamHi 6 | #undef PutOamLo 7 | #undef MapFloodCoreStep 8 | #undef MapFloodCore 9 | 10 | extern u8 RamFuncArea[]; 11 | 12 | extern void (* DrawGlyphRamFunc)(u16 const * cvtLut, void * chr, u32 const * glyph, int offset); 13 | extern void (* DecodeStringRamFunc)(char const * src, char * dst); 14 | extern void (* PutOamHiRamFunc)(int x, int y, u16 const * oam_list, int oam2); 15 | extern void (* PutOamLoRamFunc)(int x, int y, u16 const * oam_list, int oam2); 16 | extern void (* MapFloodCoreStepRamFunc)(); 17 | extern void (* MapFloodCoreRamFunc)(void); 18 | 19 | void InitRamFuncs(void) 20 | { 21 | int size = ArmCodeEnd - ArmCodeStart; 22 | 23 | CpuCopy16(ArmCodeStart, RamFuncArea, size); 24 | 25 | DrawGlyphRamFunc = (void *) RamFuncArea + (((u8 *) (void *) DrawGlyph) - ArmCodeStart); 26 | DecodeStringRamFunc = (void *) RamFuncArea + (((u8 *) (void *) DecodeString) - ArmCodeStart); 27 | PutOamHiRamFunc = (void *) RamFuncArea + (((u8 *) (void *) PutOamHi) - ArmCodeStart); 28 | PutOamLoRamFunc = (void *) RamFuncArea + (((u8 *) (void *) PutOamLo) - ArmCodeStart); 29 | MapFloodCoreStepRamFunc = (void *) RamFuncArea + (((u8 *) (void *) MapFloodCoreStep) - ArmCodeStart); 30 | MapFloodCoreRamFunc = (void *) RamFuncArea + (((u8 *) (void *) MapFloodCore) - ArmCodeStart); 31 | } 32 | 33 | void DrawGlyphRam(u16 const * cvtLut, void * chr, u32 const * glyph, int offset) 34 | { 35 | DrawGlyphRamFunc(cvtLut, chr, glyph, offset); 36 | } 37 | 38 | void DecodeStringRam(char const * src, char * dst) 39 | { 40 | DecodeStringRamFunc(src, dst); 41 | } 42 | 43 | void PutOamHiRam(int x, int y, u16 const * oam_list, int oam2) 44 | { 45 | PutOamHiRamFunc(x, y, oam_list, oam2); 46 | } 47 | 48 | void PutOamLoRam(int x, int y, u16 const * oam_list, int oam2) 49 | { 50 | PutOamLoRamFunc(x, y, oam_list, oam2); 51 | } 52 | 53 | void MapFloodCoreStepRam(int connect, int x, int y) 54 | { 55 | MapFloodCoreStepRamFunc(connect, x, y); 56 | } 57 | 58 | void MapFloodCoreRam(void) 59 | { 60 | MapFloodCoreRamFunc(); 61 | } 62 | -------------------------------------------------------------------------------- /include/action.h: -------------------------------------------------------------------------------- 1 | #ifndef ACTION_H 2 | #define ACTION_H 3 | 4 | #include "prelude.h" 5 | 6 | // valid IDs for Action::id 7 | enum 8 | { 9 | ACTION_NONE, 10 | ACTION_WAIT = 0x01, 11 | ACTION_COMBAT = 0x02, 12 | ACTION_STAFF = 0x03, 13 | ACTION_REFRESH = 0x04, 14 | // 05? 15 | ACTION_STEAL = 0x06, 16 | ACTION_RESCUE = 0x07, 17 | ACTION_DROP = 0x08, 18 | ACTION_TAKE = 0x09, 19 | ACTION_GIVE = 0x0A, 20 | // 0B? 21 | ACTION_TALK = 0x0C, 22 | ACTION_SUPPORT = 0x0D, 23 | ACTION_VISIT = 0x0E, 24 | ACTION_SEIZE = 0x0F, 25 | ACTION_DOOR = 0x10, 26 | // 11? 27 | ACTION_CHEST = 0x12, 28 | // ACTION_SHOPPED, 29 | // ACTION_ARENA, 30 | ACTION_16 = 0x16, 31 | ACTION_USEITEM = 0x17, 32 | ACTION_TRADED = 0x18, 33 | ACTION_TRADED_SUPPLY = 0x19, 34 | ACTION_TRADED_NOCHANGES = 0x1A, 35 | ACTION_TRAPPED = 0x1B, 36 | ACTION_1C = 0x1C, 37 | }; 38 | 39 | // valid values for Action::suspend_point 40 | enum 41 | { 42 | SUSPEND_POINT_PLAYER_PHASE, 43 | SUSPEND_POINT_DURING_ACTION, 44 | SUSPEND_POINT_AI_PHASE, 45 | SUSPEND_POINT_BERSERK_PHASE, 46 | SUSPEND_POINT_DURING_ARENA, 47 | SUSPEND_POINT_5, 48 | SUSPEND_POINT_6, 49 | SUSPEND_POINT_7, 50 | SUSPEND_POINT_8, 51 | SUSPEND_POINT_CHANGE_PHASE, 52 | }; 53 | 54 | struct Action 55 | { 56 | /* 00 */ u16 action_rand_st[3]; 57 | /* 06 */ u16 arena_begin_rand_st[3]; 58 | /* 0C */ u8 instigator; 59 | /* 0D */ u8 target; 60 | /* 0E */ u8 x_move, y_move; 61 | /* 10 */ u8 move_count; 62 | /* 11 */ u8 id; 63 | /* 12 */ u8 item_slot; 64 | /* 13 */ u8 x_target, y_target; 65 | /* 15 */ u8 extra; 66 | /* 16 */ u8 suspend_point; 67 | }; 68 | 69 | extern struct Action gAction; 70 | 71 | void SaveActionRand(void); 72 | void RestoreActionRand(void); 73 | bool DoAction(ProcPtr proc); 74 | 75 | void DropRescueOnDeath(ProcPtr parent, struct Unit * unit); 76 | void KillUnitOnCombatDeath(struct Unit * unit, struct Unit * opponent); 77 | void KillUnitOnArenaDeath(struct Unit * unit); 78 | void func_fe6_0802A7F4(void); 79 | 80 | extern struct ProcScr CONST_DATA ProcScr_CombatAction[]; 81 | 82 | #endif // ACTION_H 83 | -------------------------------------------------------------------------------- /tools/scripts/dump-ai-attack-config.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | def read_int(f, count, signed = False): 5 | return int.from_bytes(f.read(count), byteorder = 'little', signed = signed) 6 | 7 | def main(args): 8 | try: 9 | rom_name = args[0] 10 | offset = 0x1FFFFFF & int(args[1], base = 0) 11 | count = int(args[2], base = 0) 12 | 13 | except IndexError: 14 | sys.exit(f"Usage: {sys.argv[0]} ROM OFFSET COUNT") 15 | 16 | #with open(elf_name, 'rb') as f: 17 | # syms = { addr: name for addr, name in symbols.from_elf(f) } 18 | 19 | print(f"struct AiCombatScoreCoefficients const gUnk_{offset + 0x08000000:08X}[] =") 20 | print("{") 21 | 22 | with open(rom_name, 'rb') as f: 23 | f.seek(offset) 24 | 25 | for i in range(count): 26 | val0 = read_int(f, 1) 27 | val1 = read_int(f, 1) 28 | val2 = read_int(f, 1) 29 | val3 = read_int(f, 1) 30 | val4 = read_int(f, 1) 31 | val5 = read_int(f, 1) 32 | val6 = read_int(f, 1) 33 | val7 = read_int(f, 1) 34 | 35 | arry = [] 36 | 37 | for _ in range(12): 38 | arry.append(read_int(f, 1)) 39 | 40 | print(f" [{i}] =") 41 | print(f" {{") 42 | print(f" .unk_00 = {val0},") 43 | print(f" .unk_01 = {val1},") 44 | print(f" .unk_02 = {val2},") 45 | print(f" .unk_03 = {val3},") 46 | print(f" .unk_04 = {val4},") 47 | print(f" .unk_05 = {val5},") 48 | print(f" .unk_06 = {val6},") 49 | print(f" .unk_07 = {val7},") 50 | print(f" .unk_08 =") 51 | print(f" {{") 52 | 53 | for i, val in enumerate(arry): 54 | if val != 0: 55 | print(f" [{i}] = {val},") 56 | 57 | print(f" }}") 58 | 59 | print(f" }},") 60 | print(f"") 61 | 62 | print("};") 63 | 64 | print(f"// ends at {f.tell() + 0x08000000:08X}") 65 | 66 | if __name__ == '__main__': 67 | main(sys.argv[1:]) 68 | -------------------------------------------------------------------------------- /data/chapters/chapter17_i/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08668CB0 4 | EventListScr CONST_DATA EventListScr_Unk_08668CB0[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08670BF0, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_08670D34, 1, 0, FACTION_RED) 8 | EvtListTurn(0, EventScr_Unk_08670D3C, 2, 0, FACTION_BLUE) 9 | EvtListTurn(0, EventScr_Unk_08670D44, 6, 0, FACTION_BLUE) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867F3A4, 8, 11, FACTION_RED) 11 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867F3D4, 10, 15, FACTION_RED) 12 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867F404, 8, 11, FACTION_RED) 13 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_0867F3A4, 12, 15, FACTION_RED) 14 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_0867F3D4, 8, 9, FACTION_RED) 15 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_0867F404, 12, 15, FACTION_RED) 16 | EvtListEnd 17 | }; 18 | 19 | // EventListScr @ 08668D2C 20 | EventListScr CONST_DATA EventListScr_Unk_08668D2C[] = 21 | { 22 | EvtListEnd 23 | }; 24 | 25 | // EventListScr @ 08668D30 26 | EventListScr CONST_DATA EventListScr_Unk_08668D30[] = 27 | { 28 | EvtListTileMapChange(0, EventScr_Unk_08670DB4, 2, 12, TILE_COMMAND_VISIT) 29 | EvtListTile(0, EVENT_NOSCRIPT, 2, 11, TILE_COMMAND_PILLAGE) 30 | EvtListShop(0, ShopItems_Unk_0866A93A, 6, 8, TILE_COMMAND_ARMORY) 31 | EvtListTile(0, EventScr_Unk_08670DFC, 8, 13, TILE_COMMAND_VISIT) 32 | EvtListTile(0, EventScr_Unk_08670E38, 8, 14, TILE_COMMAND_VISIT) 33 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 29, 3, TILE_COMMAND_SEIZE) 34 | EvtListEnd 35 | }; 36 | 37 | // EventListScr @ 08668D7C 38 | EventListScr CONST_DATA EventListScr_Unk_08668D7C[] = 39 | { 40 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 41 | EvtListEnd 42 | }; 43 | 44 | // ChapterEventInfo @ 08668D8C 45 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_08668D8C = 46 | { 47 | .event_list_turn = EventListScr_Unk_08668CB0, 48 | .event_list_talk = EventListScr_Unk_08668D2C, 49 | .event_list_tile = EventListScr_Unk_08668D30, 50 | .event_list_move = EventListScr_Unk_08668D7C, 51 | .units_red = UnitInfo_Unk_0867F1D4, 52 | .units_blue = UnitInfo_Unk_0867F0E4, 53 | .event_script_victory = EventScr_Unk_08670E74, 54 | }; 55 | -------------------------------------------------------------------------------- /data/chapters/trial_d/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 0866A680 4 | EventListScr CONST_DATA EventListScr_Unk_0866A680[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_086760FC, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687184, 3, 0, FACTION_RED) 8 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687184, 6, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687184, 9, 0, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687184, 12, 0, FACTION_RED) 11 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687204, 4, 0, FACTION_RED) 12 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687204, 7, 0, FACTION_RED) 13 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687204, 10, 0, FACTION_RED) 14 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687204, 13, 0, FACTION_RED) 15 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687274, 5, 0, FACTION_RED) 16 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687274, 8, 0, FACTION_RED) 17 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687274, 11, 0, FACTION_RED) 18 | EvtListTurn(0, EventScr_LoadUnits_Unk_08687274, 14, 0, FACTION_RED) 19 | EvtListEnd 20 | }; 21 | 22 | // EventListScr @ 0866A720 23 | EventListScr CONST_DATA EventListScr_Unk_0866A720[] = 24 | { 25 | EvtListEnd 26 | }; 27 | 28 | // EventListScr @ 0866A724 29 | EventListScr CONST_DATA EventListScr_Unk_0866A724[] = 30 | { 31 | EvtListEnd 32 | }; 33 | 34 | // EventListScr @ 0866A728 35 | EventListScr CONST_DATA EventListScr_Unk_0866A728[] = 36 | { 37 | EvtListFunc(FLAG_CHAPTER_BASE, EventScr_LoadUnits_Unk_086872E4, func_fe6_0806C2F8) 38 | EvtListFunc(FLAG_3, EventScr_Unk_08676104, func_fe6_0806BF14) 39 | EvtListFlag(FLAG_3, EventScr_Unk_08676128, FLAG_101) 40 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 41 | EvtListEnd 42 | }; 43 | 44 | // ChapterEventInfo @ 0866A75C 45 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_0866A75C = 46 | { 47 | .event_list_turn = EventListScr_Unk_0866A680, 48 | .event_list_talk = EventListScr_Unk_0866A720, 49 | .event_list_tile = EventListScr_Unk_0866A724, 50 | .event_list_move = EventListScr_Unk_0866A728, 51 | .units_red = UnitInfo_Unk_08686FD4, 52 | .units_blue = UnitInfo_Unk_08686F24, 53 | .event_script_victory = EventScr_Unk_08676104, 54 | }; 55 | -------------------------------------------------------------------------------- /data/chapters/chapter15/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08668A18 4 | EventListScr CONST_DATA EventListScr_Unk_08668A18[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08670108, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_0867023C, 3, 0, FACTION_RED) 8 | EvtListTurn(0, EventScr_Unk_0867026C, 10, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_Unk_086702D4, 12, 15, FACTION_RED) 10 | EvtListEnd 11 | }; 12 | 13 | // EventListScr @ 08668A4C 14 | EventListScr CONST_DATA EventListScr_Unk_08668A4C[] = 15 | { 16 | EvtListTalk(FLAG_CHAPTER15_5, EventScr_Unk_086702FC, PID_ELFFIN, PID_PERCEVAL) 17 | EvtListTalk(FLAG_CHAPTER15_5, EventScr_Unk_08670348, PID_LARUM, PID_PERCEVAL) 18 | EvtListTalk(FLAG_CHAPTER15_7, EventScr_Unk_08670394, PID_LILINA, PID_GARRET) 19 | EvtListFunc(FLAG_CHAPTER15_8, EventScr_Unk_086703C0, func_fe6_0806BC20) 20 | EvtListEnd 21 | }; 22 | 23 | // EventListScr @ 08668A80 24 | EventListScr CONST_DATA EventListScr_Unk_08668A80[] = 25 | { 26 | EvtListTileMapChange(0, EventScr_Unk_086703DC, 8, 22, TILE_COMMAND_VISIT) 27 | EvtListTile(0, EVENT_NOSCRIPT, 8, 21, TILE_COMMAND_PILLAGE) 28 | EvtListTileMapChange(0, EventScr_Unk_08670424, 25, 15, TILE_COMMAND_VISIT) 29 | EvtListTile(0, EVENT_NOSCRIPT, 25, 14, TILE_COMMAND_PILLAGE) 30 | EvtListShop(0, ShopItems_Unk_0866A918, 26, 17, TILE_COMMAND_VENDOR) 31 | EvtListTile(0, EventScr_Unk_0867046C, 19, 23, TILE_COMMAND_VISIT) 32 | EvtListTile(0, EventScr_Unk_086704A8, 23, 19, TILE_COMMAND_VISIT) 33 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 16, 9, TILE_COMMAND_SEIZE) 34 | EvtListEnd 35 | }; 36 | 37 | // EventListScr @ 08668AE4 38 | EventListScr CONST_DATA EventListScr_Unk_08668AE4[] = 39 | { 40 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 41 | EvtListEnd 42 | }; 43 | 44 | // ChapterEventInfo @ 08668AF4 45 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_08668AF4 = 46 | { 47 | .event_list_turn = EventListScr_Unk_08668A18, 48 | .event_list_talk = EventListScr_Unk_08668A4C, 49 | .event_list_tile = EventListScr_Unk_08668A80, 50 | .event_list_move = EventListScr_Unk_08668AE4, 51 | .units_red = UnitInfo_Unk_0867E800, 52 | .units_blue = UnitInfo_Unk_0867E710, 53 | .event_script_victory = EventScr_Unk_086704E4, 54 | }; 55 | -------------------------------------------------------------------------------- /data/chapters/chapter17_s/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08669A70 4 | EventListScr CONST_DATA EventListScr_Unk_08669A70[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08673CE8, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_08673DBC, 2, 0, FACTION_BLUE) 8 | EvtListTurn(0, EventScr_LoadUnits_Unk_08682F50, 3, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_Unk_08682F50, 6, 0, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_08682F50, 9, 0, FACTION_RED) 11 | EvtListTurn(0, EventScr_LoadUnits_Unk_08682F70, 6, 8, FACTION_RED) 12 | EvtListTurn(0, EventScr_LoadUnits_Unk_08682FA0, 12, 15, FACTION_RED) 13 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_08682F70, 16, 20, FACTION_RED) 14 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_08682FA0, 11, 15, FACTION_RED) 15 | EvtListEnd 16 | }; 17 | 18 | // EventListScr @ 08669AE0 19 | EventListScr CONST_DATA EventListScr_Unk_08669AE0[] = 20 | { 21 | EvtListEnd 22 | }; 23 | 24 | // EventListScr @ 08669AE4 25 | EventListScr CONST_DATA EventListScr_Unk_08669AE4[] = 26 | { 27 | EvtListTileMapChange(0, EventScr_Unk_08673DC4, 2, 17, TILE_COMMAND_VISIT) 28 | EvtListTile(0, EVENT_NOSCRIPT, 2, 16, TILE_COMMAND_PILLAGE) 29 | EvtListTileMapChange(0, EventScr_Unk_08673E0C, 30, 2, TILE_COMMAND_VISIT) 30 | EvtListTile(0, EVENT_NOSCRIPT, 30, 1, TILE_COMMAND_PILLAGE) 31 | EvtListShop(0, ShopItems_Unk_0866AA76, 3, 19, TILE_COMMAND_ARMORY) 32 | EvtListTile(0, EventScr_Unk_08673E54, 1, 18, TILE_COMMAND_VISIT) 33 | EvtListTile(0, EventScr_Unk_08673E90, 6, 15, TILE_COMMAND_VISIT) 34 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 29, 18, TILE_COMMAND_SEIZE) 35 | EvtListEnd 36 | }; 37 | 38 | // EventListScr @ 08669B48 39 | EventListScr CONST_DATA EventListScr_Unk_08669B48[] = 40 | { 41 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 42 | EvtListEnd 43 | }; 44 | 45 | // ChapterEventInfo @ 08669B58 46 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_08669B58 = 47 | { 48 | .event_list_turn = EventListScr_Unk_08669A70, 49 | .event_list_talk = EventListScr_Unk_08669AE0, 50 | .event_list_tile = EventListScr_Unk_08669AE4, 51 | .event_list_move = EventListScr_Unk_08669B48, 52 | .units_red = UnitInfo_Unk_08682D60, 53 | .units_blue = UnitInfo_Unk_08682C70, 54 | .event_script_victory = EventScr_Unk_08673ECC, 55 | }; 56 | -------------------------------------------------------------------------------- /tools/scripts/datasplit.py: -------------------------------------------------------------------------------- 1 | import sys, re 2 | 3 | def main(args): 4 | try: 5 | splitfile_path = args[1] 6 | 7 | except IndexError: 8 | sys.exit(f"Usage: {args[0]} SPLITFILE") 9 | 10 | offmap = {} 11 | 12 | start_off = -1 13 | end_off = -1 14 | 15 | section = ".data" 16 | 17 | with open(splitfile_path, 'r') as f: 18 | for line in f.readlines(): 19 | line = line.strip() 20 | 21 | if len(line) == 0 or line[0] == '#': 22 | continue 23 | 24 | m = re.match(r'(?P[0-9A-Fa-f]{8})\s+(?P\.?[A-Za-z_][A-Za-z0-9_]*)', line) 25 | 26 | if m == None: 27 | sys.exit(f"ERROR: parse error at `{line}`") 28 | 29 | addr = m.group('addr') 30 | name = m.group('name') 31 | 32 | off = int(addr, base = 16) & 0x01FFFFFF 33 | 34 | if name == '.beg': 35 | start_off = off 36 | elif name == '.end': 37 | end_off = off 38 | elif name == '.rodata': 39 | section = '.section .rodata' 40 | elif name == '.data': 41 | section = '.data' 42 | elif name[0] == '.': 43 | sys.exit(f"ERROR: parse error at `{line}`") 44 | else: 45 | offmap[off] = name 46 | 47 | off_order = [k for k in offmap.keys()] 48 | off_order.sort() 49 | 50 | for off in off_order: 51 | if off < start_off or off > end_off: 52 | sys.exit(f"ERROR: {offmap[off]} outside of file bounds") 53 | 54 | last_off = start_off 55 | 56 | print(f" {section}") 57 | 58 | for off in off_order: 59 | if last_off != off: 60 | if off == off_order[0]: 61 | print() 62 | 63 | print(f' .incbin "fe6-base.gba", 0x{last_off:06X}, (0x{off:06X} - 0x{last_off:06X}) @ length: {off - last_off:04X}') 64 | last_off = off 65 | 66 | name = offmap[off] 67 | 68 | print() 69 | print(f" .global {name}") 70 | print(f"{name}: @ {off + 0x08000000:08X}") 71 | 72 | if last_off != end_off: 73 | print(f' .incbin "fe6-base.gba", 0x{last_off:06X}, (0x{end_off:06X} - 0x{last_off:06X}) @ length: {end_off - last_off:04X}') 74 | 75 | if __name__ == '__main__': 76 | main(sys.argv) 77 | -------------------------------------------------------------------------------- /data/chapters/chapter3/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | EventListScr CONST_DATA EventListScr_Chapter3_Turn[] = 4 | { 5 | EvtListTurn(0, EventScr_Chapter3_Opening, 1, 0, FACTION_BLUE) 6 | EvtListTurn(0, EventScr_Chapter3_ZephielScene, 3, 0, FACTION_RED) 7 | EvtListFlag(FLAG_CHAPTER3_CAVALIERSPOSTLUGH, EventScr_LoadUnits_Chapter3_CavalierReinforcements, FLAG_CHAPTER3_GOTLUGH) 8 | EvtListTurn(FLAG_CHAPTER3_ORPHANAGECUTSCENE, EventScr_Chapter3_OrphanageCutscene, 2, 0, FACTION_BLUE) 9 | EvtListTurnHard(0, EventScr_LoadUnits_Chapter3_CavalierReinforcements, 5, 0, FACTION_RED) 10 | EvtListTurnHard(0, EventScr_LoadUnits_Chapter3_CavalierReinforcements, 10, 0, FACTION_RED) 11 | EvtListTurnHard(0, EventScr_LoadUnits_Chapter3_CavalierReinforcements, 15, 0, FACTION_RED) 12 | EvtListEnd 13 | }; 14 | 15 | EventListScr CONST_DATA EventListScr_Chapter3_Talk[] = 16 | { 17 | EvtListTalk(FLAG_CHAPTER3_CHADLUGHTALK, EventScr_Chapter3_ChadLughTalk, PID_CHAD, PID_LUGH) 18 | EvtListTalk(FLAG_CHAPTER3_CHADLUGHTALK, EventScr_Chapter3_ChadLughTalk, PID_LUGH, PID_CHAD) 19 | EvtListEnd 20 | }; 21 | 22 | EventListScr CONST_DATA EventListScr_Chapter3_Tile[] = 23 | { 24 | EvtListTileMapChange(FLAG_CHAPTER3_GOTLUGH, EventScr_Chapter3_TopVillage, 3, 3, TILE_COMMAND_VISIT) 25 | EvtListTile(FLAG_CHAPTER3_GOTLUGH, EVENT_NOSCRIPT, 3, 2, TILE_COMMAND_PILLAGE) 26 | EvtListTileMapChange(0, EventScr_Chapter3_BottomVillage, 19, 19, TILE_COMMAND_VISIT) 27 | EvtListTile(0, EVENT_NOSCRIPT, 19, 18, TILE_COMMAND_PILLAGE) 28 | EvtListChest(0, IID_HALBERD, 0, 20, 11, TILE_COMMAND_CHEST) 29 | EvtListChest(0, IID_GOLD, 3000, 22, 12, TILE_COMMAND_CHEST) 30 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 19, 4, TILE_COMMAND_SEIZE) 31 | EvtListEnd 32 | }; 33 | 34 | EventListScr CONST_DATA EventListScr_Chapter3_Move[] = 35 | { 36 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 37 | EvtListEnd 38 | }; 39 | 40 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Chapter3 = 41 | { 42 | .event_list_turn = EventListScr_Chapter3_Turn, 43 | .event_list_talk = EventListScr_Chapter3_Talk, 44 | .event_list_tile = EventListScr_Chapter3_Tile, 45 | .event_list_move = EventListScr_Chapter3_Move, 46 | .units_red = UnitInfo_Chapter3_Red, 47 | .units_blue = UnitInfo_Chapter3_Blue, 48 | .event_script_victory = EventScr_Chapter3_Victory, 49 | }; 50 | -------------------------------------------------------------------------------- /include/minimap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | #include "proc.h" 6 | 7 | struct MinimapProc 8 | { 9 | /* 00 */ PROC_HEADER; 10 | /* 29 */ STRUCT_PAD(0x29, 0x2C); 11 | /* 2C */ i32 x_camera_speed; 12 | /* 30 */ i32 y_camera_speed; 13 | /* 34 */ i32 x_region_radius; 14 | /* 38 */ i32 y_region_radius; 15 | /* 3C */ i32 x_screen; 16 | /* 40 */ i32 y_screen; 17 | /* 3C */ STRUCT_PAD(0x44, 0x4A); 18 | /* 4A */ i16 camera_moved; 19 | /* 4C */ i16 anim_clock; 20 | }; 21 | 22 | int GetMinimapConnectKindAt(int x, int y); 23 | int GetMinimapRiverKindAt(int x, int y); 24 | int GetMinimapCliffKindAt(int x, int y); 25 | int GetMinimapStairTileAt(int x, int y); 26 | int GetMinimapDoorTileAt(int x, int y); 27 | int GetMinimapBridgeKindAt(int x, int y); 28 | int GetMinimapTileAt(int x, int y); 29 | u16 * GetMinimapTerrainCellAt(int x, int y); 30 | u16 * GetMinimapObjectCellAt(int x, int y); 31 | void DrawMinimapInternal(u16 * vram, int pal_num); 32 | void Minimap_Init(struct MinimapProc * proc); 33 | void MinimapOnHBlank(void); 34 | void InitMinimapWindowBuffers(void); 35 | void Minimap_InitOpenAnim(struct MinimapProc * proc); 36 | void Minimap_OpenAnim(struct MinimapProc * proc); 37 | void Minimap_InitCloseAnim(struct MinimapProc * proc); 38 | void Minimap_CloseAnim(struct MinimapProc * proc); 39 | void ApplyMinimapGraphics(int pal_num); 40 | void InitMinimapFlashPalette(void); 41 | void Minimap_ApplyFlashPalette(struct MinimapProc * proc); 42 | void Minimap_ApplyViewportFlashColor(struct MinimapProc * proc); 43 | void Minimap_PutViewport(struct MinimapProc * proc); 44 | void Minimap_AdjustDisplay(struct MinimapProc * proc); 45 | void Minimap_HandleMoveInput(struct MinimapProc * proc); 46 | void Minimap_InitProcVars(struct MinimapProc * proc); 47 | void Minimap_Fini(struct MinimapProc * proc); 48 | void Minimap_Main(struct MinimapProc * proc); 49 | 50 | void StartMinimap(void); 51 | void DrawMinimap(int chapter, void * vram, int pal_num); 52 | 53 | extern i16 gMinimapWinBuf[320 * 2]; 54 | extern i16 * gMinimapFrontWinBuf; 55 | extern i16 * gMinimapBackWinBuf; 56 | extern i16 * gMinimapDisplayedWinBuf; 57 | extern u16 * gMinimapObjectFlashPal; 58 | 59 | extern u8 const gUnk_083273E4[]; 60 | extern u16 const gUnk_083277BC[]; 61 | extern u16 const gUnk_083277DC[]; 62 | 63 | extern struct ProcScr CONST_DATA ProcScr_Minimap[]; 64 | -------------------------------------------------------------------------------- /include/banim_ekrdragon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | #include "banim_sprite.h" 5 | 6 | enum ekr_dragon_status_type_bitfile { 7 | EDRAGON_TYPE_0 = 1 << 0, 8 | EDRAGON_TYPE_1 = 1 << 1, 9 | EDRAGON_TYPE_2 = 1 << 2, 10 | EDRAGON_TYPE_3 = 1 << 3, 11 | EDRAGON_TYPE_4 = 1 << 4, 12 | }; 13 | 14 | void func_fe6_0805884C(void); 15 | bool EkrDragonIntroDone(struct BaSprite * anim); 16 | void TriggerEkrDragonEnding(struct BaSprite * anim); 17 | bool CheckEkrDragonEndingDone(struct BaSprite * anim); 18 | u32 GetEkrDragonStatusType(void); /* Different form FE8, this is a bitfile rather than enum */ 19 | u32 GetBanimDragonStatusType(void); 20 | int CheckEkrDragonDead1(void); 21 | // func_fe6_080589C4 22 | // func_fe6_080589FC 23 | u16 * GetEkrDragonStatusIdx(struct BaSprite * anim); 24 | // func_fe6_08058A1C 25 | // func_fe6_08058A34 26 | // func_fe6_08058A50 27 | // func_fe6_08058A80 28 | // func_fe6_08058ACC 29 | // func_fe6_08058B84 30 | // func_fe6_08058C3C 31 | // func_fe6_08058CEC 32 | // func_fe6_08058D08 33 | // func_fe6_08058D34 34 | // func_fe6_08058E24 35 | // func_fe6_08058E58 36 | // func_fe6_08058E90 37 | // func_fe6_08058EC8 38 | // func_fe6_08058F00 39 | void InitEkrDragonStatus(void); 40 | // func_fe6_08058F38 41 | // func_fe6_08058F60 42 | // func_fe6_08058FA8 43 | // func_fe6_08059018 44 | // func_fe6_08059078 45 | // func_fe6_08059090 46 | void func_fe6_080590B8(struct BaSprite * anim); 47 | // func_fe6_080590FC 48 | // func_fe6_08059144 49 | // func_fe6_080591AC 50 | // func_fe6_080591CC 51 | // func_fe6_080592D0 52 | // func_fe6_08059328 53 | // func_fe6_080593D4 54 | // func_fe6_08059400 55 | // func_fe6_08059418 56 | // func_fe6_0805946C 57 | // func_fe6_080594CC 58 | // func_fe6_08059578 59 | // func_fe6_080595EC 60 | // func_fe6_08059614 61 | // func_fe6_0805966C 62 | // func_fe6_08059690 63 | // func_fe6_08059730 64 | // func_fe6_08059758 65 | // func_fe6_0805979C 66 | // func_fe6_080597E0 67 | // func_fe6_08059824 68 | // func_fe6_08059868 69 | // func_fe6_080598AC 70 | // func_fe6_080598F0 71 | // func_fe6_08059928 72 | void func_fe6_080599D0(struct BaSprite * anim); 73 | // func_fe6_08059A28 74 | // func_fe6_08059A44 75 | // func_fe6_08059AD0 76 | // func_fe6_08059B78 77 | // func_fe6_08059BE4 78 | // func_fe6_08059C38 79 | // func_fe6_08059C54 80 | // func_fe6_08059C78 81 | // func_fe6_08059D34 82 | void func_fe6_08059D8C(struct BaSprite * anim); 83 | -------------------------------------------------------------------------------- /include/menuinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | #include "menu.h" 5 | #include "mapselect.h" 6 | 7 | extern struct MenuInfo CONST_DATA MenuInfo_Debug_085C7474; 8 | extern struct MenuInfo CONST_DATA MenuInfo_Debug_085C73E4; 9 | extern struct MenuInfo CONST_DATA MenuInfo_Debug_085C742C; 10 | extern struct MenuInfo CONST_DATA MenuInfo_Debug_085C7450; 11 | extern struct MenuInfo CONST_DATA MenuInfo_DebugCpControl; 12 | extern struct MenuInfo CONST_DATA MenuInfo_Map; 13 | extern struct MenuInfo CONST_DATA MenuInfo_TutorialInterruptMenu; 14 | extern struct MenuInfo CONST_DATA MenuInfo_UnitAction; 15 | extern struct MenuInfo CONST_DATA MenuInfo_DiscardItem; 16 | extern struct MenuInfo CONST_DATA MenuInfo_UnitAttackMethodPrompt; 17 | extern struct MenuInfo CONST_DATA MenuInfo_UnitAttackBallista; 18 | extern struct MenuInfo CONST_DATA MenuInfo_UnitAttackItem; 19 | extern struct MenuInfo CONST_DATA MenuInfo_UnitItem; 20 | extern struct MenuInfo CONST_DATA MenuInfo_UnitItemAction; 21 | extern struct MenuInfo CONST_DATA MenuInfo_UnitItemDiscardPrompt; 22 | extern struct MenuInfo CONST_DATA MenuInfo_UnitStaffItem; 23 | extern struct MenuInfo CONST_DATA MenuInfo_StealItem; 24 | extern struct MenuInfo CONST_DATA MenuInfo_RepairItem; 25 | extern struct MenuInfo CONST_DATA MenuInfo_PrepMap; 26 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Rescue; 27 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_DropRescue; 28 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_TakeRescue; 29 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_GiveRescue; 30 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Attack; 31 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Trade; 32 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Refresh; 33 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Talk; 34 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Support; 35 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Steal; 36 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_WarpUnit; 37 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Unlock; 38 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Repair; 39 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Heal; 40 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Restore; 41 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_Barrier; 42 | extern struct MapSelectInfo CONST_DATA MapSelectInfo_AttackStaff; 43 | -------------------------------------------------------------------------------- /src/move.c: -------------------------------------------------------------------------------- 1 | #include "move.h" 2 | 3 | struct MoveStats 4 | { 5 | /* 00 */ int count; 6 | /* 04 */ int totalSize; 7 | }; 8 | 9 | struct MoveEntry 10 | { 11 | /* 00 */ void const * src; 12 | /* 04 */ void * dest; 13 | /* 08 */ u16 size; 14 | /* 0A */ u16 mode; 15 | }; 16 | 17 | enum { MOVE_MAX = 0x20 }; 18 | 19 | enum 20 | { 21 | MOVE_MODE_COPY, 22 | MOVE_MODE_COPY_FAST, 23 | MOVE_MODE_FILL_FAST, 24 | }; 25 | 26 | struct MoveStats EWRAM_DATA gMoveStats = {}; 27 | struct MoveEntry EWRAM_DATA gMoveList[MOVE_MAX] = {}; 28 | 29 | static void ClearMoveList(void) 30 | { 31 | int i; 32 | 33 | gMoveStats.count = 0; 34 | gMoveStats.totalSize = 0; 35 | 36 | for (i = 0; i < MOVE_MAX; ++i) 37 | { 38 | gMoveList[i].src = NULL; 39 | gMoveList[i].dest = NULL; 40 | gMoveList[i].size = 0; 41 | gMoveList[i].mode = 0; 42 | } 43 | 44 | gMoveList[0].src = 0; 45 | } 46 | 47 | void RegisterDataMove(void const * src, void * dst, int size) 48 | { 49 | struct MoveEntry * entry = gMoveList + gMoveStats.count; 50 | 51 | entry->src = src; 52 | entry->dest = dst; 53 | entry->size = size; 54 | entry->mode = (size & 0x1F) 55 | ? MOVE_MODE_COPY 56 | : MOVE_MODE_COPY_FAST; 57 | 58 | gMoveStats.totalSize += size; 59 | gMoveStats.count++; 60 | } 61 | 62 | void RegisterDataFill(u32 value, void * dst, int size) 63 | { 64 | struct MoveEntry * entry = gMoveList + gMoveStats.count; 65 | 66 | entry->src = (void const *) value; 67 | entry->dest = dst; 68 | entry->size = size; 69 | entry->mode = MOVE_MODE_FILL_FAST; 70 | 71 | gMoveStats.totalSize += size; 72 | gMoveStats.count++; 73 | } 74 | 75 | void ApplyDataMoves(void) 76 | { 77 | struct MoveEntry * it = gMoveList; 78 | int i; 79 | 80 | for (i = 0; i < gMoveStats.count; ++i) 81 | { 82 | switch (it->mode) 83 | { 84 | 85 | case MOVE_MODE_COPY: 86 | CpuCopy16(it->src, it->dest, it->size); 87 | break; 88 | 89 | case MOVE_MODE_COPY_FAST: 90 | CpuFastCopy(it->src, it->dest, it->size); 91 | break; 92 | 93 | case MOVE_MODE_FILL_FAST: 94 | CpuFastFill((u32) it->src, it->dest, it->size); 95 | break; 96 | 97 | } 98 | 99 | it++; 100 | } 101 | 102 | ClearMoveList(); 103 | } 104 | -------------------------------------------------------------------------------- /src/oam.c: -------------------------------------------------------------------------------- 1 | 2 | #include "oam.h" 3 | 4 | #include "armfunc.h" 5 | 6 | struct OamSection 7 | { 8 | u16 * buf; 9 | void * oam; 10 | u16 offset; 11 | u16 count; 12 | }; 13 | 14 | static struct OamSection sOamHi; 15 | static struct OamSection sOamLo; 16 | 17 | u16 COMMON_DATA(gOam) gOam[0x200] = { 0 }; 18 | u16 * COMMON_DATA(gOamHiPutIt) gOamHiPutIt = NULL; 19 | u16 * COMMON_DATA(gOamLoPutIt) gOamLoPutIt = NULL; 20 | struct OamView * COMMON_DATA(gOamAffinePutIt) gOamAffinePutIt = NULL; 21 | u16 COMMON_DATA(gOamAffinePutId) gOamAffinePutId = 0; 22 | 23 | void InitOam(int loSz) 24 | { 25 | sOamLo.buf = gOam; 26 | sOamLo.oam = (void *) OAM; 27 | sOamLo.offset = 0; 28 | sOamLo.count = loSz; 29 | 30 | sOamHi.buf = gOam + loSz*4; 31 | sOamHi.oam = (void *) OAM + loSz*8; 32 | sOamHi.offset = loSz*8; 33 | sOamHi.count = 0x80 - loSz; 34 | } 35 | 36 | inline int GetOamSplice(void) 37 | { 38 | return sOamLo.count; 39 | } 40 | 41 | void SyncHiOam(void) 42 | { 43 | CpuFastCopy(sOamHi.buf, sOamHi.oam, sOamHi.count * 8); 44 | ClearOam(sOamHi.buf, sOamHi.count); 45 | 46 | gOamHiPutIt = sOamHi.buf; 47 | 48 | gOamAffinePutIt = (struct OamView *) gOam; 49 | gOamAffinePutId = 0; 50 | } 51 | 52 | void SyncLoOam(void) 53 | { 54 | if (sOamLo.count == 0) 55 | return; 56 | 57 | CpuFastCopy(sOamLo.buf, sOamLo.oam, sOamLo.count * 8); 58 | ClearOam(sOamLo.buf, sOamLo.count); 59 | 60 | gOamLoPutIt = sOamLo.buf; 61 | } 62 | 63 | void SetObjAffine(int id, fi16 pa, fi16 pb, fi16 pc, fi16 pd) 64 | { 65 | gOam[id*0x10 + 3] = pa; 66 | gOam[id*0x10 + 7] = pb; 67 | gOam[id*0x10 + 11] = pc; 68 | gOam[id*0x10 + 15] = pd; 69 | } 70 | 71 | void PutUnkSprite(struct UnkSprite * sprites, int xBase, int yBase) 72 | { 73 | int x, y; 74 | 75 | for (;;) 76 | { 77 | if (FALSE) 78 | return; 79 | 80 | if (sprites->oam01 == 1 || gOamHiPutIt >= gOam + 0x80) 81 | return; 82 | 83 | x = OAM1_X(sprites->x + xBase); 84 | y = OAM0_Y(sprites->y + yBase); 85 | 86 | #if MODERN 87 | *gOamHiPutIt++ = (sprites->oam01 >> 0) | y; 88 | *gOamHiPutIt++ = (sprites->oam01 >> 16) | x; 89 | *gOamHiPutIt++ = sprites->oam2; 90 | *gOamHiPutIt++ = 0; 91 | #else 92 | *(u32 *) ((u32 *) gOamHiPutIt)++ = sprites->oam01 | (x << 16) | (y); 93 | *(u16 *) ((u32 *) gOamHiPutIt)++ = sprites->oam2; 94 | #endif 95 | 96 | sprites++; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /data/chapters/chapter21/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 086691F8 4 | EventListScr CONST_DATA EventListScr_Unk_086691F8[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08671B48, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_08671E6C, 31, 0, FACTION_BLUE) 8 | EvtListFunc(FLAG_CHAPTER21_4, EventScr_Unk_08671C4C, func_fe6_0806ADC4) 9 | EvtListFunc(0, EventScr_Unk_08671CA8, func_fe6_0806ADDC) 10 | EvtListFunc(0, EventScr_Unk_08671D34, func_fe6_0806AE04) 11 | EvtListFunc(FLAG_CHAPTER21_11, EventScr_Unk_08671DC0, func_fe6_0806AE2C) 12 | EvtListFunc(0, EventScr_Unk_08671DD4, func_fe6_0806AE54) 13 | EvtListEnd 14 | }; 15 | 16 | // EventListScr @ 08669250 17 | EventListScr CONST_DATA EventListScr_Unk_08669250[] = 18 | { 19 | EvtListTalk(FLAG_CHAPTER21_17, EventScr_Unk_08671EE0, PID_SAUL, PID_YODER) 20 | EvtListTalk(FLAG_CHAPTER21_17, EventScr_Unk_08671EE0, PID_YODER, PID_SAUL) 21 | EvtListTalk(FLAG_CHAPTER21_18, EventScr_Unk_08671EF4, PID_DOROTHY, PID_YODER) 22 | EvtListTalk(FLAG_CHAPTER21_18, EventScr_Unk_08671EF4, PID_YODER, PID_DOROTHY) 23 | EvtListTalk(FLAG_CHAPTER21_15, EventScr_Unk_08671EA0, PID_MELADY, PID_GALLE) 24 | EvtListTalk(FLAG_CHAPTER21_16, EventScr_Unk_08671EC0, PID_ZEISS, PID_GALLE) 25 | EvtListEnd 26 | }; 27 | 28 | // EventListScr @ 0866929C 29 | EventListScr CONST_DATA EventListScr_Unk_0866929C[] = 30 | { 31 | EvtListShop(0, ShopItems_Unk_0866A99E, 5, 1, TILE_COMMAND_ARMORY) 32 | EvtListShop(0, ShopItems_Unk_0866A9B0, 9, 1, TILE_COMMAND_VENDOR) 33 | EvtListShop(0, ShopItems_Unk_0866A9C8, 30, 13, TILE_COMMAND_SECRET) 34 | EvtListTileMapChange(0, EventScr_Unk_08671F08, 11, 11, TILE_COMMAND_VISIT) 35 | EvtListTile(0, EVENT_NOSCRIPT, 11, 10, TILE_COMMAND_PILLAGE) 36 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 24, 27, TILE_COMMAND_SEIZE) 37 | EvtListEnd 38 | }; 39 | 40 | // EventListScr @ 086692E8 41 | EventListScr CONST_DATA EventListScr_Unk_086692E8[] = 42 | { 43 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 44 | EvtListEnd 45 | }; 46 | 47 | // ChapterEventInfo @ 086692F8 48 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_086692F8 = 49 | { 50 | .event_list_turn = EventListScr_Unk_086691F8, 51 | .event_list_talk = EventListScr_Unk_08669250, 52 | .event_list_tile = EventListScr_Unk_0866929C, 53 | .event_list_move = EventListScr_Unk_086692E8, 54 | .units_red = UnitInfo_Unk_08680454, 55 | .units_blue = UnitInfo_Unk_08680324, 56 | .event_script_victory = EventScr_Unk_08671F50, 57 | }; 58 | -------------------------------------------------------------------------------- /data/chapters/chapter9/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08668148 4 | EventListScr CONST_DATA EventListScr_Unk_08668148[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_0866DB60, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867C664, 12, 20, FACTION_RED) 8 | EvtListTurn(0, EventScr_Unk_0866DC2C, 2, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_Unk_0866DCF0, 5, 0, FACTION_RED) 10 | EvtListEnd 11 | }; 12 | 13 | // EventListScr @ 0866817C 14 | EventListScr CONST_DATA EventListScr_Unk_0866817C[] = 15 | { 16 | EvtListTalk(FLAG_CHAPTER9_5, EventScr_Unk_0866DD04, PID_NOAH, PID_FIR) 17 | EvtListTalk(FLAG_CHAPTER9_6, EventScr_Unk_0866DD30, PID_SUE, PID_SIN) 18 | EvtListEnd 19 | }; 20 | 21 | // EventListScr @ 08668198 22 | EventListScr CONST_DATA EventListScr_Unk_08668198[] = 23 | { 24 | EvtListTileMapChange(FLAG_CHAPTER9_8, EventScr_Unk_0866DDF4, 18, 2, TILE_COMMAND_VISIT) 25 | EvtListTile(FLAG_CHAPTER9_8, EVENT_NOSCRIPT, 18, 1, TILE_COMMAND_PILLAGE) 26 | EvtListTileMapChange(FLAG_CHAPTER9_7, EventScr_Unk_0866DDA4, 21, 2, TILE_COMMAND_VISIT) 27 | EvtListTile(FLAG_CHAPTER9_7, EVENT_NOSCRIPT, 21, 1, TILE_COMMAND_PILLAGE) 28 | EvtListTileMapChange(0, EventScr_Unk_0866DD5C, 2, 24, TILE_COMMAND_VISIT) 29 | EvtListTile(0, EVENT_NOSCRIPT, 2, 23, TILE_COMMAND_PILLAGE) 30 | EvtListShop(0, ShopItems_Unk_0866A87C, 23, 4, TILE_COMMAND_ARMORY) 31 | EvtListShop(0, ShopItems_Unk_0866A890, 21, 6, TILE_COMMAND_VENDOR) 32 | EvtListTile(0, EventScr_Unk_0866DE44, 1, 20, TILE_COMMAND_VISIT) 33 | EvtListTile(0, EventScr_Unk_0866DE80, 19, 22, TILE_COMMAND_VISIT) 34 | EvtListTile(0, EventScr_Unk_0866DEBC, 18, 13, TILE_COMMAND_VISIT) 35 | EvtListTile(0, EventScr_Unk_0866DEF8, 16, 1, TILE_COMMAND_VISIT) 36 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 2, 3, TILE_COMMAND_SEIZE) 37 | EvtListEnd 38 | }; 39 | 40 | // EventListScr @ 08668238 41 | EventListScr CONST_DATA EventListScr_Unk_08668238[] = 42 | { 43 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 44 | EvtListEnd 45 | }; 46 | 47 | // ChapterEventInfo @ 08668248 48 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_08668248 = 49 | { 50 | .event_list_turn = EventListScr_Unk_08668148, 51 | .event_list_talk = EventListScr_Unk_0866817C, 52 | .event_list_tile = EventListScr_Unk_08668198, 53 | .event_list_move = EventListScr_Unk_08668238, 54 | .units_red = UnitInfo_Unk_0867C484, 55 | .units_blue = UnitInfo_Unk_0867C3A4, 56 | .event_script_victory = EventScr_Unk_0866DF34, 57 | }; 58 | -------------------------------------------------------------------------------- /data/chapters/chapter10_a/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08668264 4 | EventListScr CONST_DATA EventListScr_Unk_08668264[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_0866E00C, 1, 0, FACTION_BLUE) 7 | EvtListTurn(0, EventScr_Unk_0866E11C, 4, 0, FACTION_GREEN) 8 | EvtListTurn(0, EventScr_Unk_0866E0AC, 6, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867CAE8, 4, 0, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867CB28, 6, 0, FACTION_RED) 11 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867CAE8, 7, 0, FACTION_RED) 12 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867CB28, 9, 0, FACTION_RED) 13 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867CAE8, 10, 0, FACTION_RED) 14 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867CB28, 12, 0, FACTION_RED) 15 | EvtListTurn(0, EventScr_LoadUnits_Unk_0867CB48, 13, 18, FACTION_RED) 16 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_0867CB08, 5, 0, FACTION_RED) 17 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_0867CB08, 8, 0, FACTION_RED) 18 | EvtListTurnHard(0, EventScr_LoadUnits_Unk_0867CB08, 11, 0, FACTION_RED) 19 | EvtListEnd 20 | }; 21 | 22 | // EventListScr @ 08668304 23 | EventListScr CONST_DATA EventListScr_Unk_08668304[] = 24 | { 25 | EvtListTalk(FLAG_CHAPTER10A_6, EventScr_Unk_0866E1D0, PID_LILINA, PID_GONZALEZ) 26 | EvtListTalk(FLAG_CHAPTER10A_7, EventScr_Unk_0866E1FC, PID_ROY, PID_GEESE) 27 | EvtListEnd 28 | }; 29 | 30 | // EventListScr @ 08668320 31 | EventListScr CONST_DATA EventListScr_Unk_08668320[] = 32 | { 33 | EvtListTileMapChange(FLAG_CHAPTER10A_8, EventScr_Unk_0866E228, 18, 17, TILE_COMMAND_VISIT) 34 | EvtListTile(FLAG_CHAPTER10A_8, EVENT_NOSCRIPT, 18, 16, TILE_COMMAND_PILLAGE) 35 | EvtListTile(0, EventScr_Unk_0866E270, 17, 19, TILE_COMMAND_VISIT) 36 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 18, 29, TILE_COMMAND_SEIZE) 37 | EvtListEnd 38 | }; 39 | 40 | // EventListScr @ 08668354 41 | EventListScr CONST_DATA EventListScr_Unk_08668354[] = 42 | { 43 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 44 | EvtListEnd 45 | }; 46 | 47 | // ChapterEventInfo @ 08668364 48 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_08668364 = 49 | { 50 | .event_list_turn = EventListScr_Unk_08668264, 51 | .event_list_talk = EventListScr_Unk_08668304, 52 | .event_list_tile = EventListScr_Unk_08668320, 53 | .event_list_move = EventListScr_Unk_08668354, 54 | .units_red = UnitInfo_Unk_0867C968, 55 | .units_blue = UnitInfo_Unk_0867C898, 56 | .event_script_victory = EventScr_Unk_0866E2AC, 57 | }; 58 | -------------------------------------------------------------------------------- /src/sioerror.c: -------------------------------------------------------------------------------- 1 | #include "sioerror.h" 2 | 3 | #include "hardware.h" 4 | #include "move.h" 5 | #include "sound.h" 6 | #include "text.h" 7 | #include "msg.h" 8 | #include "helpbox.h" 9 | 10 | #include "constants/msg.h" 11 | #include "constants/songs.h" 12 | #include "constants/videoalloc_global.h" // for CHR_SIZE 13 | 14 | void OnVBlank_SioError(void) 15 | { 16 | // TODO: macro 17 | (*(u16 volatile *)0x03007FF8) = 1; 18 | 19 | SyncDispIo(); 20 | SyncBgsAndPal(); 21 | ApplyDataMoves(); 22 | m4aSoundVSync(); 23 | m4aSoundMain(); 24 | } 25 | 26 | void OnMain_SioErrorWait(void) 27 | { 28 | RefreshKeySt(gKeySt); 29 | 30 | if ((gKeySt->pressed & (KEY_BUTTON_A | KEY_BUTTON_START)) != 0) 31 | SoftReset(GBA_RESET_ALL); 32 | 33 | VBlankIntrWait(); 34 | } 35 | 36 | void PutSioErrorMessage(void) 37 | { 38 | struct Text text[3]; 39 | struct HelpBoxPrintProc fake_proc; 40 | int i; 41 | 42 | struct HelpBoxPrintProc * const proc = &fake_proc; 43 | 44 | ResetText(); 45 | InitTalkTextFont(); 46 | 47 | for (i = 0; i < (int) ARRAY_COUNT(text); i++) 48 | { 49 | InitText(&text[i], 22); 50 | Text_SetColor(&text[i], TEXT_COLOR_0123); 51 | } 52 | 53 | proc->font = NULL; 54 | proc->text[0] = &text[0]; 55 | proc->text[1] = &text[1]; 56 | proc->text[2] = &text[2]; 57 | proc->line = 0; 58 | proc->str_it = DecodeMsg(MSG_C48); 59 | 60 | func_fe6_08071308(proc); 61 | 62 | PutText(&text[0], gBg0Tm + TM_OFFSET(4, 6)); 63 | PutText(&text[1], gBg0Tm + TM_OFFSET(4, 9)); 64 | PutText(&text[2], gBg0Tm + TM_OFFSET(4, 11)); 65 | 66 | EnableBgSync(BG0_SYNC_BIT); 67 | } 68 | 69 | void OnMain_SioError(void) 70 | { 71 | InitBgs(NULL); 72 | m4aSoundInit(); 73 | InitProcs(); 74 | 75 | SetBgOffset(0, 0, 0); 76 | SetDispEnable(1, 0, 0, 0, 0); 77 | SetWinEnable(0, 0, 0); 78 | SetBlendNone(); 79 | gDispIo.mosaic = 0; 80 | SyncDispIo(); 81 | 82 | CpuFastFill(0, (void *) VRAM + 0x0000, CHR_SIZE); 83 | CpuFastFill(0, (void *) VRAM + 0x8000, CHR_SIZE); 84 | 85 | PutSioErrorMessage(); 86 | 87 | PlaySe(SONG_7B); 88 | 89 | SetMainFunc(OnMain_SioErrorWait); 90 | } 91 | 92 | void StartSioErrorScreen(void) 93 | { 94 | REG_DISPSTAT = DISPSTAT_VBLANK_INT_ENABLE; 95 | REG_IME = TRUE; 96 | REG_DISPCNT = 0; 97 | 98 | SetOnVBlank(OnVBlank_SioError); 99 | SetMainFunc(OnMain_SioError); 100 | } 101 | -------------------------------------------------------------------------------- /data/chapters/chapter18_s/eventinfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EventListScr @ 08669B74 4 | EventListScr CONST_DATA EventListScr_Unk_08669B74[] = 5 | { 6 | EvtListTurn(0, EventScr_Unk_08673F24, 1, 0, FACTION_BLUE) 7 | EvtListFlag(FLAG_CHAPTER18S_6, EventScr_Unk_08673FD4, FLAG_CHAPTER18S_5) 8 | EvtListTurn(0, EventScr_LoadUnits_Unk_086833B8, 10, 0, FACTION_RED) 9 | EvtListTurn(0, EventScr_LoadUnits_Unk_086833B8, 15, 0, FACTION_RED) 10 | EvtListTurn(0, EventScr_LoadUnits_Unk_086833B8, 20, 0, FACTION_RED) 11 | EvtListTurn(0, EventScr_LoadUnits_Unk_086833F8, 12, 0, FACTION_RED) 12 | EvtListTurn(0, EventScr_LoadUnits_Unk_086833F8, 17, 0, FACTION_RED) 13 | EvtListTurn(0, EventScr_LoadUnits_Unk_086833F8, 22, 0, FACTION_RED) 14 | EvtListTurn(0, EventScr_LoadUnits_Unk_08683618, 13, 0, FACTION_RED) 15 | EvtListTurn(0, EventScr_LoadUnits_Unk_08683618, 23, 0, FACTION_RED) 16 | EvtListEnd 17 | }; 18 | 19 | // EventListScr @ 08669BF0 20 | EventListScr CONST_DATA EventListScr_Unk_08669BF0[] = 21 | { 22 | EvtListEnd 23 | }; 24 | 25 | // EventListScr @ 08669BF4 26 | EventListScr CONST_DATA EventListScr_Unk_08669BF4[] = 27 | { 28 | EvtListShop(0, ShopItems_Unk_0866AA98, 4, 3, TILE_COMMAND_ARMORY) 29 | EvtListShop(0, ShopItems_Unk_0866AAB0, 2, 3, TILE_COMMAND_VENDOR) 30 | EvtListTile(0, EventScr_Unk_086741D8, 8, 17, TILE_COMMAND_VISIT) 31 | EvtListTile(0, EventScr_Unk_08674214, 8, 21, TILE_COMMAND_VISIT) 32 | EvtListTile(0, EventScr_Unk_08674250, 12, 7, TILE_COMMAND_VISIT) 33 | EvtListTile(0, EventScr_Unk_0867428C, 15, 6, TILE_COMMAND_VISIT) 34 | EvtListTile(FLAG_3, EVENT_NOSCRIPT, 17, 19, TILE_COMMAND_SEIZE) 35 | EvtListEnd 36 | }; 37 | 38 | // EventListScr @ 08669C4C 39 | EventListScr CONST_DATA EventListScr_Unk_08669C4C[] = 40 | { 41 | EvtListFlag(0, EventScr_GameOver, FLAG_101) 42 | EvtListArea(FLAG_CHAPTER18S_5, EventScr_Unk_08673FB0, 14, 15, 20, 15) 43 | EvtListArea(FLAG_CHAPTER18S_5, EventScr_Unk_08673FB0, 13, 16, 21, 22) 44 | EvtListArea(FLAG_CHAPTER18S_5, EventScr_Unk_08673FB0, 14, 23, 20, 23) 45 | EvtListEnd 46 | }; 47 | 48 | // ChapterEventInfo @ 08669C80 49 | struct ChapterEventInfo CONST_DATA ChapterEventInfo_Unk_08669C80 = 50 | { 51 | .event_list_turn = EventListScr_Unk_08669B74, 52 | .event_list_talk = EventListScr_Unk_08669BF0, 53 | .event_list_tile = EventListScr_Unk_08669BF4, 54 | .event_list_move = EventListScr_Unk_08669C4C, 55 | .units_red = UnitInfo_Unk_086831B8, 56 | .units_blue = UnitInfo_Unk_086830B8, 57 | .event_script_victory = EventScr_Unk_086742C8, 58 | }; 59 | -------------------------------------------------------------------------------- /include/constants/terrains.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum 4 | { 5 | // Terrain identifiers 6 | 7 | // I'm going by the FE8 in-game names + some old FE7 nmm for this 8 | // TODO: figure out in better details 9 | 10 | TERRAIN_TILE_00 = 0x00, 11 | TERRAIN_PLAINS = 0x01, 12 | TERRAIN_ROAD = 0x02, 13 | TERRAIN_VILLAGE = 0x03, 14 | TERRAIN_VILLAGE_CLOSED = 0x04, 15 | TERRAIN_HOUSE = 0x05, 16 | TERRAIN_ARMORY = 0x06, 17 | TERRAIN_VENDOR = 0x07, 18 | TERRAIN_ARENA_08 = 0x08, 19 | TERRAIN_C_ROOM_09 = 0x09, 20 | TERRAIN_FORT = 0x0A, 21 | TERRAIN_GATE_0B = 0x0B, 22 | TERRAIN_FOREST = 0x0C, 23 | TERRAIN_THICKET = 0x0D, 24 | TERRAIN_SAND = 0x0E, 25 | TERRAIN_DESERT = 0x0F, 26 | TERRAIN_RIVER = 0x10, 27 | TERRAIN_MOUNTAIN = 0x11, 28 | TERRAIN_PEAK = 0x12, 29 | TERRAIN_BRIDGE = 0x13, 30 | TERRAIN_DRAWBRIDGE = 0x14, 31 | TERRAIN_SEA = 0x15, 32 | TERRAIN_LAKE = 0x16, 33 | TERRAIN_FLOOR_17 = 0x17, 34 | TERRAIN_FLOOR_18 = 0x18, 35 | TERRAIN_FENCE_19 = 0x19, 36 | TERRAIN_WALL = 0x1A, 37 | TERRAIN_WALL_BREAKABLE = 0x1B, 38 | TERRAIN_RUBBLE = 0x1C, 39 | TERRAIN_PILLAR = 0x1D, 40 | TERRAIN_DOOR = 0x1E, 41 | TERRAIN_THRONE = 0x1F, 42 | TERRAIN_CHEST_OPENED = 0x20, 43 | TERRAIN_CHEST = 0x21, 44 | TERRAIN_ROOF = 0x22, 45 | TERRAIN_GATE_23 = 0x23, 46 | TERRAIN_CHURCH = 0x24, 47 | TERRAIN_RUINS = 0x25, 48 | TERRAIN_CLIFF = 0x26, 49 | TERRAIN_BALLISTA = 0x27, 50 | TERRAIN_LONGBALLISTA = 0x28, 51 | TERRAIN_KILLERBALLISTA = 0x29, 52 | TERRAIN_SHIP_FLAT = 0x2A, 53 | TERRAIN_SHIP_WRECK = 0x2B, 54 | TERRAIN_TILE_2C = 0x2C, 55 | TERRAIN_STAIRS = 0x2D, 56 | TERRAIN_TILE_2E = 0x2E, 57 | TERRAIN_GLACIER = 0x2F, 58 | TERRAIN_ARENA_30 = 0x30, 59 | TERRAIN_VALLEY = 0x31, 60 | TERRAIN_FENCE_32 = 0x32, 61 | 62 | // TERRAIN_SNAG = 0x33, 63 | // TERRAIN_BRIDGE_34 = 0x34, 64 | // TERRAIN_SKY = 0x35, 65 | // TERRAIN_DEEPS = 0x36, 66 | // TERRAIN_RUINS_37 = 0x37, 67 | // TERRAIN_INN = 0x38, 68 | // TERRAIN_BARREL = 0x39, 69 | // TERRAIN_BONE = 0x3A, 70 | // TERRAIN_DARK = 0x3B, 71 | // TERRAIN_WATER = 0x3C, 72 | // TERRAIN_GUNNELS = 0x3D, 73 | // TERRAIN_DECK = 0x3E, 74 | // TERRAIN_BRACE = 0x3F, 75 | // TERRAIN_MAST = 0x40, 76 | 77 | TERRAIN_COUNT, 78 | }; 79 | -------------------------------------------------------------------------------- /include/save_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef SAVE_STATS_H 2 | #define SAVE_STATS_H 3 | 4 | #include "prelude.h" 5 | 6 | #include "save.h" 7 | 8 | #include "unit.h" 9 | #include "bm.h" 10 | 11 | enum 12 | { 13 | DEFEAT_CAUSE_0, 14 | DEFEAT_CAUSE_1, 15 | DEFEAT_CAUSE_COMBAT, 16 | DEFEAT_CAUSE_TRAP, 17 | DEFEAT_CAUSE_POISON, 18 | DEFEAT_CAUSE_5, 19 | DEFEAT_CAUSE_ARENA, 20 | }; 21 | 22 | struct PidStats 23 | { 24 | u32 loss_count : 8; 25 | u32 act_count : 8; 26 | u32 stat_view_count : 8; 27 | u32 defeat_chapter : 6; 28 | u32 defeat_turn : 10; 29 | u32 deploy_count : 6; 30 | u32 move_count : 10; 31 | u32 defeat_cause : 4; 32 | u32 exp_gained : 12; 33 | u32 win_count : 10; 34 | u32 battle_count : 12; 35 | u32 killer_pid : 9; 36 | u32 : 0; // unused/padding (15 bits) 37 | }; 38 | 39 | struct ChapterStats 40 | { 41 | u16 chapter_id : 6; 42 | u16 chapter_turn : 10; 43 | u16 chapter_time : 16; // in increments of 3 seconds 44 | }; 45 | 46 | #define PID_STATS_COUNT 70 47 | #define CHAPTER_STATS_COUNT 32 48 | 49 | void WriteGameSaveFreshStats(struct GameSaveBlock * gamesave_sram); 50 | void ClearPidStats(void); 51 | void ReadPidStats(void const * sram_src); 52 | void ReadChapterStats(void const * sram_src); 53 | void WritePidStats(void * sram_dst); 54 | void WriteChapterStats(void * sram_dst); 55 | struct ChapterStats * GetChapterStats(int num); 56 | bool IsValidChapterStats(struct ChapterStats * chapter_stats); 57 | int GetNextChapterStatsSlot(void); 58 | void RegisterChapterStats(struct PlaySt * play_st); 59 | struct PidStats * GetPidStats(fu8 pid); 60 | void PidStatsAddBattle(struct Unit * unit); 61 | void PidStatsAddWin(fu8 pid); 62 | void PidStatsAddLoss(fu8 pid); 63 | void PidStatsSetDefeatInfo(fu8 pid, fu8 killer_pid, int defeat_cause); 64 | void PidStatsAddAct(fu8 pid); 65 | void PidStatsAddStatView(fu8 pid); 66 | void PidStatsAddDeploy(fu8 pid); 67 | void PidStatsAddMove(fu8 pid, int amount); 68 | void PidStatsAddExpGained(fu8 pid, int amount); 69 | int PidStatsCountTotalBattles(void); 70 | int PidStatsCountTotalWins(void); 71 | int PidStatsCountTotalLosses(void); 72 | int PidStatsCountTotalLevelsGained(void); 73 | void PidStatsUpdateFromBattleOutcome(void); 74 | bool IsPlaythroughIdUnique(int playthrough_id); 75 | int GetNewPlaythroughId(void); 76 | int GetGlobalCompletedPlaythroughCount(void); 77 | bool RegisterCompletedPlaythrough(struct GlobalSaveInfo * info, int index); 78 | void WriteCompletedPlaythroughSaveData(void); 79 | void func_fe6_08084F48(void); 80 | 81 | #endif // SAVE_STATS_H 82 | -------------------------------------------------------------------------------- /docs/GLOSSARY.md: -------------------------------------------------------------------------------- 1 | ## TM/tilemap 2 | 3 | Stands for "tile map". 4 | 5 | In text background modes, each of the GBA's hardware backgrounds is assigned a tile map. 6 | This is the kind of tile map this is referring to. 7 | 8 | In GBAFE, there exists buffers for tilemaps of each of the 4 hardware backgrounds (whose 9 | names in fe6 are `gBgTm0` through `gBgTm3`). Each of these can hold 32x32 16bit tiles. 10 | 11 | ## TSA 12 | 13 | This is a term that was used to denote tile map data ever since way before my time. 14 | I do not know what it stands for (or if it even stands for anything). 15 | 16 | When the term is used here, it is _only_ referring to specifically the headered tilemaps with rows in reverse 17 | order that the `TmApplyTsa` function takes as input, and nothing else. I would say "Tile Map" or "TM" otherwise. 18 | 19 | ## BM 20 | 21 | Stands for "Battle Map". 22 | 23 | The screen where the map is displayed. 24 | 25 | ## Banim/Manim 26 | 27 | Banim stands for "Battle Animations", Manim stands for "Map (Battle) Animations". 28 | 29 | ## PID/PInfo 30 | 31 | A PID is a character ID, a PInfo is a struct containing the static info of a character. 32 | 33 | The term "PID" is what the original developers used for exacly what I use it for. It probably stands for "Person ID". 34 | 35 | The term "PInfo" is my invention. 36 | Along with "JInfo" and "IInfo", I think it makes for nice symmetric mapping between "IDs" and "Infos". 37 | 38 | ## JID/JInfo 39 | 40 | Same as PID/PInfo, but for classes. The "J" probably stands for "Job". 41 | 42 | This one is probably the biggest stretch, as no one in the western community really refers to Fire Emblem classes as "jobs". I didn't want to go for a "C" prefix because it could be confused for character as well (and CLASS starts to get long for a prefix for identifiers that are commonly used in chapter events). 43 | 44 | ## IID/IInfo 45 | 46 | Same as PID/PInfo and JID/JInfo, but for items. "I" is for "Item" (this one isn't hard to figure out). 47 | 48 | ## Unit 49 | 50 | A unit is not a character (PID/PInfo)! 51 | 52 | Units are part of the mutable game state. They have many attributes that can change over the course of a playthrough, among which is a PID and JID. 53 | 54 | Sometimes in the decompiled code, I may use the term "UID" to refer to a unit id, but those aren't really the same kind of IDs as PID/JID/IIDs. 55 | 56 | Each faction has a range of unit ids assigned to it: 57 | 58 | - blue: 0x01 through 0x3F 59 | - green: 0x41 through 0x7F 60 | - red: 0x81 through 0xBF 61 | - purple: 0xC1 through 0xFF 62 | 63 | This means that a unit's id also encodes its faction. 64 | -------------------------------------------------------------------------------- /tools/scripts/dump_helpinfo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import symbols 3 | 4 | def read_int(f, len: int, signed: bool = False) -> int: 5 | return int.from_bytes(f.read(len), byteorder = 'little', signed = signed) 6 | 7 | def main(args): 8 | try: 9 | elf_filename = args[1] 10 | rom_filename = args[2] 11 | beg_offset = int(args[3], base = 0) & 0x1FFFFFF 12 | end_offset = int(args[4], base = 0) & 0x1FFFFFF 13 | 14 | except IndexError: 15 | sys.exit(f"usage: {args[0]} ELF ROM BEGIN END") 16 | 17 | with open(elf_filename, 'rb') as f: 18 | syms = { addr: name for addr, name in symbols.from_elf(f) } 19 | 20 | offsets = [off for off in range(beg_offset, end_offset, 0x1C)] 21 | addresses = [0x08000000 + off for off in offsets] 22 | 23 | with open(rom_filename, 'rb') as f: 24 | print(f"// declarations") 25 | 26 | for addr in addresses: 27 | if addr not in syms: 28 | syms[addr] = f"HelpInfo_{addr:08X}" 29 | print(f"extern struct HelpBoxInfo CONST_DATA {syms[addr]};") 30 | 31 | print() 32 | 33 | print(f"// definitions") 34 | 35 | for offset, addr in zip(offsets, addresses): 36 | f.seek(offset) 37 | 38 | adjacent_up = read_int(f, 4) 39 | adjacent_down = read_int(f, 4) 40 | adjacent_left = read_int(f, 4) 41 | adjacent_right = read_int(f, 4) 42 | x = read_int(f, 1) 43 | y = read_int(f, 1) 44 | msg = read_int(f, 2) 45 | redirect = read_int(f, 4) 46 | populate = read_int(f, 4) 47 | 48 | print(f"struct HelpBoxInfo CONST_DATA {syms[addr]} =") 49 | print("{") 50 | 51 | if adjacent_up != 0: 52 | print(f" .adjacent_up = &{syms[adjacent_up]},") 53 | if adjacent_down != 0: 54 | print(f" .adjacent_down = &{syms[adjacent_down]},") 55 | if adjacent_left != 0: 56 | print(f" .adjacent_left = &{syms[adjacent_left]},") 57 | if adjacent_right != 0: 58 | print(f" .adjacent_right = &{syms[adjacent_right]},") 59 | 60 | print(f" .x = {x},") 61 | print(f" .y = {y},") 62 | print(f" .msg = MSG_{msg:03X},") 63 | 64 | if redirect != 0: 65 | print(f" .redirect = {syms[redirect]},") 66 | if populate != 0: 67 | print(f" .populate = {syms[populate]},") 68 | 69 | print("};") 70 | print() 71 | 72 | if __name__ == '__main__': 73 | main(sys.argv) 74 | -------------------------------------------------------------------------------- /include/trap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "prelude.h" 4 | 5 | enum 6 | { 7 | TRAP_MAX_COUNT = 0x20, 8 | }; 9 | 10 | enum 11 | { 12 | TRAP_NONE, 13 | 14 | TRAP_BALLISTA = 1, 15 | TRAP_LONGBALLISTA = 2, 16 | TRAP_KILLERBALLISTA = 3, 17 | TRAP_OBSTACLE = 4, 18 | TRAP_MAPCHANGE = 5, 19 | TRAP_FIRE = 6, 20 | TRAP_GAS = 7, 21 | TRAP_TIMEDMAPCHANGE = 8, 22 | TRAP_LIGHTARROW = 9, 23 | TRAP_STEP_FIRE = 10, 24 | TRAP_STEP_PIKE = 11, 25 | TRAP_STEP_DISARMED = 12, 26 | }; 27 | 28 | enum 29 | { 30 | TRAPDATA_TRAP_INITCNT = 0, 31 | TRAPDATA_TRAP_INTERVAL = 1, 32 | TRAPDATA_TRAP_COUNTER = 2, 33 | TRAPDATA_TRAP_DAMAGE = 3, 34 | }; 35 | 36 | struct Trap 37 | { 38 | /* 00 */ u8 x, y; 39 | /* 02 */ u8 kind; 40 | /* 03 */ u8 extra; 41 | /* 04 */ i8 data[4]; 42 | }; 43 | 44 | void InitTraps(void); 45 | struct Trap * GetTrap(int id); 46 | struct Trap * GetTrapAt(int x, int y); 47 | struct Trap * AddTrap(int x, int y, int kind, int extra); 48 | struct Trap * AddTimedTrap(int x, int y, int kind, int extra, int turn_delay_init, int turn_interval, int damage); 49 | void AddFireTrap(int x, int y, int turn_delay_init, int turn_interval); 50 | void AddGasTrap(int x, int y, int facing, int turn_delay_init, int turn_interval); 51 | void AddArrowTrap(int x, int turn_delay_init, int turn_interval); 52 | void AddTimedMapChange(int off_id, int on_id, int turn_delay_init, int turn_interval); 53 | void AddStepFireTrap(int x, int y); 54 | void AddStepPikeTrap(int x, int y, int facing); 55 | void InitMapTraps(void); 56 | void ApplyEnabledMapChanges(void); 57 | struct Trap * GetBallistaTrapAt(int x, int y); 58 | int GetBallistaItemAt(int x, int y); 59 | int GetDummyBallistaItemAt(int x, int y); 60 | int GetObstacleHpAt(int x, int y); 61 | struct MapChangeInfo const * GetMapChange(int id); 62 | int GetMapChangeIdAt(int x, int y); 63 | void ApplyMapChange(int id); 64 | void AddMapChangeTrap(int id); 65 | void UnitHideIfUnderRoof(struct Unit * unit); 66 | void UpdateRoofedUnits(void); 67 | void EnlistFireTrapTargets(int x, int y, int damage); 68 | void EnlistArrowTrapTargets(int x, int y, int damage); 69 | void EnlistGasTrapTargets(int x, int y, int damage, int facing); 70 | void ListDamagingTrapTargets(void); 71 | void ListDamagingTrapTargetsForDisplay(void); 72 | bool DoHandleStepTraps(ProcPtr proc); 73 | 74 | extern struct ProcScr CONST_DATA ProcScr_UpdateTraps[]; 75 | 76 | #define TRAP_ID(trap) ((trap) - GetTrap(0)) 77 | 78 | // hack 79 | // TODO: do we want both names to be macros and the actual function be something like "GetTerrainTrapStateAt"? 80 | #define GetBallistaUsesAt(x, y) GetObstacleHpAt((x), (y)) 81 | -------------------------------------------------------------------------------- /data/rodata_327254.s: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | 3 | .global gUnk_08327264 4 | gUnk_08327264: @ 08327264 5 | .incbin "fe6-base.gba", 0x327264, (0x32726C - 0x327264) @ length: 0008 6 | 7 | .global gUnk_0832726C 8 | gUnk_0832726C: @ 0832726C 9 | .incbin "fe6-base.gba", 0x32726C, (0x327274 - 0x32726C) @ length: 0008 10 | 11 | .global gUnk_08327274 12 | gUnk_08327274: @ 08327274 13 | .incbin "fe6-base.gba", 0x327274, (0x32727C - 0x327274) @ length: 0008 14 | 15 | .global gUnk_0832727C 16 | gUnk_0832727C: @ 0832727C 17 | .incbin "fe6-base.gba", 0x32727C, (0x327284 - 0x32727C) @ length: 0008 18 | 19 | .global gUnk_08327284 20 | gUnk_08327284: @ 08327284 21 | .incbin "fe6-base.gba", 0x327284, (0x32728C - 0x327284) @ length: 0008 22 | 23 | .global gUnk_0832728C 24 | gUnk_0832728C: @ 0832728C 25 | .incbin "fe6-base.gba", 0x32728C, (0x327294 - 0x32728C) @ length: 0008 26 | 27 | .global gUnk_08327294 28 | gUnk_08327294: @ 08327294 29 | .incbin "fe6-base.gba", 0x327294, (0x3272A4 - 0x327294) @ length: 0010 30 | 31 | .global gUnk_083272A4 32 | gUnk_083272A4: @ 083272A4 33 | .incbin "fe6-base.gba", 0x3272A4, (0x3272AC - 0x3272A4) @ length: 0008 34 | 35 | .global gUnk_083272AC 36 | gUnk_083272AC: @ 083272AC 37 | .incbin "fe6-base.gba", 0x3272AC, (0x3272B8 - 0x3272AC) @ length: 000C 38 | 39 | .global gUnk_083272B8 40 | gUnk_083272B8: @ 083272B8 41 | .incbin "fe6-base.gba", 0x3272B8, (0x3272C4 - 0x3272B8) @ length: 000C 42 | 43 | .global gUnk_083272C4 44 | gUnk_083272C4: @ 083272C4 45 | .incbin "fe6-base.gba", 0x3272C4, (0x3272CC - 0x3272C4) @ length: 0008 46 | 47 | .global gUnk_083272CC 48 | gUnk_083272CC: @ 083272CC 49 | .incbin "fe6-base.gba", 0x3272CC, (0x3272D4 - 0x3272CC) @ length: 0008 50 | 51 | .global gUnk_083272D4 52 | gUnk_083272D4: @ 083272D4 53 | .incbin "fe6-base.gba", 0x3272D4, (0x3272E0 - 0x3272D4) @ length: 000C 54 | 55 | .global gUnk_083272E0 56 | gUnk_083272E0: @ 083272E0 57 | .incbin "fe6-base.gba", 0x3272E0, (0x3272E8 - 0x3272E0) @ length: 0008 58 | 59 | .global gUnk_083272E8 60 | gUnk_083272E8: @ 083272E8 61 | .incbin "fe6-base.gba", 0x3272E8, (0x3272F0 - 0x3272E8) @ length: 0008 62 | 63 | .global gUnk_083272F0 64 | gUnk_083272F0: @ 083272F0 65 | .incbin "fe6-base.gba", 0x3272F0, (0x3272F8 - 0x3272F0) @ length: 0008 66 | 67 | .global gUnk_083272F8 68 | gUnk_083272F8: @ 083272F8 69 | .incbin "fe6-base.gba", 0x3272F8, (0x327304 - 0x3272F8) @ length: 000C 70 | 71 | .global gUnk_08327304 72 | gUnk_08327304: @ 08327304 73 | .incbin "fe6-base.gba", 0x327304, (0x32730C - 0x327304) @ length: 0008 74 | 75 | .global gUnk_0832730C 76 | gUnk_0832730C: @ 0832730C 77 | .incbin "fe6-base.gba", 0x32730C, (0x327314 - 0x32730C) @ length: 0008 78 | --------------------------------------------------------------------------------