Small optimization for receiving/passing script arguments

* combined related engine interpreter functions into a single function
for aligning the compiled ASM code better.

Minor changes to some other code and documents.
This commit is contained in:
NovaRain
2020-01-31 00:24:58 +08:00
parent 90b547a472
commit 19f4901328
9 changed files with 97 additions and 83 deletions
+10 -2
View File
@@ -87,7 +87,7 @@
#define FLAG_SEEN (0x40000000) #define FLAG_SEEN (0x40000000)
#define FLAG_SHOOTTHRU (0x80000000) #define FLAG_SHOOTTHRU (0x80000000)
/* Critter Flags */ /* Critter flags */
#define CFLG_BARTER 2 // 0x00000002 - Barter (can trade with) #define CFLG_BARTER 2 // 0x00000002 - Barter (can trade with)
#define CFLG_NOSTEAL 32 // 0x00000020 - Steal (cannot steal from) #define CFLG_NOSTEAL 32 // 0x00000020 - Steal (cannot steal from)
#define CFLG_NODROP 64 // 0x00000040 - Drop (doesn't drop items) #define CFLG_NODROP 64 // 0x00000040 - Drop (doesn't drop items)
@@ -100,12 +100,20 @@
#define CFLG_RANGED 8192 // 0x00002000 - Range (melee attack is possible at a distance) #define CFLG_RANGED 8192 // 0x00002000 - Range (melee attack is possible at a distance)
#define CFLG_NOKNOCKDOWN 16384 // 0x00004000 - Knock (cannot be knocked down) #define CFLG_NOKNOCKDOWN 16384 // 0x00004000 - Knock (cannot be knocked down)
/* Window Flags */ /* Window flags */
#define WIN_FLAG_MOVEONTOP (0x4) #define WIN_FLAG_MOVEONTOP (0x4)
#define WIN_FLAG_HIDDEN (0x8) #define WIN_FLAG_HIDDEN (0x8)
#define WIN_FLAG_EXCLUSIVE (0x10) #define WIN_FLAG_EXCLUSIVE (0x10)
#define WIN_FLAG_TRANSPARENT (0x20) #define WIN_FLAG_TRANSPARENT (0x20)
/* Message window flags */
#define MSGBOX_AUTOSIZE (0x0)
#define MSGBOX_NORMAL (0x1)
#define MSGBOX_SMALL (0x2)
#define MSGBOX_ALIGN_LEFT (0x4) // text aligned to left
#define MSGBOX_ALIGN_TOP (0x8) // text aligned to top
#define MSGBOX_YESNO (0x10) // uses YES/NO buttons instead of DONE
#define MSGBOX_CLEAN (0x20) // no buttons
//remove inven obj defines //remove inven obj defines
#define RMOBJ_CONSUME_DRUG 4666772 #define RMOBJ_CONSUME_DRUG 4666772
+2 -2
View File
@@ -718,11 +718,11 @@ optional argument:
- areaID: the ID number of the town from city.txt - areaID: the ID number of the town from city.txt
> int sfall_func4("message_box", string message, int flags, int color1, int color2) > int sfall_func4("message_box", string message, int flags, int color1, int color2)
- creates a dialog box with text and returns the result of pressing the button: 0 - No, 1 - Yes/Done - creates a dialog box with text and returns the result of pressing the button: 0 - No (Escape), 1 - Yes/Done (Enter)
- returns -1 if for some reason the dialog box cannot be created - returns -1 if for some reason the dialog box cannot be created
- message: the text in the dialog box. Use the \n control character to move text to a new line (example: "Hello\nWorld!") - message: the text in the dialog box. Use the \n control character to move text to a new line (example: "Hello\nWorld!")
optional arguments: optional arguments:
- flags: mode flags (see DIALOGOUT_* constants in define_extra.h). Pass -1 to skip setting the flags (default flags are DIALOGOUT_NORMAL|DIALOGOUT_YESNO) - flags: mode flags (see MSGBOX_* constants in define_extra.h). Pass -1 to skip setting the flags (default flags are NORMAL and YESNO)
- color1/2: the color index in Fallout palette. color1 sets the text color for the first line, and color2 for all subsequent lines of text (default color is 145) - color1/2: the color index in Fallout palette. color1 sets the text color for the first line, and color2 for all subsequent lines of text (default color is 145)
------------------------ ------------------------
+1 -1
View File
@@ -795,7 +795,7 @@ enum DialogOutFlags : long
DIALOGOUT_SMALL = 0x02, // uses smaller graphic DIALOGOUT_SMALL = 0x02, // uses smaller graphic
DIALOGOUT_ALIGN_LEFT = 0x04, // text aligned to left DIALOGOUT_ALIGN_LEFT = 0x04, // text aligned to left
DIALOGOUT_ALIGN_TOP = 0x08, // text aligned to top DIALOGOUT_ALIGN_TOP = 0x08, // text aligned to top
DIALOGOUT_YESNO = 0x10, // DONE button replaced by YES/NO buttons - WIP: currently useless in scripts DIALOGOUT_YESNO = 0x10, // DONE button replaced by YES/NO buttons
DIALOGOUT_CLEAN = 0x20 // no buttons DIALOGOUT_CLEAN = 0x20 // no buttons
}; };
+59 -28
View File
@@ -228,24 +228,48 @@ DWORD __stdcall interpretPopLong(Program* scriptPtr) {
WRAP_WATCOM_CALL1(interpretPopLong_, scriptPtr) WRAP_WATCOM_CALL1(interpretPopLong_, scriptPtr)
} }
// pushes value to Data stack (must be followed by InterpretPushShort)
void __stdcall interpretPushLong(Program* scriptPtr, DWORD val) {
WRAP_WATCOM_CALL2(interpretPushLong_, scriptPtr, val)
}
// pushes value type to Data stack (must be preceded by InterpretPushLong)
void __stdcall interpretPushShort(Program* scriptPtr, DWORD valType) {
WRAP_WATCOM_CALL2(interpretPushShort_, scriptPtr, valType)
}
DWORD __stdcall interpretAddString(Program* scriptPtr, const char* strval) {
WRAP_WATCOM_CALL2(interpretAddString_, scriptPtr, strval)
}
const char* __fastcall interpretGetString(Program* scriptPtr, DWORD dataType, DWORD strId) { const char* __fastcall interpretGetString(Program* scriptPtr, DWORD dataType, DWORD strId) {
WRAP_WATCOM_FCALL3(interpretGetString_, scriptPtr, dataType, strId) WRAP_WATCOM_FCALL3(interpretGetString_, scriptPtr, dataType, strId)
} }
void interpretReturnValue(Program* scriptPtr, DWORD val, DWORD valType) {
__asm {
mov esi, scriptPtr;
mov edx, val;
cmp valType, VAR_TYPE_STR;
jne isNotStr;
mov eax, esi;
call fo::funcoffs::interpretAddString_;
mov edx, eax;
isNotStr:
mov eax, esi;
call fo::funcoffs::interpretPushLong_; // pushes value to Data stack (must be followed by InterpretPushShort)
mov edx, valType;
mov eax, esi;
call fo::funcoffs::interpretPushShort_; // pushes value type to Data stack (must be preceded by InterpretPushLong)
}
}
DWORD __fastcall interpretGetValue(Program* scriptPtr, DWORD &outType) {
__asm {
mov eax, ecx;
call fo::funcoffs::interpretPopShort_; // pops value type from Data stack (must be followed by InterpretPopLong)
mov [edx], eax; // out type
mov edx, eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_; // pops value from Data stack (must be preceded by InterpretPopShort)
cmp dx, VAR_TYPE_STR2;
je getStr;
cmp dx, VAR_TYPE_STR;
jne isNotStr;
getStr:
mov ebx, eax;
mov eax, ecx;
call fo::funcoffs::interpretGetString_; // retrieve string argument
isNotStr:
}
}
// prints scripting error in debug.log and stops current script execution by performing longjmp // prints scripting error in debug.log and stops current script execution by performing longjmp
// USE WITH CAUTION // USE WITH CAUTION
void __declspec(naked) interpretError(const char* fmt, ...) { void __declspec(naked) interpretError(const char* fmt, ...) {
@@ -402,37 +426,44 @@ long __stdcall win_register_button(DWORD winRef, long xPos, long yPos, long widt
} }
} }
void __fastcall DialogOut(const char* text, const char** textEx, long lines) { void __stdcall DialogOut(const char* text) {
__asm { __asm {
push 1; // DIALOGOUT_NORMAL flag push 1; // DIALOGOUT_NORMAL flag
xor eax, eax; xor edx, edx;
mov al, byte ptr ds:[0x6AB718]; push edx;
push eax; // ColorMsg push edx;
push 0; // DisplayMsg (unknown) mov dl, byte ptr ds:[0x6AB718];
push eax; // ColorIndex push edx; // ColorMsg
mov eax, ecx; // DisplayText
push 116; // y
mov ecx, 192; // x mov ecx, 192; // x
mov ebx, lines; // count text lines 0-5 push 116; // y
mov eax, text; // DisplayText
xor ebx, ebx;
call fo::funcoffs::dialog_out_; call fo::funcoffs::dialog_out_;
} }
} }
long __fastcall DialogOutEx(const char* text, const char** textEx, long lines, long flags, long colors) { long __fastcall DialogOutEx(const char* text, const char** textEx, long lines, long flags, long colors) {
__asm { __asm {
xor eax, eax;
mov ebx, colors; // Color index mov ebx, colors; // Color index
xor eax, eax;
push flags;
test ebx, ebx;
jnz cColor;
mov al, byte ptr ds:[0x6AB718];
mov bl, al;
jmp skip;
cColor:
mov al, bh; mov al, bh;
push flags; // flag
and ebx, 0xFF and ebx, 0xFF
skip:
push eax; // ColorMsg2 push eax; // ColorMsg2
push 0; // DisplayMsg (unknown) push 0; // DisplayMsg (unknown)
mov eax, ecx; // DisplayText first line mov eax, ecx; // DisplayText (first line)
push ebx; // ColorMsg1 push ebx; // ColorMsg1
mov ecx, 192; // x mov ecx, 192; // x
push 116; // y push 116; // y
mov ebx, lines; // count text lines 0-5 mov ebx, lines; // count second lines
call fo::funcoffs::dialog_out_; // edx - DisplayText second and later lines call fo::funcoffs::dialog_out_; // edx - DisplayText (seconds lines)
} }
} }
+5 -9
View File
@@ -120,15 +120,11 @@ DWORD __stdcall interpretPopShort(Program* scriptPtr);
// pops value from Data stack (must be preceded by InterpretPopShort) // pops value from Data stack (must be preceded by InterpretPopShort)
DWORD __stdcall interpretPopLong(Program* scriptPtr); DWORD __stdcall interpretPopLong(Program* scriptPtr);
// pushes value to Data stack (must be followed by InterpretPushShort)
void __stdcall interpretPushLong(Program* scriptPtr, DWORD val);
// pushes value type to Data stack (must be preceded by InterpretPushLong)
void __stdcall interpretPushShort(Program* scriptPtr, DWORD valType);
const char* __fastcall interpretGetString(Program* scriptPtr, DWORD dataType, DWORD strId); const char* __fastcall interpretGetString(Program* scriptPtr, DWORD dataType, DWORD strId);
DWORD __stdcall interpretAddString(Program* scriptPtr, const char* str); void interpretReturnValue(Program* scriptPtr, DWORD val, DWORD valType);
DWORD __fastcall interpretGetValue(Program* scriptPtr, DWORD &outType);
// prints scripting error in debug.log and stops current script execution by performing longjmp // prints scripting error in debug.log and stops current script execution by performing longjmp
// USE WITH CAUTION // USE WITH CAUTION
@@ -206,9 +202,9 @@ long __stdcall stat_level(GameObject* critter, long statId);
// pictureUp/pictureDown - pointers to a surface // pictureUp/pictureDown - pointers to a surface
long __stdcall win_register_button(DWORD winRef, long xPos, long yPos, long width, long height, long hoverOn, long hoverOff, long buttonDown, long buttonUp, BYTE* pictureUp, BYTE* pictureDown, long arg12, long buttonType); long __stdcall win_register_button(DWORD winRef, long xPos, long yPos, long width, long height, long hoverOn, long hoverOff, long buttonDown, long buttonUp, BYTE* pictureUp, BYTE* pictureDown, long arg12, long buttonType);
void __fastcall DialogOut(const char* text, const char** textEx, long lines); void __stdcall DialogOut(const char* text);
long __fastcall DialogOutEx(const char* text, const char** textEx, long lines, long flags, long colors); long __fastcall DialogOutEx(const char* text, const char** textEx, long lines, long flags, long colors = 0);
// draws an image to the buffer without scaling and with transparency display toggle // draws an image to the buffer without scaling and with transparency display toggle
void __fastcall windowDisplayBuf(long x, long width, long y, long height, void* data, long noTrans); void __fastcall windowDisplayBuf(long x, long width, long y, long height, void* data, long noTrans);
@@ -130,14 +130,14 @@ void __declspec(naked) op_resume_game() {
// copy and split // copy and split
static void SplitToBuffer(const char* str, const char** str_ptr, long &lines) { static void SplitToBuffer(const char* str, const char** str_ptr, long &lines) {
size_t i = 0; size_t i = 0;
do { while (str[i]) {
if (str[i] == '\n' && lines < 4) { if (str[i] == '\n' && lines < 4) {
ScriptExtender::gTextBuffer[i] = '\0'; ScriptExtender::gTextBuffer[i] = '\0';
str_ptr[lines++] = &ScriptExtender::gTextBuffer[++i]; str_ptr[lines++] = &ScriptExtender::gTextBuffer[++i];
} else { } else {
ScriptExtender::gTextBuffer[i] = str[i++]; ScriptExtender::gTextBuffer[i] = str[i++];
} }
} while (str[i]); };
ScriptExtender::gTextBuffer[i] = '\0'; ScriptExtender::gTextBuffer[i] = '\0';
} }
@@ -153,7 +153,7 @@ void sf_create_message_window(OpcodeContext &ctx) {
SplitToBuffer(str, str_ptr, lines); SplitToBuffer(str, str_ptr, lines);
dialogShow = true; dialogShow = true;
fo::func::DialogOut(ScriptExtender::gTextBuffer, str_ptr, lines); fo::func::DialogOutEx(ScriptExtender::gTextBuffer, str_ptr, lines, fo::DIALOGOUT_NORMAL);
dialogShow = false; dialogShow = false;
} }
@@ -163,12 +163,8 @@ static void sf_metarule_exist(OpcodeContext& ctx) {
bool result = false; bool result = false;
auto funcXName = ctx.arg(0).asString(); auto funcXName = ctx.arg(0).asString();
if (funcXName[0] != '\0') { if (funcXName[0] != '\0') {
for (auto it = metaruleTable.begin(); it != metaruleTable.end(); it++) { const auto &it = metaruleTable.find(funcXName);
if (it->first == funcXName) { if (it != metaruleTable.cend()) result = true;
result = true;
break;
}
}
} }
ctx.setReturn(result); ctx.setReturn(result);
} }
+4 -16
View File
@@ -228,16 +228,9 @@ void OpcodeContext::_popArguments() {
// process arguments on stack (reverse order) // process arguments on stack (reverse order)
for (int i = _numArgs - 1; i >= 0; i--) { for (int i = _numArgs - 1; i >= 0; i--) {
// get argument from stack // get argument from stack
DWORD rawValueType = fo::func::interpretPopShort(_program); DWORD rawValueType;
DWORD rawValue = fo::func::interpretPopLong(_program); DWORD rawValue = fo::func::interpretGetValue(_program, rawValueType);
DataType type = getSfallTypeByScriptType(rawValueType); _args[i] = ScriptValue(getSfallTypeByScriptType(rawValueType), rawValue);
// retrieve string argument
if (type == DataType::STR) {
_args[i] = fo::func::interpretGetString(_program, rawValueType, rawValue);
} else {
_args[i] = ScriptValue(type, rawValue);
}
} }
} }
@@ -245,12 +238,7 @@ void OpcodeContext::_pushReturnValue() {
if (_ret.type() == DataType::NONE) { if (_ret.type() == DataType::NONE) {
_ret = ScriptValue(0); // if no value was set in handler, force return 0 to avoid stack error _ret = ScriptValue(0); // if no value was set in handler, force return 0 to avoid stack error
} }
DWORD rawResult = _ret.rawValue(); fo::func::interpretReturnValue(_program, _ret.rawValue(), getScriptTypeBySfallType(_ret.type()));
if (_ret.type() == DataType::STR) {
rawResult = fo::func::interpretAddString(_program, _ret.strValue());
}
fo::func::interpretPushLong(_program, rawResult);
fo::func::interpretPushShort(_program, getScriptTypeBySfallType(_ret.type()));
} }
} }
+11 -16
View File
@@ -43,7 +43,7 @@ struct levelRest {
std::unordered_map<int, levelRest> mapRestInfo; std::unordered_map<int, levelRest> mapRestInfo;
std::vector<std::pair<long, std::string>> wmTerrainTypeNames; // pair first: x + y * number of horizontal sub-tiles std::vector<std::pair<long, std::string>> wmTerrainTypeNames; // pair first: x + y * number of horizontal sub-tiles
std::vector<std::pair<long, std::string>> wmAreaHotSpotTitle; std::unordered_map<long, std::string> wmAreaHotSpotTitle;
static bool restMap; static bool restMap;
static bool restMode; static bool restMode;
@@ -616,14 +616,13 @@ void Worldmap::SetTerrainTypeName(long x, long y, const char* name) {
long subTileID = x + y * (fo::var::wmNumHorizontalTiles * 7); long subTileID = x + y * (fo::var::wmNumHorizontalTiles * 7);
wmTerrainTypeNames.push_back(std::make_pair(subTileID, name)); wmTerrainTypeNames.push_back(std::make_pair(subTileID, name));
} }
/*
// TODO: someone might need to know the name of a terrain type? // TODO: someone might need to know the name of a terrain type?
const char* Worldmap::GetTerrainTypeName(long x, long y) { /*const char* Worldmap::GetTerrainTypeName(long x, long y) {
//const char* name = GetOverrideTerrainName(x, y); const char* name = GetOverrideTerrainName(x, y);
//return (name) ? name : fo::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::wmGetTerrainType(x, y)); return (name) ? name : fo::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::wmGetTerrainType(x, y));
return nullptr; }*/
}
*/
// Returns the name of the terrain type in the position of the player's marker on the world map // Returns the name of the terrain type in the position of the player's marker on the world map
const char* Worldmap::GetCurrentTerrainName() { const char* Worldmap::GetCurrentTerrainName() {
const char* name = GetOverrideTerrainName(fo::var::world_xpos / 50, fo::var::world_ypos / 50); const char* name = GetOverrideTerrainName(fo::var::world_xpos / 50, fo::var::world_ypos / 50);
@@ -635,17 +634,13 @@ bool Worldmap::AreaTitlesIsEmpty() {
} }
void Worldmap::SetCustomAreaTitle(long areaID, const char* msg) { void Worldmap::SetCustomAreaTitle(long areaID, const char* msg) {
wmAreaHotSpotTitle.push_back(std::make_pair(areaID, msg)); wmAreaHotSpotTitle[areaID] = msg;
} }
const char* Worldmap::GetCustomAreaTitle(long areaID) { const char* Worldmap::GetCustomAreaTitle(long areaID) {
if (wmAreaHotSpotTitle.empty()) return nullptr; if (AreaTitlesIsEmpty()) return nullptr;
const auto &it = wmAreaHotSpotTitle.find(areaID);
auto it = std::find_if(wmAreaHotSpotTitle.crbegin(), wmAreaHotSpotTitle.crend(), return (it != wmAreaHotSpotTitle.cend()) ? it->second.c_str() : nullptr;
[=](const std::pair<long, std::string> &el)
{ return el.first == areaID; }
);
return (it != wmAreaHotSpotTitle.crend()) ? it->second.c_str() : nullptr;
} }
void Worldmap::init() { void Worldmap::init() {