aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSpp <spp@jorge.gr>2012-10-19 14:24:11 +0200
committerSpp <spp@jorge.gr>2012-10-19 14:24:11 +0200
commit2e55abcde43c7e0aef3dda5cf896165491551031 (patch)
tree9ff5edca826a758062681af16325a649d42d9e93 /src
parent56df638092c551a025cd3dc200ed5d330f92fa63 (diff)
parent4e8fa520c8aca831580fba9bf762486b9a9d7ed0 (diff)
Merge branch 'master' into 4.3.4
Conflicts: src/server/game/DataStores/DBCStructure.h src/server/game/DataStores/DBCfmt.h src/server/game/Globals/ObjectMgr.cpp src/server/game/Handlers/LFGHandler.cpp src/server/game/Server/Protocol/Opcodes.cpp src/server/game/Server/WorldSession.h
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DataStores/DBCStores.cpp2
-rwxr-xr-xsrc/server/game/DataStores/DBCStores.h2
-rw-r--r--src/server/game/DataStores/DBCStructure.h4
-rwxr-xr-xsrc/server/game/DataStores/DBCfmt.h272
-rwxr-xr-xsrc/server/game/DungeonFinding/LFG.h40
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.cpp59
-rw-r--r--src/server/game/DungeonFinding/LFGGroupData.h19
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.cpp1942
-rwxr-xr-xsrc/server/game/DungeonFinding/LFGMgr.h275
-rw-r--r--src/server/game/DungeonFinding/LFGPlayerData.cpp41
-rw-r--r--src/server/game/DungeonFinding/LFGPlayerData.h22
-rw-r--r--src/server/game/DungeonFinding/LFGQueue.cpp539
-rw-r--r--src/server/game/DungeonFinding/LFGQueue.h139
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.cpp124
-rwxr-xr-xsrc/server/game/Entities/GameObject/GameObject.cpp12
-rw-r--r--src/server/game/Entities/Player/Player.cpp32
-rw-r--r--src/server/game/Entities/Player/Player.h3
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp3
-rwxr-xr-xsrc/server/game/Groups/Group.cpp4
-rwxr-xr-xsrc/server/game/Handlers/LFGHandler.cpp298
-rwxr-xr-xsrc/server/game/Maps/Map.cpp4
-rwxr-xr-xsrc/server/game/Miscellaneous/Language.h17
-rwxr-xr-xsrc/server/game/Miscellaneous/SharedDefines.h7
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rwxr-xr-xsrc/server/game/Server/WorldSession.h13
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/World/World.cpp5
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp4
28 files changed, 2189 insertions, 1697 deletions
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 8a647bacfea..584b070def2 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -140,7 +140,7 @@ DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomProp
DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);
DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt);
-DBCStorage <LFGDungeonEntry> sLFGDungeonStore(LFGDungeonEntryfmt);
+DBCStorage <LFGDungeonEntryDbc> sLFGDungeonStore(LFGDungeonEntryfmt);
DBCStorage <LiquidTypeEntry> sLiquidTypeStore(LiquidTypefmt);
DBCStorage <LockEntry> sLockStore(LockEntryfmt);
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index c4e012c62c1..288ecbf6a0e 100755
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -152,7 +152,7 @@ extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore;
extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore;
extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore;
extern DBCStorage <ItemSetEntry> sItemSetStore;
-extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore;
+extern DBCStorage <LFGDungeonEntryDbc> sLFGDungeonStore;
extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore;
extern DBCStorage <LockEntry> sLockStore;
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index a1a0931dc5a..c4b0a760862 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1347,10 +1347,10 @@ struct ItemSetEntry
uint32 required_skill_value; // 36 m_requiredSkillRank
};
-struct LFGDungeonEntry
+struct LFGDungeonEntryDbc
{
uint32 ID; // 0
- //char* name; // 1
+ char* name; // 1
uint32 minlevel; // 2
uint32 maxlevel; // 3
uint32 reclevel; // 4
diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
index f9339f7515a..c1430c7bef0 100755
--- a/src/server/game/DataStores/DBCfmt.h
+++ b/src/server/game/DataStores/DBCfmt.h
@@ -22,152 +22,152 @@
// x - skip<uint32>, X - skip<uint8>, s - char*, f - float, i - uint32, b - uint8, d - index (not included)
// n - index (included), l - bool, p - field present in sql dbc, a - field absent in sql dbc
-const char Achievementfmt[]="niixsxiixixxii";
+char const Achievementfmt[]="niixsxiixixxii";
//const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp";
//const std::string CustomAchievementIndex = "ID";
-const char AchievementCriteriafmt[]="niiiiiiiisiiiiixxiiiiii";
-const char AreaTableEntryfmt[]="iiinixxxxxisiiiiifxxxxxxxx";
-const char AreaGroupEntryfmt[]="niiiiiii";
-const char AreaPOIEntryfmt[]="niiiiiiiiiiiffixixxixx";
-const char AreaTriggerEntryfmt[]="nifffxxxfffff";
-const char ArmorLocationfmt[]="nfffff";
-const char AuctionHouseEntryfmt[]="niiix";
-const char BankBagSlotPricesEntryfmt[]="ni";
-const char BarberShopStyleEntryfmt[]="nixxxiii";
-const char BattlemasterListEntryfmt[]="niiiiiiiiixsiiiixxxx";
-const char CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-const char CharTitlesEntryfmt[]="nxsxix";
-const char ChatChannelsEntryfmt[]="nixsx";
+char const AchievementCriteriafmt[]="niiiiiiiisiiiiixxiiiiii";
+char const AreaTableEntryfmt[]="iiinixxxxxisiiiiifxxxxxxxx";
+char const AreaGroupEntryfmt[]="niiiiiii";
+char const AreaPOIEntryfmt[]="niiiiiiiiiiiffixixxixx";
+char const AreaTriggerEntryfmt[]="nifffxxxfffff";
+char const ArmorLocationfmt[]="nfffff";
+char const AuctionHouseEntryfmt[]="niiix";
+char const BankBagSlotPricesEntryfmt[]="ni";
+char const BarberShopStyleEntryfmt[]="nixxxiii";
+char const BattlemasterListEntryfmt[]="niiiiiiiiixsiiiixxxx";
+char const CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+char const CharTitlesEntryfmt[]="nxsxix";
+char const ChatChannelsEntryfmt[]="nixsx";
-const char ChrClassesEntryfmt[]="nixsxxxixiiiii";
-const char ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx";
-const char ChrClassesXPowerTypesfmt[]="nii";
+char const ChrClassesEntryfmt[]="nixsxxxixiiiii";
+char const ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx";
+char const ChrClassesXPowerTypesfmt[]="nii";
-const char CinematicSequencesEntryfmt[]="nxxxxxxxxx";
-const char CreatureDisplayInfofmt[]="nixxfxxxxxxxxxxxx";
-const char CreatureModelDatafmt[]="nxxxxxxxxxxxxxffxxxxxxxxxxxxxxx";
-const char CreatureFamilyfmt[]="nfifiiiiixsx";
-const char CreatureSpellDatafmt[]="niiiixxxx";
-const char CreatureTypefmt[]="nxx";
-const char CurrencyTypesfmt[]="nxxxxxiiiix";
+char const CinematicSequencesEntryfmt[]="nxxxxxxxxx";
+char const CreatureDisplayInfofmt[]="nixxfxxxxxxxxxxxx";
+char const CreatureModelDatafmt[]="nxxxxxxxxxxxxxffxxxxxxxxxxxxxxx";
+char const CreatureFamilyfmt[]="nfifiiiiixsx";
+char const CreatureSpellDatafmt[]="niiiixxxx";
+char const CreatureTypefmt[]="nxx";
+char const CurrencyTypesfmt[]="nxxxxxiiiix";
-const char DestructibleModelDatafmt[]="ixxixxxixxxixxxixxxxxxxx";
-const char DungeonEncounterfmt[]="iiixisxx";
-const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
-const char DurabilityQualityfmt[]="nf";
-const char EmotesEntryfmt[]="nxxiiixx";
-const char EmotesTextEntryfmt[]="nxixxxxxxxxxxxxxxxx";
-const char FactionEntryfmt[]="niiiiiiiiiiiiiiiiiiffixsxx";
-const char FactionTemplateEntryfmt[]="niiiiiiiiiiiii";
-const char GameObjectDisplayInfofmt[]="nsxxxxxxxxxxffffffxxx";
+char const DestructibleModelDatafmt[]="ixxixxxixxxixxxixxxxxxxx";
+char const DungeonEncounterfmt[]="iiixisxx";
+char const DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
+char const DurabilityQualityfmt[]="nf";
+char const EmotesEntryfmt[]="nxxiiixx";
+char const EmotesTextEntryfmt[]="nxixxxxxxxxxxxxxxxx";
+char const FactionEntryfmt[]="niiiiiiiiiiiiiiiiiiffixsxx";
+char const FactionTemplateEntryfmt[]="niiiiiiiiiiiii";
+char const GameObjectDisplayInfofmt[]="nsxxxxxxxxxxffffffxxx";
-const char GemPropertiesEntryfmt[]="nixxix";
-const char GlyphPropertiesfmt[]="niii";
-const char GlyphSlotfmt[]="nii";
+char const GemPropertiesEntryfmt[]="nixxix";
+char const GlyphPropertiesfmt[]="niii";
+char const GlyphSlotfmt[]="nii";
-const char GtBarberShopCostBasefmt[]="xf";
-const char GtCombatRatingsfmt[]="xf";
-const char GtOCTHpPerStaminafmt[]="df";
-const char GtChanceToMeleeCritBasefmt[]="xf";
-const char GtChanceToMeleeCritfmt[]="xf";
-const char GtChanceToSpellCritBasefmt[]="xf";
-const char GtChanceToSpellCritfmt[]="xf";
-const char GtOCTClassCombatRatingScalarfmt[]="df";
-const char GtOCTRegenHPfmt[]="f";
-//const char GtOCTRegenMPfmt[]="f";
-const char GtRegenMPPerSptfmt[]="xf";
-const char GtSpellScalingfmt[]="df";
-const char GtOCTBaseHPByClassfmt[]="df";
-const char GtOCTBaseMPByClassfmt[]="df";
-const char GuildPerkSpellsfmt[]="dii";
-const char Holidaysfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
-const char ImportPriceArmorfmt[]="nffff";
-const char ImportPriceQualityfmt[]="nf";
-const char ImportPriceShieldfmt[]="nf";
-const char ImportPriceWeaponfmt[]="nf";
-const char ItemPriceBasefmt[]="diff";
-const char ItemReforgefmt[]="nifif";
-const char ItemBagFamilyfmt[]="nx";
-const char ItemArmorQualityfmt[]="nfffffffi";
-const char ItemArmorShieldfmt[]="nifffffff";
-const char ItemArmorTotalfmt[]="niffff";
-const char ItemClassfmt[]="dixxfx";
-const char ItemDamagefmt[]="nfffffffi";
-const char ItemDisenchantLootfmt[]="niiiiii";
-//const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";
-const char ItemLimitCategoryEntryfmt[]="nxii";
-const char ItemRandomPropertiesfmt[]="nxiiixxs";
-const char ItemRandomSuffixfmt[]="nsxiiiiiiiiii";
-const char ItemSetEntryfmt[]="dsiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii";
-const char LFGDungeonEntryfmt[]="nxiiiiiiiiixxixixxxxx";
-const char LiquidTypefmt[]="nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
-const char PhaseEntryfmt[]="nsi";
-const char MailTemplateEntryfmt[]="nxs";
-const char MapEntryfmt[]="nxixxxsixxixiffxiixi";
-const char MapDifficultyEntryfmt[]="diisiix";
-const char MovieEntryfmt[]="nxxx";
-const char MountCapabilityfmt[]="niiiiiii";
-const char MountTypefmt[]="niiiiiiiiiiiiiiiiiiiiiiii";
-const char NameGenfmt[] = "dsii";
-const char NumTalentsAtLevelfmt[]="df";
-const char OverrideSpellDatafmt[]="niiiiiiiiiixx";
-const char QuestSortEntryfmt[]="nx";
-const char QuestXPfmt[]="niiiiiiiiii";
-const char QuestFactionRewardfmt[]="niiiiiiiiii";
-const char PvPDifficultyfmt[]="diiiii";
-const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";
-const char ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiixi";
-const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
-const char SkillLinefmt[]="nisxixi";
-const char SkillLineAbilityfmt[]="niiiixxiiiiixx";
-const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-const char SpellCastTimefmt[]="nixx";
-const char SpellCategoriesEntryfmt[]="diiiiii";
-const char SpellDifficultyfmt[]="niiii";
+char const GtBarberShopCostBasefmt[]="xf";
+char const GtCombatRatingsfmt[]="xf";
+char const GtOCTHpPerStaminafmt[]="df";
+char const GtChanceToMeleeCritBasefmt[]="xf";
+char const GtChanceToMeleeCritfmt[]="xf";
+char const GtChanceToSpellCritBasefmt[]="xf";
+char const GtChanceToSpellCritfmt[]="xf";
+char const GtOCTClassCombatRatingScalarfmt[]="df";
+char const GtOCTRegenHPfmt[]="f";
+//char const GtOCTRegenMPfmt[]="f";
+char const GtRegenMPPerSptfmt[]="xf";
+char const GtSpellScalingfmt[]="df";
+char const GtOCTBaseHPByClassfmt[]="df";
+char const GtOCTBaseMPByClassfmt[]="df";
+char const GuildPerkSpellsfmt[]="dii";
+char const Holidaysfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
+char const ImportPriceArmorfmt[]="nffff";
+char const ImportPriceQualityfmt[]="nf";
+char const ImportPriceShieldfmt[]="nf";
+char const ImportPriceWeaponfmt[]="nf";
+char const ItemPriceBasefmt[]="diff";
+char const ItemReforgefmt[]="nifif";
+char const ItemBagFamilyfmt[]="nx";
+char const ItemArmorQualityfmt[]="nfffffffi";
+char const ItemArmorShieldfmt[]="nifffffff";
+char const ItemArmorTotalfmt[]="niffff";
+char const ItemClassfmt[]="dixxfx";
+char const ItemDamagefmt[]="nfffffffi";
+char const ItemDisenchantLootfmt[]="niiiiii";
+//char const ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";
+char const ItemLimitCategoryEntryfmt[]="nxii";
+char const ItemRandomPropertiesfmt[]="nxiiixxs";
+char const ItemRandomSuffixfmt[]="nsxiiiiiiiiii";
+char const ItemSetEntryfmt[]="dsiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii";
+char const LFGDungeonEntryfmt[]="nsiiiiiiiiixxixixxxxx";
+char const LiquidTypefmt[]="nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+char const LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
+char const PhaseEntryfmt[]="nsi";
+char const MailTemplateEntryfmt[]="nxs";
+char const MapEntryfmt[]="nxixxxsixxixiffxiixi";
+char const MapDifficultyEntryfmt[]="diisiix";
+char const MovieEntryfmt[]="nxxx";
+char const MountCapabilityfmt[]="niiiiiii";
+char const MountTypefmt[]="niiiiiiiiiiiiiiiiiiiiiiii";
+char const NameGenfmt[] = "dsii";
+char const NumTalentsAtLevelfmt[]="df";
+char const OverrideSpellDatafmt[]="niiiiiiiiiixx";
+char const QuestSortEntryfmt[]="nx";
+char const QuestXPfmt[]="niiiiiiiiii";
+char const QuestFactionRewardfmt[]="niiiiiiiiii";
+char const PvPDifficultyfmt[]="diiiii";
+char const RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";
+char const ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiixi";
+char const ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
+char const SkillLinefmt[]="nisxixi";
+char const SkillLineAbilityfmt[]="niiiixxiiiiixx";
+char const SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+char const SpellCastTimefmt[]="nixx";
+char const SpellCategoriesEntryfmt[]="diiiiii";
+char const SpellDifficultyfmt[]="niiii";
const std::string CustomSpellDifficultyfmt="ppppp";
const std::string CustomSpellDifficultyIndex="id";
-const char SpellDurationfmt[]="niii";
-const char SpellEffectEntryfmt[]="nifiiiffiiiiiifiifiiiiiiiix";
-const char SpellEntryfmt[]="niiiiiiiiiiiiiiifiiiissxxiixxixiiiiiiixiiiiiiiix";
+char const SpellDurationfmt[]="niii";
+char const SpellEffectEntryfmt[]="nifiiiffiiiiiifiifiiiiiiiix";
+char const SpellEntryfmt[]="niiiiiiiiiiiiiiifiiiissxxiixxixiiiiiiixiiiiiiiix";
const std::string CustomSpellEntryfmt="papppppppppppapapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa";
const std::string CustomSpellEntryIndex = "Id";
-const char SpellFocusObjectfmt[]="nx";
-const char SpellItemEnchantmentfmt[]="nxiiiiiixxxiiisiiiiiiix";
-const char SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX";
-const char SpellRadiusfmt[]="nfxf";
-const char SpellRangefmt[]="nffffixx";
-const char SpellReagentsEntryfmt[]="diiiiiiiiiiiiiiii";
-const char SpellScalingEntryfmt[]="diiiiffffffffffi";
-const char SpellTotemsEntryfmt[]="niiii";
-const char SpellTargetRestrictionsEntryfmt[]="nxiiii";
-const char SpellPowerEntryfmt[]="diiiixxx";
-const char SpellInterruptsEntryfmt[]="dixixi";
-const char SpellEquippedItemsEntryfmt[]="diii";
-const char SpellAuraOptionsEntryfmt[]="niiii";
-const char SpellAuraRestrictionsEntryfmt[]="diiiiiiii";
-const char SpellCastingRequirementsEntryfmt[]="dixxixi";
-const char SpellClassOptionsEntryfmt[]="dxiiiix";
-const char SpellCooldownsEntryfmt[]="diii";
-const char SpellLevelsEntryfmt[]="diii";
-const char SpellRuneCostfmt[]="niiii";
-const char SpellShapeshiftEntryfmt[]="nixixx";
-const char SpellShapeshiftFormfmt[]="nxxiixiiixxiiiiiiiixx";
-const char StableSlotPricesfmt[] = "ni";
-const char SummonPropertiesfmt[] = "niiiii";
-const char TalentEntryfmt[]="niiiiiiiiixxixxxxxx";
-const char TalentTabEntryfmt[]="nxxiiixxxxx";
-const char TalentTreePrimarySpellsfmt[]="diix";
-const char TaxiNodesEntryfmt[]="nifffsiixxx";
-const char TaxiPathEntryfmt[]="niii";
-const char TaxiPathNodeEntryfmt[]="diiifffiiii";
-const char TeamContributionPointsfmt[]="df";
-const char TotemCategoryEntryfmt[]="nxii";
-const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifiixx";
-const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxxxxxxxxxx";
-const char WMOAreaTableEntryfmt[]="niiixxxxxiixxxx";
-const char WorldMapAreaEntryfmt[]="xinxffffixxxxx";
-const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxx";
-const char WorldSafeLocsEntryfmt[]="nifffx";
+char const SpellFocusObjectfmt[]="nx";
+char const SpellItemEnchantmentfmt[]="nxiiiiiixxxiiisiiiiiiix";
+char const SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX";
+char const SpellRadiusfmt[]="nfxf";
+char const SpellRangefmt[]="nffffixx";
+char const SpellReagentsEntryfmt[]="diiiiiiiiiiiiiiii";
+char const SpellScalingEntryfmt[]="diiiiffffffffffi";
+char const SpellTotemsEntryfmt[]="niiii";
+char const SpellTargetRestrictionsEntryfmt[]="nxiiii";
+char const SpellPowerEntryfmt[]="diiiixxx";
+char const SpellInterruptsEntryfmt[]="dixixi";
+char const SpellEquippedItemsEntryfmt[]="diii";
+char const SpellAuraOptionsEntryfmt[]="niiii";
+char const SpellAuraRestrictionsEntryfmt[]="diiiiiiii";
+char const SpellCastingRequirementsEntryfmt[]="dixxixi";
+char const SpellClassOptionsEntryfmt[]="dxiiiix";
+char const SpellCooldownsEntryfmt[]="diii";
+char const SpellLevelsEntryfmt[]="diii";
+char const SpellRuneCostfmt[]="niiii";
+char const SpellShapeshiftEntryfmt[]="nixixx";
+char const SpellShapeshiftFormfmt[]="nxxiixiiixxiiiiiiiixx";
+char const StableSlotPricesfmt[] = "ni";
+char const SummonPropertiesfmt[] = "niiiii";
+char const TalentEntryfmt[]="niiiiiiiiixxixxxxxx";
+char const TalentTabEntryfmt[]="nxxiiixxxxx";
+char const TalentTreePrimarySpellsfmt[]="diix";
+char const TaxiNodesEntryfmt[]="nifffsiixxx";
+char const TaxiPathEntryfmt[]="niii";
+char const TaxiPathNodeEntryfmt[]="diiifffiiii";
+char const TeamContributionPointsfmt[]="df";
+char const TotemCategoryEntryfmt[]="nxii";
+char const VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifiixx";
+char const VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxxxxxxxxxx";
+char const WMOAreaTableEntryfmt[]="niiixxxxxiixxxx";
+char const WorldMapAreaEntryfmt[]="xinxffffixxxxx";
+char const WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxx";
+char const WorldSafeLocsEntryfmt[]="nifffx";
#endif
diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h
index 28498749af8..abdb0ffa511 100755
--- a/src/server/game/DungeonFinding/LFG.h
+++ b/src/server/game/DungeonFinding/LFG.h
@@ -20,19 +20,26 @@
#include "Common.h"
+enum LFGEnum
+{
+ LFG_TANKS_NEEDED = 1,
+ LFG_HEALERS_NEEDED = 1,
+ LFG_DPS_NEEDED = 3
+};
+
enum LfgRoles
{
- ROLE_NONE = 0x00,
- ROLE_LEADER = 0x01,
- ROLE_TANK = 0x02,
- ROLE_HEALER = 0x04,
- ROLE_DAMAGE = 0x08
+ PLAYER_ROLE_NONE = 0x00,
+ PLAYER_ROLE_LEADER = 0x01,
+ PLAYER_ROLE_TANK = 0x02,
+ PLAYER_ROLE_HEALER = 0x04,
+ PLAYER_ROLE_DAMAGE = 0x08
};
enum LfgUpdateType
{
LFG_UPDATETYPE_DEFAULT = 0, // Internal Use
- LFG_UPDATETYPE_LEADER = 1,
+ LFG_UPDATETYPE_LEADER_UNK1 = 1, // FIXME: At group leave
LFG_UPDATETYPE_ROLECHECK_ABORTED = 4,
LFG_UPDATETYPE_JOIN_PROPOSAL = 5,
LFG_UPDATETYPE_ROLECHECK_FAILED = 6,
@@ -44,7 +51,7 @@ enum LfgUpdateType
LFG_UPDATETYPE_PROPOSAL_BEGIN = 13,
LFG_UPDATETYPE_CLEAR_LOCK_LIST = 14,
LFG_UPDATETYPE_GROUP_MEMBER_OFFLINE = 15,
- LFG_UPDATETYPE_GROUP_DISBAND = 16
+ LFG_UPDATETYPE_GROUP_DISBAND_UNK16 = 16, // FIXME: Sometimes at group disband
};
enum LfgState
@@ -62,7 +69,6 @@ enum LfgState
/// Instance lock types
enum LfgLockStatusType
{
- LFG_LOCKSTATUS_OK = 0, // Internal use only
LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION = 1,
LFG_LOCKSTATUS_TOO_LOW_LEVEL = 2,
LFG_LOCKSTATUS_TOO_HIGH_LEVEL = 3,
@@ -73,18 +79,24 @@ enum LfgLockStatusType
LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL = 1002,
LFG_LOCKSTATUS_QUEST_NOT_COMPLETED = 1022,
LFG_LOCKSTATUS_MISSING_ITEM = 1025,
- LFG_LOCKSTATUS_NOT_IN_SEASON = 1031
+ LFG_LOCKSTATUS_NOT_IN_SEASON = 1031,
+ LFG_LOCKSTATUS_MISSING_ACHIEVEMENT = 1034
};
-/// Dungeon and reason why player can't join
-struct LfgLockStatus
+/// Answer state (Also used to check compatibilites)
+enum LfgAnswer
{
- uint32 dungeon; ///< Dungeon Id
- LfgLockStatusType lockstatus; ///< Lock type
+ LFG_ANSWER_PENDING = -1,
+ LFG_ANSWER_DENY = 0,
+ LFG_ANSWER_AGREE = 1
};
typedef std::set<uint32> LfgDungeonSet;
-typedef std::map<uint32, LfgLockStatusType> LfgLockMap;
+typedef std::map<uint32, uint32> LfgLockMap;
typedef std::map<uint64, LfgLockMap> LfgLockPartyMap;
+typedef std::set<uint64> LfgGuidSet;
+typedef std::list<uint64> LfgGuidList;
+typedef std::map<uint64, uint8> LfgRolesMap;
+typedef std::map<uint64, uint64> LfgGroupsMap;
#endif
diff --git a/src/server/game/DungeonFinding/LFGGroupData.cpp b/src/server/game/DungeonFinding/LFGGroupData.cpp
index 607389c5dbf..712ae5132b0 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.cpp
+++ b/src/server/game/DungeonFinding/LFGGroupData.cpp
@@ -18,25 +18,27 @@
#include "LFG.h"
#include "LFGGroupData.h"
-LfgGroupData::LfgGroupData():
-m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Dungeon(0),
-m_VotesNeeded(LFG_GROUP_KICK_VOTES_NEEDED), m_KicksLeft(LFG_GROUP_MAX_KICKS)
-{
-}
+LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE),
+ m_Leader(0), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS)
+{ }
LfgGroupData::~LfgGroupData()
+{ }
+
+bool LfgGroupData::IsLfgGroup()
{
+ return m_OldState != LFG_STATE_NONE;
}
void LfgGroupData::SetState(LfgState state)
{
switch (state)
{
+ case LFG_STATE_FINISHED_DUNGEON:
case LFG_STATE_NONE:
case LFG_STATE_DUNGEON:
- case LFG_STATE_FINISHED_DUNGEON:
m_OldState = state;
- // No break on purpose
+ // No break on purpose
default:
m_State = state;
}
@@ -47,6 +49,29 @@ void LfgGroupData::RestoreState()
m_State = m_OldState;
}
+void LfgGroupData::AddPlayer(uint64 guid)
+{
+ m_Players.insert(guid);
+}
+
+uint8 LfgGroupData::RemovePlayer(uint64 guid)
+{
+ LfgGuidSet::iterator it = m_Players.find(guid);
+ if (it != m_Players.end())
+ m_Players.erase(it);
+ return uint8(m_Players.size());
+}
+
+void LfgGroupData::RemoveAllPlayers()
+{
+ m_Players.clear();
+}
+
+void LfgGroupData::SetLeader(uint64 guid)
+{
+ m_Leader = guid;
+}
+
void LfgGroupData::SetDungeon(uint32 dungeon)
{
m_Dungeon = dungeon;
@@ -63,6 +88,21 @@ LfgState LfgGroupData::GetState() const
return m_State;
}
+LfgState LfgGroupData::GetOldState() const
+{
+ return m_OldState;
+}
+
+const LfgGuidSet &LfgGroupData::GetPlayers() const
+{
+ return m_Players;
+}
+
+uint64 LfgGroupData::GetLeader() const
+{
+ return m_Leader;
+}
+
uint32 LfgGroupData::GetDungeon(bool asId /* = true */) const
{
if (asId)
@@ -71,11 +111,6 @@ uint32 LfgGroupData::GetDungeon(bool asId /* = true */) const
return m_Dungeon;
}
-uint8 LfgGroupData::GetVotesNeeded() const
-{
- return m_VotesNeeded;
-}
-
uint8 LfgGroupData::GetKicksLeft() const
{
return m_KicksLeft;
diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h
index 74570817698..43cd64f97c3 100644
--- a/src/server/game/DungeonFinding/LFGGroupData.h
+++ b/src/server/game/DungeonFinding/LFGGroupData.h
@@ -23,7 +23,6 @@
enum LfgGroupEnum
{
LFG_GROUP_MAX_KICKS = 3,
- LFG_GROUP_KICK_VOTES_NEEDED = 3
};
/**
@@ -35,31 +34,43 @@ class LfgGroupData
LfgGroupData();
~LfgGroupData();
+ bool IsLfgGroup();
+
// General
void SetState(LfgState state);
void RestoreState();
+ void AddPlayer(uint64 guid);
+ uint8 RemovePlayer(uint64 guid);
+ void RemoveAllPlayers();
+ void SetLeader(uint64 guid);
+
// Dungeon
void SetDungeon(uint32 dungeon);
+
// VoteKick
- void SetVotesNeeded(uint8 votes);
void DecreaseKicksLeft();
// General
LfgState GetState() const;
+ LfgState GetOldState() const;
+ LfgGuidSet const& GetPlayers() const;
+ uint64 GetLeader() const;
+
// Dungeon
uint32 GetDungeon(bool asId = true) const;
+
// VoteKick
- uint8 GetVotesNeeded() const;
uint8 GetKicksLeft() const;
private:
// General
LfgState m_State; ///< State if group in LFG
LfgState m_OldState; ///< Old State
+ uint64 m_Leader; ///< Leader GUID
+ LfgGuidSet m_Players; ///< Players in group
// Dungeon
uint32 m_Dungeon; ///< Dungeon entry
// Vote Kick
- uint8 m_VotesNeeded; ///< Votes need to kick success
uint8 m_KicksLeft; ///< Number of kicks left
};
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index 2b425dffff0..16fda8952ac 100755
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -18,60 +18,30 @@
#include "Common.h"
#include "SharedDefines.h"
#include "DBCStores.h"
-#include "Containers.h"
#include "DisableMgr.h"
#include "ObjectMgr.h"
#include "SocialMgr.h"
#include "LFGMgr.h"
-#include "GroupMgr.h"
-#include "GameEventMgr.h"
#include "LFGScripts.h"
#include "LFGGroupData.h"
#include "LFGPlayerData.h"
-
+#include "LFGQueue.h"
#include "Group.h"
#include "Player.h"
+#include "GroupMgr.h"
+#include "GameEventMgr.h"
-LFGMgr::LFGMgr(): m_update(true), m_QueueTimer(0), m_lfgProposalId(1),
-m_WaitTimeAvg(-1), m_WaitTimeTank(-1), m_WaitTimeHealer(-1), m_WaitTimeDps(-1),
-m_NumWaitTimeAvg(0), m_NumWaitTimeTank(0), m_NumWaitTimeHealer(0), m_NumWaitTimeDps(0)
-{
- m_update = sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE);
- if (m_update)
- {
- new LFGPlayerScript();
- new LFGGroupScript();
-
- // Initialize dungeon cache
- for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
- {
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i);
- if (dungeon && dungeon->type != LFG_TYPE_ZONE)
- {
- if (dungeon->type != LFG_TYPE_RANDOM)
- m_CachedDungeonMap[dungeon->grouptype].insert(dungeon->ID);
- m_CachedDungeonMap[0].insert(dungeon->ID);
- }
- }
- }
-}
+LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1),
+ m_options(sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE)),
+ m_lfgPlayerScript(new LFGPlayerScript()), m_lfgGroupScript(new LFGGroupScript())
+{ }
LFGMgr::~LFGMgr()
{
for (LfgRewardMap::iterator itr = m_RewardMap.begin(); itr != m_RewardMap.end(); ++itr)
delete itr->second;
-
- for (LfgQueueInfoMap::iterator it = m_QueueInfoMap.begin(); it != m_QueueInfoMap.end(); ++it)
- delete it->second;
-
- for (LfgProposalMap::iterator it = m_Proposals.begin(); it != m_Proposals.end(); ++it)
- delete it->second;
-
- for (LfgPlayerBootMap::iterator it = m_Boots.begin(); it != m_Boots.end(); ++it)
- delete it->second;
-
- for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end(); ++it)
- delete it->second;
+ delete m_lfgPlayerScript;
+ delete m_lfgGroupScript;
}
void LFGMgr::_LoadFromDB(Field* fields, uint64 guid)
@@ -122,6 +92,89 @@ void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid)
CharacterDatabase.Execute(stmt);
}
+std::string LFGMgr::ConcatenateDungeons(LfgDungeonSet const& dungeons)
+{
+ std::string dungeonstr = "";
+ if (!dungeons.empty())
+ {
+ std::ostringstream o;
+ LfgDungeonSet::const_iterator it = dungeons.begin();
+ o << (*it);
+ for (++it; it != dungeons.end(); ++it)
+ o << ", " << uint32(*it);
+ dungeonstr = o.str();
+ }
+ return dungeonstr;
+}
+
+std::string LFGMgr::GetRolesString(uint8 roles)
+{
+ std::string rolesstr = "";
+
+ if (roles & PLAYER_ROLE_TANK)
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK));
+
+ if (roles & PLAYER_ROLE_HEALER)
+ {
+ if (!rolesstr.empty())
+ rolesstr.append(", ");
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER));
+ }
+
+ if (roles & PLAYER_ROLE_DAMAGE)
+ {
+ if (!rolesstr.empty())
+ rolesstr.append(", ");
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE));
+ }
+
+ if (roles & PLAYER_ROLE_LEADER)
+ {
+ if (!rolesstr.empty())
+ rolesstr.append(", ");
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER));
+ }
+
+ if (rolesstr.empty())
+ rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE));
+
+ return rolesstr;
+}
+
+char const * LFGMgr::GetStateString(LfgState state)
+{
+ int32 entry = LANG_LFG_ERROR;
+ switch (state)
+ {
+ case LFG_STATE_NONE:
+ entry = LANG_LFG_STATE_NONE;
+ break;
+ case LFG_STATE_ROLECHECK:
+ entry = LANG_LFG_STATE_ROLECHECK;
+ break;
+ case LFG_STATE_QUEUED:
+ entry = LANG_LFG_STATE_QUEUED;
+ break;
+ case LFG_STATE_PROPOSAL:
+ entry = LANG_LFG_STATE_PROPOSAL;
+ break;
+ case LFG_STATE_DUNGEON:
+ entry = LANG_LFG_STATE_DUNGEON;
+ break;
+ case LFG_STATE_BOOT:
+ entry = LANG_LFG_STATE_BOOT;
+ break;
+ case LFG_STATE_FINISHED_DUNGEON:
+ entry = LANG_LFG_STATE_FINISHED_DUNGEON;
+ break;
+ case LFG_STATE_RAIDBROWSER:
+ entry = LANG_LFG_STATE_RAIDBROWSER;
+ break;
+ }
+ char const * const str = sObjectMgr->GetTrinityStringForDBCLocale(entry);
+ return str;
+}
+
/// Load rewards for completing dungeons
void LFGMgr::LoadRewards()
{
@@ -155,7 +208,7 @@ void LFGMgr::LoadRewards()
uint32 otherMoneyVar = fields[6].GetUInt32();
uint32 otherXPVar = fields[7].GetUInt32();
- if (!sLFGDungeonStore.LookupEntry(dungeonId))
+ if (!GetLFGDungeon(dungeonId))
{
sLog->outError(LOG_FILTER_SQL, "Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId);
continue;
@@ -186,16 +239,50 @@ void LFGMgr::LoadRewards()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u lfg dungeon rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
-void LFGMgr::LoadEntrancePositions()
+LFGDungeonEntry const* LFGMgr::GetLFGDungeon(uint32 id)
+{
+ LFGDungeonMap::const_iterator itr = m_LfgDungeonMap.find(id);
+ if (itr != m_LfgDungeonMap.end())
+ return &(itr->second);
+
+ return NULL;
+}
+
+LFGDungeonMap & LFGMgr::GetLFGDungeonMap()
+{
+ return m_LfgDungeonMap;
+}
+
+void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
{
uint32 oldMSTime = getMSTime();
- m_entrancePositions.clear();
+ m_LfgDungeonMap.clear();
+
+ // Initialize Dungeon map with data from dbcs
+ for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
+ {
+ LFGDungeonEntryDbc const* dungeon = sLFGDungeonStore.LookupEntry(i);
+ if (!dungeon)
+ continue;
+
+ switch (dungeon->type)
+ {
+ case LFG_TYPE_DUNGEON:
+ case LFG_TYPE_HEROIC:
+ case LFG_TYPE_RAID:
+ case LFG_TYPE_RANDOM:
+ m_LfgDungeonMap[dungeon->ID] = LFGDungeonEntry(dungeon);
+ break;
+ }
+ }
+
+ // Fill teleport locations from DB
QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation FROM lfg_entrances");
if (!result)
{
- sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!");
+ sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!");
return;
}
@@ -205,49 +292,85 @@ void LFGMgr::LoadEntrancePositions()
{
Field* fields = result->Fetch();
uint32 dungeonId = fields[0].GetUInt32();
- Position pos;
- pos.m_positionX = fields[1].GetFloat();
- pos.m_positionY = fields[2].GetFloat();
- pos.m_positionZ = fields[3].GetFloat();
- pos.m_orientation = fields[4].GetFloat();
- m_entrancePositions[dungeonId] = pos;
+ LFGDungeonMap::iterator dungeonItr = m_LfgDungeonMap.find(dungeonId);
+ if (dungeonItr == m_LfgDungeonMap.end())
+ {
+ sLog->outError(LOG_FILTER_SQL, "table `lfg_entrances` contains coordinates for wrong dungeon %u", dungeonId);
+ continue;
+ }
+
+ LFGDungeonEntry& data = dungeonItr->second;
+ data.x = fields[1].GetFloat();
+ data.y = fields[2].GetFloat();
+ data.z = fields[3].GetFloat();
+ data.o = fields[4].GetFloat();
+
++count;
}
while (result->NextRow());
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u lfg entrance positions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+
+ // Fill all other teleport coords from areatriggers
+ for (LFGDungeonMap::iterator itr = m_LfgDungeonMap.begin(); itr != m_LfgDungeonMap.end(); ++itr)
+ {
+ LFGDungeonEntry& dungeon = itr->second;
+ // No teleport coords in database, load from areatriggers
+ if (dungeon.x == 0.0f && dungeon.y == 0.0f && dungeon.z == 0.0f)
+ {
+ AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon.map);
+ if (!at)
+ {
+ sLog->outError(LOG_FILTER_LFG, "LFGMgr::LoadLFGDungeons: Failed to load dungeon %s, cant find areatrigger for map %u", dungeon.name.c_str(), dungeon.map);
+ continue;
+ }
+
+ dungeon.map = at->target_mapId;
+ dungeon.x = at->target_X;
+ dungeon.y = at->target_Y;
+ dungeon.z = at->target_Z;
+ dungeon.o = at->target_Orientation;
+ }
+
+ if (dungeon.type != LFG_TYPE_RANDOM)
+ m_CachedDungeonMap[dungeon.group].insert(dungeon.id);
+ m_CachedDungeonMap[0].insert(dungeon.id);
+ }
+
+ if (reload)
+ {
+ m_CachedDungeonMap.clear();
+ // Recalculate locked dungeons
+ for (LfgPlayerDataMap::const_iterator it = m_Players.begin(); it != m_Players.end(); ++it)
+ if (Player* player = ObjectAccessor::FindPlayer(it->first))
+ InitializeLockedDungeons(player);
+ }
}
void LFGMgr::Update(uint32 diff)
{
- if (!m_update)
+ if (!m_options)
return;
- m_update = false;
time_t currTime = time(NULL);
// Remove obsolete role checks
for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end();)
{
LfgRoleCheckMap::iterator itRoleCheck = it++;
- LfgRoleCheck* roleCheck = itRoleCheck->second;
- if (currTime < roleCheck->cancelTime)
+ LfgRoleCheck& roleCheck = itRoleCheck->second;
+ if (currTime < roleCheck.cancelTime)
continue;
- roleCheck->state = LFG_ROLECHECK_MISSING_ROLE;
+ roleCheck.state = LFG_ROLECHECK_MISSING_ROLE;
- for (LfgRolesMap::const_iterator itRoles = roleCheck->roles.begin(); itRoles != roleCheck->roles.end(); ++itRoles)
+ for (LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin(); itRoles != roleCheck.roles.end(); ++itRoles)
{
uint64 guid = itRoles->first;
- ClearState(guid);
- if (Player* player = ObjectAccessor::FindPlayer(guid))
- {
- player->GetSession()->SendLfgRoleCheckUpdate(roleCheck);
-
- if (itRoles->first == roleCheck->leader)
- player->GetSession()->SendLfgJoinResult(LfgJoinResultData(LFG_JOIN_FAILED, LFG_ROLECHECK_MISSING_ROLE));
- }
+ ClearState(guid, "Remove Obsolete RoleCheck");
+ SendLfgRoleCheckUpdate(guid, roleCheck);
+ if (guid == roleCheck.leader)
+ SendLfgJoinResult(guid, LfgJoinResultData(LFG_JOIN_FAILED, LFG_ROLECHECK_MISSING_ROLE));
}
- delete roleCheck;
m_RoleChecks.erase(itRoleCheck);
}
@@ -255,7 +378,7 @@ void LFGMgr::Update(uint32 diff)
for (LfgProposalMap::iterator it = m_Proposals.begin(); it != m_Proposals.end();)
{
LfgProposalMap::iterator itRemove = it++;
- if (itRemove->second->cancelTime < currTime)
+ if (itRemove->second.cancelTime < currTime)
RemoveProposal(itRemove, LFG_UPDATETYPE_PROPOSAL_FAILED);
}
@@ -263,71 +386,51 @@ void LFGMgr::Update(uint32 diff)
for (LfgPlayerBootMap::iterator it = m_Boots.begin(); it != m_Boots.end();)
{
LfgPlayerBootMap::iterator itBoot = it++;
- LfgPlayerBoot* pBoot = itBoot->second;
- if (pBoot->cancelTime < currTime)
+ LfgPlayerBoot& boot = itBoot->second;
+ if (boot.cancelTime < currTime)
{
- pBoot->inProgress = false;
- for (LfgAnswerMap::const_iterator itVotes = pBoot->votes.begin(); itVotes != pBoot->votes.end(); ++itVotes)
- if (Player* plrg = ObjectAccessor::FindPlayer(itVotes->first))
- if (plrg->GetGUID() != pBoot->victim)
- plrg->GetSession()->SendLfgBootPlayer(pBoot);
- delete pBoot;
+ boot.inProgress = false;
+ for (LfgAnswerMap::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
+ {
+ uint64 pguid = itVotes->first;
+ if (pguid != boot.victim)
+ SendLfgBootProposalUpdate(pguid, boot);
+ }
m_Boots.erase(itBoot);
}
}
+ uint32 lastProposalId = m_lfgProposalId;
// Check if a proposal can be formed with the new groups being added
- for (LfgGuidListMap::iterator it = m_newToQueue.begin(); it != m_newToQueue.end(); ++it)
+ for (LfgQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it)
+ if (uint8 newProposals = it->second.FindGroups())
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Update: Found %u new groups in queue %u", newProposals, it->first);
+
+ if (lastProposalId != m_lfgProposalId)
{
- uint8 queueId = it->first;
- LfgGuidList& newToQueue = it->second;
- LfgGuidList& currentQueue = m_currentQueue[queueId];
- LfgGuidList firstNew;
- while (!newToQueue.empty())
+ // FIXME lastProposalId ? lastProposalId +1 ?
+ for (LfgProposalMap::const_iterator itProposal = m_Proposals.find(m_lfgProposalId); itProposal != m_Proposals.end(); ++itProposal)
{
- uint64 frontguid = newToQueue.front();
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Update: QueueId %u: checking [" UI64FMTD "] newToQueue(%u), currentQueue(%u)", queueId, frontguid, uint32(newToQueue.size()), uint32(currentQueue.size()));
- firstNew.push_back(frontguid);
- newToQueue.pop_front();
+ uint32 proposalId = itProposal->first;
+ LfgProposal& proposal = m_Proposals[proposalId];
- LfgGuidList temporalList = currentQueue;
- if (LfgProposal* pProposal = FindNewGroups(firstNew, temporalList)) // Group found!
+ uint64 guid = 0;
+ for (LfgProposalPlayerMap::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
{
- // Remove groups in the proposal from new and current queues (not from queue map)
- for (LfgGuidList::const_iterator itQueue = pProposal->queues.begin(); itQueue != pProposal->queues.end(); ++itQueue)
- {
- currentQueue.remove(*itQueue);
- newToQueue.remove(*itQueue);
- }
- m_Proposals[++m_lfgProposalId] = pProposal;
-
- uint64 guid = 0;
- for (LfgProposalPlayerMap::const_iterator itPlayers = pProposal->players.begin(); itPlayers != pProposal->players.end(); ++itPlayers)
+ guid = itPlayers->first;
+ SetState(guid, LFG_STATE_PROPOSAL);
+ if (uint64 gguid = GetGroup(guid))
{
- guid = itPlayers->first;
- SetState(guid, LFG_STATE_PROPOSAL);
- if (Player* player = ObjectAccessor::FindPlayer(itPlayers->first))
- {
- Group* grp = player->GetGroup();
- if (grp)
- {
- uint64 gguid = grp->GetGUID();
- SetState(gguid, LFG_STATE_PROPOSAL);
- player->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
- }
- else
- player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
- player->GetSession()->SendLfgUpdateProposal(m_lfgProposalId, pProposal);
- }
+ SetState(gguid, LFG_STATE_PROPOSAL);
+ SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
}
-
- if (pProposal->state == LFG_PROPOSAL_SUCCESS)
- UpdateProposal(m_lfgProposalId, guid, true);
+ else
+ SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
+ SendLfgUpdateProposal(guid, m_lfgProposalId, proposal);
}
- else
- if (std::find(currentQueue.begin(), currentQueue.end(), frontguid) == currentQueue.end()) //already in queue?
- currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue.
- firstNew.clear();
+
+ if (proposal.state == LFG_PROPOSAL_SUCCESS)
+ UpdateProposal(proposalId, guid, true);
}
}
@@ -335,105 +438,12 @@ void LFGMgr::Update(uint32 diff)
if (m_QueueTimer > LFG_QUEUEUPDATE_INTERVAL)
{
m_QueueTimer = 0;
- currTime = time(NULL);
- for (LfgQueueInfoMap::const_iterator itQueue = m_QueueInfoMap.begin(); itQueue != m_QueueInfoMap.end(); ++itQueue)
- {
- LfgQueueInfo* queue = itQueue->second;
- if (!queue)
- {
- sLog->outError(LOG_FILTER_LFG, "LFGMgr::Update: [" UI64FMTD "] queued with null queue info!", itQueue->first);
- continue;
- }
- uint32 dungeonId = (*queue->dungeons.begin());
- uint32 queuedTime = uint32(currTime - queue->joinTime);
- uint8 role = ROLE_NONE;
- for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer)
- role |= itPlayer->second;
- role &= ~ROLE_LEADER;
-
- int32 waitTime = -1;
- switch (role)
- {
- case ROLE_NONE: // Should not happen - just in case
- waitTime = -1;
- break;
- case ROLE_TANK:
- waitTime = m_WaitTimeTank;
- break;
- case ROLE_HEALER:
- waitTime = m_WaitTimeHealer;
- break;
- case ROLE_DAMAGE:
- waitTime = m_WaitTimeDps;
- break;
- default:
- waitTime = m_WaitTimeAvg;
- break;
- }
-
- for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer)
- if (Player* player = ObjectAccessor::FindPlayer(itPlayer->first))
- player->GetSession()->SendLfgQueueStatus(dungeonId, waitTime, m_WaitTimeAvg, m_WaitTimeTank, m_WaitTimeHealer, m_WaitTimeDps, queuedTime, queue->tanks, queue->healers, queue->dps);
- }
+ time_t currTime = time(NULL);
+ for (LfgQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it)
+ it->second.UpdateQueueTimers(currTime);
}
else
m_QueueTimer += diff;
- m_update = true;
-}
-
-/**
- Add a guid to the queue of guids to be added to main queue. It guid its already
- in queue does nothing. If this function is called guid is not in the main queue
- (No need to check it here)
-
- @param[in] guid Player or group guid to add to queue
- @param[in] queueId Queue Id to add player/group to
-*/
-void LFGMgr::AddToQueue(uint64 guid, uint8 queueId)
-{
- if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
- queueId = 0;
-
- LfgGuidList& list = m_newToQueue[queueId];
- if (std::find(list.begin(), list.end(), guid) != list.end())
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::AddToQueue: [" UI64FMTD "] already in new queue. ignoring", guid);
- else
- {
- list.push_back(guid);
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::AddToQueue: [" UI64FMTD "] added to m_newToQueue (size: %u)", guid, uint32(list.size()));
- }
-}
-
-/**
- Removes a guid from the main and new queues.
-
- @param[in] guid Player or group guid to add to queue
- @return true if guid was found in main queue.
-*/
-bool LFGMgr::RemoveFromQueue(uint64 guid)
-{
- for (LfgGuidListMap::iterator it = m_currentQueue.begin(); it != m_currentQueue.end(); ++it)
- it->second.remove(guid);
-
- for (LfgGuidListMap::iterator it = m_newToQueue.begin(); it != m_newToQueue.end(); ++it)
- it->second.remove(guid);
-
- RemoveFromCompatibles(guid);
-
- LfgQueueInfoMap::iterator it = m_QueueInfoMap.find(guid);
- if (it != m_QueueInfoMap.end())
- {
- delete it->second;
- m_QueueInfoMap.erase(it);
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveFromQueue: [" UI64FMTD "] removed", guid);
- return true;
- }
- else
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveFromQueue: [" UI64FMTD "] not in queue", guid);
- return false;
- }
-
}
/**
@@ -441,68 +451,61 @@ bool LFGMgr::RemoveFromQueue(uint64 guid)
@param[in] player Player we need to initialize the lock status map
*/
-void LFGMgr::InitializeLockedDungeons(Player* player)
+void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */)
{
uint64 guid = player->GetGUID();
- uint8 level = player->getLevel();
+ if (!level)
+ level = player->getLevel();
uint8 expansion = player->GetSession()->Expansion();
- LfgDungeonSet dungeons = GetDungeonsByRandom(0);
+ LfgDungeonSet const& dungeons = GetDungeonsByRandom(0);
LfgLockMap lock;
for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
{
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it);
+ LFGDungeonEntry const* dungeon = GetLFGDungeon(*it);
if (!dungeon) // should never happen - We provide a list from sLFGDungeonStore
continue;
- AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty));
-
- LfgLockStatusType locktype = LFG_LOCKSTATUS_OK;
+ uint32 lockData = 0;
if (dungeon->expansion > expansion)
- locktype = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION;
+ lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION;
else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player))
- locktype = LFG_LOCKSTATUS_RAID_LOCKED;
+ lockData = LFG_LOCKSTATUS_RAID_LOCKED;
else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty)))
- {
- //if (!player->GetGroup() || !player->GetGroup()->isLFGGroup() || GetDungeon(player->GetGroup()->GetGUID(), true) != dungeon->ID || GetState(player->GetGroup()->GetGUID()) != LFG_STATE_DUNGEON)
- locktype = LFG_LOCKSTATUS_RAID_LOCKED;
- }
+ lockData = LFG_LOCKSTATUS_RAID_LOCKED;
else if (dungeon->minlevel > level)
- locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL;
+ lockData = LFG_LOCKSTATUS_TOO_LOW_LEVEL;
else if (dungeon->maxlevel < level)
- locktype = LFG_LOCKSTATUS_TOO_HIGH_LEVEL;
- else if (dungeon->flags & LFG_FLAG_SEASONAL)
- {
- if (HolidayIds holiday = sLFGMgr->GetDungeonSeason(dungeon->ID))
- if (!IsHolidayActive(holiday))
- locktype = LFG_LOCKSTATUS_NOT_IN_SEASON;
- }
- else if (locktype == LFG_LOCKSTATUS_OK && ar)
+ lockData = LFG_LOCKSTATUS_TOO_HIGH_LEVEL;
+ else if (dungeon->seasonal && !IsSeasonActive(dungeon->id))
+ lockData = LFG_LOCKSTATUS_NOT_IN_SEASON;
+ else if (AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty)))
{
if (ar->achievement && !player->HasAchieved(ar->achievement))
- locktype = LFG_LOCKSTATUS_RAID_LOCKED; // FIXME: Check the correct lock value
+ lockData = LFG_LOCKSTATUS_MISSING_ACHIEVEMENT;
else if (player->GetTeam() == ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A))
- locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
+ lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
else if (player->GetTeam() == HORDE && ar->quest_H && !player->GetQuestRewardStatus(ar->quest_H))
- locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
+ lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
else
if (ar->item)
{
if (!player->HasItemCount(ar->item, 1) && (!ar->item2 || !player->HasItemCount(ar->item2, 1)))
- locktype = LFG_LOCKSTATUS_MISSING_ITEM;
+ lockData = LFG_LOCKSTATUS_MISSING_ITEM;
}
else if (ar->item2 && !player->HasItemCount(ar->item2, 1))
- locktype = LFG_LOCKSTATUS_MISSING_ITEM;
+ lockData = LFG_LOCKSTATUS_MISSING_ITEM;
}
+
/* TODO VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED)
- locktype = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE;
- locktype = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE;
- locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL;
- locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL;
+ lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE;
+ lockData = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE;
+ lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL;
+ lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL;
*/
- if (locktype != LFG_LOCKSTATUS_OK)
- lock[dungeon->Entry()] = locktype;
+ if (lockData)
+ lock[dungeon->Entry()] = lockData;
}
SetLockedDungeons(guid, lock);
}
@@ -517,19 +520,18 @@ void LFGMgr::InitializeLockedDungeons(Player* player)
@param[in] dungeons Dungeons the player/group is applying for
@param[in] comment Player selected comment
*/
-void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDungeons, const std::string& comment)
+void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const std::string& comment)
{
- if (!player || !player->GetSession() || selectedDungeons.empty())
- return;
+ if (!player || !player->GetSession() || dungeons.empty())
+ return;
Group* grp = player->GetGroup();
uint64 guid = player->GetGUID();
uint64 gguid = grp ? grp->GetGUID() : guid;
LfgJoinResultData joinData;
- PlayerSet players;
+ LfgGuidSet players;
uint32 rDungeonId = 0;
bool isContinue = grp && grp->isLFGGroup() && GetState(gguid) != LFG_STATE_FINISHED_DUNGEON;
- LfgDungeonSet dungeons = selectedDungeons;
// Do not allow to change dungeon in the middle of a current dungeon
if (isContinue)
@@ -539,10 +541,10 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung
}
// Already in queue?
- LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(gguid);
- if (itQueue != m_QueueInfoMap.end())
+ LfgState state = GetState(gguid);
+ if (state == LFG_STATE_QUEUED)
{
- LfgDungeonSet playerDungeons = GetSelectedDungeons(guid);
+ LfgDungeonSet const& playerDungeons = GetSelectedDungeons(guid);
if (playerDungeons == dungeons) // Joining the same dungeons -- Send OK
{
LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, comment);
@@ -556,7 +558,10 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung
return;
}
else // Remove from queue and rejoin
- RemoveFromQueue(gguid);
+ {
+ LfgQueue& queue = GetQueue(gguid);
+ queue.RemoveFromQueue(gguid);
+ }
}
// Check player or group member restrictions
@@ -586,15 +591,16 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung
else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue())
joinData.result = LFG_JOIN_USING_BG_SYSTEM;
++memberCount;
- players.insert(plrg);
+ players.insert(plrg->GetGUID());
}
}
- if (memberCount != grp->GetMembersCount())
+
+ if (joinData.result == LFG_JOIN_OK && memberCount != grp->GetMembersCount())
joinData.result = LFG_JOIN_DISCONNECTED;
}
}
else
- players.insert(player);
+ players.insert(player->GetGUID());
// Check if all dungeons are valid
bool isRaid = false;
@@ -652,25 +658,24 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung
return;
}
- // FIXME - Raid browser not supported yet
+ SetComment(guid, comment);
+
if (isRaid)
{
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Join: [" UI64FMTD "] trying to join raid browser and it's disabled.", guid);
return;
}
- SetComment(guid, comment);
-
+ std::string debugNames = "";
if (grp) // Begin rolecheck
{
// Create new rolecheck
- LfgRoleCheck* roleCheck = new LfgRoleCheck();
- roleCheck->cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK;
- roleCheck->state = LFG_ROLECHECK_INITIALITING;
- roleCheck->leader = guid;
- roleCheck->dungeons = dungeons;
- roleCheck->rDungeonId = rDungeonId;
- m_RoleChecks[gguid] = roleCheck;
+ LfgRoleCheck& roleCheck = m_RoleChecks[gguid];
+ roleCheck.cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK;
+ roleCheck.state = LFG_ROLECHECK_INITIALITING;
+ roleCheck.leader = guid;
+ roleCheck.dungeons = dungeons;
+ roleCheck.rDungeonId = rDungeonId;
if (rDungeonId)
{
@@ -690,7 +695,10 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung
SetState(pguid, LFG_STATE_ROLECHECK);
if (!isContinue)
SetSelectedDungeons(pguid, dungeons);
- roleCheck->roles[pguid] = 0;
+ roleCheck.roles[pguid] = 0;
+ if (!debugNames.empty())
+ debugNames.append(", ");
+ debugNames.append(plrg->GetName());
}
}
// Update leader role
@@ -698,24 +706,11 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung
}
else // Add player to queue
{
- // Queue player
- LfgQueueInfo* pqInfo = new LfgQueueInfo();
- pqInfo->joinTime = time_t(time(NULL));
- pqInfo->roles[player->GetGUID()] = roles;
- pqInfo->dungeons = dungeons;
- if (roles & ROLE_TANK)
- --pqInfo->tanks;
- else if (roles & ROLE_HEALER)
- --pqInfo->healers;
- else
- --pqInfo->dps;
- m_QueueInfoMap[guid] = pqInfo;
+ LfgRolesMap rolesMap;
+ rolesMap[guid] = roles;
+ LfgQueue& queue = GetQueue(gguid);
+ queue.AddQueueData(guid, time_t(time(NULL)), dungeons, rolesMap);
- // Send update to player
- player->GetSession()->SendLfgJoinResult(joinData);
- player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_PROPOSAL, dungeons, comment));
- SetState(gguid, LFG_STATE_QUEUED);
- SetRoles(guid, roles);
if (!isContinue)
{
if (rDungeonId)
@@ -725,66 +720,75 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung
}
SetSelectedDungeons(guid, dungeons);
}
- AddToQueue(guid, uint8(player->GetTeam()));
+ // Send update to player
+ player->GetSession()->SendLfgJoinResult(joinData);
+ player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_PROPOSAL, dungeons, comment));
+ SetState(gguid, LFG_STATE_QUEUED);
+ SetRoles(guid, roles);
+ debugNames.append(player->GetName());
+ }
+
+ if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG))
+ {
+ std::ostringstream o;
+ o << "LFGMgr::Join: [" << guid << "] joined (" << (grp ? "group" : "player") << ") Members: " << debugNames.c_str()
+ << ". Dungeons (" << uint32(dungeons.size()) << "): " << ConcatenateDungeons(dungeons);
+ sLog->outDebug(LOG_FILTER_LFG, "%s", o.str().c_str());
}
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Join: [" UI64FMTD "] joined with %u members. dungeons: %u", guid, grp ? grp->GetMembersCount() : 1, uint8(dungeons.size()));
}
/**
Leaves Dungeon System. Player/Group is removed from queue, rolechecks, proposals
or votekicks. Player or group needs to be not NULL and using Dungeon System
- @param[in] player Player trying to leave (can be NULL)
- @param[in] grp Group trying to leave (default NULL)
+ @param[in] guid Player or group guid
*/
-void LFGMgr::Leave(Player* player, Group* grp /* = NULL*/)
+void LFGMgr::LeaveLfg(uint64 guid)
{
- if (!player && !grp)
- return;
-
- uint64 guid = grp ? grp->GetGUID() : player->GetGUID();
LfgState state = GetState(guid);
+ uint64 gguid = IS_GROUP(guid) ? guid : GetGroup(guid);
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Leave: [" UI64FMTD "]", guid);
switch (state)
{
case LFG_STATE_QUEUED:
+ if (gguid)
{
- RemoveFromQueue(guid);
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE);
- if (grp)
+ LfgQueue& queue = GetQueue(gguid);
+ queue.RemoveFromQueue(gguid);
+ RestoreState(gguid, "Leave queue");
+ const LfgGuidSet& players = GetPlayers(gguid);
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
{
- RestoreState(guid);
- for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
- if (Player* plrg = itr->getSource())
- {
- plrg->GetSession()->SendLfgUpdateParty(updateData);
- uint64 pguid = plrg->GetGUID();
- ClearState(pguid);
- }
- }
- else
- {
- player->GetSession()->SendLfgUpdatePlayer(updateData);
- ClearState(guid);
+ uint64 guid = (*it);
+ ClearState(guid, "Leave queue");
+ SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
}
}
+ else
+ {
+ LfgQueue& queue = GetQueue(guid);
+ queue.RemoveFromQueue(guid);
+ SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
+ ClearState(guid, "Leave queue");
+ }
break;
case LFG_STATE_ROLECHECK:
- if (grp)
- UpdateRoleCheck(guid); // No player to update role = LFG_ROLECHECK_ABORTED
+ if (gguid)
+ UpdateRoleCheck(gguid); // No player to update role = LFG_ROLECHECK_ABORTED
break;
case LFG_STATE_PROPOSAL:
{
// Remove from Proposals
LfgProposalMap::iterator it = m_Proposals.begin();
+ uint64 pguid = gguid == guid ? GetLeader(gguid) : guid;
while (it != m_Proposals.end())
{
- LfgProposalPlayerMap::iterator itPlayer = it->second->players.find(player ? player->GetGUID() : grp->GetLeaderGUID());
- if (itPlayer != it->second->players.end())
+ LfgProposalPlayerMap::iterator itPlayer = it->second.players.find(pguid);
+ if (itPlayer != it->second.players.end())
{
// Mark the player/leader of group who left as didn't accept the proposal
- itPlayer->second->accept = LFG_ANSWER_DENY;
+ itPlayer->second.accept = LFG_ANSWER_DENY;
break;
}
++it;
@@ -801,312 +805,13 @@ void LFGMgr::Leave(Player* player, Group* grp /* = NULL*/)
}
/**
- Sends the leader of a group the offer to continue popup
-
- @param[in] grp Group to send offer to
-*/
-void LFGMgr::OfferContinue(Group* grp)
-{
- if (grp)
- {
- uint64 gguid = grp->GetGUID();
- if (Player* leader = ObjectAccessor::FindPlayer(grp->GetLeaderGUID()))
- leader->GetSession()->SendLfgOfferContinue(GetDungeon(gguid, false));
- }
-}
-
-/**
- Checks que main queue to try to form a Lfg group. Returns first match found (if any)
-
- @param[in] check List of guids trying to match with other groups
- @param[in] all List of all other guids in main queue to match against
- @return Pointer to proposal, if match is found
-*/
-LfgProposal* LFGMgr::FindNewGroups(LfgGuidList& check, LfgGuidList& all)
-{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FindNewGroup: (%s) - all(%s)", ConcatenateGuids(check).c_str(), ConcatenateGuids(all).c_str());
-
- LfgProposal* pProposal = NULL;
- if (check.empty() || check.size() > MAXGROUPSIZE || !CheckCompatibility(check, pProposal))
- return NULL;
-
- // Try to match with queued groups
- while (!pProposal && !all.empty())
- {
- check.push_back(all.front());
- all.pop_front();
- pProposal = FindNewGroups(check, all);
- check.pop_back();
- }
- return pProposal;
-}
-
-/**
- Check compatibilities between groups
-
- @param[in] check List of guids to check compatibilities
- @param[out] pProposal Proposal found if groups are compatibles and Match
- @return true if group are compatibles
-*/
-bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal)
-{
- if (pProposal) // Do not check anything if we already have a proposal
- return false;
-
- std::string strGuids = ConcatenateGuids(check);
-
- if (check.size() > MAXGROUPSIZE || check.empty())
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s): Size wrong - Not compatibles", strGuids.c_str());
- return false;
- }
-
- if (check.size() == 1 && IS_PLAYER_GUID(check.front())) // Player joining dungeon... compatible
- return true;
-
- // Previously cached?
- LfgAnswer answer = GetCompatibles(strGuids);
- if (answer != LFG_ANSWER_PENDING)
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) compatibles (cached): %d", strGuids.c_str(), answer);
- return bool(answer);
- }
-
- // Check all but new compatiblitity
- if (check.size() > 2)
- {
- uint64 frontGuid = check.front();
- check.pop_front();
-
- // Check all-but-new compatibilities (New, A, B, C, D) --> check(A, B, C, D)
- if (!CheckCompatibility(check, pProposal)) // Group not compatible
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) not compatibles (%s not compatibles)", strGuids.c_str(), ConcatenateGuids(check).c_str());
- SetCompatibles(strGuids, false);
- return false;
- }
- check.push_front(frontGuid);
- // all-but-new compatibles, now check with new
- }
-
- uint8 numPlayers = 0;
- uint8 numLfgGroups = 0;
- uint32 groupLowGuid = 0;
- LfgQueueInfoMap pqInfoMap;
- for (LfgGuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it)
- {
- uint64 guid = (*it);
- LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(guid);
- if (itQueue == m_QueueInfoMap.end() || GetState(guid) != LFG_STATE_QUEUED)
- {
- sLog->outError(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: [" UI64FMTD "] is not queued but listed as queued!", (*it));
- RemoveFromQueue(guid);
- return false;
- }
- pqInfoMap[guid] = itQueue->second;
- numPlayers += itQueue->second->roles.size();
-
- if (IS_GROUP(guid))
- {
- uint32 lowGuid = GUID_LOPART(guid);
- if (Group* grp = sGroupMgr->GetGroupByGUID(lowGuid))
- if (grp->isLFGGroup())
- {
- if (!numLfgGroups)
- groupLowGuid = lowGuid;
- ++numLfgGroups;
- }
- }
- }
-
- if (check.size() == 1 && numPlayers != MAXGROUPSIZE) // Single group with less than MAXGROUPSIZE - Compatibles
- return true;
-
- // Do not match - groups already in a lfgDungeon or too much players
- if (numLfgGroups > 1 || numPlayers > MAXGROUPSIZE)
- {
- SetCompatibles(strGuids, false);
- if (numLfgGroups > 1)
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups);
- else
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Too much players (%u)", strGuids.c_str(), numPlayers);
- return false;
- }
-
- // ----- Player checks -----
- LfgRolesMap rolesMap;
- uint64 leader = 0;
- for (LfgQueueInfoMap::const_iterator it = pqInfoMap.begin(); it != pqInfoMap.end(); ++it)
- {
- for (LfgRolesMap::const_iterator itRoles = it->second->roles.begin(); itRoles != it->second->roles.end(); ++itRoles)
- {
- // Assign new leader
- if (itRoles->second & ROLE_LEADER && (!leader || urand(0, 1)))
- leader = itRoles->first;
-
- rolesMap[itRoles->first] = itRoles->second;
- }
- }
-
- if (rolesMap.size() != numPlayers) // Player in multiples queues!
- return false;
-
- PlayerSet players;
- for (LfgRolesMap::const_iterator it = rolesMap.begin(); it != rolesMap.end(); ++it)
- {
- Player* player = ObjectAccessor::FindPlayer(it->first);
- if (!player)
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Warning! [" UI64FMTD "] offline! Marking as not compatibles!", strGuids.c_str(), it->first);
- else
- {
- for (PlayerSet::const_iterator itPlayer = players.begin(); itPlayer != players.end() && player; ++itPlayer)
- {
- // Do not form a group with ignoring candidates
- if (player->GetSocial()->HasIgnore((*itPlayer)->GetGUIDLow()) || (*itPlayer)->GetSocial()->HasIgnore(player->GetGUIDLow()))
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Players [" UI64FMTD "] and [" UI64FMTD "] ignoring", strGuids.c_str(), (*itPlayer)->GetGUID(), player->GetGUID());
- player = NULL;
- }
- }
- if (player)
- players.insert(player);
- }
- }
-
- // if we dont have the same ammount of players then we have self ignoring candidates or different faction groups
- // otherwise check if roles are compatible
- if (players.size() != numPlayers || !CheckGroupRoles(rolesMap))
- {
- if (players.size() == numPlayers)
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Roles not compatible", strGuids.c_str());
- SetCompatibles(strGuids, false);
- return false;
- }
-
- // ----- Selected Dungeon checks -----
- // Check if there are any compatible dungeon from the selected dungeons
- LfgDungeonSet compatibleDungeons;
-
- LfgQueueInfoMap::const_iterator itFirst = pqInfoMap.begin();
- for (LfgDungeonSet::const_iterator itDungeon = itFirst->second->dungeons.begin(); itDungeon != itFirst->second->dungeons.end(); ++itDungeon)
- {
- LfgQueueInfoMap::const_iterator itOther = itFirst;
- ++itOther;
- while (itOther != pqInfoMap.end() && itOther->second->dungeons.find(*itDungeon) != itOther->second->dungeons.end())
- ++itOther;
-
- if (itOther == pqInfoMap.end())
- compatibleDungeons.insert(*itDungeon);
- }
- LfgLockPartyMap lockMap;
- GetCompatibleDungeons(compatibleDungeons, players, lockMap);
-
- if (compatibleDungeons.empty())
- {
- SetCompatibles(strGuids, false);
- return false;
- }
- SetCompatibles(strGuids, true);
-
- // ----- Group is compatible, if we have MAXGROUPSIZE members then match is found
- if (numPlayers != MAXGROUPSIZE)
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Compatibles but not match. Players(%u)", strGuids.c_str(), numPlayers);
- uint8 Tanks_Needed = LFG_TANKS_NEEDED;
- uint8 Healers_Needed = LFG_HEALERS_NEEDED;
- uint8 Dps_Needed = LFG_DPS_NEEDED;
- for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue)
- {
- LfgQueueInfo* queue = itQueue->second;
- for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer)
- {
- uint8 roles = itPlayer->second;
- if ((roles & ROLE_TANK) && Tanks_Needed > 0)
- --Tanks_Needed;
- else if ((roles & ROLE_HEALER) && Healers_Needed > 0)
- --Healers_Needed;
- else if ((roles & ROLE_DAMAGE) && Dps_Needed > 0)
- --Dps_Needed;
- }
- }
- for (PlayerSet::const_iterator itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers)
- {
- for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue)
- {
- LfgQueueInfo* queue = itQueue->second;
- if (!queue)
- continue;
-
- for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer)
- {
- if (*itPlayers == ObjectAccessor::FindPlayer(itPlayer->first))
- {
- queue->tanks = Tanks_Needed;
- queue->healers = Healers_Needed;
- queue->dps = Dps_Needed;
- }
- }
- }
- }
- return true;
- }
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str());
-
- // GROUP FORMED!
- // TODO - Improve algorithm to select proper group based on Item Level
- // Do not match bad tank and bad healer on same group
-
- // Select a random dungeon from the compatible list
- // TODO - Select the dungeon based on group item Level, not just random
- // Create a new proposal
- pProposal = new LfgProposal(Trinity::Containers::SelectRandomContainerElement(compatibleDungeons));
- pProposal->cancelTime = time_t(time(NULL)) + LFG_TIME_PROPOSAL;
- pProposal->state = LFG_PROPOSAL_INITIATING;
- pProposal->queues = check;
- pProposal->groupLowGuid = groupLowGuid;
-
- // Assign new roles to players and assign new leader
- PlayerSet::const_iterator itPlayers = players.begin();
- if (!leader)
- {
- uint8 pos = uint8(urand(0, players.size() - 1));
- for (uint8 i = 0; i < pos; ++i)
- ++itPlayers;
- leader = (*itPlayers)->GetGUID();
- }
- pProposal->leader = leader;
-
- uint8 numAccept = 0;
- for (itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers)
- {
- uint64 guid = (*itPlayers)->GetGUID();
- LfgProposalPlayer* ppPlayer = new LfgProposalPlayer();
- if (Group* grp = (*itPlayers)->GetGroup())
- {
- ppPlayer->groupLowGuid = grp->GetLowGUID();
- if (grp->isLFGGroup()) // Player from existing group, autoaccept
- {
- ppPlayer->accept = LFG_ANSWER_AGREE;
- ++numAccept;
- }
- }
- ppPlayer->role = rolesMap[guid];
- pProposal->players[guid] = ppPlayer;
- }
- if (numAccept == MAXGROUPSIZE)
- pProposal->state = LFG_PROPOSAL_SUCCESS;
-
- return true;
-}
-
-/**
Update the Role check info with the player selected role.
@param[in] grp Group guid to update rolecheck
@param[in] guid Player guid (0 = rolecheck failed)
@param[in] roles Player selected roles
*/
-void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* = ROLE_NONE */)
+void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* = PLAYER_ROLE_NONE */)
{
if (!gguid)
return;
@@ -1116,155 +821,73 @@ void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /*
if (itRoleCheck == m_RoleChecks.end())
return;
- LfgRoleCheck* roleCheck = itRoleCheck->second;
- bool sendRoleChosen = roleCheck->state != LFG_ROLECHECK_DEFAULT && guid;
+ LfgRoleCheck& roleCheck = itRoleCheck->second;
+ bool sendRoleChosen = roleCheck.state != LFG_ROLECHECK_DEFAULT && guid;
if (!guid)
- roleCheck->state = LFG_ROLECHECK_ABORTED;
- else if (roles < ROLE_TANK) // Player selected no role.
- roleCheck->state = LFG_ROLECHECK_NO_ROLE;
+ roleCheck.state = LFG_ROLECHECK_ABORTED;
+ else if (roles < PLAYER_ROLE_TANK) // Player selected no role.
+ roleCheck.state = LFG_ROLECHECK_NO_ROLE;
else
{
- roleCheck->roles[guid] = roles;
+ roleCheck.roles[guid] = roles;
// Check if all players have selected a role
- LfgRolesMap::const_iterator itRoles = roleCheck->roles.begin();
- while (itRoles != roleCheck->roles.end() && itRoles->second != ROLE_NONE)
+ LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin();
+ while (itRoles != roleCheck.roles.end() && itRoles->second != PLAYER_ROLE_NONE)
++itRoles;
- if (itRoles == roleCheck->roles.end())
+ if (itRoles == roleCheck.roles.end())
{
// use temporal var to check roles, CheckGroupRoles modifies the roles
- check_roles = roleCheck->roles;
- roleCheck->state = CheckGroupRoles(check_roles) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES;
+ check_roles = roleCheck.roles;
+ roleCheck.state = CheckGroupRoles(check_roles) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES;
}
}
- uint8 team = 0;
LfgDungeonSet dungeons;
- if (roleCheck->rDungeonId)
- dungeons.insert(roleCheck->rDungeonId);
+ if (roleCheck.rDungeonId)
+ dungeons.insert(roleCheck.rDungeonId);
else
- dungeons = roleCheck->dungeons;
+ dungeons = roleCheck.dungeons;
- LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_FAILED, roleCheck->state);
- for (LfgRolesMap::const_iterator it = roleCheck->roles.begin(); it != roleCheck->roles.end(); ++it)
+ LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_FAILED, roleCheck.state);
+ for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
{
uint64 pguid = it->first;
- Player* plrg = ObjectAccessor::FindPlayer(pguid);
- if (!plrg)
- {
- if (roleCheck->state == LFG_ROLECHECK_FINISHED)
- SetState(pguid, LFG_STATE_QUEUED);
- else if (roleCheck->state != LFG_ROLECHECK_INITIALITING)
- ClearState(pguid);
- continue;
- }
- team = uint8(plrg->GetTeam());
if (!sendRoleChosen)
- plrg->GetSession()->SendLfgRoleChosen(guid, roles);
- plrg->GetSession()->SendLfgRoleCheckUpdate(roleCheck);
- switch (roleCheck->state)
+ SendLfgRoleChosen(pguid, guid, roles);
+
+ SendLfgRoleCheckUpdate(pguid, roleCheck);
+ switch (roleCheck.state)
{
case LFG_ROLECHECK_INITIALITING:
continue;
case LFG_ROLECHECK_FINISHED:
SetState(pguid, LFG_STATE_QUEUED);
- plrg->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid)));
+ SetRoles(pguid, it->second);
+ SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid)));
break;
default:
- if (roleCheck->leader == pguid)
- plrg->GetSession()->SendLfgJoinResult(joinData);
- plrg->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED));
- ClearState(pguid);
+ if (roleCheck.leader == pguid)
+ SendLfgJoinResult(pguid, joinData);
+ SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED));
+ ClearState(pguid, "Role check Failed");
break;
}
}
- if (roleCheck->state == LFG_ROLECHECK_FINISHED)
+ if (roleCheck.state == LFG_ROLECHECK_FINISHED)
{
SetState(gguid, LFG_STATE_QUEUED);
- LfgQueueInfo* pqInfo = new LfgQueueInfo();
- pqInfo->joinTime = time_t(time(NULL));
- pqInfo->roles = roleCheck->roles;
- pqInfo->dungeons = roleCheck->dungeons;
-
- // Set queue roles needed - As we are using check_roles will not have more that 1 tank, 1 healer, 3 dps
- for (LfgRolesMap::const_iterator it = check_roles.begin(); it != check_roles.end(); ++it)
- {
- uint8 roles2 = it->second;
- if (roles2 & ROLE_TANK)
- --pqInfo->tanks;
- else if (roles2 & ROLE_HEALER)
- --pqInfo->healers;
- else
- --pqInfo->dps;
- }
-
- m_QueueInfoMap[gguid] = pqInfo;
- if (GetState(gguid) != LFG_STATE_NONE)
- {
- LfgGuidList& currentQueue = m_currentQueue[team];
- currentQueue.push_front(gguid);
- }
- AddToQueue(gguid, team);
+ LfgQueue& queue = GetQueue(gguid);
+ queue.AddQueueData(gguid, time_t(time(NULL)), roleCheck.dungeons, roleCheck.roles);
}
+ else if (roleCheck.state != LFG_ROLECHECK_INITIALITING)
+ RestoreState(gguid, "Rolecheck Failed");
- if (roleCheck->state != LFG_ROLECHECK_INITIALITING)
- {
- if (roleCheck->state != LFG_ROLECHECK_FINISHED)
- RestoreState(gguid);
- delete roleCheck;
- m_RoleChecks.erase(itRoleCheck);
- }
-}
-
-/**
- Remove from cached compatible dungeons any entry that contains the given guid
-
- @param[in] guid Guid to remove from compatible cache
-*/
-void LFGMgr::RemoveFromCompatibles(uint64 guid)
-{
- std::stringstream out;
- out << guid;
- std::string strGuid = out.str();
-
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveFromCompatibles: Removing [" UI64FMTD "]", guid);
- for (LfgCompatibleMap::iterator itNext = m_CompatibleMap.begin(); itNext != m_CompatibleMap.end();)
- {
- LfgCompatibleMap::iterator it = itNext++;
- if (it->first.find(strGuid) != std::string::npos) // Found, remove it
- m_CompatibleMap.erase(it);
- }
-}
-
-/**
- Stores the compatibility of a list of guids
-
- @param[in] key String concatenation of guids (| used as separator)
- @param[in] compatibles Compatibles or not
-*/
-void LFGMgr::SetCompatibles(std::string key, bool compatibles)
-{
- m_CompatibleMap[key] = LfgAnswer(compatibles);
-}
-
-/**
- Get the compatibility of a group of guids
-
- @param[in] key String concatenation of guids (| used as separator)
- @return 1 (Compatibles), 0 (Not compatibles), -1 (Not set)
-*/
-LfgAnswer LFGMgr::GetCompatibles(std::string key)
-{
- LfgAnswer answer = LFG_ANSWER_PENDING;
- LfgCompatibleMap::iterator it = m_CompatibleMap.find(key);
- if (it != m_CompatibleMap.end())
- answer = it->second;
-
- return answer;
+ m_RoleChecks.erase(itRoleCheck);
}
/**
@@ -1274,13 +897,13 @@ LfgAnswer LFGMgr::GetCompatibles(std::string key)
@param[in] players Set of players to check their dungeon restrictions
@param[out] lockMap Map of players Lock status info of given dungeons (Empty if dungeons is not empty)
*/
-void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, const PlayerSet& players, LfgLockPartyMap& lockMap)
+void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, const LfgGuidSet& players, LfgLockPartyMap& lockMap)
{
lockMap.clear();
- for (PlayerSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it)
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it)
{
- uint64 guid = (*it)->GetGUID();
- LfgLockMap cachedLockMap = GetLockedDungeons(guid);
+ uint64 guid = (*it);
+ LfgLockMap const& cachedLockMap = GetLockedDungeons(guid);
for (LfgLockMap::const_iterator it2 = cachedLockMap.begin(); it2 != cachedLockMap.end() && !dungeons.empty(); ++it2)
{
uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
@@ -1314,21 +937,21 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true
if (removeLeaderFlag)
for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it)
- it->second &= ~ROLE_LEADER;
+ it->second &= ~PLAYER_ROLE_LEADER;
for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it)
{
- if (it->second == ROLE_NONE)
+ if (it->second == PLAYER_ROLE_NONE)
return false;
- if (it->second & ROLE_TANK)
+ if (it->second & PLAYER_ROLE_TANK)
{
- if (it->second != ROLE_TANK)
+ if (it->second != PLAYER_ROLE_TANK)
{
- it->second -= ROLE_TANK;
+ it->second -= PLAYER_ROLE_TANK;
if (CheckGroupRoles(groles, false))
return true;
- it->second += ROLE_TANK;
+ it->second += PLAYER_ROLE_TANK;
}
else if (tank == LFG_TANKS_NEEDED)
return false;
@@ -1336,14 +959,14 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true
tank++;
}
- if (it->second & ROLE_HEALER)
+ if (it->second & PLAYER_ROLE_HEALER)
{
- if (it->second != ROLE_HEALER)
+ if (it->second != PLAYER_ROLE_HEALER)
{
- it->second -= ROLE_HEALER;
+ it->second -= PLAYER_ROLE_HEALER;
if (CheckGroupRoles(groles, false))
return true;
- it->second += ROLE_HEALER;
+ it->second += PLAYER_ROLE_HEALER;
}
else if (healer == LFG_HEALERS_NEEDED)
return false;
@@ -1351,14 +974,14 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true
healer++;
}
- if (it->second & ROLE_DAMAGE)
+ if (it->second & PLAYER_ROLE_DAMAGE)
{
- if (it->second != ROLE_DAMAGE)
+ if (it->second != PLAYER_ROLE_DAMAGE)
{
- it->second -= ROLE_DAMAGE;
+ it->second -= PLAYER_ROLE_DAMAGE;
if (CheckGroupRoles(groles, false))
return true;
- it->second += ROLE_DAMAGE;
+ it->second += PLAYER_ROLE_DAMAGE;
}
else if (damage == LFG_DPS_NEEDED)
return false;
@@ -1370,6 +993,84 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true
}
/**
+ Makes a new group given a proposal
+ @param[in] proposal Proposal to get info from
+*/
+void LFGMgr::MakeNewGroup(const LfgProposal& proposal)
+{
+ LfgGuidList players;
+ LfgGuidList playersToTeleport;
+
+ for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ {
+ uint64 guid = it->first;
+ if (guid == proposal.leader)
+ players.push_front(guid);
+ else
+ players.push_back(guid);
+
+ if (proposal.isNew || GetGroup(guid) != proposal.group)
+ playersToTeleport.push_back(guid);
+ }
+
+ // Set the dungeon difficulty
+ LFGDungeonEntry const* dungeon = GetLFGDungeon(proposal.dungeonId);
+ ASSERT(dungeon);
+
+ Group* grp = proposal.group ? sGroupMgr->GetGroupByGUID(GUID_LOPART(proposal.group)) : NULL;
+ for (LfgGuidList::const_iterator it = players.begin(); it != players.end(); ++it)
+ {
+ uint64 pguid = (*it);
+ Player* player = ObjectAccessor::FindPlayer(pguid);
+ if (!player)
+ continue;
+
+ Group* group = player->GetGroup();
+ if (group && group != grp)
+ player->RemoveFromGroup();
+
+ if (!grp)
+ {
+ grp = new Group();
+ grp->ConvertToLFG();
+ grp->Create(player);
+ uint64 gguid = grp->GetGUID();
+ SetState(gguid, LFG_STATE_PROPOSAL);
+ sGroupMgr->AddGroup(grp);
+ }
+ else if (group != grp)
+ grp->AddMember(player);
+
+ grp->SetLfgRoles(pguid, proposal.players.find(pguid)->second.role);
+
+ // Add the cooldown spell if queued for a random dungeon
+ if (dungeon->type == LFG_TYPE_RANDOM)
+ player->CastSpell(player, LFG_SPELL_DUNGEON_COOLDOWN, false);
+ }
+
+ grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty));
+ uint64 gguid = grp->GetGUID();
+ SetDungeon(gguid, dungeon->Entry());
+ SetState(gguid, LFG_STATE_DUNGEON);
+
+ _SaveToDB(gguid, grp->GetDbStoreId());
+
+ // Teleport Player
+ for (LfgGuidList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it)
+ if (Player* player = ObjectAccessor::FindPlayer(*it))
+ TeleportPlayer(player, false);
+
+ // Update group info
+ grp->SendUpdate();
+}
+
+uint32 LFGMgr::AddProposal(LfgProposal const& proposal)
+{
+ m_Proposals[++m_lfgProposalId] = proposal;
+ return m_lfgProposalId;
+}
+
+/**
Update Proposal info with player answer
@param[in] proposalId Proposal id to be updated
@@ -1382,15 +1083,17 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
LfgProposalMap::iterator itProposal = m_Proposals.find(proposalId);
if (itProposal == m_Proposals.end())
return;
- LfgProposal* pProposal = itProposal->second;
+
+ LfgProposal& proposal = itProposal->second;
// Check if proposal have the current player
- LfgProposalPlayerMap::iterator itProposalPlayer = pProposal->players.find(guid);
- if (itProposalPlayer == pProposal->players.end())
+ LfgProposalPlayerMap::iterator itProposalPlayer = proposal.players.find(guid);
+ if (itProposalPlayer == proposal.players.end())
return;
- LfgProposalPlayer* ppPlayer = itProposalPlayer->second;
- ppPlayer->accept = LfgAnswer(accept);
+ LfgProposalPlayer& player = itProposalPlayer->second;
+ player.accept = LfgAnswer(accept);
+
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::UpdateProposal: Player [" UI64FMTD "] of proposal %u selected: %u", guid, proposalId, accept);
if (!accept)
{
@@ -1398,157 +1101,80 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
return;
}
- LfgPlayerList players;
- LfgPlayerList playersToTeleport;
-
// check if all have answered and reorder players (leader first)
bool allAnswered = true;
- for (LfgProposalPlayerMap::const_iterator itPlayers = pProposal->players.begin(); itPlayers != pProposal->players.end(); ++itPlayers)
- {
- if (Player* player = ObjectAccessor::FindPlayer(itPlayers->first))
- {
- if (itPlayers->first == pProposal->leader)
- players.push_front(player);
- else
- players.push_back(player);
-
- // Only teleport new players
- Group* grp = player->GetGroup();
- uint64 gguid = grp ? grp->GetGUID() : 0;
- if (!gguid || !grp->isLFGGroup() || GetState(gguid) == LFG_STATE_FINISHED_DUNGEON)
- playersToTeleport.push_back(player);
- }
-
- if (itPlayers->second->accept != LFG_ANSWER_AGREE) // No answer (-1) or not accepted (0)
+ for (LfgProposalPlayerMap::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
+ if (itPlayers->second.accept != LFG_ANSWER_AGREE) // No answer (-1) or not accepted (0)
allAnswered = false;
- }
if (!allAnswered)
{
- for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
- (*it)->GetSession()->SendLfgUpdateProposal(proposalId, pProposal);
- }
- else
- {
- bool sendUpdate = pProposal->state != LFG_PROPOSAL_SUCCESS;
- pProposal->state = LFG_PROPOSAL_SUCCESS;
- time_t joinTime = time_t(time(NULL));
- std::map<uint64, int32> waitTimesMap;
- // Save wait times before redoing groups
- for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
+ for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
{
- LfgProposalPlayer* player = pProposal->players[(*it)->GetGUID()];
- uint32 lowgroupguid = (*it)->GetGroup() ? (*it)->GetGroup()->GetLowGUID() : 0;
- if (player->groupLowGuid != lowgroupguid)
- sLog->outError(LOG_FILTER_LFG, "LFGMgr::UpdateProposal: [" UI64FMTD "] group mismatch: actual (%u) - queued (%u)", (*it)->GetGUID(), lowgroupguid, player->groupLowGuid);
-
- uint64 guid2 = player->groupLowGuid ? MAKE_NEW_GUID(player->groupLowGuid, 0, HIGHGUID_GROUP) : (*it)->GetGUID();
- LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(guid2);
- if (itQueue == m_QueueInfoMap.end())
- {
- sLog->outError(LOG_FILTER_LFG, "LFGMgr::UpdateProposal: Queue info for guid [" UI64FMTD "] not found!", guid);
- waitTimesMap[(*it)->GetGUID()] = -1;
- }
- else
- waitTimesMap[(*it)->GetGUID()] = int32(joinTime - itQueue->second->joinTime);
+ uint64 guid = it->first;
+ SendLfgUpdateProposal(guid, proposalId, proposal);
}
+ return;
+ }
- // Set the dungeon difficulty
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(pProposal->dungeonId);
- ASSERT(dungeon);
-
- // Create a new group (if needed)
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_GROUP_FOUND);
- Group* grp = pProposal->groupLowGuid ? sGroupMgr->GetGroupByGUID(pProposal->groupLowGuid) : NULL;
- for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
- {
- Player* player = (*it);
- uint64 pguid = player->GetGUID();
- Group* group = player->GetGroup();
- if (sendUpdate)
- player->GetSession()->SendLfgUpdateProposal(proposalId, pProposal);
-
- if (group)
- {
- player->GetSession()->SendLfgUpdateParty(updateData);
- if (group != grp)
- player->RemoveFromGroup();
- }
- else
- player->GetSession()->SendLfgUpdatePlayer(updateData);
-
- if (!grp)
- {
- grp = new Group();
- grp->Create(player);
- grp->ConvertToLFG();
- uint64 gguid = grp->GetGUID();
- SetState(gguid, LFG_STATE_PROPOSAL);
- sGroupMgr->AddGroup(grp);
- }
- else if (group != grp)
- grp->AddMember(player);
-
- // Update timers
- uint8 role = GetRoles(pguid);
- role &= ~ROLE_LEADER;
- switch (role)
- {
- case ROLE_DAMAGE:
- {
- uint32 old_number = m_NumWaitTimeDps++;
- m_WaitTimeDps = int32((m_WaitTimeDps * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeDps);
- break;
- }
- case ROLE_HEALER:
- {
- uint32 old_number = m_NumWaitTimeHealer++;
- m_WaitTimeHealer = int32((m_WaitTimeHealer * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeHealer);
- break;
- }
- case ROLE_TANK:
- {
- uint32 old_number = m_NumWaitTimeTank++;
- m_WaitTimeTank = int32((m_WaitTimeTank * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeTank);
- break;
- }
- default:
- {
- uint32 old_number = m_NumWaitTimeAvg++;
- m_WaitTimeAvg = int32((m_WaitTimeAvg * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeAvg);
- break;
- }
- }
+ bool sendUpdate = proposal.state != LFG_PROPOSAL_SUCCESS;
+ proposal.state = LFG_PROPOSAL_SUCCESS;
+ time_t joinTime = time_t(time(NULL));
- m_teleport.push_back(pguid);
- grp->SetLfgRoles(pguid, pProposal->players[pguid]->role);
- SetState(pguid, LFG_STATE_DUNGEON);
+ LfgQueue& queue = GetQueue(guid);
+ LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_GROUP_FOUND);
+ for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ {
+ uint64 pguid = it->first;
+ uint64 gguid = it->second.group;
+ uint32 dungeonId = (*GetSelectedDungeons(pguid).begin());
+ int32 waitTime = -1;
+ if (sendUpdate)
+ SendLfgUpdateProposal(pguid, proposalId, proposal);
- // Add the cooldown spell if queued for a random dungeon
- if (dungeon->type == LFG_TYPE_RANDOM)
- player->CastSpell(player, LFG_SPELL_DUNGEON_COOLDOWN, false);
+ if (gguid)
+ {
+ waitTime = int32((joinTime - queue.GetJoinTime(gguid)) / IN_MILLISECONDS);
+ SendLfgUpdateParty(pguid, updateData);
+ }
+ else
+ {
+ waitTime = int32((joinTime - queue.GetJoinTime(pguid)) / IN_MILLISECONDS);
+ SendLfgUpdatePlayer(pguid, updateData);
+ }
+ updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE;
+ SendLfgUpdatePlayer(pguid, updateData);
+ SendLfgUpdateParty(pguid, updateData);
+
+ // Update timers
+ uint8 role = GetRoles(pguid);
+ role &= ~PLAYER_ROLE_LEADER;
+ switch (role)
+ {
+ case PLAYER_ROLE_DAMAGE:
+ queue.UpdateWaitTimeDps(waitTime, dungeonId);
+ break;
+ case PLAYER_ROLE_HEALER:
+ queue.UpdateWaitTimeHealer(waitTime, dungeonId);
+ break;
+ case PLAYER_ROLE_TANK:
+ queue.UpdateWaitTimeTank(waitTime, dungeonId);
+ break;
+ default:
+ queue.UpdateWaitTimeAvg(waitTime, dungeonId);
+ break;
}
- grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty));
- uint64 gguid = grp->GetGUID();
- SetDungeon(gguid, dungeon->Entry());
- SetState(gguid, LFG_STATE_DUNGEON);
- _SaveToDB(gguid, grp->GetDbStoreId());
-
- // Remove players/groups from Queue
- for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it)
- RemoveFromQueue(*it);
-
- // Teleport Player
- for (LfgPlayerList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it)
- TeleportPlayer(*it, false);
+ m_teleport.push_back(pguid);
+ SetState(pguid, LFG_STATE_DUNGEON);
+ }
- // Update group info
- grp->SendUpdate();
+ // Remove players/groups from Queue
+ for (LfgGuidList::const_iterator it = proposal.queues.begin(); it != proposal.queues.end(); ++it)
+ queue.RemoveFromQueue(*it);
- delete pProposal;
- m_Proposals.erase(itProposal);
- }
+ MakeNewGroup(proposal);
+ m_Proposals.erase(itProposal);
}
/**
@@ -1559,51 +1185,44 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
*/
void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType type)
{
- LfgProposal* pProposal = itProposal->second;
- pProposal->state = LFG_PROPOSAL_FAILED;
+ LfgProposal& proposal = itProposal->second;
+ proposal.state = LFG_PROPOSAL_FAILED;
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Proposal %u, state FAILED, UpdateType %u", itProposal->first, type);
// Mark all people that didn't answered as no accept
if (type == LFG_UPDATETYPE_PROPOSAL_FAILED)
- for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it)
- if (it->second->accept == LFG_ANSWER_PENDING)
- it->second->accept = LFG_ANSWER_DENY;
+ for (LfgProposalPlayerMap::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ if (it->second.accept == LFG_ANSWER_PENDING)
+ it->second.accept = LFG_ANSWER_DENY;
// Mark players/groups to be removed
LfgGuidSet toRemove;
- for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it)
+ for (LfgProposalPlayerMap::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
{
- if (it->second->accept == LFG_ANSWER_AGREE)
+ if (it->second.accept == LFG_ANSWER_AGREE)
continue;
- uint64 guid = it->second->groupLowGuid ? MAKE_NEW_GUID(it->second->groupLowGuid, 0, HIGHGUID_GROUP) : it->first;
+ uint64 guid = it->second.group ? it->second.group : it->first;
// Player didn't accept or still pending when no secs left
- if (it->second->accept == LFG_ANSWER_DENY || type == LFG_UPDATETYPE_PROPOSAL_FAILED)
+ if (it->second.accept == LFG_ANSWER_DENY || type == LFG_UPDATETYPE_PROPOSAL_FAILED)
{
- it->second->accept = LFG_ANSWER_DENY;
+ it->second.accept = LFG_ANSWER_DENY;
toRemove.insert(guid);
}
}
- uint8 team = 0;
// Notify players
- for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it)
+ for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
{
- Player* player = ObjectAccessor::FindPlayer(it->first);
- if (!player)
- continue;
-
- team = uint8(player->GetTeam());
- player->GetSession()->SendLfgUpdateProposal(itProposal->first, pProposal);
+ uint64 guid = it->first;
+ uint64 gguid = it->second.group ? it->second.group : guid;
- Group* grp = player->GetGroup();
- uint64 guid = player->GetGUID();
- uint64 gguid = it->second->groupLowGuid ? MAKE_NEW_GUID(it->second->groupLowGuid, 0, HIGHGUID_GROUP) : guid;
+ SendLfgUpdateProposal(guid, itProposal->first, proposal);
if (toRemove.find(gguid) != toRemove.end()) // Didn't accept or in same group that someone that didn't accept
{
LfgUpdateData updateData;
- if (it->second->accept == LFG_ANSWER_DENY)
+ if (it->second.accept == LFG_ANSWER_DENY)
{
updateData.updateType = type;
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] didn't accept. Removing from queue and compatible cache", guid);
@@ -1613,126 +1232,110 @@ void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType t
updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE;
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] in same group that someone that didn't accept. Removing from queue and compatible cache", guid);
}
- ClearState(guid);
- if (grp)
+ ClearState(guid, "Proposal Fail (didn't accepted or in group with someone that didn't accept");
+ if (gguid != guid)
{
- RestoreState(gguid);
- player->GetSession()->SendLfgUpdateParty(updateData);
+ RestoreState(gguid, "Proposal Fail (someone in group didn't accepted)");
+ SendLfgUpdateParty(guid, updateData);
}
else
- player->GetSession()->SendLfgUpdatePlayer(updateData);
+ SendLfgUpdatePlayer(guid, updateData);
}
else
{
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Readding [" UI64FMTD "] to queue.", guid);
SetState(guid, LFG_STATE_QUEUED);
- if (grp)
+ if (gguid != guid)
{
SetState(gguid, LFG_STATE_QUEUED);
- player->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
+ SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
}
else
- player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
+ SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
}
}
+ LfgQueue& queue = GetQueue(proposal.players.begin()->first);
// Remove players/groups from queue
for (LfgGuidSet::const_iterator it = toRemove.begin(); it != toRemove.end(); ++it)
{
uint64 guid = *it;
- RemoveFromQueue(guid);
- pProposal->queues.remove(guid);
+ queue.RemoveFromQueue(guid);
+ proposal.queues.remove(guid);
}
// Readd to queue
- for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it)
+ for (LfgGuidList::const_iterator it = proposal.queues.begin(); it != proposal.queues.end(); ++it)
{
uint64 guid = *it;
- LfgGuidList& currentQueue = m_currentQueue[team];
- currentQueue.push_front(guid); //Add GUID for high priority
- AddToQueue(guid, team); //We have to add each GUID in newQueue to check for a new groups
+ queue.AddToQueue(guid);
}
- delete pProposal;
m_Proposals.erase(itProposal);
}
/**
Initialize a boot kick vote
- @param[in] grp Group the vote kicks belongs to
+ @param[in] gguid Group the vote kicks belongs to
@param[in] kicker Kicker guid
@param[in] victim Victim guid
@param[in] reason Kick reason
*/
-void LFGMgr::InitBoot(Group* grp, uint64 kicker, uint64 victim, std::string reason)
+void LFGMgr::InitBoot(uint64 gguid, uint64 kicker, uint64 victim, std::string const& reason)
{
- if (!grp)
- return;
-
- uint64 gguid = grp->GetGUID();
SetState(gguid, LFG_STATE_BOOT);
- LfgPlayerBoot* pBoot = new LfgPlayerBoot();
- pBoot->inProgress = true;
- pBoot->cancelTime = time_t(time(NULL)) + LFG_TIME_BOOT;
- pBoot->reason = reason;
- pBoot->victim = victim;
- pBoot->votedNeeded = GetVotesNeeded(gguid);
+ LfgPlayerBoot& boot = m_Boots[gguid];
+ boot.inProgress = true;
+ boot.cancelTime = time_t(time(NULL)) + LFG_TIME_BOOT;
+ boot.reason = reason;
+ boot.victim = victim;
+
+ LfgGuidSet const& players = GetPlayers(gguid);
// Set votes
- for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+ for (LfgGuidSet::const_iterator itr = players.begin(); itr != players.end(); ++itr)
{
- if (Player* plrg = itr->getSource())
- {
- uint64 guid = plrg->GetGUID();
- SetState(guid, LFG_STATE_BOOT);
- if (guid == victim)
- pBoot->votes[victim] = LFG_ANSWER_DENY; // Victim auto vote NO
- else if (guid == kicker)
- pBoot->votes[kicker] = LFG_ANSWER_AGREE; // Kicker auto vote YES
- else
- {
- pBoot->votes[guid] = LFG_ANSWER_PENDING; // Other members need to vote
- plrg->GetSession()->SendLfgBootPlayer(pBoot);
- }
- }
+ uint64 guid = (*itr);
+ SetState(guid, LFG_STATE_BOOT);
+ boot.votes[guid] = LFG_ANSWER_PENDING;
}
- m_Boots[grp->GetLowGUID()] = pBoot;
+ boot.votes[victim] = LFG_ANSWER_DENY; // Victim auto vote NO
+ boot.votes[kicker] = LFG_ANSWER_AGREE; // Kicker auto vote YES
+
+ // Notify players
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
+ SendLfgBootProposalUpdate(*it, boot);
}
/**
Update Boot info with player answer
- @param[in] player Player who has answered
+ @param[in] guid Player who has answered
@param[in] accept player answer
*/
-void LFGMgr::UpdateBoot(Player* player, bool accept)
+void LFGMgr::UpdateBoot(uint64 guid, bool accept)
{
- Group* grp = player ? player->GetGroup() : NULL;
- if (!grp)
+ uint64 gguid = GetGroup(guid);
+ if (!gguid)
return;
- uint32 bootId = grp->GetLowGUID();
- uint64 guid = player->GetGUID();
-
- LfgPlayerBootMap::iterator itBoot = m_Boots.find(bootId);
+ LfgPlayerBootMap::iterator itBoot = m_Boots.find(gguid);
if (itBoot == m_Boots.end())
return;
- LfgPlayerBoot* pBoot = itBoot->second;
- if (!pBoot)
- return;
+ LfgPlayerBoot& boot = itBoot->second;
- if (pBoot->votes[guid] != LFG_ANSWER_PENDING) // Cheat check: Player can't vote twice
+ if (boot.votes[guid] != LFG_ANSWER_PENDING) // Cheat check: Player can't vote twice
return;
- pBoot->votes[guid] = LfgAnswer(accept);
+ boot.votes[guid] = LfgAnswer(accept);
uint8 votesNum = 0;
uint8 agreeNum = 0;
- for (LfgAnswerMap::const_iterator itVotes = pBoot->votes.begin(); itVotes != pBoot->votes.end(); ++itVotes)
+ for (LfgAnswerMap::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
{
if (itVotes->second != LFG_ANSWER_PENDING)
{
@@ -1742,39 +1345,30 @@ void LFGMgr::UpdateBoot(Player* player, bool accept)
}
}
- if (agreeNum == pBoot->votedNeeded || // Vote passed
- votesNum == pBoot->votes.size() || // All voted but not passed
- (pBoot->votes.size() - votesNum + agreeNum) < pBoot->votedNeeded) // Vote didnt passed
+ // if we don't have enough votes (agree or deny) do nothing
+ if (agreeNum < LFG_GROUP_KICK_VOTES_NEEDED && (votesNum - agreeNum) < LFG_GROUP_KICK_VOTES_NEEDED)
+ return;
+
+ // Send update info to all players
+ boot.inProgress = false;
+ for (LfgAnswerMap::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
{
- // Send update info to all players
- pBoot->inProgress = false;
- for (LfgAnswerMap::const_iterator itVotes = pBoot->votes.begin(); itVotes != pBoot->votes.end(); ++itVotes)
+ uint64 pguid = itVotes->first;
+ if (pguid != boot.victim)
{
- uint64 pguid = itVotes->first;
- if (pguid != pBoot->victim)
- {
- SetState(pguid, LFG_STATE_DUNGEON);
- if (Player* plrg = ObjectAccessor::FindPlayer(pguid))
- plrg->GetSession()->SendLfgBootPlayer(pBoot);
- }
+ SetState(pguid, LFG_STATE_DUNGEON);
+ SendLfgBootProposalUpdate(pguid, boot);
}
+ }
- uint64 gguid = grp->GetGUID();
- SetState(gguid, LFG_STATE_DUNGEON);
- if (agreeNum == pBoot->votedNeeded) // Vote passed - Kick player
- {
- Player::RemoveFromGroup(grp, pBoot->victim);
- if (Player* victim = ObjectAccessor::FindPlayer(pBoot->victim))
- {
- TeleportPlayer(victim, true, false);
- SetState(pBoot->victim, LFG_STATE_NONE);
- }
- OfferContinue(grp);
- DecreaseKicksLeft(gguid);
- }
- delete pBoot;
- m_Boots.erase(itBoot);
+ SetState(gguid, LFG_STATE_DUNGEON);
+ if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player
+ {
+ if (Group* group = sGroupMgr->GetGroupByGUID(GUID_LOPART(gguid)))
+ Player::RemoveFromGroup(group, boot.victim, GROUP_REMOVEMETHOD_KICK_LFG);
+ DecreaseKicksLeft(gguid);
}
+ m_Boots.erase(itBoot);
}
/**
@@ -1788,8 +1382,20 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
{
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::TeleportPlayer: [" UI64FMTD "] is being teleported %s", player->GetGUID(), out ? "out" : "in");
- LfgTeleportError error = LFG_TELEPORTERROR_OK;
Group* grp = player->GetGroup();
+ uint64 gguid = grp->GetGUID();
+ LFGDungeonEntry const* dungeon = GetLFGDungeon(GetDungeon(gguid));
+ if (!dungeon || (out && player->GetMapId() != uint32(dungeon->map)))
+ return;
+
+ if (out)
+ {
+ player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
+ player->TeleportToBGEntryPoint();
+ return;
+ }
+
+ LfgTeleportError error = LFG_TELEPORTERROR_OK;
if (!grp || !grp->isLFGGroup()) // should never happen, but just in case...
error = LFG_TELEPORTERROR_INVALID_LOCATION;
@@ -1799,33 +1405,21 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
error = LFG_TELEPORTERROR_FALLING;
else if (player->IsMirrorTimerActive(FATIGUE_TIMER))
error = LFG_TELEPORTERROR_FATIGUE;
+ else if (player->GetVehicle())
+ error = LFG_TELEPORTERROR_IN_VEHICLE;
+ else if (player->GetCharmGUID())
+ error = LFG_TELEPORTERROR_CHARMING;
else
{
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(GetDungeon(grp->GetGUID()));
-
- if (out)
- {
- // Player needs to be inside the LFG dungeon to be able to teleport out
- if (dungeon && player->GetMapId() == uint32(dungeon->map))
- {
- player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
- player->TeleportToBGEntryPoint();
- }
- else
- player->GetSession()->SendLfgTeleportError(LFG_TELEPORTERROR_DONT_REPORT); // Not sure which error message to send
-
- return;
- }
-
if (!dungeon)
error = LFG_TELEPORTERROR_INVALID_LOCATION;
else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
{
- uint32 mapid = 0;
- float x = 0;
- float y = 0;
- float z = 0;
- float orientation = 0;
+ uint32 mapid = dungeon->map;
+ float x = dungeon->x;
+ float y = dungeon->y;
+ float z = dungeon->z;
+ float orientation = dungeon->o;
if (!fromOpcode)
{
@@ -1844,32 +1438,6 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
}
}
- if (!mapid)
- {
- LfgEntrancePositionMap::const_iterator itr = m_entrancePositions.find(dungeon->ID);
- if (itr != m_entrancePositions.end())
- {
- mapid = dungeon->map;
- x = itr->second.GetPositionX();
- y = itr->second.GetPositionY();
- z = itr->second.GetPositionZ();
- orientation = itr->second.GetOrientation();
- }
- else if (AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon->map))
- {
- mapid = at->target_mapId;
- x = at->target_X;
- y = at->target_Y;
- z = at->target_Z;
- orientation = at->target_Orientation;
- }
- else
- {
- sLog->outError(LOG_FILTER_LFG, "LfgMgr::TeleportPlayer: Failed to teleport [" UI64FMTD "]: No areatrigger found for map: %u difficulty: %u", player->GetGUID(), dungeon->map, dungeon->difficulty);
- error = LFG_TELEPORTERROR_INVALID_LOCATION;
- }
- }
-
if (error == LFG_TELEPORTERROR_OK)
{
if (!player->GetMap()->IsDungeon())
@@ -1881,10 +1449,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*
player->CleanupAfterTaxiFlight();
}
- if (player->TeleportTo(mapid, x, y, z, orientation))
- // FIXME - HACK - this should be done by teleport, when teleporting far
- player->RemoveAurasByType(SPELL_AURA_MOUNTED);
- else
+ if (!player->TeleportTo(mapid, x, y, z, orientation))
{
error = LFG_TELEPORTERROR_INVALID_LOCATION;
sLog->outError(LOG_FILTER_LFG, "LfgMgr::TeleportPlayer: Failed to teleport [" UI64FMTD "] to map %u: ", player->GetGUID(), mapid);
@@ -1932,12 +1497,12 @@ void LFGMgr::RewardDungeonDoneFor(const uint32 dungeonId, Player* player)
// Clear player related lfg stuff
uint32 rDungeonId = (*GetSelectedDungeons(guid).begin());
- ClearState(guid);
+ ClearState(guid, "Dungeon Finished");
SetState(guid, LFG_STATE_FINISHED_DUNGEON);
// Give rewards only if its a random or seasonal dungeon
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(rDungeonId);
- if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !(dungeon->flags & LFG_FLAG_SEASONAL)))
+ LFGDungeonEntry const* dungeon = GetLFGDungeon(rDungeonId);
+ if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !dungeon->seasonal))
{
sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RewardDungeonDoneFor: [" UI64FMTD "] dungeon %u is not random nor seasonal", guid, rDungeonId);
return;
@@ -1986,9 +1551,9 @@ void LFGMgr::RewardDungeonDoneFor(const uint32 dungeonId, Player* player)
*/
const LfgDungeonSet& LFGMgr::GetDungeonsByRandom(uint32 randomdungeon)
{
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(randomdungeon);
- uint32 groupType = dungeon ? dungeon->grouptype : 0;
- return m_CachedDungeonMap[groupType];
+ LFGDungeonEntry const* dungeon = GetLFGDungeon(randomdungeon);
+ uint32 group = dungeon ? dungeon->group : 0;
+ return m_CachedDungeonMap[group];
}
/**
@@ -2021,81 +1586,42 @@ LfgReward const* LFGMgr::GetRandomDungeonReward(uint32 dungeon, uint8 level)
*/
LfgType LFGMgr::GetDungeonType(uint32 dungeonId)
{
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId);
+ LFGDungeonEntry const* dungeon = GetLFGDungeon(dungeonId);
if (!dungeon)
return LFG_TYPE_NONE;
return LfgType(dungeon->type);
}
-/**
- Given a list of guids returns the concatenation using | as delimiter
-
- @param[in] check list of guids
- @returns Concatenated string
-*/
-std::string LFGMgr::ConcatenateGuids(LfgGuidList check)
-{
- if (check.empty())
- return "";
-
- std::ostringstream o;
- LfgGuidList::const_iterator it = check.begin();
- o << (*it);
- for (++it; it != check.end(); ++it)
- o << '|' << (*it);
- return o.str();
-}
-
-HolidayIds LFGMgr::GetDungeonSeason(uint32 dungeonId)
-{
- HolidayIds holiday = HOLIDAY_NONE;
-
- switch (dungeonId)
- {
- case 285:
- holiday = HOLIDAY_HALLOWS_END;
- break;
- case 286:
- holiday = HOLIDAY_FIRE_FESTIVAL;
- break;
- case 287:
- holiday = HOLIDAY_BREWFEST;
- break;
- case 288:
- holiday = HOLIDAY_LOVE_IS_IN_THE_AIR;
- break;
- default:
- break;
- }
-
- return holiday;
-}
-
LfgState LFGMgr::GetState(uint64 guid)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetState: [" UI64FMTD "]", guid);
+ LfgState state;
if (IS_GROUP(guid))
- return m_Groups[guid].GetState();
+ state = m_Groups[guid].GetState();
else
- return m_Players[guid].GetState();
+ state = m_Players[guid].GetState();
+
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetState: [" UI64FMTD "] = %u", guid, state);
+ return state;
}
-uint32 LFGMgr::GetDungeon(uint64 guid, bool asId /*= true*/)
+uint32 LFGMgr::GetDungeon(uint64 guid, bool asId /*= true */)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetDungeon: [" UI64FMTD "] asId: %u", guid, asId);
- return m_Groups[guid].GetDungeon(asId);
+ uint32 dungeon = m_Groups[guid].GetDungeon(asId);
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetDungeon: [" UI64FMTD "] asId: %u = %u", guid, asId, dungeon);
+ return dungeon;
}
uint8 LFGMgr::GetRoles(uint64 guid)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetRoles: [" UI64FMTD "]", guid);
- return m_Players[guid].GetRoles();
+ uint8 roles = m_Players[guid].GetRoles();
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetRoles: [" UI64FMTD "] = %u", guid, roles);
+ return roles;
}
const std::string& LFGMgr::GetComment(uint64 guid)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetComment: [" UI64FMTD "]", guid);
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetComment: [" UI64FMTD "] = %s", guid, m_Players[guid].GetComment().c_str());
return m_Players[guid].GetComment();
}
@@ -2123,35 +1649,49 @@ const LfgLockMap& LFGMgr::GetLockedDungeons(uint64 guid)
uint8 LFGMgr::GetKicksLeft(uint64 guid)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetKicksLeft: [" UI64FMTD "]", guid);
- return m_Groups[guid].GetKicksLeft();
-}
-
-uint8 LFGMgr::GetVotesNeeded(uint64 guid)
-{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetVotesNeeded: [" UI64FMTD "]", guid);
- return m_Groups[guid].GetVotesNeeded();
+ uint8 kicks = m_Groups[guid].GetKicksLeft();
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetKicksLeft: [" UI64FMTD "] = %u", guid, kicks);
+ return kicks;
}
-void LFGMgr::RestoreState(uint64 guid)
+void LFGMgr::RestoreState(uint64 guid, char const *debugMsg)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RestoreState: [" UI64FMTD "]", guid);
- m_Groups[guid].RestoreState();
+ LfgGroupData& data = m_Groups[guid];
+ char const * const ps = GetStateString(data.GetState());
+ char const * const os = GetStateString(data.GetOldState());
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RestoreState: Group: [" UI64FMTD "] (%s), State: %s, oldState: %s", guid, debugMsg, ps, os);
+ data.RestoreState();
}
-void LFGMgr::ClearState(uint64 guid)
+void LFGMgr::ClearState(uint64 guid, char const *debugMsg)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::ClearState: [" UI64FMTD "]", guid);
- m_Players[guid].ClearState();
+ LfgPlayerData& data = m_Players[guid];
+ char const * const ps = GetStateString(data.GetState());
+ char const * const os = GetStateString(data.GetOldState());
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::ClearState: Player: [" UI64FMTD "] (%s) State: %s, oldState: %s", guid, debugMsg, ps, os);
+ data.ClearState();
}
void LFGMgr::SetState(uint64 guid, LfgState state)
{
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: [" UI64FMTD "] state %u", guid, state);
if (IS_GROUP(guid))
- m_Groups[guid].SetState(state);
+ {
+ LfgGroupData& data = m_Groups[guid];
+ char const * const ns = GetStateString(state);
+ char const * const ps = GetStateString(data.GetState());
+ char const * const os = GetStateString(data.GetOldState());
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Group: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os);
+ data.SetState(state);
+ }
else
- m_Players[guid].SetState(state);
+ {
+ LfgPlayerData& data = m_Players[guid];
+ char const * const ns = GetStateString(state);
+ char const * const ps = GetStateString(data.GetState());
+ char const * const os = GetStateString(data.GetOldState());
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Player: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os);
+ data.SetState(state);
+ }
}
void LFGMgr::SetDungeon(uint64 guid, uint32 dungeon)
@@ -2205,3 +1745,155 @@ void LFGMgr::RemoveGroupData(uint64 guid)
if (it != m_Groups.end())
m_Groups.erase(it);
}
+
+uint8 LFGMgr::GetTeam(uint64 guid)
+{
+ return m_Players[guid].GetTeam();
+}
+
+uint8 LFGMgr::RemovePlayerFromGroup(uint64 gguid, uint64 guid)
+{
+ return m_Groups[gguid].RemovePlayer(guid);
+}
+
+void LFGMgr::AddPlayerToGroup(uint64 gguid, uint64 guid)
+{
+ m_Groups[gguid].AddPlayer(guid);
+}
+
+void LFGMgr::SetLeader(uint64 gguid, uint64 leader)
+{
+ m_Groups[gguid].SetLeader(leader);
+}
+
+void LFGMgr::SetTeam(uint64 guid, uint8 team)
+{
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
+ team = 0;
+
+ m_Players[guid].SetTeam(team);
+}
+
+uint64 LFGMgr::GetGroup(uint64 guid)
+{
+ return m_Players[guid].GetGroup();
+}
+
+void LFGMgr::SetGroup(uint64 guid, uint64 group)
+{
+ m_Players[guid].SetGroup(group);
+}
+
+const LfgGuidSet& LFGMgr::GetPlayers(uint64 guid)
+{
+ return m_Groups[guid].GetPlayers();
+}
+
+uint64 LFGMgr::GetLeader(uint64 guid)
+{
+ return m_Groups[guid].GetLeader();
+}
+
+bool LFGMgr::HasIgnore(uint64 guid1, uint64 guid2)
+{
+ Player* plr1 = ObjectAccessor::FindPlayer(guid1);
+ Player* plr2 = ObjectAccessor::FindPlayer(guid2);
+ uint32 low1 = GUID_LOPART(guid1);
+ uint32 low2 = GUID_LOPART(guid2);
+ return plr1 && plr2 && (plr1->GetSocial()->HasIgnore(low2) || plr2->GetSocial()->HasIgnore(low1));
+}
+
+void LFGMgr::SendLfgRoleChosen(uint64 guid, uint64 pguid, uint8 roles)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgRoleChosen(pguid, roles);
+}
+
+void LFGMgr::SendLfgRoleCheckUpdate(uint64 guid, const LfgRoleCheck& roleCheck)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgRoleCheckUpdate(roleCheck);
+}
+
+void LFGMgr::SendLfgUpdatePlayer(uint64 guid, const LfgUpdateData& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgUpdatePlayer(data);
+}
+
+void LFGMgr::SendLfgUpdateParty(uint64 guid, const LfgUpdateData& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgUpdateParty(data);
+}
+
+void LFGMgr::SendLfgJoinResult(uint64 guid, const LfgJoinResultData& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgJoinResult(data);
+}
+
+void LFGMgr::SendLfgBootProposalUpdate(uint64 guid, const LfgPlayerBoot& boot)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgBootProposalUpdate(boot);
+}
+
+void LFGMgr::SendLfgUpdateProposal(uint64 guid, uint32 proposalId, const LfgProposal& proposal)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgUpdateProposal(proposalId, proposal);
+}
+
+void LFGMgr::SendLfgQueueStatus(uint64 guid, const LfgQueueStatusData& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->GetSession()->SendLfgQueueStatus(data);
+}
+
+bool LFGMgr::IsLfgGroup(uint64 guid)
+{
+ return guid && IS_GROUP(guid) && m_Groups[guid].IsLfgGroup();
+}
+
+LfgQueue& LFGMgr::GetQueue(uint64 guid)
+{
+ uint8 queueId = 0;
+ if (IS_GROUP(guid))
+ {
+ const LfgGuidSet& players = GetPlayers(guid);
+ uint64 pguid = players.empty() ? 0 : (*players.begin());
+ if (pguid)
+ queueId = GetTeam(pguid);
+ }
+ else
+ queueId = GetTeam(guid);
+ return m_Queues[queueId];
+}
+
+bool LFGMgr::AllQueued(const LfgGuidList& check)
+{
+ if (check.empty())
+ return false;
+
+ for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it)
+ if (GetState(*it) != LFG_STATE_QUEUED)
+ return false;
+ return true;
+}
+
+bool LFGMgr::IsSeasonActive(uint32 dungeonId)
+{
+ switch (dungeonId)
+ {
+ case 285: // The Headless Horseman
+ return IsHolidayActive(HOLIDAY_HALLOWS_END);
+ case 286: // The Frost Lord Ahune
+ return IsHolidayActive(HOLIDAY_FIRE_FESTIVAL);
+ case 287: // Coren Direbrew
+ return IsHolidayActive(HOLIDAY_BREWFEST);
+ case 288: // The Crown Chemical Co.
+ return IsHolidayActive(HOLIDAY_LOVE_IS_IN_THE_AIR);
+ }
+ return false;
+}
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index 9937759741b..4fb03bfe701 100755
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -21,24 +21,25 @@
#include "Common.h"
#include <ace/Singleton.h>
#include "LFG.h"
+#include "LFGQueue.h"
+#include "LFGGroupData.h"
+#include "LFGPlayerData.h"
-class LfgGroupData;
-class LfgPlayerData;
+class LFGPlayerScript;
+class LFGGroupScript;
class Group;
class Player;
-enum LFGenum
+enum LFGMgrEnum
{
- LFG_TIME_ROLECHECK = 40*IN_MILLISECONDS,
- LFG_TIME_BOOT = 2*MINUTE,
- LFG_TIME_PROPOSAL = 2*MINUTE,
- LFG_TANKS_NEEDED = 1,
- LFG_HEALERS_NEEDED = 1,
- LFG_DPS_NEEDED = 3,
- LFG_QUEUEUPDATE_INTERVAL = 15*IN_MILLISECONDS,
+ LFG_TIME_ROLECHECK = 40 * IN_MILLISECONDS,
+ LFG_TIME_BOOT = 120,
+ LFG_TIME_PROPOSAL = 120,
+ LFG_QUEUEUPDATE_INTERVAL = 15 * IN_MILLISECONDS,
LFG_SPELL_DUNGEON_COOLDOWN = 71328,
LFG_SPELL_DUNGEON_DESERTER = 71041,
- LFG_SPELL_LUCK_OF_THE_DRAW = 72221
+ LFG_SPELL_LUCK_OF_THE_DRAW = 72221,
+ LFG_GROUP_KICK_VOTES_NEEDED = 3
};
enum LfgFlags
@@ -52,11 +53,9 @@ enum LfgFlags
/// Determines the type of instance
enum LfgType
{
- LFG_TYPE_NONE = 0, // Internal use only
+ LFG_TYPE_NONE = 0,
LFG_TYPE_DUNGEON = 1,
LFG_TYPE_RAID = 2,
- LFG_TYPE_QUEST = 3,
- LFG_TYPE_ZONE = 4,
LFG_TYPE_HEROIC = 5,
LFG_TYPE_RANDOM = 6
};
@@ -72,13 +71,14 @@ enum LfgProposalState
/// Teleport errors
enum LfgTeleportError
{
- // 3, 7, 8 = "You can't do that right now" | 5 = No client reaction
+ // 7 = "You can't do that right now" | 5 = No client reaction
LFG_TELEPORTERROR_OK = 0, // Internal use
LFG_TELEPORTERROR_PLAYER_DEAD = 1,
LFG_TELEPORTERROR_FALLING = 2,
- LFG_TELEPORTERROR_DONT_REPORT = 3,
+ LFG_TELEPORTERROR_IN_VEHICLE = 3,
LFG_TELEPORTERROR_FATIGUE = 4,
- LFG_TELEPORTERROR_INVALID_LOCATION = 6
+ LFG_TELEPORTERROR_INVALID_LOCATION = 6,
+ LFG_TELEPORTERROR_CHARMING = 8 // FIXME - It can be 7 or 8 (Need proper data)
};
/// Queue join results
@@ -116,42 +116,27 @@ enum LfgRoleCheckState
LFG_ROLECHECK_NO_ROLE = 6 // Someone selected no role
};
-/// Answer state (Also used to check compatibilites)
-enum LfgAnswer
-{
- LFG_ANSWER_PENDING = -1,
- LFG_ANSWER_DENY = 0,
- LFG_ANSWER_AGREE = 1
-};
-
// Forward declaration (just to have all typedef together)
+struct LFGDungeonEntry;
struct LfgReward;
-struct LfgLockStatus;
struct LfgQueueInfo;
struct LfgRoleCheck;
struct LfgProposal;
struct LfgProposalPlayer;
struct LfgPlayerBoot;
-typedef std::set<uint64> LfgGuidSet;
-typedef std::list<uint64> LfgGuidList;
-typedef std::map<uint8, LfgGuidList> LfgGuidListMap;
-typedef std::set<Player*> PlayerSet;
-typedef std::list<Player*> LfgPlayerList;
+typedef std::map<uint8, LfgQueue> LfgQueueMap;
typedef std::multimap<uint32, LfgReward const*> LfgRewardMap;
typedef std::pair<LfgRewardMap::const_iterator, LfgRewardMap::const_iterator> LfgRewardMapBounds;
-typedef std::map<std::string, LfgAnswer> LfgCompatibleMap;
-typedef std::map<uint64, LfgDungeonSet> LfgDungeonMap;
-typedef std::map<uint64, uint8> LfgRolesMap;
+typedef std::map<uint8, LfgDungeonSet> LfgCachedDungeonMap;
typedef std::map<uint64, LfgAnswer> LfgAnswerMap;
-typedef std::map<uint64, LfgRoleCheck*> LfgRoleCheckMap;
-typedef std::map<uint64, LfgQueueInfo*> LfgQueueInfoMap;
-typedef std::map<uint32, LfgProposal*> LfgProposalMap;
-typedef std::map<uint64, LfgProposalPlayer*> LfgProposalPlayerMap;
-typedef std::map<uint32, LfgPlayerBoot*> LfgPlayerBootMap;
+typedef std::map<uint64, LfgRoleCheck> LfgRoleCheckMap;
+typedef std::map<uint32, LfgProposal> LfgProposalMap;
+typedef std::map<uint64, LfgProposalPlayer> LfgProposalPlayerMap;
+typedef std::map<uint64, LfgPlayerBoot> LfgPlayerBootMap;
typedef std::map<uint64, LfgGroupData> LfgGroupDataMap;
typedef std::map<uint64, LfgPlayerData> LfgPlayerDataMap;
-typedef std::map<uint32, Position> LfgEntrancePositionMap;
+typedef UNORDERED_MAP<uint32, LFGDungeonEntry> LFGDungeonMap;
// Data needed by SMSG_LFG_JOIN_RESULT
struct LfgJoinResultData
@@ -167,7 +152,7 @@ struct LfgJoinResultData
struct LfgUpdateData
{
LfgUpdateData(LfgUpdateType _type = LFG_UPDATETYPE_DEFAULT): updateType(_type), comment("") {}
- LfgUpdateData(LfgUpdateType _type, const LfgDungeonSet& _dungeons, std::string _comment):
+ LfgUpdateData(LfgUpdateType _type, LfgDungeonSet const& _dungeons, std::string _comment):
updateType(_type), dungeons(_dungeons), comment(_comment) {}
LfgUpdateType updateType;
@@ -175,6 +160,26 @@ struct LfgUpdateData
std::string comment;
};
+// Data needed by SMSG_LFG_QUEUE_STATUS
+struct LfgQueueStatusData
+{
+ LfgQueueStatusData(uint32 _dungeonId = 0, int32 _waitTime = -1, int32 _waitTimeAvg = -1, int32 _waitTimeTank = -1, int32 _waitTimeHealer = -1,
+ int32 _waitTimeDps = -1, uint32 _queuedTime = 0, uint8 _tanks = 0, uint8 _healers = 0, uint8 _dps = 0) :
+ dungeonId(_dungeonId), waitTime(_waitTime), waitTimeAvg(_waitTimeAvg), waitTimeTank(_waitTimeTank), waitTimeHealer(_waitTimeHealer),
+ waitTimeDps(_waitTimeDps), queuedTime(_queuedTime), tanks(_tanks), healers(_healers), dps(_dps) {}
+
+ uint32 dungeonId;
+ int32 waitTime;
+ int32 waitTimeAvg;
+ int32 waitTimeTank;
+ int32 waitTimeHealer;
+ int32 waitTimeDps;
+ uint32 queuedTime;
+ uint8 tanks;
+ uint8 healers;
+ uint8 dps;
+};
+
/// Reward info
struct LfgReward
{
@@ -198,45 +203,31 @@ struct LfgReward
}
};
-/// Stores player or group queue info
-struct LfgQueueInfo
-{
- LfgQueueInfo(): joinTime(0), tanks(LFG_TANKS_NEEDED), healers(LFG_HEALERS_NEEDED), dps(LFG_DPS_NEEDED) {};
- time_t joinTime; ///< Player queue join time (to calculate wait times)
- uint8 tanks; ///< Tanks needed
- uint8 healers; ///< Healers needed
- uint8 dps; ///< Dps needed
- LfgDungeonSet dungeons; ///< Selected Player/Group Dungeon/s
- LfgRolesMap roles; ///< Selected Player Role/s
-};
-
/// Stores player data related to proposal to join
struct LfgProposalPlayer
{
- LfgProposalPlayer(): role(0), accept(LFG_ANSWER_PENDING), groupLowGuid(0) {};
+ LfgProposalPlayer(): role(0), accept(LFG_ANSWER_PENDING), group(0) { }
uint8 role; ///< Proposed role
LfgAnswer accept; ///< Accept status (-1 not answer | 0 Not agree | 1 agree)
- uint32 groupLowGuid; ///< Original group guid (Low guid) 0 if no original group
+ uint64 group; ///< Original group guid. 0 if no original group
};
/// Stores group data related to proposal to join
struct LfgProposal
{
- LfgProposal(uint32 dungeon = 0): dungeonId(dungeon), state(LFG_PROPOSAL_INITIATING), groupLowGuid(0), leader(0), cancelTime(0) {}
+ LfgProposal(uint32 dungeon = 0): dungeonId(dungeon), state(LFG_PROPOSAL_INITIATING),
+ group(0), leader(0), cancelTime(0), encounters(0), isNew(true)
+ { }
- ~LfgProposal()
- {
- for (LfgProposalPlayerMap::iterator it = players.begin(); it != players.end(); ++it)
- delete it->second;
- };
uint32 dungeonId; ///< Dungeon to join
LfgProposalState state; ///< State of the proposal
- uint32 groupLowGuid; ///< Proposal group (0 if new)
+ uint64 group; ///< Proposal group (0 if new)
uint64 leader; ///< Leader guid.
time_t cancelTime; ///< Time when we will cancel this proposal
+ uint32 encounters; ///< Dungeon Encounters
+ bool isNew; ///< Determines if it's new group or not
LfgGuidList queues; ///< Queue Ids to remove/readd
LfgProposalPlayerMap players; ///< Players data
-
};
/// Stores all rolecheck info of a group that wants to join
@@ -257,10 +248,36 @@ struct LfgPlayerBoot
bool inProgress; ///< Vote in progress
LfgAnswerMap votes; ///< Player votes (-1 not answer | 0 Not agree | 1 agree)
uint64 victim; ///< Player guid to be kicked (can't vote)
- uint8 votedNeeded; ///< Votes needed to kick the player
std::string reason; ///< kick reason
};
+struct LFGDungeonEntry
+{
+ LFGDungeonEntry(): id(0), name(""), map(0), type(0), expansion(0), group(0), minlevel(0),
+ maxlevel(0), difficulty(REGULAR_DIFFICULTY), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f)
+ { }
+ LFGDungeonEntry(LFGDungeonEntryDbc const* dbc): id(dbc->ID), name(dbc->name), map(dbc->map),
+ type(dbc->type), expansion(dbc->expansion), group(dbc->grouptype),
+ minlevel(dbc->minlevel), maxlevel(dbc->maxlevel), difficulty(Difficulty(dbc->difficulty)),
+ seasonal(dbc->flags & LFG_FLAG_SEASONAL), x(0.0f), y(0.0f), z(0.0f), o(0.0f)
+ { }
+
+ uint32 id;
+ std::string name;
+ uint16 map;
+ uint8 type;
+ uint8 expansion;
+ uint8 group;
+ uint8 minlevel;
+ uint8 maxlevel;
+ Difficulty difficulty;
+ bool seasonal;
+ float x, y, z, o;
+
+ // Helpers
+ uint32 Entry() const { return id + (type << 24); }
+};
+
class LFGMgr
{
friend class ACE_Singleton<LFGMgr, ACE_Null_Mutex>;
@@ -274,108 +291,124 @@ class LFGMgr
// Reward
void LoadRewards();
- void RewardDungeonDoneFor(const uint32 dungeonId, Player* player);
+ void RewardDungeonDoneFor(uint32 const dungeonId, Player* player);
LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level);
// Queue
- void Join(Player* player, uint8 roles, const LfgDungeonSet& dungeons, const std::string& comment);
- void Leave(Player* player, Group* grp = NULL);
+ void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment);
+ void LeaveLfg(uint64 guid);
// Role Check
- void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = ROLE_NONE);
+ void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE);
+
+ // Group Matching
+ static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true);
+ void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap);
// Proposals
+ uint32 AddProposal(LfgProposal const& proposal);
void UpdateProposal(uint32 proposalId, uint64 guid, bool accept);
// Teleportation
- void LoadEntrancePositions();
void TeleportPlayer(Player* player, bool out, bool fromOpcode = false);
// Vote kick
- void InitBoot(Group* grp, uint64 kguid, uint64 vguid, std::string reason);
- void UpdateBoot(Player* player, bool accept);
- void OfferContinue(Group* grp);
+ void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason);
+ void UpdateBoot(uint64 guid, bool accept);
- HolidayIds GetDungeonSeason(uint32 dungeonId);
+ void InitializeLockedDungeons(Player* player, uint8 level = 0);
- void InitializeLockedDungeons(Player* player);
+ void SetRoles(uint64 guid, uint8 roles);
+ void SetComment(uint64 guid, std::string const& comment);
+ void SetTeam(uint64 guid, uint8 team);
+ void SetGroup(uint64 guid, uint64 group);
+ void SetLeader(uint64 gguid, uint64 leader);
+ void SetState(uint64 guid, LfgState state);
+ void SetSelectedDungeons(uint64 guid, LfgDungeonSet const& dungeons);
void _LoadFromDB(Field* fields, uint64 guid);
void _SaveToDB(uint64 guid, uint32 db_guid);
- void SetComment(uint64 guid, const std::string& comment);
- const LfgLockMap& GetLockedDungeons(uint64 guid);
- LfgState GetState(uint64 guid);
- const LfgDungeonSet& GetSelectedDungeons(uint64 guid);
- uint32 GetDungeon(uint64 guid, bool asId = true);
- void SetState(uint64 guid, LfgState state);
- void ClearState(uint64 guid);
void RemovePlayerData(uint64 guid);
void RemoveGroupData(uint64 guid);
+ uint8 RemovePlayerFromGroup(uint64 gguid, uint64 guid);
+ void AddPlayerToGroup(uint64 gguid, uint64 guid);
+
+ LfgLockMap const& GetLockedDungeons(uint64 guid);
+ LfgDungeonSet const& GetSelectedDungeons(uint64 guid);
+ uint32 GetDungeon(uint64 guid, bool asId = true);
+ LfgState GetState(uint64 guid);
uint8 GetKicksLeft(uint64 gguid);
- uint8 GetVotesNeeded(uint64 gguid);
- bool IsTeleported(uint64 pguid);
- void SetRoles(uint64 guid, uint8 roles);
- void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons);
+ uint64 GetLeader(uint64 guid);
+ bool IsLfgGroup(uint64 guid);
+ uint8 GetRoles(uint64 guid);
+ std::string const& GetComment(uint64 gguid);
+ LfgGuidSet const& GetPlayers(uint64 guid);
+
+ bool IsTeleported(uint64 guid);
+ bool AllQueued(LfgGuidList const& check);
+ static bool HasIgnore(uint64 guid1, uint64 guid2);
+ static void SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const& data);
+
+ bool IsSeasonActive(uint32 dungeonId);
+
+ static std::string ConcatenateDungeons(LfgDungeonSet const& dungeons);
+ static std::string GetRolesString(uint8 roles);
+ static char const * GetStateString(LfgState state);
+
+ void LoadLFGDungeons(bool reload = false);
+ LFGDungeonEntry const* GetLFGDungeon(uint32 id);
+ LFGDungeonMap& GetLFGDungeonMap();
+
+ void ClearState(uint64 guid, char const *debugMsg);
private:
- uint8 GetRoles(uint64 guid);
- const std::string& GetComment(uint64 gguid);
- void RestoreState(uint64 guid);
+ uint8 GetTeam(uint64 guid);
+ uint64 GetGroup(uint64 guid);
+ void RestoreState(uint64 guid, char const *debugMsg);
+
void SetDungeon(uint64 guid, uint32 dungeon);
- void SetLockedDungeons(uint64 guid, const LfgLockMap& lock);
+ void SetLockedDungeons(uint64 guid, LfgLockMap const& lock);
void DecreaseKicksLeft(uint64 guid);
- // Queue
- void AddToQueue(uint64 guid, uint8 queueId);
- bool RemoveFromQueue(uint64 guid);
-
// Proposals
void RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType type);
-
- // Group Matching
- LfgProposal* FindNewGroups(LfgGuidList& check, LfgGuidList& all);
- bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true);
- bool CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal);
- void GetCompatibleDungeons(LfgDungeonSet& dungeons, const PlayerSet& players, LfgLockPartyMap& lockMap);
- void SetCompatibles(std::string concatenatedGuids, bool compatibles);
- LfgAnswer GetCompatibles(std::string concatenatedGuids);
- void RemoveFromCompatibles(uint64 guid);
+ void MakeNewGroup(LfgProposal const& proposal);
// Generic
- const LfgDungeonSet& GetDungeonsByRandom(uint32 randomdungeon);
+ LfgQueue &GetQueue(uint64 guid);
+ LfgDungeonSet const& GetDungeonsByRandom(uint32 randomdungeon);
LfgType GetDungeonType(uint32 dungeon);
- std::string ConcatenateGuids(LfgGuidList check);
+
+ void SendLfgBootProposalUpdate(uint64 guid, LfgPlayerBoot const& boot);
+ void SendLfgJoinResult(uint64 guid, LfgJoinResultData const& data);
+ void SendLfgRoleChosen(uint64 guid, uint64 pguid, uint8 roles);
+ void SendLfgRoleCheckUpdate(uint64 guid, LfgRoleCheck const& roleCheck);
+ void SendLfgUpdateParty(uint64 guid, LfgUpdateData const& data);
+ void SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data);
+ void SendLfgUpdateProposal(uint64 guid, uint32 proposalId, LfgProposal const& proposal);
// General variables
- bool m_update; ///< Doing an update?
uint32 m_QueueTimer; ///< used to check interval of update
uint32 m_lfgProposalId; ///< used as internal counter for proposals
- int32 m_WaitTimeAvg; ///< Average wait time to find a group queuing as multiple roles
- int32 m_WaitTimeTank; ///< Average wait time to find a group queuing as tank
- int32 m_WaitTimeHealer; ///< Average wait time to find a group queuing as healer
- int32 m_WaitTimeDps; ///< Average wait time to find a group queuing as dps
- uint32 m_NumWaitTimeAvg; ///< Num of players used to calc avs wait time
- uint32 m_NumWaitTimeTank; ///< Num of players used to calc tank wait time
- uint32 m_NumWaitTimeHealer; ///< Num of players used to calc healers wait time
- uint32 m_NumWaitTimeDps; ///< Num of players used to calc dps wait time
- LfgDungeonMap m_CachedDungeonMap; ///< Stores all dungeons by groupType
- LfgEntrancePositionMap m_entrancePositions; ///< Stores special entrance positions
+ uint32 m_options; ///< Stores config options
+
+ LfgQueueMap m_Queues; ///< Queues
+ LfgCachedDungeonMap m_CachedDungeonMap; ///< Stores all dungeons by groupType
// Reward System
LfgRewardMap m_RewardMap; ///< Stores rewards for random dungeons
- // Queue
- LfgQueueInfoMap m_QueueInfoMap; ///< Queued groups
- LfgGuidListMap m_currentQueue; ///< Ordered list. Used to find groups
- LfgGuidListMap m_newToQueue; ///< New groups to add to queue
- LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons
- LfgGuidList m_teleport; ///< Players being teleported
+ LFGDungeonMap m_LfgDungeonMap;
// Rolecheck - Proposal - Vote Kicks
LfgRoleCheckMap m_RoleChecks; ///< Current Role checks
LfgProposalMap m_Proposals; ///< Current Proposals
LfgPlayerBootMap m_Boots; ///< Current player kicks
LfgPlayerDataMap m_Players; ///< Player data
LfgGroupDataMap m_Groups; ///< Group data
+ LfgGuidList m_teleport; ///< Players being teleported
+
+ LFGPlayerScript *m_lfgPlayerScript;
+ LFGGroupScript *m_lfgGroupScript;
};
#define sLFGMgr ACE_Singleton<LFGMgr, ACE_Null_Mutex>::instance()
diff --git a/src/server/game/DungeonFinding/LFGPlayerData.cpp b/src/server/game/DungeonFinding/LFGPlayerData.cpp
index 4a6e86ab966..e5645f0f0aa 100644
--- a/src/server/game/DungeonFinding/LFGPlayerData.cpp
+++ b/src/server/game/DungeonFinding/LFGPlayerData.cpp
@@ -17,8 +17,8 @@
#include "LFGPlayerData.h"
-LfgPlayerData::LfgPlayerData():
-m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Roles(0), m_Comment("")
+LfgPlayerData::LfgPlayerData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE),
+ m_Team(0), m_Group(0), m_Roles(0), m_Comment("")
{}
LfgPlayerData::~LfgPlayerData()
@@ -30,10 +30,13 @@ void LfgPlayerData::SetState(LfgState state)
switch (state)
{
case LFG_STATE_NONE:
- case LFG_STATE_DUNGEON:
case LFG_STATE_FINISHED_DUNGEON:
+ m_Roles = 0;
+ m_SelectedDungeons.clear();
+ // No break on purpose
+ case LFG_STATE_DUNGEON:
m_OldState = state;
- // No break on purpose
+ // No break on purpose
default:
m_State = state;
}
@@ -51,6 +54,16 @@ void LfgPlayerData::SetLockedDungeons(const LfgLockMap& lockStatus)
m_LockedDungeons = lockStatus;
}
+void LfgPlayerData::SetTeam(uint8 team)
+{
+ m_Team = team;
+}
+
+void LfgPlayerData::SetGroup(uint64 group)
+{
+ m_Group = group;
+}
+
void LfgPlayerData::SetRoles(uint8 roles)
{
m_Roles = roles;
@@ -66,21 +79,31 @@ void LfgPlayerData::SetSelectedDungeons(const LfgDungeonSet& dungeons)
m_SelectedDungeons = dungeons;
}
-void LfgPlayerData::ClearSelectedDungeons()
+LfgState LfgPlayerData::GetState() const
{
- m_SelectedDungeons.clear();
+ return m_State;
}
-LfgState LfgPlayerData::GetState() const
+LfgState LfgPlayerData::GetOldState() const
{
- return m_State;
+ return m_OldState;
}
-const LfgLockMap & LfgPlayerData::GetLockedDungeons() const
+const LfgLockMap& LfgPlayerData::GetLockedDungeons() const
{
return m_LockedDungeons;
}
+uint8 LfgPlayerData::GetTeam() const
+{
+ return m_Team;
+}
+
+uint64 LfgPlayerData::GetGroup() const
+{
+ return m_Group;
+}
+
uint8 LfgPlayerData::GetRoles() const
{
return m_Roles;
diff --git a/src/server/game/DungeonFinding/LFGPlayerData.h b/src/server/game/DungeonFinding/LFGPlayerData.h
index e8bae1c5a0f..0682ad66698 100644
--- a/src/server/game/DungeonFinding/LFGPlayerData.h
+++ b/src/server/game/DungeonFinding/LFGPlayerData.h
@@ -18,7 +18,6 @@
#ifndef _LFGPLAYERDATA_H
#define _LFGPLAYERDATA_H
-#include "Common.h"
#include "LFG.h"
/**
@@ -33,20 +32,26 @@ class LfgPlayerData
// General
void SetState(LfgState state);
void ClearState();
- void SetLockedDungeons(const LfgLockMap& lock);
+ void SetLockedDungeons(LfgLockMap const& lock);
+ void SetTeam(uint8 team);
+ void SetGroup(uint64 group);
+
// Queue
void SetRoles(uint8 roles);
- void SetComment(const std::string& comment);
+ void SetComment(std::string const& comment);
void SetSelectedDungeons(const LfgDungeonSet& dungeons);
- void ClearSelectedDungeons();
// General
LfgState GetState() const;
- const LfgLockMap& GetLockedDungeons() const;
+ LfgState GetOldState() const;
+ LfgLockMap const& GetLockedDungeons() const;
+ uint8 GetTeam() const;
+ uint64 GetGroup() const;
+
// Queue
uint8 GetRoles() const;
- const std::string& GetComment() const;
- const LfgDungeonSet& GetSelectedDungeons() const;
+ std::string const& GetComment() const;
+ LfgDungeonSet const& GetSelectedDungeons() const;
private:
// General
@@ -54,6 +59,9 @@ class LfgPlayerData
LfgState m_OldState; ///< Old State
// Player
LfgLockMap m_LockedDungeons; ///< Dungeons player can't do and reason
+ uint8 m_Team; ///< Player team - determines the queue to join
+ uint64 m_Group; ///< Original group of player when joined LFG
+
// Queue
uint8 m_Roles; ///< Roles the player selected when joined LFG
std::string m_Comment; ///< Player comment used when joined LFG
diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp
new file mode 100644
index 00000000000..c1d89a16300
--- /dev/null
+++ b/src/server/game/DungeonFinding/LFGQueue.cpp
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ObjectDefines.h"
+#include "Containers.h"
+#include "DBCStructure.h"
+#include "DBCStores.h"
+#include "Group.h"
+#include "LFGQueue.h"
+#include "LFGMgr.h"
+#include "Log.h"
+#include "ObjectMgr.h"
+#include "World.h"
+
+/**
+ Given a list of guids returns the concatenation using | as delimiter
+
+ @param[in] check list of guids
+ @returns Concatenated string
+*/
+std::string ConcatenateGuids(LfgGuidList const& check)
+{
+ if (check.empty())
+ return "";
+
+ // need the guids in order to avoid duplicates
+ LfgGuidSet guids(check.begin(), check.end());
+
+ std::ostringstream o;
+
+ LfgGuidSet::const_iterator it = guids.begin();
+ o << (*it);
+ for (++it; it != guids.end(); ++it)
+ o << '|' << (*it);
+
+ return o.str();
+}
+
+char const * GetCompatibleString(LfgCompatibility compatibles)
+{
+ switch (compatibles)
+ {
+ case LFG_COMPATIBILITY_PENDING:
+ return "Pending";
+ case LFG_COMPATIBLES_BAD_STATES:
+ return "Compatibles (Bad States)";
+ case LFG_COMPATIBLES_MATCH:
+ return "Match";
+ case LFG_COMPATIBLES_WITH_LESS_PLAYERS:
+ return "Compatibles (Not enough players)";
+ case LFG_INCOMPATIBLES_HAS_IGNORES:
+ return "Has ignores";
+ case LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS:
+ return "Multiple Lfg Groups";
+ case LFG_INCOMPATIBLES_NO_DUNGEONS:
+ return "Incompatible dungeons";
+ case LFG_INCOMPATIBLES_NO_ROLES:
+ return "Incompatible roles";
+ case LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS:
+ return "Too much players";
+ case LFG_INCOMPATIBLES_WRONG_GROUP_SIZE:
+ return "Wrong group size";
+ default:
+ return "Unknown";
+ }
+}
+
+void LfgQueue::AddToQueue(uint64 guid)
+{
+ LfgQueueDataMap::iterator itQueue = m_QueueDataMap.find(guid);
+ if (itQueue == m_QueueDataMap.end())
+ {
+ sLog->outError(LOG_FILTER_LFG, "LfgQueue::AddToQueue: Queue data not found for [" UI64FMTD "]", guid);
+ return;
+ }
+
+ AddToNewQueue(guid);
+}
+
+void LfgQueue::RemoveFromQueue(uint64 guid)
+{
+ RemoveFromNewQueue(guid);
+ RemoveFromCurrentQueue(guid);
+ RemoveFromCompatibles(guid);
+ RemoveQueueData(guid);
+}
+
+void LfgQueue::AddToNewQueue(uint64 guid)
+{
+ m_newToQueue.push_back(guid);
+}
+
+void LfgQueue::RemoveFromNewQueue(uint64 guid)
+{
+ m_newToQueue.remove(guid);
+}
+
+void LfgQueue::AddToCurrentQueue(uint64 guid)
+{
+ m_currentQueue.push_back(guid);
+}
+
+void LfgQueue::RemoveFromCurrentQueue(uint64 guid)
+{
+ m_currentQueue.remove(guid);
+}
+
+void LfgQueue::AddQueueData(uint64 guid, time_t joinTime, const LfgDungeonSet &dungeons, const LfgRolesMap &rolesMap)
+{
+ m_QueueDataMap[guid] = LfgQueueData(joinTime, dungeons, rolesMap);
+ AddToQueue(guid);
+}
+
+void LfgQueue::RemoveQueueData(uint64 guid)
+{
+ LfgQueueDataMap::iterator it = m_QueueDataMap.find(guid);
+ if (it != m_QueueDataMap.end())
+ m_QueueDataMap.erase(it);
+}
+
+void LfgQueue::UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId)
+{
+ LfgWaitTime &wt = m_waitTimesAvg[dungeonId];
+ uint32 old_number = wt.number++;
+ wt.time = int32((wt.time * old_number + waitTime) / wt.number);
+}
+
+void LfgQueue::UpdateWaitTimeTank(int32 waitTime, uint32 dungeonId)
+{
+ LfgWaitTime &wt = m_waitTimesTank[dungeonId];
+ uint32 old_number = wt.number++;
+ wt.time = int32((wt.time * old_number + waitTime) / wt.number);
+}
+
+void LfgQueue::UpdateWaitTimeHealer(int32 waitTime, uint32 dungeonId)
+{
+ LfgWaitTime &wt = m_waitTimesHealer[dungeonId];
+ uint32 old_number = wt.number++;
+ wt.time = int32((wt.time * old_number + waitTime) / wt.number);
+}
+
+void LfgQueue::UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId)
+{
+ LfgWaitTime &wt = m_waitTimesDps[dungeonId];
+ uint32 old_number = wt.number++;
+ wt.time = int32((wt.time * old_number + waitTime) / wt.number);
+}
+
+/**
+ Remove from cached compatible dungeons any entry that contains the given guid
+
+ @param[in] guid Guid to remove from compatible cache
+*/
+void LfgQueue::RemoveFromCompatibles(uint64 guid)
+{
+ std::stringstream out;
+ out << guid;
+ std::string strGuid = out.str();
+
+ sLog->outDebug(LOG_FILTER_LFG, "LfgQueue::RemoveFromCompatibles: Removing [" UI64FMTD "]", guid);
+ for (LfgCompatibleMap::iterator itNext = m_CompatibleMap.begin(); itNext != m_CompatibleMap.end();)
+ {
+ LfgCompatibleMap::iterator it = itNext++;
+ if (it->first.find(strGuid) != std::string::npos) // Found, remove it
+ m_CompatibleMap.erase(it);
+ }
+}
+
+
+/**
+ Stores the compatibility of a list of guids
+
+ @param[in] key String concatenation of guids (| used as separator)
+ @param[in] compatibles type of compatibility
+*/
+void LfgQueue::SetCompatibles(const std::string &key, LfgCompatibility compatibles)
+{
+ m_CompatibleMap[key] = compatibles;
+}
+
+/**
+ Get the compatibility of a group of guids
+
+ @param[in] key String concatenation of guids (| used as separator)
+ @return LfgCompatibility type of compatibility
+*/
+LfgCompatibility LfgQueue::GetCompatibles(std::string const& key)
+{
+ LfgCompatibleMap::iterator it = m_CompatibleMap.find(key);
+ if (it != m_CompatibleMap.end())
+ return it->second;
+
+ return LFG_COMPATIBILITY_PENDING;
+}
+
+uint8 LfgQueue::FindGroups()
+{
+ uint8 proposals = 0;
+ LfgGuidList firstNew;
+ while (!m_newToQueue.empty())
+ {
+ uint64 frontguid = m_newToQueue.front();
+ sLog->outDebug(LOG_FILTER_LFG, "LfgQueue::FindGroups: checking [" UI64FMTD "] newToQueue(%u), currentQueue(%u)", frontguid, uint32(m_newToQueue.size()), uint32(m_currentQueue.size()));
+ firstNew.clear();
+ firstNew.push_back(frontguid);
+ RemoveFromNewQueue(frontguid);
+
+ LfgGuidList temporalList = m_currentQueue;
+ LfgCompatibility compatibles = FindNewGroups(firstNew, temporalList);
+
+ if (compatibles == LFG_COMPATIBLES_MATCH)
+ ++proposals;
+ else
+ AddToCurrentQueue(frontguid); // Lfg group not found, add this group to the queue.
+ }
+ return proposals;
+}
+
+/**
+ Checks que main queue to try to form a Lfg group. Returns first match found (if any)
+
+ @param[in] check List of guids trying to match with other groups
+ @param[in] all List of all other guids in main queue to match against
+ @return LfgCompatibility type of compatibility between groups
+*/
+LfgCompatibility LfgQueue::FindNewGroups(LfgGuidList& check, LfgGuidList& all)
+{
+ std::string strGuids = ConcatenateGuids(check);
+ LfgCompatibility compatibles = GetCompatibles(strGuids);
+
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::FindNewGroup: (%s): %s - all(%s)", strGuids.c_str(), GetCompatibleString(compatibles), ConcatenateGuids(all).c_str());
+ if (compatibles == LFG_COMPATIBILITY_PENDING || compatibles == LFG_COMPATIBLES_BAD_STATES) // Not previously cached, calculate
+ compatibles = CheckCompatibility(check);
+
+ if (compatibles != LFG_COMPATIBLES_WITH_LESS_PLAYERS)
+ return compatibles;
+
+ // Try to match with queued groups
+ while (!all.empty())
+ {
+ check.push_back(all.front());
+ all.pop_front();
+ LfgCompatibility subcompatibility = FindNewGroups(check, all);
+ if (subcompatibility == LFG_COMPATIBLES_MATCH)
+ return LFG_COMPATIBLES_MATCH;
+ check.pop_back();
+ }
+ return compatibles;
+}
+
+/**
+ Check compatibilities between groups. If group is Matched proposal will be created
+
+ @param[in] check List of guids to check compatibilities
+ @return LfgCompatibility type of compatibility
+*/
+LfgCompatibility LfgQueue::CheckCompatibility(LfgGuidList check)
+{
+ std::string strGuids = ConcatenateGuids(check);
+ LfgProposal proposal;
+ LfgDungeonSet proposalDungeons;
+ LfgGroupsMap proposalGroups;
+ LfgRolesMap proposalRoles;
+
+ // Check for correct size
+ if (check.size() > MAXGROUPSIZE || check.empty())
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s): Size wrong - Not compatibles", strGuids.c_str());
+ return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE;
+ }
+
+ // Player joining alone always compatible
+ if (check.size() == 1 && IS_PLAYER_GUID(check.front()))
+ return LFG_COMPATIBLES_WITH_LESS_PLAYERS;
+
+ // Check all-but-new compatiblitity
+ if (check.size() > 2)
+ {
+ uint64 frontGuid = check.front();
+ check.pop_front();
+
+ // Check all-but-new compatibilities (New, A, B, C, D) --> check(A, B, C, D)
+ LfgCompatibility child_compatibles = CheckCompatibility(check);
+ if (child_compatibles < LFG_COMPATIBLES_WITH_LESS_PLAYERS) // Group not compatible
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) child %s not compatibles", strGuids.c_str(), ConcatenateGuids(check).c_str());
+ SetCompatibles(strGuids, child_compatibles);
+ return child_compatibles;
+ }
+ check.push_front(frontGuid);
+ }
+
+ // Check if more than one LFG group and number of players joining
+ uint8 numPlayers = 0;
+ uint8 numLfgGroups = 0;
+ for (LfgGuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it)
+ {
+ uint64 guid = (*it);
+ LfgQueueDataMap::iterator itQueue = m_QueueDataMap.find(guid);
+ if (itQueue == m_QueueDataMap.end())
+ {
+ sLog->outError(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: [" UI64FMTD "] is not queued but listed as queued!", guid);
+ RemoveFromQueue(guid);
+ return LFG_COMPATIBILITY_PENDING;
+ }
+
+ // Store group so we don't need to call Mgr to get it later (if it's player group will be 0 otherwise would have joined as group)
+ for (LfgRolesMap::const_iterator it2 = itQueue->second.roles.begin(); it2 != itQueue->second.roles.end(); ++it2)
+ proposalGroups[it2->first] = IS_GROUP(itQueue->first) ? itQueue->first : 0;
+
+ numPlayers += itQueue->second.roles.size();
+
+ if (sLFGMgr->IsLfgGroup(guid))
+ {
+ if (!numLfgGroups)
+ proposal.group = guid;
+ ++numLfgGroups;
+ }
+ }
+
+ // Group with less that MAXGROUPSIZE members always compatible
+ if (check.size() == 1 && numPlayers != MAXGROUPSIZE)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) sigle group. Compatibles", strGuids.c_str());
+ return LFG_COMPATIBLES_WITH_LESS_PLAYERS;
+ }
+
+ if (numLfgGroups > 1)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups);
+ SetCompatibles(strGuids, LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS);
+ return LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS;
+ }
+
+ if (numPlayers > MAXGROUPSIZE)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Too much players (%u)", strGuids.c_str(), numPlayers);
+ SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS);
+ return LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS;
+ }
+
+ // If it's single group no need to check for duplicate players, ignores, bad roles or bad dungeons as it's been checked before joining
+ if (check.size() > 1)
+ {
+ for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it)
+ {
+ const LfgRolesMap &roles = m_QueueDataMap[(*it)].roles;
+ for (LfgRolesMap::const_iterator itRoles = roles.begin(); itRoles != roles.end(); ++itRoles)
+ {
+ LfgRolesMap::const_iterator itPlayer;
+ for (itPlayer = proposalRoles.begin(); itPlayer != proposalRoles.end(); ++itPlayer)
+ {
+ if (itRoles->first == itPlayer->first)
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: ERROR! Player multiple times in queue! [" UI64FMTD "]", itRoles->first);
+ else if (sLFGMgr->HasIgnore(itRoles->first, itPlayer->first))
+ break;
+ }
+ if (itPlayer == proposalRoles.end())
+ proposalRoles[itRoles->first] = itRoles->second;
+ }
+ }
+
+ if (uint8 playersize = numPlayers - proposalRoles.size())
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) not compatible, %u players are ignoring each other", strGuids.c_str(), playersize);
+ SetCompatibles(strGuids, LFG_INCOMPATIBLES_HAS_IGNORES);
+ return LFG_INCOMPATIBLES_HAS_IGNORES;
+ }
+
+ LfgRolesMap debugRoles = proposalRoles; // DEBUG
+ if (!LFGMgr::CheckGroupRoles(proposalRoles))
+ {
+ std::ostringstream o;
+ for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it)
+ o << ", " << it->first << ": " << sLFGMgr->GetRolesString(it->second);
+
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Roles not compatible%s", strGuids.c_str(), o.str().c_str());
+ SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES);
+ return LFG_INCOMPATIBLES_NO_ROLES;
+ }
+
+ LfgGuidList::iterator itguid = check.begin();
+ proposalDungeons = m_QueueDataMap[*itguid].dungeons;
+ std::ostringstream o;
+ o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(proposalDungeons) << ")";
+ for (++itguid; itguid != check.end(); ++itguid)
+ {
+ LfgDungeonSet temporal;
+ LfgDungeonSet &dungeons = m_QueueDataMap[*itguid].dungeons;
+ o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(dungeons) << ")";
+ std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin()));
+ proposalDungeons = temporal;
+ }
+
+ if (proposalDungeons.empty())
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) No compatible dungeons%s", strGuids.c_str(), o.str().c_str());
+ SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_DUNGEONS);
+ return LFG_INCOMPATIBLES_NO_DUNGEONS;
+ }
+ }
+ else
+ {
+ uint64 gguid = *check.begin();
+ const LfgQueueData &queue = m_QueueDataMap[gguid];
+ proposalDungeons = queue.dungeons;
+ proposalRoles = queue.roles;
+ LFGMgr::CheckGroupRoles(proposalRoles); // assing new roles
+ }
+
+ // Enough players?
+ if (numPlayers != MAXGROUPSIZE)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Compatibles but not enough players(%u)", strGuids.c_str(), numPlayers);
+ SetCompatibles(strGuids, LFG_COMPATIBLES_WITH_LESS_PLAYERS);
+ return LFG_COMPATIBLES_WITH_LESS_PLAYERS;
+ }
+
+ proposal.queues = check;
+ if (check.size() == 1)
+ {
+ for (LfgGroupsMap::const_iterator it = proposalGroups.begin(); it != proposalGroups.end(); ++it)
+ if (proposal.group && it->second != proposal.group)
+ proposal.isNew = false;
+ }
+
+ if (!sLFGMgr->AllQueued(check))
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Group MATCH but can't create proposal!", strGuids.c_str());
+ SetCompatibles(strGuids, LFG_COMPATIBLES_BAD_STATES);
+ return LFG_COMPATIBLES_BAD_STATES;
+ }
+
+ // Create a new proposal
+ proposal.cancelTime = time(NULL) + LFG_TIME_PROPOSAL;
+ proposal.state = LFG_PROPOSAL_INITIATING;
+ proposal.leader = 0;
+ proposal.dungeonId = Trinity::Containers::SelectRandomContainerElement(proposalDungeons);
+
+ bool leader = false;
+ for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles)
+ {
+ // Assing new leader
+ if (itRoles->second & PLAYER_ROLE_LEADER)
+ {
+ if (!leader || !proposal.leader || urand(0, 1))
+ proposal.leader = itRoles->first;
+ leader = true;
+ }
+ else if (!leader && (!proposal.leader || urand(0, 1)))
+ proposal.leader = itRoles->first;
+
+ // Assing player data and roles
+ LfgProposalPlayer &data = proposal.players[itRoles->first];
+ data.role = itRoles->second;
+ data.group = proposalGroups.find(itRoles->first)->second;
+ if (!proposal.isNew && data.group && data.group == proposal.group) // Player from existing group, autoaccept
+ data.accept = LFG_ANSWER_AGREE;
+ }
+
+ // Mark proposal members as not queued (but not remove queue data)
+ for (LfgGuidList::const_iterator itQueue = proposal.queues.begin(); itQueue != proposal.queues.end(); ++itQueue)
+ {
+ uint64 guid = (*itQueue);
+ RemoveFromNewQueue(guid);
+ RemoveFromCurrentQueue(guid);
+ }
+
+ sLFGMgr->AddProposal(proposal);
+
+ sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str());
+ SetCompatibles(strGuids, LFG_COMPATIBLES_MATCH);
+ return LFG_COMPATIBLES_MATCH;
+}
+
+void LfgQueue::UpdateQueueTimers(time_t currTime)
+{
+ for (LfgQueueDataMap::const_iterator itQueue = m_QueueDataMap.begin(); itQueue != m_QueueDataMap.end(); ++itQueue)
+ {
+ const LfgQueueData &queueinfo = itQueue->second;
+ uint32 dungeonId = (*queueinfo.dungeons.begin());
+ uint32 queuedTime = uint32(currTime - queueinfo.joinTime);
+ uint8 role = PLAYER_ROLE_NONE;
+ int32 waitTime = -1;
+ int32 wtTank = m_waitTimesTank[dungeonId].time;
+ int32 wtHealer = m_waitTimesHealer[dungeonId].time;
+ int32 wtDps = m_waitTimesDps[dungeonId].time;
+ int32 wtAvg = m_waitTimesAvg[dungeonId].time;
+
+ for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer)
+ role |= itPlayer->second;
+ role &= ~PLAYER_ROLE_LEADER;
+
+ switch (role)
+ {
+ case PLAYER_ROLE_NONE: // Should not happen - just in case
+ waitTime = -1;
+ break;
+ case PLAYER_ROLE_TANK:
+ waitTime = wtTank;
+ break;
+ case PLAYER_ROLE_HEALER:
+ waitTime = wtHealer;
+ break;
+ case PLAYER_ROLE_DAMAGE:
+ waitTime = wtDps;
+ break;
+ default:
+ waitTime = wtAvg;
+ break;
+ }
+
+ LfgQueueStatusData queueData(dungeonId, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps);
+ for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer)
+ {
+ uint64 pguid = itPlayer->first;
+ LFGMgr::SendLfgQueueStatus(pguid, queueData);
+ }
+ }
+}
+
+time_t LfgQueue::GetJoinTime(uint64 guid)
+{
+ return m_QueueDataMap[guid].joinTime;
+} \ No newline at end of file
diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h
new file mode 100644
index 00000000000..f08199d725a
--- /dev/null
+++ b/src/server/game/DungeonFinding/LFGQueue.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LFGQUEUE_H
+#define _LFGQUEUE_H
+
+#include "LFG.h"
+
+enum LfgCompatibility
+{
+ LFG_COMPATIBILITY_PENDING,
+ LFG_INCOMPATIBLES_WRONG_GROUP_SIZE,
+ LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS,
+ LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS,
+ LFG_INCOMPATIBLES_HAS_IGNORES,
+ LFG_INCOMPATIBLES_NO_ROLES,
+ LFG_INCOMPATIBLES_NO_DUNGEONS,
+ LFG_COMPATIBLES_WITH_LESS_PLAYERS, // Values under this = not compatible (do not modify order)
+ LFG_COMPATIBLES_BAD_STATES,
+ LFG_COMPATIBLES_MATCH // Must be the last one
+};
+
+/// Stores player or group queue info
+struct LfgQueueData
+{
+ LfgQueueData(): joinTime(time_t(time(NULL))), tanks(LFG_TANKS_NEEDED),
+ healers(LFG_HEALERS_NEEDED), dps(LFG_DPS_NEEDED)
+ { }
+
+ LfgQueueData(time_t _joinTime, const LfgDungeonSet &_dungeons, const LfgRolesMap &_roles)
+ {
+ joinTime = _joinTime;
+ dungeons = _dungeons;
+ roles = _roles;
+ tanks = LFG_TANKS_NEEDED;
+ healers = LFG_HEALERS_NEEDED;
+ dps = LFG_DPS_NEEDED;
+
+ for (LfgRolesMap::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ {
+ uint8 role = it->second;
+ if (role & PLAYER_ROLE_TANK)
+ --tanks;
+ else if (role & PLAYER_ROLE_HEALER)
+ --healers;
+ else
+ --dps;
+ }
+ }
+
+ time_t joinTime; ///< Player queue join time (to calculate wait times)
+ uint8 tanks; ///< Tanks needed
+ uint8 healers; ///< Healers needed
+ uint8 dps; ///< Dps needed
+ LfgDungeonSet dungeons; ///< Selected Player/Group Dungeon/s
+ LfgRolesMap roles; ///< Selected Player Role/s
+};
+
+struct LfgWaitTime
+{
+ LfgWaitTime(): time(-1), number(0) {}
+ int32 time; ///< Wait time
+ uint32 number; ///< Number of people used to get that wait time
+};
+
+typedef std::map<uint32, LfgWaitTime> LfgWaitTimesMap;
+typedef std::map<std::string, LfgCompatibility> LfgCompatibleMap;
+typedef std::map<uint64, LfgQueueData> LfgQueueDataMap;
+
+/**
+ Stores all data related to queue
+*/
+class LfgQueue
+{
+ public:
+
+ // Add/Remove from queue
+ void AddToQueue(uint64 guid);
+ void RemoveFromQueue(uint64 guid);
+ void AddQueueData(uint64 guid, time_t joinTime, const LfgDungeonSet &dungeons, const LfgRolesMap &rolesMap);
+ void RemoveQueueData(uint64 guid);
+
+ // Update Timers (when proposal success)
+ void UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId);
+ void UpdateWaitTimeTank(int32 waitTime, uint32 dungeonId);
+ void UpdateWaitTimeHealer(int32 waitTime, uint32 dungeonId);
+ void UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId);
+
+ // Update Queue timers
+ void UpdateQueueTimers(time_t currTime);
+ time_t GetJoinTime(uint64 guid);
+
+ // Find new group
+ uint8 FindGroups();
+
+ // Just for debugging purposes
+ LfgCompatibleMap const& GetCompatibleMap();
+ std::string DumpQueueInfo() const;
+ std::string DumpCompatibleInfo() const;
+ private:
+ void AddToNewQueue(uint64 guid);
+ void AddToCurrentQueue(uint64 guid);
+ void RemoveFromNewQueue(uint64 guid);
+ void RemoveFromCurrentQueue(uint64 guid);
+
+ void SetCompatibles(std::string const& key, LfgCompatibility compatibles);
+ LfgCompatibility GetCompatibles(std::string const& key);
+ void RemoveFromCompatibles(uint64 guid);
+
+ LfgCompatibility FindNewGroups(LfgGuidList& check, LfgGuidList& all);
+ LfgCompatibility CheckCompatibility(LfgGuidList check);
+
+ // Queue
+ LfgQueueDataMap m_QueueDataMap; ///< Queued groups
+ LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons
+
+ LfgWaitTimesMap m_waitTimesAvg; ///< Average wait time to find a group queuing as multiple roles
+ LfgWaitTimesMap m_waitTimesTank; ///< Average wait time to find a group queuing as tank
+ LfgWaitTimesMap m_waitTimesHealer; ///< Average wait time to find a group queuing as healer
+ LfgWaitTimesMap m_waitTimesDps; ///< Average wait time to find a group queuing as dps
+ LfgGuidList m_currentQueue; ///< Ordered list. Used to find groups
+ LfgGuidList m_newToQueue; ///< New groups to add to queue
+};
+
+#endif
diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp
index 36f04b3020b..10ce42da610 100644
--- a/src/server/game/DungeonFinding/LFGScripts.cpp
+++ b/src/server/game/DungeonFinding/LFGScripts.cpp
@@ -39,12 +39,12 @@ void LFGPlayerScript::OnLevelChanged(Player* player, uint8 /*oldLevel*/)
void LFGPlayerScript::OnLogout(Player* player)
{
- sLFGMgr->Leave(player);
+ uint64 guid = player->GetGUID();
+ sLFGMgr->LeaveLfg(guid);
LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE);
player->GetSession()->SendLfgUpdateParty(updateData);
player->GetSession()->SendLfgUpdatePlayer(updateData);
- player->GetSession()->SendLfgUpdateSearch(false);
- uint64 guid = player->GetGUID();
+ player->GetSession()->SendLfgLfrList(false);
// TODO - Do not remove, add timer before deleting
sLFGMgr->RemovePlayerData(guid);
}
@@ -52,6 +52,7 @@ void LFGPlayerScript::OnLogout(Player* player)
void LFGPlayerScript::OnLogin(Player* player)
{
sLFGMgr->InitializeLockedDungeons(player);
+ sLFGMgr->SetTeam(player->GetGUID(), player->GetTeam());
// TODO - Restore LfgPlayerData and send proper status to player if it was in a group
}
@@ -69,75 +70,89 @@ LFGGroupScript::LFGGroupScript() : GroupScript("LFGGroupScript")
void LFGGroupScript::OnAddMember(Group* group, uint64 guid)
{
uint64 gguid = group->GetGUID();
- if (!gguid)
- return;
+ uint64 leader = group->GetLeaderGUID();
- sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnAddMember [" UI64FMTD "]: added [" UI64FMTD "]", gguid, guid);
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_CLEAR_LOCK_LIST);
- for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ if (leader == guid)
{
- if (Player* plrg = itr->getSource())
+ sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnAddMember [" UI64FMTD "]: added [" UI64FMTD "] leader " UI64FMTD "]", gguid, guid, leader);
+ sLFGMgr->SetLeader(gguid, guid);
+ }
+ else
+ {
+ LfgState gstate = sLFGMgr->GetState(gguid);
+ LfgState state = sLFGMgr->GetState(guid);
+ sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnAddMember [" UI64FMTD "]: added [" UI64FMTD "] leader " UI64FMTD "] gstate: %u, state: %u", gguid, guid, leader, gstate, state);
+ LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_CLEAR_LOCK_LIST);
+ for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
{
- plrg->GetSession()->SendLfgUpdatePlayer(updateData);
- plrg->GetSession()->SendLfgUpdateParty(updateData);
+ if (Player* plrg = itr->getSource())
+ {
+ plrg->GetSession()->SendLfgUpdatePlayer(updateData);
+ plrg->GetSession()->SendLfgUpdateParty(updateData);
+ }
}
- }
- // TODO - if group is queued and new player is added convert to rolecheck without notify the current players queued
- if (sLFGMgr->GetState(gguid) == LFG_STATE_QUEUED)
- sLFGMgr->Leave(NULL, group);
+ if (state == LFG_STATE_QUEUED)
+ sLFGMgr->LeaveLfg(guid);
- if (sLFGMgr->GetState(guid) == LFG_STATE_QUEUED)
- if (Player* player = ObjectAccessor::FindPlayer(guid))
- sLFGMgr->Leave(player);
+ // TODO - if group is queued and new player is added convert to rolecheck without notify the current players queued
+ if (gstate == LFG_STATE_QUEUED)
+ sLFGMgr->LeaveLfg(gguid);
+ }
+
+ sLFGMgr->SetGroup(guid, gguid);
+ sLFGMgr->AddPlayerToGroup(gguid, guid);
}
void LFGGroupScript::OnRemoveMember(Group* group, uint64 guid, RemoveMethod method, uint64 kicker, char const* reason)
{
uint64 gguid = group->GetGUID();
- if (!gguid || method == GROUP_REMOVEMETHOD_DEFAULT)
- return;
-
sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnRemoveMember [" UI64FMTD "]: remove [" UI64FMTD "] Method: %d Kicker: [" UI64FMTD "] Reason: %s", gguid, guid, method, kicker, (reason ? reason : ""));
- if (sLFGMgr->GetState(gguid) == LFG_STATE_QUEUED)
- {
- // TODO - Do not remove, just remove the one leaving and rejoin queue with all other data
- sLFGMgr->Leave(NULL, group);
- }
- if (!group->isLFGGroup())
- return;
+ bool isLFG = group->isLFGGroup();
- if (method == GROUP_REMOVEMETHOD_KICK) // Player have been kicked
+ if (isLFG && method == GROUP_REMOVEMETHOD_KICK) // Player have been kicked
{
// TODO - Update internal kick cooldown of kicker
std::string str_reason = "";
if (reason)
str_reason = std::string(reason);
- sLFGMgr->InitBoot(group, kicker, guid, str_reason);
+ sLFGMgr->InitBoot(gguid, kicker, guid, str_reason);
return;
}
- uint32 state = sLFGMgr->GetState(gguid);
- sLFGMgr->ClearState(guid);
+ LfgState state = sLFGMgr->GetState(gguid);
+
+ // If group is being formed after proposal success do nothing more
+ if (state == LFG_STATE_PROPOSAL && method == GROUP_REMOVEMETHOD_DEFAULT)
+ {
+ // LfgData: Remove player from group
+ sLFGMgr->SetGroup(guid, 0);
+ sLFGMgr->RemovePlayerFromGroup(gguid, guid);
+ return;
+ }
+
+ sLFGMgr->LeaveLfg(guid);
sLFGMgr->SetState(guid, LFG_STATE_NONE);
+ sLFGMgr->SetGroup(guid, 0);
+ uint8 players = sLFGMgr->RemovePlayerFromGroup(gguid, guid);
+
if (Player* player = ObjectAccessor::FindPlayer(guid))
{
- if (method == GROUP_REMOVEMETHOD_LEAVE && sLFGMgr->GetState(gguid) != LFG_STATE_FINISHED_DUNGEON && sLFGMgr->GetDungeon(gguid, false))
+ if (method == GROUP_REMOVEMETHOD_LEAVE && state == LFG_STATE_DUNGEON &&
+ players >= LFG_GROUP_KICK_VOTES_NEEDED)
player->CastSpell(player, LFG_SPELL_DUNGEON_DESERTER, true);
- /*
- else if (group->isLfgKickActive())
+ //else if (state == LFG_STATE_BOOT)
// Update internal kick cooldown of kicked
- */
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_LEADER);
- player->GetSession()->SendLfgUpdateParty(updateData);
- if (player->GetMap()->IsDungeon()) // Teleport player out the dungeon
+ player->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_LEADER_UNK1));
+ if (isLFG && player->GetMap()->IsDungeon()) // Teleport player out the dungeon
sLFGMgr->TeleportPlayer(player, true);
}
- if (state != LFG_STATE_FINISHED_DUNGEON)// Need more players to finish the dungeon
- sLFGMgr->OfferContinue(group);
+ if (isLFG && state != LFG_STATE_FINISHED_DUNGEON) // Need more players to finish the dungeon
+ if (Player* leader = ObjectAccessor::FindPlayer(sLFGMgr->GetLeader(gguid)))
+ leader->GetSession()->SendLfgOfferContinue(sLFGMgr->GetDungeon(gguid, false));
}
void LFGGroupScript::OnDisband(Group* group)
@@ -151,30 +166,19 @@ void LFGGroupScript::OnDisband(Group* group)
void LFGGroupScript::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid)
{
uint64 gguid = group->GetGUID();
- if (!gguid)
- return;
sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnChangeLeader [" UI64FMTD "]: old [" UI64FMTD "] new [" UI64FMTD "]", gguid, newLeaderGuid, oldLeaderGuid);
- Player* player = ObjectAccessor::FindPlayer(newLeaderGuid);
-
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_LEADER);
- if (player)
- player->GetSession()->SendLfgUpdateParty(updateData);
-
- player = ObjectAccessor::FindPlayer(oldLeaderGuid);
- if (player)
- {
- updateData.updateType = LFG_UPDATETYPE_GROUP_DISBAND;
- player->GetSession()->SendLfgUpdateParty(updateData);
- }
+ sLFGMgr->SetLeader(gguid, newLeaderGuid);
}
void LFGGroupScript::OnInviteMember(Group* group, uint64 guid)
{
uint64 gguid = group->GetGUID();
- if (!gguid)
- return;
-
- sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnInviteMember [" UI64FMTD "]: invite [" UI64FMTD "] leader [" UI64FMTD "]", gguid, guid, group->GetLeaderGUID());
- sLFGMgr->Leave(NULL, group);
+ uint64 leader = group->GetLeaderGUID();
+ sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnInviteMember [" UI64FMTD "]: invite [" UI64FMTD "] leader [" UI64FMTD "]", gguid, guid, leader);
+ // No gguid == new group being formed
+ // No leader == after group creation first invite is new leader
+ // leader and no gguid == first invite after leader is added to new group (this is the real invite)
+ if (leader && !gguid)
+ sLFGMgr->LeaveLfg(leader);
}
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index d152dc5642f..68d69c2e14a 100755
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -1523,14 +1523,18 @@ void GameObject::Use(Unit* user)
Player* player = user->ToPlayer();
- if (player->CanUseBattlegroundObject())
+ if (player->CanUseBattlegroundObject(this))
{
// in battleground check
Battleground* bg = player->GetBattleground();
if (!bg)
return;
+
if (player->GetVehicle())
return;
+
+ player->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
+ player->RemoveAurasByType(SPELL_AURA_MOD_INVISIBILITY);
// BG flag click
// AB:
// 15001
@@ -1563,14 +1567,18 @@ void GameObject::Use(Unit* user)
Player* player = user->ToPlayer();
- if (player->CanUseBattlegroundObject())
+ if (player->CanUseBattlegroundObject(this))
{
// in battleground check
Battleground* bg = player->GetBattleground();
if (!bg)
return;
+
if (player->GetVehicle())
return;
+
+ player->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
+ player->RemoveAurasByType(SPELL_AURA_MOD_INVISIBILITY);
// BG flag dropped
// WS:
// 179785 - Silverwing Flag
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 036062393fb..9e62f85e3a1 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -11684,7 +11684,7 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
bool lootedObjectInDungeon = false;
Map const* map = lootedObject->GetMap();
if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true))
- if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId))
+ if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId))
if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == uint32(map->GetDifficulty()))
lootedObjectInDungeon = true;
@@ -23530,7 +23530,7 @@ PartyResult Player::CanUninviteFromGroup() const
if (state == LFG_STATE_BOOT)
return ERR_PARTY_LFG_BOOT_IN_PROGRESS;
- if (grp->GetMembersCount() <= sLFGMgr->GetVotesNeeded(gguid))
+ if (grp->GetMembersCount() <= LFG_GROUP_KICK_VOTES_NEEDED)
return ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS;
if (state == LFG_STATE_FINISHED_DUNGEON)
@@ -23563,8 +23563,22 @@ PartyResult Player::CanUninviteFromGroup() const
bool Player::isUsingLfg()
{
- uint64 guid = GetGUID();
- return sLFGMgr->GetState(guid) != LFG_STATE_NONE;
+ return sLFGMgr->GetState(GetGUID()) != LFG_STATE_NONE;
+}
+
+bool Player::inRandomLfgDungeon()
+{
+ if (isUsingLfg())
+ {
+ const LfgDungeonSet& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID());
+ if (!dungeons.empty())
+ {
+ LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(*dungeons.begin());
+ if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal))
+ return true;
+ }
+ }
+ return false;
}
void Player::SetBattlegroundOrBattlefieldRaid(Group* group, int8 subgroup)
@@ -23757,10 +23771,14 @@ WorldObject* Player::GetViewpoint() const
return NULL;
}
-bool Player::CanUseBattlegroundObject()
+bool Player::CanUseBattlegroundObject(GameObject* gameobject)
{
- // TODO : some spells gives player ForceReaction to one faction (ReputationMgr::ApplyForceReaction)
- // maybe gameobject code should handle that ForceReaction usage
+ FactionTemplateEntry const* playerFaction = getFactionTemplateEntry();
+ FactionTemplateEntry const* faction = sFactionTemplateStore.LookupEntry(gameobject->GetUInt32Value(GAMEOBJECT_FACTION));
+
+ if (playerFaction && faction && !playerFaction->IsFriendlyTo(*faction))
+ return false;
+
// BUG: sometimes when player clicks on flag in AB - client won't send gameobject_use, only gameobject_report_use packet
// Note: Mount, stealth and invisibility will be removed when used
return (!isTotalImmune() && // Damage immune
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index f1f58231bef..583423a28d5 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2429,7 +2429,7 @@ class Player : public Unit, public GridObject<Player>
bool GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const;
bool isTotalImmunity();
- bool CanUseBattlegroundObject();
+ bool CanUseBattlegroundObject(GameObject* gameobject);
bool isTotalImmune();
bool CanCaptureTowerPoint();
@@ -2548,6 +2548,7 @@ class Player : public Unit, public GridObject<Player>
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist = false);
bool isUsingLfg();
+ bool inRandomLfgDungeon();
typedef std::set<uint32> DFQuestsDoneList;
DFQuestsDoneList m_DFQuests;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index d62a4c9b9fb..87f4a0e6dbf 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -47,6 +47,7 @@
#include "PoolMgr.h"
#include "DB2Structure.h"
#include "DB2Stores.h"
+#include "LFGMgr.h"
ScriptMapMap sQuestEndScripts;
ScriptMapMap sQuestStartScripts;
@@ -4978,7 +4979,7 @@ void ObjectMgr::LoadInstanceEncounters()
continue;
}
- if (lastEncounterDungeon && !sLFGDungeonStore.LookupEntry(lastEncounterDungeon))
+ if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeon(lastEncounterDungeon))
{
sLog->outError(LOG_FILTER_SQL, "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName, lastEncounterDungeon);
continue;
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 84e5dd58e44..2b35020fd62 100755
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -554,7 +554,7 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV
WorldPacket data;
- if (method == GROUP_REMOVEMETHOD_KICK)
+ if (method == GROUP_REMOVEMETHOD_KICK || method == GROUP_REMOVEMETHOD_KICK_LFG)
{
data.Initialize(SMSG_GROUP_UNINVITE, 0);
player->GetSession()->SendPacket(&data);
@@ -631,7 +631,7 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV
if (isLFGGroup() && GetMembersCount() == 1)
{
Player* Leader = ObjectAccessor::FindPlayer(GetLeaderGUID());
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(sLFGMgr->GetDungeon(GetGUID()));
+ LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(sLFGMgr->GetDungeon(GetGUID()));
if ((Leader && dungeon && Leader->isAlive() && Leader->GetMapId() != uint32(dungeon->map)) || !dungeon)
{
Disband();
diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp
index c2d8dbb8ee0..02c5b2e1414 100755
--- a/src/server/game/Handlers/LFGHandler.cpp
+++ b/src/server/game/Handlers/LFGHandler.cpp
@@ -23,8 +23,6 @@
#include "LFGMgr.h"
#include "ObjectMgr.h"
#include "GroupMgr.h"
-#include "GameEventMgr.h"
-#include "InstanceScript.h"
void BuildPlayerLockDungeonBlock(WorldPacket& data, const LfgLockMap& lock)
{
@@ -84,18 +82,20 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData)
std::string comment;
recvData >> comment;
sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_JOIN [" UI64FMTD "] roles: %u, Dungeons: %u, Comment: %s", GetPlayer()->GetGUID(), roles, uint8(newDungeons.size()), comment.c_str());
- sLFGMgr->Join(GetPlayer(), uint8(roles), newDungeons, comment);
+ sLFGMgr->JoinLfg(GetPlayer(), uint8(roles), newDungeons, comment);
}
void WorldSession::HandleLfgLeaveOpcode(WorldPacket& /*recvData*/)
{
Group* grp = GetPlayer()->GetGroup();
+ uint64 guid = GetPlayer()->GetGUID();
+ uint64 gguid = grp ? grp->GetGUID() : guid;
- sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LEAVE [" UI64FMTD "] in group: %u", GetPlayer()->GetGUID(), grp ? 1 : 0);
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LEAVE [" UI64FMTD "] in group: %u", guid, grp ? 1 : 0);
// Check cheating - only leader can leave the queue
if (!grp || grp->GetLeaderGUID() == GetPlayer()->GetGUID())
- sLFGMgr->Leave(GetPlayer(), grp);
+ sLFGMgr->LeaveLfg(gguid);
}
void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recvData)
@@ -130,7 +130,7 @@ void WorldSession::HandleLfgSetCommentOpcode(WorldPacket& recvData)
std::string comment;
recvData >> comment;
uint64 guid = GetPlayer()->GetGUID();
- sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_LFG_COMMENT [" UI64FMTD "] comment: %s", guid, comment.c_str());
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_COMMENT [" UI64FMTD "] comment: %s", guid, comment.c_str());
sLFGMgr->SetComment(guid, comment);
}
@@ -140,8 +140,9 @@ void WorldSession::HandleLfgSetBootVoteOpcode(WorldPacket& recvData)
bool agree; // Agree to kick player
recvData >> agree;
- sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_BOOT_VOTE [" UI64FMTD "] agree: %u", GetPlayer()->GetGUID(), agree ? 1 : 0);
- sLFGMgr->UpdateBoot(GetPlayer(), agree);
+ uint64 guid = GetPlayer()->GetGUID();
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_BOOT_VOTE [" UI64FMTD "] agree: %u", guid, agree ? 1 : 0);
+ sLFGMgr->UpdateBoot(guid, agree);
}
void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recvData)
@@ -156,32 +157,24 @@ void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recvData)
void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*/)
{
uint64 guid = GetPlayer()->GetGUID();
- sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST [" UI64FMTD "]", guid);
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_PLAYER_LOCK_INFO_REQUEST [" UI64FMTD "]", guid);
// Get Random dungeons that can be done at a certain level and expansion
LfgDungeonSet randomDungeons;
uint8 level = GetPlayer()->getLevel();
uint8 expansion = GetPlayer()->GetSession()->Expansion();
- for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
- {
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i);
- if (dungeon && dungeon->expansion <= expansion && dungeon->minlevel <= level && level <= dungeon->maxlevel)
- {
- if (dungeon->flags & LFG_FLAG_SEASONAL)
- {
- if (HolidayIds holiday = sLFGMgr->GetDungeonSeason(dungeon->ID))
- if (!IsHolidayActive(holiday))
- continue;
- }
- else if (dungeon->type != LFG_TYPE_RANDOM)
- continue;
- randomDungeons.insert(dungeon->Entry());
- }
+ LFGDungeonMap& LfgDungeons = sLFGMgr->GetLFGDungeonMap();
+ for (LFGDungeonMap::const_iterator itr = LfgDungeons.begin(); itr != LfgDungeons.end(); ++itr)
+ {
+ LFGDungeonEntry const& dungeon = itr->second;
+ if ((dungeon.type == LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id)))
+ && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel)
+ randomDungeons.insert(dungeon.Entry());
}
// Get player locked Dungeons
- LfgLockMap lock = sLFGMgr->GetLockedDungeons(guid);
+ LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid);
uint32 rsize = uint32(randomDungeons.size());
uint32 lsize = uint32(lock.size());
@@ -193,40 +186,37 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*
{
data << uint32(*it); // Dungeon Entry (id + type)
LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level);
- Quest const* qRew = NULL;
+ Quest const* quest = NULL;
uint8 done = 0;
if (reward)
{
- qRew = sObjectMgr->GetQuestTemplate(reward->reward[0].questId);
- if (qRew)
+ quest = sObjectMgr->GetQuestTemplate(reward->reward[0].questId);
+ if (quest)
{
- done = !GetPlayer()->CanRewardQuest(qRew, false);
+ done = !GetPlayer()->CanRewardQuest(quest, false);
if (done)
- qRew = sObjectMgr->GetQuestTemplate(reward->reward[1].questId);
+ quest = sObjectMgr->GetQuestTemplate(reward->reward[1].questId);
}
}
- if (qRew)
+
+ if (quest)
{
data << uint8(done);
- data << uint32(qRew->GetRewOrReqMoney());
- data << uint32(qRew->XPValue(GetPlayer()));
+ data << uint32(quest->GetRewOrReqMoney());
+ data << uint32(quest->XPValue(GetPlayer()));
data << uint32(reward->reward[done].variableMoney);
data << uint32(reward->reward[done].variableXP);
- data << uint8(qRew->GetRewItemsCount());
- if (qRew->GetRewItemsCount())
+ data << uint8(quest->GetRewItemsCount());
+ if (quest->GetRewItemsCount())
{
- ItemTemplate const* iProto = NULL;
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
- {
- if (!qRew->RewardItemId[i])
- continue;
-
- iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]);
-
- data << uint32(qRew->RewardItemId[i]);
- data << uint32(iProto ? iProto->DisplayInfoID : 0);
- data << uint32(qRew->RewardItemIdCount[i]);
- }
+ if (uint32 itemId = quest->RewardItemId[i])
+ {
+ ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
+ data << uint32(itemId);
+ data << uint32(item ? item->DisplayInfoID : 0);
+ data << uint32(quest->RewardItemIdCount[i]);
+ }
}
}
else
@@ -246,7 +236,7 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*
void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData*/)
{
uint64 guid = GetPlayer()->GetGUID();
- sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PARTY_LOCK_INFO_REQUEST [" UI64FMTD "]", guid);
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_PARTY_LOCK_INFO_REQUEST [" UI64FMTD "]", guid);
Group* grp = GetPlayer()->GetGroup();
if (!grp)
@@ -277,11 +267,11 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData*
SendPacket(&data);
}
-void WorldSession::HandleLfrSearchOpcode(WorldPacket& recvData)
+void WorldSession::HandleLfrJoinOpcode(WorldPacket& recv_data)
{
uint32 entry; // Raid id to search
- recvData >> entry;
- sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_JOIN [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), entry);
+ recv_data >> entry;
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LFR_JOIN [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), entry);
//SendLfrUpdateListOpcode(entry);
}
@@ -289,7 +279,7 @@ void WorldSession::HandleLfrLeaveOpcode(WorldPacket& recvData)
{
uint32 dungeonId; // Raid id queue to leave
recvData >> dungeonId;
- sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_LEAVE [" UI64FMTD "] dungeonId: %u", GetPlayer()->GetGUID(), dungeonId);
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LFR_LEAVE [" UI64FMTD "] dungeonId: %u", GetPlayer()->GetGUID(), dungeonId);
//sLFGMgr->LeaveLfr(GetPlayer(), dungeonId);
}
@@ -297,6 +287,8 @@ void WorldSession::SendLfgUpdatePlayer(const LfgUpdateData& updateData)
{
bool queued = false;
bool extrainfo = false;
+ uint64 guid = GetPlayer()->GetGUID();
+ uint8 size = uint8(updateData.dungeons.size());
switch (updateData.updateType)
{
@@ -313,9 +305,6 @@ void WorldSession::SendLfgUpdatePlayer(const LfgUpdateData& updateData)
break;
}
- uint64 guid = GetPlayer()->GetGUID();
- uint8 size = uint8(updateData.dungeons.size());
-
sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PLAYER [" UI64FMTD "] updatetype: %u", guid, updateData.updateType);
WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + size * 4 + updateData.comment.length()));
data << uint8(updateData.updateType); // Lfg Update type
@@ -340,6 +329,8 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData)
bool join = false;
bool extrainfo = false;
bool queued = false;
+ uint64 guid = GetPlayer()->GetGUID();
+ uint8 size = uint8(updateData.dungeons.size());
switch (updateData.updateType)
{
@@ -363,9 +354,6 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData)
break;
}
- uint64 guid = GetPlayer()->GetGUID();
- uint8 size = uint8(updateData.dungeons.size());
-
sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PARTY [" UI64FMTD "] updatetype: %u", guid, updateData.updateType);
WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + size * 4 + updateData.comment.length()));
data << uint8(updateData.updateType); // Lfg Update type
@@ -399,45 +387,44 @@ void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles)
SendPacket(&data);
}
-void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck)
+void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck)
{
- ASSERT(pRoleCheck);
LfgDungeonSet dungeons;
- if (pRoleCheck->rDungeonId)
- dungeons.insert(pRoleCheck->rDungeonId);
+ if (roleCheck.rDungeonId)
+ dungeons.insert(roleCheck.rDungeonId);
else
- dungeons = pRoleCheck->dungeons;
+ dungeons = roleCheck.dungeons;
sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHECK_UPDATE [" UI64FMTD "]", GetPlayer()->GetGUID());
- WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1));
+ WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + roleCheck.roles.size() * (8 + 1 + 4 + 1));
- data << uint32(pRoleCheck->state); // Check result
- data << uint8(pRoleCheck->state == LFG_ROLECHECK_INITIALITING);
+ data << uint32(roleCheck.state); // Check result
+ data << uint8(roleCheck.state == LFG_ROLECHECK_INITIALITING);
data << uint8(dungeons.size()); // Number of dungeons
if (!dungeons.empty())
{
for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it)
{
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it);
+ LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(*it);
data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon
}
}
- data << uint8(pRoleCheck->roles.size()); // Players in group
- if (!pRoleCheck->roles.empty())
+ data << uint8(roleCheck.roles.size()); // Players in group
+ if (!roleCheck.roles.empty())
{
// Leader info MUST be sent 1st :S
- uint64 guid = pRoleCheck->leader;
- uint8 roles = pRoleCheck->roles.find(guid)->second;
+ uint64 guid = roleCheck.leader;
+ uint8 roles = roleCheck.roles.find(guid)->second;
data << uint64(guid); // Guid
data << uint8(roles > 0); // Ready
data << uint32(roles); // Roles
Player* player = ObjectAccessor::FindPlayer(guid);
data << uint8(player ? player->getLevel() : 0); // Level
- for (LfgRolesMap::const_iterator it = pRoleCheck->roles.begin(); it != pRoleCheck->roles.end(); ++it)
+ for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
{
- if (it->first == pRoleCheck->leader)
+ if (it->first == roleCheck.leader)
continue;
guid = it->first;
@@ -467,30 +454,31 @@ void WorldSession::SendLfgJoinResult(const LfgJoinResultData& joinData)
SendPacket(&data);
}
-void WorldSession::SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps)
+void WorldSession::SendLfgQueueStatus(const LfgQueueStatusData& queueData)
{
- sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_QUEUE_STATUS [" UI64FMTD "] dungeon: %u - waitTime: %d - avgWaitTime: %d - waitTimeTanks: %d - waitTimeHealer: %d - waitTimeDps: %d - queuedTime: %u - tanks: %u - healers: %u - dps: %u", GetPlayer()->GetGUID(), dungeon, waitTime, avgWaitTime, waitTimeTanks, waitTimeHealer, waitTimeDps, queuedTime, tanks, healers, dps);
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_QUEUE_STATUS [" UI64FMTD "] dungeon: %u - waitTime: %d - avgWaitTime: %d - waitTimeTanks: %d - waitTimeHealer: %d - waitTimeDps: %d - queuedTime: %u - tanks: %u - healers: %u - dps: %u",
+ GetPlayer()->GetGUID(), queueData.dungeonId, queueData.waitTime, queueData.waitTimeAvg, queueData.waitTimeTank, queueData.waitTimeHealer, queueData.waitTimeDps, queueData.queuedTime, queueData.tanks, queueData.healers, queueData.dps);
WorldPacket data(SMSG_LFG_QUEUE_STATUS, 4 + 4 + 4 + 4 + 4 +4 + 1 + 1 + 1 + 4);
- data << uint32(dungeon); // Dungeon
- data << int32(avgWaitTime); // Average Wait time
- data << int32(waitTime); // Wait Time
- data << int32(waitTimeTanks); // Wait Tanks
- data << int32(waitTimeHealer); // Wait Healers
- data << int32(waitTimeDps); // Wait Dps
- data << uint8(tanks); // Tanks needed
- data << uint8(healers); // Healers needed
- data << uint8(dps); // Dps needed
- data << uint32(queuedTime); // Player wait time in queue
+ data << uint32(queueData.dungeonId); // Dungeon
+ data << int32(queueData.waitTimeAvg); // Average Wait time
+ data << int32(queueData.waitTime); // Wait Time
+ data << int32(queueData.waitTimeTank); // Wait Tanks
+ data << int32(queueData.waitTimeHealer); // Wait Healers
+ data << int32(queueData.waitTimeDps); // Wait Dps
+ data << uint8(queueData.tanks); // Tanks needed
+ data << uint8(queueData.healers); // Healers needed
+ data << uint8(queueData.dps); // Dps needed
+ data << uint32(queueData.queuedTime); // Player wait time in queue
SendPacket(&data);
}
-void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest* qRew)
+void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest* quest)
{
- if (!rdungeonEntry || !sdungeonEntry || !qRew)
+ if (!rdungeonEntry || !sdungeonEntry || !quest)
return;
- uint8 itemNum = uint8(qRew ? qRew->GetRewItemsCount() : 0);
+ uint8 itemNum = uint8(quest ? quest->GetRewItemsCount() : 0);
sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PLAYER_REWARD [" UI64FMTD "] rdungeonEntry: %u - sdungeonEntry: %u - done: %u", GetPlayer()->GetGUID(), rdungeonEntry, sdungeonEntry, done);
WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4));
@@ -498,37 +486,33 @@ void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntr
data << uint32(sdungeonEntry); // Dungeon Finished
data << uint8(done);
data << uint32(1);
- data << uint32(qRew->GetRewOrReqMoney());
- data << uint32(qRew->XPValue(GetPlayer()));
+ data << uint32(quest->GetRewOrReqMoney());
+ data << uint32(quest->XPValue(GetPlayer()));
data << uint32(reward->reward[done].variableMoney);
data << uint32(reward->reward[done].variableXP);
data << uint8(itemNum);
if (itemNum)
{
- ItemTemplate const* iProto = NULL;
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
- {
- if (!qRew->RewardItemId[i])
- continue;
-
- iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]);
-
- data << uint32(qRew->RewardItemId[i]);
- data << uint32(iProto ? iProto->DisplayInfoID : 0);
- data << uint32(qRew->RewardItemIdCount[i]);
- }
+ if (uint32 itemId = quest->RewardItemId[i])
+ {
+ ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
+ data << uint32(itemId);
+ data << uint32(item ? item->DisplayInfoID : 0);
+ data << uint32(quest->RewardItemIdCount[i]);
+ }
}
SendPacket(&data);
}
-void WorldSession::SendLfgBootPlayer(const LfgPlayerBoot* pBoot)
+void WorldSession::SendLfgBootProposalUpdate(const LfgPlayerBoot& boot)
{
uint64 guid = GetPlayer()->GetGUID();
- LfgAnswer playerVote = pBoot->votes.find(guid)->second;
+ LfgAnswer playerVote = boot.votes.find(guid)->second;
uint8 votesNum = 0;
uint8 agreeNum = 0;
- uint32 secsleft = uint8((pBoot->cancelTime - time(NULL)) / 1000);
- for (LfgAnswerMap::const_iterator it = pBoot->votes.begin(); it != pBoot->votes.end(); ++it)
+ uint32 secsleft = uint8((boot.cancelTime - time(NULL)) / 1000);
+ for (LfgAnswerMap::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it)
{
if (it->second != LFG_ANSWER_PENDING)
{
@@ -538,107 +522,73 @@ void WorldSession::SendLfgBootPlayer(const LfgPlayerBoot* pBoot)
}
}
sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_BOOT_PROPOSAL_UPDATE [" UI64FMTD "] inProgress: %u - didVote: %u - agree: %u - victim: [" UI64FMTD "] votes: %u - agrees: %u - left: %u - needed: %u - reason %s",
- guid, uint8(pBoot->inProgress), uint8(playerVote != LFG_ANSWER_PENDING), uint8(playerVote == LFG_ANSWER_AGREE), pBoot->victim, votesNum, agreeNum, secsleft, pBoot->votedNeeded, pBoot->reason.c_str());
- WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + pBoot->reason.length());
- data << uint8(pBoot->inProgress); // Vote in progress
+ guid, uint8(boot.inProgress), uint8(playerVote != LFG_ANSWER_PENDING), uint8(playerVote == LFG_ANSWER_AGREE), boot.victim, votesNum, agreeNum, secsleft, LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str());
+ WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length());
+ data << uint8(boot.inProgress); // Vote in progress
data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote
data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree
data << uint8(0); // Unknown 4.2.2
- data << uint64(pBoot->victim); // Victim GUID
+ data << uint64(boot.victim); // Victim GUID
data << uint32(votesNum); // Total Votes
data << uint32(agreeNum); // Agree Count
data << uint32(secsleft); // Time Left
- data << uint32(pBoot->votedNeeded); // Needed Votes
- data << pBoot->reason.c_str(); // Kick reason
+ data << uint32(LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes
+ data << boot.reason.c_str(); // Kick reason
SendPacket(&data);
}
-void WorldSession::SendLfgUpdateProposal(uint32 proposalId, const LfgProposal* pProp)
+void WorldSession::SendLfgUpdateProposal(uint32 proposalId, LfgProposal const& proposal)
{
- if (!pProp)
- return;
-
uint64 guid = GetPlayer()->GetGUID();
- LfgProposalPlayerMap::const_iterator itPlayer = pProp->players.find(guid);
- if (itPlayer == pProp->players.end()) // Player MUST be in the proposal
- return;
+ uint64 gguid = proposal.players.find(guid)->second.group;
+ bool silent = !proposal.isNew && gguid == proposal.group;
+ uint32 dungeonEntry = proposal.dungeonId;
- LfgProposalPlayer* ppPlayer = itPlayer->second;
- uint32 pLowGroupGuid = ppPlayer->groupLowGuid;
- uint32 dLowGuid = pProp->groupLowGuid;
- uint32 dungeonId = pProp->dungeonId;
- bool isSameDungeon = false;
- bool isContinue = false;
- Group* grp = dLowGuid ? sGroupMgr->GetGroupByGUID(dLowGuid) : NULL;
- uint32 completedEncounters = 0;
- if (grp)
- {
- uint64 gguid = grp->GetGUID();
- isContinue = grp->isLFGGroup() && sLFGMgr->GetState(gguid) != LFG_STATE_FINISHED_DUNGEON;
- isSameDungeon = GetPlayer()->GetGroup() == grp && isContinue;
- }
-
- sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PROPOSAL_UPDATE [" UI64FMTD "] state: %u", GetPlayer()->GetGUID(), pProp->state);
- WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + pProp->players.size() * (4 + 1 + 1 + 1 + 1 +1));
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PROPOSAL_UPDATE [" UI64FMTD "] state: %u", guid, proposal.state);
+ WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + proposal.players.size() * (4 + 1 + 1 + 1 + 1 +1));
- if (!isContinue) // Only show proposal dungeon if it's continue
+ // show random dungeon if player selected random dungeon and it's not lfg group
+ if (!silent)
{
- LfgDungeonSet playerDungeons = sLFGMgr->GetSelectedDungeons(guid);
- if (playerDungeons.size() == 1)
- dungeonId = (*playerDungeons.begin());
+ LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid);
+ if (playerDungeons.find(proposal.dungeonId) == playerDungeons.end())
+ dungeonEntry = (*playerDungeons.begin());
}
- if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId))
- {
- dungeonId = dungeon->Entry();
-
- // Select a player inside to be get completed encounters from
- if (grp)
- {
- for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player* groupMember = itr->getSource();
- if (groupMember && groupMember->GetMapId() == uint32(dungeon->map))
- {
- if (InstanceScript* instance = groupMember->GetInstanceScript())
- completedEncounters = instance->GetCompletedEncounterMask();
- break;
- }
- }
- }
- }
+ if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonEntry))
+ dungeonEntry = dungeon->Entry();
- data << uint32(dungeonId); // Dungeon
- data << uint8(pProp->state); // Result state
- data << uint32(proposalId); // Internal Proposal ID
- data << uint32(completedEncounters); // Bosses killed
- data << uint8(isSameDungeon); // Silent (show client window)
- data << uint8(pProp->players.size()); // Group size
+ data << uint32(dungeonEntry); // Dungeon
+ data << uint8(proposal.state); // Proposal state
+ data << uint32(proposalId); // Proposal ID
+ data << uint32(proposal.encounters); // encounters done
+ data << uint8(silent); // Show proposal window
+ data << uint8(proposal.players.size()); // Group size
- for (itPlayer = pProp->players.begin(); itPlayer != pProp->players.end(); ++itPlayer)
+ for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
{
- ppPlayer = itPlayer->second;
- data << uint32(ppPlayer->role); // Role
- data << uint8(itPlayer->first == guid); // Self player
- if (!ppPlayer->groupLowGuid) // Player not it a group
+ LfgProposalPlayer const& player = it->second;
+ data << uint32(player.role); // Role
+ data << uint8(it->first == guid); // Self player
+ if (!player.group) // Player not it a group
{
data << uint8(0); // Not in dungeon
data << uint8(0); // Not same group
}
else
{
- data << uint8(ppPlayer->groupLowGuid == dLowGuid); // In dungeon (silent)
- data << uint8(ppPlayer->groupLowGuid == pLowGroupGuid); // Same Group than player
+ data << uint8(player.group == proposal.group); // In dungeon (silent)
+ data << uint8(player.group == gguid); // Same Group than player
}
- data << uint8(ppPlayer->accept != LFG_ANSWER_PENDING); // Answered
- data << uint8(ppPlayer->accept == LFG_ANSWER_AGREE); // Accepted
+ data << uint8(player.accept != LFG_ANSWER_PENDING); // Answered
+ data << uint8(player.accept == LFG_ANSWER_AGREE); // Accepted
}
SendPacket(&data);
}
-void WorldSession::SendLfgUpdateSearch(bool update)
+void WorldSession::SendLfgLfrList(bool update)
{
- sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_SEARCH [" UI64FMTD "] update: %u", GetPlayer()->GetGUID(), update ? 1 : 0);
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_LFR_LIST [" UI64FMTD "] update: %u", GetPlayer()->GetGUID(), update ? 1 : 0);
WorldPacket data(SMSG_LFG_UPDATE_SEARCH, 1);
data << uint8(update); // In Lfg Queue?
SendPacket(&data);
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index c0f4bfd1c24..eff6543443a 100755
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -2469,8 +2469,8 @@ bool InstanceMap::AddPlayerToMap(Player* player)
if (group && group->isLFGGroup())
if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true))
- if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId))
- if (LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin())))
+ if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId))
+ if (LFGDungeonEntry const* randomDungeon = sLFGMgr->GetLFGDungeon(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin())))
if (uint32(dungeon->map) == GetId() && dungeon->difficulty == uint32(GetDifficulty()) && randomDungeon->type == uint32(LFG_TYPE_RANDOM))
player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true);
}
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index c55c57481f4..1de08a21563 100755
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1084,7 +1084,22 @@ enum TrinityStrings
// Use for custom patches 11000-11999
LANG_AUTO_BROADCAST = 11000,
- LANG_INVALID_REALMID = 11001
+ LANG_INVALID_REALMID = 11001,
+
+ LANG_LFG_STATE_NONE = 11002,
+ LANG_LFG_STATE_ROLECHECK = 11003,
+ LANG_LFG_STATE_QUEUED = 11004,
+ LANG_LFG_STATE_PROPOSAL = 11005,
+ LANG_LFG_STATE_BOOT = 11006,
+ LANG_LFG_STATE_DUNGEON = 11007,
+ LANG_LFG_STATE_FINISHED_DUNGEON = 11008,
+ LANG_LFG_STATE_RAIDBROWSER = 11009,
+ LANG_LFG_ROLE_TANK = 11010,
+ LANG_LFG_ROLE_HEALER = 11011,
+ LANG_LFG_ROLE_DAMAGE = 11012,
+ LANG_LFG_ROLE_LEADER = 11013,
+ LANG_LFG_ROLE_NONE = 11014,
+ LANG_LFG_ERROR = 11015,
// NOT RESERVED IDS 12000-1999999999
// `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID)
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 2c0dd0aa1a3..ed7ed2ea05a 100755
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -3697,9 +3697,10 @@ enum XPColorChar
enum RemoveMethod
{
- GROUP_REMOVEMETHOD_DEFAULT = 0,
- GROUP_REMOVEMETHOD_KICK = 1,
- GROUP_REMOVEMETHOD_LEAVE = 2
+ GROUP_REMOVEMETHOD_DEFAULT = 0,
+ GROUP_REMOVEMETHOD_KICK = 1,
+ GROUP_REMOVEMETHOD_LEAVE = 2,
+ GROUP_REMOVEMETHOD_KICK_LFG = 3
};
enum ActivateTaxiReply
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 694b2cf2d7f..022faa11b27 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -1477,7 +1477,7 @@ void OpcodeTable::Initialize()
//DEFINE_OPCODE_HANDLER(CMSG_RUN_SCRIPT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_OPCODE_HANDLER(CMSG_SAVE_DANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_OPCODE_HANDLER(CMSG_SAVE_PLAYER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- //DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_JOIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrSearchOpcode );
+ //DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_JOIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrJoinOpcode );
//DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_LEAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrLeaveOpcode );
//DEFINE_OPCODE_HANDLER(CMSG_SEND_COMBAT_TRIGGER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_OPCODE_HANDLER(CMSG_SEND_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 5c61385f537..fb555b42ea0 100755
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -55,6 +55,7 @@ struct LfgJoinResultData;
struct LfgLockStatus;
struct LfgPlayerBoot;
struct LfgProposal;
+struct LfgQueueStatusData;
struct LfgReward;
struct LfgRoleCheck;
struct LfgUpdateData;
@@ -844,19 +845,19 @@ class WorldSession
void HandleLfgProposalResultOpcode(WorldPacket& recvData);
void HandleLfgSetBootVoteOpcode(WorldPacket& recvData);
void HandleLfgTeleportOpcode(WorldPacket& recvData);
- void HandleLfrSearchOpcode(WorldPacket& recvData);
+ void HandleLfrJoinOpcode(WorldPacket& recvData);
void HandleLfrLeaveOpcode(WorldPacket& recvData);
void SendLfgUpdatePlayer(const LfgUpdateData& updateData);
void SendLfgUpdateParty(const LfgUpdateData& updateData);
void SendLfgRoleChosen(uint64 guid, uint8 roles);
- void SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck);
- void SendLfgUpdateSearch(bool update);
+ void SendLfgRoleCheckUpdate(const LfgRoleCheck& pRoleCheck);
+ void SendLfgLfrList(bool update);
void SendLfgJoinResult(const LfgJoinResultData& joinData);
- void SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps);
+ void SendLfgQueueStatus(const LfgQueueStatusData& queueData);
void SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest *qRew);
- void SendLfgBootPlayer(const LfgPlayerBoot* pBoot);
- void SendLfgUpdateProposal(uint32 proposalId, const LfgProposal *pProp);
+ void SendLfgBootProposalUpdate(const LfgPlayerBoot& boot);
+ void SendLfgUpdateProposal(uint32 proposalId, const LfgProposal& proposal);
void SendLfgDisabled();
void SendLfgOfferContinue(uint32 dungeonEntry);
void SendLfgTeleportError(uint8 err);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 04a371ba776..57f3a7d3711 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5243,7 +5243,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() &&
m_targets.GetGOTarget()->GetGOInfo()->type != GAMEOBJECT_TYPE_TRAP))
if (m_caster->ToPlayer()->InBattleground() && // In Battleground players can use only flags and banners
- !m_caster->ToPlayer()->CanUseBattlegroundObject())
+ !m_caster->ToPlayer()->CanUseBattlegroundObject(m_targets.GetGOTarget()))
return SPELL_FAILED_TRY_AGAIN;
// get the lock entry
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 371668e73d9..43c0f5bd73c 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1467,14 +1467,15 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Vehicle Accessories...");
sObjectMgr->LoadVehicleAccessories(); // must be after LoadCreatureTemplates() and LoadNPCSpellClickSpells()
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG entrance positions...");
+ sLFGMgr->LoadLFGDungeons();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Dungeon boss data...");
sObjectMgr->LoadInstanceEncounters();
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG rewards...");
sLFGMgr->LoadRewards();
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG entrance positions...");
- sLFGMgr->LoadEntrancePositions();
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading SpellArea Data..."); // must be after quest load
sSpellMgr->LoadSpellAreas();
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 21402ddcd92..fee77fc5796 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -1581,12 +1581,12 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader
}
- LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*itr);
+ LFGDungeonEntry const* randomDungeon = sLFGMgr->GetLFGDungeon(*itr);
if (Group* group = owner->GetGroup())
if (Map const* map = owner->GetMap())
if (group->isLFGGroup())
if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true))
- if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId))
+ if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId))
if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == uint32(map->GetDifficulty()))
if (randomDungeon && randomDungeon->type == LFG_TYPE_RANDOM)
return; // in correct dungeon