From 34a07e5a16507013f04359f6b215390e24d2e194 Mon Sep 17 00:00:00 2001
From: MokhaLeee <nkulyc@163.com>
Date: Sun, 25 Aug 2024 07:42:49 +0000
Subject: [PATCH] dump tactician related data

---
 data/const_data_sio.s     |  13 -
 include/sio.h             |  24 +-
 include/sio_core.h        |   2 +-
 ldscript.txt              |   2 +-
 scripts/dump_tactician.py |  78 +++++
 src/sio_bat.c             |  24 +-
 src/sio_core.c            |   2 +-
 src/sio_tactician.c       | 677 +++++++++++++++++++++++++++++++++-----
 8 files changed, 703 insertions(+), 119 deletions(-)
 delete mode 100644 data/const_data_sio.s
 create mode 100755 scripts/dump_tactician.py

diff --git a/data/const_data_sio.s b/data/const_data_sio.s
deleted file mode 100644
index ae4d574a..00000000
--- a/data/const_data_sio.s
+++ /dev/null
@@ -1,13 +0,0 @@
-    .section .rodata
-
-	.global gTacticianTextConf
-gTacticianTextConf:  @ 0x080D8740
-	.incbin "baserom.gba", 0xD8740, 0x155E
-
-	.global gUnknown_080D9C9E
-gUnknown_080D9C9E:  @ 0x080D9C9E
-	.incbin "baserom.gba", 0xD9C9E, 0x96
-
-	.global gUnknown_080D9D34
-gUnknown_080D9D34:  @ 0x080D9D34
-	.incbin "baserom.gba", 0xD9D34, 0x14
diff --git a/include/sio.h b/include/sio.h
index ce304b6d..75de2f63 100644
--- a/include/sio.h
+++ b/include/sio.h
@@ -24,7 +24,7 @@ struct ProcTactician {
     /* 32 */ u8 unk32;
     /* 33 */ u8 unk33;
     /* 34 */ s16 conf_idx;
-    /* 36 */ s16 unk36;
+    /* 36 */ s16 conf_idx_bak;
     /* 38 */ u8 cur_len;                /* used tactician name string length */
     /* 39 */ u8 unk39;
     /* 3A */ u8 unk3A;
@@ -36,12 +36,11 @@ struct ProcTactician {
 
 struct TacticianTextConf {
     /* 00 */ u8 * str[0xC];
-    /* 30 */ u16 xpos;
-    /* 32 */ u16 unk32;
-    /* 34 */ u8 unk34;
-    /* 35 */ STRUCT_PAD(0x35, 0x36);
-    /* 36 */ s16 unk36[4];
-    /* 3E */ u8 unk3E;
+    /* 30 */ u16 x, y;
+    /* 34 */ u8 kind;
+    /* 35 */ u8 _pad_;
+    /* 36 */ s16 adj_idx[4];
+    /* 3E */ u8 action;
 };
 
 extern const struct TacticianTextConf gTacticianTextConf[];
@@ -214,12 +213,12 @@ void TacticianDrawCharacters(struct ProcTactician * proc);
 int StrLen(u8 * buf);
 void Tactician_InitScreen(struct ProcTactician * proc);
 void SioUpdateTeam(char * str, int team);
-void sub_80449E8(struct ProcTactician * proc, int idx, const struct TacticianTextConf * conf);
+void Tactician_MoveHand(struct ProcTactician * proc, int idx, const struct TacticianTextConf * conf);
 void TacticianTryAppendChar(struct ProcTactician * proc, const struct TacticianTextConf * conf);
 void TacticianTryDeleteChar(struct ProcTactician * proc, const struct TacticianTextConf * conf);
 void SaveTactician(struct ProcTactician * proc, const struct TacticianTextConf * conf);
 bool sub_8044B78(struct ProcTactician * proc, const struct TacticianTextConf * conf, u32 c, int d);
-void sub_8044C54(struct ProcTactician * proc, const struct TacticianTextConf * conf);
+void Tactician_LoopCore(struct ProcTactician * proc, const struct TacticianTextConf * conf);
 void Tactician_Loop(struct ProcTactician * proc);
 void sub_8044F84(void);
 void sub_8044FE4(struct ProcTactician * proc);
@@ -933,11 +932,8 @@ extern int gUnk_Sio_0203DD8C;
 // extern ??? gUnk_Sio_0203DDB4
 extern s8 gUnk_Sio_0203DDDC;
 
-// extern ??? gUnknown_080D8714
-extern s16 gUnknown_080D9C9E[];
-// extern ??? gUnknown_080D9D34
-// extern ??? gUnknown_080D9D4D
-// extern ??? gUnknown_080D9D56
+extern const s16 SioTacticianIndexMap[];
+extern const int gLinkArenaStatusMsg[];
 extern u8 const gUnknown_080D9D5E[];
 extern s8 const gUnknown_080D9D61[];
 extern u16 const Sprite_080D9D6E[];
diff --git a/include/sio_core.h b/include/sio_core.h
index a0ac1bf6..d00183a3 100644
--- a/include/sio_core.h
+++ b/include/sio_core.h
@@ -205,7 +205,7 @@ struct LinkArenaStMaybe
     /* 0B */ u8 unk_0B;
     /* 0C */ struct Text texts[11];
     /* 64 */ struct Text unk_64[7]; // maybe not all text?
-    /* 9C */ u8 unk_9C[4];
+    /* 9C */ u8 linking_status[4];
     /* A0 */ u8 unk_A0;
     /* A1 */ u8 unk_A1[4][15];
     STRUCT_PAD(0xDD, 0xEC);
diff --git a/ldscript.txt b/ldscript.txt
index 83498ff5..388767b0 100644
--- a/ldscript.txt
+++ b/ldscript.txt
@@ -716,7 +716,7 @@ SECTIONS
         . = ALIGN(4); src/cpextra_80407F0.o(.rodata);
         . = ALIGN(4); src/sio_core.o(.rodata);
         . = ALIGN(4); src/sio_main.o(.rodata);
-        . = ALIGN(4); data/const_data_sio.o(.rodata);
+        . = ALIGN(4); src/sio_tactician.o(.rodata);
         . = ALIGN(4); src/sio_main2.o(.rodata);
         . = ALIGN(4); src/sio_postbattle.o(.rodata);
         . = ALIGN(4); src/sio_result.o(.rodata);
diff --git a/scripts/dump_tactician.py b/scripts/dump_tactician.py
new file mode 100755
index 00000000..ebe2804a
--- /dev/null
+++ b/scripts/dump_tactician.py
@@ -0,0 +1,78 @@
+#!/bin/python3
+import struct
+
+bin_file_path = "baserom.gba"
+start_offset = 0x0d8740
+struct_count = 81
+
+TACTICIAN_TEXT_CONF_FORMAT = "<12I 2H B 2x 4h B"
+STRUCT_SIZE = 0x40
+
+def read_string(f):
+    array = bytearray(b'')
+
+    while True:
+        byte = f.read(1)[0]
+
+        if byte == 0:
+            break
+
+        array.append(byte)
+
+    return array
+
+def parse_jis(addr):
+    with open(bin_file_path, "rb") as f:
+        f.seek(addr & 0x1FFFFFF)
+
+        array = read_string(f)
+
+        if len(array) == 0:
+            return "\\0"
+        elif array[0] == 0x20:
+            return "\\n"
+        else:
+            return array.decode('cp932')
+
+with open(bin_file_path, "rb") as f:
+    f.seek(start_offset)
+
+    print("const struct TacticianTextConf gTacticianTextConf[] = {")
+
+    for i in range(struct_count):
+        data = f.read(STRUCT_SIZE)
+        if len(data) < STRUCT_SIZE:
+            print("Error: Not enough data read from the file.")
+            break
+
+        print(f"    [{i}] = " + "{")
+        print( "        .str = { ", end="")
+        print(f"\"{parse_jis(int.from_bytes(data[0x00:0x04], 'little'))}\", ", end="")
+        print(f"\"{parse_jis(int.from_bytes(data[0x04:0x08], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x08:0x0C], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x0C:0x10], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x10:0x14], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x14:0x18], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x18:0x1C], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x1C:0x20], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x20:0x24], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x24:0x28], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x28:0x2C], 'little'))}\",", end = "")
+        print(f"\"{parse_jis(int.from_bytes(data[0x2C:0x30], 'little'))}\",", end = "")
+        print( "},")
+        print(f"        .x = 0x{int.from_bytes(data[0x30:0x32], 'little'):X},")
+        print(f"        .y = 0x{int.from_bytes(data[0x32:0x34], 'little'):X},")
+
+        if data[0x34] != 0:
+            print(f"        .kind = {data[0x34]},")
+
+        if data[0x35] != 0:
+            print(f"        .pad = 0x{data[0x35]:02X},")
+
+        print(f"        .adj_idx = {{ {int.from_bytes(data[0x36:0x38], 'little')}, {int.from_bytes(data[0x38:0x3A], 'little')}, {int.from_bytes(data[0x3A:0x3C], 'little')}, {int.from_bytes(data[0x3C:0x3E], 'little')} }},")
+
+        if data[0x3E] != 0:
+            print(f"        .action = {data[0x3E]}")
+
+        print( "    },")
+    print("};")
diff --git a/src/sio_bat.c b/src/sio_bat.c
index 544d91e0..f49ac235 100644
--- a/src/sio_bat.c
+++ b/src/sio_bat.c
@@ -254,8 +254,6 @@ void sub_8045CE0(void)
     return;
 }
 
-extern int gUnknown_080D9D34[];
-
 //! FE8U = 0x08045CEC
 void sub_8045CEC(void)
 {
@@ -263,18 +261,18 @@ void sub_8045CEC(void)
 
     for (i = 0; i < 4; i++)
     {
-        if (gLinkArenaSt.unk_9C[i] != gSioSt->playerStatus[i])
+        if (gLinkArenaSt.linking_status[i] != gSioSt->playerStatus[i])
         {
-            gLinkArenaSt.unk_9C[i] = gSioSt->playerStatus[i];
+            gLinkArenaSt.linking_status[i] = gSioSt->playerStatus[i];
 
             ClearText(&gLinkArenaSt.texts[i]);
             Text_SetColor(&gLinkArenaSt.texts[i], 0);
 
-            if (gLinkArenaSt.unk_9C[i] < 5)
+            if (gLinkArenaSt.linking_status[i] < 5)
             {
                 PutDrawTextCentered(
                     &gLinkArenaSt.texts[i], 0xb, 5 + i * 3,
-                    GetStringFromIndex(gUnknown_080D9D34[gLinkArenaSt.unk_9C[i]]), 10);
+                    GetStringFromIndex(gLinkArenaStatusMsg[gLinkArenaSt.linking_status[i]]), 10);
                 ApplyPalette(gUnknown_085ADDA8, 0x13 + i);
             }
             else
@@ -319,7 +317,7 @@ void sub_8045DC0(struct SioBatProc * proc)
 
     for (i = 0; i < 4; i++)
     {
-        gLinkArenaSt.unk_9C[i] = 0xff;
+        gLinkArenaSt.linking_status[i] = 0xff;
     }
 
     sub_8045CEC();
@@ -720,7 +718,7 @@ void sub_80464B0(struct SioBatProc * proc)
 
     for (i = 0; i < 4; i++)
     {
-        gLinkArenaSt.unk_9C[i] = 0;
+        gLinkArenaSt.linking_status[i] = 0;
     }
 
     gSioSt->unk_00A = 1 << gSioSt->selfId;
@@ -756,7 +754,7 @@ void sub_8046580(struct SioBatProc * proc)
     {
         proc->unk_58 = (u8)SioEmitData((u8 *)&gUnknown_085A9884->units[proc->unk_64], 0x28);
         proc->unk_64++;
-        gLinkArenaSt.unk_9C[gSioSt->selfId] = proc->unk_64;
+        gLinkArenaSt.linking_status[gSioSt->selfId] = proc->unk_64;
     }
 
     if ((GetGameClock() % 0x26) == 0)
@@ -766,15 +764,15 @@ void sub_8046580(struct SioBatProc * proc)
         if (got != 0)
         {
             int base = outSenderId[0] * 0x40 + 1;
-            struct Unit * unit = GetUnit(base + gLinkArenaSt.unk_9C[outSenderId[0]]);
+            struct Unit * unit = GetUnit(base + gLinkArenaSt.linking_status[outSenderId[0]]);
 
             ClearUnit(unit);
             LoadSavedUnit(buf, unit);
             sub_8046478(unit);
 
-            unit->index = gLinkArenaSt.unk_9C[outSenderId[0]] + base;
+            unit->index = gLinkArenaSt.linking_status[outSenderId[0]] + base;
 
-            if (gLinkArenaSt.unk_9C[outSenderId[0]] == 0)
+            if (gLinkArenaSt.linking_status[outSenderId[0]] == 0)
             {
                 gUnk_Sio_0203DD90.unk_24[outSenderId[0]] = GetUnitMiniPortraitId(unit);
             }
@@ -784,7 +782,7 @@ void sub_8046580(struct SioBatProc * proc)
                 unit->state = US_BIT9;
             }
 
-            gLinkArenaSt.unk_9C[outSenderId[0]]++;
+            gLinkArenaSt.linking_status[outSenderId[0]]++;
         }
 
         for (i = 0; i < 4; i++)
diff --git a/src/sio_core.c b/src/sio_core.c
index 6249e8c5..9f5d54a4 100644
--- a/src/sio_core.c
+++ b/src/sio_core.c
@@ -618,7 +618,7 @@ void SioMain_Loop(void)
                             break;
 
                         case SIO_MSG_86:
-                            gLinkArenaSt.unk_9C[message->param] = 1;
+                            gLinkArenaSt.linking_status[message->param] = 1;
                             gSioSt->playerStatus[message->param] = PLAYER_STATUS_5;
                             gSioSt->unk_009 |= 1 << message->param;
                             gSioSt->timeoutClock[message->param] = 0;
diff --git a/src/sio_tactician.c b/src/sio_tactician.c
index 473d144b..74759cb9 100644
--- a/src/sio_tactician.c
+++ b/src/sio_tactician.c
@@ -38,6 +38,532 @@ PROC_LABEL(2),
     PROC_END,
 };
 
+const struct TacticianTextConf gTacticianTextConf[] = {
+    [0] = {
+        .str = { "", "","","","","","","","","","","",},
+        .x = 0x0,
+        .y = 0x0,
+        .adj_idx = { 0, 0, 0, 0 },
+    },
+    [1] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xCA,
+        .y = 0x48,
+        .kind = 1,
+        .adj_idx = { 5, 2, 60, 6 },
+        .action = 1
+    },
+    [2] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xCA,
+        .y = 0x58,
+        .kind = 1,
+        .adj_idx = { 1, 3, 65, 11 },
+        .action = 2
+    },
+    [3] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xCA,
+        .y = 0x68,
+        .kind = 1,
+        .adj_idx = { 2, 4, 70, 16 },
+        .action = 3
+    },
+    [4] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xCA,
+        .y = 0x78,
+        .kind = 1,
+        .adj_idx = { 5, 5, 75, 21 },
+        .action = 4
+    },
+    [5] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xCA,
+        .y = 0x88,
+        .kind = 1,
+        .adj_idx = { 4, 4, 80, 26 },
+        .action = 5
+    },
+    [6] = {
+        .str = { "A", "","","A","","","A","","","A","","",},
+        .x = 0x10,
+        .y = 0x48,
+        .adj_idx = { 26, 11, 4, 7 },
+    },
+    [7] = {
+        .str = { "B", "","","B","","","B","","","B","","",},
+        .x = 0x1A,
+        .y = 0x48,
+        .adj_idx = { 27, 12, 6, 8 },
+    },
+    [8] = {
+        .str = { "C", "","","C","","","C","","","C","","",},
+        .x = 0x24,
+        .y = 0x48,
+        .adj_idx = { 28, 13, 7, 9 },
+    },
+    [9] = {
+        .str = { "D", "","","D","","","D","","","D","","",},
+        .x = 0x2E,
+        .y = 0x48,
+        .adj_idx = { 29, 14, 8, 10 },
+    },
+    [10] = {
+        .str = { "E", "","","E","","","E","","","E","","",},
+        .x = 0x38,
+        .y = 0x48,
+        .adj_idx = { 30, 15, 9, 31 },
+    },
+    [11] = {
+        .str = { "P", "","","P","","","P","","","P","","",},
+        .x = 0x10,
+        .y = 0x58,
+        .adj_idx = { 6, 16, 4, 12 },
+    },
+    [12] = {
+        .str = { "Q", "","","Q","","","Q","","","Q","","",},
+        .x = 0x1A,
+        .y = 0x58,
+        .adj_idx = { 7, 17, 11, 13 },
+    },
+    [13] = {
+        .str = { "R", "","","R","","","R","","","R","","",},
+        .x = 0x24,
+        .y = 0x58,
+        .adj_idx = { 8, 18, 12, 14 },
+    },
+    [14] = {
+        .str = { "S", "","","S","","","S","","","S","","",},
+        .x = 0x2E,
+        .y = 0x58,
+        .adj_idx = { 9, 19, 13, 15 },
+    },
+    [15] = {
+        .str = { "T", "","","T","","","T","","","T","","",},
+        .x = 0x38,
+        .y = 0x58,
+        .adj_idx = { 10, 20, 14, 36 },
+    },
+    [16] = {
+        .str = { "a", "","","a","","","a","","","a","","",},
+        .x = 0x10,
+        .y = 0x68,
+        .adj_idx = { 11, 21, 4, 17 },
+    },
+    [17] = {
+        .str = { "b", "","","b","","","b","","","b","","",},
+        .x = 0x1A,
+        .y = 0x68,
+        .adj_idx = { 12, 22, 16, 18 },
+    },
+    [18] = {
+        .str = { "c", "","","c","","","c","","","c","","",},
+        .x = 0x24,
+        .y = 0x68,
+        .adj_idx = { 13, 23, 17, 19 },
+    },
+    [19] = {
+        .str = { "d", "","","d","","","d","","","d","","",},
+        .x = 0x2E,
+        .y = 0x68,
+        .adj_idx = { 14, 24, 18, 20 },
+    },
+    [20] = {
+        .str = { "e", "","","e","","","e","","","e","","",},
+        .x = 0x38,
+        .y = 0x68,
+        .adj_idx = { 15, 25, 19, 41 },
+    },
+    [21] = {
+        .str = { "p", "","","p","","","p","","","p","","",},
+        .x = 0x10,
+        .y = 0x78,
+        .adj_idx = { 16, 26, 4, 22 },
+    },
+    [22] = {
+        .str = { "q", "","","q","","","q","","","q","","",},
+        .x = 0x1A,
+        .y = 0x78,
+        .adj_idx = { 17, 27, 21, 23 },
+    },
+    [23] = {
+        .str = { "r", "","","r","","","r","","","r","","",},
+        .x = 0x24,
+        .y = 0x78,
+        .adj_idx = { 18, 28, 22, 24 },
+    },
+    [24] = {
+        .str = { "s", "","","s","","","s","","","s","","",},
+        .x = 0x2E,
+        .y = 0x78,
+        .adj_idx = { 19, 29, 23, 25 },
+    },
+    [25] = {
+        .str = { "t", "","","t","","","t","","","t","","",},
+        .x = 0x38,
+        .y = 0x78,
+        .adj_idx = { 20, 30, 24, 46 },
+    },
+    [26] = {
+        .str = { "1", "","","1","","","1","","","1","","",},
+        .x = 0x10,
+        .y = 0x88,
+        .adj_idx = { 21, 6, 5, 27 },
+    },
+    [27] = {
+        .str = { "2", "","","2","","","2","","","2","","",},
+        .x = 0x1A,
+        .y = 0x88,
+        .adj_idx = { 22, 7, 26, 28 },
+    },
+    [28] = {
+        .str = { "3", "","","3","","","3","","","3","","",},
+        .x = 0x24,
+        .y = 0x88,
+        .adj_idx = { 23, 8, 27, 29 },
+    },
+    [29] = {
+        .str = { "4", "","","4","","","4","","","4","","",},
+        .x = 0x2E,
+        .y = 0x88,
+        .adj_idx = { 24, 9, 28, 30 },
+    },
+    [30] = {
+        .str = { "5", "","","5","","","5","","","5","","",},
+        .x = 0x38,
+        .y = 0x88,
+        .adj_idx = { 25, 10, 29, 51 },
+    },
+    [31] = {
+        .str = { "F", "","","F","","","F","","","F","","",},
+        .x = 0x50,
+        .y = 0x48,
+        .adj_idx = { 51, 36, 10, 32 },
+    },
+    [32] = {
+        .str = { "G", "","","G","","","G","","","G","","",},
+        .x = 0x5A,
+        .y = 0x48,
+        .adj_idx = { 52, 37, 31, 33 },
+    },
+    [33] = {
+        .str = { "H", "","","H","","","H","","","H","","",},
+        .x = 0x64,
+        .y = 0x48,
+        .adj_idx = { 53, 38, 32, 34 },
+    },
+    [34] = {
+        .str = { "I", "","","I","","","I","","","I","","",},
+        .x = 0x6E,
+        .y = 0x48,
+        .adj_idx = { 54, 39, 33, 35 },
+    },
+    [35] = {
+        .str = { "J", "","","J","","","J","","","J","","",},
+        .x = 0x78,
+        .y = 0x48,
+        .adj_idx = { 55, 40, 34, 56 },
+    },
+    [36] = {
+        .str = { "U", "","","U","","","U","","","U","","",},
+        .x = 0x50,
+        .y = 0x58,
+        .adj_idx = { 31, 41, 15, 37 },
+    },
+    [37] = {
+        .str = { "V", "","","V","","","V","","","V","","",},
+        .x = 0x5A,
+        .y = 0x58,
+        .adj_idx = { 32, 42, 36, 38 },
+    },
+    [38] = {
+        .str = { "W", "","","W","","","W","","","W","","",},
+        .x = 0x64,
+        .y = 0x58,
+        .adj_idx = { 33, 43, 37, 39 },
+    },
+    [39] = {
+        .str = { "X", "","","X","","","X","","","X","","",},
+        .x = 0x6E,
+        .y = 0x58,
+        .adj_idx = { 34, 44, 38, 40 },
+    },
+    [40] = {
+        .str = { "Y", "","","Y","","","Y","","","Y","","",},
+        .x = 0x78,
+        .y = 0x58,
+        .adj_idx = { 35, 45, 39, 61 },
+    },
+    [41] = {
+        .str = { "f", "","","f","","","f","","","f","","",},
+        .x = 0x50,
+        .y = 0x68,
+        .adj_idx = { 36, 46, 20, 42 },
+    },
+    [42] = {
+        .str = { "g", "","","g","","","g","","","g","","",},
+        .x = 0x5A,
+        .y = 0x68,
+        .adj_idx = { 37, 47, 41, 43 },
+    },
+    [43] = {
+        .str = { "h", "","","h","","","h","","","h","","",},
+        .x = 0x64,
+        .y = 0x68,
+        .adj_idx = { 38, 48, 42, 44 },
+    },
+    [44] = {
+        .str = { "i", "","","i","","","i","","","i","","",},
+        .x = 0x6E,
+        .y = 0x68,
+        .adj_idx = { 39, 49, 43, 45 },
+    },
+    [45] = {
+        .str = { "j", "","","j","","","j","","","j","","",},
+        .x = 0x78,
+        .y = 0x68,
+        .adj_idx = { 40, 50, 44, 66 },
+    },
+    [46] = {
+        .str = { "u", "","","u","","","u","","","u","","",},
+        .x = 0x50,
+        .y = 0x78,
+        .adj_idx = { 41, 51, 25, 47 },
+    },
+    [47] = {
+        .str = { "v", "","","v","","","v","","","v","","",},
+        .x = 0x5A,
+        .y = 0x78,
+        .adj_idx = { 42, 52, 46, 48 },
+    },
+    [48] = {
+        .str = { "w", "","","w","","","w","","","w","","",},
+        .x = 0x64,
+        .y = 0x78,
+        .adj_idx = { 43, 53, 47, 49 },
+    },
+    [49] = {
+        .str = { "x", "","","x","","","x","","","x","","",},
+        .x = 0x6E,
+        .y = 0x78,
+        .adj_idx = { 44, 54, 48, 50 },
+    },
+    [50] = {
+        .str = { "y", "","","y","","","y","","","y","","",},
+        .x = 0x78,
+        .y = 0x78,
+        .adj_idx = { 45, 55, 49, 71 },
+    },
+    [51] = {
+        .str = { "6", "","","6","","","6","","","6","","",},
+        .x = 0x50,
+        .y = 0x88,
+        .adj_idx = { 46, 31, 30, 52 },
+    },
+    [52] = {
+        .str = { "7", "","","7","","","7","","","7","","",},
+        .x = 0x5A,
+        .y = 0x88,
+        .adj_idx = { 47, 32, 51, 53 },
+    },
+    [53] = {
+        .str = { "8", "","","8","","","8","","","8","","",},
+        .x = 0x64,
+        .y = 0x88,
+        .adj_idx = { 48, 33, 52, 54 },
+    },
+    [54] = {
+        .str = { "9", "","","9","","","9","","","9","","",},
+        .x = 0x6E,
+        .y = 0x88,
+        .adj_idx = { 49, 34, 53, 55 },
+    },
+    [55] = {
+        .str = { "0", "","","0","","","0","","","0","","",},
+        .x = 0x78,
+        .y = 0x88,
+        .adj_idx = { 50, 35, 54, 76 },
+    },
+    [56] = {
+        .str = { "K", "","","K","","","K","","","K","","",},
+        .x = 0x90,
+        .y = 0x48,
+        .adj_idx = { 76, 61, 35, 57 },
+    },
+    [57] = {
+        .str = { "L", "","","L","","","L","","","L","","",},
+        .x = 0x9A,
+        .y = 0x48,
+        .adj_idx = { 77, 62, 56, 58 },
+    },
+    [58] = {
+        .str = { "M", "","","M","","","M","","","M","","",},
+        .x = 0xA4,
+        .y = 0x48,
+        .adj_idx = { 78, 63, 57, 59 },
+    },
+    [59] = {
+        .str = { "N", "","","N","","","N","","","N","","",},
+        .x = 0xAE,
+        .y = 0x48,
+        .adj_idx = { 79, 64, 58, 60 },
+    },
+    [60] = {
+        .str = { "O", "","","O","","","O","","","O","","",},
+        .x = 0xB8,
+        .y = 0x48,
+        .adj_idx = { 80, 65, 59, 4 },
+    },
+    [61] = {
+        .str = { "Z", "","","Z","","","Z","","","Z","","",},
+        .x = 0x90,
+        .y = 0x58,
+        .adj_idx = { 56, 66, 40, 62 },
+    },
+    [62] = {
+        .str = { "!", "","","!","","","!","","","!","","",},
+        .x = 0x9A,
+        .y = 0x58,
+        .adj_idx = { 57, 67, 61, 63 },
+    },
+    [63] = {
+        .str = { "?", "","","?","","","?","","","?","","",},
+        .x = 0xA4,
+        .y = 0x58,
+        .adj_idx = { 58, 68, 62, 64 },
+    },
+    [64] = {
+        .str = { ",", "","",",","","",",","","",",","","",},
+        .x = 0xAE,
+        .y = 0x58,
+        .adj_idx = { 59, 69, 63, 65 },
+    },
+    [65] = {
+        .str = { ".", "","",".","","",".","","",".","","",},
+        .x = 0xB8,
+        .y = 0x58,
+        .adj_idx = { 60, 70, 64, 4 },
+    },
+    [66] = {
+        .str = { "k", "","","k","","","k","","","k","","",},
+        .x = 0x90,
+        .y = 0x68,
+        .adj_idx = { 61, 71, 45, 67 },
+    },
+    [67] = {
+        .str = { "l", "","","l","","","l","","","l","","",},
+        .x = 0x9A,
+        .y = 0x68,
+        .adj_idx = { 62, 72, 66, 68 },
+    },
+    [68] = {
+        .str = { "m", "","","m","","","m","","","m","","",},
+        .x = 0xA4,
+        .y = 0x68,
+        .adj_idx = { 63, 73, 67, 69 },
+    },
+    [69] = {
+        .str = { "n", "","","n","","","n","","","n","","",},
+        .x = 0xAE,
+        .y = 0x68,
+        .adj_idx = { 64, 74, 68, 70 },
+    },
+    [70] = {
+        .str = { "o", "","","o","","","o","","","o","","",},
+        .x = 0xB8,
+        .y = 0x68,
+        .adj_idx = { 65, 75, 69, 4 },
+    },
+    [71] = {
+        .str = { "z", "","","z","","","z","","","z","","",},
+        .x = 0x90,
+        .y = 0x78,
+        .adj_idx = { 66, 76, 50, 72 },
+    },
+    [72] = {
+        .str = { ":", "","",":","","",":","","",":","","",},
+        .x = 0x9A,
+        .y = 0x78,
+        .adj_idx = { 67, 77, 71, 73 },
+    },
+    [73] = {
+        .str = { "/", "","","/","","","/","","","/","","",},
+        .x = 0xA4,
+        .y = 0x78,
+        .adj_idx = { 68, 78, 72, 74 },
+    },
+    [74] = {
+        .str = { "&", "","","&","","","&","","","&","","",},
+        .x = 0xAE,
+        .y = 0x78,
+        .adj_idx = { 69, 79, 73, 75 },
+    },
+    [75] = {
+        .str = { "-", "","","-","","","-","","","-","","",},
+        .x = 0xB8,
+        .y = 0x78,
+        .adj_idx = { 70, 80, 74, 4 },
+    },
+    [76] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0x90,
+        .y = 0x88,
+        .adj_idx = { 71, 56, 55, 77 },
+    },
+    [77] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0x9A,
+        .y = 0x88,
+        .adj_idx = { 72, 57, 76, 78 },
+    },
+    [78] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xA4,
+        .y = 0x88,
+        .adj_idx = { 73, 58, 77, 79 },
+    },
+    [79] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xAE,
+        .y = 0x88,
+        .adj_idx = { 74, 59, 78, 80 },
+    },
+    [80] = {
+        .str = { " ", "",""," ","",""," ","",""," ","","",},
+        .x = 0xB8,
+        .y = 0x88,
+        .adj_idx = { 75, 60, 79, 5 },
+    },
+};
+
+const s16 SioTacticianIndexMap[] = {
+    0x06, 0x07, 0x08, 0x09, 0x0A,
+    0x1F, 0x20, 0x21, 0x22, 0x23,
+    0x38, 0x39, 0x3A, 0x3B, 0x3C,
+    0x0B, 0x0C ,0x0D, 0x0E, 0x0F,
+    0x24, 0x25, 0x26, 0x27, 0x28,
+    0x3D, 0x3E, 0x3F, 0x40, 0x41,
+    0x10, 0x11, 0x12, 0x13, 0x14,
+    0x29, 0x2A, 0x2B, 0x2C, 0x2D,
+    0x42, 0x43, 0x44, 0x45, 0x46,
+    0x15, 0x16, 0x17, 0x18, 0x19,
+    0x2E, 0x2F, 0x30, 0x31, 0x32,
+    0x47, 0x48, 0x49, 0x4A, 0x4B,
+    0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
+    0x33, 0x34, 0x35, 0x36, 0x37,
+    0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+};
+
+const int gLinkArenaStatusMsg[] = {
+    0x76D, // Not Linked
+    0x76E, // Connecting
+    0x76F, // Link Error
+    0x770, // Done
+    0x770, // Done
+};
+
+
 //! FE8U = 0x08044550
 const struct TacticianTextConf * GetTacticianTextConf(s16 idx)
 {
@@ -96,13 +622,13 @@ void sub_8044614(struct ProcTactician * proc)
 
         for (j = 0; j < 0xF; j++)
         {
-            int idx = gUnknown_080D9C9E[i * 15 + j];
+            int idx = SioTacticianIndexMap[i * 15 + j];
             const struct TacticianTextConf * conf = gTacticianTextConf + idx;
             u8 * str = conf->str[proc->line_idx * 3];
 
             if (*str != '\0')
             {
-                Text_SetCursor(Texts_0203DB14 + (i + proc->text_idx * 5), conf->xpos);
+                Text_SetCursor(Texts_0203DB14 + (i + proc->text_idx * 5), conf->x);
                 Text_DrawString(
                     Texts_0203DB14 + (i + proc->text_idx * 5),
                     conf->str[proc->line_idx * 3]
@@ -195,7 +721,7 @@ void Tactician_InitScreen(struct ProcTactician * proc)
     proc->conf_idx = 6;
 
     conf = GetTacticianTextConf(6);
-    proc->child1 = StartNameEntrySpriteDraw(proc, conf->xpos - 4, conf->unk32 + 1);
+    proc->child1 = StartNameEntrySpriteDraw(proc, conf->x - 4, conf->y + 1);
     proc->unk39 = 0;
 
     for (i = 0; i < 10; i++)
@@ -256,23 +782,23 @@ void SioUpdateTeam(char * str, int team)
     WriteMultiArenaSaveTeam(team, buffer, str);
 }
 
-void sub_80449E8(struct ProcTactician * proc, int idx, const struct TacticianTextConf * conf)
+void Tactician_MoveHand(struct ProcTactician * proc, int pos, const struct TacticianTextConf * conf)
 {
     int str_idx;
-    u16 ret;
-    const struct TacticianTextConf * conf2;
+    u16 adj_idx;
+    const struct TacticianTextConf * adj_conf;
 
-    ret = conf->unk36[idx];
-    conf2 = gTacticianTextConf + conf->unk36[idx];
+    adj_idx  = conf->adj_idx[pos];
+    adj_conf = gTacticianTextConf + conf->adj_idx[pos];
 
     str_idx = proc->line_idx * 3;
 
-    while (*conf2->str[str_idx] == '\0')
+    while (*adj_conf->str[str_idx] == '\0')
     {
-        ret = conf2->unk36[idx];
-        conf2 = gTacticianTextConf + conf2->unk36[idx];
+        adj_idx  = adj_conf->adj_idx[pos];
+        adj_conf = gTacticianTextConf + adj_conf->adj_idx[pos];
     }
-    proc->conf_idx = ret;
+    proc->conf_idx = adj_idx;
 }
 
 void TacticianTryAppendChar(struct ProcTactician * proc, const struct TacticianTextConf * conf)
@@ -385,106 +911,105 @@ bool sub_8044B78(struct ProcTactician * proc, const struct TacticianTextConf * c
 }
 
 //! FE8U = 0x08044C54
-void sub_8044C54(struct ProcTactician * proc, const struct TacticianTextConf * conf)
+void Tactician_LoopCore(struct ProcTactician * proc, const struct TacticianTextConf * conf)
 {
     char var;
 
     if ((gKeyStatusPtr->repeatedKeys & DPAD_UP) != 0)
     {
-        sub_80449E8(proc, 0, conf);
+        Tactician_MoveHand(proc, 0, conf);
     }
 
     if ((gKeyStatusPtr->repeatedKeys & DPAD_DOWN) != 0)
     {
-        sub_80449E8(proc, 1, conf);
+        Tactician_MoveHand(proc, 1, conf);
     }
 
     if ((gKeyStatusPtr->repeatedKeys & DPAD_LEFT) != 0)
     {
-        sub_80449E8(proc, 2, conf);
+        Tactician_MoveHand(proc, 2, conf);
     }
 
     if ((gKeyStatusPtr->repeatedKeys & DPAD_RIGHT) != 0)
     {
-        sub_80449E8(proc, 3, conf);
+        Tactician_MoveHand(proc, 3, conf);
     }
 
     if ((gKeyStatusPtr->newKeys & A_BUTTON) != 0)
     {
-        switch (conf->unk3E)
-        {
-            case 0:
-                TacticianTryAppendChar(proc, conf);
-                break;
+        switch (conf->action) {
+        case 0:
+            TacticianTryAppendChar(proc, conf);
+            break;
 
-            case 4:
-                TacticianTryDeleteChar(proc, conf);
-                break;
+        case 4:
+            TacticianTryDeleteChar(proc, conf);
+            break;
 
-            case 5:
-                SaveTactician(proc, conf);
-                break;
+        case 5:
+            SaveTactician(proc, conf);
+            break;
 
-            case 6:
-                sub_8044B78(proc, conf, 1, 0);
+        case 6:
+            sub_8044B78(proc, conf, 1, 0);
 
-                break;
+            break;
 
-            case 7:
-                sub_8044B78(proc, conf, 2, 0);
+        case 7:
+            sub_8044B78(proc, conf, 2, 0);
 
-                break;
+            break;
 
-            case 1:
-                if (proc->line_idx != 0)
-                {
-                    SioPlaySoundEffect(2);
-                    proc->line_idx = 0;
-                    proc->unk39 = 0;
+        case 1:
+            if (proc->line_idx != 0)
+            {
+                SioPlaySoundEffect(2);
+                proc->line_idx = 0;
+                proc->unk39 = 0;
 
-                    Proc_Goto(proc, 1);
-                    return;
-                }
+                Proc_Goto(proc, 1);
+                return;
+            }
 
-                SioPlaySoundEffect(0);
-                break;
+            SioPlaySoundEffect(0);
+            break;
 
-            case 2:
-                if (proc->line_idx != 1)
-                {
-                    SioPlaySoundEffect(2);
+        case 2:
+            if (proc->line_idx != 1)
+            {
+                SioPlaySoundEffect(2);
 
-                    proc->line_idx = 1;
-                    proc->unk39 = 0;
+                proc->line_idx = 1;
+                proc->unk39 = 0;
 
-                    Proc_Goto(proc, 1);
-                    return;
-                }
+                Proc_Goto(proc, 1);
+                return;
+            }
 
-                SioPlaySoundEffect(0);
-                break;
+            SioPlaySoundEffect(0);
+            break;
 
-            case 3:
-                if (proc->line_idx < 2 || proc->line_idx > 3)
-                {
-                    SioPlaySoundEffect(2);
+        case 3:
+            if (proc->line_idx < 2 || proc->line_idx > 3)
+            {
+                SioPlaySoundEffect(2);
 
-                    proc->line_idx = 2;
+                proc->line_idx = 2;
 
-                    if (proc->unk32 != 0)
-                    {
-                        proc->line_idx = 3;
-                    }
+                if (proc->unk32 != 0)
+                {
+                    proc->line_idx = 3;
+                }
 
-                    proc->unk39 = 0;
+                proc->unk39 = 0;
 
-                    Proc_Goto(proc, 1);
-                    return;
-                }
+                Proc_Goto(proc, 1);
+                return;
+            }
 
-                SioPlaySoundEffect(0);
+            SioPlaySoundEffect(0);
 
-                break;
+            break;
         }
     }
 
@@ -534,7 +1059,7 @@ void sub_8044C54(struct ProcTactician * proc, const struct TacticianTextConf * c
 
         if (*conf->str[proc->line_idx * 3] == 0)
         {
-            sub_80449E8(proc, 2, conf);
+            Tactician_MoveHand(proc, 2, conf);
         }
 
         Proc_Goto(proc, 1);
@@ -564,10 +1089,10 @@ void Tactician_Loop(struct ProcTactician * proc)
 {
     char _cbuf[proc->max_len + 1];
     const struct TacticianTextConf * conf = GetTacticianTextConf(proc->conf_idx);
-    proc->unk36 = proc->conf_idx;
+    proc->conf_idx_bak = proc->conf_idx;
 
-    sub_8044C54(proc, conf);
-    if (proc->unk36 != proc->conf_idx)
+    Tactician_LoopCore(proc, conf);
+    if (proc->conf_idx_bak != proc->conf_idx)
     {
         SioPlaySoundEffect(3);
     }
@@ -577,7 +1102,7 @@ void Tactician_Loop(struct ProcTactician * proc)
 
     _cbuf[proc->max_len - 1] = 0;
 
-    UpdateNameEntrySpriteDraw(proc->child1, conf->xpos - 4, conf->unk32 + 1, StrLen(_cbuf) * 7, conf->unk34, (proc->line_idx <= 1) ? proc->line_idx : 2);
+    UpdateNameEntrySpriteDraw(proc->child1, conf->x - 4, conf->y + 1, StrLen(_cbuf) * 7, conf->kind, (proc->line_idx <= 1) ? proc->line_idx : 2);
 }
 
 //! FE8U = 0x08044F84