mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 23:01:50 +00:00
- started with a ScriptUtil class which will allow moving function implementations for ACS and FraggleScript to zscript.txt
So far 3 functions for testing implemented.
This commit is contained in:
parent
ac77ca6474
commit
6fc63b9b78
10 changed files with 280 additions and 130 deletions
|
@ -998,6 +998,7 @@ set (PCH_SOURCES
|
|||
s_sound.cpp
|
||||
serializer.cpp
|
||||
sc_man.cpp
|
||||
scriptutil.cpp
|
||||
st_stuff.cpp
|
||||
statistics.cpp
|
||||
stats.cpp
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "r_utility.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "actorinlines.h"
|
||||
#include "scriptutil.h"
|
||||
|
||||
static FRandom pr_script("FScript");
|
||||
|
||||
|
@ -283,6 +284,17 @@ static int T_GetPlayerNum(const svalue_t &arg)
|
|||
return playernum;
|
||||
}
|
||||
|
||||
APlayerPawn *T_GetPlayerActor(const svalue_t &arg)
|
||||
{
|
||||
int num = T_GetPlayerNum(arg);
|
||||
return num == -1 ? nullptr : players[num].mo;
|
||||
}
|
||||
|
||||
PClassActor *T_ClassType(const svalue_t &arg)
|
||||
{
|
||||
return PClass::FindActor(stringvalue(arg));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds a sector from a tag. This has been extended to allow looking for
|
||||
|
@ -2834,34 +2846,8 @@ void FParser::SF_SetWeapon()
|
|||
{
|
||||
if (CheckArgs(2))
|
||||
{
|
||||
int playernum=T_GetPlayerNum(t_argv[0]);
|
||||
if (playernum!=-1)
|
||||
{
|
||||
AInventory *item = players[playernum].mo->FindInventory (PClass::FindActor (stringvalue(t_argv[1])));
|
||||
|
||||
if (item == NULL || !item->IsKindOf(NAME_Weapon))
|
||||
{
|
||||
}
|
||||
else if (players[playernum].ReadyWeapon == item)
|
||||
{
|
||||
// The weapon is already selected, so setweapon succeeds by default,
|
||||
// but make sure the player isn't switching away from it.
|
||||
players[playernum].PendingWeapon = WP_NOCHANGE;
|
||||
t_return.value.i = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto weap = static_cast<AWeapon *> (item);
|
||||
|
||||
if (weap->CheckAmmo (AWeapon::EitherFire, false))
|
||||
{
|
||||
// There's enough ammo, so switch to it.
|
||||
t_return.value.i = 1;
|
||||
players[playernum].PendingWeapon = weap;
|
||||
}
|
||||
}
|
||||
}
|
||||
t_return.value.i = 0;
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = ScriptUtil::Exec(NAME_SetWeapon, ScriptUtil::Pointer, T_GetPlayerActor(t_argv[0]), ScriptUtil::Class, T_ClassType(t_argv[1]), ScriptUtil::End);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -983,3 +983,8 @@ xx(snd_output)
|
|||
xx(snd_output_format)
|
||||
xx(snd_speakermode)
|
||||
xx(snd_resampler)
|
||||
|
||||
// ScriptUtil entry points
|
||||
xx(ScriptUtil)
|
||||
xx(SetMarineWeapon)
|
||||
xx(SetMarineSprite)
|
||||
|
|
106
src/p_acs.cpp
106
src/p_acs.cpp
|
@ -74,6 +74,7 @@
|
|||
#include "g_levellocals.h"
|
||||
#include "actorinlines.h"
|
||||
#include "types.h"
|
||||
#include "scriptutil.h"
|
||||
|
||||
// P-codes for ACS scripts
|
||||
enum
|
||||
|
@ -6963,28 +6964,6 @@ static bool CharArrayParms(int &capacity, int &offset, int &a, FACSStackMemory&
|
|||
return true;
|
||||
}
|
||||
|
||||
static void SetMarineWeapon(AActor *marine, int weapon)
|
||||
{
|
||||
static VMFunction *smw = nullptr;
|
||||
if (smw == nullptr) PClass::FindFunction(&smw, NAME_ScriptedMarine, NAME_SetWeapon);
|
||||
if (smw)
|
||||
{
|
||||
VMValue params[2] = { marine, weapon };
|
||||
VMCall(smw, params, 2, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetMarineSprite(AActor *marine, PClassActor *source)
|
||||
{
|
||||
static VMFunction *sms = nullptr;
|
||||
if (sms == nullptr) PClass::FindFunction(&sms, NAME_ScriptedMarine, NAME_SetSprite);
|
||||
if (sms)
|
||||
{
|
||||
VMValue params[2] = { marine, source };
|
||||
VMCall(sms, params, 2, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int DLevelScript::RunScript ()
|
||||
{
|
||||
DACSThinker *controller = DACSThinker::ActiveThinker;
|
||||
|
@ -9832,93 +9811,16 @@ scriptwait:
|
|||
break;
|
||||
|
||||
case PCD_SETWEAPON:
|
||||
if (activator == NULL || activator->player == NULL)
|
||||
{
|
||||
STACK(1) = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
AInventory *item = activator->FindInventory (PClass::FindActor (FBehavior::StaticLookupString (STACK(1))));
|
||||
|
||||
if (item == NULL || !item->IsKindOf(NAME_Weapon))
|
||||
{
|
||||
STACK(1) = 0;
|
||||
}
|
||||
else if (activator->player->ReadyWeapon == item)
|
||||
{
|
||||
// The weapon is already selected, so setweapon succeeds by default,
|
||||
// but make sure the player isn't switching away from it.
|
||||
activator->player->PendingWeapon = WP_NOCHANGE;
|
||||
STACK(1) = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
AWeapon *weap = static_cast<AWeapon *> (item);
|
||||
|
||||
if (weap->CheckAmmo (AWeapon::EitherFire, false))
|
||||
{
|
||||
// There's enough ammo, so switch to it.
|
||||
STACK(1) = 1;
|
||||
activator->player->PendingWeapon = weap;
|
||||
}
|
||||
else
|
||||
{
|
||||
STACK(1) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
STACK(1) = ScriptUtil::Exec(NAME_SetWeapon, ScriptUtil::Pointer, activator, ScriptUtil::ACSClass, STACK(1), ScriptUtil::End);
|
||||
break;
|
||||
|
||||
case PCD_SETMARINEWEAPON:
|
||||
if (STACK(2) != 0)
|
||||
{
|
||||
AActor *marine;
|
||||
NActorIterator iterator(NAME_ScriptedMarine, STACK(2));
|
||||
|
||||
while ((marine = iterator.Next()) != NULL)
|
||||
{
|
||||
SetMarineWeapon(marine, STACK(1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (activator != nullptr && activator->IsKindOf (NAME_ScriptedMarine))
|
||||
{
|
||||
SetMarineWeapon(activator, STACK(1));
|
||||
}
|
||||
}
|
||||
ScriptUtil::Exec(NAME_SetMarineWeapon, ScriptUtil::Pointer, activator, ScriptUtil::Int, STACK(2), ScriptUtil::Int, STACK(1), ScriptUtil::End);
|
||||
sp -= 2;
|
||||
break;
|
||||
|
||||
case PCD_SETMARINESPRITE:
|
||||
{
|
||||
PClassActor *type = PClass::FindActor(FBehavior::StaticLookupString (STACK(1)));
|
||||
|
||||
if (type != NULL)
|
||||
{
|
||||
if (STACK(2) != 0)
|
||||
{
|
||||
AActor *marine;
|
||||
NActorIterator iterator(NAME_ScriptedMarine, STACK(2));
|
||||
|
||||
while ((marine = iterator.Next()) != NULL)
|
||||
{
|
||||
SetMarineSprite(marine, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (activator != nullptr && activator->IsKindOf(NAME_ScriptedMarine))
|
||||
{
|
||||
SetMarineSprite(activator, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown actor type: %s\n", FBehavior::StaticLookupString (STACK(1)));
|
||||
}
|
||||
}
|
||||
ScriptUtil::Exec(NAME_SetMarineSprite, ScriptUtil::Pointer, activator, ScriptUtil::Int, STACK(2), ScriptUtil::ACSClass, STACK(1), ScriptUtil::End);
|
||||
sp -= 2;
|
||||
break;
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
class FFont;
|
||||
class FileReader;
|
||||
struct line_t;
|
||||
class FSerializer;
|
||||
|
||||
|
||||
enum
|
||||
|
|
|
@ -675,6 +675,23 @@ VMFunction *FindVMFunction(PClass *cls, const char *name);
|
|||
|
||||
FString FStringFormat(VM_ARGS, int offset = 0);
|
||||
|
||||
#define IFVM(cls, funcname) \
|
||||
static VMFunction * func = nullptr; \
|
||||
if (func == nullptr) { \
|
||||
func = dyn_cast<PFunction>(RUNTIME_CLASS(cls)->FindSymbol(#funcname, false)); \
|
||||
assert(func); \
|
||||
} \
|
||||
if (func != nullptr)
|
||||
|
||||
#define IFVMNAME(cls, funcname) \
|
||||
static VMFunction * func = nullptr; \
|
||||
if (func == nullptr) { \
|
||||
func = dyn_cast<PFunction>(PClass::FindClass(cls)->FindSymbol(#funcname, false)); \
|
||||
assert(func); \
|
||||
} \
|
||||
if (func != nullptr)
|
||||
|
||||
|
||||
|
||||
unsigned GetVirtualIndex(PClass *cls, const char *funcname);
|
||||
|
||||
|
|
104
src/scriptutil.cpp
Normal file
104
src/scriptutil.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// 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"
|
||||
|
||||
|
||||
static TArray<VMValue> parameters;
|
||||
static TMap<FName, VMFunction*> functions;
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
PClass::FindFunction(&func, 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, ¶meters[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;
|
||||
}
|
||||
}
|
27
src/scriptutil.h
Normal file
27
src/scriptutil.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "name.h"
|
||||
|
||||
|
||||
class ScriptUtil
|
||||
{
|
||||
static void BuildParameters(va_list ap);
|
||||
static void RunFunction(FName function, unsigned paramstart, VMReturn &returns);
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
End,
|
||||
Int,
|
||||
Pointer,
|
||||
Float,
|
||||
String,
|
||||
Class,
|
||||
ACSString, // convenience helpers taking an ACS string index instead of a string
|
||||
ACSClass,
|
||||
};
|
||||
|
||||
static int Exec(FName functionname, ...);
|
||||
};
|
|
@ -260,3 +260,5 @@ version "3.7"
|
|||
#include "zscript/chex/chexitems.txt"
|
||||
#include "zscript/chex/chexdecorations.txt"
|
||||
#include "zscript/chex/chexplayer.txt"
|
||||
|
||||
#include "zscript/scriptutil/scriptutil.txt"
|
||||
|
|
105
wadsrc/static/zscript/scriptutil/scriptutil.txt
Normal file
105
wadsrc/static/zscript/scriptutil/scriptutil.txt
Normal file
|
@ -0,0 +1,105 @@
|
|||
|
||||
// Container for utility functions used by ACS and FraggleScript.
|
||||
|
||||
class ScriptUtil play
|
||||
{
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int SetWeapon(Actor activator, class<Inventory> cls)
|
||||
{
|
||||
if(activator != NULL && activator.player != NULL && cls != null)
|
||||
{
|
||||
let item = Weapon(activator.FindInventory(cls));
|
||||
|
||||
if(item != NULL)
|
||||
{
|
||||
if(activator.player.ReadyWeapon == item)
|
||||
{
|
||||
// The weapon is already selected, so setweapon succeeds by default,
|
||||
// but make sure the player isn't switching away from it.
|
||||
activator.player.PendingWeapon = WP_NOCHANGE;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(item.CheckAmmo(Weapon.EitherFire, false))
|
||||
{
|
||||
// There's enough ammo, so switch to it.
|
||||
activator.player.PendingWeapon = item;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void SetMarineWeapon(Actor activator, int tid, int marineweapontype)
|
||||
{
|
||||
if (tid != 0)
|
||||
{
|
||||
let it = ActorIterator.Create(tid, 'ScriptedMarine');
|
||||
ScriptedMarine marine;
|
||||
|
||||
while ((marine = ScriptedMarine(it.Next())) != NULL)
|
||||
{
|
||||
marine.SetWeapon(marineweapontype);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
let marine = ScriptedMarine(activator);
|
||||
if (marine != null)
|
||||
{
|
||||
marine.SetWeapon(marineweapontype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void SetMarineSprite(Actor activator, int tid, class<Actor> type)
|
||||
{
|
||||
if (type != NULL)
|
||||
{
|
||||
if (tid != 0)
|
||||
{
|
||||
let it = ActorIterator.Create(tid, 'ScriptedMarine');
|
||||
ScriptedMarine marine;
|
||||
|
||||
while ((marine = ScriptedMarine(it.Next())) != NULL)
|
||||
{
|
||||
marine.SetSprite(type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
let marine = ScriptedMarine(activator);
|
||||
if (marine != null)
|
||||
{
|
||||
marine.SetSprite(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Printf ("Unknown actor type: %s\n", type.GetClassName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue