diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 89299e0fa..5dac7adbe 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5908,6 +5908,14 @@ enum CPXFflags 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_NODISTANCE = 1 << 12, + CPXF_CHECKSIGHT = 1 << 13, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) { @@ -5920,17 +5928,28 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) ACTION_PARAM_INT(ptr, 5); ACTION_SET_RESULT(false); //No inventory chain results please. + + if (!jump) + { + if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) + return; + } AActor *ref = COPY_AAPTR(self, ptr); //We need these to check out. - if (!ref || !jump || !classname || distance <= 0) + if (!ref || !classname || ((distance <= 0) && !(flags & CPXF_NODISTANCE))) return; int counter = 0; bool result = false; + const double distsquared = (double)distance * (double)distance; + double closer, farther = 0, current = closer = distsquared; + const bool ptrWillChange = !!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER)); + const bool ptrDistPref = !!(flags & (CPXF_CLOSEST | CPXF_FARTHEST)); + TThinkerIterator it; - AActor * mo; + AActor *mo, *dist = NULL; //[MC] Process of elimination, I think, will get through this as quickly and //efficiently as possible. @@ -5949,12 +5968,37 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) else if (classname != mo->GetClass()) continue; - //Make sure it's in range and respect the desire for Z or not. - if (P_AproxDistance(ref->x - mo->x, ref->y - mo->y) < distance && - ((flags & CPXF_NOZ) || - ((ref->z > mo->z && ref->z - (mo->z + mo->height) < distance) || - (ref->z <= mo->z && mo->z - (ref->z + ref->height) < distance)))) + //[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). + + TVector3 spos(ref->x, ref->y, ((flags & CPXF_NOZ) ? 0 : (ref->z + ref->height / 2))); + TVector3 tpos(mo->x, mo->y, ((flags & CPXF_NOZ) ? 0 : (mo->z + mo->height / 2))); + if ((flags & CPXF_NODISTANCE) || (tpos - spos).LengthSquared() <= distsquared) { + if ((flags & CPXF_CHECKSIGHT) && !(P_CheckSight(mo, ref, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))) + continue; + + if (ptrWillChange && ptrDistPref) + { + spos.Z = ref->z + ref->height / 2; //This one cannot have NOZ checking. + tpos.Z = mo->z + mo->height / 2; + current = (tpos - spos).LengthSquared(); + + if ((flags & CPXF_CLOSEST) && ((current < closer) || !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 last one and call it quits if there's nothing selected. + } + if (mo->flags6 & MF6_KILLED) { if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY))) @@ -5972,17 +6016,38 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) if (counter > count) { result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true; - break; + + //However, if we have one SET* flag and either the closest or farthest flags, keep the funcion 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 (!jump) return; if (result) { diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 213e2109d..835e73dbf 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -497,6 +497,14 @@ enum 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_NODISTANCE = 1 << 12, + CPXF_CHECKSIGHT = 1 << 13, }; // Flags for A_CheckBlock