From 0f70d10521d766a0ee4f109bc43793304e9414d7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 12 Feb 2016 17:21:57 -0600 Subject: [PATCH 01/17] Add 'float' and 'state' as possible return types for action functions --- src/thingdef/thingdef_expression.cpp | 1 + src/thingdef/thingdef_parse.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 987a9806e..0d6e009fd 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3147,6 +3147,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) 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; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 93a139850..255e2adaf 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -1040,6 +1040,14 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls) { rets.Push(TypeSInt32); } + else if (sc.CheckToken(TK_State)) + { + rets.Push(TypeState); + } + else if (sc.CheckToken(TK_Float)) + { + rets.Push(TypeFloat64); + } sc.MustGetToken(TK_Identifier); funcname = sc.String; ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action); From 42c6245a509cd25f2c56742dbd8c2c26656148da Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 17 Feb 2016 11:42:45 +0100 Subject: [PATCH 02/17] - restored A_CountdownArg to what it looked like before the scripting branch. The new version did not work as expected anymore. --- src/thingdef/thingdef_codeptr.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 4b9bb77de..fa2a336d4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3269,35 +3269,29 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) // A_CountdownArg // //=========================================================================== + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) { PARAM_ACTION_PROLOGUE; - PARAM_INT(argnum); - PARAM_STATE_OPT(state) { state = self->FindState(NAME_Death); } + PARAM_INT(cnt); + PARAM_STATE_OPT(state) { state = self->FindState(NAME_Death); } - if (argnum >= 0 && argnum < (int)countof(self->args)) + if (cnt<0 || cnt >= 5) return; + if (!self->args[cnt]--) { - if (!self->args[argnum]--) + if (self->flags&MF_MISSILE) { - if (self->flags & MF_MISSILE) - { - P_ExplodeMissile(self, NULL, NULL); - } - else if (self->flags & MF_SHOOTABLE) - { - P_DamageMobj(self, NULL, NULL, self->health, NAME_None, DMG_FORCED); - } - else - { - self->SetState(self->FindState(NAME_Death)); - } + P_ExplodeMissile(self, NULL, NULL); + } + else if (self->flags&MF_SHOOTABLE) + { + P_DamageMobj(self, NULL, NULL, self->health, NAME_None, DMG_FORCED); } else { self->SetState(state); } } - return 0; } //============================================================================ From f2125ea4206529095a5ee6e3c8650dd3fddaf3ed Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 17 Feb 2016 12:36:56 +0100 Subject: [PATCH 03/17] - this needs a return value... --- src/thingdef/thingdef_codeptr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index fa2a336d4..d9eba89ec 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3276,7 +3276,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) PARAM_INT(cnt); PARAM_STATE_OPT(state) { state = self->FindState(NAME_Death); } - if (cnt<0 || cnt >= 5) return; + if (cnt<0 || cnt >= 5) return 0; if (!self->args[cnt]--) { if (self->flags&MF_MISSILE) @@ -3292,6 +3292,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) self->SetState(state); } } + return 0; } //============================================================================ From ec88a30a004266520822d3d392fd5838e5073ede Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Wed, 17 Feb 2016 16:08:40 +0100 Subject: [PATCH 04/17] fix duration according to vanilla --- wadsrc/static/actors/doom/revenant.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/revenant.txt b/wadsrc/static/actors/doom/revenant.txt index ce072bec4..1a5045f34 100644 --- a/wadsrc/static/actors/doom/revenant.txt +++ b/wadsrc/static/actors/doom/revenant.txt @@ -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 From 4ccbc65f7b8d2ae5eca586bfe25f1db3ee2b4e13 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 17 Feb 2016 21:44:33 +0100 Subject: [PATCH 05/17] - Fixed mismatching Mancubus missile sequence. --- wadsrc/static/actors/doom/fatso.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/fatso.txt b/wadsrc/static/actors/doom/fatso.txt index 0b3039325..88eaef39b 100644 --- a/wadsrc/static/actors/doom/fatso.txt +++ b/wadsrc/static/actors/doom/fatso.txt @@ -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 From db6f534df57273fdc9d7c9fda1f22f29216cdcd3 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 17 Feb 2016 21:53:23 +0100 Subject: [PATCH 06/17] - Fixed wrong Pain Elemental missile sequence. --- wadsrc/static/actors/doom/painelemental.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/actors/doom/painelemental.txt b/wadsrc/static/actors/doom/painelemental.txt index 5951afd6b..b8ef795a8 100644 --- a/wadsrc/static/actors/doom/painelemental.txt +++ b/wadsrc/static/actors/doom/painelemental.txt @@ -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 A 0 BRIGHT A_PainAttack Goto See Pain: PAIN G 6 From f650bbfe1511e5c7151bd777ad59be4f5b68f1b9 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 18 Feb 2016 00:17:07 +0100 Subject: [PATCH 07/17] - Revert unneeded change to the frame letter. --- wadsrc/static/actors/doom/painelemental.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/doom/painelemental.txt b/wadsrc/static/actors/doom/painelemental.txt index b8ef795a8..ab0cd5cc9 100644 --- a/wadsrc/static/actors/doom/painelemental.txt +++ b/wadsrc/static/actors/doom/painelemental.txt @@ -30,7 +30,7 @@ ACTOR PainElemental PAIN D 5 A_FaceTarget PAIN E 5 A_FaceTarget PAIN F 5 BRIGHT A_FaceTarget - PAIN A 0 BRIGHT A_PainAttack + PAIN F 0 BRIGHT A_PainAttack Goto See Pain: PAIN G 6 From f338e5f1c4c48cc3e53035bc7a4b882248e68319 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 18 Feb 2016 22:09:05 +0100 Subject: [PATCH 08/17] - Apply the fast math flags for non-MSVC, too. Move the fast flags string creation in the main cmake file and use it where needed. --- CMakeLists.txt | 10 ++++++++++ dumb/CMakeLists.txt | 5 ++--- game-music-emu/CMakeLists.txt | 7 ++----- gdtoa/CMakeLists.txt | 5 ++++- src/CMakeLists.txt | 13 +++---------- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 006ebf476..22973e19a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/dumb/CMakeLists.txt b/dumb/CMakeLists.txt index c8fa34bf7..8455e6d15 100644 --- a/dumb/CMakeLists.txt +++ b/dumb/CMakeLists.txt @@ -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 ) diff --git a/game-music-emu/CMakeLists.txt b/game-music-emu/CMakeLists.txt index f1d467bcc..3251b5c02 100644 --- a/game-music-emu/CMakeLists.txt +++ b/game-music-emu/CMakeLists.txt @@ -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) diff --git a/gdtoa/CMakeLists.txt b/gdtoa/CMakeLists.txt index 94ab9a691..c16542283 100644 --- a/gdtoa/CMakeLists.txt +++ b/gdtoa/CMakeLists.txt @@ -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 ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6e617c712..21fb48eec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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() From b2ccd0bd28475793b8f16fb3324ed393bdef5e9a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 20:39:40 -0600 Subject: [PATCH 09/17] Use action function return value to make state jumps happen - The A_Jump family of action functions now return the state to jump to (NULL if no jump is to be taken) instead of jumping directly. It is the caller's responsibility to handle the jump. This will make it possible to use their results in if statements and do something other than jump. - DECORATE return statements can now return the result of a function (but not any random expression--it must be a function call). To make a jump happen from inside a multi-action block, you must return the value of an A_Jump function. e.g.: { return A_Jump(128, "SomeState"); } - The VMFunction class now contains its prototype instead of storing it at a higher level in PFunction. This is so that FState::CallAction can easily tell if a function returns a state. - Removed the FxTailable class because with explicit return statements, it's not useful anymore. --- src/dobject.h | 1 - src/dobjgc.cpp | 2 +- src/dobjtype.cpp | 37 +- src/dobjtype.h | 6 +- src/info.cpp | 29 +- src/info.h | 2 +- src/p_mobj.cpp | 35 +- src/p_pspr.cpp | 11 +- src/thingdef/thingdef.cpp | 23 +- src/thingdef/thingdef.h | 12 +- src/thingdef/thingdef_codeptr.cpp | 549 +++++++++------------- src/thingdef/thingdef_exp.h | 51 +- src/thingdef/thingdef_expression.cpp | 118 ++--- src/thingdef/thingdef_parse.cpp | 70 ++- src/thingdef/thingdef_states.cpp | 142 +++++- src/zscript/vm.h | 6 +- wadsrc/static/actors/actor.txt | 100 ++-- wadsrc/static/actors/shared/inventory.txt | 4 +- 18 files changed, 663 insertions(+), 535 deletions(-) diff --git a/src/dobject.h b/src/dobject.h index 254891eb5..48cf6353e 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -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 TObjPtr; diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index d9c977670..0094e3812 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -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" diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 2c45f483c..84f890c79 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -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 &argflags, VMFun { Variant variant; - variant.Proto = proto; + //variant.Proto = proto; variant.ArgFlags = argflags; variant.Implementation = impl; + impl->Proto = proto; return Variants.Push(variant); } diff --git a/src/dobjtype.h b/src/dobjtype.h index 9ba327658..1e982e74b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -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 ArgFlags; // Should be the same length as Proto->ArgumentTypes }; diff --git a/src/info.cpp b/src/info.cpp index 0f3da5d78..1ba21c5f7 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -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; } diff --git a/src/info.h b/src/info.h index 5d9d36879..eb828bcf0 100644 --- a/src/info.h +++ b/src/info.h @@ -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; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 82326c39b..6baea65e2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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(); @@ -3904,16 +3905,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); } } } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 7d52210ce..ec6c38f77 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -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; } diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index a85f0ea08..4cb03111b 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -277,11 +277,11 @@ static void FinishThingdef() // Can we call this function directly without wrapping it in an // anonymous function? e.g. Are we passing any parameters to it? - func = tcall->Code->GetDirectFunction(); + func = NULL;//tcall->Code->GetDirectFunction(); if (func == NULL) { FCompileContext ctx(tcall->ActorClass); - tcall->Code = static_cast(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 args(3); + SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action); + if (tcall->Proto != NULL) + { + sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args); + } + else + { + TArray 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); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index aa6a54445..a9703ffa6 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -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 &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 *args, TArray *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) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 4b9bb77de..778c758c6 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -728,49 +728,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) } -//========================================================================== -// -// Do the state jump -// -//========================================================================== -static void DoJump(AActor *self, AActor *stateowner, FState *callingstate, FState *jumpto) -{ - if (jumpto == NULL) return; - - if (stateowner->flags5 & MF5_INSTATECALL) - { - stateowner->state = jumpto; - } - else if (self->player != NULL && callingstate == self->player->psprites[ps_weapon].state) - { - P_SetPsprite(self->player, ps_weapon, jumpto); - } - else if (self->player != NULL && callingstate == self->player->psprites[ps_flash].state) - { - P_SetPsprite(self->player, ps_flash, jumpto); - } - else if (callingstate == self->state || (self->ObjectFlags & OF_StateChanged)) - { - // Rather than using self->SetState(jumpto) to set the state, - // set the state directly. Since this function is only called by - // action functions, which are only called by SetState(), we - // know that somewhere above us in the stack, a SetState() - // call is waiting for us to return. We use the flag OF_StateChanged - // to cause it to bypass the normal next state mechanism and use - // the one we set here instead. - self->state = jumpto; - self->ObjectFlags |= OF_StateChanged; - } - else - { // something went very wrong. This should never happen. - assert(false); - } -} - -// This is just to avoid having to directly reference the internally defined -// CallingState and statecall parameters in the code below. -#define ACTION_JUMP(offset) DoJump(self, stateowner, callingstate, offset) - //========================================================================== // // State jump function @@ -787,10 +744,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) { int jumpnum = (count == 1 ? 0 : (pr_cajump() % count)); PARAM_STATE_AT(paramnum + jumpnum, jumpto); - ACTION_JUMP(jumpto); + ACTION_RETURN_STATE(jumpto); } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - return numret; + ACTION_RETURN_STATE(NULL); } //========================================================================== @@ -811,10 +767,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) if (measured != NULL && measured->health < health) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - return numret; + ACTION_RETURN_STATE(NULL); } //========================================================================== @@ -829,10 +784,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetOutsideMeleeRange) if (!self->CheckMeleeRange()) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - return numret; + ACTION_RETURN_STATE(NULL); } //========================================================================== @@ -847,10 +801,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInsideMeleeRange) if (self->CheckMeleeRange()) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - return numret; + ACTION_RETURN_STATE(NULL); } //========================================================================== @@ -865,19 +818,18 @@ static int DoJumpIfCloser(AActor *target, VM_ARGS) PARAM_STATE (jump); PARAM_BOOL_OPT(noz) { noz = false; } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - - // No target - no jump if (!target) - return numret; + { // No target - no jump + ACTION_RETURN_STATE(NULL); + } if (self->AproxDistance(target) < dist && (noz || ((self->Z() > target->Z() && self->Z() - target->Top() < dist) || (self->Z() <= target->Z() && target->Z() - self->Top() < dist)))) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) @@ -923,16 +875,14 @@ int DoJumpIfInventory(AActor *owner, AActor *self, AActor *stateowner, FState *c PARAM_STATE (label); PARAM_INT_OPT (setowner) { setowner = AAPTR_DEFAULT; } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (itemtype == NULL) { - return numret; + ACTION_RETURN_STATE(NULL); } owner = COPY_AAPTR(owner, setowner); if (owner == NULL) { - return numret; + ACTION_RETURN_STATE(NULL); } AInventory *item = owner->FindInventory(itemtype); @@ -942,14 +892,14 @@ int DoJumpIfInventory(AActor *owner, AActor *self, AActor *stateowner, FState *c if (itemamount > 0) { if (item->Amount >= itemamount) - ACTION_JUMP(label); + ACTION_RETURN_STATE(label); } else if (item->Amount >= item->MaxAmount) { - ACTION_JUMP(label); + ACTION_RETURN_STATE(label); } } - return numret; + ACTION_RETURN_STATE(NULL); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInventory) @@ -976,13 +926,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) PARAM_STATE (label); PARAM_INT_OPT(amount) { amount = 1; } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - ABasicArmor *armor = (ABasicArmor *)self->FindInventory(NAME_BasicArmor); if (armor && armor->ArmorType == type && armor->Amount >= amount) - ACTION_JUMP(label); - return numret; + { + ACTION_RETURN_STATE(label); + } + ACTION_RETURN_STATE(NULL); } //========================================================================== @@ -1104,8 +1054,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CallSpecial) bool res = !!P_ExecuteSpecial(special, NULL, self, false, arg1, arg2, arg3, arg4, arg5); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_BOOL(res); } //========================================================================== @@ -1432,15 +1381,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) PARAM_ACTION_PROLOGUE; PARAM_STATE(jump); - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (!ACTION_CALL_FROM_WEAPON()) - return numret; + { + ACTION_RETURN_STATE(NULL); + } if (!self->player->ReadyWeapon->CheckAmmo(self->player->ReadyWeapon->bAltFire, false, true)) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } @@ -1920,7 +1870,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) // //=========================================================================== -static int DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) +static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) { int paramnum = NAP-1; PARAM_CLASS (mi, AInventory); @@ -1933,8 +1883,7 @@ static int DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) } if (receiver == NULL) { // If there's nothing to receive it, it's obviously a fail, right? - ACTION_SET_RESULT(false); - return numret; + return false; } bool res = true; @@ -1948,8 +1897,7 @@ static int DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) AInventory *item = static_cast(Spawn(mi, 0, 0, 0, NO_REPLACE)); if (item == NULL) { - ACTION_SET_RESULT(false); - return numret; + return false; } if (item->IsKindOf(RUNTIME_CLASS(AHealth))) { @@ -1964,38 +1912,26 @@ static int DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) if (!item->CallTryPickup(receiver)) { item->Destroy(); - res = false; + return false; } else { - res = true; + return true; } } - else - { - res = false; - } - if (!orresult) - { - ACTION_SET_RESULT(res); - } - else - { - ACTION_OR_RESULT(res); - } - return numret; + return false; } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveInventory) { PARAM_ACTION_PROLOGUE; - return DoGiveInventory(self, false, VM_ARGS_NAMES); + ACTION_RETURN_BOOL(DoGiveInventory(self, false, VM_ARGS_NAMES)); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) { PARAM_ACTION_PROLOGUE; - return DoGiveInventory(self->target, false, VM_ARGS_NAMES); + ACTION_RETURN_BOOL(DoGiveInventory(self->target, false, VM_ARGS_NAMES)); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) @@ -2004,16 +1940,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) TThinkerIterator it; AActor *mo; + int count = 0; - ACTION_SET_RESULT(false); while ((mo = it.Next())) { if (mo->master == self) { - numret = DoGiveInventory(mo, true, VM_ARGS_NAMES); + count += DoGiveInventory(mo, true, VM_ARGS_NAMES); } } - return numret; + ACTION_RETURN_INT(count); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) @@ -2022,19 +1958,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) TThinkerIterator it; AActor *mo; + int count = 0; - ACTION_SET_RESULT(false); if (self->master != NULL) { while ((mo = it.Next())) { if (mo->master == self->master && mo != self) { - numret = DoGiveInventory(mo, true, VM_ARGS_NAMES); + count += DoGiveInventory(mo, true, VM_ARGS_NAMES); } } } - return numret; + ACTION_RETURN_INT(count); } //=========================================================================== @@ -2048,7 +1984,7 @@ enum TIF_NOTAKEINFINITE = 1, }; -int DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) +bool DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) { int paramnum = NAP-1; PARAM_CLASS (itemtype, AInventory); @@ -2057,8 +1993,7 @@ int DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) if (itemtype == NULL) { - ACTION_SET_RESULT(true); - return numret; + return true; } if (!orresult) { @@ -2067,60 +2002,47 @@ int DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) } if (receiver == NULL) { - ACTION_SET_RESULT(false); - return numret; + return false; } - bool res = receiver->TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); - - if (!orresult) - { - ACTION_SET_RESULT(res); - } - else - { - ACTION_OR_RESULT(res); - } - return numret; + return receiver->TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeInventory) { PARAM_ACTION_PROLOGUE; - return DoTakeInventory(self, false, VM_ARGS_NAMES); + ACTION_RETURN_BOOL(DoTakeInventory(self, false, VM_ARGS_NAMES)); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) { PARAM_ACTION_PROLOGUE; - return DoTakeInventory(self->target, false, VM_ARGS_NAMES); + ACTION_RETURN_BOOL(DoTakeInventory(self->target, false, VM_ARGS_NAMES)); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromChildren) { PARAM_ACTION_PROLOGUE; - ACTION_SET_RESULT(false); - TThinkerIterator it; - AActor * mo; + AActor *mo; + int count = 0; while ((mo = it.Next())) { if (mo->master == self) { - DoTakeInventory(mo, true, VM_ARGS_NAMES); + count += DoTakeInventory(mo, true, VM_ARGS_NAMES); } } - return numret; + ACTION_RETURN_INT(count); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromSiblings) { PARAM_ACTION_PROLOGUE; - ACTION_SET_RESULT(false); - TThinkerIterator it; - AActor * mo; + AActor *mo; + int count = 0; if (self->master != NULL) { @@ -2128,11 +2050,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromSiblings) { if (mo->master == self->master && mo != self) { - DoTakeInventory(mo, true, VM_ARGS_NAMES); + count += DoTakeInventory(mo, true, VM_ARGS_NAMES); } } } - return numret; + ACTION_RETURN_INT(count); } //=========================================================================== @@ -2363,15 +2285,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) if (missile == NULL) { - ACTION_SET_RESULT(false); - return numret; + ACTION_RETURN_BOOL(false); } - ACTION_SET_RESULT(true); // Don't spawn monsters if this actor has been massacred if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) { - return numret; + ACTION_RETURN_BOOL(true); } if (distance == 0) @@ -2386,17 +2306,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) AWeapon *weapon = self->player->ReadyWeapon; if (weapon == NULL) - return numret; + ACTION_RETURN_BOOL(true); if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) - return numret; + ACTION_RETURN_BOOL(true); } AActor *mo = Spawn( missile, self->Vec3Angle(distance, self->angle, -self->floorclip + self->GetBobOffset() + zheight), ALLOW_REPLACE); int flags = (transfer_translation ? SIXF_TRANSFERTRANSLATION : 0) + (useammo ? SIXF_SETMASTER : 0); - bool res = InitSpawnedItem(self, mo, flags); - ACTION_SET_RESULT(res); // for an inventory item's use state - return numret; + ACTION_RETURN_BOOL(InitSpawnedItem(self, mo, flags)); // for an inventory item's use state } //=========================================================================== @@ -2423,17 +2341,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) if (missile == NULL) { - ACTION_SET_RESULT(false); - return numret; + ACTION_RETURN_BOOL(false); } - ACTION_SET_RESULT(true); if (chance > 0 && pr_spawnitemex() < chance) - return numret; + ACTION_RETURN_BOOL(true); // Don't spawn monsters if this actor has been massacred if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) - return numret; + ACTION_RETURN_BOOL(true); fixedvec2 pos; @@ -2467,7 +2383,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) AActor *mo = Spawn(missile, pos.x, pos.y, self->Z() - self->floorclip + self->GetBobOffset() + zofs, ALLOW_REPLACE); bool res = InitSpawnedItem(self, mo, flags); - ACTION_SET_RESULT(res); // for an inventory item's use state if (res) { if (tid != 0) @@ -2490,7 +2405,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) } mo->angle = angle; } - return numret; + ACTION_RETURN_BOOL(res); // for an inventory item's use state } //=========================================================================== @@ -2509,9 +2424,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) PARAM_FIXED_OPT (zvel) { zvel = 0; } PARAM_BOOL_OPT (useammo) { useammo = true; } - ACTION_SET_RESULT(true); if (missile == NULL) - return numret; + ACTION_RETURN_BOOL(true); if (ACTION_CALL_FROM_WEAPON()) { @@ -2519,9 +2433,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) AWeapon *weapon = self->player->ReadyWeapon; if (weapon == NULL) - return numret; + ACTION_RETURN_BOOL(true); if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) - return numret; + ACTION_RETURN_BOOL(true); } AActor *bo; @@ -2563,9 +2477,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) } else { - ACTION_SET_RESULT(false); + ACTION_RETURN_BOOL(false); } - return numret; + ACTION_RETURN_BOOL(true); } @@ -2599,8 +2513,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) if (cls == NULL || self->player == NULL) { - ACTION_SET_RESULT(false); - return numret; + ACTION_RETURN_BOOL(false); } AWeapon *weaponitem = static_cast(self->FindInventory(cls)); @@ -2611,13 +2524,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) { self->player->PendingWeapon = weaponitem; } - ACTION_SET_RESULT(true); + ACTION_RETURN_BOOL(true); } else { - ACTION_SET_RESULT(false); + ACTION_RETURN_BOOL(false); } - return numret; } @@ -2654,8 +2566,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) C_MidPrint(font != NULL ? font : SmallFont, formatted.GetChars()); con_midtime = saved; } - ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return numret; + return 0; } //=========================================================================== @@ -2686,8 +2597,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) FString formatted = strbin1(text); C_MidPrintBold(font != NULL ? font : SmallFont, formatted.GetChars()); con_midtime = saved; - ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return numret; + return 0; } //=========================================================================== @@ -2704,8 +2614,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) if (text[0] == '$') text = GStrings(&text[1]); FString formatted = strbin1(text); Printf("%s\n", formatted.GetChars()); - ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return numret; + return 0; } //========================================================================= @@ -2719,8 +2628,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) PARAM_ACTION_PROLOGUE; PARAM_INT(num); Printf("%d\n", num); - ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! - return numret; + return 0; } //=========================================================================== @@ -3031,8 +2939,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) PARAM_ACTION_PROLOGUE; PARAM_STATE(jump); - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - for (int i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) @@ -3040,19 +2946,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) // Always check sight from each player. if (P_CheckSight(players[i].mo, self, SF_IGNOREVISIBILITY)) { - return numret; + ACTION_RETURN_STATE(NULL); } // If a player is viewing from a non-player, then check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY)) { - return numret; + ACTION_RETURN_STATE(NULL); } } } - - ACTION_JUMP(jump); - return numret; + ACTION_RETURN_STATE(jump); } //=========================================================================== @@ -3105,8 +3009,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) PARAM_STATE(jump); PARAM_BOOL_OPT(twodi) { twodi = false; } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - range = range * range * (double(FRACUNIT) * FRACUNIT); // no need for square roots for (int i = 0; i < MAXPLAYERS; ++i) { @@ -3115,18 +3017,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) // Always check from each player. if (DoCheckSightOrRange(self, players[i].mo, range, twodi)) { - return numret; + ACTION_RETURN_STATE(NULL); } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckSightOrRange(self, players[i].camera, range, twodi)) { - return numret; + ACTION_RETURN_STATE(NULL); } } } - ACTION_JUMP(jump); - return numret; + ACTION_RETURN_STATE(jump); } //=========================================================================== @@ -3173,8 +3074,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) PARAM_STATE(jump); PARAM_BOOL_OPT(twodi) { twodi = false; } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - range = range * range * (double(FRACUNIT) * FRACUNIT); // no need for square roots for (int i = 0; i < MAXPLAYERS; ++i) { @@ -3183,18 +3082,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) // Always check from each player. if (DoCheckRange(self, players[i].mo, range, twodi)) { - return numret; + ACTION_RETURN_STATE(NULL); } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckRange(self, players[i].camera, range, twodi)) { - return numret; + ACTION_RETURN_STATE(NULL); } } } - ACTION_JUMP(jump); - return numret; + ACTION_RETURN_STATE(jump); } @@ -3258,10 +3156,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) PARAM_BOOL (condition); PARAM_STATE (jump); - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (condition) - ACTION_JUMP(jump); - return numret; + ACTION_RETURN_STATE(condition ? jump : NULL); } //=========================================================================== @@ -3369,12 +3264,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFloor) PARAM_ACTION_PROLOGUE; PARAM_STATE(jump); - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (self->Z() <= self->floorz) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } //=========================================================================== @@ -3389,12 +3283,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) PARAM_ACTION_PROLOGUE; PARAM_STATE(jump); - ACTION_SET_RESULT(false); if (self->Top() >= self->ceilingz) // Height needs to be counted { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } //=========================================================================== @@ -3526,13 +3419,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) PARAM_ACTION_PROLOGUE; PARAM_STATE(jump); - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (self->player != NULL && skins[self->player->userinfo.GetSkin()].othergame) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } //=========================================================================== @@ -3719,8 +3611,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) PARAM_FIXED_OPT (offsetwidth) { offsetwidth = 0; } PARAM_INT_OPT (ptr_target) { ptr_target = AAPTR_DEFAULT; } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - target = COPY_AAPTR(self, ptr_target == AAPTR_DEFAULT ? AAPTR_TARGET|AAPTR_PLAYER_GETTARGET|AAPTR_NULL : ptr_target); // no player-support by default if (flags & CLOFF_MUL_HEIGHT) @@ -3765,7 +3655,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (range && !(flags & CLOFF_CHECKPARTIAL)) { if (distance > range) - return numret; + ACTION_RETURN_STATE(NULL); } { @@ -3818,7 +3708,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) } else { - return numret; + ACTION_RETURN_STATE(NULL); } angle >>= ANGLETOFINESHIFT; @@ -3860,7 +3750,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { if (minrange > 0 && trace.Distance < minrange) { - return numret; + ACTION_RETURN_STATE(NULL); } if ((trace.HitType == TRACE_HitActor) && (trace.Actor != NULL) && !(lof_data.BadActor)) { @@ -3868,9 +3758,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (flags & (CLOFF_SETMASTER)) self->master = trace.Actor; if (flags & (CLOFF_SETTRACER)) self->tracer = trace.Actor; } - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } //========================================================================== @@ -3917,8 +3807,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) angle_t an; AActor *target, *viewport; - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - bool doCheckSight; if (!self->player) @@ -3940,11 +3828,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) } if (target == NULL) - return numret; // [KS] Let's not call P_CheckSight unnecessarily in this case. + ACTION_RETURN_STATE(NULL); // [KS] Let's not call P_CheckSight unnecessarily in this case. if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - return numret; + ACTION_RETURN_STATE(NULL); } doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -3954,7 +3842,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // Does the player aim at something that can be shot? P_AimLineAttack(self, self->angle, MISSILERANGE, &target, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0); - if (!target) return numret; + if (!target) ACTION_RETURN_STATE(NULL); switch (flags & (JLOSF_TARGETLOS|JLOSF_FLIPFOV)) { @@ -3977,21 +3865,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If target is not a combatant, don't jump if ( (flags & JLOSF_COMBATANTONLY) && (!target->player) && !(target->flags3 & MF3_ISMONSTER)) - return numret; + ACTION_RETURN_STATE(NULL); // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) - return numret; + ACTION_RETURN_STATE(NULL); fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) - return numret; + ACTION_RETURN_STATE(NULL); if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) - return numret; + ACTION_RETURN_STATE(NULL); if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -4004,7 +3892,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { viewport = self; } if (doCheckSight && !P_CheckSight (viewport, target, SF_IGNOREVISIBILITY)) - return numret; + ACTION_RETURN_STATE(NULL); if (flags & JLOSF_FLIPFOV) { @@ -4018,13 +3906,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return numret; // [KS] Outside of FOV - return + ACTION_RETURN_STATE(NULL); // [KS] Outside of FOV - return } - } - - ACTION_JUMP(jump); - return numret; + ACTION_RETURN_STATE(jump); } @@ -4047,8 +3932,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) angle_t an; AActor *target; - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - if (flags & JLOSF_CHECKMASTER) { target = self->master; @@ -4067,19 +3950,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (target == NULL) { // [KS] Let's not call P_CheckSight unnecessarily in this case. - return numret; + ACTION_RETURN_STATE(NULL); } if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - return numret; + ACTION_RETURN_STATE(NULL); } fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) { - return numret; + ACTION_RETURN_STATE(NULL); } bool doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -4087,7 +3970,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) - return numret; + ACTION_RETURN_STATE(NULL); if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -4102,14 +3985,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { - return numret; // [KS] Outside of FOV - return + ACTION_RETURN_STATE(NULL); // [KS] Outside of FOV - return } } if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY)) - return numret; + ACTION_RETURN_STATE(NULL); - ACTION_JUMP(jump); - return numret; + ACTION_RETURN_STATE(jump); } //=========================================================================== @@ -4123,14 +4005,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) PARAM_ACTION_PROLOGUE; if ( self->player == NULL || self->player->ReadyWeapon == NULL ) - return 0; + ACTION_RETURN_STATE(NULL); PARAM_INT (count); PARAM_STATE (jump); PARAM_BOOL_OPT (dontincrement) { dontincrement = false; } - if (count <= 0) - return 0; + if (numret > 0) + { + ret->SetPointer(NULL, ATAG_STATE); + numret = 1; + } AWeapon *weapon = self->player->ReadyWeapon; @@ -4144,17 +4029,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) if (ReloadCounter != 0) { // Go back to the refire frames, instead of continuing on to the reload frames. - ACTION_JUMP(jump); + if (numret != 0) + { + ret->SetPointer(jump, ATAG_STATE); + } } else { // We need to reload. However, don't reload if we're out of ammo. weapon->CheckAmmo(false, false); } - if (!dontincrement) + { weapon->ReloadCounter = ReloadCounter; - return 0; + } + return numret; } //=========================================================================== @@ -4286,19 +4175,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) PARAM_STATE (jumpto); PARAM_INT_OPT (checkpointer) { checkpointer = AAPTR_DEFAULT; } - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - AActor *owner = COPY_AAPTR(self, checkpointer); if (owner == NULL) { - return numret; + ACTION_RETURN_STATE(NULL); } if (CheckActorFlag(owner, flagname)) { - ACTION_JUMP(jumpto); + ACTION_RETURN_STATE(jumpto); } - return numret; + ACTION_RETURN_STATE(NULL); } @@ -4394,20 +4281,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) PARAM_INT (prob); PARAM_STATE (jump); - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! A_FaceTarget(self); if (pr_monsterrefire() < prob) - return numret; + ACTION_RETURN_STATE(NULL); if (self->target == NULL || P_HitFriend (self) || self->target->health <= 0 || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) ) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } //=========================================================================== @@ -4739,7 +4625,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) AActor *ref = COPY_AAPTR(self, ptr); - ACTION_SET_RESULT(false); + // A_Teleport and A_Warp were the only codepointers that can state jump + // *AND* have a meaningful inventory state chain result. Grrr. + if (numret > 1) + { + ret[1].SetInt(false); + numret = 2; + } + if (numret > 0) + { + ret[0].SetPointer(NULL, ATAG_STATE); + } + if (!ref) { return numret; @@ -4782,7 +4679,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) target_type = PClass::FindActor("BossSpot"); } - AActor * spot = state->GetSpotWithMinMaxDistance(target_type, ref->X(), ref->Y(), mindist, maxdist); + AActor *spot = state->GetSpotWithMinMaxDistance(target_type, ref->X(), ref->Y(), mindist, maxdist); if (spot == NULL) { return numret; @@ -4860,7 +4757,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) if (!(flags & TF_NOJUMP)) //The state jump should only happen with the calling actor. { - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! if (teleport_state == NULL) { // Default to Teleport. @@ -4871,11 +4767,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) return numret; } } - ACTION_JUMP(teleport_state); + if (numret > 0) + { + ret[0].SetPointer(teleport_state, ATAG_STATE); + } return numret; } } - ACTION_SET_RESULT(tele_result); + if (numret > 1) + { + ret[1].SetInt(tele_result); + } return numret; } @@ -5035,8 +4937,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) self->flags6 |= MF6_LINEDONE; // no more for this thing } } - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_BOOL(res); } //========================================================================== @@ -5177,6 +5078,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) AActor *reference; + // A_Teleport and A_Warp were the only codepointers that can state jump + // *AND* have a meaningful inventory state chain result. Grrr. + if (numret > 1) + { + ret[1].SetInt(false); + numret = 2; + } + if (numret > 0) + { + ret[0].SetPointer(NULL, ATAG_STATE); + } + if ((flags & WARPF_USETID)) { reference = SingleActorFromTID(destination_selector, self); @@ -5189,7 +5102,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) //If there is no actor to warp to, fail. if (!reference) { - ACTION_SET_RESULT(false); return numret; } @@ -5197,17 +5109,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { if (success_state) { - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + // Jumps should never set the result for inventory state chains! // in this case, you have the statejump to help you handle all the success anyway. - ACTION_JUMP(success_state); - return numret; + if (numret > 0) + { + ret[0].SetPointer(success_state, ATAG_STATE); + } + } + else if (numret > 1) + { + ret[1].SetInt(true); } - - ACTION_SET_RESULT(true); - } - else - { - ACTION_SET_RESULT(false); } return numret; } @@ -5234,8 +5146,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteWithResult) PARAM_INT_OPT (arg4) { arg4 = 0; } int res = P_ExecuteSpecial(ACS_ExecuteWithResult, NULL, self, false, -scriptname, arg1, arg2, arg3, arg4); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_INT(res); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecute) @@ -5248,8 +5159,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecute) PARAM_INT_OPT (arg3) { arg3 = 0; } int res = P_ExecuteSpecial(ACS_Execute, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_INT(res); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteAlways) @@ -5262,8 +5172,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteAlways) PARAM_INT_OPT (arg3) { arg3 = 0; } int res = P_ExecuteSpecial(ACS_ExecuteAlways, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_INT(res); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecute) @@ -5276,8 +5185,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecute) PARAM_INT_OPT (lock) { lock = 0; } int res = P_ExecuteSpecial(ACS_LockedExecute, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_INT(res); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecuteDoor) @@ -5290,8 +5198,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecuteDoor) PARAM_INT_OPT (lock) { lock = 0; } int res = P_ExecuteSpecial(ACS_LockedExecuteDoor, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_INT(res); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedSuspend) @@ -5301,8 +5208,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedSuspend) PARAM_INT_OPT (mapnum) { mapnum = 0; } int res = P_ExecuteSpecial(ACS_Suspend, NULL, self, false, -scriptname, mapnum, 0, 0, 0); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_INT(res); } DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) @@ -5312,8 +5218,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) PARAM_INT_OPT (mapnum) { mapnum = 0; } int res = P_ExecuteSpecial(ACS_Terminate, NULL, self, false, -scriptname, mapnum, 0, 0, 0); - ACTION_SET_RESULT(res); - return numret; + ACTION_RETURN_INT(res); } @@ -5348,7 +5253,6 @@ enum RadiusGiveFlags RGF_OBJECTS = 1 << 3, RGF_VOODOO = 1 << 4, RGF_CORPSES = 1 << 5, - RGF_MASK = 2111, RGF_NOTARGET = 1 << 6, RGF_NOTRACER = 1 << 7, RGF_NOMASTER = 1 << 8, @@ -5361,6 +5265,14 @@ enum RadiusGiveFlags RGF_EXFILTER = 1 << 15, RGF_EXSPECIES = 1 << 16, RGF_EITHER = 1 << 17, + + RGF_MASK = /*2111*/ + RGF_GIVESELF | + RGF_PLAYERS | + RGF_MONSTERS | + RGF_OBJECTS | + RGF_VOODOO | + RGF_CORPSES | RGF_MISSILES, }; static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amount, fixed_t distance, int flags, PClassActor *filter, FName species, fixed_t mindist) @@ -5503,8 +5415,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) // We need a valid item, valid targets, and a valid range if (item == NULL || (flags & RGF_MASK) == 0 || !flags || distance <= 0 || mindist >= distance) { - ACTION_SET_RESULT(false); - return numret; + ACTION_RETURN_INT(0); } if (amount == 0) @@ -5512,13 +5423,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) amount = 1; } AActor *thing; - bool given = false; + int given = 0; if (flags & RGF_MISSILES) { TThinkerIterator it; while ((thing = it.Next())) { - given |= DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist); + given += DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist); } } else @@ -5526,11 +5437,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance)); while ((thing = it.Next())) { - given |= DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist); + given += DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist); } } - ACTION_SET_RESULT(given); - return numret; + ACTION_RETURN_INT(given); } //=========================================================================== @@ -5547,16 +5457,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSpecies) AActor *mobj = COPY_AAPTR(self, ptr); - ACTION_SET_RESULT(false); - // Needs at least one state jump to work. - if (mobj == NULL) - { - return numret; - } - - if (jump && mobj->GetSpecies() == species) - ACTION_JUMP(jump); - return numret; + if (mobj != NULL && jump && mobj->GetSpecies() == species) + ACTION_RETURN_STATE(jump); + ACTION_RETURN_STATE(NULL); } //========================================================================== @@ -5653,7 +5556,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatSpeed) if (!ref) { - ACTION_SET_RESULT(false); return 0; } @@ -5676,12 +5578,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPainThreshold) if (!ref) { - ACTION_SET_RESULT(false); - return numret; + return 0; } ref->PainThreshold = threshold; - return numret; + return 0; } //=========================================================================== @@ -6358,15 +6259,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHigherOrLower) AActor *mobj = COPY_AAPTR(self, ptr); - ACTION_SET_RESULT(false); //No inventory jump chains please. if (mobj != NULL && mobj != self) //AAPTR_DEFAULT is completely useless in this regard. { - if ((high) && (mobj->Z() > ((includeHeight ? self->height : 0) + self->Z() + offsethigh))) - ACTION_JUMP(high); - else if ((low) && (mobj->Z() + (includeHeight ? mobj->height : 0)) < (self->Z() + offsetlow)) - ACTION_JUMP(low); + if ((high) && (mobj->Z() > ((includeHeight ? self->height : 0) + self->Z() + offsethigh))) + { + ACTION_RETURN_STATE(high); + } + else if ((low) && (mobj->Z() + (includeHeight ? mobj->height : 0)) < (self->Z() + offsetlow)) + { + ACTION_RETURN_STATE(low); + } } - return numret; + ACTION_RETURN_STATE(NULL); } //=========================================================================== @@ -6383,7 +6287,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) AActor *mobj = COPY_AAPTR(self, ptr); if (!mobj) { - ACTION_SET_RESULT(false); return 0; } @@ -6452,7 +6355,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold) AActor *mobj = COPY_AAPTR(self, ptr); if (!mobj) { - ACTION_SET_RESULT(false); return 0; } if (def) @@ -6495,19 +6397,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) PARAM_INT_OPT(flags) { flags = 0; } PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - ACTION_SET_RESULT(false); //No inventory chain results please. - - if (!jump) { if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) - return numret; + ACTION_RETURN_STATE(NULL); } AActor *ref = COPY_AAPTR(self, ptr); - //We need these to check out. + // We need these to check out. if (!ref || !classname || distance <= 0) - return numret; + ACTION_RETURN_STATE(NULL); int counter = 0; bool result = false; @@ -6617,9 +6516,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) if (result && jump) { - ACTION_JUMP(jump); + ACTION_RETURN_STATE(jump); } - return numret; + ACTION_RETURN_STATE(NULL); } /*=========================================================================== @@ -6649,16 +6548,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) AActor *mobj = COPY_AAPTR(self, ptr); - ACTION_SET_RESULT(false); //Needs at least one state jump to work. if (!mobj) { - return numret; + ACTION_RETURN_STATE(NULL); } //Nothing to block it so skip the rest. bool checker = (flags & CBF_DROPOFF) ? P_CheckMove(mobj, mobj->X(), mobj->Y()) : P_TestMobjLocation(mobj); - if (checker) return numret; + if (checker) ACTION_RETURN_STATE(NULL); if (mobj->BlockingMobj) { @@ -6675,14 +6573,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) //this point. I.e. A_CheckBlock("",CBF_SETTRACER) is like having CBF_NOLINES. //It gets the mobj blocking, if any, and doesn't jump at all. if (!block) - return numret; + ACTION_RETURN_STATE(NULL); //[MC] Easiest way to tell if an actor is blocking it, use the pointers. if (mobj->BlockingMobj || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL)) { - ACTION_JUMP(block); + ACTION_RETURN_STATE(block); } - return numret; + ACTION_RETURN_STATE(NULL); } //=========================================================================== @@ -6711,8 +6609,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) //Need an actor. if (!mobj || ((flags & FMDF_NOPITCH) && (flags & FMDF_NOANGLE))) { - ACTION_SET_RESULT(false); - return numret; + ACTION_RETURN_BOOL(false); } //Don't bother calculating this if we don't have any horizontal movement. @@ -6792,5 +6689,5 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) mobj->SetPitch(pitch, !!(flags & FMDF_INTERPOLATE)); } } - return numret; + ACTION_RETURN_BOOL(true); } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 8901e35c3..0ec4c95d7 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -204,6 +204,7 @@ public: virtual bool isConstant() const; virtual void RequestAddress(); + virtual VMFunction *GetDirectFunction(); virtual ExpEmit Emit(VMFunctionBuilder *build); @@ -817,39 +818,22 @@ 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; } @@ -862,15 +846,15 @@ public: // //========================================================================== -class FxSequence : public FxTailable +class FxSequence : public FxExpression { - TDeletingArray Expressions; + TDeletingArray 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 +864,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 +883,14 @@ 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); }; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 0d6e009fd..c94d6840d 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -129,6 +129,17 @@ bool FxExpression::isConstant() const // //========================================================================== +VMFunction *FxExpression::GetDirectFunction() +{ + return NULL; +} + +//========================================================================== +// +// +// +//========================================================================== + FxExpression *FxExpression::Resolve(FCompileContext &ctx) { isresolved = true; @@ -3064,28 +3075,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 +3082,7 @@ VMFunction *FxTailable::GetDirectFunction() //========================================================================== FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos) -: FxTailable(pos) +: FxExpression(pos) { Function = func; ArgList = args; @@ -3134,14 +3123,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) delete this; return NULL; } - TArray &rets = Function->Variants[0].Proto->ReturnTypes; - if (rets.Size() == 0) + TArray &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; @@ -3165,6 +3149,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); @@ -3191,17 +3180,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; @@ -3331,7 +3320,7 @@ FxExpression *FxSequence::Resolve(FCompileContext &ctx) CHECKRESOLVED(); for (unsigned i = 0; i < Expressions.Size(); ++i) { - if (NULL == (Expressions[i] = static_cast(Expressions[i]->Resolve(ctx)))) + if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx))) { delete this; return NULL; @@ -3346,11 +3335,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); } @@ -3378,9 +3367,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; @@ -3407,12 +3396,12 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) ABORT(Condition); if (WhenTrue != NULL) { - WhenTrue = static_cast(WhenTrue->Resolve(ctx)); + WhenTrue = WhenTrue->Resolve(ctx); ABORT(WhenTrue); } if (WhenFalse != NULL) { - WhenFalse = static_cast(WhenFalse->Resolve(ctx)); + WhenFalse = WhenFalse->Resolve(ctx); ABORT(WhenFalse); } ValueType = VAL_Unknown; @@ -3422,7 +3411,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) ExpVal condval = static_cast(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; @@ -3431,11 +3420,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 @@ -3465,24 +3454,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(); } @@ -3490,14 +3473,35 @@ 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(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(); } diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 255e2adaf..4774ac9d1 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -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 *args, TArray *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) @@ -1036,18 +1064,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); - } - else if (sc.CheckToken(TK_State)) - { - rets.Push(TypeState); - } - else if (sc.CheckToken(TK_Float)) - { - rets.Push(TypeFloat64); + 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); diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index d6f3eb939..5b54d684d 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -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(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 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 &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef) { - const TArray ¶ms = afd->Variants[0].Proto->ArgumentTypes; + const TArray ¶ms = afd->Variants[0].Implementation->Proto->ArgumentTypes; const TArray ¶mflags = afd->Variants[0].ArgFlags; int numparams = (int)params.Size(); int pnum = 0; diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 69cbe9d8d..ce5d5269a 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -162,8 +162,10 @@ 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 diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 48ee9f68f..5b0f3a2de 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -46,7 +46,7 @@ ACTOR Actor native //: Thinker // 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 +108,7 @@ ACTOR Actor native //: Thinker action native A_Die(name damagetype = "none"); action native A_Detonate(); action native A_Mushroom(class 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 +181,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 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 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 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 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 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 itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); - action native A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); - action native A_SpawnItem(class itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); - action native A_SpawnItemEx(class 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 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 itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); + action native bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); + action native bool A_SpawnItem(class itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); + action native bool A_SpawnItemEx(class 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 +209,31 @@ ACTOR Actor native //: Thinker action native A_SetMass(int mass); action native A_SpawnDebris(class 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 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 missiletype, float missileheight); - action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class 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 itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); + action native state, bool A_Teleport(state teleportstate = "", class targettype = "BossSpot", class 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 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 itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); - action native A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); - action native A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); - action native A_RadiusGive(class itemtype, float distance, int flags, int amount = 0, class 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 itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); + action native bool A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); + action native bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); + action native int A_RadiusGive(class itemtype, float distance, int flags, int amount = 0, class 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 missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); @@ -249,10 +249,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 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 whichweapon); action native A_Punch(); action native A_Feathers(); action native A_ClassBossHealth(); @@ -264,7 +264,7 @@ ACTOR Actor native //: Thinker action native A_RemoveForcefield(); action native A_DropWeaponPieces(class p1, class p2, class 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,37 +299,37 @@ ACTOR Actor native //: Thinker action native A_RemoveChildren(bool removeall = false, int flags = 0, class filter = "None", name species = "None"); action native A_RemoveSiblings(bool removeall = false, int flags = 0, class filter = "None", name species = "None"); action native A_Remove(int removee, int flags = 0, class filter = "None", name species = "None"); - action native A_GiveToChildren(class itemtype, int amount = 0); - action native A_GiveToSiblings(class itemtype, int amount = 0); - action native A_TakeFromChildren(class itemtype, int amount = 0); - action native A_TakeFromSiblings(class itemtype, int amount = 0); + action native int A_GiveToChildren(class itemtype, int amount = 0); + action native int A_GiveToSiblings(class itemtype, int amount = 0); + action native int A_TakeFromChildren(class itemtype, int amount = 0); + action native int A_TakeFromSiblings(class itemtype, int amount = 0); action native A_SetTeleFog(class oldpos, class 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 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 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 diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index ee9a35446..111339bd9 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -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 pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = ""); action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class 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 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 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(); From b8a16600ac870da0be092aeb21d65458b2058aee Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 21:39:13 -0600 Subject: [PATCH 10/17] Braces around ACTION_RETURN used in an if are no longer optional --- src/thingdef/thingdef_codeptr.cpp | 72 +++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 778c758c6..c9c4f5a6b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -892,7 +892,9 @@ int DoJumpIfInventory(AActor *owner, AActor *self, AActor *stateowner, FState *c if (itemamount > 0) { if (item->Amount >= itemamount) + { ACTION_RETURN_STATE(label); + } } else if (item->Amount >= item->MaxAmount) { @@ -2306,9 +2308,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) AWeapon *weapon = self->player->ReadyWeapon; if (weapon == NULL) + { ACTION_RETURN_BOOL(true); + } if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) + { ACTION_RETURN_BOOL(true); + } } AActor *mo = Spawn( missile, self->Vec3Angle(distance, self->angle, -self->floorclip + self->GetBobOffset() + zheight), ALLOW_REPLACE); @@ -2343,13 +2349,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) { ACTION_RETURN_BOOL(false); } - if (chance > 0 && pr_spawnitemex() < chance) + { ACTION_RETURN_BOOL(true); - + } // Don't spawn monsters if this actor has been massacred if (self->DamageType == NAME_Massacre && (GetDefaultByType(missile)->flags3 & MF3_ISMONSTER)) + { ACTION_RETURN_BOOL(true); + } fixedvec2 pos; @@ -2425,17 +2433,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) PARAM_BOOL_OPT (useammo) { useammo = true; } if (missile == NULL) + { ACTION_RETURN_BOOL(true); - + } if (ACTION_CALL_FROM_WEAPON()) { // Used from a weapon, so use some ammo AWeapon *weapon = self->player->ReadyWeapon; if (weapon == NULL) + { ACTION_RETURN_BOOL(true); + } if (useammo && !weapon->DepleteAmmo(weapon->bAltFire)) + { ACTION_RETURN_BOOL(true); + } } AActor *bo; @@ -3655,7 +3668,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (range && !(flags & CLOFF_CHECKPARTIAL)) { if (distance > range) + { ACTION_RETURN_STATE(NULL); + } } { @@ -3828,8 +3843,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) } if (target == NULL) - ACTION_RETURN_STATE(NULL); // [KS] Let's not call P_CheckSight unnecessarily in this case. - + { // [KS] Let's not call P_CheckSight unnecessarily in this case. + ACTION_RETURN_STATE(NULL); + } if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { ACTION_RETURN_STATE(NULL); @@ -3842,7 +3858,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // Does the player aim at something that can be shot? P_AimLineAttack(self, self->angle, MISSILERANGE, &target, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0); - if (!target) ACTION_RETURN_STATE(NULL); + if (!target) + { + ACTION_RETURN_STATE(NULL); + } switch (flags & (JLOSF_TARGETLOS|JLOSF_FLIPFOV)) { @@ -3865,22 +3884,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If target is not a combatant, don't jump if ( (flags & JLOSF_COMBATANTONLY) && (!target->player) && !(target->flags3 & MF3_ISMONSTER)) + { ACTION_RETURN_STATE(NULL); - + } // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) + { ACTION_RETURN_STATE(NULL); - + } fixed_t distance = self->AproxDistance3D(target); if (dist_max && (distance > dist_max)) + { ACTION_RETURN_STATE(NULL); - + } if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) + { ACTION_RETURN_STATE(NULL); - + } if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -3892,7 +3915,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) else { viewport = self; } if (doCheckSight && !P_CheckSight (viewport, target, SF_IGNOREVISIBILITY)) + { ACTION_RETURN_STATE(NULL); + } if (flags & JLOSF_FLIPFOV) { @@ -3970,8 +3995,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) + { ACTION_RETURN_STATE(NULL); - + } if (flags & JLOSF_CLOSENOFOV) fov = 0; @@ -3989,8 +4015,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) } } if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY)) + { ACTION_RETURN_STATE(NULL); - + } ACTION_RETURN_STATE(jump); } @@ -4005,8 +4032,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) PARAM_ACTION_PROLOGUE; if ( self->player == NULL || self->player->ReadyWeapon == NULL ) + { ACTION_RETURN_STATE(NULL); - + } PARAM_INT (count); PARAM_STATE (jump); PARAM_BOOL_OPT (dontincrement) { dontincrement = false; } @@ -4284,8 +4312,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) A_FaceTarget(self); if (pr_monsterrefire() < prob) + { ACTION_RETURN_STATE(NULL); - + } if (self->target == NULL || P_HitFriend (self) || self->target->health <= 0 @@ -5458,7 +5487,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSpecies) AActor *mobj = COPY_AAPTR(self, ptr); if (mobj != NULL && jump && mobj->GetSpecies() == species) + { ACTION_RETURN_STATE(jump); + } ACTION_RETURN_STATE(NULL); } @@ -6400,14 +6431,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) if (!jump) { if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) + { ACTION_RETURN_STATE(NULL); + } } AActor *ref = COPY_AAPTR(self, ptr); // We need these to check out. if (!ref || !classname || distance <= 0) + { ACTION_RETURN_STATE(NULL); - + } int counter = 0; bool result = false; fixed_t closer = distance, farther = 0, current = distance; @@ -6556,7 +6590,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) //Nothing to block it so skip the rest. bool checker = (flags & CBF_DROPOFF) ? P_CheckMove(mobj, mobj->X(), mobj->Y()) : P_TestMobjLocation(mobj); - if (checker) ACTION_RETURN_STATE(NULL); + if (checker) + { + ACTION_RETURN_STATE(NULL); + } if (mobj->BlockingMobj) { @@ -6573,8 +6610,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) //this point. I.e. A_CheckBlock("",CBF_SETTRACER) is like having CBF_NOLINES. //It gets the mobj blocking, if any, and doesn't jump at all. if (!block) + { ACTION_RETURN_STATE(NULL); - + } //[MC] Easiest way to tell if an actor is blocking it, use the pointers. if (mobj->BlockingMobj || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL)) { From ade780d810c5bf346fc8a8f99e4e272a97c1fc5c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 22:05:10 -0600 Subject: [PATCH 11/17] Redo ACustomInventory::CallStateChain to check return types --- src/thingdef/thingdef_codeptr.cpp | 67 +++++++++++++++++++++++-------- src/zscript/vmexec.h | 2 +- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index c9c4f5a6b..50bb7de33 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -108,51 +108,84 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) { INTBOOL result = false; int counter = 0; - int retval, numret; - VMReturn ret; - ret.IntAt(&retval); VMValue params[3] = { actor, this, 0 }; + // We accept return types of `state`, `(int|bool)` or `state, (int|bool)`. + // The last one is for the benefit of A_Warp and A_Teleport. + int retval, numret; + FState *nextstate; + VMReturn ret[2]; + ret[0].PointerAt((void **)&nextstate); + ret[1].IntAt(&retval); + this->flags5 |= MF5_INSTATECALL; FState *savedstate = this->state; while (state != NULL) { this->state = state; + nextstate = NULL; // assume no jump if (state->ActionFunc != NULL) { VMFrameStack stack; + PPrototype *proto = state->ActionFunc->Proto; + VMReturn *wantret; params[2] = VMValue(state, ATAG_STATE); - retval = true; // assume success - numret = stack.Call(state->ActionFunc, params, countof(params), &ret, 1); + retval = true; // assume success + wantret = NULL; // assume no return value wanted + numret = 0; + + // For functions that return nothing (or return some type + // we don't care about), we pretend they return true, + // thanks to the values set just above. + + if (proto->ReturnTypes.Size() == 1) + { + if (proto->ReturnTypes[0] == TypeState) + { // Function returns a state + wantret = &ret[0]; + } + else if (proto->ReturnTypes[0] == TypeSInt32 || proto->ReturnTypes[0] == TypeBool) + { // Function returns an int or bool + wantret = &ret[1]; + } + numret = 1; + } + else if (proto->ReturnTypes.Size() == 2) + { + if (proto->ReturnTypes[0] == TypeState && + (proto->ReturnTypes[1] == TypeSInt32 || proto->ReturnTypes[1] == TypeBool)) + { // Function returns a state and an int or bool + wantret = &ret[0]; + numret = 2; + } + } + stack.Call(state->ActionFunc, params, countof(params), wantret, numret); // As long as even one state succeeds, the whole chain succeeds unless aborted below. - result |= retval; + // A state that wants to jump does not count as "succeeded". + if (nextstate != NULL) + { + result |= retval; + } } // Since there are no delays it is a good idea to check for infinite loops here! counter++; if (counter >= 10000) break; - if (this->state == state) + if (nextstate == NULL) { - FState *next = state->GetNextState(); + nextstate = state->GetNextState(); - if (state == next) + if (state == nextstate) { // Abort immediately if the state jumps to itself! result = false; break; } - - // If both variables are still the same there was no jump - // so we must advance to the next state. - state = next; - } - else - { - state = this->state; } + state = nextstate; } this->flags5 &= ~MF5_INSTATECALL; this->state = savedstate; diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 30369baf4..0d003766f 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -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(); From b1098ede9306e43ea90814b1ccaee61a0291a26e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 22:05:16 -0600 Subject: [PATCH 12/17] Restore "direct" call optimization for DECORATE --- src/thingdef/thingdef.cpp | 2 +- src/thingdef/thingdef_exp.h | 7 ++++--- src/thingdef/thingdef_expression.cpp | 31 ++++++++++++---------------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4cb03111b..7d6fb9769 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -277,7 +277,7 @@ static void FinishThingdef() // Can we call this function directly without wrapping it in an // anonymous function? e.g. Are we passing any parameters to it? - func = NULL;//tcall->Code->GetDirectFunction(); + func = tcall->Code->GetDirectFunction(); if (func == NULL) { FCompileContext ctx(tcall->ActorClass); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 0ec4c95d7..d78638815 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -835,9 +835,9 @@ public: 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(); }; //========================================================================== @@ -891,6 +891,7 @@ public: FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + VMFunction *GetDirectFunction(); }; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index c94d6840d..742f5b52d 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3202,24 +3202,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; -} - //========================================================================== // // @@ -3505,6 +3487,19 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) 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; +} + //========================================================================== // //========================================================================== From eace79ccad325b9c6181b4e941eeb5a48604be42 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 22:11:05 -0600 Subject: [PATCH 13/17] Add some functions for use with DECORATE return - Since DECORATE's return statement can only return the results of function calls (I do not want to spend the time necessary to make it return arbitrary expressions), here are three functions to get around this limitation: * A_State - Returns the state passed to it. You can simulate A_Jump functions with this. * A_Int - Returns the int passed to it. * A_Bool - Returns the bool passed to it. - e.g. If you want to return the number 3, you use this: return A_Int(3); If you want to jump to a different state, you use this: return A_State("SomeState"); --- src/thingdef/thingdef_codeptr.cpp | 45 +++++++++++++++++++++++++++++++ src/thingdef/thingdef_parse.cpp | 4 +++ wadsrc/static/actors/actor.txt | 4 +++ 3 files changed, 53 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 40cd68b6f..19e9d4a96 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -6757,3 +6757,48 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) } ACTION_RETURN_BOOL(true); } + +//=========================================================================== +// +// A_State +// +// Returns the state passed in. +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_State) +{ + PARAM_ACTION_PROLOGUE; + PARAM_STATE(returnme); + ACTION_RETURN_STATE(returnme); +} + +//=========================================================================== +// +// A_Int +// +// Returns the int passed in. +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Int) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT(returnme); + ACTION_RETURN_INT(returnme); +} + +//=========================================================================== +// +// A_Bool +// +// Returns the bool passed in. +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Bool) +{ + PARAM_ACTION_PROLOGUE; + PARAM_BOOL(returnme); + ACTION_RETURN_BOOL(returnme); +} diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 4774ac9d1..daff4a99b 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -494,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 diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5b0f3a2de..54bc6c07c 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -332,6 +332,10 @@ ACTOR Actor native //: Thinker 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); + native state A_State(state returnme); + native int A_Int(int returnme); + native bool A_Bool(bool returnme); + States { Spawn: From aa58c5f519a6f564838245c1e271568bcaf89e27 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 22:26:37 -0600 Subject: [PATCH 14/17] Declare VMFunction::Proto to the garbage collector --- src/zscript/vm.h | 1 + src/zscript/vmframe.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/zscript/vm.h b/src/zscript/vm.h index ce5d5269a..f92906fd2 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -158,6 +158,7 @@ enum class VMFunction : public DObject { DECLARE_ABSTRACT_CLASS(VMFunction, DObject); + HAS_OBJECT_POINTERS; public: bool Native; FName Name; diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index 82affc053..ecf2511fb 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -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) From a399f40e5fb05dd4bc88b4f31ed521ca7bbde5fc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 22:40:04 -0600 Subject: [PATCH 15/17] Support casting states to booleans - This is so that you can call an A_Jump-type function from inside an if statement and do something other than jump if the jump condition was met. e.g. { if (A_Jump(128, "Foo")) { A_Log("The function would have jumped"); } else { A_Log("The function would not have jumped"); } } --- src/thingdef/thingdef_exp.h | 11 +++++ src/thingdef/thingdef_expression.cpp | 67 +++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index d78638815..3221debb8 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -390,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); +}; //========================================================================== // diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 742f5b52d..76919695f 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -168,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; @@ -511,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, 0, 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) { @@ -753,7 +819,6 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); if (Operand) - { Operand = Operand->ResolveAsBoolean(ctx); } From cb0fd5967fd8e8f1dbe78b124db52445b458b8b4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Thu, 18 Feb 2016 22:53:18 -0600 Subject: [PATCH 16/17] Oops. Had FxCastStateToBool backwards. --- src/thingdef/thingdef_expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 76919695f..714cb6c3e 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -565,7 +565,7 @@ ExpEmit FxCastStateToBool::Emit(VMFunctionBuilder *build) // If from is NULL, produce 0. Otherwise, produce 1. build->Emit(OP_LI, to.RegNum, 0); - build->Emit(OP_EQA_K, 0, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC)); + 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; From a31bd78abe33a0c85ee1011fd57d365e84945842 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 19 Feb 2016 00:29:19 -0600 Subject: [PATCH 17/17] Fix definitions of A_State/A_Int/A_Bool - These aren't action functions, so PARAM_ACTION_PROLOGUE is inappropriate. --- src/thingdef/thingdef_codeptr.cpp | 93 ++++++++++++++++--------------- wadsrc/static/actors/actor.txt | 8 +-- 2 files changed, 52 insertions(+), 49 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 19e9d4a96..6386ccfcb 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -323,6 +323,54 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance) return 0; } +//=========================================================================== +// +// A_State +// +// Returns the state passed in. +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_State) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(self, AActor); + PARAM_STATE(returnme); + ACTION_RETURN_STATE(returnme); +} + +//=========================================================================== +// +// A_Int +// +// Returns the int passed in. +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Int) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(self, AActor); + PARAM_INT(returnme); + ACTION_RETURN_INT(returnme); +} + +//=========================================================================== +// +// A_Bool +// +// Returns the bool passed in. +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Bool) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(self, AActor); + PARAM_BOOL(returnme); + ACTION_RETURN_BOOL(returnme); +} + //========================================================================== // // A_RearrangePointers @@ -6757,48 +6805,3 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) } ACTION_RETURN_BOOL(true); } - -//=========================================================================== -// -// A_State -// -// Returns the state passed in. -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_State) -{ - PARAM_ACTION_PROLOGUE; - PARAM_STATE(returnme); - ACTION_RETURN_STATE(returnme); -} - -//=========================================================================== -// -// A_Int -// -// Returns the int passed in. -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Int) -{ - PARAM_ACTION_PROLOGUE; - PARAM_INT(returnme); - ACTION_RETURN_INT(returnme); -} - -//=========================================================================== -// -// A_Bool -// -// Returns the bool passed in. -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Bool) -{ - PARAM_ACTION_PROLOGUE; - PARAM_BOOL(returnme); - ACTION_RETURN_BOOL(returnme); -} diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 54bc6c07c..b8a04c10e 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -43,6 +43,10 @@ ACTOR Actor native //: Thinker native int CountInv(class 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); @@ -331,10 +335,6 @@ ACTOR Actor native //: Thinker 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); - - native state A_State(state returnme); - native int A_Int(int returnme); - native bool A_Bool(bool returnme); States {