61 lines
2.6 KiB
Text
61 lines
2.6 KiB
Text
# faction.ludic — a friend/enemy/neutral relationship table (#57 foundation).
|
|
#
|
|
# Shared by shooter targeting and NPC AI: "who may hit / hunt / help whom". Each
|
|
# body carries a `Faction { id }`; a small square matrix records the relationship
|
|
# between two faction ids. Unset pairs fall back to the classic default — same id
|
|
# is friendly, different ids are hostile — so a game that never touches the table
|
|
# still gets sensible enemy/ally behaviour. The matrix is a plain integer buffer
|
|
# in a module var, so it is deterministic and captured by world_save.
|
|
|
|
property Faction { id: int = 0 }
|
|
|
|
const REL_FRIEND: int = 0
|
|
const REL_NEUTRAL: int = 1
|
|
const REL_HOSTILE: int = 2
|
|
|
|
# relationships stored as (rel + 1); a zero slot means "unset -> use the default"
|
|
|
|
# Faction.set(a, b, rel) — record a symmetric relationship between two factions.
|
|
@Namespace(Faction) function faction_set(gameplay_st: mut GameplayState, a: int, b: int, rel: int) -> void {
|
|
if (a < 0) or (a >= FAC_MAX) { return }
|
|
if (b < 0) or (b >= FAC_MAX) { return }
|
|
gameplay_st.fac_tbl[a * FAC_MAX + b] = rel + 1
|
|
gameplay_st.fac_tbl[b * FAC_MAX + a] = rel + 1
|
|
}
|
|
|
|
# Faction.rel(a, b) — the relationship code (0 friend, 1 neutral, 2 hostile).
|
|
@Namespace(Faction) function faction_rel(gameplay_st: mut GameplayState, a: int, b: int) -> int {
|
|
if (a >= 0) and (a < FAC_MAX) and (b >= 0) and (b < FAC_MAX) {
|
|
let v = gameplay_st.fac_tbl[a * FAC_MAX + b]
|
|
if v != 0 { return v - 1 }
|
|
}
|
|
if a == b { return REL_FRIEND }
|
|
return REL_HOSTILE
|
|
}
|
|
|
|
# Faction.hostile(a, b) / Faction.friendly(a, b) — the common yes/no queries.
|
|
@Namespace(Faction) function faction_hostile(gameplay_st: mut GameplayState, a: int, b: int) -> int {
|
|
if faction_rel(gameplay_st, a, b) == REL_HOSTILE { return 1 }
|
|
return 0
|
|
}
|
|
@Namespace(Faction) function faction_friendly(gameplay_st: mut GameplayState, a: int, b: int) -> int {
|
|
if faction_rel(gameplay_st, a, b) == REL_FRIEND { return 1 }
|
|
return 0
|
|
}
|
|
|
|
# Faction.id_of(e) — the faction id an entity carries (-1 if it has no Faction).
|
|
@Namespace(Faction) function faction_id_of(e: int) -> int {
|
|
let P = World.prop_id("Faction")
|
|
if P < 0 { return -1 }
|
|
if World.has(e, P) == 0 { return -1 }
|
|
let f = World.field_id(P, "id")
|
|
if f < 0 { return -1 }
|
|
return World.get(e, P, f)
|
|
}
|
|
|
|
# Faction.enemies(a, b) — true when the two entities' factions are hostile; the
|
|
# one-call test the shooter and AI reach for. Missing factions read as hostile
|
|
# (an unaligned hazard hits anyone) unless the ids happen to match.
|
|
@Namespace(Faction) function faction_enemies(gameplay_st: mut GameplayState, ea: int, eb: int) -> int {
|
|
return faction_hostile(gameplay_st, faction_id_of(ea), faction_id_of(eb))
|
|
}
|