initial trading post it have mem leak and dragonriding base

This commit is contained in:
luis
2026-03-14 07:08:14 -03:00
parent 19177a9f6a
commit e9876286b9
23 changed files with 1072 additions and 16 deletions
@@ -0,0 +1,35 @@
-- Perks Program - Purchases
DROP TABLE IF EXISTS `character_perks_purchases`;
CREATE TABLE `character_perks_purchases` (
`guid` INT UNSIGNED NOT NULL,
`vendor_item_id` INT UNSIGNED NOT NULL,
`purchase_time` INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`guid`, `vendor_item_id`),
INDEX `idx_guid` (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Perks Program - Frozen Items
DROP TABLE IF EXISTS `account_perks_frozen_items`;
CREATE TABLE `account_perks_frozen_items` (
`account_id` INT UNSIGNED NOT NULL,
`vendor_item_id` INT UNSIGNED NOT NULL,
`frozen_time` INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`account_id`, `vendor_item_id`),
INDEX `idx_account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Perks Program - Tracked Activities
DROP TABLE IF EXISTS `character_perks_tracked_activities`;
CREATE TABLE `character_perks_tracked_activities` (
`guid` INT UNSIGNED NOT NULL,
`activity_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`guid`, `activity_id`),
INDEX `idx_guid` (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Perks Program - Activity
DROP TABLE IF EXISTS `perk_program_activity`;
CREATE TABLE `perk_program_activity` (
`ActivityID` INT UNSIGNED NOT NULL,
PRIMARY KEY (`ActivityID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -0,0 +1,18 @@
DROP TABLE IF EXISTS `perks_vendor_item`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `perks_vendor_item` (
`ID` int unsigned NOT NULL DEFAULT '0',
`PerksVendorCategoryID` int NOT NULL DEFAULT '0',
`Unknown010001` int unsigned NOT NULL DEFAULT '0',
`ItemID` int unsigned NOT NULL DEFAULT '0',
`Unknown020001` int unsigned NOT NULL DEFAULT '0',
`CreatureDisplayInfoID` int unsigned NOT NULL DEFAULT '0',
`Cost` int unsigned NOT NULL DEFAULT '0',
`UiModelSceneID` int unsigned NOT NULL DEFAULT '0',
`UiGroupInfo` int unsigned NOT NULL DEFAULT '0',
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -2364,6 +2364,12 @@ ObjectGuid BotSpawner::CreateBotCharacter(uint32 accountId, uint8 race, uint8 cl
}
}
// CRITICAL FIX: Clear item update queue before save to prevent Item.cpp:1234 crash
// The crash occurs when invalid Item pointers (corrupted/dangling) remain in the
// player's item update queue. This can happen during character creation when
// items are added but not fully initialized.
newChar->GetItemUpdateQueue().clear();
// Save to database using async-safe PlayerbotCharacterDBInterface
CharacterDatabaseTransaction characterTransaction = sPlayerbotCharDB->BeginTransaction();
LoginDatabaseTransaction loginTransaction = LoginDatabase.BeginTransaction();
@@ -965,6 +965,51 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_PLAYER_INITIATIVE_FAVOR,
"SELECT COALESCE(SUM(amount), 0) FROM neighborhood_initiative_contributions WHERE initiativeDbId = ? AND playerGuid = ?",
CONNECTION_SYNCH);
// Perks Program - Purchases
PrepareStatement(CHAR_SEL_PERKS_PURCHASES,
"SELECT vendor_item_id, purchase_time FROM character_perks_purchases WHERE guid = ?",
CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_PERKS_PURCHASE,
"INSERT INTO character_perks_purchases (guid, vendor_item_id, purchase_time) VALUES (?, ?, ?)",
CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PERKS_PURCHASE,
"DELETE FROM character_perks_purchases WHERE guid = ? AND vendor_item_id = ?",
CONNECTION_ASYNC);
// Perks Program - Frozen Items
PrepareStatement(CHAR_SEL_ACCOUNT_PERKS_FROZEN_ITEMS,
"SELECT vendor_item_id FROM account_perks_frozen_items WHERE account_id = ?",
CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_PERKS_FROZEN_ITEM,
"INSERT IGNORE INTO account_perks_frozen_items (account_id, vendor_item_id, frozen_time) VALUES (?, ?, ?)",
CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PERKS_FROZEN_ITEM,
"DELETE FROM account_perks_frozen_items WHERE account_id = ? AND vendor_item_id = ?",
CONNECTION_ASYNC);
// Perks Program - Tracked Activities
PrepareStatement(CHAR_SEL_PERKS_TRACKED_ACTIVITIES,
"SELECT activity_id FROM character_perks_tracked_activities WHERE guid = ?",
CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_PERKS_TRACKED_ACTIVITY,
"INSERT IGNORE INTO character_perks_tracked_activities (guid, activity_id) VALUES (?, ?)",
CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PERKS_TRACKED_ACTIVITY,
"DELETE FROM character_perks_tracked_activities WHERE guid = ? AND activity_id = ?",
CONNECTION_ASYNC);
// Perks Program - Activity
PrepareStatement(CHAR_SEL_PERK_PROGRAM_ACTIVITY,
"SELECT ActivityID FROM perk_program_activity",
CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_PERK_PROGRAM_ACTIVITY,
"DELETE FROM perk_program_activity",
CONNECTION_ASYNC);
PrepareStatement(CHAR_REP_PERK_PROGRAM_ACTIVITY,
"INSERT INTO perk_program_activity (ActivityID) VALUES (?)",
CONNECTION_ASYNC);
// WowCommunity end
}
@@ -799,6 +799,21 @@ enum CharacterDatabaseStatements : uint32
CHAR_SEL_PLAYER_INITIATIVE_FAVOR,
//WowCommunity end
// Perks Program
CHAR_SEL_PERKS_PURCHASES,
CHAR_INS_PERKS_PURCHASE,
CHAR_DEL_PERKS_PURCHASE,
CHAR_SEL_ACCOUNT_PERKS_FROZEN_ITEMS,
CHAR_INS_PERKS_FROZEN_ITEM,
CHAR_DEL_PERKS_FROZEN_ITEM,
CHAR_SEL_PERKS_TRACKED_ACTIVITIES,
CHAR_INS_PERKS_TRACKED_ACTIVITY,
CHAR_DEL_PERKS_TRACKED_ACTIVITY,
CHAR_SEL_PERK_PROGRAM_ACTIVITY,
CHAR_DEL_PERK_PROGRAM_ACTIVITY,
CHAR_REP_PERK_PROGRAM_ACTIVITY,
//WowCommunity end
MAX_CHARACTERDATABASE_STATEMENTS
};
@@ -2664,6 +2664,12 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PrepareStatement(HOTFIX_SEL_DRIVE_CAPABILITY_TIER, "SELECT ID, Acceleration, MaxSpeed, DriveCapabilityID, OrderIndex"
" FROM drive_capability_tier WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_DRIVE_CAPABILITY_TIER, "SELECT MAX(ID) + 1 FROM drive_capability_tier", CONNECTION_SYNCH);
// PerksVendorItem.db2
PrepareStatement(HOTFIX_SEL_PERKS_VENDOR_ITEM, "SELECT ID, PerksVendorCategoryID, Unknown010001, ItemID, Unknown020001, CreatureDisplayInfoID, "
"Cost, UiModelSceneID, UiGroupInfo FROM perks_vendor_item WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_PERKS_VENDOR_ITEM, "SELECT MAX(ID) + 1 FROM perks_vendor_item", CONNECTION_SYNCH);
//WowCommunity end
}
@@ -483,6 +483,9 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_HOLIDAYS,
HOTFIX_SEL_HOLIDAYS_MAX_ID,
HOTFIX_SEL_PERKS_VENDOR_ITEM,
HOTFIX_SEL_PERKS_VENDOR_ITEM_MAX_ID,
HOTFIX_SEL_IMPORT_PRICE_ARMOR,
HOTFIX_SEL_IMPORT_PRICE_ARMOR_MAX_ID,
@@ -87,6 +87,9 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_SEL_WARBAND_REPUTATION_FACTIONS, "SELECT factionId FROM warband_reputation_faction", CONNECTION_SYNCH);
// Perks Program
PrepareStatement(WORLD_SEL_PERKS_VENDOR_ITEMS, "SELECT Id, ItemID, MountSpellID, PetSpellID, TransmogSet, ItemModifiedAppearanceID, ToyItem, Cost, Mon FROM perk_programs_vendor_items", CONNECTION_SYNCH);
}
WorldDatabaseConnection::WorldDatabaseConnection(MySQLConnectionInfo& connInfo, ConnectionFlags connectionFlags) : MySQLConnection(connInfo, connectionFlags)
@@ -92,6 +92,10 @@ enum WorldDatabaseStatements : uint32
WORLD_SEL_QUEST_GIVER_SPAWNS, // SELECT c.guid, c.id, c.position_x, c.position_y, c.position_z, c.map, ct.faction, COALESCE(c.zoneId, 0) as zoneId FROM creature c INNER JOIN creature_template ct ON c.id = ct.entry WHERE ct.npcflag & 2 != 0
WORLD_SEL_WARBAND_REPUTATION_FACTIONS,
// Perks Program Vendor Items
WORLD_SEL_PERKS_VENDOR_ITEMS,
// WowCommunity end
MAX_WORLDDATABASE_STATEMENTS
};
+18
View File
@@ -4327,6 +4327,24 @@ struct PerksActivityLoadInfo
static constexpr DB2LoadInfo Instance{ Fields, 7, &PerksActivityMeta::Instance, HOTFIX_SEL_PERKS_ACTIVITY };
};
struct PerksVendorItemLoadInfo
{
static constexpr DB2FieldMeta Fields[9] =
{
{.IsSigned = false, .Type = FT_INT, .Name = "ID" },
{.IsSigned = true, .Type = FT_BYTE, .Name = "PerksVendorCategoryID" },
{.IsSigned = true, .Type = FT_INT, .Name = "Unknown010001" },
{.IsSigned = true, .Type = FT_INT, .Name = "ItemID" },
{.IsSigned = true, .Type = FT_INT, .Name = "Unknown020001" },
{.IsSigned = true, .Type = FT_INT, .Name = "CreatureDisplayInfoID" },
{.IsSigned = true, .Type = FT_INT, .Name = "Cost" },
{.IsSigned = true, .Type = FT_INT, .Name = "UiModelSceneID" },
{.IsSigned = true, .Type = FT_INT, .Name = "UiGroupInfo" },
};
static constexpr DB2LoadInfo Instance{ Fields, 9, &PerksVendorItemMeta::Instance, HOTFIX_SEL_PERKS_VENDOR_ITEM };
};
struct PhaseLoadInfo
{
static constexpr DB2FieldMeta Fields[2] =
+23
View File
@@ -261,6 +261,7 @@ DB2Storage<PathEntry> sPathStore("Path.db2", &PathLoad
DB2Storage<PathNodeEntry> sPathNodeStore("PathNode.db2", &PathNodeLoadInfo::Instance);
DB2Storage<PathPropertyEntry> sPathPropertyStore("PathProperty.db2", &PathPropertyLoadInfo::Instance);
DB2Storage<PerksActivityEntry> sPerksActivityStore("PerksActivity.db2", &PerksActivityLoadInfo::Instance);
DB2Storage<PerksVendorItemEntry> sPerksVendorItemStore("PerksVendorItem.db2", &PerksVendorItemLoadInfo::Instance);
DB2Storage<PhaseEntry> sPhaseStore("Phase.db2", &PhaseLoadInfo::Instance);
DB2Storage<PhaseXPhaseGroupEntry> sPhaseXPhaseGroupStore("PhaseXPhaseGroup.db2", &PhaseXPhaseGroupLoadInfo::Instance);
DB2Storage<PlayerConditionEntry> sPlayerConditionStore("PlayerCondition.db2", &PlayerConditionLoadInfo::Instance);
@@ -547,6 +548,7 @@ typedef std::tuple<uint16, uint8, int32> WMOAreaTableKey;
typedef std::map<WMOAreaTableKey, WMOAreaTableEntry const*> WMOAreaTableLookupContainer;
typedef std::pair<uint32 /*tableHash*/, int32 /*recordId*/> HotfixBlobKey;
typedef std::map<HotfixBlobKey, std::vector<uint8>> HotfixBlobMap;
typedef std::unordered_map<uint32 /*ActivityTag*/, std::vector<PerksActivityEntry const*>> PerkProgramActivityXTag;
using AllowedHotfixOptionalData = std::pair<uint32 /*optional data key*/, bool(*)(std::vector<uint8> const& data) /*validator*/>;
namespace
@@ -648,6 +650,7 @@ namespace
std::unordered_map<uint32, std::unordered_set<uint32>> _pvpStatIdsByMap;
//WowCommunity
std::unordered_map<int32, std::vector<WarbandScenePlacementEntry const*>> _warbandScenePlacementsByScene;
PerkProgramActivityXTag _activityXTag;
//WowCommunity end
}
@@ -994,6 +997,7 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul
LOAD_DB2(sPathNodeStore);
LOAD_DB2(sPathPropertyStore);
LOAD_DB2(sPerksActivityStore);
LOAD_DB2(sPerksVendorItemStore);
LOAD_DB2(sPhaseStore);
LOAD_DB2(sPhaseXPhaseGroupStore);
LOAD_DB2(sPlayerConditionStore);
@@ -3721,4 +3725,23 @@ std::vector<WarbandScenePlacementEntry const*> const* DB2Manager::GetWarbandScen
{
return Trinity::Containers::MapGetValuePtr(_warbandScenePlacementsByScene, static_cast<int32>(warbandSceneId));
}
std::vector<PerksActivityEntry const*> DB2Manager::GetRandomActivitiesXTag()
{
std::vector<PerksActivityEntry const*> activities;
for (PerksActivityEntry const* activity : sPerksActivityStore)
{
if (activity)
activities.push_back(activity);
}
if (activities.empty())
return {};
int32 count = std::min(5, static_cast<int32>(activities.size()));
Trinity::Containers::RandomResize(activities, count);
return activities;
}
//WowCommunity
+2
View File
@@ -203,6 +203,7 @@ TC_GAME_API extern DB2Storage<MythicPlusSeasonEntry> sMythicPlusS
TC_GAME_API extern DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore;
TC_GAME_API extern DB2Storage<ParagonReputationEntry> sParagonReputationStore;
TC_GAME_API extern DB2Storage<PerksActivityEntry> sPerksActivityStore;
TC_GAME_API extern DB2Storage<PerksVendorItemEntry> sPerksVendorItemStore;
TC_GAME_API extern DB2Storage<PhaseEntry> sPhaseStore;
TC_GAME_API extern DB2Storage<PlayerConditionEntry> sPlayerConditionStore;
TC_GAME_API extern DB2Storage<PlayerDataElementAccountEntry> sPlayerDataElementAccountStore;
@@ -660,6 +661,7 @@ public:
std::unordered_set<uint32> const* GetPVPStatIDsForMap(uint32 mapId) const;
//WowCommunity
std::vector<WarbandScenePlacementEntry const*> const* GetWarbandScenePlacements(uint32 warbandSceneId) const;
std::vector<PerksActivityEntry const*> GetRandomActivitiesXTag();
//WowCommunity
private:
friend class DB2HotfixGeneratorBase;
+13
View File
@@ -3249,6 +3249,19 @@ struct PerksActivityEntry
int32 Priority;
};
struct PerksVendorItemEntry
{
int32 ID;
int8 PerksVendorCategoryID;
int32 Unknown010001;
int32 ItemID;
int32 Unknown020001;
int32 CreatureDisplayInfoID;
int32 Cost;
int32 UiModelSceneID;
int32 UiGroupInfo;
};
struct PhaseEntry
{
uint32 ID;
+8 -3
View File
@@ -19461,9 +19461,6 @@ void Player::_LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effe
}
while (auraResult->NextRow());
}
// TODO: finish dragonriding - this forces old flight mode
AddAura(404468, this);
}
void Player::_LoadGlyphAuras()
@@ -32571,4 +32568,12 @@ void Player::SendCtrOptions() const
SendDirectMessage(ctrOptions.Write());
}
void Player::AddMoveImpulse(Position direction)
{
WorldPackets::Movement::MoveAddImpulse impulse;
impulse.MoverGUID = GetGUID();
impulse.SequenceIndex = m_movementCounter++;
impulse.Direction = direction;
SendMessageToSet(impulse.Write(), true);
}
//WowCommunity
+1
View File
@@ -2032,6 +2032,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits::TraitConfig const& newConfig, bool applyTraits, bool consumeCurrencies);
void RenameTraitConfig(int32 editedConfigId, std::string&& newName);
void DeleteTraitConfig(int32 deletedConfigId);
void AddMoveImpulse(Position direction);
void ApplyTraitConfig(int32 configId, bool apply);
void ApplyTraitEntry(int32 traitNodeEntryId, int32 rank, int32 grantedRanks, bool apply);
void SetActiveCombatTraitConfigID(int32 traitConfigId) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ActiveCombatTraitConfigID), traitConfigId); }
+3 -1
View File
@@ -8417,7 +8417,9 @@ MountCapabilityEntry const* Unit::GetMountCapability(uint32 mountType) const
{
if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND && !(mountFlags.HasFlag(AreaMountFlags::AllowGroundMounts)))
continue;
if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLYING && !(mountFlags.HasFlag(AreaMountFlags::AllowFlyingMounts)))
// Allow flying everywhere for players (private server - area flags incomplete in DB2)
if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLYING && !(mountFlags.HasFlag(AreaMountFlags::AllowFlyingMounts))
&& GetTypeId() != TYPEID_PLAYER)
continue;
if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT && !(mountFlags.HasFlag(AreaMountFlags::AllowSurfaceSwimmingMounts)))
continue;
@@ -0,0 +1,167 @@
///*
// * Copyright (C) WowCommunity Project
// *
// * This SourceCode is NOT free a software. Please hold everything Private
// * and read our Terms
// */
//
//#include "PerkProgramData.h"
//#include "PerkProgramMgr.h"
//#include "Containers.h"
//#include "DatabaseEnv.h"
//#include "ObjectMgr.h"
//#include "DB2Stores.h"
//#include <sstream>
//#include "GameTime.h"
//
//PerkProgramDataStoreMgr::PerkProgramDataStoreMgr() {};
//
//PerkProgramDataStoreMgr::~PerkProgramDataStoreMgr() {};
//
//PerkProgramDataStoreMgr* PerkProgramDataStoreMgr::instance()
//{
// static PerkProgramDataStoreMgr instance;
// return &instance;
//}
//
//namespace
//{
// std::unordered_map<uint32, PerkProgramData::PerkVendorItem> _vendorTemplates;
// std::vector<PerkProgramData::ActivityTemplate> m_activeActivity;
//}
//
//void PerkProgramDataStoreMgr::Initialize()
//{
// LoadPerkVendorItem();
// LoadActivities();
//}
//
//void PerkProgramDataStoreMgr::LoadPerkVendorItem()
//{
// TC_LOG_INFO("server.loading", "Loading PerkPrograms Vendor Items Templates ...");
// _vendorTemplates.clear();
//
// if (!sPerksVendorItemStore.GetNumRows())
// {
// TC_LOG_WARN("server.loading", ">> PerksVendorItem store is empty, skipping vendor items");
// return;
// }
//
// for (PerksVendorItemEntry const* itemVendor : sPerksVendorItemStore)
// {
// if (!itemVendor)
// continue;
//
// PerkProgramData::PerkVendorItem vendorItem;
// vendorItem.Id = itemVendor->ID;
// vendorItem.ItemID = itemVendor->ItemID;
// vendorItem.MountSpellID = itemVendor->Unknown010001;
// vendorItem.PetSpellID = itemVendor->Unknown020001;
// vendorItem.TransmogSet = 0;
// vendorItem.ItemModifiedAppearanceID = 0;
// vendorItem.ToyItem = 0;
// vendorItem.Cost = itemVendor->Cost;
// vendorItem.CategoryId = itemVendor->PerksVendorCategoryID;
//
// _vendorTemplates.insert(std::make_pair(itemVendor->ID, vendorItem));
// }
//
// TC_LOG_INFO("server.loading", ">> Loaded {} PerkPrograms Vendor Items Templates", uint32(_vendorTemplates.size()));
//}
//
//std::unordered_map<uint32, PerkProgramData::PerkVendorItem> PerkProgramDataStoreMgr::GetVendorItems()
//{
// return _vendorTemplates;
//}
//
//PerkProgramData::PerkVendorItem const* PerkProgramDataStoreMgr::GetVendorItem(uint32 entry)
//{
// auto itr = _vendorTemplates.find(entry);
// if (itr != _vendorTemplates.end())
// return &itr->second;
//
// return nullptr;
//}
//
//PerkProgramData::PerkVendorItem const* PerkProgramDataStoreMgr::GetRandomVendorItem()
//{
// if (_vendorTemplates.empty())
// return nullptr;
//
// auto it = _vendorTemplates.begin();
// std::advance(it, rand() % _vendorTemplates.size());
// return &it->second;
//}
//
//std::vector<PerkProgramData::ActivityTemplate> PerkProgramDataStoreMgr::GetActivities()
//{
// return m_activeActivity;
//}
//
//uint32 PerkProgramDataStoreMgr::GetActivityCriteriatree(uint32 activityId)
//{
// for (auto const& ac : m_activeActivity)
// {
// if (ac.ActivityID == activityId)
// return ac.CriteriaTree;
// }
// return 0;
//}
//
//uint32 PerkProgramDataStoreMgr::GetActivityCurrencyAmount(uint32 activityId)
//{
// for (auto const& ac : m_activeActivity)
// {
// if (ac.ActivityID == activityId)
// return ac.CurrencyAmount;
// }
// return 0;
//}
//
//void PerkProgramDataStoreMgr::LoadActivities()
//{
// CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PERK_PROGRAM_ACTIVITY);
// PreparedQueryResult result = CharacterDatabase.Query(stmt);
// m_activeActivity.clear();
// if (!result)
// {
// GenerateRandomActivities(false);
// return;
// }
// do
// {
// Field* fields = result->Fetch();
// uint32 activityId = fields[0].GetUInt32();
// PerksActivityEntry const* entry = sPerksActivityStore.LookupEntry(activityId);
// if (!entry)
// continue;
// PerkProgramData::ActivityTemplate ac;
// ac.ActivityID = entry->ID;
// ac.CriteriaTree = entry->CriteriaTreeID;
// ac.CurrencyAmount = entry->ThresholdContributionAmount;
// ac.Priority = entry->Priority;
// m_activeActivity.push_back(ac);
//
// } while (result->NextRow());
//}
//
//void PerkProgramDataStoreMgr::GenerateRandomActivities(bool /*clearOld*/)
//{
// CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PERK_PROGRAM_ACTIVITY);
// CharacterDatabase.Execute(stmt);
// m_activeActivity.clear();
//
// for (PerksActivityEntry const* db : sDB2Manager.GetRandomActivitiesXTag())
// {
// PerkProgramData::ActivityTemplate ac;
// ac.ActivityID = db->ID;
// ac.CriteriaTree = db->CriteriaTreeID;
// ac.CurrencyAmount = db->ThresholdContributionAmount;
// ac.Priority = db->Priority;
// m_activeActivity.push_back(ac);
//
// stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_PERK_PROGRAM_ACTIVITY);
// stmt->setUInt32(0, ac.ActivityID);
// CharacterDatabase.Execute(stmt);
// }
//}
@@ -0,0 +1,75 @@
///*
// * Copyright (C) WowCommunity Project
// *
// * This SourceCode is NOT free a software. Please hold everything Private
// * and read our Terms
// */
//
//#ifndef _PERK_PROGRAM_DATA_STORE_H
//#define _PERK_PROGRAM_DATA_STORE_H
//
//#include "PerksProgramPacketsCommon.h"
//#include "PacketUtilities.h"
//#include "DatabaseEnv.h"
//#include <vector>
//#include <unordered_map>
//#include <ctime>
//
//class PerkProgramManager;
//
//namespace PerkProgramData
//{
// struct PerkVendorItem
// {
// uint32 Id;
// uint32 ItemID;
// uint32 MountSpellID;
// uint32 PetSpellID;
// uint32 TransmogSet;
// uint32 ItemModifiedAppearanceID;
// uint32 ToyItem;
// time_t AvailableUntil;
// uint32 Cost;
// uint32 CategoryId;
//
// };
//
// struct ActivityTemplate
// {
// uint32 ActivityID;
// uint32 CriteriaTree;
// uint32 Priority;
// uint32 CurrencyAmount;
// };
//};
//
//class TC_GAME_API PerkProgramDataStoreMgr
//{
// PerkProgramDataStoreMgr();
// ~PerkProgramDataStoreMgr();
//
//public:
// static PerkProgramDataStoreMgr* instance();
//
// void Initialize();
//
// std::unordered_map<uint32, PerkProgramData::PerkVendorItem> GetVendorItems();
// PerkProgramData::PerkVendorItem const* GetVendorItem(uint32 entry);
// PerkProgramData::PerkVendorItem const* GetRandomVendorItem();
//
// std::vector<PerkProgramData::ActivityTemplate> GetActivities();
// uint32 GetActivityCriteriatree(uint32 activityId);
// uint32 GetActivityCurrencyAmount(uint32 activityId);
//
//private:
//
// void LoadPerkVendorItem();
// void LoadActivities();
// void GenerateRandomActivities(bool clearOld);
// time_t m_activityTime;
//
//};
//
//#define sPerkProgramDataStore PerkProgramDataStoreMgr::instance()
//
//#endif
@@ -0,0 +1,430 @@
///*
// * Copyright (C) WowCommunity Project
// *
// * This SourceCode is NOT free a software. Please hold everything Private
// * and read our Terms
// */
//
//#include "Common.h"
//#include "CollectionMgr.h"
//#include "ObjectMgr.h"
//#include "PerkProgramMgr.h"
//#include "WorldSession.h"
//#include "Guild.h"
//#include "GuildMgr.h"
//#include "Player.h"
//#include "Creature.h"
//#include "PerkProgramData.h"
//#include "DatabaseEnv.h"
//#include "ScriptMgr.h"
//#include "AccountMgr.h"
//#include <sstream>
//#include "SpellInfo.h"
//#include "SpellMgr.h"
//#include "Language.h"
//#include "SpellPackets.h"
//#include "Chat.h"
//#include "DB2Stores.h"
//#include "Pet.h"
//#include "Item.h"
//#include "MiscPackets.h"
//#include "Unit.h"
//#include "GameTime.h"
//#include "PerksProgramPackets.h"
//
//using namespace PerkPrograms;
//
//PerkProgramManager::PerkProgramManager(WorldSession* session)
//{
// _session = session;
// if (session->GetPlayer())
// m_player = session->GetPlayer();
//
// m_currencyAmount = 0;
//}
//
//PerkProgramManager::~PerkProgramManager()
//{
//};
//
//void PerkProgramManager::SendVendorItems(Creature* vendor, std::vector<uint32> purchasedItems)
//{
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_AVAILABLE_ITEMS;
//
// uint32 cameraId = 0;
//
// switch (vendor->GetEntry())
// {
// case PerkPrograms::VENDOR_HORDE:
// cameraId = PerkPrograms::CAMERA_HORDE;
// break;
// case PerkPrograms::VENDOR_ALLIANCE:
// cameraId = PerkPrograms::CAMERA_ALLIANCE;
// break;
// default:
// cameraId = 0;
// break;
// }
// perks.Params.VendorItem.VendorGuid = vendor->GetGUID();
//
// if (cameraId != 0)
// {
// std::list<Creature*> list;
// _session->GetPlayer()->GetCreatureListWithEntryInGrid(list, cameraId, 100);
//
// for (auto cr1 : list)
// {
// perks.Params.VendorItem.ModelSceneCameraGuid = cr1->GetGUID();
// break;
// }
// }
//
// for (auto items : sPerkProgramDataStore->GetVendorItems())
// {
// WorldPackets::PerksProgram::PerksVendorItem vendorItem;
// vendorItem.VendorItemID = items.second.Id;
// vendorItem.MountID = items.second.MountSpellID;
// vendorItem.BattlePetSpeciesID = items.second.PetSpellID;
// vendorItem.ItemModifiedAppearanceID = items.second.ItemModifiedAppearanceID;
// vendorItem.ToyID = items.second.ToyItem;
// vendorItem.TransmogSetID = items.second.TransmogSet;
// vendorItem.Price = items.second.Cost;
// vendorItem.CategoryType = items.second.CategoryId;
// vendorItem.Disabled = false;
// vendorItem.AvailableUntil = items.second.AvailableUntil;
// perks.Params.VendorItem.FrozenPerksVendorItems.emplace_back(vendorItem);
//
// }
//
// _session->SendPacket(perks.Write());
//}
//
//bool PerkProgramManager::IsAccountWideItem(uint32 item)
//{
// bool level = false;
// if (auto i = sPerkProgramDataStore->GetVendorItem(item))
// {
// switch (i->CategoryId)
// {
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TOYS:
// case PerkPrograms::PERKS_VENDOR_CATEGORY_MOUNTS:
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TRANSMOG_SETS:
// level = true;
// break;
// default:
// break;
// }
// }
// return level;
//}
//
//bool PerkProgramManager::IsItemAlreadyOwned(PerkProgramData::PerkVendorItem const* vendorItem)
//{
// if (!vendorItem)
// return true;
//
// switch (vendorItem->CategoryId)
// {
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TOYS:
// return m_player->GetSession()->GetCollectionMgr()->HasToy(vendorItem->ToyItem);
// // case PerkPrograms::PERKS_VENDOR_CATEGORY_MOUNTS:
// // return m_player->GetMountCollection()->Has(vendorItem->MountSpellID);
// // case PerkPrograms::PERKS_VENDOR_CATEGORY_TRANSMOG_SETS:
// // return m_player->GetSession()->GetCollectionMgr()->HasTransmogSet(vendorItem->TransmogSet);
// // case PerkPrograms::PERKS_VENDOR_CATEGORY_TRANSMOG:
// // return m_player->GetSession()->GetCollectionMgr()->HasItemAppearance(vendorItem->ItemModifiedAppearanceID);
// // case PerkPrograms::PERKS_VENDOR_CATEGORY_PETS:
// // return m_player->GetBattlePetCollection()->HasPet(vendorItem->PetSpellID);
// default:
// break;
// }
//
// return false;
//}
//
//void PerkProgramManager::GrantItem(PerkProgramData::PerkVendorItem const* vendorItem)
//{
// if (!vendorItem)
// return;
//
// switch (vendorItem->CategoryId)
// {
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TOYS:
// {
// m_player->GetSession()->GetCollectionMgr()->AddToy(vendorItem->ToyItem, false, false);
// break;
// }
// case PerkPrograms::PERKS_VENDOR_CATEGORY_MOUNTS:
// {
// m_player->LearnSpell(vendorItem->MountSpellID, false);
// break;
// }
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TRANSMOG_SETS:
// {
// m_player->GetSession()->GetCollectionMgr()->AddTransmogSet(vendorItem->TransmogSet);
// break;
// }
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TRANSMOG:
// {
// m_player->GetSession()->GetCollectionMgr()->AddItemAppearance(vendorItem->ItemModifiedAppearanceID);
// break;
// }
// case PerkPrograms::PERKS_VENDOR_CATEGORY_PETS:
// {
// // m_player->AddBattlePet(vendorItem->PetSpellID);
// break;
// }
// case PerkPrograms::PERKS_VENDOR_CATEGORY_CONSUMABLES:
// {
// m_player->AddItem(vendorItem->ItemID, 1);
// break;
// }
// default:
// break;
// }
//}
//
//void PerkProgramManager::RemoveGrantedItem(PerkProgramData::PerkVendorItem const* vendorItem)
//{
// if (!vendorItem)
// return;
//
// switch (vendorItem->CategoryId)
// {
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TOYS:
// break;
// case PerkPrograms::PERKS_VENDOR_CATEGORY_MOUNTS:
// m_player->RemoveSpell(vendorItem->MountSpellID, false, true);
// break;
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TRANSMOG_SETS:
// break;
// case PerkPrograms::PERKS_VENDOR_CATEGORY_TRANSMOG:
// break;
// case PerkPrograms::PERKS_VENDOR_CATEGORY_PETS:
// break;
// case PerkPrograms::PERKS_VENDOR_CATEGORY_CONSUMABLES:
// m_player->DestroyItemCount(vendorItem->ItemID, 1, true);
// break;
// default:
// break;
// }
//}
//
//void PerkProgramManager::BuyItem(uint32 itemId, ObjectGuid /*vendor*/)
//{
// auto const* vendorItem = sPerkProgramDataStore->GetVendorItem(itemId);
// if (!vendorItem)
// {
// SendPerksProgramError(1);
// return;
// }
//
// if (m_currencyAmount < vendorItem->Cost)
// {
// SendPerksProgramError(2);
// return;
// }
//
// if (IsItemAlreadyOwned(vendorItem))
// {
// SendPerksProgramError(3);
// return;
// }
//
// m_currencyAmount -= vendorItem->Cost;
// m_player->ModifyCurrency(PERKS_PROGRAM_CURRENCY, -static_cast<int32>(vendorItem->Cost));
//
// GrantItem(vendorItem);
//
// RecordPurchase(itemId, GameTime::GetGameTime());
//
// SendBuyItemResult(itemId);
// SendCurrencyRefresh();
//}
//
//void PerkProgramManager::SendBuyItemResult(int32 itemId)
//{
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_BUY_ITEM;
// perks.Params.BuyItem.VendorItemID = itemId;
//
// WorldPackets::PerksProgram::JamTimePair time;
// time.BuyTime = GameTime::GetGameTime();
// time.VendorItemID = itemId;
// perks.Params.BuyItem.TimePair.emplace_back(time);
//
// _session->SendPacket(perks.Write());
//}
//
//void PerkProgramManager::SendCurrencyRefresh()
//{
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_CURRENCY_REFRESH;
// _session->SendPacket(perks.Write());
//}
//
//void PerkProgramManager::SendPerksProgramError(uint32 errorCode)
//{
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_ERROR;
// _session->SendPacket(perks.Write());
//}
//
//void PerkProgramManager::RecordPurchase(uint32 itemId, time_t purchaseTime)
//{
// m_recentPurchases.push_back(std::make_pair(itemId, purchaseTime));
//}
//
//void PerkProgramManager::RefundItem(int32 itemId)
//{
// auto it = std::find_if(m_recentPurchases.begin(), m_recentPurchases.end(),
// [itemId](std::pair<uint32, time_t> const& p) { return p.first == static_cast<uint32>(itemId); });
//
// if (it == m_recentPurchases.end())
// {
// SendPerksProgramError(4);
// return;
// }
//
// if (GameTime::GetGameTime() - it->second > REFUND_WINDOW_SECONDS)
// {
// SendPerksProgramError(5);
// return;
// }
//
// auto const* vendorItem = sPerkProgramDataStore->GetVendorItem(itemId);
// if (!vendorItem)
// return;
//
// RemoveGrantedItem(vendorItem);
//
// m_currencyAmount += vendorItem->Cost;
// m_player->ModifyCurrency(PERKS_PROGRAM_CURRENCY, static_cast<int32>(vendorItem->Cost));
//
// m_recentPurchases.erase(it);
//
// SendRefundSuccess(itemId);
// SendCurrencyRefresh();
//}
//
//void PerkProgramManager::SendRefundSuccess(int32 itemId)
//{
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_REFUND_SUCCESS;
// perks.Params.BuyItem.VendorItemID = itemId;
// _session->SendPacket(perks.Write());
//}
//
//void PerkProgramManager::CartCheckout(std::vector<uint32> const& vendorItemIDs)
//{
// uint32 totalCost = 0;
//
// for (uint32 itemId : vendorItemIDs)
// {
// auto const* item = sPerkProgramDataStore->GetVendorItem(itemId);
// if (!item)
// {
// SendPerksProgramError(1);
// return;
// }
// totalCost += item->Cost;
// }
//
// if (m_currencyAmount < totalCost)
// {
// SendPerksProgramError(2);
// return;
// }
//
// for (uint32 itemId : vendorItemIDs)
// {
// auto const* item = sPerkProgramDataStore->GetVendorItem(itemId);
// if (!item)
// continue;
//
// if (IsItemAlreadyOwned(item))
// continue;
//
// m_currencyAmount -= item->Cost;
// m_player->ModifyCurrency(PERKS_PROGRAM_CURRENCY, -static_cast<int32>(item->Cost));
//
// GrantItem(item);
// RecordPurchase(itemId, GameTime::GetGameTime());
// }
//
// SendCartCheckoutSuccess();
// SendCurrencyRefresh();
//}
//
//void PerkProgramManager::SendCartCheckoutSuccess()
//{
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_PURCHASE_CART;
// _session->SendPacket(perks.Write());
//}
//
//void PerkProgramManager::SendPerksProgramStatus()
//{
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_CURRENCY_REFRESH;
// _session->SendPacket(perks.Write());
//}
//
//void PerkProgramManager::SendPendingRewards()
//{
//}
//
//void PerkProgramManager::SetFrozenItem(int32 itemId, bool clear)
//{
// if (clear)
// {
// m_frozenItems.clear();
// }
// else
// {
// auto const* item = sPerkProgramDataStore->GetVendorItem(itemId);
// if (item)
// {
// m_frozenItems.clear();
// m_frozenItems.push_back(*item);
// }
// }
//
// WorldPackets::PerksProgram::PerksProgramResult perks;
// perks.Type = PerkPrograms::RESULT_FROZEN_ITEM;
// _session->SendPacket(perks.Write());
//}
//
//void PerkProgramManager::AddTrackedActivity(uint32 activityId)
//{
// if (std::find(m_trackedActivities.begin(), m_trackedActivities.end(), activityId) == m_trackedActivities.end())
// {
// m_trackedActivities.push_back(activityId);
// }
//}
//
//void PerkProgramManager::RemoveTrackedActivity(uint32 activityId)
//{
// auto it = std::find(m_trackedActivities.begin(), m_trackedActivities.end(), activityId);
// if (it != m_trackedActivities.end())
// {
// m_trackedActivities.erase(it);
// }
//}
//
//void PerkProgramManager::SendPerksProgramActivities()
//{
// WorldPackets::PerksProgram::PerksProgramActivityUpdate activity;
//
// activity.TimeUntilStart = GameTime::GetGameTime();
// // activity.TimeUntilEnd = sWorld->GetNextPerksProgramReset();
//
// for (auto ac : sPerkProgramDataStore->GetActivities())
// {
// activity.ActivityIDs.push_back(ac.ActivityID);
//
// }
// _session->SendPacket(activity.Write());
//
//}
@@ -0,0 +1,113 @@
///*
// * Copyright (C) WowCommunity Project
// *
// * This SourceCode is NOT free a software. Please hold everything Private
// * and read our Terms
// */
//
//#ifndef __TRINITY_PERKPROGRAMMGR_H
//#define __TRINITY_PERKPROGRAMMGR_H
//
//#include "Common.h"
//#include "PerksProgramPacketsCommon.h"
//#include "PerkProgramData.h"
//
//class WorldSession;
//class Player;
//class Creature;
//
//#define PERKS_PROGRAM_CURRENCY 2032
//
//namespace PerkPrograms
//{
// enum PerksVendorCategoryType : uint32
// {
// PERKS_VENDOR_CATEGORY_NONE = 0,
// PERKS_VENDOR_CATEGORY_MOUNTS = 1,
// PERKS_VENDOR_CATEGORY_PETS = 2,
// PERKS_VENDOR_CATEGORY_TOYS = 3,
// PERKS_VENDOR_CATEGORY_TRANSMOG = 4,
// PERKS_VENDOR_CATEGORY_TRANSMOG_SETS = 5,
// PERKS_VENDOR_CATEGORY_CONSUMABLES = 6,
// };
//
// enum ItemCollectionType : uint32
// {
// ITEM_COLLECTION_NONE = 0,
// ITEM_COLLECTION_APPEARANCE = 1,
// ITEM_COLLECTION_MOUNT = 2,
// ITEM_COLLECTION_TOY = 3,
// ITEM_COLLECTION_PET = 4,
// ITEM_COLLECTION_HEIRLOOM = 5,
// ITEM_COLLECTION_ILLUSION = 6,
// ITEM_COLLECTION_ENSEMBLE = 7,
// };
//
// enum NpcVendorAndCameras : uint32
// {
// CAMERA_HORDE = 183978,
// CAMERA_ALLIANCE = 1,
// VENDOR_HORDE = 185473,
// VENDOR_ALLIANCE = 3,
// };
//
// enum ResultType : uint32
// {
// RESULT_NONE = 0,
// RESULT_BUY_ITEM = 2,
// RESULT_AVAILABLE_ITEMS = 5,
// RESULT_PURCHASE_CART = 6,
// RESULT_REFUND_SUCCESS = 7,
// RESULT_ERROR = 10,
// RESULT_CURRENCY_REFRESH = 11,
// RESULT_FROZEN_ITEM = 12,
// RESULT_ACTIVITY_UPDATE = 13,
// };
//
//}
//
//class TC_GAME_API PerkProgramManager
//{
//
//public:
// explicit PerkProgramManager(WorldSession* session);
// ~PerkProgramManager();
//
// void SendVendorItems(Creature* vendor, std::vector<uint32> purchasedItems);
// void BuyItem(uint32 itemId, ObjectGuid vendor);
// bool IsAccountWideItem(uint32 item);
//
// void SetCurrencyAmount(uint32 amount) { m_currencyAmount = amount; }
// uint32 GetCurrencyAmount() { return m_currencyAmount; }
//
// void SendPerksProgramActivities();
// void SendPerksProgramStatus();
// void SendPendingRewards();
// void SetFrozenItem(int32 itemId, bool clear);
// void RefundItem(int32 itemId);
// void CartCheckout(std::vector<uint32> const& itemIds);
// void AddTrackedActivity(uint32 activityId);
// void RemoveTrackedActivity(uint32 activityId);
//
//private:
// void GrantItem(PerkProgramData::PerkVendorItem const* vendorItem);
// void RemoveGrantedItem(PerkProgramData::PerkVendorItem const* vendorItem);
// bool IsItemAlreadyOwned(PerkProgramData::PerkVendorItem const* vendorItem);
// void SendBuyItemResult(int32 itemId);
// void SendRefundSuccess(int32 itemId);
// void SendCartCheckoutSuccess();
// void SendCurrencyRefresh();
// void SendPerksProgramError(uint32 errorCode);
// void RecordPurchase(uint32 itemId, time_t purchaseTime);
//
// WorldSession* _session;
// Player* m_player;
// uint32 m_currencyAmount;
// std::vector<PerkProgramData::PerkVendorItem> m_frozenItems;
// std::vector<std::pair<uint32, time_t>> m_recentPurchases;
// std::vector<uint32> m_trackedActivities;
//
// static constexpr uint32 REFUND_WINDOW_SECONDS = 2 * 60 * 60;
//};
//
//#endif
@@ -2826,6 +2826,28 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo
target->SetDriveCapabilityID(mountCapability->DriveCapabilityID, false);
target->CastSpell(target, mountCapability->ModSpellAuraID, this);
}
// Private server: always enable flying for players with riding skills
if (Player* player = target->ToPlayer())
{
if (player->HasSpell(90265) || player->HasSpell(34091) || player->HasSpell(34090))
{
target->SetCanFly(true);
if (player->HasAura(404468)) // Steady Flight mode
{
target->SetCanAdvFly(false);
}
else // Skyriding mode (default)
{
target->SetCanAdvFly(true);
target->SetCanDoubleJump(true);
target->SetFlightCapabilityID(1, true);
// Cast Vigor aura - required by CasterAuraSpell check for active abilities
if (!player->HasAura(372773))
player->CastSpell(player, 372773, true);
}
}
}
}
}
else
@@ -2848,8 +2870,13 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo
if (MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(GetAmount()))
target->RemoveAurasDueToSpell(mountCapability->ModSpellAuraID, target->GetGUID());
// Clear all flight flags on dismount
target->SetCanFly(false);
target->SetCanAdvFly(false);
target->SetCanDoubleJump(false);
target->SetFlightCapabilityID(0, true);
target->SetDriveCapabilityID(0, true);
// Remove Vigor aura on dismount
target->RemoveAura(372773);
}
}
+5 -6
View File
@@ -3353,6 +3353,11 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
const_cast<SpellInfo&>(spellInfo).AttributesCu |= SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED;
}
// Dragonriding flight style auras - applied fresh on login, do not save
for (uint32 spellId : { 404464u, 404468u, 372773u })
for (SpellInfo const& spellInfo : _GetSpellInfo(spellId))
const_cast<SpellInfo&>(spellInfo).AttributesCu |= SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED;
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo custom attributes in {} ms", GetMSTimeDiffToNow(oldMSTime));
}
@@ -5176,12 +5181,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx4 |= SPELL_ATTR4_AURA_IS_BUFF;
});
// TODO: temporary, remove with dragonriding
ApplySpellFix({ 404468 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED;
});
// Sigil of Flame
ApplySpellFix({ 204598 }, [](SpellInfo* spellInfo)
{
@@ -34,13 +34,58 @@ enum DragonridingSpells
SPELL_DRAGONRIDING_WHIRLING_SURGE = 361584,
SPELL_DRAGONRIDING_LAUNCH_BOOST = 392752,
SPELL_DRAGONRIDING_LIFT_OFF = 374763,
SPELL_STEADY_FLIGHT = 404468,
SPELL_SKYRIDING = 404464,
SPELL_SKYRIDING_BASICS = 376777,
SPELL_SWITCH_FLIGHT_STYLE = 436854,
SPELL_VIGOR = 372773,
SPELL_LIFT_OFF_3 = 386451,
};
// Blizzlike impulse values from sniff data:
// Launch Boost: (0, 0, 45.0) ? pure upward, magnitude 45.0, sent on spell hit (before periodic aura)
// Whirling Surge: magnitude 5.0 per tick ? facing+pitch oriented, 5-6 ticks, periodic aura (3s duration)
// Skyward Ascent: horizontal 12.25 + Z 49.0 ? magnitude ~50.51, single impulse
// Surge Forward: magnitude 30.0 ? facing+pitch oriented, single burst (estimated; not directly observable in sniff)
// Spell 436854 - Switch Flight Style
class spell_switch_flight : public SpellScript
{
void HandleDummy(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster)
return;
bool hadSkyriding = caster->HasAura(SPELL_SKYRIDING);
caster->RemoveAura(SPELL_SKYRIDING);
caster->RemoveAura(SPELL_STEADY_FLIGHT);
if (hadSkyriding)
{
caster->CastSpell(caster, SPELL_STEADY_FLIGHT, true);
caster->RemoveAura(SPELL_VIGOR);
if (caster->IsMounted())
{
caster->SetCanAdvFly(false);
caster->SetCanDoubleJump(false);
}
}
else
{
caster->CastSpell(caster, SPELL_SKYRIDING, true);
if (!caster->HasAura(SPELL_VIGOR))
caster->CastSpell(caster, SPELL_VIGOR, true);
if (caster->IsMounted())
{
caster->SetCanAdvFly(true);
caster->SetCanDoubleJump(true);
caster->SetFlightCapabilityID(1, true);
}
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_switch_flight::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
static void SendFacingImpulse(Unit* caster, float speed)
{
@@ -188,6 +233,7 @@ class spell_dragonriding_launch_boost_aura : public AuraScript
void AddSC_dragonriding_spell_scripts()
{
RegisterSpellScript(spell_switch_flight);
RegisterSpellAndAuraScriptPair(spell_dragonriding_whirling_surge, spell_dragonriding_whirling_surge_aura);
RegisterSpellAndAuraScriptPair(spell_dragonriding_launch_boost, spell_dragonriding_launch_boost_aura);
RegisterSpellScript(spell_dragonriding_surge_forward);