From 0a44f7118a249a9085e9a8ea02edf92426b5b0fe Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 24 Oct 2020 00:55:40 +0800 Subject: [PATCH] Added support for drawing PCX images to draw_image, draw_image_scaled, and interface_art_draw Fixed bug in TalkingHeads.cpp. --- sfall/FalloutEngine.cpp | 20 +++++++ sfall/FalloutEngine.h | 7 +++ sfall/ScriptOps/InterfaceOps.hpp | 94 ++++++++++++++++++++++---------- sfall/TalkingHeads.cpp | 14 +++-- sfall/version.h | 6 +- 5 files changed, 102 insertions(+), 39 deletions(-) diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 592fb946..ebe7dc94 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -352,6 +352,7 @@ const DWORD critter_name_ = 0x42D0A8; const DWORD critter_pc_set_name_ = 0x42D138; const DWORD critterClearObjDrugs_ = 0x42DA54; const DWORD critterIsOverloaded_ = 0x42E66C; +const DWORD datafileConvertData_ = 0x42EE84; const DWORD db_access_ = 0x4390B4; const DWORD db_dir_entry_ = 0x4C5D68; const DWORD db_fclose_ = 0x4C5EB4; @@ -554,6 +555,7 @@ const DWORD ListSkills_ = 0x436154; const DWORD ListTraits_ = 0x43B8A8; const DWORD loadColorTable_ = 0x4C78E4; const DWORD LoadGame_ = 0x47C640; +const DWORD loadPCX_ = 0x496494; const DWORD loadProgram_ = 0x4A3B74; const DWORD LoadSlot_ = 0x47DC68; const DWORD load_frame_ = 0x419EC0; @@ -591,6 +593,7 @@ const DWORD move_inventory_ = 0x474708; const DWORD movieRun_ = 0x487AC8; const DWORD movieStop_ = 0x487150; const DWORD movieUpdate_ = 0x487BEC; +const DWORD my_free_ = 0x4C5C2C; const DWORD new_obj_id_ = 0x4A386C; const DWORD NixHotLines_ = 0x4999C0; const DWORD nrealloc_ = 0x4F1669; @@ -1188,6 +1191,23 @@ void __cdecl TransBufToBuf(BYTE* src, long width, long height, long src_width, B __asm emms; } +BYTE* __fastcall LoadPCXData(const char* file, long* width, long* height) { + __asm { + mov eax, ecx; + mov ebx, height; + mov ecx, _pal; + call loadPCX_; + push eax; + mov ebx, [width]; + mov edx, _pal; + mov ecx, [height]; + mov ebx, [ebx]; + mov ecx, [ecx]; + call datafileConvertData_; + pop eax; + } +} + long __fastcall GetGameConfigString(const char* outValue, const char* section, const char* param) { __asm { mov ebx, param; diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 77ce4307..c2f79988 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -106,6 +106,7 @@ #define _folder_card_title2 0x5705BC #define _frame_time 0x5709C4 #define _free_perk 0x570A29 +#define _freePtr 0x519594 #define _frstc_draw1 0x5707D8 #define _game_config 0x58E950 #define _game_global_vars 0x5186C0 @@ -206,6 +207,7 @@ #define _optionsButtonUpKey 0x518F28 #define _optnwin 0x663900 #define _outlined_object 0x518D94 +#define _pal 0x56D7E0 #define _partyMemberAIOptions 0x519DB8 #define _partyMemberCount 0x519DAC #define _partyMemberLevelUpInfoList 0x519DBC @@ -638,6 +640,7 @@ extern const DWORD critter_name_; extern const DWORD critter_pc_set_name_; extern const DWORD critterClearObjDrugs_; extern const DWORD critterIsOverloaded_; +extern const DWORD datafileConvertData_; extern const DWORD db_access_; extern const DWORD db_dir_entry_; extern const DWORD db_fclose_; @@ -843,6 +846,7 @@ extern const DWORD ListSkills_; extern const DWORD ListTraits_; extern const DWORD loadColorTable_; extern const DWORD LoadGame_; +extern const DWORD loadPCX_; extern const DWORD loadProgram_; // loads script from scripts/ folder by file name and returns pointer to it: char* - file name (w/o extension) extern const DWORD LoadSlot_; extern const DWORD load_frame_; @@ -883,6 +887,7 @@ extern const DWORD move_inventory_; extern const DWORD movieRun_; extern const DWORD movieStop_; extern const DWORD movieUpdate_; +extern const DWORD my_free_; extern const DWORD new_obj_id_; extern const DWORD NixHotLines_; extern const DWORD nrealloc_; @@ -1195,6 +1200,8 @@ void __cdecl BufToBuf(BYTE* src, long width, long height, long src_width, BYTE* // trans_buf_to_buf_ function implementation void __cdecl TransBufToBuf(BYTE* src, long width, long height, long src_width, BYTE* dst, long dst_width); +BYTE* __fastcall LoadPCXData(const char* file, long* width, long* height); + long __fastcall GetGameConfigString(const char* outValue, const char* section, const char* param); // X-Macro for wrapper functions. diff --git a/sfall/ScriptOps/InterfaceOps.hpp b/sfall/ScriptOps/InterfaceOps.hpp index 0e46be32..9254243d 100644 --- a/sfall/ScriptOps/InterfaceOps.hpp +++ b/sfall/ScriptOps/InterfaceOps.hpp @@ -531,6 +531,45 @@ static void mf_set_window_flag() { } } +static void __fastcall FreeArtFile(FrmFile* frmPtr) { + if (frmPtr->id == 'PCX') { + __asm mov eax, frmPtr; + __asm mov eax, [eax]frmPtr.pixelData; + __asm call ds:[_freePtr]; + delete[] frmPtr; + } else { + __asm mov eax, frmPtr; + __asm call my_free_; + } +} + +static FrmFile* LoadArtFile(const char* file, long frame, long direction, FrmFrameData* &framePtr, bool checkPCX) { + FrmFile* frmPtr = nullptr; + if (checkPCX) { + const char* pos = strrchr(file, '.'); + if (pos && _stricmp(pos, ".PCX") == 0) { + long w, h; + BYTE* data = LoadPCXData(file, &w, &h); + if (!data) return nullptr; + + frmPtr = reinterpret_cast(new BYTE[78]); + std::memset(frmPtr, 0, 74); + + frmPtr->id = 'PCX'; + frmPtr->width = static_cast(w); + frmPtr->height = static_cast(h); + frmPtr->pixelData = data; + framePtr = frmPtr->GetFrameData(0, 0); + return frmPtr; + } + } + if (LoadFrame(file, &frmPtr)) { + return nullptr; + } + framePtr = frmPtr->GetFrameData(direction, frame); + return frmPtr; +} + static long GetArtFIDFile(long fid, const char* &file) { long direction = 0; long _fid = fid & 0xFFFFFFF; @@ -544,16 +583,6 @@ static long GetArtFIDFile(long fid, const char* &file) { return direction; } -static FrmFile* LoadArtFile(const char* file, long frame, long direction, FrmFrameData* &framePtr) { - FrmFile* frmPtr = nullptr; - if (LoadFrame(file, &frmPtr)) { - return nullptr; - } - framePtr = frmPtr->GetFrameData(direction, frame); - - return frmPtr; -} - static void mf_draw_image() { if (*(DWORD*)_currentWindow == -1) { opHandler.printOpcodeError("draw_image() - no created/selected window for the image."); @@ -562,7 +591,9 @@ static void mf_draw_image() { } long direction = 0; const char* file = nullptr; - if (opHandler.arg(0).isInt()) { // art id + + bool isID = opHandler.arg(0).isInt(); + if (isID) { // art id long fid = opHandler.arg(0).rawValue(); if (fid == -1) { opHandler.setReturn(-1); @@ -586,17 +617,18 @@ static void mf_draw_image() { } FrmFrameData* framePtr; - FrmFile* frmPtr = LoadArtFile(file, frameno, direction, framePtr); + FrmFile* frmPtr = LoadArtFile(file, frameno, direction, framePtr, !isID); if (frmPtr == nullptr) { opHandler.printOpcodeError("draw_image() - cannot open the file: %s", file); opHandler.setReturn(-1); return; } + BYTE* pixelData = (frmPtr->id == 'PCX') ? frmPtr->pixelData : framePtr->data; // with x/y frame offsets - WindowDisplayBuf(x + frmPtr->xshift[direction], framePtr->width, y + frmPtr->yshift[direction], framePtr->height, framePtr->data, noTrans); + WindowDisplayBuf(x + frmPtr->xshift[direction], framePtr->width, y + frmPtr->yshift[direction], framePtr->height, pixelData, noTrans); - MemFree(frmPtr); + FreeArtFile(frmPtr); opHandler.setReturn(1); } @@ -608,7 +640,9 @@ static void mf_draw_image_scaled() { } long direction = 0; const char* file = nullptr; - if (opHandler.arg(0).isInt()) { // art id + + bool isID = opHandler.arg(0).isInt(); + if (isID) { // art id long fid = opHandler.arg(0).rawValue(); if (fid == -1) { opHandler.setReturn(-1); @@ -633,16 +667,17 @@ static void mf_draw_image_scaled() { } FrmFrameData* framePtr; - FrmFile* frmPtr = LoadArtFile(file, frameno, direction, framePtr); + FrmFile* frmPtr = LoadArtFile(file, frameno, direction, framePtr, !isID); if (frmPtr == nullptr) { opHandler.printOpcodeError("draw_image_scaled() - cannot open the file: %s", file); opHandler.setReturn(-1); return; } long result = 1; + BYTE* pixelData = (frmPtr->id == 'PCX') ? frmPtr->pixelData : framePtr->data; if (opHandler.numArgs() < 3) { - DisplayInWindow(framePtr->width, framePtr->width, framePtr->height, framePtr->data); // scaled to window size (w/o transparent) + DisplayInWindow(framePtr->width, framePtr->width, framePtr->height, pixelData); // scaled to window size (w/o transparent) } else { // draw to scale long s_width, s_height; @@ -666,11 +701,11 @@ static void mf_draw_image_scaled() { long w_width = WindowWidth(); long xy_pos = (y * w_width) + x; - WindowTransCscale(framePtr->width, framePtr->height, s_width, s_height, xy_pos, w_width, framePtr->data); // custom scaling + WindowTransCscale(framePtr->width, framePtr->height, s_width, s_height, xy_pos, w_width, pixelData); // custom scaling } exit: - MemFree(frmPtr); + FreeArtFile(frmPtr); opHandler.setReturn(result); } @@ -682,12 +717,11 @@ static void mf_interface_art_draw() { bool useShift = false; long direction = -1, w = -1, h = -1; - if (opHandler.arg(1).isInt()) { // art id + bool isID = opHandler.arg(1).isInt(); + if (isID) { // art id long fid = opHandler.arg(1).rawValue(); - if (fid == -1) { - result = -1; - goto exit; - } + if (fid == -1) goto exit; + useShift = (((fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER); direction = GetArtFIDFile(fid, file); } else { @@ -706,10 +740,9 @@ static void mf_interface_art_draw() { long frame = (opHandler.numArgs() > 4) ? opHandler.arg(4).rawValue() : 0; FrmFrameData* framePtr; - FrmFile* frmPtr = LoadArtFile(file, frame, direction, framePtr); + FrmFile* frmPtr = LoadArtFile(file, frame, direction, framePtr, !isID); if (frmPtr == nullptr) { opHandler.printOpcodeError("interface_art_draw() - cannot open the file: %s", file); - result = -1; goto exit; } int x = opHandler.arg(2).rawValue(); @@ -725,14 +758,15 @@ static void mf_interface_art_draw() { int width = (w >= 0) ? w : framePtr->width; int height = (h >= 0) ? h : framePtr->height; - TransCscale(framePtr->data, framePtr->width, framePtr->height, framePtr->width, + TransCscale(((frmPtr->id == 'PCX') ? frmPtr->pixelData : framePtr->data), framePtr->width, framePtr->height, framePtr->width, interfaceWin->surface + (y * interfaceWin->width) + x, width, height, interfaceWin->width ); if (!(opHandler.arg(0).rawValue() & 0x1000000)) { GNWWinRefresh(interfaceWin, &interfaceWin->rect, 0); } - MemFree(frmPtr); + + FreeArtFile(frmPtr); result = 1; } else { opHandler.printOpcodeError("interface_art_draw() - the game interface window is not created or invalid value for the interface."); @@ -825,10 +859,10 @@ static void mf_get_window_attribute() { result = 1; break; case 1: // x - result = win->wRect.left; + result = win->rect.x; break; case 2: // y - result = win->wRect.top; + result = win->rect.y; break; } opHandler.setReturn(result); diff --git a/sfall/TalkingHeads.cpp b/sfall/TalkingHeads.cpp index 7f81bc39..6d550835 100644 --- a/sfall/TalkingHeads.cpp +++ b/sfall/TalkingHeads.cpp @@ -164,21 +164,23 @@ static bool LoadFrm(Frm* frm) { return true; } -static WINinfo* dialogWin = nullptr; +static long dialogWinX = 0, dialogWinY = 0; static void __fastcall DrawHeadFrame(Frm* frm, int frameno) { if (frm && !frm->broken) { if (!frm->loaded && !LoadFrm(frm)) goto loadFail; FrmFrameData* frame = FramePtr((FrmHeaderData*)frm, frameno, 0); - if (dialogWin == nullptr) { - dialogWin = GNWFind(*ptr_dialogueBackWindow); + if (dialogWinX == -1) { + WINinfo* dialogWin = GNWFind(*ptr_dialogueBackWindow); + dialogWinX = dialogWin->rect.x; + dialogWinY = dialogWin->rect.y; } Gfx_SetHeadTex(frm->textures[frameno], frame->width, frame->height, - frame->x + frm->xshift + dialogWin->wRect.left, - frame->y + frm->yshift + dialogWin->wRect.top + frame->x + frm->xshift + dialogWinX, + frame->y + frm->yshift + dialogWinY ); showHighlights = frm->showHighlights; return; @@ -207,7 +209,7 @@ void __declspec(naked) gdDestroyHeadWindow_hack() { __asm { call Gfx_SetDefaultTechnique; mov showHighlights, 0; - //mov dialogWin, 0; // uncomment if the dialog window position is supposed to change + //mov dialogWinX, -1; // uncomment if the dialog window position is supposed to change pop ebp; pop edi; pop edx; diff --git a/sfall/version.h b/sfall/version.h index 028e1a36..03cae367 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -25,10 +25,10 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 8 #define VERSION_BUILD 28 -#define VERSION_REV 0 +#define VERSION_REV 1 #ifdef WIN2K -#define VERSION_STRING "3.8.28 win2k" +#define VERSION_STRING "3.8.28.1 win2k" #else -#define VERSION_STRING "3.8.28" +#define VERSION_STRING "3.8.28.1" #endif