Skip to content

[SUG] Detect saferooms with Nav methods instead of manual info #553

@jensewe

Description

@jensewe
#define DOOR_RANGE_TOLLERANCE 2000.0

bool IsEntityInSaferoom(int entity, bool bStartSaferoom)
{
	float vecPos[3];
	GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", vecPos);
	
	Address nav = L4D_GetNearestNavArea(vecPos);
	if (nav != Address_Null)
	{
		int spawnAttributes = L4D_GetNavArea_SpawnAttributes(nav);
		if (spawnAttributes & NAV_SPAWN_CHECKPOINT)
		{
			return bStartSaferoom != L4D2Direct_GetTerrorNavAreaFlow(nav) > DOOR_RANGE_TOLLERANCE;
		}
	}
	
	return false;
}

Latest Left 4 DHooks introduces more nav stuff and spawn attributes become available, pretty clean in use.
Pratically this was used in one of my plugin l4d2_spit_spread_patch and worked without issues.

Related plugin sources:

public IsEntityInStartSaferoom(entity)
{
if ( !IsValidEntity(entity) || GetEntSendPropOffs(entity, "m_vecOrigin", true) == -1 ) { return false; }
// get entity location
new Float: location[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", location);
return IsPointInStartSaferoom(location);
}
public IsEntityInEndSaferoom(entity)
{
if ( !IsValidEntity(entity) || GetEntSendPropOffs(entity, "m_vecOrigin", true) == -1 ) { return false; }
// get entity location
new Float: location[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", location);
return IsPointInEndSaferoom(location);
}
public IsPlayerInStartSaferoom(client)
{
if (client < 1 || client > MaxClients || !IsClientInGame(client)) { return false; }
// get client location
new Float: locationA[3];
new Float: locationB[3];
// try both abs & eye
GetClientAbsOrigin(client, locationA);
GetClientEyePosition(client, locationB);
return bool: (IsPointInStartSaferoom(locationA) || IsPointInStartSaferoom(locationB));
}
public IsPlayerInEndSaferoom(client)
{
if (client < 1 || client > MaxClients || !IsClientInGame(client)) { return false; }
// get client location
new Float: locationA[3];
new Float: locationB[3];
// try both abs & eye
GetClientAbsOrigin(client, locationA);
GetClientEyePosition(client, locationB);
return bool: (IsPointInEndSaferoom(locationA) || IsPointInEndSaferoom(locationB));
}
IsPointInStartSaferoom(Float:location[3], entity=-1)
{
if (g_iMode == DETMODE_EXACT)
{
if (!g_bHasStart) { return false; }
new bool: inSaferoom = false;
// rotate point if necessary
if (g_fStartRotate)
{
RotatePoint(g_fStartLocA, location[0], location[1], g_fStartRotate);
}
// check if the point is inside the box (end or start)
new Float: xMin, Float: xMax;
new Float: yMin, Float: yMax;
new Float: zMin, Float: zMax;
if (g_fStartLocA[0] < g_fStartLocB[0]) { xMin = g_fStartLocA[0]; xMax = g_fStartLocB[0]; } else { xMin = g_fStartLocB[0]; xMax = g_fStartLocA[0]; }
if (g_fStartLocA[1] < g_fStartLocB[1]) { yMin = g_fStartLocA[1]; yMax = g_fStartLocB[1]; } else { yMin = g_fStartLocB[1]; yMax = g_fStartLocA[1]; }
if (g_fStartLocA[2] < g_fStartLocB[2]) { zMin = g_fStartLocA[2]; zMax = g_fStartLocB[2]; } else { zMin = g_fStartLocB[2]; zMax = g_fStartLocA[2]; }
PrintDebug("dimensions checked: %f - %f (%f) -- %f - %f (%f) -- %f - %f (%f)", xMin, xMax, location[0], yMin, yMax, location[1], zMin, zMax, location[2]);
inSaferoom = bool: ( location[0] >= xMin && location[0] <= xMax
&& location[1] >= yMin && location[1] <= yMax
&& location[2] >= zMin && location[2] <= zMax );
// two-part saferooms:
if (!inSaferoom && g_bHasStartExtra)
{
if (g_fStartLocC[0] < g_fStartLocD[0]) { xMin = g_fStartLocC[0]; xMax = g_fStartLocD[0]; } else { xMin = g_fStartLocD[0]; xMax = g_fStartLocC[0]; }
if (g_fStartLocC[1] < g_fStartLocD[1]) { yMin = g_fStartLocC[1]; yMax = g_fStartLocD[1]; } else { yMin = g_fStartLocD[1]; yMax = g_fStartLocC[1]; }
if (g_fStartLocC[2] < g_fStartLocD[2]) { zMin = g_fStartLocC[2]; zMax = g_fStartLocD[2]; } else { zMin = g_fStartLocD[2]; zMax = g_fStartLocC[2]; }
PrintDebug("extra dimensions checked: %f - %f (%f) -- %f - %f (%f) -- %f - %f (%f)", xMin, xMax, location[0], yMin, yMax, location[1], zMin, zMax, location[2]);
inSaferoom = bool: ( location[0] >= xMin && location[0] <= xMax
&& location[1] >= yMin && location[1] <= yMax
&& location[2] >= zMin && location[2] <= zMax );
}
return inSaferoom;
}
else if (g_bLGOIsAvailable)
{
// trust confogl / mapinfo
new Float:saferoom_distance = LGO_GetMapValueFloat("start_dist", SR_RADIUS);
new Float:saferoom_distance_extra = LGO_GetMapValueFloat("start_extra_dist", 0.0);
new Float:saferoom[3];
LGO_GetMapValueVector("start_point", saferoom, NULL_VECTOR);
if ( entity != -1 && IsValidEntity(entity) && GetEntSendPropOffs(entity, "m_vecOrigin", true) != -1 )
{
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", location);
}
// distance to entity
return bool: ( GetVectorDistance(location, saferoom) <= ((saferoom_distance_extra > saferoom_distance) ? saferoom_distance_extra : saferoom_distance) );
}
return false;
}
IsPointInEndSaferoom(Float:location[3], entity = -1)
{
if (g_iMode == DETMODE_EXACT)
{
if (!g_bHasEnd) { return false; }
new bool: inSaferoom = false;
// rotate point if necessary
if (g_fEndRotate)
{
RotatePoint(g_fEndLocA, location[0], location[1], g_fEndRotate);
}
// check if the point is inside the box (end or start)
new Float: xMin, Float: xMax;
new Float: yMin, Float: yMax;
new Float: zMin, Float: zMax;
if (g_fEndLocA[0] < g_fEndLocB[0]) { xMin = g_fEndLocA[0]; xMax = g_fEndLocB[0]; } else { xMin = g_fEndLocB[0]; xMax = g_fEndLocA[0]; }
if (g_fEndLocA[1] < g_fEndLocB[1]) { yMin = g_fEndLocA[1]; yMax = g_fEndLocB[1]; } else { yMin = g_fEndLocB[1]; yMax = g_fEndLocA[1]; }
if (g_fEndLocA[2] < g_fEndLocB[2]) { zMin = g_fEndLocA[2]; zMax = g_fEndLocB[2]; } else { zMin = g_fEndLocB[2]; zMax = g_fEndLocA[2]; }
PrintDebug("dimensions checked: %f - %f (%f) -- %f - %f (%f) -- %f - %f (%f)", xMin, xMax, location[0], yMin, yMax, location[1], zMin, zMax, location[2]);
inSaferoom = bool: ( location[0] >= xMin && location[0] <= xMax
&& location[1] >= yMin && location[1] <= yMax
&& location[2] >= zMin && location[2] <= zMax );
// two-part saferooms:
if (!inSaferoom && g_bHasEndExtra)
{
if (g_fEndLocC[0] < g_fEndLocD[0]) { xMin = g_fEndLocC[0]; xMax = g_fEndLocD[0]; } else { xMin = g_fEndLocD[0]; xMax = g_fEndLocC[0]; }
if (g_fEndLocC[1] < g_fEndLocD[1]) { yMin = g_fEndLocC[1]; yMax = g_fEndLocD[1]; } else { yMin = g_fEndLocD[1]; yMax = g_fEndLocC[1]; }
if (g_fEndLocC[2] < g_fEndLocD[2]) { zMin = g_fEndLocC[2]; zMax = g_fEndLocD[2]; } else { zMin = g_fEndLocD[2]; zMax = g_fEndLocC[2]; }
PrintDebug("extra dimensions checked: %f - %f (%f) -- %f - %f (%f) -- %f - %f (%f)", xMin, xMax, location[0], yMin, yMax, location[1], zMin, zMax, location[2]);
inSaferoom = bool: ( location[0] >= xMin && location[0] <= xMax
&& location[1] >= yMin && location[1] <= yMax
&& location[2] >= zMin && location[2] <= zMax );
}
return inSaferoom;
}
else if (g_bLGOIsAvailable)
{
// trust confogl / mapinfo
new Float:saferoom_distance = LGO_GetMapValueFloat("end_dist", SR_RADIUS);
new Float:saferoom[3];
LGO_GetMapValueVector("end_point", saferoom, NULL_VECTOR);
if ( entity != -1 && IsValidEntity(entity) && GetEntSendPropOffs(entity, "m_vecOrigin", true) != -1 )
{
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", location);
}
// distance to entity
return bool: ( GetVectorDistance(location, saferoom) <= saferoom_distance );
}
return false;
}

stock bool IsEntityInSaferoom(int ent, int saferoom = 3) //ItemTracking (commented out)
{
float origins[3];
GetEntPropVector(ent, Prop_Send, "m_vecOrigin", origins);
if ((saferoom & START_SAFEROOM)
&& (GetVectorDistance(origins, Start_Point) <= ((Start_Extra_Dist > Start_Dist) ? Start_Extra_Dist : Start_Dist))
) {
return true;
} else if ((saferoom & END_SAFEROOM) && (GetVectorDistance(origins, End_Point) <= End_Dist)) {
return true;
} else {
return false;
}
// return ((GetVectorDistance(origins, Start_Point) <= ((Start_Extra_Dist > Start_Dist) ? Start_Extra_Dist : Start_Dist))
// || (GetVectorDistance(origins, End_Point) <= End_Dist));
}

/**
* Determines if an entity is in a start or end saferoom (based on mapinfo.txt or automatically generated info)
*
* @param ent The entity to be checked
* @return eSaferoom_Neither if entity is not in any saferoom
* eSaferoom_Start if it is in the starting saferoom
* eSaferoom_End if it is in the ending saferoom
* eSaferoom_Start | eSaferoom_End if it is in both saferooms (probably won't happen)
*/
static int IsEntityInSaferoom(int iEntity)
{
int iResult = eSaferoom_Neither;
float fOrigins[3];
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigins);
if ((GetVectorDistance(fOrigins, g_fStartPoint) <= (g_fStartExtraDist > g_fStartDist ? g_fStartExtraDist : g_fStartDist))) {
iResult |= eSaferoom_Start;
}
if (GetVectorDistance(fOrigins, g_fEndPoint) <= g_fEndDist) {
iResult |= eSaferoom_End;
}
return iResult;
}

float fOrigin[3];
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin);
bool bIsInStartSaferoom = false, bIsInStartSaferoomExtra = false;
bool bIsInEndSaferoom = false, bIsInFinaleArea = false;
float fStartDistance = GetVectorDistance(Weapon_fMapOrigin_Start, fOrigin);
if (fStartDistance <= Weapon_fMapDist_Start) {
bIsInStartSaferoom = true;
bIsInStartSaferoomExtra = true;
} else if (fStartDistance <= Weapon_fMapDist_StartExtra) {
bIsInStartSaferoomExtra = true;
} else if (GetVectorDistance(Weapon_fMapOrigin_End, fOrigin) <= Weapon_fMapDist_End) {
bIsInFinaleArea = (L4D_IsMissionFinalMap());
}

