Skip to content

Commit

Permalink
Code Cleanup, More Options and a Bugfix. (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ceikry authored Aug 14, 2024
1 parent f9fbf9e commit a571805
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 68 deletions.
10 changes: 10 additions & 0 deletions conf/transmog.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ Transmogrification.TokenAmount = 1
# Description: Allow cloth items to be transmogrified with plate for example
# Default: 0
#
# Transmogrification.AllowLowerTiers
# Description: Allows using any armor tier the player can equip (i.e. Warrior plate->cloth | Mage cloth)
# Default: 0
#
# Transmogrification.AllowMixedOffhandArmorTypes
# Description: Allow shields, offhands (i.e. lamps), and bucklers to be used interchangeably
# Default: 0
#
# Transmogrification.AllowMixedWeaponTypes
# Description: Allow axe to be transmogrified with dagger for example
# Possible options:
Expand Down Expand Up @@ -208,6 +216,8 @@ Transmogrification.AllowHeirloom = 1
Transmogrification.AllowTradeable = 0

Transmogrification.AllowMixedArmorTypes = 0
Transmogrification.AllowLowerTiers = 0
Transmogrification.AllowMixedOffhandArmorTypes = 0
Transmogrification.AllowMixedWeaponTypes = 0
Transmogrification.AllowMixedWeaponHandedness = 0
Transmogrification.AllowFishingPoles = 0
Expand Down
234 changes: 166 additions & 68 deletions src/Transmogrification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,87 +625,119 @@ bool Transmogrification::CanTransmogrifyItemWithItem(Player* player, ItemTemplat
if (IsRangedWeapon(source->Class, source->SubClass) != IsRangedWeapon(target->Class, target->SubClass))
return false;

if (source->SubClass != target->SubClass && !IsRangedWeapon(target->Class, target->SubClass))
if (source->SubClass != target->SubClass && !IsSubclassMismatchAllowed(player, source, target))
return false;

if (source->InventoryType != target->InventoryType && !IsInvTypeMismatchAllowed(source, target))
return false;

return true;
}

bool Transmogrification::IsSubclassMismatchAllowed(Player *player, const ItemTemplate *source, const ItemTemplate *target) const
{
if (IsAllowed(source->ItemId)) return true;

uint32 sourceType = source->InventoryType;
uint32 targetType = target->InventoryType;
uint32 sourceClass = source->Class;
uint32 targetClass = target->Class;
uint32 sourceSub = source->SubClass;
uint32 targetSub = target->SubClass;

if (targetClass == ITEM_CLASS_WEAPON)
{
if (!IsAllowed(source->ItemId))
if (IsRangedWeapon(sourceClass, sourceSub))
return true;

if (AllowMixedWeaponTypes == MIXED_WEAPONS_MODERN)
{
if (source->Class == ITEM_CLASS_ARMOR && !AllowMixedArmorTypes)
return false;
if (source->Class == ITEM_CLASS_WEAPON)
switch (targetSub)
{
if (AllowMixedWeaponTypes == MIXED_WEAPONS_STRICT)
{
return false;
}
if (AllowMixedWeaponTypes == MIXED_WEAPONS_MODERN)
{
switch (source->SubClass)
{
case ITEM_SUBCLASS_WEAPON_WAND:
case ITEM_SUBCLASS_WEAPON_DAGGER:
case ITEM_SUBCLASS_WEAPON_FIST:
return false;
case ITEM_SUBCLASS_WEAPON_AXE:
case ITEM_SUBCLASS_WEAPON_SWORD:
case ITEM_SUBCLASS_WEAPON_MACE:
if (target->SubClass != ITEM_SUBCLASS_WEAPON_MACE &&
target->SubClass != ITEM_SUBCLASS_WEAPON_AXE &&
target->SubClass != ITEM_SUBCLASS_WEAPON_SWORD)
{
return false;
}
break;
case ITEM_SUBCLASS_WEAPON_AXE2:
case ITEM_SUBCLASS_WEAPON_SWORD2:
case ITEM_SUBCLASS_WEAPON_MACE2:
case ITEM_SUBCLASS_WEAPON_STAFF:
case ITEM_SUBCLASS_WEAPON_POLEARM:
if (target->SubClass != ITEM_SUBCLASS_WEAPON_MACE2 &&
target->SubClass != ITEM_SUBCLASS_WEAPON_AXE2 &&
target->SubClass != ITEM_SUBCLASS_WEAPON_SWORD2 &&
target->SubClass != ITEM_SUBCLASS_WEAPON_STAFF &&
target->SubClass != ITEM_SUBCLASS_WEAPON_POLEARM)
{
return false;
}
break;
default:
break;
}
}
case ITEM_SUBCLASS_WEAPON_AXE:
case ITEM_SUBCLASS_WEAPON_SWORD:
case ITEM_SUBCLASS_WEAPON_MACE:
if (sourceSub == ITEM_SUBCLASS_WEAPON_AXE ||
sourceSub == ITEM_SUBCLASS_WEAPON_SWORD ||
sourceSub == ITEM_SUBCLASS_WEAPON_MACE )
return true;
break;
case ITEM_SUBCLASS_WEAPON_AXE2:
case ITEM_SUBCLASS_WEAPON_SWORD2:
case ITEM_SUBCLASS_WEAPON_MACE2:
case ITEM_SUBCLASS_WEAPON_STAFF:
case ITEM_SUBCLASS_WEAPON_POLEARM:
if (sourceSub == ITEM_SUBCLASS_WEAPON_AXE2 ||
sourceSub == ITEM_SUBCLASS_WEAPON_SWORD2 ||
sourceSub == ITEM_SUBCLASS_WEAPON_MACE2 ||
sourceSub == ITEM_SUBCLASS_WEAPON_STAFF ||
sourceSub == ITEM_SUBCLASS_WEAPON_POLEARM )
return true;
break;
}
}
else if (AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE)
{
return true;
}
}

if (source->InventoryType != target->InventoryType)
else if (targetClass == ITEM_CLASS_ARMOR)
{
if (AllowMixedArmorTypes)
return true;
if (AllowLowerTiers && IsTieredArmorSubclass(targetSub) && TierAvailable(player, 0, sourceSub))
return true;
if (AllowMixedOffhandArmorTypes && IsValidOffhandArmor(targetSub, targetType) && IsValidOffhandArmor(sourceSub, sourceType))
return true;
if (sourceSub == ITEM_SUBCLASS_ARMOR_MISC)
return sourceType == targetType;
}

return false;
}

bool Transmogrification::IsInvTypeMismatchAllowed(const ItemTemplate *source, const ItemTemplate *target) const
{
uint32 sourceType = source->InventoryType;
uint32 targetType = target->InventoryType;
uint32 sourceClass = source->Class;
uint32 targetClass = target->Class;
uint32 sourceSub = source->SubClass;
uint32 targetSub = target->SubClass;

if (targetClass == ITEM_CLASS_WEAPON)
{
if (IsRangedWeapon(sourceClass, sourceSub))
return true;

// Main-hand to offhand restrictions - see https://wowpedia.fandom.com/wiki/Transmogrification
if (!AllowMixedWeaponHandedness && AllowMixedWeaponTypes != MIXED_WEAPONS_LOOSE)
if (targetType == INVTYPE_WEAPONMAINHAND || targetType == INVTYPE_WEAPONOFFHAND)
{
if ((source->InventoryType == INVTYPE_WEAPONMAINHAND && target->InventoryType != INVTYPE_WEAPONMAINHAND) ||
(source->InventoryType == INVTYPE_WEAPONOFFHAND && target->InventoryType != INVTYPE_WEAPONOFFHAND))
{
return false;
}

if (AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE)
return true;
if (sourceType == INVTYPE_WEAPONMAINHAND || sourceType == INVTYPE_WEAPONOFFHAND)
return (AllowMixedWeaponHandedness || AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE);
}

if (source->Class == ITEM_CLASS_WEAPON && !(IsRangedWeapon(target->Class, target->SubClass) ||
(
// [AZTH] Yehonal: fixed weapon check
(target->InventoryType == INVTYPE_WEAPON || target->InventoryType == INVTYPE_2HWEAPON || target->InventoryType == INVTYPE_WEAPONMAINHAND || target->InventoryType == INVTYPE_WEAPONOFFHAND)
&& (source->InventoryType == INVTYPE_WEAPON || source->InventoryType == INVTYPE_2HWEAPON || source->InventoryType == INVTYPE_WEAPONMAINHAND || source->InventoryType == INVTYPE_WEAPONOFFHAND)
)
))
return false;
if (source->Class == ITEM_CLASS_ARMOR &&
!((source->InventoryType == INVTYPE_CHEST || source->InventoryType == INVTYPE_ROBE) &&
(target->InventoryType == INVTYPE_CHEST || target->InventoryType == INVTYPE_ROBE)))
return false;
}
else if (targetClass == ITEM_CLASS_ARMOR)
{
if (AllowMixedOffhandArmorTypes && IsValidOffhandArmor(targetSub, targetType) && IsValidOffhandArmor(sourceSub, sourceType))
return true;
if (targetType == INVTYPE_CHEST || targetType == INVTYPE_ROBE)
return sourceType == INVTYPE_CHEST || sourceType == INVTYPE_ROBE;
}

return false;
}

return true;
bool Transmogrification::IsValidOffhandArmor(uint32 subclass, uint32 invType) const
{
return subclass == ITEM_SUBCLASS_ARMOR_BUCKLER || (subclass == ITEM_SUBCLASS_ARMOR_MISC && invType == INVTYPE_HOLDABLE) || subclass == ITEM_SUBCLASS_ARMOR_SHIELD;
}

bool Transmogrification::IsTieredArmorSubclass(uint32 subclass) const
{
return subclass == ITEM_SUBCLASS_ARMOR_PLATE || subclass == ITEM_SUBCLASS_ARMOR_MAIL || subclass == ITEM_SUBCLASS_ARMOR_LEATHER || subclass == ITEM_SUBCLASS_ARMOR_CLOTH;
}

bool Transmogrification::SuitableForTransmogrification(Player* player, ItemTemplate const* proto) const
Expand Down Expand Up @@ -763,6 +795,9 @@ bool Transmogrification::SuitableForTransmogrification(Player* player, ItemTempl
if (!IgnoreReqLevel && player->GetLevel() < proto->RequiredLevel)
return false;

if (AllowLowerTiers && TierAvailable(player, 0, proto->SubClass))
return true;

if (!IgnoreReqSpell && proto->RequiredSpell != 0 && !player->HasSpell(proto->RequiredSpell))
return false;

Expand Down Expand Up @@ -849,12 +884,65 @@ bool Transmogrification::SuitableForTransmogrification(ObjectGuid guid, ItemTemp
if (!IgnoreReqLevel && playerLevel < proto->RequiredLevel)
return false;

if (AllowLowerTiers && TierAvailable(NULL, playerGuid, proto->SubClass))
return true;

if (!IgnoreReqSpell && proto->RequiredSpell != 0 && !(CharacterDatabase.Query("SELECT `spell` FROM `character_spell` WHERE `guid` = {} and `spell` = {}", playerGuid, proto->RequiredSpell)))
return false;

return true;
}



bool Transmogrification::TierAvailable(Player *player, int playerGuid, uint32 tier) const
{
if (!player && !playerGuid) return false;
if (!IsTieredArmorSubclass(tier)) return false;

uint32 playerHighest = ITEM_SUBCLASS_ARMOR_CLOTH;
if (player)
playerHighest = GetHighestAvailableForPlayer(player);
else if (playerGuid)
playerHighest = GetHighestAvailableForPlayer(playerGuid);

switch (playerHighest)
{
case ITEM_SUBCLASS_ARMOR_PLATE:
return true;
case ITEM_SUBCLASS_ARMOR_MAIL:
return tier != ITEM_SUBCLASS_ARMOR_PLATE;
case ITEM_SUBCLASS_ARMOR_LEATHER:
return tier == ITEM_SUBCLASS_ARMOR_LEATHER || tier == ITEM_SUBCLASS_ARMOR_CLOTH;
case ITEM_SUBCLASS_ARMOR_CLOTH:
return tier == ITEM_SUBCLASS_ARMOR_CLOTH;
}

return true;
}

uint32 Transmogrification::GetHighestAvailableForPlayer(int playerGuid) const
{
for (int i = 0; i < 4; i++)
{
if (CharacterDatabase.Query("SELECT `spell` FROM `character_spell` WHERE `guid` = {} and `spell` = {}", playerGuid, AllArmorSpellIds[i]))
return AllArmorTiers[i];
}

return ITEM_SUBCLASS_ARMOR_CLOTH;
}

uint32 Transmogrification::GetHighestAvailableForPlayer(Player *player) const
{
for (int i = 0; i < 4; i++)
{
if (player->HasSpell(AllArmorSpellIds[i]))
return AllArmorTiers[i];
}

return ITEM_SUBCLASS_ARMOR_CLOTH;
}

bool Transmogrification::IsItemTransmogrifiable(ItemTemplate const* proto, ObjectGuid const &playerGuid) const
{
if (!proto)
Expand Down Expand Up @@ -1015,6 +1103,8 @@ void Transmogrification::LoadConfig(bool reload)
AllowTradeable = sConfigMgr->GetOption<bool>("Transmogrification.AllowTradeable", false);

AllowMixedArmorTypes = sConfigMgr->GetOption<bool>("Transmogrification.AllowMixedArmorTypes", false);
AllowLowerTiers = sConfigMgr->GetOption<bool>("Transmogrification.AllowLowerTiers", false);
AllowMixedOffhandArmorTypes = sConfigMgr->GetOption<bool>("Transmogrification.AllowMixedOffhandArmorTypes", false);
AllowMixedWeaponHandedness = sConfigMgr->GetOption<bool>("Transmogrification.AllowMixedWeaponHandedness", false);
AllowFishingPoles = sConfigMgr->GetOption<bool>("Transmogrification.AllowFishingPoles", false);

Expand Down Expand Up @@ -1191,6 +1281,14 @@ bool Transmogrification::GetAllowMixedArmorTypes() const
{
return AllowMixedArmorTypes;
};
bool Transmogrification::GetAllowLowerTiers() const
{
return AllowLowerTiers;
};
bool Transmogrification::GetAllowMixedOffhandArmorTypes() const
{
return AllowMixedOffhandArmorTypes;
};
uint8 Transmogrification::GetAllowMixedWeaponTypes() const
{
return AllowMixedWeaponTypes;
Expand Down
39 changes: 39 additions & 0 deletions src/Transmogrification.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,30 @@ enum TransmogAcoreStrings // Language.h might have same entries, appears when ex
LANG_CMD_TRANSMOG_COMPLETE_SYNC = 11116,
};

enum ArmorClassSpellIDs
{
SPELL_PLATE = 750,
SPELL_MAIL = 8737,
SPELL_LEATHER = 9077,
SPELL_CLOTH = 9078
};

const uint32 AllArmorSpellIds[4] =
{
SPELL_PLATE,
SPELL_MAIL,
SPELL_LEATHER,
SPELL_CLOTH
};

const uint32 AllArmorTiers[4] =
{
ITEM_SUBCLASS_ARMOR_PLATE,
ITEM_SUBCLASS_ARMOR_MAIL,
ITEM_SUBCLASS_ARMOR_LEATHER,
ITEM_SUBCLASS_ARMOR_CLOTH
};

class Transmogrification
{
public:
Expand Down Expand Up @@ -134,6 +158,8 @@ class Transmogrification
bool AllowTradeable;

bool AllowMixedArmorTypes;
bool AllowLowerTiers;
bool AllowMixedOffhandArmorTypes;
bool AllowMixedWeaponHandedness;
bool AllowFishingPoles;

Expand Down Expand Up @@ -193,6 +219,8 @@ class Transmogrification
uint32 GetTokenAmount() const;

bool GetAllowMixedArmorTypes() const;
bool GetAllowLowerTiers() const;
bool GetAllowMixedOffhandArmorTypes() const;
uint8 GetAllowMixedWeaponTypes() const;

// Config
Expand All @@ -209,6 +237,17 @@ class Transmogrification
bool EnableResetRetroActiveAppearances() const;
[[nodiscard]] bool IsEnabled() const;

bool IsValidOffhandArmor(uint32 subclass, uint32 invType) const;
bool IsTieredArmorSubclass(uint32 subclass) const;

uint32 GetHighestAvailableForPlayer(Player* player) const;
uint32 GetHighestAvailableForPlayer(int playerGuid) const;

bool TierAvailable(Player* player, int playerGuid, uint32 tierSpell) const;

bool IsInvTypeMismatchAllowed (const ItemTemplate *source, const ItemTemplate *target) const;
bool IsSubclassMismatchAllowed (Player *player, const ItemTemplate *source, const ItemTemplate *target) const;

// Transmog Plus
bool IsTransmogPlusEnabled;
std::vector<uint32> MembershipIds;
Expand Down

0 comments on commit a571805

Please sign in to comment.