Added DialogGenderWords option to specify gender words for dialog msg

* they will be displayed depending on the player's gender.

* currently does not work for messages constructed with message_str.
This commit is contained in:
NovaRain
2020-01-04 22:59:11 +08:00
parent 5d9d11b4f5
commit db4652c105
3 changed files with 75 additions and 5 deletions
+4
View File
@@ -263,6 +263,10 @@ DataLoadOrderPatch=1
;Set to 2 to also load subtitle files from text\<language>\cuts_female\ for female PC
FemaleDialogMsgs=0
;Set to 1 to enable using the special '^' character in dialog msg files to specify the gender words
;that will be displayed in the dialogue depending on the player's gender (example: MaleWord^FemaleWord)
DialogGenderWords=0
;To change the default and starting player models, uncomment the next four lines.
;The default models can also be changed ingame via script
;MaleStartModel=hmwarr
+69 -3
View File
@@ -58,6 +58,64 @@ static std::vector<std::string> msgFileList;
static long msgNumCounter = 0x3000;
static long heroIsFemale = -1;
#define MSG_GENDER_CHECK_FLG (0x8)
// Searches the special character in the text and removes the word depending on the player's gender
// example: MaleWord^FemaleWord
static long __fastcall ReplaceGenderWord(fo::MessageNode* msgData, DWORD* msgFile) {
if (!InDialog() || msgData->flags & MSG_GENDER_CHECK_FLG) return 1;
if (heroIsFemale < 0) heroIsFemale = fo::HeroIsFemale();
unsigned char* _pos = (u_char*)msgData->message;
unsigned char* pos;
while ((pos = (u_char*)std::strchr((char*)_pos, '^')) != 0) { // pos - pointer to the character position
_pos = pos + 1; // next start position
if (heroIsFemale) {
// keep the right word
for (u_char* n = pos - 1; ; n--) {
if (*n == ' ' || n < (u_char*)msgData->message) {
_pos = n + 1;
do *++n = *++pos; while (*pos); // shift all chars to the left
break; // exit for
}
}
} else {
// keep the left word
for (u_char* n = pos + 1; *n; n++) {
if (*n == ' ') {
do *pos++ = *n++; while (*n); // shift all chars to the left
break; // exit for
}
}
*pos = '\0';
if (_pos > pos) break;
}
}
// set flag
unsigned long outValue;
fo::func::message_find(msgFile, msgData->number, &outValue);
((fo::MessageNode*)(msgFile[1] + (outValue * 16)))->flags |= MSG_GENDER_CHECK_FLG;
return 1;
}
static void __declspec(naked) scr_get_msg_str_speech_hook() {
__asm {
call fo::funcoffs::message_search_;
cmp eax, 1;
jne end;
push ecx;
lea ecx, [esp + 8]; // message data
mov edx, [esp + 0x1C - 0x0C + 8]; // message file
call ReplaceGenderWord;
pop ecx;
end:
retn;
}
}
// 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 {
@@ -81,14 +139,14 @@ noFile:
}
}
fo::MessageNode *GetMsgNode(fo::MessageList *msgList, int msgRef) {
fo::MessageNode* GetMsgNode(fo::MessageList* msgList, int msgRef) {
if (msgList != nullptr && msgList->numMsgs > 0) {
fo::MessageNode *msgNode = msgList->nodes;
long last = msgList->numMsgs - 1;
long first = 0;
long mid;
//Use Binary Search to find msg
// Use Binary Search to find msg
while (first <= last) {
mid = (first + last) / 2;
if (msgRef > msgNode[mid].number)
@@ -102,7 +160,7 @@ fo::MessageNode *GetMsgNode(fo::MessageList *msgList, int msgRef) {
return nullptr;
}
char* GetMsg(fo::MessageList *msgList, int msgRef, int msgNum) {
char* GetMsg(fo::MessageList* msgList, int msgRef, int msgNum) {
fo::MessageNode *msgNode = GetMsgNode(msgList, msgRef);
if (msgNode) {
if (msgNum == 2) {
@@ -171,6 +229,7 @@ static void ClearScriptAddedExtraGameMsg() { // C++11
}
}
msgNumCounter = 0x3000;
heroIsFemale = -1;
}
static void FallbackEnglishLoadMsgFiles() {
@@ -189,6 +248,13 @@ static void ClearReadExtraGameMsgFiles() {
void Message::init() {
msgFileList = GetConfigList("Misc", "ExtraGameMsgFileList", "", 512);
if (GetConfigInt("Misc", "DialogGenderWords", 0)) {
dlog("Applying dialog gender words patch.", DL_INIT);
HookCall(0x4A6CEE, scr_get_msg_str_speech_hook);
SafeWrite16(0x484C62, 0x9090); // message_search_
dlogr(" Done", DL_INIT);
}
LoadGameHook::OnGameInit() += FallbackEnglishLoadMsgFiles;
LoadGameHook::OnBeforeGameStart() += ReadExtraGameMsgFiles;
LoadGameHook::OnBeforeGameClose() += ClearReadExtraGameMsgFiles;
+2 -2
View File
@@ -41,7 +41,7 @@ public:
static long AddExtraMsgFile(const char* msgName, long msgNumber);
};
fo::MessageNode *GetMsgNode(fo::MessageList *msgList, int msgRef);
char* GetMsg(fo::MessageList *MsgList, int msgRef, int msgNum);
fo::MessageNode* GetMsgNode(fo::MessageList* msgList, int msgRef);
char* GetMsg(fo::MessageList* msgList, int msgRef, int msgNum);
}