mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
119 lines
3.6 KiB
C++
119 lines
3.6 KiB
C++
/*
|
|
* sfall
|
|
* Copyright (C) 2009, 2010 The sfall team
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "..\main.h"
|
|
#include "..\FalloutEngine\Fallout2.h"
|
|
#include "Message.h"
|
|
|
|
#include "Premade.h"
|
|
|
|
namespace sfall
|
|
{
|
|
|
|
static fo::PremadeChar* premade;
|
|
|
|
static const char* __fastcall GetLangPremadePath(const char* premadePath) {
|
|
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 >= 32) {
|
|
isDefault = true;
|
|
return nullptr;
|
|
}
|
|
isDefault = (_stricmp(Message::GameLanguage(), "english") == 0);
|
|
if (isDefault) return nullptr;
|
|
|
|
std::strncpy(premadeLangPath, premadePath, 8);
|
|
std::strcpy(&premadeLangPath[8], Message::GameLanguage());
|
|
}
|
|
std::strcpy(&premadeLangPath[8 + len], &premadePath[7]);
|
|
|
|
return premadeLangPath;
|
|
}
|
|
|
|
static const char* __fastcall PremadeGCD(const char* premadePath) {
|
|
const char* path = GetLangPremadePath(premadePath);
|
|
return (path && fo::func::db_access(path)) ? path : premadePath;
|
|
}
|
|
|
|
static fo::DbFile* __fastcall PremadeBIO(const char* premadePath, const char* mode) {
|
|
premadePath = GetLangPremadePath(premadePath);
|
|
return (premadePath) ? fo::func::db_fopen(premadePath, mode) : nullptr;
|
|
}
|
|
|
|
static void __declspec(naked) select_display_bio_hook() {
|
|
__asm {
|
|
push eax;
|
|
push edx;
|
|
mov ecx, eax; // premade path
|
|
call PremadeBIO;
|
|
test eax, eax;
|
|
jz default;
|
|
add esp, 8;
|
|
retn;
|
|
default:
|
|
pop edx;
|
|
pop eax;
|
|
jmp fo::funcoffs::db_fopen_;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) select_update_display_hook() {
|
|
__asm {
|
|
mov ecx, eax; // premade path
|
|
call PremadeGCD;
|
|
jmp fo::funcoffs::proto_dude_init_;
|
|
}
|
|
}
|
|
|
|
void Premade::init() {
|
|
auto premadePaths = IniReader::GetConfigList("misc", "PremadePaths", "", 512);
|
|
auto premadeFids = IniReader::GetConfigList("misc", "PremadeFIDs", "", 512);
|
|
if (!premadePaths.empty() && !premadeFids.empty()) {
|
|
dlog("Applying premade characters patch.", DL_INIT);
|
|
int count = min(premadePaths.size(), premadeFids.size());
|
|
premade = new fo::PremadeChar[count];
|
|
for (int i = 0; i < count; i++) {
|
|
auto path = "premade\\" + premadePaths[i];
|
|
if (path.size() > 19) {
|
|
dlog_f(" Failed: %s exceeds 11 characters\n", DL_INIT, premadePaths[i].c_str());
|
|
return;
|
|
}
|
|
std::strcpy(premade[i].path, path.c_str());
|
|
premade[i].fid = atoi(premadeFids[i].c_str());
|
|
}
|
|
|
|
SafeWrite32(0x51C8D4, count); // _premade_total
|
|
SafeWrite32(0x4A7D76, (DWORD)premade); // select_update_display_
|
|
SafeWrite32(0x4A8B1E, (DWORD)premade); // select_display_bio_
|
|
SafeWrite32(0x4A7E2C, (DWORD)&premade[0].fid); // select_display_portrait_
|
|
std::strcpy((char*)0x50AF68, premade[0].path); // for selfrun
|
|
dlogr(" Done", DL_INIT);
|
|
}
|
|
|
|
// Add language path for premade GCD/BIO files
|
|
HookCall(0x4A8B44, select_display_bio_hook);
|
|
HookCall(0x4A7D91, select_update_display_hook);
|
|
}
|
|
|
|
}
|