From 903d824c484c6a0fb57bcc402fb7c0475e0292f4 Mon Sep 17 00:00:00 2001 From: nmlgc Date: Sun, 13 Mar 2022 19:29:08 +0100 Subject: [PATCH] [Decompilation] [th04/th05] Dialog: Script loading functions Part of P0186, funded by [Anonymous] and Blue Bolt. --- Makefile.mak | 4 +- th04/f_dialog.cpp | 1 + th04/formats/dialog.cpp | 43 +++++++++++++++++ th04/formats/dialog.hpp | 11 +++++ th04_main.asm | 92 ++++------------------------------- th05/f_dialog.cpp | 1 + th05/formats/dialog.cpp | 41 ++++++++++++++++ th05/formats/dialog.hpp | 18 +++++++ th05_main.asm | 103 ++++------------------------------------ 9 files changed, 135 insertions(+), 179 deletions(-) create mode 100644 th04/f_dialog.cpp create mode 100644 th04/formats/dialog.cpp create mode 100644 th05/f_dialog.cpp create mode 100644 th05/formats/dialog.cpp diff --git a/Makefile.mak b/Makefile.mak index db1a19bd..946f6ee3 100644 --- a/Makefile.mak +++ b/Makefile.mak @@ -126,7 +126,7 @@ bin\th04\op.exe: bin\th04\op.obj th04\m_char.cpp bin\th01\vplanset.obj bin\th02\ $** | -bin\th04\main.exe: bin\th04\main.obj bin\th04\slowdown.obj th04\ems.cpp th04\playfld.cpp th04\dialog.cpp bin\th04\player_p.obj bin\th04\scoreupd.obj th04\hud_ovrl.cpp bin\th04\cfg_lres.obj bin\th01\vplanset.obj bin\th03\vector2.obj bin\th02\frmdely1.obj bin\th03\hfliplut.obj th04\mpn_free.cpp bin\th04\input_w.obj th04\mpn_l_i.cpp bin\th04\vector.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_kaja.obj bin\th04\snd_mode.obj bin\th04\snd_load.obj bin\th04\cdg_put.obj bin\th04\exit.obj bin\th04\initmain.obj bin\th04\cdg_p_na.obj bin\th04\cdg_p_pr.obj bin\th04\input_s.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th04\cdg_load.obj th04\gather.cpp bin\th04\scrolly3.obj bin\th04\motion_3.obj th04\mb_dft.cpp bin\th04\it_spl_u.obj th04\bullet_u.cpp th04\bullet_a.cpp +bin\th04\main.exe: bin\th04\main.obj bin\th04\slowdown.obj th04\ems.cpp th04\playfld.cpp th04\f_dialog.cpp th04\dialog.cpp bin\th04\player_p.obj bin\th04\scoreupd.obj th04\hud_ovrl.cpp bin\th04\cfg_lres.obj bin\th01\vplanset.obj bin\th03\vector2.obj bin\th02\frmdely1.obj bin\th03\hfliplut.obj th04\mpn_free.cpp bin\th04\input_w.obj th04\mpn_l_i.cpp bin\th04\vector.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_kaja.obj bin\th04\snd_mode.obj bin\th04\snd_load.obj bin\th04\cdg_put.obj bin\th04\exit.obj bin\th04\initmain.obj bin\th04\cdg_p_na.obj bin\th04\cdg_p_pr.obj bin\th04\input_s.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th04\cdg_load.obj th04\gather.cpp bin\th04\scrolly3.obj bin\th04\motion_3.obj th04\mb_dft.cpp bin\th04\it_spl_u.obj th04\bullet_u.cpp th04\bullet_a.cpp $(CC) $(CFLAGS) $(LARGE_LFLAGS) -DGAME=4 -DBINARY='M' -3 -Z -nbin\th04\ -eMAIN.EXE @&&| $** | @@ -149,7 +149,7 @@ bin\th05\op.exe: th05\op010.cpp bin\th05\op.obj th05\op011.cpp th05\m_char.cpp b $** | -bin\th05\main.exe: bin\th05\main.obj bin\th04\slowdown.obj th05\ems.cpp bin\th05\cfg_lres.obj th05\main010.cpp th05\dialog.cpp th05\playfld.cpp th05\main011.cpp th05\p_common.cpp th05\p_reimu.cpp th05\p_marisa.cpp th05\p_mima.cpp th05\p_yuuka.cpp bin\th05\player.obj bin\th05\hud_bar.obj bin\th05\scoreupd.obj th05\hud_ovrl.cpp bin\th04\player_p.obj th05\main014.cpp th05\player_a.cpp bin\th05\bullet_1.obj th05\bullet_c.cpp bin\th03\vector2.obj bin\th03\hfliplut.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_mode.obj bin\th05\bullet.obj th05\bullet_t.cpp bin\th04\cdg_p_na.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th05\cdg_put.obj bin\th04\exit.obj bin\th05\vector.obj bin\th05\snd_load.obj bin\th05\snd_kaja.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th04\scrolly3.obj bin\th04\motion_3.obj th05\gather.cpp th05\main032.cpp th05\mb_dft.cpp th05\laser_sc.cpp th05\curveb_u.cpp bin\th04\it_spl_u.obj th05\bullet_u.cpp th05\main034.cpp th05\main035.cpp th05\boss.cpp +bin\th05\main.exe: bin\th05\main.obj bin\th04\slowdown.obj th05\ems.cpp bin\th05\cfg_lres.obj th05\main010.cpp th05\f_dialog.cpp th05\dialog.cpp th05\playfld.cpp th05\main011.cpp th05\p_common.cpp th05\p_reimu.cpp th05\p_marisa.cpp th05\p_mima.cpp th05\p_yuuka.cpp bin\th05\player.obj bin\th05\hud_bar.obj bin\th05\scoreupd.obj th05\hud_ovrl.cpp bin\th04\player_p.obj th05\main014.cpp th05\player_a.cpp bin\th05\bullet_1.obj th05\bullet_c.cpp bin\th03\vector2.obj bin\th03\hfliplut.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_mode.obj bin\th05\bullet.obj th05\bullet_t.cpp bin\th04\cdg_p_na.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th05\cdg_put.obj bin\th04\exit.obj bin\th05\vector.obj bin\th05\snd_load.obj bin\th05\snd_kaja.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th04\scrolly3.obj bin\th04\motion_3.obj th05\gather.cpp th05\main032.cpp th05\mb_dft.cpp th05\laser_sc.cpp th05\curveb_u.cpp bin\th04\it_spl_u.obj th05\bullet_u.cpp th05\main034.cpp th05\main035.cpp th05\boss.cpp $(CC) $(CFLAGS) $(LARGE_LFLAGS) -3 -Z -DGAME=5 -DBINARY='M' -nbin\th05\ -eMAIN.EXE @&&| $** | diff --git a/th04/f_dialog.cpp b/th04/f_dialog.cpp new file mode 100644 index 00000000..5717089d --- /dev/null +++ b/th04/f_dialog.cpp @@ -0,0 +1 @@ +#include "th04/formats/dialog.cpp" diff --git a/th04/formats/dialog.cpp b/th04/formats/dialog.cpp new file mode 100644 index 00000000..615d0256 --- /dev/null +++ b/th04/formats/dialog.cpp @@ -0,0 +1,43 @@ +#pragma option -zCmain_TEXT + +#include +#include "platform.h" +#include "master.hpp" +#include "th04/score.h" +#include "th04/resident.hpp" +#include "th04/formats/dialog.hpp" + +void pascal near dialog_load(const char *fn) +{ + size_t size; + + // While hmem_free() isn't specified to perform a NULL check, it does in + // practice. So while this is *technically* fine, it's not the cleanest + // solution. Fixed in TH05. + hmem_free(reinterpret_cast(dialog_p)); + + file_ropen(fn); + size = file_size(); + dialog_p = reinterpret_cast(hmem_allocbyte(size)); + file_read(dialog_p, size); + file_close(); +} + +void near dialog_load(void) +{ + #define fn dialog_fn + extern char *fn; + dialog_fn[3] = resident->playchar_ascii; + dialog_fn[4] = resident->stage_ascii; + dialog_load(dialog_fn); + #undef fn +} + +void dialog_load_yuuka5_defeat_bad(void) +{ + #define fn dialog_fn_yuuka5_defeat_bad + extern char *fn; + fn[3] = resident->playchar_ascii; + dialog_load(fn); + #undef fn +} diff --git a/th04/formats/dialog.hpp b/th04/formats/dialog.hpp index e9a9fe1b..d20f7a6f 100644 --- a/th04/formats/dialog.hpp +++ b/th04/formats/dialog.hpp @@ -1,2 +1,13 @@ // Script buffer pointer extern unsigned char far *dialog_p; + +// Loads a dialog script from the file with the given name. `near` in this +// game, as it's only used internally. +void pascal near dialog_load(const char *fn); + +// Loads the dialog script after defeating Stage 5 Yuuka with continues or on +// Easy mode, shown before the Bad Ending. +void dialog_load_yuuka5_defeat_bad(void); + +// Loads the dialog script for the current player character and stage. +void near dialog_load(void); diff --git a/th04_main.asm b/th04_main.asm index 8d5e2a43..374d2b66 100644 --- a/th04_main.asm +++ b/th04_main.asm @@ -859,7 +859,7 @@ loc_B141: loc_B144: call main_01:map_load call main_01:std_load - call main_01:sub_CED4 + call @dialog_load$qv call tiles_fill_initial graph_accesspage 0 @@ -2212,82 +2212,11 @@ loc_CE8F: leave retn midboss4_render endp +main_TEXT ends - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_CE93 proc near - -arg_0 = dword ptr 4 - - push bp - mov bp, sp - push si - push word ptr _dialog_p+2 - call hmem_free - pushd [bp+arg_0] - call file_ropen - call file_size - mov si, ax - push ax - call hmem_allocbyte - mov word ptr _dialog_p+2, ax - mov word ptr _dialog_p, 0 - push ax - push word ptr _dialog_p - push si - call file_read - call file_close - pop si - pop bp - retn 4 -sub_CE93 endp - - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_CED4 proc near - push bp - mov bp, sp - les bx, _resident - assume es:nothing - mov al, es:[bx+resident_t.playchar_ascii] - les bx, off_22BAA - mov es:[bx+3], al - les bx, _resident - mov al, es:[bx+resident_t.stage_ascii] - les bx, off_22BAA - mov es:[bx+4], al - push word ptr off_22BAA+2 - push bx - call main_01:sub_CE93 - pop bp - retn -sub_CED4 endp - - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_CF01 proc far - push bp - mov bp, sp - les bx, _resident - mov al, es:[bx+resident_t.playchar_ascii] - les bx, off_22BAE - mov es:[bx+3], al - push word ptr off_22BAE+2 - push bx - call main_01:sub_CE93 - pop bp - retf -sub_CF01 endp - +DIALOG_TEXT segment byte public 'CODE' use16 + @dialog_load$qv procdesc near + extern @dialog_load_yuuka5_defeat_bad$qv:proc ; =============== S U B R O U T I N E ======================================= @@ -3170,9 +3099,7 @@ public @dialog_animate$qv pop bp retf @dialog_animate$qv endp -main_TEXT ends -DIALOG_TEXT segment byte public 'CODE' use16 @dialog_init$qv procdesc near @dialog_exit$qv procdesc near DIALOG_TEXT ends @@ -28452,7 +28379,7 @@ loc_1E7B5: jnz short loc_1E801 loc_1E7F2: - call sub_CF01 + call @dialog_load_yuuka5_defeat_bad$qv call @dialog_animate$qv call @end_game_bad$qv @@ -32105,10 +32032,9 @@ include th04/main/playfld[data].asm byte_22B9E db 1 db 0 include th04/main/frames[data].asm -off_22BAA dd a_dm00_txt - ; "_DM00.TXT" -off_22BAE dd a_dm04b_txt - ; "_DM04B.txt" +public _dialog_fn, _dialog_fn_yuuka5_defeat_bad +_dialog_fn dd a_dm00_txt +_dialog_fn_yuuka5_defeat_bad dd a_dm04b_txt include th04/main/dialog/dialog[data].asm public _number_of_calls_to_this_function _number_of_calls_to_this_function db 0 diff --git a/th05/f_dialog.cpp b/th05/f_dialog.cpp new file mode 100644 index 00000000..687bd968 --- /dev/null +++ b/th05/f_dialog.cpp @@ -0,0 +1 @@ +#include "th05/formats/dialog.cpp" diff --git a/th05/formats/dialog.cpp b/th05/formats/dialog.cpp new file mode 100644 index 00000000..b4b76920 --- /dev/null +++ b/th05/formats/dialog.cpp @@ -0,0 +1,41 @@ +#pragma option -zCmain_TEXT + +#include +#include "platform.h" +#include "master.hpp" +#include "th04/common.h" +#include "th04/score.h" +#include "th04/main/stage/stage.hpp" +#include "th05/playchar.h" +#include "th05/resident.hpp" +#include "th05/formats/dialog.hpp" + +void pascal dialog_load(const char *fn) +{ + size_t size; + tx2_header_t header; + + if(dialog_p) { + hmem_free(reinterpret_cast(dialog_p)); + } + file_ropen(fn); + file_read(&header, sizeof(header)); + + // A sanity check here would have been particularly helpful for + // translators, who tend to start out by just blindly editing a .TX2 file. + size = (header.offset_for[playchar + 1] - header.offset_for[playchar]); + + dialog_p = reinterpret_cast(hmem_allocbyte(size)); + file_seek(header.offset_for[playchar], SEEK_SET); + file_read(dialog_p, size); + file_close(); +} + +void near dialog_load(void) +{ + #define fn dialog_fn + extern char *fn; + fn[4] = ('0' + stage_id); + dialog_load(fn); + #undef fn +} diff --git a/th05/formats/dialog.hpp b/th05/formats/dialog.hpp index b7f0c496..570493c5 100644 --- a/th05/formats/dialog.hpp +++ b/th05/formats/dialog.hpp @@ -1,8 +1,26 @@ /// TH05 in-game dialog script format /// --------------------------------- +struct tx2_header_t { + // The dialog script for player character N is stored between + // `offset_for[N]` and `offset_for[N + 1]`. + uint16_t offset_for[PLAYCHAR_COUNT + 1]; +}; + const uint8_t FACE_NONE = 0xFF; // Script buffer pointer extern unsigned char far *dialog_p; + +// Loading and freeing +// ------------------- + +// Loads the dialog script for the current player character from the .TX2 file +// with the given name. `far` in this game, as it's also called from outside +// its segment. +void pascal dialog_load(const char *fn); + +// Loads the dialog script for the current player character and stage. +void near dialog_load(void); +// ------------------- /// --------------------------------- diff --git a/th05_main.asm b/th05_main.asm index dc6585a8..335c50cb 100644 --- a/th05_main.asm +++ b/th05_main.asm @@ -978,7 +978,7 @@ loc_B4A6: loc_B4A9: call map_load call std_load - call sub_EE17 + call @dialog_load$qv call tiles_fill_initial graph_accesspage 0 @@ -3703,90 +3703,11 @@ sub_EACE endp include th04/main/enemy/render.asm include th04/main/circle.asm +main_TEXT ends -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_ED87 proc far - -var_A = byte ptr -0Ah -var_8 = byte ptr -8 -arg_0 = dword ptr 6 - - enter 0Ah, 0 - push si - cmp _dialog_p, 0 - jz short loc_ED9D - push word ptr _dialog_p+2 - call hmem_free - -loc_ED9D: - pushd [bp+arg_0] - call file_ropen - push ss - lea ax, [bp+var_A] - push ax - push 0Ah - call file_read - mov al, _playchar - mov ah, 0 - add ax, ax - lea dx, [bp+var_8] - add ax, dx - mov bx, ax - mov ax, ss:[bx] - mov dl, _playchar - mov dh, 0 - add dx, dx - lea bx, [bp+var_A] - add dx, bx - mov bx, dx - sub ax, ss:[bx] - mov si, ax - push ax - call hmem_allocbyte - mov word ptr _dialog_p+2, ax - mov word ptr _dialog_p, 0 - mov al, _playchar - mov ah, 0 - add ax, ax - lea dx, [bp+var_A] - add ax, dx - mov bx, ax - movzx eax, word ptr ss:[bx] - push eax - push 0 - call file_seek - pushd [_dialog_p] - push si - call file_read - call file_close - pop si - leave - retf 4 -sub_ED87 endp - - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_EE17 proc near - push bp - mov bp, sp - les bx, off_221D0 - assume es:nothing - mov al, _stage_id - add al, 30h ; '0' - mov es:[bx+4], al - push word ptr off_221D0+2 - push bx - call sub_ED87 - pop bp - retn -sub_EE17 endp - +DIALOG_TEXT segment byte public 'CODE' use16 + extern @DIALOG_LOAD$QNXC:proc + @dialog_load$qv procdesc near ; =============== S U B R O U T I N E ======================================= @@ -4313,9 +4234,7 @@ loc_F333: pop bp retf @dialog_animate$qv endp -main_TEXT ends -DIALOG_TEXT segment byte public 'CODE' use16 @DIALOG_FACE_LOAD_UNPUT_PUT_FREE_$QIII procdesc pascal near \ left:word, top:word, cel:word @dialog_exit$qv procdesc near @@ -16075,9 +15994,7 @@ loc_1AF24: jnz short loc_1AFA7 ; default cmp _boss2_mode_change, 0 jnz short loc_1AF66 - push ds - push offset a_dm09_tx2 ; "_DM09.TX2" - call sub_ED87 + call @dialog_load$qnxc pascal, ds, offset a_dm09_tx2 ; "_DM09.TX2" mov word ptr _boss_bgm_title+2, ds mov word ptr _boss_bgm_title, offset aTH05_10 mov eax, _yuki_pos.cur @@ -16087,9 +16004,7 @@ loc_1AF24: ; --------------------------------------------------------------------------- loc_1AF66: - push ds - push offset a_dm08_tx2 ; "_DM08.TX2" - call sub_ED87 + call @dialog_load$qnxc pascal, ds, offset a_dm08_tx2 ; "_DM08.TX2" mov word ptr _boss_bgm_title+2, ds mov word ptr _boss_bgm_title, offset aTH05_11 setfarfp _boss_update, sub_1C518 @@ -23869,8 +23784,8 @@ _group_is_special db 0 _enemies_gone dw 0 _enemies_killed dw 0 include th04/main/frames[data].asm -off_221D0 dd a_dm00_tx2 - ; "_DM00.TX2" +public _dialog_fn +_dialog_fn dd a_dm00_tx2 include th04/main/dialog/dialog[data].asm byte_221EC db 0 a_dm00_tx2 db '_DM00.TX2',0