Merge branch 'master' into portal

This commit is contained in:
Christoph Oelckers 2016-02-19 10:40:07 +01:00
commit 15040c955e
28 changed files with 944 additions and 603 deletions

View file

@ -188,6 +188,16 @@ option(FORCE_INTERNAL_JPEG "Use internal jpeg")
option(FORCE_INTERNAL_BZIP2 "Use internal bzip2")
option(FORCE_INTERNAL_GME "Use internal gme" ON)
# Fast math flags, required by some subprojects
set( ZD_FASTMATH_FLAG "" )
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( ZD_FASTMATH_FLAG "-ffast-math" )
else()
if( MSVC )
set( ZD_FASTMATH_FLAG "/fp:fast" )
endif()
endif()
if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
message( STATUS "Using system zlib" )
else()

View file

@ -14,9 +14,8 @@ if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
endif(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "4.5")
endif()
if( MSVC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fp:fast" )
endif()
# Enable fast flag for dumb
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
CHECK_FUNCTION_EXISTS( itoa ITOA_EXISTS )
if( NOT ITOA_EXISTS )

View file

@ -29,11 +29,8 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
endif()
endif()
if( MSVC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fp:fast" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:fast" )
endif()
# Enable fast flag for GME
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ZD_FASTMATH_FLAG}" )
# Default emulators to build (all of them! ;)
if (NOT DEFINED USE_GME_AY)

View file

@ -5,13 +5,16 @@ set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG" )
# Disable warnings for << operator precedence (4554) and
# unreferenced labels (4102) from VC
if( MSVC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4554 /wd4102 /fp:fast" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4554 /wd4102" )
endif()
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" )
endif()
# Enable fast flag for gdtoa
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}" )
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
add_definitions( -DINFNAN_CHECK -DMULTIPLE_THREADS )

View file

@ -35,14 +35,6 @@ if( CMAKE_SIZEOF_VOID_P MATCHES "8" )
set( X64 64 )
endif()
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set ( FASTMATH "-ffast-math" )
else()
if ( MSVC )
set ( FASTMATH "/fp:fast" )
endif()
endif()
# You can either use "make install" on the FMOD distribution to put it
# in standard system locations, or you can unpack the FMOD distribution
# in the root of the zdoom tree. e.g.:
@ -866,6 +858,7 @@ set( NOT_COMPILED_SOURCE_FILES
asm_x86_64/tmap3.s
)
# Enable fast math for some sources
set( FASTMATH_SOURCES
r_swrenderer.cpp
r_3dfloors.cpp
@ -1203,12 +1196,12 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
zzautozend.cpp
)
set_source_files_properties( ${FASTMATH_SOURCES} PROPERTIES COMPILE_FLAGS ${FASTMATH} )
set_source_files_properties( ${FASTMATH_SOURCES} PROPERTIES COMPILE_FLAGS ${ZD_FASTMATH_FLAG} )
set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" )
set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" )
set_source_files_properties( ${NOT_COMPILED_SOURCE_FILES} PROPERTIES HEADER_FILE_ONLY TRUE )
if ( WIN32 )
set_source_files_properties( win32/fb_d3d9.cpp win32/fb_d3d9_wipe.cpp PROPERTIES COMPILE_FLAGS ${FASTMATH} )
set_source_files_properties( win32/fb_d3d9.cpp win32/fb_d3d9_wipe.cpp PROPERTIES COMPILE_FLAGS ${ZD_FASTMATH_FLAG} )
endif()

View file

@ -207,7 +207,6 @@ enum EObjectFlags
OF_JustSpawned = 1 << 8, // Thinker was spawned this tic
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
OF_StateChanged = 1 << 11, // Used by A_Jump* functions to feed back to SetState()
};
template<class T> class TObjPtr;

View file

@ -73,7 +73,7 @@
#include "po_man.h"
#include "autosegs.h"
#include "v_video.h"
#include "textures.h"
#include "textures/textures.h"
#include "r_utility.h"
#include "menu/menu.h"
#include "intermission/intermission.h"

View file

@ -1222,6 +1222,38 @@ PStatePointer::PStatePointer()
{
}
//==========================================================================
//
// PStatePointer :: GetStoreOp
//
//==========================================================================
int PStatePointer::GetStoreOp() const
{
return OP_SP;
}
//==========================================================================
//
// PStatePointer :: GetLoadOp
//
//==========================================================================
int PStatePointer::GetLoadOp() const
{
return OP_LP;
}
//==========================================================================
//
// PStatePointer :: GetRegType
//
//==========================================================================
int PStatePointer::GetRegType() const
{
return REGT_POINTER;
}
/* PPointer ***************************************************************/
@ -1948,7 +1980,7 @@ size_t PFunction::PropagateMark()
{
for (unsigned i = 0; i < Variants.Size(); ++i)
{
GC::Mark(Variants[i].Proto);
//GC::Mark(Variants[i].Proto);
GC::Mark(Variants[i].Implementation);
}
return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark();
@ -1967,9 +1999,10 @@ unsigned PFunction::AddVariant(PPrototype *proto, TArray<DWORD> &argflags, VMFun
{
Variant variant;
variant.Proto = proto;
//variant.Proto = proto;
variant.ArgFlags = argflags;
variant.Implementation = impl;
impl->Proto = proto;
return Variants.Push(variant);
}

View file

@ -415,6 +415,10 @@ class PStatePointer : public PBasicType
DECLARE_CLASS(PStatePointer, PBasicType);
public:
PStatePointer();
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetRegType() const;
};
class PPointer : public PBasicType
@ -582,7 +586,7 @@ class PFunction : public PSymbol
public:
struct Variant
{
PPrototype *Proto;
//PPrototype *Proto;
VMFunction *Implementation;
TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes
};

View file

@ -52,7 +52,7 @@
#include "cmdlib.h"
#include "g_level.h"
#include "stats.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
#include "d_player.h"
extern void LoadActors ();
@ -69,14 +69,37 @@ void FState::SetAction(const char *name)
ActionFunc = FindGlobalActionFunction(name)->Variants[0].Implementation;
}
bool FState::CallAction(AActor *self, AActor *stateowner)
bool FState::CallAction(AActor *self, AActor *stateowner, FState **stateret)
{
if (ActionFunc != NULL)
{
ActionCycles.Clock();
static VMFrameStack stack;
VMValue params[3] = { self, stateowner, VMValue(this, ATAG_STATE) };
stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL);
// If the function returns a state, store it at *stateret.
// If it doesn't return a state but stateret is non-NULL, we need
// to set *stateret to NULL.
if (stateret != NULL)
{
*stateret = NULL;
if (ActionFunc->Proto == NULL ||
ActionFunc->Proto->ReturnTypes.Size() == 0 ||
ActionFunc->Proto->ReturnTypes[0] != TypeState)
{
stateret = NULL;
}
}
if (stateret == NULL)
{
stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL);
}
else
{
VMReturn ret;
ret.PointerAt((void **)stateret);
stack.Call(ActionFunc, params, countof(params), &ret, 1, NULL);
}
ActionCycles.Unclock();
return true;
}

