Add config_load metarule to efficiently load INI into array and also load INI from DAT

- Refactoring: moved all ini-related handlers into new cpp
- Moved modified_ini opcode to C++
This commit is contained in:
phobos2077
2023-06-15 19:01:07 +02:00
parent 3f7ce8c412
commit e4ea3645d6
16 changed files with 347 additions and 209 deletions
+4 -2
View File
@@ -27,8 +27,10 @@ using namespace fo;
namespace sfall
{
//constexpr size_t MaxKeyLength = 260;
//constexpr size_t MaxValueLength = 512;
const Config::Data& Config::data()
{
return _data;
}
bool Config::read(const char* filePath, bool isDb)
{
+10 -4
View File
@@ -18,29 +18,35 @@
#pragma once
#include <map>
#include <unordered_map>
#include <string>
namespace sfall
{
/*
Implements reading from INI-like text config files in normal and DAT-filesystem.
100% compatible with Fallout TXT config formats (such as worldmap.txt).
*/
class Config {
public:
typedef std::map<std::string, std::string> Section;
typedef std::map<std::string, Section> Data;
bool read(const char* filePath, bool isDb);
bool getString(const char* sectionKey, const char* key, const std::string*& outValue);
bool getInt(const char* sectionKey, const char* key, int& outValue, unsigned char base = 0);
bool getDouble(const char* sectionKey, const char* key, double& outValue);
const Data& data();
// TODO:
// bool write(const char* filePath, bool isDb);
// bool setString(const char* sectionKey, const char* key, const char* value);
// bool setInt(const char* sectionKey, const char* key, int value);
// bool setDouble(const char* sectionKey, const char* key, double value);
private:
typedef std::map<std::string, std::string> Section;
typedef std::map<std::string, Section> Data;
std::string _lastSection;
Data _data;
+4 -4
View File
@@ -34,7 +34,7 @@ static char ini[65] = ".\\";
static std::unordered_map<std::string, std::unique_ptr<Config>> iniCache;
static Config* GetIniConfig(const char* iniFile) {
Config* IniReader::GetIniConfig(const char* iniFile) {
std::string pathStr(iniFile);
auto cacheHit = iniCache.find(pathStr);
if (cacheHit != iniCache.end()) {
@@ -49,7 +49,7 @@ static Config* GetIniConfig(const char* iniFile) {
}
static int getInt(const char* section, const char* setting, int defaultValue, const char* iniFile) {
auto config = GetIniConfig(iniFile);
auto config = IniReader::GetIniConfig(iniFile);
int value;
if (config == nullptr || !config->getInt(section, setting, value)) {
value = defaultValue;
@@ -58,7 +58,7 @@ static int getInt(const char* section, const char* setting, int defaultValue, co
}
static size_t getString(const char* section, const char* setting, const char* defaultValue, char* buf, size_t bufSize, const char* iniFile) {
auto config = GetIniConfig(iniFile);
auto config = IniReader::GetIniConfig(iniFile);
const std::string* value;
if (config == nullptr || !config->getString(section, setting, value)) {
strcpy_s(buf, bufSize - 1, defaultValue);
@@ -70,7 +70,7 @@ static size_t getString(const char* section, const char* setting, const char* de
}
static std::string getString(const char* section, const char* setting, const char* defaultValue, size_t bufSize, const char* iniFile) {
auto config = GetIniConfig(iniFile);
auto config = IniReader::GetIniConfig(iniFile);
const std::string* value;
if (config == nullptr || !config->getString(section, setting, value)) {
return std::string(defaultValue);
+5
View File
@@ -20,6 +20,7 @@
namespace sfall
{
class Config;
class IniReader {
public:
@@ -31,6 +32,10 @@ public:
static void SetDefaultConfigFile();
static void SetConfigFile(const char* iniFile);
// Gets a Config from an INI file at given path, relative to game root folder.
// Config is loaded once per given path when requested and only unloaded on game reset (returning to main menu).
static Config* GetIniConfig(const char* iniFile);
// Gets the integer value from the default config (i.e. ddraw.ini)
static int GetIntDefaultConfig(const char* section, const char* setting, int defaultValue);
+2 -6
View File
@@ -514,7 +514,7 @@ ScriptValue GetArray(DWORD id, const ScriptValue& key) {
return ScriptValue(0);
}
void setArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool allowUnset) {
void SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool allowUnset) {
sArrayVar &arr = arrays[id];
if (arr.isAssoc()) {
sArrayElement sEl(key.rawValue(), key.type());
@@ -560,10 +560,6 @@ void setArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool all
}
}
void SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool allowUnset) {
if (ArrayExists(id)) setArray(id, key, val, allowUnset);
}
int LenArray(DWORD id) {
array_itr it = arrays.find(id);
return (it != arrays.end()) ? it->second.size() : -1;
@@ -767,7 +763,7 @@ long StackArray(const ScriptValue& key, const ScriptValue& val) {
if (size >= ARRAY_MAX_SIZE) return 0;
if (key.rawValue() >= size) arrays[stackArrayId].val.resize(size + 1);
}
setArray(stackArrayId, key, val, false);
SetArray(stackArrayId, key, val, false);
return 0;
}
+1 -4
View File
@@ -203,11 +203,8 @@ ScriptValue GetArrayKey(DWORD id, int index);
// get array element by index (list) or key (map)
ScriptValue GetArray(DWORD id, const ScriptValue& key);
// set array element by index or key (with checking the existence of the array ID)
void SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool allowUnset);
// set array element by index or key
void setArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool allowUnset);
void SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool allowUnset);
// number of elements in list or pairs in map
int LenArray(DWORD id);
+4 -1
View File
@@ -34,8 +34,11 @@ void op_create_array(OpcodeContext& ctx) {
}
void op_set_array(OpcodeContext& ctx) {
auto arrayId = ctx.arg(0).rawValue();
if (!ArrayExists(arrayId)) return;
SetArray(
ctx.arg(0).rawValue(),
arrayId,
ctx.arg(1),
ctx.arg(2),
true
@@ -0,0 +1,262 @@
/*
* sfall
* Copyright (C) 2008-2023 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 "IniFiles.h"
#include "..\..\..\Config.h"
#include "..\..\..\Utils.h"
#include "..\..\ScriptExtender.h"
#include "..\Arrays.h"
#include <unordered_map>
namespace sfall
{
namespace script
{
static std::unordered_map<std::string, DWORD> ConfigArrayCache;
static std::unordered_map<std::string, DWORD> ConfigArrayCacheDat;
static bool IsSpecialIni(const char* str, const char* end) {
const char* pos = strfind(str, &IniReader::GetConfigFile()[2]); // TODO test
if (pos && pos < end) return true;
pos = strfind(str, "f2_res.ini");
if (pos && pos < end) return true;
return false;
}
static int ParseIniSetting(const char* iniString, const char* &key, char section[], char file[]) {
key = strstr(iniString, "|");
if (!key) return -1;
DWORD filelen = (DWORD)key - (DWORD)iniString;
if (ScriptExtender::iniConfigFolder.empty() && filelen >= 64) return -1;
const char* fileEnd = key;
key = strstr(key + 1, "|");
if (!key) return -1;
DWORD seclen = (DWORD)key - ((DWORD)iniString + filelen + 1);
if (seclen > 32) return -1;
file[0] = '.';
file[1] = '\\';
if (!ScriptExtender::iniConfigFolder.empty() && !IsSpecialIni(iniString, fileEnd)) {
size_t len = ScriptExtender::iniConfigFolder.length(); // limit up to 62 characters
memcpy(&file[2], ScriptExtender::iniConfigFolder.c_str(), len);
memcpy(&file[2 + len], iniString, filelen); // copy path and file
file[2 + len + filelen] = 0;
if (GetFileAttributesA(file) & FILE_ATTRIBUTE_DIRECTORY) goto defRoot; // also file not found
} else {
defRoot:
memcpy(&file[2], iniString, filelen);
file[2 + filelen] = 0;
}
memcpy(section, &iniString[filelen + 1], seclen);
section[seclen] = 0;
key++;
return 1;
}
static DWORD GetIniSetting(const char* str, bool isString) {
const char* key;
char section[33], file[128];
if (ParseIniSetting(str, key, section, file) < 0) {
return -1;
}
if (isString) {
ScriptExtender::gTextBuffer[0] = 0;
IniReader::GetString(section, key, "", ScriptExtender::gTextBuffer, 256, file);
return (DWORD)&ScriptExtender::gTextBuffer[0];
} else {
return IniReader::GetInt(section, key, -1, file);
}
}
void op_get_ini_setting(OpcodeContext& ctx) {
ctx.setReturn(GetIniSetting(ctx.arg(0).strValue(), false));
}
void op_get_ini_string(OpcodeContext& ctx) {
DWORD result = GetIniSetting(ctx.arg(0).strValue(), true);
ctx.setReturn(result, (result != -1) ? DataType::STR : DataType::INT);
}
void op_modified_ini(OpcodeContext& ctx) {
ctx.setReturn(IniReader::modifiedIni);
}
void mf_set_ini_setting(OpcodeContext& ctx) {
const ScriptValue &argVal = ctx.arg(1);
const char* saveValue;
if (argVal.isInt()) {
_itoa_s(argVal.rawValue(), ScriptExtender::gTextBuffer, 10);
saveValue = ScriptExtender::gTextBuffer;
} else {
saveValue = argVal.strValue();
}
const char* key;
char section[33], file[128];
int result = ParseIniSetting(ctx.arg(0).strValue(), key, section, file);
if (result > 0) {
result = WritePrivateProfileStringA(section, key, saveValue, file);
}
switch (result) {
case 0:
ctx.printOpcodeError("%s() - value save error.", ctx.getMetaruleName());
break;
case -1:
ctx.printOpcodeError("%s() - invalid setting argument.", ctx.getMetaruleName());
break;
default:
return;
}
ctx.setReturn(-1);
}
static std::string GetIniFilePathFromArg(const ScriptValue& arg) {
const char* pathArg = arg.strValue();
std::string fileName(".\\");
if (ScriptExtender::iniConfigFolder.empty()) {
fileName += pathArg;
} else {
fileName += ScriptExtender::iniConfigFolder;
fileName += pathArg;
if (GetFileAttributesA(fileName.c_str()) & FILE_ATTRIBUTE_DIRECTORY) {
auto str = pathArg;
for (size_t i = 2; ; i++, str++) {
//if (*str == '.') str += (str[1] == '.') ? 3 : 2; // skip '.\' or '..\'
fileName[i] = *str;
if (!*str) break;
}
}
}
return std::move(fileName);
}
void mf_get_ini_sections(OpcodeContext& ctx) {
// TODO: use Config
if (!GetPrivateProfileSectionNamesA(ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePathFromArg(ctx.arg(0)).c_str())) {
ctx.setReturn(CreateTempArray(0, 0));
return;
}
std::vector<char*> sections;
char* section = ScriptExtender::gTextBuffer;
while (*section != 0) {
sections.push_back(section); // position
section += std::strlen(section) + 1;
}
size_t sz = sections.size();
int arrayId = CreateTempArray(sz, 0);
auto& arr = arrays[arrayId];
for (size_t i = 0; i < sz; ++i) {
size_t j = i + 1;
int len = (j < sz) ? sections[j] - sections[i] - 1 : -1;
arr.val[i].set(sections[i], len); // copy string from buffer
}
ctx.setReturn(arrayId);
}
void mf_get_ini_section(OpcodeContext& ctx) {
auto section = ctx.arg(1).strValue();
int arrayId = CreateTempArray(-1, 0); // associative
// TODO: use config
if (GetPrivateProfileSectionA(section, ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePathFromArg(ctx.arg(0)).c_str())) {
auto& arr = arrays[arrayId];
char *key = ScriptExtender::gTextBuffer, *val = nullptr;
while (*key != 0) {
char* val = std::strpbrk(key, "=");
if (val != nullptr) {
*val = '\0';
val += 1;
SetArray(arrayId, ScriptValue(key), ScriptValue(val), false);
key = val + std::strlen(val) + 1;
} else {
key += std::strlen(key) + 1;
}
}
}
ctx.setReturn(arrayId);
}
void mf_config_load(OpcodeContext& ctx) {
bool isDb = ctx.arg(1).asBool();
std::string filePath(isDb ? ctx.arg(0).strValue() : GetIniFilePathFromArg(ctx.arg(0)));
// Check if array exists in either cache.
auto& cache = isDb ? ConfigArrayCacheDat : ConfigArrayCache;
auto cacheHit = cache.find(filePath);
if (cacheHit != cache.end()) {
if (ArrayExists(cacheHit->second)) {
// Previously loaded array still exists, so return it.
ctx.setReturn(cacheHit->second);
return;
}
// Array was deleted. Remove it from cache and proceed with loading.
cache.erase(cacheHit);
}
// Try to read INI config from DAT database.
Config* config;
std::unique_ptr<Config> configUniq;
if (isDb) {
configUniq = std::make_unique<Config>();
if (!configUniq->read(filePath.c_str(), isDb)) {
ctx.printOpcodeError("Could not read config file from DAT: %s", filePath.c_str());
ctx.setReturn(0);
return;
}
config = configUniq.get();
}
else {
// Request config from IniReader (to take advantage of it's cache).
config = IniReader::GetIniConfig(filePath.c_str());
if (config == nullptr) {
ctx.printOpcodeError("Could not read config file: %s", filePath.c_str());
ctx.setReturn(0);
return;
}
}
// Copy data to new Sfall Array.
DWORD arrayId = CreateArray(-1, 0);
const auto& data = config->data();
for (auto sectIt = data.cbegin(); sectIt != data.cend(); ++sectIt) {
DWORD subArrayId = CreateArray(-1, 0);
const auto& section = sectIt->second;
for (auto valueIt = section.cbegin(); valueIt != section.cend(); ++valueIt) {
SetArray(subArrayId, valueIt->first.c_str(), valueIt->second.c_str(), false);
}
SetArray(arrayId, sectIt->first.c_str(), subArrayId, false);
}
// Save new array ID to cache and return it.
cache.emplace(filePath, arrayId);
ctx.setReturn(arrayId);
}
}
}
@@ -0,0 +1,43 @@
/*
* sfall
* Copyright (C) 2008-2023 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/>.
*/
#pragma once
#include "..\OpcodeContext.h"
namespace sfall
{
namespace script
{
void op_get_ini_setting(OpcodeContext&);
void op_get_ini_string(OpcodeContext&);
void op_modified_ini(OpcodeContext&);
void mf_set_ini_setting(OpcodeContext&);
void mf_get_ini_sections(OpcodeContext&);
void mf_get_ini_section(OpcodeContext&);
void mf_config_load(OpcodeContext&);
}
}
@@ -709,10 +709,10 @@ void mf_get_window_attribute(OpcodeContext& ctx) {
switch (ctx.arg(1).rawValue()) {
case -1: // rectangle map.left map.top map.right map.bottom
result = CreateTempArray(-1, 0); // associative
setArray(result, ScriptValue("left"), ScriptValue(win->rect.x), false);
setArray(result, ScriptValue("top"), ScriptValue(win->rect.y), false);
setArray(result, ScriptValue("right"), ScriptValue(win->rect.offx), false);
setArray(result, ScriptValue("bottom"), ScriptValue(win->rect.offy), false);
SetArray(result, ScriptValue("left"), ScriptValue(win->rect.x), false);
SetArray(result, ScriptValue("top"), ScriptValue(win->rect.y), false);
SetArray(result, ScriptValue("right"), ScriptValue(win->rect.offx), false);
SetArray(result, ScriptValue("bottom"), ScriptValue(win->rect.offy), false);
break;
case 0: // check if window exists
result = 1;
@@ -23,6 +23,7 @@
#include "Anims.h"
#include "Combat.h"
#include "Core.h"
#include "IniFiles.h"
#include "Interface.h"
#include "Inventory.h"
#include "Math.h"
@@ -77,6 +78,7 @@ static const SfallMetarule metarules[] = {
{"attack_is_aimed", mf_attack_is_aimed, 0, 0},
{"car_gas_amount", mf_car_gas_amount, 0, 0},
{"combat_data", mf_combat_data, 0, 0},
{"config_load", mf_config_load, 2, 2, 0, {ARG_STRING, ARG_INT}},
{"create_win", mf_create_win, 5, 6, -1, {ARG_STRING, ARG_INT, ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
{"critter_inven_obj2", mf_critter_inven_obj2, 2, 2, 0, {ARG_OBJECT, ARG_INT}},
{"dialog_message", mf_dialog_message, 1, 1, -1, {ARG_STRING}},
-171
View File
@@ -112,74 +112,6 @@ end:
}
}
static bool IsSpecialIni(const char* str, const char* end) {
const char* pos = strfind(str, &IniReader::GetConfigFile()[2]); // TODO test
if (pos && pos < end) return true;
pos = strfind(str, "f2_res.ini");
if (pos && pos < end) return true;
return false;
}
static int ParseIniSetting(const char* iniString, const char* &key, char section[], char file[]) {
key = strstr(iniString, "|");
if (!key) return -1;
DWORD filelen = (DWORD)key - (DWORD)iniString;
if (ScriptExtender::iniConfigFolder.empty() && filelen >= 64) return -1;
const char* fileEnd = key;
key = strstr(key + 1, "|");
if (!key) return -1;
DWORD seclen = (DWORD)key - ((DWORD)iniString + filelen + 1);
if (seclen > 32) return -1;
file[0] = '.';
file[1] = '\\';
if (!ScriptExtender::iniConfigFolder.empty() && !IsSpecialIni(iniString, fileEnd)) {
size_t len = ScriptExtender::iniConfigFolder.length(); // limit up to 62 characters
memcpy(&file[2], ScriptExtender::iniConfigFolder.c_str(), len);
memcpy(&file[2 + len], iniString, filelen); // copy path and file
file[2 + len + filelen] = 0;
if (GetFileAttributesA(file) & FILE_ATTRIBUTE_DIRECTORY) goto defRoot; // also file not found
} else {
defRoot:
memcpy(&file[2], iniString, filelen);
file[2 + filelen] = 0;
}
memcpy(section, &iniString[filelen + 1], seclen);
section[seclen] = 0;
key++;
return 1;
}
static DWORD GetIniSetting(const char* str, bool isString) {
const char* key;
char section[33], file[128];
if (ParseIniSetting(str, key, section, file) < 0) {
return -1;
}
if (isString) {
ScriptExtender::gTextBuffer[0] = 0;
IniReader::GetString(section, key, "", ScriptExtender::gTextBuffer, 256, file);
return (DWORD)&ScriptExtender::gTextBuffer[0];
} else {
return IniReader::GetInt(section, key, -1, file);
}
}
void op_get_ini_setting(OpcodeContext& ctx) {
ctx.setReturn(GetIniSetting(ctx.arg(0).strValue(), false));
}
void op_get_ini_string(OpcodeContext& ctx) {
DWORD result = GetIniSetting(ctx.arg(0).strValue(), true);
ctx.setReturn(result, (result != -1) ? DataType::STR : DataType::INT);
}
void __declspec(naked) op_get_uptime() {
__asm {
mov esi, ecx;
@@ -362,13 +294,6 @@ void op_get_tile_fid(OpcodeContext& ctx) {
ctx.setReturn(result);
}
void __declspec(naked) op_modified_ini() {
__asm {
mov edx, IniReader::modifiedIni;
_J_RET_VAL_TYPE(VAR_TYPE_INT);
}
}
void __declspec(naked) op_mark_movie_played() {
__asm {
_GET_ARG_INT(end);
@@ -419,102 +344,6 @@ void mf_exec_map_update_scripts(OpcodeContext& ctx) {
__asm call fo::funcoffs::scr_exec_map_update_scripts_
}
void mf_set_ini_setting(OpcodeContext& ctx) {
const ScriptValue &argVal = ctx.arg(1);
const char* saveValue;
if (argVal.isInt()) {
_itoa_s(argVal.rawValue(), ScriptExtender::gTextBuffer, 10);
saveValue = ScriptExtender::gTextBuffer;
} else {
saveValue = argVal.strValue();
}
const char* key;
char section[33], file[128];
int result = ParseIniSetting(ctx.arg(0).strValue(), key, section, file);
if (result > 0) {
result = WritePrivateProfileStringA(section, key, saveValue, file);
}
switch (result) {
case 0:
ctx.printOpcodeError("%s() - value save error.", ctx.getMetaruleName());
break;
case -1:
ctx.printOpcodeError("%s() - invalid setting argument.", ctx.getMetaruleName());
break;
default:
return;
}
ctx.setReturn(-1);
}
static std::string GetIniFilePath(const ScriptValue &arg) {
std::string fileName(".\\");
if (ScriptExtender::iniConfigFolder.empty()) {
fileName += arg.strValue();
} else {
fileName += ScriptExtender::iniConfigFolder;
fileName += arg.strValue();
if (GetFileAttributesA(fileName.c_str()) & FILE_ATTRIBUTE_DIRECTORY) {
auto str = arg.strValue();
for (size_t i = 2; ; i++, str++) {
//if (*str == '.') str += (str[1] == '.') ? 3 : 2; // skip '.\' or '..\'
fileName[i] = *str;
if (!*str) break;
}
}
}
return fileName;
}
void mf_get_ini_sections(OpcodeContext& ctx) {
if (!GetPrivateProfileSectionNamesA(ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).c_str())) {
ctx.setReturn(CreateTempArray(0, 0));
return;
}
std::vector<char*> sections;
char* section = ScriptExtender::gTextBuffer;
while (*section != 0) {
sections.push_back(section); // position
section += std::strlen(section) + 1;
}
size_t sz = sections.size();
int arrayId = CreateTempArray(sz, 0);
auto& arr = arrays[arrayId];
for (size_t i = 0; i < sz; ++i) {
size_t j = i + 1;
int len = (j < sz) ? sections[j] - sections[i] - 1 : -1;
arr.val[i].set(sections[i], len); // copy string from buffer
}
ctx.setReturn(arrayId);
}
void mf_get_ini_section(OpcodeContext& ctx) {
auto section = ctx.arg(1).strValue();
int arrayId = CreateTempArray(-1, 0); // associative
if (GetPrivateProfileSectionA(section, ScriptExtender::gTextBuffer, ScriptExtender::TextBufferSize(), GetIniFilePath(ctx.arg(0)).c_str())) {
auto& arr = arrays[arrayId];
char *key = ScriptExtender::gTextBuffer, *val = nullptr;
while (*key != 0) {
char* val = std::strpbrk(key, "=");
if (val != nullptr) {
*val = '\0';
val += 1;
setArray(arrayId, ScriptValue(key), ScriptValue(val), false);
key = val + std::strlen(val) + 1;
} else {
key += std::strlen(key) + 1;
}
}
}
ctx.setReturn(arrayId);
}
void mf_set_quest_failure_value(OpcodeContext& ctx) {
QuestList::AddQuestFailureValue(ctx.arg(0).rawValue(), ctx.arg(1).rawValue());
}
-12
View File
@@ -49,10 +49,6 @@ void __declspec() op_eax_available();
void __declspec() op_set_eax_environment();
void op_get_ini_setting(OpcodeContext&);
void op_get_ini_string(OpcodeContext&);
void __declspec() op_get_uptime();
void __declspec() op_set_car_current_town();
@@ -84,8 +80,6 @@ void __declspec() op_stop_sfall_sound();
void op_get_tile_fid(OpcodeContext&);
void __declspec() op_modified_ini();
void __declspec() op_mark_movie_played();
void __declspec() op_tile_under_cursor();
@@ -98,12 +92,6 @@ void op_tile_light(OpcodeContext&);
void mf_exec_map_update_scripts(OpcodeContext&);
void mf_set_ini_setting(OpcodeContext&);
void mf_get_ini_sections(OpcodeContext&);
void mf_get_ini_section(OpcodeContext&);
void mf_set_quest_failure_value(OpcodeContext&);
void mf_set_scr_name(OpcodeContext&);
+2 -1
View File
@@ -26,6 +26,7 @@
#include "Handlers\Core.h"
#include "Handlers\FileSystem.h"
#include "Handlers\Graphics.h"
#include "Handlers\IniFiles.h"
#include "Handlers\Interface.h"
#include "Handlers\Inventory.h"
#include "Handlers\Math.h"
@@ -178,6 +179,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x238, "atof", op_atof, 1, true, 0, {ARG_STRING}},
{0x239, "scan_array", op_scan_array, 2, true, -1, {ARG_OBJECT, ARG_ANY}},
{0x23a, "get_tile_fid", op_get_tile_fid, 1, true, 0, {ARG_INT}},
{0x23b, "modified_ini", op_modified_ini, 0, true},
{0x23c, "get_sfall_args", op_get_sfall_args, 0, true},
{0x23d, "set_sfall_arg", op_set_sfall_arg, 2, false, 0, {ARG_INT, ARG_ANY}}, // hook script system will validate type
{0x241, "get_npc_level", op_get_npc_level, 1, true, -1, {ARG_INTSTR}},
@@ -409,7 +411,6 @@ void Opcodes::InitNew() {
opcodes[0x227] = op_refresh_pc_art;
opcodes[0x22c] = op_stop_sfall_sound;
opcodes[0x23b] = op_modified_ini;
opcodes[0x23e] = op_force_aimed_shots;
opcodes[0x23f] = op_disable_aimed_shots;
opcodes[0x240] = op_mark_movie_played;
+2
View File
@@ -419,6 +419,7 @@
<ClInclude Include="Modules\Objects.h" />
<ClInclude Include="Modules\PlayerModel.h" />
<ClInclude Include="Modules\Scripting\Handlers\Combat.h" />
<ClInclude Include="Modules\Scripting\Handlers\IniFiles.h" />
<ClInclude Include="Modules\Scripting\Handlers\Inventory.h" />
<ClInclude Include="Modules\Scripting\Handlers\Math.h" />
<ClInclude Include="Modules\SpeedPatch.h" />
@@ -556,6 +557,7 @@
<ClCompile Include="Modules\LoadOrder.cpp" />
<ClCompile Include="Modules\Objects.cpp" />
<ClCompile Include="Modules\PlayerModel.cpp" />
<ClCompile Include="Modules\Scripting\Handlers\IniFiles.cpp" />
<ClCompile Include="Modules\Scripting\Handlers\Combat.cpp" />
<ClCompile Include="Modules\Scripting\Handlers\Inventory.cpp" />
<ClCompile Include="Modules\Scripting\Handlers\Math.cpp" />
+2
View File
@@ -453,6 +453,7 @@
<Filter>HLSL</Filter>
</ClInclude>
<ClInclude Include="Config.h" />
<ClInclude Include="Modules\Scripting\Handlers\IniFiles.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
@@ -826,6 +827,7 @@
<Filter>Modules\SubModules</Filter>
</ClCompile>
<ClCompile Include="Config.cpp" />
<ClCompile Include="Modules\Scripting\Handlers\IniFiles.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="version.rc" />