Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jensewe opened this issue Oct 25, 2022 · 4 comments
Open

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

jensewe opened this issue Oct 25, 2022 · 4 comments
Labels
Suggestion Suggested change for the Github.

Comments

@jensewe
Copy link
Contributor

jensewe commented Oct 25, 2022

#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;
}
}
}
}

@A1mDev
Copy link
Contributor

A1mDev commented Oct 30, 2022

DOOR_RANGE_TOLLERANCE? Something is confusing me with this code.

@jensewe
Copy link
Contributor Author

jensewe commented Oct 30, 2022

DOOR_RANGE_TOLLERANCE? Something is confusing me with this code.

Stolen from Silvers' left4dhooks, looks reliable. Not really matters or instead convert into flow percent like this: https://developer.valvesoftware.com/wiki/L4D2_Vscript_Helpers

@ProjectSky
Copy link
Contributor

some maps like blood harvest & the passing finale have spawn attributes inside a finale marked area

@A1mDev
Copy link
Contributor

A1mDev commented Nov 7, 2022

For players it would be more correct to use GetLastKnowArea.

@SirPlease SirPlease added the Suggestion Suggested change for the Github. label Jun 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Suggestion Suggested change for the Github.
Projects
None yet
Development

No branches or pull requests

4 participants