View file

@ -128,7 +128,7 @@ struct FState
void SetAction(VMFunction *func) { ActionFunc = func; }
void ClearAction() { ActionFunc = NULL; }
void SetAction(const char *name);
bool CallAction(AActor *self, AActor *stateowner);
bool CallAction(AActor *self, AActor *stateowner, FState **stateret);
static PClassActor *StaticFindStateOwner (const FState *state);
static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info);
static FRandom pr_statetics;

View file

@ -614,21 +614,22 @@ bool AActor::SetState (FState *newstate, bool nofunction)
}
}
if (!nofunction && newstate->CallAction(this, this))
if (!nofunction)
{
// Check whether the called action function resulted in destroying the actor
if (ObjectFlags & OF_EuthanizeMe)
FState *returned_state;
if (newstate->CallAction(this, this, &returned_state))
{
return false;
}
if (ObjectFlags & OF_StateChanged)
{ // The action was an A_Jump-style function that wants to change the next state.
ObjectFlags &= ~OF_StateChanged;
FState *saved = newstate;
newstate = state;
state = saved; // we need this for comparison of sprites.
tics = 0; // make sure we loop and set the new state properly
continue;
// Check whether the called action function resulted in destroying the actor
if (ObjectFlags & OF_EuthanizeMe)
{
return false;
}
if (returned_state != NULL)
{ // The action was an A_Jump-style function that wants to change the next state.
newstate = returned_state;
tics = 0; // make sure we loop and set the new state properly
continue;
}
}
}
newstate = newstate->GetNextState();
@ -3905,16 +3906,16 @@ bool AActor::CheckNoDelay()
{
// For immediately spawned objects with the NoDelay flag set for their
// Spawn state, explicitly call the current state's function.
if (state->CallAction(this, this))
FState *newstate;
if (state->CallAction(this, this, &newstate))
{
if (ObjectFlags & OF_EuthanizeMe)
{
return false; // freed itself
}
if (ObjectFlags & OF_StateChanged)
if (newstate != NULL)
{
ObjectFlags &= ~OF_StateChanged;
return SetState(state);
return SetState(newstate);
}
}
}

View file

@ -178,9 +178,16 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio
if (!nofunction && player->mo != NULL)
{
if (state->CallAction(player->mo, player->ReadyWeapon))
FState *newstate;
if (state->CallAction(player->mo, player->ReadyWeapon, &newstate))
{
if (!psp->state)
if (newstate != NULL)
{
state = newstate;
psp->tics = 0;
continue;
}
if (psp->state == NULL)
{
break;
}

View file

@ -281,7 +281,7 @@ static void FinishThingdef()
if (func == NULL)
{
FCompileContext ctx(tcall->ActorClass);
tcall->Code = static_cast<FxTailable *>(tcall->Code->Resolve(ctx));
tcall->Code = tcall->Code->Resolve(ctx);
// Make sure resolving it didn't obliterate it.
if (tcall->Code != NULL)
@ -292,11 +292,25 @@ static void FinishThingdef()
// self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(3);
// Emit a tail call via FxVMFunctionCall
tcall->Code->Emit(&buildit, true);
// Emit code
tcall->Code->Emit(&buildit);
VMScriptFunction *sfunc = buildit.MakeFunction();
sfunc->NumArgs = NAP;
// Generate prototype for this anonymous function
TArray<PType *> args(3);
SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action);
if (tcall->Proto != NULL)
{
sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args);
}
else
{
TArray<PType *> norets(0);
sfunc->Proto = NewPrototype(norets, args);
}
func = sfunc;
if (dump != NULL)
@ -354,6 +368,7 @@ static void FinishThingdef()
dmg->Emit(&buildit);
sfunc = buildit.MakeFunction();
sfunc->NumArgs = 1;
sfunc->Proto = NULL; ///FIXME: Need a proper prototype here
// Save this function in case this damage value was reused
// (which happens quite easily with inheritance).
dmg->SetFunction(sfunc);

View file

@ -122,7 +122,8 @@ struct FStateTempCall
FStateTempCall() : ActorClass(NULL), Code(NULL), FirstState(0), NumStates(0) {}
PClassActor *ActorClass;
class FxTailable *Code;
class FxExpression *Code;
class PPrototype *Proto;
int FirstState;
int NumStates;
};
@ -189,8 +190,10 @@ AFuncDesc *FindFunction(const char * string);
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
PFunction *afd, FString statestring, FStateDefinitions *statedef);
FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag);
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&proto, bool &endswithret);
class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag);
void AddImplicitReturn(class FxSequence *code, const PPrototype *proto, FScanner &sc);
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, PClassActor *cls, DWORD funcflags);
PFunction *FindGlobalActionFunction(const char *name);
@ -354,8 +357,9 @@ int MatchString (const char *in, const char **strings);
}
#define ACTION_SET_RESULT(v) do { if (numret > 0) { assert(ret != NULL); ret->SetInt(v); numret = 1; } } while(0)
#define ACTION_OR_RESULT(v) do { if (numret > 0) { assert(ret != NULL); ret->SetInt(*(int *)ret->Location | int(v)); numret = 1; } } while(0)
#define ACTION_RETURN_STATE(state) if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0
#define ACTION_RETURN_INT(v) if (numret > 0) { assert(ret != NULL); ret->SetInt(v); return 1; } return 0
#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v)
// Checks to see what called the current action function
#define ACTION_CALL_FROM_ACTOR() (callingstate == self->state)

File diff suppressed because it is too large Load diff

View file

@ -204,6 +204,7 @@ public:
virtual bool isConstant() const;
virtual void RequestAddress();
virtual VMFunction *GetDirectFunction();
virtual ExpEmit Emit(VMFunctionBuilder *build);
@ -389,6 +390,17 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
class FxCastStateToBool : public FxExpression
{
FxExpression *basex;
public:
FxCastStateToBool(FxExpression *x);
~FxCastStateToBool();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
@ -817,43 +829,26 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxTailable
//
// An expression that can produce a tail call
//
//==========================================================================
class FxTailable : public FxExpression
{
public:
FxTailable(const FScriptPosition &pos) : FxExpression(pos) {}
virtual ExpEmit Emit(VMFunctionBuilder *build, bool tailcall) = 0;
ExpEmit Emit(VMFunctionBuilder *build);
virtual VMFunction *GetDirectFunction();
};
//==========================================================================
//
// FxVMFunctionCall
//
//==========================================================================
class FxVMFunctionCall : public FxTailable
class FxVMFunctionCall : public FxExpression
{
PFunction *Function;
FArgumentList *ArgList;
PType *ReturnType;
public:
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
~FxVMFunctionCall();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
unsigned GetArgCount() { return ArgList == NULL ? 0 : ArgList->Size(); }
VMFunction *GetVMFunction() { return Function->Variants[0].Implementation; }
VMFunction *GetDirectFunction();
unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); }
VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; }
bool IsDirectFunction();
};
//==========================================================================
@ -862,15 +857,15 @@ public:
//
//==========================================================================
class FxSequence : public FxTailable
class FxSequence : public FxExpression
{
TDeletingArray<FxTailable *> Expressions;
TDeletingArray<FxExpression *> Expressions;
public:
FxSequence(const FScriptPosition &pos) : FxTailable(pos) {}
FxSequence(const FScriptPosition &pos) : FxExpression(pos) {}
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
void Add(FxTailable *expr) { if (expr != NULL) Expressions.Push(expr); }
ExpEmit Emit(VMFunctionBuilder *build);
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); }
VMFunction *GetDirectFunction();
};
@ -880,17 +875,17 @@ public:
//
//==========================================================================
class FxIfStatement : public FxTailable
class FxIfStatement : public FxExpression
{
FxExpression *Condition;
FxTailable *WhenTrue;
FxTailable *WhenFalse;
FxExpression *WhenTrue;
FxExpression *WhenFalse;
public:
FxIfStatement(FxExpression *cond, FxTailable *true_part, FxTailable *false_part, const FScriptPosition &pos);
FxIfStatement(FxExpression *cond, FxExpression *true_part, FxExpression *false_part, const FScriptPosition &pos);
~FxIfStatement();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -899,11 +894,15 @@ public:
//
//==========================================================================
class FxReturnStatement : public FxTailable
class FxReturnStatement : public FxExpression
{
FxVMFunctionCall *Call;
public:
FxReturnStatement(const FScriptPosition &pos);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
VMFunction *GetDirectFunction();
};
//==========================================================================

View file

@ -129,6 +129,17 @@ bool FxExpression::isConstant() const
//
//==========================================================================
VMFunction *FxExpression::GetDirectFunction()
{
return NULL;
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxExpression::Resolve(FCompileContext &ctx)
{
isresolved = true;
@ -157,6 +168,11 @@ FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx)
x->ValueType = VAL_Int;
break;
case VAL_State:
x = new FxCastStateToBool(x);
x = x->Resolve(ctx);
break;
default:
ScriptPosition.Message(MSG_ERROR, "Not an integral type");
delete this;
@ -500,6 +516,67 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxCastStateToBool::FxCastStateToBool(FxExpression *x)
: FxExpression(x->ScriptPosition)
{
basex = x;
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxCastStateToBool::~FxCastStateToBool()
{
SAFE_DELETE(basex);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxCastStateToBool::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
assert(basex->ValueType == VAL_State);
assert(!basex->isConstant() && "We shouldn't be able to generate a constant state ref");
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxCastStateToBool::Emit(VMFunctionBuilder *build)
{
ExpEmit from = basex->Emit(build);
assert(from.RegType == REGT_POINTER);
from.Free(build);
ExpEmit to(build, REGT_INT);
// If from is NULL, produce 0. Otherwise, produce 1.
build->Emit(OP_LI, to.RegNum, 0);
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
return to;
}
//==========================================================================
//
//
//
//==========================================================================
FxPlusSign::FxPlusSign(FxExpression *operand)
: FxExpression(operand->ScriptPosition)
{
@ -742,7 +819,6 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (Operand)
{
Operand = Operand->ResolveAsBoolean(ctx);
}
@ -3064,28 +3140,6 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
return dest;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxTailable::Emit(VMFunctionBuilder *build)
{
return Emit(build, false);
}
//==========================================================================
//
//
//
//==========================================================================
VMFunction *FxTailable::GetDirectFunction()
{
return NULL;
}
//==========================================================================
//
// FxVMFunctionCall
@ -3093,7 +3147,7 @@ VMFunction *FxTailable::GetDirectFunction()
//==========================================================================
FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos)
: FxTailable(pos)
: FxExpression(pos)
{
Function = func;
ArgList = args;
@ -3134,19 +3188,15 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
delete this;
return NULL;
}
TArray<PType *> &rets = Function->Variants[0].Proto->ReturnTypes;
if (rets.Size() == 0)
TArray<PType *> &rets = Function->Variants[0].Implementation->Proto->ReturnTypes;
if (rets.Size() > 0)
{
ReturnType = TypeVoid;
}
else
{
ReturnType = rets[0];
// If more types are added to ParseNativeFunction(), add them here too.
if (rets[0] == TypeSInt32) ValueType = VAL_Int;
else if (rets[0] == TypeFloat64) ValueType = VAL_Float;
else if (rets[0] == TypeAngle) ValueType = VAL_Angle;
else if (rets[0] == TypeFixed) ValueType = VAL_Fixed;
else if (rets[0] == TypeState) ValueType = VAL_State;
else
{
ValueType = VAL_Int;
@ -3164,6 +3214,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
//
//==========================================================================
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
return Emit(build, false);
}
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
{
assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3);
@ -3190,17 +3245,17 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
}
}
// Get a constant register for this function
int funcaddr = build->GetConstantAddress(Function->Variants[0].Implementation, ATAG_OBJECT);
VMFunction *vmfunc = Function->Variants[0].Implementation;
int funcaddr = build->GetConstantAddress(vmfunc, ATAG_OBJECT);
// Emit the call
if (tailcall)
{ // Tail call
build->Emit(OP_TAIL_K, funcaddr, count, 0);
return ExpEmit();
}
else if (ReturnType != TypeVoid)
else if (vmfunc->Proto->ReturnTypes.Size() > 0)
{ // Call, expecting one result
assert(ReturnType != NULL);
ExpEmit reg(build, ReturnType->GetRegType());
ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType());
build->Emit(OP_CALL_K, funcaddr, count, 1);
build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum);
return reg;
@ -3212,24 +3267,6 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
}
}
//==========================================================================
//
// FxVMFunctionCall :: GetDirectFunction
//
// If the function is not passed any explicit arguments, returns the
// function. Otherwise returns NULL.
//
//==========================================================================
VMFunction *FxVMFunctionCall::GetDirectFunction()
{
if (GetArgCount() == 0)
{
return GetVMFunction();
}
return NULL;
}
//==========================================================================
//
//
@ -3330,7 +3367,7 @@ FxExpression *FxSequence::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
for (unsigned i = 0; i < Expressions.Size(); ++i)
{
if (NULL == (Expressions[i] = static_cast<FxTailable *>(Expressions[i]->Resolve(ctx))))
if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx)))
{
delete this;
return NULL;
@ -3345,11 +3382,11 @@ FxExpression *FxSequence::Resolve(FCompileContext &ctx)
//
//==========================================================================
ExpEmit FxSequence::Emit(VMFunctionBuilder *build, bool tailcall)
ExpEmit FxSequence::Emit(VMFunctionBuilder *build)
{
for (unsigned i = 0; i < Expressions.Size(); ++i)
{
ExpEmit v = Expressions[i]->Emit(build, tailcall ? i == Expressions.Size()-1 : false);
ExpEmit v = Expressions[i]->Emit(build);
// Throw away any result. We don't care about it.
v.Free(build);
}
@ -3377,9 +3414,9 @@ VMFunction *FxSequence::GetDirectFunction()
//
//==========================================================================
FxIfStatement::FxIfStatement(FxExpression *cond, FxTailable *true_part,
FxTailable *false_part, const FScriptPosition &pos)
: FxTailable(pos)
FxIfStatement::FxIfStatement(FxExpression *cond, FxExpression *true_part,
FxExpression *false_part, const FScriptPosition &pos)
: FxExpression(pos)
{
Condition = cond;
WhenTrue = true_part;
@ -3406,12 +3443,12 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
ABORT(Condition);
if (WhenTrue != NULL)
{
WhenTrue = static_cast<FxTailable *>(WhenTrue->Resolve(ctx));
WhenTrue = WhenTrue->Resolve(ctx);
ABORT(WhenTrue);
}
if (WhenFalse != NULL)
{
WhenFalse = static_cast<FxTailable *>(WhenFalse->Resolve(ctx));
WhenFalse = WhenFalse->Resolve(ctx);
ABORT(WhenFalse);
}
ValueType = VAL_Unknown;
@ -3421,7 +3458,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
ExpVal condval = static_cast<FxConstant *>(Condition)->GetValue();
bool result = condval.GetBool();
FxTailable *e = result ? WhenTrue : WhenFalse;
FxExpression *e = result ? WhenTrue : WhenFalse;
delete (result ? WhenFalse : WhenTrue);
WhenTrue = WhenFalse = NULL;
delete this;
@ -3430,11 +3467,11 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
return this;
}
ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build, bool tailcall)
ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
{
ExpEmit v;
size_t jumpspot;
FxTailable *path1, *path2;
FxExpression *path1, *path2;
int condcheck;
// This is pretty much copied from FxConditional, except we don't
@ -3464,24 +3501,18 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build, bool tailcall)
cond.Free(build);
// Evaluate first path
v = path1->Emit(build, tailcall);
v = path1->Emit(build);
v.Free(build);
if (path2 != NULL)
{
size_t path1jump = build->Emit(OP_JMP, 0);
// Evaluate second path
build->BackpatchToHere(jumpspot);
v = path2->Emit(build, tailcall);
v = path2->Emit(build);
v.Free(build);
jumpspot = path1jump;
}
build->BackpatchToHere(jumpspot);
if (tailcall)
{
// When tailcall is true, execution is not expected to get past
// this if statement, so issue a RET.
build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
}
return ExpEmit();
}
@ -3489,17 +3520,51 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build, bool tailcall)
//
//==========================================================================
FxReturnStatement::FxReturnStatement(const FScriptPosition &pos)
: FxTailable(pos)
FxReturnStatement::FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos)
: FxExpression(pos), Call(call)
{
}
ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build, bool tailcall)
FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
{
build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
CHECKRESOLVED();
if (Call != NULL)
{
Call = static_cast<FxVMFunctionCall *>(Call->Resolve(ctx));
ABORT(Call);
}
return this;
}
ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
{
// If we return nothing, use a regular RET opcode. If we return
// something, use TAIL to call the function. Our return type
// should be compatible with the called function's return type.
if (Call == NULL)
{
build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
}
else
{
Call->Emit(build, true);
}
return ExpEmit();
}
VMFunction *FxReturnStatement::GetDirectFunction()
{
// If this return statement calls a function with no arguments,
// then it can be a "direct" function. That is, the DECORATE
// definition can call that function directly without wrapping
// it inside VM code.
if (Call != NULL && Call->GetArgCount() == 0)
{
return Call->GetVMFunction();
}
return NULL;
}
//==========================================================================
//
//==========================================================================

