From ca2ac4e4fd16c63c3459f2c5d26165cb68ab1541 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 11 Jan 2017 17:16:07 +0100 Subject: [PATCH 1/4] - reverted debug stuff. --- src/win32/i_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 906bf9539..14c4791c6 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -1337,7 +1337,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - _crtBreakAlloc = 124459; + //_crtBreakAlloc = 53039; #endif DoMain (hInstance); From 5ef9429ae4cfaa364bfc84d51b90e2c572fe01d6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 11 Jan 2017 23:46:03 +0100 Subject: [PATCH 2/4] - added the ability to attach a constructor or destructor to an internally defined struct. There are a few which require explicit native construction or destruction that need to be exported to the VM, e.g. FCheckPosition. The VM cannot handle this directly, it needs two special functions to be attached to handle such elements. --- src/dobjtype.h | 4 ++ src/p_map.cpp | 22 ++++++++++ src/scripting/codegeneration/codegen.cpp | 48 ++++++++++++++++++++++ src/scripting/codegeneration/codegen.h | 1 + src/scripting/codegeneration/dynarrays.cpp | 16 ++++---- src/scripting/thingdef_data.cpp | 10 +++++ src/scripting/vm/vm.h | 6 +-- src/scripting/vm/vmbuilder.h | 2 + src/tarray.h | 2 +- wadsrc/static/zscript/actor.txt | 34 +++++++++++++++ 10 files changed, 132 insertions(+), 13 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index d31dac3ce..952f4d627 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -708,11 +708,15 @@ protected: class PStruct : public PNamedType { DECLARE_CLASS(PStruct, PNamedType); + public: PStruct(FName name, PTypeBase *outer); TArray Fields; bool HasNativeFields; + // Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use thes two functions for it. + VMFunction *mConstructor = nullptr; + VMFunction *mDestructor = nullptr; virtual PField *AddField(FName name, PType *type, DWORD flags=0); virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); diff --git a/src/p_map.cpp b/src/p_map.cpp index d48fb4e5a..a3427d486 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -84,6 +84,28 @@ TArray spechit; TArray portalhit; +// FCheckPosition requires explicit contstruction and destruction when used in the VM +DEFINE_ACTION_FUNCTION(_FCheckPosition, _Constructor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + new(self) FCheckPosition; + return 0; +} + +DEFINE_ACTION_FUNCTION(_FCheckPosition, _Destructor) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + self->~FCheckPosition(); + return 0; +} + +DEFINE_ACTION_FUNCTION(_FCheckPosition, ClearLastRipped) +{ + PARAM_SELF_STRUCT_PROLOGUE(FCheckPosition); + self->LastRipped.Clear(); + return 0; +} + //========================================================================== // // CanCollideWith diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index d8c1aa3dd..b2f9d40eb 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5160,6 +5160,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -5410,6 +5411,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -5504,6 +5506,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); @@ -7801,6 +7804,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use if (EmitTail) { build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); @@ -8072,6 +8076,8 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); int count = 0; + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use + if (count == 1) { ExpEmit reg; @@ -9508,6 +9514,19 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) { ExpEmit out(0, REGT_NIL); + // call the destructors for all structs requiring one. + // go in reverse order of construction + for (int i = build->ConstructedStructs.Size() - 1; i >= 0; i--) + { + auto pstr = static_cast(build->ConstructedStructs[i]->ValueType); + assert(pstr->mDestructor != nullptr); + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(build->ConstructedStructs[i]->StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + // If we return nothing, use a regular RET opcode. // Otherwise just return the value we're given. if (Value == nullptr) @@ -10173,6 +10192,19 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) else { // Init arrays and structs. + if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + { + auto pstr = static_cast(ValueType); + if (pstr->mConstructor != nullptr) + { + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mConstructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + if (pstr->mDestructor != nullptr) build->ConstructedStructs.Push(this); + } } return ExpEmit(); } @@ -10184,6 +10216,22 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) { build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); } + else + { + if (ValueType->IsA(RUNTIME_CLASS(PStruct))) + { + auto pstr = static_cast(ValueType); + if (pstr->mDestructor != nullptr) + { + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, build->FramePointer.RegNum, build->GetConstantInt(StackOffset)); + build->Emit(OP_PARAM, 0, reg.RegType, reg.RegNum); + build->Emit(OP_CALL_K, build->GetConstantAddress(pstr->mDestructor, ATAG_OBJECT), 1, 0); + reg.Free(build); + } + build->ConstructedStructs.Delete(build->ConstructedStructs.Find(this)); + } + } // Stack space will not be released because that would make controlled destruction impossible. // For that all local stack variables need to live for the entire execution of a function. } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 08afa6d93..a0a66a776 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -1993,6 +1993,7 @@ class FxLocalVariableDeclaration : public FxExpression public: int StackOffset = -1; int RegNum = -1; + bool constructed = false; FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p); ~FxLocalVariableDeclaration(); diff --git a/src/scripting/codegeneration/dynarrays.cpp b/src/scripting/codegeneration/dynarrays.cpp index 4489bbcb2..05e18a3ca 100644 --- a/src/scripting/codegeneration/dynarrays.cpp +++ b/src/scripting/codegeneration/dynarrays.cpp @@ -37,9 +37,7 @@ ** */ -#define private public // this file needs public access to TArray's private 'Count' field so just hack the visibility qualifiers here #include "tarray.h" -#undef private #include "dobject.h" #include "thingdef.h" // We need one specific type for each of the 7 integral VM types and instantiate the needed functions for each of them. @@ -775,10 +773,10 @@ DEFINE_ACTION_FUNCTION(FDynArray_String, Clear) return 0; } -DEFINE_FIELD_NAMED(FDynArray_I8, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_I16, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_I32, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_F32, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_F64, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_Ptr, Count, Size) // clashes with type 'Inventory'. -DEFINE_FIELD_NAMED(FDynArray_String, Count, Size) // clashes with type 'Inventory'. +DEFINE_FIELD_NAMED_X(DynArray_I8, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_I16, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_I32, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_F32, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_F64, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_Ptr, FArray, Count, Size) +DEFINE_FIELD_NAMED_X(DynArray_String, FArray, Count, Size) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f57509d81..407fd6307 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -50,6 +50,8 @@ #include "zstring.h" #include "d_event.h" #include "g_levellocals.h" +#include "vm.h" +#include "p_checkposition.h" static TArray properties; static TArray AFTable; @@ -856,6 +858,14 @@ void InitThingdef() qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } + // Add the constructor and destructor to FCheckPosition. + auto fcp = NewStruct("FCheckPosition", nullptr); + fcp->mConstructor = *FindFunction(fcp, "_Constructor")->VMPointer; + fcp->mDestructor = *FindFunction(fcp, "_Destructor")->VMPointer; + fcp->Size = sizeof(FCheckPosition); + fcp->Align = alignof(FCheckPosition); + + FieldTable.Clear(); if (FieldTable.Size() == 0) { diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 2e98e865e..1035c2f8e 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1116,9 +1116,9 @@ struct AFuncDesc MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##icls##_##name; #define DEFINE_FIELD_NAMED_X(cls, icls, name, scriptname) \ - static const FieldDesc VMField_##icls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ - extern FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr; \ - MSVC_FSEG FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##icls##_##scriptname; + static const FieldDesc VMField_##cls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; #define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \ diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index da099256e..b7746f1ce 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -5,6 +5,7 @@ class VMFunctionBuilder; class FxExpression; +class FxLocalVariableDeclaration; struct ExpEmit { @@ -92,6 +93,7 @@ public: // keep the frame pointer, if needed, in a register because the LFP opcode is hideously inefficient, requiring more than 20 instructions on x64. ExpEmit FramePointer; + TArray ConstructedStructs; private: struct AddrKonst diff --git a/src/tarray.h b/src/tarray.h index fc9a62587..fe0d8c1e2 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -71,8 +71,8 @@ protected: struct FArray { void *Array; - unsigned int Most; unsigned int Count; + unsigned int Most; }; // T is the type stored in the array. diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index b71b8126a..00720ce79 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1,3 +1,37 @@ +struct FCheckPosition +{ +/* + + // in + native Actor thing; + native Vector3 pos; + + // out + native sector sector; + native double floorz; + native double ceilingz; + native double dropoffz; + nativeTextureID floorpic; + native int floorterrain; + native sector floorsector; + native TextureID ceilingpic; + native sector ceilingsector; + native bool touchmidtex; + native bool abovemidtex; + native bool floatok; + native bool FromPMove; + native line ceilingline; + native AActor stepthing; + native bool DoRipping; + native bool portalstep; + + native int PushTime; +*/ + + native void ClearLastRipped(); +} + + class Actor : Thinker native { const DEFAULT_HEALTH = 1000; From ea163f389863cd905eb47a4426961abc32f22d76 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 12 Jan 2017 00:26:16 +0100 Subject: [PATCH 3/4] - exported FCheckPosition to the VM and completed the parameter lists for Actor.CheckPosition and Actor.TryMove. --- src/p_local.h | 2 +- src/p_map.cpp | 47 ++++++++++++++++++++++++++++++--- wadsrc/static/zscript/actor.txt | 17 +++++------- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 6bb65ad97..8ebdf9fae 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -261,7 +261,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo AActor *P_CheckOnmobj (AActor *thing); void P_FakeZMovement (AActor *mo); bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); -bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor = NULL); +bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor = NULL, bool missilecheck = false); bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags = 0); void P_ApplyTorque(AActor *mo); diff --git a/src/p_map.cpp b/src/p_map.cpp index a3427d486..4e873c99a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -106,6 +106,27 @@ DEFINE_ACTION_FUNCTION(_FCheckPosition, ClearLastRipped) return 0; } +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos); +DEFINE_FIELD_NAMED_X(FCheckPosition, FCheckPosition, sector, cursector); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorz); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingz); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, dropoffz); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorpic); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorterrain); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floorsector); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingpic); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingsector); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, touchmidtex); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, abovemidtex); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, floatok); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, FromPMove); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingline); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, stepthing); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, DoRipping); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, portalstep); +DEFINE_FIELD_X(FCheckPosition, FCheckPosition, PushTime); + //========================================================================== // // CanCollideWith @@ -1867,9 +1888,18 @@ DEFINE_ACTION_FUNCTION(AActor, CheckPosition) PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_BOOL_DEF(actorsonly); - ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly)); + PARAM_POINTER_DEF(tm, FCheckPosition); + if (tm) + { + ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), *tm, actorsonly)); + } + else + { + ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly)); + } } + //---------------------------------------------------------------------------- // // FUNC P_TestMobjLocation @@ -2659,10 +2689,10 @@ pushline: bool P_TryMove(AActor *thing, const DVector2 &pos, int dropoff, // killough 3/15/98: allow dropoff as option - const secplane_t *onfloor) // [RH] Let P_TryMove keep the thing on the floor + const secplane_t *onfloor, bool missilecheck) // [RH] Let P_TryMove keep the thing on the floor { FCheckPosition tm; - return P_TryMove(thing, pos, dropoff, onfloor, tm); + return P_TryMove(thing, pos, dropoff, onfloor, tm, missilecheck); } DEFINE_ACTION_FUNCTION(AActor, TryMove) @@ -2671,7 +2701,16 @@ DEFINE_ACTION_FUNCTION(AActor, TryMove) PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_INT(dropoff); - ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff)); + PARAM_BOOL_DEF(missilecheck); + PARAM_POINTER_DEF(tm, FCheckPosition); + if (tm == nullptr) + { + ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff, nullptr, missilecheck)); + } + else + { + ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff, nullptr, *tm, missilecheck)); + } } diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 00720ce79..dc058aaf9 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1,32 +1,29 @@ struct FCheckPosition { -/* - // in native Actor thing; native Vector3 pos; // out - native sector sector; + native Sector cursector; native double floorz; native double ceilingz; native double dropoffz; - nativeTextureID floorpic; + native TextureID floorpic; native int floorterrain; - native sector floorsector; + native Sector floorsector; native TextureID ceilingpic; - native sector ceilingsector; + native Sector ceilingsector; native bool touchmidtex; native bool abovemidtex; native bool floatok; native bool FromPMove; native line ceilingline; - native AActor stepthing; + native Actor stepthing; native bool DoRipping; native bool portalstep; native int PushTime; -*/ native void ClearLastRipped(); } @@ -361,7 +358,7 @@ class Actor : Thinker native native double BulletSlope(out FTranslatedLineTarget pLineTarget = null, int aimflags = 0); native Actor AimTarget(); native bool CheckMissileSpawn(double maxdist); - native bool CheckPosition(Vector2 pos, bool actorsonly = false); + native bool CheckPosition(Vector2 pos, bool actorsonly = false, FCheckPosition tm = null); native bool TestMobjLocation(); native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); native Actor SpawnMissile(Actor dest, class type, Actor owner = null); @@ -422,7 +419,7 @@ class Actor : Thinker native return true; } - native bool TryMove(vector2 newpos, int dropoff); + native bool TryMove(vector2 newpos, int dropoff, bool missilecheck = false, FCheckPosition tm = null); native void NewChaseDir(); native void RandomChaseDir(); native bool CheckMissileRange(); From 85488f2f30a34c658177c8f29c825c1a9de743f8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 12 Jan 2017 00:49:40 +0100 Subject: [PATCH 4/4] - added GetActorFloorTexture and GetActorFloorTerrain ACS functions. --- src/p_acs.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f1a0ae8bf..15bb8d0b4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4408,6 +4408,8 @@ enum EACSFunctions ACSF_DamageActor, // [arookas] ACSF_SetActorFlag, ACSF_SetTranslation, + ACSF_GetActorFloorTexture, + ACSF_GetActorFloorTerrain, // OpenGL stuff @@ -6100,6 +6102,35 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) break; } + case ACSF_GetActorFloorTexture: + { + auto a = SingleActorFromTID(args[0], activator); + if (a != nullptr) + { + return GlobalACSStrings.AddString(TexMan[a->floorpic]->Name); + } + else + { + return GlobalACSStrings.AddString(""); + } + break; + } + + case ACSF_GetActorFloorTerrain: + { + auto a = SingleActorFromTID(args[0], activator); + if (a != nullptr) + { + return GlobalACSStrings.AddString(Terrains[a->floorterrain].Name); + } + else + { + return GlobalACSStrings.AddString(""); + } + break; + } + + default: break;