Kelsidavis-WoWee/include/pipeline/wowee_factions.hpp
Kelsi 4868f780cc feat(pipeline): add WFAC (Wowee Faction Catalog) format
Novel open replacement for Blizzard's Faction.dbc +
FactionTemplate.dbc + the AzerothCore-style
reputation_reward / reputation_spillover SQL tables. The
17th open format added to the editor.

Combines the "displayable Faction" (player-facing name +
reputation thresholds for friendly/honored/revered/exalted)
with the "FactionTemplate matrix" (which factions are
hostile to which) into one entry. The runtime walks the
catalog to answer two questions:
  • "Will faction A attack faction B on sight?" -> enemy list
  • "What rep tier is the player with X?"      -> thresholds

Cross-references with previously-added formats:
  WCRT.entry.factionId       -> WFAC.entry.factionId
  WFAC.entry.parentFactionId -> WFAC.entry.factionId
  WFAC.entry.enemies[]       -> WFAC.entry.factionId
  WFAC.entry.friends[]       -> WFAC.entry.factionId

The starter preset's factionId 35 (Friendly) and 14
(Hostile) deliberately match the WCRT preset defaults, so
the demo content stack is consistent: WCRT.makeBandit's
factionId=14 has a real entry in WFAC.makeStarter that
declares it hostile to friendly NPCs (35) and players (1).

Format:
  • magic "WFAC", version 1, little-endian
  • per faction: factionId / parentFactionId / name /
    description / reputationFlags / baseReputation /
    7 ascending tier thresholds (hostile..exalted) /
    enemies[] / friends[]

Enums:
  • ReputationFlags: VisibleOnTab / AtWarDefault / Hidden /
                      NoReputation / IsHeader (group label)
  • Tier (canonical): Hated / Hostile / Unfriendly /
                       Neutral / Friendly / Honored /
                       Revered / Exalted

API: WoweeFactionLoader::save / load / exists / findById +
WoweeFaction::isHostile(a, b); presets makeStarter (3-faction
demo matching WCRT defaults), makeAlliance (header +
Stormwind / Darnassus / Ironforge with reciprocal friend
lists + Defias enemy), makeWildlife (4 beast factions, each
hostile to player but ignoring other beasts).

CLI added (5 flags, 514 documented total now):
  --gen-factions / --gen-factions-alliance / --gen-factions-wildlife
  --info-wfac / --validate-wfac

Validator catches: factionId=0 + duplicates, empty name,
threshold ordering violations (hostile must be < unfriendly
< neutral < ... < exalted), self-listed as enemy or friend,
faction in both enemies and friends (incoherent).
2026-05-09 15:37:59 -07:00

130 lines
4.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <cstdint>
#include <string>
#include <vector>
namespace wowee {
namespace pipeline {
// Wowee Open Faction Catalog (.wfac) — novel replacement for
// Blizzard's Faction.dbc + FactionTemplate.dbc + the
// AzerothCore-style reputation_reward / reputation_spillover
// SQL tables. The 17th open format added to the editor.
//
// Combines the "displayable Faction" (player-facing name,
// reputation thresholds for friendly/honored/revered/exalted)
// with the "FactionTemplate matrix" (which factions are
// hostile to which) into one entry. The runtime walks the
// catalog to answer two questions:
// • "Will faction A attack faction B on sight?" -> enemy list
// • "What reputation tier is this player with X?" -> thresholds
//
// Cross-references:
// WCRT.entry.factionId -> WFAC.entry.factionId
// WFAC.entry.parentFactionId -> WFAC.entry.factionId
// (intra-format hierarchy)
// WFAC.entry.enemies[] -> WFAC.entry.factionId
// WFAC.entry.friends[] -> WFAC.entry.factionId
//
// Binary layout (little-endian):
// magic[4] = "WFAC"
// version (uint32) = current 1
// nameLen + name (catalog label)
// entryCount (uint32)
// entries (each):
// factionId (uint32)
// parentFactionId (uint32)
// nameLen + name
// descLen + description
// reputationFlags (uint32)
// baseReputation (int32)
// thresholdHostile (int32)
// thresholdUnfriendly (int32)
// thresholdNeutral (int32)
// thresholdFriendly (int32)
// thresholdHonored (int32)
// thresholdRevered (int32)
// thresholdExalted (int32)
// enemyCount (uint8) + pad[3] + enemies[] (factionId × N)
// friendCount (uint8) + pad[3] + friends[] (factionId × N)
struct WoweeFaction {
enum ReputationFlags : uint32_t {
VisibleOnTab = 0x01, // shows up in the player's reputation panel
AtWarDefault = 0x02, // new players are at-war on first contact
Hidden = 0x04, // never shown (internal reputation tracking)
NoReputation = 0x08, // gives no reputation gains/losses
IsHeader = 0x10, // grouping header (parent), not a faction itself
};
// Canonical reputation tiers — clients use the threshold
// values to decide which tier badge to display.
enum Tier : int32_t {
Hated = -42000,
Hostile = -6000,
Unfriendly = -3000,
Neutral = 0,
Friendly = 3000,
Honored = 9000,
Revered = 21000,
Exalted = 42000,
};
struct Entry {
uint32_t factionId = 0;
uint32_t parentFactionId = 0;
std::string name;
std::string description;
uint32_t reputationFlags = VisibleOnTab;
int32_t baseReputation = 0;
int32_t thresholdHostile = Hostile;
int32_t thresholdUnfriendly = Unfriendly;
int32_t thresholdNeutral = Neutral;
int32_t thresholdFriendly = Friendly;
int32_t thresholdHonored = Honored;
int32_t thresholdRevered = Revered;
int32_t thresholdExalted = Exalted;
std::vector<uint32_t> enemies;
std::vector<uint32_t> friends;
};
std::string name;
std::vector<Entry> entries;
bool isValid() const { return !entries.empty(); }
// Lookup by factionId — nullptr if not present.
const Entry* findById(uint32_t factionId) const;
// True if A's enemies list contains B (hostile-on-sight).
// Does NOT walk parent factions; use isAtWarTransitive
// for that.
bool isHostile(uint32_t aFactionId, uint32_t bFactionId) const;
};
class WoweeFactionLoader {
public:
static bool save(const WoweeFaction& cat,
const std::string& basePath);
static WoweeFaction load(const std::string& basePath);
static bool exists(const std::string& basePath);
// Preset emitters used by --gen-factions* variants.
//
// makeStarter — 3 factions: Friendly (35), Hostile (14),
// PlayerHorde (1). Friendly is enemies of
// Hostile, vice versa. Useful as a starter
// template.
// makeAlliance — Stormwind / Ironforge / Darnassus (with
// reciprocal friend lists) + the canonical
// Defias enemy.
// makeWildlife — neutral wildlife factions: wolves, bears,
// spiders, kobolds. Each hostile to players
// but not to each other.
static WoweeFaction makeStarter(const std::string& catalogName);
static WoweeFaction makeAlliance(const std::string& catalogName);
static WoweeFaction makeWildlife(const std::string& catalogName);
};
} // namespace pipeline
} // namespace wowee