Fixed appearance validation
Implemented proper facial hair validation Implemented transmog Set fix interaction of spells like Shadowmeld with Threat reducing effects
This commit is contained in:
@@ -675,6 +675,19 @@ namespace Game.Entities
|
||||
_owner.GetPlayer().RemoveDynamicValue(PlayerDynamicFields.ConditionalTransmog, itemModifiedAppearance.Id);
|
||||
_temporaryAppearances.Remove(itemModifiedAppearance.Id);
|
||||
}
|
||||
|
||||
ItemRecord item = CliDB.ItemStorage.LookupByKey(itemModifiedAppearance.ItemID);
|
||||
if (item != null)
|
||||
{
|
||||
int transmogSlot = Item.ItemTransmogrificationSlots[(int)item.inventoryType];
|
||||
if (transmogSlot >= 0)
|
||||
_owner.GetPlayer().UpdateCriteria(CriteriaTypes.AppearanceUnlockedBySlot, (ulong)transmogSlot, 1);
|
||||
}
|
||||
|
||||
var sets = Global.DB2Mgr.GetTransmogSetsForItemModifiedAppearance(itemModifiedAppearance.Id);
|
||||
foreach (TransmogSetRecord set in sets)
|
||||
if (IsSetCompleted(set.Id))
|
||||
_owner.GetPlayer().UpdateCriteria(CriteriaTypes.TransmogSetUnlocked, set.TransmogSetGroupID);
|
||||
}
|
||||
|
||||
void AddTemporaryAppearance(ObjectGuid itemGuid, ItemModifiedAppearanceRecord itemModifiedAppearance)
|
||||
@@ -763,6 +776,54 @@ namespace Game.Entities
|
||||
_owner.SendPacket(transmogCollectionUpdate);
|
||||
}
|
||||
|
||||
public void AddTransmogSet(uint transmogSetId)
|
||||
{
|
||||
var items = Global.DB2Mgr.GetTransmogSetItems(transmogSetId);
|
||||
if (items.Empty())
|
||||
return;
|
||||
|
||||
foreach (TransmogSetItemRecord item in items)
|
||||
{
|
||||
ItemModifiedAppearanceRecord itemModifiedAppearance = CliDB.ItemModifiedAppearanceStorage.LookupByKey(item.ItemModifiedAppearanceID);
|
||||
if (itemModifiedAppearance == null)
|
||||
continue;
|
||||
|
||||
AddItemAppearance(itemModifiedAppearance);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsSetCompleted(uint transmogSetId)
|
||||
{
|
||||
var transmogSetItems = Global.DB2Mgr.GetTransmogSetItems(transmogSetId);
|
||||
if (transmogSetItems.Empty())
|
||||
return false;
|
||||
|
||||
int[] knownPieces = new int[EquipmentSlot.End];
|
||||
for (var i = 0; i < EquipmentSlot.End; ++i)
|
||||
knownPieces[i] = -1;
|
||||
|
||||
foreach (TransmogSetItemRecord transmogSetItem in transmogSetItems)
|
||||
{
|
||||
ItemModifiedAppearanceRecord itemModifiedAppearance = CliDB.ItemModifiedAppearanceStorage.LookupByKey(transmogSetItem.ItemModifiedAppearanceID);
|
||||
if (itemModifiedAppearance == null)
|
||||
continue;
|
||||
|
||||
ItemRecord item = CliDB.ItemStorage.LookupByKey(itemModifiedAppearance.ItemID);
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
int transmogSlot = Item.ItemTransmogrificationSlots[(int)item.inventoryType];
|
||||
if (transmogSlot < 0 || knownPieces[transmogSlot] == 1)
|
||||
continue;
|
||||
|
||||
(var hasAppearance, var isTemporary) = HasItemAppearance(transmogSetItem.ItemModifiedAppearanceID);
|
||||
|
||||
knownPieces[transmogSlot] = (hasAppearance && !isTemporary) ? 1 : 0;
|
||||
}
|
||||
|
||||
return !knownPieces.Contains(0);
|
||||
}
|
||||
|
||||
public bool HasToy(uint itemId) { return _toys.ContainsKey(itemId); }
|
||||
public Dictionary<uint, bool> GetAccountToys() { return _toys; }
|
||||
public Dictionary<uint, HeirloomData> GetAccountHeirlooms() { return _heirlooms; }
|
||||
|
||||
@@ -56,11 +56,13 @@ namespace Game.Entities
|
||||
public void ResetCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, bool evenIfCriteriaComplete = false)
|
||||
{
|
||||
m_achievementSys.ResetCriteria(type, miscValue1, miscValue2, evenIfCriteriaComplete);
|
||||
m_questObjectiveCriteriaMgr.ResetCriteria(type, miscValue1, miscValue2, evenIfCriteriaComplete);
|
||||
}
|
||||
|
||||
public void UpdateCriteria(CriteriaTypes type, ulong miscValue1 = 0, ulong miscValue2 = 0, ulong miscValue3 = 0, Unit unit = null)
|
||||
{
|
||||
m_achievementSys.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
|
||||
m_questObjectiveCriteriaMgr.UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this);
|
||||
|
||||
// Update only individual achievement criteria here, otherwise we may get multiple updates
|
||||
// from a single boss kill
|
||||
|
||||
@@ -261,7 +261,7 @@ namespace Game.Entities
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
item.SetRefundRecipient(GetGUID());
|
||||
item.SetPaidMoney(result.Read<uint>(0));
|
||||
item.SetPaidMoney(result.Read<ulong>(0));
|
||||
item.SetPaidExtendedCost(result.Read<ushort>(1));
|
||||
AddRefundReference(item.GetGUID());
|
||||
}
|
||||
@@ -2373,6 +2373,7 @@ namespace Game.Entities
|
||||
|
||||
// load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria)
|
||||
m_achievementSys.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Achievements), holder.GetResult(PlayerLoginQueryLoad.CriteriaProgress));
|
||||
m_questObjectiveCriteriaMgr.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.QuestStatusObjectivesCriteria), holder.GetResult(PlayerLoginQueryLoad.QuestStatusObjectivesCriteriaProgress));
|
||||
|
||||
ulong money = result.Read<ulong>(8);
|
||||
if (money > PlayerConst.MaxMoneyAmount)
|
||||
@@ -3035,7 +3036,7 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
m_achievementSys.CheckAllAchievementCriteria(this);
|
||||
|
||||
m_questObjectiveCriteriaMgr.CheckAllQuestObjectiveCriteria(this);
|
||||
return true;
|
||||
}
|
||||
public void SaveToDB(bool create = false)
|
||||
@@ -3383,6 +3384,7 @@ namespace Game.Entities
|
||||
_SaveSkills(trans);
|
||||
m_achievementSys.SaveToDB(trans);
|
||||
reputationMgr.SaveToDB(trans);
|
||||
m_questObjectiveCriteriaMgr.SaveToDB(trans);
|
||||
_SaveEquipmentSets(trans);
|
||||
GetSession().SaveTutorialsData(trans); // changed only while character in game
|
||||
_SaveInstanceTimeRestrictions(trans);
|
||||
|
||||
@@ -202,6 +202,7 @@ namespace Game.Entities
|
||||
public uint m_timeSyncClient;
|
||||
public uint m_timeSyncServer;
|
||||
ReputationMgr reputationMgr;
|
||||
QuestObjectiveCriteriaManager m_questObjectiveCriteriaMgr;
|
||||
public AtLoginFlags atLoginFlags;
|
||||
public bool m_itemUpdateQueueBlocked;
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Game.Entities
|
||||
|
||||
SendItemRefundResult(item, iece, 0);
|
||||
|
||||
uint moneyRefund = item.GetPaidMoney(); // item. will be invalidated in DestroyItem
|
||||
ulong moneyRefund = item.GetPaidMoney(); // item. will be invalidated in DestroyItem
|
||||
|
||||
// Save all relevant data to DB to prevent desynchronisation exploits
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
@@ -142,7 +142,7 @@ namespace Game.Entities
|
||||
|
||||
// Grant back money
|
||||
if (moneyRefund != 0)
|
||||
ModifyMoney(moneyRefund); // Saved in SaveInventoryAndGoldToDB
|
||||
ModifyMoney((long)moneyRefund); // Saved in SaveInventoryAndGoldToDB
|
||||
|
||||
SaveInventoryAndGoldToDB(trans);
|
||||
|
||||
@@ -2483,7 +2483,7 @@ namespace Game.Entities
|
||||
}
|
||||
AutoUnequipOffhandIfNeed();
|
||||
}
|
||||
bool _StoreOrEquipNewItem(uint vendorslot, uint item, byte count, byte bag, byte slot, int price, ItemTemplate pProto, Creature pVendor, VendorItem crItem, bool bStore)
|
||||
bool _StoreOrEquipNewItem(uint vendorslot, uint item, byte count, byte bag, byte slot, long price, ItemTemplate pProto, Creature pVendor, VendorItem crItem, bool bStore)
|
||||
{
|
||||
uint stacks = count / pProto.GetBuyCount();
|
||||
List<ItemPosCount> vDest = new List<ItemPosCount>();
|
||||
@@ -3632,7 +3632,7 @@ namespace Game.Entities
|
||||
// check current item amount if it limited
|
||||
if (crItem.maxcount != 0)
|
||||
{
|
||||
if (creature.GetVendorItemCurrentCount(crItem) < pProto.GetBuyCount() * count)
|
||||
if (creature.GetVendorItemCurrentCount(crItem) < count)
|
||||
{
|
||||
SendBuyError(BuyResult.ItemAlreadySold, creature, item);
|
||||
return false;
|
||||
@@ -3722,19 +3722,20 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
uint price = 0;
|
||||
ulong price = 0;
|
||||
if (crItem.IsGoldRequired(pProto) && pProto.GetBuyPrice() > 0) //Assume price cannot be negative (do not know why it is int32)
|
||||
{
|
||||
uint maxCount = (uint)(Int64.MaxValue / pProto.GetBuyPrice());
|
||||
float buyPricePerItem = pProto.GetBuyPrice() / pProto.GetBuyCount();
|
||||
ulong maxCount = (ulong)(PlayerConst.MaxMoneyAmount / buyPricePerItem);
|
||||
if (count > maxCount)
|
||||
{
|
||||
Log.outError(LogFilter.Player, "Player {0} tried to buy {1} item id {2}, causing overflow", GetName(), count, pProto.GetId());
|
||||
count = (byte)maxCount;
|
||||
}
|
||||
price = pProto.GetBuyPrice() * count; //it should not exceed MAX_MONEY_AMOUNT
|
||||
price = (ulong)(buyPricePerItem * count); //it should not exceed MAX_MONEY_AMOUNT
|
||||
|
||||
// reputation discount
|
||||
price = (uint)Math.Floor(price * GetReputationPriceDiscount(creature));
|
||||
price = (ulong)Math.Floor(price * GetReputationPriceDiscount(creature));
|
||||
|
||||
int priceMod = GetTotalAuraModifier(AuraType.ModVendorItemsPrices);
|
||||
if (priceMod != 0)
|
||||
|
||||
@@ -540,6 +540,11 @@ namespace Game.Entities
|
||||
{
|
||||
AddQuest(quest, questGiver);
|
||||
|
||||
foreach (QuestObjective obj in quest.Objectives)
|
||||
if (obj.Type == QuestObjectiveType.CriteriaTree)
|
||||
if (m_questObjectiveCriteriaMgr.HasCompletedObjective(obj))
|
||||
KillCreditCriteriaTreeObjective(obj);
|
||||
|
||||
if (CanCompleteQuest(quest.Id))
|
||||
CompleteQuest(quest.Id);
|
||||
|
||||
@@ -700,11 +705,20 @@ namespace Game.Entities
|
||||
|
||||
foreach (QuestObjective obj in quest.Objectives)
|
||||
{
|
||||
if (obj.Type == QuestObjectiveType.MinReputation || obj.Type == QuestObjectiveType.MaxReputation)
|
||||
switch (obj.Type)
|
||||
{
|
||||
FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(obj.ObjectID);
|
||||
if (factionEntry != null)
|
||||
GetReputationMgr().SetVisible(factionEntry);
|
||||
case QuestObjectiveType.MinReputation:
|
||||
case QuestObjectiveType.MaxReputation:
|
||||
FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(obj.ObjectID);
|
||||
if (factionEntry != null)
|
||||
GetReputationMgr().SetVisible(factionEntry);
|
||||
break;
|
||||
case QuestObjectiveType.CriteriaTree:
|
||||
if (quest.HasFlagEx(QuestFlagsEx.ClearProgressOfCriteriaTreeObjectivesOnAccept))
|
||||
m_questObjectiveCriteriaMgr.ResetCriteriaTree((uint)obj.ObjectID);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1423,7 +1437,7 @@ namespace Game.Entities
|
||||
|
||||
public bool SatisfyQuestConditions(Quest qInfo, bool msg)
|
||||
{
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.QuestAccept, qInfo.Id, this))
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.QuestAvailable, qInfo.Id, this))
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
@@ -1818,7 +1832,7 @@ namespace Game.Entities
|
||||
if (quest == null)
|
||||
continue;
|
||||
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.QuestAccept, quest.Id, this))
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.QuestAvailable, quest.Id, this))
|
||||
continue;
|
||||
|
||||
QuestStatus status = GetQuestStatus(questId);
|
||||
@@ -1844,7 +1858,7 @@ namespace Game.Entities
|
||||
if (quest == null)
|
||||
continue;
|
||||
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.QuestAccept, quest.Id, this))
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.QuestAvailable, quest.Id, this))
|
||||
continue;
|
||||
|
||||
QuestStatus status = GetQuestStatus(questId);
|
||||
@@ -2273,6 +2287,21 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public void KillCreditCriteriaTreeObjective(QuestObjective questObjective)
|
||||
{
|
||||
if (questObjective.Type != QuestObjectiveType.CriteriaTree)
|
||||
return;
|
||||
|
||||
if (GetQuestStatus(questObjective.QuestID) == QuestStatus.Incomplete)
|
||||
{
|
||||
SetQuestObjectiveData(questObjective, 1);
|
||||
SendQuestUpdateAddCreditSimple(questObjective);
|
||||
|
||||
if (CanCompleteQuest(questObjective.QuestID))
|
||||
CompleteQuest(questObjective.QuestID);
|
||||
}
|
||||
}
|
||||
|
||||
public void TalkedToCreature(uint entry, ObjectGuid guid)
|
||||
{
|
||||
ushort addTalkCount = 1;
|
||||
@@ -2579,6 +2608,7 @@ namespace Game.Entities
|
||||
return false;
|
||||
break;
|
||||
case QuestObjectiveType.AreaTrigger:
|
||||
case QuestObjectiveType.CriteriaTree:
|
||||
if (GetQuestObjectiveData(quest, objective.StorageIndex) == 0)
|
||||
return false;
|
||||
break;
|
||||
|
||||
@@ -1844,7 +1844,7 @@ namespace Game.Entities
|
||||
{
|
||||
for (CurrentSpellTypes i = 0; i < CurrentSpellTypes.Max; ++i)
|
||||
{
|
||||
Spell spell = m_currentSpells[i];
|
||||
Spell spell = GetCurrentSpell(i);
|
||||
if (spell != null)
|
||||
RestoreSpellMods(spell, ownerAuraId, aura);
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ namespace Game.Entities
|
||||
|
||||
m_achievementSys = new PlayerAchievementMgr(this);
|
||||
reputationMgr = new ReputationMgr(this);
|
||||
m_questObjectiveCriteriaMgr = new QuestObjectiveCriteriaManager(this);
|
||||
m_sceneMgr = new SceneMgr(this);
|
||||
|
||||
m_bgBattlegroundQueueID[0] = new BgBattlegroundQueueID_Rec();
|
||||
@@ -283,7 +284,7 @@ namespace Game.Entities
|
||||
|
||||
InitRunes();
|
||||
|
||||
SetUInt32Value(PlayerFields.Coinage, WorldConfig.GetUIntValue(WorldCfg.StartPlayerMoney));
|
||||
SetUInt64Value(PlayerFields.Coinage, WorldConfig.GetUIntValue(WorldCfg.StartPlayerMoney));
|
||||
SetCurrency(CurrencyTypes.ApexisCrystals, WorldConfig.GetUIntValue(WorldCfg.CurrencyStartApexisCrystals));
|
||||
SetCurrency(CurrencyTypes.JusticePoints, WorldConfig.GetUIntValue(WorldCfg.CurrencyStartJusticePoints));
|
||||
|
||||
@@ -2551,7 +2552,7 @@ namespace Game.Entities
|
||||
GetSession().SendStablePet(guid);
|
||||
break;
|
||||
case GossipOption.Trainer:
|
||||
GetSession().SendTrainerList(guid, menuItemData.TrainerId);
|
||||
GetSession().SendTrainerList(source.ToCreature(), menuItemData.TrainerId);
|
||||
break;
|
||||
case GossipOption.Learndualspec:
|
||||
break;
|
||||
@@ -4086,45 +4087,42 @@ namespace Game.Entities
|
||||
|
||||
return ComponentFlagsMatch(entry, GetSelectionFromContext(2, class_));
|
||||
}
|
||||
static bool IsSectionValid(Race race, Class class_, Gender gender, CharBaseSectionVariation variation, byte variationIndex, byte colorIndex, bool create)
|
||||
{
|
||||
CharSectionsRecord section = Global.DB2Mgr.GetCharSectionEntry(race, gender, variation, variationIndex, colorIndex);
|
||||
if (section != null)
|
||||
return IsSectionFlagValid(section, class_, create);
|
||||
|
||||
return false;
|
||||
}
|
||||
public static bool IsValidGender(Gender _gender) { return _gender <= Gender.Female; }
|
||||
public static bool IsValidClass(Class _class) { return Convert.ToBoolean((1 << ((int)_class - 1)) & (int)Class.ClassMaskAllPlayable); }
|
||||
public static bool IsValidRace(Race _race) { return Convert.ToBoolean((1 << ((int)_race - 1)) & (int)Race.RaceMaskAllPlayable); }
|
||||
|
||||
public static bool ValidateAppearance(Race race, Class class_, Gender gender, byte hairID, byte hairColor, byte faceID, byte facialHairId, byte skinColor, Array<byte> customDisplay, bool create = false)
|
||||
{
|
||||
CharSectionsRecord skin = Global.DB2Mgr.GetCharSectionEntry(race, CharSectionType.Skin, gender, 0, skinColor);
|
||||
if (skin == null)
|
||||
if (!IsSectionValid(race, class_, gender, CharBaseSectionVariation.Skin, 0, skinColor, create))
|
||||
return false;
|
||||
|
||||
if (!IsSectionFlagValid(skin, class_, create))
|
||||
if (!IsSectionValid(race, class_, gender, CharBaseSectionVariation.Face, faceID, skinColor, create))
|
||||
return false;
|
||||
|
||||
CharSectionsRecord face = Global.DB2Mgr.GetCharSectionEntry(race, CharSectionType.Face, gender, faceID, skinColor);
|
||||
if (face == null)
|
||||
if (!IsSectionValid(race, class_, gender, CharBaseSectionVariation.Hair, hairID, hairColor, create))
|
||||
return false;
|
||||
|
||||
if (!IsSectionFlagValid(face, class_, create))
|
||||
if (!IsSectionValid(race, class_, gender, CharBaseSectionVariation.FacialHair, facialHairId, hairColor, create))
|
||||
if (Global.DB2Mgr.HasCharSections(race, gender, CharBaseSectionVariation.FacialHair) || !Global.DB2Mgr.HasCharacterFacialHairStyle(race, gender, facialHairId))
|
||||
return false;
|
||||
|
||||
if (!IsSectionValid(race, class_, gender, CharBaseSectionVariation.CustomDisplay1, customDisplay[0], 0, create))
|
||||
return false;
|
||||
|
||||
CharSectionsRecord hair = Global.DB2Mgr.GetCharSectionEntry(race, CharSectionType.Hair, gender, hairID, hairColor);
|
||||
if (hair == null)
|
||||
if (!IsSectionValid(race, class_, gender, CharBaseSectionVariation.CustomDisplay2, customDisplay[1], 0, create))
|
||||
return false;
|
||||
|
||||
if (!IsSectionFlagValid(hair, class_, create))
|
||||
if (!IsSectionValid(race, class_, gender, CharBaseSectionVariation.CustomDisplay3, customDisplay[2], 0, create))
|
||||
return false;
|
||||
|
||||
CharSectionsRecord facialHair = Global.DB2Mgr.GetCharSectionEntry(race, CharSectionType.Hair, gender, facialHairId, hairColor);
|
||||
if (facialHair == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < PlayerConst.CustomDisplaySize; ++i)
|
||||
{
|
||||
CharSectionsRecord entry = Global.DB2Mgr.GetCharSectionEntry(race, (CharSectionType.CustomDisplay1 + i * 2), gender, customDisplay[i], 0);
|
||||
if (entry != null)
|
||||
if (!IsSectionFlagValid(entry, class_, create))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5125,8 +5123,8 @@ namespace Game.Entities
|
||||
SetMoney((ulong)(GetMoney() > (ulong)-amount ? (long)GetMoney() + amount : 0));
|
||||
else
|
||||
{
|
||||
if (GetMoney() < (ulong)(PlayerConst.MaxMoneyAmount - amount))
|
||||
SetMoney((ulong)((long)GetMoney() + amount));
|
||||
if (GetMoney() <= (PlayerConst.MaxMoneyAmount - (ulong)amount))
|
||||
SetMoney((ulong)(GetMoney() + (ulong)amount));
|
||||
else
|
||||
{
|
||||
if (sendError)
|
||||
@@ -5514,6 +5512,7 @@ namespace Game.Entities
|
||||
SendEquipmentSetList();
|
||||
|
||||
m_achievementSys.SendAllData(this);
|
||||
m_questObjectiveCriteriaMgr.SendAllData(this);
|
||||
|
||||
// SMSG_LOGIN_SETTIMESPEED
|
||||
float TimeSpeed = 0.01666667f;
|
||||
|
||||
Reference in New Issue
Block a user