Factions
Factions control how entities interact with each other. Faction settings independently determine which groups an entity belongs to, which entities it considers hostile, and which entities it can damage.
Faction properties are divided into two systems, each comprised of supporting properties:
- Group factions act on a set of 52 predefined faction group flags.
- Membership - Which factions the entity belongs to.
- Hostility - Which factions the AI and targeting functions consider enemies.
- Damage - Which factions the entity can damage with attacks.
- Indirect Damage - Which factions the entity can damage collaterally (ex. thrown by another entity).
- Type factions use legacy entity types such as
player,enemy, andnpc.- Hostility - Which types the AI ad targeting functions consider enemies.
- Damage - Which types the the entity can damage with attacks.
- Indirect Damage - Which types the entity can damage collaterally (ex. thrown by another entity).
Both systems may be combined for highly specific interaction rules.
Note this means that by design, hostility and damage permissions are separate. An entity may consider another entity hostile without being able to damage it, or damage an entity it does not consider hostile.
Factions properties are script accessible and stored in both entity and model structures - meaning faction data exists at three levels - template, starting default, and current condition. This in turn enables on the fly swapping and restoration. For example, an entity might be affected with mind control by modifying its group flags for a limited time, then restored from its starting defaults when the effect wears off.
Design
OpenBOR's faction API is intentionally designed to function either as a standalone faction system or as a hardware-speed primitive for complex higher-level relationships. Its 52 native factions are obviously more than most projects will ever approach. Even so, creators may instead arrange them as behavioral flags for any number of custom factions. Creator-defined factions may use several flags, share flags with other factions, change their assignments during play, or use no native group at all.
Groups may represent geography, allegiance, species, political status, temporary conditions, or any other distinction useful to the project. The resulting combinations are expressed through four hardware-native masks: membership, hostility, direct damage, and indirect damage.
Each property supports 252 possible group arrangements, not merely a choice among 52 factions. Together, the four faction properties provide approximately 4.11 * 1062 possible configurations. That's roughly 4 * 1038 configurations for every star in the observable universe, using NASA's upper estimate.
Higher-Level Example
Suppose a project tracks Game of Thrones (or A Song of Ice and Fire if you prefer) houses in its own relationship table. For a Stark-aligned entity, the table might resolve the current political state as follows:
| Creator Faction | Current State | Resolved Membership | OpenBOR Membership |
|---|---|---|---|
| House Stark | Northern loyalist | The North, Westeros, Living | A B G |
| House Greyjoy | Allied with the North | The North, Westeros, Living | A B G |
| House Greyjoy | In rebellion | Unaligned with the North | B G |
| House Lannister | Southern loyalist | Westeros, Living | B C G |
| House Lannister | Sworn to the Night's Watch | The North, Westeros, Night's Watch, Living | A B D G |
| Wildlings | Beyond the Wall | Free Folk, Beyond the Wall, Living | E F G |
| Wildlings | Settled in the North | The North, Westeros, Free Folk, Living | A B E G |
| Night King | Leading the Army of the Dead | Beyond the Wall, Army of the Dead | F H |
For a Stark entity hostile toward the Southern Kingdoms and Army of the Dead:
faction_group_member A B G
faction_group_hostile C H
faction_group_damage_direct C H
faction_group_damage_indirect C H
The Lannister southern loyalist matches group C, while the Lannister sworn to the Night's Watch does not. Both remain House Lannister in the creator's system, but their current OpenBOR faction behavior differs.
Group factions
Group factions use named flags. OpenBOR provides 52 normal faction groups:
a b c d e f g h i j k l m
n o p q r s t u v w x y z
a1 b1 c1 d1 e1 f1 g1 h1 i1 j1 k1 l1 m1
n1 o1 p1 q1 r1 s1 t1 u1 v1 w1 x1 y1 z1
Faction names are case-insensitive. For example, a1 and A1 identify the same faction.
An entity may belong to multiple factions and may target multiple factions with each property. For example, an entity belonging to factions a and b1 matches any faction check containing either group. There is no additional CPU or memory cost for number of faction groups in use by an object.
Group values
| Value | Description |
|---|---|
a through z
|
Selects one of the first 26 normal faction groups. |
a1 through z1
|
Selects one of the second 26 normal faction groups. |
all0
|
Selects every normal faction group from a through z.
|
all1
|
Selects every normal faction group from a1 through z1.
|
all
|
Selects every normal faction group. |
neutral
|
Inert faction flag. Hostility and damage checks ignore it. |
no_copy
|
Prevents the affected faction property from copying to child entities, projectiles, weapons, alternate models, and similar derived entities. |
player_verses
|
Ignores applicable level and versus settings when checking hostility or damage between players. |
type_inclusive
|
Includes the corresponding type-faction property. Both the group check and type check must pass. |
type_exclusive
|
Uses only the corresponding type-faction property, overriding the normal group check. |
The player_verses, type_inclusive, and type_exclusive flags have no useful effect in faction_group_member. They control how hostile and damage properties perform their checks.
Member
Defines the faction groups to which the entity belongs.
faction_group_member {factions}
# Default
faction_group_member a
Multiple groups may be supplied:
faction_group_member a c g1 z1
An entity using this example is a member of factions a, c, g1, and z1.
Damage direct
Defines the faction groups the entity can damage with normal attacks.
faction_group_damage_direct {factions}
# Default
faction_group_damage_direct a type_inclusive
| Value | Effect |
|---|---|
a through z
|
Permits direct damage against members of the selected original faction groups. |
a1 through z1
|
Permits direct damage against members of the selected additional faction groups. |
all0
|
Permits direct damage against members of every normal group from A-Z. |
all1
|
Permits direct damage against members of every normal group from A1-Z1. |
all
|
Permits direct damage against members of every normal faction group. |
neutral
|
No effect on damage checks. |
no_copy
|
Prevents this property from copying to derived entities or alternate models. |
player_verses
|
Ignores applicable level and versus restrictions when damaging other players. |
type_inclusive
|
Requires both this group check and faction_type_damage_direct to pass. |
type_exclusive
|
Ignores this group list and uses only faction_type_damage_direct. |
Damage indirect
Defines the faction groups the entity can damage when thrown, blasted, or otherwise used as an indirect attack.
For example, when a player throws an enemy into a group of other enemies, the thrown enemy's indirect damage properties determine which entities it can hit.
faction_group_damage_indirect {factions}
# Default
faction_group_damage_indirect a type_inclusive
| Value | Effect |
|---|---|
a through z
|
Permits indirect damage against members of the selected first 26 faction groups. |
a1 through z1
|
Permits indirect damage against members of the selected second 26 faction groups. |
all0
|
Permits indirect damage against members of every normal group from A-Z. |
all1
|
Permits indirect damage against members of every normal group from A1-Z1. |
all
|
Permits indirect damage against members of every normal faction group. |
neutral
|
No effect on damage checks. |
no_copy
|
Prevents this property from copying to derived entities or alternate models. |
player_verses
|
Ignores applicable level and versus restrictions when damaging other players. |
type_inclusive
|
Requires both this group check and faction_type_damage_indirect to pass. |
type_exclusive
|
Ignores this group list and uses only faction_type_damage_indirect. |
Hostile
faction_group_hostile {factions}
# Default
faction_group_hostile a type_inclusive
Defines the faction groups the entity considers hostile. Hostility generally controls targeting and AI behavior rather than damage permission.
| Value | Effect |
|---|---|
a through z
|
Marks members of the selected first 26 faction groups as hostile. |
a1 through z1
|
Marks members of the selected second 26 faction groups as hostile. |
all0
|
Marks members of every normal faction group from A-Z as hostile. |
all1
|
Marks members of every normal faction group from A1-Z1 as hostile. |
all
|
Marks members of every normal faction group as hostile. |
neutral
|
No effect on hostility checks. |
no_copy
|
Prevents this property from copying to derived entities or alternate models. |
player_verses
|
Ignores applicable level and versus restrictions when checking hostility toward other players. |
type_inclusive
|
Requires both this group check and faction_type_hostile to pass. |
type_exclusive
|
Ignores this group list and uses only faction_type_hostile. |
Type factions
Prior to OpenBOR 4.0, faction behavior relied solely on entity types. Type-faction properties preserve that behavior and may be used alone or combined with group factions.
Type properties target entity types rather than named faction groups. Common type values include:
end_level
enemy
item
none
npc
obstacle
panel
player
projectile
shot
steamer
text_box
trap
Default type-faction values depend on the model's own type. For example, enemy models are normally hostile toward players, while players can normally damage enemies and obstacles.
Group properties must contain type_inclusive or type_exclusive before their corresponding type property affects the interaction check.
Damage direct
faction_type_damage_direct <types>
Default: Varies by model type. See Type.
Defines the entity types this entity can damage with normal attacks.
faction_type_damage_direct enemy npc obstacle
Accepted values include:
- Any valid entity type.
no_copy- Prevents this property from copying to derived entities or alternate models.
Damage indirect
faction_type_damage_indirect <types>
Default: Varies by model type. See Type.
Defines the entity types this entity can damage when thrown, blasted, or otherwise used as an indirect attack.
faction_type_damage_indirect enemy obstacle
Accepted values include:
- Any valid entity type.
no_copy- Prevents this property from copying to derived entities or alternate models.
Hostile
faction_type_hostile <types>
Default: Varies by model type. See Type.
Defines the entity types this entity considers hostile.
faction_type_hostile player npc
Accepted values include:
- Any valid entity type.
no_copy- Prevents this property from copying to derived entities or alternate models.
Interaction modes
The group-property control flags determine how group and type factions work together.
| Group-property configuration | Result |
|---|---|
| No type flag | Uses only the group-faction check. |
type_inclusive
|
Requires both the group-faction check and corresponding type-faction check to pass. |
type_exclusive
|
Uses only the corresponding type-faction check. |
For example:
faction_group_damage_direct c d e type_inclusive
faction_type_damage_direct enemy npc
This entity can directly damage another entity only when both conditions are true:
- The target belongs to faction
c,d, ore. - The target is an
enemyornpctype.
Removing type_inclusive would make the type list irrelevant to the direct-damage check. Replacing it with type_exclusive would make the group list irrelevant.
Setup
Model text
Use the faction commands in a model header to establish its starting faction configuration.
The following model belongs to factions a, b, and a1. It is hostile toward and can directly damage members of factions c, d, e, and z1. When thrown or blasted, it can damage members of its own factions.
faction_group_damage_direct c d e z1
faction_group_damage_indirect a b a1
faction_group_hostile c d e z1
faction_group_member a b a1
The next example adds type_inclusive. Targets must now pass both the group and type checks.
faction_group_damage_direct c d e z1 type_inclusive
faction_group_damage_indirect a b a1 type_inclusive
faction_group_hostile c d e z1 type_inclusive
faction_group_member a b a1
faction_type_damage_direct enemy npc
faction_type_damage_indirect player
faction_type_hostile enemy npc
Level spawn
Faction commands may appear in level spawn entries to override a model's faction settings for that spawn. Syntax is identical to model text.
The following spawn belongs to factions e and e1, while treating factions g, h, and h1 as hostile and directly damageable.
spawn Shermie
coords 350 160
faction_group_damage_direct g h h1
faction_group_damage_indirect e e1
faction_group_hostile g h h1
faction_group_member e e1
at 10
Script access
Faction properties are accessible through get_faction_property() and set_faction_property().
Faction group values are unsigned 64-bit masks. Use the named constants supplied by openborconstant() and combine them with bitwise operators. Raw numeric faction values are implementation details and should not be used.
Get property
Returns a faction property from a faction handle.
mixed value = get_faction_property(
void faction_handle,
int property
);
Set property
Sets a faction property on a faction handle.
set_faction_property(
void faction_handle,
int property,
mixed value
);
Property constants
| Property constant | Value type | Description |
|---|---|---|
FACTION_PROPERTY_GROUP_DAMAGE_DIRECT
|
Unsigned 64-bit integer | Group direct-damage mask. |
FACTION_PROPERTY_GROUP_DAMAGE_INDIRECT
|
Unsigned 64-bit integer | Group indirect-damage mask. |
FACTION_PROPERTY_GROUP_HOSTILE
|
Unsigned 64-bit integer | Group hostility mask. |
FACTION_PROPERTY_GROUP_MEMBER
|
Unsigned 64-bit integer | Group membership mask. |
FACTION_PROPERTY_TYPE_DAMAGE_DIRECT
|
Unsigned 64-bit integer | Type direct-damage mask. Combine applicable TYPE_* constants.
|
FACTION_PROPERTY_TYPE_DAMAGE_INDIRECT
|
Unsigned 64-bit integer | Type indirect-damage mask. Combine applicable TYPE_* constants.
|
FACTION_PROPERTY_TYPE_HOSTILE
|
Unsigned 64-bit integer | Type hostility mask. Combine applicable TYPE_* constants.
|
Group constants
The following constants are available through openborconstant():
| Constant | Description |
|---|---|
FACTION_GROUP_NONE
|
Empty faction mask. |
FACTION_GROUP_NEUTRAL
|
Inert faction flag. |
FACTION_GROUP_NO_COPY
|
Prevents the property from copying. |
FACTION_GROUP_PLAYER_VERSES
|
Ignores applicable player-versus-player restrictions. |
FACTION_GROUP_TYPE_EXCLUSIVE
|
Uses only the corresponding type-faction check. |
FACTION_GROUP_TYPE_INCLUSIVE
|
Requires both group and type checks. |
FACTION_GROUP_ALL_NORMAL_0
|
Contains every normal faction from A-Z. |
FACTION_GROUP_ALL_NORMAL_1
|
Contains every normal faction from A1-Z1. |
FACTION_GROUP_ALL_NORMAL
|
Contains every normal faction from A-Z and A1-Z1. |
FACTION_GROUP_ALL
|
Contains every normal faction plus the operational player-versus and type-check flags. |
FACTION_GROUP_DEFAULT
|
Default group configuration. |
FACTION_GROUP_NO_CHECK
|
Combined mask of flags excluded from normal faction-group matching. |
FACTION_GROUP_A through FACTION_GROUP_Z
|
Original 26 normal faction flags. |
FACTION_GROUP_A1 through FACTION_GROUP_Z1
|
Additional 26 normal faction flags. |
Script example
The following example combines factions a, c, a1, and z1, then assigns the result as the faction membership mask.
mixed faction_mask =
openborconstant("FACTION_GROUP_A")
| openborconstant("FACTION_GROUP_C")
| openborconstant("FACTION_GROUP_A1")
| openborconstant("FACTION_GROUP_Z1");
set_faction_property(
faction_handle,
openborconstant("FACTION_PROPERTY_GROUP_MEMBER"),
faction_mask
);
Individual flags may be tested with bitwise AND:
mixed faction_mask = get_faction_property(
faction_handle,
openborconstant("FACTION_PROPERTY_GROUP_MEMBER")
);
if (faction_mask & openborconstant("FACTION_GROUP_A1"))
{
// Entity is a member of faction A1.
}