From 38a0ddb1ebde86776461d290d5e9cde85496ea81 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 3 Nov 2020 15:10:33 +0800 Subject: [PATCH] Backported "add_extra_msg_file" function from 4.1 Re-ordered critical table fixes in Criticals.cpp. --- artifacts/scripting/headers/sfall.h | 1 + artifacts/scripting/sfall function notes.txt | 9 + sfall/Criticals.cpp | 200 ++++++++++--------- sfall/LoadGameHook.cpp | 1 + sfall/Message.cpp | 37 ++++ sfall/Message.h | 3 + sfall/ScriptExtender.cpp | 1 + sfall/ScriptOps/MetaruleOps.hpp | 1 + sfall/ScriptOps/ScriptUtils.hpp | 15 ++ 9 files changed, 170 insertions(+), 98 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 25312263..d57ada46 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -259,6 +259,7 @@ /* sfall_funcX macros */ +#define add_extra_msg_file(name) sfall_func1("add_extra_msg_file", name) #define add_global_timer_event(time, fixedParam) sfall_func2("add_g_timer_event", time, fixedParam) #define add_iface_tag sfall_func0("add_iface_tag") #define add_trait(traitID) sfall_func1("add_trait", traitID) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index fd34b1fd..2032da74 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -557,6 +557,15 @@ optional arguments: - NOTE: to omit optional arguments starting from the right, call the functions with different sfall_funcX (e.g. sfall_func4("draw_image", pathFile, frame, x, y)) - if draw_image_scaled is called without x/y/width/height arguments, the image will be scaled to fit the window without transparent background +> int sfall_func1("add_extra_msg_file", string fileName) +> int sfall_func2("add_extra_msg_file", string fileName, int fileNumber) +- loads the custom message file, and returns the file ID number assigned to it in range from 0x3000 to 0x3FFF for the message_str_game function to get messages from the file +- fileName: the name of the custom message file (including the .msg extension) in "text\\game\" directory +- NOTE: if the msg file does not exist in the current language directory, the function will try to load it from "text\English\game\" directory +optional argument: +- fileNumber: the file ID number for the message_str_game function. The available range is from 0x2000 to 0x2FFF (see ExtraGameMsgFileList setting in ddraw.ini) + use fileNumber only if you want to add a message file without editing ddraw.ini or existing scripts to support the old way + > void sfall_func2("unwield_slot", object critter, int slot) - unequips an item from the specified slot for a critter or the player - can take off player's equipped item when the inventory is opened, or the player is in the barter screen diff --git a/sfall/Criticals.cpp b/sfall/Criticals.cpp index 8fef869c..60c6260b 100644 --- a/sfall/Criticals.cpp +++ b/sfall/Criticals.cpp @@ -166,58 +166,120 @@ static void CriticalTableOverride() { SafeWrite32(0x423FB3, (DWORD)critTable); if (mode == 2 || mode == 3) { // bug fixes + // Children + SetEntry(2, LegRight, 1, FlagsFail, 0); + SetEntry(2, LegRight, 1, Message, 5216); + SetEntry(2, LegRight, 1, MsgFail, 5000); + + SetEntry(2, LegRight, 2, FlagsFail, 0); + SetEntry(2, LegRight, 2, Message, 5216); + SetEntry(2, LegRight, 2, MsgFail, 5000); + + SetEntry(2, LegLeft, 1, FlagsFail, 0); + SetEntry(2, LegLeft, 1, Message, 5216); + SetEntry(2, LegLeft, 1, MsgFail, 5000); + + SetEntry(2, LegLeft, 2, FlagsFail, 0); + SetEntry(2, LegLeft, 2, Message, 5216); + SetEntry(2, LegLeft, 2, MsgFail, 5000); + + // Super Mutants + SetEntry(3, LegLeft, 1, MsgFail, 5306); + + // Ghouls + SetEntry(4, Head, 4, StatCheck, -1); + + // Brahmin + SetEntry(5, Head, 4, StatCheck, -1); + + // Radscorpions + SetEntry(6, LegRight, 1, FlagsFail, DAM_KNOCKED_DOWN); + + SetEntry(6, LegLeft, 1, FlagsFail, DAM_KNOCKED_DOWN); + SetEntry(6, LegLeft, 2, MsgFail, 5608); + + // Centaurs + SetEntry(9, Torso, 3, FlagsFail, DAM_KNOCKED_DOWN); + + // Deathclaws + SetEntry(13, LegLeft, 1, FlagsFail, DAM_CRIP_LEG_LEFT); + SetEntry(13, LegLeft, 2, FlagsFail, DAM_CRIP_LEG_LEFT); + SetEntry(13, LegLeft, 3, FlagsFail, DAM_CRIP_LEG_LEFT); + SetEntry(13, LegLeft, 4, FlagsFail, DAM_CRIP_LEG_LEFT); + SetEntry(13, LegLeft, 5, FlagsFail, DAM_CRIP_LEG_LEFT); + + // Big Bad Boss + SetEntry(18, Head, 0, Message, 5001); + SetEntry(18, Head, 1, Message, 5001); + SetEntry(18, Head, 2, Message, 5001); + SetEntry(18, Head, 3, Message, 7105); + SetEntry(18, Head, 4, Message, 7101); + SetEntry(18, Head, 4, MsgFail, 7104); + SetEntry(18, Head, 5, Message, 7101); + + SetEntry(18, ArmLeft, 0, Message, 5008); + SetEntry(18, ArmLeft, 1, Message, 5008); + SetEntry(18, ArmLeft, 2, Message, 5009); + SetEntry(18, ArmLeft, 3, Message, 5009); + SetEntry(18, ArmLeft, 4, Message, 7102); + SetEntry(18, ArmLeft, 5, Message, 7102); + + SetEntry(18, ArmRight, 0, Message, 5008); + SetEntry(18, ArmRight, 1, Message, 5008); + SetEntry(18, ArmRight, 2, Message, 5009); + SetEntry(18, ArmRight, 3, Message, 5009); + SetEntry(18, ArmRight, 4, Message, 7102); + SetEntry(18, ArmRight, 5, Message, 7102); + + SetEntry(18, Torso, 4, Message, 7101); + SetEntry(18, Torso, 5, Message, 7101); + + SetEntry(18, LegRight, 0, Message, 5023); + SetEntry(18, LegRight, 1, Message, 7101); + SetEntry(18, LegRight, 1, MsgFail, 7103); + SetEntry(18, LegRight, 2, Message, 7101); + SetEntry(18, LegRight, 2, MsgFail, 7103); + SetEntry(18, LegRight, 3, Message, 7103); + SetEntry(18, LegRight, 4, Message, 7103); + SetEntry(18, LegRight, 5, Message, 7103); + + SetEntry(18, LegLeft, 0, Message, 5023); + SetEntry(18, LegLeft, 1, Message, 7101); + SetEntry(18, LegLeft, 1, MsgFail, 7103); + SetEntry(18, LegLeft, 2, Message, 7101); + SetEntry(18, LegLeft, 2, MsgFail, 7103); + SetEntry(18, LegLeft, 3, Message, 7103); + SetEntry(18, LegLeft, 4, Message, 7103); + SetEntry(18, LegLeft, 5, Message, 7103); + + SetEntry(18, Eyes, 0, Message, 5027); + SetEntry(18, Eyes, 1, Message, 5027); + SetEntry(18, Eyes, 2, Message, 5027); + SetEntry(18, Eyes, 3, Message, 5027); + SetEntry(18, Eyes, 4, Message, 7104); + SetEntry(18, Eyes, 5, Message, 7104); + + SetEntry(18, Groin, 0, Message, 5033); + SetEntry(18, Groin, 1, Message, 5027); + SetEntry(18, Groin, 1, MsgFail, 7101); + SetEntry(18, Groin, 2, Message, 7101); + SetEntry(18, Groin, 3, Message, 7101); + SetEntry(18, Groin, 4, Message, 7101); + SetEntry(18, Groin, 5, Message, 7101); + + // Fixes for uncalled tables // Men SetEntry(0, Uncalled, 2, Flags, DAM_KNOCKED_DOWN | DAM_BYPASS); // 0 SetEntry(0, Uncalled, 2, Message, 5019); // 5018 // Children - SetEntry(2, LegRight, 1, FlagsFail, 0); // 5216 - SetEntry(2, LegRight, 1, Message, 5216); // 5000 - SetEntry(2, LegRight, 1, MsgFail, 5000); // 0 - - SetEntry(2, LegRight, 2, FlagsFail, 0); // 5216 - SetEntry(2, LegRight, 2, Message, 5216); // 5000 - SetEntry(2, LegRight, 2, MsgFail, 5000); // 0 - - SetEntry(2, LegLeft, 1, FlagsFail, 0); // 5216 - SetEntry(2, LegLeft, 1, Message, 5216); // 5000 - SetEntry(2, LegLeft, 1, MsgFail, 5000); // 0 - - SetEntry(2, LegLeft, 2, FlagsFail, 0); // 5216 - SetEntry(2, LegLeft, 2, Message, 5216); // 5000 - SetEntry(2, LegLeft, 2, MsgFail, 5000); // 0 - SetEntry(2, Uncalled, 1, DmgMult, 4); // 3 SetEntry(2, Uncalled, 2, Flags, DAM_KNOCKED_DOWN | DAM_BYPASS); // DAM_BYPASS SetEntry(2, Uncalled, 2, Message, 5212); // 5211 - // Super Mutants - SetEntry(3, LegLeft, 1, MsgFail, 5306); // 5312 - - // Ghouls - SetEntry(4, Head, 4, StatCheck, -1); // STAT_st - - // Brahmin - SetEntry(5, Head, 4, StatCheck, -1); // STAT_st - - // Radscorpions - SetEntry(6, LegRight, 1, FlagsFail, DAM_KNOCKED_DOWN); // 0 - - SetEntry(6, LegLeft, 1, FlagsFail, DAM_KNOCKED_DOWN); // 0 - SetEntry(6, LegLeft, 2, MsgFail, 5608); // 5008 - // Centaurs - SetEntry(9, Torso, 3, FlagsFail, DAM_KNOCKED_DOWN); // 0 - SetEntry(9, Uncalled, 3, FlagsFail, DAM_KNOCKED_DOWN); // 0 - // Deathclaws - SetEntry(13, LegLeft, 1, FlagsFail, DAM_CRIP_LEG_LEFT); // DAM_CRIP_LEG_RIGHT - SetEntry(13, LegLeft, 2, FlagsFail, DAM_CRIP_LEG_LEFT); // DAM_CRIP_LEG_RIGHT - SetEntry(13, LegLeft, 3, FlagsFail, DAM_CRIP_LEG_LEFT); // DAM_CRIP_LEG_RIGHT - SetEntry(13, LegLeft, 4, FlagsFail, DAM_CRIP_LEG_LEFT); // DAM_CRIP_LEG_RIGHT - SetEntry(13, LegLeft, 5, FlagsFail, DAM_CRIP_LEG_LEFT); // DAM_CRIP_LEG_RIGHT - // Geckos SetEntry(15, Uncalled, 0, Message, 6701); // 6700 SetEntry(15, Uncalled, 1, Message, 6701); // 6700 @@ -234,64 +296,6 @@ static void CriticalTableOverride() { SetEntry(17, Uncalled, 2, Flags, DAM_KNOCKED_DOWN | DAM_BYPASS); // 0 // Big Bad Boss - SetEntry(18, Head, 0, Message, 5001); // 7101 - SetEntry(18, Head, 1, Message, 5001); // 7102 - SetEntry(18, Head, 2, Message, 5001); // 7102 - SetEntry(18, Head, 3, Message, 7105); // 7104 - SetEntry(18, Head, 4, Message, 7101); // 7105 - SetEntry(18, Head, 4, MsgFail, 7104); // 7106 - SetEntry(18, Head, 5, Message, 7101); // 7105 - - SetEntry(18, ArmLeft, 0, Message, 5008); // 7106 - SetEntry(18, ArmLeft, 1, Message, 5008); // 7106 - SetEntry(18, ArmLeft, 2, Message, 5009); // 7106 - SetEntry(18, ArmLeft, 3, Message, 5009); // 7106 - SetEntry(18, ArmLeft, 4, Message, 7102); // 7106 - SetEntry(18, ArmLeft, 5, Message, 7102); // 7106 - - SetEntry(18, ArmRight, 0, Message, 5008); // 7106 - SetEntry(18, ArmRight, 1, Message, 5008); // 7106 - SetEntry(18, ArmRight, 2, Message, 5009); // 7106 - SetEntry(18, ArmRight, 3, Message, 5009); // 7106 - SetEntry(18, ArmRight, 4, Message, 7102); // 7106 - SetEntry(18, ArmRight, 5, Message, 7102); // 7106 - - SetEntry(18, Torso, 4, Message, 7101); // 7106 - SetEntry(18, Torso, 5, Message, 7101); // 7106 - - SetEntry(18, LegRight, 0, Message, 5023); // 7106 - SetEntry(18, LegRight, 1, Message, 7101); // 7106 - SetEntry(18, LegRight, 1, MsgFail, 7103); // 7106 - SetEntry(18, LegRight, 2, Message, 7101); // 7060 - SetEntry(18, LegRight, 2, MsgFail, 7103); // 7106 - SetEntry(18, LegRight, 3, Message, 7103); // 7106 - SetEntry(18, LegRight, 4, Message, 7103); // 7106 - SetEntry(18, LegRight, 5, Message, 7103); // 7106 - - SetEntry(18, LegLeft, 0, Message, 5023); // 7106 - SetEntry(18, LegLeft, 1, Message, 7101); // 7106 - SetEntry(18, LegLeft, 1, MsgFail, 7103); // 7124 - SetEntry(18, LegLeft, 2, Message, 7101); // 7106 - SetEntry(18, LegLeft, 2, MsgFail, 7103); // 7124 - SetEntry(18, LegLeft, 3, Message, 7103); // 7106 - SetEntry(18, LegLeft, 4, Message, 7103); // 7106 - SetEntry(18, LegLeft, 5, Message, 7103); // 7106 - - SetEntry(18, Eyes, 0, Message, 5027); // 7106 - SetEntry(18, Eyes, 1, Message, 5027); // 7106 - SetEntry(18, Eyes, 2, Message, 5027); // 7106 - SetEntry(18, Eyes, 3, Message, 5027); // 7106 - SetEntry(18, Eyes, 4, Message, 7104); // 7106 - SetEntry(18, Eyes, 5, Message, 7104); // 7106 - - SetEntry(18, Groin, 0, Message, 5033); // 7106 - SetEntry(18, Groin, 1, Message, 5027); // 7106 - SetEntry(18, Groin, 1, MsgFail, 7101); // 7106 - SetEntry(18, Groin, 2, Message, 7101); // 7106 - SetEntry(18, Groin, 3, Message, 7101); // 7106 - SetEntry(18, Groin, 4, Message, 7101); // 7106 - SetEntry(18, Groin, 5, Message, 7101); // 7106 - SetEntry(18, Uncalled, 2, DmgMult, 3); // 4 SetEntry(18, Uncalled, 4, DmgMult, 4); // 5 SetEntry(18, Uncalled, 4, Message, 7101); // 7106 diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index ec85e402..1ae98e35 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -104,6 +104,7 @@ static void __stdcall ResetState(DWORD onLoad) { // OnGameReset & OnBeforeGameSt InventoryReset(); PartyControl_OnGameLoad(); ResetExplosionRadius(); + ClearScriptAddedExtraGameMsg(); BarBoxes_OnGameLoad(); MetaruleExtenderReset(); ScriptExtender_OnGameLoad(); diff --git a/sfall/Message.cpp b/sfall/Message.cpp index 3c7eef21..671ece51 100644 --- a/sfall/Message.cpp +++ b/sfall/Message.cpp @@ -51,6 +51,8 @@ const MSGList* gameMsgFiles[] = { ExtraGameMessageListsMap gExtraGameMsgLists; static std::vector msgFileList; +static long msgNumCounter = 0x3000; + // Loads the msg file from the 'english' folder if it does not exist in the current language directory static void __declspec(naked) message_load_hook() { __asm { @@ -132,6 +134,41 @@ void ReadExtraGameMsgFiles() { } } +long __stdcall Message_AddExtraMsgFile(const char* msgName, long msgNumber) { + if (msgNumber) { + if (msgNumber < 0x2000 || msgNumber > 0x2FFF) return -1; + if (gExtraGameMsgLists.count(msgNumber)) return 0; // file has already been added + } else if (msgNumCounter > 0x3FFF) return -3; + + std::string path("game\\"); + path += msgName; + MSGList* list = new MSGList(); + if (!MessageLoad(list, path.c_str())) { + // change current language folder + //path.insert(0, "..\\english\\"); + //if (!MessageLoad(list, path.c_str())) { + delete list; + return -2; + //} + } + if (msgNumber == 0) msgNumber = msgNumCounter++; + gExtraGameMsgLists.insert(std::make_pair(msgNumber, list)); + return msgNumber; +} + +void ClearScriptAddedExtraGameMsg() { + for (ExtraGameMessageListsMap::iterator it = gExtraGameMsgLists.begin(); it != gExtraGameMsgLists.end();) { + if (it->first >= 0x3000 && it->first <= 0x3FFF) { + MessageExit(it->second); + delete it->second; + it = gExtraGameMsgLists.erase(it); + } else { + ++it; + } + } + msgNumCounter = 0x3000; +} + void FallbackEnglishLoadMsgFiles() { char value[128]; if (GetGameConfigString(value, "system", "language") && _stricmp(value, "english") != 0) { diff --git a/sfall/Message.h b/sfall/Message.h index 949f2b98..675ba259 100644 --- a/sfall/Message.h +++ b/sfall/Message.h @@ -52,6 +52,9 @@ void Message_Exit(); void FallbackEnglishLoadMsgFiles(); void ReadExtraGameMsgFiles(); void ClearReadExtraGameMsgFiles(); +void ClearScriptAddedExtraGameMsg(); + +long __stdcall Message_AddExtraMsgFile(const char* msgName, long msgNumber); MSGNode* GetMsgNode(MSGList* msgList, int msgRef); char* GetMsg(MSGList* msgList, int msgRef, int msgNum); diff --git a/sfall/ScriptExtender.cpp b/sfall/ScriptExtender.cpp index bdf22e47..d8a9eb82 100644 --- a/sfall/ScriptExtender.cpp +++ b/sfall/ScriptExtender.cpp @@ -851,6 +851,7 @@ static void __declspec(naked) op_sfall_ver_build() { If you don't include opcode in this array, you should take care of all argument validation inside handler itself. */ static const SfallOpcodeMetadata opcodeMetaArray[] = { + {mf_add_extra_msg_file, "add_extra_msg_file", {DATATYPE_MASK_STR, DATATYPE_MASK_INT}}, {mf_add_g_timer_event, "add_g_timer_event", {DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {mf_add_trait, "add_trait", {DATATYPE_MASK_INT}}, {mf_create_win, "create_win", {DATATYPE_MASK_STR, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, diff --git a/sfall/ScriptOps/MetaruleOps.hpp b/sfall/ScriptOps/MetaruleOps.hpp index c2607726..f76614b2 100644 --- a/sfall/ScriptOps/MetaruleOps.hpp +++ b/sfall/ScriptOps/MetaruleOps.hpp @@ -115,6 +115,7 @@ static void mf_metarule_exist() { - minArgs/maxArgs - minimum and maximum number of arguments allowed for this function (max 6) */ static const SfallMetarule metaruleArray[] = { + {"add_extra_msg_file", mf_add_extra_msg_file, 1, 2}, {"add_iface_tag", mf_add_iface_tag, 0, 0}, {"add_g_timer_event", mf_add_g_timer_event, 2, 2}, {"add_trait", mf_add_trait, 1, 1}, diff --git a/sfall/ScriptOps/ScriptUtils.hpp b/sfall/ScriptOps/ScriptUtils.hpp index 10568674..9de8b154 100644 --- a/sfall/ScriptOps/ScriptUtils.hpp +++ b/sfall/ScriptOps/ScriptUtils.hpp @@ -515,6 +515,21 @@ static void __declspec(naked) op_message_str_game() { _WRAP_OPCODE(op_message_str_game2, 2, 1) } +static void mf_add_extra_msg_file() { + long result = Message_AddExtraMsgFile(opHandler.arg(0).strValue(), (opHandler.numArgs() == 2) ? opHandler.arg(1).rawValue() : 0); + switch (result) { + case -1 : + opHandler.printOpcodeError("add_extra_msg_file() - cannot add message file with the specified number."); + break; + case -2 : + opHandler.printOpcodeError("add_extra_msg_file() - error loading message file."); + break; + case -3 : + opHandler.printOpcodeError("add_extra_msg_file() - the limit of adding message files has been exceeded."); + } + opHandler.setReturn(result); +} + static void mf_get_text_width() { const ScriptValue &textArg = opHandler.arg(0);