mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Refactoring ScriptExtender module.
This commit is contained in:
@@ -218,6 +218,7 @@ namespace VarPtr
|
||||
#define VARDECL(type, name) \
|
||||
extern type* const name;
|
||||
|
||||
// TODO: assign appropriate types (arrays, structs, strings, etc.) for all variables
|
||||
|
||||
VARDECL(long, pc_trait) // 2 of them
|
||||
VARDECL(DWORD, aiInfoList)
|
||||
|
||||
@@ -61,6 +61,14 @@ void display_print(const char* msg) {
|
||||
}
|
||||
}
|
||||
|
||||
void executeProcedure(TProgram* sptr, int procNum) {
|
||||
__asm {
|
||||
mov edx, procNum;
|
||||
mov eax, sptr;
|
||||
call FuncOffs::executeProcedure_
|
||||
}
|
||||
}
|
||||
|
||||
const char* _stdcall getmsg(DWORD fileAddr, int messageId, sMessage* result) {
|
||||
__asm {
|
||||
mov eax, fileAddr
|
||||
@@ -123,6 +131,14 @@ void intface_redraw() {
|
||||
__asm call FuncOffs::intface_redraw_
|
||||
}
|
||||
|
||||
int __stdcall interpretFindProcedure(TProgram* scriptPtr, const char* procName) {
|
||||
__asm {
|
||||
mov edx, procName;
|
||||
mov eax, scriptPtr;
|
||||
call FuncOffs::interpretFindProcedure_;
|
||||
}
|
||||
}
|
||||
|
||||
// pops value type from Data stack (must be followed by InterpretPopLong)
|
||||
DWORD __stdcall interpretPopShort(TProgram* scriptPtr) {
|
||||
__asm {
|
||||
@@ -217,4 +233,11 @@ int __stdcall message_search(DWORD* file, sMessage* msg) {
|
||||
}
|
||||
}
|
||||
|
||||
DWORD* __stdcall runProgram(TProgram* progPtr) {
|
||||
__asm {
|
||||
mov eax, progPtr;
|
||||
call FuncOffs::runProgram_;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ char* proto_ptr(DWORD pid);
|
||||
// Displays message in main UI console window
|
||||
void display_print(const char* msg);
|
||||
|
||||
// execute script proc by internal proc number (from script's proc table, basically a sequential number of a procedure as defined in code, starting from 1)
|
||||
void executeProcedure(TProgram* sptr, int procNum);
|
||||
|
||||
int __stdcall item_get_type(TGameObj* item);
|
||||
|
||||
// Change the name of playable character
|
||||
@@ -68,6 +71,9 @@ TGameObj* __stdcall inven_left_hand(TGameObj* critter);
|
||||
// item in critter's right hand slot
|
||||
TGameObj* __stdcall inven_right_hand(TGameObj* critter);
|
||||
|
||||
// finds procedure ID for given script program pointer and procedure name
|
||||
int __stdcall interpretFindProcedure(TProgram* scriptPtr, const char* procName);
|
||||
|
||||
// pops value type from Data stack (must be followed by InterpretPopLong)
|
||||
DWORD __stdcall interpretPopShort(TProgram* scriptPtr);
|
||||
|
||||
@@ -96,4 +102,6 @@ const char* __stdcall findCurrentProc(TProgram* program);
|
||||
|
||||
int __stdcall message_search(DWORD* file, sMessage* msg);
|
||||
|
||||
DWORD* __stdcall runProgram(TProgram* progPtr);
|
||||
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ static void _stdcall RunSpecificHookScript(sHookScript *hook) {
|
||||
cArg=0;
|
||||
cRetTmp=0;
|
||||
if (hook->callback != -1)
|
||||
RunScriptProcByNum(hook->prog.ptr, hook->callback);
|
||||
Wrapper::executeProcedure(hook->prog.ptr, hook->callback);
|
||||
else
|
||||
RunScriptProc(&hook->prog, start);
|
||||
}
|
||||
@@ -1076,7 +1076,7 @@ void _stdcall SetHSReturn(DWORD d) {
|
||||
if (cRetTmp > cRet)
|
||||
cRet = cRetTmp;
|
||||
}
|
||||
void _stdcall RegisterHook( DWORD script, DWORD id, DWORD procNum )
|
||||
void _stdcall RegisterHook(TProgram* script, int id, int procNum )
|
||||
{
|
||||
if (id >= numHooks) return;
|
||||
for (std::vector<sHookScript>::iterator it = hooks[id].begin(); it != hooks[id].end(); ++it) {
|
||||
@@ -1108,7 +1108,7 @@ static void LoadHookScript(const char* name, int id) {
|
||||
mov fileExist, al
|
||||
}
|
||||
|
||||
if (fileExist && !isGameScript(name)) {
|
||||
if (fileExist && !IsGameScript(name)) {
|
||||
sScriptProgram prog;
|
||||
dlog(">", DL_HOOK);
|
||||
dlog(name, DL_HOOK);
|
||||
|
||||
@@ -55,7 +55,7 @@ DWORD* _stdcall GetHSArgs();
|
||||
void _stdcall SetHSArg(DWORD id, DWORD value);
|
||||
void _stdcall SetHSReturn(DWORD d);
|
||||
// register hook by proc num (special values: -1 - use default (start) procedure, 0 - unregister)
|
||||
void _stdcall RegisterHook(DWORD script, DWORD id, DWORD procNum);
|
||||
void _stdcall RegisterHook(TProgram* script, int id, int procNum);
|
||||
|
||||
void HookScriptInit();
|
||||
void HookScriptClear();
|
||||
|
||||
+81
-1149
File diff suppressed because it is too large
Load Diff
@@ -17,15 +17,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "..\main.h"
|
||||
|
||||
// TODO: replace with enum class
|
||||
enum SfallDataType {
|
||||
DATATYPE_NONE = 0,
|
||||
DATATYPE_INT,
|
||||
DATATYPE_FLOAT,
|
||||
DATATYPE_STR
|
||||
};
|
||||
#include "..\main.h"
|
||||
#include "..\FalloutEngine\Structs.h"
|
||||
|
||||
struct sGlobalVar {
|
||||
__int64 id;
|
||||
@@ -34,13 +28,13 @@ struct sGlobalVar {
|
||||
|
||||
#define SCRIPT_PROC_MAX (27)
|
||||
typedef struct {
|
||||
DWORD ptr;
|
||||
DWORD procLookup[SCRIPT_PROC_MAX+1];
|
||||
TProgram* ptr;
|
||||
int procLookup[SCRIPT_PROC_MAX+1];
|
||||
char initialized;
|
||||
} sScriptProgram;
|
||||
|
||||
void ScriptExtenderSetup();
|
||||
bool _stdcall isGameScript(const char* filename);
|
||||
bool _stdcall IsGameScript(const char* filename);
|
||||
void LoadGlobalScripts();
|
||||
void ClearGlobalScripts();
|
||||
|
||||
@@ -66,22 +60,18 @@ void GetAppearanceGlobals(int *race, int *style);
|
||||
|
||||
void _stdcall RegAnimCombatCheck(DWORD newValue);
|
||||
|
||||
DWORD _stdcall ScriptHasLoaded(DWORD script);
|
||||
// finds procedure ID for given script program pointer and procedure name
|
||||
DWORD GetScriptProcByName(DWORD scriptPtr, const char* procName);
|
||||
bool _stdcall ScriptHasLoaded(TProgram* script);
|
||||
// loads script from .int file into scripting engine, fill scriptPtr and proc table
|
||||
void LoadScriptProgram(sScriptProgram &prog, const char* fileName);
|
||||
// init program after load, needs to be called once
|
||||
void InitScriptProgram(sScriptProgram &prog);
|
||||
// execute script proc by internal proc number (from script's proc table, basically a sequential number of a procedure as defined in code, starting from 1)
|
||||
void RunScriptProcByNum(DWORD sptr, DWORD procNum);
|
||||
// execute script by specific proc name
|
||||
void RunScriptProc(sScriptProgram* prog, const char* procName);
|
||||
// execute script proc by procId from define.h
|
||||
void RunScriptProc(sScriptProgram* prog, DWORD procId);
|
||||
void RunScriptProc(sScriptProgram* prog, int procId);
|
||||
|
||||
void AddProgramToMap(sScriptProgram &prog);
|
||||
sScriptProgram* GetGlobalScriptProgram(DWORD scriptPtr);
|
||||
sScriptProgram* GetGlobalScriptProgram(TProgram* scriptPtr);
|
||||
|
||||
char* _stdcall mysubstr(char* str, int pos, int length);
|
||||
// variables
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Arrays.h"
|
||||
#include "..\ScriptExtender.h"
|
||||
#include "..\Scripting\ScriptValue.h"
|
||||
#include "..\Scripting\OpcodeHandler.h"
|
||||
|
||||
#include "Arrays.h"
|
||||
|
||||
/*
|
||||
GLOBAL variable for arrays
|
||||
@@ -314,47 +317,6 @@ void DESetArray(int id, const DWORD* types, const void* data) {
|
||||
TODO: move somewhere else
|
||||
*/
|
||||
|
||||
const char* _stdcall GetSfallTypeName(DWORD dataType) {
|
||||
switch (dataType) {
|
||||
case DATATYPE_NONE:
|
||||
return "(none)";
|
||||
case DATATYPE_STR:
|
||||
return "string";
|
||||
case DATATYPE_FLOAT:
|
||||
return "float";
|
||||
case DATATYPE_INT:
|
||||
return "integer";
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
DWORD _stdcall getSfallTypeByScriptType(DWORD varType) {
|
||||
varType &= 0xffff;
|
||||
switch (varType) {
|
||||
case VAR_TYPE_STR:
|
||||
case VAR_TYPE_STR2:
|
||||
return DATATYPE_STR;
|
||||
case VAR_TYPE_FLOAT:
|
||||
return DATATYPE_FLOAT;
|
||||
case VAR_TYPE_INT:
|
||||
default:
|
||||
return DATATYPE_INT;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD _stdcall getScriptTypeBySfallType(DWORD dataType) {
|
||||
switch (dataType) {
|
||||
case DATATYPE_STR:
|
||||
return VAR_TYPE_STR;
|
||||
case DATATYPE_FLOAT:
|
||||
return VAR_TYPE_FLOAT;
|
||||
case DATATYPE_INT:
|
||||
default:
|
||||
return VAR_TYPE_INT;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD _stdcall CreateArray(int len, DWORD nothing) {
|
||||
sArrayVar var;
|
||||
if (len < 0) var.flags |= ARRAYFLAG_ASSOC;
|
||||
@@ -419,7 +381,7 @@ DWORD _stdcall GetArray(DWORD id, DWORD key, DWORD keyType, DWORD* resultType) {
|
||||
int el;
|
||||
sArrayVar &arr = arrays[id];
|
||||
if (arr.isAssoc()) {
|
||||
ArrayKeysMap::iterator it = arr.keyHash.find(sArrayElement(key, getSfallTypeByScriptType(keyType)));
|
||||
ArrayKeysMap::iterator it = arr.keyHash.find(sArrayElement(key, OpcodeHandler::getSfallTypeByScriptType(keyType)));
|
||||
if (it != arr.keyHash.end())
|
||||
el = it->second + 1;
|
||||
else
|
||||
@@ -443,8 +405,8 @@ DWORD _stdcall GetArray(DWORD id, DWORD key, DWORD keyType, DWORD* resultType) {
|
||||
return 0;
|
||||
}
|
||||
void _stdcall SetArray(DWORD id, DWORD key, DWORD keyType, DWORD val, DWORD valType, DWORD allowUnset) {
|
||||
keyType = getSfallTypeByScriptType(keyType);
|
||||
valType = getSfallTypeByScriptType(valType);
|
||||
keyType = OpcodeHandler::getSfallTypeByScriptType(keyType);
|
||||
valType = OpcodeHandler::getSfallTypeByScriptType(valType);
|
||||
if(arrays.find(id)==arrays.end()) return;
|
||||
int el;
|
||||
sArrayVar &arr = arrays[id];
|
||||
@@ -536,7 +498,7 @@ void _stdcall FixArray(DWORD id) {
|
||||
}
|
||||
int _stdcall ScanArray(DWORD id, DWORD val, DWORD datatype, DWORD* resultType) {
|
||||
*resultType = VAR_TYPE_INT;
|
||||
datatype = getSfallTypeByScriptType(datatype);
|
||||
datatype = OpcodeHandler::getSfallTypeByScriptType(datatype);
|
||||
if (arrays.find(id) == arrays.end()) return -1;
|
||||
char step = arrays[id].isAssoc() ? 2 : 1;
|
||||
for (DWORD i = 0; i < arrays[id].val.size(); i += step) {
|
||||
@@ -545,7 +507,7 @@ int _stdcall ScanArray(DWORD id, DWORD val, DWORD datatype, DWORD* resultType) {
|
||||
if ((datatype != DATATYPE_STR && *(DWORD*)&(el.intVal) == val) ||
|
||||
(datatype == DATATYPE_STR && strcmp(el.strVal, (char*)val) == 0)) {
|
||||
if (arrays[id].isAssoc()) { // return key instead of index for associative arrays
|
||||
*resultType = getScriptTypeBySfallType(arrays[id].val[i].type);
|
||||
*resultType = OpcodeHandler::getScriptTypeBySfallType(arrays[id].val[i].type);
|
||||
return *(DWORD *)&arrays[id].val[i].intVal;
|
||||
} else {
|
||||
return i;
|
||||
@@ -557,7 +519,7 @@ int _stdcall ScanArray(DWORD id, DWORD val, DWORD datatype, DWORD* resultType) {
|
||||
}
|
||||
|
||||
DWORD _stdcall LoadArray(DWORD key, DWORD keyType) {
|
||||
int dataType = getSfallTypeByScriptType(keyType);
|
||||
int dataType = OpcodeHandler::getSfallTypeByScriptType(keyType);
|
||||
if (dataType != DATATYPE_INT || key != 0) { // returns arrayId by it's key (ignoring int(0) because it is used to "unsave" array)
|
||||
sArrayElement keyEl = sArrayElement(key, dataType);
|
||||
if (keyEl.type == DATATYPE_STR && strcmp(keyEl.strVal, get_all_arrays_special_key) == 0) { // this is a special case to get temp array containing all saved arrays
|
||||
@@ -583,7 +545,7 @@ DWORD _stdcall LoadArray(DWORD key, DWORD keyType) {
|
||||
|
||||
void _stdcall SaveArray(DWORD key, DWORD keyType, DWORD id) {
|
||||
array_itr it = arrays.find(id), it2;
|
||||
int dataType = getSfallTypeByScriptType(keyType);
|
||||
int dataType = OpcodeHandler::getSfallTypeByScriptType(keyType);
|
||||
if (it != arrays.end()) {
|
||||
if (dataType != DATATYPE_INT || key != 0) {
|
||||
// make array permanent
|
||||
|
||||
@@ -143,9 +143,6 @@ void GetArrays(int* arrays);
|
||||
void DEGetArray(int id, DWORD* types, void* data);
|
||||
void DESetArray(int id, const DWORD* types, const void* data);
|
||||
|
||||
const char* _stdcall GetSfallTypeName(DWORD dataType);
|
||||
DWORD _stdcall getSfallTypeByScriptType(DWORD varType);
|
||||
DWORD _stdcall getScriptTypeBySfallType(DWORD dataType);
|
||||
// creates new normal (persistent) array. len == -1 specifies associative array (map)
|
||||
DWORD _stdcall CreateArray(int len, DWORD nothing);
|
||||
// same as CreateArray, but creates temporary array instead (will die at the end of the frame)
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
- use this macros outside of other __asm {} blocks (obviously)
|
||||
*/
|
||||
|
||||
//eax contains the script pointer, edx contains the opcode*4
|
||||
|
||||
//To read a value, mov the script pointer to eax, call interpretPopShort_, eax now contains the value type
|
||||
//mov the script pointer to eax, call interpretPopLong_, eax now contains the value
|
||||
|
||||
//To return a value, move it to edx, mov the script pointer to eax, call FuncOffs::interpretPushLong_
|
||||
//mov the value type to edx, mov the script pointer to eax, call FuncOffs::interpretPushShort_
|
||||
|
||||
|
||||
// rscript - 32-bit register where script pointer will be put (it is used for several related functions)
|
||||
#define _OP_BEGIN(rscript) __asm \
|
||||
{ \
|
||||
|
||||
@@ -135,16 +135,8 @@ static bool ValidateMetaruleArguments(const SfallMetarule* metaruleInfo) {
|
||||
|
||||
return false;
|
||||
} else {
|
||||
// check if metadata is available for this handler
|
||||
OpcodeMetaTableType::iterator it = opcodeMetaTable.find(metaruleInfo->func);
|
||||
if (it != opcodeMetaTable.end()) {
|
||||
const SfallOpcodeMetadata* meta = it->second;
|
||||
|
||||
// automatically validate argument types
|
||||
return opHandler.validateArguments(meta->argTypeMasks, argCount, metaruleInfo->name);
|
||||
}
|
||||
return opHandler.validateArguments(metaruleInfo->func, argCount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _stdcall op_sfall_metarule_handler() {
|
||||
|
||||
@@ -21,11 +21,14 @@
|
||||
#include "..\..\main.h"
|
||||
|
||||
#include "..\AI.h"
|
||||
#include "..\Criticals.h"
|
||||
#include "..\HeroAppearance.h"
|
||||
#include "..\Inventory.h"
|
||||
#include "..\KillCounter.h"
|
||||
#include "..\Knockback.h"
|
||||
#include "..\Movies.h"
|
||||
#include "..\ScriptExtender.h"
|
||||
#include "..\Stats.h"
|
||||
|
||||
/*
|
||||
* Misc operators
|
||||
@@ -972,6 +975,7 @@ end:
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) funcGetCriticalTable() {
|
||||
__asm {
|
||||
pushad;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2016 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 "..\ScriptExtender.h"
|
||||
|
||||
#include "OpcodeHandler.h"
|
||||
|
||||
OpcodeHandler::OpcodeHandler() {
|
||||
_argShift = 0;
|
||||
_args.reserve (OP_MAX_ARGUMENTS);
|
||||
}
|
||||
|
||||
int OpcodeHandler::numArgs() const {
|
||||
return _args.size() - _argShift;
|
||||
}
|
||||
|
||||
int OpcodeHandler::argShift() const {
|
||||
return _argShift;
|
||||
}
|
||||
|
||||
void OpcodeHandler::setArgShift (int shift) {
|
||||
assert(shift >= 0);
|
||||
|
||||
_argShift = shift;
|
||||
}
|
||||
|
||||
const ScriptValue& OpcodeHandler::arg(int index) const {
|
||||
return _args.at(index + _argShift);
|
||||
}
|
||||
|
||||
const ScriptValue& OpcodeHandler::returnValue() const {
|
||||
return _ret;
|
||||
}
|
||||
|
||||
TProgram* OpcodeHandler::program() const {
|
||||
return _program;
|
||||
}
|
||||
|
||||
void OpcodeHandler::setReturn(DWORD value, SfallDataType type) {
|
||||
_ret = ScriptValue(type, value);
|
||||
}
|
||||
|
||||
void OpcodeHandler::setReturn(const ScriptValue& val) {
|
||||
_ret = val;
|
||||
}
|
||||
|
||||
void OpcodeHandler::resetState(TProgram* program, int argNum) {
|
||||
_program = program;
|
||||
|
||||
// reset return value
|
||||
_ret = ScriptValue();
|
||||
// reset argument list
|
||||
_args.resize(argNum);
|
||||
// reset arg shift
|
||||
_argShift = 0;
|
||||
}
|
||||
|
||||
void OpcodeHandler::printOpcodeError(const char* fmt, ...) const {
|
||||
assert(_program != nullptr);
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char msg[1024];
|
||||
vsnprintf_s(msg, sizeof msg, _TRUNCATE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
const char* procName = Wrapper::findCurrentProc(_program);
|
||||
Wrapper::debug_printf("\nOPCODE ERROR: %s\n Current script: %s, procedure %s.", msg, _program->fileName, procName);
|
||||
}
|
||||
|
||||
bool OpcodeHandler::validateArguments(void (*func)(), int argNum) const {
|
||||
OpcodeMetaTableType::const_iterator it = _opcodeMetaTable.find(func);
|
||||
if (it != _opcodeMetaTable.end()) {
|
||||
const SfallOpcodeMetadata* meta = it->second;
|
||||
|
||||
// automatically validate argument types
|
||||
return validateArguments(meta->argTypeMasks, argNum, meta->name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpcodeHandler::validateArguments(const int argTypeMasks[], int argCount, const char* opcodeName) const {
|
||||
for (int i = 0; i < argCount; i++) {
|
||||
int typeMask = argTypeMasks[i];
|
||||
const ScriptValue &argI = arg(i);
|
||||
if (typeMask != 0 && ((1 << argI.type()) & typeMask) == 0) {
|
||||
printOpcodeError(
|
||||
"%s() - argument #%d has invalid type: %s.",
|
||||
opcodeName,
|
||||
i,
|
||||
getSfallTypeName(argI.type()));
|
||||
|
||||
return false;
|
||||
} else if ((typeMask & DATATYPE_MASK_NOT_NULL) && argI.rawValue() == 0) {
|
||||
printOpcodeError(
|
||||
"%s() - argument #%d is null.",
|
||||
opcodeName,
|
||||
i);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void __thiscall OpcodeHandler::handleOpcode(TProgram* program, void(*func)(), int argNum, bool hasReturn) {
|
||||
assert(argNum < OP_MAX_ARGUMENTS);
|
||||
|
||||
// reset state after previous
|
||||
resetState(program, argNum);
|
||||
|
||||
// process arguments on stack (reverse order)
|
||||
for (int i = argNum - 1; i >= 0; i--) {
|
||||
// get argument from stack
|
||||
DWORD rawValueType = Wrapper::interpretPopShort(program);
|
||||
DWORD rawValue = Wrapper::interpretPopLong(program);
|
||||
SfallDataType type = static_cast<SfallDataType>(getSfallTypeByScriptType(rawValueType));
|
||||
|
||||
// retrieve string argument
|
||||
if (type == DATATYPE_STR) {
|
||||
_args.at(i) = Wrapper::interpretGetString(program, rawValue, rawValueType);
|
||||
} else {
|
||||
_args.at(i) = ScriptValue(type, rawValue);
|
||||
}
|
||||
}
|
||||
|
||||
// call opcode handler if arguments are valid (or no automatic validation was done)
|
||||
if (validateArguments(func, argNum)) {
|
||||
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 = Wrapper::interpretAddString(program, _ret.asString());
|
||||
}
|
||||
Wrapper::interpretPushLong(program, rawResult);
|
||||
Wrapper::interpretPushShort(program, getScriptTypeBySfallType(_ret.type()));
|
||||
}
|
||||
}
|
||||
|
||||
void OpcodeHandler::addOpcodeMetaData(const SfallOpcodeMetadata* data) {
|
||||
_opcodeMetaTable[data->handler] = data;
|
||||
}
|
||||
|
||||
const char* OpcodeHandler::getSfallTypeName(DWORD dataType) {
|
||||
switch (dataType) {
|
||||
case DATATYPE_NONE:
|
||||
return "(none)";
|
||||
case DATATYPE_STR:
|
||||
return "string";
|
||||
case DATATYPE_FLOAT:
|
||||
return "float";
|
||||
case DATATYPE_INT:
|
||||
return "integer";
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
DWORD OpcodeHandler::getSfallTypeByScriptType(DWORD varType) {
|
||||
varType &= 0xffff;
|
||||
switch (varType) {
|
||||
case VAR_TYPE_STR:
|
||||
case VAR_TYPE_STR2:
|
||||
return DATATYPE_STR;
|
||||
case VAR_TYPE_FLOAT:
|
||||
return DATATYPE_FLOAT;
|
||||
case VAR_TYPE_INT:
|
||||
default:
|
||||
return DATATYPE_INT;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD OpcodeHandler::getScriptTypeBySfallType(DWORD dataType) {
|
||||
switch (dataType) {
|
||||
case DATATYPE_STR:
|
||||
return VAR_TYPE_STR;
|
||||
case DATATYPE_FLOAT:
|
||||
return VAR_TYPE_FLOAT;
|
||||
case DATATYPE_INT:
|
||||
default:
|
||||
return VAR_TYPE_INT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2016 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 <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "..\..\FalloutEngine\Structs.h"
|
||||
#include "ScriptValue.h"
|
||||
|
||||
// variables for new opcodes
|
||||
#define OP_MAX_ARGUMENTS (10)
|
||||
|
||||
// masks for argument validation
|
||||
#define DATATYPE_MASK_INT (1 << DATATYPE_INT)
|
||||
#define DATATYPE_MASK_FLOAT (1 << DATATYPE_FLOAT)
|
||||
#define DATATYPE_MASK_STR (1 << DATATYPE_STR)
|
||||
#define DATATYPE_MASK_NOT_NULL (0x00010000)
|
||||
#define DATATYPE_MASK_VALID_OBJ (DATATYPE_MASK_INT | DATATYPE_MASK_NOT_NULL)
|
||||
|
||||
|
||||
|
||||
struct SfallOpcodeMetadata {
|
||||
// opcode handler, will be used as key
|
||||
void (*handler)();
|
||||
|
||||
// opcode name, only used for logging
|
||||
const char* name;
|
||||
|
||||
// argument validation masks
|
||||
int argTypeMasks[OP_MAX_ARGUMENTS];
|
||||
};
|
||||
|
||||
typedef std::tr1::unordered_map<void(*)(), const SfallOpcodeMetadata*> OpcodeMetaTableType;
|
||||
|
||||
class OpcodeHandler {
|
||||
public:
|
||||
OpcodeHandler();
|
||||
|
||||
void addOpcodeMetaData(const SfallOpcodeMetadata* data);
|
||||
|
||||
// number of arguments, possibly reduced by argShift
|
||||
int numArgs() const;
|
||||
|
||||
// returns current argument shift, default is 0
|
||||
int argShift() const;
|
||||
|
||||
// sets shift value for arguments
|
||||
// for example if shift value is 2, then subsequent calls to arg(i) will return arg(i+2) instead, etc.
|
||||
void setArgShift(int shift);
|
||||
|
||||
// returns argument with given index, possible shifted by argShift
|
||||
const ScriptValue& arg(int index) const;
|
||||
|
||||
// current return value
|
||||
const ScriptValue& returnValue() const;
|
||||
|
||||
// current script program
|
||||
TProgram* program() const;
|
||||
|
||||
// set return value for current opcode
|
||||
void setReturn(unsigned long value, SfallDataType type);
|
||||
|
||||
// set return value for current opcode
|
||||
void setReturn(const ScriptValue& val);
|
||||
|
||||
// resets the state of handler for new opcode invocation
|
||||
void resetState(TProgram* program, int argNum);
|
||||
|
||||
// writes error message to debug.log along with the name of script & procedure
|
||||
void printOpcodeError(const char* fmt, ...) const;
|
||||
|
||||
// Validate opcode arguments against type masks
|
||||
// if validation pass, returns true, otherwise writes error to debug.log and returns false
|
||||
bool validateArguments(const int argTypeMasks[], int argCount, const char* opcodeName) const;
|
||||
|
||||
// validate opcode arguments given opcode handler function and actual number of arguments
|
||||
bool validateArguments(void (*func)(), int argNum) const;
|
||||
|
||||
// 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* program, void(*func)(), int argNum, bool hasReturn);
|
||||
|
||||
static const char* getSfallTypeName(DWORD dataType);
|
||||
static DWORD getSfallTypeByScriptType(DWORD varType);
|
||||
static DWORD getScriptTypeBySfallType(DWORD dataType);
|
||||
|
||||
private:
|
||||
TProgram* _program;
|
||||
|
||||
int _argShift;
|
||||
std::vector<ScriptValue> _args;
|
||||
ScriptValue _ret;
|
||||
OpcodeMetaTableType _opcodeMetaTable;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2016 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 "ScriptValue.h"
|
||||
|
||||
|
||||
ScriptValue::ScriptValue( SfallDataType type, unsigned long value )
|
||||
{
|
||||
_val.dw = value;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
ScriptValue::ScriptValue() {
|
||||
_val.dw = 0;
|
||||
_type = DATATYPE_NONE;
|
||||
}
|
||||
|
||||
ScriptValue::ScriptValue(const char* strval) {
|
||||
_val.str = strval;
|
||||
_type = DATATYPE_STR;
|
||||
}
|
||||
|
||||
ScriptValue::ScriptValue(int val) {
|
||||
_val.i = val;
|
||||
_type = DATATYPE_INT;
|
||||
}
|
||||
|
||||
ScriptValue::ScriptValue(float strval) {
|
||||
_val.f = strval;
|
||||
_type = DATATYPE_FLOAT;
|
||||
}
|
||||
|
||||
ScriptValue::ScriptValue(TGameObj* obj) {
|
||||
_val.gObj = obj;
|
||||
_type = DATATYPE_INT;
|
||||
}
|
||||
|
||||
bool ScriptValue::isInt() const
|
||||
{
|
||||
return _type == DATATYPE_INT;
|
||||
}
|
||||
|
||||
bool ScriptValue::isFloat() const {
|
||||
return _type == DATATYPE_FLOAT;
|
||||
}
|
||||
|
||||
bool ScriptValue::isString() const {
|
||||
return _type == DATATYPE_STR;
|
||||
}
|
||||
|
||||
unsigned long ScriptValue::rawValue() const {
|
||||
return _val.dw;
|
||||
}
|
||||
|
||||
int ScriptValue::asInt() const {
|
||||
switch (_type) {
|
||||
case DATATYPE_FLOAT:
|
||||
return static_cast<int>(_val.f);
|
||||
case DATATYPE_INT:
|
||||
return _val.i;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float ScriptValue::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* ScriptValue::asString() const {
|
||||
return (_type == DATATYPE_STR)
|
||||
? _val.str
|
||||
: "";
|
||||
}
|
||||
|
||||
TGameObj* ScriptValue::asObject() const {
|
||||
return (_type == DATATYPE_INT)
|
||||
? _val.gObj
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
SfallDataType ScriptValue::type() const {
|
||||
return _type;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2016 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 "..\..\FalloutEngine\Structs.h"
|
||||
|
||||
// TODO: replace with enum class
|
||||
enum SfallDataType {
|
||||
DATATYPE_NONE = 0,
|
||||
DATATYPE_INT,
|
||||
DATATYPE_FLOAT,
|
||||
DATATYPE_STR
|
||||
};
|
||||
|
||||
class ScriptValue {
|
||||
public:
|
||||
ScriptValue(SfallDataType type, unsigned long value);
|
||||
|
||||
ScriptValue();
|
||||
|
||||
ScriptValue(const char* strval);
|
||||
|
||||
ScriptValue(int val);
|
||||
|
||||
ScriptValue(float strval);
|
||||
|
||||
ScriptValue(TGameObj* obj);
|
||||
|
||||
bool isInt() const;
|
||||
|
||||
bool isFloat() const;
|
||||
|
||||
bool isString() const;
|
||||
|
||||
unsigned long rawValue() const;
|
||||
|
||||
int asInt() const;
|
||||
|
||||
float asFloat() const;
|
||||
|
||||
const char* asString() const;
|
||||
|
||||
TGameObj* asObject() const;
|
||||
|
||||
SfallDataType type() const;
|
||||
|
||||
private:
|
||||
union Value {
|
||||
unsigned long dw;
|
||||
int i;
|
||||
float f;
|
||||
const char* str;
|
||||
TGameObj* gObj;
|
||||
} _val;
|
||||
|
||||
SfallDataType _type; // TODO: replace with enum class
|
||||
};
|
||||
|
||||
@@ -222,9 +222,12 @@
|
||||
<ClInclude Include="Modules\Scripting\MetaruleOp.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\MiscOps.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\ObjectsOps.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\OpcodeHandler.h" />
|
||||
<ClInclude Include="Modules\Scripting\Opcodes.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\PerksOp.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\ScriptArrays.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\ScriptUtils.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\ScriptValue.h" />
|
||||
<ClInclude Include="Modules\Scripting\StatsOp.hpp" />
|
||||
<ClInclude Include="Modules\Scripting\WorldmapOps.hpp" />
|
||||
<ClInclude Include="win9x\Cpp11_emu.h" />
|
||||
@@ -305,6 +308,8 @@
|
||||
<ClCompile Include="Modules\QuestList.cpp" />
|
||||
<ClCompile Include="Modules\Reputations.cpp" />
|
||||
<ClCompile Include="Modules\Scripting\Arrays.cpp" />
|
||||
<ClCompile Include="Modules\Scripting\OpcodeHandler.cpp" />
|
||||
<ClCompile Include="Modules\Scripting\ScriptValue.cpp" />
|
||||
<ClCompile Include="SafeWrite.cpp" />
|
||||
<ClCompile Include="Modules\Skills.cpp" />
|
||||
<ClCompile Include="Modules\Sound.cpp" />
|
||||
|
||||
@@ -204,6 +204,15 @@
|
||||
<ClInclude Include="FalloutEngine\Utils.h">
|
||||
<Filter>FalloutEngine</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Modules\Scripting\OpcodeHandler.h">
|
||||
<Filter>Modules\Scripting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Modules\Scripting\ScriptValue.h">
|
||||
<Filter>Modules\Scripting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Modules\Scripting\Opcodes.hpp">
|
||||
<Filter>Modules\Scripting</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
@@ -340,6 +349,12 @@
|
||||
<ClCompile Include="FalloutEngine\Utils.cpp">
|
||||
<Filter>FalloutEngine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Modules\Scripting\OpcodeHandler.cpp">
|
||||
<Filter>Modules\Scripting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Modules\Scripting\ScriptValue.cpp">
|
||||
<Filter>Modules\Scripting</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="version.rc" />
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
//#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include "SafeWrite.h"
|
||||
|
||||
Reference in New Issue
Block a user