qzdoom/src/scriptutil.cpp

110 lines
2.8 KiB
C++

//-----------------------------------------------------------------------------
//
// Copyright 2018 Christoph Oelckers
//
// 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/
//
//-----------------------------------------------------------------------------
//
//
// DESCRIPTION: generalized interface for implementing ACS/FS functions
// in ZScript.
//
//-----------------------------------------------------------------------------
#include "i_system.h"
#include "tarray.h"
#include "dobject.h"
#include "vm.h"
#include "scriptutil.h"
#include "p_acs.h"
#include "actorinlines.h"
static TArray<VMValue> parameters;
static TMap<FName, VMFunction*> functions;
void ScriptUtil::Clear()
{
parameters.Clear();
functions.Clear();
}
void ScriptUtil::BuildParameters(va_list ap)
{
for(int type = va_arg(ap, int); type != End; type = va_arg(ap, int))
{
switch (type)
{
case Int:
parameters.Push(VMValue(va_arg(ap, int)));
break;
case Pointer:
case Class: // this is just a pointer.
case String: // must be passed by reference to a persistent location!
parameters.Push(VMValue(va_arg(ap, void*)));
break;
case Float:
parameters.Push(VMValue(va_arg(ap, double)));
break;
case ACSClass:
parameters.Push(VMValue(PClass::FindActor(FBehavior::StaticLookupString(va_arg(ap, int)))));
break;
}
}
}
void ScriptUtil::RunFunction(FName functionname, unsigned paramstart, VMReturn &returns)
{
VMFunction *func = nullptr;
auto check = functions.CheckKey(functionname);
if (!check)
{
func = PClass::FindFunction(NAME_ScriptUtil, functionname);
if (func == nullptr)
{
I_Error("Call to undefined function ScriptUtil.%s", functionname.GetChars());
}
functions.Insert(functionname, func);
}
else func = *check;
VMCall(func, &parameters[paramstart], parameters.Size() - paramstart, &returns, 1);
}
int ScriptUtil::Exec(FName functionname, ...)
{
unsigned paramstart = parameters.Size();
va_list ap;
va_start(ap, functionname);
try
{
BuildParameters(ap);
int ret = 0;
VMReturn returns(&ret);
RunFunction(functionname, paramstart, returns);
va_end(ap);
parameters.Clamp(paramstart);
return ret;
}
catch(...)
{
va_end(ap);
parameters.Clamp(paramstart);
throw;
}
}