From 6633e41ccaeb5381c88410297467a400fc1c07ae Mon Sep 17 00:00:00 2001 From: Benjamin Moir Date: Mon, 9 May 2016 16:41:35 +1000 Subject: [PATCH] added CheckProximity to ACS --- src/p_acs.cpp | 17 +++- src/p_local.h | 19 +++++ src/p_things.cpp | 117 +++++++++++++++++++++++++++ src/thingdef/thingdef_codeptr.cpp | 130 +----------------------------- 4 files changed, 152 insertions(+), 131 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 3248e738c..d66d0f8f8 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4464,7 +4464,8 @@ enum EACSFunctions ACSF_SetSectorTerrain, ACSF_SpawnParticle, ACSF_SetMusicVolume, - // 2 more left... + ACSF_CheckProximity, + // 1 more left... /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -6063,7 +6064,19 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) case ACSF_SetMusicVolume: I_SetMusicVolume(ACSToFloat(args[0])); break; - + + case ACSF_CheckProximity: + { + // [zombie] ACS version of A_CheckProximity + actor = SingleActorFromTID(args[0], activator); + PClass *classname = PClass::FindClass(FBehavior::StaticLookupString(args[1])); + double distance = ACSToDouble(args[2]); + int count = argCount >= 4 ? args[3] : 1; + int flags = argCount >= 5 ? args[4] : 0; + int ptr = argCount >= 6 ? args[5] : AAPTR_DEFAULT; + return P_Thing_CheckProximity(actor, classname, distance, count, flags, ptr); + } + default: break; } diff --git a/src/p_local.h b/src/p_local.h index 8e64c3414..f7862d45f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -26,6 +26,7 @@ #include #include "doomtype.h" #include "vectors.h" +#include "dobject.h" const double NO_VALUE = FLT_MAX; @@ -160,6 +161,24 @@ bool P_Thing_CanRaise(AActor *thing); PClassActor *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch); +bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr); + +enum CPXF +{ + CPXF_ANCESTOR = 1 << 0, + CPXF_LESSOREQUAL = 1 << 1, + CPXF_NOZ = 1 << 2, + CPXF_COUNTDEAD = 1 << 3, + CPXF_DEADONLY = 1 << 4, + CPXF_EXACT = 1 << 5, + CPXF_SETTARGET = 1 << 6, + CPXF_SETMASTER = 1 << 7, + CPXF_SETTRACER = 1 << 8, + CPXF_FARTHEST = 1 << 9, + CPXF_CLOSEST = 1 << 10, + CPXF_SETONPTR = 1 << 11, + CPXF_CHECKSIGHT = 1 << 12, +}; enum WARPF { diff --git a/src/p_things.cpp b/src/p_things.cpp index ba1b29a1a..cad3022b0 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -50,6 +50,7 @@ #include "r_utility.h" #include "p_spec.h" #include "math/cmath.h" +#include "actorptrselect.h" // Set of spawnable things for the Thing_Spawn and Thing_Projectile specials. FClassMap SpawnableThings; @@ -666,6 +667,122 @@ void InitSpawnablesFromMapinfo() InitClassMap(StrifeTypes, ConversationIDsFromMapinfo); } +bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr) +{ + AActor *ref = COPY_AAPTR(self, ptr); + + // We need these to check out. + if (!ref || !classname || distance <= 0) + return nullptr; + + int counter = 0; + bool result = false; + double closer = distance, farther = 0, current = distance; + const bool ptrWillChange = !!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER)); + const bool ptrDistPref = !!(flags & (CPXF_CLOSEST | CPXF_FARTHEST)); + + TThinkerIterator it; + AActor *mo, *dist = nullptr; + + // [MC] Process of elimination, I think, will get through this as quickly and + // efficiently as possible. + while ((mo = it.Next())) + { + if (mo == ref) //Don't count self. + continue; + + // no unmorphed versions of currently morphed players. + if (mo->flags & MF_UNMORPHED) + continue; + + // Check inheritance for the classname. Taken partly from CheckClass DECORATE function. + if (flags & CPXF_ANCESTOR) + { + if (!(mo->IsKindOf(classname))) + continue; + } + // Otherwise, just check for the regular class name. + else if (classname != mo->GetClass()) + continue; + + // [MC]Make sure it's in range and respect the desire for Z or not. The function forces it to use + // Z later for ensuring CLOSEST and FARTHEST flags are respected perfectly. + // Ripped from sphere checking in A_RadiusGive (along with a number of things). + if ((ref->Distance2D(mo) < distance && + ((flags & CPXF_NOZ) || + ((ref->Z() > mo->Z() && ref->Z() - mo->Top() < distance) || + (ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance))))) + { + if ((flags & CPXF_CHECKSIGHT) && !(P_CheckSight(mo, ref, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))) + continue; + + if (ptrWillChange) + { + current = ref->Distance2D(mo); + + if ((flags & CPXF_CLOSEST) && (current < closer)) + { + dist = mo; + closer = current; // This actor's closer. Set the new standard. + } + else if ((flags & CPXF_FARTHEST) && (current > farther)) + { + dist = mo; + farther = current; + } + else if (!dist) + dist = mo; // Just get the first one and call it quits if there's nothing selected. + } + if (mo->flags6 & MF6_KILLED) + { + if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY))) + continue; + counter++; + } + else + { + if (flags & CPXF_DEADONLY) + continue; + counter++; + } + + // Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal. + if (counter > count) + { + result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true; + + // However, if we have one SET* flag and either the closest or farthest flags, keep the function going. + if (ptrWillChange && ptrDistPref) + continue; + else + break; + } + } + } + + if (ptrWillChange && dist != 0) + { + if (flags & CPXF_SETONPTR) + { + if (flags & CPXF_SETTARGET) ref->target = dist; + if (flags & CPXF_SETMASTER) ref->master = dist; + if (flags & CPXF_SETTRACER) ref->tracer = dist; + } + else + { + if (flags & CPXF_SETTARGET) self->target = dist; + if (flags & CPXF_SETMASTER) self->master = dist; + if (flags & CPXF_SETTRACER) self->tracer = dist; + } + } + + if (counter == count) + result = true; + else if (counter < count) + result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)); + + return result; +} int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch) { diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 86de07b5d..92514bff1 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -6605,22 +6605,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold) // Checks to see if a certain actor class is close to the // actor/pointer within distance, in numbers. //========================================================================== -enum CPXFflags -{ - CPXF_ANCESTOR = 1 << 0, - CPXF_LESSOREQUAL = 1 << 1, - CPXF_NOZ = 1 << 2, - CPXF_COUNTDEAD = 1 << 3, - CPXF_DEADONLY = 1 << 4, - CPXF_EXACT = 1 << 5, - CPXF_SETTARGET = 1 << 6, - CPXF_SETMASTER = 1 << 7, - CPXF_SETTRACER = 1 << 8, - CPXF_FARTHEST = 1 << 9, - CPXF_CLOSEST = 1 << 10, - CPXF_SETONPTR = 1 << 11, - CPXF_CHECKSIGHT = 1 << 12, -}; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) { PARAM_SELF_PROLOGUE(AActor); @@ -6638,120 +6622,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) 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; - double closer = distance, farther = 0, current = distance; - const bool ptrWillChange = !!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER)); - const bool ptrDistPref = !!(flags & (CPXF_CLOSEST | CPXF_FARTHEST)); - - TThinkerIterator it; - AActor *mo, *dist = NULL; - - //[MC] Process of elimination, I think, will get through this as quickly and - //efficiently as possible. - while ((mo = it.Next())) - { - if (mo == ref) //Don't count self. - continue; - - // no unmorphed versions of currently morphed players. - if (mo->flags & MF_UNMORPHED) - continue; - - //Check inheritance for the classname. Taken partly from CheckClass DECORATE function. - if (flags & CPXF_ANCESTOR) - { - if (!(mo->IsKindOf(classname))) - continue; - } - //Otherwise, just check for the regular class name. - else if (classname != mo->GetClass()) - continue; - - //[MC]Make sure it's in range and respect the desire for Z or not. The function forces it to use - //Z later for ensuring CLOSEST and FARTHEST flags are respected perfectly. - //Ripped from sphere checking in A_RadiusGive (along with a number of things). - if ((ref->Distance2D(mo) < distance && - ((flags & CPXF_NOZ) || - ((ref->Z() > mo->Z() && ref->Z() - mo->Top() < distance) || - (ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance))))) - { - if ((flags & CPXF_CHECKSIGHT) && !(P_CheckSight(mo, ref, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))) - continue; - - if (ptrWillChange) - { - current = ref->Distance2D(mo); - - if ((flags & CPXF_CLOSEST) && (current < closer)) - { - dist = mo; - closer = current; //This actor's closer. Set the new standard. - } - else if ((flags & CPXF_FARTHEST) && (current > farther)) - { - dist = mo; - farther = current; - } - else if (!dist) - dist = mo; //Just get the first one and call it quits if there's nothing selected. - } - if (mo->flags6 & MF6_KILLED) - { - if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY))) - continue; - counter++; - } - else - { - if (flags & CPXF_DEADONLY) - continue; - counter++; - } - - //Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal. - if (counter > count) - { - result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true; - - //However, if we have one SET* flag and either the closest or farthest flags, keep the function going. - if (ptrWillChange && ptrDistPref) - continue; - else - break; - } - } - } - - if (ptrWillChange && dist != NULL) - { - if (flags & CPXF_SETONPTR) - { - if (flags & CPXF_SETTARGET) ref->target = dist; - if (flags & CPXF_SETMASTER) ref->master = dist; - if (flags & CPXF_SETTRACER) ref->tracer = dist; - } - else - { - if (flags & CPXF_SETTARGET) self->target = dist; - if (flags & CPXF_SETMASTER) self->master = dist; - if (flags & CPXF_SETTRACER) self->tracer = dist; - } - } - - if (counter == count) - result = true; - else if (counter < count) - result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)); - - if (result && jump) + if (P_Thing_CheckProximity(self, classname, distance, count, flags, ptr) && jump) { ACTION_RETURN_STATE(jump); }