mirror of
https://github.com/alexbatalov/fallout2-ce.git
synced 2024-09-04 13:59:04 +00:00
parent
6c03e4e293
commit
fe9ba9171e
@ -2022,6 +2022,8 @@ int combatInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_COMBAT, &gCombatMessageList);
|
||||
|
||||
// SFALL
|
||||
criticalsInit();
|
||||
burstModInit();
|
||||
@ -2061,6 +2063,7 @@ void combatReset()
|
||||
// 0x420E14
|
||||
void combatExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_COMBAT, nullptr);
|
||||
messageListFree(&gCombatMessageList);
|
||||
|
||||
// SFALL
|
||||
|
@ -3433,6 +3433,8 @@ static int aiMessageListInit()
|
||||
messageListFilterBadwords(&gCombatAiMessageList);
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_COMBAT_AI, &gCombatAiMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3441,6 +3443,7 @@ static int aiMessageListInit()
|
||||
// 0x42BBD8
|
||||
static int aiMessageListFree()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_COMBAT_AI, nullptr);
|
||||
if (!messageListFree(&gCombatAiMessageList)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -178,6 +178,8 @@ int critterInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRNAME, &gCritterMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -193,6 +195,7 @@ void critterReset()
|
||||
// 0x42D004
|
||||
void critterExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRNAME, nullptr);
|
||||
messageListFree(&gCritterMessageList);
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,10 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Message list repository is considered a specialized file manager, so
|
||||
// it should be initialized early in the process.
|
||||
messageListRepositoryInit();
|
||||
|
||||
runElectronicRegistration();
|
||||
programWindowSetTitle(windowTitle);
|
||||
_initWindow(1, a4);
|
||||
@ -358,6 +362,8 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||
return -1;
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MISC, &gMiscMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -402,6 +408,7 @@ void gameReset()
|
||||
// SFALL
|
||||
sfallGlobalVarsReset();
|
||||
sfallListsReset();
|
||||
messageListRepositoryReset();
|
||||
}
|
||||
|
||||
// 0x442C34
|
||||
@ -415,6 +422,7 @@ void gameExit()
|
||||
premadeCharactersExit();
|
||||
|
||||
tileDisable();
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MISC, nullptr);
|
||||
messageListFree(&gMiscMessageList);
|
||||
combatExit();
|
||||
gameDialogExit();
|
||||
@ -448,6 +456,7 @@ void gameExit()
|
||||
endgameDeathEndingExit();
|
||||
interfaceFontsExit();
|
||||
_windowClose();
|
||||
messageListRepositoryExit();
|
||||
dbExit();
|
||||
settingsExit(true);
|
||||
sfallConfigExit();
|
||||
|
@ -201,6 +201,8 @@ int itemsInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_ITEM, &gItemsMessageList);
|
||||
|
||||
// SFALL
|
||||
booksInit();
|
||||
explosionsInit();
|
||||
@ -219,6 +221,7 @@ void itemsReset()
|
||||
// 0x477148
|
||||
void itemsExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_ITEM, nullptr);
|
||||
messageListFree(&gItemsMessageList);
|
||||
|
||||
// SFALL
|
||||
|
@ -306,6 +306,8 @@ void _map_init()
|
||||
tickersAdd(gameMouseRefresh);
|
||||
_gmouse_disable(0);
|
||||
windowUnhide(gIsoWindow);
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MAP, &gMapMessageList);
|
||||
}
|
||||
|
||||
// 0x482084
|
||||
@ -314,6 +316,8 @@ void _map_exit()
|
||||
windowHide(gIsoWindow);
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
tickersRemove(gameMouseRefresh);
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MAP, nullptr);
|
||||
if (!messageListFree(&gMapMessageList)) {
|
||||
debugPrint("\nError exiting map_msg_file!");
|
||||
}
|
||||
|
210
src/message.cc
210
src/message.cc
@ -5,6 +5,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
@ -17,11 +20,33 @@ namespace fallout {
|
||||
|
||||
#define BADWORD_LENGTH_MAX 80
|
||||
|
||||
static constexpr int kFirstStandardMessageListId = 0;
|
||||
static constexpr int kLastStandardMessageListId = kFirstStandardMessageListId + STANDARD_MESSAGE_LIST_COUNT - 1;
|
||||
|
||||
static constexpr int kFirstProtoMessageListId = 0x1000;
|
||||
static constexpr int kLastProtoMessageListId = kFirstProtoMessageListId + PROTO_MESSAGE_LIST_COUNT - 1;
|
||||
|
||||
static constexpr int kFirstPersistentMessageListId = 0x2000;
|
||||
static constexpr int kLastPersistentMessageListId = 0x2FFF;
|
||||
|
||||
static constexpr int kFirstTemporaryMessageListId = 0x3000;
|
||||
static constexpr int kLastTemporaryMessageListId = 0x3FFF;
|
||||
|
||||
struct MessageListRepositoryState {
|
||||
std::array<MessageList*, STANDARD_MESSAGE_LIST_COUNT> standardMessageLists;
|
||||
std::array<MessageList*, PROTO_MESSAGE_LIST_COUNT> protoMessageLists;
|
||||
std::unordered_map<int, MessageList*> persistentMessageLists;
|
||||
std::unordered_map<int, MessageList*> temporaryMessageLists;
|
||||
int nextTemporaryMessageListId = kFirstTemporaryMessageListId;
|
||||
};
|
||||
|
||||
static bool _message_find(MessageList* msg, int num, int* out_index);
|
||||
static bool _message_add(MessageList* msg, MessageListItem* new_entry);
|
||||
static bool _message_parse_number(int* out_num, const char* str);
|
||||
static int _message_load_field(File* file, char* str);
|
||||
|
||||
static MessageList* messageListRepositoryLoad(const char* path);
|
||||
|
||||
// 0x50B79C
|
||||
static char _Error_1[] = "Error";
|
||||
|
||||
@ -47,6 +72,8 @@ static char* _message_error_str = _Error_1;
|
||||
// 0x63207C
|
||||
static char _bad_copy[MESSAGE_LIST_ITEM_FIELD_MAX_SIZE];
|
||||
|
||||
static MessageListRepositoryState* _messageListRepositoryState;
|
||||
|
||||
// 0x484770
|
||||
int badwordsInit()
|
||||
{
|
||||
@ -604,4 +631,187 @@ void messageListFilterGenderWords(MessageList* messageList, int gender)
|
||||
}
|
||||
}
|
||||
|
||||
bool messageListRepositoryInit()
|
||||
{
|
||||
_messageListRepositoryState = new (std::nothrow) MessageListRepositoryState();
|
||||
if (_messageListRepositoryState == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* fileList;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY, &fileList);
|
||||
if (fileList != nullptr && *fileList == '\0') {
|
||||
fileList = nullptr;
|
||||
}
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
int nextMessageListId = 0;
|
||||
while (fileList != nullptr) {
|
||||
char* pch = strchr(fileList, ',');
|
||||
if (pch != nullptr) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
char* sep = strchr(fileList, ':');
|
||||
if (sep != nullptr) {
|
||||
*sep = '\0';
|
||||
nextMessageListId = atoi(sep + 1);
|
||||
}
|
||||
|
||||
sprintf(path, "%s\\%s.msg", "game", fileList);
|
||||
|
||||
if (sep != nullptr) {
|
||||
*sep = ':';
|
||||
}
|
||||
|
||||
MessageList* messageList = messageListRepositoryLoad(path);
|
||||
if (messageList != nullptr) {
|
||||
_messageListRepositoryState->persistentMessageLists[kFirstPersistentMessageListId + nextMessageListId] = messageList;
|
||||
}
|
||||
|
||||
if (pch != nullptr) {
|
||||
*pch = ',';
|
||||
fileList = pch + 1;
|
||||
} else {
|
||||
fileList = nullptr;
|
||||
}
|
||||
|
||||
// Sfall's implementation is a little bit odd. |nextMessageListId| can
|
||||
// be set via "key:value" pair in the config, so if the first pair is
|
||||
// "msg:12287", then this check will think it's the end of the loop.
|
||||
// In order to maintain compatibility we'll use the same approach,
|
||||
// however it looks like the whole idea of auto-numbering extra message
|
||||
// lists is a bad one. To use these extra message lists we need to
|
||||
// specify their ids from user-space scripts. Without explicitly
|
||||
// specifying message list ids as "key:value" pairs a mere change of
|
||||
// order in the config will break such scripts in an unexpected way.
|
||||
nextMessageListId++;
|
||||
if (nextMessageListId == kLastPersistentMessageListId - kFirstPersistentMessageListId + 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void messageListRepositoryReset()
|
||||
{
|
||||
for (auto& pair : _messageListRepositoryState->temporaryMessageLists) {
|
||||
messageListFree(pair.second);
|
||||
delete pair.second;
|
||||
}
|
||||
_messageListRepositoryState->temporaryMessageLists.clear();
|
||||
_messageListRepositoryState->nextTemporaryMessageListId = kFirstTemporaryMessageListId;
|
||||
}
|
||||
|
||||
void messageListRepositoryExit()
|
||||
{
|
||||
if (_messageListRepositoryState != nullptr) {
|
||||
for (auto& pair : _messageListRepositoryState->temporaryMessageLists) {
|
||||
messageListFree(pair.second);
|
||||
delete pair.second;
|
||||
}
|
||||
|
||||
for (auto& pair : _messageListRepositoryState->persistentMessageLists) {
|
||||
messageListFree(pair.second);
|
||||
delete pair.second;
|
||||
}
|
||||
|
||||
delete _messageListRepositoryState;
|
||||
_messageListRepositoryState = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void messageListRepositorySetStandardMessageList(int standardMessageList, MessageList* messageList)
|
||||
{
|
||||
_messageListRepositoryState->standardMessageLists[standardMessageList] = messageList;
|
||||
}
|
||||
|
||||
void messageListRepositorySetProtoMessageList(int protoMessageList, MessageList* messageList)
|
||||
{
|
||||
_messageListRepositoryState->protoMessageLists[protoMessageList] = messageList;
|
||||
}
|
||||
|
||||
int messageListRepositoryAddExtra(int messageListId, const char* path)
|
||||
{
|
||||
if (messageListId != 0) {
|
||||
// CE: Probably there is a bug in Sfall, when |messageListId| is
|
||||
// non-zero, it is enforced to be within persistent id range. That is
|
||||
// the scripting engine is allowed to add persistent message lists.
|
||||
// Everything added/changed by scripting engine should be temporary by
|
||||
// design.
|
||||
if (messageListId < kFirstPersistentMessageListId || messageListId > kLastPersistentMessageListId) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// CE: Sfall stores both persistent and temporary message lists in
|
||||
// one map, however since we've passed check above, we should only
|
||||
// check in persistent message lists.
|
||||
if (_messageListRepositoryState->persistentMessageLists.find(messageListId) != _messageListRepositoryState->persistentMessageLists.end()) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (_messageListRepositoryState->nextTemporaryMessageListId > kLastTemporaryMessageListId) {
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
MessageList* messageList = messageListRepositoryLoad(path);
|
||||
if (messageList == nullptr) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (messageListId == 0) {
|
||||
messageListId == _messageListRepositoryState->nextTemporaryMessageListId++;
|
||||
}
|
||||
|
||||
_messageListRepositoryState->temporaryMessageLists[messageListId] = messageList;
|
||||
|
||||
return messageListId;
|
||||
}
|
||||
|
||||
char* messageListRepositoryGetMsg(int messageListId, int messageId)
|
||||
{
|
||||
MessageList* messageList = nullptr;
|
||||
|
||||
if (messageListId >= kFirstStandardMessageListId && messageListId <= kLastStandardMessageListId) {
|
||||
messageList = _messageListRepositoryState->standardMessageLists[messageListId - kFirstStandardMessageListId];
|
||||
} else if (messageListId >= kFirstProtoMessageListId && messageListId <= kLastProtoMessageListId) {
|
||||
messageList = _messageListRepositoryState->protoMessageLists[messageListId - kFirstProtoMessageListId];
|
||||
} else if (messageListId >= kFirstPersistentMessageListId && messageListId <= kLastPersistentMessageListId) {
|
||||
auto it = _messageListRepositoryState->persistentMessageLists.find(messageListId);
|
||||
if (it != _messageListRepositoryState->persistentMessageLists.end()) {
|
||||
messageList = it->second;
|
||||
}
|
||||
} else if (messageListId >= kFirstTemporaryMessageListId && messageListId <= kLastTemporaryMessageListId) {
|
||||
auto it = _messageListRepositoryState->temporaryMessageLists.find(messageListId);
|
||||
if (it != _messageListRepositoryState->temporaryMessageLists.end()) {
|
||||
messageList = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
MessageListItem messageListItem;
|
||||
return getmsg(messageList, &messageListItem, messageId);
|
||||
}
|
||||
|
||||
static MessageList* messageListRepositoryLoad(const char* path)
|
||||
{
|
||||
MessageList* messageList = new (std::nothrow) MessageList();
|
||||
if (messageList == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!messageListInit(messageList)) {
|
||||
delete messageList;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!messageListLoad(messageList, path)) {
|
||||
delete messageList;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return messageList;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
@ -7,6 +7,57 @@ namespace fallout {
|
||||
|
||||
#define MESSAGE_LIST_ITEM_FIELD_MAX_SIZE 1024
|
||||
|
||||
// CE: Working with standard message lists is tricky in Sfall. Many message
|
||||
// lists are initialized only for the duration of appropriate modal window. This
|
||||
// is not documented in Sfall and shifts too much responsibility to scripters
|
||||
// (who should check game mode before accessing volatile message lists). For now
|
||||
// CE only exposes persistent standard message lists:
|
||||
// - combat.msg
|
||||
// - combatai.msg
|
||||
// - scrname.msg
|
||||
// - misc.msg
|
||||
// - item.msg
|
||||
// - map.msg
|
||||
// - proto.msg
|
||||
// - script.msg
|
||||
// - skill.msg
|
||||
// - stat.msg
|
||||
// - trait.msg
|
||||
// - worldmap.msg
|
||||
enum StandardMessageList {
|
||||
STANDARD_MESSAGE_LIST_COMBAT,
|
||||
STANDARD_MESSAGE_LIST_COMBAT_AI,
|
||||
STANDARD_MESSAGE_LIST_SCRNAME,
|
||||
STANDARD_MESSAGE_LIST_MISC,
|
||||
STANDARD_MESSAGE_LIST_CUSTOM,
|
||||
STANDARD_MESSAGE_LIST_INVENTORY,
|
||||
STANDARD_MESSAGE_LIST_ITEM,
|
||||
STANDARD_MESSAGE_LIST_LSGAME,
|
||||
STANDARD_MESSAGE_LIST_MAP,
|
||||
STANDARD_MESSAGE_LIST_OPTIONS,
|
||||
STANDARD_MESSAGE_LIST_PERK,
|
||||
STANDARD_MESSAGE_LIST_PIPBOY,
|
||||
STANDARD_MESSAGE_LIST_QUESTS,
|
||||
STANDARD_MESSAGE_LIST_PROTO,
|
||||
STANDARD_MESSAGE_LIST_SCRIPT,
|
||||
STANDARD_MESSAGE_LIST_SKILL,
|
||||
STANDARD_MESSAGE_LIST_SKILLDEX,
|
||||
STANDARD_MESSAGE_LIST_STAT,
|
||||
STANDARD_MESSAGE_LIST_TRAIT,
|
||||
STANDARD_MESSAGE_LIST_WORLDMAP,
|
||||
STANDARD_MESSAGE_LIST_COUNT,
|
||||
};
|
||||
|
||||
enum {
|
||||
PROTO_MESSAGE_LIST_ITEMS,
|
||||
PROTO_MESSAGE_LIST_CRITTERS,
|
||||
PROTO_MESSAGE_LIST_SCENERY,
|
||||
PROTO_MESSAGE_LIST_TILES,
|
||||
PROTO_MESSAGE_LIST_WALLS,
|
||||
PROTO_MESSAGE_LIST_MISC,
|
||||
PROTO_MESSAGE_LIST_COUNT,
|
||||
};
|
||||
|
||||
typedef struct MessageListItem {
|
||||
int num;
|
||||
int flags;
|
||||
@ -31,6 +82,14 @@ bool messageListFilterBadwords(MessageList* messageList);
|
||||
|
||||
void messageListFilterGenderWords(MessageList* messageList, int gender);
|
||||
|
||||
bool messageListRepositoryInit();
|
||||
void messageListRepositoryReset();
|
||||
void messageListRepositoryExit();
|
||||
void messageListRepositorySetStandardMessageList(int messageListId, MessageList* messageList);
|
||||
void messageListRepositorySetProtoMessageList(int messageListId, MessageList* messageList);
|
||||
int messageListRepositoryAddExtra(int messageListId, const char* path);
|
||||
char* messageListRepositoryGetMsg(int messageListId, int messageId);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* MESSAGE_H */
|
||||
|
@ -212,6 +212,8 @@ int perksInit()
|
||||
}
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_PERK, &gPerksMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -224,6 +226,7 @@ void perksReset()
|
||||
// 0x4966B8
|
||||
void perksExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_PERK, nullptr);
|
||||
messageListFree(&gPerksMessageList);
|
||||
|
||||
if (gPartyMemberPerkRanks != NULL) {
|
||||
|
@ -1111,6 +1111,10 @@ int protoInit()
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
messageListRepositorySetProtoMessageList(i, &(_proto_msg_files[i]));
|
||||
}
|
||||
|
||||
_mp_critter_stats_list = _aDrugStatSpecia;
|
||||
_critter_stats_list = _critter_stats_list_strs;
|
||||
_critter_stats_list_None = _aNone_1;
|
||||
@ -1181,6 +1185,8 @@ int protoInit()
|
||||
gBodyTypeNames[i] = getmsg(&gProtoMessageList, &messageListItem, 400 + i);
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_PROTO, &gProtoMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1218,9 +1224,11 @@ void protoExit()
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
messageListRepositorySetProtoMessageList(i, nullptr);
|
||||
messageListFree(&(_proto_msg_files[i]));
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_PROTO, nullptr);
|
||||
messageListFree(&gProtoMessageList);
|
||||
}
|
||||
|
||||
|
@ -1521,6 +1521,8 @@ int scriptsInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRIPT, &gScrMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1576,6 +1578,8 @@ int _scr_game_init()
|
||||
// NOTE: Uninline.
|
||||
scriptsClearPendingRequests();
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRIPT, &gScrMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1595,6 +1599,8 @@ int scriptsExit()
|
||||
{
|
||||
gScriptsEnabled = false;
|
||||
_script_engine_run_critters = 0;
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRIPT, nullptr);
|
||||
if (!messageListFree(&gScrMessageList)) {
|
||||
debugPrint("\nError exiting script message file!");
|
||||
return -1;
|
||||
@ -1646,6 +1652,7 @@ int _scr_game_exit()
|
||||
_scr_remove_all();
|
||||
programListFree();
|
||||
tickersRemove(_doBkProcesses);
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRIPT, nullptr);
|
||||
messageListFree(&gScrMessageList);
|
||||
if (scriptsClearDudeScript() == -1) {
|
||||
return -1;
|
||||
|
@ -49,6 +49,7 @@ bool sfallConfigInit(int argc, char** argv)
|
||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_CENTER_DIVISOR_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR);
|
||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_MULTIPLIER_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_MULTIPLIER);
|
||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_DIVISOR_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_DIVISOR);
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY, "");
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
char* executable = argv[0];
|
||||
|
@ -59,6 +59,7 @@ namespace fallout {
|
||||
#define SFALL_CONFIG_TWEAKS_FILE_KEY "TweaksFile"
|
||||
#define SFALL_CONFIG_GAME_DIALOG_GENDER_WORDS_KEY "DialogGenderWords"
|
||||
#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY "TownMapHotkeysFix"
|
||||
#define SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY "ExtraGameMsgFileList"
|
||||
|
||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
|
||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "interface.h"
|
||||
#include "interpreter.h"
|
||||
#include "item.h"
|
||||
#include "message.h"
|
||||
#include "mouse.h"
|
||||
#include "object.h"
|
||||
#include "sfall_global_vars.h"
|
||||
@ -223,6 +224,15 @@ static void opGetStringLength(Program* program)
|
||||
programStackPushInteger(program, static_cast<int>(strlen(string)));
|
||||
}
|
||||
|
||||
// message_str_game
|
||||
static void opGetMessage(Program* program)
|
||||
{
|
||||
int messageId = programStackPopInteger(program);
|
||||
int messageListId = programStackPopInteger(program);
|
||||
char* text = messageListRepositoryGetMsg(messageListId, messageId);
|
||||
programStackPushString(program, text);
|
||||
}
|
||||
|
||||
// round
|
||||
static void opRound(Program* program)
|
||||
{
|
||||
@ -262,6 +272,7 @@ void sfallOpcodesInit()
|
||||
interpreterRegisterOpcode(0x8221, opGetScreenHeight);
|
||||
interpreterRegisterOpcode(0x8237, opParseInt);
|
||||
interpreterRegisterOpcode(0x824F, opGetStringLength);
|
||||
interpreterRegisterOpcode(0x826B, opGetMessage);
|
||||
interpreterRegisterOpcode(0x8267, opRound);
|
||||
interpreterRegisterOpcode(0x8274, opArtExists);
|
||||
}
|
||||
|
@ -158,6 +158,8 @@ int skillsInit()
|
||||
// NOTE: Uninline.
|
||||
skill_use_slot_clear();
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SKILL, &gSkillsMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -175,6 +177,7 @@ void skillsReset()
|
||||
// 0x4AA478
|
||||
void skillsExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SKILL, nullptr);
|
||||
messageListFree(&gSkillsMessageList);
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,8 @@ int statsInit()
|
||||
gStatValueDescriptions[index] = getmsg(&gStatsMessageList, &messageListItem, 301 + index);
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_STAT, &gStatsMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -146,6 +148,7 @@ int statsReset()
|
||||
// 0x4AEEE4
|
||||
int statsExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_STAT, nullptr);
|
||||
messageListFree(&gStatsMessageList);
|
||||
|
||||
return 0;
|
||||
|
@ -85,6 +85,8 @@ int traitsInit()
|
||||
// NOTE: Uninline.
|
||||
traitsReset();
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_TRAIT, &gTraitsMessageList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -99,6 +101,7 @@ void traitsReset()
|
||||
// 0x4B3AF8
|
||||
void traitsExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_TRAIT, nullptr);
|
||||
messageListFree(&gTraitsMessageList);
|
||||
}
|
||||
|
||||
|
@ -858,6 +858,8 @@ int wmWorldMap_init()
|
||||
citySizeDescription->fid = buildFid(OBJ_TYPE_INTERFACE, 336 + citySize, 0, 0, 0);
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_WORLDMAP, &wmMsgFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1010,6 +1012,7 @@ void wmWorldMap_exit()
|
||||
circleBlendTable = NULL;
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_WORLDMAP, nullptr);
|
||||
messageListFree(&wmMsgFile);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user