-
Member
ManagerBase = 0x301EE70;
entry 0x18;
vector3 pos, 0x148
UnitField 0x160
current_hp 0xD4B0
max_hp 0xD4B8
someone found faction ? or "friendly" in UnitField ?
-
-
Post Thanks / Like - 1 Thanks
empathe (1 members gave Thanks to Razzue for this useful post)
-
Member
Originally Posted by
empathe
ManagerBase = 0x301EE70;
entry 0x18;
vector3 pos, 0x148
UnitField 0x160
current_hp 0xD4B0
max_hp 0xD4B8
someone found faction ? or "friendly" in UnitField ?
db2 parse , factionid = entry + 0xD5EC , parse db2 = FactionTemplate.db2 with factionid and compare flags from Razzue post
PS may be can do it with offsets ...
Code:
#define MAX_FACTION_RELATIONS 4
struct FactionTemplateEntry
{
uint32 ID; // 0
uint32 Faction; // 1
uint32 Flags; // 2
uint32 FactionGroup; // 3
uint32 FriendGroup; // 4
uint32 EnemyGroup; // 5
uint32 Enemies[MAX_FACTION_RELATIONS]; // 6-9
uint32 Friend[MAX_FACTION_RELATIONS]; // 10-13
// helpers
bool IsFriendlyTo(FactionTemplateEntry const& entry) const
{
if (entry.Faction)
{
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
if (Enemies[i] == entry.Faction)
return false;
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
if (Friend[i] == entry.Faction)
return true;
}
return (FriendGroup & entry.FactionGroup) || (FactionGroup & entry.FriendGroup);
}
bool IsHostileTo(FactionTemplateEntry const& entry) const
{
if (entry.Faction)
{
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
if (Enemies[i] == entry.Faction)
return true;
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
if (Friend[i] == entry.Faction)
return false;
}
return (EnemyGroup & entry.FactionGroup) != 0;
}
bool IsHostileToPlayers() const { return (EnemyGroup & FACTION_MASK_PLAYER) != 0; }
bool IsNeutralToAll() const
{
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
if (Enemies[i] != 0)
return false;
return EnemyGroup == 0 && FriendGroup == 0;
}
bool IsContestedGuardFaction() const { return (Flags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD) != 0; }
};
check zone (eg dalaran)
Code:
struct AreaTableEntry
{
uint32 ID; // 0
uint32 ContinentID; // 1
uint32 ParentAreaID; // 2 if 0 then it's zone, else it's zone id of this area
uint32 AreaBit; // 3
uint32 Flags; // 4
//uint32 SoundProviderPref; // 5
//uint32 SoundProviderPrefUnderwater; // 6
//uint32 AmbienceID; // 7
//uint32 ZoneMusic; // 8
//uint32 IntroSound; // 9
int32 ExplorationLevel; // 10
char const* AreaName[16]; // 11-26
//uint32 AreaName_lang_mask; // 27
uint32 FactionGroupMask; // 28
uint32 LiquidTypeID[4]; // 29-32 liquid override by type
//float MinElevation; // 33
//float AmbientMultiplier; // 34
//uint32 LightID; // 35
// helpers
bool IsSanctuary() const
{
if (ContinentID == 609)
return true;
return (Flags & AREA_FLAG_SANCTUARY) != 0;
}
bool IsFlyable() const
{
if (Flags & AREA_FLAG_OUTLAND)
{
if (!(Flags & AREA_FLAG_NO_FLY_ZONE))
return true;
}
return false;
}
};
this will give an analog lua UnitIsEnemy, next step checking flags...
Last edited by ermite66; 10-18-2022 at 05:50 AM.
-
Post Thanks / Like - 1 Thanks
empathe (1 members gave Thanks to ermite66 for this useful post)
-
Contributor
Originally Posted by
Razzue
You know... it's almost like I shared an updated field offsets over here in comment # 7
Link (Classic Wrath => Build 45327)
That oddly enough has the offset you're looking for even. This is why I have told you multiple times to simply
READ the first few pages of this forum, but alas it seems like my suggestions have gone in one ear, and out the other.
There's no reason to be condescending when you're a glorified copy paster.
-
Post Thanks / Like - 1 Thanks
empathe (1 members gave Thanks to ChrisIsMe for this useful post)
-
-
Member
thanks all for reply,
for me flag3 is ok
for alliance i can use this:
entry + 0xD5F8 (offset flag3)
and compare this value:
Code:
if(
//player friendly i can heal this guy
entityFlag3[total_entity] == 0x31 ||
entityFlag3[total_entity] == 0x32 ||
entityFlag3[total_entity] == 0x61b ||
entityFlag3[total_entity] == 0x38 ||
entityFlag3[total_entity] == 0x61c ||
entityFlag3[total_entity] == 0x35 ||
entityFlag3[total_entity] == 0x36 ||
entityFlag3[total_entity] == 0x37 ||
entityFlag3[total_entity] == 0x3efd ||
entityFlag3[total_entity] == 0x3efe
)
{
entityCanHeal[total_entity] = 1;
}
else if(
//player not friendly i can't heal this guy
entityFlag3[total_entity] == 0x3b ||
entityFlag3[total_entity] == 0x34 ||
entityFlag3[total_entity] == 0x5c6 ||
entityFlag3[total_entity] == 0x5c7 ||
entityFlag3[total_entity] == 0x3a ||
entityFlag3[total_entity] == 0x39 ||
entityFlag3[total_entity] == 0x3c ||
entityFlag3[total_entity] == 0x3c73 ||
entityFlag3[total_entity] == 0x3c74 ||
entityFlag3[total_entity] == 0x33
)
{
entityCanHeal[total_entity] = 2;
}
else
{
//unknow so i have to check flag value for add
entityCanHeal[total_entity] = 3;
}
works on dalaran & joug
Maybe i have to check if people is dead now or if is priest in holly form (death)
Last edited by empathe; 10-18-2022 at 07:01 AM.
Reason: balise
-
Member
Originally Posted by
empathe
thanks all for reply,
for me flag3 is ok
for alliance i can use this:
entry + 0xD5F8 (offset flag3)
and compare this value:
Code:
if(
//player friendly i can heal this guy
entityFlag3[total_entity] == 0x31 ||
entityFlag3[total_entity] == 0x32 ||
entityFlag3[total_entity] == 0x61b ||
entityFlag3[total_entity] == 0x38 ||
entityFlag3[total_entity] == 0x61c ||
entityFlag3[total_entity] == 0x35 ||
entityFlag3[total_entity] == 0x36 ||
entityFlag3[total_entity] == 0x37 ||
entityFlag3[total_entity] == 0x3efd ||
entityFlag3[total_entity] == 0x3efe
)
{
entityCanHeal[total_entity] = 1;
}
else if(
//player not friendly i can't heal this guy
entityFlag3[total_entity] == 0x3b ||
entityFlag3[total_entity] == 0x34 ||
entityFlag3[total_entity] == 0x5c6 ||
entityFlag3[total_entity] == 0x5c7 ||
entityFlag3[total_entity] == 0x3a ||
entityFlag3[total_entity] == 0x39 ||
entityFlag3[total_entity] == 0x3c ||
entityFlag3[total_entity] == 0x3c73 ||
entityFlag3[total_entity] == 0x3c74 ||
entityFlag3[total_entity] == 0x33
)
{
entityCanHeal[total_entity] = 2;
}
else
{
//unknow so i have to check flag value for add
entityCanHeal[total_entity] = 3;
}
works on dalaran & joug
Maybe i have to check if people is dead now or if is priest in holly form (death)
I think only compare flags dont work , my shit still detects anything ...
https://www.twitch.tv/videos/1628050237
-
Active Member
Originally Posted by
empathe
thanks all for reply,
for me flag3 is ok
for alliance i can use this:
entry + 0xD5F8 (offset flag3)
and compare this value:
Code:
if(
//player friendly i can heal this guy
entityFlag3[total_entity] == 0x31 ||
entityFlag3[total_entity] == 0x32 ||
entityFlag3[total_entity] == 0x61b ||
entityFlag3[total_entity] == 0x38 ||
entityFlag3[total_entity] == 0x61c ||
entityFlag3[total_entity] == 0x35 ||
entityFlag3[total_entity] == 0x36 ||
entityFlag3[total_entity] == 0x37 ||
entityFlag3[total_entity] == 0x3efd ||
entityFlag3[total_entity] == 0x3efe
)
{
entityCanHeal[total_entity] = 1;
}
else if(
//player not friendly i can't heal this guy
entityFlag3[total_entity] == 0x3b ||
entityFlag3[total_entity] == 0x34 ||
entityFlag3[total_entity] == 0x5c6 ||
entityFlag3[total_entity] == 0x5c7 ||
entityFlag3[total_entity] == 0x3a ||
entityFlag3[total_entity] == 0x39 ||
entityFlag3[total_entity] == 0x3c ||
entityFlag3[total_entity] == 0x3c73 ||
entityFlag3[total_entity] == 0x3c74 ||
entityFlag3[total_entity] == 0x33
)
{
entityCanHeal[total_entity] = 2;
}
else
{
//unknow so i have to check flag value for add
entityCanHeal[total_entity] = 3;
}
works on dalaran & joug
Maybe i have to check if people is dead now or if is priest in holly form (death)
I would strongly recommend you to learn about "Flags" (Enum.HasFlag(Enum) Methode (System) | Microsoft Learn)
Having a giant if/else statement for simple flag operations is so much more work and extremely error prune.
You can find the values for UnitFlags3 here: TrinityCore/UnitDefines.h at master . TrinityCore/TrinityCore . GitHub
-
Post Thanks / Like - 1 Thanks
empathe (1 members gave Thanks to SatyPardus for this useful post)
-
Member
Originally Posted by
empathe
thanks all for reply,
for me flag3 is ok
for alliance i can use this:
entry + 0xD5F8 (offset flag3)
and compare this value:
Code:
if(
//player friendly i can heal this guy
entityFlag3[total_entity] == 0x31 ||
entityFlag3[total_entity] == 0x32 ||
entityFlag3[total_entity] == 0x61b ||
entityFlag3[total_entity] == 0x38 ||
entityFlag3[total_entity] == 0x61c ||
entityFlag3[total_entity] == 0x35 ||
entityFlag3[total_entity] == 0x36 ||
entityFlag3[total_entity] == 0x37 ||
entityFlag3[total_entity] == 0x3efd ||
entityFlag3[total_entity] == 0x3efe
)
{
entityCanHeal[total_entity] = 1;
}
else if(
//player not friendly i can't heal this guy
entityFlag3[total_entity] == 0x3b ||
entityFlag3[total_entity] == 0x34 ||
entityFlag3[total_entity] == 0x5c6 ||
entityFlag3[total_entity] == 0x5c7 ||
entityFlag3[total_entity] == 0x3a ||
entityFlag3[total_entity] == 0x39 ||
entityFlag3[total_entity] == 0x3c ||
entityFlag3[total_entity] == 0x3c73 ||
entityFlag3[total_entity] == 0x3c74 ||
entityFlag3[total_entity] == 0x33
)
{
entityCanHeal[total_entity] = 2;
}
else
{
//unknow so i have to check flag value for add
entityCanHeal[total_entity] = 3;
}
works on dalaran & joug
Maybe i have to check if people is dead now or if is priest in holly form (death)
You can seen flags from UnitCanAttack - a1 = ptr on unit1 , a2 = ptr on unit2 , also can seen offsets for Flags1, Flags2 ect., eg "a1 + 0xDBA0", apparently they read the player flags too
Code:
char __fastcall sub_1413C8D50(__int64 a1, __int64 a2, char a3)
{
int v5; // eax
__int64 v6; // rax
int v7; // ecx
int v8; // eax
int v9; // edx
__int64 v10; // rcx
__int64 v11; // rdx
__int64 v12; // rsi
__int64 v13; // r8
unsigned int v14; // eax
__int64 v15; // rax
__int64 v16; // rcx
__int64 v17; // rax
__int64 v18; // rsi
__int64 v19; // rbp
__int64 v20; // rdx
__int64 v21; // r8
__int64 v22; // rsi
_QWORD *v23; // rax
_QWORD *v24; // rax
char v26; // [rsp+40h] [rbp+8h] BYREF
if ( (dword_1426623F0[*(unsigned __int8 *)(a1 + 0x10)] & 0x40) != 0
&& a1
&& (*(_DWORD *)(a1 + 0xDBA0) & 0x80480000) != 0 )
{
return 0;
}
if ( (dword_1426623F0[*(unsigned __int8 *)(a2 + 0x10)] & 0x40) != 0 )
{
if ( a2 )
{
v5 = *(_DWORD *)(a2 + 0xDBA0);
if ( (v5 & 0x80480000) != 0 )
return 0;
if ( (v5 & 0x10) != 0 )
{
v6 = *(_QWORD *)(a1 + 0x380);
if ( !v6 || (*(_BYTE *)(v6 + 0xE8) & 2) == 0 )
return 0;
}
}
}
v7 = *(_DWORD *)(a2 + 0xD5F0);
if ( (v7 & 0x2110082) != 0 )
return 0;
v8 = *(_DWORD *)(a2 + 0xDC);
if ( (v8 & 1) != 0 && (v8 & 2) == 0 )
return 0;
if ( (*(_DWORD *)(a2 + 0xD5F8) & 0x100) != 0 )
return 0;
v9 = *(_DWORD *)(a1 + 0xD5F0);
if ( (v9 & 8) == 0 && (v7 & 0x200) != 0 )
return 0;
if ( (v7 & 8) == 0 && (v9 & 0x200) != 0
|| !a3 && ((*(_DWORD *)(a1 + 0xD5F0) & 8) != 0 && (v7 & 0x100) != 0 || (v7 & 8) != 0 && (v9 & 0x100) != 0) )
{
return 0;
}
if ( (*(_DWORD *)(a2 + 0xD5F4) & 0x10000000) != 0 && !(unsigned __int8)sub_1413E8070(a1, a2) )
return 0;
v10 = 54584i64;
if ( !(*(_QWORD *)(a2 + 0xD540) >> 58) )
v10 = 54616i64;
v12 = sub_14157C730(
a2 + v10,
0x20i64,
"D:\\BuildServer\\A\\work\\DedicatedCheckout\\Classic\\Source\\Object\\ObjectClient\\Unit_C.cpp",
0x52CBi64);
if ( v12 )
{
v14 = sub_14157BEE0();
v15 = sub_1404828D0(&qword_142CF3430, v14, 0i64, &v26);
v16 = *(unsigned __int8 *)(v12 + 0x10);
v13 = v15;
v11 = (unsigned int)dword_1426623F0[v16] >> 6;
if ( (dword_1426623F0[v16] & 0x40) != 0 && *(int *)(v12 + 0xD618) > 0 && (*(_DWORD *)(v12 + 0xD5F8) & 4) == 0 )
{
v17 = *(_QWORD *)(v12 + 0x380);
if ( !v17 || (*(_DWORD *)(v17 + 232) & 0x800) == 0 )
{
if ( v13 )
{
v18 = v13 + 0x18;
if ( (unsigned __int8)sub_140F1B4F0(v13 + 0x18) != 3 && (unsigned __int8)sub_140F1B4F0(v18) != 4 )
return 0;
}
}
}
}
if ( (*(_BYTE *)(a1 + 0xD5F6) & 1) != 0 || (*(_BYTE *)(a2 + 0xD5F6) & 1) != 0 )
{
v19 = sub_1414C5F80(a1, v11, v13);
v22 = sub_1414C5F80(a2, v20, v21);
if ( v19 )
{
v23 = (_QWORD *)sub_1403D9E60();
if ( (sub_140200D20(v19, 0, 0i64, v23) & 0x20000000) != 0 && sub_1414C5D40(a2, a1) == a1 )
return 0;
}
if ( v22 )
{
v24 = (_QWORD *)sub_1403D9E60();
if ( (sub_140200D20(v22, 0, 0i64, v24) & 0x20000000) != 0 && sub_1414C5D40(a1, a2) == a2 )
return 0;
}
}
if ( (*(_DWORD *)(a1 + 54768) & 8) == 0 && (*(_DWORD *)(a2 + 0xD5F0) & 8) == 0 )
return (int)sub_141403840(a1, a2) <= 1 || (int)sub_141403840(a2, a1) <= 1;
v26 = 0;
if ( (unsigned __int8)sub_1413CE530(a1, a2, &v26) )
return v26;
else
return (int)sub_141403840(a1, a2) < 4;
}
PS if wanna compare flags "if then else if ... "
Code:
#define GetBitVal(Data, nBit) ( (Data >> nBit) & 1)
to get bit value from index
Last edited by ermite66; 10-19-2022 at 04:45 AM.
-
Post Thanks / Like - 1 Thanks
empathe (1 members gave Thanks to ermite66 for this useful post)
-
Contributor
Avid Ailurophile
Originally Posted by
ermite66
You can seen flags from UnitCanAttack - a1 = ptr on unit1 , a2 = ptr on unit2 , also can seen offsets for Flags1, Flags2 ect., eg "a1 + 0xDBA0", apparently they read the player flags too
PS if wanna compare flags "if then else if ... "
Code:
#define GetBitVal(Data, nBit) ( (Data >> nBit) & 1)
to get bit value from index
Or just do eazy way to compare flags: ( Flag & (Value1 | Value2 | Value3)) != 0; but whatever.
Also, they legit just use Unit flag three to check if mounted combat is not allowed (Flag & 0x4 == 0) and if a unit is ignoring combat (Flag & 0x100 != 0).
You're also looking at CGUnit_C_CanAttack, the actual script Script_UnitCanAttack is found at
Code:
48 89 5C 24 ? 57 48 83 EC ? BA ? ? ? ? 48 8B D9 E8 ? ? ? ? 85 C0 0F 84 ? ? ? ? BA ? ? ? ? 48 8B CB E8 ? ? ? ? 85 C0 0F 84 ? ? ? ? 45 33 C0 48 8B CB 41 8D 50 ? E8 ? ? ? ? 48 8B C8 33 D2 E8 ? ? ? ? 45 33 C0 48 8B CB 48 8B F8 41 8D 50 ? E8 ? ? ? ? 48 8B C8 33 D2 E8 ? ? ? ? 48 85 FF 74 ? 48 85 C0 74 ? 45 33 C0
"May all your bacon burn"
-
Member
Originally Posted by
Razzue
Or just do eazy way to compare flags: ( Flag & (Value1 | Value2 | Value3)) != 0; but whatever.
Also, they legit just use Unit flag three to check if mounted combat is not allowed (Flag & 0x4 == 0) and if a unit is ignoring combat (Flag & 0x100 != 0).
You're also looking at CGUnit_C_CanAttack, the actual script Script_UnitCanAttack is found at
Code:
48 89 5C 24 ? 57 48 83 EC ? BA ? ? ? ? 48 8B D9 E8 ? ? ? ? 85 C0 0F 84 ? ? ? ? BA ? ? ? ? 48 8B CB E8 ? ? ? ? 85 C0 0F 84 ? ? ? ? 45 33 C0 48 8B CB 41 8D 50 ? E8 ? ? ? ? 48 8B C8 33 D2 E8 ? ? ? ? 45 33 C0 48 8B CB 48 8B F8 41 8D 50 ? E8 ? ? ? ? 48 8B C8 33 D2 E8 ? ? ? ? 48 85 FF 74 ? 48 85 C0 74 ? 45 33 C0
what is this WowClassic.exe + 0x26623F0 ?
Code:
if ( (dword_1426623F0[*(unsigned __int8 *)(a1 + 0x10)] & 0x40) != 0
&& a1
&& (*(_DWORD *)(a1 + 0xDBA0) & 0x80480000) != 0 )
{
return 0;
}
-
-
Member
Originally Posted by
ermite66
what did you use for scene display ?
Code:
D3DXMATRIX matView;
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (cameraX, cameraY, cameraZ),//sound good
&D3DXVECTOR3 (MyX, MyY, MyZ),// <<<<< sound not good, the look at position is not exactly the x,y,z player
&D3DXVECTOR3 (0.0f, 0.0f, 1.0f));
d3ddev->SetTransform(D3DTS_VIEW, &matView);
D3DXMATRIX matProjection;
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(54),
((FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT)*-1,
1.0f,
5000.0f);
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection);
any way to calculate the "look at position" ? with memory information about camera ?
i have some flicker of position with this config
Last edited by empathe; 10-19-2022 at 07:47 AM.
Reason: balise code
-
Member
Originally Posted by
empathe
what did you use for scene display ?
Code:
D3DXMATRIX matView;
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (cameraX, cameraY, cameraZ),//sound good
&D3DXVECTOR3 (MyX, MyY, MyZ),// <<<<< sound not good, the look at position is not exactly the x,y,z player
&D3DXVECTOR3 (0.0f, 0.0f, 1.0f));
d3ddev->SetTransform(D3DTS_VIEW, &matView);
D3DXMATRIX matProjection;
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(54),
((FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT)*-1,
1.0f,
5000.0f);
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection);
any way to calculate the "look at position" ? with memory information about camera ?
i have some flicker of position with this config
anything d3dx overlay with vsunc , methods for batching , this give perfomance for render lines, circles, text, ect. u can see how this work on imgui. next step read camera;
Code:
uint64 camera_mgr_ptr = [[WowClassic.exe + 0x2F4B178] + 0x38E8]
Vector3 m_Camera_pos; // [camera_mgr_ptr + 0x0010]
Matrix3x3 mat; // [camera_mgr_ptr + 0x001C]
float FOV; // [camera_mgr_ptr + 0x0040]
Code:
bool DrawManager::WorldToScreen(Vector3 pos, Vector2& out)
{
Vector3 difference{ pos.x - m_Camera_pos.x, pos.y - m_Camera_pos.y, pos.z - m_Camera_pos.z };
float product = difference.x * mat.M11 + difference.y * mat.M12 + difference.z * mat.M13;
if (product < 0)
return false;
Matrix3x3 inverse = mat.Inverse();
Vector3 view
{
inverse.M11 * difference.x + inverse.M21 * difference.y + inverse.M31 * difference.z ,
inverse.M12 * difference.x + inverse.M22 * difference.y + inverse.M32 * difference.z,
inverse.M13 * difference.x + inverse.M23 * difference.y + inverse.M33 * difference.z
};
Vector3 camera{ -view.y, -view.z, view.x };
Vector2 gameScreen{ (float)m_iWidth / 2.0f , (float)m_iHeight / 2.0f };
Vector2 aspect{ gameScreen.x / tanf(((m_Camera.FOV * 55.0f) / 2.0f) * M_DEG2RAD) ,gameScreen.y / tanf(((m_Camera.FOV * 35.0f) / 2.0f) * M_DEG2RAD) };
Vector2 screenPos{ gameScreen.x + camera.x * aspect.x / camera.z,gameScreen.y + camera.y * aspect.y / camera.z };
if (screenPos.x < 0 || screenPos.y < 0 || screenPos.x >(float)m_iWidth || screenPos.y > (float)m_iHeight)
return false;
out = screenPos;
return true;
}
One moment - 1 memory read per 1 struct or offset, dont need read in anything methods of unit.
1. new frame in renderer
2. read camera, objects, units , ect, and write this to struct
3. do anithing with readed data
4. draw what u need
5. go to p.1
my bot (if this semi-finished product can be called that) easily produces 400 frames per second, if not iterate all paths to all available objects on the continent
PS maybe ill post it later, but first need to finish
Last edited by ermite66; 10-19-2022 at 10:11 AM.
-
Member
Originally Posted by
Razzue
Or just do eazy way to compare flags: ( Flag & (Value1 | Value2 | Value3)) != 0; but whatever.
Also, they legit just use Unit flag three to check if mounted combat is not allowed (Flag & 0x4 == 0) and if a unit is ignoring combat (Flag & 0x100 != 0).
i dont understand , about flags u say.
Больной молодой волк - NPC - WotLK Classic
i can attack this mob , but all they flags equal flags of nearest friendly NPC
the only solution i see is faction comparison
PS sort by FactionTemplate.db2
Снимок.JPG
Last edited by ermite66; 10-19-2022 at 01:55 PM.