View file

@ -375,6 +375,42 @@ static void ParseArgListDef(FScanner &sc, PClassActor *cls,
sc.MustGetToken(';');
}
//==========================================================================
//
// SetImplicitArgs
//
// Adds the parameters implied by the function flags.
//
//==========================================================================
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, PClassActor *cls, DWORD funcflags)
{
// Must be called before adding any other arguments.
assert(args == NULL || args->Size() == 0);
assert(argflags == NULL || argflags->Size() == 0);
if (funcflags & VARF_Method)
{
// implied self pointer
if (args != NULL) args->Push(NewClassPointer(cls));
if (argflags != NULL) argflags->Push(0);
}
if (funcflags & VARF_Action)
{
// implied stateowner and callingstate pointers
if (args != NULL)
{
args->Push(NewClassPointer(RUNTIME_CLASS(AActor)));
args->Push(TypeState);
}
if (argflags != NULL)
{
argflags->Push(0);
argflags->Push(0);
}
}
}
//==========================================================================
//
// ParseFunctionDef
@ -401,15 +437,7 @@ void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname,
}
sc.MustGetToken('(');
if (funcflags & VARF_Method)
{
args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer
}
if (funcflags & VARF_Action)
{
args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer
args.Push(TypeState), argflags.Push(0); // implied callingstate pointer
}
SetImplicitArgs(&args, &argflags, cls, funcflags);
ParseArgListDef(sc, cls, args, argflags);
if (afd != NULL)
@ -466,6 +494,10 @@ static void ParseNativeFunction(FScanner &sc, PClassActor *cls)
rets.Push(TypeFixed);
break;
case TK_State:
rets.Push(TypeState);
break;
case TK_Identifier:
rets.Push(NewPointer(RUNTIME_CLASS(DObject)));
// Todo: Object type
@ -1036,10 +1068,22 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
sc.MustGetToken(TK_Native);
// check for a return value
if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Bool))
do
{
rets.Push(TypeSInt32);
if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Bool))
{
rets.Push(TypeSInt32);
}
else if (sc.CheckToken(TK_State))
{
rets.Push(TypeState);
}
else if (sc.CheckToken(TK_Float))
{
rets.Push(TypeFloat64);
}
}
while (sc.CheckToken(','));
sc.MustGetToken(TK_Identifier);
funcname = sc.String;
ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action);

