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:
@@ -2369,7 +2369,7 @@ namespace Game.Entities
|
||||
return stats.GenerateHealth(cInfo);
|
||||
}
|
||||
|
||||
float GetHealthMultiplierForTarget(WorldObject target)
|
||||
public override float GetHealthMultiplierForTarget(WorldObject target)
|
||||
{
|
||||
if (!HasScalableLevels())
|
||||
return 1.0f;
|
||||
@@ -2388,7 +2388,7 @@ namespace Game.Entities
|
||||
return stats.GenerateBaseDamage(cInfo);
|
||||
}
|
||||
|
||||
float GetDamageMultiplierForTarget(WorldObject target)
|
||||
public override float GetDamageMultiplierForTarget(WorldObject target)
|
||||
{
|
||||
if (!HasScalableLevels())
|
||||
return 1.0f;
|
||||
@@ -2405,7 +2405,7 @@ namespace Game.Entities
|
||||
return stats.GenerateArmor(cInfo);
|
||||
}
|
||||
|
||||
float GetArmorMultiplierForTarget(WorldObject target)
|
||||
public override float GetArmorMultiplierForTarget(WorldObject target)
|
||||
{
|
||||
if (!HasScalableLevels())
|
||||
return 1.0f;
|
||||
|
||||
+11
-18
@@ -1497,11 +1497,11 @@ namespace Game.Entities
|
||||
return ItemTransmogrificationWeaponCategory.Invalid;
|
||||
}
|
||||
|
||||
static int[] ItemTransmogrificationSlots =
|
||||
public static int[] ItemTransmogrificationSlots =
|
||||
{
|
||||
-1, // INVTYPE_NON_EQUIP
|
||||
EquipmentSlot.Head, // INVTYPE_HEAD
|
||||
EquipmentSlot.Neck, // INVTYPE_NECK
|
||||
-1, // INVTYPE_NECK
|
||||
EquipmentSlot.Shoulders, // INVTYPE_SHOULDERS
|
||||
EquipmentSlot.Shirt, // INVTYPE_BODY
|
||||
EquipmentSlot.Chest, // INVTYPE_CHEST
|
||||
@@ -1516,15 +1516,15 @@ namespace Game.Entities
|
||||
EquipmentSlot.OffHand, // INVTYPE_SHIELD
|
||||
EquipmentSlot.MainHand, // INVTYPE_RANGED
|
||||
EquipmentSlot.Cloak, // INVTYPE_CLOAK
|
||||
-1, // INVTYPE_2HWEAPON
|
||||
EquipmentSlot.MainHand, // INVTYPE_2HWEAPON
|
||||
-1, // INVTYPE_BAG
|
||||
EquipmentSlot.Tabard, // INVTYPE_TABARD
|
||||
EquipmentSlot.Chest, // INVTYPE_ROBE
|
||||
EquipmentSlot.MainHand, // INVTYPE_WEAPONMAINHAND
|
||||
EquipmentSlot.OffHand, // INVTYPE_WEAPONOFFHAND
|
||||
EquipmentSlot.MainHand, // INVTYPE_WEAPONOFFHAND
|
||||
EquipmentSlot.OffHand, // INVTYPE_HOLDABLE
|
||||
-1, // INVTYPE_AMMO
|
||||
EquipmentSlot.MainHand, // INVTYPE_THROWN
|
||||
-1, // INVTYPE_THROWN
|
||||
EquipmentSlot.MainHand, // INVTYPE_RANGEDRIGHT
|
||||
-1, // INVTYPE_QUIVER
|
||||
-1 // INVTYPE_RELIC
|
||||
@@ -1566,22 +1566,15 @@ namespace Game.Entities
|
||||
case ItemClass.Armor:
|
||||
if ((ItemSubClassArmor)source.GetSubClass() != ItemSubClassArmor.Cosmetic)
|
||||
return false;
|
||||
if (source.GetInventoryType() != target.GetInventoryType())
|
||||
if (ItemTransmogrificationSlots[(int)source.GetInventoryType()] != ItemTransmogrificationSlots[(int)target.GetInventoryType()])
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (source.GetInventoryType() != target.GetInventoryType())
|
||||
{
|
||||
int sourceSlot = ItemTransmogrificationSlots[(int)source.GetInventoryType()];
|
||||
if (sourceSlot == -1 && source.GetInventoryType() == InventoryType.Weapon && (target.GetInventoryType() == InventoryType.WeaponMainhand || target.GetInventoryType() == InventoryType.WeaponOffhand))
|
||||
sourceSlot = ItemTransmogrificationSlots[(int)target.GetInventoryType()];
|
||||
|
||||
if (sourceSlot != ItemTransmogrificationSlots[(int)target.GetInventoryType()])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2531,11 +2524,11 @@ namespace Game.Entities
|
||||
public uint GetScalingStatDistribution() { return _bonusData.ScalingStatDistribution; }
|
||||
|
||||
public void SetRefundRecipient(ObjectGuid guid) { m_refundRecipient = guid; }
|
||||
public void SetPaidMoney(uint money) { m_paidMoney = money; }
|
||||
public void SetPaidMoney(ulong money) { m_paidMoney = money; }
|
||||
public void SetPaidExtendedCost(uint iece) { m_paidExtendedCost = iece; }
|
||||
|
||||
public ObjectGuid GetRefundRecipient() { return m_refundRecipient; }
|
||||
public uint GetPaidMoney() { return m_paidMoney; }
|
||||
public ulong GetPaidMoney() { return m_paidMoney; }
|
||||
public uint GetPaidExtendedCost() { return m_paidExtendedCost; }
|
||||
|
||||
public uint GetScriptId() { return GetTemplate().ScriptId; }
|
||||
@@ -2637,7 +2630,7 @@ namespace Game.Entities
|
||||
|
||||
ItemUpdateState uState;
|
||||
uint m_paidExtendedCost;
|
||||
uint m_paidMoney;
|
||||
ulong m_paidMoney;
|
||||
ObjectGuid m_refundRecipient;
|
||||
byte m_slot;
|
||||
Bag m_container;
|
||||
|
||||
@@ -2417,6 +2417,14 @@ namespace Game.Entities
|
||||
SendMessageToSet(sound, true);
|
||||
}
|
||||
|
||||
public void PlayDirectMusic(uint musicId, Player target = null)
|
||||
{
|
||||
if (target)
|
||||
target.SendPacket(new PlayMusic(musicId));
|
||||
else
|
||||
SendMessageToSet(new PlayMusic(musicId), true);
|
||||
}
|
||||
|
||||
public void DestroyForNearbyPlayers()
|
||||
{
|
||||
if (!IsInWorld)
|
||||
|
||||
@@ -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;
|
||||
|
||||
+15
-18
@@ -656,38 +656,37 @@ namespace Game.Entities
|
||||
|
||||
float GetUnitCriticalChance(WeaponAttackType attackType, Unit victim)
|
||||
{
|
||||
float crit;
|
||||
|
||||
float chance = 0.0f;
|
||||
if (IsTypeId(TypeId.Player))
|
||||
{
|
||||
switch (attackType)
|
||||
{
|
||||
case WeaponAttackType.BaseAttack:
|
||||
crit = GetFloatValue(PlayerFields.CritPercentage);
|
||||
chance = GetFloatValue(PlayerFields.CritPercentage);
|
||||
break;
|
||||
case WeaponAttackType.OffAttack:
|
||||
crit = GetFloatValue(PlayerFields.OffhandCritPercentage);
|
||||
chance = GetFloatValue(PlayerFields.OffhandCritPercentage);
|
||||
break;
|
||||
case WeaponAttackType.RangedAttack:
|
||||
crit = GetFloatValue(PlayerFields.RangedCritPercentage);
|
||||
break;
|
||||
default:
|
||||
crit = 0.0f;
|
||||
chance = GetFloatValue(PlayerFields.RangedCritPercentage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
crit = 5.0f;
|
||||
crit += GetTotalAuraModifier(AuraType.ModWeaponCritPercent);
|
||||
crit += GetTotalAuraModifier(AuraType.ModCritPct);
|
||||
if (!ToCreature().GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoCrit))
|
||||
{
|
||||
chance = 5.0f;
|
||||
chance += GetTotalAuraModifier(AuraType.ModWeaponCritPercent);
|
||||
chance += GetTotalAuraModifier(AuraType.ModCritPct);
|
||||
}
|
||||
}
|
||||
|
||||
// flat aura mods
|
||||
if (attackType == WeaponAttackType.RangedAttack)
|
||||
crit += victim.GetTotalAuraModifier(AuraType.ModAttackerRangedCritChance);
|
||||
chance += victim.GetTotalAuraModifier(AuraType.ModAttackerRangedCritChance);
|
||||
else
|
||||
crit += victim.GetTotalAuraModifier(AuraType.ModAttackerMeleeCritChance);
|
||||
chance += victim.GetTotalAuraModifier(AuraType.ModAttackerMeleeCritChance);
|
||||
|
||||
var critChanceForCaster = victim.GetAuraEffectsByType(AuraType.ModCritChanceForCaster);
|
||||
foreach (AuraEffect aurEff in critChanceForCaster)
|
||||
@@ -695,14 +694,12 @@ namespace Game.Entities
|
||||
if (aurEff.GetCasterGUID() != GetGUID())
|
||||
continue;
|
||||
|
||||
crit += aurEff.GetAmount();
|
||||
chance += aurEff.GetAmount();
|
||||
}
|
||||
|
||||
crit += victim.GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance);
|
||||
chance += victim.GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance);
|
||||
|
||||
if (crit < 0.0f)
|
||||
crit = 0.0f;
|
||||
return crit;
|
||||
return Math.Max(chance, 0.0f);
|
||||
}
|
||||
float GetUnitDodgeChance(WeaponAttackType attType, Unit victim)
|
||||
{
|
||||
|
||||
@@ -688,19 +688,18 @@ namespace Game.Entities
|
||||
}
|
||||
public Unit GetMeleeHitRedirectTarget(Unit victim, SpellInfo spellInfo = null)
|
||||
{
|
||||
var hitTriggerAuras = victim.GetAuraEffectsByType(AuraType.AddCasterHitTrigger);
|
||||
foreach (var i in hitTriggerAuras)
|
||||
var interceptAuras = victim.GetAuraEffectsByType(AuraType.InterceptMeleeRangedAttacks);
|
||||
foreach (var i in interceptAuras)
|
||||
{
|
||||
Unit magnet = i.GetCaster();
|
||||
if (magnet != null)
|
||||
if (_IsValidAttackTarget(magnet, spellInfo) && magnet.IsWithinLOSInMap(this)
|
||||
&& (spellInfo == null || (spellInfo.CheckExplicitTarget(this, magnet) == SpellCastResult.SpellCastOk
|
||||
&& spellInfo.CheckTarget(this, magnet, false) == SpellCastResult.SpellCastOk)))
|
||||
if (RandomHelper.randChance(i.GetAmount()))
|
||||
{
|
||||
i.GetBase().DropCharge(AuraRemoveMode.Expire);
|
||||
return magnet;
|
||||
}
|
||||
{
|
||||
i.GetBase().DropCharge(AuraRemoveMode.Expire);
|
||||
return magnet;
|
||||
}
|
||||
}
|
||||
return victim;
|
||||
}
|
||||
@@ -2053,10 +2052,7 @@ namespace Game.Entities
|
||||
// 6.CRIT
|
||||
tmp = crit_chance;
|
||||
if (tmp > 0 && roll < (sum += tmp))
|
||||
{
|
||||
if (GetTypeId() != TypeId.Unit || !(ToCreature().GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoCrit)))
|
||||
return MeleeHitOutcome.Crit;
|
||||
}
|
||||
return MeleeHitOutcome.Crit;
|
||||
|
||||
// 7. CRUSHING
|
||||
// mobs can score crushing blows if they're 4 or more levels above victim
|
||||
|
||||
@@ -182,7 +182,6 @@ namespace Game.Entities
|
||||
|
||||
public SpellInfo GetSpellInfo()
|
||||
{
|
||||
/// WORKAROUND: unfinished new proc system
|
||||
if (_spell)
|
||||
return _spell.GetSpellInfo();
|
||||
if (_damageInfo != null)
|
||||
@@ -194,7 +193,6 @@ namespace Game.Entities
|
||||
}
|
||||
public SpellSchoolMask GetSchoolMask()
|
||||
{
|
||||
/// WORKAROUND: unfinished new proc system
|
||||
if (_spell)
|
||||
return _spell.GetSpellInfo().GetSchoolMask();
|
||||
if (_damageInfo != null)
|
||||
|
||||
@@ -752,6 +752,13 @@ namespace Game.Entities
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Spell crit suppression
|
||||
if (victim.GetTypeId() == TypeId.Unit)
|
||||
{
|
||||
int levelDiff = (int)(victim.GetLevelForTarget(this) - getLevel());
|
||||
crit_chance -= levelDiff * 1.0f;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -776,7 +783,7 @@ namespace Game.Entities
|
||||
if (aurEff.GetCasterGUID() == GetGUID() && aurEff.IsAffectingSpell(spellProto))
|
||||
crit_chance += aurEff.GetAmount();
|
||||
|
||||
return crit_chance > 0.0f ? crit_chance : 0.0f;
|
||||
return Math.Max(crit_chance, 0.0f);
|
||||
}
|
||||
|
||||
// Calculate spell hit result can be:
|
||||
@@ -1813,7 +1820,7 @@ namespace Game.Entities
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// use provided list of auras which can proc
|
||||
if (!procAuras.Empty())
|
||||
if (procAuras != null)
|
||||
{
|
||||
foreach (AuraApplication aurApp in procAuras)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user