Jump to content

Factions: Difference between revisions

From OpenBOR
No edit summary
No edit summary
Line 14: Line 14:
Both systems may be combined for highly specific interaction rules.
Both systems may be combined for highly specific interaction rules.


Note this means hostility and damage permission are separate. An entity may consider another entity hostile without being able to damage it, or damage an entity it does not consider hostile. Group factions are script accessible and stored at both [[entity]] and [[model]] level - enabling on the fly swapping and restoration. For example, an entity might be affected by mind control by modifying its group flags for a limited time, then restore from its model defaults when the effect wears off.
Note this means hostility and damage permission are separate. An entity may consider another entity hostile without being able to damage it, or damage an entity it does not consider hostile. Group factions are script accessible and stored in both [[entity]] and [[model]] structures - meaning effectively 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 by mind control by modifying its group flags for a limited time, then restore from its starting defaults when the effect wears off.


== Design ==
== Design ==

Revision as of 10:39, 28 July 2026

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:

  • Group factions comprise 52 available group flags.
  • Type factions use legacy entity types such as player, enemy, and npc.

In turn, Groups and Type are each made up of four properties that may contain one or more assignments:

  • Membership - Which factions the entity belongs to.
  • Hostility - Which factions the AI and targeting functions considers an enemy.
  • Damage - Which factions the entity can damage with attacks.
  • Indirect Damage - Which factions the entity can damage collaterally (ex. thrown by another entity).

Both systems may be combined for highly specific interaction rules.

Note this means hostility and damage permission are separate. An entity may consider another entity hostile without being able to damage it, or damage an entity it does not consider hostile. Group factions are script accessible and stored in both entity and model structures - meaning effectively 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 by mind control by modifying its group flags for a limited time, then restore from its starting defaults when the effect wears off.

Design

OpenBOR's faction system is intentionally designed as a hardware-speed primitive for complex higher-level relationships. Creators may use the 52 native flags directly as ready-made factions, or 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 52 factions. Together, the four faction properties provide approximately 4.11 * 1062 possible configurations - 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 Song of Fire and Ice 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 Neutral 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, 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.

Group values

Value Description
a through z Selects one of the original 26 normal faction groups.
a1 through z1 Selects one of the additional 26 normal faction groups.
all Selects every normal faction group from a through z and a1 through z1.
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.
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 original faction groups.
a1 through z1 Permits indirect damage against members of the selected additional faction groups.
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 original faction groups as hostile.
a1 through z1 Marks members of the selected additional faction groups 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:

  1. The target belongs to faction c, d, or e.
  2. The target is an enemy or npc type.

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 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.
}