View file

@ -314,7 +314,12 @@ do_stop:
continue;
}
tcall->Code = ParseActions(sc, state, statestring, bag);
bool hasfinalret;
tcall->Code = ParseActions(sc, state, statestring, bag, tcall->Proto, hasfinalret);
if (!hasfinalret)
{
AddImplicitReturn(static_cast<FxSequence*>(tcall->Code), tcall->Proto, sc);
}
goto endofstate;
}
sc.UnGet();
@ -348,49 +353,162 @@ endofstate:
//==========================================================================
//
// ParseActions
// AddImplicitReturn
//
// Adds an implied return; statement to the end of a code sequence.
//
//==========================================================================
FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag)
void AddImplicitReturn(FxSequence *code, const PPrototype *proto, FScanner &sc)
{
if (proto == NULL || proto->ReturnTypes.Size() == 0)
{ // Returns nothing. Good. We can safely add an implied return.
code->Add(new FxReturnStatement(NULL, sc));
}
else
{ // Something was returned earlier in the sequence. Make it an error
// instead of adding an implicit one.
sc.ScriptError("Action list must end with a return statement");
}
}
//==========================================================================
//
// ReturnCheck
//
// If proto1 is NULL, returns proto2. If proto2 is NULL, returns proto1.
// If neither is null, checks if both prototypes define the same return
// types. If not, an error is flagged.
//
//==========================================================================
static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner &sc)
{
if (proto1 == NULL)
{
return proto2;
}
if (proto2 == NULL)
{
return proto1;
}
// A prototype that defines fewer return types can be compatible with
// one that defines more if the shorter one matches the initial types
// for the longer one.
if (proto2->ReturnTypes.Size() < proto1->ReturnTypes.Size())
{ // Make proto1 the shorter one to avoid code duplication below.
swapvalues(proto1, proto2);
}
// If one prototype returns nothing, they both must.
if (proto1->ReturnTypes.Size() == 0)
{
if (proto2->ReturnTypes.Size() == 0)
{
return proto1;
}
proto1 = NULL;
}
else
{
for (unsigned i = 0; i < proto1->ReturnTypes.Size(); ++i)
{
if (proto1->ReturnTypes[i] != proto2->ReturnTypes[i])
{ // Incompatible
proto1 = NULL;
break;
}
}
}
if (proto1 == NULL)
{
sc.ScriptError("Return types are incompatible");
}
return proto1;
}
//==========================================================================
//
// ParseActions
//
// If this action block contains any return statements, the prototype for
// one of them will be returned. This is used for deducing the return type
// of anonymous functions. All called functions passed to return must have
// matching return types.
//
//==========================================================================
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
PPrototype *&retproto, bool &endswithret)
{
// If it's not a '{', then it should be a single action.
// Otherwise, it's a sequence of actions.
if (!sc.Compare("{"))
{
return ParseAction(sc, state, statestring, bag);
FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag);
retproto = call->GetVMFunction()->Proto;
endswithret = true;
return new FxReturnStatement(call, sc);
}
const FScriptPosition pos(sc);
FxSequence *seq = NULL;
PPrototype *proto = NULL;
bool lastwasret = false;
sc.MustGetString();
while (!sc.Compare("}"))
{
FxTailable *add;
FxExpression *add;
lastwasret = false;
if (sc.Compare("if"))
{ // Hangle an if statement
FxExpression *cond;
FxTailable *true_part, *false_part = NULL;
FxExpression *true_part, *false_part = NULL;
PPrototype *true_proto, *false_proto = NULL;
bool true_ret, false_ret = false;
sc.MustGetStringName("(");
cond = ParseExpression(sc, bag.Info);
sc.MustGetStringName(")");
sc.MustGetStringName("{"); // braces are mandatory
true_part = ParseActions(sc, state, statestring, bag);
true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret);
sc.MustGetString();
if (sc.Compare("else"))
{
sc.MustGetStringName("{"); // braces are still mandatory
false_part = ParseActions(sc, state, statestring, bag);
false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret);
sc.MustGetString();
}
add = new FxIfStatement(cond, true_part, false_part, sc);
proto = ReturnCheck(proto, true_proto, sc);
proto = ReturnCheck(proto, false_proto, sc);
// If one side does not end with a return, we don't consider the if statement
// to end with a return.
if (true_ret && (false_proto == NULL || false_ret))
{
lastwasret = true;
}
}
else if (sc.Compare("return"))
{ // Handle a return statement
sc.MustGetStringName(";");
lastwasret = true;
FxVMFunctionCall *retexp = NULL;
PPrototype *retproto;
sc.MustGetString();
add = new FxReturnStatement(sc);
if (!sc.Compare(";"))
{
retexp = ParseAction(sc, state, statestring, bag);
sc.MustGetStringName(";");
retproto = retexp->GetVMFunction()->Proto;
}
else
{ // Returning nothing; we still need a prototype for that.
TArray<PType *> notypes(0);
retproto = NewPrototype(notypes, notypes);
}
proto = ReturnCheck(proto, retproto, sc);
sc.MustGetString();
add = new FxReturnStatement(retexp, sc);
}
else
{ // Handle a regular action function call
@ -408,6 +526,8 @@ FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggag
seq->Add(add);
}
}
endswithret = lastwasret;
retproto = proto;
return seq;
}
@ -460,7 +580,7 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
PFunction *afd, FString statestring, FStateDefinitions *statedef)
{
const TArray<PType *> &params = afd->Variants[0].Proto->ArgumentTypes;
const TArray<PType *> &params = afd->Variants[0].Implementation->Proto->ArgumentTypes;
const TArray<DWORD> &paramflags = afd->Variants[0].ArgFlags;
int numparams = (int)params.Size();
int pnum = 0;

View file

@ -158,12 +158,15 @@ enum
class VMFunction : public DObject
{
DECLARE_ABSTRACT_CLASS(VMFunction, DObject);
HAS_OBJECT_POINTERS;
public:
bool Native;
FName Name;
VMFunction() : Native(false), Name(NAME_None) {}
VMFunction(FName name) : Native(false), Name(name) {}
class PPrototype *Proto;
VMFunction() : Native(false), Name(NAME_None), Proto(NULL) {}
VMFunction(FName name) : Native(false), Name(name), Proto(NULL) {}
};
enum EVMOpMode

View file

@ -551,7 +551,7 @@ begin:
}
stack->PopFrame();
}
assert(numret == C);
assert(numret == C && "Number of parameters returned differs from what was expected by the caller");
for (b = B; b != 0; --b)
{
reg.param[--f->NumParam].~VMValue();

View file

@ -2,7 +2,9 @@
#include "vm.h"
IMPLEMENT_CLASS(VMException)
IMPLEMENT_ABSTRACT_CLASS(VMFunction)
IMPLEMENT_ABSTRACT_POINTY_CLASS(VMFunction)
DECLARE_POINTER(Proto)
END_POINTERS
IMPLEMENT_CLASS(VMScriptFunction)
IMPLEMENT_CLASS(VMNativeFunction)

View file

@ -43,10 +43,14 @@ ACTOR Actor native //: Thinker
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT);
native state A_State(state returnme);
native int A_Int(int returnme);
native bool A_Bool(bool returnme);
// Action functions
// Meh, MBF redundant functions. Only for DeHackEd support.
action native A_Turn(float angle = 0);
action native A_LineEffect(int boomspecial = 0, int tag = 0);
action native bool A_LineEffect(int boomspecial = 0, int tag = 0);
// End of MBF redundant functions.
action native A_MonsterRail();
@ -108,7 +112,7 @@ ACTOR Actor native //: Thinker
action native A_Die(name damagetype = "none");
action native A_Detonate();
action native A_Mushroom(class<Actor> spawntype = "FatShot", int numspawns = 0, int flags = 0, float vrange = 4.0, float hrange = 0.5);
action native A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0);
action native bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0);
action native A_SetFloorClip();
action native A_UnSetFloorClip();
@ -181,22 +185,22 @@ ACTOR Actor native //: Thinker
action native A_PlaySoundEx(sound whattoplay, coerce name slot, bool looping = false, int attenuation = 0);
action native A_StopSoundEx(coerce name slot);
action native A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10);
action native A_Jump(int chance = 256, state label, ...);
action native state A_Jump(int chance = 256, state label, ...);
action native A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET);
action native A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET);
action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270);
action native A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT);
action native A_JumpIfCloser(float distance, state label, bool noz = false);
action native A_JumpIfTracerCloser(float distance, state label, bool noz = false);
action native A_JumpIfMasterCloser(float distance, state label, bool noz = false);
action native A_JumpIfTargetOutsideMeleeRange(state label);
action native A_JumpIfTargetInsideMeleeRange(state label);
action native A_JumpIfInventory(class<Inventory> itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT);
action native A_JumpIfArmorType(name Type, state label, int amount = 1);
action native A_GiveInventory(class<Inventory> itemtype, int amount = 0, int giveto = AAPTR_DEFAULT);
action native A_TakeInventory(class<Inventory> itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT);
action native A_SpawnItem(class<Actor> itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false);
action native A_SpawnItemEx(class<Actor> itemtype, float xofs = 0, float yofs = 0, float zofs = 0, float xvel = 0, float yvel = 0, float zvel = 0, float angle = 0, int flags = 0, int failchance = 0, int tid=0);
action native state A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT);
action native state A_JumpIfCloser(float distance, state label, bool noz = false);
action native state A_JumpIfTracerCloser(float distance, state label, bool noz = false);
action native state A_JumpIfMasterCloser(float distance, state label, bool noz = false);
action native state A_JumpIfTargetOutsideMeleeRange(state label);
action native state A_JumpIfTargetInsideMeleeRange(state label);
action native state A_JumpIfInventory(class<Inventory> itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT);
action native state A_JumpIfArmorType(name Type, state label, int amount = 1);
action native bool A_GiveInventory(class<Inventory> itemtype, int amount = 0, int giveto = AAPTR_DEFAULT);
action native bool A_TakeInventory(class<Inventory> itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT);
action native bool A_SpawnItem(class<Actor> itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false);
action native bool A_SpawnItemEx(class<Actor> itemtype, float xofs = 0, float yofs = 0, float zofs = 0, float xvel = 0, float yvel = 0, float zvel = 0, float angle = 0, int flags = 0, int failchance = 0, int tid=0);
action native A_Print(string whattoprint, float time = 0, name fontname = "");
action native A_PrintBold(string whattoprint, float time = 0, name fontname = "");
action native A_Log(string whattoprint);
@ -209,31 +213,31 @@ ACTOR Actor native //: Thinker
action native A_SetMass(int mass);
action native A_SpawnDebris(class<Actor> spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1);
action native A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, int size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1);
action native A_CheckSight(state label);
action native state A_CheckSight(state label);
action native A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false);
action native A_DropInventory(class<Inventory> itemtype);
action native A_SetBlend(color color1, float alpha, int tics, color color2 = "");
action native A_ChangeFlag(string flagname, bool value);
action native A_CheckFlag(string flagname, state label, int check_pointer = AAPTR_DEFAULT);
action native A_JumpIf(bool expression, state label);
action native state A_CheckFlag(string flagname, state label, int check_pointer = AAPTR_DEFAULT);
action native state A_JumpIf(bool expression, state label);
action native A_RaiseMaster(bool copy = 0);
action native A_RaiseChildren(bool copy = 0);
action native A_RaiseSiblings(bool copy = 0);
action native A_CheckFloor(state label);
action native A_CheckCeiling(state label);
action native A_PlayerSkinCheck(state label);
action native state A_CheckFloor(state label);
action native state A_CheckCeiling(state label);
action native state A_PlayerSkinCheck(state label);
action native A_BasicAttack(int meleedamage, sound meleesound, class<actor> missiletype, float missileheight);
action native A_Teleport(state teleportstate = "", class<SpecialSpot> targettype = "BossSpot", class<Actor> fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0, int ptr = AAPTR_DEFAULT);
action native A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = "", float heightoffset = 0, float radiusoffset = 0, float pitch = 0);
action native A_ThrowGrenade(class<Actor> itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true);
action native state, bool A_Teleport(state teleportstate = "", class<SpecialSpot> targettype = "BossSpot", class<Actor> fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0, int ptr = AAPTR_DEFAULT);
action native state, bool A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = "", float heightoffset = 0, float radiusoffset = 0, float pitch = 0);
action native bool A_ThrowGrenade(class<Actor> itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true);
action native A_Weave(int xspeed, int yspeed, float xdist, float ydist);
action native A_Recoil(float xyvel);
action native A_JumpIfInTargetInventory(class<Inventory> itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT);
action native A_GiveToTarget(class<Inventory> itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT);
action native A_TakeFromTarget(class<Inventory> itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT);
action native A_RadiusGive(class<Inventory> itemtype, float distance, int flags, int amount = 0, class<Actor> filter = "None", name species = "None", int mindist = 0);
action native A_CheckSpecies(state jump, name species = "", int ptr = AAPTR_DEFAULT);
action native state A_JumpIfInTargetInventory(class<Inventory> itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT);
action native bool A_GiveToTarget(class<Inventory> itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT);
action native bool A_TakeFromTarget(class<Inventory> itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT);
action native int A_RadiusGive(class<Inventory> itemtype, float distance, int flags, int amount = 0, class<Actor> filter = "None", name species = "None", int mindist = 0);
action native state A_CheckSpecies(state jump, name species = "", int ptr = AAPTR_DEFAULT);
action native A_CountdownArg(int argnum, state targstate = "");
action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true);
action native A_CustomComboAttack(class<Actor> missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true);
@ -249,10 +253,10 @@ ACTOR Actor native //: Thinker
action native A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, state label = "");
action native A_ClearLastHeard();
action native A_ClearTarget();
action native A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT);
action native A_JumpIfTargetInLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0);
action native A_JumpIfInTargetLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0);
action native A_SelectWeapon(class<Weapon> whichweapon);
action native state A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT);
action native state A_JumpIfTargetInLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0);
action native state A_JumpIfInTargetLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0);
action native bool A_SelectWeapon(class<Weapon> whichweapon);
action native A_Punch();
action native A_Feathers();
action native A_ClassBossHealth();
@ -264,7 +268,7 @@ ACTOR Actor native //: Thinker
action native A_RemoveForcefield();
action native A_DropWeaponPieces(class<Actor> p1, class<Actor> p2, class<Actor> p3);
action native A_PigPain ();
action native A_MonsterRefire(int chance, state label);
action native state A_MonsterRefire(int chance, state label);
action native A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
action native A_SetPitch(float pitch, int flags = 0, int ptr = AAPTR_DEFAULT);
action native A_SetRoll(float/*angle*/ roll, int flags = 0, int ptr = AAPTR_DEFAULT);
@ -299,39 +303,39 @@ ACTOR Actor native //: Thinker
action native A_RemoveChildren(bool removeall = false, int flags = 0, class<Actor> filter = "None", name species = "None");
action native A_RemoveSiblings(bool removeall = false, int flags = 0, class<Actor> filter = "None", name species = "None");
action native A_Remove(int removee, int flags = 0, class<Actor> filter = "None", name species = "None");
action native A_GiveToChildren(class<Inventory> itemtype, int amount = 0);
action native A_GiveToSiblings(class<Inventory> itemtype, int amount = 0);
action native A_TakeFromChildren(class<Inventory> itemtype, int amount = 0);
action native A_TakeFromSiblings(class<Inventory> itemtype, int amount = 0);
action native int A_GiveToChildren(class<Inventory> itemtype, int amount = 0);
action native int A_GiveToSiblings(class<Inventory> itemtype, int amount = 0);
action native int A_TakeFromChildren(class<Inventory> itemtype, int amount = 0);
action native int A_TakeFromSiblings(class<Inventory> itemtype, int amount = 0);
action native A_SetTeleFog(class<Actor> oldpos, class<Actor> newpos);
action native A_SwapTeleFog();
action native A_SetFloatBobPhase(int bob);
action native A_SetHealth(int health, int ptr = AAPTR_DEFAULT);
action native A_ResetHealth(int ptr = AAPTR_DEFAULT);
action native A_JumpIfHigherOrLower(state high, state low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET);
action native state A_JumpIfHigherOrLower(state high, state low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET);
action native A_SetSpecies(name species, int ptr = AAPTR_DEFAULT);
action native A_SetRipperLevel(int level);
action native A_SetRipMin(int min);
action native A_SetRipMax(int max);
action native A_SetChaseThreshold(int threshold, bool def = false, int ptr = AAPTR_DEFAULT);
action native A_CheckProximity(state jump, class<Actor> classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT);
action native A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT);
action native A_CheckSightOrRange(float distance, state label, bool two_dimension = false);
action native A_CheckRange(float distance, state label, bool two_dimension = false);
action native A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
action native state A_CheckProximity(state jump, class<Actor> classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT);
action native state A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT);
action native state A_CheckSightOrRange(float distance, state label, bool two_dimension = false);
action native state A_CheckRange(float distance, state label, bool two_dimension = false);
action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
action native A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
action native A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);
action native A_CopyFriendliness(int ptr_source = AAPTR_MASTER);
action native ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0);
action native ACS_NamedSuspend(name script, int mapnum=0);
action native ACS_NamedTerminate(name script, int mapnum=0);
action native ACS_NamedLockedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0);
action native ACS_NamedLockedExecuteDoor(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0);
action native ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0);
action native int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0);
action native int ACS_NamedSuspend(name script, int mapnum=0);
action native int ACS_NamedTerminate(name script, int mapnum=0);
action native int ACS_NamedLockedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0);
action native int ACS_NamedLockedExecuteDoor(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0);
action native int ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0);
action native ACS_NamedExecuteAlways(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0);
States
{
Spawn:

View file

@ -34,7 +34,7 @@ ACTOR Fatso
FATT H 10 BRIGHT A_FatAttack2
FATT IG 5 A_FaceTarget
FATT H 10 BRIGHT A_FatAttack3
FATT IG 5
FATT IG 5 A_FaceTarget
Goto See
Pain:
FATT J 3

View file

@ -29,8 +29,8 @@ ACTOR PainElemental
Missile:
PAIN D 5 A_FaceTarget
PAIN E 5 A_FaceTarget
PAIN F 4 BRIGHT A_FaceTarget
PAIN F 1 BRIGHT A_PainAttack
PAIN F 5 BRIGHT A_FaceTarget
PAIN F 0 BRIGHT A_PainAttack
Goto See
Pain:
PAIN G 6

View file

@ -31,7 +31,7 @@ ACTOR Revenant
SKEL AABBCCDDEEFF 2 A_Chase
Loop
Melee:
SKEL G 1 A_FaceTarget
SKEL G 0 A_FaceTarget
SKEL G 6 A_SkelWhoosh
SKEL H 6 A_FaceTarget
SKEL I 6 A_SkelFist

View file

@ -7,7 +7,7 @@ ACTOR Inventory native
Inventory.PickupSound "misc/i_pkup"
Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG"
action native A_JumpIfNoAmmo(state label);
action native state A_JumpIfNoAmmo(state label);
action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class<Actor> pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class<BasicArmorBonus> armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = "");
action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0);
action native A_FireCustomMissile(class<Actor> missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0);
@ -42,7 +42,7 @@ ACTOR Inventory native
action native A_CheckReload();
action native A_GunFlash(state flash = "", int flags = 0);
action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class<Actor> pufftype = "BulletPuff", int flags = 0, float range = 0, float/*angle*/ spread_xy = 2.8125, float/*angle*/ spread_z = 0, float lifesteal = 0, int lifestealmax = 0, class<BasicArmorBonus> armorbonustype = "ArmorBonus");
action native A_CheckForReload(int counter, state label, bool dontincrement = false);
action native state A_CheckForReload(int counter, state label, bool dontincrement = false);
action native A_ResetReloadCounter();
action native A_RestoreSpecialPosition();
action native A_RestoreSpecialDoomThing();