← Home SEEBIE90 DOCS
The GTG Safe Zone mod is published under the Arma Public License (APL)Example code is free to useSuggestions: Discord to the author

GTG Safe Zone

Place and faction

If the position alone decides, the zone is a free pass for exactly the side it is meant to keep out. The alarm would go off, the defenders could answer – and the intruder could not be hit.

In plain wordsProtection depends on two things: where you are and whose side you are on. An enemy standing in the middle of the zone is still killable.

Who is an enemy

The zone has an owner: one or several factions. Whoever is not friendly towards the owner and is hostile to it counts as an enemy. Three outcomes, not two: the same faction or a friendly one is protected, a hostile one is an enemy, and everything in between – neutral – is neither.

Example code – free to use
protected bool IsEnemy(notnull IEntity entity)
{
	FactionAffiliationComponent affiliation = FactionAffiliationComponent.Cast(entity.FindComponent(FactionAffiliationComponent));
	if (!affiliation)
		return false;

	Faction entityFaction = affiliation.GetAffiliatedFaction();
	if (!entityFaction)
		return false;

	FactionManager factionManager = GetGame().GetFactionManager();
	if (!factionManager)
		return false;

	foreach (FactionKey key : m_aOwnerKeys)
	{
		Faction owner = factionManager.GetFactionByKey(key);
		if (!owner)
			continue;

		if (owner == entityFaction || owner.IsFactionFriendly(entityFaction))
			return false;			// one friendly owner is enough: protected

		if (owner.IsFactionEnemy(entityFaction))
			return true;
	}

	return false;					// neutral: neither
}

Protected means inside, and not an enemy, and not forfeited

One function answers the question the damage guard asks. Place first, then faction, then the state described on Shooting from inside. Each step can only take protection away.

Example code – free to use
static MyAD_Zone FindShieldingZoneOf(IEntity entity)
{
	MyAD_Zone zone = FindProtectingZoneOf(entity);		// place
	if (!zone)
		return null;

	if (zone.IsEnemy(entity))							// faction
		return null;

	if (MyAD_Forfeit.HasForfeited(entity))				// behaviour
		return null;

	return zone;
}

static MyAD_Zone FindProtectingZoneOf(IEntity entity)
{
	if (!entity)
		return null;

	return FindProtectingZone(WorldPos(entity));		// the entity's world position - not GetOrigin()
}
PitfallAsk with the entity and its world position, never with GetOrigin(). A player who sits in a vehicle is a child of that vehicle, and GetOrigin() is then relative to it. The occupants would be tested at coordinates near the world origin – inside the zone, or far outside it, by accident.

The owner can follow the base

On a server where bases change hands, a fixed owner is wrong after the first swap, and the zone would then protect the attackers. So a zone with no fixed owner looks for one: the faction that controls a military base or owns a spawn point inside the zone. When the base changes hands, the zone follows; the lookup is repeated on every scan. The lookup uses a world query around the zone's bounding sphere, and the callback keeps what it finds in a member, because its signature takes no extra parameters.

Example code – free to use
protected FactionKey m_sFound;		// written by the query callback

protected void UpdateOwnerFromBases()
{
	m_sFound = FactionKey.Empty;

	GetGame().GetWorld().QueryEntitiesBySphere(
		m_vBoundsCenter, m_fBoundsRadius, OnOwnerCandidate, null, EQueryEntitiesFlags.ALL);

	m_sOwner = m_sFound;			// empty if nothing was found - see the next box
}

protected bool OnOwnerCandidate(notnull IEntity entity)
{
	if (!IsInside(WorldPos(entity)))
		return true;				// not ours, keep looking

	SCR_MilitaryBaseComponent militaryBase = SCR_MilitaryBaseComponent.Cast(entity.FindComponent(SCR_MilitaryBaseComponent));
	if (militaryBase && militaryBase.GetFaction())
	{
		m_sFound = militaryBase.GetFaction().GetFactionKey();
		return false;				// found one - stop the query
	}

	SCR_SpawnPoint spawn = SCR_SpawnPoint.Cast(entity);
	if (spawn && !spawn.GetFactionKey().IsEmpty())
	{
		m_sFound = spawn.GetFactionKey();
		return false;
	}

	return true;
}
PitfallA zone without an owner has no enemies. The alarm never goes off, and hostile AI standing in the zone is as invulnerable as everyone else. Three different-looking symptoms, one cause. Say so loudly in the log, with the remedy, the moment it happens – and stay quiet for a zone that is neutral on purpose.

A neutral zone, on purpose

For a trading post or a meeting place that should be open to everybody, the owner can be switched off: every faction is protected, nobody counts as an enemy, and there is no alarm. It takes priority over any owner that is also entered.

Example code on this page is free to use in your own projects (credit appreciated). The GTG Safe Zone mod is published under the Arma Public License (APL). Suggestions: Discord. Arma Reforger / Enfusion are trademarks of Bohemia Interactive.
Impressum · Privacy Policy