Just saw a post in the dump thread for 3.3.3a about asking how to compare factions.
A while ago we actually stopped using UnitReaction in favor of a 'local' comparison method. This allows us to compare factions 'out of process' fairly easily.
I won't bore you with the details; so here's the WoWFaction class that handles most of it.
Code:
public class WoWFaction
{
private readonly FactionTemplateDbcRecord _template;
private FactionDbcRecord _record;
public WoWFaction(int id, bool isTemplate = true)
{
Id = id;
if (IsValid)
{
if (isTemplate)
{
_template = OnyxWoW.Db[ClientDb.FactionTemplate].GetRow(id).GetStruct<FactionTemplateDbcRecord>();
_record = OnyxWoW.Db[ClientDb.Faction].GetRow(_template.FactionId).GetStruct<FactionDbcRecord>();
}
else
{
_record = OnyxWoW.Db[ClientDb.Faction].GetRow(id).GetStruct<FactionDbcRecord>();
}
}
}
public int Id { get; private set; }
public string Name { get { return _record.Name; } }
public string Description { get { return _record.Description; } }
public WoWFaction ParentFaction { get { return new WoWFaction(_record.ParentFaction, false); } }
public bool IsValid { get { return Id != 0; } }
public WoWUnitRelation RelationTo(WoWFaction other)
{
return CompareFactions(this, other);
}
public static WoWUnitRelation CompareFactions(WoWFaction factionA, WoWFaction factionB)
{
FactionTemplateDbcRecord atmpl = factionA._template;
FactionTemplateDbcRecord btmpl = factionB._template;
if ((btmpl.FightSupport & atmpl.HostileMask) != 0)
{
return (WoWUnitRelation) 1;
}
for (int i = 0; i < 4; i++)
{
if (atmpl.EnemyFactions[i] == btmpl.Id)
{
return (WoWUnitRelation) 1;
}
if (atmpl.EnemyFactions[i] == 0)
{
break;
}
}
if ((btmpl.FightSupport & atmpl.FriendlyMask) != 0)
{
return (WoWUnitRelation) 4;
}
for (int i = 0; i < 4; i++)
{
if (atmpl.FriendlyFactions[i] == btmpl.Id)
{
return (WoWUnitRelation) 4;
}
if (atmpl.FriendlyFactions[i] == 0)
{
break;
}
}
if ((atmpl.FightSupport & btmpl.FriendlyMask) != 0)
{
return (WoWUnitRelation) 4;
}
for (int i = 0; i < 4; i++)
{
if (btmpl.FriendlyFactions[i] == atmpl.Id)
{
return (WoWUnitRelation) 4;
}
if (btmpl.FriendlyFactions[i] == 0)
{
break;
}
}
return (WoWUnitRelation) (~(byte) ((uint) atmpl.FactionFlags >> 12) & 2 | 1);
}
public override string ToString()
{
if (!IsValid)
{
return "N/A";
}
return Name + ", Parent: " + ParentFaction;
}
#region Nested type: FactionDbcRecord
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct FactionDbcRecord
{
public int Id;
private int _unk0;
public int Allied;
public int AtWar;
private int _unk1;
private int _unk2;
private int _unk3;
private int _unk4;
private int _unk5;
private int _unk6;
public int Reputation;
public int Mod1;
public int Mod2;
public int Mod3;
private int _unk7;
private int _unk8;
private int _unk9;
private int _unk10;
public int ParentFaction;
// 4 unknowns added recently. Cba to figure out what they're for
// since I have no use for them!
private int _unk11;
private int _unk12;
private int _unk13;
private int _unk14;
[MarshalAs(UnmanagedType.LPStr)]
public string Name;
[MarshalAs(UnmanagedType.LPStr)]
public string Description;
}
#endregion
#region Nested type: FactionTemplateDbcRecord
[StructLayout(LayoutKind.Sequential)]
private struct FactionTemplateDbcRecord
{
public int Id;
public int FactionId;
public int FactionFlags;
public int FightSupport;
public int FriendlyMask;
public int HostileMask;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] EnemyFactions;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] FriendlyFactions;
}
#endregion
}
And more importantly; the actual comparison method (it's almost line-for-line taken from WoW, and yes, it does work.)
Code:
public static WoWUnitRelation CompareFactions(WoWFaction factionA, WoWFaction factionB)
{
FactionTemplateDbcRecord atmpl = factionA._template;
FactionTemplateDbcRecord btmpl = factionB._template;
if ((btmpl.FightSupport & atmpl.HostileMask) != 0)
{
return (WoWUnitRelation) 1;
}
for (int i = 0; i < 4; i++)
{
if (atmpl.EnemyFactions[i] == btmpl.Id)
{
return (WoWUnitRelation) 1;
}
if (atmpl.EnemyFactions[i] == 0)
{
break;
}
}
if ((btmpl.FightSupport & atmpl.FriendlyMask) != 0)
{
return (WoWUnitRelation) 4;
}
for (int i = 0; i < 4; i++)
{
if (atmpl.FriendlyFactions[i] == btmpl.Id)
{
return (WoWUnitRelation) 4;
}
if (atmpl.FriendlyFactions[i] == 0)
{
break;
}
}
if ((atmpl.FightSupport & btmpl.FriendlyMask) != 0)
{
return (WoWUnitRelation) 4;
}
for (int i = 0; i < 4; i++)
{
if (btmpl.FriendlyFactions[i] == atmpl.Id)
{
return (WoWUnitRelation) 4;
}
if (btmpl.FriendlyFactions[i] == 0)
{
break;
}
}
return (WoWUnitRelation) (~(byte) ((uint) atmpl.FactionFlags >> 12) & 2 | 1);
}