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:
hondacrx
2017-08-24 18:01:44 -04:00
parent 7934d51702
commit 0707f9b377
71 changed files with 2968 additions and 632 deletions
+61
View File
@@ -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
+4 -2
View File
@@ -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);
+1
View File
@@ -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;
+9 -8
View File
@@ -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)
+37 -7
View File
@@ -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;
+1 -1
View File
@@ -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);
}
+24 -25
View File
@@ -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;