mahlendur/_work/Data/Scripts/Content/LeGo/ConsoleCommands.d
Daniel Heße 892a40ff0f Initial commit with Subversion-codebase from 13/05/2022.
Cleaned up the mess, at this time, only viable data get synced (_work directory for Gothic-data, miranda for mdc-scripts.
Need to symlink files to a working directory.
2022-05-13 17:38:52 +02:00

186 lines
5.7 KiB
D

/***********************************\
CONSOLECOMMANDS
\***********************************/
//========================================
// [intern] Class / Variables
//========================================
class CCItem {
var int fncID;
var string cmd;
};
instance CCItem@(CCItem);
const int _CC_List = 0; // Non-persistent record of all CCs
//========================================
// Check if CC is registered
//========================================
func int CC_Active(var func function) {
if (!_CC_List) {
return FALSE;
};
var int symID; symID = MEM_GetFuncID(function);
// Iterate over all registered CCs
var zCArray a; a = _^(_CC_List);
repeat(i, a.numInArray); var int i;
var CCItem cc; cc = _^(MEM_ReadIntArray(a.array, i));
if (cc.fncID == symID) {
return TRUE;
};
end;
return FALSE;
};
//========================================
// Remove CC
//========================================
func void CC_Remove(var func function) {
if (!_CC_List) {
return;
};
var int symID; symID = MEM_GetFuncID(function);
// Iterate over all registered CCs
var zCArray a; a = _^(_CC_List);
repeat(i, a.numInArray); var int i;
var int ccPtr; ccPtr = MEM_ReadIntArray(a.array, i);
var CCItem cc; cc = _^(ccPtr);
if (cc.fncID == symID) {
MEM_ArrayRemoveIndex(_CC_List, ccPtr);
MEM_Free(ccPtr);
};
end;
};
//========================================
// [intern] Register auto-completion
//========================================
func void CC_AutoComplete(var string commandPrefix, var string description) {
var int descPtr; descPtr = _@s(description);
var int comPtr; comPtr = _@s(commandPrefix);
const int call = 0;
if (CALL_Begin(call)) {
CALL_PtrParam(_@(descPtr));
CALL_PtrParam(_@(comPtr));
CALL__thiscall(_@(zcon_address_lego), zCConsole__Register);
call = CALL_End();
};
};
//========================================
// Register new CC
//========================================
func void CC_Register(var func function, var string commandPrefix, var string description) {
// Remove any left over handles (from LeGo 2.4.0) if they are unarchived from old game saves
if (hasHndl(CCItem@)) {
foreachHndl(CCItem@, _CCItem_deleteHandles);
};
// Only add if not already present
if (CC_Active(function)) {
return;
};
// Check validity of function signature
var int symID; symID = MEM_GetFuncID(function);
var zCPar_Symbol symb; symb = _^(MEM_GetSymbolByIndex(symID));
if ((symb.bitfield & zCPar_Symbol_bitfield_ele) != 1) || (symb.offset != (zPAR_TYPE_STRING >> 12)) {
MEM_Error(ConcatStrings("CONSOLECOMMANDS: Function has to have one parameter and needs to return a string: ",
symb.name));
return;
};
symb = _^(MEM_GetSymbolByIndex(symID+1));
if ((symb.bitfield & zCPar_Symbol_bitfield_type) != zPAR_TYPE_STRING) {
MEM_Error(ConcatStrings("CONSOLECOMMANDS: Function parameter needs to be a string: ", symb.name));
return;
};
// Register auto-completion
commandPrefix = STR_Upper(commandPrefix);
CC_AutoComplete(commandPrefix, description);
// Create CC object
var int ccPtr; ccPtr = create(CCItem@);
var CCItem cc; cc = _^(ccPtr);
cc.fncID = symID;
cc.cmd = commandPrefix;
// Initialize once
if (!_CC_List) {
_CC_List = MEM_ArrayCreate();
};
// Add CC to 'list'
MEM_ArrayInsert(_CC_List, ccPtr);
};
//========================================
// [intern] Engine hook
//========================================
func void _CC_Hook() {
if (!_CC_List) {
return;
};
// Get query entered into console
var int stackOffset; stackOffset = MEMINT_SwitchG1G2(/*2ach*/ 684, /*424h*/ 1060);
var string query; query = MEM_ReadString(MEM_ReadInt(ESP+stackOffset+4));
// Iterate over all registered CCs
var zCArray a; a = _^(_CC_List);
repeat(i, a.numInArray); var int i;
var CCItem cc; cc = _^(MEM_ReadIntArray(a.array, i));
// Check if entered query starts with defined command
if (STR_StartsWith(query, cc.cmd)) {
// Cut off everything after the command
var int cmdLen; cmdLen = STR_Len(cc.cmd);
var int qryLen; qryLen = STR_Len(query);
STR_SubStr(query, cmdLen, qryLen-cmdLen); // Leave on data stack
// Call the CC function (argument already on data stack)
MEM_CallByID(cc.fncID);
var string ret; ret = MEM_PopStringResult();
// If the CC function returns a valid string, stop the loop
// This additional check allows multiple CCs with the same command
if (!Hlp_StrCmp(ret, "")) {
MEM_WriteString(EAX, ret);
break;
};
};
end;
};
//=======================================
// Simple LeGo console command
//=======================================
func string CC_LeGo(var string _) {
var int s; s = SB_New();
SB(LeGO_Version);
SBc(10); SBc(13);
_LeGo_Flags;
MEM_Call(LeGo_FlagsHR);
SB(MEM_PopStringResult());
var string ret; ret = SB_ToString();
SB_Destroy();
return ret;
};
//========================================
// [intern] Old game save compatibility
//========================================
// ConsoleCommands have been rewritten to not be stored to game saves. To ensure compatibility with old game saves from
// LeGo 2.4.0, this function is necessary to prevent errors on unarchiving, because 'fncID' was stored as string.
func void CCItem_Unarchiver(var CCItem this) {};
func int _CCItem_deleteHandles(var int hndl) {
delete(hndl);
return rContinue;
};