bool bIsInSaferoom = false;
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin);
// Within start safe room
if (!Weapon_bReplaceTier2_All && IsVersus()) {
if (GetVectorDistance(Weapon_fMapOrigin_Start, fOrigin) > Weapon_fMapDist_StartExtra
&& GetVectorDistance(Weapon_fMapOrigin_End, fOrigin) > Weapon_fMapDist_End
) {
#if (DEBUG_WI)
LogMessage("[%s] Weapon is outside of a saferoom", WI_MODULE_NAME);
#endif
if (!bSpawnerEvent) {
#if (DEBUG_WI)
LogMessage("[%s] }", WI_MODULE_NAME);
#endif
return;
}
} else {
#if (DEBUG_WI)
LogMessage("[%s] Weapon is inside a saferoom", WI_MODULE_NAME);
#endif
bIsInSaferoom = true;
}
}

void FindSurvivorStart()
{
int iEntityCount = GetEntityCount();
char EdictClassName[128];
float Location[3];
//Search entities for either a locked saferoom door,
for (int i = 0; i <= iEntityCount; i++) {
if (IsValidEntity(i)) {
GetEdictClassname(i, EdictClassName, sizeof(EdictClassName));
if ((StrContains(EdictClassName, "prop_door_rotating_checkpoint", false) != -1) && (GetEntProp(i, Prop_Send, "m_bLocked")== 1)) {
GetEntPropVector(i, Prop_Send, "m_vecOrigin", Location);
SurvivorStart = Location;
return;
}
}
}
//or a survivor start point.
for (int i = 0; i <= iEntityCount; i++) {
if (IsValidEntity(i)) {
GetEdictClassname(i, EdictClassName, sizeof(EdictClassName));
if (StrContains(EdictClassName, "info_survivor_position", false) != -1) {
GetEntPropVector(i, Prop_Send, "m_vecOrigin", Location);
SurvivorStart = Location;
return;
}
}
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    SuggestionSuggested change for the Github.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions