Refactor: encapsulated opcode-related functions and variables into classes

This commit is contained in:
phobos2077
2016-11-05 03:34:09 +07:00
parent 18b34767b6
commit 3bc84a0040
6 changed files with 274 additions and 257 deletions
+184 -132
View File
@@ -41,6 +41,104 @@ void _stdcall HandleMapUpdateForScripts(DWORD procId);
// variables for new opcodes
#define OP_MAX_ARGUMENTS (10)
class ScriptValue {
public:
ScriptValue(SfallDataType type, DWORD value) {
_val.dw = value;
_type = type;
}
ScriptValue() {
_val.dw = 0;
_type = DATATYPE_NONE;
}
ScriptValue(const char* strval) {
_val.str = strval;
_type = DATATYPE_STR;
}
ScriptValue(int val) {
_val.i = val;
_type = DATATYPE_INT;
}
ScriptValue(float strval) {
_val.f = strval;
_type = DATATYPE_FLOAT;
}
ScriptValue(TGameObj* obj) {
_val.gObj = obj;
_type = DATATYPE_INT;
}
bool isInt() const {
return _type == DATATYPE_INT;
}
bool isFloat() const {
return _type == DATATYPE_FLOAT;
}
bool isString() const {
return _type == DATATYPE_STR;
}
DWORD rawValue() const {
return _val.dw;
}
int asInt() const {
switch (_type) {
case DATATYPE_FLOAT:
return static_cast<int>(_val.f);
case DATATYPE_INT:
return _val.i;
default:
return 0;
}
}
float asFloat() const {
switch (_type) {
case DATATYPE_FLOAT:
return _val.f;
case DATATYPE_INT:
return static_cast<float>(_val.i);
default:
return 0.0;
}
}
const char* asString() const {
return (_type == DATATYPE_STR)
? _val.str
: "";
}
TGameObj* asObject() const {
return (_type == DATATYPE_INT)
? _val.gObj
: nullptr;
}
SfallDataType type() const {
return _type;
}
private:
union Value {
DWORD dw;
int i;
float f;
const char* str;
TGameObj* gObj;
} _val;
SfallDataType _type; // TODO: replace with enum class
} ;
typedef struct {
union Value {
DWORD dw;
@@ -50,93 +148,99 @@ typedef struct {
TGameObj* gObj;
} val;
DWORD type; // TODO: replace with enum class
} ScriptValue;
} ScriptValue1;
static TProgram* opProgram;
static DWORD opArgCount = 0;
static ScriptValue opArgs[OP_MAX_ARGUMENTS];
static ScriptValue opRet;
static void _stdcall SetOpReturn(DWORD value, DWORD type) {
opRet.val.dw = value;
opRet.type = type;
}
static void _stdcall SetOpReturn(int value) {
opRet.val.i = value;
opRet.type = DATATYPE_INT;
}
static void _stdcall SetOpReturn(float value) {
opRet.val.f = value;
opRet.type = DATATYPE_FLOAT;
}
static void _stdcall SetOpReturn(const char* value) {
opRet.val.str = value;
opRet.type = DATATYPE_STR;
}
static void _stdcall SetOpReturn(TGameObj* value) {
opRet.val.gObj = value;
opRet.type = DATATYPE_INT;
}
// TODO: replace these functions with proper ScriptValue class (encapsulation...)
static bool _stdcall IsOpArgInt(int num) {
return (opArgs[num].type == DATATYPE_INT);
}
static bool _stdcall IsOpArgFloat(int num) {
return (opArgs[num].type == DATATYPE_FLOAT);
}
static bool _stdcall IsOpArgStr(int num) {
return (opArgs[num].type == DATATYPE_STR);
}
static int _stdcall GetOpArgCount() {
return opArgCount;
}
static int _stdcall GetOpArgInt(int num) {
switch (opArgs[num].type) {
case DATATYPE_FLOAT:
return static_cast<int>(opArgs[num].val.f);
case DATATYPE_INT:
return opArgs[num].val.i;
default:
return 0;
class OpcodeHandler {
public:
// number of arguments
int numArgs() const {
return _args.size();
}
}
static float _stdcall GetOpArgFloat(int num) {
switch (opArgs[num].type) {
case DATATYPE_FLOAT:
return opArgs[num].val.f;
case DATATYPE_INT:
return static_cast<float>(opArgs[num].val.i);
default:
return 0.0;
// returns argument with given index
const ScriptValue& arg(int index) const {
return _args.at(index);
}
// current return value
const ScriptValue& returnValue() const {
return _ret;
}
}
static const char* _stdcall GetOpArgStr(int num) {
return (opArgs[num].type == DATATYPE_STR)
? opArgs[num].val.str
: "";
}
// current script program
TProgram* program() const {
return _program;
}
// set return value for current opcode
void setReturn(DWORD value, SfallDataType type) {
_ret = ScriptValue(type, value);
}
// set return value for current opcode
void setReturn(const ScriptValue& val) {
_ret = val;
}
static TGameObj* _stdcall GetOpArgObj(int num) {
return (opArgs[num].type == DATATYPE_INT)
? opArgs[num].val.gObj
: nullptr;
}
// Handle opcodes
// scriptPtr - pointer to script program (from the engine)
// func - opcode handler
// hasReturn - true if opcode has return value (is expression)
void __thiscall HandleOpcode(TProgram* scriptPtr, void(*func)(), int argNum, bool hasReturn) {
assert(argNum < OP_MAX_ARGUMENTS);
_program = scriptPtr;
// reset return value
_ret = ScriptValue();
// process arguments on stack (reverse order)
_args.resize(0);
for (int i = argNum - 1; i >= 0; i--) {
// get argument from stack
DWORD rawValueType = InterpretPopShort(scriptPtr);
DWORD rawValue = InterpretPopLong(scriptPtr);
SfallDataType type = static_cast<SfallDataType>(getSfallTypeByScriptType(rawValueType));
// retrieve string argument
if (type == DATATYPE_STR) {
_args.push_back(InterpretGetString(scriptPtr, rawValue, rawValueType));
} else {
_args.push_back(ScriptValue(type, rawValue));
}
}
// call opcode handler
func();
// process return value
if (hasReturn) {
if (_ret.type() == DATATYPE_NONE) {
// if no value was set in handler, force return 0 to avoid stack error
_ret = ScriptValue(0);
}
DWORD rawResult = _ret.rawValue();
if (_ret.type() == DATATYPE_STR) {
rawResult = InterpretAddString(scriptPtr, _ret.asString());
}
InterpretPushLong(scriptPtr, rawResult);
InterpretPushShort(scriptPtr, getScriptTypeBySfallType(_ret.type()));
}
}
private:
TProgram* _program;
int _argCount;
std::vector<ScriptValue> _args;
ScriptValue _ret;
};
static OpcodeHandler opHandler;
// writes error message to debug.log along with the name of script & procedure
static void _stdcall PrintOpcodeError(const char* fmt, ...) {
assert(opProgram != nullptr);
assert(opHandler.program() != nullptr);
va_list args;
va_start(args, fmt);
@@ -144,62 +248,10 @@ static void _stdcall PrintOpcodeError(const char* fmt, ...) {
vsnprintf_s(msg, sizeof msg, _TRUNCATE, fmt, args);
va_end(args);
const char* procName = FindCurrentProc(opProgram);
DebugPrintf("\nOPCODE ERROR: %s\n Current script: %s, procedure %s.", msg, opProgram->fileName, procName);
const char* procName = FindCurrentProc(opHandler.program());
DebugPrintf("\nOPCODE ERROR: %s\n Current script: %s, procedure %s.", msg, opHandler.program()->fileName, procName);
}
// Handle opcodes
// scriptPtr - pointer to script program (from the engine)
// func - opcode handler
// hasReturn - true if opcode has return value (is expression)
static void __stdcall HandleOpcode(TProgram* scriptPtr, void(*func)(), int argNum, bool hasReturn) {
assert(argNum < OP_MAX_ARGUMENTS);
opProgram = scriptPtr;
// reset return value
opRet.type = DATATYPE_NONE;
opRet.val.dw = 0;
// process arguments on stack (reverse order)
opArgCount = argNum;
for (int i = OP_MAX_ARGUMENTS - 1; i >= 0; i--) {
if (i < argNum) {
// get argument from stack
DWORD rawValueType = InterpretPopShort(scriptPtr);
DWORD rawValue = InterpretPopLong(scriptPtr);
opArgs[i].type = getSfallTypeByScriptType(rawValueType);
// retrieve string argument
if (opArgs[i].type == DATATYPE_STR) {
opArgs[i].val.str = InterpretGetString(scriptPtr, rawValue, rawValueType);
} else {
opArgs[i].val.dw = rawValue;
}
} else {
// reset other arguments
opArgs[i].val.dw = 0;
opArgs[i].type = DATATYPE_NONE;
}
}
// call opcode handler
func();
// process return value
if (hasReturn) {
if (opRet.type == DATATYPE_NONE) {
// if no value was set in handler, force return 0 to avoid stack error
SetOpReturn(0, DATATYPE_INT);
}
DWORD rawResult = opRet.val.dw;
if (opRet.type == DATATYPE_STR) {
rawResult = InterpretAddString(scriptPtr, opRet.val.str);
}
InterpretPushLong(scriptPtr, rawResult);
InterpretPushShort(scriptPtr, getScriptTypeBySfallType(opRet.type));
}
}
#include "ScriptOps\AsmMacros.h"
#include "ScriptOps\ScriptArrays.hpp"
+2 -46
View File
@@ -145,53 +145,9 @@ __asm resultnotstr##num: \
__asm push argnum \
__asm push func \
__asm push eax \
__asm call HandleOpcode \
__asm lea ecx, opHandler \
__asm call OpcodeHandler::HandleOpcode \
__asm popad \
__asm retn \
}
// Old wrapping macros.. does not support string arguments
#define _WRAP_OPCODE_OLD(argnum, func) __asm { \
__asm pushad \
__asm mov ebp, eax \
__asm mov esi, argnum \
__asm shl esi, 2 \
__asm mov opArgCount, argnum \
__asm mov opRetType, 0 \
__asm loopbegin: \
__asm test esi, esi \
__asm jz loopend \
__asm sub esi, 4 \
__asm mov eax, ebp \
__asm call interpretPopShort_ \
__asm push eax \
__asm call getSfallTypeByScriptType \
__asm mov opArgTypes[esi], eax \
__asm mov eax, ebp \
__asm call interpretPopLong_ \
__asm mov opArgs[esi], eax \
__asm jmp loopbegin \
__asm loopend: \
__asm call func \
__asm mov eax, opRetType \
__asm test eax, eax \
__asm jz end \
__asm push eax \
__asm call getScriptTypeBySfallType \
__asm mov ecx, eax \
__asm mov edx, opRet \
__asm cmp ecx, VAR_TYPE_STR \
__asm jne notstring \
__asm mov eax, ebp \
__asm call interpretAddString_ \
__asm mov edx, eax \
__asm notstring: \
__asm mov eax, ebp \
__asm call interpretPushLong_ \
__asm mov edx, ecx \
__asm mov eax, ebp \
__asm call interpretPushShort_ \
__asm end: \
__asm popad \
__asm retn \
}
+1 -1
View File
@@ -459,5 +459,5 @@ static void sf_intface_is_hidden() {
call intface_is_hidden_
mov isHidden, eax;
}
SetOpReturn(isHidden);
opHandler.setReturn(isHidden);
}
+17 -15
View File
@@ -29,7 +29,7 @@
// Prefix all function handlers with sf_ and add them to sfall_metarule_table.
// DO NOT add arguments and/or return values to function handlers!
// Use functions GetOpArgXXX(), IsOpArgXXX() inside handler function to read arguments, but argument 0 is always function name.
// Use SetOpReturn() to set return value.
// Use opHandler.setReturn() to set return value.
// If you want to call user-defined procedures in your handler, use RunScriptProc().
struct SfallMetarule {
@@ -61,17 +61,18 @@ static std::string sf_test_stringBuf;
static void sf_test() {
std::ostringstream sstream;
sstream << "sfall_funcX(\"test\"";
for (DWORD i = 1; i < opArgCount; i++) {
for (int i = 1; i < opHandler.numArgs(); i++) {
const ScriptValue &arg = opHandler.arg(i);
sstream << ", ";
switch (opArgs[i].type) {
switch (arg.type()) {
case DATATYPE_INT:
sstream << GetOpArgInt(i);
sstream << arg.asInt();
break;
case DATATYPE_FLOAT:
sstream << GetOpArgFloat(i);
sstream << arg.asFloat();
break;
case DATATYPE_STR:
sstream << '"' << GetOpArgStr(i) << '"';
sstream << '"' << arg.asString() << '"';
break;
default:
sstream << "???";
@@ -81,7 +82,7 @@ static void sf_test() {
sstream << ")";
sf_test_stringBuf = sstream.str();
SetOpReturn(sf_test_stringBuf.c_str());
opHandler.setReturn(sf_test_stringBuf.c_str());
}
// returns current contents of metarule table
@@ -92,7 +93,7 @@ static void sf_get_metarule_table() {
arrays[arr].val[i].set(it->first.c_str());
i++;
}
SetOpReturn(arr, DATATYPE_INT);
opHandler.setReturn(arr, DATATYPE_INT);
}
/*
@@ -130,7 +131,7 @@ static void InitMetaruleTable() {
// Validates arguments against metarule specification.
// On error prints to debug.log and returns false.
static bool ValidateOpcodeArguments(const SfallMetarule* metaruleInfo) {
int argCount = GetOpArgCount() - 1; // don't count function name
int argCount = opHandler.numArgs() - 1; // don't count function name
if (argCount < metaruleInfo->minArgs || argCount > metaruleInfo->maxArgs) {
PrintOpcodeError(
"sfall_funcX(\"%s\", ...) - invalid number of arguments (%d), must be from %d to %d.",
@@ -143,16 +144,16 @@ static bool ValidateOpcodeArguments(const SfallMetarule* metaruleInfo) {
} else {
for (int i = 0; i < argCount; i++) {
int typeMask = metaruleInfo->argTypeMasks[i];
ScriptValue arg = opArgs[i + 1];
if (typeMask != 0 && ((1 << arg.type) & typeMask) == 0) {
const ScriptValue &arg = opHandler.arg(i + 1);
if (typeMask != 0 && ((1 << arg.type()) & typeMask) == 0) {
PrintOpcodeError(
"sfall_funcX(\"%s\", ...) - argument #%d has invalid type: %s.",
metaruleInfo->name,
i + 1,
GetSfallTypeName(arg.type));
GetSfallTypeName(arg.type()));
return false;
} else if ((typeMask & DATATYPE_MASK_NOT_NULL) && arg.val.dw == 0) {
} else if ((typeMask & DATATYPE_MASK_NOT_NULL) && arg.rawValue() == 0) {
PrintOpcodeError(
"sfall_funcX(\"%s\", ...) - argument #%d is null.",
metaruleInfo->name,
@@ -166,8 +167,9 @@ static bool ValidateOpcodeArguments(const SfallMetarule* metaruleInfo) {
}
static void _stdcall op_sfall_metarule_handler() {
if (IsOpArgStr(0)) {
const char* name = GetOpArgStr(0);
const ScriptValue &nameArg = opHandler.arg(0);
if (nameArg.isString()) {
const char* name = nameArg.asString();
MetaruleTableType::iterator lookup = metaruleTable.find(name);
if (lookup != metaruleTable.end()) {
const SfallMetarule* metaruleInfo = lookup->second;
+40 -37
View File
@@ -115,10 +115,10 @@ end:
// TODO: rewrite, remove all ASM
static void _stdcall op_create_spatial2() {
DWORD scriptIndex = GetOpArgInt(0),
tile = GetOpArgInt(1),
elevation = GetOpArgInt(2),
radius = GetOpArgInt(3),
DWORD scriptIndex = opHandler.arg(0).asInt(),
tile = opHandler.arg(1).asInt(),
elevation = opHandler.arg(2).asInt(),
radius = opHandler.arg(3).asInt(),
scriptId, tmp, objectPtr,
scriptPtr;
__asm {
@@ -151,7 +151,7 @@ static void _stdcall op_create_spatial2() {
call scr_find_obj_from_program_;
mov objectPtr, eax;
}
SetOpReturn((int)objectPtr);
opHandler.setReturn((int)objectPtr);
}
static void __declspec(naked) op_create_spatial() {
@@ -159,10 +159,10 @@ static void __declspec(naked) op_create_spatial() {
}
static void sf_spatial_radius() {
TGameObj* spatialObj = GetOpArgObj(1);
TGameObj* spatialObj = opHandler.arg(1).asObject();
TScript* script;
if (ScrPtr(spatialObj->scriptID, &script) != -1) {
SetOpReturn(script->spatial_radius);
opHandler.setReturn(script->spatial_radius);
}
}
@@ -376,13 +376,13 @@ static DWORD getBlockingFunc(DWORD type) {
}
static void _stdcall op_make_straight_path2() {
DWORD objFrom = GetOpArgInt(0),
tileTo = GetOpArgInt(1),
type = GetOpArgInt(2),
DWORD objFrom = opHandler.arg(0).asInt(),
tileTo = opHandler.arg(1).asInt(),
type = opHandler.arg(2).asInt(),
resultObj, arg6;
arg6 = (type == BLOCKING_TYPE_SHOOT) ? 32 : 0;
make_straight_path_func_wrapper(objFrom, *(DWORD*)(objFrom + 4), 0, tileTo, &resultObj, arg6, getBlockingFunc(type));
SetOpReturn(resultObj, DATATYPE_INT);
opHandler.setReturn(resultObj, DATATYPE_INT);
}
static void __declspec(naked) op_make_straight_path() {
@@ -390,15 +390,15 @@ static void __declspec(naked) op_make_straight_path() {
}
static void _stdcall op_make_path2() {
DWORD objFrom = GetOpArgInt(0),
DWORD objFrom = opHandler.arg(0).asInt(),
tileFrom = 0,
tileTo = GetOpArgInt(1),
type = GetOpArgInt(2),
tileTo = opHandler.arg(1).asInt(),
type = opHandler.arg(2).asInt(),
func = getBlockingFunc(type),
arr;
long pathLength, a5 = 1;
if (!objFrom) {
SetOpReturn(0, DATATYPE_INT);
opHandler.setReturn(0, DATATYPE_INT);
return;
}
tileFrom = *(DWORD*)(objFrom + 4);
@@ -418,7 +418,7 @@ static void _stdcall op_make_path2() {
for (int i=0; i < pathLength; i++) {
arrays[arr].val[i].set((long)pathData[i]);
}
SetOpReturn(arr, DATATYPE_INT);
opHandler.setReturn(arr, DATATYPE_INT);
}
static void __declspec(naked) op_make_path() {
@@ -426,16 +426,16 @@ static void __declspec(naked) op_make_path() {
}
static void _stdcall op_obj_blocking_at2() {
DWORD tile = GetOpArgInt(0),
elevation = GetOpArgInt(1),
type = GetOpArgInt(2),
DWORD tile = opHandler.arg(0).asInt(),
elevation = opHandler.arg(1).asInt(),
type = opHandler.arg(2).asInt(),
resultObj;
resultObj = obj_blocking_at_wrapper(0, tile, elevation, getBlockingFunc(type));
if (resultObj && type == BLOCKING_TYPE_SHOOT && (*(DWORD*)(resultObj + 39) & 0x80)) { // don't know what this flag means, copy-pasted from the engine code
// this check was added because the engine always does exactly this when using shoot blocking checks
resultObj = 0;
}
SetOpReturn(resultObj, DATATYPE_INT);
opHandler.setReturn(resultObj, DATATYPE_INT);
}
static void __declspec(naked) op_obj_blocking_at() {
@@ -443,8 +443,8 @@ static void __declspec(naked) op_obj_blocking_at() {
}
static void _stdcall op_tile_get_objects2() {
DWORD tile = GetOpArgInt(0),
elevation = GetOpArgInt(1),
DWORD tile = opHandler.arg(0).asInt(),
elevation = opHandler.arg(1).asInt(),
obj;
DWORD arrayId = TempArray(0, 4);
__asm {
@@ -460,7 +460,7 @@ static void _stdcall op_tile_get_objects2() {
mov obj, eax;
}
}
SetOpReturn(arrayId, DATATYPE_INT);
opHandler.setReturn(arrayId, DATATYPE_INT);
}
static void __declspec(naked) op_tile_get_objects() {
@@ -468,7 +468,7 @@ static void __declspec(naked) op_tile_get_objects() {
}
static void _stdcall op_get_party_members2() {
DWORD obj, mode = GetOpArgInt(0), isDead;
DWORD obj, mode = opHandler.arg(0).asInt(), isDead;
int i, actualCount = *(DWORD*)_partyMemberCount;
DWORD arrayId = TempArray(0, 4);
DWORD* partyMemberList = *(DWORD**)_partyMemberList;
@@ -489,7 +489,7 @@ static void _stdcall op_get_party_members2() {
}
arrays[arrayId].push_back((long)obj);
}
SetOpReturn(arrayId, DATATYPE_INT);
opHandler.setReturn(arrayId, DATATYPE_INT);
}
static void __declspec(naked) op_get_party_members() {
@@ -512,11 +512,14 @@ end:
}
static void _stdcall op_obj_is_carrying_obj2() {
DWORD num = 0;
if (IsOpArgInt(0) && IsOpArgInt(1)) {
TGameObj *invenObj = (TGameObj*)GetOpArgInt(0),
*itemObj = (TGameObj*)GetOpArgInt(1);
if (invenObj && itemObj) {
int num = 0;
const ScriptValue &invenObjArg = opHandler.arg(0),
&itemObjArg = opHandler.arg(1);
if (invenObjArg.isInt() && itemObjArg.isInt()) {
TGameObj *invenObj = (TGameObj*)invenObjArg.asObject(),
*itemObj = (TGameObj*)itemObjArg.asObject();
if (invenObj != nullptr && itemObj != nullptr) {
for (int i = 0; i < invenObj->invenCount; i++) {
if (invenObj->invenTablePtr[i].object == itemObj) {
num = invenObj->invenTablePtr[i].count;
@@ -525,7 +528,7 @@ static void _stdcall op_obj_is_carrying_obj2() {
}
}
}
SetOpReturn(num, DATATYPE_INT);
opHandler.setReturn(num);
}
static void __declspec(naked) op_obj_is_carrying_obj() {
@@ -533,20 +536,20 @@ static void __declspec(naked) op_obj_is_carrying_obj() {
}
static void sf_critter_inven_obj2() {
TGameObj* critter = GetOpArgObj(1);
int slot = GetOpArgInt(2);
TGameObj* critter = opHandler.arg(1).asObject();
int slot = opHandler.arg(2).asInt();
switch (slot) {
case 0:
SetOpReturn(InvenWorn(critter));
opHandler.setReturn(InvenWorn(critter));
break;
case 1:
SetOpReturn(InvenRightHand(critter));
opHandler.setReturn(InvenRightHand(critter));
break;
case 2:
SetOpReturn(InvenLeftHand(critter));
opHandler.setReturn(InvenLeftHand(critter));
break;
case -2:
SetOpReturn(critter->invenCount);
opHandler.setReturn(critter->invenCount);
break;
default:
PrintOpcodeError("critter_inven_obj2() - invalid type.");
+30 -26
View File
@@ -770,21 +770,22 @@ end:
}
static void funcPow2() {
float base, result = 0.0;
if (!IsOpArgStr(0) && !IsOpArgStr(1)) {
base = GetOpArgFloat(0);
if (IsOpArgFloat(1))
result = pow(base, GetOpArgFloat(1));
const ScriptValue &base = opHandler.arg(0),
&power = opHandler.arg(1);
float result = 0.0;
if (!base.isString() && !power.isString()) {
if (power.isFloat())
result = pow(base.asFloat(), power.asFloat());
else
result = pow(base, GetOpArgInt(1));
result = pow(base.asFloat(), power.asInt());
if (IsOpArgInt(0) && IsOpArgInt(1)) {
SetOpReturn((DWORD)(int)result, DATATYPE_INT);
if (base.isInt() && power.isInt()) {
opHandler.setReturn(static_cast<int>(result));
} else {
SetOpReturn(result);
opHandler.setReturn(result);
}
} else {
SetOpReturn(0, DATATYPE_INT);
opHandler.setReturn(0);
}
}
@@ -793,7 +794,7 @@ static void __declspec(naked) funcPow() {
}
static void funcLog2() {
SetOpReturn(log(GetOpArgFloat(0)));
opHandler.setReturn(log(opHandler.arg(0).asFloat()));
}
static void __declspec(naked) funcLog() {
@@ -801,7 +802,7 @@ static void __declspec(naked) funcLog() {
}
static void funcExp2() {
SetOpReturn(exp(GetOpArgFloat(0)));
opHandler.setReturn(exp(opHandler.arg(0).asFloat()));
}
static void __declspec(naked) funcExp() {
@@ -809,7 +810,7 @@ static void __declspec(naked) funcExp() {
}
static void funcCeil2() {
SetOpReturn((int)ceil(GetOpArgFloat(0)), DATATYPE_INT);
opHandler.setReturn(static_cast<int>(ceil(opHandler.arg(0).asFloat())));
}
static void __declspec(naked) funcCeil() {
@@ -817,12 +818,13 @@ static void __declspec(naked) funcCeil() {
}
static void funcRound2() {
float arg = GetOpArgFloat(0);
int argI = (int)arg;
float mod = arg - (float)argI;
if (abs(mod) >= 0.5)
float arg = opHandler.arg(0).asFloat();
int argI = static_cast<int>(arg);
float mod = arg - static_cast<float>(argI);
if (abs(mod) >= 0.5) {
argI += (mod > 0 ? 1 : -1);
SetOpReturn(argI, DATATYPE_INT);
}
opHandler.setReturn(argI);
}
static void __declspec(naked) funcRound() {
@@ -833,6 +835,7 @@ static void __declspec(naked) funcRound() {
*/
// TODO: move to FalloutEngine module
static const DWORD game_msg_files[] =
{ 0x56D368 // COMBAT
, 0x56D510 // AI
@@ -855,14 +858,16 @@ static const DWORD game_msg_files[] =
, 0x66BE38 // TRAIT
, 0x672FB0 }; // WORLDMAP
// TODO: move to FalloutEngine
static const DWORD* proto_msg_files = (DWORD*)0x006647AC;
static void _stdcall op_message_str_game2() {
const char* msg = 0;
if (IsOpArgInt(0) && IsOpArgInt(1)) {
int fileId = GetOpArgInt(0);
int msgId = GetOpArgInt(1);
const ScriptValue &fileIdArg = opHandler.arg(0),
&msgIdArg = opHandler.arg(1);
if (fileIdArg.isInt() && msgIdArg.isInt()) {
int fileId = fileIdArg.asInt();
int msgId = msgIdArg.asInt();
if (fileId < 20) { // main msg files
msg = GetMessageStr(game_msg_files[fileId], msgId);
}
@@ -877,11 +882,10 @@ static void _stdcall op_message_str_game2() {
}
}
}
if (msg == 0)
if (msg == 0) {
msg = "Error";
SetOpReturn(msg);
}
opHandler.setReturn(msg);
}
static void __declspec(naked) op_message_str_game() {