mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added language path for loading fonts (#368)
Some code fixes to support the language path.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
UseCommandLine=0
|
||||
|
||||
;Uncomment and point to a file to get alternate translations for some sfall messages
|
||||
;This file can be placed in text\<language>\ for sfall to get the translations depending on the game language
|
||||
;TranslationsINI=sfall\Translations.ini
|
||||
|
||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
+51
-8
@@ -508,18 +508,52 @@ long __fastcall fo_get_game_config_string(const char** outValue, const char* sec
|
||||
|
||||
static MSGNode messageBuf;
|
||||
|
||||
const char* GetMessageStr(const MSGList* fileAddr, long messageId) {
|
||||
return fo_getmsg(fileAddr, &messageBuf, messageId);
|
||||
const char* GetMessageStr(const MSGList* file, long messageId) {
|
||||
return fo_getmsg(file, &messageBuf, messageId);
|
||||
}
|
||||
|
||||
const char* MessageSearch(const MSGList* fileAddr, long messageId) {
|
||||
const char* MessageSearch(const MSGList* file, long messageId) {
|
||||
messageBuf.number = messageId;
|
||||
if (fo_message_search(fileAddr, &messageBuf) == 1) {
|
||||
if (fo_message_search(file, &messageBuf) == 1) {
|
||||
return messageBuf.message;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MSGNode* GetMsgNode(MSGList* msgList, int msgNum) {
|
||||
if (msgList != nullptr && msgList->numMsgs > 0) {
|
||||
MSGNode *msgNode = msgList->nodes;
|
||||
long last = msgList->numMsgs - 1;
|
||||
long first = 0;
|
||||
long mid;
|
||||
|
||||
// Use Binary Search to find msg
|
||||
while (first <= last) {
|
||||
mid = (first + last) / 2;
|
||||
if (msgNum > msgNode[mid].number)
|
||||
first = mid + 1;
|
||||
else if (msgNum < msgNode[mid].number)
|
||||
last = mid - 1;
|
||||
else
|
||||
return &msgNode[mid];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Alternative version of getmsg_ function
|
||||
char* GetMsg(MSGList* msgList, int msgNum, int msgType) {
|
||||
MSGNode *msgNode = GetMsgNode(msgList, msgNum);
|
||||
if (msgNode) {
|
||||
if (msgType == 2) {
|
||||
return msgNode->message;
|
||||
} else if (msgType == 1) {
|
||||
return msgNode->audio;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Queue* QueueFind(TGameObj* object, long type) {
|
||||
if (*ptr_queue) {
|
||||
Queue* queue = *ptr_queue;
|
||||
@@ -981,14 +1015,23 @@ static bool LoadFrmFrame(UNLSTDfrm::Frame *frame, DbFile* frmStream) {
|
||||
UNLSTDfrm *LoadUnlistedFrm(char *frmName, unsigned int folderRef) {
|
||||
if (folderRef > OBJ_TYPE_SKILLDEX) return nullptr;
|
||||
|
||||
char *artfolder = ptr_art[folderRef].path; // address of art type name
|
||||
char FrmPath[MAX_PATH];
|
||||
const char *artfolder = ptr_art[folderRef].path; // address of art type name
|
||||
char frmPath[MAX_PATH];
|
||||
|
||||
sprintf_s(FrmPath, MAX_PATH, "art\\%s\\%s", artfolder, frmName);
|
||||
if (*ptr_use_language) {
|
||||
sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s\\%s", (const char*)ptr_language, artfolder, frmName);
|
||||
} else {
|
||||
sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s", artfolder, frmName);
|
||||
}
|
||||
|
||||
UNLSTDfrm *frm = new UNLSTDfrm;
|
||||
|
||||
DbFile* frmStream = fo_xfopen(FrmPath, "rb");
|
||||
DbFile* frmStream = fo_db_fopen(frmPath, "rb");
|
||||
|
||||
if (!frmStream && *ptr_use_language) {
|
||||
sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s", artfolder, frmName);
|
||||
frmStream = fo_db_fopen(frmPath, "rb");
|
||||
}
|
||||
|
||||
if (frmStream != nullptr) {
|
||||
if (!LoadFrmHeader(frm, frmStream)) {
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
// Global variable offsets
|
||||
// TODO: probably need to hide these by moving inside implementation file
|
||||
|
||||
#define FO_VAR_aDialogS_msg 0x50DBE8
|
||||
#define FO_VAR_aiInfoList 0x510948
|
||||
#define FO_VAR_ambient_light 0x51923C
|
||||
#define FO_VAR_anim_set 0x54CC14
|
||||
@@ -42,6 +43,9 @@
|
||||
#define FO_VAR_art_vault_guy_num 0x5108A4
|
||||
#define FO_VAR_art_vault_person_nums 0x5108A8
|
||||
#define FO_VAR_artCritterFidShouldRunData 0x56CAF0
|
||||
#define FO_VAR_aTextSCuts 0x501A8C
|
||||
#define FO_VAR_aTextSCutsS 0x503530
|
||||
#define FO_VAR_aTextSCutsSS 0x50B01C
|
||||
#define FO_VAR_background_volume 0x518E88
|
||||
#define FO_VAR_bboxslot 0x5970E0
|
||||
#define FO_VAR_bckgnd 0x5707A4
|
||||
@@ -154,6 +158,7 @@
|
||||
#define FO_VAR_itemButtonItems 0x5970F8
|
||||
#define FO_VAR_itemCurrentItem 0x518F78
|
||||
#define FO_VAR_kb_lock_flags 0x51E2EA
|
||||
#define FO_VAR_language 0x56C970 // aka _darn_foreign_sub_path
|
||||
#define FO_VAR_last_buttons 0x51E2AC
|
||||
#define FO_VAR_last_button_winID 0x51E404
|
||||
#define FO_VAR_last_level 0x5707B4
|
||||
@@ -293,6 +298,7 @@
|
||||
#define FO_VAR_title_color 0x56D750
|
||||
#define FO_VAR_title_font 0x56D748
|
||||
#define FO_VAR_trait_data 0x51DB84
|
||||
#define FO_VAR_use_language 0x510898 // aka _darn_foreigners
|
||||
#define FO_VAR_view_page 0x664520
|
||||
#define FO_VAR_wd_obj 0x59E98C
|
||||
#define FO_VAR_window 0x6ADE58
|
||||
@@ -505,6 +511,10 @@ const char* GetMessageStr(const MSGList* fileAddr, long messageId);
|
||||
// similar to GetMessageStr, but returns nullptr when no message is found
|
||||
const char* MessageSearch(const MSGList* fileAddr, long messageId);
|
||||
|
||||
MSGNode* GetMsgNode(MSGList* msgList, int msgNum);
|
||||
|
||||
char* GetMsg(MSGList* msgList, int msgNum, int msgType);
|
||||
|
||||
Queue* QueueFind(TGameObj* object, long type);
|
||||
|
||||
// returns weapon animation code
|
||||
|
||||
@@ -90,6 +90,7 @@ PTR_(inventry_message_file, MSGList)
|
||||
PTR_(itemButtonItems, ItemButtonItem) // array of 2 ItemButtonItem, 0 - left, 1 - right
|
||||
PTR_(itemCurrentItem, long) // 0 - left, 1 - right
|
||||
PTR_(kb_lock_flags, DWORD)
|
||||
PTR_(language, char) // array of 32 char
|
||||
PTR_(last_buttons, DWORD)
|
||||
PTR_(last_button_winID, DWORD)
|
||||
PTR_(last_level, DWORD)
|
||||
@@ -212,7 +213,8 @@ PTR_(text_width, DWORD)
|
||||
PTR_(tile, DWORD)
|
||||
PTR_(title_color, DWORD)
|
||||
PTR_(title_font, DWORD)
|
||||
PTR_(trait_data, TraitInfo) // // array of size == TRAIT_count
|
||||
PTR_(trait_data, TraitInfo) // array of size == TRAIT_count
|
||||
PTR_(use_language, DWORD)
|
||||
PTR_(view_page, DWORD)
|
||||
PTR_(wd_obj, DWORD)
|
||||
PTR_(window, WINinfo*) // array of 50 WINinfo*
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "IniReader.h"
|
||||
|
||||
DWORD IniReader_modifiedIni;
|
||||
DWORD modifiedIni;
|
||||
|
||||
static const char* ddrawIni = ".\\ddraw.ini";
|
||||
static char ini[65] = ".\\";
|
||||
@@ -107,5 +107,5 @@ int SetConfigInt(const char* section, const char* setting, int value) {
|
||||
}
|
||||
|
||||
void IniReader_Init() {
|
||||
IniReader_modifiedIni = GetConfigInt("Main", "ModifiedIni", 0);
|
||||
modifiedIni = GetConfigInt("Main", "ModifiedIni", 0);
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
extern DWORD IniReader_modifiedIni;
|
||||
extern DWORD modifiedIni;
|
||||
|
||||
void IniReader_Init();
|
||||
|
||||
|
||||
@@ -283,6 +283,32 @@ artNotExist:
|
||||
}
|
||||
}
|
||||
|
||||
static DbFile* __fastcall LoadFont(const char* font, const char* mode) {
|
||||
char file[128];
|
||||
const char* lang;
|
||||
if (fo_get_game_config_string(&lang, "system", "language") && _stricmp(lang, "english") != 0) {
|
||||
std::sprintf(file, "%s\\%s", lang, font);
|
||||
return fo_db_fopen(file, mode);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void __declspec(naked) load_font_hook() {
|
||||
__asm {
|
||||
mov ebp, edx;
|
||||
mov ebx, eax;
|
||||
mov ecx, eax;
|
||||
call LoadFont;
|
||||
test eax, eax;
|
||||
jz default;
|
||||
retn;
|
||||
default:
|
||||
mov edx, ebp;
|
||||
mov eax, ebx;
|
||||
jmp db_fopen_;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadOrder_OnGameLoad() {
|
||||
savPrototypes.clear();
|
||||
RemoveSavFiles();
|
||||
@@ -318,4 +344,11 @@ void LoadOrder_Init() {
|
||||
MakeCall(0x47FB80, SlotMap2Game_hack); // load game
|
||||
MakeCall(0x47FBBF, SlotMap2Game_hack_attr, 1);
|
||||
dlogr(" Done", DL_INIT);
|
||||
|
||||
// Load fonts based on the game language
|
||||
const DWORD loadFontAddr[] = {
|
||||
0x4D5621, // load_font_
|
||||
0x441D58 // FMLoadFont_
|
||||
};
|
||||
HookCalls(load_font_hook, loadFontAddr);
|
||||
}
|
||||
|
||||
+1
-34
@@ -48,7 +48,7 @@ const MSGList* gameMsgFiles[] = {
|
||||
};
|
||||
#undef CASTMSG
|
||||
|
||||
static char gameLanguage[41]; // max length of language string is 40
|
||||
static char gameLanguage[32]; // (max length of language string is 40)
|
||||
|
||||
const char* Message_GameLanguage() {
|
||||
return &gameLanguage[0];
|
||||
@@ -82,39 +82,6 @@ noFile:
|
||||
}
|
||||
}
|
||||
|
||||
MSGNode* GetMsgNode(MSGList* msgList, int msgRef) {
|
||||
if (msgList != nullptr && msgList->numMsgs > 0) {
|
||||
MSGNode *MsgNode = msgList->nodes;
|
||||
long last = msgList->numMsgs - 1;
|
||||
long first = 0;
|
||||
long mid;
|
||||
|
||||
// Use Binary Search to find msg
|
||||
while (first <= last) {
|
||||
mid = (first + last) / 2;
|
||||
if (msgRef > MsgNode[mid].number)
|
||||
first = mid + 1;
|
||||
else if (msgRef < MsgNode[mid].number)
|
||||
last = mid - 1;
|
||||
else
|
||||
return &MsgNode[mid];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* GetMsg(MSGList* msgList, int msgRef, int msgNum) {
|
||||
MSGNode *msgNode = GetMsgNode(msgList, msgRef);
|
||||
if (msgNode) {
|
||||
if (msgNum == 2) {
|
||||
return msgNode->message;
|
||||
} else if (msgNum == 1) {
|
||||
return msgNode->audio;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ReadExtraGameMsgFiles() {
|
||||
if (!msgFileList.empty()) {
|
||||
int number = 0;
|
||||
|
||||
+1
-4
@@ -21,7 +21,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "main.h"
|
||||
#include "FalloutEngine.h"
|
||||
//#include "FalloutEngine.h"
|
||||
|
||||
#define MSG_FILE_COMBAT (0x56D368)
|
||||
#define MSG_FILE_AI (0x56D510)
|
||||
@@ -58,6 +58,3 @@ void ClearScriptAddedExtraGameMsg();
|
||||
const char* Message_GameLanguage();
|
||||
|
||||
long __stdcall Message_AddExtraMsgFile(const char* msgName, long msgNumber);
|
||||
|
||||
MSGNode* GetMsgNode(MSGList* msgList, int msgRef);
|
||||
char* GetMsg(MSGList* msgList, int msgRef, int msgNum);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "ScriptExtender.h"
|
||||
|
||||
static char mapName[17] = {};
|
||||
static char mapName[16] = {};
|
||||
static char patchName[65] = {};
|
||||
static char versionString[65] = {};
|
||||
|
||||
@@ -711,7 +711,7 @@ static void EngineOptimizationPatches() {
|
||||
void MiscPatches_Init() {
|
||||
EngineOptimizationPatches();
|
||||
|
||||
if (GetConfigString("Misc", "StartingMap", "", mapName, 17)) {
|
||||
if (GetConfigString("Misc", "StartingMap", "", mapName, 16)) {
|
||||
dlog("Applying starting map patch.", DL_INIT);
|
||||
SafeWrite32(0x480AAA, (DWORD)&mapName);
|
||||
dlogr(" Done", DL_INIT);
|
||||
|
||||
@@ -21,19 +21,19 @@
|
||||
#include "Logging.h"
|
||||
#include "SafeWrite.h"
|
||||
|
||||
static char startMaleModelName[65] = {};
|
||||
static char startMaleModelName[33] = {};
|
||||
char defaultMaleModelName[65] = {};
|
||||
static char startFemaleModelName[65] = {};
|
||||
static char startFemaleModelName[33] = {};
|
||||
char defaultFemaleModelName[65] = {};
|
||||
|
||||
void PlayerModel_Init() {
|
||||
if (GetConfigString("Misc", "MaleStartModel", "", startMaleModelName, 65)) {
|
||||
if (GetConfigString("Misc", "MaleStartModel", "", startMaleModelName, 33)) {
|
||||
dlog("Applying male start model patch.", DL_INIT);
|
||||
SafeWrite32(0x418B88, (DWORD)&startMaleModelName);
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
if (GetConfigString("Misc", "FemaleStartModel", "", startFemaleModelName, 65)) {
|
||||
if (GetConfigString("Misc", "FemaleStartModel", "", startFemaleModelName, 33)) {
|
||||
dlog("Applying female start model patch.", DL_INIT);
|
||||
SafeWrite32(0x418BAB, (DWORD)&startFemaleModelName);
|
||||
dlogr(" Done", DL_INIT);
|
||||
|
||||
+2
-2
@@ -23,14 +23,14 @@
|
||||
static PremadeChar* premade;
|
||||
|
||||
static const char* __fastcall GetLangPremadePath(const char* premadePath) {
|
||||
static char premadeLangPath[65]; // premade\<language>\combat.bio
|
||||
static char premadeLangPath[56]; // premade\<language>\combat.bio
|
||||
static bool isDefault = false;
|
||||
static long len = 0;
|
||||
|
||||
if (isDefault) return nullptr;
|
||||
if (len == 0) {
|
||||
len = std::strlen(Message_GameLanguage());
|
||||
if (len == 0 || len > 40) {
|
||||
if (len == 0 || len >= 32) {
|
||||
isDefault = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -568,16 +568,27 @@ static FrmFile* __stdcall LoadArtFile(const char* file, long frame, long directi
|
||||
return frmPtr;
|
||||
}
|
||||
|
||||
static long __stdcall GetArtFIDFile(long fid, const char* &file) {
|
||||
static long __stdcall GetArtFIDFile(long fid, char* outFilePath) {
|
||||
long direction = 0;
|
||||
long _fid = fid & 0xFFFFFFF;
|
||||
file = fo_art_get_name(_fid); // .frm
|
||||
|
||||
const char* artPathName = fo_art_get_name(_fid); // <cd>\art\type\file.frm
|
||||
|
||||
if (_fid >> 24 == OBJ_TYPE_CRITTER) {
|
||||
direction = (fid >> 28);
|
||||
if (direction > 0 && !fo_db_access(file)) {
|
||||
file = fo_art_get_name(fid); // .fr#
|
||||
if (direction > 0 && !fo_db_access(artPathName)) {
|
||||
artPathName = fo_art_get_name(fid); // .fr#
|
||||
}
|
||||
} else {
|
||||
if (*ptr_use_language) {
|
||||
const char* _artPathName = std::strchr(artPathName, '\\');
|
||||
if (_artPathName && *(++_artPathName)) {
|
||||
sprintf_s(outFilePath, MAX_PATH, "art\\%s\\%s", (const char*)ptr_language, _artPathName);
|
||||
if (fo_db_access(outFilePath)) return direction;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::strcpy(outFilePath, artPathName);
|
||||
return direction;
|
||||
}
|
||||
|
||||
@@ -594,7 +605,9 @@ static long __stdcall DrawImage(OpcodeHandler& opHandler, bool isScaled, const c
|
||||
long fid = opHandler.arg(0).rawValue();
|
||||
if (fid == -1) return -1;
|
||||
|
||||
direction = GetArtFIDFile(fid, file);
|
||||
char fileBuf[MAX_PATH];
|
||||
direction = GetArtFIDFile(fid, fileBuf);
|
||||
file = fileBuf;
|
||||
} else {
|
||||
file = opHandler.arg(0).strValue(); // path to frm/pcx file
|
||||
}
|
||||
@@ -664,7 +677,10 @@ static long __stdcall InterfaceDrawImage(OpcodeHandler& opHandler, WINinfo* ifac
|
||||
if (fid == -1) return -1;
|
||||
|
||||
useShift = (((fid & 0xF000000) >> 24) == OBJ_TYPE_CRITTER);
|
||||
direction = GetArtFIDFile(fid, file);
|
||||
|
||||
char fileBuf[MAX_PATH];
|
||||
direction = GetArtFIDFile(fid, fileBuf);
|
||||
file = fileBuf;
|
||||
} else {
|
||||
file = opHandler.arg(1).strValue(); // path to frm/pcx file
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ fail:
|
||||
|
||||
static void __declspec(naked) op_modified_ini() {
|
||||
__asm {
|
||||
mov edx, IniReader_modifiedIni;
|
||||
mov edx, modifiedIni;
|
||||
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user