mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-07 08:21:04 +00:00
added CheckProximity to ACS
This commit is contained in:
parent
334962da2c
commit
6633e41cca
4 changed files with 152 additions and 131 deletions
|
@ -4464,7 +4464,8 @@ enum EACSFunctions
|
||||||
ACSF_SetSectorTerrain,
|
ACSF_SetSectorTerrain,
|
||||||
ACSF_SpawnParticle,
|
ACSF_SpawnParticle,
|
||||||
ACSF_SetMusicVolume,
|
ACSF_SetMusicVolume,
|
||||||
// 2 more left...
|
ACSF_CheckProximity,
|
||||||
|
// 1 more left...
|
||||||
|
|
||||||
/* Zandronum's - these must be skipped when we reach 99!
|
/* Zandronum's - these must be skipped when we reach 99!
|
||||||
-100:ResetMap(0),
|
-100:ResetMap(0),
|
||||||
|
@ -6063,7 +6064,19 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
||||||
case ACSF_SetMusicVolume:
|
case ACSF_SetMusicVolume:
|
||||||
I_SetMusicVolume(ACSToFloat(args[0]));
|
I_SetMusicVolume(ACSToFloat(args[0]));
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
#include "vectors.h"
|
#include "vectors.h"
|
||||||
|
#include "dobject.h"
|
||||||
|
|
||||||
const double NO_VALUE = FLT_MAX;
|
const double NO_VALUE = FLT_MAX;
|
||||||
|
|
||||||
|
@ -160,6 +161,24 @@ bool P_Thing_CanRaise(AActor *thing);
|
||||||
PClassActor *P_GetSpawnableType(int spawnnum);
|
PClassActor *P_GetSpawnableType(int spawnnum);
|
||||||
void InitSpawnablesFromMapinfo();
|
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);
|
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
|
enum WARPF
|
||||||
{
|
{
|
||||||
|
|
117
src/p_things.cpp
117
src/p_things.cpp
|
@ -50,6 +50,7 @@
|
||||||
#include "r_utility.h"
|
#include "r_utility.h"
|
||||||
#include "p_spec.h"
|
#include "p_spec.h"
|
||||||
#include "math/cmath.h"
|
#include "math/cmath.h"
|
||||||
|
#include "actorptrselect.h"
|
||||||
|
|
||||||
// Set of spawnable things for the Thing_Spawn and Thing_Projectile specials.
|
// Set of spawnable things for the Thing_Spawn and Thing_Projectile specials.
|
||||||
FClassMap SpawnableThings;
|
FClassMap SpawnableThings;
|
||||||
|
@ -666,6 +667,122 @@ void InitSpawnablesFromMapinfo()
|
||||||
InitClassMap(StrifeTypes, ConversationIDsFromMapinfo);
|
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<AActor> 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)
|
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6605,22 +6605,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold)
|
||||||
// Checks to see if a certain actor class is close to the
|
// Checks to see if a certain actor class is close to the
|
||||||
// actor/pointer within distance, in numbers.
|
// 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)
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity)
|
||||||
{
|
{
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
@ -6638,120 +6622,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity)
|
||||||
ACTION_RETURN_STATE(NULL);
|
ACTION_RETURN_STATE(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AActor *ref = COPY_AAPTR(self, ptr);
|
|
||||||
|
|
||||||
// We need these to check out.
|
if (P_Thing_CheckProximity(self, classname, distance, count, flags, ptr) && jump)
|
||||||
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<AActor> 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)
|
|
||||||
{
|
{
|
||||||
ACTION_RETURN_STATE(jump);
|
ACTION_RETURN_STATE(jump);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue