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.
186 lines
5.7 KiB
D
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;
|
|
};
|