From 8c465df44e49204c393f36107175d4e5cf3e57de Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 1 Aug 2012 03:12:43 +0000 Subject: [PATCH] - Added ACS function IsTIDUsed(tid): It returns whether any actors using the given TID exist. This is more efficient than ThingCount(tid, T_NONE), because it only needs to check for one actor with the TID and not all of them. It also makes no distinction between dead things and live things like ThingCount does. - Added ACS function UniqueTID(tid, limit): It returns a new TID that is not currently used by any actors. It has two modes of operation. If tid is non-zero, then it checks TIDs one-by-one starting at the given tid until if finds a free one. If tid is zero, then it returns a completely random TID. If limit is non-zero, then it will only check that many times for a free TID, so it might not find a free one. If no free TID is found, 0 is returned. If limit is zero, then the search is effectively unlimited. SVN r3798 (trunk) --- src/actor.h | 4 +++ src/p_acs.cpp | 10 ++++++ src/p_mobj.cpp | 93 +++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 103 insertions(+), 4 deletions(-) diff --git a/src/actor.h b/src/actor.h index 13ddf91fa..a0fd4578e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -976,6 +976,7 @@ private: static FSharedStringArena mStringPropertyData; friend class FActorIterator; + friend bool P_IsTIDUsed(int tid); sector_t *LinkToWorldForMapThing (); @@ -1070,6 +1071,9 @@ public: } }; +bool P_IsTIDUsed(int tid); +int P_FindUniqueTID(int start_tid, int limit); + inline AActor *Spawn (const PClass *type, fixed_t x, fixed_t y, fixed_t z, replace_t allowreplacement) { return AActor::StaticSpawn (type, x, y, z, allowreplacement); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 8ab158d48..fe2001411 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3363,6 +3363,8 @@ enum EACSFunctions ACSF_ACS_NamedLockedExecuteDoor, ACSF_ACS_NamedExecuteWithResult, ACSF_ACS_NamedExecuteAlways, + ACSF_UniqueTID, + ACSF_IsTIDUsed, // ZDaemon ACSF_GetTeamScore = 19620, @@ -3879,6 +3881,14 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } break; + case ACSF_UniqueTID: + return P_FindUniqueTID(argCount > 0 ? args[0] : 0, argCount > 1 ? args[1] : 0); + break; + + case ACSF_IsTIDUsed: + return P_IsTIDUsed(args[0]); + break; + default: break; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 666cb2612..938c976f3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -37,6 +37,7 @@ #include "doomstat.h" #include "v_video.h" #include "c_cvars.h" +#include "c_dispatch.h" #include "b_bot.h" //Added by MC: #include "stats.h" #include "a_hexenglobal.h" @@ -107,6 +108,7 @@ static FRandom pr_missiledamage ("MissileDamage"); FRandom pr_slam ("SkullSlam"); static FRandom pr_multiclasschoice ("MultiClassChoice"); static FRandom pr_rockettrail("RocketTrail"); +static FRandom pr_uniquetid("UniqueTID"); // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -2612,10 +2614,7 @@ AActor *AActor::TIDHash[128]; void AActor::ClearTIDHashes () { - int i; - - for (i = 0; i < 128; i++) - TIDHash[i] = NULL; + memset(TIDHash, NULL, sizeof(TIDHash)); } // @@ -2666,6 +2665,92 @@ void AActor::RemoveFromHash () tid = 0; } +//========================================================================== +// +// P_IsTIDUsed +// +// Returns true if there is at least one actor with the specified TID +// (dead or alive). +// +//========================================================================== + +bool P_IsTIDUsed(int tid) +{ + AActor *probe = AActor::TIDHash[tid & 127]; + while (probe != NULL) + { + if (probe->tid == tid) + { + return true; + } + probe = probe->inext; + } + return false; +} + +//========================================================================== +// +// P_FindUniqueTID +// +// Returns an unused TID. If start_tid is 0, then a random TID will be +// chosen. Otherwise, it will perform a linear search starting from +// start_tid. If limit is non-0, then it will not check more than +// number of TIDs. Returns 0 if no suitable TID was found. +// +//========================================================================== + +int P_FindUniqueTID(int start_tid, int limit) +{ + int tid; + + if (start_tid != 0) + { // Do a linear search. + limit = start_tid + limit - 1; + if (limit < start_tid) + { // If it overflowed, clamp to INT_MAX + limit = INT_MAX; + } + for (tid = start_tid; tid <= limit; ++tid) + { + if (tid != 0 && !P_IsTIDUsed(tid)) + { + return tid; + } + } + // Nothing free found. + return 0; + } + // Do a random search. To try and be a bit more performant, this + // actually does several linear searches. In the case of *very* + // dense TID usage, this could potentially perform worse than doing + // a complete linear scan starting at 1. However, you would need + // to use an absolutely ridiculous number of actors before this + // becomes a real concern. + if (limit == 0) + { + limit = INT_MAX; + } + for (int i = 0; i < limit; i += 5) + { + // Use a positive starting TID. + tid = pr_uniquetid.GenRand32() & INT_MAX; + tid = P_FindUniqueTID(tid == 0 ? 1 : tid, 5); + if (tid != 0) + { + return tid; + } + } + // Nothing free found. + return 0; +} + +CCMD(utid) +{ + Printf("%d\n", + P_FindUniqueTID(argv.argc() > 1 ? atoi(argv[1]) : 0, + argv.argc() > 2 ? atoi(argv[2]) : 0)); +} + //========================================================================== // // AActor :: GetMissileDamage